docker-compose编排django+uwsgi+nginx+mysql+redis项目

项目架构

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
mydocker/
├── compose
│  ├── mysql
│  │   ├── conf
│  │   ├── init
│  │   └── mysql-files
│  ├── nginx
│  │   ├── Dockerfile
│  │   ├── log
│  │   ├── nginx.conf
│  │   └── ssl
│  ├── redis
│  │   └── redis.conf
│  └── uwsgi
│  ├── myproject-master.pid
│  └── myproject-uwsgi.log
├── docker-compose.yml
└── myproject
├── apps
├── db.sqlite3
├── db_tools
├── Dockerfile
├── extra_apps
├── manage.py
├── media
├── mycelery
├── myproject
├── __pycache__
├── requirements.txt
├── start.sh
├── static
├── staticfiles
├── templates
├── tests
└── uwsgi.ini

docker-compose

  • 1.为了方便修改各项配置文件、和数据的持久化我们需要挂载一些数据卷并且可以指定完整路径挂载到你想指定的路径下,
    如果不指定完整路径需要在volumes中声明,一般会储存在/var/lib/docker/volumes/并以项目名_卷名为名称,如果定义
    了external:true需要提前创建好该文件
  • 2.build会找寻指定目录下的Dockerfile并生成对应image,通过image创造容器
  • 3.注意端口是否占用
  • 4.注意各个镜像的版本,不同版本需要不同配置
  • 5.由于使用nginx反向代理,需要把静态文件和nginx做绑定
    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
    version: "3"

    volumes: # 自定义数据卷,位于宿主机/var/lib/docker/volumes内
    myproject_db_vol: # 定义数据卷同步容器内mysql数据
    myproject_redis_vol: # 定义数据卷同步redis容器内数据
    myproject_media_vol: # 定义数据卷同步media文件夹数据

    services:
    redis:
    image: redis
    command: redis-server /etc/redis/redis.conf # 容器启动后启动redis服务器
    volumes:
    - myproject_redis_vol:/data # 通过挂载给redis数据备份
    - ./compose/redis/redis.conf:/etc/redis/redis.conf # 挂载redis配置文

    ports:
    - "6379:6379"
    restart: always # always表容器运行发生错误时一直重启
    stdin_open: true
    tty: true

    db:
    image: mysql
    env_file:
    - ./myproject/.env
    volumes:
    - myproject_db_vol:/var/lib/mysql:rw # 挂载数据库数据, 可读可写
    - ./compose/mysql/conf/my.cnf:/etc/mysql/my.cnf # 挂载配置文件
    - ./compose/mysql/init:/docker-entrypoint-initdb.d/ # 挂载数据初始化
    sql脚本
    - ./compose/mysql/mysql-files:/var/lib/mysql-files/
    ports:
    - "3306:3306" # 与配置文件保持一致
    restart: always

    web:
    build: ./myproject # 使用myproject目录下的Dockerfile
    expose:
    - "8000"
    volumes:
    - ./myproject:/var/www/html/myproject # 挂载项目代码
    - myproject_media_vol:/var/www/html/myproject/media # 以数据卷挂载容
    器内用户上传媒体文件
    - ./compose/uwsgi:/tmp # 挂载uwsgi日志
    links:
    - db
    - redis
    depends_on: # 依赖关系
    - db
    - redis
    environment:
    - DEBUG=False
    restart: always
    tty: true
    stdin_open: true

    nginx:
    build: ./compose/nginx
    ports:
    - "80:80"
    - "443:443"
    expose:
    - "80"
    volumes:
    - ./myproject/static:/usr/share/nginx/html/static # 挂载静态文件
    - ./compose/nginx/ssl:/usr/share/nginx/ssl # 挂载ssl证书目录
    - ./compose/nginx/log:/var/log/nginx # 挂载日志
    - myproject_media_vol:/usr/share/nginx/html/media # 挂载用户上传媒体
    文件
    links:
    - web
    depends_on:
    - web
    restart: always


web容器和配置文件

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
# myproject/Dockerfile
# 建立 python3.8 环境

FROM python:3.8
MAINTAINER chunjianghuayueye

# 设置 python 环境变量
ENV PYTHONUNBUFFERED 1


# 创建 myproject 文件夹
RUN mkdir -p /var/www/html/myproject

# 将 myproject 文件夹为工作目录
WORKDIR /var/www/html/myproject

# 将当前目录加入到工作目录中(. 表示当前目录)
ADD . /var/www/html/myproject

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

# 利用 pip 安装依赖
RUN pip install -r requirements.txt


# 去除windows系统编辑文件中多余的\r回车空格
RUN sed -i 's/\r//' ./start.sh

# 给start.sh可执行权限
RUN chmod +x ./start.sh
ENTRYPOINT /bash/bin ./start.sh

start.sh

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
# 从第一行到最后一行分别表示:
# 1. 收集静态文件到根目录,
# 2. 生成数据库可执行文件,
# 3. 根据数据库可执行文件来修改数据库
# 4. 用 uwsgi启动 django 服务
python manage.py collectstatic --noinput&&
python manage.py makemigrations&&
python manage.py migrate&&
uwsgi --ini /var/www/html/myproject/uwsgi.ini

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
[uwsgi]

project=myproject
uid=www-data
gid=www-data
base=/var/www/html

chdir=%(base)/%(project)
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
python-autoreload=1

nginx容器和配置文件

修改配置文件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
41
# nginx配置文件
# compose/nginx/nginx.conf

upstream django {
ip_hash;
server web:8000; # Docker-compose web服务端口
}

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

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

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

location /media {
alias /usr/share/nginx/html/media; # 媒体资源,用户上传文件路径
}
location / {
include /etc/nginx/uwsgi_params;
uwsgi_pass django;
uwsgi_read_timeout 600;
uwsgi_connect_timeout 600;
uwsgi_send_timeout 600;

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

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

server_tokens off;

Dcokerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# nginx镜像compose/nginx/Dockerfile

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;"]

db数据库

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
 compose/mysql/conf/my.cnf
[mysqld]
user=mysql
default-storage-engine=INNODB
character-set-server=utf8

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

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
GRANT ALL PRIVILEGES ON myproject.* TO dbuser@"%" IDENTIFIED BY "Password1";
FLUSH PRIVILEGES;

.env

1
2
3
4
MYSQL_ROOT_PASSWORD=Password1 # 数据库密码
MYSQL_DATABASE=myproject # 数据库名称
MYSQL_USER=dbuser # 数据库用户名
MYSQL_PASSWORD=Password1 # 用户密码

settings配置

主要添加以下静态路径和修改一下mysql、redis配置

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
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'myproject',
'USER': 'root',
'PASSWORD': 'Zhanghaowei1',
'HOST': 'db',
'PORT': '3306',
}
}

CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://redis:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}

STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = 'static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "staticfiles"),
]
print(STATICFILES_DIRS)
IMPORT_EXPORT_USE_TRANSACTIONS = True
MEDIA_URL = "media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

创建容器

1
2
3
docker-compose build
# 启动
docker-compose up
分享到