
Migrate GitLab CI from Kaniko to BuildKit with AWS ECR
Aron Schüler Published
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
Feature | Kaniko | BuildKit |
---|---|---|
Build Speed | Baseline | Can be 40-60% faster |
Caching | Limited | Advanced (registry, inline, local) |
Security | Requires privileges | Rootless mode available |
Development Status | Archived (fork maintained) | Active |
Multi-platform builds | No | Yes |
Secret management | Basic | Advanced (SSH, secrets) |
Docker-in-Docker needed | No | No |
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 permissionsAWS_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:
- BuildKit multi-platform builds for ARM and AMD64 support
- BuildKit secrets management for handling sensitive build arguments
- Custom BuildKit frontends for specialized build workflows
- Local caching strategies for even faster development builds
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!