隔空想念

宝塔docker使用指南

· Vanguard

总结

实际步骤

  1. 确保 compose(可配置多个镜像, 插入.dev 等) 文件准确 dockerfile(部署单个镜像) 文件准确
  2. 上传 compose 文件 .env.test 文件 至 /www/server/panel/data/compose/oversea_test/.env.test
  3. 根据文档中编写好的命令来编译镜像文件并导出压缩 上传至宝塔
  4. 根据 compose 配置 .env.test 配置 新镜像文件, 创建容器
  5. 持续更新 编译新镜像, 更新 compose 更新 .env (提前删除旧容器文件夹 避免影响)

概念解释

关系:Dockerfile 用于 构建镜像;Docker Compose 用于 运行一个或多个容器服务、定义它们如何组合、互联、配置。换句话说:先用 Dockerfile 定义服务镜像,再用 Compose 将服务镜像与其他服务一起运行。

问题案例

如果在 ARM64 Mac (Apple Silicon) 上构建镜像,直接传输到 AMD64 Linux 服务器会出现平台不匹配错误。

解决方案

方案一: 本地构建 AMD64 镜像 (推荐)

在本地 Mac 构建 AMD64 架构镜像:

# 1. 构建 AMD64 架构镜像
npm run docker:build:test:amd64
# 或生产环境
npm run docker:build:prod:amd64

# 2. 导出镜像
npm run docker:save:test
# 或生产环境
npm run docker:save:prod

# 3. 压缩镜像 (可选)
gzip oversea-service-test.tar

# 4. 上传到服务器
scp oversea-service-test.tar.gz user@server:/path/to/app/

在服务器加载镜像:

# 1. 解压 (如果压缩了)
gunzip oversea-service-test.tar.gz

# 2. 加载镜像
docker load -i oversea-service-test.tar

# 3. 验证镜像
docker images | grep oversea-service

# 4. 确保环境文件存在
# 方式 1: 上传 .env.test 文件
scp .env.test user@server:/path/to/app/.env.test

# 方式 2: 在服务器创建
cat > .env.test << 'EOF'
NODE_ENV=test
PORT=3000
JWT_SECRET=your_secret
# ... 其他配置
EOF

# 5. 确保 docker-compose 文件存在
ls -la docker-compose.test.yml

# 6. 启动容器
docker-compose -f docker-compose.test.yml up -d

# 7. 查看状态
docker ps
docker logs -f oversea_service_test

环境文件检查清单

在服务器上运行容器前,确保:

# 1. 检查环境文件是否存在
ls -la .env.test

# 2. 检查文件不是目录
file .env.test
# 输出应该是: .env.test: ASCII text

# 3. 检查文件权限
chmod 644 .env.test

# 4. 验证文件内容
cat .env.test | head -5

# 5. 确保必要的配置项存在
grep -E "NODE_ENV|PORT|JWT_SECRET|MONGO" .env.test

常见错误处理

错误 1: Platform mismatch

The requested image's platform (linux/arm64) does not match the detected host platform (linux/amd64)

解决:

# 重新构建 AMD64 镜像
docker build --platform linux/amd64 -t oversea-service:test .

# 或在 docker-compose.yml 中指定 platform
platform: linux/amd64

错误 2: Not a directory

Are you trying to mount a directory onto a file (or vice-versa)?

解决:

# 确保 .env.test 是文件,不是目录
rm -rf .env.test  # 如果是目录
touch .env.test   # 创建文件
vim .env.test     # 添加配置

# 或不使用文件挂载,改用 env_file
# docker-compose.yml 中:
env_file:
  - .env.test

错误 3: No such file or directory

.env.test: no such file or directory

解决:

# 从模板创建
cp .env.template .env.test
vim .env.test

# 或从本地上传
scp .env.test user@server:/path/to/app/.env.test

完整部署脚本

创建 deploy-to-server.sh:

#!/bin/bash

