Using docker-compose to deploy docker containers in production - docker

I have created the following docker-compose.yml file to build docker containers for a Django application:
version: "2.4"
services:
db:
image: postgres:11
env_file:
- .env_prod_db
volumes:
- db:/var/lib/postgresql/data/
networks:
- net
logging:
driver: "json-file"
options:
max-file: "5"
max-size: "10m"
web:
build:
context: .
dockerfile: Dockerfile
env_file:
- .env_prod_web
command: gunicorn roster_project.wsgi:application --disable-redirect-access-to-syslog --error-logfile '-' --access-logfile '-' --access-logformat '%(t)s [GUNICORN] %(h)s %(l)s %(u)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' --workers 3 --bind 0.0.0.0:8000
volumes:
- static:/roster/webserver/static/
networks:
- net
expose:
- 8000
depends_on:
- db
logging:
driver: "json-file"
options:
max-file: "5"
max-size: "10m"
nginx:
build: ./nginx
ports:
- 80:80
volumes:
- static:/roster/webserver/static/
networks:
- net
depends_on:
- web
logging:
driver: "json-file"
options:
max-file: "5"
max-size: "10m"
networks:
net:
enable_ipv6: true
driver: bridge
ipam:
driver: default
config:
- subnet: fd02::/64
gateway: fd02::1
volumes:
db:
static:
Potential users of my app could use this file to deploy my app if they first download all the source code from Github. However, I would like them to be able to deploy the app just by using docker-compose to download docker images that I have stored in my Docker Hub repo.
If I upload my docker images to a Docker Hub repo, do I need to create an additional docker-compose.yml that refers to the repo images so that others can deploy my app on their own docker hosts ? Or can I somehow combine the build and deploy requirements into a single docker-compose.yml file ?

You can use multiple Compose files when you run docker-compose commands. The easiest way to do this is to have a main docker-compose.yml file that lists out the standard (usually production-oriented) settings, and a docker-compose.override.yml file that overrides its settings.
For example, the base docker-compose.yml file could look like:
version: "2.4"
services:
db:
image: postgres:11
volumes:
- db:/var/lib/postgresql/data/
web:
image: me/web
depends_on:
- db
nginx:
image: me/nginx
ports:
- 80:80
depends_on:
- web
volumes:
db:
Note that I've removed all of the deployment-specific setup (logging configuration, manual IP overrides, environment files); I'm using the Compose-provided default network; I avoid overwriting the static assets with old content from a Docker volume; and I provide an image: name even for things I build locally.
The differences between this and the "real" production settings can be put in a separate docker-compose.production.yml file:
version: "2.4"
services:
db:
# Note, no image: or other similar settings here;
# they come from the base docker-compose.yml
env_file:
- .env_prod_db
logging:
driver: "json-file"
options:
max-file: "5"
max-size: "10m"
web: # similarly
db: # similarly
networks:
default:
enable_ipv6: true
# and other settings as necessary
For development, on the other hand, you need to supply the build: information. docker-compose.development.yml can contain:
version: "2.4"
services:
web:
build: .
nginx:
build: ./nginx
Then you can use a symbolic link to make one of these the current override file
ln -sf docker-compose.production.yml docker-compose.override.yml
A downstream deployer will need the base docker-compose.yml, that mentions the Docker Hub image. They can use your production values if it makes sense for them, or they can use a different setup. They shouldn't need the rest of the application source code or Dockerfiles (though it's probably all in the same GitHub repository).

Related

docker-compose: service "gateway" refers to undefined volume ${PWD}/config/gateway/gateway-configuration.ini: invalid compose project

My goal: generate docker-compose.yaml from docker-compose.yaml and docker-compose.override.yaml and keep the variables as they are now = without interpolate
I've tried to run
docker compose -f docker-compose.yaml -f docker-compose.override.yaml convert --no-interpolate > new-docker-compose.yaml
Here is my docker-compose.yaml:
version: "3.5"
services:
redis-db:
image: redislabs/rejson:2.0.11
container_name: redis-db
restart: unless-stopped
volumes:
- redis-storage-vol:/data
- ${PWD}/config/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
ports:
- 6379:6379
runner:
image: "${REPO}/runner/${RUNNER_CPU_IMAGE}:${RUNNER_CPU_TAG}"
container_name: runner
restart: unless-stopped
volumes:
- data-storage-vol:/data
- ${PWD}/config/runner/runner-configuration.ini:/configuration.ini:ro
- "${PWD}/solutions/${ALGO}:/home/scripts/algorithmic_solutions_list.txt:ro"
depends_on:
- "redis-db"
gateway:
image: "${REPO}/gateway/gateway-server:${GATEWAY_TAG}"
container_name: gateway
restart: unless-stopped
volumes:
- data-storage-vol:/data
- ${PWD}/config/gateway/gateway-configuration.ini:/configuration.ini:ro
ports:
- 8000:8000
depends_on:
- "redis-db"
volumes:
data-storage-vol:
driver_opts:
type: "tmpfs"
device: "tmpfs"
o: "size=5g,uid=1000"
redis-storage-vol:
driver: local
docker-compose.override.yaml
version: "3.5"
services:
runner:
image: "${REPO}/runner/${RUNNER_GPU_IMAGE}:${RUNNER_GPU_TAG}"
deploy:
resources:
reservations:
devices:
- driver: nvidia
capabilities: [ GPU ]
What I've tried:
Run docker compose convert without flag --no-interpolate, it worked well but the variables was populated.
Run like the example - but got this error:
service "gateway" refers to undefined volume ${PWD}/config/gateway/gateway-configuration.ini: invalid compose project
I want to keep using docker compose commands and not edit files after its created.

