docker 技术如今很是火热,经过容器构建项目环境,运行效率和部署效率都很不错。因此最近抽空看了一些教程,而后将博客部署方式改成了docker,感受网上没有特别好的关于 docker 部署django项目的教程,特地写了这篇文章,算是记录本身的心得。html
本次教程的测试环境为 Deepin,主要侧重于容器的编排和 Django 相关部署知识,一些细节方面,例如环境依赖安装,不会讲得特别详细。因为是在本地测试,因此在配置 nginx 相关信息时,将配置 http 代理而非 https 代理。python
部署方式选择了 docker 加 docker-compose,所以须要安装 docker 和 docker-compose。mysql
docker 能够经过 sudo apt install docker-ce
命令安装。nginx
docker-compose 可经过如下命令安装。web
sudo curl -L https://get.daocloud.io/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
复制代码
安装完成之后,输入 docker version
,看到如下画面表示 docker 安装成功。 redis
输入 docker-compose version
,看到如下画面表示 docker-compose 安装成功。 sql
博客项目中使用到了 Django, Mysql, Redis, Nginx,所以须要四个容器,每一个容器对应一个应用,固然这些容器是有前后顺序的,也就是说存在依赖关系。而后经过 docker-compose 编排这四个容器,构建容器运行环境。docker
总共四个容器:shell
下面是容器的结构图。 数据库
容器依赖关系:Django 容器依赖 Redis 容器和 Mysql 容器,Nginx 容器依赖Gunicorn 容器。
看这个教程的小伙伴请尽可能把目录和教程中目录保持一致,不然在后续部署过程当中极有可能会出错。
my_blog 是 django 项目目录,deployment 文件夹放置了除 Django 容器外的三个容器配置信息。
Dockerfile:docker 环境文件
docker-compose.yml:编排容器文件
start.sh:容器初始化后执行的 shell 命令脚本
requirements.txt:django项目环境依赖文件
gunicorn.conf:gunicorn 配置文件
deployment 目录包含 mysql 容器配置信息,nginx 容器配置信息和 redis 容器数据目录。
mysql:放置数据库配置信息,conf 放置数据库初始化配置文件 my.cnf,data 用于挂载数据库数据,init 放置 sql 脚本(导入表结构和数据,并挂载到容器中)。
nginx:放置 nginx 配置信息,ssl 放置 ssl证书
redis: 挂载 redis 数据
容器环境和本机环境是隔离的,你能够把容器当作另外一个系统,起初这个系统与你本机的系统并没有关联,咱们经过编写 Dockerfile 文件配置并构建容器环境(像在干净的系统中配置 python 环境同样)。
# 创建 python3.6 环境
FROM daocloud.io/python:3.6
# 镜像做者
MAINTAINER zyk 2295098032@qq.com
# 设置 python 环境变量
ENV PYTHONUNBUFFERED 1
# 建立 my_blog 文件夹
RUN mkdir /my_blog
# 将 my_blog 文件夹为工做目录
WORKDIR /my_blog
# 将当前目录加入到工做目录中(. 表示当前目录)
ADD . /my_blog
# 利用 pip 安装依赖(- i 表示指定清华源,默认源下载过慢)
RUN pip3 install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/
#设置环境变量
ENV SPIDER=/my_blog
复制代码
编写 gunicorn.conf 文件,用于 gunicorn 的启动
workers=3 # 并行工做进程数
threads = 2 # 指定每一个工做者的线程数
bind=['0.0.0.0:8000'] # 监听内网端口8000
proc_name='my_blog' # 进程名称
pidfile='/tmp/blog.pid' # 设置进程文件目录
worker_class='gevent' # 工做模式协程
timeout=30 # 超时
max_requests=6000 # 最大请求数
复制代码
start.sh 脚本用于启动 django 容器
#!/bin/bash
# 从第一行到最后一行分别表示:
# 1. 守护进程执行 celery,没有这个需求的小伙伴能够将第一行命令其删除
# 2. 收集静态文件到根目录,
# 3. 生成数据库可执行文件,
# 4. 根据数据库可执行文件来修改数据库
# 5. 用 gunicorn 启动 django 服务
celery multi start w1 -A celery_tasks.tasks worker -l info&&
python manage.py collectstatic --noinput&&
python manage.py makemigrations&&
python manage.py migrate&&
gunicorn my_blog.wsgi:application -c gunicorn.conf
复制代码
# nginx镜像
FROM daocloud.io/nginx
# 删除原有配置文件,建立静态资源文件夹和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
# 添加配置文件
ADD ./nginx.conf /etc/nginx/conf.d/ 复制代码
nginx.conf用于反向代理域名或者 ip,将动态请求分发至内部的 django 容器的8000端口,并配置静态资源路径。
配置反向代理时,注意 host 必定要改成 web,web便是django容器的名称(在docker-compose.yml中配置)
# 仅用于本地docker环境测试(80端口代理http请求)
server {
listen 80; # 监听80端口
server_name 127.0.0.1; # 生产环境请换成域名
location / {
proxy_pass http://web:8000; # 反向代理 django容器8000端口,web为django容器名称,切记不要写域名或者ip
proxy_set_header Host $host;
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /static/ {
alias /usr/share/nginx/html/static/; #静态资源路径
}
location /media/ {
alias /usr/share/nginx/html/media/; #上传文件路径
}
}
复制代码
my.cnf 文件用于初始化 mysql 配置,这个文件将被挂载到容器中。
[mysqld]
user=mysql
default-storage-engine=INNODB
character-set-server=utf8
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
复制代码
将须要导入的sql文件放入init目录下,并修改其名称为init.sql
编写 docker-compose.yml
version: "3"
services:
redis:
image: daocloud.io/redis:3
command: redis-server
volumes:
- ./deployment/redis:/data
ports:
- "6379:6379"
restart: always # always表容器运行发生错误时一直重启
db:
image: daocloud.io/mysql:5.7
environment:
- MYSQL_DATABASE=my_blog # 数据库名称
- MYSQL_ROOT_PASSWORD=19960331 # 数据库密码
volumes:
- ./deployment/mysql/data:/var/lib/mysql # 挂载数据库数据
- ./deployment/mysql/conf/my.cnf:/etc/mysql/my.cnf # 挂载配置文件
- ./deployment/mysql/init:/docker-entrypoint-initdb.d/ # 挂载数据初始化sql脚本
ports:
- "3306:3306"
restart: always
web:
build: .
expose:
- "8000"
volumes:
- .:/my_blog
- /tmp/logs:/tmp
command: bash start.sh
links:
- db
- redis
depends_on:
- db
- redis
restart: always
nginx:
build: deployment/nginx
ports:
- "80:80"
- "443:443"
expose:
- "8000"
volumes:
- ./collect_static:/usr/share/nginx/html/static # 挂载静态文件
- ./media:/usr/share/nginx/html/media # 挂载上传文件
- ./deployment/nginx/ssl:/usr/share/nginx/ssl # 挂载ssl证书目录
links:
- web
depends_on:
- web
restart: always
复制代码
redis,db,web,nginx为容器名称。
image 表示拉取镜像名称,build会在给定目录下寻找 Dockerfile 并构建容器环境。
expose 表示将端口暴露给其余容器,但不暴露给主机(不一样容器默认相互隔离)。
ports 表示将该容器端口映射到主机端口(从右往左读,例如ports: - "3307:3306",是指把容器的3306端口映射到主机的3307端口),同时该容器端口也会对其余容器开放。
volumes 表示挂载,就是将本机的文件和容器中的文件映射起来,容器和本地环境原本是隔离的,挂载至关因而凿了一个小洞,让二者数据能够互通。
links 表示将容器互联起来。
depends_on:表示依赖关系,由于容器的启动有前后顺序,django 容器依赖于 mysql 容器和 redis 容器(django须要从数据库和缓存中读写数据),而 nginx 依赖于 django 容器(nginx 容器须要反向代理 django 容器的8000端口)
在构建运行容器以前,须要修改 django 项目的 settings.py文件。
将 数据库链接 HOST 改成 mysql 容器名称 db
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # mysql驱动
'NAME': 'my_blog', # 数据库名称
'USER': 'root', # 登陆账号
'PASSWORD': '19960331', # 登陆密码
'HOST': 'db', # 主机地址(容器部署)
# 'HOST': '127.0.0.1', # 主机地址
'PORT': '3306', # 端口
'OPTIONS': {'charset': 'utf8mb4'},
}
}
复制代码
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://redis:6379', # redis(容器)
# 'LOCATION': '127.0.0.1:6379',
'OPTIONS': {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100},
'SOCKET_TIMEOUT': 10,
},
},
}
复制代码
生产环境部署请将 settings.py 中的 DEBUG = True
改成 DEBUG = False
以关闭debug模式。
最后在项目根目录执行命令 docker-compose up --build
。
执行完毕之后看到如下画面代表构建成功。
在浏览器端口访问127.0.0.1或者你的公网 ip,若能成功访问代表构建成功。
我也是第一次用 docker-compose 来部署 django 项目,如有写得不得当或者有误的地方麻烦你们帮忙指出。