docker in all

docker vs hyper-v,vmware,xen,kvmphp

docker host, docker container, docker engineen, docker imagehtml

images = stopped containernode

container = running imagesmysql

 

docker操做示意圖linux

workflownginx

 

开始使用docker(以windows下为例)git

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:latest

Hello 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 the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share 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 187kBgithub

 

 

以上docker run hello-world命令本质上的执行过程:golang

1. docker client向docker daemon(engine)联络,告诉docker engine,请帮我运行一个hello-wold containerweb

2. docker daemon(engine)收到该命令后先在本地查找是否有hello-world这个image,若是没有则从regisry查找而且pull下来

3. docker daemon以该image实例化一个container,而且运行该image定义的executable,而这个executable将产生output;

4. docker daemon streamed that output to the docker client,这样咱们就看到了hello world的消息

docker image到底包含了什么?

强烈建议: https://www.csdn.net/article/2015-08-21/2825511

咱们知道linux系统由内核+发行版组成,一样的内核好比3.8之上,咱们能够有debian, ubuntu, centos等不一样的发行版本。相似地,Docker镜像就是相似于“ubuntu操做系统发行版”,可 以在任何知足要求的Linux内核之上运行。简单一点有“Debian操做系统发行版”Docker镜像、“Ubuntu操做系统发行版”Docker镜 像;若是在Debian镜像中安装MySQL 5.6,那咱们能够将其命名为Mysql:5.6镜像;若是在Debian镜像中安装有Golang 1.3,那咱们能够将其命名为golang:1.3镜像;以此类推,你们能够根据本身安装的软件,获得任何本身想要的镜像。

修改默认pull image存放位置

在windows下本质上docker engine是工做在hyper-v虚拟机中,全部的docker客户端敲的命令在该虚拟机中运行,pull的image也放在该虚拟机中,所以咱们要修改image保存的位置实际上只要修改hyper-v的MobyLinuxVM对应的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:是对一个docker image的存储定义

将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:bebe7ce6215aee349bee5d67222abeb5c5a834bbeaa2f2f5d05363d9fd68db41

docker run detached mode启动一个web服务

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主机上面的container id
PS G:\dockerdata> docker ps

CONTAINER 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

上面的命令执行后将在docker host主机上启动一个web服务器,使用http://localhost:9090就能够直接访问到该container的服务了!!

启动一个container而且在该container中执行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

简单批量维护命令:

PS G:\dockerdata> docker ps -aq
9b4970dcb02a
27b4bc07a3e2
135da1372a06
PS G:\dockerdata> docker stop $(docker ps -aq)
9b4970dcb02a
27b4bc07a3e2
135da1372a06

 

swarm:

一群docker engines加入一个cluster分组就被称为swarm, a cluster = a swarm

swarm里面的engine工做于swarm mode

manager nodes维护swarm,

worker nodes 执行manager nodes分发过来的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吞吐量)约束造成的独立运行环境。

engine 

engine经过外部api接受命令负责屏蔽OS的namespace及cgroup,而且建立对应的container运行于host环境中

不一样module协同工做实现的container运行过程

一旦container被启动运行后,containerd和它之间就能够没有了关系,之后能够经过发现过程来取得新的联系

image

image包含app运行所需的

1.OS Files library, objects;

2. app files

3. manifest-->定义这些文件是如何组织在一块儿工做的

image是层叠结构的文件系统.

docker image pull redis的工做分两步:第一步从registry这里获取到manifest文件;第二步pull layers

 

docker history redis  # 罗列出全部可以建立redis这个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支持的网络模式

bridge模式: -net = bridge

这是默认网络,docker engine一旦启动后就会在宿主host上建立一个docker0的网桥(能够理解为switch),默认建立的容器都是添加到该网桥(switch)的网段中,能够想象这些容器就是链接在一个交换机的不一样网口上,他们的网关就是docker0的ip(172.17.0.1)

host模式: -net = host

容器不会得到独立的network namespace,而是与宿主host主机共用一个,这也意味着container不会拥有本身的网卡信息,而是使用宿主机的。host模式的容器之间除了网络,其余都是隔离的。

none模式: -net = none

容器将获取独立的network namespace,可是不会为容器进行任何网络配置,须要咱们本身去手工配置

container模式: -net = container:Name/ID

