什麼是 Docker
Docker是一個使用 Go 語言開發的,並且開源的應用容器引擎,基於LXC(Linux Container)內核虛擬化技術實現,提供一系列更強的功能,比如鏡像、Dockerfile等;
Docker理念是將應用及依賴包打包到一個可移植的容器中,可發佈到任意Linux發行版的Docker引擎上,使用沙箱機制運行程序,程序之間相互隔離;
Docker採用C/S架構,Dcoker daemon作爲服務端接受來自客戶端請求,並處理這些請求,比如創建、運行容器等;客戶端爲用戶提供一系列指令與Docker Daemon交互;
LXC:Linux容器技術,共享內核,宿主機資源,使用NameSpace和Cgroups對資源限制與隔離;
Cgroups(control groups):Linux內核提供的一種限制單進程或者多進程資源的機制;比如CPU、內存等資源的使用限制;
NameSpace:命名空間,也稱名字空間,Linux內核提供的一種限制單進程或者多進程資源隔離機制;一個進程可以屬於多個命名空間;Linux內核提供了六種NameSpace:UTS、IPC、PID、Network、Mount和User。
AUFS(advanced multi layered unification filesystem):高級多層統一文件系統,是UFS的一種,每個branch可以指定readonly(ro只讀)、readwrite(讀寫)和whiteout-able(wo隱藏)權限;一般情況下,aufs只有最上層的branch纔有讀寫權限,其他branch均爲只讀權限。
UFS(UnionFS):聯合文件系統,支持將不同位置的目錄掛載到同一虛擬文件系統,形成一種分層的模型;成員目錄稱爲虛擬文件系統的一個分支(branch);
Doker 優點與虛擬機的區別
持續集成
在項目快速迭代情況下,輕量級容器對項目快速構建、環境打包、發佈等流程就能提高工作效率;版本控制
每個鏡像就是一個版本,在一個項目多個版本時可以很方便管理;可移植性
容器可以移動到任意一臺Linux的Docker引擎上,而不需要過多關注底層系統;標準化
應用程序環境及依賴、操作系統等問題,增加了生產環境故障率,容器保證了所有配置、依賴始終不變;隔離性與安全
容器之間的進程是相互隔離的,一個容器出現問題不會影響其他容器;
以KVM舉例,與Docker對比
Ø 啓動時間
Docker是秒級啓動,而KVM是分鐘級;
Ø 輕量級
容器鏡像大小通常以M爲單位,而虛擬機以G爲單位;容器資源佔用小,要比虛擬機部署更快速;
Ø 性能
容器共享宿主機內核,系統級虛擬化,佔用資源少,沒有Hypervisor層開銷,容器性能基本接近物理機;而虛擬機需要Hypervisor層支持,虛擬化一些設備,具有完整的GuestOS,虛擬化開銷大,因而降低性能,沒有容器性能好;
Ø 安全性
由於共享宿主機內核,只是進程級隔離,因此隔離性和穩定性不如虛擬機,容器具有一定權限訪問宿主機內核,存在一定安全隱患,在這一點上可能就是Doker唯一比不上的吧.....
Ø 使用要求
KVM基於硬件的完全虛擬化,需要硬件CPU虛擬化技術支持;容器共享宿主機內核,可運行在主流的Linux發行版,不用考慮CPU是否支持虛擬化技術;
應用場景
Ø 應用打包與部署自動化
構建標準化的運行環境;現在大多方案是在物理機和虛擬機上部署運行環境,面臨問題是環境雜亂、完整性遷移難度高等問題,容器即開即用;
Ø 自動化測試和持續集成/部署
自動化構建鏡像和良好的REST API,能夠很好的集成到持續集成/部署環境來;
Ø 部署與彈性擴展
由於容器是應用級的,資源佔用小,彈性擴展部署速度要更快;
Ø 微服務
Docker這種容器華隔離技術,正式應對了微服務理念,將業務模塊放到容器中運行,容器的可複用性大大增加了業務模塊擴展性;
Docker 的安裝
# 安裝依賴包yum install -y yum-utils device-mapper-persistent-data lvm2# 添加Docker軟件包源yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo# 更新yum包索引yum makecache fast# 安裝Docker CEyum install docker-ce# 啓動systemctl start docker# 測試docker run hello-world docker version# 卸載yum remove docker-ce rm -rf /var/lib/docker
Centos6對於Docker的官方支持理論上來說只能算是勉強能用,因爲只提供了基於1.7.1版本的docker-io,還得先裝EPEL源,然而1.7.1版本很多功能都有缺失,至少到1.9才能算夠用,具體解決方案:傳送門
Docker 鏡像
Docker 鏡像是一個不包含Linux內核而又精簡的Linux操作系統
Docker Hub公共鏡像庫:https://hub.docker.com/search/?q=&type=image
默認是國外的源,下載會慢,可以國內的源提供下載速度:curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://04be47cf.m.daocloud.io
鏡像工作原理
當我們啓動一個新的容器時,Docker會加載只讀鏡像,並在其之上添加一個讀寫層,並將鏡像中的目錄複製一份到/var/lib/docker/aufs/mnt/容器ID
目錄下,我們可以使用chroot進入此目錄,如果運行中的容器修改一個已經存在的文件,那麼會將該文件從下面的只讀層複製到讀寫層,只讀層的這個文件就會覆蓋,但還存在,這就實現了文件系統隔離,當刪除容器後,讀寫層的數據將會刪除,只讀鏡像不變;
鏡像文件存儲結構
Docker相關文件存放在:/var/lib/docker
/var/lib/docker/aufs/diff
目錄下是每層與其父層之間的文件差異;
/var/lib/docker/aufs/layers/
目錄下是每層一個文件,記錄其父層一直到根層之間的ID,大部分文件的最後一行都已,表示繼承來自同一層;
/var/lib/docker/aufs/mnt
目錄下是聯合掛載點,從只讀層複製到最上層可讀寫層的文件系統數據在建立鏡像時,每次寫操作,都被視作一種增量操作,即在原有的數據層上添加一個新層;所以一個鏡像會有若干個層組成;每次commit提交就會對產生一個ID,就相當於在上一層有加了一層,可以通過這個ID對鏡像回滾;
鏡像管理的相關命令
#模糊查詢鏡像庫的鏡像,docker search [鏡像名稱]docker search centos#下載鏡像庫的鏡像,docker pull [鏡像名稱]docker pull centos #查詢本地的鏡像信息,docker imagesdocker images#將修改的內容保存爲一個新的鏡像,docker commit [容器名] [鏡像名]{:[標籤]}docker commit test centos:self #刪除本地鏡像,docker rmi [鏡像名]{:[標籤]}docker rmi mysql#導出容器的文件系統生成一個tar包,docker export [容器名] > [導出保存的路徑]docker export test_self_image > test_self_image.tar#將tar包導入到本地鏡像,docker import [tar包名] [鏡像名]{:[標籤]}docker import test_self_image.tar centos:v1.0.0#將鏡像導出爲tar包,docker save [鏡像名]{:[標籤]}docker save nginx > nginx.tar#將tar包導入到本地鏡像庫,docker load -i [tar包名]docker load -i nginx.tar
docker save保存的是鏡像(image)
docker export保存的是容器(container)
Docker 容器管理的相關命令
創建容器命令格式:
docker create [OPTIONS] IMAGE [COMMAND] [ARG...]docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Options(常用選項):
-i,--interactive:標準輸入;
-t,--tty:分配僞終端;
-d,--detach:容器到後臺運行;--add-host list:添加hosts解析;
--cap-add list:添加內核訪問控制權限;
--cap-drop list:去除內核訪問控制權限;
--cidfile string:容器ID寫入到PID文件路徑;
--device list:添加宿主的設備到容器;
--dns list:指定dns解析服務器地址;
-e,--env list:設置變量到容器中;
--env-file list:指定變量文件路徑;
--expose list:申明容器提供的端口;
-h,--hostname string:設置容器主機名;
--ip string:設置容器主機IP地址;
--log-driver:指定容器日誌格式(none、json-file、syslog、fluentd、splunk);
--network string:連接容器到指定網絡;
--oom-kill-disable:禁用自動檢測進程資源佔用過大而kill掉該容器;
-p,--publish list:端口映射;
--restart:嘗試重新啓動,比如--restart on-failure:3掛掉後嘗試重啓3次;
--ulimit ulimit:設定最大進程數和最大文件打開數;
-w,--workdir string:進入容器後所在的工作目錄;
-m,--memory:硬限制容器運行所使用的最大內存值;
--memory-reservation bytes:軟限制容器運行所使用的最大內存值;
--memory-swappiness int:設置是否使用Swap交換內存;
#查看容器docker ps -als#進入一個容器,docker attach [容器名]docker attach mydocker 或 docker exec -it mydocker /bin/bash#刪除容器,docker rm [容器名],加上-f 選項則表示強制刪除docker rm mydocker#啓動容器,docker start [容器名]docker start mydocker#停止容器,docker stop [容器名]docker stop mydocker#殺死容器進程docker kill [容器名]docker kill mydocker#掛起容器,docker pause/unpause [容器名]docker pause mydocker docker unpause mydocker#重命名容器,docker rename [原容器名] [新容器名]docker rename mydocker idocker#查看容器所有信息,docker inspect [容器名]docker inspect idocker#容器中執行命令,docker exec [容器名] [命令]docker exec idocker ls /home/#查看容器中運行的進程,docker top [容器名]docker top idocker#查看容器的端口映射,docker port [容器名]docker port idocker#拷貝文件,docker cp [拷貝的文件] [存放的位置]docker cp pass.txt idocker:/home docker cp idocker:/home/pass.txt /tmp/pass_idocker.txt#查看容器自啓動後的變更,docker diff [容器名]docker diff idocker#查看容器標準輸出日誌,docker logs [容器名]docker logs idocker#動態查看容器利用率,docker stats [容器名],加上--no-stream選項則表示輸出一次docker stats idocker#及時修改跟新容器配置,docker update [容器名]docker update idocker#查看Docker主機事件docker events
刪除所有容器:docker rm -f $(docker ps -q -a)
容器數據持久化
數據卷
將宿主機目錄掛載到容器目錄
數據卷特點:
Ø 在容器啓動初始化時,如果容器使用的宿主機掛載點有數據,這些數據就會拷貝到容器中。
Ø 數據卷可以在容器直接共享和重用。
Ø 可以直接對數據卷裏的內容進行修改。
Ø 數據卷的變化不會影響鏡像的更新。
Ø 卷會一直存在,即使掛載數據卷的容器已經刪除。
示例:
docker run -itd --name docker_web -v /container_data/web:/data centos
/container_data/web爲宿主機目錄,/data是容器中目錄,目錄不存在會自動創建
容器數據卷
將一個運行的容器作爲數據卷,讓其他容器通過掛載這個容器實現數據共享。
示例:
docker run -itd -v /data --name docker_data centos
docker run -itd --name docker_web --volumes-from docker_data centos
搭建WoedPress LNMP Docker
# 創建mysql數據庫容器docker run -itd --name mysql -p 3333:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql --character-set-server=utf8# 創建wp數據庫docker exec mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e"create database wp"'#查看數據庫是否創建成功docker exec mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e"show databases;"'# 創建PHP環境容器docker run -itd --name web --link mysql:db -p 8080:80 -v /container_data/web:/app webdevops/php-nginx# 以wordpress博客爲例測試wget https://cn.wordpress.org/wordpress-4.7.4-zh_CN.tar.gz tar zxf wordpress-4.7.4-zh_CN.tar.gz mv wordpress/* /container_data/web/
瀏覽器測試訪問
http://IP:8080
Docker 網絡
網絡模式
先創建一個docker0的網橋,使用veth pair創建一對虛擬網卡,一端放到新創建的容器中,並重命名eth0,另一端放到宿主機上,以veth+隨機7個字符串命名,並將這個網絡設備加入到docker0網橋中,網橋自動爲容器分配一個IP,並設置docker0的IP爲容器默認網關;所以容器默認網絡都加入了這個網橋,因此都可以彼此通信;同時在iptables添加SNAT轉換網絡段IP,以便容器訪問外網;
Ø bridge
默認網絡,Docker啓動後創建一個docker0網橋,默認創建的容器也是添加到這個網橋中;IP地址段是172.17.0.1/16;
Ø host
容器不會獲得一個獨立的network namespace,而是與宿主機共用一個;
Ø none
獲取獨立的network namespace,但不爲容器進行任何網絡配置;
Ø container
與指定的容器使用同一個network namespace,網卡配置也都是相同的;
Ø 自定義
自定義網橋,默認與bridge網絡一樣;
容器網絡訪問原理
Docker主要通過Netfilter/Iptables實現網絡通信;iptables由netfilter和iptables組成,Netfilter組件是Linux內核集成的信息包過濾系統,它維護一個信息包過濾表,這個表用於控制信息包過濾處理的規則集;而Iptables只是一個在用戶空間的工具,用於增刪改查這個過濾表的規則;
容器訪問外部
[root@docker ~]# iptables -t nat -nLChain POSTROUTING (policy ACCEPT) target prot opt source destination MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0 MASQUERADE tcp -- 172.17.0.3 172.17.0.3 tcp dpt:33060MASQUERADE tcp -- 172.17.0.4 172.17.0.4 tcp dpt:80
外部訪問容器
[root@docker ~]# iptables -t nat -nLChain DOCKER (2 references) target prot opt source destination DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:3333 to:172.17.0.3:33060DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.4:80
橋接宿主機網絡與配置固定IP
橋接宿主機網絡
#關掉docker0ifconfig docker0 down#刪除dockerbrctl delbr docker0#增加網橋br0yum install bridge-utils #配置網橋vim /etc/sysconfig/network-scripts/ifcfg-br0 TYPE=Bridge DEVICE=br0 BOOTPROTO=static ONBOOT=yesIPADDR=192.168.0.152NETMASK=255.255.255.0GATEWAY=192.168.0.1DNS1=8.8.8.8#配置網卡vim /etc/sysconfig/network-scripts/ifcfg-eno16777736 TYPE="Ethernet"DEVICE="eno16777736"NAME="eno16777736"BOOTPROTO="none"ONBOOT="yes"BRIDGE="br0"#重啓網絡systemctl restart network#查看物理機上有哪些網橋brctl show bridge name bridge id STP enabled interfaces br0 8000.000c2984bb70 no eno16777736
配置Docker橋接網絡
#方案一:自定義腳本 docker_auto.shvim docker_auto.shread -p "Please Enter Your Docker Name:" dockernameread -p "Please Enter Your Docker Image Name:" dkimgread -p "Please Enter Your Docker IP Address:" dockeripread -p "Please Enter Your Docker IP GW:" dockergwread -p "Please Enter Your Network BG Name:" bgname#配置固定IPC_ID=$(docker run -itd --net=none --name ${dockername} ${dkimg}) C_PID=$(docker inspect -f '{{.State.Pid}}' $C_ID)# 創建network namespace目錄並將容器的network namespace軟連接到此目錄,以便ip netns命令讀取mkdir -p /var/run/netns ln -s /proc/$C_PID/ns/net /var/run/netns/$C_PID# 添加虛擬網卡veth+容器PID,類型是veth pair,名稱是vp+容器PIDip link add veth$C_PID type veth peer name vp$C_PID# 添加虛擬網卡到br0網橋brctl addif $bgname veth$C_PID# 激活虛擬網卡ip link set veth$C_PID up# 給進程配置一個network namespaceip link set vp$C_PID netns $C_PID# 在容器進程裏面設置網卡信息ip netns exec $C_PID ip link set dev vp$C_PID name eth0ip netns exec $C_PID ip link set eth0 up ip netns exec $C_PID ip addr add ${dockerip}/24 dev eth0ip netns exec $C_PID ip route add default via $dockergw echo $dockername $dkimg $dockerip $dockergw $bgname $C_ID $C_PID#方案二:使用pipework工具git clone https://github.com/jpetazzo/pipework.git cp pipework/pipework /usr/local/bin/ docker run -itd --net=none --name idocker2 centos pipework br0 idocker2 192.168.0.88/[email protected]
容器SSH連接
docker run -itd --name idocker3 centosdocker attach idocker3 yum install openssh-serverpasswd root docker commit idocker3 centos_ssh docker run -itd --name idocker3 -p 2222:22 centos_ssh
Docker File
常用命令
指令 | 描述 |
---|---|
FROM | 構建的新鏡像是基於哪個鏡像; 例如:FROM centos:6 |
MAINTAINER | 鏡像維護者姓名或郵箱地址; 例如:MAINTAINER lizhenliang |
RUN | 構建鏡像時運行的Shell命令 例如:RUN [“yum”, “install”, “httpd”] RUN yum install httpd |
CMD | 運行容器時執行的Shell命令; 例如:CMD [“-c”, “/start.sh”] CMD ["/usr/sbin/sshd", "-D"] CMD /usr/sbin/sshd –D |
EXPOSE | 聲明容器運行的服務端口; 例如:EXPOSE 80 443 |
ENV | 設置容器內環境變量; 例如:ENV MYSQL_ROOT_PASSWORD 123456 |
ADD | 拷貝文件或目錄到鏡像,如果是URL或壓縮包會自動下載或自動解壓 ADD <src>… <dest> ADD [“<src>”,… “<dest>”] ADD https://xxx.com/html.tar.gz /var/www/html ADD html.tar.gz /var/www/html |
COPY | 拷貝文件或目錄到鏡像,用法同上; 例如:COPY ./start.sh /start.sh |
ENTRYPOINT | 運行容器時執行的Shell命令; 例如:ENTRYPOINT [“/bin/bash", “-c", “/start.sh"] ENTRYPOINT /bin/bash -c ‘/start.sh’ |
VOLUME | 指定容器掛載點到宿主機自動生成的目錄或其他容器; 例如:VOLUME ["/var/lib/mysql"] |
USER | 爲RUN、CMD和ENTRYPOINT執行命令指定運行用戶 USER <user>[:<group>] or USER <UID>[:<GID>] 例如:USER lizhenliang |
WORKDIR | 爲RUN、CMD、ENTRYPOINT、COPY和ADD設置工作目錄; 例如:WORKDIR /data |
HEALTHCHECK | 健康檢查; HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ exit 1 |
ARG | 在構建鏡像時指定一些參數; 例如:FROM centos:6 ARG user # ARG user=root USER $user # docker build --build-arg user=lizhenliang Dockerfile. |
RUN、CMD和ENTRYPOINT指令區別
1.RUN在building時運行,可以寫多條;
2.CMD和ENTRYPOINT在運行container時運行,只能寫一條,如果寫多條,最後一條生效;
3.CMD在run時可以被COMMAND覆蓋,ENTRYPOINT不會被COMMAND覆蓋,但可以指定—entrypoint覆蓋;
Build鏡像構建
使用Dockerfile文件構建鏡像
Usage: docker build [OPTIONS] PATH | URL | - Options: -t, --tag list # 鏡像名稱-f, --file string # 指定Dockerfile文件位置示例: docker build . # 默認找當前目錄以Dockerfile爲命名的文件docker build -t shykes/myapp . docker build -t shykes/myapp -f /path/Dockerfile /path docker build -t shykes/myapp - < Dockerfile docker build -t shykes/myapp - < context.tar.gz docker build -t shykes/myapp http://www.example.com/Dockerfiledocker build -f shykes/myapp http://www.example.com/contex.tar.gz
構建 PHP 網站環境鏡像
#Dockerfiler文件配置FROM centos:6MAINTAINER Mingo RUN yum install -y httpd php php-gd php-mysql mysql mysql-server ENV MYSQL_ROOT_PASSWORD 123456RUN echo "<?php phpinfo(); ?>" > /var/www/html/index.php COPY start.sh /start.sh RUN chmod +x /start.sh ADD https://cn.wordpress.org/wordpress-4.7.4-zh_CN.tar.gz /var/www/htmlCOPY wp-config.php /var/www/html/wordpress VOLUME ["/var/lib/mysql"] CMD /start.sh EXPOSE 80 3306vim start.sh service httpd start service mysqld start mysqladmin -uroot password $MYSQL_ROOT_PASSWORD tail -f
tail -f主要是爲了進程阻塞,防止掉進程
構建 JAVA 網站環境鏡像
FROM centos:6MAINTAINER Mingo COPY jdk-8u45-linux-x64.tar.gz /usr/localENV JAVA_HOME /usr/local/jdk1.8.0_45ADD http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.0.45/bin/apache- tomcat-8.0.45.tar.gz /usr/localWORKDIR /usr/local/apache-tomcat-8.0.45ENTRYPOINT ["bin/catalina.sh", "run"] EXPOSE 8080
構建支持 SSH 服務鏡像
FROM centos:6 MAINTAINER Mingo ENV ROOT_PASSWORD 123456 RUN yum install -y openssh-serverRUN echo $ROOT_PASSWORD |passwd --stdin rootRUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key CMD ["/usr/sbin/sshd", "-D"] EXPOSE 22