apache mysql Firefox 开源 Python google Windows 程序员 linux java Ubuntu Android shell 编程 微软 centos 云计算 php nginx wordpress

10個日常Docker使用技巧

我有機會建立一個以Docker為基礎的微服務架構在我現在的工作中,很多人都會分享他們使用Docker的心得,我想我也不會例外。因此我總結了一些,可能你會在日常使用Docker的時候會用到。

1. 一臺主機部署多個Docker實例

如果你想運行多個Docker 容器在一臺主機上,如果要設置不同的TLS設置,網絡設置,日誌設置和存儲驅動程序特定的容器,這是特別有用的。例如,我們目前正在運行一個標準設立兩個Docker守護進程。一運行consul提供DNS解析,並作為群集存儲為其他Docker 容器。

For example:

01 # start a docker daemon and bind to a specific port
02 docker daemon -H tcp://$ip:5000 --storage-opt dm.fs=xfs \
03             -p "/var/run/docker1.pid" \
04             -g "/var/lib/docker1" \
05             --exec-root="/var/run/docker1
06 # and start another daemon
07 docker daemon -H tcp://$IP:5001 --storage-opt dm.fs=xfs \
08         -s devicemapper \
09         --storage-opt dm.thinpooldev=/dev/mapper/docker--vg-docker--pool \
10         -p "/var/run/docker2.pid" \
11         -g "/var/lib/docker2" --exec-root="/var/run/docker2"
12         --cluster-store=consul://$IP:8500 \
13         --cluster-advertise=$IP:2376
01 # start a docker daemon and bind to a specific port
02 dockerdaemon -H tcp://$IP:5000 --storage-opt dm.fs=xfs \
03             -p "/var/run/docker1.pid" \
04             -g "/var/lib/docker1" \
05             --exec-root="/var/run/docker1
06 # and start another daemon
07 docker daemon -H tcp://$IP:5001 --storage-opt dm.fs=xfs \
08         -s devicemapper \
09         --storage-opt dm.thinpooldev=/dev/mapper/docker--vg-docker--pool \
10         -p "/var/run/docker2.pid" \
11         -g "/var/lib/docker2" --exec-root="/var/run/docker2"
12         --cluster-store=consul://$IP:8500 \
13         --cluster-advertise=$IP:2376

2. Docker Exec的使用

Docker Exec是一個很重要很多人都會用到的工具,也許你使用Docker不只是為你的升級,生產和測試環境,同時也對本地機器上運行的數據庫,服務器密鑰庫等,這是能夠直接運行的容器的上下文中運行的命令,非常方便。

我們做了大量的Cassandra,並檢查表是否包含正確的數據。如果你只是想執行一個快速CQL查詢,Docker exec 就很贊:

1 $ docker ps --format "table {{.ID}}\t {{.Names}}\t {{.Status}}"
2 CONTAINER ID        NAMES               STATUS
3 682f47f97fce         cassandra           Up 2 minutes
4 4c45aea49180         consul              Up 2 minutes
5 $ docker exec -ti 682f47f97fce cqlsh --color
6 Connected to test Cluster at 127.0.0.1:9042.
7 [cqlsh 5.0.1 | Cassandra 2.2.3 | CQL spec 3.3.1 | Native protocol v4]
8 Use help for help.
9 cqlsh>
1 $ dockerps --format "table {{.ID}}\t {{.Names}}\t {{.Status}}"
2 CONTAINERID        NAMES              STATUS
3 682f47f97fce        cassandra          Up 2 minutes
4 4c45aea49180        consul              Up 2 minutes
5 $ dockerexec -ti 682f47f97fce cqlsh --color
6 Connectedto TestClusterat 127.0.0.1:9042.
7 [cqlsh 5.0.1 | Cassandra 2.2.3 | CQLspec 3.3.1 | Native protocolv4]
8 Use HELPfor help.
9 cqlsh>

或者只是訪問nodetool或鏡像中可用的任何其他工具:

1 $ docker exec -ti 682f47f97fce nodetool status
2 Datacenter: datacenter1
3 =======================
4 Status=Up/Down
5 |/ State=Normal/Leaving/Joining/Moving
6 --  Address         Load       Tokens       Owns    host ID                               Rack
7 UN  192.168.99.100  443.34 KB  256          ?       8f9f4a9c-5c4d-4453-b64b-7e01676361ff  rack1
8 Note: Non-system keyspaces don't have the same replication settings, effective ownership information
1 $ dockerexec -ti 682f47f97fce nodetoolstatus
2 Datacenter: datacenter1
3 =======================
4 Status=Up/Down
5 |/ State=Normal/Leaving/Joining/Moving
6 --  Address        Load      Tokens      Owns    hostid                              Rack
7 UN  192.168.99.100  443.34 KB  256          ?      8f9f4a9c-5c4d-4453-b64b-7e01676361ff  rack1
8 Note: Non-systemkeyspacesdon't havethesamereplicationsettings, effectiveownershipinformation

這當然可以被應用到任何(Client)的工具捆綁在一起的鏡像中。我個人覺得這樣會比所有客戶端和本地更新更簡單。

3. Docker 的檢查 和JQ

與其說這是一個Docker技巧,不如說是一個JQ技巧。如果你沒有聽過JQ,它是一個在命令行解析JSON的偉大工具。因為我們可以不需要使用format specifier而能夠查看容器裏面發生的一切。

01 # Get network information:
02 $ docker inspect 4c45aea49180 | jq '.[].NetworkSettings.Networks'
03 {
04   "bridge": {
05     "EndpointID""ba1b6efba16de99f260e0fa8892fd4685dbe2f79cba37ac0114195e9fad66075",
06     "Gateway""172.17.0.1",
07     "IPAddress""172.17.0.2",
08     "IPPrefixLen": 16,
09     "IPv6Gateway""",
10     "GlobalIPv6Address""",
11     "GlobalIPv6PrefixLen": 0,
12     "MacAddress""02:42:ac:11:00:02"
13   }
14 }
15 # Get the arguments with which the container was started
16 $ docker inspect 4c45aea49180 | jq '.[].Args'
17 [
18   "-server",
19   "-advertise",
20   "192.168.99.100",
21   "-bootstrap-expect",
22   "1"
23 ]
24 # Get all the mounted volumes
25 11:22 $ docker inspect 4c45aea49180 | jq '.[].Mounts'
26 [
27   {
28     "Name""a8125ffdf6c4be1db4464345ba36b0417a18aaa3a025267596e292249ca4391f",
29     "Source""/mnt/sda1/var/lib/docker/volumes/a8125ffdf6c4be1db4464345ba36b0417a18aaa3a025267596e292249ca4391f/_data",
30     "Destination""/data",
31     "Driver""local",
32     "Mode""",
33     "RW"true
34   }
35 ]
01 # Get network information:
02 $ dockerinspect 4c45aea49180 | jq '.[].NetworkSettings.Networks'
03 {
04   "bridge": {
05     "EndpointID""ba1b6efba16de99f260e0fa8892fd4685dbe2f79cba37ac0114195e9fad66075",
06     "Gateway""172.17.0.1",
07     "IPAddress""172.17.0.2",
08     "IPPrefixLen": 16,
09     "IPv6Gateway""",
10     "GlobalIPv6Address""",
11     "GlobalIPv6PrefixLen": 0,
12     "MacAddress""02:42:ac:11:00:02"
13   }
14 }
15 # Get the arguments with which the container was started
16 $ dockerinspect 4c45aea49180 | jq '.[].Args'
17 [
18   "-server",
19   "-advertise",
20   "192.168.99.100",
21   "-bootstrap-expect",
22   "1"
23 ]
24 # Get all the mounted volumes
25 11:22 $ dockerinspect 4c45aea49180 | jq '.[].Mounts'
26 [
27   {
28     "Name""a8125ffdf6c4be1db4464345ba36b0417a18aaa3a025267596e292249ca4391f",
29     "Source""/mnt/sda1/var/lib/docker/volumes/a8125ffdf6c4be1db4464345ba36b0417a18aaa3a025267596e292249ca4391f/_data",
30     "Destination""/data",
31     "Driver""local",
32     "Mode""",
33     "RW"true
34   }
35 ]

