在现代软件开发中,Docker 已成为容器化部署的事实标准。然而在实际使用过程中,开发者经常会在 Docker 镜像构建和容器运行时遇到各种问题。本文将结合实际案例,深入分析 Docker 镜像构建和容器运行中的常见坑点,并提供相应的解决方案。
坑点一:容器内任务重复执行
问题现象
在您的 docker-compose.yaml 配置中,django-app 服务配置了自动创建超级用户和数据库迁移的启动命令。然而在实际运行中,您发现系统中存在多个 Celery Beat 进程,导致定时任务被重复执行。
通过以下命令检查发现:
ps aux | grep celery.beat
存在两个 Celery Beat 进程:
进程 ID 9307,于今天 10:25 启动
进程 ID 17435,于 8 月 14 日启动
问题分析
问题根源在于您的 docker-compose.yaml 中配置了 celery-beat 服务,但系统中还运行着通过其他方式启动的 Celery Beat 进程。多个调度器实例同时运行会导致同一个任务被多次调度执行。
解决方案
1.停止多余的 Celery Beat 进程
# 停止 8 月 14 日启动的进程
kill 17435
# 停止今天 10:25 启动的进程(如果不需要的话)
kill 9307
2.统一使用 Docker 管理服务 确保只通过 docker-compose 来管理所有服务,避免在宿主机上手动启动相关进程。
3.检查定时任务配置 进入 Django shell 检查任务配置:
python manage.py shell
from django_celery_beat.models import PeriodicTask
# 检查特定任务
PeriodicTask.objects.filter(name='1').values('name', 'task', 'enabled', 'crontab', 'interval')
# 检查是否有重复的 TestTask.tasks.run_test_task 任务
PeriodicTask.objects.filter(task='TestTask.tasks.run_test_task')
坑点二:Docker 守护进程连接失败
问题现象
执行 Docker 命令时出现以下错误:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
问题分析
此问题通常是由于 /var/run/docker.sock 文件未生成,导致 Docker Daemon 无法连接。
解决方案
1.检查 Docker 服务配置
sudo nano /usr/lib/systemd/system/docker.service
确保配置包含:
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock
2.重新加载并重启 Docker 服务
sudo systemctl daemon-reload
sudo systemctl restart docker
3.验证 Docker 服务状态
docker ps
坑点三:Dockerfile 启动命令语法错误
问题现象
容器启动失败,日志显示:
sh: 12: Syntax error: "fi" unexpected
问题分析
查看您的 docker-compose.yaml 文件中的 django-app 服务配置,问题出现在 command 指令中:
command: >
sh -c "
. /envs/dj/bin/activate &&
cd /data/ITP &&
if [ \"$$FIRST_DEPLOY\" = \"true\" ]; then
echo 'Running first deployment tasks...' &&
python manage.py collectstatic --noinput &&
echo 'Creating empty migration...' &&
python manage.py makemigrations --empty users &&
echo 'Generating new migrations...' &&
python manage.py makemigrations &&
echo 'Migrating users app...' &&
python manage.py migrate users &&
echo 'Migrating all apps...' &&
python manage.py migrate && # 此处不能有连接符
fi &&
exec /envs/dj/bin/gunicorn ITP.wsgi:application --name ITP --workers 3 --bind 0.0.0.0:8000 --log-level info --log-file -
"
在 python manage.py migrate && 后面多了一个连接符 &&,但后面没有其他命令,导致语法错误。
解决方案
修正 docker-compose.yaml 中的 command 配置:
command: >
sh -c "
. /envs/dj/bin/activate &&
cd /data/ITP &&
if [ \"$$FIRST_DEPLOY\" = \"true\" ]; then
echo 'Running first deployment tasks...' &&
python manage.py collectstatic --noinput &&
echo 'Creating empty migration...' &&
python manage.py makemigrations --empty users &&
echo 'Generating new migrations...' &&
python manage.py makemigrations &&
echo 'Migrating users app...' &&
python manage.py migrate users &&
echo 'Migrating all apps...' &&
python manage.py migrate
fi &&
exec /envs/dj/bin/gunicorn ITP.wsgi:application --name ITP --workers 3 --bind 0.0.0.0:8000 --log-level info --log-file -
"
预防措施与最佳实践
1.统一服务管理
始终使用 docker-compose 管理所有相关服务,避免混合使用多种部署方式。
2.定期检查进程
定期检查系统中的进程,确保没有重复的服务实例运行。
3.语法验证
在修改复杂命令前,先在本地测试语法正确性。
4.日志监控
建立完善的日志监控体系,及时发现和处理异常。
5.版本控制
将 docker-compose.yaml 等配置文件纳入版本控制,方便追踪变更和回滚。
通过以上分析和解决方案,您可以有效避免 Docker 镜像构建和容器运行中的常见问题,提高系统的稳定性和可靠性。在实际开发中,建议建立完善的测试和验证流程,确保配置变更不会引入新的问题。
立即体验:访问 http://1.95.215.79:18899/(测试账号:tester/88888888)
项目地址:
https://gitee.com/hp631012651/itp.git