Docker容器技術基礎

一、Docker簡介

[TOC]

1.1、什么是Docker

? Docker是在2013年由dotCloud發起的一個開源項目,使用Go語言進行開發,基于LInux內核的cgroup、namespace等技術,對進程進行封裝隔離,屬于操作系統層面的虛擬化技術。

? Docker基于LXC的基礎上進一步封裝,從文件系統、網絡互聯到進程隔離等等,極大簡化了容器的創建和維護,使Docker技術比虛擬機技術更為輕便、快捷。

docker1.png

1.2、為什么使用Docker

  • 更高效的系統資源利用率

    ? 由于容器不需要進行硬件虛擬化以及運行完整操作系統等額外開銷,Docker對系統資源利用率更高。無論是應用執行速度、內存損耗或者文件存儲速度,都要比傳統虛擬機技術更高效。因此,相比虛擬機技術,一個相同配置的主機,往往可以運行更多數量的應用。

  • 更快速的啟動時間

    傳統虛擬機技術啟動應用服務因需要啟動完整的操作系統,往往需要數分鐘,而Docker容器應用運行于宿主機內核,無需啟動完整的操作系統,因此可以做到秒級、甚至毫秒級啟動。大大節約了開發、測試、部署的時間。

  • 環境一致性

    開發過程中一個常見的問題是環境一致性問題。由于開發、測試、預發布、生產環境不一致,導致有些問題未及時發現。而Docker的鏡像提供了除內和外完整的運行時環境,確保了應用運行環境一致性。

  • 更高效的持續交付和部署

    通過Docker可以定制應用鏡像實現持續集成、持續交付、持續部署,可以很容器的部署或遷移到另一個平臺,而不用擔心運行環境的變化導致應用無法正常運行。

  • 更輕松的維護和擴展

    Docker使用分層存儲以及鏡像的技術,可以更容易的復用應用重復部分,應用的部署、運維也更加簡單。

對比傳統虛擬機總結:

特性 容器 虛擬機
啟動 秒級 分鐘級
硬盤使用 一般為MB 一般為GB
性能 接近原生 弱于原生
系統支持量 單機支持上千個容器 一般為幾十個

二、基本概念

Docker包含了三大基本概念:

  • 鏡像(Image)

    Docker鏡像是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些為運行時準備的一些配置參數(如環境變量、用戶等)。鏡像不包含任何動態數據,其內容在構建之后也不會被改變,這個和容器的根本區別。

  • 容器(Container)

    鏡像和容器的關系,就像是面向對象程序設計中的實例一樣,鏡像是靜態的定義,容器是鏡像運行時的實體。容器可以被創建、啟動、停止、刪除、暫停等。容器運行時,以鏡像為基礎層(鏡像本身時只讀的),在其上創建一個可寫層,鏡像本身時保持不變的。

  • 倉庫(Repository)

    Docker倉庫類似于代碼倉庫,是Docker集中存放鏡像文件的地方。很多時候有人會將Docker倉庫和注冊服務器(registry)混為一談。實際上,注冊服務器是存放倉庫的地方,可以包含多個倉庫;每個倉庫可以包含多個標簽(tag);每個標簽對應一個鏡像。

三、Docker安裝

3.1、Ubuntu

安裝必要的一些系統工具

apt-get -y install apt-transport-https ca-certificates curl software-properties-common

安裝GPG證書

curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

添加軟件源

add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"

安裝Docker

apt-get -y update
apt-get -y install docker-ce

安裝指定版本:

查詢docker版本

apt-cache madison docker-ce

安裝指定版本(VERSION 例如18.06.1ce-0ubuntu-xenial)

apt-get -y install docker-ce-[VERSION]

3.2、CentOS7

安裝必要的一些系統工具

yum -y install yum-utils device-mapper-persistent-data lvm2

添加軟件源

yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

安裝Docker

yum makecache fast
yum -y install docker-ce

安裝指定版本:

查詢docker版本

yum list docker-ce --showduplicates | sort -r

安裝指定版本(VERSION 例如18.09.0.ce.1-1.el7.centos)

yum -y install docker-ce-[VERSION]

3.3、Docker配置文件

