Skip to content

Docker-compose部署Django项目笔记

Hsinyan
Updated date:
1 min read

准备好以下的内容

  1. 项目文件
  2. 使用pip freeze > requirements.txt命令打包好项目的依赖包列表
  3. 安装好Docker和Docker-compose,可以分别用docker -vdocker-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)。

RUNWORKDIR 指令都是针对容器的,功能是在容器里创建目录、并将其设置为工作目录。注意宿主机是没有这个目录的。

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,不需要改动它。

从整体上看,我们定义了三个容器,分别是appdb、和nginx,容器之间通过定义的端口进行通讯。定义了两个网络,分别是web_networkdb_network,只有处在同一网络下的容器才能够互相通讯。不同网络之间是隔离的,即便采用同样的端口,也无法通讯。定义了一个数据卷static-volume。数据卷非常适合多个容器共享使用同一数据,可以看到appnginx都使用到了它。exposeports都可以暴露容器的端口,区别是expose仅暴露给其他容器,而ports会暴露给其他容器和宿主机。

下面具体分析一下:

定义了一个名叫 app 的容器。后面的内容都是 app 容器的相关配置:

分析一下 db 容器:

添加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_networkdb_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即可启用服务。

下面附上一下经常用到的命令:

Previous
使用xlrd、xlrt和xlutils读写xls文件
Next
Markdown 写作规范和格式规范