Docker Basic
Table of Contents
在近年的軟體開發中,DevOps 實踐已成為主流,其核心理念是透過自動化和持續性來縮短軟體開發週期,而 CI/CD 流程正是實現這一目標的關鍵。在 CI/CD 的發展中,容器化技術扮演了重要的基石角色,因為它解決了軟體開發中長期遇到的環境不一致問題,提供了一個標準化的封裝方式。
What is Docker #
Docker 是一個用來實現應用程式容器化(Containerization)的工具,幫助開發人員在不同的作業系統上達到快速且一致的應用部署。在軟體開發服務上,要確保應用程式在不同環境下穩定且一致的運作,是一項常見的難題。而透過容器化,能夠直接解決這個問題。容器化是將應用程式的依賴項目(程式庫、設定檔等)封裝成一個獨立且可執行的單元—容器。這種做法提供獨立性、一致性和可攜性的特性,確保在開發階段可行的應用程式內容,在正式環境中也能正常運作。
一致性:容器會將應用程式的依賴項目封裝在一起,因此能建立一致的獨立運作空間,解決在不同作業環境下的各種可能衝突。
獨立性:每個容器會在獨立的空間中運作,這種隔離機制確保應用程式的程式庫和依賴項目,不會與在同一主機上執行的其他容器發生衝突。
可攜性:擁有輕量化以及可以高速部署的特性,能在不同硬體、作業系統、雲端服務之間輕鬆遷移和運作。
VM vs Docker #
容器化技術是虛擬化的一種形式,但卻比虛擬機(virtual machine,VM)更輕巧且更有效率。要理解為什麼容器化會更有優勢,就要提到電腦的基本架構。這裡稍微將電腦基本架構簡化為三個層面,從底層硬體一路往上到應用程式本身。
- 硬體層:這是電腦的實體層,由實體伺服器或虛擬機器組成,提供 CPU、記憶體、儲存空間和網路資源。
- 主機作業系統:主機作業系統 (例如 Linux) 位於硬體層之上,負責管理系統資源並充當應用程式與硬體之間的橋樑。
- 應用程式層:作業系統之上的應用軟體,為使用者提供服務的軟體或應用程式。
而 Docker 在架構中作為介於作業系統和應用程式層之間的容器引擎1實現容器化,與虛擬機差異的主要差異在於
- Docker 僅將應用程式層虛擬化變成容器,所以容器內沒有專屬的作業系統。而且在一台宿主機上可以啟動多個容器,所有容器將會共用宿主的作業系統核心。
- 虛擬機則完整虛擬化一個獨立的作業系統以及應用程式層。
因為虛擬化過程容器化技術缺少了作業系統,所以 Docker 在部署應用程式時需要的記憶體更少,速度更高效,能進一步優化資源使用,同時能達到快速擴張(scaling)的能力。

