Docker部署Django(三)docker-compose編排Django+Uwsgi+Nginx+MySQL

寫在前面

實際的生產環境中,我們往往需要定義數量龐大的 docker 容器,並且容器之間具有錯綜複雜的依賴聯繫,一個一個去手動創建容器並記錄和配置這些複雜的容器關係,不僅效率低下而且容易出錯,所以迫切需要一種定義容器集羣編排和部署的工具,這就是docker-compose

什麼是docker-compose及docker-compose工具的安裝

Docker-compose是一個用來定義和運行復雜應用的 Docker 工具。使用 docker-compose 後不再需要使用 shell 腳本來逐一創建和啓動容器,還可以通過 docker-compose.yml 文件構建和管理複雜多容器組合。

pip安裝docker-compose
pip3 install docker-compose

ln -s /usr/local/python3/bin/docker-compose /usr/bin/docker-compose

docker-compose -version

多容器部署Django項目示意圖

在這裏插入圖片描述

  • 當客戶端通過80端口訪問服務,宿主機80端口映射到djang_nginx容器的80端口,找到django_nginx容器,django_nginx收到請求轉發到uwsgi服務的8000端口
  • 8000端口映射到django_uwsgi容器,View視圖處理時如果用到了數據庫內容,則將尋找settings.py中配置的數據信息,尋找3306端口的mysql服務
  • 3306端口映射到MySQL容器,從該容器的上獲取數據,然後依次返回用戶

Django+Uwsgi+Nginx+MySQL代碼佈局圖

docker_project  # 項目根目錄
├── compose  # 存放各項容器服務的Dockerfile和配置文件
│   ├── mysql
│   │   ├── conf
│   │   │   └── my.cnf  # MySQL配置文件
│   │   └── init
│   │       └── init.sql  # MySQL啓動腳本
│   └── nginx
│       ├── Dockerfile  # 構建Nginx鏡像所的Dockerfile
│       ├── nginx.conf  # Nginx配置文件
│       ├── nginx.log  # 掛載保存nginx容器內nginx日誌
│       │   ├── access.log
│       │   └── error.log 
│       └── ssl
├── docker-compose.yml  # 核心編排文件
└── docker_django  # 常規Django項目目錄
    ├── db.sqlite3
    ├── docker_django  # Django項目配置文件
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── Dockerfile  # 構建Django+Uwsgi鏡像的Dockerfile
    ├── manage.py
    ├── media  # 用戶上傳的媒體資源與靜態文件
    ├── requirements.txt  # Django項目依賴文件
    ├── start.sh  # 啓動Django+Uwsgi容器後要執行的腳本
    ├── static  # 項目所使用到的靜態文件
    └── uwsgi.ini  # uwsgi配置文件

部署開始

第一步:編寫Web (Django+Uwsgi)鏡像和容器所需文件
FROM FROM python:3.7.2

MAINTAINER Fat Puffer <dcpuffer@outlook.com>

# 設置 python 環境變量
ENV PYTHONUNBUFFERED 1
 
# 在容器內/var/www/html/下創建docker_django文件夾
RUN mkdir -p /var/www/html/docker_django
 
# 設置容器內工作目錄
WORKDIR /var/www/html/docker_django
 
# 將當前目錄文件加入到容器工作目錄中(. 表示當前宿主機目錄)
ADD . /var/www/html/docker_django
 
# 更新pip版本
RUN /usr/local/bin/python3 -m pip3 install --upgrade pip

# 利用 pip3 安裝依賴
RUN pip3 install -r requirements.txt -i https://pypi.douban.com/simple

# Windows環境下編寫的start.sh每行命令結尾有多餘的\r字符,需移除。
RUN sed -i 's/\r//' ./start.sh
 
# 設置start.sh文件可執行權限
RUN chmod +x ./start.sh
  • start.sh腳本
 #!/bin/bash
 # 從第一行到最後一行分別表示:
 # 1. 收集靜態文件到根目錄,
 # 2. 生成數據庫可執行文件,
 # 3. 根據數據庫可執行文件來修改數據庫
 # 4. 用 uwsgi啓動 django 服務
 python3 manage.py collectstatic --noinput &&
 python3 manage.py makemigrations &&
 python3 manage.py collectstatic &&
 python3 manage.py migrate &&
 uwsgi --ini /var/www/html/docker_project/docker_django/uwsgi.ini
  • uwsgi.ini文件
[uwsgi]

; 使用nginx連接時使用
socket = 0.0.0.0:8000

