github.com/boynux/docker@v1.11.0-rc4/docs/admin/ambassador_pattern_linking.md (about)

     1  <!--[metadata]>
     2  +++
     3  aliases = ["/engine/articles/ambassador_pattern_linking/"]
     4  title = "Link via an ambassador container"
     5  description = "Using the Ambassador pattern to abstract (network) services"
     6  keywords = ["Examples, Usage, links, docker, documentation, examples, names, name,  container naming"]
     7  [menu.main]
     8  parent = "engine_admin"
     9  weight = 6
    10  +++
    11  <![end-metadata]-->
    12  
    13  # Link via an ambassador container
    14  
    15  Rather than hardcoding network links between a service consumer and
    16  provider, Docker encourages service portability, for example instead of:
    17  
    18      (consumer) --> (redis)
    19  
    20  Requiring you to restart the `consumer` to attach it to a different
    21  `redis` service, you can add ambassadors:
    22  
    23      (consumer) --> (redis-ambassador) --> (redis)
    24  
    25  Or
    26  
    27      (consumer) --> (redis-ambassador) ---network---> (redis-ambassador) --> (redis)
    28  
    29  When you need to rewire your consumer to talk to a different Redis
    30  server, you can just restart the `redis-ambassador` container that the
    31  consumer is connected to.
    32  
    33  This pattern also allows you to transparently move the Redis server to a
    34  different docker host from the consumer.
    35  
    36  Using the `svendowideit/ambassador` container, the link wiring is
    37  controlled entirely from the `docker run` parameters.
    38  
    39  ## Two host example
    40  
    41  Start actual Redis server on one Docker host
    42  
    43      big-server $ docker run -d --name redis crosbymichael/redis
    44  
    45  Then add an ambassador linked to the Redis server, mapping a port to the
    46  outside world
    47  
    48      big-server $ docker run -d --link redis:redis --name redis_ambassador -p 6379:6379 svendowideit/ambassador
    49  
    50  On the other host, you can set up another ambassador setting environment
    51  variables for each remote port we want to proxy to the `big-server`
    52  
    53      client-server $ docker run -d --name redis_ambassador --expose 6379 -e REDIS_PORT_6379_TCP=tcp://192.168.1.52:6379 svendowideit/ambassador
    54  
    55  Then on the `client-server` host, you can use a Redis client container
    56  to talk to the remote Redis server, just by linking to the local Redis
    57  ambassador.
    58  
    59      client-server $ docker run -i -t --rm --link redis_ambassador:redis relateiq/redis-cli
    60      redis 172.17.0.160:6379> ping
    61      PONG
    62  
    63  ## How it works
    64  
    65  The following example shows what the `svendowideit/ambassador` container
    66  does automatically (with a tiny amount of `sed`)
    67  
    68  On the Docker host (192.168.1.52) that Redis will run on:
    69  
    70      # start actual redis server
    71      $ docker run -d --name redis crosbymichael/redis
    72  
    73      # get a redis-cli container for connection testing
    74      $ docker pull relateiq/redis-cli
    75  
    76      # test the redis server by talking to it directly
    77      $ docker run -t -i --rm --link redis:redis relateiq/redis-cli
    78      redis 172.17.0.136:6379> ping
    79      PONG
    80      ^D
    81  
    82      # add redis ambassador
    83      $ docker run -t -i --link redis:redis --name redis_ambassador -p 6379:6379 alpine:3.2 sh
    84  
    85  In the `redis_ambassador` container, you can see the linked Redis
    86  containers `env`:
    87  
    88      / # env
    89      REDIS_PORT=tcp://172.17.0.136:6379
    90      REDIS_PORT_6379_TCP_ADDR=172.17.0.136
    91      REDIS_NAME=/redis_ambassador/redis
    92      HOSTNAME=19d7adf4705e
    93      SHLVL=1
    94      HOME=/root
    95      REDIS_PORT_6379_TCP_PORT=6379
    96      REDIS_PORT_6379_TCP_PROTO=tcp
    97      REDIS_PORT_6379_TCP=tcp://172.17.0.136:6379
    98      TERM=xterm
    99      PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
   100      PWD=/
   101      / # exit
   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      $ CMD="apk update && apk add socat && sh"
   108      $ docker run -t -i --link redis:redis --name redis_ambassador -p 6379:6379 alpine:3.2 sh -c "$CMD"
   109      [...]
   110      / # socat -t 100000000 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      $ CMD="apk update && apk add socat && sh"
   117      $ docker run -t -i --expose 6379 --name redis_ambassador alpine:3.2 sh -c "$CMD"
   118      [...]
   119      / # socat -t 100000000 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 based on the `alpine:3.2` image with
   131  `socat` installed. 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      # do
   143      #   docker build -t svendowideit/ambassador .
   144      # then to run it (on the host that has the real backend on it)
   145      #   docker run -t -i -link redis:redis -name redis_ambassador -p 6379:6379 svendowideit/ambassador
   146      # on the remote host, you can set up another ambassador
   147      #    docker run -t -i -name redis_ambassador -expose 6379 -e REDIS_PORT_6379_TCP=tcp://192.168.1.52:6379 svendowideit/ambassador sh
   148      # you can read more about this process at https://docs.docker.com/articles/ambassador_pattern_linking/
   149  
   150      # use alpine because its a minimal image with a package manager.
   151      # prettymuch all that is needed is a container that has a functioning env and socat (or equivalent)
   152      FROM	alpine:3.2
   153      MAINTAINER	SvenDowideit@home.org.au
   154  
   155      RUN apk update && \
   156      	apk add socat && \
   157      	rm -r /var/cache/
   158  
   159      CMD	env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' && echo wait) | sh