cat > /etc/docker/daemon.json <<EOF
{
 "registry-mirrors": ["https://registry.docker-cn.com"],
 "exec-opts": ["native.cgroupdriver=systemd"],
 "storage-driver": "overlay2",
 "storage-opts":["overlay2.override_kernel_check=true"],
 "graph": "/data/data/docker",
 "log-driver": "json-file",
 "log-opts": {
     "max-size": "100m",
     "max-file": "10"
 },
 "oom-score-adjust": -1000,
 "bip": "192.168.100.1/24"
}
EOF

注意:

  • registry-mirrors指定鏡像加速地址,這里指定官方在國內的地址
  • insecure-registries指定私有docker倉庫地址
  • docker默認存放路徑在/var/lib/docker下,graph可以自定義存放路徑。
  • bip可以指定docker運行的網段

四、Docker常用操作

4.1、操作容器

從鏡像創建并啟動容器(需要注意的是,容器運行在后臺模式下,是不能使用--rm選項的。)

docker run -itd -p 8080:8080 -v /data:/data --name k8s registry.k8sre.com/library/alpine:3.9
docker container run -it --rm registry.k8sre.com/library/alpine:3.9

說明:

1、-t 選項讓Docker分配一個偽終端并綁定到容器的標準輸入上

2、-i 選項讓容器的標準輸入保持打開

3、-d選項讓容器可以后臺運行

4、當操作者執行docker run --privileged --privileged=true 時,Docker將擁有訪問主機所有設備的權限,同時Docker也會在apparmor或者selinux做一些設置,使容器可以容易的訪問那些運行在容器外部的設備。

查看容器

docker ps           #列出當前正在運行的容器
docker ps -a        #列出所有的容器,包括正在運行的和其他未運行的
docker ps -l        #列出最近一次啟動的容器
docker ps -a -q     #列出所有容器的CONTAINER_ID
docker container ls -a #列出所有容器

啟動/停止/重啟/刪除容器(新版本逐步使用docker container來管理容器)

docker start xxxx
docker stop xxxx
docker restart xxxx
docker rm -f xxxx
docker container prune #清理容器

進入容器

docker attach xxxx
docker exec -it xxxx

注意:使用docker attach從這個sedin中exit,會導致容器的停止,而docker exec并不會。所以推薦大家使用docker exec。

導出和導入容器

docker save alpine:3.9 -o xxx.tar 
docker load -i xxx.tar
docker export alpine:3.9 > alpine.tar
cat alpine.tar | docker import - registry.k8sre.com/library/alpine:3.9

注意:既可以使用docker load來導入鏡像文件到本地鏡像庫,也可以使用docker import來導入一個容器快照到本地鏡像庫。這兩者的區別在于docker import導入容器快照文件將丟棄所有的歷史記錄和元數據信息(即僅保存容器當時的快照狀態),而docker load導入鏡像存儲文件將保存完整記錄,體積也要大。此外容器快照文件導入時可以重新制定標簽等元數據信息。

宿主機與容器間傳文件

docker cp -r /root/tomcat.tar.gz CONTAINER_ID:/root #從宿主機復制到容器
docker cp -r CONTAINER_ID:/root/tomcat.tar.gz /root/    #從容器復制到宿主機

創建并使用存儲卷

docker run -v /data/downloads:/usr/downloads  --name dataVol ubuntu64 /bin/bash
docker run -it --volumes-from dataVol ubuntu64 /bin/bash

4.2、操作鏡像

docker1.13+推薦使用docker image管理鏡像

從Dockerfile構建鏡像

docker build -t registry.k8sre.com/libary/alpine:3.9 .

將運行的容器保存為鏡像

docker commit -a "作者名字" -m "說明文字" 容器ID 鏡像名:tag

搜索/獲取鏡像

docker search ubuntu
docker pull [選項] [Docker Registry地址]<倉庫名>:<標簽>
docker image pull ubunut:18.04      

查看鏡像

docker images -q
docker history IMAGE_ID     #查看鏡像內的歷史記錄
docker image ls 
docker images --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}" #自定義結構查看鏡像

刪除鏡像

docker rmi $(docker images -q -f dangling=true)     #刪除所有虛懸鏡像
docker rmi IMAGE_ID/$(docker images -q)                 #刪除單個或所有鏡像

