12

Using terraform to pull and reload an public image from Dockerhub (or just custom image) to ECR. I was thinking about something like

# Create ECR repository
resource "aws_ecr_repository" "ecr_repo" {
  name                 = var.ecr_name
}
# Docker image
resource "null_resource" "docker_hub" {
        ......
        ......
  depends_on = [aws_ecr_repository.ecr_repo]
}

Basically create an ECR repo and then uplodading an image... I'm new to terrform and been spending quite a lot of time on this. so anything would help. Thanks

minnie
  • 123
  • 1
  • 1
  • 6

3 Answers3

13

Terraform was really only designed for creating infrastructure like the AWS ECR repository and policy document resources. It is possible to coerce Terraform to do what you want using the local-exec provisioner which would let you add arbitrary commands, but it's not really best practice. As they mention in the documentation Terraform provisioners should be treated as a last resort.

The simplest way forward would be to just combine Terraform with Docker and AWS CLI commands to build and push the image:

# ...terraform commands    
docker build -t ${ACCOUNT}.dkr.ecr.${REGION}.amazonaws.com/${REPO} .

aws ecr get-login-password \
    --region ${REGION} \
| docker login \
    --username AWS \
    --password-stdin ${ACCOUNT}.dkr.ecr.${REGION}.amazonaws.com

docker push ${ACCOUNT}.dkr.ecr.${REGION}.amazonaws.com/${REPO}

Alternatively, you could use HashiCorp Packer which was designed for this purpose (building VM/container images) and has great integration with Terraform. This would mean more of a learning curve though, as Packer doesn't use Dockerfiles. Anyway, if you go down this path you'd need to use the Docker builder combined with the Docker push post-processor.

polycode
  • 186
  • 3
  • 2
    I agree with this answer. I just want to add that you could use the [Amazon ECR Credential Helper](https://github.com/awslabs/amazon-ecr-credential-helper) and skip the `aws ecr get-login-password` step. – Mark B Aug 05 '21 at 14:26
  • if you were to run the script above in a local-exec provisioner, how would you go about installing and running docker, which would be required to run that script? – Kappacake May 17 '23 at 13:32
  • also, how do you deal with authentication when running the aws cli command? – Kappacake May 17 '23 at 14:47
  • I second @Kappacake I dont get how to run this without docker – Nathanael Steinhauer Aug 22 '23 at 23:14
2

you would use the aws_ecr_repository resource as you have done, and any other resources you would like to use in the ECR AWS Provider. The one below is the aws_ecr_repository_policy to be able to set the permissions on the repository.

resource "aws_ecr_repository_policy" "demo-repo-policy" {
  repository = aws_ecr_repository.demo-repository.name
  policy     = <<EOF
  {
    "Version": "2008-10-17",
    "Statement": [
      {
        "Sid": "adds full ecr access to the demo repository",
        "Effect": "Allow",
        "Principal": "*",
        "Action": [
          "ecr:BatchCheckLayerAvailability",
          "ecr:BatchGetImage",
          "ecr:CompleteLayerUpload",
          "ecr:GetDownloadUrlForLayer",
          "ecr:GetLifecyclePolicy",
          "ecr:InitiateLayerUpload",
          "ecr:PutImage",
          "ecr:UploadLayerPart"
        ]
      }
    ]
  }
  EOF
}

Afterwards you can use the attributes from the resources you have used, for the docker push command

docker push ${aws_account_id}.dkr.ecr.${region}.amazonaws.com/${repository-name}

more information in the following tutorial https://www.oneworldcoders.com/blog/using-terraform-to-provision-amazons-ecr-and-ecs-to-manage-containers-docker

Shaqil Ismail
  • 1,794
  • 1
  • 4
  • 5
1

Use the aws_ecr_authorization_token data source to configure the Docker provider to read/push from AWS ECR.

This works atleast as of July 2023. See example terraform configuration file:

# tell terraform which provider plugins are needed
terraform {
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = "3.0.2"
    }
    aws = {
      source  = "hashicorp/aws"
      version = "5.6.2"
    }
  }
}

# configure aws provider
provider "aws" {}

# create ecr repo
resource "aws_ecr_repository" "my-ecr-repo" {
  name = "my-ecr-repo"
}

# get authorization credentials to push to ecr
data "aws_ecr_authorization_token" "token" {}

# configure docker provider
provider "docker" {
  registry_auth {
      address = data.aws_ecr_authorization_token.token.proxy_endpoint
      username = data.aws_ecr_authorization_token.token.user_name
      password  = data.aws_ecr_authorization_token.token.password
    }
}

# build docker image
resource "docker_image" "my-docker-image" {
  name = "${data.aws_ecr_authorization_token.token.proxy_endpoint}/my-ecr-repo:latest"
  build {
    context = "."
  }
  platform = "linux/arm64"
}

# push image to ecr repo
resource "docker_registry_image" "media-handler" {
  name = docker_image.my-docker-image.name
}
Govind Rai
  • 14,406
  • 9
  • 72
  • 83
  • this doesn't work for me. Says "Error: Error pinging Docker server: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? provider 'docker' { ". Any ideas? – Nathanael Steinhauer Aug 22 '23 at 22:18
  • yes, that means docker is not running :) You need to turn on docker desktop or docker daemon from the command line if you don't have docker desktop. – Govind Rai Aug 22 '23 at 23:36
  • 1
    Unfortunately i'm looking for a solution with Terraform Cloud not my local environment. And I've found everyone build their images outside of Terraform, so now i'm using Github Actions to do that. – Nathanael Steinhauer Aug 31 '23 at 02:11