The number 1 problem faced by people trying to use Docker in production today is how to run multi-server Docker apps. Docker's linking mechanism only works within a single-host environment, so if (for example) you want to link your database to your wordpress, they have to be on the same host. But there is a new ops pattern being established to fix this problem. It is called ambassadors. Both Docker and CoreOS have tutorials [1, 2] for using the ambassador pattern. So what are ambassadors?

Ambassadors are containers who's sole purpose is to help connect containers across multiple hosts.

If you think of each container as it's own country, the ambassador of the country is in charge of communicating with foreign countries. How's that for explaining a self-explanatory metaphor?

Here's a visual representation of this metaphor: (container) --> (local ambassador) --network--> (foreign ambassador) --> (container)

The docker -link command works well within a single Docker host, but when your app needs to scale across multiple servers, linking gets you nowhere. This is where ambassadors come in.

How to Run a Simple Ambassador

There is a clever little one-liner container based on busybox called ctlc/ambassador which sets up a simple reverse-proxy with socat. First, you need to create the basic service container (let's say MySQL):

$ docker run -d -name mysql ctlc/mysql

Notice that we are not exposing the MySQL port to the external world here. That's the ambassador's job, not the service's. Now, your service container needs an ambassador on the same host:

$ docker run -t -i -link mysql:mysql -name mysql_ambassador -p 3306:3306 ctlc/ambassador

Finally, run this command on a totally separate server to create a "Foreign Ambassador" for your MySQL service:

$ docker run -t -i -name mysql_ambassador -expose 3306 -e MYSQL_PORT_3306_TCP=tcp://192.168.1.52:3306 ctlc/ambassador

The end result is a socat proxy running this little reverse proxy:

socat TCP4-LISTEN:3306,fork,reuseaddr TCP4:192.168.1.52:3306

Notice that the 192.168.1.52 IP address should be an address accessible to the foreign host, but ideally not to the entire world. In AWS, you would have to create a private network to do this. In CenturyLink Cloud, you get subnets for free by default, so this is less work.

How to Build a 2-Server WordPress with Ambassadors and Fig

If you've been following along our progress on the blog, we've been using Fig, Serf and Haproxy to build increasingly complex applications. Now we will finally explain how to create multi-server AND multi-container apps.

First, on your WordPress server, run fig up -d with this fig.yml:

ambassador:
    image: ctlc/ambassador
    ports:
     - 3306:3306
    links:
      - db
db:
    image: ctlc/mysql
    ports:
      - 3306 volumes:
      - /mysql:/var/lib/mysql
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_ROOT_PASSWORD: qa1N76pWAri9

Notice that we can link to the db-ambassador container as if it were the MySQL database itself. On the machine that runs your MySQL server, you will need to run fig up -d with its own fig.yml.

ambassador:
    image: ctlc/ambassador
    ports:
      - 3306:3306
    links:
      - db
db:
    image: ctlc/mysql
    ports:
      - 3306 volumes:
      - /mysql:/var/lib/mysql
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_ROOT_PASSWORD: qa1N76pWAri9

Now you have Docker containers on separate servers communicating with each other. Yay!

More Complex Ambassadors

What else can you do with ambassadors? The real power of ambassadors is when you use them to auto-discover services and to create audit and compliance barriers. Here are some of the cool things you can do:

  • Turn any container into a Serf-aware container (instead of doing it by hand)
  • Auto-register Docker services into CoreOS
  • Create audit and compliance barriers for your services
  • Scale complex multi-server Docker clusters
  • Centralized logging

For example: Imagine being able to enforce a compliance barrier that prevents DELETE actions to a MySQL database. Your ambassador can be more than a passive reverse-proxy and can enforce what actions your code can take with your services.

Conclusion

In future posts, we will dig into showing exactly how to go beyond this simple example. We will show you how to turn any container on the Docker Hub into a Serf-aware container and how to incorporate any container image into CoreOS's etcd. We will also talk about how to do audit and compliance with ambassadors. Join the mailing list to make sure you get updates when these posts are made.