推送鏡像到倉庫

docker login -u k8sre registry.k8sre.com
docker tag IMAGE_ID registry.k8sre.com/libary/xxx:xxx
docker push registry.k8sre.com/libary/xxx:xxx

4.3、其他常用命令

docker system df            //顯示Docker磁盤使用狀態
docker system events        //顯示Docker服務實時事件信息
docker system info          //顯示系統信息
docker system prune         //刪除未使用的數據
docker trust inspect        //返回Key和簽名的低級別信息
docker trust key            //管理用于鏡像簽名的Key
docker trust revoke         //撤銷對鏡像的簽名
docker trust sign           //對鏡像進行簽名
docker trust signer         //管理可以對鏡像簽名的用戶
docker volume create       //創建一個卷
docker volume insoect      //顯示一或多個卷的詳細信息
docker volume ls           //列出卷
docker volume prune        //刪除所有未使用的卷
docker volume rm           //刪除一或多個卷
docker pause xxxx          //暫停一或多個容器內所有進程
docker unpause xxxx        //取消暫停一或多個容器內所有進程
docker port xxxx           //列出容器與主機的端口映射
docker rename xxx          //重命名容器名稱
docker diff                //查看容器文件系統內有差異的文件
docker stats xxx           //實時輸出指定容器的資源使用狀態
docker top xxxx            //顯示指定容器運行中的進程信息
docker update              //更新一或多個容器配置,如資源配額、重啟策略等等
docker wait xxx            //捕捉一或多個容器的退出狀態

五、Docker網絡實現和文件系統

5.1、Docker的網絡模式

? Docker的網絡實現利用了Linux上網絡命名空間和虛擬網絡設備(特別是veth pair)。熟悉這兩部分的基本概念,可以有助于理解Docker網絡的實現過程。

5.1.1、基本原理

? 要實現網絡通信,主機需要至少一個網絡接口(物理接口或虛擬接口)與外界相通,并可以收發數據包;此外,如果不同子網之間要進行通信,需要額外的路由機制。

? Docker中的網絡接口默認都是虛擬的接口。虛擬接口的最大優勢就是轉發效率極高。這是因為Linxu通過在內核中進行數據復制來實現虛擬接口之間的數據轉發,即發送接口的發送緩存中的數據包將被直接復制到接收接口的接收緩存中,而無需通過外部物理網絡設備進行交換。對于本地系統和容器內系統來看,虛擬接口跟一個正常的以太網卡相比并無區別,只是它速度要快得多。

? Docker容器網絡就很好的利用了Linux虛擬網絡技術。它在本地主機和容器內分別建立一個虛擬接口,并讓它們彼此連通(這樣的一對接口叫做veth pair)。

docker2.png

5.1.2、網絡創建過程

Docker創建一個容器的時候,會執行以下操作:

? 1、創建一對虛擬接口,分別放到本地主機和新容器的命名空間中。

? 2、本地主機一端的虛擬接口連接到默認的docker0網橋,并具有一個veth開頭的唯一名字。

? 3、容器一端的虛擬接口將放到新創建容器中,并修改名字作為eth0。這個接口只在容器的命名空間中可見。

? 4、從網橋可用的地址段中獲取一個空閑地址分配給容器的eth0,并配置默認路由網關為docker0網卡的內部接口docker0的IP地址。

? 5、此時,容器就可以使用它所能看到的eth0虛擬網卡來連接其他容器和訪問外部網絡了。

5.1.3、常見Docker網絡模型

  • bridge

    通過veth接口來連接容器,默認配置

  • host

    不將容器網絡放到隔離的命名空間中,即不要容器化容器內的網絡。可以使用本地主機的網絡,它擁有完全的本地主機接口訪問權限。容器進程可以跟主機其他root進程一樣打開低范圍端口,可以訪問本地網絡服務(比如D-bus),還可以讓容器做一些影響主機系統的事情,比如重啟主機等。因此使用這個選項的時候要謹慎,如果進一步的使用--privileged=true參數,容器甚至會被允許直接配置主機的網絡堆棧。

  • container

    將新建的容器的進程放到一個已存在容器的網絡棧中,新容器進程有自己的文件系統、進程列表、資源限制,但會和已存在的容器共享IP地址和端口等網絡資源,兩者進程可以直接通過lo環回接口通信。

  • none

    將新建容器放到隔離的網絡棧中,但是不進行網絡配置。之后,用戶可以自己進行配置。

