Docker部署Django(三)docker-compose编排Django+Uwsgi+Nginx+MySQL

写在前面

实际的生产环境中,我们往往需要定义数量庞大的 docker 容器,并且容器之间具有错综复杂的依赖联系,一个一个去手动创建容器并记录和配置这些复杂的容器关系,不仅效率低下而且容易出错,所以迫切需要一种定义容器集群编排和部署的工具,这就是docker-compose

什么是docker-compose及docker-compose工具的安装

Docker-compose是一个用来定义和运行复杂应用的 Docker 工具。使用 docker-compose 后不再需要使用 shell 脚本来逐一创建和启动容器,还可以通过 docker-compose.yml 文件构建和管理复杂多容器组合。

pip安装docker-compose
pip3 install docker-compose

ln -s /usr/local/python3/bin/docker-compose /usr/bin/docker-compose

docker-compose -version
更换docker镜像源
vi /etc/docker/daemon.json
{
 "registry-mirrors": ["http://hub-mirror.c.163.com"]
}
systemctl restart docker

多容器部署Django项目示意图

在这里插入图片描述

  • 当客户端通过80端口访问服务,宿主机80端口映射到djang_nginx容器的80端口,找到django_nginx容器,django_nginx收到请求转发到uwsgi服务的8000端口
  • 8000端口映射到django_uwsgi容器,View视图处理时如果用到了数据库内容,则将寻找settings.py中配置的数据信息,寻找3306端口的mysql服务
  • 3306端口映射到MySQL容器,从该容器的上获取数据,然后依次返回用户

Django+Uwsgi+Nginx+MySQL代码布局图

docker_project  # 项目根目录
├── compose  # 存放各项容器服务的Dockerfile和配置文件
│   ├── mysql
│   │   ├── conf
│   │   │   └── my.cnf  # MySQL配置文件
│   │   └── init
│   │       └── init.sql  # MySQL启动脚本
│   └── nginx
│       ├── Dockerfile  # 构建Nginx镜像所的Dockerfile
│       ├── nginx.conf  # Nginx配置文件
│       ├── nginx.log  # 挂载保存nginx容器内nginx日志
│       │   ├── access.log
│       │   └── error.log 
│       └── ssl
├── docker-compose.yml  # 核心编排文件
└── docker_django  # 常规Django项目目录
    ├── db.sqlite3
    ├── docker_django  # Django项目配置文件
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── Dockerfile  # 构建Django+Uwsgi镜像的Dockerfile
    ├── manage.py
    ├── media  # 用户上传的媒体资源与静态文件
    ├── requirements.txt  # Django项目依赖文件
    ├── start.sh  # 启动Django+Uwsgi容器后要执行的脚本
    ├── static  # 项目所使用到的静态文件
    └── uwsgi.ini  # uwsgi配置文件

部署开始

第一步:编写Web (Django+Uwsgi)镜像和容器所需文件
FROM python:3.7.2

MAINTAINER Fat Puffer <dcpuffer@outlook.com>

# 设置 python 环境变量
ENV PYTHONUNBUFFERED 1
 
# 在容器内/var/www/html/下创建docker_django文件夹
RUN mkdir -p /var/www/html/docker_django
 
# 设置容器内工作目录
WORKDIR /var/www/html/docker_django
 
# 将当前目录文件加入到容器工作目录中(. 表示当前宿主机目录)
ADD . /var/www/html/docker_django
 
# 更新pip版本
RUN /usr/local/bin/python3 -m pip3 install --upgrade pip

# 利用 pip3 安装依赖
RUN pip3 install -r requirements.txt -i https://pypi.douban.com/simple

# Windows环境下编写的start.sh每行命令结尾有多余的\r字符,需移除。
RUN sed -i 's/\r//' ./start.sh
 
# 设置start.sh文件可执行权限
RUN chmod +x ./start.sh
  • start.sh脚本
 #!/bin/bash
 # 从第一行到最后一行分别表示:
 # 1. 收集静态文件到根目录,
 # 2. 生成数据库可执行文件,
 # 3. 根据数据库可执行文件来修改数据库
 # 4. 用 uwsgi启动 django 服务
 python3 manage.py collectstatic --noinput &&
 python3 manage.py makemigrations &&
 python3 manage.py collectstatic &&
 python3 manage.py migrate &&
 uwsgi --ini /var/www/html/docker_project/docker_django/uwsgi.ini
  • uwsgi.ini文件
