Skip to main content

Docker

https://github.com/docker/cli https://github.com/docker/compose

Docker is a platform for developing, shipping, and running applications in containers.

Scaffold provides a configuration for Docker and Docker Compose to run the project in all environments using containers.

Special thanks to Lagoon for providing the Docker images that make this possible.

info

Lagoon images are production-grade and are used in production environments. They receive regular updates and are maintained by the Lagoon team.

If you are using Lagoon as your hosting provider, then all of your environments are using identical images to run the project.

About Docker and Docker Compose

note

Below is a brief overview of Docker and Docker Compose. For more information, see the official documentation.

Docker is a technology that allows to define services such as a web server or a database server as standalone containers, which are then run in an isolated environment and can talk to each other.

The containers are started from images - templates that define what is installed in the container and how it is configured. Images allow to run containers with consistent content and configuration.

Docker is an engine that runs containers, built from images, allowing them to share host system resources and communicate to each other. When run locally, Docker can be controlled with Docker CLI command, called docker.

Docker Compose is a tool that allows to define and run multi-container Docker applications in a single docker-compose.yml file: multiple containers that work together can be described in a single file, which makes it easier to manage them.

When working with Drupal, which requires multiple service containers to run, a developer would normally use Docker Compose CLI commands (rather than Docker CLI commands) called docker compose. Note that this commands runs in the context of the current directory, so it is important to run them from the project root directory. This means that the issued commands will only affect the containers defined in the docker-compose.yml file in the current directory and will not affect any other containers running on the host.

When a project is fully configured, the usage of Docker-based application comes down to a handful of commands to manage the state of the containers (per project):

  • docker compose up -d - start the containers in the background.
  • docker compose down - stop and remove the containers.
  • docker compose exec <service> - run a command in a running <service> container.
  • docker compose logs -f - follow the logs of all the containers.
  • docker compose ps - list all running containers.

More advanced commands are normally used when adjusting the project Docker configuration and services.

Using Docker

Scaffold uses Docker to run the project in a containerized environment locally and in CI.

Some of the commands are wrapped in the Ahoy script as a shorthand. But all the commands can be run directly using docker compose command.

Specific commands are described in the relevant workflows sections.

Understanding docker-compose.yml

Docker Compose reads the configuration from the docker-compose.yml and docker-compose.override.yml files. The configuration files are written in YAML, which support anchors and references that help to reduce duplication.

The file provided by Scaffold contains the following sections:

Volumes definitions

Volumes are used to share data between containers. If the host supports volume mounting, then the data can be shared between containers through the host, making it possible to access and modify the data from the host.

This is used during development to share the application code between the container and the host, so that the changes made on the host are immediately reflected in the running application.

There are 2 volumes defined:

  • Project root directory . maps to /app directory within a container. This is where a PHP engine accesses the application code.
  • Files directory ./web/sites/default/files maps to /app/web/sites/default/files directory within a container as an override to the default volume definition. This allows to use different type of syncing to optimise performance, because files are not changed as often as the code.

There are 2 more volumes defined and commented out - these are used in environments without volume mounting support, such as CircleCI. These volumes definitions are automatically uncommented in CI environment, and they replace the host volume mounting, which is removed.

VOLUME_FLAGS environment variable allows to define the consistency of the data within mounted volumes. The values are:

  • default: Equivalent to consistent.
  • consistent: Full consistency. The container runtime and the host maintain an identical view of the mount at all times.
  • cached: The host's view of the mount is authoritative. There may be delays before updates made on the host are visible within a container.
  • delegated: The container runtime's view of the mount is authoritative. There may be delays before updates made in a container are visible on the host.

The default value is delegated, so that any changes done in the container are immediately visible on the host.

Default user

The default user is defined as 1000 - this is the user ID that is used in the container to run the application. This is the same user ID as the host user, so that the files created in the container are owned by the host user.

Changes this value if your user ID is different.

Environment variables

By default, the Docker Composer reads environment variables from the .env file. Scaffold provides an additional capability to read files from .env.local file as well. This allows to override the environment variables locally without modifying the .env file.

The variables read from .env and .env.local files then passed into the containers.

This section only defines 2 types of variables:

  1. Variables that are specific to the stack and require a default value ( like LAGOON_ROUTE).
  2. Variables that cannot be stored in .env file and are injected from the actual environment (like secrets).

Any other variables should be defined in the .env file.

Consider the example:

  TZ: ${DREVOPS_TZ:-Australia/Melbourne}
# Local development URL.
DREVOPS_LOCALDEV_URL: &default-url ${COMPOSE_PROJECT_NAME:-example-site}.docker.amazee.io
# Local development route used in Lagoon images and Pygmy to route requests.
LAGOON_ROUTE: *default-url

where

  • TZ: ${DREVOPS_TZ:-Australia/Melbourne} - defines a variable TZ with a default value of Australia/Melbourne, but only if DREVOPS_TZ variable is not defined.
  • DREVOPS_LOCALDEV_URL: &default-url ${COMPOSE_PROJECT_NAME:-example-site}.docker.amazee.io
    • defines a variable DREVOPS_LOCALDEV_URL with a default value of ${COMPOSE_PROJECT_NAME:-example-site}.docker.amazee.io, but only if DREVOPS_LOCALDEV_URL variable is not defined. The value of the variable is also stored in a YAML anchor default-url for later use.
  • LAGOON_ROUTE: *default-url - defines a variable LAGOON_ROUTE with a value of *default-url, which is a reference to the default-url YAML anchor defined above.

See more information about environment variables in the official documentation.

Services

Services section describes the configuration for each container.

The following services are defined in the docker-compose.yml file provided by Scaffold:

  • cli - a container that runs a shell. This container is used to run commands in the context of the project, such as composer or drush. This is also a container where cron jobs are run within a hosting environment (if that environment supports containerisation).
  • nginx - a container that runs a web server. This container is used to serve the application and pass requests to the PHP container.
  • php - a container that runs a PHP engine. This container is used to run the application code and execute commands in the context of the application. It is different from the cli container in that it does not have certain development dependencies installed, has a smaller size and is optimised for scalability.
  • mariadb - a container that runs a database server. This container is used to store the application data. It can be accessed from the host via a randomly assigned port - run docker compose port mariadb 3306 to get the port number.
  • redis - an optional container that runs a Redis server. This container is used to store the application cache.
  • solr - an optional container that runs a Solr server. This container is used to store the application search index. It can be accessed from the host via a randomly assigned port - run docker compose port solr 8983 to get the port number.
  • clamav - an optional container that runs a ClamAV antivirus server. This container is used to scan uploaded files for viruses.
    • chrome - container that runs a Chrome browser. This container is used to run Behat tests. It is based on the official Selenium image which has additional required tools, like virtual desktop, installed.
  • wait_dependencies - a container that runs a script to wait for applications within other containers to become available. Docker itself can coordinate startup of containers, but it does not know when the application within the container is ready to accept connections. This container is used to wait for specified application ports to become available. The whole stack is considered ready to be worked with only when this container exits with a zero exit code.

Networks

Networks section defines the networks that are used to connect containers to each other. Pygmy provides the default amazeeio-network network that is used to connect all containers together.

Validate docker-compose.yml

After updating the docker-compose.yml file, it is useful sometimes to validate it before running the build. This can be done with the following command:


docker compose -f docker-compose.yml config