islegmar
islegmar

Reputation: 101

"Force" docker image creation in Terraform with docker_registry_image (kreuzwerker/docker)

I am developing series of lambdas that are using docker images. The first step is to create them and registering in AWS ECR (not sure if everything I am doing is ok, so any advice is welcomed :-) ):

terraform {
  ...
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = ">= 2.12"
    }
  }
}

resource aws_ecr_repository lambda_repo {
   name = "lambda"
}

resource docker_registry_image lambda_image {
  name = "<account_id>.dkr.ecr.<region>.amazonaws.com/lambda:latest"

  build {
    context    = "./code/lambda"
  }

  depends_on = [
    aws_ecr_repository.lambda_repo
  ]

  keep_remotely = true
}

resource aws_lambda_function lambda {
  ...
  image_uri = "<account_id>.dkr.ecr.<region>.amazonaws.com/lambda:latest"
  source_code_hash = docker_registry_image.lambda_image.sha256_digest
  ...
}

So with this code:

The problem I have is how to "force" docker_registry_image > lambda_image to rebuild the image and update the "lambda:latest" when the Dockerfile or app.py (the main code that is added in the file) has changed. Also I am not sure if this is the way to build the images.

Thanks!!

Upvotes: 6

Views: 1491

Answers (1)

Luke
Luke

Reputation: 51

I was stuck with the exact same problem, and was disappointed to find your question hadn't been answered. I struggled a good bit, but I just clicked late tonight and got mine working.

The problem is incorrect thinking based on bad Docker habits (guilty of the same here!):

  1. latest is a bad habit: it's based on tag mutability, which isn't how docker was designed, and pulling latest is non-deterministic, anyway - you never know what you're going to get. Usually, latest will pull the most recent version on a docker pull.
  2. More on tag immutability: as developers, when encountering a small bug, we often quickly rebuild and overwrite the existing image with the same tag because "nobody will know, and it's just a small fix".
  3. Thinking of the Lambda code files as something with state that should trigger a Terraform replace - the code files are not a resource, they're an asset for creating the Lambda.

Here is the better way to think about this:

  1. docker_registry_image and the kreusewerker/docker provider are based on tag immutability.
  2. docker_registry_image gets "replaced" in Terraform state (you'll see that in the Terraform plan when you try it), but the effect in your ECR repository is to add a new image with a the next sequential tag number, not to replace the actual image as one usually thinks with Terraform.
  3. Each change to your Lambda source code files requires a new image build with a new tag number.
  4. If you find your images piling up on you, then you need a lifecycle policy to automate managing that.
Looking at your code, here is the solution:
  1. Create a new variable called image_tag:
variable "image_tag" {
  default = 1
}
  1. Modify your docker_registry_image so that it uses the image_tag variable (also touching up the docker_registry_image name so you're not doing to much error-prone string building):
resource docker_registry_image lambda_image {
  name = "${aws_ecr_repository.lambda_repo.repository_url}:${var.image_tag}"

  build {
    context    = "./code/lambda"
  }

...
}
  1. Modify your aws_lambda_function. Change the image_uri to the name of the docker_registry_image so that those two are never out of sync:
resource aws_lambda_function lambda {
 
  image_uri = docker_registry_image.lambda_image.name
  source_code_hash = docker_registry_image.lambda_image.sha256_digest
  
}
  1. Each time you change the code in the Lambda's source file(s), increment the image_tag variable by 1. Then try a terraform plan and you'll see that the docker_registry_image and aws_lambda_function will be replaced. A good exercise, would be to look at your ECR repo and Lambda function in the console while you do this. You'll see the images appearing in your ECR repo, and the Lambda function's image uri being updated with the new image_tag.
  2. If you don't like how your image versions are piling up in your ECR repo, look into implementing a ecr_lifecycle_policy

Hope this helps. I sure feel a whole lot better tonight!

Upvotes: 5

Related Questions