在Docker的实现机制中,有两个重要的概念,“Docker客户端”和“Docker守护进程”。“Docker守护进程”运行在宿主计算机上,在CS模式中充当Server的角色,它为“Docker客户端”提供服务,并且完成Docker中的各项任务。
sequenceDiagram
用户->>Docker客户端: 命令行指令
Docker客户端->>Docker守护进程: 执行指令
Docker守护进程->>Docker客户端: 执行结果
Docker客户端->>用户: 命令行输出
除了“Docker客户端”这个最主要的与“Docker守护进程”交互的方式外,Docker还提供了RESTful风格的“Remote API”,这就意味着我们可以通过编写程序,调用这些API来将自己的程序与Docker进行集成。“Remote API”在某些复杂的情况下,也支持“STDIN”、“STDOUT”以及“STRERR”的通讯机制进行交互。
sequenceDiagram
用户->>自定义程序: 程序输入
自定义程序->>Docker守护进程: Remote API
Docker守护进程->>自定义程序: 执行结果
自定义程序->>用户: 程序输出
Docker Remote API Reference:
https://docs.docker.com/engine/reference/api/docker_remote_api/
“Docker客户端”和“Docker守护进程”是通过socket进行连接的,官方提供了三种进行连接的模式:
- unix:///var/run/docker.sock
- tcp://host:port
- fd://socketfd
其中,“unix”模式是默认提供的,我们来验证一下:
schen@scvmu01:~$ ps -ef | grep docker
root 1106 1 0 21:14 ? 00:00:04 /usr/bin/dockerd -H fd://
root 1224 1106 0 21:15 ? 00:00:00 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc
schen 1603 1582 0 22:03 pts/0 00:00:00 grep --color=auto docker
schen@scvmu01:~$
schen@scvmu01:~$ docker version
Client:
Version: 1.12.1
API version: 1.24
Go version: go1.6.3
Git commit: 23cf638
Built: Thu Aug 18 05:33:38 2016
OS/Arch: linux/amd64
Server:
Version: 1.12.1
API version: 1.24
Go version: go1.6.3
Git commit: 23cf638
Built: Thu Aug 18 05:33:38 2016
OS/Arch: linux/amd64
schen@scvmu01:~$
schen@scvmu01:~$ ls -l /var/run/docker.sock
srw-rw---- 1 root docker 0 Sep 7 21:14 /var/run/docker.sock
schen@scvmu01:~$
schen@scvmu01:~$ nc -U /var/run/docker.sock
GET /info HTTP/1.0
HTTP/1.0 200 OK
Content-Type: application/json
Server: Docker/1.12.1 (linux)
Date: Thu, 17 Nov 2016 12:16:25 GMT
Content-Length: 1874
{"ID":"VVPW:WOIW:TCPI:YDUG:J67N:5DHU:WSWW:RMMN:64FK:KNHO:NPPH:ATSL","Containers":26,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":26,"Images":44,"Driver":"aufs","DriverStatus":[["Root Dir","/var/lib/docker/aufs"],["Backing Filesystem","extfs"],["Dirs","83"],["Dirperm1 Supported","true"]],"SystemStatus":null,"Plugins":{"Volume":["local"],"Network":["host","bridge","null","overlay"],"Authorization":null},"MemoryLimit":true,"SwapLimit":false,"KernelMemory":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"IPv4Forwarding":true,"BridgeNfIptables":true,"BridgeNfIp6tables":true,"Debug":false,"NFd":14,"OomKillDisable":true,"NGoroutines":22,"SystemTime":"2016-11-17T20:16:25.663603424+08:00","ExecutionDriver":"","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-45-generic","OperatingSystem":"Ubuntu 16.04 LTS","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":1,"MemTotal":512176128,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"scvmu01.shichen.org","Labels":null,"ExperimentalBuild":false,"ServerVersion":"1.12.1","ClusterStore":"","ClusterAdvertise":"","SecurityOptions":["apparmor","seccomp"],"Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null,"Nodes":0,"Managers":0,"Cluster":{"ID":"","Version":{},"CreatedAt":"0001-01-01T00:00:00Z","UpdatedAt":"0001-01-01T00:00:00Z","Spec":{"Orchestration":{},"Raft":{},"Dispatcher":{},"CAConfig":{},"TaskDefaults":{}}}},"LiveRestoreEnabled":false}
schen@scvmu01:~$
可以看到,在Docker的守护进程dockerd
的参数列表中,我们并没有指定“unix”套接字,但是我们却可以通过它来访问Docker的守护进程,并使用HTTP协议获取有关Docker守护进程的信息,当然这些信息是以JSON格式提供的。
要查看Docker守护进程的状态,我们可以使用Linux自带的ps
命令:
schen@scvmu01:~$ ps -ef | grep docker
root 1106 1 0 21:14 ? 00:00:04 /usr/bin/dockerd -H fd://
root 1224 1106 0 21:15 ? 00:00:00 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc
schen 1603 1582 0 22:03 pts/0 00:00:00 grep --color=auto docker
schen@scvmu01:~$
除了我们熟悉的ps
命令外,我们还可以通过status
命令进行查看,但是由于该命令在Ubuntu虚拟机中需要额外的设置才能使用,故这里不再演示。而如果status
命令不存在,可以使用sudo apt-get install upstart
进行安装。
我们可以使Linux的service
命令来管理Docker的守护进程,它可以:
1. 启动docker的守护进程 sudo service docker start
2. 停止docker的守护进程 sudo service docker stop
3. 重启docker的守护进程 sudo service docker restart
4. 查看docker的守护进程 sudo service docker status
schen@scvmu01:~$ sudo service docker status | grep PID
Main PID: 1080 (dockerd)
schen@scvmu01:~$
schen@scvmu01:~$ sudo service docker stop
schen@scvmu01:~$
schen@scvmu01:~$ sudo service docker status | grep PID
Main PID: 1080 (code=exited, status=0/SUCCESS)
schen@scvmu01:~$
schen@scvmu01:~$ sudo service docker start
schen@scvmu01:~$
schen@scvmu01:~$ sudo service docker status | grep PID
Main PID: 27822 (dockerd)
schen@scvmu01:~$
schen@scvmu01:~$ sudo service docker restart
schen@scvmu01:~$
schen@scvmu01:~$ sudo service docker status | grep PID
Main PID: 27937 (dockerd)
schen@scvmu01:~$
Docker守护进程提供了非常丰富的配置选项,其中包括:
1. 守护进程运行相关选项(-D, -e, -g, --icc, -l, --label, -p
等)
2. Docker服务器连接相关选项(-G, -H, --tls, --tlscacert, --tlscert, --tlskey, --tlsverify
等)
3. RemoteAPI相关选项(--api-enable-cors
等)
4. 存储相关选项(-s, --selinux-enabled, --storage-opt
等)
5. Registry相关选项(--insecure-registry, --registry-mirror
等)
6. 网络相关选项(-b, --bip, --fixed-cidr, --dns, --dns-search, --ip, --ip-forward, --ip-masq, --iptables, --ipv6, --mtu
等)
有关于这些参数的解释,可以通过docker daemon --help
命令查看,也可以查阅Docker的官方网站。
Docker命令行参考:https://docs.docker.com/engine/reference/commandline/
我们可以通过修改/etc/default/docker
文件实现对Docker守护进程的启动配置。
schen@scvmu01:~$ sudo vi /etc/default/docker
schen@scvmu01:~$
schen@scvmu01:~$ grep "^DOCKER_OPTS" /etc/default/docker
DOCKER_OPTS="--label name=docker_server_1"
schen@scvmu01:~$
schen@scvmu01:~$ sudo service docker restart
schen@scvmu01:~$
schen@scvmu01:~$ ps -ef | grep docker
root 28238 1 13 22:39 ? 00:00:01 /usr/bin/dockerd -H fd://
root 28244 28238 0 22:39 ? 00:00:00 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc
schen 28333 27696 0 22:39 pts/0 00:00:00 grep --color=auto docker
schen@scvmu01:~$
这时我们发现设置并没有生效,这是因为/etc/default/docker
文件是为upstart
和SysVInit
准备的(正如文件第一行注释所言),而使用service
命令时并不会读取它,因此我们还需要做如下更改:
schen@scvmu01:~$ sudo mkdir -p /etc/systemd/system/docker.service.d
schen@scvmu01:~$
schen@scvmu01:~$ sudo vi /etc/systemd/system/docker.service.d/Using_Environment_File.conf
[Service]
EnvironmentFile=-/etc/default/docker
ExecStart=
ExecStart=/usr/bin/docker daemon -H fd:// $DOCKER_OPTS
~
~
schen@scvmu01:~$
schen@scvmu01:~$ sudo systemctl daemon-reload
schen@scvmu01:~$
schen@scvmu01:~$ sudo service docker restart
schen@scvmu01:~$
schen@scvmu01:~$ ps -ef | grep docker
root 4287 1 0 21:52 ? 00:00:02 dockerd -H fd:// --label name=docker_server_1
root 4296 4287 0 21:52 ? 00:00:00 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc
schen 4395 2377 0 22:07 pts/1 00:00:00 grep --color=auto docker
schen@scvmu01:~$
有关此问题的参考文献:
- https://github.com/docker/docker/issues/9889
- http://docs.master.dockerproject.org/engine/admin/systemd/
通过配置Docker守护进程,可以使Docker客户端和守护进程运行在不同的服务器上,即实现Docker的远程访问。
准备工作:
1. 第二台安装有Docker的服务器;
2. 修改Docker守护进程启动选项,用--label
区别服务器;
3. 保证Client API与Server API版本一致;
我们在第一台服务器上将其Docker守护进程的label指定为name=docker_server_1
,同样将第二台服务器上的label指定为name=docker_server_2
,并重启Docker服务。以下是这两台Docker服务器的详细信息:
schen@scvmu01:~$ docker info
Containers: 15
Running: 0
Paused: 0
Stopped: 15
Images: 8
Server Version: 1.12.1
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 49
Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host null overlay
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Security Options: apparmor seccomp
Kernel Version: 4.4.0-45-generic
Operating System: Ubuntu 16.04 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 488.4 MiB
Name: scvmu01.shichen.org
ID: VVPW:WOIW:TCPI:YDUG:J67N:5DHU:WSWW:RMMN:64FK:KNHO:NPPH:ATSL
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Username: shichen
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
Labels:
name=docker_server_1
Insecure Registries:
127.0.0.0/8
schen@scvmu01:~$
schen@scvmu02:~$ docker info
Containers: 15
Running: 0
Paused: 0
Stopped: 15
Images: 8
Server Version: 1.12.1
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 49
Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: overlay null host bridge
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Security Options: apparmor seccomp
Kernel Version: 4.4.0-45-generic
Operating System: Ubuntu 16.04 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 488.4 MiB
Name: scvmu02.shichen.org
ID: VVPW:WOIW:TCPI:YDUG:J67N:5DHU:WSWW:RMMN:64FK:KNHO:NPPH:ATSL
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Username: shichen
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
Labels:
name=docker_server_2
Insecure Registries:
127.0.0.0/8
schen@scvmu02:~$
要实现远程访问,我们就要修改docker守护进程启动选项-H
的值,将它指定为tcp模式。
schen@scvmu01:~$ sudo vi /etc/default/docker
schen@scvmu01:~$
schen@scvmu01:~$ grep "^DOCKER_OPTS" /etc/default/docker
DOCKER_OPTS="--label name=docker_server_1 -H tcp://0.0.0.0:2375"
schen@scvmu01:~$
schen@scvmu01:~$ sudo service docker restart
schen@scvmu01:~$
我们在第一台服务器上,将Docker守护进程-H
选项指定为tcp://0.0.0.0:2375
,这里使用全零的地址是让Docker绑定服务器自身的IP地址,而“2375”是Docker服务器常用的端口号。现在我们来到第二台服务器上,验证一下我们的配置:
schen@scvmu02:~$ curl http://scvmu01:2375/info
{"ID":"VVPW:WOIW:TCPI:YDUG:J67N:5DHU:WSWW:RMMN:64FK:KNHO:NPPH:ATSL","Containers":15,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":15,"Images":8,"Driver":"aufs","DriverStatus":[["Root Dir","/var/lib/docker/aufs"],["Backing Filesystem","extfs"],["Dirs","49"],["Dirperm1 Supported","true"]],"SystemStatus":null,"Plugins":{"Volume":["local"],"Network":["overlay","null","host","bridge"],"Authorization":null},"MemoryLimit":true,"SwapLimit":false,"KernelMemory":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"IPv4Forwarding":true,"BridgeNfIptables":true,"BridgeNfIp6tables":true,"Debug":false,"NFd":15,"OomKillDisable":true,"NGoroutines":23,"SystemTime":"2016-10-25T19:50:46.471062364+08:00","ExecutionDriver":"","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-45-generic","OperatingSystem":"Ubuntu 16.04 LTS","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":1,"MemTotal":512176128,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"scvmu01.shichen.org","Labels":["name=docker_server_1"],"ExperimentalBuild":false,"ServerVersion":"1.12.1","ClusterStore":"","ClusterAdvertise":"","SecurityOptions":["apparmor","seccomp"],"Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null,"Nodes":0,"Managers":0,"Cluster":{"ID":"","Version":{},"CreatedAt":"0001-01-01T00:00:00Z","UpdatedAt":"0001-01-01T00:00:00Z","Spec":{"Orchestration":{},"Raft":{},"Dispatcher":{},"CAConfig":{},"TaskDefaults":{}}}},"LiveRestoreEnabled":false}
schen@scvmu02:~$
因为主机名已经设置好,所以我们可以直接使用主机名scvmu01
代替其IP地址。使用curl
命令访问远程Docker服务器的/info
接口,得到了JSON格式的数据反馈,说明服务器已经可以正常连接了。
与服务端类似,客户端也支持-H
选项,我们可以通过指定这个选项,让客户端与指定的服务端相连:
schen@scvmu02:~$ docker -H tcp://scvmu01:2375 info
Containers: 15
Running: 0
Paused: 0
Stopped: 15
Images: 8
Server Version: 1.12.1
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 49
Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: overlay null host bridge
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Security Options: apparmor seccomp
Kernel Version: 4.4.0-45-generic
Operating System: Ubuntu 16.04 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 488.4 MiB
Name: scvmu01.shichen.org
ID: VVPW:WOIW:TCPI:YDUG:J67N:5DHU:WSWW:RMMN:64FK:KNHO:NPPH:ATSL
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Username: shichen
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
Labels:
name=docker_server_1
Insecure Registries:
127.0.0.0/8
schen@scvmu02:~$
当我们要频繁操作一个远程Docker服务器时,重复地使用-H
选项就会显得很麻烦,这时我们可以通过设定DOCKER_HOST
环境变量解决这个问题:
schen@scvmu02:~$ export DOCKER_HOST="tcp://scvmu01:2375"
schen@scvmu02:~$
schen@scvmu02:~$ docker info
Containers: 15
Running: 0
Paused: 0
Stopped: 15
Images: 8
Server Version: 1.12.1
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 49
Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: host bridge null overlay
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Security Options: apparmor seccomp
Kernel Version: 4.4.0-45-generic
Operating System: Ubuntu 16.04 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 488.4 MiB
Name: scvmu01.shichen.org
ID: VVPW:WOIW:TCPI:YDUG:J67N:5DHU:WSWW:RMMN:64FK:KNHO:NPPH:ATSL
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Username: shichen
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
Labels:
name=docker_server_1
Insecure Registries:
127.0.0.0/8
schen@scvmu02:~$
当我们使用完远程的Docker服务器后,想要连接本机的Docker服务端,只需要将DOCKER_HOST
变量置空即可:
schen@scvmu02:~$ export DOCKER_HOST=""
schen@scvmu02:~$
schen@scvmu02:~$ docker info
Containers: 15
Running: 0
Paused: 0
Stopped: 15
Images: 8
Server Version: 1.12.1
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 49
Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: host null bridge overlay
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Security Options: apparmor seccomp
Kernel Version: 4.4.0-45-generic
Operating System: Ubuntu 16.04 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 488.4 MiB
Name: scvmu02.shichen.org
ID: VVPW:WOIW:TCPI:YDUG:J67N:5DHU:WSWW:RMMN:64FK:KNHO:NPPH:ATSL
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Username: shichen
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
Labels:
name=docker_server_2
Insecure Registries:
127.0.0.0/8
schen@scvmu02:~$
当我们回到第一台服务器上,发现Docker客户端仍然可以在不指定-H
参数的情况下,直接与本地的服务端相连。这是因为Docker守护进程在启动时,还默认指定了-H fd://
参数,这也说明我们可以通过给Docker守护进程指定多个-H
参数来为Docker客户端提供更多的连接方式:
schen@scvmu01:~$ echo $DOCKER_HOST
schen@scvmu01:~$
schen@scvmu01:~$ docker info
Containers: 15
Running: 0
Paused: 0
Stopped: 15
Images: 8
Server Version: 1.12.1
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 49
Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: overlay null host bridge
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Security Options: apparmor seccomp
Kernel Version: 4.4.0-45-generic
Operating System: Ubuntu 16.04 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 488.4 MiB
Name: scvmu01.shichen.org
ID: VVPW:WOIW:TCPI:YDUG:J67N:5DHU:WSWW:RMMN:64FK:KNHO:NPPH:ATSL
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Username: shichen
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
Labels:
name=docker_server_1
Insecure Registries:
127.0.0.0/8
schen@scvmu01:~$ ps -ef | grep dockerd
root 1131 1 0 19:34 ? 00:00:06 dockerd -H fd:// --label name=docker_server_1 -H tcp://0.0.0.0:2375
schen 1637 1587 0 20:31 pts/0 00:00:00 grep --color=auto dockerd
schen@scvmu01:~$