Django使用Docker部署

2020-04-26 | Tags: 博客搭建

blog部署

缘起

最近把blog用docker重新部署了一下,之前这个blog是采用django+uWSGI+nginx在自己的物理服务器上部署的,后来服务器重装过了一次,深感各种安装各种配置真的麻烦,因此这次各种软件和服务的部署都尽量采用docker进行部署。docker可以将所有环节和配置都打包到镜像中,还不依赖宿主机的系统,真正做到一行命令就完成部署。

配置

在之前的配置中,django对接uWSGI,然后由nginx代理外部请求,其中对动态页面的请求接入uWSGI来访问django,对静态页面的请求直接代理到服务器的静态文件目录。

所以这次重新部署开始考虑的就是django,uWSGI,nginx各一个镜像,动态页面通过设定同一docker网络进行相互通信,静态文件目录通过django手动collection同步之后挂载到nginx镜像中,保证整体运行。

然后稍微尝试了一下,感觉这样一搞三个独立的镜像配置的时候很麻烦,而且出了问题要到处查,非常不方便,就不想这么干了。

后来考虑到本站是个小网站,也没啥访问量,uWSGI做服务绰绰有余,干脆就把django和uWSGI打包在一起,做成一个单独的镜像,处理动态页面的访问请求。对于静态文件请求本来打算uWSGI一起搞定,后来考虑到国内访问速度的问题,就打包扔到阿里的OSS服务上去了。这样不但访问速度快,还能给主站省点流量。

OSS

首先搞个OSS服务,上阿里云找到OSS对象存储,建一个bucket。然后在django里配置一个aliyun官方的OSS插件django-oss-storage

安装
pip install django-oss-storage
配置settings

添加django_oss_storage到INSTALLED_APPS

添加如下配置,设定静态存储和Media后端

STATICFILES_STORAGE = 'django_oss_storage.backends.OssStaticStorage'
DEFAULT_FILE_STORAGE = 'django_oss_storage.backends.OssMediaStorage'

添加如下配置,设定静态存储和Media的访问url,同时作为在OSS上存储文件的前缀。

STATIC_URL = '/static/'
MEDIA_URL = '/media/'

最后就是添加要关联的阿里云OSS的具体配置参数

# AliCloud access key ID(阿里云账户的Access key)
OSS_ACCESS_KEY_ID = <Your Access Key ID>

# AliCloud access key secret(阿里云账户的Access key Secret)
OSS_ACCESS_KEY_SECRET = <Your Access Key Secret>

# The name of the bucket to store files in(刚才建的bucket名字)
OSS_BUCKET_NAME = <Your bucket name>

# The URL of AliCloud OSS endpoint
# Refer https://www.alibabacloud.com/help/zh/doc-detail/31837.htm for OSS Region & Endpoint
# Endpoint和OSS建立时选的区域有关,可以参考上面的网址
OSS_ENDPOINT = <Your access endpoint>

另外还有一个OSS_EXPIRE_TIME参数,默认是30days,这个参数的意思是当你的bucket是私有的时候,django-oss-storage在生成对oss的访问链接的时候,会使用你的信息对链接进行签名,这个签名后的链接有个过期时间,就是这个OSS_EXPIRE_TIME。这个参数的意义在于保证生成的链接在一定时间之后就不可用,有防止盗链的作用。一般按默认值就可以了,如果比较在意的话可以设一个比较短的时间。

最后在django主目录下执行python manage.py collectstatic,就可以将静态文件全部同步到阿里云OSS的bucket中去了。

收费

阿里云OSS大陆区域的收费标准

存储:0.12元/GB/月

外网流出流量00:00-08:00(闲时):0.25元/GB 8:00-24:00(忙时):0.50元/GB

请求费用:0.01元/万次

非常的便宜,速度又快又稳定

对于我这种没啥访问的小网站来说,四舍五入一下就是不要钱= =,哈哈。

Docker部署

docker这边编写一个Dockerfile

FROM python:3.6

# add project to the image
COPY run/  /app/run/
COPY blog/  /app/blog/

# set working directory to /app/
WORKDIR /app/run

# install python dependencies
RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

# RUN server after docker is up
CMD ./start.sh

Dockerfile第一部分

# add project to the image
COPY run/  /app/run/
COPY blog/  /app/blog/

这边先在docker镜像中建两个目录,其中/app/blog/用于之后将django源码挂载进来。/app/run/下写了一些启动脚本和配置文件,具体如下

run
├── requirements.txt
├── start.sh*
└── uwsgi.ini*

其中uwsgi.ini是uWSGI启动时所用的配置,具体如下

[uwsgi]
# uWSGI字节对外监听端口
http=0.0.0.0:8080

# 运行目录
chdir=/app/blog

# django的wsgi配置文件
wsgi-file = blog/wsgi.py

# uWSGI重启文件(docker中不需要)
# touch-reload=run/reload

# uWSGI的处理进程数
processes = 3

# 请求超时时间
harakiri=20

# 最大请求次数,到达后重启进程
max-requests=5000

# 启动为主进程
master=True

# 当服务器退出的时候自动删除unix socket文件和pid文件。(docker中不需要)
# vacuum=True

Dockerfile第二部分

# set working directory to /app/
WORKDIR /app/run

# install python dependencies
RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

# RUN server after docker is up
CMD ./start.sh

这边就是切换到刚刚COPY进去的run目录,pip安装所需要的python包,包括了django,uWSIGI等,我的requirements.txt如下:

Django==2.2.10
django-markdownx==3.0.1
django-tracking2==0.5.0
django-oss-storage==1.1.1
Markdown==3.2.1
Pillow==7.1.1
pytz==2019.3
sqlparse==0.3.1
uWSGI==2.0.18
six==1.14.0

最后就是使用CMD命令将uWSGI服务拉起来,start.sh的内容非常简单,目前就是uwsgi --ini uwsgi.ini,如果后续需要更多的操作的话,可以在脚本中继续添加。

Docker启动

现在就可以将docker启动

首先在Dockerfile所在目录下执行build指令

docker build -t docker_blog:1.0 .

确定正常build后就可以启动镜像了

docker run -d --restart=unless-stopped --name blog1.0 -v /home/zhuxi/blog/:/app/blog -p:8080:8080 docker_blog:1.0

这里-v将django源码挂载到docker镜像内部的/app/blog中,供镜像中的uWSGI调用。这样做的好处是在宿主机中对django源码进行修改后不需要在重写制作docker镜像,直接重启当前正在运行的镜像就可以更新django源码。省了许多事情。

-p将uWSGI监听的http=0.0.0.0:8080端口映射到宿主机的8080端口,供宿主机对外提供访问能力。

这个时候通过访问宿主机ip:8080就可以正常访问我们自己的blog啦,以后需要重写部署的时候把code从github上拉下来,配置一下数据库和静态文件。然后执行上面启动镜像的命令就可以马上部署网站,非常的方便。

部署代码已commit到github