英文:
golang lambda docker from alternative image
问题
我正在尝试为运行golang处理程序的lambda创建一个docker镜像,但不使用public.ecr.aws/lambda/go:1或public.ecr.aws/lambda/provided:al2。
我尝试按照AWS文档中的步骤进行操作,参考替代基础镜像。
还有这个教程:
https://hichaelmart.medium.com/using-container-images-with-aws-lambda-7ffbd23697f1
但是它就是不起作用。Lambda函数启动了,但不会处理任何请求。发送请求:
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"body":{"name":"Test"}}'
从不返回。
如果我使用public.ecr.aws/lambda/go:1,它就可以正常工作。
根据我所看到的,可能缺少"运行时接口",但他们的go api声称将其作为处理程序代码的包装器来实现。
这是我的Dockerfile
FROM alpine:3.16
ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/bin/aws-lambda-rie
RUN chmod 755 /usr/bin/aws-lambda-rie
WORKDIR /var/task
COPY main ./
ENTRYPOINT ["/usr/bin/aws-lambda-rie", "/var/task/main"]
这是我的lambda处理程序
type MyEvent struct {
	Name string `json:"name"`
}
func HandleRequest(_ context.Context, name MyEvent) (string, error) {
	return fmt.Sprintf("Hello %s!", name.Name), nil
}
func main() {
	lambda.Start(HandleRequest)
}
在处理请求的docker上的日志如下:
15 May 2023 06:34:03,985 [INFO] (rapid) exec '/var/task/main' (cwd=/var/task, handler=/var/task/main)
15 May 2023 06:34:08,178 [INFO] (rapid) extensionsDisabledByLayer(/opt/disable-extensions-jwigqn8j) -> stat /opt/disable-extensions-jwigqn8j: no such file or directory
15 May 2023 06:34:08,180 [INFO] (rapid) Configuring and starting Operator Domain
15 May 2023 06:34:08,182 [INFO] (rapid) Starting runtime domain
15 May 2023 06:34:08,188 [WARNING] (rapid) Cannot list external agents error=open /opt/extensions: no such file or directory
START RequestId: dfbc9842-2a7b-4a3e-bfd2-2434aa126f63 Version: $LATEST
15 May 2023 06:34:08,198 [INFO] (rapid) Starting runtime without AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN , Expected?: false
START RequestId: 5e0f07ac-46a3-42e0-8a60-851293544020 Version: $LATEST
如果有关于我需要在Dockerfile中添加什么的任何帮助,将不胜感激。
英文:
I'm trying to create a docker image for lambda running a golang handler, but which does not take from public.ecr.aws/lambda/go:1 or public.ecr.aws/lambda/provided:al2.
I tried to follow the steps on aws documentation for alternative base image.
And also this tutorial:
https://hichaelmart.medium.com/using-container-images-with-aws-lambda-7ffbd23697f1
It just won't work. The lambda starts but won't serve any requests. Making a request:
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"body":{"name":"Test"}}'
Never returns.
If I use public.ecr.aws/lambda/go:1 it works fine.
From what I've seen, it might be missing the "runtime interface" but their go api claims to be implementing it as a wrapper to the handler code.
This is my Dockerfile
FROM alpine:3.16
ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/bin/aws-lambda-rie
RUN chmod 755 /usr/bin/aws-lambda-rie
WORKDIR /var/task
COPY main ./
ENTRYPOINT ["/usr/bin/aws-lambda-rie", "/var/task/main"]
This is my lambda handler
type MyEvent struct {
	Name string `json:"name"`
}
func HandleRequest(_ context.Context, name MyEvent) (string, error) {
	return fmt.Sprintf("Hello %s!", name.Name), nil
}
func main() {
	lambda.Start(HandleRequest)
}
The logs on the docker serving the requests are
15 May 2023 06:34:03,985 [INFO] (rapid) exec '/var/task/main' (cwd=/var/task, handler=/var/task/main)
15 May 2023 06:34:08,178 [INFO] (rapid) extensionsDisabledByLayer(/opt/disable-extensions-jwigqn8j) -> stat /opt/disable-extensions-jwigqn8j: no such file or directory
15 May 2023 06:34:08,180 [INFO] (rapid) Configuring and starting Operator Domain
15 May 2023 06:34:08,182 [INFO] (rapid) Starting runtime domain
15 May 2023 06:34:08,188 [WARNING] (rapid) Cannot list external agents error=open /opt/extensions: no such file or directory
START RequestId: dfbc9842-2a7b-4a3e-bfd2-2434aa126f63 Version: $LATEST
15 May 2023 06:34:08,198 [INFO] (rapid) Starting runtime without AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN , Expected?: false
START RequestId: 5e0f07ac-46a3-42e0-8a60-851293544020 Version: $LATEST
Any help on what I need to add to the Dockerfile would be appreciated.
答案1
得分: 0
main二进制文件的构建方式尚不清楚,但很可能不是为alpine构建的。如果你检查容器的日志,应该会看到类似以下的内容:
[WARNING] (rapid) First fatal error stored in appctx: Runtime.InvalidEntrypoint
[ERROR] (rapid) Init failed error=fork/exec /var/task/main: no such file or directory InvokeID=
解决方案有两种:
- 要么替换基础的Docker镜像以匹配
main的构建方式; - 要么重新为
alpine构建main二进制文件。 
下面的Dockerfile展示了如何为alpine构建main二进制文件:
# ==== 构建阶段 ====
FROM golang:1.18.4-alpine3.16 as build
WORKDIR /app
COPY . .
RUN go build -o main .
# ==== 最终阶段 ====
FROM alpine:3.16.1
ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/bin/aws-lambda-rie
RUN chmod 755 /usr/bin/aws-lambda-rie
WORKDIR /var/task
COPY --from=build /app/main ./
ENTRYPOINT ["/usr/bin/aws-lambda-rie", "/var/task/main"]
我也对为什么aws-lambda-rie在alpine上工作感到好奇。我发现它是使用CGO_ENABLED=0构建的(参见这里)。因为简单的演示不需要cgo,我们可以采用相同的方式构建:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main .
这个main二进制文件也可以在alpine上工作。
英文:
It's not clear how the main binary is built, but it's most likely that it's not built for alpine. If you check the log of the container, you should see something like this:
[WARNING] (rapid) First fatal error stored in appctx: Runtime.InvalidEntrypoint
[ERROR] (rapid) Init failed error=fork/exec /var/task/main: no such file or directory InvokeID=
The solutions are:
- either replace the base docker image to match what 
mainis built for; - or rebuild the 
mainbinary foralpine. 
The Dockerfile below shows how to build the main binary for alpine:
# ==== build stage ====
FROM golang:1.18.4-alpine3.16 as build
WORKDIR /app
COPY . .
RUN go build -o main .
# ==== final stage ====
FROM alpine:3.16.1
ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/bin/aws-lambda-rie
RUN chmod 755 /usr/bin/aws-lambda-rie
WORKDIR /var/task
COPY --from=build /app/main ./
ENTRYPOINT ["/usr/bin/aws-lambda-rie", "/var/task/main"]
I'm also curious about why aws-lambda-rie works on alpine. And I found that it's built with CGO_ENABLED=0 (see here). We can do the same thing because the simple demo don't need cgo:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main .
This main binary works on alpine too.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论