Docker-Compose – HackMD

<style>
.present {
text-align: left;
}
</style>

# Docker-Compose
## Week 19 Day 4

## Lecture Videos 1 (10 minutes)
Watch:
– Using Docker Compose (7:30)

### Docker-Compose
docker-compose allows you to create a collection of interconnected containers, networks, and volumes with a single command.

A lot of the options you had to specify at the command line every time you ran a container can be totally automated with docker-compose.

To use docker-compose, you first create a __docker-compose.yml__ file which describes all of the services, networks, and volumes in your application.

### `docker-compose.yml` file
The docker-compose tool uses files written in a data-serialization language called YAML (extension is `.yml`).

At the top level of each file, include the version of docker-compose, then you can list services (containers), plus any volumes or networks if necessary.

“`yaml
version: ‘3.8’

services:
# any services go here
networks:
# networks go here
volumes:
# volumes
“`

### `services`
Services are containers. Immediately under the `services` keyword, the next level down will be the name of the containers.

“`yaml
version: ‘3.8’

services:
container_name_1:
# more info
container_name_2:
# more info
“`

### `services` keywords: `build`
When we create a container, we always have to specify an image.

If we are building the image from a Dockerfile, we can use the `build` keyword to specify the context for the Dockerfile. If the Dockerfile is in the same folder as the docker-compose.yml file, that context will just be `.` to indicate the present folder
“`yaml
container_name_1:
build: .
“`

### `services` keywords: `build`

If the Dockerfile is named anything other than Dockerfile, you can indicate the Dockerfile name and the context (path) separately.

“`yaml
container_name_1:
build:
context: .
dockerfile: Dockerfile-prod
“`

### `services` keywords: `image`

If you are using an existing image that does not need to be built from a Dockerfile, you can specify the image name with the `image` keyword.

Docker will look for that image locally, and if it does not find it, it will pull from Dockerhub.
“`yaml
container_name_1:
image: image_name
“`

If you are also using the `build` keyword, then __the `image` keyword will not have the same function__.

### `services` keywords: `image`

If you are building an image with the `build` keyword, then the `image` keyword will name the image that you are building.

“`yaml
container_name_1:
build: .
image: new_image_name
“`

### `services` keywords: `volumes`

The `volumes` keyword can specify any volumes or bind mounts that will be associated with the service.

If you use any named volumes, they will also need to be listed under the top level `volumes` keyword.
“`yaml
container_name_1:
volumes:
# for bind mounts
– ./path/locally:/path/to/bind/mount/on/container
# for named volumes
– volume_name:/path/to/volume/on/container
# for anonymous volumes
– /path/to/volume/on/container
“`

### `services` keywords: `networks`

By default, all the containers in the docker-compose file will be put onto one custom network together. Sometimes, however, you may want separate networks. You can use the networks keyword on a given service to connect it to specific networks.

If you use any additional networks, they will need to be listed under the top level `networks` keyword. If you are only using the default network you don’t need to use the top-level `networks` keyword.

“`yaml
container_name_1:
networks:
– network_name
“`

### `services` keywords: `environment`

You can specify environment variables, like `DATABASE_URL`, `SECRET_KEY`, etc, using the environment keyword. That will allow you to specify the keywords directly.

“`yaml
container_name_1:
environment:
NAME: value
“`

If you want to use a `.env` file instead, you can use the `env_file` keyword:

“`yaml
container_name_1:
env_file:
– ./.env
“`

### `services` keywords: `ports`

You can use the `ports` keyword to publish mappings between internal and external ports.

Unlike `EXPOSE` in a Dockerfile, this will actually publish the port, like using the `-p` flag with `docker container run`.

“`yaml
container_name_1:
ports:
# <external port>:<internal port>
-8000:80
“`

### Docker `services` summary

“`yaml=
services:
service_name_1:
build:
context: ./folder_with_dockerfile
dockerfile: Dockerfile-alternate.Dockerfile
image: imagename
volumes:
# with a named volume – also list name under top-level volumes
– volume_name:/path/to/volume/on/container
# for bind mounts
– ./path/locally:/path/to/bind/mount/on/container
# by default, docker-compose will create a single network for all containers
networks:
– network_name
environment:
DATABASE_URL: postgresql://username:password/localhost
ANOTHER_VARIABLE: more-stuff
ports:
# <external port>:<internal port>
-8000:80
second_service_2:
image:
#… all the other keywords for this service
“`

### `volumes`
If you include any named volumes, list their names under the top-level “volumes” key.

Anonymous volumes and bind mounts don’t need to be listed.

“`yaml
volumes:
some_named_volume:
another_named_volume:
“`

### networks
If you don’t specify a network, all the containers in the docker-compose file will be put onto one custom network together.

If you want multiple networks, specify all the names under the top-level volumes key. Containers can belong to multiple networks.

“`yaml
networks:
network_name:
second_network_name:
“`

### Putting it all together…

“`yaml=
version: ‘3.8’

services:
db:
env_file:
– ./.env.prod.db
image: postgres:latest
networks:
– default
volumes:
– postgres-data:/var/lib/postgresql/data

api:
build: .
env_file:
– ./.env.prod
depends_on:
– db
networks:
– default
ports:
– 8000:8000

volumes:
postgres-data:
“`

### Useful docker-compose CLI commands
– `docker-compose up`: create all containers, networks and volumes described in our docker-compose file
– `docker-compose up -d`: same as above, but run containers in detached mode
– `docker-compose -f <filename> up`: create containers based on a different docker-compose file
– `docker-compose down`: remove all containers and networks
– `docker-compose down -v`: remove all containers, networks, and volumes

## Projects today
– First Docker Compose File
– Become Docker Compose Pros

Do not do the “Putting It Together” project—it does not match how we are going to deploy.