docker入門知識總結

TheMonkeyKing_發表於2020-11-01

Docker入門知識的個人筆記總結,不適合0基礎的同學作為入門資料學習。

Docker為什麼比虛擬化省資源?

Docker利用了Linux核心中的資源分離機制,如cgroups和linux的名稱空間namespace,來建立獨立的容器。它和宿主機共用核心,避免了虛擬機器使用自己獨立作業系統所帶來的開銷。

Docker如何實現資源隔離

cgroups提供硬體計算資源的隔離,包括cpu,記憶體,儲存,io與網路。

名稱空間隔離了工作環境,包括程式數、網路、使用者ID、掛載系統等等

名稱空間分為6種,不同版本的linux核心對其支援程度是不同的,具體如下:

namespace系統呼叫引數隔離內容最終完成的核心版本
UTSCLONE_NEWUTS主機名和域名2.6.19
IPCCLONE_NEWIPC訊號量,訊息佇列與共享記憶體2.6.19
PIDCLONE_NEWPID程式編號2.6.24
NetworkCLONE_NEWNET網路裝置、網路棧、埠等2.6.29
MountCLONE_NEWNS檔案系統2.4.19
UserCLONE_NEWUSER使用者和使用者組3.8

國內大多愛用Centos和Ubuntu,部署docker服務最好使用Centos7以上或Ubuntu,Centos6的原始核心太老對Docker的支援不太好。

docker架構的組成部分

Docker 的核心元件包括:

  1. Docker 客戶端 - Client,使用docker命令實現對容器的管理
  2. Docker 服務端/引擎 - Docker daemon 管理和docker客戶端的互動,管理容器程式
  3. Docker 映象 - Image
  4. Registry - 映象倉庫
  5. docker 容器 - Container

在這裡插入圖片描述

容器與映象的區別

  • 映象(Images)

    • 只讀的硬碟檔案,用來建立容器
    • 一個映象經常是基於另一個映象,加了一些定製化內容
    • 你可以構建自己的映象,你也可以使用別人放在公共映象倉庫的映象
  • 容器(Containers)

    • 容器是一個映象執行時的例項
    • 可以通過docker的api或者命令列命令對container進行建立、執行、移動,刪除等操作
    • 一個容器可以被連線進多個網路、新增儲存或者根據目前的容器狀態建立一個新的映象

docker的安裝

Centos7的Extra倉庫提供了docker-ce的安裝包,但是版本可能相對老一些。

官方網站的是最新版本但是源站的yum倉庫在海外,很慢。可以使用國內的映象倉庫

比如使用清華大學的映象:

sudo yum remove docker docker-common docker-selinux docker-engine
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
wget -O /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo
sudo sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
sudo yum makecache fast
sudo yum install docker-ce

其他系統版本可參考:
https://mirror.tuna.tsinghua.edu.cn/help/docker-ce/

安裝後可以進行docker環境的檢查:

docker version可以檢視當前docker及其內部元件的具體版本

[root@master ~]# docker version
Client: Docker Engine - Community
 Version:           19.03.12
 API version:       1.40
 Go version:        go1.13.10
 Git commit:        48a66213fe
 Built:             Mon Jun 22 15:46:54 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.12
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.10
  Git commit:       48a66213fe
  Built:            Mon Jun 22 15:45:28 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

Docker常用操作

docker search

在docker hub上搜尋該images

docker pull

從某個repository或者registry拉取映象

docker images

列出images

docker create

建立一個新的container

docker start

啟動一個或多個容器

docker run

在一個新的容器中執行一個命令

docker attach

掛載至一個執行的容器

docker ps

列出容器列表

docker logs

獲得某個容器的日誌;容器的日誌預設是列印至容器的tty終端的,因此需要使用該命令才能列印至宿主機的tty終端

docker restart

重啟一個容器

docker stop

停止一個或多個容器

docker kill

殺死一個或多個容器

docker rm

移除一個或多個容器

