Docker三大核心組件:鏡像、容器與倉庫,你瞭解多少呢?

鏡像(Image),容器(Container),倉庫(Repository)是我們常說的Docker的三大組件,在這篇文章中,我們就來一起詳細地探索一番吧。

Docker三大核心組件:鏡像、容器與倉庫,你瞭解多少呢?

 

01 鏡像(Image)

什麼是Docker鏡像?

簡單地理解,Docker鏡像就是一個Linux的文件系統(Root FileSystem),這個文件系統裏面包含可以運行在Linux內核的程序以及相應的數據。

談到這裏,我們可能需要先補充一點與Linux操作系統相關的知識:

一般而言, Linux分爲兩個部分:Linux內核(Linux Kernel)與用戶空間,而真正的Linux操作系統,是指Linux內核,我們常用的Ubuntu,Centos等操作系統其實是不同廠商在Linux內核基礎上添加自己的軟件與工具集(tools)形成的發佈版本(Linux Distribution)。

因此,我們也可以把鏡像看成是上面所說的用戶空間,當Docker通過鏡像創建一個容器時,就是將鏡像定義好的用戶空間作爲獨立隔離的進程運行在宿主機的Linux內核之上。

這裏要強調一下鏡像的兩個特徵:

  1. 鏡像是分層(Layer)的:即一個鏡像可以多箇中間層組成,多個鏡像可以共享同一中間層,我們也可以通過在鏡像添加多一層來生成一個新的鏡像。
  2. 鏡像是隻讀的(read-only):鏡像在構建完成之後,便不可以再修改,而上面我們所說的添加一層構建新的鏡像,這中間實際是通過創建一個臨時的容器,在容器上增加或刪除文件,從而形成新的鏡像,因爲容器是可以動態改變的。

通過下面的示意圖,我可以更好地理解Docker鏡像與Linux的關係:

Docker三大核心組件:鏡像、容器與倉庫,你瞭解多少呢?

 

1.1 操作鏡像的命令

Docker中與鏡像操作相關的命令都在docker image這條子命令下,通過docker image --help這條命令,可以看到docker image子命令的詳細文檔,如下:

Usage: docker image COMMAND
Manage images
Commands:
 build Build an image from a Dockerfile(構建鏡像的命令)
 history Show the history of an image(顯示鏡像構建歷史過程)
 import Import the contents from a tarball to create a filesystem image(導入一個由容器導出的鏡像)
 inspect Display detailed information on one or more images(顯示一個鏡像的詳細信息)
 load Load an image from a tar archive or STDIN(從一個文件或標準輸入流中導入鏡像)
 ls List images(查看鏡像列表)
 prune Remove unused images(刪除虛懸鏡像)
 pull Pull an image or a repository from a registry(從倉庫拉取鏡像)
 push Push an image or a repository to a registry(推送鏡像到倉庫)
 rm Remove one or more images(刪除鏡像)
 save Save one or more images to a tar archive (streamed to STDOUT by default)(保存鏡像到文件)
 tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE(給鏡像打標籤)

1.2 獲取鏡像

在安裝了Docker之後,我們本地並沒有任何鏡像,當然我們可以自己構建,不過更方便還是從Docker官方提供的倉庫服務Docker Hub上拉取官方或第三方已經構建好的鏡像。

拉取鏡像可以使用docker image pull,其格式如下:

docker image pull [OPTIONS] NAME[:TAG|@DIGEST]

當然,docker image pull有更簡潔的用法:如:

docker pull [OPTIONS] NAME[:TAG|@DIGEST]

要拉取鏡像,需要指定Docker Registry的URL和端口號,默認是Docker Hub,另外還需要指定倉庫名和標籤,倉庫名和標籤唯一確定一個鏡像,而標籤是可能省略,如果省略,則默認使用latest作爲標籤名,而倉庫名則由作者名和軟件名組成。

所以,在省略了那麼參數後,比如我們想拉取centos鏡像,可以使用下面簡單的命令從Docker Hub上拉到:

$ docker pull centos

1.3 查看本地鏡像

通過上面的方法我們將鏡像拉取到了本地,那要如何查看本地有哪些鏡像呢?通過下面的命令我們可以查看本地的全部鏡像:

$ docker image ls

當然Docker提供了更簡潔的寫法,如下:

$ docker images

