Docker的三大核心組件:鏡像,容器與倉庫

原創做者,公衆號【程序員讀書】,歡迎關注公衆號,轉載文章請註明出處哦。mysql

鏡像(Image)容器(Container)倉庫(Repository)是咱們常說的Docker的三大組件,其實咱們在上一篇文章《10分鐘快速掌握Docker必備基礎知識》已經有簡單地瞭解過三大組件的知識,可是並無很詳細地講解,因此在這篇文章中,咱們就來一塊兒詳細地探索一番吧。nginx

鏡像(Image)

什麼是Docker鏡像?程序員

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

談到這裏,咱們可能須要先補充一點與Linux操做系統相關的知識:redis

通常而言, Linux分爲兩個部分:Linux內核(Linux Kernel)用戶空間,而真正的Linux操做系統,是指Linux內核,咱們經常使用的Ubuntu,Centos等操做系統實際上是不一樣廠商在Linux內核基礎上添加本身的軟件與工具集(tools)造成的發佈版本(Linux Distribution)。sql

所以,咱們也能夠把鏡像當作是上面所說的用戶空間,當Docker經過鏡像建立一個容器時,就是將鏡像定義好的用戶空間做爲獨立隔離的進程運行在宿主機的Linux內核之上。docker

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

  1. 鏡像是分層(Layer)的:即一個鏡像能夠多箇中間層組成,多個鏡像能夠共享同一中間層,咱們也能夠經過在鏡像添加多一層來生成一個新的鏡像。centos

  2. 鏡像是隻讀的(read-only):鏡像在構建完成以後,便不能夠再修改,而上面咱們所說的添加一層構建新的鏡像,這中間實際是經過建立一個臨時的容器,在容器上增長或刪除文件,從而造成新的鏡像,由於容器是能夠動態改變的。安全

經過下面的示意圖,我能夠更好地理解Docker鏡像Linux的關係:

操做鏡像的命令

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(給鏡像打標籤)
複製代碼

獲取鏡像

在安裝了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
複製代碼

查看本地鏡像

經過上面的方法咱們將鏡像拉取到了本地,那要如何查看本地有哪些鏡像呢?經過下面的命令咱們能夠查看本地的所有鏡像:

$ docker image ls
複製代碼

固然Docker提供了更簡潔的寫法,以下:

$ docker images
複製代碼
虛懸鏡像

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

虛懸鏡像通常是當咱們使用docker pull拉取最新鏡像時,生成的新的鏡像,因此倉庫名標籤給了新的鏡像,舊的鏡像倉庫和標籤則被取消,成爲虛懸鏡像

咱們可使用下面的語句打印全部的虛懸鏡像

$ docker image ls -f dangling=true
複製代碼

通常的虛懸鏡像已經沒有什麼做用了,因此能夠清理掉的,下面的命令能夠清除全部的虛懸鏡像:

$ docker image prune
複製代碼

不過,若是咱們想保留一些有用的虛擬鏡像時,可使用docker tag命令從新給鏡像起個倉庫名和標籤:

$ docker tag 621d57f27e93 "test:1.0"
複製代碼

鏡像導出與導入

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

$ docker image save -o /tmp/test_image.tar.gz centos:latest
複製代碼

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

$ docker load < /tmp/test_image.tar.gz
複製代碼

刪除本地鏡像

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

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
複製代碼

使用docker commit構建鏡像

上面的例子都是直接使用官方提供的鏡像,其實,除了從官方倉庫或其餘鏡像倉庫拉取別人構建好的鏡像外,咱們也能夠構建本身的鏡像,通常有如下兩種構建方式。

使用docker commit命令,咱們能夠將修改過的容器從新提交爲一個鏡像,如:

$ docker commit conntaner_id my-hello:1.0
複製代碼

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

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

使用Dockerfile構建鏡像

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

編寫一個簡單的Got程序
package main
import "fmt"

func main(){
    fmt.Println("Hello Go")
}
複製代碼

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

$ go build hello.go
複製代碼
編寫Dockerfile文件

下面咱們編寫一個簡單的Dockerfile文件,構建本身的第一個鏡像,以下:

# 從一個空白的鏡像開始
FROM stratch
ADD hello /
# 執行
CMD /hello
複製代碼
開始構建鏡像

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

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

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

容器(Container)

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

由於容器是經過鏡像來建立的,因此必須先有鏡像才能建立容器,而生成的容器是一個獨立於宿主機的隔離進程,而且有屬於容器本身的網絡和命名空間。

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

操做容器的相關命令

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 複製代碼

啓動容器

啓動容器有幾種不一樣的方式,最經常使用的方法是使用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
複製代碼

查看本地容器列表

運行容器後,咱們能夠經過下面的命令查看本地全部容器:

$ 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
複製代碼

中止容器

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

$ docker stop container_id1,container_id2...
複製代碼

批量中止容器,如:

$ docker stop $(docker ps -qa)
複製代碼

容器的三種運行模式

歸納而言,Docker容器大致上有三種運行模式,以下:

運行後退出

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

$ docker run centos echo "hellowrold"
複製代碼
常駐內存,就是守護進程的模式

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

$ docker run -d -p 80:80 nginx
複製代碼
交互式

咱們也能夠在運行容器時,直接與容器交互。

$ docker run -it centos /bin/bash
複製代碼

刪除容器

$ docker container rm container_id
複製代碼

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

$ docker rm container_id
複製代碼

也能夠像上面批量中止容器同樣,咱們也能夠批量刪除容器,如:

$ docker rm $(docker ps -qa)
複製代碼

進入容器

對於正在運行的容器,咱們也能夠經過docker exec命令再次進入容器,如:

$ docker exec -it f4f184f5ffb9 /bin/bash
複製代碼

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

導出容器爲鏡像

$ docker export -o ./image.tar.gz f4f184f5ffb9
複製代碼

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

$ docker import image.tar.gz
複製代碼

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

倉庫(Repository)

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

公共倉庫

公共倉庫通常是指Docker Hub,前面咱們已經屢次介紹如何從Docker Hub獲取鏡像,除了獲取鏡像外,咱們也能夠將本身構建的鏡像存放到Docker Hub,這樣,別人也可使用咱們構建的鏡像。

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

註冊好了以後,能夠在本地使用命令登陸到Dokcer Hub了,過程以下:

# 在命令行中輸入
$ docker login
複製代碼

在輸入帳號密碼登陸到Docker Hub以後,即可以使用docker push命令把鏡像推送到Docker Hub

$ docker push test:1.0
複製代碼

私有倉庫

有時候本身部門內部有一些鏡像要共享時,若是直接導出鏡像拿給別人又比較麻煩,使用像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
複製代碼

小結

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


歡迎掃碼關注,共同窗習進步

相關文章
相關標籤/搜索