Image of Migrate GitLab CI from Kaniko to BuildKit with AWS ECR

Migrate GitLab CI from Kaniko to BuildKit with AWS ECR

Aron Schüler Published


Table of Contents

Intro

If you’re still using Kaniko for building container images in your GitLab CI pipelines, it’s time to make a change. Kaniko was officially archived by Google on June 3, 2025 (though Chainguard has forked and continues maintaining it), and BuildKit has emerged as the modern, efficient alternative for building container images in CI/CD environments. BuildKit offers superior caching capabilities, better performance, and enhanced security features compared to its predecessor. While Gitlab Docs offer examples, I had to spend some time getting our pipelines authenticated for AWS and allowing ECR pushes to work flawlessly.

In this post, I’ll walk you through migrating your GitLab pipelines from Kaniko to BuildKit, specifically focusing on building images, authenticating against AWS, and then pushing them to AWS Elastic Container Registry (ECR). The migration makes sure your pipelines stay up to date with industry standards. It should also bring improvements in build speed and reliability!

Prerequisites

Before you begin this GitLab CI BuildKit tutorial, make sure you have:

  • GitLab CI/CD enabled on your project
  • AWS account with ECR access and appropriate permissions
  • Basic Docker knowledge and familiarity with Dockerfiles
  • GitLab CI variables access to configure secrets
  • An existing GitLab runner (shared or dedicated)

Why Migrate from Kaniko to BuildKit?

BuildKit has become the modern standard for building Docker images in CI/CD environments, and for good reasons. Here’s why you should consider this Kaniko alternative:

Performance and Caching

BuildKit offers significantly faster build times through advanced caching mechanisms. Unlike Kaniko, BuildKit supports:

  • Layer caching with registry backends
  • Inline cache for distributed builds
  • Concurrent build stages for multi-stage Dockerfiles

In our tests, BuildKit can reduce build times by 40-60% compared to Kaniko, especially for projects with good cache utilization. Performance improvements vary based on your Dockerfile structure and caching strategy.

Security Improvements

BuildKit rootless mode is a major security advantage:

  • No privileged access required - runs without root permissions
  • Reduced attack surface in CI/CD environments
  • Better isolation between builds

Active Development

While Kaniko was officially archived by Google on June 3, 2025 (though a Chainguard-maintained fork continues development), BuildKit is actively maintained by the Docker/Moby project with regular updates and new features.

Kaniko vs BuildKit Comparison

FeatureKanikoBuildKit
Build SpeedBaselineCan be 40-60% faster
CachingLimitedAdvanced (registry, inline, local)
SecurityRequires privilegesRootless mode available
Development StatusArchived (fork maintained)Active
Multi-platform buildsNoYes
Secret managementBasicAdvanced (SSH, secrets)
Docker-in-Docker neededNoNo

Step-by-Step Guide

This GitLab ECR integration guide will walk you through the complete migration process for building Docker images in GitLab CI.

1. BuildKit Setup for GitLab CI

BuildKit runs in rootless mode for enhanced security, which means it doesn’t require privileged access to build container images. The key components of our setup include:

  • BuildKit rootless image: moby/buildkit:rootless
  • ECR credential helper: For seamless authentication with AWS ECR
  • BuildKit daemon: Running in daemonless mode for GitLab CI compatibility

2. Base Job Configuration for BuildKit in GitLab

First, let’s create a reusable job template that contains all the common configuration. You can reuse this later for different kind of build, e.g. production vs QA builds, or maybe E2E builds.

This base configuration sets up BuildKit rootless mode for secure Docker image building:

.build backend:
  stage: build
  tags:
    - medium-runner
  variables:
    GIT_STRATEGY: fetch
    AWS_DEFAULT_REGION: eu-central-1
    ECR_REPOSITORY: $ECR_REPOSITORY
    ECR_REGISTRY: $ECR_REGISTRY
    AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
    AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
    BUILDKITD_FLAGS: --oci-worker-no-process-sandbox
  image:
    name: moby/buildkit:rootless
    entrypoint: [""]

The BUILDKITD_FLAGS: --oci-worker-no-process-sandbox flag is necessary for running BuildKit in GitLab’s shared runners without requiring additional privileges and something I had missing in my first jobs.

3. AWS ECR Authentication Setup for BuildKit

The before_script section handles the ECR authentication setup.

This configuration downloads and configures the ECR credential helper for automatic AWS authentication:

before_script:
  ## Install ecr login helper
  - mkdir credentials-binaries
  - wget -O credentials-binaries/docker-credential-ecr-login https://amazon-ecr-credential-helper-releases.s3.us-east-2.amazonaws.com/0.10.0/linux-amd64/docker-credential-ecr-login
  - chmod +x credentials-binaries/docker-credential-ecr-login
  - chown 1000:1000 credentials-binaries/docker-credential-*
  - export PATH="${CI_PROJECT_DIR}/credentials-binaries:$PATH"
 
  ## Create docker config for ECR authentication
  - mkdir -p ~/.docker
  - |
    cat << EOF > ~/.docker/config.json
    {
        "credHelpers": {
            "$ECR_REGISTRY": "ecr-login"
        }
    }
    EOF

This setup downloads the ECR credential helper and configures Docker to use it for authentication, using your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY for that. The credential helper also handles token refresh, so you don’t need manual docker login commands.

