部署运维
精选
Docker 部署 PocketBase 完整指南
详细介绍如何使用 Docker 容器化部署 PocketBase,包括单机部署、数据持久化、反向代理配置、以及生产环境最佳实践。
PocketBase.cn
· 目录
为什么使用 Docker
Docker 部署优势
传统部署 Docker 部署┌─────────────────┐ ┌─────────────────┐│ 环境依赖复杂 │ │ 环境隔离 ││ 版本冲突 │ VS │ 一致的运行环境 ││ 迁移困难 │ │ 快速部署 ││ 扩展不便 │ │ 容易扩展 ││ 回滚麻烦 │ │ 快速回滚 │└─────────────────┘ └─────────────────┘| 优势 | 说明 |
|---|---|
| 环境一致性 | 开发、测试、生产环境完全一致 |
| 快速部署 | 几秒钟启动新实例 |
| 易于扩展 | 支持水平扩展和负载均衡 |
| 资源隔离 | CPU、内存、网络隔离 |
| 版本管理 | 镜像版本化管理,支持快速回滚 |
| 安全性 | 最小化容器,减少攻击面 |
基础部署
1. 快速开始
使用官方镜像
# 拉取最新镜像docker pull ghcr.io/muchdogesec/pocketbase:latest
# 运行容器docker run -d \ --name pocketbase \ -p 8090:8090 \ ghcr.io/muchdogesec/pocketbase:latest使用国内镜像
# 使用阿里云镜像加速docker pull registry.cn-hangzhou.aliyuncs.com/pocketbase/pocketbase:latest
docker run -d \ --name pocketbase \ -p 8090:8090 \ registry.cn-hangzhou.aliyuncs.com/pocketbase/pocketbase:latest2. Docker Compose 部署
创建 docker-compose.yml:
version: "3.8"
services: pocketbase: image: ghcr.io/muchdogesec/pocketbase:latest container_name: pocketbase ports: - "8090:8090" volumes: - ./pb_data:/pb_data - ./pb_public:/pb_public restart: unless-stopped healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8090/api/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s environment: - TZ=Asia/Shanghai启动服务:
# 启动docker-compose up -d
# 查看日志docker-compose logs -f
# 停止docker-compose down3. 自定义 Dockerfile
如果需要自定义配置,创建 Dockerfile:
# 使用官方镜像作为基础FROM ghcr.io/muchdogesec/pocketbase:latest
# 设置时区ENV TZ=Asia/ShanghaiRUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 创建必要的目录RUN mkdir -p /pb_data /pb_public /pb_hooks
# 复制自定义 HooksCOPY ./pb_hooks /pb_hooks
# 设置权限RUN chown -R pocketbase:pocketbase /pb_data /pb_public /pb_hooks
# 切换用户USER pocketbase
# 暴露端口EXPOSE 8090
# 健康检查HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD wget -q --spider http://localhost:8090/api/health || exit 1
# 启动命令CMD ["/pocketbase", "serve", "--http=0.0.0.0:8090"]构建和运行:
# 构建镜像docker build -t my-pocketbase:latest .
# 运行容器docker run -d \ --name pocketbase \ -p 8090:8090 \ -v $(pwd)/pb_data:/pb_data \ -v $(pwd)/pb_public:/pb_public \ my-pocketbase:latest数据持久化
1. 理解 PocketBase 数据目录
PocketBase 容器├── /pb_data/ # 数据库和核心数据(必须持久化)│ ├── data.db # SQLite 数据库文件│ └── ...├── /pb_public/ # 公共静态文件(建议持久化)│ └── uploads/ # 用户上传的文件├── /pb_hooks/ # 自定义 Hooks(可选持久化)└── /pb_migrations/ # 数据库迁移文件(可选持久化)2. Volume 配置方式
命名 Volume(推荐用于生产)
version: "3.8"
services: pocketbase: image: ghcr.io/muchdogesec/pocketbase:latest volumes: - pb_data:/pb_data - pb_public:/pb_public ports: - "8090:8090" restart: unless-stopped
volumes: pb_data: driver: local pb_public: driver: local绑定挂载(适合开发)
version: "3.8"
services: pocketbase: image: ghcr.io/muchdogesec/pocketbase:latest volumes: - ./data:/pb_data - ./public:/pb_public ports: - "8090:8090"3. 数据备份策略
自动备份脚本
#!/bin/bashBACKUP_DIR="./backups"DATE=$(date +%Y%m%d_%H%M%S)CONTAINER_NAME="pocketbase"
# 创建备份目录mkdir -p "$BACKUP_DIR"
# 备份数据库docker exec $CONTAINER_NAME \ wget -qO- "http://localhost:8090/api/export-database" \ > "$BACKUP_DIR/data_$DATE.db"
# 压缩备份tar -czf "$BACKUP_DIR/backup_$DATE.tar.gz" \ -C ./data . \ -C ./public .
# 删除 7 天前的备份find "$BACKUP_DIR" -name "backup_*.tar.gz" -mtime +7 -delete
echo "Backup completed: backup_$DATE.tar.gz"定时备份(Cron)
# 编辑 crontabcrontab -e
# 每天凌晨 2 点备份0 2 * * * /path/to/backup.sh >> /var/log/pocketbase-backup.log 2>&1反向代理配置
1. Nginx 配置
基础配置
upstream pocketbase { server 127.0.0.1:8090; keepalive 32;}
server { listen 80; server_name api.yourdomain.com;
# 重定向到 HTTPS return 301 https://$server_name$request_uri;}
server { listen 443 ssl http2; server_name api.yourdomain.com;
# SSL 证书配置 ssl_certificate /etc/ssl/certs/yourdomain.crt; ssl_certificate_key /etc/ssl/private/yourdomain.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5;
# 日志 access_log /var/log/nginx/pocketbase-access.log; error_log /var/log/nginx/pocketbase-error.log;
# 上传文件大小限制 client_max_body_size 100M;
# 代理设置 location / { proxy_pass http://pocketbase; proxy_http_version 1.1;
# WebSocket 支持 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
# 通用头部 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; }
# 静态文件缓存 location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ { proxy_pass http://pocketbase; expires 30d; add_header Cache-Control "public, immutable"; }}使用 Let’s Encrypt 自动证书
# 安装 certbotapt install certbot python3-certbot-nginx
# 获取证书certbot --nginx -d api.yourdomain.com
# 自动续期certbot renew --dry-run2. Traefik 集成
version: "3.8"
services: pocketbase: image: ghcr.io/muchdogesec/pocketbase:latest volumes: - pb_data:/pb_data - pb_public:/pb_public networks: - web labels: - "traefik.enable=true" - "traefik.http.routers.pocketbase.rule=Host(`api.yourdomain.com`)" - "traefik.http.routers.pocketbase.entrypoints=websecure" - "traefik.http.routers.pocketbase.tls.certresolver=letsencrypt" - "traefik.http.services.pocketbase.loadbalancer.server.port=8090" restart: unless-stopped
traefik: image: traefik:v2.10 command: - "--api.dashboard=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" - "--certificatesresolvers.letsencrypt.acme.email=your@email.com" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./letsencrypt:/letsencrypt" networks: - web
networks: web: external: true
volumes: pb_data: pb_public:3. Caddy 配置
# Caddyfileapi.yourdomain.com { reverse_proxy localhost:8090
# WebSocket 支持 header_up Upgrade {>Connection} header_up Connection websocket
# 日志 log { output file /var/log/caddy/pocketbase-access.log }}生产环境配置
1. 完整生产配置
version: "3.8"
services: pocketbase: image: ghcr.io/muchdogesec/pocketbase:latest container_name: pocketbase hostname: pocketbase ports: - "127.0.0.1:8090:8090" volumes: - pb_data:/pb_data - pb_public:/pb_public - ./pb_hooks:/pb_hooks:ro environment: - TZ=Asia/Shanghai - POCKETBASE_ENCRYPTION_KEY=${ENCRYPTION_KEY} env_file: - .env restart: unless-stopped healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8090/api/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s deploy: resources: limits: cpus: "1.0" memory: 512M reservations: cpus: "0.25" memory: 128M logging: driver: "json-file" options: max-size: "10m" max-file: "3" networks: - pocketbase-net
nginx: image: nginx:alpine container_name: pocketbase-nginx ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx/ssl:/etc/nginx/ssl:ro - ./nginx/logs:/var/log/nginx depends_on: pocketbase: condition: service_healthy restart: unless-stopped networks: - pocketbase-net
volumes: pb_data: driver: local driver_opts: type: none o: bind device: /opt/pocketbase/data pb_public: driver: local
networks: pocketbase-net: driver: bridge2. 环境变量配置
创建 .env 文件:
# 时区TZ=Asia/Shanghai
# 数据加密密钥(生产环境必须设置)# 使用 openssl rand -base64 32 生成POCKETBASE_ENCRYPTION_KEY=your-32-character-encryption-key
# 日志级别LOG_LEVEL=info
# 邮件配置(用于发送通知)SMTP_HOST=smtp.example.comSMTP_PORT=587SMTP_USER=noreply@example.comSMTP_PASS=your-smtp-passwordSMTP_FROM=PocketBase <noreply@example.com>3. 安全加固
限制容器权限
services: pocketbase: image: ghcr.io/muchdogesec/pocketbase:latest security_opt: - no-new-privileges:true read_only: true tmpfs: - /tmp cap_drop: - ALL cap_add: - CHOWN - SETGID - SETUID pids_limit: 100 ulimits: nproc: 512 nofile: soft: 1024 hard: 2048防火墙配置
# UFW 配置sudo ufw allow 80/tcpsudo ufw allow 443/tcpsudo ufw deny 8090/tcp # 仅允许本地访问sudo ufw enable
# iptables 配置iptables -A INPUT -p tcp --dport 80 -j ACCEPTiptables -A INPUT -p tcp --dport 443 -j ACCEPTiptables -A INPUT -p tcp --dport 8090 -s 127.0.0.1 -j ACCEPTiptables -A INPUT -p tcp --dport 8090 -j DROP高级配置
1. 多实例部署(负载均衡)
version: "3.8"
services: pocketbase-1: image: ghcr.io/muchdogesec/pocketbase:latest volumes: - pb_data:/pb_data - pb_public:/pb_public networks: - pocketbase-net restart: unless-stopped
pocketbase-2: image: ghcr.io/muchdogesec/pocketbase:latest volumes: - pb_data:/pb_data - pb_public:/pb_public networks: - pocketbase-net restart: unless-stopped
nginx: image: nginx:alpine ports: - "80:80" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: - pocketbase-1 - pocketbase-2 networks: - pocketbase-net
volumes: pb_data: pb_public:
networks: pocketbase-net:Nginx 负载均衡配置:
upstream pocketbase_cluster { least_conn; server pocketbase-1:8090 max_fails=3 fail_timeout=30s; server pocketbase-2:8090 max_fails=3 fail_timeout=30s;}
server { listen 80; server_name api.yourdomain.com;
location / { proxy_pass http://pocketbase_cluster; # ... 其他配置 }}2. 自动重启策略
services: pocketbase: image: ghcr.io/muchdogesec/pocketbase:latest restart: always # 始终重启 # restart: unless-stopped # 除非手动停止 # restart: on-failure:5 # 失败时重启,最多5次3. 资源限制
services: pocketbase: deploy: resources: limits: cpus: "1.0" # 最多 1 个 CPU 核心 memory: 512M # 最多 512MB 内存 reservations: cpus: "0.25" # 保留 0.25 个 CPU 核心 memory: 128M # 保留 128MB 内存监控与日志
1. 日志配置
services: pocketbase: logging: driver: "json-file" options: max-size: "10m" # 单个日志文件最大 10MB max-file: "3" # 保留 3 个日志文件 labels: "service"2. 监控集成
Prometheus + Grafana
version: "3.8"
services: pocketbase: image: ghcr.io/muchdogesec/pocketbase:latest # ... 其他配置
prometheus: image: prom/prometheus:latest volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus-data:/prometheus ports: - "9090:9090"
grafana: image: grafana/grafana:latest volumes: - grafana-data:/var/lib/grafana environment: - GF_SECURITY_ADMIN_PASSWORD=admin ports: - "3000:3000"
volumes: prometheus-data: grafana-data:cAdvisor(容器监控)
version: "3.8"
services: cadvisor: image: gcr.io/cadvisor/cadvisor:latest volumes: - /:/rootfs:ro - /var/run:/var/run:ro - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro ports: - "8081:8080" restart: unless-stopped故障排查
常见问题
1. 容器无法启动
# 查看日志docker logs pocketbase
# 检查端口占用ss -tlnp | grep 8090
# 检查文件权限ls -la ./pb_data2. 数据丢失
# 检查 volume 挂载docker inspect pocketbase | grep -A 10 Mounts
# 恢复备份docker exec -i pocketbase \ sh -c 'cat > /pb_data/data.db' < backup/data.db3. 性能问题
# 检查资源使用docker stats pocketbase
# 检查数据库大小docker exec pocketbase ls -lh /pb_data/
# 数据库优化docker exec pocketbase \ sqlite3 /pb_data/data.db "VACUUM;"健康检查脚本
#!/bin/bashCONTAINER_NAME="pocketbase"EXPECTED_URL="http://localhost:8090/api/health"
if docker ps | grep -q $CONTAINER_NAME; then if curl -f -s $EXPECTED_URL > /dev/null; then echo "OK: PocketBase is healthy" exit 0 else echo "ERROR: PocketBase not responding" exit 1 fielse echo "ERROR: Container not running" exit 2fi