簡單說:容器(container)就是計算機上的一個沙盒程序,它與計算機上的所有其它程序相隔離。
這種隔離是怎麼做到的呢?它利用了核心提供的 namespace 和 cgroup 這 2 種技術。這些技術能力在 Linux 中已經存在了很長時間。而 Docker 或容器技術致力於將這些功能更易於使用和更方便使用。容器技術把 linux 中已存在的這些技術顯性化了,讓使用者容易操作使用,體驗更好。
」沙盒「就像是一個集裝箱,能夠把應用及其相關依賴軟體裝在一起。在 docker 的隔離下,應用和應用之間就有了邊界,相互隔離不被打擾,也方便「搬來搬去」,搬到各種伺服器環境中執行。
Docker 的 logo 是一條鯨魚駝著許多"四方盒子「 - 標準集裝箱,很形象的表達。把軟體打包標準化,像一個一個集裝箱,可以方便快捷運輸到各種伺服器環境中並安裝。
Docker 的口號:
Develop faster. Run anywhere.
Docker 是容器技術的一種實現,還有其它容器比如 Podman,Container 等。
容器的實質是程序。但與直接執行在宿主機上的程序不同,容器程序執行在屬於自己獨立的名稱空間。因此,容器可以擁有自己獨立的 root 檔案系統、網路設定、程序空間、自己的使用者 ID 空間等等。
容器的一些特性總結:
比如開發人員在自己筆電上建立並測試好的容器,無須修改就可以在生產系統的虛擬機器器、伺服器等上面執行。
我們把應用程式開發完之後,部署到伺服器上時,會有很多軟體需要部署,比如部署 PHP 程式開發的應用專案,就有 MySQL,Redis,Nginx 等各種軟體需要部署。
部署的伺服器環境呈現多樣化,比如物理伺服器,雲伺服器,虛擬機器器等,不同伺服器上安裝的作業系統可能又不同,執行環境不同,依賴各不同。
面對這種多個軟體需要部署,不同的伺服器環境、不同的作業系統,環境差異這麼大,如何能做到一鍵部署且遮蔽彼此的各種差異?如何做到構建一次完之後就能部署到各種不同的伺服器環境中?也就是,一次構建,多地多次部署,且都能順利執行。
這時容器技術就可以解決這些問題。容器能夠把應用程式及其依賴的軟體打包到一個容器中,然後釋出到各種伺服器上。
這樣就能加快執行環境搭建、應用程式的部署,解決了運維效率和成本高的一些問題。
一次構建,隨時隨地搬運,任意環境執行
(Build,Ship and Run Anywhere)
Docker 還提供了一種類似「程式設計的方式」來方便構建映象:Dockerfile。
映象(Container Image)是一個模板,一種容器化標準化交付物,容器應用打包的標準格式,用於打包應用程式及其依賴環境。
容器和映象的關係,這個就相當於物件導向程式語言中,類(container image)和範例(container instance)的關係。映象是靜態定義,容器是映象執行時的實體。容器可以被建立、啟動、刪除、暫停等。
容器映象是一個隨時可以執行的軟體包,當執行一個容器時,它使用一個隔離的檔案系統,這個自定義的檔案系統包含應用程式所需的依賴項、設定、指令碼、二進位制檔案等,映象也包含其它平臺的設定。
我們可以借用 Buildah 等開源工具,來建立相容 OCI 和 Docker 的映象檔案。
Dockerfile 是用來構建映象的文字檔案,文字內容包含了構建映象所需的指令和說明。Docker 等工具可以通過讀取 Dockerfile 中的指令自動構建生成容器映象。
映象倉庫(container repository)是儲存、分發映象檔案的地方。這些映象檔案放在映象倉庫裡。映象倉庫可以是開放的映象倉庫,例如 docker hub;也可以是自建的映象倉庫,比如用 docker-registry ,harbor , Nexus 等。
Docker 是用 Go 開發實現,基於 linux 的 cgroup,namespace 和 UniosFS 等主要技術,對程序進行封裝隔離,在作業系統之上的虛擬化技術。隔離的程序是獨立於宿主和其它程序,它又稱為容器。
Docker 容器,又進一步的封裝,從檔案系統、網路到程序隔離等,簡化了容器的建立、啟動、刪除等操作。Docker 技術比虛擬機器器技術更為輕便。
Docker 可以快速、一致性的交付你的應用程式。
(來自 kubernetes 官網)
從上圖軟體交付的變化歷程圖可以看出,容器和傳統虛擬機器器的不同。
傳統虛擬機器器是虛擬出一套硬體,在其上執行完整作業系統,在這之上再來執行各種應用軟體。
容器直接執行在容器執行時上,容器執行時直接執行在宿主機的核心裡,它也不需要進行硬體虛擬化。
虛擬機器器和容器的比較:
特點 | 容器 | 虛擬機器器 |
---|---|---|
隔離性 | 較弱的隔離 | 強隔離 |
啟動速度 | 秒級 | 分鐘級 |
映象大小 | 最小的幾 MB | 幾百 MB 到幾個 GB |
效能(與裸機比) | 損耗小於 2% | 損耗 15% 左右 |
系統支援數量 | 單機可支援 100 個到 1000 個容器 | 單機支援 10 到 100 個左右 |
安全性 | 1.容器內的使用者從普通使用者許可權提升到root使用者,就直接具備宿主機root許可權 2. 容器中沒有硬體隔離,這使得容器攻擊彼此牽連 | 1.虛擬機器器租戶root許可權和主機的root許可權是分離的 2.硬體隔離技術:防止虛擬機器器彼此互動 |
Docker 整體架構圖:
(來自:docker docs architecture)
Docker 架構是一個使用者端-伺服器端架構,使用者端是 Client
,伺服器端是 Docker Host
。後面的 Registry
是一個映象倉庫。
Docker 使用者端與 Docker daemon 守護行程進行通訊,守護行程負責構建、執行和分發 Docker 容器。Docker 使用者端和 Docker 守護行程直接進行資訊互動。Docker 還有另外一個使用者端 Docker Compose,它處理一組容器組成的應用程式。
Client :docker 使用者端。docker run
,docker build
,docker pull
,都是 docker 裡的命令。
docker build
:執行 docker 構建命令,會根據 docker 檔案構建一個映象存放在本機上。docker run
:執行 docker 啟動命令,它會將映象執行為容器。docker pull
:該命令從映象倉庫拉取映象檔案至本地 docker 主機,或將本地映象推播至遠端映象倉庫。Docker Host:docker 主機。Docker daemon,守護行程;Images,映象;Containers,容器。
Registry:映象倉庫,儲存映象的倉庫。
其實上面的架構圖已經把 docker 執行流程畫出來了。只不過看起來不太明顯,在簡化下:
(docker 命令執行流程,實線條不同顏色代表不同步驟)
從圖上可以看出,docker 使用者端發出命令,後都會與 docker host(docker 主機)互動,然後在由 docker 主機進行後面的操作。
比如 docker 構建:在 docker 使用者端發出命令,docker 主機的守護行程接收命令,然後它通過映象來執行出一個容器。
請看下面的架構圖:
(docker 底層技術構成簡圖)
linux kernel,docker 技術的實現依賴了 linux 底層一些技術特性:
Docker 使用儲存驅動程式(storage driver)來儲存 image 的影象層,將資料儲存在容器的可寫層中。
Docker 映象是由一系列層(layers)構建而成,每層代表 Dockerfile 的一條指令。除了最後一層之外每一層都是唯讀的。
Docker 用 UnionFS (聯合檔案系統)把這些層聯合在一起。
(來源docker storage driver:images and layers)
(圖片來源網路侵刪)
docker engine
docker engine 引擎裡的 runc 是開放容器執行時,它是 OCI(Open Container Initiative)Spec 的一個實現。
docker engine 在 linux 下提供了很多儲存驅動,Docker Storage Driver:
Docker Storage Driver |
---|
overlay2 |
fuse-overlayfs |
btrfs and zfs |
vfs |
devicemapper |
關於上面 docker storage driver 的更多資訊請檢視:https://docs.docker.com/storage/storagedriver/select-storage-driver/ 。
Docker 可以在不同的作業系統中安裝,官方安裝地址:
我在虛擬機器器中裝的 ubuntu 作業系統:
Description: Ubuntu 20.04.2 LTS, Codename: focal
該系統對應 docker 官方安裝地址:https://docs.docker.com/engine/install/ubuntu/ 。
具體安裝 docker 就不詳細說明了,請按照官方檔案一步一步進行安裝。
我安裝的docker版本:
$ docker -v
Docker version 24.0.1, build 6802122
驗證是否安裝成功:
$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
719385e32844: Pull complete
Digest: sha256:fc6cf906cbfa013e80938cdf0bb199fbdbb86d6e3e013783e5a766f50f5dbce0
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
docker cli檔案地址:https://docs.docker.com/engine/reference/commandline/cli/
建立或啟動一個新容器的命令:docker run
, 語法為:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
獲取更多 docker run 幫助檔案:docker run --help
。
比如,下面的命令輸出一個「hello world」後,終止容器。
因為我本地沒有 ubuntu:20.04 這個映象,所以要先下載,docker run
會自動下載這個映象,命令和執行過程如下:
$ sudo docker run ubuntu:20.04 /bin/echo 'hello world'
Unable to find image 'ubuntu:20.04' locally
20.04: Pulling from library/ubuntu
ca1778b69356: Pull complete
Digest: sha256:db8bf6f4fb351aa7a26e27ba2686cf35a6a409f65603e59d4c203e58387dc6b3
Status: Downloaded newer image for ubuntu:20.04
hello world
下載完映象後,自動執行這個映象,最後輸出了 hello world 。
啟動一個 bash 終端,允許使用者進入容器終端進行互動:
$ sudo docker run -t -i ubuntu:20.04 /bin/bash
root@049706bffe28:/#
輸入 ls 命令:
root@049706bffe28:/# ls
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
來解釋一下 docker run -t -i
這個命令中的引數:
-t
選項讓 docker 分配一個偽終端並繫結到容器的標準輸入上
-i
互動式操作,也就是命令列模式進入容器這2個引數也可以寫一起:
docker run -it ubuntu:20.04 /bin/bash
退出容器終端可以輸入命令 exit
。
上面的兩個引數還可以合一起:
docker run -dit ubuntu:20.04
-d
指定容器執行模式, 預設不會進入容器,想要進入容器需要繼續執行指令 docker exec
,下面會介紹。如果 docker 命令太長,還可以用 \
來換行,如下:
docker run -it --rm \
ubuntu:20.04 \
/bin/bash
啟動已經停止執行容器:docker start
或 docker container start
重新啟動容器:docker container restart
命令將一個執行態的容器終止,然後重新啟動它
終止執行中容器:docker container stop
來終止一個執行中的容器
檢視所有的容器:
VirtualBox:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
56ca83925f03 ubuntu:20.04 "/bin/bash" 15 minutes ago Up 15 minutes strange_allen
c1482012b069 ubuntu:20.04 "/bin/bash" 26 minutes ago Exited (0) 20 minutes ago gallant_ellis
啟動停止的容器 container id c1482012b069:
VirtualBox:~$ sudo docker start c1482012b069
c1482012b069
VirtualBox:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
56ca83925f03 ubuntu:20.04 "/bin/bash" 21 minutes ago Up 20 minutes strange_allen
c1482012b069 ubuntu:20.04 "/bin/bash" 31 minutes ago Up 8 seconds gallant_ellis
大量的映象檔案都儲存在遠端的映象倉庫中,比如 docker hub 。獲取映象的命令 docker pull
,語法為:
docker pull [OPTIONS] NAME[:TAG|@DIGEST]
獲取 docker pull 更詳細引數:docker pull --help
。
比如,拉取 ubuntu:20.04 這個映象檔案:
$ sudo docker pull ubuntu:20.04
20.04: Pulling from library/ubuntu
Digest: sha256:db8bf6f4fb351aa7a26e27ba2686cf35a6a409f65603e59d4c203e58387dc6b3
Status: Image is up to date for ubuntu:20.04
docker.io/library/ubuntu:20.04
由於前面啟動映象命令 docker run
執行了這個映象檔案,顯示 Image is up to date for ubuntu:20.04 。
拉取映象後,就可以啟動這個映象,命令 docker run
。
$ sudo docker run -it --rm ubuntu:20.04 bash
root@5c2a77428b80:/#
-it
:-i
表示互動操作,-t
表示是一個終端
--rm
:這個參數列示容器退出後會將其刪除。在預設情況下,為了排障需要,退出的容器並不會馬上刪除,觸發手動執行 docker rm。我這裡只是演示命令的執行,不需要排障,--rm
可以避免浪費空間ubuntu:20.04:表示映象,以這個映象來作為啟動容器
bash:放在映象後面的是命令。這裡希望進入互動式 shell,所以用 bash
列出所有映象
列出映象的命令:docker image ls
,顯示映象下載到本地後,展開後各層所佔用空間的總和。語法:
docker image ls [OPTIONS] [REPOSITORY[:TAG]]
關於 docker image ls 更多用法,可以檢視幫助命令:docker image ls --help
。
$ sudo docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 9c7a54a9a43c 2 weeks ago 13.3kB
ubuntu 20.04 88bd68917189 5 weeks ago 72.8MB
列出了倉庫名、標籤、映象ID、建立時間、所佔用的空間大小。
映象ID是映象的唯一識別符號,一個映象可以對應多個標籤。
列出部分映象
列出部分映象的命令:docker image ls 映象名
比如下面例子;
$ sudo docker image ls ubuntu
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 20.04 88bd68917189 5 weeks ago 72.8MB
還可以加過濾的引數 --filter
,
$ sudo docker image ls --format "{{.ID}}: {{.Repository}}"
9c7a54a9a43c: hello-world
88bd68917189: ubuntu
刪除本地映象的命令:docker image rm
,語法:
docker image rm [OPTIONS] IMAGE [IMAGE...]
上面大家映象 IMAGE ,可以是映象長ID、映象短ID、映象名 或映象摘要。
比如用映象短ID來刪除映象:
$ sudo docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 9c7a54a9a43c 2 weeks ago 13.3kB
ubuntu 20.04 88bd68917189 5 weeks ago 72.8MB
$ sudo docker image rm 189
檢視映象詳細資訊的命令:docker image inspect
。
檢視映象 hello-world:latest 的詳細資訊:
docker image inspect hello-world:latest
搜尋遠端倉庫映象命令:docker search
。
例如 檢視遠端倉庫中 ubuntu 的映象有哪些:
docker search ubuntu
使用 -d
引數,容器啟動後可以進入後臺。
在容器啟動後,我們有時需要進入容器映象操作,命令有 docker attach
或 docker exec
,推薦使用 docker exec
, 因為 docker attach
進入容器操作完 exit 退出後,會導致容器停止,而 exec 不會。
$ sudo docker run -dit ubuntu:20.04
c1482012b06914449cafd461931eb890dec01fa8e6858233d3fcc98de9ceb4bc
$ sudo docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c1482012b069 ubuntu:20.04 "/bin/bash" 53 seconds ago Up 42 seconds gallant_ellis
$ sudo docker attach c148
root@c1482012b069:/#
上面引數 -d
表示容器啟動後會進入後臺執行。
注意:上面容器用
exit
退出後會導致容器停止執行
root@c1482012b069:/# exit
exit
VirtualBox:~$ sudo docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
用命令檢視容器,剛才執行的容器退出了。exec
就不會。
// 執行容器
VirtualBox:~$ sudo docker run -dit ubuntu:20.04
56ca83925f039f9ba087aff8a521678e2dcc87836bffede90ed2f2614aec8065
// 列出容器列表
VirtualBox:~$ sudo docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
56ca83925f03 ubuntu:20.04 "/bin/bash" 16 seconds ago Up 13 seconds strange_allen
// 進入容器
VirtualBox:~$ sudo docker exec -it 56ca bash
root@56ca83925f03:/# ls
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
// 退出容器
root@56ca83925f03:/# exit
exit
退出容器後,在列出容器列表:
VirtualBox:~$ sudo docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
56ca83925f03 ubuntu:20.04 "/bin/bash" 2 minutes ago Up 2 minutes strange_allen
CONTAINER ID 和前面顯示的 CONTAINER ID 相同,STATUS 狀態也是 Up 2 minutes,執行狀態,容器沒有退出。
刪除終止狀態的容器命令:docker container rm
docker container rm strange_allen
-f
歡迎大家提建議,討論,點贊