github.com/circular-dark/docker@v1.7.0/docs/articles/ambassador_pattern_linking.md (about) 1 <!--[metadata]> 2 +++ 3 title = "Link via an ambassador container" 4 description = "Using the Ambassador pattern to abstract (network) services" 5 keywords = ["Examples, Usage, links, docker, documentation, examples, names, name, container naming"] 6 [menu.main] 7 parent = "smn_administrate" 8 weight = 6 9 +++ 10 <![end-metadata]--> 11 12 # Link via an ambassador container 13 14 ## Introduction 15 16 Rather than hardcoding network links between a service consumer and 17 provider, Docker encourages service portability, for example instead of: 18 19 (consumer) --> (redis) 20 21 Requiring you to restart the `consumer` to attach it to a different 22 `redis` service, you can add ambassadors: 23 24 (consumer) --> (redis-ambassador) --> (redis) 25 26 Or 27 28 (consumer) --> (redis-ambassador) ---network---> (redis-ambassador) --> (redis) 29 30 When you need to rewire your consumer to talk to a different Redis 31 server, you can just restart the `redis-ambassador` container that the 32 consumer is connected to. 33 34 This pattern also allows you to transparently move the Redis server to a 35 different docker host from the consumer. 36 37 Using the `svendowideit/ambassador` container, the link wiring is 38 controlled entirely from the `docker run` parameters. 39 40 ## Two host example 41 42 Start actual Redis server on one Docker host 43 44 big-server $ docker run -d --name redis crosbymichael/redis 45 46 Then add an ambassador linked to the Redis server, mapping a port to the 47 outside world 48 49 big-server $ docker run -d --link redis:redis --name redis_ambassador -p 6379:6379 svendowideit/ambassador 50 51 On the other host, you can set up another ambassador setting environment 52 variables for each remote port we want to proxy to the `big-server` 53 54 client-server $ docker run -d --name redis_ambassador --expose 6379 -e REDIS_PORT_6379_TCP=tcp://192.168.1.52:6379 svendowideit/ambassador 55 56 Then on the `client-server` host, you can use a Redis client container 57 to talk to the remote Redis server, just by linking to the local Redis 58 ambassador. 59 60 client-server $ docker run -i -t --rm --link redis_ambassador:redis relateiq/redis-cli 61 redis 172.17.0.160:6379> ping 62 PONG 63 64 ## How it works 65 66 The following example shows what the `svendowideit/ambassador` container 67 does automatically (with a tiny amount of `sed`) 68 69 On the Docker host (192.168.1.52) that Redis will run on: 70 71 # start actual redis server 72 $ docker run -d --name redis crosbymichael/redis 73 74 # get a redis-cli container for connection testing 75 $ docker pull relateiq/redis-cli 76 77 # test the redis server by talking to it directly 78 $ docker run -t -i --rm --link redis:redis relateiq/redis-cli 79 redis 172.17.0.136:6379> ping 80 PONG 81 ^D 82 83 # add redis ambassador 84 $ docker run -t -i --link redis:redis --name redis_ambassador -p 6379:6379 busybox sh 85 86 In the `redis_ambassador` container, you can see the linked Redis 87 containers `env`: 88 89 $ env 90 REDIS_PORT=tcp://172.17.0.136:6379 91 REDIS_PORT_6379_TCP_ADDR=172.17.0.136 92 REDIS_NAME=/redis_ambassador/redis 93 HOSTNAME=19d7adf4705e 94 REDIS_PORT_6379_TCP_PORT=6379 95 HOME=/ 96 REDIS_PORT_6379_TCP_PROTO=tcp 97 container=lxc 98 REDIS_PORT_6379_TCP=tcp://172.17.0.136:6379 99 TERM=xterm 100 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 101 PWD=/ 102 103 This environment is used by the ambassador `socat` script to expose Redis 104 to the world (via the `-p 6379:6379` port mapping): 105 106 $ docker rm redis_ambassador 107 $ sudo ./contrib/mkimage-unittest.sh 108 $ docker run -t -i --link redis:redis --name redis_ambassador -p 6379:6379 docker-ut sh 109 110 $ socat TCP4-LISTEN:6379,fork,reuseaddr TCP4:172.17.0.136:6379 111 112 Now ping the Redis server via the ambassador: 113 114 Now go to a different server: 115 116 $ sudo ./contrib/mkimage-unittest.sh 117 $ docker run -t -i --expose 6379 --name redis_ambassador docker-ut sh 118 119 $ socat TCP4-LISTEN:6379,fork,reuseaddr TCP4:192.168.1.52:6379 120 121 And get the `redis-cli` image so we can talk over the ambassador bridge. 122 123 $ docker pull relateiq/redis-cli 124 $ docker run -i -t --rm --link redis_ambassador:redis relateiq/redis-cli 125 redis 172.17.0.160:6379> ping 126 PONG 127 128 ## The svendowideit/ambassador Dockerfile 129 130 The `svendowideit/ambassador` image is a small `busybox` image with 131 `socat` built in. When you start the container, it uses a small `sed` 132 script to parse out the (possibly multiple) link environment variables 133 to set up the port forwarding. On the remote host, you need to set the 134 variable using the `-e` command line option. 135 136 --expose 1234 -e REDIS_PORT_1234_TCP=tcp://192.168.1.52:6379 137 138 Will forward the local `1234` port to the remote IP and port, in this 139 case `192.168.1.52:6379`. 140 141 # 142 # 143 # first you need to build the docker-ut image 144 # using ./contrib/mkimage-unittest.sh 145 # then 146 # docker build -t SvenDowideit/ambassador . 147 # docker tag SvenDowideit/ambassador ambassador 148 # then to run it (on the host that has the real backend on it) 149 # docker run -t -i --link redis:redis --name redis_ambassador -p 6379:6379 ambassador 150 # on the remote host, you can set up another ambassador 151 # docker run -t -i --name redis_ambassador --expose 6379 sh 152 153 FROM docker-ut 154 MAINTAINER SvenDowideit@home.org.au 155 156 157 CMD env | grep _TCP= | sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' | sh && top