1.3.1 虛懸鏡像

我們知道Docker鏡像名由倉庫名和標籤組成,但有時候我們會看到倉庫名和標籤皆爲<none>的鏡像,我們稱爲這種鏡像爲虛懸鏡像,如下圖所示:

Docker三大核心組件:鏡像、容器與倉庫,你瞭解多少呢?

 

虛懸鏡像一般是當我們使用docker pull拉取最新鏡像時,生成的新的鏡像,所以倉庫名和標籤給了新的鏡像,舊的鏡像倉庫和標籤則被取消,成爲虛懸鏡像。

我們可以使用下面的語句打印所有的虛懸鏡像:

$ docker image ls -f dangling=true

一般的虛懸鏡像已經沒有什麼作用了,所以可以清理掉的,下面的命令可以清除所有的虛懸鏡像:

$ docker image prune

不過,如果我們想保留一些有用的虛擬鏡像時,可以使用docker tag命令重新給鏡像起個倉庫名和標籤:

$ docker tag 621d57f27e93 "test:1.0"

1.4 鏡像導出與導入

如果想與別人共享某個鏡像,除了從鏡像服務倉庫中pull鏡像和把鏡像push到倉庫上去之外,其實我們還可以將本地構建好的鏡像直接導出並保存爲文件發送給別人,如下:

$ docker image save /tmp/test_image.tar.gz

而當你拿到別人導出的鏡像文件,你可以使用docker load命令把鏡像加載到本地的Docker鏡像列表中,如下:

$ docker load < /tmp/test_image.tar.gz

1.5 刪除本地鏡像

要刪除一個或多個本地的鏡像,可以使用下面的命令:

docker image rm [option] IMAGE1,IMAGE2,...IMAGEn

也可以使用更簡潔的方式,如:

docker rmi [option] IMAGE1,IMAGE2,...IMAGEn

可以使用鏡像的長id、鏡像短id、鏡像摘要以及鏡像名稱來刪除鏡像,如下

$ docker rmi f7302e4ab3a8

一般更常用鏡像的短id,如:

$ docker rmi f7302

使用鏡像的摘要也可以刪除鏡像,鏡像的摘要可以使用下面的命令查詢:

$ docker image ls --digests

當然我們想要清除本地全部鏡像時,可以使用下面的命令,不過一般不建議使用。

$ docker rmi $(docker images -qa)

另外,一般如果鏡像已經被使用來創建容器,使用上面的命令刪除會報下面的錯誤,告訴我們該鏡像已經被使用,不允許刪除。

Error response from daemon: conflict: unable to remove repository reference "mysql:5.7" (must force) - container ccd406c07a78 is using its referenced image e1e1680ac726

對於已經被用於創建容器的鏡像,刪除方法有兩種,一種是先把容器刪除,再刪除鏡像,另一種則只需要在刪除鏡像的命令中跟一個-f參數便可,如:

$ docker rim -f f7302

1.6 使用docker commit構建鏡像

上面的例子都是直接使用官方提供的鏡像,其實,除了從官方倉庫或其他鏡像倉庫拉取別人構建好的鏡像外,我們也可以構建自己的鏡像,一般有以下兩種構建方式。

使用docker commit命令,我們可以將修改過的容器重新提交爲一個鏡像,如:

$ docker commit conntaner_id my-hello:1.0

使用這種方式構建的鏡像,我們稱爲黑箱鏡像,就是一個黑箱子一樣,別人並不知道我們對容器做了哪些修改和操作,所以會對其安全性有所質疑。

所以不推薦使用這種方式構建鏡像,下面我們介紹一種更加通用且方便的方式。

1.7 使用Dockerfile構建鏡像

一般推薦編寫Dockerfile來構建一種鏡像,Docker Hub上的鏡像都是採用這種方式構建的,採用這種方式的好處就是,我們不用把鏡像分發給別人,而只是把Dockerfile和相應需要寫入鏡像的資料發給別人,別人也能自己構建鏡像,安全透明。

1.7.1 編寫一個簡單的Got程序

package main
import "fmt"
func main(){
 fmt.Println("Hello Go")
}

將Go程序編譯爲可執行程序,如:

$ go build hello.go

1.7.2 編寫Dockerfile文件

下面我們編寫一個簡單的Dockerfile文件,構建自己的第一個鏡像,如下:

