Abstract: Docker + Nginx + Mysql + Redis +Django + uwsgi 部署模板

文件目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
│  docker-compose.yml

├─compose
│ ├─mysql
│ │ ├─conf
│ │ │ my.cnf
│ │ │
│ │ └─init
│ │ init.sql
│ │
│ ├─nginx
│ │ │ Dockerfile
│ │ │ nginx.conf
│ │ │
│ │ ├─log
│ │ │
│ │ └─ssl
│ ├─redis
│ │ redis.conf
│ │
│ └─uwsgi

└─Django-project
│ .env
│ Dockerfile
│ manage.py
│ pip.conf
│ requirements.txt
│ start.sh
│ uwsgi.ini

├─app

├─log

└─Django-project

编写docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
version: "3"

volumes: # 自定义数据卷
db_vol: #定义数据卷同步存放容器内mysql数据
redis_vol: #定义数据卷同步存放redis数据
media_vol: #定义数据卷同步存放web项目用户上传到media文件夹的数据
static_vol: #定义数据卷同步存放web项目static文件夹的数据

networks: # 自定义网络(默认桥接), 不使用links通信
nginx_network:
driver: bridge
db_network:
driver: bridge
redis_network:
driver: bridge

services:
redis:
image: redis:latest
command: redis-server /etc/redis/redis.conf # 容器启动后启动redis服务器
networks:
- redis_network
volumes:
- redis_vol:/data # 通过挂载给redis数据备份
- ./compose/redis/redis.conf:/etc/redis/redis.conf # 挂载redis配置文件
ports:
- "6379:6379"
restart: always # always表容器运行发生错误时一直重启

db:
image: mysql:latest
env_file:
- ./Django-project/.env # 使用了环境变量文件
networks:
- db_network
volumes:
- db_vol:/var/lib/mysql:rw # 挂载数据库数据, 可读可写
- ./compose/mysql/conf/my.cnf:/etc/mysql/my.cnf # 挂载配置文件
- ./compose/mysql/init:/docker-entrypoint-initdb.d/ # 挂载数据初始化sql脚本
ports:
- "3306:3306" # 与配置文件保持一致
restart: always

web:
build: ./Django-project
expose:
- "8000"
volumes:
- *** # 挂载项目代码
- static_vol:*** # 以数据卷挂载容器内static文件
- media_vol:*** # 以数据卷挂载容器内用户上传媒体文件
- ./compose/uwsgi:/tmp # 挂载uwsgi日志
networks:
- nginx_network
- db_network
- redis_network
depends_on:
- db
- redis
restart: always
tty: true
stdin_open: true

nginx:
build: ./compose/nginx
ports:
- "80:80"
- "443:443"
expose:
- "80"
volumes:
- ./compose/nginx/nginx.conf:/etc/nginx/conf.d/nginx.conf # 挂载nginx配置文件
- ./compose/nginx/ssl:/usr/share/nginx/ssl/ # 挂载ssl证书目录
- ./compose/nginx/log:/var/log/nginx/ # 挂载日志
- static_vol:/usr/share/nginx/html/static/ # 挂载静态文件
- media_vol:/usr/share/nginx/html/media/ # 挂载用户上传媒体文件
networks:
- nginx_network
depends_on:
- web
restart: always

Mysql 配置

my.cnf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[mysqld]
user=mysql
default-storage-engine=INNODB
character-set-server=utf8
secure-file-priv=NULL # mysql 8 新增这行配置
default-authentication-plugin=mysql_native_password # mysql 8 新增这行配置

port = 3306 # 端口与docker-compose里映射端口保持一致
#bind-address= localhost #一定要注释掉,mysql所在容器和django所在容器不同IP

basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
skip-name-resolve # 这个参数是禁止域名解析的,远程访问推荐开启skip_name_resolve。

[client]
port = 3306
default-character-set=utf8

[mysql]
no-auto-rehash
default-character-set=utf8

init.sql

1
2
3
Alter user '(username)'@'%' IDENTIFIED WITH mysql_native_password BY '(password)';
GRANT ALL PRIVILEGES ON (database).* TO '(username)'@'%';
FLUSH PRIVILEGES;

Nginx 配置

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
FROM nginx:latest

# 删除原有配置文件,创建静态资源文件夹和ssl证书保存文件夹
RUN rm /etc/nginx/conf.d/default.conf \
&& mkdir -p /usr/share/nginx/html/static \
&& mkdir -p /usr/share/nginx/html/media \
&& mkdir -p /usr/share/nginx/ssl

# 设置Media文件夹用户和用户组为Linux默认www-data, 并给予可读和可执行权限,
# 否则用户上传的图片无法正确显示。
RUN chown -R www-data:www-data /usr/share/nginx/html/media \
&& chmod -R 775 /usr/share/nginx/html/media

# 添加配置文件
ADD ./nginx.conf /etc/nginx/conf.d/

# 关闭守护模式
CMD ["nginx", "-g", "daemon off;"]

nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
upstream django {
ip_hash;
server web:8000; # Docker-compose web服务端口
}

