skip to Main Content

I’m making a simple Rest API using Go and I want to containerize it using docker for deployment. My Dockerfile looks like this

FROM golang:1.19

# Port to expose
ENV PORT=8080

WORKDIR /go/src/app

# Install libvips
RUN apt-get update && apt-get install -y libvips-dev

# Copy go.mod and go.sum
COPY go.mod go.sum ./

# Install go dependencies
RUN go mod download

# Set PKG_CONFIG_PATH for libvips
ENV PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig
RUN pkg-config --libs vips

# Copy the source code
COPY . .

# Uncomment to build the app 
# Build the app 
RUN go build -o main .

# Expose the port
EXPOSE 8080

# Run the app
CMD ["./main"]

and my docker-compose file looks like this:

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: backend
    command: ./main
    ports:
      - "3000:8080"
    volumes:
      - .:/go/src/app

I’m new to docker and containerization, but I think this should work in terms of setup (Note: It has worked a few times before, but recently stopped working for some reason). I get the following error: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "./main": stat ./main: no such file or directory: unknown.

This error leads me to believe that my exe is not being built in the working directory, but I am unsure where it gets built since I’ve set the build command using relative paths. Any idea on what could be causing this issue?

3

Answers


  1. You shouldn’t include the volumes mapping (.:/go/src/app) in the docker-compose file.

    When you do this, you’re overwriting the container’s folder with your host’s folder.

    A key difference between the two is that the container’s folder includes the output from go build. You’re building the binary (/go/src/app/main) and then overwriting the entire folder with the volumes mapping.

    NOTE It’s better practice to use ENTRYPOINT rather than CMD to run the binary, i.e. ENTRYPOINT ["./main"]. The value(s) of CMD are overwritten by any parameters provided when the container is run whereas ENTRYPOINT may only be overwritten by explicitly setting the --entrypoint flag. Conventionally, use ENTRYPOINT to define the binary (and any flags) that must always be invoked by the container and use CMD for optional flags that may be overwritten.

    Login or Signup to reply.
  2. This is a slight tangent, but use --no-install-recommends with libvips. The Debian package includes libvips-tools in the recommends list for libvips-dev, and that in turn will pull in the libvips GUI and most of X11.

    You can see the difference it makes like this:

    $ docker run -it --rm golang:1.19
    root@c54a0cab0cb0:/go# 
    root@c54a0cab0cb0:/go# 
    root@c54a0cab0cb0:/go# apt update
    ...
    root@c54a0cab0cb0:/go# apt install libvips-dev
    ...
    Need to get 189 MB of archives.
    After this operation, 740 MB of additional disk space will be used.
    Do you want to continue? [Y/n] ^C
    ...
    

    So a reular install is 740mb of space. But:

    root@c54a0cab0cb0:/go# apt install libvips-dev --no-install-recommends
    Need to get 92.2 MB of archives.
    After this operation, 374 MB of additional disk space will be used.
    Do you want to continue? [Y/n] ^C
    

    About half the size.

    Login or Signup to reply.
  3. When you run the container, the value of CMD will be overwritten by any parameters provided. It is better to use ENTRYPOINT instead of CMD to run binary files, that is ENTRYPOINT ["./main"].

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