github.com/rsampaio/docker@v0.7.2-0.20150827203920-fdc73cc3fc31/experimental/compose_swarm_networking.md (about)

     1  # Experimental: Compose, Swarm and Multi-Host Networking
     2  
     3  The [experimental build of Docker](https://github.com/docker/docker/tree/master/experimental) has an entirely new networking system, which enables secure communication between containers on multiple hosts. In combination with Docker Swarm and Docker Compose, you can now run multi-container apps on multi-host clusters with the same tooling and configuration format you use to develop them locally.
     4  
     5  > Note: This functionality is in the experimental stage, and contains some hacks and workarounds which will be removed as it matures.
     6  
     7  ## Prerequisites
     8  
     9  Before you start, you’ll need to install the experimental build of Docker, and the latest versions of Machine and Compose.
    10  
    11  -   To install the experimental Docker build on a Linux machine, follow the instructions [here](https://github.com/docker/docker/tree/master/experimental#install-docker-experimental).
    12  
    13  -   To install the experimental Docker build on a Mac, run these commands:
    14  
    15          $ curl -L https://experimental.docker.com/builds/Darwin/x86_64/docker-latest > /usr/local/bin/docker
    16          $ chmod +x /usr/local/bin/docker
    17  
    18  -   To install Machine, follow the instructions [here](http://docs.docker.com/machine/).
    19  
    20  -   To install Compose, follow the instructions [here](http://docs.docker.com/compose/install/).
    21  
    22  You’ll also need a [Docker Hub](https://hub.docker.com/account/signup/) account and a [Digital Ocean](https://www.digitalocean.com/) account.  
    23  It works with the amazonec2 driver as well (by adapting the commands accordingly), except you'll need to manually open the ports 8500 (consul) and 7946 (serf) by editing the inbound rules of the corresponding security group.
    24  
    25  ## Set up a swarm with multi-host networking
    26  
    27  Set the `DIGITALOCEAN_ACCESS_TOKEN` environment variable to a valid Digital Ocean API token, which you can generate in the [API panel](https://cloud.digitalocean.com/settings/applications).
    28  
    29      export DIGITALOCEAN_ACCESS_TOKEN=abc12345
    30  
    31  Start a consul server:
    32  
    33      docker-machine --debug create \
    34          -d digitalocean \
    35          --engine-install-url="https://experimental.docker.com" \
    36          consul
    37  
    38      docker $(docker-machine config consul) run -d \
    39          -p "8500:8500" \
    40          -h "consul" \
    41          progrium/consul -server -bootstrap
    42  
    43  (In a real world setting you’d set up a distributed consul, but that’s beyond the scope of this guide!)
    44  
    45  Create a Swarm token:
    46  
    47      export SWARM_TOKEN=$(docker run swarm create)
    48  
    49  Next, you create a Swarm master with Machine: 
    50  
    51      docker-machine --debug create \
    52          -d digitalocean \
    53          --digitalocean-image="ubuntu-14-10-x64" \
    54          --engine-install-url="https://experimental.docker.com" \
    55          --engine-opt="default-network=overlay:multihost" \
    56          --engine-opt="kv-store=consul:$(docker-machine ip consul):8500" \
    57          --engine-label="com.docker.network.driver.overlay.bind_interface=eth0" \
    58          swarm-0
    59  
    60  Usually Machine can create Swarms for you, but it doesn't yet fully support multi-host networks yet, so you'll have to start up the Swarm manually:
    61  
    62      docker $(docker-machine config swarm-0) run -d \
    63          --restart="always" \
    64          --net="bridge" \
    65          swarm:latest join \
    66              --addr "$(docker-machine ip swarm-0):2376" \
    67              "token://$SWARM_TOKEN"
    68  
    69      docker $(docker-machine config swarm-0) run -d \
    70          --restart="always" \
    71          --net="bridge" \
    72          -p "3376:3376" \
    73          -v "/etc/docker:/etc/docker" \
    74          swarm:latest manage \
    75              --tlsverify \
    76              --tlscacert="/etc/docker/ca.pem" \
    77              --tlscert="/etc/docker/server.pem" \
    78              --tlskey="/etc/docker/server-key.pem" \
    79              -H "tcp://0.0.0.0:3376" \
    80              --strategy spread \
    81              "token://$SWARM_TOKEN"
    82  
    83  Create a Swarm node:
    84  
    85      docker-machine --debug create \
    86          -d digitalocean \
    87          --digitalocean-image="ubuntu-14-10-x64" \
    88          --engine-install-url="https://experimental.docker.com" \
    89          --engine-opt="default-network=overlay:multihost" \
    90          --engine-opt="kv-store=consul:$(docker-machine ip consul):8500" \
    91          --engine-label="com.docker.network.driver.overlay.bind_interface=eth0" \
    92          --engine-label="com.docker.network.driver.overlay.neighbor_ip=$(docker-machine ip swarm-0)" \
    93          swarm-1
    94  
    95      docker $(docker-machine config swarm-1) run -d \
    96          --restart="always" \
    97          --net="bridge" \
    98          swarm:latest join \
    99              --addr "$(docker-machine ip swarm-1):2376" \
   100              "token://$SWARM_TOKEN"
   101  
   102  You can create more Swarm nodes if you want - it’s best to give them sensible names (swarm-2, swarm-3, etc).
   103  
   104  Finally, point Docker at your swarm:
   105  
   106      export DOCKER_HOST=tcp://"$(docker-machine ip swarm-0):3376"
   107      export DOCKER_TLS_VERIFY=1
   108      export DOCKER_CERT_PATH="$HOME/.docker/machine/machines/swarm-0"
   109  
   110  ## Run containers and get them communicating
   111  
   112  Now that you’ve got a swarm up and running, you can create containers on it just like a single Docker instance:
   113  
   114      $ docker run busybox echo hello world
   115      hello world
   116  
   117  If you run `docker ps -a`, you can see what node that container was started on by looking at its name (here it’s swarm-3):
   118  
   119      $ docker ps -a
   120      CONTAINER ID        IMAGE                      COMMAND                CREATED              STATUS                      PORTS                                   NAMES
   121      41f59749737b        busybox                    "echo hello world"     15 seconds ago       Exited (0) 13 seconds ago                                           swarm-3/trusting_leakey
   122  
   123  As you start more containers, they’ll be placed on different nodes across the cluster, thanks to Swarm’s default “spread” scheduling strategy.
   124  
   125  Every container started on this swarm will use the “overlay:multihost” network by default, meaning they can all intercommunicate. Each container gets an IP address on that network, and an `/etc/hosts` file which will be updated on-the-fly with every other container’s IP address and name. That means that if you have a running container named ‘foo’, other containers can access it at the hostname ‘foo’.
   126  
   127  Let’s verify that multi-host networking is functioning. Start a long-running container:
   128  
   129      $ docker run -d --name long-running busybox top
   130      <container id>
   131  
   132  If you start a new container and inspect its /etc/hosts file, you’ll see the long-running container in there:
   133  
   134      $ docker run busybox cat /etc/hosts
   135      ...
   136      172.21.0.6  long-running
   137  
   138  Verify that connectivity works between containers:
   139  
   140      $ docker run busybox ping long-running
   141      PING long-running (172.21.0.6): 56 data bytes
   142      64 bytes from 172.21.0.6: seq=0 ttl=64 time=7.975 ms
   143      64 bytes from 172.21.0.6: seq=1 ttl=64 time=1.378 ms
   144      64 bytes from 172.21.0.6: seq=2 ttl=64 time=1.348 ms
   145      ^C
   146      --- long-running ping statistics ---
   147      3 packets transmitted, 3 packets received, 0% packet loss
   148      round-trip min/avg/max = 1.140/2.099/7.975 ms
   149  
   150  ## Run a Compose application
   151  
   152  Here’s an example of a simple Python + Redis app using multi-host networking on a swarm.
   153  
   154  Create a directory for the app:
   155  
   156      $ mkdir composetest
   157      $ cd composetest
   158  
   159  Inside this directory, create 2 files.
   160  
   161  First, create `app.py` - a simple web app that uses the Flask framework and increments a value in Redis:
   162  
   163      from flask import Flask
   164      from redis import Redis
   165      import os
   166      app = Flask(__name__)
   167      redis = Redis(host='composetest_redis_1', port=6379)
   168  
   169      @app.route('/')
   170      def hello():
   171          redis.incr('hits')
   172          return 'Hello World! I have been seen %s times.' % redis.get('hits')
   173  
   174      if __name__ == "__main__":
   175          app.run(host="0.0.0.0", debug=True)
   176  
   177  Note that we’re connecting to a host called `composetest_redis_1` - this is the name of the Redis container that Compose will start.
   178  
   179  Second, create a Dockerfile for the app container:
   180  
   181      FROM python:2.7
   182      RUN pip install flask redis
   183      ADD . /code
   184      WORKDIR /code
   185      CMD ["python", "app.py"]
   186  
   187  Build the Docker image and push it to the Hub (you’ll need a Hub account). Replace `<username>` with your Docker Hub username:
   188  
   189      $ docker build -t <username>/counter .
   190      $ docker push <username>/counter
   191  
   192  Next, create a `docker-compose.yml`, which defines the configuration for the web and redis containers. Once again, replace `<username>` with your Hub username:
   193  
   194      web:
   195        image: <username>/counter
   196        ports:
   197         - "80:5000"
   198      redis:
   199        image: redis
   200  
   201  Now start the app:
   202  
   203      $ docker-compose up -d
   204      Pulling web (username/counter:latest)...
   205      swarm-0: Pulling username/counter:latest... : downloaded
   206      swarm-2: Pulling username/counter:latest... : downloaded
   207      swarm-1: Pulling username/counter:latest... : downloaded
   208      swarm-3: Pulling username/counter:latest... : downloaded
   209      swarm-4: Pulling username/counter:latest... : downloaded
   210      Creating composetest_web_1...
   211      Pulling redis (redis:latest)...
   212      swarm-2: Pulling redis:latest... : downloaded
   213      swarm-1: Pulling redis:latest... : downloaded
   214      swarm-3: Pulling redis:latest... : downloaded
   215      swarm-4: Pulling redis:latest... : downloaded
   216      swarm-0: Pulling redis:latest... : downloaded
   217      Creating composetest_redis_1...
   218  
   219  Swarm has created containers for both web and redis, and placed them on different nodes, which you can check with `docker ps`:
   220  
   221      $ docker ps
   222      CONTAINER ID        IMAGE                      COMMAND                CREATED             STATUS              PORTS                                  NAMES
   223      92faad2135c9        redis                      "/entrypoint.sh redi   43 seconds ago      Up 42 seconds                                              swarm-2/composetest_redis_1
   224      adb809e5cdac        username/counter           "/bin/sh -c 'python    55 seconds ago      Up 54 seconds       45.67.8.9:80->5000/tcp                 swarm-1/composetest_web_1
   225  
   226  You can also see that the web container has exposed port 80 on its swarm node. If you curl that IP, you’ll get a response from the container:
   227  
   228      $ curl http://45.67.8.9
   229      Hello World! I have been seen 1 times.
   230  
   231  If you hit it repeatedly, the counter will increment, demonstrating that the web and redis container are communicating:
   232  
   233      $ curl http://45.67.8.9
   234      Hello World! I have been seen 2 times.
   235      $ curl http://45.67.8.9
   236      Hello World! I have been seen 3 times.
   237      $ curl http://45.67.8.9
   238      Hello World! I have been seen 4 times.