# How-to: build and push Docker images with Kaniko

**URL:** <https://discuss.circleci.com/t/how-to-build-and-push-docker-images-with-kaniko/44923>\
**Category:** Tips, Tricks, and Hacks\
**Tags:** kaniko, docker\
**Created:** [August 2, 2022, 3:08am UTC](https://discuss.circleci.com/t/how-to-build-and-push-docker-images-with-kaniko/44923 "2022-08-02T03:08:25Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![kelvintaywl](https://sea2.discourse-cdn.com/circleci/user_avatar/discuss.circleci.com/kelvintaywl/32/28141_2.png) [@kelvintaywl](https://discuss.circleci.com/u/kelvintaywl)\
**Post date:** [August 2, 2022, 3:08am UTC](https://discuss.circleci.com/t/how-to-build-and-push-docker-images-with-kaniko/44923/1 "2022-08-02T03:08:25Z")

</div>

**Brief**

[Kaniko](https://github.com/GoogleContainerTools/kaniko) is a tool to build and push Docker images from within a container or k8s cluster.  
Importantly, this is done without a Docker daemon.

For CircleCI builds, Kaniko allows us to build and push Docker images **without** [the Remote Docker engine](https://circleci.com/docs/glossary#remote-docker).

In this how-to guide, we will take a look at how to push images, with Kaniko, to the following:

- AWS ECR
- Docker Hub

**Before you start**

> 📝 I am using [project environment variables](https://circleci.com/docs/env-vars#setting-an-environment-variable-in-a-project) (env vars) for storing credentials for Docker Hub and AWS ECR. Your team may choose to use [org contexts](https://circleci.com/docs/contexts) instead.

> ⚠ Docker Layer Caching feature is not compatible for Kaniko builds (since there are no Docker daemons).   
> Consider using [Kaniko’s caching feature instead](https://github.com/GoogleContainerTools/kaniko#caching).   
>   
> Please also be aware of existing [limitations with Kaniko](https://github.com/GoogleContainerTools/kaniko#limitations).

**AWS ECR**

1. [Configure AWS credentials](https://github.com/GoogleContainerTools/kaniko#pushing-to-amazon-ecr)
  - [Ensure least-privilege permissions](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) (to push image to AWS ECR) if possible.
  - In this example, I’ve set up AWS credentials via [project environment variables](https://circleci.com/docs/env-vars#setting-an-environment-variable-in-a-project)

2. Define a CircleCI [Docker executor](https://circleci.com/docs/using-docker) job as shown below

```yaml
jobs:
  kaniko-build-push-aws-ecr:
    # NOTE: Kaniko executor already comes with AWS ECR credential helper installed
    # See https://github.com/GoogleContainerTools/kaniko#pushing-to-amazon-ecr
    # What this means is that, we can just inject AWS credentials.
    # In this example, we set credentials via AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY project env vars
    environment:
      # NOTE: Replace these values as required
      AWS_DEFAULT_REGION: ap-northeast-1
      AWS_REGION: ap-northeast-1
    docker:
      # we use the debug tag since it comes with sh
      - image: gcr.io/kaniko-project/executor:debug
        entrypoint: ""
    steps:
      - checkout
      - run:
          name: Build and Push image
          command: |
            # We pass in AWS credentials and configuration through the AWS_* env vars, via build-arg arguments.
            # See https://github.com/GoogleContainerTools/kaniko/issues/713#issuecomment-557596725
            # NOTE: please replace --destination to your AWS ECR image's URL accordingly
            /kaniko/executor \
                --context "$(pwd)" \
                --dockerfile "$(pwd)/Dockerfile" \
                --build-arg AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION \
                --build-arg AWS_REGION=$AWS_REGION \
                --build-arg AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
                --build-arg AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
                --destination "public.ecr.aws/z1j6a2i1/kelvintaywl/fancy-nginx:${CIRCLE_SHA1}"

```

**Docker Hub**

1. [Set up Docker Hub credentials](https://github.com/GoogleContainerTools/kaniko#pushing-to-docker-hub)
  - Create a config.json file with Docker Hub credentials which we will mount to the Kaniko container
  - In this example, I have [dynamically created a config.json](https://github.com/kelvintaywl-cci/whale-this-work/blob/6329a273a4e3e9ce21a30cba0ab7467ab736bbf0/.circleci/config.yml#L179-L184) by running [a shell script](https://github.com/kelvintaywl-cci/whale-this-work/blob/master/config.sh) injecting the env vars

2. Define a CircleCI [Docker executor](https://circleci.com/docs/using-docker) job as shown below

```yaml
jobs:
  kaniko-build-push-docker-hub:
    environment:
      # NOTE: Replace these values as required
      DOCKER_REGISTRY: docker.io
    docker:
      # we use the debug tag since it comes with sh
      - image: gcr.io/kaniko-project/executor:debug
        entrypoint: ""
    steps:
      - checkout
      - run:
          name: add Docker Hub credentials
          command: |
            # NOTE: Docker Hub credentials (DOCKER_LOGIN and DOCKER_PASSWORD env vars)
            # are injected via project env vars
            mkdir -p /kaniko/.docker
            ./config.sh
            mv config.json /kaniko/.docker
      - run:
          name: Build and Push image
          command: |
            /kaniko/executor \
                --context "$(pwd)" \
                --dockerfile "$(pwd)/Dockerfile" \
                --destination "${DOCKER_REGISTRY}/kelvintaywl/fancy-nginx:${CIRCLE_SHA1}"

```

**Important**

Note that the Kaniko executor image is only concerned with building and pushing images.  
If your job is trying to do more than that, consider **splitting the concerns** to separate jobs (in the same workflow).

**Follow-up**

For a working example, do feel free to refer to a public project I have here:

- GitHub repo: [GitHub - kelvintaywl-cci/whale-this-work: Exploring Docker building (and pushing) images with CircleCI](https://github.com/kelvintaywl-cci/whale-this-work)
- CircleCI pipelines: [https://app.circleci.com/pipelines/github/kelvintaywl-cci/whale-this-work](https://app.circleci.com/pipelines/github/kelvintaywl-cci/whale-this-work) (See the `kaniko` workflow)

In addition, GitLab also has a great document on using Kaniko on GitLab CI:

> **[Use kaniko to build Docker images | GitLab](https://docs.gitlab.com/ee/ci/docker/using_kaniko.html)**
>
> GitLab product documentation.

I hope this is useful and helpful for anyone trying to use Kaniko on CircleCI 🤓
