在上一節(jié)《Docker docker-compose》中我們已經(jīng)將應(yīng)用成功的部署好了,下面再來(lái)介紹一下如何使用 Docker Compose 啟動(dòng)、停止和刪除應(yīng)用,以及獲取應(yīng)用狀態(tài)。并且還會(huì)演示如何使用掛載的卷來(lái)實(shí)現(xiàn)對(duì) Web 前端的更新。
既然應(yīng)用已經(jīng)啟動(dòng),下面看一下如何使其停止。為了實(shí)現(xiàn)這一點(diǎn),將子命令 up 替換成 down 即可。
由于是使用 & 啟動(dòng)的應(yīng)用,因此它運(yùn)行在前臺(tái)。這意味著在終端上會(huì)打印詳細(xì)的輸出,從而可以很好地了解其執(zhí)行過(guò)程。下面介紹一下每一行都代表什么意思。
第 1、2 行開(kāi)始嘗試關(guān)閉兩個(gè)服務(wù),即 Compose 文件中定義的 web-fe 和 redis。由第 3 行可知 stop 指令會(huì)發(fā)送 SIGTERM 信號(hào)。信號(hào)會(huì)被發(fā)送到每個(gè)容器中 PID 為 1 的進(jìn)程。第 4~6 行顯示 Redis 容器接收到信號(hào)后優(yōu)雅地自行關(guān)閉。第 7、8 行表明已成功停止 Redis。第 9 行表明 web-fe 服務(wù)也被成功停止。由第 10 和 11 行可知已停止的服務(wù)被刪除。第 12 行顯示 counter-net 網(wǎng)絡(luò)被刪除,第 13 行顯示 docker-compose up 進(jìn)程退出。
需要特別注意的是,counter-vol 卷并沒(méi)有被刪除,因?yàn)榫響?yīng)該是用于數(shù)據(jù)的長(zhǎng)期持久化存儲(chǔ)的。因此,卷的生命周期是與相應(yīng)的容器完全解耦的。執(zhí)行 docker volume ls 可見(jiàn)該卷依然存在于系統(tǒng)中。寫(xiě)到卷上的所有數(shù)據(jù)都會(huì)保存下來(lái)。
同樣,執(zhí)行 docker-compose up 過(guò)程中拉取或構(gòu)建的鏡像也會(huì)保留在系統(tǒng)中。因此,再次部署該應(yīng)用將更加快捷。
下面繼續(xù)介紹其他幾個(gè) docker-compose 子命令。使用如下命令再次啟動(dòng)應(yīng)用,但是這次在后臺(tái)啟動(dòng)它。
$ docker-compose up -d
Creating network "counterapp_counter-net" with the default driver
Creating counterapp_redis_1 ... done
Creating counterapp_web-fe_1 ... done
這時(shí)會(huì)發(fā)現(xiàn)這次啟動(dòng)要快很多——因?yàn)?counter-vol 卷已經(jīng)存在,而且不需要去拉取和構(gòu)建鏡像。
使用 docker-compose up 命令來(lái)查看應(yīng)用的狀態(tài)。
$ docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------
counterapp_redis_1 docker-entrypoint... Up 6379/tcp
counterapp_web-fe_1 python app.py Up 0.0.0.0:5000->5000/tcp
輸出中會(huì)顯示容器名稱、其中運(yùn)行的 Command、當(dāng)前狀態(tài)以及其監(jiān)聽(tīng)的網(wǎng)絡(luò)端口。
使用 docker-compose top 命令列出各個(gè)服務(wù)(容器)內(nèi)運(yùn)行的進(jìn)程。
$ docker-compose top
counterapp_redis_1
PID USER TIME COMMAND
------------------------------------
843 dockrema 0:00 redis-server
counterapp_web-fe_1
PID USER TIME COMMAND
-------------------------------------------------
928 root 0:00 python app.py
1016 root 0:00 /usr/local/bin/python app.py
其中 PID 編號(hào)是在 Docker 主機(jī)上(而不是容器內(nèi))的進(jìn)程 ID。
docker-compose stop 命令會(huì)停止應(yīng)用,但并不會(huì)刪除資源。然后再次運(yùn)行 docker-compose ps 查看狀態(tài)。
$ docker-compose stop
Stopping counterapp_web-fe_1 ... done
Stopping counterapp_redis_1 ... done
$ docker-compose ps
Name Command State
---------------------------------------------------------
counterapp_redis_1 docker-entrypoint.sh redis Exit 0
counterapp_web-fe_1 python app.py Exit 0
可以看到,停止 Compose 應(yīng)用并不會(huì)在系統(tǒng)中刪除對(duì)應(yīng)用的定義,而僅將應(yīng)用的容器停止。這一點(diǎn)可以使用 docker container ls -a 命令進(jìn)行驗(yàn)證。
對(duì)于已停止的 Compose 應(yīng)用,可以使用 docker-compose rm 命令來(lái)刪除。這會(huì)刪除應(yīng)用相關(guān)的容器和網(wǎng)絡(luò),但是不會(huì)刪除卷和鏡像。
當(dāng)然,也不會(huì)刪除應(yīng)用源碼(項(xiàng)目目錄下的 app.py、Dockerfile、requirements.txt 和 docker-compose.yml)。
執(zhí)行 docker-compose restart 命令重啟應(yīng)用。
$ docker-compose restart
Restarting counterapp_web-fe_1 ... done
Restarting counterapp_redis_1 ... done
查看執(zhí)行結(jié)果。
$ docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------
counterapp_redis_1 docker-entrypoint... Up 6379/tcp
counterapp_web-fe_1 python app.py Up 0.0.0.0:5000->5000/tcp
使用 docker-compose down 這一個(gè)命令就可以停止和關(guān)閉應(yīng)用。
$ docker-compose down
Stopping counterapp_web-fe_1 ... done
Stopping counterapp_redis_1 ... done
Removing counterapp_web-fe_1 ... done
Removing counterapp_redis_1 ... done
Removing network counterapp_counter-net
應(yīng)用被刪除,僅留下了鏡像、卷和源碼。下面最后一次部署應(yīng)用,然后查看卷的情況。
$ docker compose up -d
Creating network "counterapp_counter-net" with the default driver
Creating counterapp_redis_1 ... done
Creating counterapp_web-fe_1 ... done
如果查看 Compose 文件會(huì)發(fā)現(xiàn),其中定義了一個(gè)名為 counter-vol 的新卷,并將其掛載到 web-fe 服務(wù)的 /code 路徑上。
services:
web-fe:
<Snip>
volumes:
- type: volume
source: counter-vol
target: /code
<Snip>
volumes:
counter-vol:
當(dāng)?shù)谝淮尾渴鹪搼?yīng)用的時(shí)候,Docker Compose 會(huì)檢查是否有同名的卷存在。如果不存在,則會(huì)創(chuàng)建它。也可使用 docker volume ls 命令手動(dòng)查看。
$ docker volume ls
RIVER VOLUME NAME
local counterapp_counter-vol
值得注意的是,Docker Compose 會(huì)在部署服務(wù)之前創(chuàng)建網(wǎng)絡(luò)和卷。這很合理,因?yàn)樗鼈兪枪┓?wù)(容器)使用的底層基礎(chǔ)資源。
如下可見(jiàn),Docker Compose 會(huì)首先創(chuàng)建網(wǎng)絡(luò)和卷(甚至先于構(gòu)建和拉取鏡像)。
$ docker-compose up -d
Creating network "counterapp_counter-net" with the default driver
Creating volume "counterapp_counter-vol" with default driver
Pulling redis (redis:alpine)...
<Snip>
再次研讀 Dockerfile 中關(guān)于 web-fe 服務(wù)的定義,會(huì)看到它將卷 counter-app 掛載到容器的 /code 目錄。
還會(huì)發(fā)現(xiàn),/code 正是應(yīng)用安裝和執(zhí)行的目錄。由此可知,應(yīng)用的代碼是位于 Docker 卷中的,如下圖所示。
這意味著,我們?cè)?Docker 主機(jī)對(duì)卷中文件的修改,會(huì)立刻反應(yīng)到應(yīng)用中。下面驗(yàn)證一下。
具體的驗(yàn)證過(guò)程包含這樣幾個(gè)步驟。首先在項(xiàng)目目錄下編輯 app.py 文件,從而應(yīng)用在瀏覽器中的頁(yè)面會(huì)顯示不同的文本。然后將更新的文件復(fù)制到位于 Docker 主機(jī)的卷中。最后刷新應(yīng)用的 Web 頁(yè)面來(lái)查看更新的內(nèi)容。
因?yàn)椋袑?duì)位于 Docker 主機(jī)上的卷中內(nèi)容的修改都會(huì)立刻反映在容器內(nèi)的卷里。
請(qǐng)使用順手的文本編輯器修改位于項(xiàng)目目錄下的 app.py 文件,這里我們使用的是 vim。
$ vim ~/counter-app/app.py
修改第 22 行位于雙引號(hào)之間的文字。這一行以 "What's up..." 開(kāi)始,可在雙引號(hào)內(nèi)隨意輸入文字并保存。
更新源碼后,將其復(fù)制到 Docker 主機(jī)上相應(yīng)的卷中,也就是復(fù)制到一個(gè)或多個(gè)容器的掛載點(diǎn)(Mount Point)中。
使用 docker volume inspect 命令可以查看卷位于 Docker 主機(jī)的什么位置。
$ docker volume inspect counterapp_counter-vol | grep Mount
"Mountpoint": "/var/lib/docker/volumes/counterapp_counter-vol/_data",
復(fù)制文件后,該文件就會(huì)出現(xiàn)在 web-fe 容器的 /code 中,覆蓋掉容器中原有的 /code/app.py 文件。
$ cp ~/counterapp/app.py \
/var/lib/docker/volumes/counterapp_counter-vol/_data/app.py
現(xiàn)在更新的 app.py 文件已經(jīng)位于容器中了。請(qǐng)?jiān)跒g覽器中通過(guò) Docker 主機(jī)的 IP 和端口 5000 連接到應(yīng)用來(lái)查看更新的內(nèi)容。
更新后的情況如下圖所示。
顯然在生產(chǎn)環(huán)境中不會(huì)這樣做,但是在開(kāi)發(fā)環(huán)境中這確實(shí)很節(jié)省時(shí)間。