Django-Docker容器化部署:Django-Docker-MySQL部署
上一章我们成功搭建了容器化的 Django 项目,用到的数据库为默认的 Sqlite。Sqlite 虽然简单易用,但是线上部署时通常会选择更高效、更可靠的数据库,比如 MySQL。
本章将在上一章的基础上,修改并构建 Docker + Django + MySQL 的容器项目。
Docker-compose
我们在学习面向对象的编程语言时,会想方设法把功能独立的模块给独立出来,方便复用和维护。
容器也是一样的。虽然理论上可以把所有组件塞到同一个容器中去,但更好的做法是各模块在单独容器中,只要保持必要的通信就可以了。
也就是说,本教程中现在需要两个容器了:
- 名称叫 app 的 Django 容器
- 名称叫 db 的 MySQL 容器
所以如何构建 MySQL 镜像?别担心,这么常用的镜像官方已经帮你构建好了,只需要把它从仓库拉取到本地就可以了。
修改上一章写的 docker-compose.yml
,增加 MySQL 容器:
version: "3" services: app: restart: always build: . command: bash -c "python3 manage.py migrate && python3 manage.py runserver 0.0.0.0:8000" volumes: - .:/code ports: - "8000:8000" depends_on: - db db: image: mysql:5.7 volumes: - "./mysql:/var/lib/mysql" ports: - "3306:3306" restart: always environment: - MYSQL_ROOT_PASSWORD=mypassword - MYSQL_DATABASE=django_app
app
容器的 command
指令做了修改,让其在运行前先执行数据迁移;新增了配置 depends_on
,意思是此容器需要等待 db
容器启动完毕才能够启动。
分析一下新添加的 db
容器:
image
:从仓库拉取 MySQL 5.7 。最新版本为 MySQL 8,不过很坑的是新版本修改了用户登录的验证方法,导致很容易出现无法通过身份验证的问题。教程为了简单起见选用 5.7 版本。后期会在教程示例代码中添加[mysql-8]()分支并给出操作方法,有兴趣的读者可以查看。volumes
:定义卷(这里实际是挂载),上一章已经讲过了,它实现了宿主机和容器目录的映射。功能是将容器中的 MySQL 数据映射到宿主机。ports
:MySQL 默认通信端口为 3306 。environment
:定义容器的环境变量,设置了 MySQL 的 root 用户的密码、数据库的名称。
这里为什么要用卷?就让数据在容器中、保持隔离不好吗?把数据保存在容器中,理论上确实是可以的,但有一个致命的问题,即数据和容器的生命周期挂钩了:万一哪天手贱把容器给删了,连同里面的数据随风而逝,你就是全公司那个删库跑路的传奇人物了。要知道容器的生命周期可能会非常短暂,删除指令也相当顺滑(docker-compose down
)。将数据映射到宿主机,容器即使被删除掉,但数据还是安全的躺在你的服务器中的。换句话说,容器内部非常适合运行无状态的应用;涉及到如数据之类有状态的东西,一定要谨慎思考。
Dockerfile
接下来修改 Dockerfile
:
FROM python:3.7 ENV PYTHONUNBUFFERED 1 # 添加这两行 RUN apt-get update RUN apt-get install python3-dev default-libmysqlclient-dev -y RUN mkdir /code WORKDIR /code RUN pip install pip -U ADD requirements.txt /code/ RUN pip install -r requirements.txt ADD . /code/
增加的两行代码在系统中安装了 MySQL 的连接器,具体解释见官方文档。
其他配置
修改 requirements.txt
,增加 MySQL 驱动:
django==2.2 mysqlclient==1.3.14
然后还需要修改 django_app/settings.py
,将数据库设置为 MySQL:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'django_app', 'USER': 'root', 'PASSWORD': 'mypassword', 'HOST': 'db', 'PORT': '3306', 'OPTIONS': {'charset': 'utf8mb4'}, } }
注意 HOST 填写的是容器的名称,即 db 。
这就可以啦。接下来测试。
测试
测试之前,请先确认没有其他程序占用了 3306 端口,比如宿主机安装的 MySQL。
重新生成镜像:
$ docker-compose build
生成并启动容器:
$ docker-compose up Creating network "django_app_default" with the default driver Creating django_app_db_1 ... done Creating django_app_app_1 ... done Attaching to django_app_db_1, django_app_app_1 db_1 | 2019-10-06T12:24:57.183860Z 0 [Note] mysqld (mysqld 5.7.27) starting as process 1 ... ... db_1 | 2019-10-06T12:24:58.120480Z 0 [Note] mysqld: ready for connections. db_1 | Version: '5.7.27' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL) app_1 | Operations to perform: app_1 | Apply all migrations: admin, auth, contenttypes, sessions app_1 | Running migrations: app_1 | Applying contenttypes.0001_initial... OK ... app_1 | Applying sessions.0001_initial... OK app_1 | Watching for file changes with StatReloader app_1 | Performing system checks... app_1 | app_1 | System check identified no issues (0 silenced). app_1 | October 06, 2019 - 12:24:58 app_1 | Django version 2.2, using settings 'django_app.settings' app_1 | Starting development server at http://0.0.0.0:8000/ app_1 | Quit the server with CONTROL-C.
打开浏览器访问 127.0.0.1:8000
,又能看到 Django 小火箭啦。
注意:第一次启动容器时可能会出现无法连接 MySQL 的错误,这是由于虽然 db 容器已经启动,但初始化并未完成;重新启动容器之后就可以正常工作了。若多次启动都无法正常工作,那就是别的原因了,好好检查吧。
总结
本章加入了 MySQL 容器,并实现了多容器协同工作。
下一章将实现正式部署的 Docker + Django + MySQL + Nginx + Gunicorn 项目。
- 有疑问请在杜赛的个人网站留言,我会尽快回复。
- 教程示例代码:django-docker-tutorial
- 或Email私信我:[email protected]