Search code examples
dockergoaws-lambda

exec /main: no such file or directory when building docker image of Go app


I have a golang application which I want to dockerize and run on AWS Lambda. Here is my Dockerfile:

FROM golang:1.21 as build
WORKDIR /app
RUN apt-get update
RUN apt-get install -y libvips libvips-dev
COPY go.mod go.sum ./
COPY main.go .
RUN GOOS=linux GOARCH=amd64 go build -o main main.go

FROM alpine:3.19
COPY --from=build /app/main /main
ENTRYPOINT [ "/main" ]

I install libvips because I am using bimg library for image compression.

Here is my minified go app:

package main

import (
    "context"
    "log"

    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/s3"
    "github.com/h2non/bimg"
)

var (
    s3Client *s3.Client
)

func init() {
    cfg, err := config.LoadDefaultConfig(context.Background())
    if err != nil {
        log.Fatalf("failed to load AWS config: %v", err)
    }

    s3Client = s3.NewFromConfig(cfg)
}

func main() {
    lambda.Start(Handler)
}

func Handler(ctx context.Context, event events.S3Event) error {
    // compress and upload and do stuff
    return nil
}

Not only I get the error exec /main: no such file or directory when I try to test the lambda from aws dashboard, but it also gives me the same error when I try to run the image on my local machine with the following command:

docker run --rm -it  s3-image-compressor-lambda:latest

I know the lambda won't work on my local machine but I believe it shouldn't say file not found but rather I would expect a runtime error.

UPDATE: I added some commands to Dockerfile to try to debug to see what's going on.

I added RUN ls -l / right after COPY of the main file and here is the output:

#16 [stage-1 4/7] RUN ls -l /
#16 0.354 total 18668
#16 0.354 drwxr-xr-x    2 root     root          4096 Jan 26 17:53 bin
#16 0.354 drwxr-xr-x    5 root     root           340 Apr  4 22:28 dev
#16 0.354 drwxr-xr-x    1 root     root          4096 Apr  4 22:28 etc
#16 0.354 drwxr-xr-x    2 root     root          4096 Jan 26 17:53 home
#16 0.354 drwxr-xr-x    7 root     root          4096 Jan 26 17:53 lib
#16 0.354 -rwxr-xr-x    1 root     root      19055376 Apr  4 22:06 main
#16 0.354 drwxr-xr-x    5 root     root          4096 Jan 26 17:53 media
#16 0.354 drwxr-xr-x    2 root     root          4096 Jan 26 17:53 mnt
#16 0.354 drwxr-xr-x    2 root     root          4096 Jan 26 17:53 opt
#16 0.354 dr-xr-xr-x  459 root     root             0 Apr  4 22:28 proc
#16 0.354 drwx------    2 root     root          4096 Jan 26 17:53 root
#16 0.354 drwxr-xr-x    2 root     root          4096 Jan 26 17:53 run
#16 0.354 drwxr-xr-x    2 root     root          4096 Jan 26 17:53 sbin
#16 0.354 drwxr-xr-x    2 root     root          4096 Jan 26 17:53 srv
#16 0.354 dr-xr-xr-x   13 root     root             0 Apr  4 22:28 sys
#16 0.354 drwxrwxrwt    2 root     root          4096 Jan 26 17:53 tmp
#16 0.354 drwxr-xr-x    7 root     root          4096 Jan 26 17:53 usr
#16 0.354 drwxr-xr-x   12 root     root          4096 Jan 26 17:53 var
#16 DONE 0.4s

So there is actually a main file in the root directory.

After that I added RUN /main to see what is gonna happen, and here is the output:

 > [stage-1 8/8] RUN /main:
0.258 /bin/sh: /main: not found

Solution

  • FROM golang:1.21 as build
    
    WORKDIR /app
    
    RUN apt-get update
    RUN apt-get install -y libvips libvips-dev
    
    COPY go.mod go.sum main.go .
    
    RUN go mod download
    RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build \
            -tags netgo \
            -o main main.go
    
    FROM debian:bookworm-slim
    
    RUN apt-get update && apt-get install -y libvips
    
    COPY --from=build /app /app
    
    ENTRYPOINT ["/app/main"]