Docker Community Forums

Share and learn in the Docker community.

How to deploy to production when using docker compose?

I heard someone say that…

Docker compose is designed for development NOT for production.

But I have seen people use Docker compose on production with bind mounts. Then pull the latest changes from github and it appears live in production without the need to rebuild. But others say that you need to COPY . . for production and rebuild.

But how does this work? Because in docker-compose.yaml you can specify depends-on which doesn’t start one container until the other is running. If I don’t use docker-compose in production then what about this?

How would I push my docker-compose to production (I have 4 services / 4 images that I need to run). With docker-compose up -d it is so easy.

version: '3'
services:

  # Nginx client server
  nginx-client:
    container_name: nginx-client
    build:
        context: .                  
    restart: always
    stdin_open: true  
    environment:
      - CHOKIDAR_USEPOLLING=true  
    ports:
      - 28874:3000
    volumes:
      - ./client:/var/www
      - /var/www/node_modules
    networks:
      - app-network


  # MySQL server for the server side app
  mysql-server:
    image: mysql:5.7.22
    container_name: mysql-server
    restart: always
    tty: true
    ports:
      - "16427:3306"
    environment:
      MYSQL_USER: root
      MYSQL_ROOT_PASSWORD: BcGH2Gj41J5VF1
      MYSQL_DATABASE: todo
    volumes:
      - ./docker/mysql-server/my.cnf:/etc/mysql/my.cnf
    networks:
      - app-network


  # Nginx server for the server side app
  nginx-server:
    container_name: nginx-server
    image: nginx:1.17-alpine
    restart: always
    ports:
      - 49691:80
    volumes:
      - ./server:/var/www
      - ./docker/nginx-server/etc/nginx/conf.d:/etc/nginx/conf.d
    depends_on:
    - php-server
    - mysql-server
    networks:
      - app-network


  # PHP server for the server side app
  php-server:
    build:
      context: .        
      dockerfile: ./docker/php-server/Dockerfile
    container_name: php-server
    restart: always
    tty: true
    environment:
      SERVICE_NAME: php
      SERVICE_TAGS: dev
    working_dir: /var/www
    volumes:
      - ./server:/var/www
      - ./docker/php-server/local.ini:/usr/local/etc/php/conf.d/local.ini
      - /var/www/vendor
    networks:
      - app-network
    depends_on:
      - mysql-server


# Networks
networks:
  app-network:
    driver: bridge

What you want
– seperation of concerns: strip out the build part and create and use a ci/cd pipeline to trigger builds on git push, build each needed image and push it to a private container registry. Use the images in your docker-compose.yml; use compose for deployments only,
– use a deployment pipeline to deploy your docker-compose stacks
– treat images as fixed artifacts: indeed do COPY the source code and if necessary compile binaries and make them part of the image. It is necessary that a tag results in a specific version (=development state) of your application. Use different tags for dev and production images. Every other approach is a development solution at best.
– Consider to move to multinode docker swarm deployments, rather then single node docker-compose deployments
– Consider using a nfs server to store the details and use volumes to access them, rather then bind mounts - if a container is respawned on a different node, the volume content will be still accessible.
– depends_on will only work for docker-compose, there is no such thing for Docker Swarm or Kubernetes. Make sure you “wait for dependencies” in your entrypoint scripts instead!
– with envsubst you can introduce a simple templating that goes beyond what .env files are capable to do. I posted some examples in the forum on how to leverage it

I have seen Docker Swarm and Kubernetes beeing used in production.While you encounter Kubernetes practicaly everywhere, Swarm is rarely seen. While Swarm uses compose.yml files, Kubernetes uses a bunch of yml based manifest files to archive the same (to be fair: it is way more powerfull than Swarm) or Helm Charts (which you have to write yourself for your own apps).

A remote Docker host is a machine, inside or outside our local network which is running a Docker Engine and has ports exposed for querying the Engine API.

The sample application can be deployed on a remote host in several ways. Assume we have SSH access to a remote docker host with a key-based authentication to avoid a password prompt when deploying the application.

There are three ways to deploy it on the remote host:

  1. Manual deployment by copying project files, install docker-compose and running it
    A common usage of Compose is to copy the project source with the docker-compose.yml, install docker-compose on the target machine where we want to deploy the compose app and finally run it.

scp -r hello-docker user@remotehost:/path/to/src ssh user@remotehost
pip install docker-compose cd /path/to/src/hello-docker
$ docker-compose up -d

The disadvantages in this case is that for any change in the application sources or Compose file, we have to copy, connect to the remote host and re-run.

  1. Using DOCKER_HOST environment variable to set up the target engine
    Throughout this exercise we use the DOCKER_HOST environment variable scenario to target docker hosts, but the same can be achieved by passing the -H, –host argument to docker-compose.

cd hello-docker DOCKER_HOST=“ssh://user@remotehost” docker-compose up -d

This is a better approach than the manual deployment. But it gets quite annoying as it requires to set/export the remote host endpoint on every application change or host change.

  1. Using docker contexts
    docker context ls NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR … remote ssh://user@remotemachine cd hello-docker
    $ docker-compose ‐‐context remote up -d

Docker Contexts are an efficient way to automatically switch between different deployment targets. We will discuss contexts in the next section in order to understand how Docker Contexts can be used with compose to ease / speed up deployment.