Docker詳解

1. 電腦虛擬化概述

電腦虛擬化起始於上世紀60年代的IBM公司。

虛擬化:將底層的電腦資源抽象(虛擬)為多組彼此之間互相隔離的計算平台,每個計算平台都應該具有五大基本部件中的所有設備

  • CPU
  • 記憶體(Memory)
  • IO(keyboard鍵盤,monitor顯示器)

1.1 CPU的虛擬化

所有的內核在開發時都以為自己可以操作所有的硬體設備,也就是運行在環0上

1.1.1 模擬:emulation

  • 虛擬是直接在每個虛擬機上用軟體虛擬化一個CPU,用純軟體的方式事先,性能很差
  • 底層和上層的架構可以不一致
  • 要模擬CPU的環0、1、2、3

1.1.2 虛擬:virtulization

  • 上層架構和底層架構要保持一致
  • 虛擬只需要模擬環0
  • 因為上層架構和底層架構一致,所以Guest上用戶空間的指令直接可以放到Host上來運行

1)完全虛擬化(full-virtulization)

所謂完全虛擬化,即虛擬機都不知道自己是運行在虛擬環境中的

完全虛擬化一定會導致中間有個轉換的過程

  • BT:(二進位翻譯軟體)
    • 能讓客戶機對特權指令的調用按需直接翻譯成宿主機對特權指令的調用
    • Guest的用戶空間在環3上,Guest的內核空間在環1上,Host的內核空間在環0上,BT就監控在環1上,隨時將Guest的內核的調用轉換成特權指令的調用
  • HVM:(硬體輔助的虛擬機,硬體虛擬化)
    • 多增一個指令環,有5個級別的環
    • 宿主機的內核空間在環-1上,Guest直接運行在環0上,但是環0上沒有指令,但它能自動捕獲後放到環-1上運行

2)半虛擬化(para-virtulization)

  • 宿主機系統是明確知道自己在虛擬環境中的(特製的內核)
  • 對hypervisor(宿主機)的調用被稱為hyper call

1.2 Memory及I/O的虛擬化

1)記憶體的虛擬化

  • 進程:線性地址空間
  • 內核:物理地址空間
  • shadow page table
  • MMU的虛擬化
    • Interl:EPT,Extend Page Table
    • AMD:NTP,Nested Page Table
  • TLB的虛擬化
    • tagged TLB

2)I/O的虛擬化

  • 模擬:完全用軟體來模擬真實硬體(鍵盤滑鼠通常都是完全模擬實現的)
  • 半虛擬化(這種虛擬通常只適用於硬碟和網卡)
    • IO frontend 前端驅動
    • IO backend 後端驅動
  • IO-through:IO透傳
    • 讓虛擬機直接去操作硬體,但依然需要hypervisor來協調
  • Intel:VT-d
    • 要完成中斷映射
    • 基於北橋的硬體輔助的虛擬化技術

1.3 虛擬化的實現及分類

1)虛擬化的兩種實現方式

  • Type-I
    • 直接在硬體上運行hypervisor,所有運行在當前機器上的都是虛擬機
    • 如 xen,vmware ESX/ESXi
  • Type-II
    • 宿主機運行在硬體上,在宿主機上運行客戶機
    • kvm,vmware workstation,virtualbox

2)虛擬化技術的分類

  • 模擬:著名的模擬器:PearPC,Bochs,QEMU
  • 完全虛擬化(native virtulization)
    • 兩種加速方式
      • BT 二進位翻譯
      • HVM 硬體輔助虛擬化
    • 產品:VMware Workstation,VMware Server,KVM,Xen(HVM)
  • 半虛擬化(para-virtulization)
    • xen,uml(user-mod linux)
  • OS級別的虛擬化
    • OpenVZ
    • LXC
    • Solaris Containers
    • FreeBSD jails
  • 庫虛擬化:wine
  • 應用程式虛擬化:jvm

1.4 創建和配置橋

  • 橋設備不支援使用NetworkManager來管理服務,必須確保NetworkManager處於關閉狀態
  • 要先安裝一個橋設備管理程式包:yum  install  bridge-utils
  • 橋0也就是br0是被當做了一台交換機來使用(它其實就是宿主機的物理網卡),而原本宿主機的IP地址被配置在了一塊虛擬出來的網卡上,且這塊網卡被橋接到了br0上

1)使用brctl的配置過程

brctl add br0              # 創建br0橋
brctl stp br0 on           # 開啟生成樹
ifconfig eth0 0 up         # 要將eth0的地址刪除
brctl addif br0 eth0       # 向br0上添加eth0
ifconfig br0 IP/NETMASK up # 在br0上添加IP地址
route add default gw GW    # 添加默認網關

2)全手動配置

看起來ens33更像是橋,但實際上是把ens33做成交br0的橋了,引用的時候要引用br0

  • ifcfg-ens33
    TYPE=Ethernet
    NM_CONTROLLED=no
    BOOTPROTO=none
    IPV6INIT=no
    NAME=ens33
    DEVICE=ens33
    ONBOOT=yes
    BRIDGE=br0   # 這塊網卡橋接到br0上
    USERCTL=no
  • ifcfg-dr0
    TYPE=Bridge
    BOOTPROTO=none
    NM_CONTROLLED=no
    IPV6INIT=no
    NAME=br0
    DEVICE=br0
    ONBOOT=yes
    IPADDR=10.0.0.201
    NETMASK=255.255.255.0
    GATEWAY=10.0.0.2
    DNS1=10.0.0.2
    USERCTL=no

3)查看橋設備特徵

# 顯示當前的橋設備及橋設備的特徵
brctl show

2. Docker簡介

2.1 LXC

LXC(Linux Container)是一種輕量級的虛擬化手段,LXC提供了在單一可控主節點上支援多個相互隔離的server container通知執行的機制。

LXC有點像chroot,提供了一個擁有自己進程的網路空間的虛擬環境,但又有別於虛擬機,因為lxc是一種作業系統層次上的資源的虛擬化。

容器將單個作業系統管理的資源劃分到孤立的組中,可以更好的平衡孤立的組之間資源使用的衝突。

docker底層使用了LXC來實現,LXC將linux進程沙盒化,使得進程之間相互隔離,並且能夠控制各進程的資源分配。在LXC的基礎之上,docker提供了一系列更強大的功能。

2.2 Docker概述

1)Docker簡介

docker只是LXC的前端工具,Docker的底層就是通過LXC來實現,LXC將Linux進程沙盒化,使進程之間相互孤立,並且能夠控制各進程的資源分配。

docker是一個開源的應用容器引擎,基於go語言開發。

docker可以讓開發者打包到他們的應用以及依賴包到一個輕量級、可移植的容器中,然後發布到任何流行的linux伺服器,也可以實現虛擬化。容器是完全適用沙盒機制,相互之間不會有任何介面,並且容器開銷及其低。

2)docker的版本

  • CE:Community Edition 社區版
  • EE:Enterprise Edition 商業版

3)虛擬機、容器、鏡像

  • 虛擬機:
    • 虛擬機運行的是一個完整的作業系統,通過虛擬機管理程式對主機資源進行訪問
  • 容器:
    • 容器共享主機的內核,它運行的是一個獨立的進程,且不佔用其他任何可執行文件的記憶體
  • 鏡像:
    • 通過鏡像啟動一個容器,一個鏡像是一個可執行的包,其中包括運行應用程式所需要的內容如程式碼、運行時間、庫、環境變數、配置文件等
    • 容器是鏡像的運行實例

4)docker的運行方式

docker的運行方式:「分層構建  聯合掛載

一個docker啟動一個進程,它就是一個普通的進程,非常方便,再掛載外部目錄進行存儲

大規模使用docker時必須由編排工具,因為如果有很多台伺服器,為了使得資源不濫用或者過度空閑,需要將需求(業務端)和資源端(伺服器)對接起來,將這個需求放到最合適的伺服器上並開始構建,人是不知道哪台伺服器閑置的(或者需要提前檢查),編排工具就可以。一些服務啟動或關閉有依賴關係(dependent),這些docker本身也無法解決,也需要編排工具來解決。如lnmp搭載的系統。

2.3 容器在內核中支援的2種重要技術

docker本質就是宿主機中的一個進程,docker是通過namespace實現資源隔離,通過cgroup實現資源限制,通過寫時複製機制(copy-on-write)實現高效的文件操作(類似虛擬機的磁碟分配500G並不是佔用物理磁碟500G)

1)namespace名稱空間

2)Control Group控制組

  • cgroup的特點:
    • cgroup的api以一個偽文件系統的實現方式,用戶的程式可以通過文件系統實現cgroup的組件管理
    • cgroup的組件管理操作單元可以細粒度到執行緒級別,另外用戶可以創建和銷毀cgroup,從而實現資源再分配和再利用
    • 所有資源管理的功能都以子系統的方式實現,介面同一子任務創建之初與其父任務處於同一個cgroup的控制組
  • 四大功能:
    • 資源限制:可以對任務使用的資源總額進行限制
    • 優先順序分配:通過分配的cpu時間片數量以及磁碟IO頻寬大小,實際上相當於控制了任務運行優先順序
    • 資源統計:可以統計系統的資源使用量,如cpu時長,記憶體用量等
    • 任務控制:cgroup可以對任務執行掛起、恢復等操作

2.4 鏡像&容器&倉庫

1)image鏡像

docker鏡像含有啟動容器所需要的文件系統及其內容,因此其用於創建並啟動docker容器

  • docker鏡像就是一個只讀模板;比如,一個鏡像可以包含一個完整的centos,裡面僅安裝apache或用戶的其他應用,鏡像可以用來創建docker容器
  • docker提供了一個很簡單的機制來創建鏡像或者更新現有的鏡像,用戶甚至可以直接從其他人那裡下載一個已經做好的鏡像來直接使用

採用分層構建機制,最底層為bootfs,其上為rootfs:

  • bootfs:用於系統引導的文件系統,包括bootloader和kernel,容器啟動完成後會被卸載以節約記憶體資源
  • rootfs:位於bootfs之上,表現為docker容器的根文件系統
    • 傳統模式中,系統啟動之時,內核掛載rootfs時會首先將其掛載為「只讀」模式,完整性自檢完成後將其重新掛載為讀寫模式
    • docker中,rootfs由內核掛載為「只讀」模式,而後通過 「聯合掛載」 技術額外掛載一個 「可寫」 層

鏡像的層次:

  • 位於下層的鏡像稱為父鏡像(parent image),最底層的稱為基礎鏡像(base image)
  • 最上層的為 「可讀寫」 層,其下的均為 「只讀」 層

關於Aufs(advanced multi-layered unification filesystem)高級多層同一文件系統:

  • aufs用於為Linux系統實現 「聯合掛載」
  • aufs是之前的UnionFS的重新實現,docker最初使用aufs作為容器文件系統層,它目前仍然作為存儲後端之一來支援
  • aufs的競爭產品是overlayfs,overlayfs從3.18版本開始被合併到Linux內核
  • docker的分層鏡像,除了aufs,docker還支援btrfs,devicemaapper和vfs等
    • 在Ubuntu系統下,docker默認Ubuntu的aufs,而在CentOS7上,用的是devicemapper

2)container容器

docker利用容器來運行應用,容器是從鏡像創建的運行實例,它可以被啟動、開始、停止、刪除。

每個容器都是互相隔離的,保證安全的平台,可以把容器看做是個簡易版的linux環境(包括root用戶許可權、鏡像空間、用戶空間和網路空間等)和運行在其中的應用程式。

3)repository倉庫

  • 由某特定的docker鏡像的所有迭代版本組成的鏡像倉庫
  • 一個Registry中可以存在多個Repository
    • Repository可分為 「頂層倉庫」 和 「用戶倉庫」 
    • 用戶倉庫名稱格式為 「用戶名/倉庫名」
  • Index
    • 維護用戶帳號、鏡像的校驗以及公共命名空間的資訊
    • 相當於為Registry提供了一個完成用戶認證等功能的檢索介面

4)圖示

  • 標識一個鏡像:
    • 倉庫名+標籤,如   nginx:1.10
    • nginx是倉庫名,1.10是標籤
    • 如果只給倉庫名而沒有給標籤,則默認是最新版,nginx:latest
  • 鏡像:
    • 靜態的
    • 鏡像文件是只讀的
  • 容器:
    • 動態的,有生命周期
    • 因為一個容器只運行單個應用程式,所以這個應用程式必須運行在前台,否則容器會直接停止

3. Docker架構概述

3.1 docker client

  • docker client是docker架構中用戶用來和docker daemon建立通訊的客戶端
    • 用戶使用的可執行文件為docker,通過docker命令行工具可以發起眾多管理container的請求。
  • docker client可以通過三種方式和docker daemon建立通訊:
    • tcp://host:port
    • unix:path_to_socker
    • fd://sockerfd
  • docker可以通過設置命令行flag參數的形式設置安全傳輸層(TLS)的有關參數,保證傳輸的安全性
  • docker client發送容器管理請求後,由docker daemon接受並處理請求,當docker client接收到返回的請求響應並簡單處理後,docker client一次完整的生命周期就結束了
    • 當需要繼續發送容器管理請求後,用戶必須再次通過docker可執行文件創建docker client

3.2 docker daemon

  • docker daemon是docker架構中一個常駐在後台的系統進程,它負責接收處理docker client發送的請求
    • 該守護進程在後台啟動一個server,server負責接受docker client發送的請求
    • 接受請求後,server通過路由與分發調度,找到相應的handler來執行請求
  • docker daemon啟動所使用的可執行文件也為docker,與docker client啟動所使用的可執行文件docker相同,在docker命令執行時,通過傳入的參數來判別docker daemon與docker client

3.3 docker server

  •  docker server在docker架構中專門服務於docker client的server,該server的功能是接受並調度分發docker client發送的請求

架構圖示:

4. Docker的安裝和使用

4.1 Docker的安裝和配置

1)安裝docker

配置清華大學鏡像源,然後直接yum安裝:

yum install docker-ce  -y

注意:如果直接下載repo文件的話,需要手動修改其中的源資訊,因為這個文件中是直接指向了docker官方的地址的,需要改成中國的源

2)配置鏡像加速

要在 /etc/docker/daemon.json 文件中定義一個鏡像加速器(這是一個json格式的數組,這個文件需要自己創建)

{  
    "registry-mirrors":  ["//registry.docker-cn.com"]
}

3)啟動docker服務

因為docker是運行方式是C/S架構模式的,需要啟動docker守護進程

systemctl  start  docker

4.2 docker的基本使用命令

1)基本資訊查看

# 查看docker版本及其他資訊
docker version
docker info
# 鏡像查看
docker image ls
# 查看容器資訊
docker container ls
docker container ls -a
# 狀態查看
docker ps 
docker ps -a  # 可以查看處於停止狀態的容器
# 查看網路狀態
docker network ls

2)鏡像的搜索和拉取

### 鏡像搜索
docker search nginx:latest
docker search nginx:1.16

### 鏡像的拉取和刪除
# 鏡像拉取
docker image pull busybox
# 鏡像刪除
docker image rm busybox  # 刪除鏡像
docker rmi busybox     # 刪除鏡像
docker rm busybox      # 刪除容器

3)鏡像的啟動和停止

# 啟動容器
docker start -i -a b1
    # -i 互動式
    # -a 依附於終端

# 創建並啟動容器 
# docker run可以創建並啟動容器,如果沒有鏡像會自動去下載鏡像
docker run --name b1 -i -t busybox:latest
docker run --name web1 -d nginx:1.16
    # -d 剝離終端
    # -t 啟用終端

# 停止容器
docker stop b1
# 殺死容器
docker kill b1
# 刪除容器
docker rm b1

# 查看指定容器的日誌
docker logs web1

# 查看容器的資訊
docker inspect b1

# 在指定的容器中執行指定的命令
docker container exec -i -t web1 /bin/sh

# 依附於一個啟動的容器
docker attach b1 

# 如果不想運行容器中給定的命令,只需在docker run後面給定命令即可
docker run --name tinyweb -it --rm -P tinyhttpd:v0.2-5 ls /data/web/html

4)從別的地址來拉取鏡像

  • 拉取鏡像的語法:
    docker pull <registry>[:<port>]/[<namespace>/]<name>:<tag>
  • 默認是從docker hub來拉取鏡像,如果要從別的地址拉取鏡像,如 quay.io這個地址來拉取:
    docker pull quay.io/coreos/flannel
    # 默認是443埠

4.3 基於容器製作鏡像

  • 鏡像的生成途徑
    • Dockerfile:通過build命令來製作
    • 基於容器製作
    • Docker Hub automated builds

1)運行一個busybox並做些改動

# 運行一個busybox
docker run --name b1 -it busybox

# 創建一個html文件並寫入一些內容
vi  /data/html/index.html

2)創建鏡像並打上標籤

  • 注意:要新開一個會話
# 新開一個ssh會話,創建鏡像
docker commit -p b1
    # -p 表示在commit的時候暫停容器
    # 也可以在創建鏡像的時候就打上標籤
        docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

# 為鏡像打上標籤,語法:docker tag 鏡像的ID號  標籤
docker tag  鏡像ID  dockerhgzero/httpd:v0.1
# 還可以再打個標籤
docker tag hgzero/httpd:v0.1 dockerhgzero/httpd:latest

3)修改鏡像啟動時要運行的命令

# docker inspect 中有個Cmd的項,此項就是容器啟動時要執行的命令
docker inspect dockerhgzero/httpd:latest

# 修改原有基礎鏡像啟動時要運行的命令,改Cmd就行了
docker commit -a "hgzerowzh <[email protected]>" -c 'CMD ["/bin/httpd","-f","-h","/data/html"]' -p b1 dockerhgzerowzh/httpd:v1.1
    # docker commit 的選項:
         # -a 指明作者名
         # -c 改動列表
         # -p 製作時讓其處於暫停狀態
    # httpd的選項:
         # -f 運行在前台
         # -h 指明網頁文件的目錄

4)將鏡像推送到Docker Hub

  • 要先在Docekr Hub上建立個倉庫,並且本地的名稱和倉庫的名稱要保持一致
# 在推送之前要登錄
# 也可以指定伺服器,默認是登錄Docker Hub
docker login -u 用戶名 -p 密碼

# 推送到dockerhub
docker image push dockerhgzerowzh/httpd
  • 如果要推送到其他從庫,在打標時必須帶上倉庫地址
# 推送到阿里雲
docker tag hgzerowzh/httpd:v0.1 registry.cn-qingdao.aliyuncs.com/hgzerowzh/httpd:v0.2

4.4 鏡像的導入和導出

1)鏡像的導出

docker save -o myimage.gz dockerhgzerowzh/httpd:v0.1 dockerhgzerowzh/httpd:v1.1
# -o 指明保存為一個文件
# 會自動壓縮

2)鏡像的導入

docker load -i myimage.gz
# 使用這種方式要事先準備好本地鏡像,否則執行docker run的時候它還是會到docker hub上去下載

5. 容器虛擬化網路

5.1 docker中的網路模式概述

  • 默認docker會自動創建3個網路:host、none、bridge

1)Host

相當於VMware中的橋接模式,與宿主機在同一個網路中,但是沒有獨立的IP地址。

Docker使用了Linux的Namespace技術來進行資源隔離,如PID Namespace隔離進程,Mount Namespace隔離文件系統,Network Namespace隔離網路等。一個Network Namespace提供了一份獨立的網路環境,包括網卡、路由、iptables規則等都與其他的Network Namespace隔離。

一個Docker容器一般會分配一個獨立的Network Namespace,但如果啟動容器的時候使用host模式,那麼這個容器將不會獲得一個獨立的Network Namespace,而是和宿主機公用一個Network Namespace,容器將不會虛擬出自己動網卡、配置自己的IP等,而是使用宿主機的IP和埠。

外界訪問容器中的應用,不用任何NAT轉換,就如同直接跑在宿主機中一樣。但是,容器的其他方面,如文件系統、進程列表等還是和宿主機隔離的。

2)None

該模式將容器放置在它自己的網路棧中,但是並不進行任何配置。

實際上,該模式關閉了容器的網路功能,在如下情況中是有用的:容器並不需要網路(例如只需要寫磁碟卷的批處理任務)

3)Bridge

 相當於VMware中的NAT模式,容器使用獨立的Network Namespace,並連接到docker0的虛擬網卡(默認模式)。通過docker0網橋以及iptables nat表配置與宿主機通訊。

bridge模式是Docker默認的網路設置,此模式會為每一個容器分配Network Namespace、設置IP等,並將一個主機上的Docker容器連接到一個虛擬網橋上。

4)Container

這個模式指定新創建的容器和已經存在的一個容器共享一個Network Namespace,而不是和宿主機共享。

新創建的容器不會創建自己的網卡、配置自己的IP,而是和一個指定的容器共享IP地址、埠範圍等。

兩個容器除了網路方面,其他的如文件系統、進程列表還是隔離的。兩個容器的進程可以通過lo網卡設備通訊。

5.2 Bridge模式詳解

1)Bridge模式的拓撲詳解

當Docker Server啟動時,會在主機上創建一個名為docker0的虛擬網橋,此主機上啟動的Docker容器會連接到這個虛擬網橋上。虛擬網橋的工作方式和物理交換機類似,這樣主機上的所有容器就通過交換機連在了一個二層網路中。

接下來會為容器分配IP,Docker會從私有IP網段中,選擇一個和宿主機不同的IP地址和子網分配給docker0,連接到docker0的容器就從這個子網中選擇一個未佔用的IP使用。如一般Docker會使用172.17.0.0/16這個網段,並將172.17.0.1/16分配給docker0網橋(在主機上使用ficonfig命令是可以看到docker0的,可以認為它是網橋的管理介面,在宿主機上作為一塊虛擬網卡使用)

2)Docker網路模式詳解

Docker完成以上網路配置的過程大致是這樣:

  1. 在主機上創建一堆虛擬網卡veth pair設備。veth設備總是成對出現,它們組成了一個數據的通道,數據從一個設備進入,就會從另一個設備出來。因此,veth設備常用來連接兩個網路設備。
  2. Docker將veth pair設備的一端放在新創建的容器中,並命名為eth0。另一端放在主機中,以eth65f9這樣類似的名字命名,並將這個網路設備加入到docker0網橋中,可以通過brctl show命令來查看
    $ brctl show
    bridge name     bridge id               STP enabled     interfaces
    docker0         8000.02425f21c208       no
  3. 從docker0子網中分配一個IP給容器使用,並設備docker0的IP地址為容器的默認網關
    # 查看容器網路
    docker inspect 9582dbec7981
    
    # 查看橋設備資訊
    docker network inspect bridge

3)bridge模式下容器的通訊

在bridge模式下,連在同一網橋上的容器可以相互通訊;出於安全考慮,也可以禁止它們之間通訊:在DOCKER_OPTS變數中設置 –icc=false,這樣只有使用–link才能使兩個容器通訊。

Docker可以開啟容器間通訊(意味著默認配置 –icc=true),也就是說,宿主機上的所有容器可以不受任何限制的相互通訊,這可能導致拒絕服務攻擊;Docker可以通過–ip_forward和–iptables兩個選項控制容器間、容器和外部世界的通訊。

容器也可以和外部通訊,主機上定義了如下iptables規則:

-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
# 這條規則會將源地址為172.17.0.0/16的包(也就是從Docker容器產生的包)
#   並且不是從docker0網卡發出的包,進行源地址轉換,轉換成主機網卡的地址
#   這樣在外界看來,這個包是從主機網卡上發出來的,Docker容器對外是不可見的

5.3 自定義網路

5.4 Docker中設置網路

  • 默認創建容器時如果沒有特別指定,則都使用的是橋接網路(bridge),是NAT橋
  • 指定容器的網路模式:docker container run –network xxx

1)查看網路的相關內容

# 查看網路模式
docker network ls

# 查看網路的現骨幹內容
docker network inspect bridge

2)docker中設置網路

docker run --name t1 -it --network bridge --rm busybox:latest
    --rm 
     # 表示容器退出自動刪除
    --network  # 指定網路類型
        # none
        # bridge 默認
    --hostname www.hgzerowzh.com  
     # 設置主機名,注入到容器中
    --dns 114.114.114.114 
     # 注入設置DNS
    --dns-search hgzerowzh.com  
     # 向容器中注入搜索域
    --add-host www.hgzerowzh.com:10.0.0.201 
     # 向容器中注入hosts文件解析記錄

3)設置埠映射

  • 查看指定容器上的埠映射:docker port myweb
# 將myweb容器上的80埠暴露到宿主機的隨機埠(一般是3萬之後)
docker run --name myweb --rm -p 80 hgzerowzh/httpd:v0.2
    # 可以在iptables生成的規則中查看這個隨機埠
    # iptables -t nat -vnl
    # 這條iptables規則會隨著容器的刪除而自動刪除

# 埠映射的規則,-p選項可以使用多次
    -p 80 
        # 將容器的80埠expose至宿主機的隨機埠(一般是3萬之後)
     # 會暴露到宿主機上所有的IP上
    -p 宿主機IP::容器埠
        # 將指定的容器埠映射到主機指定IP的動態埠
     # 只是指定宿主機的IP地址,宿主機的埠還是隨機的
    -p 80:80
        # 將宿主機的80埠映射到容器的80埠(前面的80表示宿主機)
    -p 宿主機IP:宿主機埠:容器埠
       # 將宿主機指定IP的指定埠映射到容器的埠
    -P  # 大P表示直接暴露容器中暴露的埠
     # 表示只要容器中暴露了埠,則將其直接暴露到宿主機中

5.5 聯盟式容器

1)概述

聯盟式容器指用某個已經存在的網路介面的容器,介面被聯盟內的各容器共享使用,因此,聯盟式容器彼此間完全無隔離。

聯盟式容器彼此之間雖然共享一個網路名稱空間,但其他名稱空間如User、Mount等還是隔離的。

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

2)容器之間共享網路名稱空間

# 創建一個監聽於2222埠的http服務容器
docker run --name b1 -d -it --rm -p 2222 busybox:latest /bin/httpd -p 2222 -f 

# 創建一個聯盟式容器,並查看其監聽的埠
docker run --name b2 -it --rm --network container:b1 buxybox:latest netstat -tan
    # --network container:b1 表示這個b2容器共享b1容器的網路名稱空間

 5.6 自定義網橋

1)自定義docker0橋網路屬性資訊

  • 編輯 /etc/docker/daemon.json 文件
{
  "bip": "192.168.1.5/24",
  "fixed-cidr": "10.20.0.0/16",
  "mtu": 1500,
  "default-gateway": "10.20.1.1",
  "default-gateway-v6": "2001:db8:abcd::89",
  "dns": ["10.20.1.2","10.20.1.3"]              
}
# 核心選項為bip,即bridge ip之意,用於指定docker0橋自身的IP地址
# 配置文件中最後一個key後面不能有逗號,否則語法錯誤
# 一般指定bip就可以了,其他選項會自動計算得知,如果希望容器的dns不使用系統的dns,也可以指定dns

2)自己創建橋

  • 可以自己手動再創建一個網橋
# 再創建一個網橋mybr0,地址是172.26.0.0/16,網關是172.26.0.1
docker network create -d bridge --subnet "172.26.0.0/16" --gateway "172.26.0.1" mybr0
# mybr0隻是網路叫mybr0,網路介面的名字是 自動生成的,可以改成其他名字
  • 創建一個容器,加入剛剛的網路
docker run --name t1 -it --network mybr0 busybox:latest

# 在宿主機上打開核心轉發,就可以讓兩個網段的容器通訊
# 如果ping不通,是跟iptables規則有關,被iptables阻斷了而已

3)允許docker從外部連入

  • 默認docker是監聽在本機的Unix Sock套接字上
  • docker的守護進程的C/S,其默認僅監聽Unix Socker格式的地址,/var/run/docker.sock
  • 如果要使用TCP套接字,需要修改配置文件 /etc/docker/daemon.json
"hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]
  • 遠程連入docker:
    • docker  -H  10.0.0.204:2375  ps
    • docker  -H  10.0.0.204:2374  image  ls

6. docker存儲卷

6.1 存儲卷概述

1)文件的寫時複製

Docker鏡像由多個只讀層疊加而成,啟動容器時,Docker會載入只讀鏡像層並在鏡像棧頂部添加一個讀寫層。

如果運行中的容器修改了現有的一個已經存在的文件,那該文件會從讀寫層下面的只讀層複製到讀寫層,該文件的只讀版本仍然存在,只是已經被讀寫層中該文件的副本所隱藏,此即「寫時複製(COW)」機制。

2)數據持久化問題

當關閉並重啟容器時,其數據不受影響,但是如果刪除Docker容器,則其更改將會全部丟失。

  • 容器存儲數據會存在如下問題:
    • 容器中的數據存儲於聯合文件系統中,不易於宿主機訪問
    • 容器間數據共享不便
    • 刪除容器其數據會丟失
  • 解決方案:卷(volume)
    • 「卷」 是容器上的一個或多個 「目錄」,此類目錄可以繞過聯合文件系統,與宿主機上的某目錄「綁定(關聯)」

Volume與容器初始化之時就會創建,由base image提供的卷中的數據會於此期間完成複製。

Volume的初衷是獨立於容器的生命周期實現數據持久化,因此刪除容器的時候既不會刪除卷,也不會對未被引用的卷做垃圾回收操作。

3)獨立於容器的數據管理機制

可以把「鏡像」想成靜態文件,例如「程式」,把卷類比為動態內容,例如「數據」,於是,鏡像可以重用,而卷可以共享

卷實現了「程式(鏡像)」和「數據(卷)」分離,以及「程式(鏡像)」和「製作鏡像的主機」分離,用戶製作鏡像時無須再考慮鏡像運行的容器所在的主機的環境。

3)常見的服務可以分為有狀態的服務和無狀態的服務兩種

  • 有狀態的服務:mysql、redis、tomcat,需要持久存儲
  • 無狀態的服務:nginx、httpd等

6.2 卷的類型Volume Type

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

1)Bind mount volume (綁定掛載卷)

  • 明確指定容器和宿主機上的對應位置
  • 即需要手工指定宿主機和容器內目錄的綁定關係
  • 注意:bind方式創建的目錄在容器刪除後依舊可以實現持久化存儲,不會刪除或消失

2)Docker-managed volume (Docker管理的卷)

  • 在容器中指定位置,但它在宿主機中對應的位置由docker來自行管控
  • 不需要特別指定綁定關係,而由docker管理,一般綁定的目錄為/var/lib/docker/volumes/container id 目錄下
  • 注意:這種方式創建的文件會在容器刪除後自動刪除,不能實現真正的持久化

6.3 在docker中使用volumes

  • 為docker run命令使用-v選項即可使用Volumes

1)Docker管理的卷

# 將容器的/data目錄映射到宿主機的docker管理的目錄中
docker run -it --name bbox1 -v /data busybox

# 可以使用docker inspect bbox1來查看/data在宿主機上所對應的目錄位置
# 在docker inspect的Mounts建所對應的值中查看
  • 過濾docker inspect中的內容
# 過濾顯示根下的Mounts中的內容
docker inspect -f {{.Mounts}} b2

# 過濾顯示根下的NetworkSettings中的內容
docker inspect -f {{.NetworkSettings}} b2

# 過濾顯示根下的NetworkSettings下的IPAddress中的內容
docker inspect -f {{.NetworkSettings.IPAddress}} b2

# 以上的 . 點 表示docker inspect顯示內容的根

2)綁定掛載卷

# 語法:docker run -it -v HOSTDIR:VOLUMEDIR --name bbox2 busybox

# 將宿主機中的/data/volumes/b2目錄和容器中的/data目錄做映射
docker run -it -v /data/volumes/b2:/data busybox

# 默認會在宿主機上自動創建目錄

3)複製使用其他容器的卷

  • 為docker run命令使用 –volumes-from 選項即可
# 創建bbox2時直接複製使用bbox1的卷
docker run -it --name bbox2 --volumes-from bbox1 busybox

7. dockerfile文件詳解

7.1 Dockerfile簡介

1)Dockerfile

  • 將用來全自動構建鏡像文件,命名為Dockerfile
  • 注釋行用 # 號開頭
  • 用docker build做鏡像時,docker build主機還要隱藏式的啟用一個容器,以提供容器製作環境

2)打包時過濾文件

可以做一個單獨的隱藏文件: .dockerignore

在這個文件可以寫文件路徑,一行一個,可以使用通配符;在打包時,凡是在此文件中的內容,在打包時都不包含進來,包括dockerignore本身和dockerignore中定義的文件,都不會被打包進來

7.2 Dockerfile中的環境變數

1)變數的定義

  • 可以用ENV指令來定義環境變數

2)變數的引用(以下兩種寫法等價)

  • $variable_name
  • ${variable_name}

3)其他用法

${variable:-word}
    # 如果該變數沒有值或者值為空,則將word賦值給該變數
    # 如果變數有值,就用變數自身的值
${variable:+word}
    # 如果變數有值,則將word賦值給該變數
    # 如果該變數沒有值,則不設置該變數的值

4)在docker run時,向變數傳值

  • 在docker run時,使用-e參數即可向變數傳值
docker run --name web1 --rm -P -e WEB_SERVER_PACKAGE="nginx-1.15.1" tinyhttpd:v0.1-7 printenv 

7.3 Dockerfile文件編寫指令及語法

  • 在Dockerfile文件中是不區分字元大小寫的
  • 在Dockerfile中,每一條指令都會生成一個新的鏡像層,因此,如果能把兩條指令寫成一條,就一定要寫成一條

1)FROM

  • FROM指定必須為Dockerfile文件開篇的第一個非注釋行,用於為構建過程指定基準鏡像,後續的指令運行於此基準鏡像所提供的運行環境。
  • 基準鏡像可以是任何可用鏡像文件,默認情況下,docker build會在docker主機上查找指定的鏡像文件,在其不存在時,則會從Docker Hub Registry上拉取所需的鏡像文件。如果找不到指定的鏡像文件,docker build會返回一個錯誤資訊。
  • 兩種使用語法格式:
    # 第一種,直接指定倉庫和標籤
    FROM <repository>[:<tag>]
    # 如 FROM busybox:latest
    # 如果不指定tag,則默認就為latest
    
    # 第二種,指定鏡像的哈希碼,以防止鏡像被別人冒名頂替
    FROM <repository>@<digest>

2)LABEL

  • 用於讓Dockefile製作者提供本人的詳細資訊,定義為key=value的形式
  • 一個鏡像可以有多個LABEL,並且可以將多個LABEL定義在一行
  • 兩種語法格式:
    # 以下兩種方式等價
    LABEL  "hgzerowzh <[email protected]>"
    LABEL  maintainer="hgzerowzh <[email protected]>" 

3)COPY

  • 用於從Docker主機複製文件至創建的新印象文件
  • 使用語法:
    COPY  <src>  ...  <dest>
    # <src> 表示要複製的源文件或目錄,支援使用通配符
    # <dest>  表示目標路徑,即真在創建的image的文件系統路徑,
        # 建議dest使用絕對路徑,否則COPY指定則以WORKDIR為其起始路徑
    
    # 如果路徑中有空白字元時,可以使用如下格式
    COPY  ["<src>" ... "<dest>"]
  • 注意事項:
    • <src> 必須是build上下文中的路徑,不能是其父目錄中的文件
    • 如果<src>是目錄,則其內部文件或子目錄會被遞歸複製,但<src>目錄自身不會被複制(如果源是目錄,那麼只會複製該目錄下的所有文件)
    • 如果指定了多個<src>,或在<src>中使用了通配符,則<dest>必須是一個目錄,且必須以 / 結尾

4)ADD

  • ADD指令類似於COPY指令,ADD支援使用tar文件和URL路徑
  • 使用語法:
    ADD  <src> ... <dest>
    
    # 或者使用如下形式
    ADD  ["<src>" ... "<dest>"]
  • 注意事項:
    • 如果<src>為URL,且<dest>不以 / 結尾,則<src>指定的文件將被下載並創建為<dest>;如果<dest>以 / 結尾,則文件名URL指定的文件將被下載並保存為<dest>/<filename>
    • 如果<src>是一個本地系統上壓縮格式的tar文件,它將被展開為一個目錄,其行為類似於「tar -x」命令;但是通過URL獲取到的tar文件將不會自動展開
    • 如果<src>有多個,或其使用了通配符,則<dest>必須是一個以 / 結尾的目錄路徑;如果<dest>不以 / 結尾,則其被視作一個普通文件,<src>的內容將被直接寫入到<dest>

5)WORKDIR

  • 用於為Dockerfile中所有的RUN、CMD、ENTRYPOINT、COPY和ADD設定工作目錄
  • 使用語法:
    # 使用格式
    WORKDIR  <dir_path>
    
    # 使用示例
    WORKDIR /var/log
    WORKDIR $STATEPATH
  • 注意事項:
    • 在Dockerfile文件中,WORKDIR指令可出現多次,其路徑也可以為相對路徑,但它是相對於此前一個WORKDIR指令指定的路徑
    • WORKDIR也可以調用有ENV指定定義的變數

6)VOLUME

  • 用於在image中創建一個掛載點目錄,以掛載Docker host上的卷或其他容器上的卷
  • 使用語法:
    VOLUME   <mountpoint>
    
    # 或者使用如下語法
    VOLUME  ["<mountpoint>"]
  • 注意事項:
    • 如果掛載點目錄路徑下存在文件,docker run命令會在卷掛載完成後將此前的所有文件複製到新掛載的卷中

7)EXPOSE

  • 用於為容器打開指定要監聽的埠以實現與外部通訊
  • 使用語法:
    EXPOSE  <port>[/<protocol>][<port>[/<protocol>] ... ]
    # <protocol>用於指定傳輸層協議,可為tcp或udp二者之一,默認為TCP協議
    
    # EXPOSE指令可一次指定多個埠
    EXPOSE  11211/udp  11211/tcp

8)ENV

  • 用於為鏡像定義所需要的環境變數,並可被Dockerfile文件中位於其後的其他指令(如ENV、ADD、COPY等)所調用
  • 調用格式為 $variable_name 或 ${variable_name}
  • 使用語法:
    # <key>之後的所有內容均會被視作其<value>的組成部分,因此,一次只能設置一個變數
    ENV  <key>  <value>
    
    # 可用一次設置多個變數,每個變數為一個"<key>=<value>"的鍵值對
    # 如果<value>中包含空格,可以以反斜線 \ 進行轉義,也可以通過對<value>加引號進行標識
    # 反斜線也可以用於續行ENV  <key>=<value> ...
  • 注意事項:
    • 定義多個變數時,建議使用第二種方式,以便在同一層中完成所有功能

9)RUN

  • 用於指定docker build過程中運行的程式,其可以是任何命令
    • 每條RUN指令將在當前鏡像基礎上執行指定命令,並提交為新的鏡像,後續的RUN都在之前RUN提交後的鏡像為基礎
    • 鏡像是分層的,可以通過一個鏡像的任何一個歷史提交點來創建,類似源碼的 版本控制
  • exec會被解析為一個 JSON 數組,所以必須使用雙引號而不是單引號
  • exec方式不會調用一個命令shell,所以也不會繼承相應的變數
    ### 第一種使用語法
    RUN <command>
    # 在這種格式中,<command>通常是一個shell命令,且以"/bin/sh -c"來運行
    # 這意味著此進程在容器中的PID不為1,不能接收到Unix訊號,因此,當使用docker stop命令停止容器時,此進程接收不到SIGTERM訊號
    
    ### 第二種使用語法
    RUN <"executable","param1","param2">
    # 在這種格式中的參數是一個JSON格式的數組,<executable>為要運行的命令,後面的<param>為傳遞給命令的選項或參數
    # 但是這種格式指令的命令不會以"/bin/sh -c"來發起,因此常見的shell操作如變數替換以及通配符(?,*等)替換將不會進行
    # 如要要運行的命令依賴於此shell特性的時,可以將其替換為如下格式:
    RUN ["/bin/bash","-c","<executable>","<param1>"]
    RUN [
    "sh", "-c", "echo", "$HOME" ] # RUN產生的快取在下一次構建的時候是不會失效的,會被重用 # 可以使用--no-cache選項,即docker build-no-cache,這樣便不會快取

基本使用示例 :

  • mkdir  test  && cd  test
  • vim  Dockerfile
    # Description: test image
    FROM busybox:latest
    #FROM busybox@哈希碼
    # MAINTAINER "hgzerowzh <[email protected]>"
    LABEL maintainer="hgzerowzh <[email protected]>"
    ENV DOC_ROOT=/data/web/html \
        WEB_SERVER_PACKAGE="nginx-1.15.2"
    COPY index.html ${DOC_ROOT:-/data/web/html/}
    
    ADD http://nginx.org/download/nginx-1.15.2.tar.gz /usr/local/src/
    
    # WORKDIR /usr/local
    
    COPY yum.repos.d /etc/yum.repos.d/
    # ADD ${WEB_SERVER_PACKAGE}.tar.gz /usr/local/src/
    
    VOLUME /data/mysql/
    
    EXPOSE 80/tcp
    
    RUN cd /usr/local/src && \
        tar -x nginx-1.15.2.tar.gz
  • docker build -t tinyhttpd:v0.1-1  ./
    • -t   表示打上標籤

10)CMD

  • 類似於RUN指令,CMD指令也可用於運行任何命令或應用程式,但是二者的運行時間點不同
    • RUN指令運行於印象文件構建過程中,而CMD指令運行於基於Dockerfile構建出的新映像文件啟動一個容器時
    • CMD指令的首要目的在於為啟動的容器指定默認要運行的程式,且其運行結束後,容器也將終止;但CMD指定的命令可以為docker run 的命令行選項所覆蓋
    • 在Dockerfile中可以存在多個CMD指令,但僅最後一個會生效
  • 使用語法:
    # 下面這兩種語法格式的意義同RUN
    CMD <command> # 這種CMD運行命令的方式pid不為1 CMD ["<executable>", "<param1>", "<param2>"] # 這種語法格式用於為ENTRYPOINT指令提供默認參數
    CMD ["<param1>", "param2"]
  • 使用示例:
    FROM busybox
    LABEL maintainer="hgzerowzh <[email protected]>" app="httpd"
    
    ENV WEB_DOC_ROOT="/data/web/html"
    
    RUN mkdir -p $WEB_DOC_ROOT && \
        echo "<h1>Busybox httpd server.</h1>" > ${WEB_DOC_ROOT}/index.html
    
    # CMD /bin/httpd -f -h ${WEB_DOC_ROOT}
    CMD ["/bin/sh","-c","/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]

11)ENTRYPOINT

  • 類似CMD指令的功能,用於為容器指定默認運行程式,從而使得容器像是一個單獨的可執行程式
  • 由ENTRYPOINT啟動的程式不會被docker run命令行指定的參數所覆蓋,這些命令行參數會被當做參數傳遞給ENTRYPOINT指定的程式
    • docker run命令的–entrypoint選項的參數可以覆蓋ENTRYPOINT指令指定的程式
  • 如果dockerfile文件中同時存在CMD和ENTRYPOINT,則CMD的參數將被作為可選項傳遞給ENTRYPOINT
    • 如果docker run中指定有命令行參數選項,則這些命令行參數將會覆蓋掉CMD,並附加到ENTRYPOINT命令行作為其參數使用,否則才會將CMD作為參數傳遞給ENTRYPOINT
    • dockerfile文件中也可以存在多個ENTRYPOINT,但只有最後一個有效
  • 使用語法:
    # 跟RUN類似,在這種格式中,command通常為一個shell命令,且以"/bin/sh -c"來運行
    # 此進程在容器中的PID不為1
    ENTRYPOINT <command>
    
    # 跟RUN類似,這種格式指定的命令不會以"/bin/sh -c"發起,無法使用shell通配符等特性
    ENTRYPOINT ["<executable>","<param1>","<param2>"]
  • 使用示例:
    FROM busybox
    LABEL maintainer="hgzerowzh <[email protected]>" app="httpd"
    
    ENV WEB_DOC_ROOT="/data/web/html/"
    
    RUN mkdir -p $WEB_DOC_ROOT && \
        echo "<h1>Busybox httpd server.<h1>" > ${WEB_DOC_ROOT}/index.html
    
    # CMD /bin/httpd -f -h ${WEB_DOC_ROOT}
    CMD ["/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]
    ENTRYPOINT /bin/sh -c
    # 這樣運行時會用/bin/sh -c 來運行ENTRYPOINT中的/bin/sh -c ,並且CMD中的命令將會作為參數傳遞給ENTRYPOINT中的指令
    # 如果不想重複啟用/bin/sh -c ,可以寫成如下格式:
    # ENTRYPOINT ["/bin/sh","-c"]

實際使用示例:

  • dockerfile文件:
    FROM nginx:1.14-alpine
    LABEL maintainer="hgzerowzh <[email protected]>"
    
    ENV NGX_DOC_ROOT="/data/web/html"
    
    ADD index.html ${NGX_DOC_ROOT}
    ADD entrypoint.sh /bin/
    
    CMD ["/usr/sbin/nginx","-g","daemon off;"]
    
    ENTRYPOINT ["/bin/entrypoint.sh"]
  • 被調用的shell腳本文件:
    #!/bin/sh
    #
    cat > /etc/nginx/conf.d/www.conf << EOF
    server {
      server_name ${HOSTNAME};
      listen ${IP:-0.0.0.0}:${PORT:-80};
      root ${NGX_DOC_ROOT:-/usr/share/nginx/html};  
    }
    EOF
    
    exec "$@"
    # 因為CMD指令中的內容將會作為參數傳遞給ENTRYPOINT,
    # 所以當ENTRYPOINT調用此腳本文件執行完畢後,可以用exec來調用CMD指令內容中的nginx來覆蓋當前進程
    # 這樣保證了nginx進程的PID號依然為1

12)USER

  • 用於指定運行image時的用戶名或UID
  • 或者指定運行Dockerfile中任何RUN、CMD、ENTRYPOINT指令指定的程式時的用戶名或UID
  • 默認情況下,容器的運行身份為root用戶
  • 使用語法
    USER <UID> | <UserName>
    # <UID>可以為任意數字,但實踐中必須為/etc/passwd中某用戶的有效UID,否則docker run命令將運行失敗

13)HEALTHCHECK

  • 監控檢查,可以根據主進程所提供的服務正常與否來進行判定健康與否
  • 使用語法及參數:
    # 兩種語法形式
    HEALTHCHECK [OPTIONS] CMD command # CMD關鍵詞後也可以跟執行shell腳本的命令或者exec數組 HEALTHCHECK NONE # 意思是禁止從父鏡像繼承的HEALTHCHECK生效 # OPTIONS可設定的參數(下面選項中的值都是默認值)   --interval=30s # 每隔多長時間進行一次健康檢查(從容器運行起來開始計時),單位s、m、h   --timeout=30s # 執行command的超時時間   --start-period=0s # 啟動時間,也就是在這裡指定的時候之後再進行健康檢查   --retries=3 # 重試次數,連續檢查次數 # CMD執行完成可能的返回值   0 health狀態   1 unhealth狀態   2 reserved狀態 # 注意:在Dockerfile中只能有一個HEALTHCHECK指令,如果列出多個,則只有最後一個生效
  • 使用示例:
    HEALTHCHECK --interval=5m --timeout=3s \
        CMD curl -f //localhost/ || exit 1
  • 實際案例:
    FROM nginx:1.14-alpine
    LABEL maintainer="hgzerowzh <[email protected]>"
    
    ENV NGX_DOC_ROOT="/data/web/html"
    
    ADD index.html ${NGX_DOC_ROOT}
    ADD entrypoint.sh /bin/
    
    HEALTHCHECK --start-period=3s CMD wget -O - -q //${IP:-0.0.0.0}:${PORT:-80}/
    
    CMD ["/usr/sbin/nginx","-g","daemon off;"]
    
    ENTRYPOINT ["/bin/entrypoint.sh"]

14)SHELL

  • SHELL指令允許覆蓋用於shell形式命令的默認shell
    • Linux上默認的shell是 [“/bin/sh”, “-c”]
    • Windows上是 [“cmd”, “/S”, “/C”]
  • SHELL指令必須以JSON格式寫入Dockerfile,且SHELL指令可以出現多次,每個SHELL指令都會覆蓋所有先前的SHELL指令,並影響所有後續指令
  • 使用示例:
    FROM microsoft/windowsservercore
    
    # Executed as cmd /S /C echo default
    RUN echo default
    
    # Executed as cmd /S /C powershell -command Write-Host default
    RUN powershell -command Write-Host default
    
    # Executed as powershell -command Write-Host hello
    SHELL ["powershell", "-command"]
    RUN Write-Host hello
    
    # Executed as cmd /S /C echo hello
    SHELL ["cmd", "/S", "/C"]
    RUN echo hello

15)STOPSIGNAL

  • STOPSIGNAL指令設置將發送到容器的系統調用訊號以退出
    • 此訊號可以是與內核的系統調用表中的位置匹配的有效無符號數,如9,或SIGNAME格式的訊號名,如SIGKILL
    • 停止進程的訊號,默認是發15的訊號,也可以改成9
  • 默認的stop-signal是SIGTERM,在docker stop的時候會給容器內PID為1的進程發送這個signal,主要的目的是為了讓容器內的應用程式在接收到signal之後可以先做一些事情,實現容器的平滑退出,如果不做任何處理,容器將在一段時間之後強制退出,會造成業務的強制中斷,這個時間默認是10s
  • 使用語法:
    STOPSIGNAL signal

16)ARG

  • 可以在dockerfile文件中用ARG指令定義一些變數,然後在docker build的時候將這些變數傳遞進去
    • ARG所定義的參數,在docker build命令中以 –build-arg NAME=VALUE的形式進行賦值
    • 如果docker build命令傳遞的參數在Dockerfile中沒有對應的參數,則會拋出警告
  • 使用示例:
    • 先在dockerfile文件中定義ARG
      ARG author=「hgzerowzh」
    • 然後在dockerbuild的時候通過 –build-arg 將對應的值傳進去
      docker build --build-arg author=「wzh」 -t myweb:v0.3-10 ./

17)ONBUILD

  • ONBUILD用於在dockerfile中定義一個觸發器
    • 這個觸發器不是在自己被build的時候執行,而是此鏡像被別人拿去做基礎鏡像時觸發執行,也就是被別人FROM的時候觸發執行
    • 一般ONBUILD都是執行RUN或者ADD
  • ONBUILD不能自我嵌套,且不會觸發FROM和MAINTAINER指令
  • 使用包含ONBUILD指令的Dockerfile構建的鏡像應該使用特殊的標籤,如ruby:2.0-onbuild
  • 在ONBUILD指令中使用ADD或COPY指令時應該要特別注意,因為新構建過程的上下文在缺少指定的源文件時會失敗
  • 使用示例:
    ONBUILD ADD . /app/src
    ONBUILD RUN /usr/local/bin/python-build --dri /app/src

8. 構建私有Registry

8.1 私有Registry概述

1)私有倉庫搭建的好處

  • 節約頻寬
  • 可以自己訂製系統
  • 更加安全

2)構建私有Registry的方式

  1. 利用官方提供的工具docker-registry來配置私庫
    • 這個工具是一個鏡像,直接下載並使用registry鏡像啟動docker實例就可以了
  2. 利用Harbor-Registry來搭建私庫
    • Harbor是一個用於存儲Docker鏡像的企業級Registry服務

8.2 通過docker-registry來配置私庫

1)安裝docker私有倉庫

  • 要在私庫上安裝好docker,然後直接yum安裝docker-registry
yum install docker-registry

# 安裝完成後即可直接啟動服務,要注意這裡的是docker-distribution
systemctl start docker-distribution

# 安裝完成後可以查看一下生成的文件
rpm -ql docker-distribution

2)配置文件

  • vim  /etc/docker-distribution/registry/config.yml 
version: 0.1
log:
  fields:
    service: registry        # 定義啟動的服務
storage:
    cache:
        layerinfo: inmemory  # 定義快取在記憶體中
    filesystem:
        rootdirectory: /var/lib/registry  # 定義數據存放的位置
http:  
    addr: :5000              # 定義監聽的埠,冒號後面沒寫地址表示監聽本機的所有地址

3)把鏡像推送到剛剛建好的私有倉庫

  • 先要對鏡像打標:
    dcoekr tag myweb:v0.3-11  node1.hgzerowzh.com:5000/myweb:v0.3-11
    # myweb前面沒有加其他的用戶名,這裡表示這是一個頂層倉庫
    # node1.hgzerowzh.com:5000是倉庫的地址
  • 然後將鏡像推送上去:
    # 如果不給標籤,會推送整個倉庫
    docker push node1.hgzerowzh.com:5000/myweb
    
    # 推送時,因為客戶端使用的是https的連接,而服務端是http的響應,所以推送時會出錯
    docker push node1.hgzerowzh.com:5000/myweb:v0.3-11
    
    # 倉庫必須做成https的
    # 如果是在內網使用,確實不想使用https,就可以在客戶端添加配置,明確說明要使用非安全的docker registry

4)明確指定要使用非安全的docker-registry

# 特別注意,如下配置是要在客戶端配置的,誰要連接docker-registry就在誰上配置

vim /etc/docker/daemon.json

{
        "registry-mirrors": ["//registry.docker-cn.com"],
        "insecure-registries":["node1.hgzerowzh.com:5000"]  # 在這裡指定非安全的docker-registry
}

8.3 通過harbor-registry來配置私庫

1)harbor概述

harbor是VMwar公司基於docker registry開發的一個用於存儲和分發docker鏡像的企業級registry伺服器。

harbor通過添加需要的功能如安全性、身份認證、管理來擴展了源Docker Distribution,提升了鏡像的傳輸效率;harbor支援registry之間複製鏡像,還提供了更高級的安全功能,比如:漏洞分析、用戶管理、訪問控制、活動審計等。

2)harbor的安裝

harbor有兩種安裝方式:online installer / offline installer

online installer:從docker hub下載安裝

offline installer:沒有網路時,下載離線安裝包安裝

9. Docker資源限制

9.1 記憶體資源限制

9.2 CPU資源限制

 

 

 

 

 參考:

  • //www.cnblogs.com/xiaoshancun/p/12352981.html
  • //www.cnblogs.com/zuxing/articles/8780661.html
  • //www.cnblogs.com/zhangxingeng/p/11236968.html
  • //www.cnblogs.com/zhangxingeng/p/11558782.html
  • //www.cnblogs.com/zhangxingeng/p/11598708.html

 

 

 

Tags: