When building a custom function or container (or deploying a custom listener) for Direktiv on Kubernetes, you might sometimes run into the following error:
exec format error
Let's look at why. Let's build the custom container:
% docker build -t linode-receiver . [+] Building 7.0s (16/16) FINISHED => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 37B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/alpine:latest 1.7s => [internal] load metadata for docker.io/library/golang:1.18.2-alpine 1.3s => [auth] library/golang:pull token for registry-1.docker.io 0.0s => [auth] library/alpine:pull token for registry-1.docker.io 0.0s => [certs 1/2] FROM docker.io/library/alpine:latest@sha256:69665d02cb32192e52e07644d76bc6f25abeb5410edc1c7a81a10ba3f0efb90a 0.5s => => resolve docker.io/library/alpine:latest@sha256:69665d02cb32192e52e07644d76bc6f25abeb5410edc1c7a81a10ba3f0efb90a 0.0s => => sha256:d74e625d91152966d38fe8a62c60daadb96d4b94c1a366de01fab5f334806239 1.49kB / 1.49kB 0.0s => => sha256:af6eaf76a39c2d3e7e0b8a0420486e3df33c4027d696c076a99a3d0ac09026af 3.26MB / 3.26MB 0.4s => => sha256:69665d02cb32192e52e07644d76bc6f25abeb5410edc1c7a81a10ba3f0efb90a 1.64kB / 1.64kB 0.0s => => sha256:c41ab5c992deb4fe7e5da09f67a8804a46bd0592bfdf0b1847dde0e0889d2bff 528B / 528B 0.0s => => extracting sha256:af6eaf76a39c2d3e7e0b8a0420486e3df33c4027d696c076a99a3d0ac09026af 0.1s => [build 1/4] FROM docker.io/library/golang:1.18.2-alpine@sha256:4795c5d21f01e0777707ada02408debe77fe31848be97cf9fa8a1462da78d949 0.0s => [internal] load build context 0.0s => => transferring context: 302B 0.0s => CACHED [build 2/4] WORKDIR /go/src/app 0.0s => [build 3/4] ADD . /go/src/app 0.0s => [build 4/4] RUN CGO_ENABLED=0 go build -o /linode-receiver -ldflags="-s -w" *.go 4.8s => [certs 2/2] RUN apk --update add ca-certificates 1.2s => [stage-2 1/2] COPY --from=build /linode-receiver / 0.0s => [stage-2 2/2] COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:e91976d53c8ff1b9b3de2c99c31d3aa94af397aa2a862f0d4580b6d05af909df 0.0s => => naming to docker.io/library/linode-receiver
Looking at the custom listener built for Linode (as an example), the docker images list shows the following:
% docker images REPOSITORY TAG IMAGE ID CREATED SIZE linode-receiver latest e91976d53c8f About a minute ago 9.13MB wwonigkeit/linode-receiver 1.0 e91976d53c8f About a minute ago 9.13MB
The image is pushed to Docker Hub (my repository) using the following command:
% docker push wwonigkeit/linode-receiver:1.0 The push refers to repository [docker.io/wwonigkeit/linode-receiver] 926226f30997: Pushed 87f24d75638c: Pushed 1.0: digest: sha256:2694fe4b68266b1cb6fa62ab3aa5f66fcc9c22bd338fb6d5d0a1dcebc2c0bf94 size: 737
So now I want to run this as a container in Kubernetes to send events to Direktiv. For this we use the following command (the full configuration YAML file simply pushes the above Docker Hub container into the default namespace:
% kubectl apply -f linode-receiver.yaml configmap/linode-receiver-cfg-cm created deployment.apps/linode-receiver created
Looking at the pod in Kubernetes:
% kubectl get pods NAME READY STATUS RESTARTS AGE direktiv-api-6f8567555b-pq7q8 2/2 Running 0 15d direktiv-flow-564c8fc4cc-jh5dh 3/3 Running 0 15d direktiv-functions-6f6698d7fb-s7n9z 2/2 Running 0 15d direktiv-prometheus-server-667b8c6d65-6nzxm 3/3 Running 0 15d direktiv-ui-d947dccc-zlzxc 2/2 Running 0 15d knative-operator-58647bbfd5-w9kvc 1/1 Running 0 15d linode-receiver-547b5fd95d-fz5q6 0/1 CrashLoopBackOff 1 (3s ago) 6s operator-webhook-b866dc4c-6klqx 1/1 Running 0 15d
Let's look at the error message:
% kubectl logs linode-receiver-547b5fd95d-fz5q6 exec /linode-receiver: exec format error
So why is this happening? The container was built for the default platform on which the docker image was created! In this case, I was using Apple Silicon (linux/arm64), while Direktiv needs an linux/amd64 image type!
There is a VERY simple solution. Simply build the image with the following argument added to your Docker build command:
% docker build --platform linux/amd64 -t linode-receiver . [+] Building 1.3s (16/16) FINISHED => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 37B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/alpine:latest 1.1s => [internal] load metadata for docker.io/library/golang:1.18.2-alpine 1.2s => [auth] library/alpine:pull token for registry-1.docker.io 0.0s => [auth] library/golang:pull token for registry-1.docker.io 0.0s => [internal] load build context 0.0s => => transferring context: 302B 0.0s => [build 1/4] FROM docker.io/library/golang:1.18.2-alpine@sha256:4795c5d21f01e0777707ada02408debe77fe31848be97cf9fa8a1462da78d949 0.0s => [certs 1/2] FROM docker.io/library/alpine:latest@sha256:69665d02cb32192e52e07644d76bc6f25abeb5410edc1c7a81a10ba3f0efb90a 0.0s => CACHED [build 2/4] WORKDIR /go/src/app 0.0s => CACHED [build 3/4] ADD . /go/src/app 0.0s => CACHED [build 4/4] RUN CGO_ENABLED=0 go build -o /linode-receiver -ldflags="-s -w" *.go 0.0s => CACHED [stage-2 1/2] COPY --from=build /linode-receiver / 0.0s => CACHED [certs 2/2] RUN apk --update add ca-certificates 0.0s => CACHED [stage-2 2/2] COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:fd937c0bce7c4d6591bf9599eac882e204bf5049dea980e54b7ad7b3982e85b7 0.0s => => naming to docker.io/library/linode-receiver
That's all it takes! You now have an linux/amd64 compatible image for Direktiv!
Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article