这种模式建立的容器将与指定的容器使用同一个network namespace,具备一样的网络配置信息,这种容器之间除了网络,其余都是隔离的。

自定义网络模式:

与默认的bridge原理同样,但自定义网络内部具有dns发现的能力,能够经过容器名或者主机名容器之间网络通讯

docker logs经过查看容器log来定位调试问题

默认状况下docker logs和ldocker service logs命令显示命令执行的输出,就像是你在命令行直接执行该程序时的情形同样。unix和linux程序每每会打开三个I/O Streams,分别称为STDIN,STDOUT,STDERR。其中stdin是命令的input stream, 能够包含从键盘得到的input或者从其余命令的输出做为input;    stdout是应用程序的normal output.而stderr则被用于错误信息输出。默认状况下,docker logs将显示命令的stdout和stderr输出。基于以上信息,在多重场景下docker logs没法提供有效的log:

1. 若是你使用了一个logging driver(logging driver是docker提供的从运行的container或者service中获取有用信息的机制)将log发往一个文件,或者一个外部的主机,一个数据库或者其余的logging back-end,那么docker logs将不会显示任何有用的信息;

https://docs.docker.com/config/containers/logging/configure/

docker daemon有一个默认的logging driver,每一个启动的容器都将使用它除非你配置了使用一个不一样的logging driver.

好比,咱们能够配置docker daemon使用syslog来作log的收集,他就会经过syslog将运行容器的stdout,stderr信息实时打印到远程服务器。在这种状况下,咱们实际上就不可能使用docker logs来查看运行时的状态,而只能经过syslog服务器来获取信息;

2. 若是咱们的image运行在non-interactive 进程中,好比web server或者database的进程,这种进程会将其输出信息直接送往log文件,而不是stdout或者stderr.

在这种状况下,咱们一方面能够进入容器来查看相似nginx和myql的log文件获取运行时信息;另一方面官方的nginx,httpd都提供了workaround方式,好比nginx image的构建中经过建立一个符号链接将 /var/log/nginx/access.log指向到/dev/stdout; 将/var/log/nginx/error.log指向到/dev/stderr的方式来解决。 httpd image则默认输出到/proc/self/fd/1 (stdout),   error则将写往 /proc/self/fd/2(stderr)

这样咱们依然能够经过docker logs -tail 8 -f来实时查看log

docker networking

https://success.docker.com/article/networking

建议使用自定义网络,docker默认的docker0 bridge支持--link参数,可是--link参数未来也会废弃。

$ brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242bd712cd8       no
br-9694b511a9af         8000.0242e7c72a3d       no
br-81195db0babc         8000.0242d6feb257       no              veth375600f
                                                                vethbc86c59
br-c301fa0c30d5         8000.024241d93a8e       no              veth73040a3
                                                                veth72eebce
                                                                vethd5af9cd
                                                                veth12d8ab4
                                                                veth6d89a9d        

我们来看一下使用laradock docker-compose up -d nginx mysql以后的网络拓补图分析过程:

$ brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242bd712cd8       no
br-9694b511a9af         8000.0242e7c72a3d       no
br-81195db0babc         8000.0242d6feb257       no              veth375600f
                                                        vethbc86c59
br-c301fa0c30d5         8000.024241d93a8e       no              veth73040a3
                                                        veth72eebce
                                                        vethd5af9cd
                                                        veth12d8ab4
                                                        veth6d89a9d
[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              veth375600f
                                                        vethbc86c59
br-c301fa0c30d5         8000.024241d93a8e       no              veth73040a3
                                                        veth72eebce
                                                        vethd5af9cd
                                                        veth12d8ab4
                                                        veth6d89a9d
[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": {}
    }
]

关于环境变量env

https://vsupalov.com/docker-arg-env-variable-guide/

关于volumes

https://docs.docker.com/storage/volumes/

若是咱们不须要永久持久化,可是又须要在运行时保存一些状态信息,能够考虑使用tmpfs mount直接mount到内存中,加快速度。

 

容器中进程启动的两种模式:shell模式和exec模式

docker容器内启动的全部进程所有都是宿主机上的独立进程;另外,该进程是否是docker容器进程自己(即:1号进程)取决于dockerfile的写法。

在ENTRYPOINT和CMD命令中,有两种不一样的进程执行方式:shell和exec.

1.在shell方式中,CMD/ENTRYPOINT指令以下方式定义

CMD executable param1 param2

