Django-Docker容器化部署:Django-Docker-MySQL部署
上一章我們成功搭建了容器化的 Django 專案,用到的資料庫為預設的 Sqlite。Sqlite 雖然簡單易用,但是線上部署時通常會選擇更高效、更可靠的資料庫,比如 MySQL。
本章將在上一章的基礎上,修改並構建 Docker + Django + MySQL 的容器專案。
Docker-compose
我們在學習面向物件的程式語言時,會想方設法把功能獨立的模組給獨立出來,方便複用和維護。
容器也是一樣的。雖然理論上可以把所有元件塞到同一個容器中去,但更好的做法是各模組在單獨容器中,只要保持必要的通訊就可以了。
也就是說,本教程中現在需要兩個容器了:
- 名稱叫 app 的 Django 容器
- 名稱叫 db 的 MySQL 容器
所以如何構建 MySQL 映象?別擔心,這麼常用的映象官方已經幫你構建好了,只需要把它從倉庫拉取到本地就可以了。
修改上一章寫的 docker-compose.yml
,增加 MySQL 容器:
version: "3"
services:
app:
restart: always
build: .
command: bash -c "python3 manage.py migrate && python3 manage.py runserver 0.0.0.0:8000"
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
db:
image: mysql:5.7
volumes:
- "./mysql:/var/lib/mysql"
ports:
- "3306:3306"
restart: always
environment:
- MYSQL_ROOT_PASSWORD=mypassword
- MYSQL_DATABASE=django_app
複製程式碼
app
容器的 command
指令做了修改,讓其在執行前先執行資料遷移;新增了配置 depends_on
,意思是此容器需要等待 db
容器啟動完畢才能夠啟動。
分析一下新新增的 db
容器:
-
image
:從倉庫拉取 MySQL 5.7 。最新版本為 MySQL 8,不過很坑的是新版本修改了使用者登入的驗證方法,導致很容易出現無法通過身份驗證的問題。教程為了簡單起見選用 5.7 版本。後期會在教程示例程式碼中新增mysql-8分支並給出操作方法,有興趣的讀者可以檢視。 -
volumes
:定義卷(這裡實際是掛載),上一章已經講過了,它實現了宿主機和容器目錄的對映。功能是將容器中的 MySQL 資料對映到宿主機。 -
ports
:MySQL 預設通訊埠為 3306 。 -
environment
:定義容器的環境變數,設定了 MySQL 的 root 使用者的密碼、資料庫的名稱。
這裡為什麼要用卷?就讓資料在容器中、保持隔離不好嗎?把資料儲存在容器中,理論上確實是可以的,但有一個致命的問題,即資料和容器的生命週期掛鉤了:萬一哪天手賤把容器給刪了,連同裡面的資料隨風而逝,你就是全公司那個刪庫跑路的傳奇人物了。要知道容器的生命週期可能會非常短暫,刪除指令也相當順滑(docker-compose down
)。將資料對映到宿主機,容器即使被刪除掉,但資料還是安全的躺在你的伺服器中的。換句話說,容器內部非常適合執行無狀態的應用;涉及到如資料之類有狀態的東西,一定要謹慎思考。
Dockerfile
接下來修改 Dockerfile
:
FROM python:3.7
ENV PYTHONUNBUFFERED 1
# 新增這兩行
RUN apt-get update
RUN apt-get install python3-dev default-libmysqlclient-dev -y
RUN mkdir /code
WORKDIR /code
RUN pip install pip -U
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
複製程式碼
增加的兩行程式碼在系統中安裝了 MySQL 的聯結器,具體解釋見官方檔案。
其他配置
修改 requirements.txt
,增加 MySQL 驅動:
django==2.2
mysqlclient==1.3.14
複製程式碼
然後還需要修改 django_app/settings.py
,將資料庫設定為 MySQL:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql','NAME': 'django_app','USER': 'root','PASSWORD': 'mypassword','HOST': 'db','PORT': '3306','OPTIONS': {'charset': 'utf8mb4'},}
}
複製程式碼
注意 HOST 填寫的是容器的名稱,即 db 。
這就可以啦。接下來測試。
測試
測試之前,請先確認沒有其他程式佔用了 3306 埠,比如宿主機安裝的 MySQL。
重新生成映象:
$ docker-compose build
複製程式碼
生成並啟動容器:
$ docker-compose up
Creating network "django_app_default" with the default driver
Creating django_app_db_1 ... done
Creating django_app_app_1 ... done
Attaching to django_app_db_1,django_app_app_1
db_1 | 2019-10-06T12:24:57.183860Z 0 [Note] mysqld (mysqld 5.7.27) starting as process 1 ...
...
db_1 | 2019-10-06T12:24:58.120480Z 0 [Note] mysqld: ready for connections.
db_1 | Version: '5.7.27' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
app_1 | Operations to perform:
app_1 | Apply all migrations: admin,auth,contenttypes,sessions
app_1 | Running migrations:
app_1 | Applying contenttypes.0001_initial... OK
...
app_1 | Applying sessions.0001_initial... OK
app_1 | Watching for file changes with StatReloader
app_1 | Performing system checks...
app_1 |
app_1 | System check identified no issues (0 silenced).
app_1 | October 06,2019 - 12:24:58
app_1 | Django version 2.2,using settings 'django_app.settings'
app_1 | Starting development server at http://0.0.0.0:8000/
app_1 | Quit the server with CONTROL-C.
複製程式碼
開啟瀏覽器訪問 127.0.0.1:8000
,又能看到 Django 小火箭啦。
**注意:**第一次啟動容器時可能會出現無法連線 MySQL 的錯誤,這是由於雖然 db 容器已經啟動,但初始化並未完成;重新啟動容器之後就可以正常工作了。若多次啟動都無法正常工作,那就是別的原因了,好好檢查吧。
總結
本章加入了 MySQL 容器,並實現了多容器協同工作。
下一章將實現正式部署的 Docker + Django + MySQL + Nginx + Gunicorn 專案。
- 有疑問請在杜賽的個人網站留言,我會盡快回復。
- 教程示例程式碼:django-docker-tutorial
- 或Email私信我:[email protected]