github.com/netbrain/docker@v1.9.0-rc2/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 alpine:3.2 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      SHLVL=1
    95      HOME=/root
    96      REDIS_PORT_6379_TCP_PORT=6379
    97      REDIS_PORT_6379_TCP_PROTO=tcp
    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      / # exit
   103  
   104  This environment is used by the ambassador `socat` script to expose Redis
   105  to the world (via the `-p 6379:6379` port mapping):
   106  
   107      $ docker rm redis_ambassador
   108      $ CMD="apk update && apk add socat && sh"
   109      $ docker run -t -i --link redis:redis --name redis_ambassador -p 6379:6379 alpine:3.2 sh -c "$CMD"
   110      [...]
   111      / # socat -t 100000000 TCP4-LISTEN:6379,fork,reuseaddr TCP4:172.17.0.136:6379
   112  
   113  Now ping the Redis server via the ambassador:
   114  
   115  Now go to a different server:
   116  
   117      $ CMD="apk update && apk add socat && sh"
   118      $ docker run -t -i --expose 6379 --name redis_ambassador alpine:3.2 sh -c "$CMD"
   119      [...]
   120      / # socat -t 100000000 TCP4-LISTEN:6379,fork,reuseaddr TCP4:192.168.1.52:6379
   121  
   122  And get the `redis-cli` image so we can talk over the ambassador bridge.
   123  
   124      $ docker pull relateiq/redis-cli
   125      $ docker run -i -t --rm --link redis_ambassador:redis relateiq/redis-cli
   126      redis 172.17.0.160:6379> ping
   127      PONG
   128  
   129  ## The svendowideit/ambassador Dockerfile
   130  
   131  The `svendowideit/ambassador` image is based on the `alpine:3.2` image with
   132  `socat` installed. When you start the container, it uses a small `sed`
   133  script to parse out the (possibly multiple) link environment variables
   134  to set up the port forwarding. On the remote host, you need to set the
   135  variable using the `-e` command line option.
   136  
   137      --expose 1234 -e REDIS_PORT_1234_TCP=tcp://192.168.1.52:6379
   138  
   139  Will forward the local `1234` port to the remote IP and port, in this
   140  case `192.168.1.52:6379`.
   141  
   142      #
   143      # do
   144      #   docker build -t svendowideit/ambassador .
   145      # then to run it (on the host that has the real backend on it)
   146      #   docker run -t -i -link redis:redis -name redis_ambassador -p 6379:6379 svendowideit/ambassador
   147      # on the remote host, you can set up another ambassador
   148      #    docker run -t -i -name redis_ambassador -expose 6379 -e REDIS_PORT_6379_TCP=tcp://192.168.1.52:6379 svendowideit/ambassador sh
   149      # you can read more about this process at https://docs.docker.com/articles/ambassador_pattern_linking/
   150  
   151      # use alpine because its a minimal image with a package manager.
   152      # prettymuch all that is needed is a container that has a functioning env and socat (or equivalent)
   153      FROM	alpine:3.2
   154      MAINTAINER	SvenDowideit@home.org.au
   155  
   156      RUN apk update && \
   157      	apk add socat && \
   158      	rm -r /var/cache/
   159  
   160      CMD	env | grep _TCP= | sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \& wait/' | sh