5.1.4、網絡配置

? 用戶使用--net=none后,Docker將不對容器網絡進行配置,可以使用以下方式進行配置:

啟用一個網絡為none的容器

docker run -it --net=none alpine /bin/bash

查找容器進程id

docker inspect -f '{{.State.Pid}}' container_id

查看docker0網絡信息

ip addr show docker0

創建一對”veth pair“接口A和B,綁定其中一個到docker0

ip link add A type veth peer name B
brctl addif docker0 A
ip link set A up

將B接口放到容器的網絡命名空間,命名為eth0

ip link set B netns $PID
ip netns exec $PID ip link set dev B name eth0
ip netns exec $PID ip link set eth0 up

配置容器網絡和網關

ip netns exec $PID ip addr add 172.17.1.2/24 dev eth0
ip netns exec $PID ip route add default via 172.17.1.1

以上就是Docker網絡的配置過程。

當容器終止后,Docker會清空容器,容器內的網絡接口會隨網絡命名空間一起被清除,A接口也被自動從docker0卸載并清除。

此外,在刪除/var/run/netns/下的內容之前,用戶可以使用ip netns exec 命令指定網絡命名中進行配置,從而影響容器內的網絡。

5.2、Docker聯合文件系統

5.2.1、基本原理

? 聯合文件系統(UnionFS)是一種輕量級的高性能分層文件系統,它支持將文件系統中的修改信息作為一次提交,并層層疊加,同時可以將不同目錄掛載到同一個虛擬文件系統下。

聯合文件系統是實現Docker鏡像的技術基礎。鏡像可以通過分層來繼承。例如,用戶基于基礎鏡像(沒有父鏡像的鏡像成為基礎鏡像)來制作各種不同的應用鏡像。這些鏡像共享同一個基礎鏡像曾,提高了存儲效率。此外,當用戶改變一個Docker鏡像,則一個新的層(layer)會被創建。因此,用戶不用替換整個原鏡像或者重新建立,只要添加新層即可用戶分發鏡像的時候,也只需要分發被改動的新層內容(增量部分)。這讓Docker的鏡像管理變得十分輕量級和快速。

docker3.jpg

5.2.2、Docker常見聯合文件系統

  • devicemapper

    1、建議不要在生產環境使用此存儲方案

    2、本地文件容易丟失,且不容易擴展空間

    3、從性能上而言,本地文件掛接方式讓存儲結構跟復雜且性能更低

    4、本地文件在集群和分布式存儲方式中讓系統架構更加復雜

    5、不能很好的體現data數據和meta數據分離的優越性

  • overlay

    1、RHEL/CentOS 必須是 7.2 或以上版本

    2、Docker必須是最新版本,并且支持Overlay

    3、底層文件系統必須是XFS

    4、SELinux在宿主機上必須打開設為enforcing模式,但docker服務啟動時不能打開支持selinux選項,不能設置"--selinux-enabled"。目前RHEL 7.2系統還不支持overlay下的selinux

    5、為了支持yum和rpm工具在以overlay為基礎的容器中正常運行,需要安裝yum-plugin-ovl軟件包。

  • overlay2

    1、overlay2 是 overlay 的升級,與overlay的結構基本相同

    2、使用了從寫的函數,在存儲上是不兼容的,因此從overlay升級的話需要刪除所有的鏡像和容器

    3、Overlay2解決了overlay inode損耗和提交(commit)性能問題,但是只在Docker 1.11之后的版本才能實現

    4、overlay2在docker 18之前的版本需要升級內核版本才可以使用,目前最新版已經不需要升級內核即可使用

六、Dockerfile詳解

? 鏡像的定制實際上就是定制每一層所添加的配置文件。如果我們可以把每一層修改、安裝、構建、操作的命令都寫入一個腳本,用這個腳本來定制、構建鏡像,那么無法重復、鏡像構建透明性、鏡像體積的問題都會解決。這個腳本就是Dockerfile。

