Docker的使用筆記
作者:jakieli
一、為什么使用Docker
我們的業(yè)務(wù)需要使用公司內(nèi)部的一個平臺做報表展示,公司內(nèi)部的一個平臺支持的數(shù)據(jù)庫都是正式環(huán)境或者IDC環(huán)境,這使得我們的業(yè)務(wù)邏輯也需要部署到正式環(huán)境或者IDC環(huán)境。自從自研資源上云后,鵝廠內(nèi)部使用IDC資源時不再推薦使用方單獨申請IDC資源,而是推薦使用容器服務(wù)進行資源的申請和使用。具體來說,就是我們需要把我們的業(yè)務(wù)先在測試環(huán)境上使用docker做成鏡像,再把鏡像上傳到鏡像倉庫,再從容器服務(wù)中把我們的鏡像給啟動起來。因此,我們就有了使用docker的訴求。

二、Docker是什么
Docker是一個開源平臺,它允許用戶快速構(gòu)建、測試和部署應(yīng)用程序。Docker通過將軟件及其依賴項打包到輕量級、可移植的容器中來實現(xiàn)這一目標(biāo)。這些容器是獨立的、可執(zhí)行的軟件包,它們包含了運行應(yīng)用程序所需的所有內(nèi)容,包括代碼、運行時、庫、環(huán)境變量和系統(tǒng)工具。
Docker的一個重要特點是它可以屏蔽環(huán)境差異。這意味著,只要應(yīng)用程序及其依賴項被打包到Docker容器中,那么無論應(yīng)用程序運行在哪個環(huán)境中,它的行為都是一致的。這消除了“在我的環(huán)境上可以運行”的問題,并實現(xiàn)了“build once, run everywhere”的目標(biāo)。
Docker的另一個優(yōu)勢是快速部署。由于容器啟動速度非常快,并且只要確保一個容器中的程序正確運行,就可以確信無論在生產(chǎn)環(huán)境部署多少個容器都能正確運行,因此Docker非常適合用于快速部署應(yīng)用程序。
Docker的關(guān)鍵組件包括Dockerfile文件、Docker映像和Docker容器。Dockerfile文件是一個包含命令的腳本,用于組裝Docker映像并定義其中的內(nèi)容。Docker映像是一個只讀的模板,用于創(chuàng)建Docker容器。Docker容器是從Docker映像啟動的運行實例。
Docker被廣泛使用,因為它簡化了應(yīng)用程序的部署過程,并為開發(fā)人員提供了可移植性、一致性和效率。Docker的創(chuàng)新性在于它將程序的所有依賴項一起打包,從而簡化了運行環(huán)境管理的繁瑣步驟。
三、怎么使用Docker
1. Docker的安裝
在不同操作系統(tǒng)上,docker的安裝命令不同,我們這次以Ubuntu系統(tǒng)為例來說明如何安裝docker。下面的各個步驟都是來源于混元大語言模型的返回:
在Ubuntu系統(tǒng)上安裝Docker,你可以按照以下步驟操作:
(1) 更新軟件包索引:
sudo apt-get update(2) 安裝依賴項:
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common(3) 添加Docker官方GPG密鑰:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg(4) 設(shè)置Docker穩(wěn)定版本的存儲庫:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null(5) 更新軟件包索引:
sudo apt-get update(6) 安裝Docker:
sudo apt-get install docker-ce docker-ce-cli containerd.io(7) 驗證Docker是否已成功安裝:
sudo docker --version按照混元大模型給出來的步驟執(zhí)行安裝,問題出現(xiàn)在了第4-6步。環(huán)境中的lsb_release執(zhí)行報錯:
Traceback (most recent call last):
File "/usr/bin/lsb_release", line 25, in <module>
import lsb_release
ModuleNotFoundError: No module named 'lsb_release'這個錯誤解決了半天也沒有搞定,最后通過繞道而搞定。按照道理,第四步的目的是指定當(dāng)前系統(tǒng)的穩(wěn)定docker版本,這里可以通過下面的命令替代:
codename=$(cat /etc/os-release | grep "VERSION_CODENAME" | cut -d "=" -f 2)把codename的值替換到第4步中的$(lsb_release -cs),再執(zhí)行第6步就能成功了。如果還是執(zhí)行失敗的話,可以新建個文件:/etc/apt/sources.list.d/docker.list,并且把第4步的前半部分,即:
deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu bionic stable寫入到文件中,其中“bionic”就是前面提到的codename。注意,這個命令要寫對,一定要以deb開頭,在stable前一定要有codename值。
2. 生成鏡像
(1) 創(chuàng)建Dockerfile
生成鏡像的第一步是創(chuàng)建一個Dockerfile。在我這里,參考著官方文檔,使用混元平臺生成了一個大致可用的Dockerfile,我跟混元的對話如下(當(dāng)然第一次沒把需求提的這么清楚,經(jīng)過多輪對話我的要求優(yōu)化為):
寫一個Dockerfile,滿足下面的要求:
0、創(chuàng)建一個Ubuntu鏡像
1、在docker中安裝python3
2、使用requirements.txt安裝依賴
3、把accuracy_recall_for_ehp、cos_log_download_process和test_rule_checker三個文件夾拷貝到docker中
4、寫一個start.sh,在腳本中分別使用python來啟動accuracy_recall_for_ehp、cos_log_download_process和test_rule_checker三個文件夾中的main.py,每個python腳本的執(zhí)行記錄都寫到日志文件中,且每個程序保持在后臺運行
5、使用start.sh作為docker的啟動命令混元的返回是:
# 0. 創(chuàng)建一個Ubuntu鏡像
FROM ubuntu:latest
# 設(shè)置工作目錄
WORKDIR /app
# 1. 在docker中安裝python3
RUN apt-get update && \
apt-get install -y python3 python3-pip
# 2. 使用requirements.txt安裝依賴
COPY requirements.txt .
RUN pip3 install -r requirements.txt
# 3. 把accuracy_recall_for_ehp、cos_log_download_process和test_rule_checker三個文件夾拷貝到docker中
COPY accuracy_recall_for_ehp cos_log_download_process test_rule_checker /app/
# 4. 寫一個start.sh,在腳本中分別使用python來啟動accuracy_recall_for_ehp、cos_log_download_process和test_rule_checker三個文件夾中的main.py,每個python腳本的執(zhí)行記錄都寫到日志文件中,且每個程序保持在后臺運行
RUN echo '#!/bin/bash' > start.sh && \
echo 'python3 /app/accuracy_recall_for_ehp/main.py > /app/accuracy_recall_for_ehp.log 2>&1 &' >> start.sh && \
echo 'python3 /app/cos_log_download_process/main.py > /app/cos_log_download_process.log 2>&1 &' >> start.sh && \
echo 'python3 /app/test_rule_checker/main.py > /app/test_rule_checker.log 2>&1 &' >> start.sh && \
chmod +x start.sh
# 5. 使用start.sh作為docker的啟動命令
CMD ["/app/start.sh"]經(jīng)過測試,這個Dockerfile他是可用的。從一個側(cè)面也說明了大語言模型對我們工作效率的提升還是比較有效的。
(2) 鏡像倉庫
在正式創(chuàng)建Docker鏡像前,我們先來說下鏡像倉庫。
① 鏡像倉庫是什么
鏡像倉庫是一種存儲、分發(fā)和檢索軟件鏡像(即Docker鏡像)的集中化服務(wù)。以下是為什么需要使用鏡像倉庫的一些原因:
- 便捷性:鏡像倉庫允許用戶在不構(gòu)建本地鏡像的情況下,快速獲取并運行預(yù)構(gòu)建的鏡像。這樣可以節(jié)省時間和資源,提高開發(fā)效率。
- 版本控制:鏡像倉庫可以幫助用戶跟蹤和回溯軟件的版本歷史,并且可以輕松地將軟件回滾到以前的版本。這對于在生產(chǎn)環(huán)境中進行故障排查和修復(fù)問題時非常有用。
- 安全性:鏡像倉庫可以幫助用戶集中管理和控制對鏡像的訪問權(quán)限。這可以防止未經(jīng)授權(quán)的訪問和潛在的惡意攻擊。
- 協(xié)作:鏡像倉庫支持多人合作開發(fā)同一個項目。通過將鏡像存儲在倉庫中,團隊成員可以輕松地共享和同步軟件鏡像,從而提高團隊協(xié)作效率。
- 可擴展性:鏡像倉庫可以輕松地支持大量用戶和鏡像。這對于大型組織和企業(yè)在全球范圍內(nèi)分發(fā)和部署軟件鏡像非常有用。
綜上所述,鏡像倉庫可以幫助用戶更快速、安全、便捷地管理和分發(fā)軟件鏡像,從而提高開發(fā)效率和團隊協(xié)作水平。
② 常用的鏡像倉庫
常用的Docker倉庫包括以下幾種:
- Docker Hub:Docker官方提供的公共倉庫,包含了大量的官方和社區(qū)維護的鏡像,用戶可以通過docker pul命令從Docker Hub獲取鏡像。
- 私有倉庫:可以在本地或私有網(wǎng)絡(luò)中搭建的私有Docker倉庫,用于存儲和管理自定義的鏡像。常見的私有倉庫包括Docker Registry、Harbor等。
- 第三方倉庫:除了Docker Hub和私有倉庫,還有一些第三方的Docker倉庫,提供了特定領(lǐng)域或特定用途的鏡像。例如,Gogle Cloud Container Registry、AWS Elastic Container Registry等。
- 其他公共倉庫:除了Docker Hub,還有一些其他的公共倉庫,例如Quay.io、Azure Container Registry等,它們提供了各種不同的鏡像和服務(wù)。
這些倉庫為用戶提供了方便、安全、高效的Docker鏡像存儲和分發(fā)解決方案,幫助用戶更好地管理和部署應(yīng)用程序。
(3) 使用Dockerfile創(chuàng)建鏡像
在生成了Dockerfile之后,就是使用Dockerfile來生成鏡像了。如果只是在本地測試,那么使用docker build命令就可以了:
sudo docker build -t my-image .如果我們想要把鏡像存入到鏡像倉庫中,我們在創(chuàng)建鏡像時,就需要使用把鏡像的名字生成的“講究”、漂亮一些。具體來說,如果我們想把鏡像存入到鏡像倉庫中以備后續(xù)在容器服務(wù)中使用的話,我們?yōu)殓R像起名字時要把我們后續(xù)需要使用的鏡像倉庫地址以、個人文件夾寫入到鏡像名字中。建議先創(chuàng)建一個個人的鏡像來做測試。在創(chuàng)建好自己的倉庫地址后,在build鏡像時需要指定倉庫的地址為鏡像的名稱,即:
sudo docker build -t myusername/myimage:latest .其中,latest為倉庫的tag。在創(chuàng)建好鏡像后,可以通過下面的命令來查看鏡像是否創(chuàng)建成功(結(jié)果就不貼了,是否成功一目了然):
sudo docker images3. 啟動鏡像
在創(chuàng)建好鏡像后,可以通過下面的命令來啟動鏡像:
sudo docker run -d -p 80:80 --name test-container myusername/myimage其中test-container為鏡像啟動后的容器名稱。在啟動后,可以通過下面的命令來判斷當(dāng)前容器的運行情況:
sudo docker ps -a返回的格式如下:

建議使用ps -a而不是ps,使用ps -a能夠看到全量的包括歷史上運行已經(jīng)停止了的容器的情況。
(1) 容器運行狀態(tài)
上面提到了使用ps -a命令能看到容器當(dāng)前的運行情況,其中STATUS這一列說明了不同容器當(dāng)前的運行狀態(tài)。STATUS可能的值包括:Up、Exited、Created、Restarting、Removing和Dead。這些值的具體含義如下:
- Up: 容器正在運行。
- Exited: 容器已退出,通常表示容器內(nèi)的主進程已完成并正常退出。
- Created: 容器已創(chuàng)建,但尚未啟動。
- Restarting: 容器正在重啟。
- Removing: 容器正在被刪除。
- Dead: 容器已死亡,通常表示容器內(nèi)的主進程已崩潰或被終止。
① inspect命令
上面的值可能會因為Docker版本和操作系統(tǒng)的不同而有所不同。要獲取更詳細的信息,你可以使用docker inspect命令查看容器的詳細信息。例如:
docker inspect 9c436ea546b9inspect命令的返回值是個json文件,包含對象的所有屬性和配置,一些常見的字段包括:“Id”、“Name”、“State”、“Mounts”、“NetworkSettings”等值。這里就不展開說明,感興趣的小伙伴們可以自己試試。
② Exited原因解析
繼續(xù)說回STATUS中的Exited狀態(tài),這個狀態(tài)的不同值能反應(yīng)容器退出的原因,當(dāng)Docker ps命令的STATUS列顯示為Exited時,表示容器已經(jīng)退出。Exited后面的數(shù)字表示容器退出時的狀態(tài)碼。狀態(tài)碼0表示容器正常退出,而非0的狀態(tài)碼表示容器異常退出。
非0的狀態(tài)碼通常表示容器在執(zhí)行過程中遇到了錯誤,以下是一些常見的非0狀態(tài)碼及其含義:
- 1:一般性未知錯誤
- 2:不適用的shell或者語法錯誤
- 126:命令不可執(zhí)行
- 127:未找到命令
- 128:無效的退出參數(shù)
- 128+n:通過信號n終止的程序
- 130:通過Ctrl+C終止的程序
- 255:退出狀態(tài)碼超出有效范圍
需要注意的是,這些狀態(tài)碼并不是唯一的,具體的狀態(tài)碼可能會因應(yīng)用程序的不同而有所不同。
③ logs命令
在實際使用中,建議查看容器的日志以獲取更多關(guān)于錯誤的詳細信息。如果容器運行起來后就處于Exited狀態(tài),我們除了可以通過inspect命令來查看當(dāng)前退出可能的原因外,我們也可以通過docker logs命令來查看容器運行起來時的日志,具體的命令如下:
sudo docker logs 9c436ea546b9其中“9c436ea546b9”為Container_Id。在實際應(yīng)用中,我使用logs命令發(fā)現(xiàn)了我的進程異常退出的原因:
ubuntu@VM-77-147-ubuntu:~$ sudo docker logs 5ade7c784050
start.sh: line 7: ture: command not found腳本寫錯了,把true寫成了ture(這是在混元返回的基礎(chǔ)上自己寫的少量代碼之一,這也說明了人沒那么靠譜?)。LOL。
另外,建議在啟動腳本中,啟動應(yīng)用時,以nohup啟動并將程序的運行日志重定向到文件中。如果腳本中只是啟動一個守護進程,可以在啟動腳本后面增加一個循環(huán)語句或者wait命令,讓鏡像能持續(xù)的運行。
4. 進入容器
可以使用下面的命令進入到容器中:
sudo docker exec -it “CONTAINER ID” /bin/sh其中CONTAINER ID為上面docker ps命令返回的第一列。進入到容器后,可以像在本地的系統(tǒng)一樣進行調(diào)試,可以通過啟動腳本或者其他命令來查看我們想要執(zhí)行的命令是否正確。
5. 關(guān)閉容器
一般來說,在本地調(diào)試時,可以通過下面的命令來進行關(guān)閉容器:
sudo docker stop “CONTAINER ID”其中CONTAINER ID為上面docker ps命令返回的第一列。在使用stop命令后,可以再次調(diào)用ps -a命令查看當(dāng)前的docker進程情況
6. 推送鏡像
在本地測試通過后,可以通過下面的命令將生成的鏡像推送到鏡像倉庫中:
sudo docker push myusername/myimage:latest這時在3.2.3中提到的-t的創(chuàng)建鏡像時指定名稱就起作用了,在這里指定好鏡像的命令,進行推送。推送成功后,倉庫中就能見到myusername目錄下的標(biāo)簽是latest的鏡像了。
7. 更新鏡像
在測試的過程中遇到了一些環(huán)境問題(這里舉例說明如何更新鏡像,后來環(huán)境問題通過其他方式解決了),比如我們需要使用Python 3.12,而現(xiàn)在Python的官網(wǎng)上并未正式的支持Python3.12,我們不能通過apt-install的方式進行安裝,并且使用下面的命令在執(zhí)行時也失敗了:
sudo add-apt-repository ppa:deadsnakes/ppappa安裝失敗。花了一些功夫沒有解決掉。這時候想到了一個可以繞道的辦法,像在本地安裝Python3.12這樣,下載Python3.12的安裝文件夾,把這個文件夾拷貝到鏡像中,使用3.4中提到的方法進入到容器中,再進入到Python3.12的路徑下通過./configure,mak -j和make altintall的方式進行安裝。安裝成功后的結(jié)果:

這時退出容器,通過docker的commit方法把剛才的操作給存起來,我們從docker --help能看到docker commit的釋義:
commit Create a new image from a container's changes從這個能看出來,commit的作用是把現(xiàn)在容器中的變化給存儲起來。具體的命令是:
sudo docker commit 10074a786927 myusername/myimage:v2其中“10074a786927”是前面提到的“CONTAINER ID”。提交成功后,再push到鏡像倉庫中。
8. 刪除容器
在3.3中提到了如何啟動容器,在3.4中提到了如何進入到容器中。除了這兩點外,我們還可以使用docker ps -a命令查看當(dāng)前的容器運行情況,在命令的返回結(jié)果中我們能看到容器的名字,如果我們想要刪除某些容器,可以使用下面的命令來刪除:
sudo docker rm my_container其中my_container是容器的名字。
9. 刪除鏡像
在前面3.2.3中我們看到可以使用docker images來查看當(dāng)前的鏡像的狀態(tài),如果我們有些鏡像不用了,需要刪除掉這些鏡像,我們可以使用下面的命令來進行刪除:
sudo docker rmi image_id其中image_id是鏡像的id。
四、鏡像部署
在把鏡像上傳到倉庫后,就可以在自己的容器配置平臺進行鏡像部署了。由于大家的鏡像部署環(huán)境和平臺都不相同,大家可以參考自己的平臺配置指引進行部署,這里就不給大家舉例子了。






















