之前部署Web应用,没用docker,直接在服务器上部署,使用了django+nginx+supervisor+gunicorn部署博客应用。但后来了解了docker,为其“Build,Ship and Run Any App,Anywhere”的思想所折服,觉得这个太牛逼了,所以我也尝试一下自己用docker部署Web应用。本篇文章为了记录我用docker部署web应用的过程和心得。
Django常见的两种部署方式:
Django + Nginx + uWSGI
Django+ Nginx + Gunicorn
采用用 uWSGI 配合 Nginx的部署方式
构建的容器:
- Django+nginx+uwsgi 容器 (dockerfiles/django-uwsgi-nginx)
- 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