此时PID=1的进程为/bin/sh -c "executable param1 param2",真正的executable工做进程是其子进程

2.在exec方式中,CMD/ENTRYPOINT指令则以下方式定义:

CMD ["executable", "param1","param2"]

此时PID=1的进程直接是工做进程executable param1 param2

这两种启动模式还带来进程退出机制的区别,若是使用不当会形成僵尸进程。

docker提供了docker stop和docker kill两个命令向1号进程发送信号。当执行docker stop时,docker会先想PID1的进程发送一个SIGTERM信号,若是容器收到该信号后没有结束进程,则docker daemon会在等待10秒后发送SIGKILL信号,将容器进程杀死(PID1)并变为退出状态。

PID1的进程必须可以正确处理SIGTERM信号并通知全部子进程退出。若是用shell脚本启动容器,其1号进程为shell进程,而shell进程中并无对SIGTERM信号的处理逻辑,所以会忽略接收到的SIGTERM信号,这样就没法实现优雅的退出(好比持久化数据),所以docker官方建议的模式是:令每一个容器中只包含一个进程,同时采用exec模式启动进程。或者使用定制化shell脚本启动,须要可以接受SIGTERM信号而且分发该信号到全部的子进程,或者工做进程以exec方式启动,同时该工做进程可以处理SIGTERM并负责分发给子进程

docker daemon只监控1号进程。

Docker容器的运行时模型

linux中的父进程用fork命令建立子进程,而后调用exec执行子进程函数,每一个进程都有一个PID。另外,除了常见的通常应用进程,操做系统中还有如下特殊的进程。

1. PID=0是调度进程,该进程是内核的一部分,不会执行磁盘上的任何程序;

2. PID=1为init进程,一般读取与系统有关的初始化文件/etc/rc*文件,/etc/inittab,/etc/init.d/中的文件

3. PID=2为页守护进程,负责支持虚拟存储系统的分页操做。

Docker启动时,利用fork命令从Docker-containerd进程中fork出一个子进程,而后以exec方式启动本身的程序。容器进程被fork以后便建立了namespace,下面就要执行一系列的初始化操做,该操做分为三个阶段,dockerinit负责初始化网络栈;ENTRYPOINT负责完成用户态配置;CMD负责启动入口。启动后的docker容器和docker daemon就经过sock文件描述符实现IPC通讯。

docker volumes vs binding mount

docker数据持久化建议有两种或者说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_NAME

named volumes是经过docker volume create volume_name的方式手工建立的volumes,他们都存储在/var/lib/docker/volumes目录下,能够仅仅使用volume name来引用。好比,若是咱们建立了mysql_data这个volume,则能够在docker run -v mysql_data:/containerdata IMAGE_NAME来引用它。

而在dockerfile中定义的volumes,是使用VOLUME指令来建立的,他们也存储于/var/lib/docker/volumes中,可是他们没有一个自定义的名字,通常使用hash做为其名称,而且dockerfile中定义的volumes后续参数其实是指定了在container中的路径,若是在image中已经populate了数据,则container执行后会自动将该目录数据copy到host自动建立的目录中(若是指定了host路径则不会覆盖host的数据!)

https://stackoverflow.com/questions/41935435/understanding-volume-instruction-in-dockerfile

docker from development to production

通常来讲,咱们在开发时但愿经过一个volume来绑定host主机的source代码以方便即改即调的快捷流程,可是在production阶段

咱们每每直接将代码复制到image中从而实现容器就是代码,独立于主机能够在任何地点运行的便捷。

一个比较好的策略是

docker-compose.yml中这样定义:

version: '2'
services:
    app:
        build: .
        image: app:1.0.0-test
        volumes:
        - ./host_src:/user/share/nginx/html
        ports:
        - "8080:80"

其中nginx app build时须要使用的Dockerfile能够简单定义以下:

FROM nginx
COPY host_src /usr/share/nginx/html

在nginx app中首先COPY host_src到container对应的目录中,随后在dev的compose yml中为方便实时修改代码和测试则mount了一个volume将host_src也映射到nginx app中相同目录下;

随后,在nginx app变为production时,咱们能够这样建立一个docker-compose-production.yml

version: '2'
services:
    app:
        build: .
        image: app:1.0.0-production
        ports:
        - "80:80"

和dev的yml文件相比,咱们仅仅剔除了volume的绑定,而是直接使用COPY到image中的代码去运行

