Django-Docker容器化部署:Django-Docker-MySQL-Nginx-Gunicorn雲端部署

上一章我們實現了在 Docker 中添加了 MySQL 數據庫,但採用的開發服務器雖然使用便捷,但性能差、可靠性低,無法應用在生產環境中。

因此本章將實現 Docker + Django + MySQL + Nginx + Gunicorn 容器項目,完成最終的服務器部署。

直接進入本章的 Docker 入門讀者,建議回到教程第一章開始閱讀,否則某些內容不好理解。對 Django 項目部署都沒有概念的讀者,還可以先閱讀我的博文:將 Django 項目部署到服務器

Docker-compose

在部署到服務器之前,先來嘗試本地部署。

在上一章的基礎上,繼續修改 docker-compose.yml 配置:

version: "3"

services:
  app:
    restart: always
    build: .
    command: bash -c "python3 manage.py collectstatic --no-input && python3 manage.py migrate && gunicorn --timeout=30 --workers=4 --bind :8000 django_app.wsgi:application"
    volumes:
      - .:/code
      - static-volume:/code/collected_static
    expose:
      - "8000"
    depends_on:
      - db
    networks:
      - web_network
      - db_network
  db:
    image: mysql:5.7
    volumes:
      - "./mysql:/var/lib/mysql"
    ports:
      - "3306:3306"
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=mypassword
      - MYSQL_DATABASE=django_app
    networks:
      - db_network
  nginx:
    restart: always
    image: nginx:latest
    ports:
      - "8000:8000"
    volumes:
      - static-volume:/code/collected_static
      - ./config/nginx:/etc/nginx/conf.d
    depends_on:
      - app
    networks:
      - web_network
      
networks:
  web_network:
    driver: bridge
  db_network:
    driver: bridge
    
volumes:
  static-volume:

有點複雜。來看看大體思路:

  • 定義了 3 個容器,分別是 appdbnginx 。容器之間通過定義的端口進行通訊。
  • 定義了 2 個網絡,分別是 web_networkdb_network 。只有處在相同網絡的容器才能互相通訊。不同網絡之間是隔離的,即便採用同樣的端口,也無法通訊。
  • 定義了 1 個數據卷static-volume 。數據卷非常適合多個容器共享使用同一數據,你可以看到 appnginx 都用到了它。
  • exposeports 都可以暴露容器的端口,區別是 expose 僅暴露給其他容器,而 ports 會暴露給其他容器和宿主機。

這麼講可能還是很難理解,讓我們繼續分解。

網絡 network

Docker 允許用戶給每個容器定義其工作的網絡,只有在相同的網絡之中才能進行通訊。你可以看到 nginx 容器處於 web_network 網絡,而 db 容器處於 db_network 網絡,因此它兩是無法通訊的,實際上確實也不需要通訊。而 app 容器同時處於 web_networkdb_network 網絡,相當於是橋樑,連通了3個容器。

定義網絡可以隔離容器的網絡環境,也方便運維人員一眼看出網絡的邏輯關係。

數據卷

之前我們見識過的用於映射宿主機和容器目錄的捲了,實際上稱爲掛載;現在新出現的 static-volume 才叫。它的使用方式像這樣:static-volume:/code/collected_static ,冒號後面還是容器內的目錄,但冒號前的卻不是宿主機目錄、僅僅是卷的名稱而已。從本質上講,數據卷也是實現了宿主機和容器的目錄映射,但是數據卷是由 Docker 進行管理的,你甚至都不需要知道數據卷保存在宿主機的具體位置。

相比掛載,數據卷的優點是由於是 Docker 統一管理的,不存在由於權限不夠引發的掛載問題,也不需要在不同服務器指定不同的路徑;缺點是它不太適合單配置文件的映射。

和掛載一樣,數據卷的生命週期脫離了容器,刪除容器之後卷還是存在的。下次構建鏡像時,指定卷的名稱就可以繼續使用了。

既然 Docker 能夠管理卷,所以要想刪除卷也是非常容易的。指令嘛,我不告訴你,生產環境千萬不要手賤。定期備份數據是個好習慣。

