skip to Main Content

I’ve 3 app in a single repo. For a project it’s Api, Admin UI & Front-end. In all of those I’m facing the issue that the source code is not getting updated correctly. Following is the Dockerfile for Api

FROM golang:1.22.5-alpine3.20

WORKDIR /usr/src/app

COPY go.mod go.sum ./
RUN go mod download && go mod verify

COPY . .
RUN go build -v -o /usr/local/bin/app ./

EXPOSE 3000

CMD ["app"]

Following is docker-compose.yaml

services:
  db:
    image: mariadb:10.5.25
    restart: always
    # ...
  adminer:
    image: adminer
    restart: always
    # ...
  API: # Our focus is in here
    container_name: bjm_api
    build: ./api
    ports:
      - "3000:3000"
    develop:
      watch:
        - action: sync
          path: ./api
          target: /usr/src/app
    networks:
      - bjm_net
    volumes:
      - api_data_bjm:/app/logs
    env_file: ./api/.env
    depends_on:
      db:
        condition: service_healthy
  admin:
    container_name: bjm_admin
    build: ./admin
    ports:
      - "3001:3001"
    # ...
    depends_on:
      api:
        condition: service_started
  web:
    container_name: bjm_web
    build: ./web
    ports:
      - "3002:3002"
    # ...
    depends_on:
      api:
        condition: service_started

networks:
  bjm_net:
    name: bjm-net
volumes:
  db_data_bjm:
    driver: local
  api_data_bjm:
    driver: local

Then ran with docker compose up --watch

Steps to reproduce the issue

  1. After the above do change something in the (go file) code
  2. Notice that the thing is not updated in the output.
    But in terminal it shows that updated code is taken into container. Following is shown in terminal
bjm_api    | ➡ POST /v1/auth/sign-in - 400
           ⦿ Syncing "api" after changes were detected
           ⦿ Syncing "api" after changes were detected

I think the code was syncked but the executable is not being built. How to solve this?

My setup
Docker version 27.1.1
Ubuntu 24.04

2

Answers


  1. Chosen as BEST ANSWER

    @David Maze's answer is a good solution when not using air

    It turned out on further inspection that I was not using auto-reload (configured with air), but instead using standard way to build & run the binary. this is not efficient for development purposes. Now I'm using air to pick up code changes & automatically build the binary & serve that, No need to image rebuild which also triggers rebuild on dependant containers.

    Following is my Dockerfile

    FROM golang:1.22.5-alpine3.20
    
    WORKDIR /usr/src/app
    
    # install air
    RUN go install github.com/air-verse/air@latest
    
    # pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them
    # in subsequent builds if they change
    COPY go.mod go.sum ./
    RUN go mod download && go mod verify
    
    COPY . .
    # RUN go build -v -o /usr/local/bin/app ./ # not necessary for air
    
    EXPOSE 3000
    
    CMD ["air"] # run with air
    

    Updated docker-compose.yaml

    services:
      api:
        container_name: bjm_api
        build: ./api
        ports:
          - "3000:3000"
        develop:
          watch:
            - action: sync # get updated file from host so air can rebuild bin
              path: ./api #path on host
              target: /usr/src/app # path on container
              ignore:
                - .idea/
                - storage/
                - README.md
                - Todo.md
                - .gitignore
                - .dockerignore
        # ...
        depends_on:
          db:
            condition: service_healthy
    

    This way API service gets all the updates but other services don't get rebuilt/ restarted. This makes it fast.


  2. Go is a compiled language. Just mapping the original Go source code into the container doesn’t do anything, because it doesn’t get run. Instead, your Dockerfile produces the compiled app binary, and that’s what gets run. When your source code changes, you need to rebuild the image (and with it the Go binary).

    The Compose watch block has a couple of different action values. You’ve set it to sync, which tries to copy files into the container. You actually need to set it to rebuild to get your Go application rebuilt.

    version: '4.x'  # develop: not in Compose file formats 2.x/3.x
    services:
      api:
        build: ./api
        ports:
          - "3000:3000"
        develop:
          watch:
            - action: rebuild  # <--- change this
              path: ./api
        volumes:
          - api_data_bjm:/app/logs
        env_file: ./api/.env
        depends_on:
          db:
            condition: service_healthy
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search