講到Docker不得不說下虛擬化
在計算機術語中虛擬化技術或虛擬技術(Virtualization)是一種資源管理技術,它虛擬的是整個PC硬件。也就是將計算機的各種實體資源(CPU、內存、磁盤空間、網絡適配器等),予以抽象、轉換後呈現出來並可供分割、組合爲一個或多個計算機配置環境。來由此打破實體結構間的不可切割的障礙,使用戶可以比原本的配置更好的方式來應用這些計算機硬件資源。這些資源的新虛擬部分是不受現有資源的架設方式,地域或物理配置所限制(摘自 wikipedia)
容器與虛擬化
- 虛擬化:
虛擬化技術有多種比如CPU、網絡、主機、存儲、服務器、應用虛擬化等,而常見的虛擬化技術即通過Hypervisor將OS運行在物理設備或是宿主OS上。Hypervisor 是一種運行在物理服務器和操作系統之間的中間軟件層,可允許多個操作系統和應用共享一套基礎物理硬件,因此也可以看作是虛擬環境中的“元”操作系統,它可以協調訪問服務器上的所有物理設備和虛擬機,也叫虛擬機監視器。 - 常見的 Hypervisor 分兩類:裸機型與宿主型
- 裸機型:裸機型虛擬機是直接運行在系統硬件上,創建硬件全仿真實例,被稱爲“裸機”型。裸機型在虛擬化中Hypervisor直接管理調用硬件資源,不需要底層操作系統,也可以將Hypervisor看作一個很薄的操作系統。這種方案的性能處於主機虛擬化與操作系統虛擬化之間。
- 宿主型:宿主型虛擬機運行在傳統操作系統上,同樣創建的是硬件全仿真實例,被稱爲“託管(宿主)”型。託管型/主機型Hypervisor運行在基礎操作系統上,構建出一整套虛擬硬件平臺(CPU/Memory/Storage/Adapter),使用者根據需要安裝新的操作系統和應用軟件,底層和上層的操作系統可以完全無關化,如Windows運行Linux操作系統。
- 容器化:
容器化技術即用戶空間虛擬化技術,也就是將用戶空間分割多個,多個用戶空間都將在一個內核中運行。容器虛擬化技術依賴Linux技術的名稱空間服務即(NameSpace)。常見的技術有lxc(Linux Container)、OpenVZ等。
而Docker就屬於軟件虛擬化技術中的操作系統層虛擬化技術,它是基於LXC實現的一個應用容器引擎。Docker的出現可以讓開發者打包他們的應用及依賴環境到一個可移植的容器中,然後可以將這個容器快速應用部署開發測試生產等。
容器虛擬化之 Docker
Docker的初始版本是在2013年開發出來的,使用的是Go語言開發並且遵循Apache2.0協議,是一個開放源代碼軟件項目。讓應用程序部署在容器化下的工作可以自動化進行,藉此在Linux操作系統上提供一個額外的軟件抽象層,以及操作系統層虛擬化的自動管理機制。更多的Docker周邊請瀏覽 Docker官網 ,Docker Hub
Docker利用Linux核心中的資源分離機制,CGroup及Linux核心名稱空間(NameSpace),來創建獨立的容器(containers)。這可以在單一Linux實體下運作,避免啓動一個虛擬機造成的額外負擔。Linux核心對名稱空間的支持完全隔離了工作環境中應用程序的視野,包括進程樹、網絡、用戶ID與掛載文件系統。而核心的cgroup提供資源隔離,包括CPU、存儲器、block I/O與網絡。從0.9版本起Dockers在使用抽象虛擬是經由libvirt的LXC與systemd - nspawn提供界面的基礎上,開始包括libcontainer庫做爲以自己的方式開始直接使用由Linux核心提供的虛擬化的設施(摘自 wikipedia)。
容器的PID NameSpace(名空間)
在Docker中進程管理的基礎就是Linux內核中的PID名空間技術,在不同PID名空間中進程ID是獨立的,即在兩個不同名空間下的進程可以有相同的PID。
Linux內核爲所有的PID名空間維護了一個樹狀結構。最頂層的是系統初始化時創建的root namespace(根名空間),再創建的新PID namespace就稱之爲child namespace(子名空間),而原先的PID名空間就是新創建的PID名空間的parent namespace(父名空間)。通過這種方式,系統中的PID名空間會形成一個層級體系。父節點可以看到子節點中的進程,並可以通過信號等方式對子節點中的進程產生影響。反過來,子節點不能看到父節點名空間中的任何內容,也不可能通過kill或ptrace影響父節點或其他名空間中的進程。
在Docker中,每個Container都是Docker Daemon的子進程,每個Container進程缺省都具有不同的PID名空間。通過名空間技術,Docker實現容器間的進程隔離。另外Docker Daemon也會利用PID名空間的樹狀結構,實現了對容器中的進程交互、監控和回收。下面是Docker利用名空間技術所使用到的各種資源隔離方法,關於它是做什麼的可自行Google這裏不在闡述,只講它的功能;
Docker容器級技術依賴於 NameSpace,CGroup,AUFS,Device Mapper
- NameSpace:即在內核級完成環境隔離的技術方法
- NameSpace:進程編號(PID)隔離,使每個用戶空間所看到進程數都是獨立且彼此互不干擾;
- Network NameSpace:實現網絡運行用戶環境隔離,網絡設備,網絡棧,端口等網絡資源隔離;
- User NameSpace:用來完成用戶隔離(用戶和用戶組隔離),Linux 3.8成熟起來;
- IPC NameSpace:進程間通信技術也需要隔離,信號量、消息隊列、共享內存的隔離,2.6.19引入;
- UTS NameSpace:主機名和域名的隔離,Linux 2.6.19開始引入;
- Mount NameSpace:實現已掛載文件系統隔離,Linux 2.4.19開始引入;
注意:爲了能夠向NameSpace發起調用,讓NameSpace完成某些操作,其API有 clone(),setns(),unshare()
- CGroup:Linux Control Group,控制組內核級功能,收入於Linux 2.6.24
- 實踐中CGroup主要作用:隔離一個進程集合,爲進程分配足夠內存、帶寬而後限制其訪問有哪些設備,並恢復完成資源限制機制;
- CGroup基礎作用:來限制、控制與分離一個進程組羣的資源,CPU、內存、IO;
所實現的功能:
Resource limitation:資源限制
Prioritization:優先級控制
Accounting:審計和統計,主要是計費
Control:掛起進程,恢復進程
- CGroup子系統:
- blkio:實現限制跨設備IO能力而設定的一個子系統;
- cpu:使用調度程序對CPU的任務訪問;
- cpuaccount:主要實現cpu使用時長統計;
- cpuset:cpu集合,爲CGroup任務進程分配獨立的cpu核心和內存節點,真正實現資源指派;
- memory:在cgroup當中設定內存的使用限制,按段分配;
- devices:主要用來控制cgroup中的任務對設備的訪問能力;
- freezer:主要用來實現掛起進程或恢復某個指定的cgroup中的進程任務;
- net_cls:(classid)主要使用等級級別標識符來標記網絡數據包,限制數率來實現流量控制(基於tc完成對不同的cgroup中產生的流量控制 tc命令)
- perf_event:實現對每個用戶空間當中的任務所運行時的性能本身分別所產生的事件進行歸類統計;
- hugetlb:轉換後援緩衝器,主要對HugeTLB系統進行限制;
- CGroup術語:
- task(任務):進程或線程;
- cgroup:每一個cgroup就是一個獨立的資源分配控制單位,可包含一個多個子系統;
- subsystem:子系統,需要關聯到cgroup中來完成指派;
- hierarchy:資源層級結構;
------ 多個子系統參考路徑 ls /sys/fs/cgroup ------
- AUFS:如您使用的是紅帽系列發行版系統,建議使用Overlay
- UnionFS:把不同的物理位置的目錄合併(掛載)到同一個目錄中,最上層可寫,下層只讀;
- UnionFS是內核原生技術,Docker強依賴AUFS,但Linux內核不支持AUFS,替代品Device mapper;
- 多數Linux發行版都對AUFS提供了支持,但Linux內核和紅帽就牛逼,咋說都不用;
- Overlay與AUFS的對比 Overlay與AUFS對比,AUFS簡單參考
- Device Mapper:
- Linux 2.6內核引入,爲底層跨設備提供抽象設備,用於在內核中支持邏輯卷管理的通用設備映射機制;
- Device mapper 在內核中作爲一個塊設備驅動被註冊,它包含三個重要的對象概念;
mapped device:被映射的設備
mapping table:被映射的表
target device:源設備 - 詳細的Device Mapper介紹可參考IBM開發者論壇 Device Mapper介紹
Docker的核心組件
- docker client:是用戶使用docker主要接口,docker client與docker daemon通信並將結果返回給客戶;
- docker daemon:運行於宿主機上,是docker的守護進程,用戶可通過docker client與其交互;
- docker image:鏡像文件且只讀,是用來創建container,一個鏡像可運行多個container。鏡像文件可通過Dockerfile文件創建也可從docker倉庫下載;
- docker repository
- 公共倉庫:docker hub or docker registry
- 私有倉庫:docker registry
- docker link:網絡組件
- docker volume:持久化數據存儲組件
- dockerfile:用於docker鏡像構建
Docker的用途
- 簡單將就是提供 隔離應用、維護鏡像、創建易於分發的應用及快速擴展等功能;
- 提供一次性的環境。比如,本地測試他人的軟件、持續集成的時候提供單元測試和構建的環境;
- 提供彈性的雲服務。因爲 Docker 容器可以隨開隨關,很適合動態擴容和縮容;
- 組建微服務架構。通過多個容器,一臺機器可以跑多個服務,因此在本機就可以模擬出微服務架構;
Docker的基礎使用
- 怎麼安裝
- 環境是CentOS 7.4
[root@192_168 ~]# yum install -y docker [root@192_168 ~]# systemctl enable docker [root@192_168 ~]# systemctl start docker [root@192_168 ~]# systemctl status docker
- 環境是CentOS 7.4
- 簡單使用
- docker -h //docker 幫助
- docker help daemon //docker 的子命令幫助
- docker search centos //從互聯網搜索相關服務鏡像
- docker pull centos //從互聯網pull鏡像到本地
- 相關子命令
- 跟環境信息相關子命令:
[root@192_168 ~]# docker info [root@192_168 ~]# docker version
- 跟系統維護相關子命令:
[root@192_168 ~]# docker images/inspect [root@192_168 ~]# docker build/commit [root@192_168 ~]# docker pause/unpause [root@192_168 ~]# docker rm/rmi [root@192_168 ~]# docker top/kill [root@192_168 ~]# docker run/start [root@192_168 ~]# docker stop/restart [root@192_168 ~]# docker ps/ps -a [root@192_168 ~]# docker rm
- 跟日誌相關子命令:
[root@192_168 ~]# docker events [root@192_168 ~]# docker history [root@192_168 ~]# docker logs
- docker hub服務相關子命令:
[root@192_168 ~]# docker login/logout [root@192_168 ~]# docker pull/search
- 跟環境信息相關子命令:
- docker鏡像的啓停
- 通過鏡像啓動一個容器 docker run
- 啓動一個已停止的容器 docker start
[root@192_168 ~]# docker run -it --rm busybox:latest /bin/sh
- 容器運行中創建自有container
[root@192_168 ~]# docker commit bb1954ab1978 centos:base-tools
- docker簡單架構
- Docker 使用客戶端-服務器 (C/S) 架構模式,使用遠程API來管理和創建Docker容器;
- Docker 容器通過 Docker 鏡像來創建;
- 容器與鏡像的關係類似於面向對象編程中的對象與類;
Docker的相關組件
- docker鏡像與docker存儲位置關係:
容器鏡像:即包含了啓動docker容器所需的文件系統層級及其內容,基於UnionFS採用分層結構實現;
存儲倉庫:registry:保存docker鏡像及鏡像層次結構和元數據,一個registry包含多個repository一個repository內包含多個鏡像;
repository:由具有某個功能的鏡像的所有相關版本構成的集合;
index:管理用戶的賬號、權限、鏡像及鏡像標籤等等相關信息的檢索庫 docker search;
graph:從registry中下載的docker鏡像需要保存在本地,此功能既由graph來完成/var/lib/docker/graph;
鏡像相關命令:docker images/search/pull/push/login/logout/docker rmi及docker commit/build 等;
- 容器:即獨立運行的一個或一組應用,以及它們運行時所需要的環境
相關命令:run、kill、stop、start、restart、logs、attach、import、export
啓動容器:通過鏡像創建一個新的容器 run
啓動一個處於停止狀態的容器 start
run 命令:--name 給容器起一個名字,在後續的命令執行中可直接調用;
-i 保持一個打開的STDIN狀態,通常與-t結合使用;
-t 關聯一個終端;
--net=default 啓動一個容器關聯到哪個橋上去,默認啓動在docker0橋上;
-d --detach=false 在後臺(守護進程)方式運行docker;
注意:在交互式模式下啓動的容器,關閉時可使用exit命令或Ctrl+d鍵;
~]# docker run -it --name busybox --net=default -d busybox:latest
Docker私有倉庫構建(Docker Registry)
安裝:環境是CentOS 7.4
[root@192_168 ~]# yum install -y docker docker-distribution
啓動:[root@192_168 ~]# systemctl start docker
[root@192_168 ~]# systemctl start docker-distribution
[root@192_168 ~]# systemctl status docker docker-distribution
如果需要監聽在80端口,可以用iptables轉發實現[root@192_168 ~]# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 5000
構建本地鏡像[root@192_168 ~]# docker images
[root@192_168 ~]# docker tag 1e1148e4cc2c localhost:5000/centos:1.0.1
[root@192_168 ~]# docker push localhost:5000/centos:1.0.1
[root@192_168 ~]# docker images
[root@192_168 ~]# docker rmi localhost:5000/centos:1.0.1
[root@192_168 ~]# docker pull localhost:5000/centos:1.0.1
修改docker配置文件,默認使用內網倉庫
修改文件/etc/sysconfig/docker
#添加內網倉庫ADD_REGISTRY='--add-registry localhost:5000'
#禁用官方倉庫docker.io(可選)BLOCK_REGISTRY='--block-registry docker.io'
配置文件:#INSECURE_REGISTRY='--insecure-registry localhost:5000'
#ADD_REGISTRY='--add-registry localhost:5000'
#BLOCK_REGISTRY='--block-registry docker.io'
Docker 數據卷
- 數據卷的特性:
(1) 數據卷是提供一個或多個容器使用的文件或目錄,有多種特性
(2) 可共享於多個容器之間
(3) 對數據卷的修改會立即生效
(4) 對數據卷的更新與鏡像無關
(5) 數據卷會一直存在
- 容器使用數據卷的方式:
-v --volume=[ ] 綁定掛載一個數據卷,默認存儲路徑:/var/lib/docker/volumes/
- 容器運行中掛載示例:
~]# docker run -it --name busybox --rm -v /data busybox:latest
- 容器退出重掛使用原存儲卷示例:
~]# docker run -it --name busybox -v /var/lib/docker/volumes/a8c7da4dcc16e757303b6358e3d4dc50cb1adfa38118216cb5f9a55331b2107d/_data/:/data busybox:latest
- 提示:冒號前是宿主機路徑,冒號後容器主機路徑
Dockerfile 構建
- dockerfile是由一系列用於根據基礎鏡像構建新的鏡像文件的專用指令序列組成;
- 指令有:選定基礎鏡像、安裝必要程序、複製配置文件和數據文件自動運行的服務及要暴露的端口等
- 命令是:docker build
- docker build語法
- 指令行:由指令及指令參數構成,字符不區分大小寫
- 註釋行:#開頭的行,必須單獨位於一行當中
- 空白行:會被忽略
- 相關指令:
- FROM指令:必須是第一非註釋行,用於指定所用到的基礎鏡像
語法格式:FROM <image>[:<tag>] 或 FROM <image>@<digest>
簡單示例:FROM busybox:latest or FROM centos:1.0
注意事項:一個file文件可多個from指令,但儘量不在一個dockerfile文件中使用多個from指令
- MAINTAINER指令:提供信息讓著作者提供本人信息,不限制出現位置,建議在FROM指令後
語法格式:MAINTAINER <author's detail>
簡單示例:MAINTANIER Aliyun.com <[email protected]>
- ONBUILD指令:定義觸發器。用於在當前dockerfile構建出的鏡像被用作基礎鏡像去構建其它鏡像時,ONBUILD指令指定的操作纔會被執行
語法格式:ONBUILD <INSTRUCTION> ONBUILD 後面跟的是dockerfile的指令
簡單示例:ONBUILD ADD my.cnf /etc/mysql/my.cnf
注意事項:ONBUILD不能自我嵌套,且不會觸發FROM和MAINTANIER等指令
- EXPOSE指令:用於爲容器指定要暴露的端口
語法格式:EXPOSE <Port>[/<protocol>] <Port>[/<protocol>] ...
簡單示例:EXPOSE 11211/tcp 11211/udp
- CMD指令:類似於RUN指令用於運行程序,但二者的運行的時間點不同。不是在docker build 是在docker run中運行。Docker Run 的CMD指令優於dockerfile中已定義的指令,會覆蓋dockerfile中指令,如不想覆蓋就使用ENTRYPOINT指令
語法格式: CMD <command> CMD ["<executeable>","<param1>","<param2>",...] CMD RUN ["<param1>","<param2>",...] 此指令爲ENTRYPOINT指令指定的程序提供默認參數
簡單示例:CMD ["/usr/sbin/httpd","-c","/etc/httpd/conf/httpd.conf"]
注意事項:如果dockerfile中存在多個CMD指令,僅最後一個生效
- RUN指令:用於指定docker build過程中要運行的命令,而不是docker run
語法格式: RUN <COMMAND> 即shell命令會啓動shell進程運行它,此進程UID不爲1 RUN ["<executeable>","<param1>","<param2>",...] executeable運行的命令向命令傳參param1,不啓動shell進程不支持通配
簡單示例: run yum install -y net-tools run ["/bin/bash","-c","<executeable>","<param1>","<param2>",...]
注意事項:每個RUN都會啓動一個新層
- 其它更多相關指令請參考官網 dockerfile 指令
- FROM指令:必須是第一非註釋行,用於指定所用到的基礎鏡像
- dockerfile 示例
[root@192_168 ~]# mkdir httpd-dockerfile && cd httpd-dockerfile
[root@192_168 httpd-dockerfile]# vim httpd.df
[root@192_168 httpd-dockerfile]# cat docker-httpd.df
FROM centos:latest
MAINTAINER Hehehuyu '<[email protected]>'
RUN yum install -y httpd php php-mysql php-mbstring
RUN echo -e '<?php\n\tphpinfo();\n?>' > /var/www/html/info.php
EXPOSE 80/tcp
CMD ["/usr/sbin/httpd","-f","/etc/httpd/conf/httpd.conf","-DFOREGROUND"]
[root@192_168 httpd-dockerfile]# docker build -f docker-httpd.df -t httpd:2.4 ./
[root@192_168 httpd-dockerfile]# docker images
[root@192_168 httpd-dockerfile]# docker run --rm --name httpd -P httpd:2.4
[root@192_168 httpd-dockerfile]# docker port httpd (http://172.10.10.101:32768/info.php)
[root@192_168 httpd-dockerfile]# docker kill httpd
[root@192_168 httpd-dockerfile]# docker run -d --name httpd -p 80:80 httpd:2.4
更多的關於docker的周邊
- 更多Docker的容器互聯,網絡模型,容器間依賴等實現方法請參考官方幫助文檔 docs