# 從一個空白的鏡像開始
FROM stratch
ADD hello /
# 執行
CMD /hello

1.7.3 開始構建鏡像

編寫好Dockerfile文件後,需要使用docker build命令進行構建,docker build命令的格式如下:

$ docker build [OPTIONS] PATH | URL | -
# 注意最後的點(.)表示當前目錄,即Dockerfile所在的目錄
$ docker build -t "hello-go:1.0" .

上面只是簡單演示了使用Dockerfile文件如何構建鏡像,關於Dockerfile,還有許多更加深入地用法,我們之後有機再談。

02 容器(Container)

容器與鏡像的關係,就如同面向編程中對象與類之間的關係。

因爲容器是通過鏡像來創建的,所以必須先有鏡像才能創建容器,而生成的容器是一個獨立於宿主機的隔離進程,並且有屬於容器自己的網絡和命名空間。

我們前面介紹過,鏡像由多箇中間層(layer)組成,生成的鏡像是隻讀的,但容器卻是可讀可寫的,這是因爲容器是在鏡像上面添一層讀寫層(writer/read layer)來實現的,如下圖所示:

Docker三大核心組件:鏡像、容器與倉庫,你瞭解多少呢?

 

2.1 操作容器的相關命令

Usage: docker container COMMAND
Manage containers
Commands:
 attach Attach local standard input, output, and error streams to a runnin g container
 commit Create a new image from a container's changes(把容器保存爲鏡像)
 cp Copy files/folders between a container and the local filesystem
 create Create a new container(創建一個新的容器)
 diff Inspect changes to files or directories on a container's filesyste m
 exec Run a command in a running container(在一個運行的容器中執行命令)
 export Export a container's filesystem as a tar archive
 inspect Display detailed information on one or more containers
 kill Kill one or more running containers(殺死一個或多個正在運行的容器)
 logs Fetch the logs of a container
 ls List containers(顯示本地容器列表)
 pause Pause all processes within one or more containers
 port List port mappings or a specific mapping for the container
 prune Remove all stopped containers
 rename Rename a container(重命名容器)
 restart Restart one or more containers(重啓一個或多個容器)
 rm Remove one or more containers(刪除一個或多個容器)
 run Run a command in a new container(運行一個新的容器)
 start Start one or more stopped containers
 stats Display a live stream of container(s) resource usage statistics
 stop Stop one or more running containers(停止一個或多個容器)
 top Display the running processes of a container
 unpause Unpause all processes within one or more containers
 update Update configuration of one or more containers
 wait Block until one or more containers stop, then print their exit codes

2.2 啓動容器

啓動容器有幾種不同的方式,最常用的方法是使用docker run命令可以通過鏡像創建一個容器,如:

# /bin/bash表示運行容器後要執行的命令
$ docker run -it centos /bin/bash

docker run命令有一些比較常用的參數,比如容器是一種提供服務的守護進程,那麼通常需要開放端口供外部訪問,如:

$ docker run -p 80:80 nginx

也可以爲容器指定一個名稱,如:

$ docker run -p 80:80 --name webserver nginx

另外一種則是使用docker start命令重新啓動已經停止運行的容器,如:

# container_id表示容器的id
$ docker start container_id

而對於正在運行的容器,也可以通過docker restart命令重新啓動,如:

# container_id表示容器的id
$ docker restart container_id

2.3 查看本地容器列表

運行容器後,我們可以通過下面的命令查看本地所有容器:

$ docker container ls

不過docker container ls也簡潔的寫法:

$ docker ps

上面命令執行結果如下:

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f4f184f5ffb9 redis:latest "docker-entrypoint.s…" 6 seconds ago Up 4 seconds 0.0.0.0:6379->6379/tcp myredis
f7d970e7d4ce mysql:5.7 "docker-entrypoint.s…" 7 seconds ago Up 5 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp docker-mysql

上面的命令只會顯示正在運行的容器,如果要顯示全部容器,包含退出執行的,可以加參數-a,如:

$ docker ps -a

有時候,我們只想查到容器的id,可以用下面的命令:

$ docker ps -aq

執行結果

f4f184f5ffb9
f7d970e7d4ce

2.4 停止容器

對於已經不需要的容器,可以使用docker stop命令停止其運行,如:

