Using GitLab CI to Build and Push Docker Image to AWS ECR
Reference: https://devops.cisel.ch/push-your-docker-containers-from-gitlab-to-amazon-ecr
We have set up an IAM user for that: ecr
.
Protect your GitLab repository’s staging
and production
branches.
In GitLab Project’s CI/CD settings, add the following protected environment variables:
AWS_REGION=ap-southeast-1
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
Then set up .gitlab-ci.yml. Example: lovia/id-card-repo.
.gitlab-ci.yml
for NestJS:
variables:
DOCKER_REGISTRY: *****.dkr.ecr.ap-southeast-1.amazonaws.com
AWS_DEFAULT_REGION: ap-southeast-1
APP_NAME: lovia/lovia-billing # change this to your ECR repository name
DOCKER_HOST: tcp://docker:2375
# Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled
# DOCKER_HOST: tcp://docker:2376
# DOCKER_TLS_CERTDIR: "/certs"
# Reference: https://medium.com/devops-with-valentine/gitlab-ci-build-push-docker-image-to-aws-ecr-elastic-container-registry-b63b91a58728
publish_staging:
stage: build
# Note: AWS CLI v2 does NOT work with Docker-Alpine: https://github.com/aws/aws-cli/issues/4685#issuecomment-556436861
# image: docker:latest
image:
name: amazon/aws-cli
entrypoint: [""]
services:
- docker:dind
before_script:
- amazon-linux-extras install docker
- aws --version
- docker --version
script:
- aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY
- docker build --cache-from $DOCKER_REGISTRY/$APP_NAME:staging -t $DOCKER_REGISTRY/$APP_NAME:$CI_COMMIT_SHA -t $DOCKER_REGISTRY/$APP_NAME:staging .
- docker push $DOCKER_REGISTRY/$APP_NAME:$CI_COMMIT_SHA
- docker push $DOCKER_REGISTRY/$APP_NAME:staging
only:
- staging
publish_production:
stage: build
# Note: AWS CLI v2 does NOT work with Docker-Alpine: https://github.com/aws/aws-cli/issues/4685#issuecomment-556436861
# image: docker:latest
image:
name: amazon/aws-cli
entrypoint: [""]
services:
- docker:dind
before_script:
- amazon-linux-extras install docker
- aws --version
- docker --version
script:
- aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY
- docker build --cache-from $DOCKER_REGISTRY/$APP_NAME:production -t $DOCKER_REGISTRY/$APP_NAME:$CI_COMMIT_SHA -t $DOCKER_REGISTRY/$APP_NAME:production .
- docker push $DOCKER_REGISTRY/$APP_NAME:$CI_COMMIT_SHA
- docker push $DOCKER_REGISTRY/$APP_NAME:production
only:
- production
Ensure that your image is properly pushed ECR, under :staging or :production tag.
Now you can use it in your AWS ECS/Fargate task definition and launch it as an ECS service.
Tips for Running Docker Image on AWS ECS
- Set
FORCE_COLOR=0
andNO_COLOR=1
. Better put it in Dockerfile. - If you use yarn in your
Dockerfile
, add--no-color
, e.g.CMD [ "yarn", "start:prod", "--no-color" ]
Using Kaniko and GitLab CI (Experimental)
Alternatives: Kaniko (does not use Docker daemon), Buildah (like DinD, uses Docker daemon)
Inside Docker/GitLab CI, Kaniko should have faster builds and more secure than docker build:
- https://docs.gitlab.com/ee/ci/docker/using_kaniko.html
- https://github.com/GoogleContainerTools/kaniko#running-kaniko-in-docker
- https://github.com/GoogleContainerTools/kaniko/blob/master/docs/tutorial.md
- https://medium.com/swlh/we-migrated-from-github-to-gitlab-41eec1d21355
- https://itnext.io/docker-kaniko-buildah-209abdde5f94
- https://blog.csanchez.org/2020/10/07/building-docker-images-with-kaniko-pushing-to-amazon-elastic-container-registry-ecr/
- https://forum.gitlab.com/t/docker-deployment-to-either-amazon-ecs-or-ecr/41241/2 -> uses :debug (which has /bin/sh) instead of :latest
- https://gitlab.com/gitlab-org/gitlab/-/issues/25674
Working:
publish_prod:
stage: build
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
# see https://github.com/GoogleContainerTools/kaniko/issues/1227
- mkdir -p /kaniko/.docker
# Requires AWS_REGION, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY in https://gitlab.com/lovia/lovia-billing/-/settings/ci_cd > Variables
- echo "{\"credHelpers\":{\"${DOCKER_REGISTRY}\":\"ecr-login\"}, \"auths\":{\"${CI_REGISTRY}\":{\"auth\":\"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json
- >-
/kaniko/executor
--cache=true --cache-repo=$CI_REGISTRY_IMAGE
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
--destination "$DOCKER_REGISTRY/$APP_NAME:$CI_COMMIT_SHA"
--destination "$DOCKER_REGISTRY/$APP_NAME:prod"
only:
- stack/prod