pip freeze > requirements.txt
命令打包好項目的依賴包列表docker -v
和docker-vompose -v
命令查看是否安裝成功。Docker 允許通過文本格式的配置文件來構建鏡像,默認名稱為 Dockerfile
# 從Docker倉庫中拉去帶有Python3.7的Linux環境
FROM python:3.7
# 設置 python 環境變量
ENV PYTHONUNBUFFERED 1
# 這兩行是在系統鐘安裝了MySQL的連接器
RUN apt-get update
RUN apt-get install python3-dev default-libmysqlclient-dev -y
# 創建 code 文件夾並將其設置為工作目錄
RUN mkdir /code
WORKDIR /code
# 更新 pip
RUN pip install pip -U
# 將 requirements.txt 復制到容器的 code 目錄
ADD requirements.txt /code/
# 安裝庫
RUN pip install -r requirements.txt
# 將當前目錄復制到容器的 code 目錄
ADD . /code/
理解這些Docker指令的關鍵,在於牢記容器內的環境和宿主機是隔離的,核心問題是搞清楚那些操作是針對宿主機,哪些操作是針對容器。
FROM python:3.7
指令從倉庫拉取一個包含 python 3.7 的 Linux 操作系統環境(Linux 版本為 Debian)。
RUN
和 WORKDIR
指令都是針對容器的,功能是在容器裡創建目錄、並將其設置為工作目錄。注意宿主機是沒有這個目錄的。
ADD
指令出現了兩次。ADD requirements.txt /code/
意思是將宿主機當前目錄(即 Dockerfile 所在目錄)的 requirements.txt
文件復制到容器的 /code
目錄中。ADD . /code/
意思是把當前目錄所有內容復制到容器 /code/
目錄,注意中間那個點。
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:
- "3307:3306"
restart: always
environment:
- MYSQL_ROOT_PASSWORD=mypassword
- MYSQL_DATABASE=django_app
networks:
- db_network
nginx:
restart: always
image: nginx:latest
ports:
- "8001: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:
version
代表 docker-compose.yml 的版本,目前最新版為 3,不需要改動它。
從整體上看,我們定義了三個容器,分別是app
、db
、和nginx
,容器之間通過定義的端口進行通訊。定義了兩個網絡,分別是web_network
和db_network
,只有處在同一網絡下的容器才能夠互相通訊。不同網絡之間是隔離的,即便采用同樣的端口,也無法通訊。定義了一個數據卷static-volume
。數據卷非常適合多個容器共享使用同一數據,可以看到app
和nginx
都使用到了它。expose
和ports
都可以暴露容器的端口,區別是expose
僅暴露給其他容器,而ports
會暴露給其他容器和宿主機。
下面具體分析一下:
定義了一個名叫 app
的容器。後面的內容都是 app
容器的相關配置:
restart
:除正常工作外,容器會在任何時候重啟,比如遭遇 bug、進程崩潰、docker 重啟等情況。build
:指定一個包含 Dockerfile 的路徑,並通過此 Dockerfile 來構建容器鏡像。注意那個 "." ,代表當前目錄。command
:容器運行時需要執行的命令。這裡就是我們很熟悉的運行開發服務器了。volumes
:卷,這是個很重要的概念。前面說過容器是和宿主機完全隔離的,但是有些時候又需要將其連通;比如我們開發的 Django 項目代碼常常會更新,並且更新時還依賴如 Git 之類的程序,在容器裡操作就顯得不太方便。所以就有卷,它定義了宿主機和容器之間的映射:"." 表示宿主機的當前目錄,":" 為分隔符,"/code" 表示容器中的目錄。即宿主機當前目錄和容器的 /code 目錄是連通的,宿主機當前目錄的 Django 代碼更新時,容器中的 /code 目錄中的代碼也相應的更新了。這有點兒像是在容器上打了一個洞,某種程度上也是實用性和隔離性的一種妥協。嚴格意義上講,這裡用到的 .:/code
並不是卷,而是叫掛載,它兩是有區別的,只不過 docker-compose 允許將掛載寫到卷的配置中。
expose
:暴露容器的8000端口供其他容器訪問,宿主機和外界無法訪問networks
:能夠訪問web_network
和db_network
depends_on
,意思是此容器需要等待 db
容器啟動完畢才能夠啟動。分析一下 db
容器:
image
:從倉庫拉取 MySQL 5.7 。volumes
:這裡出現的 static-volume
叫卷。它的使用方式像這樣:static-volume:/code/collected_static
,冒號後面還是容器內的目錄,但冒號前的卻不是宿主機目錄、僅僅是卷的名稱而已。從本質上講,數據卷也是實現了宿主機和容器的目錄映射,但是數據卷是由 Docker 進行管理的,你甚至都不需要知道數據卷保存在宿主機的具體位置。相比掛載,數據卷的優點是由於是 Docker 統一管理的,不存在由於權限不夠引發的掛載問題,也不需要在不同服務器指定不同的路徑;缺點是它不太適合單配置文件的映射。和掛載一樣,數據卷的生命周期脫離了容器,刪除容器之後卷還是存在的。下次構建鏡像時,指定卷的名稱就可以繼續使用了。
ports
:MySQL 默認通信端口為 3306 。由於我的機子上已經跑了一個MySQL服務,所以我將容器內的3306端口映射為本機的3307端口。environment
:定義容器的環境變量,設置了 MySQL 的 root 用戶的密碼、數據庫的名稱。network
:只能夠訪問db_network
。添加db
容器後記得的修改Django
裡的數據庫設置。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_app',
'USER': 'root',
'PASSWORD': 'mypassword',
'HOST': 'db',
'PORT': '3306',
'OPTIONS': {'charset': 'utf8mb4'},
}
}
最後分析一下nginx
容器,其他配置與上述兩個大致一樣,值得說一說的是ports
設置,由於我的服務器上部署了其他服務,所以我將nginx端口映射為8001。
Docker 允許用戶給每個容器定義其工作的網絡,只有在相同的網絡之中才能進行通訊。可以看到 nginx
容器處於 web_network
網絡,而 db
容器處於 db_network
網絡,因此它兩是無法通訊的,實際上確實也不需要通訊。而 app
容器同時處於 web_network
和 db_network
網絡,相當於是橋梁,連通了3個容器。
修改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
文件的最後兩行增加mysqlclient
庫和gunicorn
庫。
mysqlclient==2.0.1
gunicorn==19.9.0
再修改Django項目的配置文件
ALLOWED_HOSTS = ['*']
...
STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')
STATIC_URL = '/static/'
運行命令docker-compose build
構造鏡像,再使用docker-compose up
即可啟用服務。
下面附上一下經常用到的命令:
docker-compose down
docker-compose up -d
。docker-compose up -d db
或者docker-compose up -d app
即可啟動db
容器或app
容器。docker exec -it container_id /bin/bash
container_id
如果不知道如何獲取可以通過docker ps
命令查看。Catalog 1 Calculate the year,
Anaconda Download and install
Search the Internet for many a