Error: exec format error

Modified on Thu, 25 May, 2023 at 12:46 PM

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

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article