4. Building and Pushing Images with BuildKit

The main build logic uses buildctl-daemonless.sh, which is perfect for CI environments that don’t have the docker service available.

This command builds your Docker image and pushes it to ECR with layer caching enabled:

script:
  ## Build and push image using BuildKit
  - |
    buildctl-daemonless.sh build \
      --frontend dockerfile.v0 \
      --local context=$CI_PROJECT_DIR/backend \
      --local dockerfile=$CI_PROJECT_DIR/backend \
      --export-cache type=registry,ref=$ECR_REPOSITORY:buildcache \
      --import-cache type=registry,ref=$ECR_REPOSITORY:buildcache \
      --output type=image,name=$ECR_REPOSITORY:$IMAGE_TAG,push=true

The build uses registry-based caching for subsequent builds and builds+pushes to ECR in a single operation, based on the backend/ folder in this example and the backend/Dockerfile. Of course, this might need adaption in your usecase.

5. Creating Environment-Specific Jobs

Extend the base job for different environments:

build backend test:
  extends:
    - .build backend
  environment:
    name: test
  variables:
    IMAGE_TAG: backend-latest
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: on_success
    - when: never

This pattern allows you to create jobs for different environments (staging, production) or usecases by extending the base job and overriding necessary variables.

6. Required GitLab CI Variables

Ensure these variables are configured in your GitLab project settings:

  • ECR_REGISTRY: ECR registry domain (e.g., 123456789.dkr.ecr.eu-central-1.amazonaws.com)
  • ECR_REPOSITORY: Full ECR repository URI (e.g., 123456789.dkr.ecr.eu-central-1.amazonaws.com/my-app) (could reuse $ECR_REGISTRY lol)
  • AWS_ACCESS_KEY_ID: AWS credentials with ECR push permissions
  • AWS_SECRET_ACCESS_KEY: Corresponding AWS secret key

Troubleshooting Common Issues

BuildKit Authentication Failed

Error: failed to authorize: failed to fetch anonymous token

Solution: Verify your ECR credential helper is correctly installed and your AWS credentials have the necessary ECR permissions:

aws ecr get-login-password --region eu-central-1

Process Sandbox Error

Error: failed to create shim: OCI runtime create failed

Solution: Ensure you have BUILDKITD_FLAGS: --oci-worker-no-process-sandbox in your variables section.

Cache Not Working

Issue: Builds are always starting from scratch

Solution: Check that your ECR repository has the buildcache tag and your AWS credentials have pull permissions. BuildKit needs both push and pull access for caching to work.

Permission Denied Errors

Error: permission denied while trying to connect to the Docker daemon

Solution: Make sure you’re using the moby/buildkit:rootless image and not trying to run Docker-in-Docker. BuildKit rootless mode doesn’t require Docker daemon access.

Frequently Asked Questions

Why is Kaniko archived?

Google officially archived Kaniko on June 3, 2025, making it read-only. However, Chainguard immediately forked the project and continues to maintain it. Despite this, much of the community has moved to BuildKit, which is actively maintained by the Docker/Moby project and offers superior performance and features.

Is BuildKit faster than Kaniko?

Yes, BuildKit can be 40-60% faster than Kaniko due to advanced caching mechanisms and concurrent build stage execution. The exact improvement varies significantly based on your Dockerfile structure, caching strategy, and specific use case.

Do I need Docker-in-Docker for BuildKit?

No! That’s one of the major advantages. BuildKit rootless mode works without Docker daemon access, making it perfect for shared CI/CD runners where Docker-in-Docker might not be available or desirable for security reasons.

How much does BuildKit improve build times?

In our experience, BuildKit can reduce build times by 40-60% compared to Kaniko when caching is properly configured. Projects with multi-stage builds and good layer caching see the most dramatic improvements. Results vary based on your specific configuration and Dockerfile complexity.

Can I use BuildKit with other registries besides ECR?

Absolutely! While this tutorial focuses on AWS ECR, BuildKit works with any OCI-compliant registry including Docker Hub, Google Container Registry (GCR), Azure Container Registry (ACR), GitHub Container Registry, and private registries.

Conclusion

The setup shown here provides a solid foundation for Docker image building in GitLab CI that you can customize for your specific needs. Migrating from Kaniko to BuildKit is straightforward with this GitLab CI BuildKit tutorial, and the benefits are immediate.

Key Takeaways

BuildKit brings your CI/CD pipeline up to date with current best practices and delivers:

  • Improved build speeds through better caching (40-60% faster in most cases)
  • Enhanced security with BuildKit rootless mode
  • More reliable image building with active maintenance and updates
  • Advanced features like multi-platform builds and secret management

The ECR integration step is something that I needed to piece together from different sources, but I’m very happy with the setup and the speed improvements we’ve seen in production.

Next Steps

As you implement this in your own projects, consider exploring:

Share Your Experience

Have you migrated from Kaniko to BuildKit? I’d love to hear about your experience! Drop a comment below with:

  • How much did your build times improve?
  • What challenges did you face during migration?
  • Any tips or optimizations you discovered?

Feel free to ask questions about this migration approach - I’m happy to help troubleshoot any issues you encounter!


Related Posts

Find posts on similar topics:


Support me via buymeacoffee

If I helped you solve a problem or you just like my content, consider supporting me by buying me a coffee.

Buy me a coffee

Comments