Search code examples
dockerkubernetesnext.jsdockerfileazure-aks

exec /usr/local/bin/docker-entrypoint.sh: exec format error


I created a custom docker image for my nextjs app that i pushed to my azure container registry (ACR), in order to pull into the pod of my azure kubernetes (AKS) cluster, but the pod status says 'CrashLoopBackOff', and the pod logs reveal the error:

exec /usr/local/bin/docker-entrypoint.sh: exec format error

I've looked at this thread (as well as several other similar ones): Docker : exec /usr/bin/sh: exec format error, and I found out I was building my image for the wrong architecture. I was building it on ARM whereas the architecture of my kubernetes node is Linux/AMD64. However, even after changing it, the pod is still logging the same error, and i'm certain that the image is built correctly now for amd64, and that the node architecture is amd64.

I ran this to build the image for amd64: docker buildx build --platform linux/amd64 -t <container_url>/<container_image>:<tag> . --load

I ran this to push the image to my azure container: docker push <container_url>/<container_image>:<tag>

I ran this to verify the image does work locally:

docker run --platform linux/amd64 -it --rm <acr_name>.azurecr.io/<image_name>:v0.1.0

And, to verify the architecture of both the container and pod, I ran the following commands:

docker image inspect <image_id>

output:

[
    {
     ...,
     "Architecture": "amd64",
     "Os": "linux",
    }
]

kubectl get nodes -o=jsonpath='{.items[0].status.nodeInfo.architecture}'

output: 'amd64'

so the architectures appear to match.

I also tried adding a shebang # at the beginning of my dockerfile. Still, i can't seem to figure out why i'm getting the error.

Here's my dockerfile:

#!/bin/bash

# Use an official Node.js runtime as the parent image
FROM node:16

# Update and install dependencies
RUN apt-get update && apt-get install -y curl gnupg

# Install Yarn
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
    echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
    apt-get update && apt-get install -y yarn

# Clean up
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Set the working directory inside the container
WORKDIR /usr/src/app

# Copy .npmrc or .yarnrc for private package access
COPY .npmrc .npmrc

# Copy package.json and package-lock.json (or yarn.lock) to the container
COPY package*.json ./

# Copy the application code to the container
COPY . .

# Install the application's dependencies inside the container
RUN yarn install

# Remove .npmrc or .yarnrc after installation
RUN rm -f .npmrc

# Build the Next.js app
RUN yarn build

# Override the default entrypoint
ENTRYPOINT []

EXPOSE 3000

# Specify the command to run when the container starts
CMD [ "yarn", "start" ]

note: i don't think that ENTRYPOINT [] did anything. If i inspect the image in docker, an image history appears, which displays a list of commands and one them displays:

/bin/sh -c #(nop) ENTRYPOINT ["docker-entrypoint.sh"]

deployment.yaml (angular brackets are used to obfuscate details):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: <placeholder>
spec:
  selector:
    matchLabels:
      app: <placeholder>
  replicas: 1
  template:
    metadata:
      labels:
        app: <placeholder>
    spec:
      containers:
        - name: <container_name>
          image: <container_url>.azurecr.io/<repo_name>:<version_#>
          ports:
            - containerPort: 3000
      imagePullSecrets:
        - name: <secret>

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: <app_name>
spec:
  selector:
    app: <app_name>
  ports:
    - protocol: TCP
      port: 3000
      targetPort: 3000 # Match this to the containerPort above.
  type: LoadBalancer

My nextjs app is just what's generated from running npx create-next-app@latest, no other modifications to the code.

Any thoughts on how to resolve the error? Or perhaps, how to further diagnose the error?

Otherwise, if you know of any good (fairly recent) guides/ articles that go into depth on how to dockerize nextjs for Azure containers and deploy them on azure kubernetes that would also be helpful.

Thank you in advance!


Solution

  • By and large, the error exec /usr/local/bin/docker-entrypoint.sh: exec format error commonly arises due to a CPU/architecture mismatch between the machine that builds the image and the host machine that runs the container.

    In this particular case, the error persisted because the imagePullPolicy was not explicitly set in the deployment.yaml file. When not set, Kubernetes defaults to the IfNotPresent policy, which means it will only pull the image if it isn't already present on the node. Thus, even if an updated image is pushed to the repository of the container registry, a pod could still use the cached old version of the image.

    To ensure the latest version of the image is always used, set the imagePullPolicy to Always:

    spec:
      containers:
        - name: <container_name>
          image: <image_url>:<version_tag>
          imagePullPolicy: Always
    

    Specifically in Azure Kubernetes Service (AKS), if the image is not set to be pulled every time, the node will cache the image. This means that if the pod is deleted and recreated, it will use the cached image rather than fetching it again from the container registry.