docker日常使用指南
前言
在對外提供應用程式時,常常碰到執行環境與開發環境不一致的情況,或雖然作業系統一樣,但部署時可能碰到一些系統庫版本不一樣導致執行問題。或對外提供庫時,沒有客戶需要的環境,需要花時間搭建虛擬機器。這一些坑,大部分情況下都能通過docker這個工具幫我們方便的解決。因此學習docker是比較有價值的,同時,docker的使用也非常的簡單,核心的命令比較少。本文對自己使用中用到的一些方式進行總結,一些理解可能不完全正確,更詳細的可以去看官方文件。
1.基礎知識
1.1 docker是什麼
docker是一種容器技術,是一種沙盒技術。它提供了一種非常遍歷的打包機制,這種機制直接打包了應用執行所需要的整個作業系統,從而能夠保證本地環境(開發環境)和生產環境(執行環境)的高度一致。
想了解docker更底層技術的,可以去擴充套件閱讀:Cgroups和Namespace技術
擴充套件閱讀2:daemon和client
1.2 與虛擬機器(VM)的區別
圖的左邊,畫出了虛擬機器的工作原理。其中,名為 Hypervisor 的軟體是虛擬機器最主要的部分。它通過硬體虛擬化功能,模擬出了執行一個作業系統需要的各種硬體,比如 CPU、記憶體、I/O 裝置等等。然後,它在這些虛擬的硬體上安裝了一個新的作業系統,即 Guest OS。
跟真實存在的虛擬機器不同,在使用 Docker 的時候,並沒有一個真正的“Docker 容器”執行在宿主機裡面。Docker 專案幫助使用者啟動的,還是原來的應用程式,只不過在建立這些程式時,Docker 為它們加上了各種各樣的 Namespace 引數。
總而言之:Docker其實共享了宿主機作業系統的核心,因此核心不同的情況下,不能很好的使用docker, 比如windows上想用linux的docker就比較麻煩。Docker相對於VM比較輕量。
1.3 映象與容器
映象與容器的關係有點像類與物件的關係,映象是一個靜態概念,容器是一個執行時概念,容器是映象的例項。通俗的講,映象就是放在硬碟上的,而容器是基於映象跑起來後的東西。
2.安裝
以下步驟預設宿主機為Ubuntu, 其它作業系統可以參考官方文件。
快捷安裝指令碼可通過文末的方式去獲得。
2.1 線上安裝
安裝docker: https://docs.docker.com/engine/install/ubuntu/
sudo apt-get update
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=amd64 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
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
驗證安裝結果:
sudo docker run --rm hello-world
如果宿主機沒有顯示卡或者我們不使用顯示卡,到這一步就結束了安裝,如果要使用顯示卡,還需要進一步安裝 nvidia-docker2:
https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#install-guide
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update && sudo apt-get install -y nvidia-docker2
sudo systemctl restart docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://6kx4zyno.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"],
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
EOF
sudo systemctl restart docker
sudo docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi 可用於驗證能否訪問GPU
2.2 離線安裝
對於宿主機不讓聯網的時候,可以進行離線安裝,也比較方便。
可以參考這篇總結:https://fanfuhan.github.io/2019/11/22/docker_based_use/
3.配置
此節總結幾個常見的可能修改的配置。大部分的配置都可以通過修改/etc/docker/daemon.json
完成,也有例外。
3.1 映象儲存位置設定
docker映象預設佔用根目錄空間,有些時候根目錄空間不足,需要指定其他位置。
此時通過修改/etc/docker/daemon.json完成:
{
"data_root":"myownpath", ### 儲存位置
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
執行命令使配置生效(修改daemon.json後都需要執行):
systemctl daemon-reload
systemctl restart docker
3.2 設定映象源
映象源是來獲取映象的地方,類似pip源,有時候官方源速度不行或根本訪問不了。這時候可以通過設定代理(下節)或設定映象源的方式去改善。
{
"data_root":"myownpath", ### 儲存位置
"registry-mirrors": ["https://6kx4zyno.mirror.aliyuncs.com"], ### 映象源,可以設定多個
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
3.3 代理設定
有些時候需要掛代理去下載程式碼或者映象。代理的設定分為對daemon的設定(主要影響映象下載)和client(影響的是容器執行中的)。
3.3.1 daemon代理
docker是一個C/S架構,我們執行的docker命令實際是一種客戶端,它會發起REST API到daemon(Server端),由daemon去拉取需要的映象。此節設定的就是daemon的代理。幾乎所有的daemon相關設定都可以在daemon.json中完成,但代理是個例外,這個設定需要建立:
/etc/systemd/system/docker.service.d/http-proxy.conf 檔案。
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:80"
Environment="HTTPS_PROXY=https://proxy.example.com:443"
Environment="NO_PROXY=localhost,127.0.0.1,docker-registry.example.com,.corp" ### 設定一些ip跳過代理
3.3.2 容器代理
建立~/.docker/config.json
:
{
"proxies":
{
"default":
{
"httpProxy": "http://192.168.1.12:3128",
"httpsProxy": "http://192.168.1.12:3128",
"noProxy": "*.test.example.com,.example2.com,127.0.0.0/8"
}
}
}
還有一種方式是在Dockerfile或啟動容器的時候設定環境變數:
4.docker的使用
4.1 基礎使用
4.1.1 啟動容器(docker run)
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
docker run有比較多的引數可以設定,完整的參見:https://docs.docker.com/engine/reference/commandline/run/
比較常用的是下面一些:
-d: 後臺執行容器,並返回容器ID;
-i: 以互動模式執行容器,通常與 -t 同時使用;
-P: 隨機埠對映,容器內部埠隨機對映到主機的埠
-p: 指定埠對映,格式為:主機(宿主)埠:容器埠
-t: 為容器重新分配一個偽輸入終端,通常與 -i 同時使用;
--name="nginx-lb": 為容器指定一個名稱;
--cpuset="0-2" or --cpuset="0,1,2": 繫結容器到指定CPU執行;
-m :設定容器使用記憶體最大值;
--net=bridge: 指定容器的網路連線型別,支援 bridge/host/none/container: 四種型別;
--expose=[]: 開放一個埠或一組埠;
--volume , -v: 繫結一個卷
--rm ,退出容器後刪除名字
--restart ,重啟選項,有no/always/on-failure/unless-stopped
--entrypoint ,重寫容器程式的入口
比如我們執行sudo docker run -it --name test ubuntu:16.04
就是以前臺互動形式,以ubuntu:16.04映象啟動一個容器,第一次執行大概會輸出下面這些內容:
Unable to find image 'ubuntu:16.04' locally
16.04: Pulling from library/ubuntu
58690f9b18fc: Pull complete
b51569e7c507: Pull complete
da8ef40b9eca: Pull complete
fb15d46c38dc: Pull complete
Digest: sha256:454054f5bbd571b088db25b662099c6c7b3f0cb78536a2077d54adc48f00cd68
Status: Downloaded newer image for ubuntu:16.04
root@d8324be2d956:/#
也就是第一次執行時,會去拉取映象,然後啟動容器並進入容器終端(也可以通過docker pull
去自己拉取)。進入容器終端,我們就可以像普通終端一樣去安裝工具,編譯程式碼等等了。
而如果以後臺形式執行,則是:
sudo docker run -d --name test ubuntu:16.04
a64fea9800522c5347eaa9feb87ee6c9d67762d81519cc58dbdeec5a8a786066
容器將以後臺形式執行。那麼我們怎麼進入在後臺執行的容器呢?
4.1.2 進入容器
進入容器有2種方式,一種是attach, 一種是
docker exec -it 容器ID/名稱 bash
推薦使用這種。進入後,可輸入exit退出容器終端(只是退出終端,容器並不停止)
4.1.3 停止/刪除/啟動/重啟容器
docker stop 容器ID/名稱
docker rm 容器ID/名稱 ### 當容器發生重名時,我們就得刪除以前的或者把新的改名
docker start 容器ID/名稱
docker restart 容器ID/名稱
還是非常好理解的,基本上就是英文加容器即可。
還有一個docker update
可用於修改docker run時指定的引數。
基本上學會以上操作,就能跑起來一個現場的容器,建立一個隔離的環境了。但僅僅有這些還不夠,因為一旦刪除容器了,我們在容器裡建立的內容都不在了。
4.2 進階使用
4.2.1 持久化(掛載主機硬碟)
啟動時通過-v 主機目錄:容器目錄
選項即可將主機的目錄掛載到容器中。
sudo docker run -d --name test -v /home/xxx:/root/xxx ubuntu:16.04
4.2.2 埠對映
有時候容器內啟動的是一個網路服務,這個服務去監聽一個介面。但它監聽的實際上是容器的內部埠,直接去訪問是不行的,需要對映一個主機埠到容器的埠。
通過-p 主機埠:容器埠
或直接使用主機網路--net=host
docker run -d -p 5000:5000 ubuntu:16.04
docker run -d --net=host ubuntu:16.04
4.2.3 自定義啟動命令
截止到目前,我們都沒有指定過容器啟動後執行什麼命令,其實run的最後一個引數可以用於在啟動容器後執行的命令:
docker run -d --name test ubuntu:16.04 /bin/bash
docker run -d --name test ubuntu:16.04 sh -c “/run.sh && /bin/bash” ### 多條命令拼接
4.2.4 容器狀態/日誌檢視
> docker ps ###列出當前容器(包括已經停止的)
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b8862fc5d600 6e4bffa46d70 "kube-controller-man…" 13 days ago Up 13 days k8s_kube-controller-manager_kube-controller-manager-alg-dev01_kube-system_5af433af822e5ae2fb8825ecf24ac394_11
8ed05c4c9210 ebac1ae204a2 "kube-scheduler --au…" 13 days ago Up 13 days k8s_kube-scheduler_kube-scheduler-alg-dev01_kube-system_8d0b3537ceaac4d2c6bbcb377f490c26_10
f36f7818738b 66f781e54201 "nvidia-device-plugin" 2 weeks ago Up 2 weeks k8s_nvidia-device-plugin-ctr_nvidia-device-plugin-daemonset-d2ct6_kube-system_09c990d8-83a5-4bc5-b8ad-c7bf00079f59_158850
c60e540d83d6 k8s.gcr.io/pause:3.1 "/pause" 2 weeks ago Up 2 weeks
> docker logs [-f等選項] 容器名/ID
4.2.5 對容器修改的提交
很多時候我們基於一個映象啟動了容器,在容器中我們安裝了我們需要的軟體,想在容器刪除後也能夠使用,而不是再裝一次。這時就需要我們能夠提交這個修改。和git類似,也是通過commit
指令去提交。
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
Create a new image from a container's changes
Options:
-a, --author string Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
-c, --change list Apply Dockerfile instruction to the created image
-m, --message string Commit message
-p, --pause Pause container during commit (default true)
例如在我們上述啟動的ubuntu16.04的容器基礎上,我們裝了一些軟體:
docker commit test ubuntu:my16.04
即可生成一個新的映象(注意不是容器)。那麼下次我們啟動時直接用我們生成的這個映象,啟動的容器就包含了我們已經安裝過的環境了。
docker run -d --name test ubuntu:my16.04 /bin/bash
4.3 製作映象(Dockerfile)
4.3.1 Dockerfile編寫
通過在容器內修改再提交的方式雖然能夠生成映象,但手動操作太多,而且不便於自動化。更常用的製作映象的方式是Dockerfile。Dockerfile的基本使用比較簡單,只需要掌握幾個關鍵字:
FROM ubuntu:16.04 ### FROM: 基礎映象
ENV LANG C.UTF-8
ENV TZ=Asia/Shanghai ### 設定容器的時區, ENV用於設定環境變數
RUN mkdir /opt/alg ### RUN: 執行一條命令,多個命令可以通過&&
ADD config/ /opt/alg/config/ ### ADD: 除有COPY的功能外,還能通過URL下載檔案,並且會自動解壓縮
COPY Dependency/ /opt/alg/Dependency/ ### COPY: 拷貝宿主機的檔案或資料夾到映象
COPY bin/ /opt/alg/bin/
COPY models/ /opt/alg/models/
ENTRYPOINT ["/opt/alg/config/start_service.sh" ] ### 設定容器啟動的入口,類似於main函式,在docker run中可以通過 --entrypoint=XXX 覆蓋,如果有這個,那麼docker run時設定的command就會被當作它的引數
除了用ENTRYPOINT去指定入口,還可以用CMD去指定,這2者也可能混用。它們之間的差異參考:https://blog.csdn.net/wuce_bai/article/details/88997725
4.3.2 映象生成
有點類似於我們編譯程式碼,docker提供的生成映象的命令也是build
:
在Dockerfile所在目錄執行:
docker build . -t 映象名:標籤
例如:
docker build . -t myapp:v1
映象生成後,我們就可以使用前文的方式去啟動容器了。
4.4 映象的儲存、載入
映象既可以上傳至官方的DockerHub供人pull,也可以自行搭建私有化的映象倉庫(如harbor)。但對於普通人或日常使用,更多的可能是想將映象儲存成一個可傳輸的檔案,然後放到其他機器,再載入。這個docker也是有對應命令支援的。
docker save [OPTIONS] IMAGE [IMAGE...]
> docker save -o my_ubuntu_v3.tar runoob/ubuntu:v3 ###將映象runoob/ubuntu:v3 儲存成my_ubuntu_v3.tar
docker load
--input , -i : 指定匯入的檔案,代替 STDIN。
--quiet , -q : 精簡輸出資訊。
> docker load -i my_ubuntu_v3.tar
也可以結合其他壓縮軟體的命令,直接儲存出壓縮包:
docker save <myimage>:<tag> | gzip > <myimage>_<tag>.tar.gz
gunzip -c <myimage>_<tag>.tar.gz | docker load
4.5 顯示卡的使用
對於深度學習部署,很多可能需要顯示卡,使用docker時,需要保證顯示卡驅動安裝,同時按上述步驟安裝了nvidia-docker2。
啟動容器時,增加--gpus
選項即可:
sudo docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi ### all: 所有顯示卡都可用
sudo docker run --rm --gpus device=0,2 nvidia/cuda:11.0-base nvidia-smi ### 0,2 卡可用
也可以用下列方式:
sudo docker run --rm --gpus '"device=0"' nvidia/cuda:11.0-base nvidia-smi ### 0卡可用
4.6 其他常用指令
docker images 列出所有映象
docker rmi 刪除映象
docker cp 宿主機和容器間拷貝檔案
還有一個不錯的工具叫runlike
,可以用來檢視容器啟動時的引數,可自行安裝。
5. 使用場景
docker即可以用來發布應用,服務,這可能也是它的一種主要使用場景,也可以用來方便的建立不同的開發編譯環境,比如在我們的ubuntu16.04機器上,去開發centos SDK, 甚至它也可以通過vnc去連線,獲得圖形化的開發環境。
一鍵快捷安裝指令碼:
連結:https://pan.baidu.com/s/1tb9tWEMzs6Ms1WDCzf1fqQ
提取碼:58q3
若以上鍊接失效,關注 老司機的視覺屋,回覆dockertool即可獲取連結