# 配置
SERVER_USER="your_username"
SERVER_HOST="your_server_ip"
SERVER_PATH="/path/to/app"
ENV="test"  # 或 prod

echo "🚀 开始部署到服务器..."

# 1. 构建 AMD64 镜像
echo "1️⃣  构建 AMD64 镜像..."
docker build --platform linux/amd64 -t oversea-service:$ENV .

# 2. 导出镜像
echo "2️⃣  导出镜像..."
docker save oversea-service:$ENV -o oversea-service-$ENV.tar

# 3. 压缩
echo "3️⃣  压缩镜像..."
gzip -f oversea-service-$ENV.tar

# 4. 上传镜像
echo "4️⃣  上传镜像到服务器..."
scp oversea-service-$ENV.tar.gz $SERVER_USER@$SERVER_HOST:$SERVER_PATH/

# 5. 上传配置文件
echo "5️⃣  上传配置文件..."
scp .env.$ENV $SERVER_USER@$SERVER_HOST:$SERVER_PATH/
scp docker-compose.$ENV.yml $SERVER_USER@$SERVER_HOST:$SERVER_PATH/

# 6. 远程部署
echo "6️⃣  在服务器上部署..."
ssh $SERVER_USER@$SERVER_HOST << ENDSSH
cd $SERVER_PATH

# 解压镜像
gunzip -f oversea-service-$ENV.tar.gz

# 加载镜像
docker load -i oversea-service-$ENV.tar

# 停止旧容器
docker-compose -f docker-compose.$ENV.yml down

# 启动新容器
docker-compose -f docker-compose.$ENV.yml up -d

# 查看状态
docker ps | grep oversea

# 查看日志
docker logs --tail 50 oversea_service_$ENV

echo "✅ 部署完成!"
ENDSSH

echo "✅ 所有步骤完成!"

使用:

chmod +x deploy-to-server.sh
./deploy-to-server.sh

验证部署

# 1. 检查容器状态
docker ps | grep oversea

# 2. 查看实时日志
docker logs --tail 100 -f oversea_service_test

# 3. 检查 PM2 进程状态
docker exec -it oversea_service_test pm2 list

# 4. 查看 PM2 日志
docker exec -it oversea_service_test pm2 logs

# 5. 测试服务
curl http://localhost:3001/health  # 测试环境
curl http://localhost:3000/health  # 生产环境

# 6. 查看容器详情
docker inspect oversea_service_test

# 7. 进入容器调试
docker exec -it oversea_service_test sh
# 在容器内:
pm2 list           # 查看 PM2 进程
pm2 logs           # 查看应用日志
env | grep NODE    # 查看环境变量
ls -la             # 查看文件结构

常见问题排查

问题 1: PM2 进程启动后立即退出

症状: 容器运行但服务无法访问,PM2 显示 online 后立即消失

原因:

  • 环境变量配置错误
  • MongoDB 连接失败
  • 端口已被占用
  • 代码启动错误

解决步骤:

# 1. 查看容器日志
docker logs oversea_service_test

# 2. 进入容器检查 PM2
docker exec -it oversea_service_test sh
pm2 list
pm2 logs --lines 100

# 3. 检查环境变量
env | grep -E "NODE_ENV|MONGO|JWT"

# 4. 手动启动查看详细错误
pm2 delete all
node server.js

# 5. 检查端口占用
netstat -tuln | grep 3000

问题 2: 容器不断重启

症状: docker ps 显示容器一直在重启

解决:

# 查看容器重启次数和原因
docker inspect oversea_service_test | grep -A 10 State

# 查看最近的错误日志
docker logs --tail 200 oversea_service_test

# 临时禁用自动重启,查看错误
docker update --restart=no oversea_service_test

# 重新构建镜像
docker-compose -f docker-compose.test.yml build --no-cache
docker-compose -f docker-compose.test.yml up -d

问题 3: MongoDB 连接失败

症状: 日志显示 MongoDB 连接错误