當然,它也能很好的完成查詢其他類型的(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 鏡像中這樣我們就可以很方便的檢查我們的服務是否正常。

1 FROM progrium/consul
2 USER root
3 ADD bin/jq /bin/jq
4 ADD scripts/health-check.sh /bin/health-check.sh
1 FROMprogrium/consul
2 USERroot
3 ADDbin/jq /bin/jq
4 ADDscripts/health-check.sh /bin/health-check.sh

我們有了health check scripts and JQ我們就可以從我們自己的consul image做health check了。我們也有一個本地註冊表運行鏡像在創建後,我們只是標記生成的鏡像,並將其推到我們的本地註冊表

1 $ docker build .
2 ...
3 $ docker tag a3157e9edc18 <local-registry>/consul-local:some-tag
4 $ docker push <local-registry>/consul-local:some-tag
1 $ dockerbuild .
2 ...
3 $ dockertaga3157e9edc18 <local-registry>/consul-local:some-tag
4 $ dockerpush <local-registry>/consul-local:some-tag

現在,它可以提供給我們的開發者了。並且也可在我們的不同的測試環境中使用。

5. 訪問遠程主機的Docker

Docker的CLI是一個非常酷的工具,其中一個很大的特點是,你可以用它來輕松地訪問多Docker守護進程,即使它們在不同的主機。你需要做的就是設置DOCKER_HOST環境變量指向Docker daemon的監聽地址。如果該端口是可以的訪問,你可以直接在遠程主機上的Docker,這和你運行一個Docker daemon ,並設置為通過docker-machine幾乎相同的原理。

1 $ docker-machine env demo
2 export DOCKER_TLS_VERIFY="1"
3 export DOCKER_HOST="tcp://192.168.99.100:2376"
4 export DOCKER_CERT_PATH="/users/jos/.docker/machine/machines/demo"
5 export DOCKER_MACHINE_NAME="demo"
1 $ docker-machineenvdemo
2 exportDOCKER_TLS_VERIFY="1"
3 exportDOCKER_HOST="tcp://192.168.99.100:2376"
4 exportDOCKER_CERT_PATH="/Users/jos/.docker/machine/machines/demo"
5 exportDOCKER_MACHINE_NAME="demo"

但你不必限制自己Docker daemons 程通過docker-machine啟動。如果你有你的後臺程序運行的控制,以及安全的網絡,你可以很容易地從一臺機器控制所有的。

6. 簡單的主機目錄掛載

當你正在使用你的容器,你有時需要得到容器裏面的一些數據。您可以復制它,或者通過使用ssh命令。但多數情況下是最容易的是將一個主機目錄添加容器中。可以很容易地通過執行下面的命令完成操作:

01 mkdir /Users/jos/temp/samplevolume/
02 ls /Users/jos/temp/samplevolume/
03 $ docker run -v /Users/jos/temp/samplevolume/:/samplevolume  -it --rm busybox
04 $ docker run -v /Users/jos/temp/samplevolume/:/samplevolume  -it --rm busybox
05 # ls samplevolume/
06 # touch samplevolume/hello
07 # ls samplevolume/
08 hello
09 # exit
10 ls /Users/jos/temp/samplevolume/
11 hello
01 mkdir /Users/jos/temp/samplevolume/
02 ls /Users/jos/temp/samplevolume/
03 $ dockerrun -v /Users/jos/temp/samplevolume/:/samplevolume  -it --rmbusybox
04 $ dockerrun -v /Users/jos/temp/samplevolume/:/samplevolume  -it --rmbusybox
05 # ls samplevolume/
06 # touch samplevolume/hello
07 # ls samplevolume/
08 hello
09 # exit
10 ls /Users/jos/temp/samplevolume/
11 hello

你可以看到我們指定的目錄安裝在容器內,而且我們把所有的文件都在主機上,並在容器內可見。我們也可以使用inspect查看,看看有什麽安裝在哪裏。

1 $ docker inspect 76465cee5d49 | jq '.[].Mounts'
2 [
3   {
4     "Source""/Users/jos/temp/samplevolume",
5     "Destination""/samplevolume",
6     "Mode""",
7     "RW"true
8   }
9 ]
1 $ dockerinspect 76465cee5d49 | jq '.[].Mounts'
2 [
3   {
4     "Source""/Users/jos/temp/samplevolume",
5     "Destination""/samplevolume",
6     "Mode""",
7     "RW"true
8   }
9 ]

我們可以在Docker官網看到更多的特性和使用方 法: https://docs.docker.com/engine/userguide/dockervolumes/

7.添加DNS解析到你的容器

我之前提到過,我們可以通過consul來管理容器。Consul是一個支持多數據中心分布式高可用的服務發現和配置共享的服務軟件,可以為容器提供服務發現和健康檢查。對於服務發現Consul提供無論是REST API或傳統DNS,他的偉大的之處是,當你運行一個具體的鏡像,你可以指定你的容器DNS服務器。

当你有Consul运行(或者其它 DNS server)你可以把它添加到您的Docker daemon就像这样:

1 docker run -d --dns $IP_CONSUL --dns-search service.consul <rest of confguration>
1 dockerrun -d --dns $IP_CONSUL --dns-searchservice.consul <restofconfguration>

現在,我們可以解決與Consul的名字註冊的所有容器的IP地址,比如在我們的環境我們有了一個cassandra 集群。每個cassandra將自己註冊名稱為“cassandra”我們的Consul 集群。最酷的是,我們現在只是解決卡cassandra的地址基於主機名(而不必使用Docker鏈接)

1 $ docker exec -ti 00c22e9e7c4e bash
2 daemon@00c22e9e7c4e:/opt/docker$ ping cassandra
3 PING cassandra.service.consul (192.168.99.100): 56 data bytes
4 64 bytes from 192.168.99.100: icmp_seq=0 ttl=64 time=0.053 ms
5 64 bytes from 192.168.99.100: icmp_seq=1 ttl=64 time=0.077 ms
6 ^C--- cassandra.service.consul ping statistics ---
7 2 packets transmitted, 2 packets received, 0% packet loss
8 round-trip min/avg/max/stddev = 0.053/0.065/0.077/0.000 ms
9 daemon@00c22e9e7c4e:/opt/docker$
1 $ dockerexec -ti 00c22e9e7c4e bash
2 daemon@00c22e9e7c4e:/opt/docker$ pingcassandra
3 PINGcassandra.service.consul (192.168.99.100): 56 databytes
4 64 bytesfrom 192.168.99.100: icmp_seq=0 ttl=64 time=0.053 ms
5 64 bytesfrom 192.168.99.100: icmp_seq=1 ttl=64 time=0.077 ms
6 ^C--- cassandra.service.consulpingstatistics ---
7 2 packetstransmitted, 2 packetsreceived, 0% packetloss
8 round-tripmin/avg/max/stddev = 0.053/0.065/0.077/0.000 ms
9 daemon@00c22e9e7c4e:/opt/docker$

8. Docker-UI是一個很棒來查看和獲取洞察你容器的方式

使用Docker CLI來查看Docker容器所發生的一切並不難。很多時候,雖然你並不需要的Docker CLI的全部功能,但只是想快速瀏覽其中的容器運行,看看發生了什麽。Docker UI ( https://github.com/crosbymichael/dockerui )就是一個這樣偉大的項目,並且他是開源的

10个日常Docker使用技巧

有了這個工具,你可以看到一個特定的Docker deamon的容器和鏡像的最重要的東西。

9. Container 不能啟動? Overwrite the Entry Point你只需要從bash啟動。

有時候一個容器只是沒有做你想要它做的事情,你已經重新創建了Docker 鏡像,你在啟動時運行了幾次,但不知何故,該應用程序沒有反應,然後日誌顯示也沒什麽有用的信息。最簡單的調試方法是overwrite the entry point ,看看在容器內部發生的一切,查看文件權限是否正確。拷貝進入鏡像的文件是否正確,或者任何其它可能出現的錯誤。幸運的是,Docker有這樣做的一個簡單的解決方案。你可以從一個選擇的入口點啟動你的容器:

1 $ docker run -ti --entrypoint=bash cassandra
2 root@896757f0bfd4:/# ls
3 bin   dev    etc   lib mediaopt   root  sbin  sys  usr
4 boot  docker-entrypoint.sh  home  lib64  mntproc  run   srv   tmp  var
5 root@896757f0bfd4:/#
1 $ dockerrun -ti --entrypoint=bashcassandra
2 root@896757f0bfd4:/# ls
3 bin  dev    etc  libmediaopt  root  sbin  sys  usr
4 boot  docker-entrypoint.sh  home  lib64  mntproc  run  srv  tmp  var
5 root@896757f0bfd4:/#

10. 監聽一個容器的事件:

當你編寫自己的腳本,或者只是想了解發生了什麽,你可以Docker event command運行你的鏡像,為此編寫腳本很容易。

10个日常Docker使用技巧

這是我們沒有使用Docker Compose 和Swarm yet和Docker 1.9網絡層 特性的情況,Docker一個很酷的工具,有一套偉大的工具。在未來希望Docker越來越好,我也會給大家展示一些Docker更酷的東西。

延伸阅读

    评论