- 上圖是上一篇章,我們手動構建四個容器,分別對應Nginx,Django Uwsgi,Redis,MySQL器,部署一個web項目。然而在實際生產環境中,我們定義數量較多的docker容器,並且伴隨容器之間關系比較復雜。一個個去構建容器,不僅效率低下,而且容器出錯。而docker-compose可以定義容器集群的編排
1.docker-compose什么鬼
-
它用來定義和運行復雜應用Docker工具。使用docker-compose后不再需要使用shell腳本來逐一創建和啟動容器,還可以通過docker-compose.yml 文件構建和管理復雜容器組合
-
下載docker-compose
# 下載並安裝docker-compose curl -L https://github.com/docker/compose/releases/download/1.14.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose # 設置權限 chmod +x /usr/local/bin/docker-compose # 檢查 docker-compose -version
2.docker-compose組合容器
-
通過docker-compose編排並啟動4個容器,這更接近於實際生成環境下的部署。
1.Django + Uwsgi容器:應用程序,后端
2.MySQL容器:數據庫服務
3.Redis容器:緩存服務
4.Nginx容器:反向代理,處理靜態資源
這四個容器的依賴關系是:Django+Uwsgi 容器依賴 Redis 容器和 MySQL 容器,Nginx 容器依賴Django+Uwsgi容器。這四個容器別名及通信端口如下圖所示:
3.Docker-compose部署Django項目布局樹形圖
-
在根目錄新建一個文件夾build_project,用於項目構建,根目錄下創建項目目錄,這樣不同django項目可以共享compose文件。結構目錄如下
/build_project/ ├── compose# 存放各容器服務Dockerfile配置文件 │ ├── mysql │ │ ├── conf │ │ │ └── my.cnf# mysql配置文件 │ │ ├── init │ │ │ └── init.sql# mysql初始化啟動腳本 │ │ └── sqldata# sql數據 │ │ └── west_coast.sql │ ├── nginx │ │ ├── Dockerfile# 構建nginx鏡像的dockerfile │ │ ├── log# 掛載保存nginx容器內日志 │ │ ├── nginx.conf# nginx配置文件 │ │ ├── phone.tar.gz# vue靜態打包文件手機端 │ │ └── web.tar.gz# vue靜態打包文件pc端 │ ├── redis │ │ └── redis.conf# redis配置文件 │ └── uwsgi# 掛載保存django+uwsgi容器內uwsgi日志 ├── docker-compose.yml# 部署編排文件 └── west_coast__company_project# 項目目錄 ├── app# 存在項目app ├── Dockerfile# # 構建Django+Uwsgi鏡像的dockerfile ├── logs# 項目日志 ├── manage.py ├── pip.conf# pypi源設置。加速pip install ├── requirements.txt# django項目依賴 ├── run.sh# 啟動Django+Uwsgi 腳本 ├── static# 靜態文件 ├── uwsgi.ini# uwsgi配置 ├── uwsgi.log └── west_coast__company_project# Django項目配置文件 ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py
4.基礎鏡像下載
nginx: docker pull nginx
redis: docker pull redis:3.2
mysql: docker pull mysql:5.6
python3: docker pull python:3.6
5.編寫Dockerfile
-
通過docker-compose.yml,編排了4項容器服務,別名分別為redis, db, nginx和web:
version: "3" volumes: # 自定義數據卷,位於宿主機/var/lib/docker/volumes內 myproject_db_vol: # 定義數據卷同步容器內mysql數據 myproject_redis_vol: # 定義數據卷同步redis容器內數據 services: redis: image: redis:3.2 volumes: - myproject_redis_vol:/data #給redis數據備份 - ./compose/redis/redis.conf:/etc/redis/redis.conf # 掛載redis配置文件 expose: - "6379" restart: always # always表容器運行發生錯誤時一直重啟 db: image: mysql:5.7 environment: - MYSQL_ROOT_PASSWORD=123456 # 數據庫密碼 - MYSQL_DATABASE=west_coast # 數據庫名稱 - MYSQL_USER=xujunkai # 數據庫用戶名 - MYSQL_PASSWORD=123456 # 用戶密碼 volumes: - myproject_db_vol:/var/lib/mysql:rw # 掛載數據庫數據, 可讀可寫 - ./compose/mysql/sqldata:/opt:rw - ./compose/mysql/conf/my.cnf:/etc/mysql/my.cnf # 掛載配置文件 - ./compose/mysql/init:/docker-entrypoint-initdb.d/ # 掛載數據初始化sql腳本 ports: - "3306:3306" # 與配置文件保持一致,映射端口 restart: always web: build: ./west_coast__company_project # 使用west_coast__company_project目錄下的Dockerfile ports: - "9000:9000" expose: - "9000" volumes: - ./west_coast__company_project:/var/api/west_coast__company_project # 掛載項目代碼 - ./compose/uwsgi:/tmp # 掛載uwsgi日志 links: - db - redis depends_on: # 依賴關系 - db - redis environment: - DEBUG=False restart: always tty: true stdin_open: true nginx: build: ./compose/nginx ports: - "80:80" - "8000:8000" expose: - "80" - "8000" volumes: - ./compose/nginx/log:/var/log/nginx # 掛載日志 links: - web depends_on: - web restart: always
6.編寫web鏡像
-
構建west_coast__company_project/Dockerfile
# 建立 python3.6 環境 FROM python:3.6 MAINTAINER xujunkai<xujunkaipy@163.com> # 設置 python 環境變量 ENV PYTHONUNBUFFERED 1 COPY pip.conf /root/.pip/pip.conf # 容器內創建項目目錄 RUN mkdir -p /opt/west_coast__company_project WORKDIR /opt/west_coast__company_project # 將當前目錄下文件 放入容器指定目錄 ADD . /opt/west_coast__company_project # 更新pip RUN /usr/local/bin/python -m pip install --upgrade pip # 安裝依賴 RUN pip3 install -r requirements.txt # 啟動項目腳本 增加執行權限 RUN chmod +x ./run.sh
-
run.sh
#!/bin/bash # 生成數據庫可執行文件, # 根據數據庫可執行文件來修改數據庫 # 用 uwsgi啟動 django 服務 python3 manage.py makemigrations && python3 manage.py migrate && uwsgi --ini /opt/west_coast__company_project/uwsgi.ini
-
uwsgi.ini配置
[uwsgi] project=west_coast__company_project base=/opt # the base directory (full path) # 指定項目的絕對路徑的第一層路徑(很重要) chdir = %(base)/%(project) # Django's wsgi file # 指定項目的 wsgi.py文件 # 寫入相對路徑即可,這個參數是以chdir參數為相對路徑 module = %(project).wsgi:application master = true processes = 2 socket = 0.0.0.0:9000 vacuum = true max-requests = 5000 pidfile=/tmp/%(project)-master.pid daemonize=/tmp/%(project)-uwsgi.log #設置一個請求的超時時間(秒),如果一個請求超過了這個時間,則請求被丟棄 harakiri = 60 post buffering = 8192 buffer-size= 65535 #當一個請求被harakiri殺掉會,會輸出一條日志 harakiri-verbose = true #開啟內存使用情況報告 memory-report = true #設置平滑的重啟(直到處理完接收到的請求)的長等待時間(秒) reload-mercy = 10 #設置工作進程使用虛擬內存超過N MB就回收重啟 reload-on-as= 1024 python-autoreload=1
7.編寫Nginx鏡像
-
Nginx鏡像使用Dockerfile如下所述:
FROM nginx:latest # 刪除原有配置文件 RUN rm /etc/nginx/conf.d/default.conf # 靜態文件拷貝容器,並解壓 ADD phone.tar.gz /opt/ ADD web.tar.gz /opt/ # 添加新配置文件 ADD ./nginx.conf /etc/nginx/conf.d/ # 關閉守護模式 CMD ["nginx","-g","daemon off;"]
-
nginx.conf
server { listen 80 default_server; listen [::]:80 default_server; server_name localhost; location / { root /opt/web/dist; { root /opt/phone/dist; } index index.html; try_files $uri $uri/ /index.html; } location ~.*(jpg|jpeg|png|gif|ico|css|js)$ { root /opt/web/dist; { root /opt/phone/dist; } expires 365d; } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } } server { listen 8000; server_name web; location / { # 指定Docker-compose web服務的端口。反向代理 uwsgi_pass web:9000; uwsgi_read_timeout 600; uwsgi_connect_timeout 600; uwsgi_send_timeout 600; include uwsgi_params; 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; } } access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log warn; server_tokens off;
8.編寫MySQL容器
-
之前我們已經從官網拉取鏡像,用官網鏡像即可,只需更改MySQL相關配置,
# compose/mysql/conf/my.cnf [mysqld] user=mysql default-storage-engine=INNODB character-set-server=utf8 port = 3306 # 這里端口於docker-compose里映射端口保持一致 #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 default-character-set=utf8
-
當然我們需要設置啟動腳本命令。這里給docker-compose.yml里設置的MySQL的環境變量要一致。
GRANT ALL PRIVILEGES ON west_coast.* TO xujunkai@"%" IDENTIFIED BY "123456"; FLUSH PRIVILEGES;
9.編寫redis容器配置
-
這里使用默認配置
# compose/redis/redis.conf 注釋掉 bind 127.0.0.1 即可
10.修改django項目settings.py
-
在這里修改mysql,redis服務連接配置
# 生產環境設置 Debug = False Debug = False ALLOWED_HOSTS = ["*"] #或是你的服務的IP # 設置數據庫。這里用戶名和密碼必需和docker-compose.yml里mysql環境變量保持一致 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'myproject', # 數據庫名 'USER':'xujunkai', # 你設置的用戶名 - 非root用戶 'PASSWORD':'123456', # # 換成你自己密碼 'HOST': 'db', # 注意:這里使用的是db別名,docker會自動解析成ip 'PORT':'3306', # 端口 } } # 設置redis緩存。這里密碼為redis.conf里設置的密碼 CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://redis:6379/1", #這里直接使用redis別名作為host ip地址 "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", # "PASSWORD": "yourpassword", # 換成你自己密碼 }, } }
11.使用docker-compose構建鏡像並啟動容器組
# 在docker-compose.yml所在文件夾下。輸入指令
sudo docker-compose build
# 查看已生成的鏡像
sudo docker images
# 啟動容器組服務
sudo docker-compose up
# 查看運行中的容器
sudo docker ps
# 重新構建
docker-compose up --build -d
- 可以看到運行容器
12.進入web容器執行啟動腳本
sudo docker exec -it {web容器id} /bin/bash start.sh
13.數據導入
- 這里我進入容器進行數據導入,當然也可以通過構建mysql的dockerfile去執行shell命令導入
#進入mysql 容器
docker exec -it {mysql容器id} /bin/bash
#登陸mysql
mysql -uroot -p你的密碼
# use到指定項目的庫
use west_coast
# 數據導入
source /opt/west_coast.sql
- 最終訪問ip就可以啦!
---問題存在:
-
連接數據庫粗在‘performance_schema.session_variables’ doesn’t exist問題。可進入構建mysql容器
docker exec -it {mysql容器id} /bin/bash # 執行命令 mysql_upgrade -u root -p --force # 輸入密碼,然后重啟mysql服務即可