Engineering

⌘K
  1. Home
  2. Docs
  3. Engineering
  4. Docker

Docker

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 and NO_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:

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

How can we help?