使用Docker部署Django应用的过程和心得


之前部署Web应用,没用docker,直接在服务器上部署,使用了django+nginx+supervisor+gunicorn部署博客应用。但后来了解了docker,为其“Build,Ship and Run Any App,Anywhere”的思想所折服,觉得这个太牛逼了,所以我也尝试一下自己用docker部署Web应用。本篇文章为了记录我用docker部署web应用的过程和心得。

Django常见的两种部署方式:

  1. Django + Nginx + uWSGI

  2. Django+ Nginx + Gunicorn

采用用 uWSGI 配合 Nginx的部署方式

构建的容器:

  1. Django+nginx+uwsgi 容器 (dockerfiles/django-uwsgi-nginx)
  2. MySQL容器 (mysql:5.6)

下载镜像

下载好镜像, 就是要运行容器. 在这之前需要为容器自定义创建专属网络

docker.io/redis                            latest              f9b990972689        17 months ago       104 MB
docker.io/mysql                            5.6                 742f7d5a4104        21 months ago       302 MB
docker.io/elasticsearch                    5.6                 752be83a5396        2 years ago         486 MB
docker.io/dockerfiles/django-uwsgi-nginx   latest              c19f9896b632        2 years ago         588 MB

 

1.创建专属网络

docker network create django_network
NETWORK ID          NAME                DRIVER              SCOPE
9c6f50c41bdf        bridge              bridge              local
9bb3d435400f        django_network      bridge              local
7f89bb948cdf        host                host                local
343a8957ba28        none                null                local

后面的服务都会使用这个专属网络进行通信,主机名就是域名地址,通信地址直接填主机名,docker提供了域名解析,所以我settings.py的数据库配置如下:

# 配置mysql
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'djmyblog',
        'USER': '用户',
        'PASSWORD': '密码',
        'HOST': 'django_mysql',  # 这就是数据库容器名  通过域名解析
        'PORT': '端口',
    }
}

2.部署Mysql Redis Elasticsearch


# mysql容器
docker run -d -p 3307:3306 --network django_network --name django_mysql -e MYSQL_ROOT_PASSWORD=xxxx mysql:5.6

# 说明下参数意义
# -p 映射端口:docker内部端口: 端口映射,只有将容器端口映射到外部,外部才能访问
# -e 环境变量,指定一些服务内读取的变量,以初始化服务,这里的变量意义从字面上不难理解
# --network 指定容器所在网络,需要互相访问的容器记得指定到同一个网络!
# --name 容器名,这个名字在同一个容器网络里是可以直接当成域名访问的!


# redis容器
docker run -d -p 6969:6379 --network django_network --name django_redis docker.io/redis  --requirepass "xxxxx"


# es容器
docker run --name elasticsearch -d -e ES_JAVA_OPTS="-Xms128m -Xmx128m" -e "discovery.type=single-node" -p 9200:9200 -p 9300:9300 --network django_network  elasticsearch:5.6

3.部署web服务

 docker run -d --network django_network --name django_web -p 80:80 -p 443:443 -v /home:/home  dockerfiles/django-uwsgi-nginx
# 说明下参数意义
# -p 映射端口:docker内部端口: 端口映射,只有将容器端口映射到外部,外部才能访问
# -v 数据卷,可以将主机上的某个目录与容器的某个目录关联起来,容器上的挂载点下的内容就是主机的这个目录下的内容
# --network 指定容器所在网络,需要互相访问的容器记得指定到同一个网络!
# --name 容器名,这个名字在同一个容器网络里是可以直接当成域名访问的!

4.Nginx配置(nginx目录)

接下是配置 Nginx 来处理用户请求。

先在服务器的 /etc/nginx/sites-available/ 目录下新建一个配置文件,文件名我一般就设置为域名。写上下面的配置内容:

server {
        # 80端口转发443
        server_name ch3nnn.cn;  # 绑定域名                          
        rewrite ^(.*) https://$server_name$1 permanent;

}  

