一、Docker 簡介Docker 兩個主要部件:
Docker 使用客戶端-服務(wù)器 (C/S) 架構(gòu)模式。Docker 客戶端會與 Docker 守護(hù)進(jìn)程進(jìn)行通信。Docker 守護(hù)進(jìn)程會處理復(fù)雜繁重的任務(wù),例如建立、運(yùn)行、發(fā)布你的 Docker 容器。Docker 客戶端和守護(hù)進(jìn)程可以運(yùn)行在同一個系統(tǒng)上,當(dāng)然你也可以使用 Docker 客戶端去連接一個遠(yuǎn)程的 Docker 守護(hù)進(jìn)程。Docker 客戶端和守護(hù)進(jìn)程之間通過 socket 或者 RESTful API 進(jìn)行通信。
1.1 Docker 守護(hù)進(jìn)程如上圖所示,Docker 守護(hù)進(jìn)程運(yùn)行在一臺主機(jī)上。用戶并不直接和守護(hù)進(jìn)程進(jìn)行交互,而是通過 Docker 客戶端間接和其通信。 1.2 Docker 客戶端Docker 客戶端,實(shí)際上是 docker 的二進(jìn)制程序,是主要的用戶與 Docker 交互方式。它接收用戶指令并且與背后的 Docker 守護(hù)進(jìn)程通信,如此來回往復(fù)。 1.3 Docker 內(nèi)部要理解 Docker 內(nèi)部構(gòu)建,需要理解以下三種部件:
Docker 鏡像Docker 鏡像是 Docker 容器運(yùn)行時的只讀模板,每一個鏡像由一系列的層 (layers) 組成。Docker 使用 UnionFS 來將這些層聯(lián)合到單獨(dú)的鏡像中。UnionFS 允許獨(dú)立文件系統(tǒng)中的文件和文件夾(稱之為分支)被透明覆蓋,形成一個單獨(dú)連貫的文件系統(tǒng)。正因?yàn)橛辛诉@些層的存在,Docker 是如此的輕量。當(dāng)你改變了一個 Docker 鏡像,比如升級到某個程序到新的版本,一個新的層會被創(chuàng)建。因此,不用替換整個原先的鏡像或者重新建立(在使用虛擬機(jī)的時候你可能會這么做),只是一個新 的層被添加或升級了。現(xiàn)在你不用重新發(fā)布整個鏡像,只需要升級,層使得分發(fā) Docker 鏡像變得簡單和快速。 Docker 倉庫Docker 倉庫用來保存鏡像,可以理解為代碼控制中的代碼倉庫。同樣的,Docker 倉庫也有公有和私有的概念。公有的 Docker 倉庫名字是 Docker Hub。Docker Hub 提供了龐大的鏡像集合供使用。這些鏡像可以是自己創(chuàng)建,或者在別人的鏡像基礎(chǔ)上創(chuàng)建。Docker 倉庫是 Docker 的分發(fā)部分。 Docker 容器Docker 容器和文件夾很類似,一個Docker容器包含了所有的某個應(yīng)用運(yùn)行所需要的環(huán)境。每一個 Docker 容器都是從 Docker 鏡像創(chuàng)建的。Docker 容器可以運(yùn)行、開始、停止、移動和刪除。每一個 Docker 容器都是獨(dú)立和安全的應(yīng)用平臺,Docker 容器是 Docker 的運(yùn)行部分。 1.4 libcontainerDocker 從 0.9 版本開始使用 libcontainer 替代 lxc,libcontainer 和 Linux 系統(tǒng)的交互圖如下:
1.5 命名空間「Namespaces」pid namespace不同用戶的進(jìn)程就是通過 pid namespace 隔離開的,且不同 namespace 中可以有相同 PID。具有以下特征:
參考文檔:Introduction to Linux namespaces – Part 3: PID mnt namespace類似 chroot,將一個進(jìn)程放到一個特定的目錄執(zhí)行。mnt namespace 允許不同 namespace 的進(jìn)程看到的文件結(jié)構(gòu)不同,這樣每個 namespace 中的進(jìn)程所看到的文件目錄就被隔離開了。同 chroot 不同,每個 namespace 中的 container 在 /proc/mounts 的信息只包含所在 namespace 的 mount point。 net namespace網(wǎng)絡(luò)隔離是通過 net namespace 實(shí)現(xiàn)的, 每個 net namespace 有獨(dú)立的 network devices, IP addresses, IP routing tables, /proc/net 目錄。這樣每個 container 的網(wǎng)絡(luò)就能隔離開來。 docker 默認(rèn)采用 veth 的方式將 container 中的虛擬網(wǎng)卡同 host 上的一個 docker bridge 連接在一起。 參考文檔:Introduction to Linux namespaces – Part 5: NET uts namespaceUTS ('UNIX Time-sharing System') namespace 允許每個 container 擁有獨(dú)立的 hostname 和 domain name, 使其在網(wǎng)絡(luò)上可以被視作一個獨(dú)立的節(jié)點(diǎn)而非 Host 上的一個進(jìn)程。 參考文檔:Introduction to Linux namespaces – Part 1: UTS ipc namespacecontainer 中進(jìn)程交互還是采用 Linux 常見的進(jìn)程間交互方法 (interprocess communication - IPC), 包括常見的信號量、消息隊(duì)列和共享內(nèi)存。然而同 VM 不同,container 的進(jìn)程間交互實(shí)際上還是 host 上具有相同 pid namespace 中的進(jìn)程間交互,因此需要在IPC資源申請時加入 namespace 信息 - 每個 IPC 資源有一個唯一的 32bit ID。 參考文檔:Introduction to Linux namespaces – Part 2: IPC user namespace每個 container 可以有不同的 user 和 group id, 也就是說可以以 container 內(nèi)部的用戶在 container 內(nèi)部執(zhí)行程序而非 Host 上的用戶。 有了以上 6 種 namespace 從進(jìn)程、網(wǎng)絡(luò)、IPC、文件系統(tǒng)、UTS 和用戶角度的隔離,一個 container 就可以對外展現(xiàn)出一個獨(dú)立計(jì)算機(jī)的能力,并且不同 container 從 OS 層面實(shí)現(xiàn)了隔離。 然而不同 namespace 之間資源還是相互競爭的,仍然需要類似 ulimit 來管理每個 container 所能使用的資源 - cgroup。 Reference1.6 資源配額「cgroups」cgroups 實(shí)現(xiàn)了對資源的配額和度量。 cgroups 的使用非常簡單,提供類似文件的接口,在 /cgroup 目錄下新建一個文件夾即可新建一個 group,在此文件夾中新建 task 文件,并將 pid 寫入該文件,即可實(shí)現(xiàn)對該進(jìn)程的資源控制。具體的資源配置選項(xiàng)可以在該文件夾中新建子 subsystem ,{子系統(tǒng)前綴}.{資源項(xiàng)} 是典型的配置方法, 如 memory.usageinbytes 就定義了該 group 在 subsystem memory 中的一個內(nèi)存限制選項(xiàng)。 另外,cgroups 中的 subsystem 可以隨意組合,一個 subsystem 可以在不同的 group 中,也可以一個 group 包含多個 subsystem - 也就是說一個 subsystem。
參考文檔:how to use cgroup 二、Docker 安裝docker 的相關(guān)安裝方法這里不作介紹,具體安裝參考 官檔 獲取當(dāng)前 docker 版本 $ sudo docker versionClient version: 1.3.2Client API version: 1.15Go version (client): go1.3.3Git commit (client): 39fa2fa/1.3.2OS/Arch (client): linux/amd64Server version: 1.3.2Server API version: 1.15Go version (server): go1.3.3Git commit (server): 39fa2fa/1.3.2 三、Docker 基礎(chǔ)用法Docker HUB : Docker鏡像首頁,包括官方鏡像和其它公開鏡像 因?yàn)閲榈脑颍瑖鴥?nèi)下載 Docker HUB 官方的相關(guān)鏡像比較慢,可以使用 docker.cn 鏡像,鏡像保持和官方一致,關(guān)鍵是速度塊,推薦使用。 3.1 Search images$ sudo docker search ubuntu 3.2 Pull images$ sudo docker pull ubuntu # 獲取 ubuntu 官方鏡像 $ sudo docker images # 查看當(dāng)前鏡像列表 3.3 Running an interactive shell$ sudo docker run -i -t ubuntu:14.04 /bin/bash
注: ubuntu 會有多個版本,通過指定 tag 來啟動特定的版本 [image]:[tag] $ sudo docker ps # 查看當(dāng)前運(yùn)行的容器, ps -a 列出當(dāng)前系統(tǒng)所有的容器 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES6c9129e9df10 ubuntu:14.04 /bin/bash 6 minutes ago Up 6 minutes cranky_babbage 3.4 相關(guān)快捷鍵
四、Docker 命令幫助4.1 docker helpdocker command$ sudo docker # docker 命令幫助Commands: attach Attach to a running container # 當(dāng)前 shell 下 attach 連接指定運(yùn)行鏡像 build Build an image from a Dockerfile # 通過 Dockerfile 定制鏡像 commit Create a new image from a container's changes # 提交當(dāng)前容器為新的鏡像 cp Copy files/folders from the containers filesystem to the host path # 從容器中拷貝指定文件或者目錄到宿主機(jī)中 create Create a new container # 創(chuàng)建一個新的容器,同 run,但不啟動容器 diff Inspect changes on a container's filesystem # 查看 docker 容器變化 events Get real time events from the server # 從 docker 服務(wù)獲取容器實(shí)時事件 exec Run a command in an existing container # 在已存在的容器上運(yùn)行命令 export Stream the contents of a container as a tar archive # 導(dǎo)出容器的內(nèi)容流作為一個 tar 歸檔文件[對應(yīng) import ] history Show the history of an image # 展示一個鏡像形成歷史 images List images # 列出系統(tǒng)當(dāng)前鏡像 import Create a new filesystem image from the contents of a tarball # 從tar包中的內(nèi)容創(chuàng)建一個新的文件系統(tǒng)映像[對應(yīng) export] info Display system-wide information # 顯示系統(tǒng)相關(guān)信息 inspect Return low-level information on a container # 查看容器詳細(xì)信息 kill Kill a running container # kill 指定 docker 容器 load Load an image from a tar archive # 從一個 tar 包中加載一個鏡像[對應(yīng) save] login Register or Login to the docker registry server # 注冊或者登陸一個 docker 源服務(wù)器 logout Log out from a Docker registry server # 從當(dāng)前 Docker registry 退出 logs Fetch the logs of a container # 輸出當(dāng)前容器日志信息 port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT # 查看映射端口對應(yīng)的容器內(nèi)部源端口 pause Pause all processes within a container # 暫停容器 ps List containers # 列出容器列表 pull Pull an image or a repository from the docker registry server # 從docker鏡像源服務(wù)器拉取指定鏡像或者庫鏡像 push Push an image or a repository to the docker registry server # 推送指定鏡像或者庫鏡像至docker源服務(wù)器 restart Restart a running container # 重啟運(yùn)行的容器 rm Remove one or more containers # 移除一個或者多個容器 rmi Remove one or more images # 移除一個或多個鏡像[無容器使用該鏡像才可刪除,否則需刪除相關(guān)容器才可繼續(xù)或 -f 強(qiáng)制刪除] run Run a command in a new container # 創(chuàng)建一個新的容器并運(yùn)行一個命令 save Save an image to a tar archive # 保存一個鏡像為一個 tar 包[對應(yīng) load] search Search for an image on the Docker Hub # 在 docker hub 中搜索鏡像 start Start a stopped containers # 啟動容器 stop Stop a running containers # 停止容器 tag Tag an image into a repository # 給源中鏡像打標(biāo)簽 top Lookup the running processes of a container # 查看容器中運(yùn)行的進(jìn)程信息 unpause Unpause a paused container # 取消暫停容器 version Show the docker version information # 查看 docker 版本號 wait Block until a container stops, then print its exit code # 截取容器停止時的退出狀態(tài)值Run 'docker COMMAND --help' for more information on a command. docker optionUsage of docker: --api-enable-cors=false Enable CORS headers in the remote API # 遠(yuǎn)程 API 中開啟 CORS 頭 -b, --bridge='' Attach containers to a pre-existing network bridge # 橋接網(wǎng)絡(luò) use 'none' to disable container networking --bip='' Use this CIDR notation address for the network bridge's IP, not compatible with -b # 和 -b 選項(xiàng)不兼容,具體沒有測試過 -d, --daemon=false Enable daemon mode # daemon 模式 -D, --debug=false Enable debug mode # debug 模式 --dns=[] Force docker to use specific DNS servers # 強(qiáng)制 docker 使用指定 dns 服務(wù)器 --dns-search=[] Force Docker to use specific DNS search domains # 強(qiáng)制 docker 使用指定 dns 搜索域 -e, --exec-driver='native' Force the docker runtime to use a specific exec driver # 強(qiáng)制 docker 運(yùn)行時使用指定執(zhí)行驅(qū)動器 --fixed-cidr='' IPv4 subnet for fixed IPs (ex: 10.20.0.0/16) this subnet must be nested in the bridge subnet (which is defined by -b or --bip) -G, --group='docker' Group to assign the unix socket specified by -H when running in daemon mode use '' (the empty string) to disable setting of a group -g, --graph='/var/lib/docker' Path to use as the root of the docker runtime # 容器運(yùn)行的根目錄路徑 -H, --host=[] The socket(s) to bind to in daemon mode # daemon 模式下 docker 指定綁定方式[tcp or 本地 socket] specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd. --icc=true Enable inter-container communication # 跨容器通信 --insecure-registry=[] Enable insecure communication with specified registries (no certificate verification for HTTPS and enable HTTP fallback) (e.g., localhost:5000 or 10.20.0.0/16) --ip='0.0.0.0' Default IP address to use when binding container ports # 指定監(jiān)聽地址,默認(rèn)所有 ip --ip-forward=true Enable net.ipv4.ip_forward # 開啟轉(zhuǎn)發(fā) --ip-masq=true Enable IP masquerading for bridge's IP range --iptables=true Enable Docker's addition of iptables rules # 添加對應(yīng) iptables 規(guī)則 --mtu=0 Set the containers network MTU # 設(shè)置網(wǎng)絡(luò) mtu if no value is provided: default to the default route MTU or 1500 if no default route is available -p, --pidfile='/var/run/docker.pid' Path to use for daemon PID file # 指定 pid 文件位置 --registry-mirror=[] Specify a preferred Docker registry mirror -s, --storage-driver='' Force the docker runtime to use a specific storage driver # 強(qiáng)制 docker 運(yùn)行時使用指定存儲驅(qū)動 --selinux-enabled=false Enable selinux support # 開啟 selinux 支持 --storage-opt=[] Set storage driver options # 設(shè)置存儲驅(qū)動選項(xiàng) --tls=false Use TLS; implied by tls-verify flags # 開啟 tls --tlscacert='/root/.docker/ca.pem' Trust only remotes providing a certificate signed by the CA given here --tlscert='/root/.docker/cert.pem' Path to TLS certificate file # tls 證書文件位置 --tlskey='/root/.docker/key.pem' Path to TLS key file # tls key 文件位置 --tlsverify=false Use TLS and verify the remote (daemon: verify client, client: verify daemon) # 使用 tls 并確認(rèn)遠(yuǎn)程控制主機(jī) -v, --version=false Print version information and quit # 輸出 docker 版本信息 4.2 docker search$ sudo docker search --helpUsage: docker search TERMSearch the Docker Hub for images # 從 Docker Hub 搜索鏡像 --automated=false Only show automated builds --no-trunc=false Don't truncate output -s, --stars=0 Only displays with at least xxx stars 示例: $ sudo docker search -s 100 ubuntu # 查找 star 數(shù)至少為 100 的鏡像,找出只有官方鏡像 start 數(shù)超過 100,默認(rèn)不加 s 選項(xiàng)找出所有相關(guān) ubuntu 鏡像 NAME DESCRIPTION STARS OFFICIAL AUTOMATEDubuntu Official Ubuntu base image 425 [OK] 4.3 docker info$ sudo docker info Containers: 1 # 容器個數(shù) Images: 22 # 鏡像個數(shù) Storage Driver: devicemapper # 存儲驅(qū)動 Pool Name: docker-8:17-3221225728-pool Pool Blocksize: 65.54 kB Data file: /data/docker/devicemapper/devicemapper/data Metadata file: /data/docker/devicemapper/devicemapper/metadata Data Space Used: 1.83 GB Data Space Total: 107.4 GB Metadata Space Used: 2.191 MB Metadata Space Total: 2.147 GB Library Version: 1.02.84-RHEL7 (2014-03-26) Execution Driver: native-0.2 # 存儲驅(qū)動 Kernel Version: 3.10.0-123.el7.x86_64Operating System: CentOS Linux 7 (Core) 4.4 docker pull && docker push$ sudo docker pull --help # pull 拉取鏡像 Usage: docker pull [OPTIONS] NAME[:TAG] Pull an image or a repository from the registry -a, --all-tags=false Download all tagged images in the repository $ sudo docker push # push 推送指定鏡像 Usage: docker push NAME[:TAG] Push an image or a repository to the registry 示例: $ sudo docker pull ubuntu # 下載官方 ubuntu docker 鏡像,默認(rèn)下載所有 ubuntu 官方庫鏡像 $ sudo docker pull ubuntu:14.04 # 下載指定版本 ubuntu 官方鏡像 $ sudo docker push 192.168.0.100:5000/ubuntu # 推送鏡像庫到私有源[可注冊 docker 官方賬戶,推送到官方自有賬戶] $ sudo docker push 192.168.0.100:5000/ubuntu:14.04 # 推送指定鏡像到私有源 4.5 docker images列出當(dāng)前系統(tǒng)鏡像 $ sudo docker images --helpUsage: docker images [OPTIONS] [NAME] List images -a, --all=false Show all images (by default filter out the intermediate image layers) # -a 顯示當(dāng)前系統(tǒng)的所有鏡像,包括過渡層鏡像,默認(rèn) docker images 顯示最終鏡像,不包括過渡層鏡像 -f, --filter=[] Provide filter values (i.e. 'dangling=true') --no-trunc=false Don't truncate output -q, --quiet=false Only show numeric IDs 示例: $ sudo docker images # 顯示當(dāng)前系統(tǒng)鏡像,不包括過渡層鏡像 $ sudo docker images -a # 顯示當(dāng)前系統(tǒng)所有鏡像,包括過渡層鏡像 $ sudo docker images ubuntu # 顯示當(dāng)前系統(tǒng) docker ubuntu 庫中的所有鏡像 REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZEubuntu 12.04 ebe4be4dd427 4 weeks ago 210.6 MBubuntu 14.04 e54ca5efa2e9 4 weeks ago 276.5 MBubuntu 14.04-ssh 6334d3ac099a 7 weeks ago 383.2 MB 4.6 docker rmi刪除一個或者多個鏡像 $ sudo docker rmi --helpUsage: docker rmi IMAGE [IMAGE...] Remove one or more images -f, --force=false Force removal of the image # 強(qiáng)制移除鏡像不管是否有容器使用該鏡像 --no-prune=false Do not delete untagged parents # 不要刪除未標(biāo)記的父鏡像 4.7 docker run$ sudo docker run --helpUsage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] Run a command in a new container -a, --attach=[] Attach to stdin, stdout or stderr. -c, --cpu-shares=0 CPU shares (relative weight) # 設(shè)置 cpu 使用權(quán)重 --cap-add=[] Add Linux capabilities --cap-drop=[] Drop Linux capabilities --cidfile='' Write the container ID to the file # 把容器 id 寫入到指定文件 --cpuset='' CPUs in which to allow execution (0-3, 0,1) # cpu 綁定 -d, --detach=false Detached mode: Run container in the background, print new container id # 后臺運(yùn)行容器 --device=[] Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc) --dns=[] Set custom dns servers # 設(shè)置 dns --dns-search=[] Set custom dns search domains # 設(shè)置 dns 域搜索 -e, --env=[] Set environment variables # 定義環(huán)境變量 --entrypoint='' Overwrite the default entrypoint of the image # ? --env-file=[] Read in a line delimited file of ENV variables # 從指定文件讀取變量值 --expose=[] Expose a port from the container without publishing it to your host # 指定對外提供服務(wù)端口 -h, --hostname='' Container host name # 設(shè)置容器主機(jī)名 -i, --interactive=false Keep stdin open even if not attached # 保持標(biāo)準(zhǔn)輸出開啟即使沒有 attached --link=[] Add link to another container (name:alias) # 添加鏈接到另外一個容器 --lxc-conf=[] (lxc exec-driver only) Add custom lxc options --lxc-conf='lxc.cgroup.cpuset.cpus = 0,1' -m, --memory='' Memory limit (format: number> 示例: $ sudo docker images ubuntuREPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZEubuntu 14.04 e54ca5efa2e9 4 weeks ago 276.5 MB... ... $ sudo docker run -t -i -c 100 -m 512MB -h test1 -d --name='docker_test1' ubuntu /bin/bash # 創(chuàng)建一個 cpu 優(yōu)先級為 100,內(nèi)存限制 512MB,主機(jī)名為 test1,名為 docker_test1 后臺運(yùn)行 bash 的容器 a424ca613c9f2247cd3ede95adfbaf8d28400cbcb1d5f9b69a7b56f97b2b52e5 $ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESa424ca613c9f ubuntu:14.04 /bin/bash 6 seconds ago Up 5 seconds docker_test1 $ sudo docker attach docker_test1root@test1:/# pwd /root@test1:/# exit exit 關(guān)于cpu優(yōu)先級:
4.8 docker start|stop|kill... ...dockerstart|stop|kill|restart|pause|unpause|rm|commit|inspect|logs
參考文檔:Docker Run Reference 4.9 Docker 1.3 新增特性和命令Digital Signature VerificationDocker 1.3 版本將使用數(shù)字簽名自動驗(yàn)證所有官方庫的來源和完整性,如果一個官方鏡像被篡改或者被破壞,目前 Docker 只會對這種情況發(fā)出警告而并不阻止容器的運(yùn)行。 Inject new processes withdocker execdocker exec --helpUsage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...] Run a command in an existing container -d, --detach=false Detached mode: run command in the background -i, --interactive=false Keep STDIN open even if not attached -t, --tty=false Allocate a pseudo-TTY 為了簡化調(diào)試,可以使用docker exec命令通過 Docker API 和 CLI 在運(yùn)行的容器上運(yùn)行程序。 $ docker exec -it ubuntu_bash bash 上例將在容器 ubuntu_bash 中創(chuàng)建一個新的 Bash 會話。 Tune container lifecycles withdocker create我們可以通過docker run 上例創(chuàng)建了一個可寫的容器層 (并且打印出容器 ID),但是并不運(yùn)行它,可以使用以下命令運(yùn)行該容器: 通過--security-opt選項(xiàng),運(yùn)行容器時用戶可自定義 SELinux 和 AppArmor 卷標(biāo)和配置。 上例只允許容器監(jiān)聽在 Apache 端口,這個選項(xiàng)的好處是用戶不需要運(yùn)行 docker 的時候指定--privileged選項(xiàng),降低安全風(fēng)險(xiǎn)。 參考文檔:Docker 1.3: signed images, process injection, security options, Mac shared directories 參考文檔:Docker 1.5 新特性 無論如何,這些 ip 是基于本地系統(tǒng)的并且容器的端口非本地主機(jī)是訪問不到的。此外,除了端口只能本地訪問外,對于容器的另外一個問題是這些 ip 在容器每次啟動的時候都會改變。 Docker 解決了容器的這兩個問題,并且給容器內(nèi)部服務(wù)的訪問提供了一個簡單而可靠的方法。Docker 通過端口綁定主機(jī)系統(tǒng)的接口,允許非本地客戶端訪問容器內(nèi)部運(yùn)行的服務(wù)。為了簡便的使得容器間通信,Docker 提供了這種連接機(jī)制。 -P使用時需要指定--expose選項(xiàng),指定需要對外提供服務(wù)的端口 使用docker run -P自動綁定所有對外提供服務(wù)的容器端口,映射的端口將會從沒有使用的端口池中 (49000..49900) 自動選擇,你可以通過docker ps、docker inspect 基本語法 默認(rèn)不指定綁定 ip 則監(jiān)聽所有網(wǎng)絡(luò)接口。 圖: Docker - container and lightweight virtualization Dokcer 通過使用 Linux 橋接提供容器之間的通信,docker0 橋接接口的目的就是方便 Docker 管理。當(dāng) Docker daemon 啟動時需要做以下操作: 四種網(wǎng)絡(luò)模式摘自 Docker 網(wǎng)絡(luò)詳解及 pipework 源碼解讀與實(shí)踐 docker run 創(chuàng)建 Docker 容器時,可以用 --net 選項(xiàng)指定容器的網(wǎng)絡(luò)模式,Docker 有以下 4 種網(wǎng)絡(luò)模式: 如果啟動容器的時候使用 host 模式,那么這個容器將不會獲得一個獨(dú)立的 Network Namespace,而是和宿主機(jī)共用一個 Network Namespace。容器將不會虛擬出自己的網(wǎng)卡,配置自己的 IP 等,而是使用宿主機(jī)的 IP 和端口。 例如,我們在 10.10.101.105/24 的機(jī)器上用 host 模式啟動一個含有 web 應(yīng)用的 Docker 容器,監(jiān)聽 tcp 80 端口。當(dāng)我們在容器中執(zhí)行任何類似 ifconfig 命令查看網(wǎng)絡(luò)環(huán)境時,看到的都是宿主機(jī)上的信息。而外界訪問容器中的應(yīng)用,則直接使用 10.10.101.105:80 即可,不用任何 NAT 轉(zhuǎn)換,就如直接跑在宿主機(jī)中一樣。但是,容器的其他方面,如文件系統(tǒng)、進(jìn)程列表等還是和宿主機(jī)隔離的。 這個模式指定新創(chuàng)建的容器和已經(jīng)存在的一個容器共享一個 Network Namespace,而不是和宿主機(jī)共享。新創(chuàng)建的容器不會創(chuàng)建自己的網(wǎng)卡,配置自己的 IP,而是和一個指定的容器共享 IP、端口范圍等。同樣,兩個容器除了網(wǎng)絡(luò)方面,其他的如文件系統(tǒng)、進(jìn)程列表等還是隔離的。兩個容器的進(jìn)程可以通過 lo 網(wǎng)卡設(shè)備通信。 這個模式和前兩個不同。在這種模式下,Docker 容器擁有自己的 Network Namespace,但是,并不為 Docker容器進(jìn)行任何網(wǎng)絡(luò)配置。也就是說,這個 Docker 容器沒有網(wǎng)卡、IP、路由等信息。需要我們自己為 Docker 容器添加網(wǎng)卡、配置 IP 等。 圖:The Container World | Part 2 Networking bridge 模式是 Docker 默認(rèn)的網(wǎng)絡(luò)設(shè)置,此模式會為每一個容器分配 Network Namespace、設(shè)置 IP 等,并將一個主機(jī)上的 Docker 容器連接到一個虛擬網(wǎng)橋上。當(dāng) Docker server 啟動時,會在主機(jī)上創(chuàng)建一個名為 docker0 的虛擬網(wǎng)橋,此主機(jī)上啟動的 Docker 容器會連接到這個虛擬網(wǎng)橋上。虛擬網(wǎng)橋的工作方式和物理交換機(jī)類似,這樣主機(jī)上的所有容器就通過交換機(jī)連在了一個二層網(wǎng)絡(luò)中。接下來就要為容器分配 IP 了,Docker 會從 RFC1918 所定義的私有 IP 網(wǎng)段中,選擇一個和宿主機(jī)不同的IP地址和子網(wǎng)分配給 docker0,連接到 docker0 的容器就從這個子網(wǎng)中選擇一個未占用的 IP 使用。如一般 Docker 會使用 172.17.0.0/16 這個網(wǎng)段,并將 172.17.42.1/16 分配給 docker0 網(wǎng)橋(在主機(jī)上使用 ifconfig 命令是可以看到 docker0 的,可以認(rèn)為它是網(wǎng)橋的管理接口,在宿主機(jī)上作為一塊虛擬網(wǎng)卡使用) 在容器運(yùn)行時,每個容器都會分配一個特定的虛擬機(jī)口并橋接到 docker0。每個容器都會配置同 docker0 ip 相同網(wǎng)段的專用 ip 地址,docker0 的 IP 地址被用于所有容器的默認(rèn)網(wǎng)關(guān)。 以上, docker0 扮演著 52f811c5d3d6 container 這個容器的虛擬接口 vethQCDY1N interface 橋接的角色。 Docker 會嘗試尋找沒有被主機(jī)使用的 ip 段,盡管它適用于大多數(shù)情況下,但是它不是萬能的,有時候我們還是需要對 ip 進(jìn)一步規(guī)劃。Docker 允許你管理 docker0 橋接或者通過-b選項(xiàng)自定義橋接網(wǎng)卡,需要安裝bridge-utils軟件包。 基本步驟如下: 參考文檔: Network Configuration 不同容器之間的通信可以借助于 pipework 這個工具: 橋接網(wǎng)絡(luò)可以參考 日常問題處理 Tips 關(guān)于橋接的配置說明,這里不再贅述。 可以刪除 docker0,直接把 docker 的橋接指定為 br0。也可以保留使用默認(rèn)的配置,這樣單主機(jī)容器之間的通信可以通過 docker0,而跨主機(jī)不同容器之間通過 pipework 新建 docker 容器的網(wǎng)卡橋接到 br0,這樣跨主機(jī)容器之間就可以通信了。 不同容器之間的通信可以借助于 pipework 這個工具給 docker 容器新建虛擬網(wǎng)卡并綁定 IP 橋接到 br0 如果刪除了默認(rèn)的 docker0 橋接,把 docker 默認(rèn)橋接指定到了 br0,則最好在創(chuàng)建容器的時候加上--net=none,防止自動分配的 IP 在局域網(wǎng)中有沖突。 使用ip netns添加靜態(tài)路由,避免創(chuàng)建容器使用--privileged=true選項(xiàng)造成一些不必要的安全問題: 在其它宿主機(jī)進(jìn)行相應(yīng)的配置,新建容器并使用 pipework 添加虛擬網(wǎng)卡橋接到 br0,測試通信情況即可。 另外,pipework 可以創(chuàng)建容器的 vlan 網(wǎng)絡(luò),這里不作過多的介紹了,官方文檔已經(jīng)寫的很清楚了,可以查看以下兩篇文章: Docker 可以通過 Dockerfile 的內(nèi)容來自動構(gòu)建鏡像。Dockerfile 是一個包含創(chuàng)建鏡像所有命令的文本文件,通過docker build命令可以根據(jù) Dockerfile 的內(nèi)容構(gòu)建鏡像,在介紹如何構(gòu)建之前先介紹下 Dockerfile 的基本語法結(jié)構(gòu)。 Dockerfile 有以下指令選項(xiàng): 用法: 或者 用法: 指定創(chuàng)建鏡像的用戶 RUN 有兩種使用方式 每條RUN指令將在當(dāng)前鏡像基礎(chǔ)上執(zhí)行指定命令,并提交為新的鏡像,后續(xù)的RUN都在之前RUN提交后的鏡像為基礎(chǔ),鏡像是分層的,可以通過一個鏡像的任何一個歷史提交點(diǎn)來創(chuàng)建,類似源碼的版本控制。 exec 方式會被解析為一個 JSON 數(shù)組,所以必須使用雙引號而不是單引號。exec 方式不會調(diào)用一個命令 shell,所以也就不會繼承相應(yīng)的變量,如: 這種方式是不會達(dá)到輸出 HOME 變量的,正確的方式應(yīng)該是這樣的 RUN產(chǎn)生的緩存在下一次構(gòu)建的時候是不會失效的,會被重用,可以使用--no-cache選項(xiàng),即docker build --no-cache,如此便不會緩存。 CMD有三種使用方式: CMD指定在 Dockerfile 中只能使用一次,如果有多個,則只有最后一個會生效。 CMD的目的是為了在啟動容器時提供一個默認(rèn)的命令執(zhí)行選項(xiàng)。如果用戶啟動容器時指定了運(yùn)行的命令,則會覆蓋掉CMD指定的命令。 CMD會在啟動容器的時候執(zhí)行,build 時不執(zhí)行,而RUN只是在構(gòu)建鏡像的時候執(zhí)行,后續(xù)鏡像構(gòu)建完成之后,啟動容器就與RUN無關(guān)了,這個初學(xué)者容易弄混這個概念,這里簡單注解一下。 告訴 Docker 服務(wù)端容器對外映射的本地端口,需要在 docker run 的時候使用-p或者-P選項(xiàng)生效。 指定一個環(huán)節(jié)變量,會被后續(xù)RUN指令使用,并在容器運(yùn)行時保留。 例子: 等同于 ADD復(fù)制本地主機(jī)文件、目錄或者遠(yuǎn)程文件 URLS 從 并且添加到容器指定路徑中 。 支持通過 GO 的正則模糊匹配,具體規(guī)則可參見 Go filepath.Match COPY復(fù)制新文件或者目錄從 并且添加到容器指定路徑中 。用法同ADD,唯一的不同是不能指定遠(yuǎn)程文件 URLS。 配置容器啟動后執(zhí)行的命令,并且不可被 docker run 提供的參數(shù)覆蓋,而CMD是可以被覆蓋的。如果需要覆蓋,則可以使用docker run --entrypoint選項(xiàng)。 每個 Dockerfile 中只能有一個ENTRYPOINT,當(dāng)指定多個時,只有最后一個生效。 通過ENTRYPOINT使用 exec form 方式設(shè)置穩(wěn)定的默認(rèn)命令和選項(xiàng),而使用CMD添加默認(rèn)之外經(jīng)常被改動的選項(xiàng)。 通過 Dockerfile 使用ENTRYPOINT展示前臺運(yùn)行 Apache 服務(wù) 這種方式會在/bin/sh -c中執(zhí)行,會忽略任何CMD或者docker run命令行選項(xiàng),為了確保docker stop能夠停止長時間運(yùn)行ENTRYPOINT的容器,確保執(zhí)行的時候使用exec選項(xiàng)。 如果在ENTRYPOINT忘記使用exec選項(xiàng),則可以使用CMD補(bǔ)上: 創(chuàng)建一個可以從本地主機(jī)或其他容器掛載的掛載點(diǎn),后續(xù)具體介紹。 指定運(yùn)行容器時的用戶名或 UID,后續(xù)的RUN、CMD、ENTRYPOINT也會使用指定用戶。 為后續(xù)的RUN、CMD、ENTRYPOINT指令配置工作目錄??梢允褂枚鄠€WORKDIR指令,后續(xù)命令如果參數(shù)是相對路徑,則會基于之前命令指定的路徑。 最終路徑是/a/b/c。 WORKDIR指令可以在ENV設(shè)置變量之后調(diào)用環(huán)境變量: 最終路徑則為 /path/$DIRNAME。 配置當(dāng)所創(chuàng)建的鏡像作為其它新創(chuàng)建鏡像的基礎(chǔ)鏡像時,所執(zhí)行的操作指令。 例如,Dockerfile 使用如下的內(nèi)容創(chuàng)建了鏡像 image-A: 如果基于 image-A 創(chuàng)建新的鏡像時,新的 Dockerfile 中使用 FROM image-A 指定基礎(chǔ)鏡像時,會自動執(zhí)行 ONBUILD 指令內(nèi)容,等價于在后面添加了兩條指令。 使用ONBUILD指令的鏡像,推薦在標(biāo)簽中注明,例如 ruby:1.9-onbuild。 參考文檔:Dockerfile Reference 為了在docker build過程中更快上傳和更加高效,應(yīng)該使用一個.dockerignore文件用來排除構(gòu)建鏡像時不需要的文件或目錄。例如,除非.git在構(gòu)建過程中需要用到,否則你應(yīng)該將它添加到.dockerignore文件中,這樣可以節(jié)省很多時間。 為了降低復(fù)雜性、依賴性、文件大小以及構(gòu)建時間,應(yīng)該避免安裝額外的或不必要的包。例如,不需要在一個數(shù)據(jù)庫鏡像中安裝一個文本編輯器。 在大多數(shù)情況下,一個容器應(yīng)該只單獨(dú)跑一個程序。解耦應(yīng)用到多個容器使其更容易橫向擴(kuò)展和重用。如果一個服務(wù)依賴另外一個服務(wù),可以參考 Linking Containers Together。 我們知道每執(zhí)行一個指令,都會有一次鏡像的提交,鏡像是分層的結(jié)構(gòu),對于Dockerfile,應(yīng)該找到可讀性和最小化層之間的平衡。 如果可能,通過字母順序來排序,這樣可以避免安裝包的重復(fù)并且更容易更新列表,另外可讀性也會更強(qiáng),添加一個空行使用\換行: 鏡像構(gòu)建過程中會按照Dockerfile的順序依次執(zhí)行,每執(zhí)行一次指令 Docker 會尋找是否有存在的鏡像緩存可復(fù)用,如果沒有則創(chuàng)建新的鏡像。如果不想使用緩存,則可以在docker build時添加--no-cache=true選項(xiàng)。 從基礎(chǔ)鏡像開始就已經(jīng)在緩存中了,下一個指令會對比所有的子鏡像尋找是否執(zhí)行相同的指令,如果沒有則緩存失效。在大多數(shù)情況下只對比Dockerfile指令和子鏡像就足夠了。ADD和COPY指令除外,執(zhí)行ADD和COPY時存放到鏡像的文件也是需要檢查的,完成一個文件的校驗(yàn)之后再利用這個校驗(yàn)在緩存中查找,如果檢測的文件改變則緩存失效。RUN apt-get -y update命令只檢查命令是否匹配,如果匹配就不會再執(zhí)行更新了。 為了有效地利用緩存,你需要保持你的 Dockerfile 一致,并且盡量在末尾修改。 例子: ENV也可以這樣定義變量: 如不推薦這種方式: 推薦使用 curl 或者 wget 替換,使用如下方式: 如果不需要添加 tar 文件,推薦使用COPY。 參考文檔: docker管理數(shù)據(jù)的方式有兩種: 數(shù)據(jù)卷是一個或多個容器專門指定繞過Union File System的目錄,為持續(xù)性或共享數(shù)據(jù)提供一些有用的功能: 你可以使用-v選項(xiàng)添加一個數(shù)據(jù)卷,或者可以使用多次-v選項(xiàng)為一個 docker 容器運(yùn)行掛載多個數(shù)據(jù)卷。 創(chuàng)建的數(shù)據(jù)卷可以通過docker inspect獲取宿主機(jī)對應(yīng)路徑 或者直接指定獲取 -v選項(xiàng)除了可以創(chuàng)建卷,也可以掛載當(dāng)前主機(jī)的一個目錄到容器中。 默認(rèn)掛載卷是可讀寫的,可以在掛載時指定只讀 如果你有一些持久性的數(shù)據(jù)并且想在容器間共享,或者想用在非持久性的容器上,最好的方法是創(chuàng)建一個數(shù)據(jù)卷容器,然后從此容器上掛載數(shù)據(jù)。 創(chuàng)建數(shù)據(jù)卷容器 使用--volumes-from選項(xiàng)在另一個容器中掛載 /test 卷。不管 test 容器是否運(yùn)行,其它容器都可以掛載該容器數(shù)據(jù)卷,當(dāng)然如果只是單獨(dú)的數(shù)據(jù)卷是沒必要運(yùn)行容器的。 添加另一個容器 也可以繼承其它掛載有 /test 卷的容器 啟動一個新的容器并且從test容器中掛載卷,然后掛載當(dāng)前目錄到容器中為 backup,并備份 test 卷中所有的數(shù)據(jù)為 test.tar,執(zhí)行完成之后刪除容器--rm,此時備份就在當(dāng)前的目錄下,名為test.tar。 你可以恢復(fù)給同一個容器或者另外的容器,新建容器并解壓備份文件到新的容器數(shù)據(jù)卷 Volume 只有在下列情況下才能被刪除: 否則,會在/var/lib/docker/vfs/dir目錄中遺留很多不明目錄。 參考文檔: docker 允許把多個容器連接在一起,相互交互信息。docker 鏈接會創(chuàng)建一種容器父子級別的關(guān)系,其中父容器可以看到其子容器提供的信息。 在創(chuàng)建容器時,如果不指定容器的名字,則默認(rèn)會自動創(chuàng)建一個名字,這里推薦給容器命名: 可以通過--name選項(xiàng)給容器自定義命名: 注:容器名稱必須唯一,即你只能命名一個叫test的容器。如果你想復(fù)用容器名,則必須在創(chuàng)建新的容器前通過docker rm刪除舊的容器或者創(chuàng)建容器時添加--rm選項(xiàng)。 鏈接允許容器間安全通信,使用--link選項(xiàng)創(chuàng)建鏈接。 基于 training/postgres 鏡像創(chuàng)建一個名為 db 的容器,然后下面創(chuàng)建一個叫做 web 的容器,并且將它與 db 相互連接在一起 --link 查看 web 容器的鏈接關(guān)系: 可以看到 web 容器被鏈接到 db 容器為/web/db,這允許 web 容器訪問 db 容器的信息。 容器之間的鏈接實(shí)際做了什么?一個鏈接允許一個源容器提供信息訪問給一個接收容器。在本例中,web 容器作為一個接收者,允許訪問源容器 db 的相關(guān)服務(wù)信息。Docker 創(chuàng)建了一個安全隧道而不需要對外公開任何端口給外部容器,因此不需要在創(chuàng)建容器的時候添加-p或-P指定對外公開的端口,這也是鏈接容器的最大好處,本例為 PostgreSQL 數(shù)據(jù)庫。 Docker 主要通過以下兩個方式提供連接信息給接收容器: 當(dāng)兩個容器鏈接,Docker 會在目標(biāo)容器上設(shè)置一些環(huán)境變量,以獲取源容器的相關(guān)信息。 首先,Docker 會在每個通過--link選項(xiàng)指定別名的目標(biāo)容器上設(shè)置一個 以之前的為例,Docker 還會設(shè)置端口變量: 注:這些環(huán)境變量只設(shè)置給容器中的第一個進(jìn)程,類似一些守護(hù)進(jìn)程 (如 sshd ) 當(dāng)他們派生 shells 時會清除這些變量 除了環(huán)境變量,Docker 會在目標(biāo)容器上添加相關(guān)主機(jī)條目到/etc/hosts中,上例中就是 web 容器。 /etc/host文件在源容器被重啟之后會自動更新 IP 地址,而環(huán)境變量中的 IP 地址則不會自動更新的。 Docker 官方提供了 docker registry 的構(gòu)建方法 docker-registry 快速構(gòu)建 docker registry 通過以下兩步: 這種方法通過 Docker hub 使用官方鏡像 official image from the Docker hub 或者 使用 github clone 手動安裝 使用gunicorn控制: 或者對外監(jiān)聽開放 更多的配置選項(xiàng)推薦閱讀官方文檔: |
|