Docker 入門

什麼是 Docker

Docker是一個使用 Go 語言開發的,並且開源的應用容器引擎,基於LXC(Linux Container)內核虛擬化技術實現,提供一系列更強的功能,比如鏡像、Dockerfile等;

Docker理念是將應用及依賴包打包到一個可移植的容器中,可發佈到任意Linux發行版的Docker引擎上,使用沙箱機制運行程序,程序之間相互隔離;

Docker採用C/S架構,Dcoker daemon作爲服務端接受來自客戶端請求,並處理這些請求,比如創建、運行容器等;客戶端爲用戶提供一系列指令與Docker Daemon交互;
Docker架構與內部組件

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);
Docker 內部結構

Doker 優點與虛擬機的區別

  • 持續集成
    在項目快速迭代情況下,輕量級容器對項目快速構建、環境打包、發佈等流程就能提高工作效率;

  • 版本控制
    每個鏡像就是一個版本,在一個項目多個版本時可以很方便管理;

  • 可移植性
    容器可以移動到任意一臺Linux的Docker引擎上,而不需要過多關注底層系統;

  • 標準化
    應用程序環境及依賴、操作系統等問題,增加了生產環境故障率,容器保證了所有配置、依賴始終不變;

  • 隔離性與安全
    容器之間的進程是相互隔離的,一個容器出現問題不會影響其他容器;

VMware VS Docker

以KVM舉例,與Docker對比
Ø 啓動時間
Docker是秒級啓動,而KVM是分鐘級;
Ø 輕量級
容器鏡像大小通常以M爲單位,而虛擬機以G爲單位;容器資源佔用小,要比虛擬機部署更快速;
Ø 性能
容器共享宿主機內核,系統級虛擬化,佔用資源少,沒有Hypervisor層開銷,容器性能基本接近物理機;而虛擬機需要Hypervisor層支持,虛擬化一些設備,具有完整的GuestOS,虛擬化開銷大,因而降低性能,沒有容器性能好;
Ø 安全性
由於共享宿主機內核,只是進程級隔離,因此隔離性和穩定性不如虛擬機,容器具有一定權限訪問宿主機內核,存在一定安全隱患,在這一點上可能就是Doker唯一比不上的吧..... tongue.png 
Ø 使用要求
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
PHPinfo

Docker 網絡

網絡模式

先創建一個docker0的網橋,使用veth pair創建一對虛擬網卡,一端放到新創建的容器中,並重命名eth0,另一端放到宿主機上,以veth+隨機7個字符串命名,並將這個網絡設備加入到docker0網橋中,網橋自動爲容器分配一個IP,並設置docker0的IP爲容器默認網關;所以容器默認網絡都加入了這個網橋,因此都可以彼此通信;同時在iptables添加SNAT轉換網絡段IP,以便容器訪問外網;

Docker 主機默認網絡

Ø 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只是一個在用戶空間的工具,用於增刪改查這個過濾表的規則;

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章