解决:

# 检查 MongoDB 连接字符串
docker exec -it oversea_service_test env | grep MONGO_URI

# 如果 MongoDB 在宿主机:
# - macOS/Windows: 使用 host.docker.internal
# - Linux: 使用宿主机 IP 或 172.17.0.1

# 修改 .env.test 中的 MONGO_URI
# 示例:
MONGO_URI=mongodb://host.docker.internal:27017  # Mac/Win
MONGO_URI=mongodb://172.17.0.1:27017           # Linux

# 或者将 MongoDB 也放在 Docker 中
# 在 docker-compose.test.yml 添加 MongoDB 服务

问题 4: 健康检查失败

症状: docker ps 显示容器为 unhealthy

解决:

# 查看健康检查日志
docker inspect oversea_service_test | grep -A 20 Health

# 进入容器手动测试
docker exec -it oversea_service_test sh
wget -O- http://localhost:3000/health
# 或
curl http://localhost:3000/health

# 如果应用没有 /health 端点,修改 docker-compose.yml
# 移除 healthcheck 或修改为:
healthcheck:
  test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/"]

问题 5: 环境文件加载失败

症状: 应用启动但配置为默认值

解决:

# 检查环境文件是否正确加载
docker exec -it oversea_service_test env

# 确保 .env.test 在正确位置
ls -la .env.test

# 重新上传环境文件
scp .env.test user@server:/path/to/app/.env.test

# 重启容器
docker-compose -f docker-compose.test.yml restart

调试技巧

使用交互式模式启动容器

# 停止后台容器
docker-compose -f docker-compose.test.yml down

# 交互式启动,查看完整启动过程
docker run -it --rm \
  -e NODE_ENV=test \
  --env-file .env.test \
  -p 3001:3000 \
  oversea-service:test \
  sh

# 在容器内手动启动
ls -la
env | grep NODE
pm2-runtime start ecosystem.config.cjs --only oversea_test

查看详细的 PM2 日志

# 进入容器
docker exec -it oversea_service_test sh

# 查看 PM2 日志文件
pm2 logs --lines 200

# 查看特定应用的日志
pm2 logs oversea_test --lines 100

# 查看错误日志
pm2 logs oversea_test --err --lines 50

# 监控实时日志
pm2 logs oversea_test --raw

完整诊断脚本

创建 diagnose.sh:

#!/bin/bash

CONTAINER_NAME="oversea_service_test"

echo "🔍 开始诊断容器: $CONTAINER_NAME"
echo "================================"

# 1. 容器状态
echo "📦 容器状态:"
docker ps -a | grep $CONTAINER_NAME

# 2. 容器日志
echo ""
echo "📋 最近 50 行日志:"
docker logs --tail 50 $CONTAINER_NAME

# 3. PM2 进程
echo ""
echo "⚙️  PM2 进程状态:"
docker exec -it $CONTAINER_NAME pm2 list 2>/dev/null || echo "无法获取 PM2 状态"

# 4. 环境变量
echo ""
echo "🔧 环境变量:"
docker exec -it $CONTAINER_NAME env | grep -E "NODE_ENV|MONGO|JWT|PORT" 2>/dev/null

# 5. 端口监听
echo ""
echo "🌐 端口监听:"
docker exec -it $CONTAINER_NAME netstat -tuln 2>/dev/null || echo "netstat 不可用"

# 6. 健康状态
echo ""
echo "💚 健康检查:"
docker inspect $CONTAINER_NAME | grep -A 10 Health

echo ""
echo "================================"
echo "✅ 诊断完成"

使用:

chmod +x diagnose.sh
./diagnose.sh

回滚

如果部署失败,快速回滚:

# 1. 停止新容器
docker-compose -f docker-compose.test.yml down

# 2. 加载备份镜像
docker load -i oversea-service-test-backup.tar

# 3. 启动旧版本
docker-compose -f docker-compose.test.yml up -d