容器的生命週期

在這裡插入圖片描述

Docker Image

Docker映象含有啟動容器所需要的的檔案系統及其內容,因此,其用於建立並啟動docker 容器。

  • 採用分層構建機制,最底層為bootfs,其次為rootfs
    • bootfs:用於系統引導的檔案系統,包括bootloader和kernel,容器啟動完成後會被解除安裝以節約記憶體資源
    • rootfs:位於bootfs之上,表現為docker容器根檔案系統。docker中,rootfs由核心掛載為只讀模式,然後通過聯合掛載技術額外掛載一個可寫層。

在這裡插入圖片描述

docker的映象層次

位於下層的映象被稱為父映象(parentn image),最底層的稱為基礎映象(base image)

最上層為可寫層,其下均為只讀層。
在這裡插入圖片描述

聯合掛載檔案系統將這些層次組織起來,常見的聯合掛載系統有aufs(ubuntu預設),devicemapper(centos7預設),overlayfs等

Docker registry

啟動容器時,docker daemon會試圖從本地獲取相關映象,本地映象不存在時,其將從Registry中下載該映象並儲存到本地

registry:registry是一個無狀態的,高度可擴充套件的伺服器應用程式,負責儲存和分發docker images

在這裡插入圖片描述

Docker Registry

Registry 用於儲存docker映象,包括映象的層次結構和後設資料。使用者可以自建Registry,也可以使用官方的Docker Hub

分類:

  • Sponsor Registry:第三方的registry,供客戶和Docker社群使用
  • Mirror Registry:第三方的registry,只讓客戶使用
  • Vendor Registry:由釋出Dokcer映象的供應商提供的registry
  • Private Registry:通過設有防火牆和額外的安全層的私有實體提供的registry

Repository

由某個特定的docker映象的所有迭代版本組成的映象倉庫

  • 一個Registry中可以存在多個Repository
    • Repositry可以分為"頂層倉庫"和"使用者倉庫"
    • 使用者倉庫名稱格式為"使用者名稱/倉庫名"
  • 每個倉庫可以包含多個Tag,每個Tag對應一個映象

registry可以理解為Repository的倉庫,repository是images的倉庫

registry中的映象通常由開發人員製作,而後推送至"公共"或"私有"Registry上儲存,供其他人員使用,例如部署到生產環境。
在這裡插入圖片描述

Docker Hub

docker預設的雲端倉庫服務。主要提供了以下功能。

  • Image Repositories(映象倉庫)
    • 從社群和官方庫中尋找、拉取、管理、上傳映象
  • Automated Builds(自動構建)
    • 當你改變映象構建原始碼時,自動建立新的映象
  • Webhooks
  • 當你成功push之後可以繫結一個鉤子去觸發一些動作
  • Organizations
    • 建立工作組來管理映象倉庫
  • GitHub and Bitbucket Integration
    • 將docker hub加入至持續整合工作流中

可以使用如下格式的命令從指定倉庫獲取映象:
docker pull [:]/[/]:

映象製作途徑

  • 通過Dockerfile製作映象
  • 從一個執行中的容器製作映象(執行中容器改動後製作成映象)

基於容器製作映象

