Docker Container Linking

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介:
前面有一篇关于docker 通过DNAT将container的端口映射出来的效率问题.
本文将讲一下container之间的通讯方法, 除了使用-p或-P将端口映射出来, 还可以使用--link, 连接多个container.
(--link 其实也是通过IP通讯的(通过虚拟网桥管理, 或者使用openvswitch), 只是docker会自动维护一些变量和主机名, 方便使用者使用)

以一个例子来讲解 : 

首先启动一个container, 注意我们这里没有使用--name指定名字. 也没有使用-p或-P做DNAT映射.
[root@db-172-16-3-221 ~]# docker run -d postgres:9.3.5
64366c42153653adf595242b1f36dca189ea671aed24a3d642bf104a49b7359d
[root@db-172-16-3-221 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
64366c421536        postgres:9          /docker-entrypoint.s   2 seconds ago       Up 1 seconds        5432/tcp            dreamy_ptolemy 

查看这个container的网络 : 
[root@db-172-16-3-221 ~]# docker inspect 64366c421536
[{
    "Args": [
        "postgres"
    ],
    "Config": {
        "AttachStderr": false,
        "AttachStdin": false,
        "AttachStdout": false,
        "Cmd": [
            "postgres"
        ],
        "CpuShares": 0,
        "Cpuset": "",
        "Domainname": "",
        "Entrypoint": [
            "/docker-entrypoint.sh"
        ],
        "Env": [
            "PATH=/usr/lib/postgresql/9.3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
            "LANG=en_US.utf8",
            "PG_MAJOR=9.3",
            "PG_VERSION=9.3.5-1.pgdg70+1",
            "PGDATA=/var/lib/postgresql/data"
        ],
        "ExposedPorts": {
            "5432/tcp": {}
        },
        "Hostname": "64366c421536",
        "Image": "postgres:9.3.5",
        "Memory": 0,
        "MemorySwap": 0,
        "NetworkDisabled": false,
        "OnBuild": null,
        "OpenStdin": false,
        "PortSpecs": null,
        "StdinOnce": false,
        "Tty": false,
        "User": "",
        "Volumes": {
            "/var/lib/postgresql/data": {}
        },
        "WorkingDir": ""
    },
    "Created": "2014-10-27T02:26:37.738875408Z",
    "Driver": "devicemapper",
    "ExecDriver": "native-0.2",
    "HostConfig": {
        "Binds": null,
        "ContainerIDFile": "",
        "Dns": null,
        "DnsSearch": null,
        "Links": null,
        "LxcConf": [],
        "NetworkMode": "bridge",
        "PortBindings": {},
        "Privileged": false,
        "PublishAllPorts": false,
        "VolumesFrom": null
    },
    "HostnamePath": "/var/lib/docker/containers/64366c42153653adf595242b1f36dca189ea671aed24a3d642bf104a49b7359d/hostname",
    "HostsPath": "/var/lib/docker/containers/64366c42153653adf595242b1f36dca189ea671aed24a3d642bf104a49b7359d/hosts",
    "Id": "64366c42153653adf595242b1f36dca189ea671aed24a3d642bf104a49b7359d",
    "Image": "935836384c524aafc0ac1c05246002c9c93343f0b4283a34e77a5f92f97f9a7c",
    "MountLabel": "",
    "Name": "/dreamy_ptolemy",
    "NetworkSettings": {
        "Bridge": "docker0",
        "Gateway": "172.17.42.1",
        "IPAddress": "172.17.0.13",
        "IPPrefixLen": 16,
        "PortMapping": null,
        "Ports": {
            "5432/tcp": null
        }
    },
    "Path": "/docker-entrypoint.sh",
    "ProcessLabel": "",
    "ResolvConfPath": "/etc/resolv.conf",
    "State": {
        "ExitCode": 0,
        "FinishedAt": "0001-01-01T00:00:00Z",
        "Paused": false,
        "Pid": 8584,
        "Running": true,
        "StartedAt": "2014-10-27T02:26:38.525831218Z"
    },
    "Volumes": {
        "/var/lib/postgresql/data": "/var/lib/docker/vfs/dir/52a3cbd99e3462e1fd8593d086d82bd86afa94c435ec0bc141872f7f5507144a"
    },
    "VolumesRW": {
        "/var/lib/postgresql/data": true
    }
}

在宿主机通过网络可以连接到container.
[root@db-172-16-3-221 ~]# ping 172.17.0.13
PING 172.17.0.13 (172.17.0.13) 56(84) bytes of data.
64 bytes from 172.17.0.13: icmp_seq=1 ttl=64 time=1.10 ms

[root@db-172-16-3-221 ~]# telnet 172.17.0.13 5432
Trying 172.17.0.13...
Connected to 172.17.0.13.
Escape character is '^]'.
quit
Connection closed by foreign host.


接下来启动另一个container, 使用--link来建立链接. 格式 : 
--link 源container_name:源container_alias

[root@db-172-16-3-221 ~]# docker run -t -i --link dreamy_ptolemy:db1 postgres:9.3.5 /bin/bash
root@3e76ddd8025c:/# ping 172.17.0.13
PING 172.17.0.13 (172.17.0.13): 48 data bytes
56 bytes from 172.17.0.13: icmp_seq=0 ttl=64 time=1.428 ms


在建立完连接后, 在当前的container可以看到两个变化, 
1. /etc/hosts
2. env

1. 自动在/etc/hosts中建立源container的条目, 主机名即alias.

172.17.0.13     db1

root@3e76ddd8025c:/# cat /etc/hosts
172.17.0.14     3e76ddd8025c
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.13     db1


2. 另外会自动创建环境变量 : 
以alias_开头的一些环境变量 : 

<name>_PORT_<port>_<protocol> will contain a URL reference to the port. Where <name> is the alias name specified in the --link parameter (e.g. webdb), <port> is the port number being exposed, and <protocol> is either TCP or UDP. The format of the URL will be: <protocol>://<container_ip_address>:<port> (e.g. tcp://172.17.0.82:8080). This URL will then be split into the following 3 environment variables for convinience:
<name>_PORT_<port>_<protocol>_ADDR will contain just the IP address from the URL (e.g. WEBDB_PORT_8080_TCP_ADDR=172.17.0.82).
<name>_PORT_<port>_<protocol>_PORT will contain just the port number from the URL (e.g. WEBDB_PORT_8080_TCP_PORT=8080).
<name>_PORT_<port>_<protocol>_PROTO will contain just the protocol from the URL (e.g. WEBDB_PORT_8080_TCP_PROTO=tcp).

例如 : 
DB1_NAME=/nostalgic_mclean/db1
DB1_PORT=tcp://172.17.0.13:5432
DB1_PORT_5432_TCP=tcp://172.17.0.13:5432
DB1_PORT_5432_TCP_PROTO=tcp
DB1_PORT_5432_TCP_ADDR=172.17.0.13
DB1_PORT_5432_TCP_PORT=5432
DB1_ENV_PGDATA=/var/lib/postgresql/data
DB1_ENV_LANG=en_US.utf8
DB1_ENV_PG_VERSION=9.3.5-1.pgdg70+1
DB1_ENV_PG_MAJOR=9.3


root@3e76ddd8025c:/# env
HOSTNAME=3e76ddd8025c
DB1_ENV_PG_VERSION=9.3.5-1.pgdg70+1
TERM=xterm
DB1_ENV_PG_MAJOR=9.3
DB1_PORT_5432_TCP_PORT=5432
PG_MAJOR=9.3
DB1_PORT_5432_TCP=tcp://172.17.0.13:5432
DB1_PORT_5432_TCP_ADDR=172.17.0.13
PATH=/usr/lib/postgresql/9.3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
DB1_ENV_PGDATA=/var/lib/postgresql/data
DB1_ENV_LANG=en_US.utf8
PWD=/
LANG=en_US.utf8
HOME=/
SHLVL=1
PG_VERSION=9.3.5-1.pgdg70+1
DB1_PORT=tcp://172.17.0.13:5432
PGDATA=/var/lib/postgresql/data
DB1_PORT_5432_TCP_PROTO=tcp
DB1_NAME=/nostalgic_mclean/db1
_=/usr/bin/env


其实--link主要的好处是维护了一个unique alias, 在container中连其他container, 使用alias即可, 而不需要知道IP是多少.
例如 : ping --link指定的alias即可.

root@3e76ddd8025c:/# ping db1
PING db1 (172.17.0.13): 48 data bytes
56 bytes from 172.17.0.13: icmp_seq=0 ttl=64 time=0.069 ms
56 bytes from 172.17.0.13: icmp_seq=1 ttl=64 time=0.076 ms

root@3e76ddd8025c:/# psql -h db1 -p 5432 -U postgres postgres
psql (9.3.5)
Type "help" for help.
postgres=# \q

测试一下在一个container中使用pgbench测试另一个container的数据库.
和在宿主机测试效率差不多.

root@3e76ddd8025c:/# echo "select 1;" >./test.sql
root@3e76ddd8025c:/# pgbench -M prepared -n -r -f ./test.sql -h db1 -p 5432 -U postgres -c 16 -j 4 -T 30 postgres
transaction type: Custom query
scaling factor: 1
query mode: prepared
number of clients: 16
number of threads: 4
duration: 30 s
number of transactions actually processed: 4528033
tps = 150932.697607 (including connections establishing)
tps = 151004.884662 (excluding connections establishing)
statement latencies in milliseconds:
        0.104734        select 1;


查看当前宿主机的iptables条目.
[root@db-172-16-3-221 ~]# iptables-save
# Generated by iptables-save v1.4.7 on Mon Oct 27 10:45:13 2014
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [1683:453100]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT 
-A INPUT -p icmp -j ACCEPT 
-A INPUT -i lo -j ACCEPT 
-A INPUT -s 192.168.0.0/16 -j ACCEPT 
-A INPUT -s 10.0.0.0/8 -j ACCEPT 
-A INPUT -s 172.16.0.0/16 -j ACCEPT 
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT 
-A INPUT -j REJECT --reject-with icmp-host-prohibited 
-A FORWARD -s 172.17.0.13/32 -d 172.17.0.14/32 -i docker0 -o docker0 -p tcp -m tcp --sport 5432 -j ACCEPT 
-A FORWARD -s 172.17.0.14/32 -d 172.17.0.13/32 -i docker0 -o docker0 -p tcp -m tcp --dport 5432 -j ACCEPT 
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT 
-A FORWARD -i docker0 -o docker0 -j ACCEPT 
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT 
-A FORWARD -i docker0 -o docker0 -j ACCEPT 
-A FORWARD -j REJECT --reject-with icmp-host-prohibited 
COMMIT
# Completed on Mon Oct 27 10:45:13 2014
# Generated by iptables-save v1.4.7 on Mon Oct 27 10:45:13 2014
*nat
:PREROUTING ACCEPT [543:173998]
:POSTROUTING ACCEPT [472:24624]
:OUTPUT ACCEPT [276:14384]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER 
-A POSTROUTING -s 172.17.0.0/16 ! -d 172.17.0.0/16 -j MASQUERADE 
-A POSTROUTING -s 172.17.0.0/16 ! -d 172.17.0.0/16 -j MASQUERADE 
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER 
COMMIT
# Completed on Mon Oct 27 10:45:13 2014

网桥信息 : 
[root@db-172-16-3-221 ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.12551bd59cad       no              veth6cb1
                                                        vetha6e7

[参考]
2. man docker-run

      -P,  -publish-all=true|false When set to true publish all exposed ports to the host interfaces.  The default is
       false.  If the operator uses -P (or -p) then Docker will make the exposed port accessible on the host  and  the
       ports  will be available to any client that can reach the host.  To find the map between the host ports and the
       exposed ports, use docker port.

       -p, -publish=[] Publish a container's port to the host (format: ip:hostPort:containerPort | ip::containerPort |
       hostPort:containerPort) (use docker port to see the actual mapping)

3.  http://blog.163.com/digoal@126/blog/static/163877040201492315242694/
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
1月前
|
缓存 自然语言处理 Docker
[Docker] DevContainer高效开发(第一篇):基于remote container开发
VS Code的Dev Containers简化了Python的容器化开发,将开发环境与应用一同打包在Docker中,消除环境配置问题。这种方式使得多语言、多版本开发变得整洁高效。
|
4月前
|
网络协议 应用服务中间件 nginx
一文详解Docker容器(Container)
一文详解Docker容器(Container)
|
5月前
|
Docker 容器
docker run 报错“Container XXX is restarting, wait until the container is running“
docker run 报错“Container XXX is restarting, wait until the container is running“
229 0
|
8月前
|
负载均衡 安全 Linux
【Docker】Docker network之bridge、host、none、container以及自定义网络的详细讲解
【Docker】Docker network之bridge、host、none、container以及自定义网络的详细讲解
326 0
|
9月前
|
Shell Docker Python
docker container的操作
docker container的操作
59 0
|
10月前
|
存储 缓存 固态存储
【Docker】浅谈Docker之AUFS、BTRFS、ZFS、Container、分层的概念
【Docker】浅谈Docker之AUFS、BTRFS、ZFS、Container、分层的概念
280 0
|
Docker 容器
Docker:查看container容器的 ip 地址
Docker:查看container容器的 ip 地址
710 0
|
Ubuntu Unix Linux
Docker 镜像(image)& 容器(container)
什么是 Docker 镜像(image)? 镜像由多个层组成,每层叠加之后,从外部看来就如一个独立的对象; 镜像内部是一个精简的操作系统(OS),同时还包含应用运行所必须的文件和依赖包; 镜像可以运行一个或多个容器,同时镜像也可以停止某个容器的运行,并从中创建新的镜像;【镜像(iamge)的分类】...
496 1
Docker 镜像(image)& 容器(container)
|
网络安全 Docker 容器
docker启动出现Error response from daemon: Cannot restart container的报错
docker启动出现Error response from daemon: Cannot restart container的报错
docker启动出现Error response from daemon: Cannot restart container的报错
|
Kubernetes 安全 Linux
From Docker to Kubernetes(一)- Image And Container
From Docker to Kubernetes(一)- Image And Container
From Docker to Kubernetes(一)- Image And Container