AWS Lambda Error block

Hashicorp Packer builds containers, virtual machines, and machine images with virtually any kind of provisioner. In particular, it can create docker images without a Dockerfile and then push them to a repository like ECR. I recently had a project where I used Packer to create a docker image using a bash script provisioner, pushed to AWS Elastic Container Registry (ECR) for use in AWS Lambda. However, the container failed to execute due to a runtime error:

{
  "errorType": "Runtime.ExitError",
  "errorMessage": "RequestId: 1ece70ef-c145-4674-b83b-77acdbc2ecdf Error: Runtime exited with error: exit status 127"
}
{
  "time": "2024-08-10T12:08:07.158Z",
  "type": "platform.initStart",
  "record": {
    "initializationType": "on-demand",
    "phase": "init",
    "functionName": "example",
    "functionVersion": "$LATEST"
  }
}
"/bin/sh: index.handler: No such file or directory"

I specified index.handler as the command to execute in the container; I have function handler exported in index.js under /var/task. It seems the runtime interface client is not working correctly.

Here is a snippet of the packer configuration I used:

packer {
  required_plugins {
    docker = {
      source  = "github.com/hashicorp/docker"
      version = "~> 1"
    }
  }
}

source "docker" "nodejs" {
  image = "public.ecr.aws/lambda/nodejs:20"
  commit = true
}

build {
  sources = ["source.docker.nodejs"]

  provisioner "file" {
    destination = "/var/task"
    source      = "./path/to/code/."
  }

  provisioner "shell" {
    script = "./provision.sh"
    remote_folder = "/var/task"
  }

  post-processors {
    post-processor "docker-tag" {
      repository = "${local.account_id}.dkr.ecr.${var.aws_region}.amazonaws.com/example"
      tags       = [var.environment]
    }

    post-processor "docker-push" {
      ecr_login = true
      aws_access_key = var.aws_access_key
      aws_secret_key = var.aws_secret_key
      login_server = "${local.account_id}.dkr.ecr.${var.aws_region}.amazonaws.com"
    }
  }
}

Looking at the public.ecr.aws/lambda/nodejs:20 Dockerfile, I see the entrypoint defined as /lambda-entrypoint.sh. But inspecting the image packer created shows /bin/sh as the entrypoint, which corresponds to the error message in Lambda:

$ docker image ls
REPOSITORY                                           TAG           IMAGE ID       CREATED             SIZE
<redacted>.dkr.ecr.us-east-1.amazonaws.com/example   development   f60c698142eb   41 minutes ago      2.17GB

$ docker inspect f60c698142eb
[
    {
        # ...
        "Config": {
            # ...
            "Cmd": null,
            "Entrypoint": [
                "/bin/sh"
            ],
        }
    }
]

I didn’t specify the entrypoint at all. Standard docker behavior is to adopt the command and entrypoint values from the source image. Packer, however, changes them in order to provision the image and didn’t set them back to their original values, requiring them to be explicitly defined in the packer configuration. Issues #9 and #176 were opened and resolved by PRs #167 and #177, respectively, effectively solving the problem on June 5 of this year when version 1.0.10 was released.

Updating the docker plugin corrects the entrypoint:

$ packer init -upgrade example.pkr.hcl
Installed plugin github.com/hashicorp/docker v1.0.10 in "/home/<username>/.config/packer/plugins/github.com/hashicorp/docker/packer-plugin-docker_v1.0.10_x5.0_linux_amd64"

$ packer build example.pkr.hcl
# ...

$ docker image ls
REPOSITORY                                           TAG           IMAGE ID       CREATED             SIZE
<redacted>.dkr.ecr.us-east-1.amazonaws.com/example   development   5de1cdd045d9   2 minutes ago      2.17GB

$ docker inspect 5de1cdd045d9
[
    {
        # ...
        "Config": {
            # ...
            "Cmd": [
                ""
            ],
            "Entrypoint": [
                "/lambda-entrypoint.sh"
            ],
        }
    }
]

Note that I define the command in my lambda runtime configuration instead of within the docker image. I did have to delete the lambda function and recreate it for it to refetch the updated image from ECR, but this resolved the problem.