我有机会建立一个以Docker为基础的微服务架构在我现在的工作中,很多人都会分享他们使用Docker的心得,我想我也不会例外。因此我总结了一些,可能你会在日常使用Docker的时候会用到。
1. 一台主机部署多个Docker实例
如果你想运行多个Docker 容器在一台主机上,如果要设置不同的TLS设置,网络设置,日志设置和存储驱动程序特定的容器,这是特别有用的。例如,我们目前正在运行一个标准设立两个Docker守护进程。一运行consul提供DNS解析,并作为群集存储为其他Docker 容器。
For example:
# start a docker daemon and bind to a specific port
docker daemon -H tcp://$IP:5000 --storage-opt dm.fs=xfs \
-p "/var/run/docker1.pid" \
-g "/var/lib/docker1" \
--exec-root="/var/run/docker1
# and start another daemon
docker daemon -H tcp://$IP:5001 --storage-opt dm.fs=xfs \
-s devicemapper \
--storage-opt dm.thinpooldev=/dev/mapper/docker--vg-docker--pool \
-p "/var/run/docker2.pid" \
-g "/var/lib/docker2" --exec-root="/var/run/docker2"
--cluster-store=consul://$IP:8500 \
--cluster-advertise=$IP:2376
# start a docker daemon and bind to a specific port
dockerdaemon -H tcp://$IP:5000 --storage-opt dm.fs=xfs \
-p "/var/run/docker1.pid" \
-g "/var/lib/docker1" \
--exec-root="/var/run/docker1
# and start another daemon
docker daemon -H tcp://$IP:5001 --storage-opt dm.fs=xfs \
-s devicemapper \
--storage-opt dm.thinpooldev=/dev/mapper/docker--vg-docker--pool \
-p "/var/run/docker2.pid" \
-g "/var/lib/docker2" --exec-root="/var/run/docker2"
--cluster-store=consul://$IP:8500 \
--cluster-advertise=$IP:2376
2. Docker Exec的使用
Docker Exec是一个很重要很多人都会用到的工具,也许你使用Docker不只是为你的升级,生产和测试环境,同时也对本地机器上运行的数据库,服务器密钥库等,这是能够直接运行的容器的上下文中运行的命令,非常方便。
我们做了大量的Cassandra,并检查表是否包含正确的数据。如果你只是想执行一个快速CQL查询,Docker exec 就很赞:
$ docker ps --format "table {{.ID}}\t {{.Names}}\t {{.Status}}"
CONTAINER ID NAMES STATUS
682f47f97fce cassandra Up 2 minutes
4c45aea49180 consul Up 2 minutes
$ docker exec -ti 682f47f97fce cqlsh --color
Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 2.2.3 | CQL spec 3.3.1 | Native protocol v4]
Use HELP for help.
cqlsh>
$ dockerps --format "table {{.ID}}\t {{.Names}}\t {{.Status}}"
CONTAINERID NAMES STATUS
682f47f97fce cassandra Up 2 minutes
4c45aea49180 consul Up 2 minutes
$ dockerexec -ti 682f47f97fce cqlsh --color
Connectedto TestClusterat 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 2.2.3 | CQLspec 3.3.1 | Native protocolv4]
Use HELPfor help.
cqlsh>
或者只是访问nodetool或镜像中可用的任何其他工具:
$ docker exec -ti 682f47f97fce nodetool status Datacenter: datacenter1 ======================= Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns Host ID Rack UN 192.168.99.100 443.34 KB 256 ? 8f9f4a9c-5c4d-4453-b64b-7e01676361ff rack1 Note: Non-system keyspaces don't have the same replication settings, effective ownership information $ dockerexec -ti 682f47f97fce nodetoolstatus Datacenter: datacenter1 ======================= Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns HostID Rack UN 192.168.99.100 443.34 KB 256 ? 8f9f4a9c-5c4d-4453-b64b-7e01676361ff rack1 Note: Non-systemkeyspacesdon't havethesamereplicationsettings, effectiveownershipinformation
这当然可以被应用到任何(Client)的工具捆绑在一起的镜像中。我个人觉得这样会比所有客户端和本地更新更简单。
3. Docker 的检查 和JQ
与其说这是一个Docker技巧,不如说是一个JQ技巧。如果你没有听过JQ,它是一个在命令行解析JSON的伟大工具。因为我们可以不需要使用format specifier而能够查看容器里面发生的一切。
# Get network information:
$ docker inspect 4c45aea49180 | jq '.[].NetworkSettings.Networks'
{
"bridge": {
"EndpointID": "ba1b6efba16de99f260e0fa8892fd4685dbe2f79cba37ac0114195e9fad66075",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02"
}
}
# Get the arguments with which the container was started
$ docker inspect 4c45aea49180 | jq '.[].Args'
[
"-server",
"-advertise",
"192.168.99.100",
"-bootstrap-expect",
"1"
]
# Get all the mounted volumes
11:22 $ docker inspect 4c45aea49180 | jq '.[].Mounts'
[
{
"Name": "a8125ffdf6c4be1db4464345ba36b0417a18aaa3a025267596e292249ca4391f",
"Source": "/mnt/sda1/var/lib/docker/volumes/a8125ffdf6c4be1db4464345ba36b0417a18aaa3a025267596e292249ca4391f/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true
}
]
# Get network information:
$ dockerinspect 4c45aea49180 | jq '.[].NetworkSettings.Networks'
{
"bridge": {
"EndpointID": "ba1b6efba16de99f260e0fa8892fd4685dbe2f79cba37ac0114195e9fad66075",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02"
}
}
# Get the arguments with which the container was started
$ dockerinspect 4c45aea49180 | jq '.[].Args'
[
"-server",
"-advertise",
"192.168.99.100",
"-bootstrap-expect",
"1"
]
# Get all the mounted volumes
11:22 $ dockerinspect 4c45aea49180 | jq '.[].Mounts'
[
{
"Name": "a8125ffdf6c4be1db4464345ba36b0417a18aaa3a025267596e292249ca4391f",
"Source": "/mnt/sda1/var/lib/docker/volumes/a8125ffdf6c4be1db4464345ba36b0417a18aaa3a025267596e292249ca4391f/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true
}
]
当然,它也能很好的完成查询其他类型的(Docker-esque) API生成的JSON(e.g Marathon, Mesos, Consul etc.)JQ提供了一个非常广泛的API,用于访问和处理JSON.更多信息可以在这里找到: https://stedolan.github.io/jq/
4. 扩展现有容器和在本地注册
在Docker hub中有大量可以使用的的不同使用场景的镜像。我们注意到,虽然有很多可用的镜像,但是很多时候我们不得对他们做一些修改。比如更好的健康检查consul,通过系统变量或命令行参数的其他配置,为更好地设置或增加我们的集群,这是不容易做到的。如果我们碰到这个是刚刚创建自己的Docker的镜像和把它推到我们的本地注册表。我们通常是这么做的。
比如,我们希望有JQ可在我们的consul 镜像中这样我们就可以很方便的检查我们的服务是否正常。
FROM progrium/consul USER root ADD bin/jq /bin/jq ADD scripts/health-check.sh /bin/health-check.sh
FROMprogrium/consul USERroot ADDbin/jq /bin/jq ADDscripts/health-check.sh /bin/health-check.sh
我们有了health check scripts and JQ我们就可以从我们自己的consul image做health check了。我们也有一个本地注册表运行镜像在创建后,我们只是标记生成的镜像,并将其推到我们的本地注册表
$ docker build . ... $ docker tag a3157e9edc18 <local-registry>/consul-local:some-tag $ docker push <local-registry>/consul-local:some-tag
$ dockerbuild . ... $ dockertaga3157e9edc18 <local-registry>/consul-local:some-tag $ dockerpush <local-registry>/consul-local:some-tag
现在,它可以提供给我们的开发者了。并且也可在我们的不同的测试环境中使用。
5. 访问远程主机的Docker
Docker的CLI是一个非常酷的工具,其中一个很大的特点是,你可以用它来轻松地访问多Docker守护进程,即使它们在不同的主机