[uwsgi]

; 使用nginx连接时使用
socket = 0.0.0.0:8000

; 直接做web服务器使用,指定要监听的ip和端口号,即我们运行项目时的ip和端口
; http = 0.0.0.0:8000

; 项目目录
chdir = /var/www/html/docker_project/docker_django

; 项目中的wsgi.py文件的目录
module = docker_django.wsgi:application

; 静态文件映射,测试uwsgi配置时为了能够访问到静态资源,所以加上这个配置。在使用nginx时,需要注销掉这个配置,改用nginx来代理静态资源访>; 可使用 python manage.py collectstatic
static-map=/static=/var/www/html/docker_project/docker_django/static

; 指定启动的工作进程数
processes = 4

; 指定每个进程中的线程数
threads = 2

; 指定在工作进程中存在一个主进程
master = True

; 服务停止时自动移除unix Socket和pid文件
vacuum = True

; 保存启动之后主进程的进程号
pidfile = uwsgi.pid

; 设置uwsgi后台运行,运行信息保存在uwsgi.log
; 切记在docker中使用uwsgi记录日志时,指定日志目录需要使用logto,而不是daemonize,否则会导致容器直接退出
; daemonize = uwsgi.log
logto = uwsgi.log

; 单个日志的大小
buffer-size=32768

; 设置每个工作进程处理请求的上限,达到上限时,将回收(重启)该进程。可以预防内存泄漏
max-requests=5000
第二步:编写Nginx镜像和容器所需文件
  • xxx/compose/nginx/Dockerfile
FROM nginx:latest

# 镜像维护者
MAINTAINER Fat Puffer <dcpuffer@outlook.com>

# 将项目nginx配置文件拷贝到nginx配置文件目录下
ADD nginx.conf /etc/nginx/conf.d/

# sed是一个Linux编辑器吧,此命令的作用是查找文件/etc/nginx/nginx.conf中包含user的行,并将此行的nginx替换成root
RUN sed -i '/user/{s/nginx/root/}' /etc/nginx/nginx.conf

# 删除原有配置文件,创建静态资源文件夹和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

CMD ["nginx", "-g", "daemon off;"]
  • xxx/compose/nginx/nginx.conf
# nginx配置文件。
upstream django {
    ip_hash;  # 负载策略
    server web:8000; # Django+uwsgi容器所在IP地址及开放端口,非宿主机外网IP
}
 
server {
    listen 80; # 监听80端口
    server_name localhost; # 可以是nginx容器所在ip地址或127.0.0.1,不能写宿主机外网ip地址
    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;    
    }
}
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
第三步:编写MySQL镜像和容器所需文件
  • xxx/compose/mysql/my.cnf
[mysqld]
user=mysql
default-storage-engine=INNODB
character-set-server=utf8

# 端口与docker-compose里映射端口保持一致
port=3306

#一定要注释掉,mysql所在容器和django所在容器不同IP
# bind-address=localhost

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
  • xxx/compose/mysql/init.sql
# 注意这里的数据库名django_docker和用户名admin和密码password必需和docker-compose.yml里与MySQL相关的环境变量保持一致

GRANT ALL PRIVILEGES ON docker_django.* TO admin@"%" IDENTIFIED BY "password@";
FLUSH PRIVILEGES;
第四步:编写docker-compose.yml文件

docker-compose.yml的核心内容如下。我们定义了2个数据卷,用于挂载各个容器内动态生成的数据,比如MySQL的存储数据,和django容器中用户上传的媒体资源与文件。这样即使删除容器,容器内产生的数据也不会丢失。我们还编排了3项容器服务,别名分别为mysql, nginx和web,接下来我们将依次看看各个容器的Dockerfile和配置文件。

version: "3"

volumes: # 自定义数据卷,默认位于宿主机/var/lib/docker/volumes内
  docker_django_mysql_vol: # 定义数据卷同步容器内mysql数据
  docker_django_media_vol: # 定义数据卷同步media文件夹数据

