天天看點

2.Docker容器學習之新生入門必備基礎知識

文章目錄

        • 0x02 Docker 核心概念
          • 1.鏡像 [image]
          • 2.容器 [Container]
          • 3.倉庫 [Repository]
        • 0x03 Docker 資料管理
          • 1.資料卷
          • 2.資料卷容器
        • 0x04 Docker 網絡管理

0x02 Docker 核心概念

描述:Docker的三大核心概念鏡像/容器和倉庫, 通過三大對象核心概念所建構的高效工作流程;

1.鏡像 [image]

描述:images 類似于虛拟機鏡像,借鑒了Git利用分成分層優點,通過檔案系統分層的概念實作了分層複用,極大的節約了磁盤空間;簡單的您可以将它了解成為一個面向Docker引擎的隻讀模闆包含檔案系統;

  • 鏡像是建立Docker容器的基礎,然後通過版本管理和增量的檔案系統;
  • 使用者基于鏡像來運作自己的容器,鏡像是基于 Union 檔案系統的層式結構;

Docker運作容器前本地必須存在對應的鏡像,如果不指定鏡像名将會預設自動采用Docker Hub公共注冊伺服器倉庫中該名稱的鏡像;

Docker 鏡像使用幫助:https://lug.ustc.edu.cn/wiki/mirrors/help/docker

基礎知識:

  • 1.鏡像名稱格式:

    Image hub address/Namespace/Repository:tag

    hub.weiyigeek.top/Test//alpine-apps:1.0

  • 2.典型Linux啟動需要運作兩個FS即:

    Kernel > Bootfs > Rootfs

  • 3.鏡像的分層結構: 新鏡像是從Base鏡像一層一層疊加的,每安裝一個軟體就在現有鏡像基礎上增加一層;

鏡像操作關鍵點:

docker search [鏡像名稱] #搜尋關于Archlinux鏡像
#支援的參數:
--automated=false #僅僅顯示自動建立的鏡像(官方)
--no-trunc=false  #輸出資訊不截斷顯示
-s,--stars=0    #指定僅顯示評價為指定星級以上的鏡像

#倉庫名(Repository) 或者 标簽名[不指定着預設latest,即最新]
docker pull name/[repository[:tag]] #擷取Hub鏡像如果不指定TAG将預設選擇倉庫中最新頒布的鏡像
docker push DockerHubUser使用者/test:latest  #上傳到docker倉庫

docker images   #列出本機已有鏡像

docker tag 原倉庫[:标簽] 新倉庫名[:标簽]  #為本地鏡像添加一個新标簽 [注意倉庫名稱必須小寫]
docker tag <image id> username/name:devel #修改鏡像的标簽

docker inspect [image id]  #擷取鏡像的詳細資訊
docker inspect -f {{".Architecture"}} 550(images Id 前面3位)  #-f 擷取單個屬性 傳回JSON
  
docker rmi [<image id>|<repository> ]   #删除鏡像 鏡像id|倉庫名稱
docker rmi -f <images id>   #不建議強行删除正在容器中運作的鏡像檔案

docker save -o 儲存檔案名.tar  [repository[:tag]]  #将鏡像檔案打包存出到磁盤
docker save [repository[:tag]] > 儲存檔案名 #将鏡像檔案打包存出到磁盤

docker load --input 儲存檔案名.tar   #将打包的鏡像檔案進行載人
docker load < 儲存檔案名.tar
           

運作案例:

$ sudo docker pull ubuntu:16.04                #下載下傳14.04 tag的鏡像
Using default tag: latest
latest: Pulling from library/ubuntu
#從下面可以看出鏡像檔案一般是由若幹組成,行首f476d66f5408代表了各層的ID,下載下傳過程中會擷取并輸出鏡像各層資訊
#層(Layer)其實是AUFS(Advanced Union File System聯合檔案系統)重要機率是實作增量儲存于更新的基礎
f476d66f5408: Pulling fs layer
8882c27f669e: Pulling fs layer
d9af21273955: Pulling fs layer
f5029279ec12: Waiting

$ sudo docker pull registry.hub.docker.com:5000/ubuntu   #從指定長倉庫進行下載下傳

$ sudo docker run -t -i Ubuntu /bin/bash        #利用dockerubuntu鏡像建立一個容器 倉庫後面是接的指令
[email protected]:/# w
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
 03:34:47 up  1:59,  0 users,  load average: 0.00, 0.05, 0.06
[email protected]:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.2 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.2 LTS"


$ sudo docker images   #列出鏡像
#其中Image id的資訊十分重要,它唯一标示了鏡像,Tag資訊來區分發行版本(如14.04,16.04) 
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              d131e0fa2585        9 days ago          102MB
centos              latest              9f38484d220f        7 weeks ago         202MB
#REPOSITORY (來自哪個倉庫)  TAG (鏡像的标簽資訊)   IMAGE ID (鏡像的ID号,唯一)    CREATED [Created:建立時間] VIRTUAL SIZE (鏡像大小)


$ sudo docker tag ubuntu:latest ubuntu18.04:latest #修改鏡像名稱使用該方式進行添加新标簽原來的不會被删除
$ sudo docker tag d131e0fa2585 ubuntutls:latest
$ sudo docker images
#更改後鏡像的ID是完全一緻的,其實都指向了同一個鏡像檔案相當于别名而已;
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntutls           latest              d131e0fa2585        9 days ago          102MB
ubuntu18.04         latest              d131e0fa2585        9 days ago          102MB 

$ sudo docker inspect d131e0fa2585 #擷取該鏡像的詳細資訊
$ sudo docker inspect -f {{".Architecture"}} d131  #擷取系統架構 通常使用鏡像ID的前三位
amd64
           