? Dockerfile是一個文本文件,其內包含了一條條的指令,所有指令都是在開頭,并且必須為大寫字母,每一條指令構建一層,因此每一條指令的內容,就是描述該層當如何構建。Dockerfile的指令會按從上到下的順序執行。

  • FROM:指定基礎鏡像

    所謂定制鏡像,那一定是以一個鏡像為基礎的,在其上進行定制,而FROM就是指定基礎鏡像,因此Dockerfile中FROM是必備的指令,并且必須是第一條指令。

  • RUN:執行命令

    RUN指令是用來執行命令行命令的,由于命令行的強大能力,RUN指令是在定制鏡像時最常用的指令之一。其格式有兩種:

    • shell格式:RUN <命令>,就像直接在命令行種輸入的命令一樣。
    • exec格式:RUN [“可執行文件”,“參數1”,"參數2"],這更像是函數調用種的格式。

    ? 因每一條指定構建一層,當有多個shell格式的RUN指令時,盡量使用&&將各個命令串聯起來,簡化鏡像層。Dockerfile支持shell類的行尾添加\的命令換行方式,以及行首#進行注釋的格式。良好的格式,比如換行、縮進、注釋等,會讓維護、排障更為容易,這是一個比較好的習慣。

    ? 此外,在指令結束時務必進行緩存清理,之前說過,鏡像時多層的,每一層的東西并不會在下一層被刪除,會一直跟隨著鏡像。因此鏡像構建時,一定確保每一層只添加真正需要的東西,任何無關的東西都應該清理掉。很多初學者制作令很臃腫的鏡像的原因之一,就是忘記了每一層構建的最后一定要清理掉無關文件。

  • COPY:復制文件

    格式:

    • COPY <源路徑> …<目標路徑>
    • COPY ["<源路徑1>",..."<目標路徑>"]

    ? 和RUN指令一樣,也有兩種格式,一種類似命令行,一種類似于函數調用。COPY指令將從構建上下文目錄<源路徑>的文件/目錄復制到新的一層鏡像內的<目標路徑>指定位置。

    ? <源路徑>可以是多個,甚至可以是通配符,其通配符規則要滿足GO的規則。

    ? <目標路徑>可以是容器內的絕對路徑,也可以是相對于工作目錄的相對路徑(工作目錄可以用WORKDIR指令來指定)。目標路徑不需要事先創建,如果目錄不存在會在復制文件前先行創建缺失目錄。

    ? 此外,還需要注意一點,使用COPY指令,源文件的各種元數據都會保留。比如讀、寫、執行權限、文件變更時間等。這個特性對于鏡像定制很有用。

  • ADD:更高級的復制文件

    ? ADD指令和COPY的格式和性質基本一致。但是在COPY基礎上增加了一些功能。比如<源路徑>可以是一個URL,這種情況下,Docker引擎會試圖去下載這個鏈接的文件放到<目標路徑>去。下載后的文件權限自動設置為600,如果這并不是想要的權限,那么還需要增加額外的一層RUN進行權限調整,另外,下載的是個壓縮包,需要使用額外一層RUN進行解壓縮。所以不如直接使用RUN指令,然后wget、curl下載,處理權限、解壓縮、然后清理無用文件更合理。因此,這個功能其實并不實用,而且不推薦。

    ? 如果<源路徑>為一個tar壓縮文件的話,壓縮格式為gzip、bzip2、xz的情況下,ADD指令將會自動解壓縮。

    ? 在Docker官方文檔中,ADD指令會令鏡像構建緩存失效,從而可能會令鏡像變得比較緩慢。因此,盡可能的使用COPY,因為COPY語義很明確,就是復制文件而已,而ADD則包含了更復雜的功能,其行為也不一定很清晰。最適合使用ADD的場合,就是自動解壓縮的場合。

  • CMD:容器啟動命令

    CMD指令的格式和RUN相似,也是兩種格式:

    • shell格式:CMD <命令>
    • exec格式:CMD [“可執行文件”,"參數1","參數2"...]
    • 參數列表格式:CMD ["參數1","參數2"…]。在指定了CNTRYPOINT指令后,用CMD指定具體參數。

    ? Docker不是虛擬機,容器就是進城。既然是進程,那么在啟動容器的時候,需要指定所運行的程序及參數。CMD指令就是用于指定默認的容器主進程的啟動命令。在運行時可以指定新的命令來替代鏡像設置中的這個默認命令。

    ? 在指令格式上,一般推薦使用exec格式,這類格式在解析時會被解析喂JSON數組,因此一定要使用雙引號,而不是單引號。如果使用shell格式的話,實際的命令會被包裝為sh -c的參數的形式進行執行。

    ? Docker不是虛擬機,容器中的應用都應該在前臺執行,而不是像虛擬機、物理機里面那樣,用upstart/systemd去啟動后臺服務,容器內沒有后臺服務的概念。

    CMD ["nginx","-g","daemon off"]
    
  • ENTRYPOINT:接入點

    ? ENTRYPOINT的格式和RUN指令的格式一樣,分為exec格式和shell格式。ENTRYPOINT的目的和CMD一樣,都是在指定容器啟動程序及參數。ENTRYPOINT在運行時也可以替代,需要通過--entrypoint來指定。

    ? 當指定來ENTRYPOINT后,CMD的含義就發生了改變,不再是直接運行其命令,而是將CMD的內容作為參數傳給ENTRYPOINT指令。

  • ENV:設置環境變量

    格式有兩種:

    • ENV <key> <value>
    • ENV <key1>=<value1> <key2>=<value2>

    ? 這個指令很簡單,就是設置環境變量而已,無論是后面的其它指令,如RUN,還是運行時的應用,都可以直接使用這里定義的環境變量。

  • ARG:構建參數

    格式:ARG <參數名> [=<默認值]

    ? 構建參數和ENV的效果一樣,都是設置環境變量。不同的是,ARG所設置的構建環境的環境變量,在將來容器運行時是不會存在這些環境變量的。但是不要因此就使用ARG保存密碼之類的信息,因為docker history還是可以看到所有值的。

    ? Dockerfile中的ARG指令時定義參數名稱,以及定義其默認值。該默認值可以在構建命令docker build中用--build-arg <參數名>=<值>來覆蓋。

    ? 在1.13之前的版本,要求--build-arg中的參數名,必須在Dockerfile中用ARG定義過了,換句話說,就是--build-arg指定的參數,必須在Dockerfile中使用了。如果對應參數沒有被使用,則會報錯退出構建。從1.13開始,這種嚴格的限制被放開,不再報錯退出,而是現實警告信息,并繼續構建。這對于使用CI系統,用同樣的構建流程構建不同的Dockerfile的時候比較有幫助,避免構建命令必須根據每個Dockerfile的內容修改。

  • VOLUME:定義存儲卷

    格式:

    • VOLUME ["<路徑1>","<路徑2>"...]
    • VOLUME <路徑>

    ? 之前我們說過,容器運行時應該盡量避免容器存儲層不發生寫操作,對于數據庫類需要保存動態數據的應用,其數據庫文件應該保存于卷(volume)中,在Dockerfile中,我們可以事先指定某些目錄掛載為匿名卷,這樣在運行時如果忘記指定掛載,其應用也可以這個正常運行,不會向容器存儲層寫入大量數據。

  • EXPOSE:聲明端口

    格式: EXPOSE <端口1> [<端口2>…]。

    ? EXPOSE指令時聲明運行時容器提供服務端口,這只是一個聲明,在運行時并不會因為這個聲明應用就會開啟這個端口的服務。

  • WORKDIR:指定工作目錄

    格式: WORKDIR <工作目錄路徑>。

    ? 使用WORKDIR指令可以來指定工作目錄(或者稱為當前目錄),以后各層的當前目錄就被改為指定的目錄,如該目錄不存在,WORKDIR會幫你創建目錄。

  • USER:指定當前用戶

    格式:USER <用戶名>

    ? USER指定和WORKDIR相似,都是改變環境狀態并影響以后層。WORKDIR是改變工作目錄,USER則是改變之后層的執行RUN、CMD以及ENTRYPOINT這類命令的身份。

    ? USER只是幫助你切換到指定用戶而已,這個用戶必須是事先創建好的,否則無法切換。

  • HEALTHCHECK:健康檢查

    格式:

    • HEALTHCHECK [選項] CMD <命令> :設置檢查容器健康狀況的命令
    • HEALTHCHECK NONE :如果基礎鏡像有健康檢查指令,使用這行可以屏蔽掉其健康檢查指令

    ? HEALTHCHECK指令是Docker應該如何進行判斷容器的狀態是否正常,這是Docker1.12引入的新指令。通過該指令指定一行命令,用這行命令來判斷容器主進程的服務狀態是否正常,從而比較真實的反應容器實際狀態。

    ? 當一個鏡像指定了HEALTHCHECK指令后,用其啟動容器,初始狀態會為starting,在HEALTHCHECK指令檢查成功后變為healthy,如果連續一定次數失敗,則會變為unhealthy。

    HEALTHCHECK支持下列選項:

    • --interval=<間隔> :兩次健康檢查的間隔,默認為30秒。
    • --timeout=<時長> :健康檢查命令運行超時時間,如果超過這個時間,本次健康檢查就被視為失敗,默認30秒。
    • --retries=<次數> :當連續失敗指定次數后,則將容器狀態視為unhealth,默認3次。

    ? 和CMD、ENTRYPOINT一樣,HEALTHCHECK只可以出現一次,如果寫了多個,只有最后一個生效。在HEALTHCHECK [選項] CMD 后面的命令,格式和ENTRYPOINT一樣,分為shell格式和exec格式。命令的返回值決定了該次健康檢查的成功與否:0:成功;1:失敗;2:保留。不要使用這個值。

  • ONBUILD:為他人做嫁衣

    格式:ONBUILD <其他指令>。

    ? ONBUILD是一個特殊的指令,它后面跟的是其它指令,比如RUN、COPY等,而這些指令,在當前鏡像構建時并不會被執行。只有當以當前鏡像為基礎鏡像,去構建下一級鏡像的時候才會被執行。Dockerfile中的其它指令都是為了定制當前鏡像而準備的,唯有ONBUILD是為了幫助別人定制自己而準備的。

