dockergodocker-composedockerfiledocker-multi-stage-build

How to run both CMD and ENTRYPOINT scripts if they are in different images?


I'm using docker multistage build and am trying to add a live reload feature to my dockerized go application. I have an entrypoint.sh with its own configurations in the second image.

Now, the problem is that the command CMD ["air", "-c", ".air.toml"] from the first image gets overwritten by the ENTRYPOINT ["/entrypoint.sh"] scripts from the second image, so it is only the ENTRYPOINT that is started and CMD doesn't run.

I can't combine them into the only command like so

ENTRYPOINT ["/entrypoint.sh", "air", "-c", ".air.toml"]

because the second Image doesn't have Golang language installed with the respective libraries.

Is it possible somehow to run CMD and ENTRYPOINT side by side? Thank you.

Dockerfile

FROM golang:1.17.2
COPY . /go/src/sample

WORKDIR /go/src/sample
RUN go install github.com/go-delve/delve/cmd/dlv@latest
RUN go install github.com/cosmtrek/air@latest
CMD ["air", "-c", ".air.toml"]

FROM eclipse-temurin:17-focal
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

docker-compose.yml

version: '3'
services:
  go:
    build:
      context: ./backend
      dockerfile: Dockerfile
    volumes:
      - ./backend:/go/src/backend
    working_dir: /go/src/backend
    ports:
      - 8080:8080

Solution

  • Read the arguments passed to the entrypoint which is the CMD.

    For example, below is your entrypoint script. You can access the args and do something with them, i.e. execute them.

    #!/bin/bash
    
    # dome something in your entrypoint
    
    # execute the original command
    # substituting the current process id
    # so that command is run with pid 1
    exec "$@"
    

    In your docker image, make sure you have the desired command, i.e.

    ENTRYPOINT ["/entryppoint.sh"]
    CMD ["echo", "command"]
    

    Apart from this technical aspect, you seem to imply that you want to run the CMD that relies on go being available without go being available. That is not possible. You need to ensure the thing you are trying to execute and its dependencies are available.

    You can probably copy the air binary from the first stage. Something like this.

    COPY --from=0 /go/bin/air /usr/local/bin/air
    

    Potentially, you want to compile air this with CGO_ENABLED=0.

    However, I would assume that you need the go compiler to be present in your image for any hot reload to work, since your app needs to be recompiled on code change. So perhaps you should not even use multi staging here.

    That, said. Doing hot reload in a container seems a bit like an anti pattern. Containers are usually a mean to distribute your artifacts.