2.Docker容器學習之新生入門必備基礎知識

當該鏡像在容器運作存在的時候,鏡像檔案預設是無法被删除的;必須停止/删除容器ID才能删除鏡像檔案;

#當同一個鏡像有多個标簽的時候rmi指令隻是删錯了該進行的标簽而且,并不影響鏡像檔案
#但當隻剩下一個标簽的時候就要小心了,如果在停止的狀态下再次使用rmi指令則會删除該鏡像
$ sudo docker rmi ubuntu18.04
Untagged: ubuntu18.04:latest
$ sudo docker rmi ubuntu ubuntutls
Untagged: ubuntu:latest 
Untagged:  #删除了這個鏡像檔案的所有AUFS層
[email protected]:d26d529daa4d8567167181d9d569f2a85da3c5ecaf539cace2c6223355d69981

$ sudo docker rmi -f ubuntutls  #強制删除
Untagged: ubuntutls:latest
Deleted: sha256:d131e0fa2585a7efbfb187f70d648aa50e251d9d3b7031edf4730ca6154e221e
           

建立鏡像有三種辦法:

  • 1.從已有鏡像的容器建立
  • 2.基于本地模闆導入:使用作業系統模闆導入一個鏡像檔案;這裡推薦使用OpenVZ提供的模闆來常見
  • 3.基于Dockerfile導入
######### 從已有鏡像建立 ############
$sudo docker commit [option-選項] ContainerId [Repository[:Tag]]
$sudo docker commit -m "xx" -a "oo" ContainerID(被修改過的ID) [Repository[:Tag]] 
# -a,--author="作者"
# -m,--message="更改資訊"
# -p,--pause=ture 送出時暫停容器Container運作

$sudo docker run -it centos:latest /bin/bash
[[email protected] ~]$ touch {1..10}.txt  #上面這個容器ID非常重要在進行修改之後

$sudo docker container ls -a   #檢視容器記錄
#建立一個新的鏡像
$sudo docker commit -m "Zabbix base in Centos7" -a "Weiyigeek" 32a481e170c6 centoszabbix:latest
sha256:680ddb57c4b80c625ef68e113f553ee932a06f25d4685d25a0b6464cf5d60982  #成功會給出一個鏡像ID

######### 從本地模闆導入 ############
$sudo cat ubuntu-14.04.tar.gz | docker import - ubuntu:14.04  #本地導入鏡像指令
           

存出和載人鏡像并上傳鏡像到DockerHub中執行個體:

$docker save -o zabbixcentos.tar centoszabbix:latest
ls -alh zabbixcentos.tar
-rw------- 1 root root 200M 5月   6 13:16 zabbixcentos.tar
$docker load --input zabbixcentos.tar
Loaded image: centoszabbix:latest

$docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centoszabbix (上面從已有鏡像檔案中建立)       latest              622b7661c06b        13 minutes ago      202MB

#使用者需要在DockerHub網站注冊後才能進行上傳鏡像
$docker login  #在及其上進行登入
# Login with your Docker ID to push and pull images from Docker Hub. If you don have a Docker ID, head over to https://hub.docker.com to create one.
# Username: weiyigeek
# Password: 輸入hub密碼
# WARNING! 賬号密碼base64編碼存放于 /root/.docker/config.json 檔案中
# echo "d2VpeW********VrO***ldlaXllMjAxOQ==" | base64 -d
# weiyigeek:Docker
# https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded  #表示登入成功

$docker push weiyigeek/czabbix:latest
The push refers to repository [docker.io/weiyigeek/czabbix]
484404f26982: Pushed
d69483a6face: Mounted from library/centos
latest: digest: sha256:c1d891c2d56a0677ff28639189fa7252790d3b8ef417816570fb3a7654bc4e05 size: 736  #表示上傳成功傳回的票據
           
2.Docker容器學習之新生入門必備基礎知識

鏡像的F&Q相關問題

Q:Docker 鏡像是怎麼實作增量的修改和維護的?

答:每個鏡像都由很多層次構成,Docker 使用 Union FS 将這些不同的層結合到一個鏡像中去。

通常 Union FS 有兩個用途:(Docker 在 AUFS 上建構的容器也是利用了類似的原理)

  • 一方面可以實作不借助 LVM、RAID 将多個 disk 挂到同一個目錄下
  • 就是将一個隻讀的分支和一個可寫的分支聯合在一起,Live CD 正是基于此方法可以允許在鏡像不變的基礎上允許使用者在其上進行一些寫操作

Q:什麼是鏡像寫時複制?

答: 比如典型的Linux啟動首先會将rootfs置為readonly再進行一系列檢查後将其切換為readwrite供使用者使用,當在Docker中起初也是将rootfs置為readonly,然後利用union mount将一個readwrite檔案系統挂載隻讀的rootfs之上,并且運作再次将下層的檔案系統設定為readonly并且向上疊加,我們把這樣一組readonly和一個writeable的結構構成一個容器的運作目錄,每一個被稱為一個Layer;

Writable : Container  (可以向上疊加同時它變成一層Image)
add Apache : Image (Reference parent-引用父)
add Emacs : Image  (Reference parent-引用父)
Debian : Base Image
> Bootfs
lxc,aufs,brtfs : Kernel
           

Q:Docker 中 save 和 export 指令的差別?

