
准备好以下的内容
- 项目文件
- 使用
pip freeze > requirements.txt命令打包好项目的依赖包列表 - 安装好Docker和Docker-compose,可以分别用
docker -v和docker-vompose -v命令查看是否安装成功。
编写Dockerfile文件
Docker 允许通过文本格式的配置文件来构建镜像,默认名称为 Dockerfile
# 从Docker仓库中拉去带有Python3.7的Linux环境
FROM python:3.7
# 设置 python 环境变量
ENV PYTHONUNBUFFERED 1
# 这两行是在系统钟安装了MySQL的连接器
RUN apt-get update
RUN apt-get install python3-dev default-libmysqlclient-dev -y
# 创建 code 文件夹并将其设置为工作目录
RUN mkdir /code
WORKDIR /code
# 更新 pip
RUN pip install pip -U
# 将 requirements.txt 复制到容器的 code 目录
ADD requirements.txt /code/
# 安装库
RUN pip install -r requirements.txt
# 将当前目录复制到容器的 code 目录
ADD . /code/理解这些Docker指令的关键,在于牢记容器内的环境和宿主机是隔离的,核心问题是搞清楚那些操作是针对宿主机,哪些操作是针对容器。
FROM python:3.7 指令从仓库拉取一个包含 python 3.7 的 Linux 操作系统环境(Linux 版本为 Debian)。
RUN 和 WORKDIR 指令都是针对容器的,功能是在容器里创建目录、并将其设置为工作目录。注意宿主机是没有这个目录的。
ADD 指令出现了两次。ADD requirements.txt /code/ 意思是将宿主机当前目录(即 Dockerfile 所在目录)的 requirements.txt 文件复制到容器的 /code 目录中。ADD . /code/ 意思是把当前目录所有内容复制到容器 /code/ 目录,注意中间那个点。
编写docker-compose.yml文件
version: "3"
services:
app:
restart: always
build: .
command: bash -c "python3 manage.py collectstatic --no-input && python3 manage.py migrate && gunicorn --timeout=30 --workers=4 --bind :8000 django_app.wsgi:application"
volumes:
- .:/code
- static-volume:/code/collected_static
expose:
- "8000"
depends_on:
- db
networks:
- web_network
- db_network
db:
image: mysql:5.7
volumes:
- "./mysql:/var/lib/mysql"
ports:
- "3307:3306"
restart: always
environment:
- MYSQL_ROOT_PASSWORD=mypassword
- MYSQL_DATABASE=django_app
networks:
- db_network
nginx:
restart: always
image: nginx:latest
ports:
- "8001:8000"
volumes:
- static-volume:/code/collected_static
- ./config/nginx:/etc/nginx/conf.d
depends_on:
- app
networks:,
- web_network
networks:
web_network:
driver: bridge
db_network:
driver: bridge
volumes:
static-volume:version 代表 docker-compose.yml 的版本,目前最新版为 3,不需要改动它。
从整体上看,我们定义了三个容器,分别是app、db、和nginx,容器之间通过定义的端口进行通讯。定义了两个网络,分别是web_network和db_network,只有处在同一网络下的容器才能够互相通讯。不同网络之间是隔离的,即便采用同样的端口,也无法通讯。定义了一个数据卷static-volume。数据卷非常适合多个容器共享使用同一数据,可以看到app和nginx都使用到了它。expose和ports都可以暴露容器的端口,区别是expose仅暴露给其他容器,而ports会暴露给其他容器和宿主机。
下面具体分析一下:
定义了一个名叫 app 的容器。后面的内容都是 app 容器的相关配置:
restart:除正常工作外,容器会在任何时候重启,比如遭遇 bug、进程崩溃、docker 重启等情况。build:指定一个包含 Dockerfile 的路径,并通过此 Dockerfile 来构建容器镜像。注意那个 "." ,代表当前目录。command:容器运行时需要执行的命令。这里就是我们很熟悉的运行开发服务器了。volumes:卷,这是个很重要的概念。前面说过容器是和宿主机完全隔离的,但是有些时候又需要将其连通;比如我们开发的 Django 项目代码常常会更新,并且更新时还依赖如 Git 之类的程序,在容器里操作就显得不太方便。所以就有卷,它定义了宿主机和容器之间的映射:"." 表示宿主机的当前目录,":" 为分隔符,"/code" 表示容器中的目录。即宿主机当前目录和容器的 /code 目录是连通的,宿主机当前目录的 Django 代码更新时,容器中的 /code 目录中的代码也相应的更新了。这有点儿像是在容器上打了一个洞,某种程度上也是实用性和隔离性的一种妥协。严格意义上讲,这里用到的
.:/code并不是卷,而是叫挂载,它两是有区别的,只不过 docker-compose 允许将挂载写到卷的配置中。expose:暴露容器的8000端口供其他容器访问,宿主机和外界无法访问networks:能够访问web_network和db_networkdepends_on,意思是此容器需要等待db容器启动完毕才能够启动。
分析一下 db 容器:
image:从仓库拉取 MySQL 5.7 。volumes:这里出现的static-volume叫卷。它的使用方式像这样:static-volume:/code/collected_static,冒号后面还是容器内的目录,但冒号前的却不是宿主机目录、仅仅是卷的名称而已。从本质上讲,数据卷也是实现了宿主机和容器的目录映射,但是数据卷是由 Docker 进行管理的,你甚至都不需要知道数据卷保存在宿主机的具体位置。相比挂载,数据卷的优点是由于是 Docker 统一管理的,不存在由于权限不够引发的挂载问题,也不需要在不同服务器指定不同的路径;缺点是它不太适合单配置文件的映射。和挂载一样,数据卷的生命周期脱离了容器,删除容器之后卷还是存在的。下次构建镜像时,指定卷的名称就可以继续使用了。
ports:MySQL 默认通信端口为 3306 。由于我的机子上已经跑了一个MySQL服务,所以我将容器内的3306端口映射为本机的3307端口。environment:定义容器的环境变量,设置了 MySQL 的 root 用户的密码、数据库的名称。network:只能够访问db_network。
添加db容器后记得的修改Django里的数据库设置。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_app',
'USER': 'root',
'PASSWORD': 'mypassword',
'HOST': 'db',
'PORT': '3306',
'OPTIONS': {'charset': 'utf8mb4'},
}
}最后分析一下nginx容器,其他配置与上述两个大致一样,值得说一说的是ports设置,由于我的服务器上部署了其他服务,所以我将nginx端口映射为8001。
Docker 允许用户给每个容器定义其工作的网络,只有在相同的网络之中才能进行通讯。可以看到 nginx 容器处于 web_network 网络,而 db 容器处于 db_network 网络,因此它两是无法通讯的,实际上确实也不需要通讯。而 app 容器同时处于 web_network 和 db_network 网络,相当于是桥梁,连通了3个容器。
Nginx配置
修改Nginx的配置文件,即映射到nginx容器内的config/nginx/django_app.conf
upstream app {
ip_hash;
server app:8000;
}
server {
listen 8000;
server_name localhost;
location /static/ {
autoindex on;
alias /code/collected_static/;
}
location / {
proxy_pass http://app/;
}
}此配置下 Nginx 会监听容器的 8000 端口,并将收到的请求发送到 app 容器(静态文件请求除外)。
之后在requirements.txt文件的最后两行增加mysqlclient库和gunicorn库。
mysqlclient==2.0.1
gunicorn==19.9.0再修改Django项目的配置文件
ALLOWED_HOSTS = ['*']
...
STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')
STATIC_URL = '/static/'部署
运行命令docker-compose build构造镜像,再使用docker-compose up即可启用服务。
下面附上一下经常用到的命令:
- 停止容器,
docker-compose down - 后台运行docker容器:
docker-compose up -d。 - 只想启动其中的一个容器:
docker-compose up -d db或者docker-compose up -d app即可启动db容器或app容器。 - 进入容器:
docker exec -it container_id /bin/bash - 上面的
container_id如果不知道如何获取可以通过docker ps命令查看。
1 条评论
您好~我是腾讯云+社区的运营,关注了您分享的技术文章,觉得内容很棒,我们诚挚邀请您加入腾讯云自媒体分享计划。完整福利和申请地址请见:https://cloud.tencent.com/developer/support-plan
作者申请此计划后将作者的文章进行搬迁同步到社区的专栏下,你只需要简单填写一下表单申请即可,我们会给作者提供包括流量、云服务器等,另外还有些周边礼物。