skip to Main Content

When I run docker compose up, I’m expecting for my postgres_container to run before my go_container since the go_container is dependent on postgres_container as specified in the yml file depends_on. However, my go_container is executed first and the postgres_container doesn’t seem to ever start.

docker-compose.yml

version: '3.8'
services:
  go_container:
    container_name: go_container
    environment:
      - DATABASE_USER=${DATABASE_USER}
      - DATABASE_PASSWORD=${DATABASE_PASSWORD}
      - DATABASE_NAME=${DATABASE_NAME}
      - DATABASE_HOST=${DATABASE_HOST}
      - DATABASE_PORT=${DATABASE_PORT}
      - API_KEY=${API_KEY}
    build: .
    ports:
     - 8080:8080
    volumes:
      - .:/src
    depends_on:
      - postgres_container
    restart: on-failure
    networks:
      - weather
  postgres_container:
    container_name: postgres_container 
    user: postgres
    image: postgres:latest
    restart: always
    environment:
      - POSTGRES_USER=${DATABASE_USER}
      - POSTGRES_DB=${DATABASE_NAME}
      - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
    ports:
      - 5432:5432
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./sql/create.sql:/docker-entrypoint-initdb.d/create.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready", "-U", "${DATABASE_USER}"]
    networks:
      - weather
volumes:
  db_data: {}
networks:
  weather:
    driver: bridge

Dockerfile

FROM golang:1.21.5

EXPOSE 8080

WORKDIR /src

COPY .env .

COPY . .

RUN go mod download && go mod verify

WORKDIR /src/cmd/app

RUN go run main.go

At first, my docker-compose.yml was respecting the depends_on key but after some changes it stopped. Im not sure at what point it stopped working. I thought it was a bug in my docker installation so I tired reinstalling Docker but the problem persists.

.env file

DATABASE_HOST=postgres_container
DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASSWORD=postgres
DATABASE_NAME=weather
SERVER_PORT=8080

Here are the logs:
docker log

2

Answers


  1. The depends_on directive, as you’ve used it here, is almost entirely useless, because the dependency is only on container startup. That is, go_container starts after postgres_container has started, but that doesn’t mean that Postgres is actually ready to service connections.

    You can use the extended form of the depends_on directive to achieve the ordering you want. See this documentation; the resulting configuration would look something like:

    services:
      go_container:
        container_name: go_container
        environment:
          - DATABASE_USER=${DATABASE_USER}
          - DATABASE_PASSWORD=${DATABASE_PASSWORD}
          - DATABASE_NAME=${DATABASE_NAME}
          - DATABASE_HOST=${DATABASE_HOST}
          - DATABASE_PORT=${DATABASE_PORT}
          - API_KEY=${API_KEY}
        build: .
        ports:
         - 8080:8080
        volumes:
          - .:/src
        depends_on:
          postgres_container:
            condition: service_healthy
        restart: on-failure
        networks:
          - weather
    
      postgres_container:
        container_name: postgres_container 
        user: postgres
        image: postgres:latest
        restart: always
        environment:
          - POSTGRES_USER=${DATABASE_USER}
          - POSTGRES_DB=${DATABASE_NAME}
          - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
        ports:
          - 5432:5432
        volumes:
          - db_data:/var/lib/postgresql/data
          - ./sql/create.sql:/docker-entrypoint-initdb.d/create.sql
        healthcheck:
          test: ["CMD-SHELL", "pg_isready", "-U", "${DATABASE_USER}"]
        networks:
          - weather
    volumes:
      db_data: {}
    networks:
      weather:
        driver: bridge
    
    Login or Signup to reply.
  2. If we take a look at the logs, we see that the image build process fails. Looking closely at the containerfile, we see the following on the last line:

    ...
    RUN go run main.go
    

    RUN is executed at image buildtime, not container runtime. In contrast, depends_on in the docker-compose.yml controls the order in which containers are started; it has no effect for image building.

    To fix this issue, we need to either use CMD (docs.docker.com), ENTRYPOINT (docs.docker.com) or a combination of both to define the command. I will continue using the ENTRYPONT approach:

    ...
    ENTRYPOINT [ "go", "run", "main.go" ]
    

    Please also look at @larsks‘s answer. Their answer has a valid point with regards to startup order.


    A remark: it is strange to use go run ... in a containerile to run the code. I would recommend compiling the code first, and then executing the result of the compilation. We can achieve this with a multi-stage build (docs.docker.com). I also wrote a blog article discussing multi-stage containerfiles (turing85.github.io). An example can be found here (github.com).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search