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": ["https://registry.docker-cn.com","http://hub-mirror.c.163.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 <hgzerowzh@qq.com>" -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完成以上網絡配置的過程大致是這樣:
- 在主機上創建一堆虛擬網卡veth pair設備。veth設備總是成對出現,它們組成了一個數據的通道,數據從一個設備進入,就會從另一個設備出來。因此,veth設備常用來連接兩個網絡設備。
- Docker將veth pair設備的一端放在新創建的容器中,並命名為eth0。另一端放在主機中,以eth65f9這樣類似的名字命名,並將這個網絡設備加入到docker0網橋中,可以通過brctl show命令來查看
$ brctl show bridge name bridge id STP enabled interfaces docker0 8000.02425f21c208 no
- 從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
4)docker配置允許從外部tcp連接時報錯
- 報錯信息:
dockerd[2144]: unable to configure the Docker daemon with file /etc/docker/daemon.json: the following directives are specified both as a flag and in the configuratio n file: hosts: (from flag: [fd://], from file: [unix:///var/run/docker.sock])
- 解決:
在/usr/lib/systemd/system/docker.service中將ExecStart項中docker啟動的 -H fd:// 刪掉即可
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 <hgzerowzh@qq.com>" LABEL maintainer="hgzerowzh <hgzerowzh@qq.com>"
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 <hgzerowzh@qq.com>" LABEL maintainer="hgzerowzh <hgzerowzh@qq.com>" 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 <hgzerowzh@qq.com>" 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 <hgzerowzh@qq.com>" 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 <hgzerowzh@qq.com>" 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 http://localhost/ || exit 1
- 實際案例:
FROM nginx:1.14-alpine LABEL maintainer="hgzerowzh <hgzerowzh@qq.com>" 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 http://${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 ./
- 先在dockerfile文件中定義ARG
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的方式
- 利用官方提供的工具docker-registry來配置私庫
- 這個工具是一個鏡像,直接下載並使用registry鏡像啟動docker實例就可以了
- 利用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": ["https://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資源限制
參考:
- https://www.cnblogs.com/xiaoshancun/p/12352981.html
- https://www.cnblogs.com/zuxing/articles/8780661.html
- https://www.cnblogs.com/zhangxingeng/p/11236968.html
- https://www.cnblogs.com/zhangxingeng/p/11558782.html
- https://www.cnblogs.com/zhangxingeng/p/11598708.html
"http://hub-mirror.c.163.com",