server {
        # 443 https 

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/www.ch3nnn.cn/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/www.ch3nnn.cn/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot



        server_name blog;

        location /static {
                alias /home/django-blog/blogproject/root_static;
        }
        location /media {
                alias /home/django-blog/blogproject/media;
        }
        location / {
                proxy_pass http://127.0.0.1:8000;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header REMOTE_ADDR $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                real_ip_recursive on;
                proxy_max_temp_file_size 0;
                proxy_connect_timeout      90;
                proxy_send_timeout         90;
                proxy_read_timeout         90;
                proxy_buffer_size          4k;
                proxy_buffers              4 32k;
                proxy_busy_buffers_size    64k;
                proxy_temp_file_write_size 64k;

              #proxy_redirect off;
              #proxy_cache cache_one;
              #proxy_cache_valid 200 304 12h;
              #proxy_cache_valid 301 302 1d;
              #proxy_cache_valid any 5m;
              #expires 1d;
              #add_header wall  "hey, nginx静态文件缓存";

        }
        # 看板娘
        location /static/look_girl_models {
                 add_header Access-Control-Allow-Origin https://paugram.com;
        }
        # 静态文件缓存
        location ~ .*\.(js|css|png|jpg|gif)$ {
                root /home/django-blog/blogproject; 
                if (-f $request_filename) {
                    expires 1d;
                break;
                }
        }
        # 静态文件html缓存
        location ~ /archives/(\d+\.html$) {
              proxy_pass http://127.0.0.1:8000/archives/$1;
              #proxy_redirect off;
              #proxy_cache cache_one;
              #proxy_cache_valid 200 304 12h;
              #proxy_cache_valid 301 302 1d;
              #proxy_cache_valid any 5m;
              #expires 1d;
              add_header wall  "hey, nginx静态文件缓存";
        }


}

在 /etc/nginx/sites-available/ 放置了配置文件,接下来需要创建一个符号链接,把这个配置文件加入到启用的网站列表中去,被启用网站的目录在 /etc/nginx/sites-enabled/,你可以理解为从 sites-available/ 目录下发送了一个配置文件的快捷方式到 sites-enabled/ 目录。具体命令如下:

sudo ln -s /etc/nginx/sites-available/myblog /etc/nginx/sites-enabled/myblog

5. 使用 Gunicorn

Gunicorn 一般用来管理多个进程,有进程挂了Gunicorn 可以把它拉起来,防止服务器长时间停止服务,还可以动态调整 worker 的数量,请求多的时候增加 worker 的数量,请求少的时候减少。

安装 Gunicorn:

pip install gunicorn

用 Gunicorn 启动服务器进程:

# 需要在项目目录下
gunicorn --bind 0.0.0.0:8000 blogproject.wsgi:application 

6. 进程管理工具 Supervisor 

supervisor-app.conf 配置信息

# gunicorn
[program: gunicorn-app]
# 项目目录
directory = /home/django-blog/blogproject
# 命令
command = nohup gunicorn --bind 0.0.0.0:8000 blogproject.wsgi:application  > /dev/null 2>&1

# nginx
[program:nginx-app]
command = /usr/sbin/nginx

7. 运行项目

# 这时候你可以使用supervisorctl命令
supervisorctl start all

# 查看运行状态命令 
supervisorctl status
#gunicorn-app                     RUNNING   pid 128, uptime 0:45:08
#nginx-app                        RUNNING   pid 129, uptime 0:45:08

这里为什么要使用Supervisor, 因为以后每次部署项目就不需要在运行各个组件. 只需要一个命令就可以将项目起来, 很方便.

 

部署的时候踩的坑的问题

docker 容器中乱码解决办法(真实解决!!!) 

进入web容器找到项目, 在运行web是报错了, settint.py文件里的中文注释全部乱码

解决方法:

LANG=C.UTF-8

然后再激活:

source /etc/profile 

然而实际上这样显示是没有出问题了,但是我的hdfs命令却失效了!!!

提示command not find

然而发现不使用激活环境激活语句,直接也就可以看到中文正常显示了,或者使用这样进行环境变量的设置:

export LANG=C.UTF-8

但是有个问题就是每次进入容器都要执行一次 export LANG=C.UTF-8 确实很麻烦

这里就需要修改Linux的配置文件 

.bashrc             当你登入shell时执行

需要vim添加 .bashrc 文件

# vim打开配置文件
vim ~/.bashrc  


# 在文件最后添加
​export LANG=C.UTF-8

​