使用docker部署django技术栈项目的方法步骤
随着Docker的普及成熟,已经逐渐成为部署项目的首选,今天来和大家分享下如何使用docker部署django技术栈项目。
我们这里说的Django技术栈为:python3.6、Django2.2、redis、mysql、celery、gunicorn和nginx。在实际的生产项目中,这些组件分布在集群的不同机器,如Nginx、redis和Mysql可能会有单独的团队或部门负责。涉及的部署架构和容器的编排会更为复杂,本文暂不去深究。本文主要介绍,如何使用 docker-compose来编排这些组件,这种方式适用于测试环境的部署或者你的个人 sideproject的部署。
本文默认你已经了解 docker和 docker-compose的一些基本知识,若你不了解,可阅读下面这些资料:
- Docker知识大全
- Docker官方文档
- DockerCompose文档
下面我们来说下如何部署。
项目组织结构
首先,看下我们的项目组织结构,结构如下:
├──LICENSE ├──README.md ├──compose │├──celery ││├──Dockerfile ││├──celery-beat.sh ││└──celery.sh │├──mysql ││└──my.cnf │├──nginx ││└──nginx.conf │└──web │├──Dockerfile │├──entrypoint.sh │├──gunicorn.conf │└──gunicorn.sh ├──docker-compose.yml ├──docker_django_demo │├──__init__.py │├──celery.py │├──settings.py │├──urls.py │└──wsgi.py ├──env.tpl ├──manage.py ├──requirements.txt
除了Django的项目文件外,主要增加了 compose配置文件目录和 docker-compose.yml配置文件。
- compose目录主要存放各组件的dockerfile文件和启动脚本。
- docker-compose.yml是docker-compose的编排配置文件。
编写Dockerfile及启动初始化脚本
在docker-compose中,容器的启动有两种方法,一种是直接使用公共的镜像来启动容器,另一种是通过我们自己编写的Dockerfile。因为我们要安装额外的工具包和初始化相关配置,web和celery组件我们使用自定义的Dockerfile方式。
web容器的 compose/web/Dockerfile:
FROMpython:3.6 ENVPYTHONUNBUFFERED1 RUNmkdir/code WORKDIR/code COPY./requirements.txt/code/ RUNpipinstall--no-cache-dir-rrequirements.txt\ &&rm-rfrequirements.txt COPY./code/ COPY./compose/web/*.sh/code/ RUNsed-i's/\r//'gunicorn.sh\ &&chmod+xgunicorn.sh\ &&sed-i's/\r//'entrypoint.sh\ &&chmod+xentrypoint.sh ENTRYPOINT["/bin/bash","entrypoint.sh"]
web容器的其他文件:
- compose/web/entrypoint.shweb容器的启动脚本,执行一些初始化或检测逻辑。
- compose/web/gunicorn.confgunicorn配置文件。
- compose/web/gunicorn.shgunicorn的启动脚本。
celery的Dockerfile:
FROMpython:3.6 ENVPYTHONUNBUFFERED1 RUNmkdir/code WORKDIR/code COPY./requirements.txt/code/ COPY./compose/celery/*.sh/code/ RUNpipinstall--no-cache-dir-rrequirements.txt\ &&rm-rfrequirements.txt&&shinit_env.sh COPY./code/ COPY./compose/celery/*.sh/code/ RUNsed-i's/\r//'celery.sh\ &&chmod+xcelery.sh\ &&sed-i's/\r//'celery-beat.sh\ &&chmod+xcelery-beat.sh
celery的其他文件:
- compose/celery/celery.shcelery的启动脚本。
- compose/celery/celery-beat.shcelery-beat的启动脚本。
编写Compose启动配置文件
docker-compose配置如下:
version:'2' services: redis: image:redis ports: -"6379:6379" db: restart:always image:mysql:5.7.19 #command:--character-set-server=utf8mb4--collation-server=utf8mb4_unicode_ci volumes: -./compose/mysql/:/etc/mysql/conf.d -./db:/var/lib/mysql #fortest ports: -"127.0.0.1:3307:3306" #(HOST:CONTAINER) env_file: -.env web: #restart:always build: context:. dockerfile:./compose/web/Dockerfile command:shgunicorn.sh#["/bin/bash","gunicorn.sh"] ports: -"8080:8002" #(HOST:CONTAINER) volumes: -./logs:/var/logs/ -./collect_static:/code/collect_static -./static:/code/static -./templates:/code/templates -./uploads:/code/uploads env_file:.env depends_on: -redis -db nginx: restart:always image:nginx:1.13.0 volumes: -./compose/nginx:/etc/nginx/conf.d/ -./staticfiles:/code/staticfiles -./logs:/var/log/nginx ports: -"80:80" #(HOST:CONTAINER) depends_on: -web celery: build: context:. dockerfile:./compose/celery/Dockerfile command:shcelery.sh volumes: -./logs:/var/logs/ -./uploads:/code/uploads depends_on: -redis -db env_file:.env celery-beat: build: context:. dockerfile:./compose/celery/Dockerfile command:shcelery-beat.sh volumes: -./logs:/var/logs/ depends_on: -redis -db env_file:.env
celery的worker和beat这里我们使用同一个镜像Dockerfile,按照一个镜像一个进程的原则,启动两个容器来分别跑worker和beat进程。
编译测试
编写好配置文件之后,编译镜像测试运行:
docker-composebuild docker-composeup#前台运行 docker-composeup-d#无误后可后台运行
docker-composeps可以看到启动好的容器:
$docker-composeps NameCommandStatePorts -------------------------------------------------------------------------------------------------- dockerdjangodemo_celery-beat_1shcelery-beat.shUp dockerdjangodemo_celery_1shcelery.shUp dockerdjangodemo_db_1docker-entrypoint.shmysqldUp127.0.0.1:3307->3306/tcp dockerdjangodemo_nginx_1nginx-gdaemonoff;Up0.0.0.0:80->80/tcp dockerdjangodemo_redis_1docker-entrypoint.shredis...Up0.0.0.0:6379->6379/tcp dockerdjangodemo_web_1/bin/bashentrypoint.shsh...Up0.0.0.0:8080->8002/tcp
映射端口可根据自己的实际情况调整。
问题
下面说下在构建过程中的几个需要注意的问题。
mysql编码问题
docker提供的mysql镜像,默认编码为 latin1,在保存中文时会显示乱码。官方提供了一种修改编码方式的方法,在启动脚本后指定编码格式,文档可见这里。mysql容器5.7.19版本可直接在docker-compose.yml中的command后跟上参数 --character-set-server=utf8mb4--collation-server=utf8mb4_general_ci。这种方式,只是修改server端的编码。可直接使用配置文件覆盖的方式,指定所有的编码格式。
配置如下:
[mysqld] default-storage-engine=INNODB character-set-server=utf8mb4 collation-server=utf8mb4_general_ci init-connect='SETNAMESutf8mb4' init_connect='SETcollation_connection=utf8mb4_general_ci' skip-character-set-client-handshake#跳过客户端的编码配置,客户端直接使用服务端的编码配置 bind-address=0.0.0.0
注:mysql5.7.19配置文件方式成功,5.7.4、5.7.17均失败,可做参考。
web等mysql启动完成后再继续
mysql容器在启动起来之前是无法接受数据库链接的,在web启动初始化时,若数据库还没有启动好会导致web容器启动失败直接退出。我们可以增加在web容器启动时增加检测脚本,数据库连通之后,再继续。
脚本如下:
#!/usr/bin/envbash set-oerrexit set-opipefail echo$MYSQL_PASSWORD echo$MYSQL_DATABASE echo$MYSQL_HOST echo$MYSQL_USER echo$MYSQL_PORT functionmysql_ready(){ python<&2echo"MySQLisunavailable-sleeping" sleep1 done >&2echo"MySQLisup-continuing..."
总结
到此,使用docker来部署django技术栈服务就完成了,完整的项目代码,大家可参阅 docker-django-demo。
文章开始说了,该部署方式不适合大型网站的线上生产服务,耦合度太高,不好维护等存在着许多问题。但是,部署自己的sideproject或者测试环境,在硬件资源有限的情况的下还是非常不错的。除了减少环境部署搭建的麻烦外,迁移起来也是很方便的。
demo项目中也有些开发环境下如何使用docker的案例,但是个人一直认为docker更适合部署,在开发环境方便不如直接搭建来的灵活方便。欢迎大家留言,共同讨论docker在开发和部署上的使用心得。
参考
cookiecutter-django
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。