; 直接做web服務器使用,指定要監聽的ip和端口號,即我們運行項目時的ip和端口
; http = 0.0.0.0:8000

; 項目目錄
chdir = /var/www/html/docker_project/docker_django

; 項目中的wsgi.py文件的目錄
module = docker_django.wsgi:application

; 靜態文件映射,測試uwsgi配置時爲了能夠訪問到靜態資源,所以加上這個配置。在使用nginx時,需要註銷掉這個配置,改用nginx來代理靜態資源訪>; 可使用 python manage.py collectstatic
static-map=/static=/var/www/html/docker_project/docker_django/static

; 指定啓動的工作進程數
processes = 4

; 指定每個進程中的線程數
threads = 2

; 指定在工作進程中存在一個主進程
master = True

; 服務停止時自動移除unix Socket和pid文件
vacuum = True

; 保存啓動之後主進程的進程號
pidfile = uwsgi.pid

; 設置uwsgi後臺運行,運行信息保存在uwsgi.log
; daemonize = uwsgi.log

; 單個日誌的大小
buffer-size=32768

; 設置每個工作進程處理請求的上限,達到上限時,將回收(重啓)該進程。可以預防內存泄漏
max-requests=5000
第二步:編寫Nginx鏡像和容器所需文件
  • xxx/compose/nginx/Dockerfile
FROM nginx:latest

# 鏡像維護者
MAINTAINER Fat Puffer <dcpuffer@outlook.com>

# 將項目nginx配置文件拷貝到nginx配置文件目錄下
ADD nginx.conf /etc/nginx/conf.d/

# sed是一個Linux編輯器吧,此命令的作用是查找文件/etc/nginx/nginx.conf中包含user的行,並將此行的nginx替換成root
RUN sed -i '/user/{s/nginx/root/}' /etc/nginx/nginx.conf

# 刪除原有配置文件,創建靜態資源文件夾和ssl證書保存文件夾
RUN rm /etc/nginx/conf.d/default.conf \
 && mkdir -p /usr/share/nginx/html/static \
 && mkdir -p /usr/share/nginx/html/media \
 && mkdir -p /usr/share/nginx/ssl

CMD ["nginx", "-g", "daemon off;"]
  • xxx/compose/nginx/nginx.conf
# nginx配置文件。
upstream django {
    ip_hash;  # 負載策略
    server web:8000; # Django+uwsgi容器所在IP地址及開放端口,非宿主機外網IP
}
 
server {
    listen 80; # 監聽80端口
    server_name localhost; # 可以是nginx容器所在ip地址或127.0.0.1,不能寫宿主機外網ip地址
    location /static {
        alias /usr/share/nginx/html/static; # 靜態資源路徑
    }
 
    location /media {
        alias /usr/share/nginx/html/media; # 媒體資源,用戶上傳文件路徑
    }
 
    location / {
        include /etc/nginx/uwsgi_params;
        uwsgi_pass django;
        uwsgi_read_timeout 600;
        uwsgi_connect_timeout 600;
        uwsgi_send_timeout 600;
        
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP  $remote_addr;
        # proxy_pass http://django;    
    }
}
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
第三步:編寫MySQL鏡像和容器所需文件
  • xxx/compose/mysql/my.cnf
[mysqld]
user=mysql
default-storage-engine=INNODB
character-set-server=utf8

# 端口與docker-compose裏映射端口保持一致
port=3306

#一定要註釋掉,mysql所在容器和django所在容器不同IP
# bind-address=localhost

basedir=/usr
datadir=/var/lib/mysql
tmpdir=/tmp
pid-file=/var/run/mysqld/mysqld.pid
socket=/var/run/mysqld/mysqld.sock

# 這個參數是禁止域名解析的,遠程訪問推薦開啓skip_name_resolve
skip-name-resolve

[client]
port = 3306
default-character-set=utf8

[mysql]
no-auto-rehash
  • xxx/compose/mysql/init.sql
# 注意這裏的數據庫名django_docker和用戶名admin和密碼password必需和docker-compose.yml裏與MySQL相關的環境變量保持一致

GRANT ALL PRIVILEGES ON docker_django.* TO admin@"%" IDENTIFIED BY "password@";
FLUSH PRIVILEGES;
第四步:編寫docker-compose.yml文件

docker-compose.yml的核心內容如下。我們定義了2個數據卷,用於掛載各個容器內動態生成的數據,比如MySQL的存儲數據,和django容器中用戶上傳的媒體資源與文件。這樣即使刪除容器,容器內產生的數據也不會丟失。我們還編排了3項容器服務,別名分別爲mysql, nginx和web,接下來我們將依次看看各個容器的Dockerfile和配置文件。