Docker Basic #
了解容器化技術和 Docker 的優勢,接著要來介紹如何使用 Docker 來建造應用程式容器。但在進入更詳細的操作說明前,需要介紹 4 個涵蓋在容器的生命週期中的專有名詞:
- 映像檔 (Image):
- 映像檔是建立容器的唯讀檔案,定義和描述容器將如何建置,通常存放在 Registry 中。
- 可以為映像檔建立標籤,進行版本控制,追蹤開發變更,確保應用程式的穩定性。
- 容器 (Container):
- 容器是一種輕量級的虛擬化技術,是應用程式的標準執行單元。
- 每個容器都是從映像檔創建的,包含了應用程式運作所需的一切元件。
- 提供應用程式隔離環境,讓多個應用程式在同一台主機上獨立運作而不互相干擾。
- 容器能輕鬆啟動、停止、刪除,但刪除容器時所有在容器內的操作將不會被保留。
- Registry:
- 這是存放映像檔的遠端空間,像是 Docker Hub、RedHat、Amazon ECR、Google Container Registry等。
- 在公共的映像檔倉庫,用戶可以發佈和下載映像,並提供了大量現成的應用程式映像檔,方便開發者快速開始使用。
- Dockerfile:
- Dockerfile 是用來定義映像檔建構過程的文件,透過一系列指令,告訴 Docker 如何構建映像檔。
通常一個容器的生命週期是從取得映像檔開始,Docker 接著依照映像檔啟動容器。之後應用程式會在容器內開始運作,直到出現下一個版本的映像檔,舊的容器會被關閉、刪除,接著啟動新一輪的生命週期。
Starting a Container Lifecycle #
經過上面種種的介紹,可以得知一個容器的基礎是映像檔。取得映像檔有兩種方式,一種是從 registry 拉取,另一種是透基於 Dockerfile 構建。若沒有取得映像檔就直接啟動容器,那麼 Docker 將會試著從 DockerHub 拉取相同名稱的 image。如果沒有在 DockerHub 上沒有檔案將會失敗,因此建議在啟動前最好要確保地端有該檔案。
Build or Get an image #
如果要從 registry 拉取映像檔,需要使用以下的指令,並透過指定 version 來指定特定版本。Docker 預設從 DockerHub 拉取,如果要從其他倉庫拉取,需要處理授權問題,再指定映像檔的存放路徑。例如從 AWS 的私人 Elastic Container Registry (ECR) 拉取,其授權的 token 限定 12 小時的有效期限2。
# default pull from DockerHub
docker pull image_name:version
# pull from public AWS public registry
docker pull public.ecr.aws/registry_alias/repository:tag
第二種方式是根據指定路徑的 Dockerfile 直接建置映像檔,建置完成後將儲存在本機的快取儲存中。這裡需要注意要使用 docker buildx build 來執行,因為 docker build 的版本已經被取代了。同樣在建置過程也有許多標籤,能夠用來設定建置過程跟結果,有關更多標籤的使用方法可以參照官網的說明。
docker buildx build -f <filepath> . -t <image_name>:<image_tag>
Tags
-f or --file 用來指訂定特定路徑中的 Dockerfile,如果沒有指定則會尋找工作目錄下 Dockerfile。另外若使用相對路徑,Docker 會根據上下文目錄來搜尋。
. 是建構時候提供的 context,將當前目錄及其所有內容作為建構過程的「來源資料庫」,非常重要切記不能忽略。(因為上下文目錄而產生的問題:https://shiun.me/blog/a-project-with-multiple-dockerfiles-an-introduction-to-build-context/)
-t or --tag 用來命名建置的映像檔以及對應標籤
Image Management #
取得映像檔後,可以透過指令來檢查安裝的映像檔。除了確認是否下載正確外,在系統中長期積累的使用下會佔用大量記憶體空間,所以需要適時的管理和清除已經過時或沒在使用的映像檔。
# list top level images
docker images
# remove image with ID
docker rmi IMAGEID
# or if an image has one or more tags referencing it
# you must remove all of them before the image is removed.
docker rmi REPOSITORY:TAG
# use -f --force will untags and removes all images that match the specified ID.
docker rmi -f IMAGEID
# check memory usage
docker system df
# remove all images that are not used for any container
docker image prune
Create a container #
容器是透過執行映像檔而得到的實例,同樣能設定標籤來標記管理容器。如使用 name tag 可以為容器命名方便管理,使用 detach tag 可以讓容器在背景運作,使用 rm tag 可以在離開容器後自動刪除所有容器內容。
docker run --name test -it ubuntu bash
Tags
--name 用來命名容器
-i interactive and -t terminal flags 在啟動容器後,進入容器內部並使用終端機與容器互動
More common used tags
-d or --detach 指定容器在背景執行
--rm automatically removes container when you exit.
-p local port:container port or --publish 將主機連接埠對應到容器對應的連接埠
-v or --volume 掛載磁碟區讓主機與容器共用檔案及資料夾,避免遺失在容器內產生的改變
--network 將容器連接到特定的 Docker 網絡,從而允許同一網路上的容器之間進行通訊。
--entrypoint 指定要作為該容器入口點運行的不同命令,通常使用 .sh 檔案。
Stop or Remove Containers #
啟動容器後,為了確保有正常運作,可以透過docker ps 查看執行中的容器。同時如果需要操作應用程式,能夠透過**docker exec**在容器中執行命令。以下列出一些常用的容器執行指令
# list out running containers (default) -all means list all including stopped
docker ps -all
# stop container with ID or name
docker stop CONTAINERID
# remove container
docker rm --force <CONTAINERID>
# excute command in a running container
docker exec bash
# get logs from containers
# -f --follow will continue streaming the new output
# -t shows timestamp with each log
# --since shows logs generated after a given date
docker logs -f -t --since 2h <CONTAINERID>
總結 #
在這篇文章我們認識到容器化因為僅有虛擬化應用程式層、提供標準化的封裝流程,不但解決環境不一致而造成的問題,更為現在化 CI/CD 流程提供快速部署及擴張的效率優勢。接著介紹如何使用 Docker 來建造應用程式容器,並說明 4 個專有名詞在整個容器的生命週期的地位及作用。在下一個篇章將會深入探討如何撰寫一個 Dockerfile,並進一步了解在 CI/CD 流程中 Docker 扮演的角色。
參考資料
https://www.youtube.com/watch?v=pg19Z8LL06w&feature=youtu.be
https://www.docker.com/resources/what-container/
https://docs.docker.com/get-started/docker-overview/
容器引擎指的是啟用容器化的軟體,如 Docker、Kubernetes、Podman、Google Kubernetes Engine (GKE)。引擎會按照指示建立、執行及管理容器。 ↩︎
https://docs.aws.amazon.com/AmazonECR/latest/userguide/docker-pull-ecr-image.html ↩︎