專題 - Docker 容器實際操作
上次更新日期 2021/01/xx
docker 的基礎操作之外,基本管理與實戰也是很重要的一環。上一章節談到的許多指令,其實並沒有談到如何管理, 大部分都是在簡單的操作而已,如何處理映像檔、資料交流與網路等,則沒有一個好的說明。這個章節就讓我們來聊聊如何簡單的管理, 以及進行一些基礎的實戰。
映像檔 (image) 與倉儲 (repository) 管理
- 使用官網的映像檔建立屬於自己的新映像檔:
- 使用容器,處理既有的映像檔資料:
上一章我們曾經從官網 (docker hub) 下載過 centos 這個映像檔,但是,這個映像檔可能不是我們要的, 所以,我們可以針對這個系統進行加工的行為:
# 1. 先檢查上週下載的映像檔是否還存在? # docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos latest 300e315adb2f 3 weeks ago 209MB ubuntu latest f643c72bc252 5 weeks ago 72.9MB # 2. 啟動名為 centos_new 的容器,使用的就是這個 centos 映像檔,且執行 bash: # docker run -it --name centos_new centos bash [root@2a0e0964347a /]# # 注意,特殊字元就是這個容器的獨一無二的 ID 喔! # 3. 檢查 (1)是否有網路 (2)是否有容量 (3)是否有 repository 設定 [root@2a0e0964347a /]# ip addr show 10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP... link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0 valid_lft forever preferred_lft forever [root@2a0e0964347a /]# df -h | grep -v tmpfs Filesystem Size Used Avail Use% Mounted on overlay 10G 5.1G 5.0G 51% / shm 64M 0 64M 0% /dev/shm /dev/mapper/centos-root 10G 5.1G 5.0G 51% /etc/hosts [root@2a0e0964347a /]# yum repolist Failed to set locale, defaulting to C.UTF-8 repo id repo name appstream CentOS Linux 8 - AppStream baseos CentOS Linux 8 - BaseOS extras CentOS Linux 8 - Extras # 4. 開始安裝幾個常見的需要的軟體,提供 Linux 用戶練習 [root@2a0e0964347a /]# yum install vim-enhanced bash-completion net-tools wget bind-utils # 5. 離開並觀察容器資訊 [root@2a0e0964347a /]# exit # docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES 2a0e0964347a centos "bash" 13 minutes ago Exited (0) 3 minutes ago centos_new
假設這個時候就將我們的環境建置妥當,這個容器的內容想要做成映像檔,方便未來提供大家大量使用。
- 使用 commit 上傳容器成為新的映像檔:
上傳容器成為新的映像檔,方式真的很像 git 喔!基本語法是這樣的:
# docker commit --help Usage: 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)
現在,我們處理 centos_new 成為新的映像檔,映像檔名稱為 centos8_inst 好了:
# docker commit -m 'installed tools' -a 'vbird tsai' centos_new centos8_inst sha256:41e458d7a84c043869f4e3882b8a3cb121d57d69e366b4daebf4dfd067b9b881 # docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos8_inst latest 41e458d7a84c 28 seconds ago 337MB centos latest 300e315adb2f 3 weeks ago 209MB ubuntu latest f643c72bc252 5 weeks ago 72.9MB
- 使用新的映像檔來進行容器建置測試看看:
# docker run -it --name centos_new2 centos8_inst bash [root@b7bb796a003d /]# rpm -q net-tools net-tools-2.0-0.52.20160912git.el8.x86_64 [root@b7bb796a003d /]# exit
確認是有安裝 net-tools 的!所以,我們未來啟用這個映像檔,就不需要重複那些安裝的行為等, 操作上面會比較快速!
- 使用容器,處理既有的映像檔資料:
- 將映像檔備份為 tarball 單一檔案,或由單一檔案復原:
- 映像檔的備份:
假設上面這個 centos8_inst 映像檔整理得很不錯,所以我想要將這個映像檔備份下來, 這時,你可以使用 save 的功能來處理映像檔的備份喔。
# docker save -o centos8_inst.tar centos8_inst # ll -h centos8_inst.tar -rw-------. 1 root root 331M 1月 4 02:30 centos8_inst.tar # tar -tvf centos8_inst.tar -rw-r--r-- 0/0 2178 2021-01-04 02:01 41e458d7a84c043869...4dfd067b9b881.json drwxr-xr-x 0/0 0 2021-01-04 02:01 789dbb27ef49925cb9...19c74344c4b20/ -rw-r--r-- 0/0 3 2021-01-04 02:01 789dbb27ef49925cb9...19c74344c4b20/VERSION -rw-r--r-- 0/0 1456 2021-01-04 02:01 789dbb27ef49925cb9...19c74344c4b20/json -rw-r--r-- 0/0 129692672 2021-01-04 02:01 789dbb27ef49925cb9...19c74344c4b20/layer.tar drwxr-xr-x 0/0 0 2021-01-04 02:01 ba21ed01ee58f0af0f...1d02205b59ff0/ -rw-r--r-- 0/0 3 2021-01-04 02:01 ba21ed01ee58f0af0f...1d02205b59ff0/VERSION -rw-r--r-- 0/0 406 2021-01-04 02:01 ba21ed01ee58f0af0f...1d02205b59ff0/json -rw-r--r-- 0/0 216524800 2021-01-04 02:01 ba21ed01ee58f0af0f...1d02205b59ff0/layer.tar -rw-r--r-- 0/0 285 1970-01-01 08:00 manifest.json -rw-r--r-- 0/0 95 1970-01-01 08:00 repositories
這樣就可以壓製成為一個 tar 的檔案,雖然可以查閱該檔案內容,不過,除了 json 檔案之外, 想要知道詳細的檔案檔名資訊,可能還得要持續解開啊!總之,這樣我們就擁有一個備份檔案了。 - 由 tarball 復原映像檔:
現在,假設你將 tarball 複製到其他 docker host,又或者是你的 image 不小心被自己殺掉了! 此時,如何使用備份檔案來回復系統呢?使用 load 即可。
# 1. 先刪除使用 centos8_inst 的容器: # docker ps -adocker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES b7bb796a003d centos8_inst "bash" 17 minutes ago Exited (0) 16 minutes centos_new2 2a0e0964347a centos "bash" 59 minutes ago Exited (0) 49 minutes centos_new # docker rm centos_new2 # 2. 刪除 centos8_inst 映像檔 # docker rmi centos8_inst:latest Untagged: centos8_inst:latest Deleted: sha256:41e458d7a84c043869f4e3882b8a3cb121d57d69e366b4daebf4dfd067b9b881 Deleted: sha256:d885f0d4608d43492385820afc027dac3d027289bd6c63a4a2e41407edb2b211 # 3. 載入映像檔 # docker image load -i centos8_inst.tar 619782606bfb: Loading layer [=============================>] 129.7MB/129.7MB Loaded image: centos8_inst:latest # docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos8_inst latest 41e458d7a84c 40 minutes ago 337MB centos latest 300e315adb2f 3 weeks ago 209MB ubuntu latest f643c72bc252 5 weeks ago 72.9MB
這樣就可以進行映像檔的移動囉!
- 映像檔的備份:
- 建立私有倉庫:
- 預設的倉庫為使用 docker.io 亦即是 docker hub 所提供的映像檔。你當然可以自己下載映像檔, 透過上面的方式整理好之後,以備份 tarball 的方式進行傳輸。但另一方面,你也可以自己設置私有倉庫, 讓你的用戶系統全部指向內部私有倉庫來進行映像檔的下載!這樣應該在傳輸上面,會比較快速一點哩!
- 下載與觀察私有倉庫映像檔:
docker hub 有提供一個名為 registry 的映像檔,這個映像檔似乎就是提供倉庫運作的功能。我們先下載, 然後觀察一下這個映像檔的內容看看:
# 1. 先搜尋有沒有 registry 這個映像檔 # docker search registry NAME DESCRIPTION STARS OFFICIAL AUTOMATED registry The Docker Registry 2.0 impl... 3153 [OK] distribution/registry WARNING: NOT the registry of... 57 [OK] ..... # 2. 開始下載: # docker image pull registry Using default tag: latest latest: Pulling from library/registry 0a6724ff3fcd: Pull complete d550a247d74f: Pull complete 1a938458ca36: Pull complete acd758c36fc9: Pull complete 9af6d68b484a: Pull complete Digest: sha256:d5459fcb27aecc752520df4b492b08358.... Status: Downloaded newer image for registry:latest docker.io/library/registry:latest # docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos8_inst latest 41e458d7a84c 2 hours ago 337MB registry latest 678dfa38fcfa 2 weeks ago 26.2MB centos latest 300e315adb2f 3 weeks ago 209MB ubuntu latest f643c72bc252 5 weeks ago 72.9MB # 3. 查看這個映像檔資訊 # docker image inspect registry [ { "Id": "sha256:678dfa38fcfa349ccbdb1b6d52ac113ace67d5746794b36dfbad9dd96a9d1c43", "RepoTags": [ "registry:latest" ..... "DockerVersion": "19.03.12", "Author": "", "Config": { "Hostname": "", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "5000/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/etc/docker/registry/config.yml" ], "Image": "sha256:1d6cf98b1a921f8756b63c1103209dbe648e9dda42cf3ee2...", "Volumes": { "/var/lib/registry": {} }, "WorkingDir": "", "Entrypoint": [ "/entrypoint.sh" ], "OnBuild": null, "Labels": null }, .....
會看到這個映像檔預社會開啟一個 port 5000 的埠口,提供使用者來處理。 - 建立 regitry 容器檔,且提供對外連線埠口:
我們在上一個章節中,啟動的 centos1 容器中,可以透過 docker0 這個橋接界面進行網路設定, 因此,所有的 docker 容器都是可以具有 IP 位址的。問題是,這個 docker0 是在 Linux 作業系統內的虛擬橋接器, 預設是不給直接連線的。因此,我們得要透過 port mapping 的功能進行轉 port 的工作。
docker 可以根據你啟動容器時的指令,來主動提供 port mapping 喔!整體流程架構也挺簡單的:
# docker run -d -it -p hostport:dockerport \ > -v volume --name dockername registry -d 讓 docker 以 daemon 的方式,直接啟動在背景持續執行 -p hostport:dockerport 讓連線到本機 hostport 埠口的連線,導向 docker 的 dockerport 埠口 -v volume 讓 docker 容器掛載某個本機的目錄,這樣可以持續經營
上述的 -v 比較有趣,它的內容主要是針對本機目錄與 docker 內的目錄做連結, 最簡單的用法就是,讓本機的 /srv/registry 掛載到 docker 內的 /tmp/registry 目錄時, 可以使用『 -v /srv/registry:/tmp/registry 』這種格式來處理。
現在,讓我們使用底下的機制來處理這個容器:
- 使用 daemon 的方式啟動容器
- 本機埠口 5000 對應到容器 port 5000 上面
- 本機的 /srv/registry 掛載到容器的 /var/lib/registry 上
- 容器的名稱為 myregistry
# docker run -d -it -p 5000:5000 -v /srv/registry:/var/lib/registry \ > --name myregistry registry # docker ps -a CONTAINER ID IMAGE COMMAND PORTS NAMES 16c328633cc2 registry "/entrypoint.sh /etc.." 0.0.0.0:5000->5000/tcp myregistry 2a0e0964347a centos "bash" centos_new # iptables-save| grep -i docker :DOCKER - [0:0] :DOCKER-ISOLATION-STAGE-1 - [0:0] :DOCKER-ISOLATION-STAGE-2 - [0:0] :DOCKER-USER - [0:0] -A FORWARD -j DOCKER-USER -A FORWARD -j DOCKER-ISOLATION-STAGE-1 -A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -o docker0 -j DOCKER -A FORWARD -i docker0 ! -o docker0 -j ACCEPT -A FORWARD -i docker0 -o docker0 -j ACCEPT -A DOCKER -d 172.18.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 5000 -j ACCEPT -A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2 -A DOCKER-ISOLATION-STAGE-1 -j RETURN -A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP -A DOCKER-ISOLATION-STAGE-2 -j RETURN -A DOCKER-USER -j RETURN :DOCKER - [0:0] -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER -A POSTROUTING -s 172.18.0.0/16 ! -o docker0 -j MASQUERADE -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER -A DOCKER -i docker0 -j RETURN -A DOCKER ! -i docker0 -p tcp -m tcp --dport 5000 -j DNAT --to-destination 172.18.0.2:5000
我們可以很快速的發現到,剛剛建立的新的 myregistry 容器,他的 IP 應該是 172.18.0.2 才對,而且相關的防火牆對應也做好了, 相當簡單快速。
- 將本機的映像檔上傳到私有倉庫上:
接下來,讓我們將本機的映像檔上傳到私有倉庫,以提供自己的夥伴們下載使用。處理的方式很簡單:
# docker tag --help Usage: docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
那個 TARGET_IMAGE[:TAG] 如果是放置到外部倉庫上,而不是本機的映像檔資訊時,應該會寫成:
registryhost/[username/]img_name[:tag]
現在,請將 centos8_inst 製作出你本機 IP 的映像檔名稱:
# 1. 觀察本機的映像檔 # docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos8_inst latest 41e458d7a84c 3 hours ago 337MB registry latest 678dfa38fcfa 2 weeks ago 26.2MB centos latest 300e315adb2f 3 weeks ago 209MB ubuntu latest f643c72bc252 5 weeks ago 72.9MB # 2. 對上面的映像檔,製作出給本機 IP 對應的映像檔檔名: # ip addr show | grep 'inet ' inet 127.0.0.1/8 scope host lo inet 192.168.40.200/24 brd 192.168.40.255 scope global noprefixroute ens3 inet 172.17.200.254/24 brd 172.17.200.255 scope global noprefixroute ens7 inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0 inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0 # docker tag centos8_inst 192.168.40.200:5000/centos8_inst # docker images REPOSITORY TAG IMAGE ID CREATED SIZE 192.168.40.200:5000/centos8_inst latest 41e458d7a84c 4 hours ago 337MB centos8_inst latest 41e458d7a84c 4 hours ago 337MB
製作好對應的映像檔參數後,就可以直接將映像檔上傳了:
# docker push 192.168.40.200:5000/centos8_inst Using default tag: latest The push refers to repository [192.168.40.200:5000/centos8_inst] Get https://192.168.40.200:5000/v2/: http: server gave HTTP response to HTTPS client
出現上面的問題,主要原因是 docker 的安全性問題,需要修改 docker 的設定檔,同意放行私有倉庫才行。 處理的方法如下:
# 1. 修改 docker 設定檔: # vim /etc/docker/daemon.json { "live-restore": true, "group": "dockerroot", "insecure-registries": ["192.168.40.200:5000"] } # 2. 重新啟動 docker # systemctl restart docker # 3. 重新啟動 myregistry 容器 # docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES 13c2c53af60d registry "/entrypoint.." 6 minute Exited (2) 46 se myregistry 2a0e0964347a centos "bash" 5 hours Exited (0) 4 hou centos_new # docker start myregistry # 4. 最後,再次上傳 images ! # docker image push 192.168.40.200:5000/centos8_inst Using default tag: latest The push refers to repository [192.168.40.200:5000/centos8_inst] 619782606bfb: Pushed 2653d992f4ef: Pushed latest: digest: sha256:e22009d955f2dcd1cf99a6006569ec493a0624e5... size: 741 # 5. 再看看剛剛提供給 docker 容器的目錄 # ll /srv/registry/docker/registry/v2/repositories/ drwxr-xr-x. 5 root root 55 1月 4 06:16 centos8_inst
- 完成底下的實做
- 用 student 的身份,在 server 上面,設計一隻名為 install_docker.yml 的 play book 檔案,主要目的是要讓 managed host
成為 docker host。需要的任務有:
- 先上傳 docker 的 repository 檔案,才能夠做 yum 安裝
- 完整的將 docker 安裝上去 (包括移除不要的軟體、安裝需要的軟體等)
- 上傳需要的 /etc/docker/daemon.json 設定檔
- 啟動且開機預設啟動 docker 軟體
- 前往 webserver1,使用 root 進行映像檔下載與容器處理:
- 嘗試從 192.168.40.*:5000 下載你剛剛上傳的 image,並且觀察 image 的設定 (inspect)
- 重新 tag 一個新的 image ,名稱為 centos8_my,來源就是上面這個映像檔
- 啟動一個名為 mycentos8 的容器,使用 mycentos_my 的映像檔,且啟動到背景中
- 前往 webserver1,使用 root 執行映像檔重新建立:
- 在 mycentos8 的容器當中,嘗試啟動 sshd 服務,你可能需要 (1)安裝 openssh-server (2)手動啟動 sshd (絕對路徑) (3)找不到 host key 的情境下,執行 ssh-keygen -A 產生 (4)重新執行 sshd 指令 (5)使用 netstat 檢查埠口。
- 停止 mycentos8,將此容器製作成為映像檔,然後上傳到 192.168.40.*:5000 上面去。
- 在 server 的環境下進行如下的行為:
- 將剛剛 webserver1 傳上來的映像檔,下載到本機上
- 啟動一個容器,這個容器會有 port 2222 對應到 22 的功能,且會執行 sshd 喔!
- 從本機上面使用 ssh 嘗試連線到 2222 ,看看會有什麼情況發生。
- 用 student 的身份,在 server 上面,設計一隻名為 install_docker.yml 的 play book 檔案,主要目的是要讓 managed host
成為 docker host。需要的任務有:
...
參考資料
- ps01:維基百科之作業系統層虛擬化:https://en.wikipedia.org/wiki/OS-level_virtualisation
- ps02:docker 入門到實戰(值得慢慢看):https://philipzheng.gitbooks.io/docker_practice/content/
- https://www.cloudsavvyit.com/490/what-does-docker-do-and-when-should-you-use-it/
- https://itnext.io/getting-started-with-docker-facts-you-should-know-d000e5815598
- https://docs.docker.com/engine/install/centos/
- https://docs.docker.com/registry/deploying/
- 清輝的 Docker 基本教學