services:
  db-mysql:
    image: mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=password@123  # root用户数据库密码
      - MYSQL_DATABASE=docker_django  # 数据库名称
      - MYSQL_USER=admin  # 数据库用户名
      - MYSQL_PASSWORD=password@  # 创建的admin用户密码

    volumes:  
      - docker_django_mysql_vol:/var/lib/mysql:rw  # 挂载数据库数据, 可读可写
      - ./compose/mysql/conf/my.cnf:/etc/mysql/my.cnf  # 挂载配置文件
      -v /etc/localtime:/etc/localtime:ro
      - ./compose/mysql/init:/docker-entrypoint-initdb.d/  # 挂载数据初始化sql脚本
    ports:
      - "3306:3306" # 与配置文件保持一致
    restart: always
 
  web:
    build: ./docker_django  # 使用docker_django目录下的Dockerfile
    expose:
      - "8000"
    volumes:
      - ./docker_django:/var/www/html/docker_django  # 挂载项目代码
      - docker_django_media_vol:/var/www/html/docker_django/media  # 以数据卷挂载容器内用户上传媒体文件
      - ./compose/uwsgi:/tmp  # 挂载uwsgi日志
    links:
      - db-mysql
    depends_on:  # 依赖关系
      - db-mysql
    environment:
      - DEBUG=False
    restart: always
    tty: true
    stdin_open: true

  nginx:
    build: ./compose/nginx
    ports:
      - "80:80"
      - "443:443"
    expose:
      - "80"
    volumes:  # 可以在此处指定日志目录,将docker容器内的日志路径映射到本地
      - ./docker_django/static:/usr/share/nginx/html/static  # 挂载静态文件
      - ./compose/nginx/ssl:/usr/share/nginx/ssl  # 挂载ssl证书目录
	  - ./compose/nginx/nginx.log:/var/log/nginx  # 挂载日志
      - docker_django_media_vol:/usr/share/nginx/html/media  # 挂载用户上传媒体文件
    links:
      - web
    depends_on:
      - web
    restart: always
第五步:修改Django项目settings.py
# 生产环境设置 Debug = False
Debug = False
 
# 设置ALLOWED HOSTS
ALLOWED_HOSTS = ['localhost', '10.10.101.238']
 
# 设置STATIC ROOT 和 STATIC URL
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = "/static/"
 
# 设置MEDIA ROOT 和 MEDIA URL
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = "/media/"
 
# 设置数据库。这里用户名和密码必需和docker-compose.yml里mysql环境变量保持一致
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'docker_django',  # 数据库名
        'USER':'admin',  # 你设置的用户名 - 非root用户
        'PASSWORD':'password@',  # 换成你自己密码
        'HOST': 'db-mysql',  # 注意:这里使用的是db别名,docker会自动解析成ip
        'PORT':'3306',  # 端口
    }
}
第六步:修改项目配置文件下的__init__.py
  • 由于要使用mysql作为是数据库后台,所以需要在该文件下增加以下内容
import pymysql

pymysql.install_as_MySQLdb()
  • 安装pymysqlpip3 install pymysql
  • 别忘记重新导出环境依赖包pip3 freeze > requirements.txt
第七步:使用docker-compose 构建镜像并启动容器组服务
# 进入docker-compose.yml所在文件夹,输入以下命令构建镜像
sudo docker-compose build

# 查看已生成的镜像
sudo docker images

# 启动容器组服务 -d 后台启动
sudo docker-compose up -d

# 查看运行中的容器
sudo docker ps

# 停止容器组命令:
sudo docker-compose down

# 启动某个容器
sudo docker-compose start 容器名

# 停止某个容器
sudo docker-compose stop 容器名

在这里插入图片描述

第八步:进入web容器内执行Django命令并启动uwsgi服务器
sudo docker exec -it docker_project_web_1 /bin/bash start.sh
第九步:浏览器访问
http://10.10.102.238/admin

在这里插入图片描述

项目代码

GitHub传送门:https://github.com/FatPuffer/docker-compose-deploy-django

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值