Launching multiple containers manually can be a hassle, especially when the infrastructure goes increasingly complex. Dependencies, shared variables, and common networking can be easily handled with the orchestration tool named Docker Compose. In a simply YAML file, we can describe what services are needed to run our application (proxy, application, databases, and so on). In this section, we'll show how to create a simple LAMP docker-compose file, then we'll show how we can iterate from that to build some staging and production specific changes.
To step through this recipe, you will need the following:
To orchestrate multiple containers together using Docker Compose, let's start with an easy WordPress example. The team at WordPress built a container that auto-configures to some extent through environment variables similar to what we saw earlier in this chapter. If we just apply the documentation shipped with the WordPress Docker container, we end up with the following docker-compose.yml
at the root of some new directory (it can be a Git repository if needed):
version: '2' services: wordpress: image: wordpress ports: - 8080:80 environment: WORDPRESS_DB_PASSWORD: example mysql: image: mariadb environment: MYSQL_ROOT_PASSWORD: example
This has the great advantage to work out of the box; the latest WordPress and MariaDB images get downloaded, local HTTP port 80 gets redirected on port 8080 on the host, and MySQL stays isolated. The WordPress container takes one environment variable in this case—the MySQL root password, which should match the environment variable from MySQL. We'll see that many more are possible.
Executing Docker Compose will automatically create a Docker network and run the containers:
$ docker-compose up [...] mysql_1 | 2016-12-01 20:51:14 139820361766848 [Note] mysqld (mysqld 10.1.19-MariaDB-1~jessie) starting as process 1 ... [...] mysql_1 | 2016-12-01 20:51:15 139820361766848 [Note] mysqld: ready for connections. [...] wordpress_1 | [Thu Dec 01 20:51:17.865932 2016] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.10 (Debian) PHP/5.6.28 configured -- resuming normal operations wordpress_1 | [Thu Dec 01 20:51:17.865980 2016] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
Let's verify we can connect to the WordPress HTTP server locally, on the redirected port 8080
:
$ curl -IL http://localhost:8080 HTTP/1.1 302 Found [...] HTTP/1.1 200 OK [...]
More information can be seen using the ps
command:
$ docker-compose ps Name Command State Ports ----------------------------------------------------------------------------------- 1basics_mysql_1 docker-entrypoint.sh mysqld Up 3306/tcp 1basics_wordpress_1 docker-entrypoint.sh apach ... Up 0.0.0.0:8080->80/tcp
Let's ensure the password used for the MySQL root password is really the one provided by the docker-compose.yml
file, using the docker-compose exec
command, very similar to the docker run
command (it takes docker-compose.yml
names):
$ docker-compose exec mysql /usr/bin/mysql -uroot -pexample [...] MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | wordpress | +--------------------+ 4 rows in set (0.00 sec)
When we're done with our initial Docker Compose environment, let's destroy it; the containers and networks will be removed:
$ docker-compose down
Now we know the basics, let's extend the usage a little. We're not happy with the default password and would like to use a better one, so simulate the staging environment. Let's use the overriding feature of Docker Compose for that and create a docker-compose.staging.yml
file that will simply override the concerned values:
version: '2' services: wordpress: image: wordpress:4.6 environment: WORDPRESS_DB_PASSWORD: s3cur3 mysql: environment: MYSQL_ROOT_PASSWORD: s3cur3
The two environment variables WORDPRESS_DB_PASSWORD
and MYSQL_ROOT_PASSWORD
will be overridden when docker-compose
is executed with multiple configuration files taken in order:
$ docker-compose -f docker-compose.yml -f docker-compose.staging.yml up
Verify that the new password is indeed working for MySQL:
$ docker exec -it 1basics_mysql_1 mysql -uroot -ps3cur3 Welcome to the MariaDB monitor. Commands end with ; or g. Your MariaDB connection id is 4
We're very easily overriding values with simple YAML files!
Suppose that we now want to include a reverse proxy to the mix, with a slightly earlier version of the Docker image and another MySQL password, to mimic a specific situation we have in production. We can use the excellent dynamic Nginx image from jwilder/nginx-proxy
to do this job and add a new proxy service, sharing port 80
and the local Docker socket as read-only (to dynamically access running containers) on a docker-compose.production.yml
file:
proxy: image: jwilder/nginx-proxy ports: - "80:80" volumes: - /var/run/docker.sock:/tmp/docker.sock:ro
This nginx-proxy
container needs a variable named VIRTUAL_HOST
to know what to answer in case of multiple virtual hosts. Let's add it as localhost (or adapt to your local hostname), along with the better password and the WordPress image version:
wordpress: image: wordpress:4.5 environment: WORDPRESS_DB_PASSWORD: sup3rs3cur3 VIRTUAL_HOST: localhost
Make the password match in the MySQL section as well and we'll be done with our production environment simulation:
$ docker-compose -f docker-compose.yml -f docker-compose.production.yml up
Confirm nginx-proxy
is answering in HTTP/80
and forwarding a proper HTTP answer from the WordPress container:
$ curl -IL http://localhost/ HTTP/1.1 302 Found Server: nginx/1.11.3 [...] HTTP/1.1 200 OK Server: nginx/1.11.3
We've seen how, with only a few lines of YAML, we can easily orchestrate containers, how it can be used to handle different cases and environments, and how it can also be successfully extended. This is, however, just a small introduction to what can be done with Docker Compose—it's quite a powerful tool!
3.144.97.216