version: "3"

volumes: # 自定義數據卷,默認位於宿主機/var/lib/docker/volumes內
  docker_django_mysql_vol: # 定義數據卷同步容器內mysql數據
  docker_django_media_vol: # 定義數據卷同步media文件夾數據

services:
  db-mysql:
    image: mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=password@123  # root用戶數據庫密碼
      - MYSQL_DATABASE=docker_django  # 數據庫名稱
      - MYSQL_USER=admin  # 數據庫用戶名
      - MYSQL_PASSWORD=password@  # 創建的admin用戶密碼

    volumes:  
      - docker_django_mysql_vol:/var/lib/mysql:rw  # 掛載數據庫數據, 可讀可寫
      - ./compose/mysql/conf/my.cnf:/etc/mysql/my.cnf  # 掛載配置文件
      -v /etc/localtime:/etc/localtime:ro
      - ./compose/mysql/init:/docker-entrypoint-initdb.d/  # 掛載數據初始化sql腳本
    ports:
      - "3306:3306" # 與配置文件保持一致
    restart: always
 
  web:
    build: ./docker_django  # 使用docker_django目錄下的Dockerfile
    expose:
      - "8000"
    volumes:
      - ./docker_django:/var/www/html/docker_django  # 掛載項目代碼
      - docker_django_media_vol:/var/www/html/docker_django/media  # 以數據卷掛載容器內用戶上傳媒體文件
      - ./compose/uwsgi:/tmp  # 掛載uwsgi日誌
    links:
      - db-mysql
    depends_on:  # 依賴關係
      - db-mysql
    environment:
      - DEBUG=False
    restart: always
    tty: true
    stdin_open: true

  nginx:
    build: ./compose/nginx
    ports:
      - "80:80"
      - "443:443"
    expose:
      - "80"
    volumes:  # 可以在此處指定日誌目錄,將docker容器內的日誌路徑映射到本地
      - ./docker_django/static:/usr/share/nginx/html/static  # 掛載靜態文件
      - ./compose/nginx/ssl:/usr/share/nginx/ssl  # 掛載ssl證書目錄
	  - ./compose/nginx/nginx.log:/var/log/nginx  # 掛載日誌
      - docker_django_media_vol:/usr/share/nginx/html/media  # 掛載用戶上傳媒體文件
    links:
      - web
    depends_on:
      - web
    restart: always
第五步:修改Django項目settings.py
# 生產環境設置 Debug = False
Debug = False
 
# 設置ALLOWED HOSTS
ALLOWED_HOSTS = ['localhost', '10.10.101.238']
 
# 設置STATIC ROOT 和 STATIC URL
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = "/static/"
 
# 設置MEDIA ROOT 和 MEDIA URL
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = "/media/"
 
# 設置數據庫。這裏用戶名和密碼必需和docker-compose.yml裏mysql環境變量保持一致
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'docker_django',  # 數據庫名
        'USER':'admin',  # 你設置的用戶名 - 非root用戶
        'PASSWORD':'password@',  # 換成你自己密碼
        'HOST': 'db-mysql',  # 注意:這裏使用的是db別名,docker會自動解析成ip
        'PORT':'3306',  # 端口
    }
}
第六步:修改項目配置文件下的__init__.py
  • 由於要使用mysql作爲是數據庫後臺,所以需要在該文件下增加以下內容
import pymysql

pymysql.install_as_MySQLdb()
  • 安裝pymysqlpip3 install pymysql
  • 別忘記重新導出環境依賴包pip3 freeze > requirements.txt
第七步:使用docker-compose 構建鏡像並啓動容器組服務
# 進入docker-compose.yml所在文件夾,輸入以下命令構建鏡像
sudo docker-compose build

# 查看已生成的鏡像
sudo docker images

# 啓動容器組服務 -d 後臺啓動
sudo docker-compose up -d

# 查看運行中的容器
sudo docker ps

# 停止容器組命令:
sudo docker-compose down

# 啓動某個容器
sudo docker-compose start 容器名

# 停止某個容器
sudo docker-compose stop 容器名

在這裏插入圖片描述

第八步:進入web容器內執行Django命令並啓動uwsgi服務器
sudo docker exec -it docker_project_web_1 /bin/bash start.sh
第九步:瀏覽器訪問
http://10.10.102.238/admin

在這裏插入圖片描述

項目代碼

GitHub傳送門:https://github.com/FatPuffer/docker-compose-deploy-django

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