Docker -- docker compose 部署 Django 项目
1. 架构
Django + UWsgi + Mysql + 数据采集中台
2. 项目上传
1. Django
1. 准备模块文件
pip freeze > requirements.txt
上传文件到 /home/app/src/requirements.txt
APScheduler==3.10.4
uwsgi==2.0.22 # 添加 uwsgi模块
asgiref==3.7.2
backports.zoneinfo==0.2.1
certifi==2023.11.17
charset-normalizer==3.3.2
colorama==0.4.6
Django==3.2.20
django-apscheduler==0.6.2
django-cors-headers==4.1.0
django-db-connection-pool==1.2.4
djangorestframework==3.14.0
djangorestframework-jwt==1.11.0
greenlet==3.0.3
idna==3.6
importlib-metadata==6.7.0
Pillow==9.5.0
PyJWT==1.7.1
PyMySQL==1.1.0
pypng==0.20220715.0
pytz==2023.3.post1
qrcode==7.4.2
requests==2.31.0
six==1.16.0
SQLAlchemy==2.0.23
sqlparams==5.1.0
sqlparse==0.4.4
typing_extensions==4.7.1
tzdata==2023.3
tzlocal==5.1
urllib3==2.0.7
zipp==3.15.0
2. 上传项目
1. 删除所有migrations 下的文件
2. 上传Django 代码到 /home/app/src/project/
3. 修改 settings.py
修改数据库的连接地址为docker-compose.yaml中的定义的服务名
DATABASES = {
'default': {
"ENGINE": "dj_db_conn_pool.backends.mysql",
"HOST": "mysql.server", # 修改 MySQL 的连接为docker compose 中的mysql容器名
"PORT": "3306",
"USER": "root",
"PASSWORD": "vansing2022",
"NAME": "scadasoft2.0",
"OPTIONS": {
# 取消外键约束
"init_command": "SET foreign_key_checks = 0;"
},
'POOL_OPTIONS': { # dj_db_conn_pool的参数
'POOL_SIZE': 10,
'MAX_OVERFLOW': 10,
'RECYCLE': 30,
}
}
}
4. 压缩成 tar 包
tar -czvf scadasoft.tar.gz scadasoft-2.0/
2. Middle
1. 准备模块文件
pip freeze > requirements.txt
上传文件到 /home/app/src/requirements.txt
APScheduler==3.10.4
uwsgi==2.0.22 # 添加 uwsgi模块
asgiref==3.7.2
backports.zoneinfo==0.2.1
certifi==2023.11.17
charset-normalizer==3.3.2
colorama==0.4.6
Django==3.2.20
django-apscheduler==0.6.2
django-cors-headers==4.1.0
django-db-connection-pool==1.2.4
djangorestframework==3.14.0
djangorestframework-jwt==1.11.0
greenlet==3.0.3
idna==3.6
importlib-metadata==6.7.0
Pillow==9.5.0
PyJWT==1.7.1
PyMySQL==1.1.0
pypng==0.20220715.0
pytz==2023.3.post1
qrcode==7.4.2
requests==2.31.0
six==1.16.0
SQLAlchemy==2.0.23
sqlparams==5.1.0
sqlparse==0.4.4
typing_extensions==4.7.1
tzdata==2023.3
tzlocal==5.1
urllib3==2.0.7
zipp==3.15.0
2. 上传项目
1. 删除所有migrations 下的文件
2. 上传Django 代码到 /home/app/src/project/
3. 压缩成 tar 包
tar -czvf scadasoft.tar.gz scadasoft-2.0/
3. 修改 settings.py
修改数据库的连接地址为docker-compose.yaml中的定义的服务名
DATABASES = {
'default': {
"ENGINE": "dj_db_conn_pool.backends.mysql",
"HOST": "mysql.server", # 修改 MySQL 的连接为docker compose 中的mysql容器名
"PORT": "3306",
"USER": "root",
"PASSWORD": "vansing2022",
"NAME": "scadasoft2.0",
"OPTIONS": {
# 取消外键约束
"init_command": "SET foreign_key_checks = 0;"
},
'POOL_OPTIONS': { # dj_db_conn_pool的参数
'POOL_SIZE': 10,
'MAX_OVERFLOW': 10,
'RECYCLE': 30,
}
}
}
4. 压缩成 tar 包
tar -czvf middle.tar.gz middle/
3. 编写Dockerfile
1. Django
目录为: /home/app/src/project/
1. 基于 Ubuntu镜像
如果没有 localtime timezone包
cd /home/app/src/project/
cp /etc/localtime /etc/timezone .
/home/app/src/project/Dockerfile
vim /home/app/src/project/Dockerfile
FROM ubuntu:20.04
LABEL maintainer="huangjing@vansing.net"
ADD localtime timezone /etc/
# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE=1
# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED=1
#RUN sed -i s@/archive.ubuntu.com/@/mirrors.ustc.edu.cn/@g /etc/apt/sources.list && \
RUN apt-get update && \
apt-get install -y python3-pip libpcre3 libpcre3-dev
RUN rm -rf /var/lib/apt/lists/*
# 下载 Python 项目的依赖模块
COPY requirements.txt .
RUN python3 -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --no-cache-dir --upgrade -r requirements_uwsgi.txt
ADD scadasoft.tar.gz /var/www
# 注意: 这里工作目录要和项目解压出来的主目录名称一致
WORKDIR /var/www/scadasoft-2.0
2. 基于 Python 镜像
1. 搜索镜像, Linux版

2. 编写Dockerfile
FROM python:3.7.17-slim
LABEL maintainer="huangjing@vansing.net"
ADD localtime timezone /etc/
# 下载 Python 项目的依赖模块
COPY requirements.txt .
RUN python3 -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --no-cache-dir --upgrade -r requirements_uwsgi.txt
ADD scadasoft.tar.gz /var/www
# 注意: 这里工作目录要和项目解压出来的主目录名称一致
WORKDIR /var/www/scadasoft-2.0
这里的镜像名与 docker-compose.yaml 文件中的一致
docker build -t air2_uwsgi.server .
2. MySQL
/home/app/src/mysql/Dockerfile
cd /home/app/src/mysql/
vim Dockerfile
FROM mysql:5.7
MAINTAINER Huangjing@vansing.net
ADD localtime my.cnf timezone /etc/
ENV MYSQL_ROOT_PASSWORD=vansing2022
ENV MYSQL_DATABASE=scadasoft2.0
/home/app/src/mysql/my.cnf
vim my.cnf
[mysqld]
character-set-server=utf8
event_scheduler=ON
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
3. Middle
1. 进入中层项目目录
cd /home/app/src/middle/
2. 编写Dockerfile
vim Dockerfile
/home/app/src/middle/Dockerfile
FROM ubuntu:20.04
LABEL maintainer="huangjing@vansing.net"
ADD localtime timezone /etc/
# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE=1
# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED=1
#RUN sed -i s@/archive.ubuntu.com/@/mirrors.ustc.edu.cn/@g /etc/apt/sources.list && \
RUN apt-get update && \
apt-get install -y python3-pip
RUN rm -rf /var/lib/apt/lists/*
# Install pip requirements
COPY requirements.txt .
RUN python3 -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --no-cache-dir --upgrade -r requirements.txt
#EXPOSE 2022
ADD middle.tar.gz /
WORKDIR /middle_level_scheduling
# Creates a non-root user with an explicit UID and adds permission to access the /middle_level_scheduling folder
#RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /middle_level_scheduling
#USER appuser
#CMD ["python3", "main.py"]
4. 构建镜像和网络
1. 创建脚本文件
cd /home/app/src
vim build.sh
build.sh
echo "VERSION=$(date +"%y.%m.%d")" > .env
VERSION=$(date +"%y.%m.%d")
cd web
if test -d scadasoft-2.0; then
tar -czvf scadasoft.tar.gz scadasoft-2.0/ coll_version/
fi
cd ../middle/
if test -d middle_level_scheduling; then
tar -czvf middle.tar.gz middle_level_scheduling
fi
cd ../
docker compose build
rm .env
docker tag air2_uwsgi.server:${VERSION} air2_uwsgi.server:latest
docker tag air2_middle.server:${VERSION} air2_middle.server:latest
docker tag air2_mysql.server:${VERSION} air2_mysql.server:latest
#docker-compose build
2. 赋予其执行权限
chomd +x build.sh
3. 执行脚本
./build.sh
5. 编写docker-compose
1. docker-compose.yaml
/home/app/run/docker-compose.yaml
version: "3.9"
services:
mysql.server:
image: air2_mysql.server:${VERSION:-latest}
restart: always
volumes:
- ./db_data:/var/lib/mysql
- ./mysql/init:/docker-entrypoint-initdb.d/
networks:
- mysql_network
uwsgi.server:
depends_on:
- mysql.server
image: air2_uwsgi.server:${VERSION:-latest}
restart: always
ports:
- "15012:8000"
# command: ["sleep","infinity"] #
command: bash -c "uwsgi --ini params/uwsgi.ini "
# command: bash -c "python3 manage.py makemigrations product collector basic_config collect && python3 manage.py migrate && uwsgi --ini params/uwsgi.ini "
volumes:
- ./product/migrations:/var/www/scadasoft-2.0/product/migrations
- ./collector/migrations:/var/www/scadasoft-2.0/collector/migrations
- ./basic_config/migrations:/var/www/scadasoft-2.0/basic_config/migrations
- ./collect/migrations:/var/www/scadasoft-2.0/collect/migrations
- ./params:/var/www/scadasoft-2.0/params
- ./coll_version:/var/www/coll_version
networks:
- mysql_network
- influxdb2_web-network
middle.server:
depends_on:
- mysql.server
image: air2_middle.server:${VERSION:-latest}
ports:
- "20012:2022"
restart: always
volumes:
- ./coll_version:/middle_baler/coll_version
- ./cert/client:/middle_baler/cert/client
- ./cert/server_m:/middle_baler/cert/server_m
command: bash -c "python3 main.py"
networks:
- mysql_network
- influxdb2_web-network
networks:
mysql_network:
driver: bridge
influxdb2_web-network:
external: true
version: "3.9"
services:
mysql.server:
image: air2_mysql.server:latest
restart: always
volumes:
- ./db_data:/var/lib/mysql
- ./mysql/init:/docker-entrypoint-initdb.d/
networks:
- mysql_network
uwsgi.server:
depends_on:
- mysql.server
image: air2_uwsgi.server:latest
# command: ["sleep","infinity"] # 当Django项目有问题时,可以执行这个命令跳过这些问题,先启动容器
# command: bash -c "uwsgi --ini params/uwsgi.ini " # 只启动uwsgi服务
command: bash -c "python3 manage.py makemigrations product collector basic_config collect && python3 manage.py migrate && uwsgi --ini params/uwsgi.ini "
volumes:
- ./product/migrations:/var/www/scadasoft-2.0/product/migrations
- ./collector/migrations:/var/www/scadasoft-2.0/collector/migrations
- ./basic_config/migrations:/var/www/scadasoft-2.0/basic_config/migrations
- ./collect/migrations:/var/www/scadasoft-2.0/collect/migrations
- ./params:/var/www/scadasoft-2.0/params
- ./coll_version:/var/www/coll_version
ports:
- "15012:8000"
restart: always
networks:
- mysql_network
- influxdb2_web-network
middle.server:
depends_on:
- mysql.server
image: air2_middle.server:latest
volumes:
- ./coll_version:/middle_level_scheduling/coll_version
- ./cert/client:/middle_level_scheduling/cert/client
- ./cert/server_m:/middle_level_scheduling/cert/server_m
ports:
- "20012:2022"
restart: always
command: bash -c "python3 main.py"
networks:
- mysql_network
- influxdb2_web-network
networks:
mysql_network:
driver: bridge
influxdb2_web-network:
external: true
2. uwsgi.ini
/home/app/run/params/uwsgi.ini
[uwsgi]
domain=fast # 声明 mount 中使用到的 动态 URL 后缀参数
project=scadasoft-2.0
softname=baler
base=/var/www
chdir=%(base)/%(project)
master=True
processes=2
workers = 2 #启动4个工人
threads=4 #启动4个线程
enable-threads=True #开启多线程模式
buffer-size = 32768 #设置用于uwsgi包解析的内部缓存区大小为64k。默认是4k。
log-maxsize = 5000000 #设置最大日志文件大小
# 这里的路径为Django项目中的wsgi.py
# /%(domain)/api 指的是在 URL 前加 http://IP:端口/fast/api/...
mount = /%(domain)/api=%(base)/%(project)/%(softname)/wsgi.py
manage-script-name = true
#http=0.0.0.0:8000 # 此连接方式可以外部访问
socket=0.0.0.0:8000 # 此链接方式不可以在外部访问到,只能通过socket访问
chown-socket=%(uid):www-data
chmod-socket=664
vacuum=True
max-requests=5000
pidfile=/tmp/%(project)-master.pid
#daemonize=/tmp/%(project)-uwsgi.log
logger = file:/tmp/uwsgi.log
#设置一个请求的超时时间(秒),如果一个请求超过了这个时间,则请求被丢弃
harakiri = 60
post buffering = 8192
#当一个请求被harakiri杀掉会,会输出一条日志
harakiri-verbose = true
#开启内存使用情况报告
memory-report = true
#设置平滑的重启(直到处理完接收到的请求)的长等待时间(秒)
reload-mercy = 10
#设置工作进程使用虚拟内存超过N MB就回收重启
reload-on-as= 1024
6. 启动
# 最新版命令,不要中间的-
docker compose up
docker compose up -d
# 旧版命令
docker-compose up
docker-compose up -d
7. 遇到的问题
1. 如果第一次启动项目未成功,但是创建了表结构python manage.py migrate,再次启动时再次执行 docker-compose.yaml 会由于之前已经创建了表结构,再次创建就会报错,哪怕是进入到 mysql 的容器中将表删除,也会由于 python 的site-package 中在之前已经创建过 admin session 等django的基础表,再此创建时不会在次创建这些表结构,而导致缺失这些表
# 解决办法
1. 新建一个新的启动目录
2. 将 docker-compose.yaml 和 params/* 拷贝到新的目录中
3. 重新执行 docker compose up -d

浙公网安备 33010602011771号