# 配置http请求,80端口
server {
listen 80; # 监听80端口
server_name 127.0.0.1; # 可以是nginx容器所在ip地址或127.0.0.1,不能写宿主机外网ip地址

charset utf-8;
client_max_body_size 10M; # 限制用户上传文件大小

access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;

location /static/ {
alias /usr/share/nginx/html/static; # 静态资源路径
autoindex off;
}

location /media/ {
alias /usr/share/nginx/html/media; # 媒体资源,用户上传文件路径
autoindex off;
}

location / {
include /etc/nginx/uwsgi_params;
uwsgi_pass django;
uwsgi_read_timeout 600;
uwsgi_connect_timeout 600;
uwsgi_send_timeout 600;

proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_pass http://django; # 使用uwsgi通信,而不是http,所以不使用proxy_pass。
}
}

Redis 配置

redis.conf

修改以下配置

1
2
3
4
5
# 请注释掉下面一行,变成#bind 127.0.0.1,这样其它机器或容器也可访问
bind 127.0.0.1

# 取消下行注释,给redis设置登录密码。这个密码django settings.py会用到。
requirepass (password)

.env 文件

1
2
3
4
5
MYSQL_ROOT_PASSWORD=(root_password)

MYSQL_USER=(username)
MYSQL_DATABASE=(database)
MYSQL_PASSWORD=(password)

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# 设定ubuntu版本,避免运行pip时
FROM ubuntu:20.04

# 建立 python 环境
FROM python:3.9

# 镜像作者
MAINTAINER K

# 设置 python 环境变量
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# 安装netcat
RUN echo > /etc/apt/sources.list
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
RUN echo "deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse\
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse\
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse\
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse\
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse\
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse\
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse\
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse\
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse\
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse" > /etc/apt/sources.list
RUN apt-get update && apt install -y netcat

# 设置pip源为国内源
COPY pip.conf /root/.pip/pip.conf

# 在容器内创建项目文件夹
ENV APP_HOME=()
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME

# 设置容器内工作目录
WORKDIR $APP_HOME

# 将当前目录文件加入到容器工作目录中(. 表示当前宿主机目录)
ADD . $APP_HOME

# 日志文件夹赋权
RUN chmod 777 -R $APP_HOME/log

# 更新pip
RUN /usr/local/bin/python -m pip install --upgrade pip

# 安装项目依赖
RUN pip install setuptools==50.3.2
RUN pip install uwsgi
RUN pip install -r requirements.txt

# Windows环境下编写的start.sh每行命令结尾有多余的\r字符,需移除。
RUN sed -i 's/\r//' ./start.sh

# 设置start.sh文件可执行权限
RUN chmod +x ./start.sh

ENTRYPOINT /bin/bash ./start.sh

pip.conf

1
2
3
[global]
trusted-host = mirrors.aliyun.com
index-url = http://mirrors.aliyun.com/pypi/simple

start.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
# 从第一行到最后一行分别表示:
# 1. 等待MySQL服务启动后再进行数据迁移。nc即netcat缩写
# 2. 收集静态文件到根目录static文件夹,
# 3. 生成数据库可执行文件,
# 4. 根据数据库可执行文件来修改数据库
# 5. 用 uwsgi启动 django 服务 启动celery
# 6. tail空命令防止web容器执行脚本后退出
while ! nc -z db 3306 ; do
echo "Waiting for the MySQL Server"
sleep 3
done

python manage.py collectstatic --noinput&&
python manage.py makemigrations&&
python manage.py migrate&&
uwsgi --ini (uwsgi.ini路径)&&
celery -A (Django-project) worker -l info -P eventlet --logfile=log/celery.log&&
tail -f /dev/null

exec "$@"

uwsgi.ini

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

[uwsgi]

project=(Django-project)
uid=www-data
gid=www-data
base=(/**/Django-project)

chdir=%(base)
wsgi-file=%(base)/%(project)/wsgi.py
module=%(project).wsgi:application
master=True
processes=2

socket=0.0.0.0:8000
chown-socket=%(uid):www-data
chmod-socket=664

vacuum=True
max-requests=5000

pidfile=/tmp/%(project)-master.pid
daemonize=/tmp/%(project)-uwsgi.log

#设置一个请求的超时时间(秒),如果一个请求超过了这个时间,则请求被丢弃
harakiri = 60
post buffering = 8192
buffer-size= 65535
#当一个请求被harakiri杀掉会,会输出一条日志
harakiri-verbose = true

#开启内存使用情况报告
memory-report = true

#设置平滑的重启(直到处理完接收到的请求)的长等待时间(秒)
reload-mercy = 10

#设置工作进程使用虚拟内存超过N MB就回收重启
reload-on-as= 1024

生成 requirements.txt

1
pip freeze > requirements.txt

Docker-compose 常用命令

1
2
3
4
5
6
docker-compose up -d #后台启动容器
docker-compose rm [name] #删除容器
docker-compose ps [-a] #查看容器状态
docker-compose exec [name] /bin/bash #进入某容器
docker-compose stop [name] #停止容器
docker-compose build #构建容器