Converting a docker-compose.yml file with Kompose to K8S with a build step

I've the following docker-compose.yml file, I'd like to convert it to K8S configuration files.
version: '3.1'
services:
api-fiber:
build:
context: .
dockerfile: Dockerfile
ports:
- 8666:8666
volumes:
- ./:/var/app/current
networks:
- api-network
redis:
image: redis:latest
container_name: redis
restart: always
ports:
- 6379:6379
networks:
api-network:
driver: bridge
Kompose converts the resources to yaml, but skip the build section of the api-fiber specs. How to reference this step to make Kompose aware of it?

Why in docker-compose after recreate conteiner i get "Docker cannot link to a non running container"?

I have two conteiners:
docker-compose.yml
version: '3.8'
services:
db:
image: postgres:14.1
container_name: postgres
volumes:
- postgres_data:/var/lib/postgresql/data/
......
network_mode: bridge
web:
container_name: web
build: .
........
network_mode: bridge
external_links:
- postgres
depends_on:
- db
volumes:
postgres_data:
name: postgres_data
After docker-compose up, when i recreate only one container - "db", all works, but i can not connect to conteiner "web", i get error: "Failure
Cannot link to a non running container: /postgres AS /web/postgres".
In conteiner "web" i call db as host=postgres.
What am I doing wrong?
The external_links: setting is obsolete and you don't need it. You can just remove it with no adverse consequences.
network_mode: bridge and container_name: are also unnecessary, though they shouldn't specifically cause problems; still, I'd delete them. What you show can be reduced to
version: '3.8'
services:
db:
image: postgres:14.1
volumes:
- postgres_data:/var/lib/postgresql/data/
......
web:
build: .
........
depends_on:
- db
volumes:
postgres_data: # empty
Since Compose creates a network named default for you and attaches containers to it, your application container can still reach the database container using the hostname db. Networking in Compose in the Docker documentation describes this further.

Docker : Accessing another container by host

I have two containers defined in a docker-compose yaml file that need to talk to each other, but they can't.
version: "3.9"
networks:
localdev:
driver: 'bridge'
services:
master-db:
image: mysql:8.0
container_name: master-db
hostname: master-db
command: --default-authentication-plugin=mysql_native_password
restart: always
ports:
- "4000:3306"
networks:
- localdev
page-store:
hostname: page-store
build:
context: .
dockerfile: Dockerfile.page_store
container_name: page-store
ports:
- "2020:2020"
networks:
- localdev
links:
- master-db
In the page-store Python Flask microservice, I try to access the MySQL database by using its hostname of master-db, but the name cannot resolve.
You should be able to connect each other using respective service names. master-db and page-store removing hostname
As per Official guide you may have to define master-db,page-store in container's /etc/hosts, if you want to use hostname: page-store etc.
Please refer this SO thread.
Also using --links may not be the best option.

Is it possible to set global settings for services in a docker compose file?

Is it possible to specify global settings for services in a Docker compose file?
For example, take this Docker Compose file:
version: "3.9"
services:
test1:
env_file: /path/to/env/file
image: test
container_name: test1
ports:
- "1234:22"
networks:
- dmz
restart: always
test2:
env_file: /path/to/env/file
image: test
container_name: test2
ports:
- "2345:22"
networks:
- trust
restart: always
networks:
dmz:
driver: bridge
trust:
driver: bridge
I don't want to have env_file: /path/to/env/file for every service and would like to make it apply to all services. I know I can pass it in the docker-compose command line but I'm hoping to do it from within the Docker compose file.
Although #timsmelik's answer points in the right direction and shows how to use a yaml anchor and alias with scalar values, you can probably take advantage of the merge key yaml feature here to set overridable default values for your services.
Here is an example to illustrate
version: "3.9"
x-service_defaults: &service_defaults
env_file: /path/to/env/file
image: test
restart: always
services:
test1:
<< : *service_defaults
container_name: test1
ports:
- "1234:22"
networks:
- dmz
test2:
<< : *service_defaults
container_name: test2
ports:
- "2345:22"
networks:
- trust
test3:
<< : *service_defaults
env_file: /some/override/env/file
container_name: test3
volumes:
- /some/bind/dir:/whatever/target
networks:
dmz:
driver: bridge
trust:
driver: bridge
You can find a pretty good comprehensive explanation of all possible yaml anchor/alias usage applied to docker-compose files in the following blog post
Try using extensions as fragments.
With the support for extension fields, Compose file can be written as follows to improve readability of reused fragments:
This is the example from the README.md:
x-logging: &default-logging
options:
max-size: "12m"
max-file: "5"
driver: json-file
services:
frontend:
image: awesome/webapp
logging: *default-logging
backend:
image: awesome/database
logging: *default-logging

Resources