Compose
Deploy multiple containers on a single host
A YAML file defining version (DEPRECATED), services (REQUIRED), networks, volumes, configs and secrets
Default path is compose.yaml (or compose.yml, docker-compose.yaml, docker-compose.yml) in working directory
Build and Compose
1. Build an image from local
2. Compose containers
version: "3.9" # version of Docker Compose
services:
webapp: # container
image: lchenlangley/count # image name [domain/image:tag]
build: . # search local, if image does not exist, build image from local
ports:
- 8000:5000 # host port : container port
environment:
- MYREDIS_HOST=redisserver # environment variable
redisserver: # container
image: redis:alpine # if image exist in local, use the local image
# a bridge network is created by default
Fetch and Compose
1. Fetch images from repositories
2. Compose containers
version: "3.9"
services:
webapp:
image: lchenlangley/count # fetch image from Docker Hub
ports:
- 8000:5000
environment:
- MYREDIS_HOST=redisserver
redisserver:
image: "redis:alpine" # fetch image from Docker Hub
Multiple Compose Files
# compose_1.yaml
version: "3.9"
services:
webapp: # container
image: lchenlangley/count
#build: .
volumes:
- type: volume
source: voltemp
target: /code
volumes:
voltemp:
# compose_2.yaml
version: "3.9"
services:
webapp: # container
ports:
- target: 5000
published: 8000
protocol: tcp
mode: host
environment:
MYREDIS_HOST: redisserver
redisserver: # container
image: redis:alpine
docker-compose -f compose_1.yaml -f compose_2.yaml up
docker-compose -f compose_1.yaml -f compose_2.yaml down
Configuration Extension
re-use a common configuration
# compose.yaml
version: "3.9"
services:
webapp: # container
extends:
file: common.yaml
service: template
image: lchenlangley/count
#build: .
volumes:
- type: volume
source: voltemp
target: /code
redisserver: # container
image: redis:alpine
volumes:
voltemp:
# common.yaml, contains a common configuration
version: "3.9"
services:
template: # container
ports:
- target: 5000
published: 8000
protocol: tcp
mode: host
environment:
MYREDIS_HOST: redisserver
docker-compose up
docker-compose down
Services
Abstract concept implementing docker run
image
- Specifies the image to start the container from
image: redis # [domainName/imageName:tag]
ports
- Expose ports from container to host
ports:
- 8000:5000 # host_port:container_port
build
- Build image from local source code, allow to miss the image attribute
services:
webapp:
image: awesome/webapp # image name
build: . # path for source code and Dockerfile
services:
webapp:
image: awesome/database # image name
build:
context: . # source code path
dockerfile: ../Dockerfile # Dockerfile path
services:
webapp:
build: . # source code path
environment
- Add environment variables
services:
webapp:
...
environment:
MYREDIS_HOST: redisserver
services:
webapp:
...
environment:
- MYREDIS_HOST=redisserver
networks
- Specify the networks to join
services:
webapp:
...
networks:
- frontend-network
- backend-network
restart
- restart containers when restarting the docker daemon, rebooting your server, using a CMD inside a container and running an exit, etc.
- restart policy is ignored when containers are stopped manually, such as stop and kill by docker-compose
restart: always
env_file
- Add environment variables from a file, not really work in the test
# .env, default environment file
MYREDIS_HOST=redisserver
# compose.yml
services:
webapp:
...
environment:
- MYREDIS_HOST=${MYREDIS_HOST}
# env/webapp.env
MYREDIS_HOST=redisserver
# compose.yml
services:
webapp:
...
environment:
- MYREDIS_HOST=${MYREDIS_HOST}
# compose
docker-compose --env-file env/webapp.env up
# turn off compose
docker-compose --env-file env/webapp.env down
profiles and depends_on
- Selectively enable services
- If unassigned, the service is always started
- If assigned, the service is only started if the profile is activated
services:
foo:
image: foo
bar:
image: bar
profiles:
- test
baz:
image: baz
depends_on:
- bar
profiles:
- test
zot:
image: zot
depends_on:
- bar
profiles:
- debug
# enable test (bar, baz) and foo
docker-compose --profile test up
# invalid, profile debug (zot) is enabled, but zot depends on bar which is in the profile test
docker-compose --profile debug up
# enable test(bar, baz), debug(zot) and foo
docker-compose --profile debug --profile test up
# enable bar, profile test is active, but baz is not enabled
docker-compose up bar
# enable baz, profile test is active, bar is enabled by depends_on constraint
docker-compose up baz
# enable zot and test, bar is enabled by depends_on constraint
docker-compose --profile test up zot
command
- Override the default command of a container
command: python app.py
expose
- Specify the port number exposed from container
- Same as expose in Dockerfile, it functions as a type of documentation
- By default, make the access port number in app, the expose number in dockerfile, and the expose port number in compose file match
expose:
- "5000"
container_name
- Specify container name instead of using default name
container_name: redis-container
hostname
- Specify host name inside a container
hostname: redis-host
Networks
Capability abstraction to establish an IP route between containers, analogous to docker network create
By default, docker-compose sets up a single network, containers join the network for communication
- [directory]_default, network name
version: "3.9"
services:
webapp: # container
image: lchenlangley/count
#build: .
volumes:
- type: volume
source: voltemp
target: /code
ports:
- target: 5000
published: 8000
protocol: tcp
mode: host
environment:
MYREDIS_HOST: ${MYREDIS_HOST}
networks:
- app-net
redisserver: # container
image: redis:alpine
networks:
- app-net
volumes:
voltemp:
networks:
app-net: # create a network named [directory]_app-net
Volumes
Analogous to docker volume create
Volume
# Short Syntax
services:
app:
# ...
volumes: # volumes for a particular service
- [source]:[target]:[mode]
# source, named volume, defined in the top level "volumes"
# target, an absolute path in container
# mode, read-only or read-write
volumes: # define volumes
version: "3.9"
services:
webapp:
image: lchenlangley/count
build: .
ports:
- 8000:5000
volumes:
- voltemp:/code
environment:
- MYREDIS_HOST=redisserver
- FLASK_ENV=development
depends_on:
- redisserver
redisserver:
image: "redis:alpine"
volumes:
voltemp: # volume name length should greater than five
# Syntax
services:
app:
# ...
volumes: # volumes for a particular service
- type: volume
source: [volume_name]
target: [path]
volumes: # define volumes
version: "3.9"
services:
webapp:
image: lchenlangley/count
build: .
ports:
- 8000:5000
volumes:
- type: volume
source: voltemp
target: /code
environment:
- MYREDIS_HOST=redisserver
- FLASK_ENV=development
depends_on:
- redisserver
redisserver:
image: "redis:alpine"
volumes:
voltemp:
Bind Mount
# Short Syntax
services:
app:
# ...
volumes: # volumes for a particular service
- [source]:[target]:[mode]
# source, a path (absolute or relate)
# target, an absolute path in container
# mode, read-only or read-write
version: "3.9"
services:
webapp:
image: lchenlangley/count
build: .
ports:
- 8000:5000
volumes:
- .:/code
environment:
- MYREDIS_HOST=redisserver
- FLASK_ENV=development
depends_on:
- redisserver
redisserver:
image: "redis:alpine"
# Syntax
services:
app:
# ...
volumes: # volumes for a particular service
- type: bind
source: [path]
target: [path]
version: "3.9"
services:
webapp:
image: lchenlangley/count
build: .
ports:
- 8000:5000
volumes:
- type: bind
source: .
target: /code
environment:
- MYREDIS_HOST=redisserver
- FLASK_ENV=development
depends_on:
- redisserver
redisserver:
image: "redis:alpine"
Configs
Grant access to configs on a per-service basis
Secret
Grant access to secrets on a per-service basis
Example
2 services, backed by Docker images: webapp and database
1 secret (HTTPS certificate), injected into the frontend
1 configuration (HTTP), injected into the frontend
1 persistent volume, attached to the backend
2 networks: front-tier and back-tier
services:
frontend:
image: awesome/webapp
ports:
- "443:8043"
networks:
- front-tier
- back-tier
configs:
- httpd-config
secrets:
- server-certificate
backend:
image: awesome/database
volumes:
- db-data:/etc/data
networks:
- back-tier
volumes:
db-data:
driver: flocker
driver_opts:
size: "10GiB"
configs:
httpd-config:
external: true
secrets:
server-certificate:
external: true
networks:
# The presence of these objects is sufficient to define them
front-tier: {}
back-tier: {}
docker-compose
# get command help
docker-compose --help
# start services
# --build, build images from source code instead of loading built images before starting containers
# -d, detached
# docker-compose up [service list]
docker-compose up # start all services
docker-compose up webapp # start service webapp
docker-compose -f [composeFileName] up # specify compose file
# turn off and remove services
docker-compose down
# build images in compose file
docker-compose build
# list images of the current compose
docker-compose images
# list service of the current compose
docker-compose ps
# stop services of the current compose
docker-compose stop [serviceName] # stop a specific service
docker-compose stop # stop services in the current compose
# start services
docker-compose start [serviceName] # start a specific service
docker-compose start # start services in the current compose
# one-off command
# docker-compose run [serviceName] [command]
docker-compose run webapp env
# view the compose file
docker-compose config
Reference