Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Docker-compose: replace "build"-based service with pre-built image in production?

Let's say we have the following docker-compose.yml:

version: '3'
services:
  db:
    image: "postgres"
    ports:
     - "5432:5432"
    environment:
     - POSTGRES_PASSWORD=mysecretpassword
  web:
    build: web
    depends_on: [ db ]
    ports:
     - "80:80"

The first service, db, just runs a container with the official postgres image from Docker Hub.

The second service, web, first builds a new image based on the Dockerfile in a folder also called web, then runs a container with that image.

While developing, we now can (repeatedly) make changes to whatever is in the web folder, then run docker-compose up --build to run our app locally.

Let's say we now want to deploy to production. My understanding is that docker-compose.yml can now be used to "define a stack in Docker's swarm mode" (see this answer, for instance). However, for the build step of the web service, Docker's compose file documentation states that

This option is ignored when deploying a stack in swarm mode with a (version 3) Compose file. The docker stack command accepts only pre-built images.

It probably wouldn't be a great idea to build the image on the production machine anyways, as this would leave build artifacts (source code) behind; this should happen on a build server.

My question is, is there a recommended way to modify docker-compose.yml en route to production to swap out build: web with image: <id> somehow?

Nothing on Use Compose in production on that. Is there something wrong with my approach in general?

like image 996
Max Avatar asked Dec 21 '18 21:12

Max


2 Answers

docker-compose.yml should only contain canonical service definitions.

Anything that's specific to the build environment (e.g. dev vs prod) should be declared in a separate file docker-compose.override.yml. Each build environment can have its own version of that file.

The build: web declaration doesn't belong into docker-compose.yml, as it's only supposed to run locally (and possibly on a build server), not in production.

Therefore, in the example above, this is what docker-compose.yml should look like:

version: '3'
services:
  db:
    image: "postgres"
    ports:
     - "5432:5432"
    environment:
     - POSTGRES_PASSWORD=mysecretpassword
  web:
    depends_on: [ db ]
    ports:
     - "80:80"

And this would be the default docker-compose.override.yml for local development:

version: '3'
services:
  web:
    build: web

Running docker-compose up --build -d will now build the latest code changes and launch our app locally.

There could also be another version docker-compose.override.build.yml, targeting a build/CI server:

version: '3'
services:
  web:
    build: web
    image: mydockeruser/web

Running docker-compose -f docker-compose.yml -f docker-compose.override.build.yml push will build the latest code changes and push the image to its registry/repository.

Finally, there could be another version docker-compose.override.prod.yml:

version: '3'
services:
  web:
    image: mydockeruser/web

Deploying to production (just to a single Docker host, not a cluster) can now be as simple as copying over only docker-compose.yml and docker-compose.override.prod.yml and running docker-compose -f docker-compose.yml -f docker-compose.override.prod.yml up -d.

like image 165
Max Avatar answered Nov 15 '22 05:11

Max


The correct way to do it (i.e. the way I do it :P) is to have different docker-compose files; for example, docker-compose.dev.yml and docker-compose.prod.yml. You can then push your production-ready image to a repository, say Docker Hub, and reference that image in docker-compose.prod.yml's web service. All the while you can use the dev docker-compose file (the one with the build option) for local development.

Also, in case you've thought about this, you cannot use env variables as keys in docker-compose (see here). So there is no way to conditionally set either image or build options.

like image 20
nebuler Avatar answered Nov 15 '22 05:11

nebuler