答: 我們先簡單的說一下其差別,在随後的的例子中使您更快的了解;

  • 1.save 與 load 指令對應即導出與導入鏡像,而export與import指令對應即導出導入容器;
  • 2.save 儲存後 load 加載的鏡像沒有丢失曆史和層(Layer),而容器export導出然後import導入時所有的送出曆史将會丢失,這意味着您無法復原到之前的層;
  • 3.補充:通過import導入的方式鏡像隻有一層,而通過commit的方式生成的鏡像實際是在原有的Base Image(即複寫層)上又生成了一層;
# 1.在一個正在運作的容器上建立一個目錄然後commit
docker exec -it test1 mkdir /tmp/demo
docker commit -a "WeiyiGeek" -m "create /tmp/demo directory" test1 test:1.2 #加上tag鏡像名稱:版本防止玄虛鏡像
sha256:30a048249000dd36561bffaa9fecc7690a45ef12096849c77afd4543b0d2d9b0

# 2.采用save指令進行導出送出的鏡像
docker save -o save.tar 30a048

# 3.采用export進行導出正則運作的容器
docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
25d2d645bfc9        test1               "top -b -d 2"       2 weeks ago         Up 3 days                               test1
docker export test1 > export.tar # 或者 docker export 25d > export.tar


# 4.在另外一台機器上進行分别導入 save.tar 與 export.tar
docker load -i save.tar #此時預設導入會導緻虛懸鏡像
Loaded image ID: sha256:30a048249000dd36561bffaa9fecc7690a45ef12096849c77afd4543b0d2d9b0
cat export.tar | docker import - test1:1.0
sha256:cdd65e7054be9e1928fe8133380817e81ff12b8493b40e2f9106efedac5ee572

# 5.檢視導入情況
docker images
REPOSITORY                            TAG                 IMAGE ID            CREATED             SIZE
<none>                                <none>              30a048249000        2 minutes ago       7.37MB
test1                                 1.0                 cdd65e7054be        3 minutes ago       7.35MB

# 6.檢視異同
[[email protected] ~]$ docker history 30a # save 方式 存在曆史層資訊
# IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
# 30a048249000        22 minutes ago      -d 2                                            193B                create /tmp/demo directory
# <missing>           2 weeks ago         /bin/sh -c #(nop)  CMD ["-d" "2"]               0B
# <missing>           2 weeks ago         /bin/sh -c #(nop)  ENTRYPOINT ["top" "-b"]      0B
# <missing>           2 weeks ago         /bin/sh -c echo "http://mirrors.huaweicloud".…   1.8MB
# <missing>           2 weeks ago         /bin/sh -c #(nop)  MAINTAINER WeiyiGeek mast…   0B
# <missing>           2 weeks ago         /bin/sh -c #(nop)  LABEL Author=WeiyiGeek De…   0B
# <missing>           5 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
# <missing>           5 weeks ago         /bin/sh -c #(nop) ADD file:c92c248239f8c7b9b…   5.57MB
[[email protected] ~]$ docker history cdd # export 方式無曆史層資訊且隻有一層
# IMAGE               CREATED             CREATED BY          SIZE                COMMENT
# cdd65e7054be        23 minutes ago                          7.35MB              Imported from -
           
2.容器 [Container]

描述:Docker容器Container類似于一個輕量級的沙箱,也可以看做一個簡易版的Linux系統環境;因為容器是運作應用程式的,是以必須得先有一個作業系統為基礎

Docker利用容器來運作和隔離應用;

  • 容器是從鏡像建立的應用獨立運作的執行個體;
  • 可以進行啟動/開始/停止/删除容器,而這些容器都是互相隔離,互不可見的;
  • 鏡像自身隻讀的,容器從鏡像啟動的時候會在鏡像的最上層建立一個可寫層,鏡像本身将保持不變;
  • 建立容器、啟動容器、終止容器、進入容器、删除容器、導入導出容器實作容器遷移;

當建立并運作容器時候Docker在背景運作的标準操作包括:

  • 檢查本地是否存在指定鏡像,不存在就從公有倉庫下載下傳
  • 利用鏡像建立并啟動一個容器
  • 配置設定一個檔案系統,并在隻讀的鏡像層外面挂載一個可讀寫層
  • 從宿主主機配置的網橋接口中橋接一個虛拟接口到容器中去
  • 從位址池配置一個IP位址給容器
  • 執行使用者指定的應用程式
  • 執行完畢後容器被終止

啟動容器有兩種方式:

  • 一種是基于鏡像建立一個容器并啟動
  • 另外一個是将在終止狀态(stopped)的容器重新啟動。

關鍵指令:

docker create -it repository[:tag] #建立容器但處于停止狀态

docker start -a -i <container id>   #啟動建立的容器
# -a 參數   連接配接容器并列印輸出或錯誤 -
# -i 參數   啟動容器并進入互動模式

docker run -t -i repository[:tag]  /bin/bash #建立并啟動容器 等同于上面兩條指令
# -t:讓Docker配置設定一個僞終端(pseudo-tty)并綁定在容器的标準輸入上.
# -i:則讓容器的标準輸入保持打開.
# CTRL+Z 和 Exit 則退出容器Container
docker run -d repository[:tag] /bin/sh -C "echo hello word" #守護态運作
# -d 參數即可背景運作,使用者無法看到容器中的資訊
# -c 執行的Command
# --rm 添加這個标記,容器會在停止後立即删除自身   (注意:與-d不能同時使用)
# --name 使用--name web 标記可以為容器重新命名

docker logs <Container-id>      #擷取容器的輸出資訊

docker attach [names]  #采用ps -a NAMES 進入容器

docker exec -it <Container-id>  /bin/bash  #docker exec 至1.3版本起可以在容器中運作指令

docker ps -aq   #顯示本機上的所有容器ID運作的容器ID資訊

docker restart <container id>  #重新開機容器

