skip to Main Content

I have two Dockerfiles for the foo service: foo-dev and foo-debug. There are only 3 lines of differences between these files where foo-debug installs delve allowing me to debug the docker container for golang. I use the make commands to send the correct dockerfile to docker compose. It works as expected but there is a quirk. Switching between the containers of debug and dev is cumbersome where I need to stop the container, kill it, and rebuild the other one by passing –build to docker compose, then I can run the make command. Is there a better strategy? Provided simplified code snippets below

Makefile

compose-dev:
    DOCKER_FILE=foo-dev.Dockerfile docker compose up -d

compose-debug: 
    DOCKER_FILE=foo-debug.Dockerfile docker compose up -d

docker-compose.yml

version: '3'
services: 
  foo: 
    build: 
      context: . 
      dockerfile: ${DOCKER_FILE} 

foo-dev.Dockerfile -> foo-debug.Dockerfile (diff shown below)

FROM golang:1.20.8-bullseye as builder
+ RUN CGO_ENABLED=0 go install -ldflags "-s -w -extldflags '-static'" github.com/go-delve/delve/cmd/dlv@latest

FROM debian:bullseye-slim COPY --from=builder /go/bin/foo ./bin/foo
+ COPY --from=builder /go/bin/dlv ./bin/dlv
+ CMD [ "./bin/dlv", "--listen=:4001", "--headless=true", "--log=true", "--accept-multiclient", "--api-version=2", "exec", "./bin/foo"]
- CMD ["./bin/foo", "-debug"]

I know Docker Compose offers profiles; however, this would result in duplicated code where the docker-compose.yml would contain both a foo-dev service and foo-debug to differentiate them but with the same duplicated sub configuration.

2

Answers


  1. I dont understand quiet to ur question, but what ur goal is, to make ur workflow faster without boilerplate + without more typing ?

    If u hate the switching process, where you need to stop, kill, run correct file. You can create some function at makefile and do chain calls.

    dcdown:
     @docker-compose down
    dcstop:
     @docker-compose stop
    dcrerun-dev: dcstop dcdown
     @DOCKER_FILE=foo-dev.Dockerfile docker compose up -d
    dcrerun-debug: dcstop dcdown
     @DOCKER_FILE=foo-debug.Dockerfile docker compose up -d
    

    my point is that how u made ur own func for passing docker arg, you can do that with other bash stuffs.

    btw. whats wrong with running both of containers ? i mean if you have HW, then docker/containerd is pretty lightweight container runtime engine.

    Login or Signup to reply.
  2. If I understand the problem to simplify the process of switching between development and debug modes without duplicating your Docker Compose configurations or Dockerfiles excessively, consider the following strategies:
    Use Argument in Dockerfile:

    # syntax=docker/dockerfile:1
    FROM golang:1.20.8-bullseye as builder
    ARG MODE
    RUN if [ "$MODE" = "debug" ] ; then CGO_ENABLED=0 go install -ldflags "-s -w -extldflags '-static'" github.com/go-delve/delve/cmd/dlv@latest ; fi
    
    FROM debian:bullseye-slim
    COPY --from=builder /go/bin/foo ./bin/foo
    COPY --from=builder /go/bin/dlv ./bin/dlv
    CMD if [ "$MODE" = "debug" ] ; then exec ./bin/dlv --listen=:4001 --headless=true --log=true --accept-multiclient --api-version=2 exec ./bin/foo; else exec ./bin/foo -debug; fi
    

    Now, you just need to pass the build argument in your Docker Compose file:

    version: '3'
    services: 
      foo: 
        build: 
          context: . 
          dockerfile: Dockerfile 
          args: 
            MODE: ${MODE}
    

    Utilize Makefile for Mode Setting:
    In your Makefile, you can set the MODE environment variable which will be picked up by Docker Compose:

    compose-dev:
        MODE=development docker compose up -d
    
    compose-debug: 
        MODE=debug docker compose up -d
    

    This setup means you only maintain one Dockerfile and one Docker Compose configuration. You toggle between the modes using the MODE argument.

    Reducing Rebuild Time:
    To avoid complete rebuilds when switching between modes, make sure that the steps that are common between the two modes (like copying code, installing dependencies) are kept at the top of the Dockerfile, and only the diverging steps (like installing Delve) are under the conditional block. This way, Docker can utilize its caching mechanism efficiently.

    Cleanup:

    clean:
        docker compose down
    

    Now you can switch between modes with just make compose-dev or make compose-debug, and when you want to clean up, just run make clean. This setup reduces the manual steps involved and keeps your configuration DRY by avoiding duplication.

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