$ docker stop container_id1,container_id2...

批量停止容器,如:

$ docker stop $(docker ps -qa)

2.5 容器的三種運行模式

概括而言,Docker容器大體上有三種運行模式,如下:

2.5.1 運行後退出

下面語句創建的容器,在運行後會退出。

$ docker run centos echo "hellowrold"

2.5.2 常駐內存,就是守護進程的模式

如果容器中運行一個守護進程,則容器會一直處於運行狀態,如:

$ docker run -d -p 80:80 nginx

2.5.3 交互式

我們也可以在運行容器時,直接與容器交互。

$ docker run -it centos /bin/bash

2.6 刪除容器

$ docker container rm container_id

刪除容器的命令也有簡潔的寫法,如下:

$ docker rm container_id

也可以像上面批量停止容器一樣,我們也可以批量刪除容器,如:

$ docker rm $(docker ps -qa)

2.7 進入容器

對於正在運行的容器,我們也可以通過docker exec命令再次進入容器,如:

$ docker exec -it f4f184f5ffb9 /bin/bash

需要指定容器的id或name,上面的命令我們用的是id。

2.8 導出容器爲鏡像

$ docker export -o ./image.tar.gz f4f184f5ffb9

將容器導出後,我們可以另外一臺有安裝Docker的電腦中將文件包導入成爲鏡像,如:

$ docker import image.tar.gz

上面講的是容器的概念和一些常用的命令,關於容器,還可以設置數據卷和網絡空間,這些我們有機會後面再談。

03 倉庫(Repository)

倉庫(Repository)是集中存儲鏡像的地方,這裏有個概念要區分一下,那就是倉庫與倉庫服務器(Registry)是兩回事,像我們上面說的Docker Hub,就是Docker官方提供的一個倉庫服務器,不過其實有時候我們不太需要太過區分這兩個概念。

3.1 公共倉庫

公共倉庫一般是指Docker Hub,前面我們已經多次介紹如何從Docker Hub獲取鏡像,除了獲取鏡像外,我們也可以將自己構建的鏡像存放到Docker Hub,這樣,別人也可以使用我們構建的鏡像。

不過要將鏡像上傳到Docker Hub,必須先在Docker的官方網站上註冊一個賬號,註冊界面如下,按要求填寫必要的信息就可以註冊了,很簡單的。

Docker三大核心組件:鏡像、容器與倉庫,你瞭解多少呢?

 

註冊好了之後,可以在本地使用命令登錄到Dokcer Hub了,過程如下

# 在命令行中輸入
$ docker login

Docker三大核心組件:鏡像、容器與倉庫,你瞭解多少呢?

 

在輸入賬號密碼登錄到Docker Hub之後,便可以使用docker push命令把鏡像推送到Docker Hub。

$ docker push test:1.0

3.2 私有倉庫

有時候自己部門內部有一些鏡像要共享時,如果直接導出鏡像拿給別人又比較麻煩,使用像Docker Hub這樣的公共倉庫又不是很方便,這時候我們可以自己搭建屬於自己的私有倉庫服務,用於存儲和分佈我們的鏡像。

Docker官方提供了registry這個鏡像,可以用於搭建私有倉庫服務,我們把鏡像拉到本地之後,用下面命令創建該鏡像的容器便可以搭建一個倉庫服務,如下:

$ docker run -d -p 5000:5000 --restart=always --name registry registry

假設我們把一臺IP爲192.168.0.100的服務器作爲倉庫服務,並運行上面的語句,那麼我們可以下面的語句重新構建上面的鏡像,如:

$ docker build -t "192.168.0.100/hello-go:1.0" .

然後使用下面的語句推送到自己的私有倉庫服務器:

$ docker push 192.168.0.100/hello-word:1.0

原文鏈接:https://juejin.im/post/5d57c1b5f265da03dc076ba6#heading-2

04 小結

鏡像是靜態的概念,構建完成之後便不能再修改,而容器則是一個動態的概念,使用Docker可以簡單輕鬆地創建或刪除容器,鏡像與容器的關係,就如同面向對象編程中的類與對象的關係,而倉庫則是存儲和分發鏡像的地方。

看完後如果覺得有所收穫,就請轉發一下點個贊再走唄~

Docker三大核心組件:鏡像、容器與倉庫,你瞭解多少呢?

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章