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
posted @ 2024-02-26 09:42  河图s  阅读(88)  评论(0)    收藏  举报