七、Docker核心技術

? Docker采用了標準的C/S架構,包括客戶端和服務端兩大部分。

? 客戶端可以和服務端機可以運行在一個機器,也可以通過socket或者RESTful API來進行通信。

7.1、服務端

? Docker daemon一般在宿主機后臺運行,作為服務端接受來自客戶的請求,并處理這些請求(創建、運行、分發容器)。在設計上,Docker daemon是一個非常松耦合的架構,通過專門的ENgine模塊來分發管理各個來自客戶端的任務。

? Docker服務端默認監聽本地的unux:///var/run/docker.sock套接字,只允許本地的root用戶訪問。可以通過-H選項修改監聽方式。

docker -H 0.0.0.0:666 -d &

此外,Docker還支持通過HTPPS認證方式來驗證訪問。

7.2、客戶端

? Docker客戶端為用戶提供了一系列可執行命令,用戶通過這些命令實現與Docker daemon的交互。

? 用戶使用的Docker可執行命令即為客戶端程序。與Docker daemon不同的是,客戶端發送命令后,等待服務端返回,一旦收到返回后,客戶端立刻執行結束并退出。用戶執行新的命令,需要再次調用客戶端命令。

? 同樣,客戶端默認通過本地的unux:///var/run/docker.sock套接字向服務端發送命令。如果服務端沒有監聽到默認套接字,則需要客戶端在執行命令的時候顯式指定。

