Docker container linking is important concept to understand since any application in production will typically run on a cluster of containers across multiple hosts. But simple container linking does not allow cross-host communication.
Whats the issue with Docker container linking?
Docker containers can communicate with each other be manually linking as shown in Tech Tip #66 or orchestrated using Fig as shown in Tech Tip #68. Both of these using container linking but that has an inherent disadvantage that it is restricted to a single host. Linking does not work if containers are running across multiple hosts.
What is the solution?
Docker container linking across multiple hosts can be easily done by explicitly publishing the host/port and using it from a container on a different host.
Lets get started!
- Start MySQL container as:
123docker run --name mysqldb -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -p 5306:3306 -d mysql
The MySQL container is explicitly forwarding the port
- Git repo has customization/execute.sh that creates the MySQL data source. The command looks like:
123data-source add --name=mysqlDS --driver-name=mysql --jndi-name=java:jboss/datasources/ExampleMySQLDS --connection-url=jdbc:mysql://$DB_PORT_3306_TCP_ADDR:$DB_PORT_3306_TCP_PORT/sample?useUnicode=true&characterEncoding=UTF-8 --user-name=mysql --password=mysql --use-ccm=false --max-pool-size=25 --blocking-timeout-wait-millis=5000 --enabled=true
This command creates the JDBC resource for WildFly using jboss-cli. It is using
$DB_PORT_3306_TCP_PORTvariables which are defined per Container Linking Environment Variables. The scheme by which the environment variables for containers are created is rather weird. It exposes the port number in the variable name itself. I hope this improves in subsequent releases.
This command needs to be updated such that an explicit host/port can be used instead.
So update the command to:123data-source add --name=mysqlDS --driver-name=mysql --jndi-name=java:jboss/datasources/ExampleMySQLDS --connection-url=jdbc:mysql://$MYSQL_HOST:$MYSQL_PORT/sample?useUnicode=true&characterEncoding=UTF-8 --user-name=mysql --password=mysql --use-ccm=false --max-pool-size=25 --blocking-timeout-wait-millis=5000 --enabled=true
The only change in the command is to use
$MYSQL_PORTvariables. This command already exists in the file but is commented. So just comment the previous one and uncomment this one.
- Build the image and run it as:
1234docker build -t arungupta/wildfly-mysql-javaee7 .docker run --name mywildfly -e MYSQL_HOST=<IP_ADDRESS> -e MYSQL_PORT=5306 -p 8080:8080 -d arungupta/wildfly-mysql-javaee7
Make sure to substitute
<IP_ADDRESS>with the IP address of your host. For convenience, I ran it on the same host. The IP address in this case can be easily obtained using
- A quick verification of the deployment can be done by accessing the REST endpoint:
1234curl http://192.168.59.103:8080/employees/resources/employees/<?xml version="1.0" encoding="UTF-8" standalone="yes"?><collection><employee><id>1</id><name>Penny</name></employee><employee><id>2</id><name>Sheldon</name></employee><employee><id>3</id><name>Amy</name></employee><employee><id>4</id><name>Leonard</name></employee><employee><id>5</id><name>Bernadette</name></employee><employee><id>6</id><name>Raj</name></employee><employee><id>7</id><name>Howard</name></employee><employee><id>8</id><name>Priya</name></employee></collection>
With this, your WildFly and MySQL can run on two separate hosts, no special configuration required.
Docker allows cross-host container linking using Ambassador Containers but that adds a redundant hop for the service to be accessed. A cleaner solution would to use Kubernetes or Swarm, more on that later.
Marek also blogged about a more elaborate solution in Connecting Docker Containers on Multiple Hosts.