數據卷有個很重要的特性:啓動時如果卷是空的,則會將容器映射目錄的所有內容複製到卷裏去。換句話說就是,只要卷初始化完成後,容器原始的 collected_static 目錄就不會再使用了,新增的文件也只存在於卷中,容器中是沒有的。

實際上 static 靜態文件(以及 media 媒體文件)的持久存儲,通過掛載或者數據卷都可以實現;具體用哪種,這個就見仁見智了,你自己選擇。

篇幅有限,教程沒有講到 media 媒體文件,但它的設置和 static 是完全相同的。

其他配置

首先修改 Nginx 的配置文件,即映射到 nginx 容器的 config/nginx/django_app.conf

upstream app {
  ip_hash;
  server app:8000;
}

server {
  listen 8000;
  server_name localhost;
  
  location /static/ {
    autoindex on;
    alias /code/collected_static/;
  }
  
  location / {
    proxy_pass http://app/;
  }
}

此配置下 Nginx 會監聽容器的 8000 端口,並將受到的請求發送到 app 容器(靜態文件請求除外)。

requirements.txt 文件中增加 gunicorn 庫:

django==2.2
mysqlclient==1.3.14
gunicorn==19.9.0

最後修改 django_app/settings.py和靜態文件存放目錄的配置:

...

ALLOWED_HOSTS = ['*']

...

STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')
STATIC_URL = '/static/'

所有配置就完成了。

教程使用空的 Django 項目,爲演示效果,就沒有修改 DEBUG=False 了。若你用的自己的項目測試,記得把它爲 False。

測試

測試指令就一條:

$ docker-compose up

瀏覽器訪問 127.0.0.1:8000 又看到熟悉的 Django 小火箭了。

和上一章類似,第一次啓動容器時可能會出現無法連接 MySQL 的錯誤,這是由於雖然 db 容器已經啓動,但初始化並未完成;重新啓動容器之後就可以正常工作了。若多次啓動都無法正常工作,那就是別的原因了,好好檢查吧。

本地部署成功,下一步服務器部署。

服務器部署

有了本地部署的經驗,服務器部署就非常非常簡單了。

還是類似的,部署前將 Docker 、 Docker-compose 、 Python3 等工具在服務器上安裝好;將項目用 Git 克隆到服務器本地。

接下來把 settings.pyconfig/nginx/django_app.confrequirements.txt 相關位置都按教程流程改好;將 docker-compose.ymlDockerfile 複製到服務器。

由於 http 請求默認爲 80 端口,所以爲了接收公網請求,還需要做一點點修改 docker-compose.yml 的工作:

version: "3"

services:
  app:
    ...
    command: bash -c "... your_project_name.wsgi:application"  # 改爲你的項目名稱
    ...
  db:
    ...
  nginx:
    ...
    ports:
      - "80:8000"  # 監聽 80 端口
    ...
      
networks:
  ...
    
volumes:
  ...

修改 Gunicorn 綁定的項目名稱,以及讓宿主機監聽公網 http 默認的 80 端口。

此外還要修改 config/nginx/django_app.conf

upstream your_domain_name {
  ip_hash;
  server app:8000;
}

server {
  ...
  
  location / {
    proxy_pass http://your_domain_name/;
  }
}

這個改動主要是爲了照顧各種第三方登錄的回調地址(不改這裏, GitHub、Weibo 三方登錄都會失敗)。如果你沒有類似的需求,不改也是可以的。比如博主的個人網站www.dusaiphoto.com,所以這裏的 your_domain_name 就修改爲 www.dusaiphoto.com

最後,記得將 settings.py 中的 DEBUG 配置修改好:

# DEBUG=True 註釋掉
DEBUG=False

這樣就可以了!構建鏡像並啓動容器:

 docker-compose up

在瀏覽器中就可以正常訪問你的網站了。

總結

現在你已經可以部署一個線上的容器化 Django 項目了,恭喜!

若本教程對你有幫助,請到GitHub給個 Star 喲,也歡迎閱讀我的Django 搭建博客教程

老朋友們,下個教程見!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章