docker -H tcp://127.0.0.1:666 version

7.3、命令空間

? 命令空間(Namespace)是Linux內核針對實現容器虛擬化而引入的一個強大特性。

? 每個容器都可以擁有自己單獨的命名空間,運行在其中的應用都像是在獨立的操作系統中運行一樣。命名空間保證了容器之間互不影響。

? 眾所周知,在操作系統中,包括內核、文件系統、網絡、PID、UID、IPC、內存、硬盤、CPU等資源,所有的資源都是應用進程直接共享的。要想實現虛擬化,除了要實現對內存、CPU、網絡IO、硬盤IO、存儲空間等的限制外,還要實現文件系統、網絡、PID、UID、IPC等等的相互隔離。前者相對實現容易實現一些,后者則需要宿主機系統的深入支持。

? 隨著Linux系統的逐步完善,已經實現讓某些進程在彼此隔離的命名空間中運行,這些進程都共用一個內核和某些運行時環境(runtime),但是彼此是不可見的-它們各自認為是自己獨占系統的。

7.3.1、進程命名空間

? Linux通過命名空間管理進程號,對于同一個進程(同一個task_struct),在不同的命名空間中,看到的進程號不相同,每個進程命名空間有一套自己的進程號股那里方法。進程命名空間是一個父子關系的結構,子空間中的進程對于父空間是可見的。新fork出的進程在父命名空間個子命名空間將分別由一個進程號來對應。

7.3.2、網絡命名空間

? 如果有了PID命名空間,那么每個名字空間中的進程就可以相互隔離,但是網絡端口還是共享本地系統的端口,

? 通過網絡命名空間,可以實現網絡隔離。一個網絡命名空間為進程提供了一個完全獨立的網絡協議棧的視圖。包括網絡設備接口、IPv4和IPv6協議棧、IP路由表】防火墻規則,Sockets等等。這樣每個容器的網絡就能隔離。Docker采用虛擬網絡設備(Virtual Network Device)的方式,將不同命名空間的網絡設備連接到一起。默認情況下,容器中的虛擬網卡將同本地主機上的docker0網橋連接在一起。

查看橋街道宿主機docker0網橋的虛擬網口:

brctl show

7.3.3、IPC命名空間

? 容器中進程交互還是采用了LInux常見的進程間交互方法(Interprocess Communication IPC),包括信號量、消息隊列和共享內存等。PID命名空間和IPC命名空間可以組合起來一起使用,同一個IPC名字空間內的進程可以彼此可見,允許進行交互;不同名字空間的進程則無法交互。

7.3.4、掛載命名空間

? 類似chroot,將一個進程放到一個特定的目錄執行。掛載命名空間運行不同命名空間的進程看到的文件結構不同,這樣每個命名空間中的進程所看到的文件目錄彼此隔離。

7.3.5、UTS命名空間

? UTS(UNIX Time-sharing System)命名空間允許每個容器擁有獨立的主機名和域名,從而可以虛擬出一個獨立主機名和網絡空間的環境,就跟網絡上一臺獨立的主機一樣。

7.3.6、用戶命名空間

? 每個容器可以有不同的用戶和組ID,也就是說可以在容器內使用特定的內部用戶執行程序,而非本地系統上存在的用戶。

? 每個容器內部都可以由root用戶,跟宿主機不在同一個命名空間。

7.4、控制組

? 控制組(CGroups)是Linux內核的一個特性,主要用來對共享資源進行隔離、限制、審計等。只有能控制分配到容器的資源,Docker才能避免多個容器同時運行時的系統資源競爭。

? 控制組可以提供對容器的內存、CPU、磁盤IO等資源進行限制和計費管理。控制組的設計目標是為不同的應用情況提供統一的接口,從控制單一進程(比如nice工具)到系統級虛擬化(包括OpenVZ、Linux-VServer、LXC等)。

控制組提供以下功能:

  • 資源限制(Resource Limiting):可以設置為不超過設定的內存限制。比如內存子系統可以為進程組設定一個內存使用上限,一旦進程組使用的內存達到限額再申請內存,就會觸發Out of Memory。
  • 優先級(Prioritization):通過優先級讓一些組優先得到更多的CPU、MEM等資源
  • 資源審計(Accounting):用來統計系統實際上把多少資源用到適合的目的上,可以使用cpuacct子系統記錄某個進程組使用的CPU時間
  • 隔離(Isolation):為組隔離名字空間,這樣一個組不會看到另一個組的進程、網絡連接、文件系統
  • 控制(Control):掛起、恢復和重啟動等操作
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,791評論 6 545
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,795評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,943評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,057評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,773評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,106評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,082評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,282評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,793評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,507評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,741評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,220評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,929評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,325評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,661評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,482評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,702評論 2 380

推薦閱讀更多精彩內容