Django容器(下): 使用Gunicorn管理Django

  • 2019 年 12 月 19 日
  • 筆記

開始之前


在上一篇文章《Django容器(上): 自定義基礎鏡像》我們已經封裝好了Django項目的基礎鏡像,接下來需要在基礎鏡像之上做些收尾工作,主要以下幾點:

  • 在基礎鏡像中加入項目程式碼。
  • 配置 Gunicorn 管理 Django 應用。
  • 配置 Supervisor 管理 Nginx 與 Gunicorn進程。

一些問題


為什麼使用 Gunicorn 管理 Django 應用?

Gunicorn (Green Unicorn)是一個高效的 Python WSGI Server,常用來管理多個進程。

如果有進程掛了Gunicorn 可以把它啟動起來,防止長時間停止服務。

此外 Gunicorn 還可以動態調整 worker的數量,請求多時增加 worker的數量,相反則減少。

為什麼使用 Nginx 代理 Gunicorn 應用?

當訪問網站時,伺服器會接收到不同類型的資源請求:a. Pic、Css、Js 等靜態資源文件。b. 詳情頁等需要調用資料庫動態獲取的數據。

對於動態數據請求,文章數據需要 Django 從資料庫中獲取Nginx會把這個請求轉發給 Django處理。

對於靜態資源請求,只需要 Nginx 去項目所在的目錄直接獲取,不再麻煩Django

相比 Django框架內置的Web伺服器,Nginx可以更高效的處理靜態文件請求。

因此生產環境推薦使用 Nginx + Gunicorn + Django 的方式。

梳理一下本項目中進程關係
使用 `supervisor` 來管理 'gunicorn' 與 'Nginx'進程。  使用 `gunicorn` 來管理 'django'應用,實現管理多個'worker'進程。  使用 `nginx` 反向代理 'gunicorn' 應用,實現"動/靜態分離"。

操作步驟


1. 項目鏡像構建目錄

tree -L 1 ./  ./  ├── base       # 基礎鏡像目錄  ├── Dockerfile # 項目 Dockerfile  └── start      # 項目程式碼目錄    2 directories, 1 file

2. Dockerfile 文件

cat Dockerfile    # use start-base image  FROM start-base    # nginx  COPY base/conf/nginx.conf /etc/nginx/nginx.conf  COPY base/conf/default.conf /etc/nginx/conf.d/default.conf  COPY base/conf/ssl /etc/nginx/ssl    # django  COPY start /start  WORKDIR /start  # 收集靜態文件到 STATIC_ROOT 中,項目中為 /start/static  RUN python manage.py collectstatic -l --noinput    # supervisor  COPY base/conf/supervisord.conf /etc/supervisor/supervisord.conf  CMD ["/usr/bin/supervisord","-c","/etc/supervisor/supervisord.conf"]

相關命令可以參考 《如何使用 Dockerfile自定義鏡像?》 這篇文章。

3. supervisor 配置文件

cat base/conf/supervisord.conf    [supervisord]  nodaemon=true  pidfile=/var/run/supervisord.pid  logfile=/var/log/supervisor/supervisord.log    [program:nginx]  command=/usr/sbin/nginx -g "daemon off;"    [program:gunicorn]  command=gunicorn -w 2 -b unix:/var/run/django.socket web.wsgi:application  stderr_logfile=/var/log/gunicorn.stderr  stdout_logfile=/var/log/gunicorn.stdout

supervisor 配置可以參考《為什麼需要自定義一個基礎鏡像? 》 這篇文章。gunicorn 選項請參考下面。

4. nginx 配置文件

cat base/conf/default.conf    server {        listen 80;      listen 443 ssl;      server_name  www.zongming.net;      # 其它配置項省略...        # 保持與 django MEDIA_URL 一致      location ^~ /attachments {          alias /start/uploads/;          expires 180d;      }        # 保持與 django STATIC_URL 一致      location ^~ /static {          root /start/;          expires 180d;      }        location / {          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;          proxy_set_header X-Forwarded-Proto $scheme;          proxy_set_header Host $http_host;          proxy_pass http://unix:/var/run/django.socket;          proxy_redirect default;      }        access_log  /var/log/nginx/access.log access;      error_log  /var/log/nginx/error.log;  }

注意,proxy_pass代理的 sokect文件路徑,與 supervisor中保持一致。

nginx 代理配置項可以參考《Nginx Proxy 反向代理》 這篇文章。

5. 構建項目鏡像

docker build -t start:0.0.1 .  Sending build context to Docker daemon  3.5mb  Step 1/9 : FROM python:3  # ...省略  Successfully built cd2a8533ab3d  Successfully tagged start:0.0.1

6. 驗證django容器

a. 創建容器

docker run --name test -d start:0.0.1  66655a0cff8b#省略..2f59ce1cd14d03e606581

b. 容器進程

pstree 15585  supervisord─┬─gunicorn───2*[gunicorn]              └─nginx───nginx

c. 訪問服務

curl www.demo.com  HTTP/1.1 200 OK  Server: nginx  Date: Thu, 19 Jan 2018 04:37:12 GMT  Content-Type: text/html; charset=utf-8  Connection: keep-alive  Keep-Alive: timeout=10  Vary: Accept-Encoding  X-Frame-Options: SAMEORIGIN

命令幫助

語法: gunicorn [OPTIONS] APP_MODULE  示例: gunicorn -w 2 -b unix:/var/run/django.socket web.wsgi:application  `web` 為 django項目應用名稱,例如示例中的 Django工程是使用以下命令創建的。  # 創建 start 項目  django-admin startproject start  # 創建 web 應用  python manage.py startapp web    選項  -b BIND  指定要綁定的伺服器套接字。伺服器套接字可以是:  `$(HOST)`, `$(HOST):$(PORT)`, `unix:$(PATH)`中的任何一個。IP 是有效的`$(HOST)`。  默認值為 ['127.0.0.1:8000']    -w WORKERS  處理請求的工作進程數。此值通常應為伺服器中每個核心(CPU) 2-4之間,默認值為1。

小結


最後來總結下文章中的知識點

  • 使用 supervisor 在 docker 容器中管理 nginx、gunicorn進程。
  • Gunicorn是一個高效的 Python WSGI Server,常用來管理多個進程。
  • 對於 django項目,推薦生產環境使用 Nginx + Gunicorn + Django 的方式