Search code examples
dockerdocker-composedockerfiledocker-containerdocker-image

Can I rename the original image in docker-compose?


My Configuration

My docker-compose.yml looks like this with some config for backend etc..., but I need some changes for db service.

version: '3.6'
services:
  db:
    container_name: db-${STAGE:-dev}
    image: postgres:14.0-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    ports:
      - "5432:5432"
    env_file:
      - .env.${STAGE:-dev}

I don't want to have multiple docker-compose.yml files, so...

What do I want?

I want to run this docker-compose.yml twice, the first time with STAGE=prod and the second time with STAGE=dev. I need to use different .env files (.env.dev, .env.prod), because of once the db service is built, the image name is postgres:14.0-alpine and it also builds with only one of the .env.${STAGE} files, so it will only work with development or production, due to different passwords etc....

I want to build 2 different images for postgres db (e.g. db-dev and db-prod) that will use .env.dev for db-dev and .env.prod for db-prod.

The reason I want to do this is that I would like to deploy both a development and a production server on one VPS, I'm not sure if this is a good idea, so can you give me some recommendations on this as well please.


Solution

  • The most important statement in the question is this:

    I want to run this docker-compose.yml twice

    Compose has the notion of a project name. This affects the names of most things Compose generates. These include the containers themselves; the project name is included not just in the default project name but also in labels attached to the containers. A common related problem here is that running STAGE=qa docker-compose up -d will delete the STAGE=dev containers; for example, How do I run the same docker-compose.yml several times on same docker daemon with different names?

    The first important thing you can do is start the two Compose instances with different project names. You can do this with a COMPOSE_PROJECT_NAME environment variable or a docker-compose -p option. Whichever you use, you need to make sure it's available for all docker-compose invocations.

    STAGE=dev
    docker-compose -p "$STAGE" up -d
    docker-compose -p "$STAGE" ps
    

    The project name also gets included in the names of other generated objects. This especially includes volumes. If your top-level volumes: block is just a minimal

    volumes:
      postgres_data:
        # empty
    

    then the underlying Docker volume will be named after the project name.

    The important thing that's happening in your setup, I think, is that you're reusing the existing volume between the "dev" and "prod" environments. You're using the same image as well, but that's normal – you're not recompiling the PostgreSQL server for different environments. Setting the Compose project name will work around this and give you a different volume for each environment.

    In your Compose setup you can also use $COMPOSE_PROJECT_NAME explicitly. You might be able to save a step by letting Compose choose the names of all of the objects, and using the project name directly in the one place you need it (the env_file: name).

    version: '3.8'
    services:
      db:
        image: postgres:14.0-alpine
        volumes:
          - postgres_data:/var/lib/postgresql/data/
        ports:
          - "5432:5432"
        env_file:
          - .env.${COMPOSE_PROJECT_NAME}
    volumes:
      postgres_data:
    
    # without setting $STAGE
    docker-compose -p dev up -d