docker commit [OPTIONS] CONTAINER [REPOSITORY:[TAG]

選項預設值(如果有)Description
–author, -a作者
–change,-c提交同時改變Dockerfile中的內容
–message,-m提交message
–pause,-ptrue提交期間掛起容器

例子:
docker commit --change=‘CMD [“httpd”, “-h /data/httpd/htdocs”, “-f”]’ -c “EXPOSE 80” bbox1 suny/busybox/httpd:v0.1

為映象打標籤

docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

可以基於ID打標,或者基於名稱和標籤打標,還額可以基於私有Registry打標。

將映象push到Docker倉庫

推倒Docker Hub時首先需要使用docker login登入,然後使用docker push

docker push USERNAME/IMAGE

映象匯入和匯出

  • docker save

    • 儲存一個或多個映象到一個tar包(預設STDOUT)
    • docker save [OPTIONS] IMAGE [IMAGE…]
      • –output,-o:寫到一個檔案,而不是STDOUT
  • docker load

    • Load一個image從一個tar或者STDIN
    • docker load [OPTIONS]
      • –input,-i:從一個TAR檔案而不是STDIN
      • –quiet,-q:抑制輸出

Docker 資料卷

docker映象由多個只讀層疊加而成,啟動容器時,Docker會載入只讀映象層並在映象棧頂部新增一個讀寫層

如果執行中的容器修改了現有的一個已經存在的檔案,那該檔案將會從讀寫層下面的只讀層複製到讀寫層,該檔案的只讀版本仍然存在,只是已經被讀寫層中該檔案的副本所隱藏,這就是“寫時複製(COW)”機制

在這裡插入圖片描述

關閉並重啟容器,其資料不受影響,但是刪除容器後,更改會全部丟失。

docker的資料讀寫機制帶來如下問題:

  • 儲存於聯合檔案系統中,不易於宿主機訪問
  • 容器間的共享不變
  • 刪除容器後資料會丟失

解決方案:Data volumes

Docker volumes

卷是容器上的一個或多個目錄,此類目錄可繞過聯合檔案系統,與宿主機的某目錄關聯。

在這裡插入圖片描述

Data volumes提供瞭如下一些特性以便於容器間的資料共享與持久化:

  • volume與容器初始化之時就會建立,由base image提供的卷中的資料會在此期間完成複製
  • 容器間的volumes可以被共享或重用
  • 可以直接對volume中的資料進行修改
  • volume中的資料不影響image更新升級
  • 即使容器自身被刪除,容器卷也會存留。即使volume沒有被任何容器引用,也不會主動做垃圾回收操作。volume的資料持久化獨立於容器的生命週期之外。

映象好比原始碼,容器好比執行原始碼後的程式,卷好比資料。於是映象可以重用,卷可以共享。

卷實現了原始碼(映象)和資料(卷)的分離,使用者製作映象時無須考慮映象執行的容器所在的主機的環境。

在這裡插入圖片描述

資料卷型別

Docker有兩種型別的卷,每種型別都在容器中存在一個掛載點,但其在宿主機上的位置有所不同。

  • bind mount volume
    • 和宿主機檔案系統中的某一目錄繫結的卷,資料儲存於與卷繫結的宿主機目錄中
  • docker managed volume
    • 由docker daemon建立的卷,在宿主機中表現為docker所屬的一個檔案

在這裡插入圖片描述

docker run命令使用-v選項即可使用Volume

  • Docker-managed volume
    • docker run -it -name bbox1 -v /data busybox
    • docker inspect -f {{.Mounts}} bbox1
  • Bind-mount Volume
    • docker run -it -v HOSTDIR:VOLUMEDIR --name bbox2 busybox
    • docker inspect -f {{.Mounts}} bbox2

共享資料卷

多個容器之間可以通過如下兩種方式共享資料卷。

  • 多個容器的卷使用同一個主機目錄。如:
    • docker run -it --name c1 -v /docker/volumes/v1:/data busybox
    • docker run -it --name c2 -v /docker/volumes/v1:/data busybox
  • 複製使用其他容器的卷,docker run命令使用–volumes-from選項
    • docker run -it --name bbox1 -v /docker/volumes/v1:/data busybox
    • docker run -it --name bbox2 --volumes-from bbox1 busybox

docker 網路

單主機虛擬網路:容器之間可互通,但是和外界隔離

多主機網路
在這裡插入圖片描述
在這裡插入圖片描述

橋接式容器(Bridged containers)

橋接式容器一般擁有兩個介面,一個環回介面,一個連線至主機上某個橋裝置的乙太網介面。

docker daemon 啟動時預設會建立一個名為docker0的網路橋,並且建立的容器為橋接式容器,其乙太網介面橋接至docker0

  • –net bridge即為將容器介面新增至 docker0橋

docker0橋為NAT橋,因此橋接式容器可通過此橋介面訪問外部網路,但防火牆規則阻止了一切從外部網路訪問橋接式容器的請求。

docker run --rm --net bridge busybox:latest ifconfig -a

引數補充:
- --hostname HOSTNAME : 為容器指定主機名
- --dns DNS_SERVER_IP 為容器指定所使用的的dns伺服器地址
- --add-host HOSTNAME:IP為容器指定本地主機名解析

封閉式容器(Closed containers)

  • 不參與網路通訊,執行於此類容器中的程式僅能訪問本地環回介面
  • 僅適用於程式無需網路通訊的場景中,如備份、程式診斷及各種離線任務等。
    • docker run --rm --net none busybox:latest ifconfig -a

Opening inbound communication

Docker0為NAT橋,因此容器一般獲得的是私有網路地址

可以把容器想象為宿主機NAT伺服器背後的主機

如果開放容器或騎上的服務為可被外部網路訪問,需要在宿主機上為其定義DNAT規則。如:

  • 對宿主機某IP地址的某埠的訪問對映給某容器地址的某埠
    -A PREROUTING -d 主機IP -j DNAT --to-destination 容器IP
  • 對宿主機某IP地址的某埠的訪問對映給某容器地址的某埠
    • 主機IP:PORT 容器IP:PORT
      • -A PREROUTING -d 主機IP -p {tcp|udp} --dport 主機埠 -j DNAT --to-destination 容器IP:容器埠

為docker run 命令使用-p選項即可實現埠對映,無需手動新增規則:

  • -p
    • 將指定的容器埠對映至主機所有地址的一個動態埠
  • -p :
    • 將指定的容器埠對映至主機指定的主機埠
  • -p ::
    • 將指定的容器埠對映到主機指定ip的動態埠
  • -p ::
    • 將指定的容器埠對映至主機指定ip的埠hostPort

“動態埠”指的是隨機埠,具體的對映結果可使用docker port命令檢視。

可以使用-P或–publish-all將容器所有計劃要暴露的埠全部對映至主機埠,如:

docker run -d -P --expose 2222 --expose 3333 --name web busybox:latest /bin/httpd -p 2222 -f

docker port web

如果不想使用預設的docker0橋介面,或者需要修改此橋介面的網路屬性,可以通過docker daemon命令使用-b,–bip,–fixed-cidr,–default-gateway,–dns和–mtu等選項進行設定。

聯盟式容器(Joined containers)

聯盟式容器是指使用某個已存在容器的網路介面的容器,介面被聯盟內的各個容器共享使用,因此聯盟式容器彼此間的網路名稱空間是共用的。

  • 建立一個監聽與2222埠的http伺服器
    • docker run -d -it --rm -p 2222 busybox:latest /bin/httpd -p 2222 -f
  • 建立一個聯盟式容器,並檢視其監聽的埠
    • docker run -it --rm --net container:web --name joined busybox:latest netstat -tan

聯盟式容器間網路名稱空間雖然共用,但是其他名稱空間比如User,Mount等還是隔離的

聯盟式容器彼此間存在埠衝突的可能性,因此,通常只會在多個容器上的程式lookback互相通訊,或對某個已存在的容器的網路屬性進行監控時才是用這種模式的網路模型。

開放式容器(open containers)

開放式容器共享主機網路名稱空間的容器,他們對主機的網路名稱空間擁有全部的訪問全向,包括訪問哪些關鍵性服務,這對宿主機安全性有很大的潛在威脅。

為docker run命令使用–net host選項即可建立開放式容器,例如:
docker run -it --rm --net host busybox:latest /bin/sh

Dockerfile

前文提到過,映象的生成途徑包括Dockerfile和基於容器製作。本節介紹Dockerfile。

Dockerfile是構建docker image的原始碼。
Docker可以通過閱讀Dockerfile的指令來自動構建docker images。一個Dockerfile檔案只是一個包含了所有配置映象命令的文字檔案。

Dockerfile語法

#開頭為註釋
每行為一個命令,基礎格式為:指令+引數。指令是大小寫不敏感的。但是將指令大寫是約定俗成的慣例,它可以很好地將指令和引數區分開

docker執行dockerfile時,從上到下依次執行

第一條指令必須是FROM,以確定你需要構建映象的基礎映象。

常用指令

FROM

必須為Dockerfile檔案開篇的第一個非註釋行,用於為映像檔案構建過程指定基準映象。後續的指令執行於此基準映象所提供的執行環境。

基準映象可以是任何可用的映象檔案。預設情況下docker build會在docker主機上查詢指定的映象檔案,其不存在時,則會從Docker Hub Registry上拉取所需的映象檔案。

語法:

  • FROM [:] 或者
  • FROM @

MAINTANIER

用於讓Dockerfile製作者提供本人的詳細資訊。Dockerfile並不限制MAINTAINER指令出現的位置,但是建議將其放置於FROM指令之後。

語法:

  • MAINTAINER <author’s info> 如:
  • MAINTAINER “suny suny@eusc.com”

COPY

用於從Docker主機複製檔案至建立的新映像檔案

語法:

  • COPY … 或者
  • COPY ["",…""]
    • 要複製的原始檔或目錄,支援使用萬用字元
    • 目標路徑,映象中檔案系統路徑,建議使用絕對路徑,否則以WORKDIR為其起始路徑。

檔案複製準則:

  • 必須是build上下文中的路徑,不能是其父目錄中的檔案
  • 如果是目錄,則其內部檔案或子目錄會被遞迴複製,而src目錄自身不會被複制
  • 如果指定了多個,或者在中使用了萬用字元,則必須是一個目錄,且必須以/結尾。
  • 如果事先不存在,他將會被自動建立,這包括父目錄路徑。

ADD

ADD指令類似於COPY指令,ADD支援使用TAR檔案和URL路徑

語法:

  • ADD … 或者
  • ADD ["",…""]

操作準則:

  • 同COPY指令
  • 如果為URL且dest不以/結尾,則被下載並直接建立為dest,若以/結尾,則檔案被下載至dest目錄,原檔名保留
  • 如果src是tar檔案,則被展開為一個目錄,行為類似tar -x命令;通過URL獲取的tar檔案不會自動展開

WORKDIR

用於為Dockerfile中所有的RUN,CMD,ENTRYPOINT,COPY和ADD指定設定工作目錄

語法:

  • WORKDIR
    • 在Dockerfile檔案中,WORKDIR指令可出現多次,其路徑也可以為相對路徑,不過是相對於前一個WORKDIR指令指定的路徑
    • WORKDIR也可以呼叫由ENV指定定義的變數

如:
- WORKDIR /var/log
- WORKDIR $STATEPATH

VOLUME

用於在image中建立一個掛載點目錄,以掛載Docker host上的卷或其他容器上的卷。

  • VOLUME
  • VOLUME [""]

EXPOSE

用於為容器開啟指定要監聽的埠以實現與外部通訊。

  • EXPOSE [/][[/]]
    • protocol用於指定傳輸協議,tcp或udp,預設tcp

如:

  • EXPOSE 指令可以一次指定多個埠
  • EXPOSE 11211/udp 11211/tcp

ENV

ENV用於指明容器環境中的環境變數。

引用環境變數時可以用 v a r i a b l e n a m e 或 者 variable_name或者 variablename{variable_name}

${variable_name}這種語法也被一些標準的bash直譯器支援

  • ${variable:-word} 如果變數已被賦值值,那麼最終值將為此前設定的值,如果此前未賦值,則為此時賦的值
  • ${variable:+word} 如果此前變數有值則覆蓋,如果變數無值,則賦給它空字串

ENV =

RUN

指定docker build過程中執行的程式

  • RUN

  • RUN ["","",""]

  • 第一種格式中,通常是一個shell命令,且以"/bin/sh -c"來執行它,這意味著此程式在容器中的PID不是1,不能接受Unix訊號,因此當使用docker stop 命令停止容器的時候,此程式收不到SIGTERM訊號;

  • 第二種語法格式中的引數是一個JSON格式的陣列,executable是要執行的命令,是傳遞給命令的選項或引數。然而,此種格式指定的命令不會以/bin/sh -c來發起,因此常見的shell操作如變數替換及萬用字元替換不會進行,不過要執行的命令想依賴於shell特性的話,可以將其替換為類似下面的格式。

  • RUN ["/bin/bash","-c","",“param1”]

CMD

類似於RUN指令,CMD指令也可以用於執行任何命令或者應用程式,但是兩者的執行時間點不同。

  • RUN指令執行於映像檔案構建過程中,而CMD指令執行於基於Dockerfile構建出的新映像檔案啟動第一個容器時

語法:

  • CMD
  • CMD [“executable”,"",""]
  • CMD ["",""]

前兩種語法格式的意義同RUN

第三種則用於ENTRYPOINT指令提供預設引數

ENTRYPOINT

類似CMD指令的功能,用於為容器指定預設的執行程式,從而使得容器像是一個單獨的可執行程式。

與CMD不同的是,由ENTRYPOINT啟動的程式不會被docker run 命令列指定的引數所覆蓋,而且這些命令列引數會被當做引數傳遞給ENTRYPOINT指定的程式。docker run命令的–entrypoint選項的引數可以覆蓋ENTRYPOINT指令指定的程式。

語法:

  • ENTRYPOINT
  • ENTRYPOINT [“executable”,"",""]

docker run 命令傳入的命令引數會覆蓋CMD指令的內容並附加到ENTRYPOINT命令最後作為其引數使用。

Dockerfile檔案中可以存在多個ENTRYPOINT指令,但是僅有最後一個會生效。

RUN,CMD,ENTRYPOINT之間的區別:

  • RUN:執行於docker build階段,每個都有效
  • CMD:執行於docker run階段,僅最後一個有效
  • ENTRYPOINT:執行於docker run階段,僅最後一個有效

USER

用於指定執行image時的或執行Dockerfile中任何RUN、CMD、或ENTRYPOINT指令指定的程式時的使用者名稱或者UID

預設情況下,container的執行身份是root使用者。

語法:

  • USER |

uid需要是在/etc/passwd中有效的使用者UID

ONBUILD

用於在Dockerfile中定義一個觸發器。Dockerfile用來build映像檔案,這個映像也可以作為base image被另外一個Dockerfile用作FROM指令的引數,並以之構建新的映像檔案,此時將會觸發base image的Dockerfile檔案中的ONBUILD指令定義的觸發器。

ONBUILD不能自我巢狀,且不會觸發FROM和MAINTAINER指令

使用包含ONBUILD指令的Dockerfile構建的映象應該使用特殊的標籤,如ruby:2.0-onbuild

在ONBUILD指令中使用ADD或COPY指令應該格外小心,因為新構建過程的上下文在缺少指定的原始檔時會失敗。

.dockerignore file

在docker cli傳送內容給docker daemon時,他會先查詢.dockerignore檔案中的內容。如果存在則將.dockerignore檔案中的內容排除在外。

Docker資源限制

docker提供了三種flag來管理記憶體、cpu、和裝置資源,可以在docker run和dockeer create命令中使用:

  • 記憶體限制

    • -m或者–memory
  • CPU限制

    • –cpu-shares
    • –cpuset-cpus
  • devices

    • –device
  • –ipc

  • –privileged

Docker Private Registry

可以通過docker-distribution建立私有倉庫

yum install docker-distribution

更改docker-daemon服務,使其能夠預設從私有倉庫拉取而不是docker hub