是否能够修改从parent image中继承的volume data?

好比,A image的dockerfile以下:

FROM bash
RUN mkdir "/data" && echo "FOO" > "/data/test"
VOLUME "/data"

咱们再定义一个B image,它继承于A,咱们在dockerfile中但愿修改A image中的“默认”数据:

FROM A
RUN echo "BAR" > "/data/test"

以上测试中B image中的/data/test实际上其值为FOO,并非BAR

这其实是Docker自己的特性使然,如何workaround?

1. 直接修改parent docker file,咱们从google搜索如下信息

docker <image-name:version> source

咱们就可以找到对应的父亲image的dockerfile,经过删除其volume来实现。

VOLUMES自己并非IMAGE的一部分,所以咱们须要经过seed data来实现上面的需求。当docker image被放到另外地方运行时,它将在启动后是一个空的volume,所以,若是你但愿将数据和image一块儿打包,就不要使用volume,而应该使用copy.

若是你确实须要从新build新的image的话,你应该先将这个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推荐的持久化数据的方式,可是volume的用法有不少种,他们之间到底有什么区别?

要回答这个问题先得明白"volume是一个持久化数据的目录,存在于/var/lib/docker/volumes/..."

这个事实。你能够:

1. 在Dockerfile中声明一个volume,这意味着每次从image中运行一个container时,该volume就将被created,可是确是(empty)空的,即使你并未使用一个-v参数在docker run -v命令中

2.你能够在运行时指定mount的volume:

docker run -v [host-dir:]container-dir
docker run -d \ --name devtest \ --mount source=myvol2,target=/app \ nginx:latest
# -v和--mount有相同的效果,若是还不存在myvol2则建立一个volume到/var/lib/docker/volumes目录,随后mount到container中
docker run -d \ --name devtest \ -v myvol2:/app \ nginx:latest

这种模式就结合了VOLUME in dockerfile和docker run -v二者的优势,他会将host folder mount到由container持久化并存储于/var/lib/docker/volumes/...的卷

3.docker volume create将建立一个命名式的volume,能够快速被其余容器来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
# 等价于如下命令,bind mount主机的目录到target机器上
docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app \
  nginx:latest

 

dockerfile执行顺序及变动

1 FROM ubuntu:16.04
2 RUN apt-get update
3 RUN apt-get install nginx
4 RUN apt-get install php5

若是上面的dockerfile咱们作过build,随后咱们想把nginx换成apache,并从新build,则这时候第1和第2行不会再运行,由于都保存在cache中,可是第3和第4行都会从新执行,由于第3行作了变动,而第4行又依赖于第3行,所以第3和第4行都将从新执行最终构建出image

Docker AUFS原理

 

使用docker数据容器的备份策略

咱们知道在网站平常运维中会有不少数据产生,包括数据库自己,不少配置文件,包括dockerfile, docker-compose等数据,如何备份这个数据是一个挑战。之前直接使用云主机提供商提供的数据卷镜像备份虽然能够work,可是每每备份了不少没必要要的数据,额外占用的空间将产生额外的费用。而目前不少容器服务提供商可以免费提供私有数据容器存储,这又能够为咱们节省一笔开支。

个人建议思路是:使用busybox基础镜像,COPY指令将须要备份的数据copy到镜像中,而且tag后push到私有仓库来存储。

FROM busybox:1.30
COPY ./datainhost /dataincontainer

须要注意的是./datainhost目录是相对于Dockerfile-databackup这个文件的相对路径。

若是须要copy不在build context中的目录到image中,能够这么作:

  • go to you build path
  • mkdir -p some_name
  • sudo mount --bind src_dir ./some_name

而后在dockerfile的copy指令中直接用some_name来引用外部文件夹而且实施copy便可。

 

随后在host上(包含dockerfile的那个目录上)执行如下shell命令:

docker build -f Dockerfile-databackup -t registry-internal.cn-shanghai.aliyuncs.com/namespace/reponame:$(date +"%F") .

该命令将会生成registry-internal.../reponame:2019-03-20相似的tag到构建好的image上去。

随后直接push一下就行了。

注意上述registry对于阿里云主机使用内网ip不占用带宽,很是快速好用

docker 子命令 tab completion

https://github.com/samneirinck/posh-docker

相关文章
相关标签/搜索