CircleCI has recently released a new product called orbs which are designed to get you up and running quickly on CircleCI. You can now easily integrate your DevOps tools with trusted orbs provided by our technology partners.

In this post I’ll demonstrate and explain the AWS ECR Orb and its usage within the CircleCI configuration file, leveraging CircleCI Workflows, and pushing an image to Docker Hub and a specified AWS ECR.

What are CircleCI orbs?

Orbs are packages of CircleCI configuration that can be shared across projects. Orbs allow you to make a single bundle of jobs, commands, and executors that can reference each other and can be imported into a CircleCI build configuration and invoked in their own namespace. Orbs are registered with CircleCI, with revisions expressed using the semver pattern. CircleCI orbs are hosted and maintained on the CircleCI Orbs Registry which is a centralized repository for CircleCI orbs.

Prerequisites

Before you get started you’ll need to have these things:

After you have completed all the prerequisites, you’re ready to proceed to the next section.

Configure CircleCI Project Environment Variables

Our project’s CI/CD pipeline will deploy Docker images to multiple container repositories so you need to set some environment variables within the CircleCI Project Settings:

  • Click Add Project on the CircleCI Dashboard in the left menu
  • Find and click the project’s name in the projects list and Click Set Up Project on the right side
  • Click the Project cog button in the CircleCI Dashboard in the top right area
  • In the Build Settings section, click Environment Variables
  • Click Add Variable

In the Add an Environment Variable dialog box you’re going to define several environment variables needed for this build. Below is a list of the environment variables that must be defined:

  • Name: AWS_ECR_ACCOUNT_URL Value: Your AWS ECR Registry URL
  • Name: AWS_ACCESS_KEY_ID Value: Your AWS IAM Account's Access Key ID
  • Name: AWS_SECRET_ACCESS_KEY Value: Your AWS IAM Account's Secret Access Key
  • Name: DOCKER_LOGIN Value: Your Docker Hub User Name
  • Name: Docker_PWD Value: Your Docker Hub Password

Setting these environment variables correctly is critical to the build successfully completing. Ensure that these variables and their values are properly set before continuing to the next section.

Using the CircleCI AWS ECR Orb

Below is the config.yml file that defines this project’s pipeline. In the following sections I’ll explain the various element of this config.yml file.

version: 2.1

orbs:
  aws-ecr: circleci/aws-ecr@0.0.4

workflows:
  build_test_deploy:
    jobs:
      - build_test
      - docker_hub_build_push_image:
          requires:
            - build_test
      - aws-ecr/build_and_push_image:
          region: us-east-1
          account-url: ${AWS_ECR_ACCOUNT_URL}
          repo: ${CIRCLE_PROJECT_REPONAME}
          tag: ${CIRCLE_BUILD_NUM}
          requires:
            - build_test
jobs:
  build_test:
    docker:
      - image: circleci/python:2.7.14
    steps:
      - checkout
      - run:
          name: Setup VirtualEnv
          command: |
            virtualenv helloworld
            . helloworld/bin/activate
            pip install --no-cache-dir -r requirements.txt
      - run:
          name: Run Tests
          command: |
            . helloworld/bin/activate
            python test_hello_world.py
  docker_hub_build_push_image:
    docker:
      - image: circleci/python:2.7.14
    steps:
      - checkout
      - setup_remote_docker:
          docker_layer_caching: false
      - run:
          name: Build and push Docker image to Docker Hub
          command: |
            echo 'export TAG=0.1.${CIRCLE_BUILD_NUM}' >> ${BASH_ENV}
            echo 'export IMAGE_NAME=${CIRCLE_PROJECT_REPONAME}' >> ${BASH_ENV}
            source ${BASH_ENV}
            docker build -t ${DOCKER_LOGIN}/${IMAGE_NAME} -t ${DOCKER_LOGIN}/${IMAGE_NAME}:${TAG} .
            echo ${DOCKER_PWD} | docker login -u ${DOCKER_LOGIN} --password-stdin
            docker push ${DOCKER_LOGIN}/${IMAGE_NAME}

Specifying workflows and orbs

orbs:
  aws-ecr: circleci/aws-ecr@0.0.4

The orbs: key specifies that an orb will be used in this pipeline. The aws-ecr: keys defines an internal name used within the config. The circleci/aws-ecr@0.0.4 value specifies and associates the actual orb to be used and referenced by the aws-ecr: key. These orb statements could be considered as import statements found in other languages and frameworks.

workflows:
  build_test_deploy:
    jobs:
      - build_test
      - docker_hub_build_push_image:
          requires:
            - build_test
      - aws-ecr/build_and_push_image:
          region: us-east-1
          account-url: ${AWS_ECR_ACCOUNT_URL}
          repo: ${CIRCLE_PROJECT_REPONAME}
          tag: ${CIRCLE_BUILD_NUM}
          requires:
            - build_test