docker stop <container id>  #停止容器
docker kill <cantainer id>  #強行終止容器 可以直接發送SIGKILL信号來終止容器

docker rm <container id>    #删除容器删除依賴該鏡像的容器ID,前3位即可
# -f,--force=false 強制終止并删除一個運作中的容器[預設會發生SIGKILL信号]
# -l,--link=false  删除容器連接配接但保留容器
# -v,--volumes=false  删除容器挂載的資料卷

docker export <container id> >導出檔案.tar  #導出容器

docker import - repository[:tag] #導入容器
           
2.Docker容器學習之新生入門必備基礎知識

執行個體指令:

#建立容器
$sudo docker create -it weiyigeek/czabbix  
2b72a3410be576aeb9023ef2c41488e7b2630cf2282b8a0b1dddce771f22231f

#啟動容器ID執行交換登入,start可以進入到任何在容器中運作
$sudo docker start -i 2b7  
# [[email protected] /]# whoami
# root
# [[email protected] /]# exit
#對于建立後的容器采用exit指令退出後該容器自動處于終止狀态;
#提示:正常退出不關閉容器請按Ctrl+P+Q進行退出容器

$sudo docker ps -a  #顯示本機上存在的所有容器
# CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                           PORTS               NAMES
# 634e7ed26d76        d131e0fa2585        "/bin/bash"         About an hour ago   Exited (130) About an hour ago                       recursing_goodall
# b72a3410be5        weiyigeek/czabbix   "/bin/bash"         41 seconds ago      Up 21 seconds                           priceless_chaplygin

$docker run -t -i centos /bin/bash  #建立容器并且運作
# [[email protected] /]# hostname
# 0b9aef4876d3

$ddocker run -d centoszabbix /bin/sh -c "echo Hello World,Docker Container"
4e62768b1d9196fc79fd740c103df79c8e3bb09d9c6810aa43976abeda036a26

$ddocker logs 4e62  #擷取容器輸出的資訊
Hello World,Docker Container

$docker attach priceless_chaplygin  #通過上面的ps -a 中names進入想對應的容器
#當多個視窗同時 attach 到同一個容器的時候 所有視窗都會同步顯示 。當某個視窗因指令阻塞時,其他視窗也無法執行操作了
# [[email protected] /]$ hostname
# b72a3410be5

$docker exec -ti b72 /bin/echo "whoami"   #可以通過exec直接執行指令和進入shell
# whoami


#停止容器
#當需要删除一個在容器中運作的鏡像的時候,會導緻不能删除鏡像[Image]這時候必須先停止再删除容器[container]:
$sudo docker stop 634e7ed26d76  

#鏡像的容器ID,前3位即可,然後在删除鏡像
$sudo docker rm 634      #此時再用鏡像ID來删除進行,成功則會列印出删除各層資訊
$sudo docker rmi -f d131e0fa2585     #鏡像的容器ID,前3位即可,然後在删除鏡像

#導出鏡像
$sudo docker export 092 > czabbix.tar

#導入鏡像
$cat czabbix.tar | docker import - test:latest
sha256:bbb9dbcaa5fff9c5b1b99c978df4dcaeeca3d2200d82fc466f5064931bd3bba2
[[email protected] ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                latest              bbb9dbcaa5ff        14 seconds ago      202MB

           

補充:使用nsenter工具進入Docker容器

#擷取容器的PID
$PID=$(docker inspect --format "{{ .State.Pid}}" <container id>)
#通過得到的這個PID,就可以連接配接到這個容器:
$nsenter --target $PID --mount --uts --ipc --net --pid

#手動擷取docker container 運作的PID
[[email protected] ~]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED
092d1b82c6a0        weiyigeek/czabbix   "/bin/bash"         17 minutes ago      ck
[[email protected] ~]$ docker inspect --format "{{ .State.Pid}}" 092
9030
[[email protected] ~]$ nsenter --target 9030 --mount --uts --ipc --net --pid
[[email protected] /]$ cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)
#成功進入該容器,9030就是容器092d1b82c6a0的程序PID
           

Docker load 與 Docker import 的比較

描述:導入容器和導入鏡像是差不多的但是實際上又是有所差別的

  • load:導入鏡像存儲檔案到本地鏡像庫 而 import:導入一個容器快照到本地鏡像庫
  • 容器快照:檔案将丢失所有的曆史記錄和中繼資料資訊(即保留容器當時的快照狀态),導入的時候還需要重新制定标簽等中繼資料資訊;
  • 鏡像存儲:檔案将儲存完整的記錄,并且體積也要大;

總結:

  • 容器的名稱是唯一性的如果不指定名稱,将會自動生成一個容器名稱;
  • 容器是直接提供應用服務的元件,也是Docker實作快速啟停和高效伺服器性能的基礎
  • 在生産環境中因為容器自身的輕量性,建議在容器前段引入HA(高可靠性)機制,當出現錯誤的時候能快速切換到其他容器之中,還能自動重新開機故障容器;
3.倉庫 [Repository]

描述:Docker 倉庫(Repository)類似于代碼倉庫,是Docker集中存放鏡像檔案的場所;該概念的引入為Docker鏡像檔案的分發和管理提供了便捷的途徑。

倉庫注冊位址:https://hub.docker.com/

安裝幫助文檔:http://www.widuu.com/docker/installation/ubuntu.html

注冊伺服器是存放倉庫的地方,其上往往存放着多個倉庫,每個倉庫集中存放某一類鏡像,往往包括多個鏡像檔案,通過不同的标簽[TAG]來進行區分;

  • 目前最大的公開倉庫是 Docker Hub 存放了數量龐大的鏡像提供使用者下載下傳
  • 國内的公開倉庫包括Docker Pool等等可以提供穩定的國内通路。

例如:對于倉庫位址dl.dockerpool.com/ubuntu來說,dl.dockerpool.com是注冊伺服器,ubuntu是倉庫名;

2.Docker容器學習之新生入門必備基礎知識

Docker 倉庫分類:

  • 公開倉庫(Public)
  • 私有倉庫(Private)

官方與使用者提供的鏡像比較:

  • 官方:centos 由Docker維護的基礎或根鏡像;
  • 個人:user/centos 表示由user使用者維護的centos基礎鏡像;

關鍵點:

docker login   #連接配接并初始化hub倉庫 需要輸入使用者名和密碼認證,然後存放于/root/.docker/config.json 檔案中
docker pull [repository]  #下載下傳指定倉庫到本地
docker push [imges]

#執行個體
$docker pull dl.dockerpool.com:5000/ubuntu:12.04 #連接配接其他的注冊伺服器
$docker images
$docker tag dl.dockerpool.com:5000/ubuntu:12.04 ubuntu:12.04   #更新标簽與官方标簽保持一緻
$docker push dl.dockerpool.com:5000/ubuntu:12.04  #上傳到私有鏡像
           

(1)建立和使用私有倉庫:

最快捷還是搭建本地的倉庫伺服器(注意:配置不當會導緻漏洞)

$ docker run -d -p 5000:5000 registry
#預設情況下倉庫建立在容器的/tmp/register目錄下,-v 通過鏡像檔案存放在主控端本地的指定路徑/opt/data/registry上;
$ docker run -d -p 5000:5000 -v /opt/data/registry:/tmp/registry registry 
# -d:容器啟動後會進入背景,使用者無法看到容器中的資訊.
# -p:指定倉庫鏡像的端口.
# -v:将鏡像的存放位置放在本地指定的路徑上.
           

此時會在本地啟動一個私有倉庫服務,監聽端口為5000; 更新标簽本地倉庫位址并上傳到私有倉庫之中:

$docker tag ubuntu:14.04 10.0.2.2:5000/test  #更改鏡像的标簽
$docker pull 10.0.2.2:5000/test              #下載下傳鏡像

#可以以這個來測試是不是存在docker 5000未授權通路漏洞
$ curl http://10.0.2.2:5000/v1/search  #上傳成功後可以檢視到傳回的json字元串
           

(2)自動建立[Automated Builds]

該功能是對于需要經常更新鏡像内程式來說十分的友善,使用者建立鏡像發生更改的時候進行手動更新鏡像,并能通過自動建立功能跟蹤目标網絡,一旦項目發現新的送出則自動執行建立;配置自動建立步驟如下:

  • 建立登入Docker Hub 綁定Github;
  • 在Docker Hub中配置一個自動建立
  • 選取一個目标網站中的項目(需要Dockerfile和分支)
  • 指定Dockerfile的位置并送出建立,可以在"自動建立頁面"跟蹤每次建立的狀态;

總結:

  • 倉庫管理鏡像的設計理論與Git差不多,工作流程為檔案分發和合作帶來的衆多優勢。

0x03 Docker 資料管理

Data Management,在使用Docker時候必然會在容器内産生資料,或者需要将容器内的資料進行備份,甚至多個容器之間進行資料共享,這時資料管理變得尤為重要;

2.Docker容器學習之新生入門必備基礎知識

容器中管理資料的主要有兩種方式:

  • 資料卷:Data Volumns
  • 資料卷容器:Data Volume Dontainers

資料管理共享的方式:

  • 使用資料卷容器在容器和主機
  • 容器和容器之間共享資料
1.資料卷

描述:是一個可供容器使用的資料目錄,并且讓檔案系統提供很多有用的特性,資料卷的使用類似于Linux對目錄或者檔案進行mount操作;

特性:

  • 資料庫可以在容器之間共享和重用
  • 資料卷修改後會立馬生效
  • 對資料卷的更新不會影響鏡像
  • 卷會一直存在,即使容器被删除

Q:如何在容器内建立一個資料卷?

#### 建立一個web容器并建立一個資料卷挂載到容器的/webapp目錄下(預設将主控端/根映射到容器中webapp目錄中)
$ sudo docker run -d -P 5000 --name web(建立容器) -v /webapp(容器目錄) training/webapp(鏡像) python app.py
# --name 指定容器的名稱
# -v:将鏡像的存放位置放在本地指定的路徑上.
# -P:是允許外部通路容器需要暴露的port
# -d:是容器的背景運作守護

#cp 把容器檔案copy到主控端,或者把主控端的檔案copy到容器
$docker cp 容器id或者name:/home/wwwroot/1.php /home/Lcy/ #把容器的1.php拷貝到主控端家目錄
$docker cp config.php 容器id或者name:/home/wwwroot/    #把主控端的config.php拷貝到容器
           

挂載主機目錄/檔案作為資料卷:

#挂載一個主機目錄作為資料卷 /src/webapp[主機目錄]:/opt/webapp[容器目錄]:rw (權限)
$ sudo docker run -d -P --name web -v  /src/webapp:/opt/webapp:rw training/webapp python app.py
# Docker挂載資料卷的預設權限 rw,ro[隻讀]          //加入ro後資料卷的資料就無法修改了

#挂載一個本地檔案作為資料卷(注意再挂載檔案得時候盡量設定ro自讀,防止inode不一緻報錯)
$ sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash
# --rm :當它退出自動移除容器 即docker ps -aq 不能查詢到
           
2.資料卷容器

描述:IF使用者需要在容器之間共享一些持續的資料,最簡單的方式就是使用資料卷容器(實際上就是一個普通容器);

使用資料卷容器可以讓使用者在容器之間自由地更新和移動資料卷;

首先建立一個資料卷容器dbdata并在其中建立一個資料卷挂載到/dbdata上;

$ sudo docker run -it -v /dbdate --name dbdate ubuntu

#然後在容器中進行使用 建立兩個容器db1 / db2
$ sudo docker run -it --volumes-from dbdate --name db1 ubuntu
$ sudo docker run -it --volumes-from dbdate --name db2 ubuntu
#使用--volumes-from參數所挂載資料卷的容器自身并不需要保持運作狀态


#修改目錄中其中任何一個檔案,其他容器的該目錄都會改變
$ sudo docker run -d --name db2 --volumes-from db1 tarining/postgresql      #可以從已有挂載了容器卷的容器來挂載資料卷
#删除挂載的容器(dbdata 、 db1 、db2)資料卷餅不會被自動的删除,必須在删除最後一個挂載着它容器時顯示使用Docker rm -v 指令來指定同時删除關聯的容器;
           

(1) 資料卷容器遷移資料

可以利用資料卷容器對其中的資料卷進行備份、恢複以實作資料的遷移;

#備份: 建立一個worker容器 ,将本地目前目錄挂載到容器中backup目錄,進行選擇資料目錄備份壓縮
$ sudo docker run --volumes-from dbdata -v $(pwd):/backup --name worker ubuntu tar cvf /backup/backup.tar /dbdate

#恢複: 首先建立一個帶有資料卷的容器dbdata2
$ sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
#解壓備份檔案到挂載的資料卷中
$ sudo docker run --volumes-from dbdata2 $(pwd):/backup busybox tar xvf /backup/backup.tar
           

執行個體示範:

#挂載
$docker run --name web --rm -dit -v /opt:/opt/ centos /bin/bash
5b3d35fe3305fb458e8b33f39d5fedfbd7d9cb1f6742bcf725cfbf2ecd0245fc
#進入容器
$docker start -i 5b3
#建立一個檔案
[[email protected] opt]$ vi containerDokcer.txt
#主控端器目錄檢視
[[email protected] opt]$ cat containerDokcer.txt
#!/bin/bash
docker

#挂載單個檔案
$docker run --rm -it -v ~/.bash_history:/root/.bash_history centos /bin/bash
$docker rm -vf web  #删除容器和資料卷
$docker ps -a  #由于使用--rm參數則會在容器退出時候删除容器
           

補充說明::Z與:z的差別

#配置selinux标簽如果使用selinux,可以添加z或z選項來修改挂載到容器中的主機檔案或目錄的selinux标簽
#:z選項訓示綁定挂載内容在多個容器之間共享。
#:Z選項表示綁定挂載内容是私有和非共享的。
#重要:當使用綁定與服務挂載時,selinux标簽(:z和:Z)以及:ro将被忽略,設定了z選項以指定多個容器可以共享綁定挂載的内容,此時不能使用——mount标記修改selinux标簽
docker run -d --restart=always --name zhcx-v /disk/webapp/war/:/usr/local/tomcat/webapps:z -p 4081:8080 -e JAVA_OPTS=-Dsome.property=value -e Xmx=1536m tomcat-base:6.0.85-jre8
           

總結:

  • 推薦直接挂載檔案目錄到容器中,如果直接挂載一個檔案到容器中在使用文本編輯工具時候可能會報錯;
  • 可以多次使用–volumes-from參數從來多個容器挂載多個資料卷;鎖挂載的容器自身并不需要保持在運作狀态
  • 推薦使用資料卷和資料容器之外的實體備份存儲系統,如RAID或者分布式系統如Ceph,GPFS,HDFS等

0x04 Docker 網絡管理

大量網際網路服務包括多個服務元件往往需要多個容器之間進行網絡通信互相配合,Docker目前提供了映射容器端口與宿主主機和容器互聯機制來為容器提網絡服務;并且采用Linux系統知道的網絡系統來實作對網絡服務的支援使之能提供穩定支援以及快速的高性能轉發;

當在一台未經過特殊網絡配置的centos 或 ubuntu機器上安裝完docker之後,在主控端上通過ifconfig指令可以看到多了一塊名為docker0的網卡;不難想到docker0就不隻是一個簡單的網卡裝置了而是一個網橋。

$ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255
$route -n
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0

#下圖即為Docker預設網絡模式(bridge模式)下的網絡環境拓撲圖,建立了docker0網橋,并以eth pair連接配接各容器的網絡,容器中的資料通過docker0網橋轉發到eth0網卡上。
#網橋(等同于交換機)

#在Linux中,可以使用brctl指令檢視和管理網橋(需要安裝bridge-utils軟體包),比如檢視本機上的Linux網橋以及其上的端口:
$yum install bridge-utils
$brctl show
bridge name     bridge id               STP enabled     interfaces
br-63791a62ad5a   8000.024258a66d6e       no        veth4ce6e0e
                                                    vethe5abf0f
br-6cde78afe495   8000.02420a2496c6       no      veth93e8dc0
                                                  vethfda7b14
docker0   8000.024216e63d3c       no

#docker0網橋是在Docker daemon啟動時自動建立的,其IP預設為172.18.0.1/16,之後建立的Docker容器都會在docker0子網的範圍内選取一個未占用的IP使用,并連接配接到docker0網橋上。

#除了使用docker0網橋外,還可以使用自己建立的網橋,比如建立一個名為br0的網橋,配置IP:
brctl  addbr br0
ifconfig  br0 18.18.0.1

#在Docker容器和外界通信的過程中,還涉及了資料包在多個網卡間的轉發(如從docker0網卡轉發到主控端ens160網卡)
#需要核心将ip-forward功能打開即将ip_forward系統參數設1
echo 1 > /proc/sys/net/ipv4/ip_forward
           
2.Docker容器學習之新生入門必備基礎知識

在Docker在1.9版本中network子指令和跨主機網絡支援,為了标準化網絡的驅動開發步驟和支援多種網絡驅動,Docker公司在libnetwork中使用了CNM(Container Network Model)定義了建構容器虛拟化網絡的模型。

libnetwork和Docker daemon及各個網絡驅動的關系圖:

Docker daemon通過調用libnetwork對外提供的API完成網絡的建立和管理等功能,libnetwrok中則使用了CNM來完成網絡功能的提供;

2.Docker容器學習之新生入門必備基礎知識

CNM中主要有沙盒(sandbox)、端點(endpoint)、網絡(network)3種元件:

  • (1)Sandbox:包含了一個容器網絡棧的資訊,實作對容器的接口、路由和DNS設定等進行管理;
  • (2)Endpoint:它可以加入一個沙盒和一個網絡,且一個端點隻可以屬于一個網絡并且隻屬于一個沙盒;
  • (3)Network:可以直接互相聯通的端點(包含多個端點),網絡的實作可以是Linux bridge、VLAN等

libnetwork共有5種内置驅動:bridge驅動、host驅動、overlay驅動、remote驅動、null驅動。

  • (1)bridge驅動: Docker預設設定驅動,它可以将建立出來的Docker容器連接配接到Docker網橋正常方法能滿足容器基礎需求,然後在複雜場景下使用又諸多限制(使用NAT轉發)
  • (2)host驅動:它将不為Docker容器建立網絡協定棧(不會建立獨立的network namespace),即容器于主控端共用一個network namespace并使用主控端的網卡/IP端口等等資訊,該驅動适用于對于容器叢集規模不大的場景;
  • (3)overlay驅動: 采用IETE标準的VXLAN方式,并且是VXLAN中被普遍認為最适合大規模的雲計算虛拟化環境的SDN controller模式,使用時候需要額外的配置存儲服務(例如Consul、etcd和zookeeper)
  • (4)remote驅動: 該驅動并未做真正的網絡服務實作而是調用了使用者自行實作的網絡驅動插件,使libnetwork實作了驅動的可插件化,更好地滿足了使用者的多種需求
  • (5)null驅動: 容器擁有自己的網絡命名空間,但并不為Docker容器進行任何網絡配置;容器除了network namespace自帶的loopback網卡名,沒有其他任何網卡、IP、路由等資訊(需要使用者對齊配置)

libnetwork官方示例:

2.Docker容器學習之新生入門必備基礎知識

(1)端口映射實作通路容器

通過-P或者-p來指定端口,

  • 使用-P時候:會進行選擇 49000 ~ 49900 端口随機配置設定映射;
  • 使用-p時候:會讓你您設定固定與容器映射的端口;

支援的格式:

  • hostPort:containerPort < 映射到本地指定端口以及容器端口
  • ip:hostPort:containerPort < 映射到本地指定位址以及本地指定端口和容器端口
  • ip::containerPort < 映射本地指定IP的任意端口和容器端口 (注意此處是:😃
#随機開啟端口
$sudo docker run -d -P centos python app.py 

#檢視轉發的端口
$docker ps -l   

#檢視詳細的日志資訊
$sudo docker logs -f [NAMES] 

#1.映射所有接口位址 [将本地的5000端口映射到容器的5000端口]
$sudo docker run -d -p 5000:5000 centos python app.py 
#2.映射指定位址指定端口
$sudo docker run -d -p 127.0.0.1:5000:5000 centos python app.py 
#3.映射指定位址到的任意端口 還能使用tcp标記來指定udp端口
$sudo docker run -d -p 127.0.0.1::5000/tcp centos python app.py 

#檢視端口映射配置
$sudo docker port [NAMES] 5000 #容器Port
           

(2)實作容器間通信

容器的連結(Linking)系統是除了端口映射外的另一種可以與容器中應用進行交換的方式;它會在源和接收容器之間建立一個隧道,接收容器可以看到源容器指定的資訊;

Docker兩種方式為容器公開連接配接資訊:

  • 1.環境變量
  • 2.更新/etc/hosts
#首先建立一個新的資料庫容器,啟動db容器的時候并沒有使用-p與-P标記,避免了暴露資料庫端口到外部網絡上
$sudo docker run -d --name db tranining/postgres

#使db容器與web容器建立互聯關系;
#--link name:alias  其中namd是連結的容器的名稱,alias是這個連結的别名.
$ sudo docker run -d -P --name web --link db:db training/webapp python app.py

#使用 docker ps 來檢視容器的連接配接
$ docker ps 
CONTAINER ID IMAGE COMMAND CREATED STAT
US PORTS NAMES
349169744e49 training/postgres:latest su postgres -c '/usr About a minute ago Up About a minute 5432/tcp db, web/db'
#web/db這表示web 容器連結到 db 容器,web 容器将被允許通路 db 容器的資訊。


#使用env指令來檢視web容器的環境變量
$sudo docker run --rm --name web1 --link db:db training/webapp env
#起點彙總DB_開頭的環境變量是提供web容器連接配接到db使用,字首采用大寫的連結别名
DB_NAME=/web2/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5000_TCP=tcp://172.17.0.5:5432
DB_PORT_5000_TCP_PROTO=tcp
DB_PORT_5000_TCP_PORT=5432
DB_PORT_5000_TCP_ADDR=172.17.0.5


#同時Docker還添加host資訊到父容器的/etc/hosts檔案
$sudo docker run -it --rm --link db:db training/webapp /bin/bash
cat /etc/hosts
           

執行個體:

$docker pull nginx
$docker run -d -p 80:80 --name web nginx
$docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
16207d8f2291        nginx               "nginx -g 'daemon of…"   19 seconds ago      Up 18 seconds       0.0.0.0:80->80/tcp   web
#容器有自己的内部網絡和IP位址,使用docker inspect + 容器ID 可以擷取所有的變量值;
$docker inspect web
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.2",
"MacAddress": "02:42:ac:12:00:02",

#然後打開80端口進行通路采用logs列印通路
$docker logs -f web
218.x.x.xx - - [08/May/2019:15:00:11 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0" "-"

#進行link關聯容器使之能進行正常通信
[[email protected] ~]$docker run -d --name web1 --link web:nginx_web alpine cat /etc/hosts
ebe1df8c1fb00462b127d36201d558a9f62507c81faea1ce6c4bf4b5ea6075e3

[[email protected] ~]$docker run -d --name web2 --link web:nginx_web alpine env
baa9dfe5f64519eb5ccbd122fc191e0f40118a4ee28385a818f7ffe6e2e03639

[[email protected] ~]$docker start -i web1
172.18.0.2      nginx_web 16207d8f2291 web  #成功添加web
172.18.0.3      ebe1df8c1fb0

[[email protected] ~]$docker start -i web2
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=baa9dfe5f645
NGINX_WEB_PORT=tcp://172.18.0.2:80  #web2也成功添加web
NGINX_WEB_PORT_80_TCP=tcp://172.18.0.2:80
NGINX_WEB_PORT_80_TCP_ADDR=172.18.0.2
NGINX_WEB_PORT_80_TCP_PORT=80
NGINX_WEB_PORT_80_TCP_PROTO=tcp
NGINX_WEB_NAME=/web2/nginx_web
NGINX_WEB_ENV_NGINX_VERSION=1.15.12-1~stretch
NGINX_WEB_ENV_NJS_VERSION=1.15.12.0.3.1-1~stretch
           
2.Docker容器學習之新生入門必備基礎知識

(3)libnetwork庫官方示例

執行流程:

#docker内置的預設預設網卡是是無法使用docker network rm進行删除;
$docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f26c3ed5f7b0        bridge              bridge              local
fd3572aceb38        host                host                local
01da6464c812        none                null                local

#Step 1.建立名為backend、frontend兩個網絡
$docker network create backend
6cde78afe495a310bb27c5e1a50074b20e204bfa72e71bcaf6a4c37feb300b93
$docker network create frontend
63791a62ad5a5fe4aeb5926616b2ea1d65b490bb9fb718824b7cb1c408ae50c1
$docker network create -d bridge test-net
#-d:參數指定 Docker 網絡類型,有 bridge、overlay/none。

#Step 2. 将c1與c2的容器加入到backend網絡中,将c3容器加入到frontend網絡中
$docker run -itd --name c1 --net backend alpine
729f2abef71ceaf831999d66264d05f78674d9cd2c235f84481a14b366698adb
$docker run -itd --name c2 --net backend alpine
26d47af2d39a1b00f767c60a68cd5f61f1cf5f48652cdcbcb0216968a3185f5e
$docker run -itd --name c3 --net frontend alpine
9cb94f7c66955ba5a95c90d08ce314da0e477f6eddbcea0329309ec36ca5a711


#Step 3. 分别進入c1和c3容器使用ping指令測試其與c2的連通性,因為c1和c2都在backend網絡中,是以兩者可以連通。但是因為c3和c2不在一個網絡中,是以兩個容器之間不能連通:
# 使用docker inspect c3 檢視IP資訊:
C1: 172.19.0.2
C2: 172.19.0.3
C3: "IPAddress": "172.20.0.2",

# 進入c1容器ping c2通、ping c3不通。其它兩個容器就不進入示範了,大家自己可以試一下:
# docker exec -it c1 sh
# ip addr
18: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:13:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.2/16 brd 172.19.255.255 scope global eth0
# ping c2
PING c2 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.065 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.050 ms
/ # ping 172.20.0.2
PING 172.20.0.2 (172.20.0.2): 56 data bytes


# Step 4. 将c2連接配接加入到front網絡中,使用exec進入c2中檢視網卡資訊,測試c2與c3的連通性後,可以發現兩者已經連通
$docker network connect frontend c2
$docker exec -it c2 sh
/ $ ip addr
20: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:13:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.3/16 brd 172.19.255.255 scope global eth0
24: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:14:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.3/16 brd 172.20.255.255 scope global eth1

/ $ ping c3
PING c3 (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.100 ms
           

(4) 跨主機實作互通

通過添加路由路由的方式route

比如:

Docker1: 172.18.0.1/24 --Gateways-- 192.168.1.99
           

總結:

  • 使用者可以連結多個子容器到父容器中比如連接配接多個web到db容器上;
  • 學習額外的機制比如SDN(軟體定義網絡)或者NFV(網絡功能虛拟化)的相關技術
WeiyiGeek Blog - 為了能到遠方,腳下的每一步都不能少。

部落客 Blog 鏡像站點(

友鍊交換請郵我喲

):

  • https://weiyigeek.top # 國内通路較慢
  • https://blog.weiyigeek.top # 更新頻繁
  • https://weiyigeek.gitee.io # 國内通路快可能會有更新不及時得情況

更多原創學習筆記文章請關注 WeiyiGeek 公衆賬号

【點選我關注】

2.Docker容器學習之新生入門必備基礎知識