docker in all
docker vs hyper-v,vmware,xen,kvm
docker host, docker container, docker engineen, docker image
images = stopped container
container = running images
?
docker操作示意圖
workflow
?
開(kāi)始使用docker(以windows下為例)
PS G:\dockerdata> docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 1b930d010525: Pull complete Digest: sha256:2557e3c07ed1e38f26e389462d03ed943586f744621577a99efb77324b0fe535 Status: Downloaded newer image for hello-world:latestHello from Docker! This message shows that your installation appears to be working correctly.To generate this message, Docker took the following steps:1. The Docker client contacted the Docker daemon.2. The Docker daemon pulled the "hello-world" image from the Docker Hub.(amd64)3. The Docker daemon created a new container from that image which runs theexecutable that produces the output you are currently reading.4. The Docker daemon streamed that output to the Docker client, which sent itto your terminal.To try something more ambitious, you can run an Ubuntu container with:$ docker run -it ubuntu bashShare images, automate workflows, and more with a free Docker ID:https://hub.docker.com/ For more examples and ideas, visit:https://docs.docker.com/get-started/PS G:\dockerdata> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest fce289e99eb9 2 months ago 1.84kB
docker4w/nsenter-dockerd latest 2f1c802f322f 4 months ago 187kB
?
?以上docker run hello-world命令本質(zhì)上的執(zhí)行過(guò)程:
1. docker client向docker daemon(engine)聯(lián)絡(luò),告訴docker engine,請(qǐng)幫我運(yùn)行一個(gè)hello-wold container
2. docker daemon(engine)收到該命令后先在本地查找是否有hello-world這個(gè)image,如果沒(méi)有則從regisry查找并且pull下來(lái)
3. docker daemon以該image實(shí)例化一個(gè)container,并且運(yùn)行該image定義的executable,而這個(gè)executable將產(chǎn)生output;
4. docker daemon streamed that output to the docker client,這樣我們就看到了hello world的消息
docker image到底包含了什么?
強(qiáng)烈建議:?https://www.csdn.net/article/2015-08-21/2825511
我們知道linux系統(tǒng)由內(nèi)核+發(fā)行版組成,同樣的內(nèi)核比如3.8之上,我們可以有debian, ubuntu, centos等不同的發(fā)行版本。類似地,Docker鏡像就是類似于“ubuntu操作系統(tǒng)發(fā)行版”,可 以在任何滿足要求的Linux內(nèi)核之上運(yùn)行。簡(jiǎn)單一點(diǎn)有“Debian操作系統(tǒng)發(fā)行版”Docker鏡像、“Ubuntu操作系統(tǒng)發(fā)行版”Docker鏡 像;如果在Debian鏡像中安裝MySQL 5.6,那我們可以將其命名為Mysql:5.6鏡像;如果在Debian鏡像中安裝有Golang 1.3,那我們可以將其命名為golang:1.3鏡像;以此類推,大家可以根據(jù)自己安裝的軟件,得到任何自己想要的鏡像。
修改默認(rèn)pull image存放位置
在windows下本質(zhì)上docker engine是工作在hyper-v虛擬機(jī)中,所有的docker客戶端敲的命令在該虛擬機(jī)中運(yùn)行,pull的image也放在該虛擬機(jī)中,因此我們要修改image保存的位置實(shí)際上只要修改hyper-v的MobyLinuxVM對(duì)應(yīng)的vhdx文件的位置即可。
http://www.cnblogs.com/show668/p/5341283.html
?docker ps/docker images
PS G:\dockerdata> docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest fce289e99eb9 2 months ago 1.84kB docker4w/nsenter-dockerd latest 2f1c802f322f 4 months ago 187kB PS G:\dockerdata> docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES PS G:\dockerdata> docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 135da1372a06 hello-world "/hello" 24 minutes ago Exited (0) 24 minutes ago modest_spence?pull特定版本的image
docker pull ubuntu:14.04
Repository:是對(duì)一個(gè)docker image的存儲(chǔ)定義
將docker hub mirror配置為阿里云加速器
刪除本地的image
PS G:\dockerdata> docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest 47b19964fb50 3 weeks ago 88.1MB alpine latest caf27325b298 4 weeks ago 5.53MB hello-world latest fce289e99eb9 2 months ago 1.84kB docker4w/nsenter-dockerd latest 2f1c802f322f 4 months ago 187kB PS G:\dockerdata> docker rmi ubuntu Untagged: ubuntu:latest Untagged: ubuntu@sha256:7a47ccc3bbe8a451b500d2b53104868b46d60ee8f5b35a24b41a86077c650210 Deleted: sha256:47b19964fb500f3158ae57f20d16d8784cc4af37c52c49d3b4f5bc5eede49541 Deleted: sha256:d4c69838355b876cd3eb0d92b4ef27b1839f5b094a4eb1ad2a1d747dd5d6088f Deleted: sha256:1c29a32189d8f2738d0d99378dc0912c9f9d289b52fb698bdd6c1c8cd7a33727 Deleted: sha256:d801a12f6af7beff367268f99607376584d8b2da656dcd8656973b7ad9779ab4 Deleted: sha256:bebe7ce6215aee349bee5d67222abeb5c5a834bbeaa2f2f5d05363d9fd68db41docker run detached mode啟動(dòng)一個(gè)web服務(wù)
PS G:\dockerdata> docker run -d --name web -p 9090:8080 nigelpoulton/pluralsight-docker-ci Unable to find image 'nigelpoulton/pluralsight-docker-ci:latest' locally latest: Pulling from nigelpoulton/pluralsight-docker-ci a3ed95caeb02: Pull complete 3b231ed5aa2f: Pull complete 7e4f9cd54d46: Pull complete 929432235e51: Pull complete 6899ef41c594: Pull complete 0b38fccd0dab: Pull complete Digest: sha256:7a6b0125fe7893e70dc63b2c42ad779e5866c6d2779ceb9b12a28e2c38bd8d3d Status: Downloaded newer image for nigelpoulton/pluralsight-docker-ci:latest 27b4bc07a3e299e738ea8fc05bb6de9fa160c192a5ab71886b84e432d5422aea #這就是docker host主機(jī)上面的container id PS G:\dockerdata> docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
27b4bc07a3e2 nigelpoulton/pluralsight-docker-ci "/bin/sh -c 'cd /src…" 4 minutes ago Up 4 minutes 0.0.0.0:9090->8080/tcp web
上面的命令執(zhí)行后將在docker host主機(jī)上啟動(dòng)一個(gè)web服務(wù)器,使用http://localhost:9090就可以直接訪問(wèn)到該container的服務(wù)了!!
啟動(dòng)一個(gè)container并且在該container中執(zhí)行bash
PS G:\dockerdata> docker run -it --name temp ubuntu:latest /bin/bash Unable to find image 'ubuntu:latest' locally latest: Pulling from library/ubuntu 6cf436f81810: Pull complete 987088a85b96: Pull complete b4624b3efe06: Pull complete d42beb8ded59: Pull complete Digest: sha256:7a47ccc3bbe8a451b500d2b53104868b46d60ee8f5b35a24b41a86077c650210 Status: Downloaded newer image for ubuntu:latest root@9b4970dcb02a:/# ls bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var簡(jiǎn)單批量維護(hù)命令:
PS G:\dockerdata> docker ps -aq 9b4970dcb02a 27b4bc07a3e2 135da1372a06 PS G:\dockerdata> docker stop $(docker ps -aq) 9b4970dcb02a 27b4bc07a3e2 135da1372a06?
swarm:
一群docker engines加入一個(gè)cluster分組就被稱為swarm, a cluster = a swarm
swarm里面的engine工作于swarm mode
manager nodes維護(hù)swarm,
worker nodes 執(zhí)行manager nodes分發(fā)過(guò)來(lái)的tasks
services: declarative/scalable
tasks: assigned to worker nodes ,means? ~ containers? currently
docker swarm init --advertise-addr xxx:2377 --listen-addr xxx:2377 # engine port 2375, secure engine port: 2376, swarm port: 2377 docker service create --name web-fe --replicas 5 ...?
Container
container is isolated area of an OS with resource usage limits applied.
它由name space和control group(限定cpu,ram,networking吞吐量,io吞吐量)約束形成的獨(dú)立運(yùn)行環(huán)境。
engine?
engine通過(guò)外部api接受命令負(fù)責(zé)屏蔽OS的namespace及cgroup,并且創(chuàng)建對(duì)應(yīng)的container運(yùn)行于host環(huán)境中
不同module協(xié)同工作實(shí)現(xiàn)的container運(yùn)行過(guò)程
一旦container被啟動(dòng)運(yùn)行后,containerd和它之間就可以沒(méi)有了關(guān)系,以后可以通過(guò)發(fā)現(xiàn)過(guò)程來(lái)取得新的聯(lián)系
image
image包含app運(yùn)行所需的
1.OS Files library, objects;
2. app files
3. manifest-->定義這些文件是如何組織在一起工作的
image是層疊結(jié)構(gòu)的文件系統(tǒng).
docker image pull redis的工作分兩步:第一步從registry這里獲取到manifest文件;第二步pull layers
?
docker history redis # 羅列出所有能夠創(chuàng)建redis這個(gè)image的命令列表 $ docker image inspect redis [{"Id": "sha256:0f55cf3661e92cc44014f9d93e6f7cbd2a59b7220a26edcdb0828289cf6a361f","RepoTags": ["redis:latest"],"RepoDigests": ["redis@sha256:dd5b84ce536dffdcab79024f4df5485d010affa09e6c399b215e199a0dca38c4"],"Parent": "","Comment": "","Created": "2019-02-06T09:02:43.375297494Z","Container": "1abd8103d4a4423fa8339aabdb3442026bf6b8e9dca21c4ed44973e73ffd90cf","ContainerConfig": {"Hostname": "1abd8103d4a4","Domainname": "","User": "","AttachStdin": false,"AttachStdout": false,"AttachStderr": false,"ExposedPorts": {"6379/tcp": {}},"Tty": false,"OpenStdin": false,"StdinOnce": false,"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","GOSU_VERSION=1.10","REDIS_VERSION=5.0.3","REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-5.0.3.tar.gz","REDIS_DOWNLOAD_SHA=e290b4ddf817b26254a74d5d564095b11f9cd20d8f165459efa53eb63cd93e02"],"Cmd": ["/bin/sh","-c","#(nop) ","CMD [\"redis-server\"]"],"ArgsEscaped": true,"Image": "sha256:68d73e8c5e2090bf28a588569b92595ab2d60e38eb92ba968be552b496eb6ed3","Volumes": {"/data": {}},"WorkingDir": "/data","Entrypoint": ["docker-entrypoint.sh"],"OnBuild": null,"Labels": {}},"DockerVersion": "18.06.1-ce","Author": "","Config": {"Hostname": "","Domainname": "","User": "","AttachStdin": false,"AttachStdout": false,"AttachStderr": false,"ExposedPorts": {"6379/tcp": {}},"Tty": false,"OpenStdin": false,"StdinOnce": false,"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","GOSU_VERSION=1.10","REDIS_VERSION=5.0.3","REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-5.0.3.tar.gz","REDIS_DOWNLOAD_SHA=e290b4ddf817b26254a74d5d564095b11f9cd20d8f165459efa53eb63cd93e02"],"Cmd": ["redis-server"],"ArgsEscaped": true,"Image": "sha256:68d73e8c5e2090bf28a588569b92595ab2d60e38eb92ba968be552b496eb6ed3","Volumes": {"/data": {}},"WorkingDir": "/data","Entrypoint": ["docker-entrypoint.sh"],"OnBuild": null,"Labels": null},"Architecture": "amd64","Os": "linux","Size": 94993858,"VirtualSize": 94993858,"GraphDriver": {"Data": {"LowerDir": "/var/lib/docker/overlay2/1aeb385f6b9def8e0c2048213c6a68446b233f4d44c9230657859257505dace5/diff:/var/lib/docker/overlay2/5e8dc35e2ed45cee79a8b5108cc74bfe7000311e75db45bd83d254f21e1892e7/diff:/var/lib/docker/overlay2/bfb61b0335946076ea36f25716da9e43d133dd6e8cf0211e7abadb6a23c001f3/diff:/var/lib/docker/overlay2/591b4074f127d18d3b7d84078891e464eb9c808439bd70f78f653ece9fa1101e/diff:/var/lib/docker/overlay2/30c283b2c4910e51dc162b23d6344575697e9fb478aeccf330edcef05c90aeae/diff","MergedDir": "/var/lib/docker/overlay2/358068125c47e5995e7b1308b71a7ba11dd1509a9a69b36c1495e5c23a5c71f0/merged","UpperDir": "/var/lib/docker/overlay2/358068125c47e5995e7b1308b71a7ba11dd1509a9a69b36c1495e5c23a5c71f0/diff","WorkDir": "/var/lib/docker/overlay2/358068125c47e5995e7b1308b71a7ba11dd1509a9a69b36c1495e5c23a5c71f0/work"},"Name": "overlay2"},"RootFS": {"Type": "layers","Layers": ["sha256:0a07e81f5da36e4cd6c89d9bc3af643345e56bb2ed74cc8772e42ec0d393aee3","sha256:943fb767d8100f2c44a54abbdde4bf2c0f6340da71125f4ef73ad2db7007841d","sha256:16d37f04beb4896e44557df69c060fc93e1486391c4c3dedf3c6ebd773098d90","sha256:5e1afad325f9c970c66dcc5db47d19f034691f29492bf2fe83b7fec680a9d122","sha256:d98df0140af1ee738e8987862268e80074503ab33212f6ebe253195b0f461a43","sha256:b437bb5668d3cd5424015d7b7aefc99332c4af3530b17367e6d9d067ce9bb6d5"]},"Metadata": {"LastTagTime": "0001-01-01T00:00:00Z"}} ]docker支持的網(wǎng)絡(luò)模式
bridge模式: -net = bridge
這是默認(rèn)網(wǎng)絡(luò),docker engine一旦啟動(dòng)后就會(huì)在宿主host上創(chuàng)建一個(gè)docker0的網(wǎng)橋(可以理解為switch),默認(rèn)創(chuàng)建的容器都是添加到該網(wǎng)橋(switch)的網(wǎng)段中,可以想象這些容器就是連接在一個(gè)交換機(jī)的不同網(wǎng)口上,他們的網(wǎng)關(guān)就是docker0的ip(172.17.0.1)
host模式: -net = host
容器不會(huì)獲得獨(dú)立的network namespace,而是與宿主host主機(jī)共用一個(gè),這也意味著container不會(huì)擁有自己的網(wǎng)卡信息,而是使用宿主機(jī)的。host模式的容器之間除了網(wǎng)絡(luò),其他都是隔離的。
none模式: -net = none
容器將獲取獨(dú)立的network namespace,但是不會(huì)為容器進(jìn)行任何網(wǎng)絡(luò)配置,需要我們自己去手工配置
container模式: -net = container:Name/ID
這種模式創(chuàng)建的容器將與指定的容器使用同一個(gè)network namespace,具有同樣的網(wǎng)絡(luò)配置信息,這種容器之間除了網(wǎng)絡(luò),其他都是隔離的。
自定義網(wǎng)絡(luò)模式:
與默認(rèn)的bridge原理一樣,但自定義網(wǎng)絡(luò)內(nèi)部具備dns發(fā)現(xiàn)的能力,可以通過(guò)容器名或者主機(jī)名容器之間網(wǎng)絡(luò)通信
docker logs通過(guò)查看容器log來(lái)定位調(diào)試問(wèn)題
默認(rèn)情況下docker logs和ldocker service logs命令顯示命令執(zhí)行的輸出,就像是你在命令行直接執(zhí)行該程序時(shí)的情形一樣。unix和linux程序往往會(huì)打開(kāi)三個(gè)I/O Streams,分別稱為STDIN,STDOUT,STDERR。其中stdin是命令的input stream, 可以包含從鍵盤獲得的input或者從其他命令的輸出作為input; stdout是應(yīng)用程序的normal output.而stderr則被用于錯(cuò)誤信息輸出。默認(rèn)情況下,docker logs將顯示命令的stdout和stderr輸出。基于以上信息,在多重場(chǎng)景下docker logs無(wú)法提供有效的log:
1. 如果你使用了一個(gè)logging driver(logging driver是docker提供的從運(yùn)行的container或者service中獲取有用信息的機(jī)制)將log發(fā)往一個(gè)文件,或者一個(gè)外部的主機(jī),一個(gè)數(shù)據(jù)庫(kù)或者其他的logging back-end,那么docker logs將不會(huì)顯示任何有用的信息;
https://docs.docker.com/config/containers/logging/configure/
docker daemon有一個(gè)默認(rèn)的logging driver,每個(gè)啟動(dòng)的容器都將使用它除非你配置了使用一個(gè)不同的logging driver.
比如,我們可以配置docker daemon使用syslog來(lái)做log的收集,他就會(huì)通過(guò)syslog將運(yùn)行容器的stdout,stderr信息實(shí)時(shí)打印到遠(yuǎn)程服務(wù)器。在這種情況下,我們實(shí)際上就不可能使用docker logs來(lái)查看運(yùn)行時(shí)的狀態(tài),而只能通過(guò)syslog服務(wù)器來(lái)獲取信息;
2. 如果我們的image運(yùn)行在non-interactive 進(jìn)程中,比如web server或者database的進(jìn)程,這種進(jìn)程會(huì)將其輸出信息直接送往log文件,而不是stdout或者stderr.
在這種情況下,我們一方面可以進(jìn)入容器來(lái)查看類似nginx和myql的log文件獲取運(yùn)行時(shí)信息;另外一方面官方的nginx,httpd都提供了workaround方式,比如nginx image的構(gòu)建中通過(guò)創(chuàng)建一個(gè)符號(hào)連接將 /var/log/nginx/access.log指向到/dev/stdout; 將/var/log/nginx/error.log指向到/dev/stderr的方式來(lái)解決。 httpd image則默認(rèn)輸出到/proc/self/fd/1 (stdout),? error則將寫往 /proc/self/fd/2(stderr)
這樣我們依然可以通過(guò)docker logs -tail 8 -f來(lái)實(shí)時(shí)查看log
docker networking
https://success.docker.com/article/networking
建議使用自定義網(wǎng)絡(luò),docker默認(rèn)的docker0 bridge支持--link參數(shù),但是--link參數(shù)將來(lái)也會(huì)廢棄。
$ brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242bd712cd8 no br-9694b511a9af 8000.0242e7c72a3d no br-81195db0babc 8000.0242d6feb257 no veth375600fvethbc86c59 br-c301fa0c30d5 8000.024241d93a8e no veth73040a3veth72eebcevethd5af9cdveth12d8ab4veth6d89a9d咱們來(lái)看一下使用laradock docker-compose up -d nginx mysql之后的網(wǎng)絡(luò)拓補(bǔ)圖分析過(guò)程:
$ brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242bd712cd8 no br-9694b511a9af 8000.0242e7c72a3d no br-81195db0babc 8000.0242d6feb257 no veth375600fvethbc86c59 br-c301fa0c30d5 8000.024241d93a8e no veth73040a3veth72eebcevethd5af9cdveth12d8ab4veth6d89a9d [node1] (local) root@192.168.0.13 ~/apiato/laradock $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 25dd9253f860 laradock_nginx "/bin/bash /opt/star…" 2 hours ago Up 2 hours 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp laradock_nginx_1 a2070a01035c laradock_php-fpm "docker-php-entrypoi…" 2 hours ago Up 2 hours 9000/tcp laradock_php-fpm_1 d1f9327cb61c laradock_workspace "/sbin/my_init" 2 hours ago Up 2 hours 0.0.0.0:2222->22/tcp laradock_workspace_1 a70f2b180a0d laradock_mysql "docker-entrypoint.s…" 2 hours ago Up 2 hours 0.0.0.0:3306->3306/tcp, 33060/tcp laradock_mysql_1 01f438a6efa9 docker:dind "dockerd-entrypoint.…" 2 hours ago Up 2 hours 2375/tcp laradock_docker-in-docker_1 [node1] (local) root@192.168.0.13 ~/apiato/laradock $ [node1] (local) root@192.168.0.13 ~/apiato/laradock $ [node1] (local) root@192.168.0.13 ~/apiato/laradock $ [node1] (local) root@192.168.0.13 ~/apiato/laradock $ [node1] (local) root@192.168.0.13 ~/apiato/laradock $ docker network ls NETWORK ID NAME DRIVER SCOPE 60e8d0d3dd8c bridge bridge local 5130e0e1e134 host host local c301fa0c30d5 laradock_backend bridge local 9694b511a9af laradock_default bridge local 81195db0babc laradock_frontend bridge local cb098f68c7be none null local [node1] (local) root@192.168.0.13 ~/apiato/laradock $ brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242bd712cd8 no br-9694b511a9af 8000.0242e7c72a3d no br-81195db0babc 8000.0242d6feb257 no veth375600fvethbc86c59 br-c301fa0c30d5 8000.024241d93a8e no veth73040a3veth72eebcevethd5af9cdveth12d8ab4veth6d89a9d [node1] (local) root@192.168.0.13 ~/apiato/laradock $ docker network inspect c301 [{"Name": "laradock_backend","Id": "c301fa0c30d5f44e8daab0ffecf8166012f63edee764ce2abeaf3e884ce54446","Created": "2019-03-13T12:25:42.645372888Z","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": null,"Config": [{"Subnet": "172.21.0.0/16","Gateway": "172.21.0.1"}]},"Internal": false,"Attachable": true,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {"01f438a6efa996b4e5c8df8f36b742ae468bf09762a1e6eabdefd66f5c920e11": {"Name": "laradock_docker-in-docker_1","EndpointID": "d01c244fc579cd288bf8b1e79a6e936486b348f3167db3e7034044e08beae44c","MacAddress": "02:42:ac:15:00:02","IPv4Address": "172.21.0.2/16","IPv6Address": ""},"25dd9253f860588321b1ff05ae4b43226ae6c22f83044973b86c0c57871ed924": {"Name": "laradock_nginx_1","EndpointID": "24b527973345960c10bf2f97a11612c33562a5146732e9c4049625fc99cadca8","MacAddress": "02:42:ac:15:00:06","IPv4Address": "172.21.0.6/16","IPv6Address": ""},"a2070a01035cbd8c15005c074e9e19ea18f795cdf6a2bc48863d86cc638b35b5": {"Name": "laradock_php-fpm_1","EndpointID": "b3071a2d3d019a6e10b0b778ce0b4f99efbaff28898d295d3829d41e840aa15c","MacAddress": "02:42:ac:15:00:05","IPv4Address": "172.21.0.5/16","IPv6Address": ""},"a70f2b180a0dfcc18c26e4991897946b9389b678ce4ea2cd6527859c301bb78e": {"Name": "laradock_mysql_1","EndpointID": "815e801431b16f4a245b0a243e08cc9642482b3933b09480928ae40fadd56b14","MacAddress": "02:42:ac:15:00:03","IPv4Address": "172.21.0.3/16","IPv6Address": ""},"d1f9327cb61cbd26f43c55911cbffa1cd3f53b912f783725bbf73e0c6edad5ef": {"Name": "laradock_workspace_1","EndpointID": "5bbe5ceae7d15ff3eb65236ab0243619591d69474f3a0a13df07e507d2e25a22","MacAddress": "02:42:ac:15:00:04","IPv4Address": "172.21.0.4/16","IPv6Address": ""}},"Options": {},"Labels": {"com.docker.compose.network": "backend","com.docker.compose.project": "laradock","com.docker.compose.version": "1.23.2"}} ] [node1] (local) root@192.168.0.13 ~/apiato/laradock $ docker network inspect 8119 [{"Name": "laradock_frontend","Id": "81195db0babc4aff1b4ae09b2ad078038b74643c798b396409a46f2948ff89c8","Created": "2019-03-13T12:25:42.057604176Z","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": null,"Config": [{"Subnet": "172.20.0.0/16","Gateway": "172.20.0.1"}]},"Internal": false,"Attachable": true,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {"25dd9253f860588321b1ff05ae4b43226ae6c22f83044973b86c0c57871ed924": {"Name": "laradock_nginx_1","EndpointID": "e1ad08b19608cc3884a9da04e509a71566ca4847245db12310d77463bcb80814","MacAddress": "02:42:ac:14:00:03","IPv4Address": "172.20.0.3/16","IPv6Address": ""},"d1f9327cb61cbd26f43c55911cbffa1cd3f53b912f783725bbf73e0c6edad5ef": {"Name": "laradock_workspace_1","EndpointID": "64d65215f6e0d6135bb7dbf5f341bd858972bc8e869cd8a177991d27d5652491","MacAddress": "02:42:ac:14:00:02","IPv4Address": "172.20.0.2/16","IPv6Address": ""}},"Options": {},"Labels": {"com.docker.compose.network": "frontend","com.docker.compose.project": "laradock","com.docker.compose.version": "1.23.2"}} ] [node1] (local) root@192.168.0.13 ~/apiato/laradock $ docker network inspect 9694 [{"Name": "laradock_default","Id": "9694b511a9afac9a43d3b45ae4296976bf193633148465141f5e0cd787b12082","Created": "2019-03-13T12:25:41.924774946Z","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": null,"Config": [{"Subnet": "172.19.0.0/16","Gateway": "172.19.0.1"}]},"Internal": false,"Attachable": true,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {},"Options": {},"Labels": {"com.docker.compose.network": "default","com.docker.compose.project": "laradock","com.docker.compose.version": "1.23.2"}} ] [node1] (local) root@192.168.0.13 ~/apiato/laradock $ docker network inspect 5130 [{"Name": "host","Id": "5130e0e1e1340fb58d5704528257cfb0f7dc98e9f718055c3e32f96705355597","Created": "2019-03-13T12:23:30.472608001Z","Scope": "local","Driver": "host","EnableIPv6": false,"IPAM": {"Driver": "default","Options": null,"Config": []},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {},"Options": {},"Labels": {}} ] [node1] (local) root@192.168.0.13 ~/apiato/laradock $ docker network inspect 60e8 [{"Name": "bridge","Id": "60e8d0d3dd8c376a31a802f9965227301dc06a74910852895f9b010d07fd4417","Created": "2019-03-13T12:23:30.540268336Z","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": null,"Config": [{"Subnet": "172.17.0.0/16"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {},"Options": {"com.docker.network.bridge.default_bridge": "true","com.docker.network.bridge.enable_icc": "true","com.docker.network.bridge.enable_ip_masquerade": "true","com.docker.network.bridge.host_binding_ipv4": "0.0.0.0","com.docker.network.bridge.name": "docker0","com.docker.network.driver.mtu": "1500"},"Labels": {}} ]關(guān)于環(huán)境變量env
https://vsupalov.com/docker-arg-env-variable-guide/
關(guān)于volumes
https://docs.docker.com/storage/volumes/
如果我們不需要永久持久化,但是又需要在運(yùn)行時(shí)保存一些狀態(tài)信息,可以考慮使用tmpfs mount直接mount到內(nèi)存中,加快速度。
?
容器中進(jìn)程啟動(dòng)的兩種模式:shell模式和exec模式
docker容器內(nèi)啟動(dòng)的所有進(jìn)程全部都是宿主機(jī)上的獨(dú)立進(jìn)程;另外,該進(jìn)程是不是docker容器進(jìn)程本身(即:1號(hào)進(jìn)程)取決于dockerfile的寫法。
在ENTRYPOINT和CMD命令中,有兩種不同的進(jìn)程執(zhí)行方式:shell和exec.
1.在shell方式中,CMD/ENTRYPOINT指令如下方式定義
CMD executable param1 param2此時(shí)PID=1的進(jìn)程為/bin/sh -c "executable param1 param2",真正的executable工作進(jìn)程是其子進(jìn)程
2.在exec方式中,CMD/ENTRYPOINT指令則如下方式定義:
CMD ["executable", "param1","param2"]此時(shí)PID=1的進(jìn)程直接是工作進(jìn)程executable param1 param2
這兩種啟動(dòng)模式還帶來(lái)進(jìn)程退出機(jī)制的區(qū)別,如果使用不當(dāng)會(huì)造成僵尸進(jìn)程。
docker提供了docker stop和docker kill兩個(gè)命令向1號(hào)進(jìn)程發(fā)送信號(hào)。當(dāng)執(zhí)行docker stop時(shí),docker會(huì)先想PID1的進(jìn)程發(fā)送一個(gè)SIGTERM信號(hào),如果容器收到該信號(hào)后沒(méi)有結(jié)束進(jìn)程,則docker daemon會(huì)在等待10秒后發(fā)送SIGKILL信號(hào),將容器進(jìn)程殺死(PID1)并變?yōu)橥顺鰻顟B(tài)。
PID1的進(jìn)程必須能夠正確處理SIGTERM信號(hào)并通知所有子進(jìn)程退出。如果用shell腳本啟動(dòng)容器,其1號(hào)進(jìn)程為shell進(jìn)程,而shell進(jìn)程中并沒(méi)有對(duì)SIGTERM信號(hào)的處理邏輯,因此會(huì)忽略接收到的SIGTERM信號(hào),這樣就無(wú)法實(shí)現(xiàn)優(yōu)雅的退出(比如持久化數(shù)據(jù)),因此docker官方建議的模式是:令每個(gè)容器中只包含一個(gè)進(jìn)程,同時(shí)采用exec模式啟動(dòng)進(jìn)程。或者使用定制化shell腳本啟動(dòng),需要能夠接受SIGTERM信號(hào)并且分發(fā)該信號(hào)到所有的子進(jìn)程,或者工作進(jìn)程以exec方式啟動(dòng),同時(shí)該工作進(jìn)程能夠處理SIGTERM并負(fù)責(zé)分發(fā)給子進(jìn)程。
docker daemon只監(jiān)控1號(hào)進(jìn)程。
Docker容器的運(yùn)行時(shí)模型
linux中的父進(jìn)程用fork命令創(chuàng)建子進(jìn)程,然后調(diào)用exec執(zhí)行子進(jìn)程函數(shù),每個(gè)進(jìn)程都有一個(gè)PID。另外,除了常見(jiàn)的一般應(yīng)用進(jìn)程,操作系統(tǒng)中還有以下特殊的進(jìn)程。
1. PID=0是調(diào)度進(jìn)程,該進(jìn)程是內(nèi)核的一部分,不會(huì)執(zhí)行磁盤上的任何程序;
2. PID=1為init進(jìn)程,通常讀取與系統(tǒng)有關(guān)的初始化文件/etc/rc*文件,/etc/inittab,/etc/init.d/中的文件
3. PID=2為頁(yè)守護(hù)進(jìn)程,負(fù)責(zé)支持虛擬存儲(chǔ)系統(tǒng)的分頁(yè)操作。
Docker啟動(dòng)時(shí),利用fork命令從Docker-containerd進(jìn)程中fork出一個(gè)子進(jìn)程,然后以exec方式啟動(dòng)自己的程序。容器進(jìn)程被fork之后便創(chuàng)建了namespace,下面就要執(zhí)行一系列的初始化操作,該操作分為三個(gè)階段,dockerinit負(fù)責(zé)初始化網(wǎng)絡(luò)棧;ENTRYPOINT負(fù)責(zé)完成用戶態(tài)配置;CMD負(fù)責(zé)啟動(dòng)入口。啟動(dòng)后的docker容器和docker daemon就通過(guò)sock文件描述符實(shí)現(xiàn)IPC通信。
docker volumes vs binding mount
docker數(shù)據(jù)持久化建議有兩種或者說(shuō)3種模式:
1. bind mounts;
2. named volumes
3. volumes in dockerfile
bind mounts的作用是將host的本地目錄mount到container中,
docker run -v /hostdir:/containerdir IMAGE_NAME docker run --mount type=bind,source=/hostdir,target=/containerdir IMAGE_NAMEnamed volumes是通過(guò)docker volume create volume_name的方式手工創(chuàng)建的volumes,他們都存儲(chǔ)在/var/lib/docker/volumes目錄下,可以僅僅使用volume name來(lái)引用。比如,如果我們創(chuàng)建了mysql_data這個(gè)volume,則可以在docker run -v mysql_data:/containerdata IMAGE_NAME來(lái)引用它。
而在dockerfile中定義的volumes,是使用VOLUME指令來(lái)創(chuàng)建的,他們也存儲(chǔ)于/var/lib/docker/volumes中,但是他們沒(méi)有一個(gè)自定義的名字,一般使用hash作為其名稱,并且dockerfile中定義的volumes后續(xù)參數(shù)實(shí)際上是指定了在container中的路徑,如果在image中已經(jīng)populate了數(shù)據(jù),則container執(zhí)行后會(huì)自動(dòng)將該目錄數(shù)據(jù)copy到host自動(dòng)創(chuàng)建的目錄中(如果指定了host路徑則不會(huì)覆蓋host的數(shù)據(jù)!)
https://stackoverflow.com/questions/41935435/understanding-volume-instruction-in-dockerfile
docker from development to production
一般來(lái)說(shuō),我們?cè)陂_(kāi)發(fā)時(shí)希望通過(guò)一個(gè)volume來(lái)綁定host主機(jī)的source代碼以方便即改即調(diào)的快捷流程,但是在production階段
我們往往直接將代碼復(fù)制到image中從而實(shí)現(xiàn)容器就是代碼,獨(dú)立于主機(jī)可以在任何地點(diǎn)運(yùn)行的便捷。
一個(gè)比較好的策略是
docker-compose.yml中這樣定義:
version: '2' services:app:build: .image: app:1.0.0-testvolumes:- ./host_src:/user/share/nginx/htmlports:- "8080:80"其中nginx app build時(shí)需要使用的Dockerfile可以簡(jiǎn)單定義如下:
FROM nginx COPY host_src /usr/share/nginx/html在nginx app中首先COPY host_src到container對(duì)應(yīng)的目錄中,隨后在dev的compose yml中為方便實(shí)時(shí)修改代碼和測(cè)試則mount了一個(gè)volume將host_src也映射到nginx app中相同目錄下;
隨后,在nginx app變?yōu)閜roduction時(shí),我們可以這樣創(chuàng)建一個(gè)docker-compose-production.yml
version: '2' services:app:build: .image: app:1.0.0-productionports:- "80:80"和dev的yml文件相比,我們僅僅剔除了volume的綁定,而是直接使用COPY到image中的代碼去運(yùn)行
是否可以修改從parent image中繼承的volume data?
比如,A image的dockerfile如下:
FROM bash RUN mkdir "/data" && echo "FOO" > "/data/test" VOLUME "/data"我們?cè)俣x一個(gè)B image,它繼承于A,我們?cè)赿ockerfile中希望修改A image中的“默認(rèn)”數(shù)據(jù):
FROM A RUN echo "BAR" > "/data/test"以上測(cè)試中B image中的/data/test實(shí)際上其值為FOO,并不是BAR
這實(shí)際上是Docker本身的特性使然,如何workaround?
1. 直接修改parent docker file,我們從google搜索以下信息
docker <image-name:version> source
我們就能夠找到對(duì)應(yīng)的父親image的dockerfile,通過(guò)刪除其volume來(lái)實(shí)現(xiàn)。
VOLUMES本身并不是IMAGE的一部分,因此我們需要通過(guò)seed data來(lái)實(shí)現(xiàn)上面的需求。當(dāng)docker image被放到另外地方運(yùn)行時(shí),它將在啟動(dòng)后是一個(gè)空的volume,因此,如果你希望將數(shù)據(jù)和image一起打包,就不要使用volume,而應(yīng)該使用copy.
如果你確實(shí)需要重新build新的image的話,你應(yīng)該先將這個(gè)volume刪除掉。
https://stackoverflow.com/questions/46227454/modifying-volume-data-inherited-from-parent-image
docker volume create$docker run -v /host_path:container_path$VOLUME in Dockerfile
使用volume是docker推薦的持久化數(shù)據(jù)的方式,但是volume的用法有很多種,他們之間到底有什么區(qū)別?
要回答這個(gè)問(wèn)題先得明白"volume是一個(gè)持久化數(shù)據(jù)的目錄,存在于/var/lib/docker/volumes/..."
這個(gè)事實(shí)。你可以:
1. 在Dockerfile中聲明一個(gè)volume,這意味著每次從image中運(yùn)行一個(gè)container時(shí),該volume就將被created,但是確是(empty)空的,即便你并未使用一個(gè)-v參數(shù)在docker run -v命令中
2.你可以在運(yùn)行時(shí)指定mount的volume:
docker run -v [host-dir:]container-dirdocker run -d \--name devtest \--mount source=myvol2,target=/app \ nginx:latest # -v和--mount有相同的效果,如果還不存在myvol2則創(chuàng)建一個(gè)volume到/var/lib/docker/volumes目錄,隨后mount到container中 docker run -d \--name devtest \ -v myvol2:/app \ nginx:latest
這種模式就結(jié)合了VOLUME in dockerfile和docker run -v兩者的優(yōu)點(diǎn),他會(huì)將host folder mount到由container持久化并存儲(chǔ)于/var/lib/docker/volumes/...的卷
3.docker volume create將創(chuàng)建一個(gè)命名式的volume,可以快速被其他容器來(lái)mount
https://stackoverflow.com/questions/34809646/what-is-the-purpose-of-volume-in-dockerfile
docker run -d \-it \--name devtest \--mount type=bind,source="$(pwd)"/target,target=/app \nginx:latest # 等價(jià)于以下命令,bind mount主機(jī)的目錄到target機(jī)器上 docker run -d \-it \--name devtest \-v "$(pwd)"/target:/app \nginx:latest?
dockerfile執(zhí)行順序及變更
1 FROM ubuntu:16.04 2 RUN apt-get update 3 RUN apt-get install nginx 4 RUN apt-get install php5如果上面的dockerfile我們做過(guò)build,隨后我們想把nginx換成apache,并重新build,則這時(shí)候第1和第2行不會(huì)再運(yùn)行,因?yàn)槎急4嬖赾ache中,但是第3和第4行都會(huì)重新執(zhí)行,因?yàn)榈?行做了變更,而第4行又依賴于第3行,因此第3和第4行都將重新執(zhí)行最終構(gòu)建出image
Docker AUFS原理
?
使用docker數(shù)據(jù)容器的備份策略
我們知道在網(wǎng)站日常運(yùn)維中會(huì)有很多數(shù)據(jù)產(chǎn)生,包括數(shù)據(jù)庫(kù)本身,很多配置文件,包括dockerfile, docker-compose等數(shù)據(jù),如何備份這個(gè)數(shù)據(jù)是一個(gè)挑戰(zhàn)。以前直接使用云主機(jī)提供商提供的數(shù)據(jù)卷鏡像備份雖然可以work,但是往往備份了很多不必要的數(shù)據(jù),額外占用的空間將產(chǎn)生額外的費(fèi)用。而目前很多容器服務(wù)提供商能夠免費(fèi)提供私有數(shù)據(jù)容器存儲(chǔ),這又可以為我們節(jié)省一筆開(kāi)支。
我的建議思路是:使用busybox基礎(chǔ)鏡像,COPY指令將需要備份的數(shù)據(jù)copy到鏡像中,并且tag后push到私有倉(cāng)庫(kù)來(lái)存儲(chǔ)。
FROM busybox:1.30 COPY ./datainhost /dataincontainer需要注意的是./datainhost目錄是相對(duì)于Dockerfile-databackup這個(gè)文件的相對(duì)路徑。
如果需要copy不在build context中的目錄到image中,可以這么做:
- go to you build path
- mkdir -p some_name
- sudo mount --bind src_dir ./some_name
然后在dockerfile的copy指令中直接用some_name來(lái)引用外部文件夾并且實(shí)施copy即可。
?
隨后在host上(包含dockerfile的那個(gè)目錄上)執(zhí)行以下shell命令:
docker build -f Dockerfile-databackup -t registry-internal.cn-shanghai.aliyuncs.com/namespace/reponame:$(date +"%F") .該命令將會(huì)生成registry-internal.../reponame:2019-03-20類似的tag到構(gòu)建好的image上去。
隨后直接push一下就好了。
注意上述registry對(duì)于阿里云主機(jī)使用內(nèi)網(wǎng)ip不占用帶寬,非常快速好用
?
轉(zhuǎn)載于:https://www.cnblogs.com/kidsitcn/p/10466022.html
總結(jié)
以上是生活随笔為你收集整理的docker in all的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Spring】- Bean生命周期
- 下一篇: 解决zabbix-agent二进制班不能