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
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.
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.
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:
Now, you just need to pass the build argument in your Docker Compose file:
Utilize Makefile for Mode Setting:
In your Makefile, you can set the MODE environment variable which will be picked up by Docker Compose:
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:
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.