Workflow definitions

The workflows: key specifies a list of workflows which are composed of build jobs and orbs. This segment specifies a workflow called build_test_deploy:

jobs:
  - build_test
  - docker_hub_build_push_image:
      requires:
        - build_test

In this segment a jobs: key is specified and lists all of the jobs and orbs executed within this pipeline. The first job in this list is build_test which doesn’t have job dependency.

Orb definitions

The next job in the workflow list, docker_hub_build_push_image:, refers to a job that will be discussed later, but make note of the requires: key which specifies that the docker_hub_build_push_image: job is dependent on the build_test job passing. Otherwise the entire build will fail and the remaining jobs in the workflow will not execute.

- aws-ecr/build_and_push_image:
    region: us-east-1
    account-url: ${AWS_ECR_ACCOUNT_URL}
    repo: ${CIRCLE_PROJECT_REPONAME}
    tag: ${CIRCLE_BUILD_NUM}
    requires:
      - build_test

The above segment shows the aws-ecr/build_and_push_image: key which specifies the execution of the AWS ECR Orb. The AWS ECR Orb has parameters that require values which are assigned built-in enviroment variables in this example. See the AWS ECR Orb docs for more details on this orb. This specific AWS ERC Orb has a dependency on the build_test: job successfully completing before executing the build_and_push_image method of this orb.

Job definitions

I’ve discussed the workflows: and orbs: elements of the config which are references to jobs defined in the primary jobs: elements of this config. The following segment of code shows all of the jobs defined in this configuration syntax.

jobs:
  build_test:
    docker:
      - image: circleci/python:2.7.14
    steps:
      - checkout
      - run:
          name: Setup VirtualEnv
          command: |
            virtualenv helloworld
            . helloworld/bin/activate
            pip install --no-cache-dir -r requirements.txt
      - run:
          name: Run Tests
          command: |
            . helloworld/bin/activate
            python test_hello_world.py
  docker_hub_build_push_image:
    docker:
      - image: circleci/python:2.7.14
    steps:
      - checkout
      - setup_remote_docker:
          docker_layer_caching: false
      - run:
          name: Build and push Docker image to Docker Hub
          command: |
            echo 'export TAG=0.1.${CIRCLE_BUILD_NUM}' >> ${BASH_ENV}
            echo 'export IMAGE_NAME=${CIRCLE_PROJECT_REPONAME}' >> ${BASH_ENV}
            source ${BASH_ENV}
            docker build -t ${DOCKER_LOGIN}/${IMAGE_NAME} -t ${DOCKER_LOGIN}/${IMAGE_NAME}:${TAG} .
            echo ${DOCKER_PWD} | docker login -u ${DOCKER_LOGIN} --password-stdin
            docker push ${DOCKER_LOGIN}/${IMAGE_NAME}

In the above segment, two jobs are defined build_test: and docker_hub_build_push-image: which demonstrates raw configuration syntax. The build_test: job instantiates a Python container, installs app dependencies, and runs the app’s unit tests.

The docker_hub_build_push_image: job sets environment variables used for naming and tagging the image, builds the Docker image based on the Dockerfile, and pushes the built image to Docker Hub.

This entire configuration demonstrates how to define and implement workflows, orbs, and jobs, which offer robust and powerful capabilities in configuration syntax. After successfully executing this pipeline you should end up with a tested Docker image in Docker Hub and your AWS ECR repository.

Summary

As you can see the jobs: segment is a bit more verbose compared to the AWS ECR Orb definition. Orbs are designed to encapsulate functionality, provide consistency and reduce the amount repeated code in pipeline configurations, therefore rendering less verbose configuration syntax.

With orbs, you can share your preferred CI/CD set-up across teams and projects, and integrate tools and third-party solutions easily with just a few lines. Orbs can be written by members of the development community to solve common problems and to help with managing configuration. Sharing and re-using orbs for common use cases frees teams to solve the interesting, unique problems that differentiate their business while offering others within the community solutions that accelerate their CI/CD workflows.

I look forward to the future development of orbs and the awesome streamlined functionality they bring to CI/CD pipelines. If you browse the orb registry and don’t find an orb that fits the functionality that you require, then I encourage you to author your own custom orb. Be aware that at the moment all orbs hosted on the CircleCI Orb Registry are open and publicly available. Private orbs are currently not supported in the registry but this feature is on the orbs road map and will be available in the future.

References

To learn more about orbs, workflows, and CircleCI use the references listed below: