4

I have deployed my lambda with Terraform. It is pointing successfully to ECR and the image runs with the expected ENTRYPOINT. However, every time I push new code to ECR, I have to go to the web console, click "Deploy New Image" else the lambda runs the old image.

Also, I tried using :latest as the tag, but that didn't seem to help. I was able to force a new image by uploading :2, :3 and then manually pointing the lambda at those. If there is a way to use the :latest tag that would be a nice convenience.

I'd be happier to do this with bash or boto, but no obvious way to do so from my reading of the docs.

This similar question was shut down because lambdas used to not be backed by docker images.

MatthewMartin
  • 32,326
  • 33
  • 105
  • 164
  • 1
    Reusing the "latest" tag is problematic pretty much everywhere that runs docker containers (or really any re-use of the same tag). One option would be to have another lambda monitor ECR for new tags and automatically update your current lambda. https://stackoverflow.com/q/47416819/1032785 – jordanm Apr 06 '21 at 22:26
  • You could also adjust you're deployment pipeline that create and uploads the image to ECR to also handle modifying the lambda – jordanm Apr 06 '21 at 22:27

3 Answers3

6

Use the aws cli to update the lambda function.

Assuming you've got a profile or have appropriate credentials set in your environment you can call aws lambda update-function-code and provide your required image-uri. As you've defined the uri already you can query the function for the value.

aws lambda update-function-code --function-name $MY_FUNC --image-uri $(aws lambda get-function --function-name $MY_FUNC | jq -r '.Code.ImageUri')

I'm using jq to extract the ImageUri but I'm sure there are as many other ways and opinions about how to go about it.

If you have a look at the entire .Code object returned from aws lambda get-function --function-name $MY_FUNC you can check the sha256 and see that refect your updated function image.

Current docs: AWS CLI update-function-code docs

Matt Bracewell
  • 159
  • 1
  • 9
1

It is wise to separate the image storage from the deployment process. I propose using semver for versioning the docker images. https://semver.org/

Then you can store the version number for the lambda docker image in a variable in terraform and pass it to your lambda module.

Of course this will be an extra step of running terraform apply for deployment, but this will lock down the state of your system and will make it easier to reproduce the environment state.

wasserholz
  • 1,960
  • 2
  • 20
  • 26
1

I was having this problem and it was because I was also using latest. My Terraform code is being run as a second job in a GitHub actions workflow, and the first job builds, pushes and tags the new image. So the solution was to use a needs context output to pass the tag from the first job to the second job, and then use a -var argument to pass the tag into the Plan/Apply step of the Terraform job:

deploy-lambda.yml (Based on this.)

- name: Terraform Apply
  if: github.ref == 'refs/heads/main' && github.event_name == 'push'
  run: terraform apply -auto-approve -input=false -var="ECR_IMAGE_TAG=${{ needs.deploy.outputs.image_tag }}"

You could also just pass the variable in when calling terraform apply from the command line, as above. The key change was this in my Terraform code. (Of course, I also had to declare the variable.)

lambda.tf

resource "aws_lambda_function" "default" {
  function_name = var.project_name

  role    = aws_iam_role.lambda.arn
  timeout = "180"

  package_type = "Image"
  image_uri    =  "${data.aws_ecr_repository.repo.repository_url}:${var.ECR_IMAGE_TAG}"
}

Now, every time I push, the lambda is pointed to the newest version of the image by its tag (the GitHub SHA).

(I know you probably aren't using GHA, but the solution would be similar in any IaC/CI workflow.)

Vivek Jain
  • 3,811
  • 6
  • 30
  • 47
Nick K9
  • 3,885
  • 1
  • 29
  • 62