Detailed comparison between Kimia and Kaniko for Kubernetes-native container image building.
Kimia - Non-root by design:
securityContext:
runAsUser: 1000
runAsNonRoot: trueKaniko - Runs as root:
securityContext:
runAsUser: 0 # Root userImpact: Even if the container is compromised, an attacker only has unprivileged user access with Kimia, whereas Kaniko running as root poses higher risk.
Kimia:
Container UID 0 → Host UID 1000 (unprivileged)
Container UID 1 → Host UID 100000
Container UID 2 → Host UID 100001
Kaniko:
Container UID 0 → Host UID 0 (if container escape occurs)
Impact: Kimia provides an additional security boundary through user namespaces. If a container escape occurs, the attacker is still mapped to an unprivileged user on the host.
Kimia - Minimal explicit capabilities:
capabilities:
drop: [ALL]
add: [SETUID, SETGID] # Only for user namespacesKaniko - No capabilities explicitly needed:
capabilities:
drop: [ALL]
# No capabilities added - runs as root insteadImpact: Kimia's approach is more transparent about security requirements. The SETUID and SETGID capabilities are specifically for user namespace creation, which is much safer than running as root.
Kimia handles complex ownership changes better:
# This works reliably in Kimia
FROM ubuntu:22.04
RUN useradd -m -u 1001 appuser
COPY --chown=appuser:appuser . /app
RUN chown -R appuser:appuser /app
USER appuserKaniko may have issues with certain chown operations in unprivileged scenarios.
Kimia supports Docker-specific Dockerfile instructions via BUILDAH_FORMAT:
# These work with BUILDAH_FORMAT=docker
HEALTHCHECK --interval=30s CMD curl -f http://localhost/ || exit 1
SHELL ["/bin/bash", "-c"]
STOPSIGNAL SIGTERMMost Kaniko arguments work directly with Kimia:
| Kaniko Argument | Kimia Equivalent | Compatibility |
|---|---|---|
--context |
--context |
✅ 100% |
--dockerfile |
--dockerfile |
✅ 100% |
--destination |
--destination |
✅ 100% (repeatable) |
--build-arg |
--build-arg |
✅ 100% |
--target |
--target |
✅ 100% |
--cache |
--cache |
✅ 100% |
--cache-dir |
--cache-dir |
✅ 100% |
--insecure |
--insecure |
✅ 100% |
--skip-tls-verify |
--skip-tls-verify |
✅ 100% |
--verbosity |
--verbosity |
✅ 100% |
--label |
--label |
✅ 100% |
--git |
--context=git://... |
✅ Compatible |
--snapshot-mode |
N/A | ℹ️ VFS handles this |
--use-new-run |
N/A | ℹ️ Buildah default |
--reproducible |
--reproducible |
✅ Native support |
-
Security is Paramount
- Defense-in-depth security required
- Compliance mandates rootless containers
- Need Pod Security Standard "Restricted" compliance
- Regulatory requirements (PCI-DSS, HIPAA, SOC 2)
-
Complex Build Requirements
- Dockerfiles with complex ownership operations
- Need for
chownoperations - Docker-specific instructions (HEALTHCHECK, SHELL)
-
Reproducible Builds
- Supply chain security requirements
- Need byte-for-byte identical builds
- Compliance verification needed
-
Modern Kubernetes Environments
- User namespaces already enabled
- Pod Security Standards enforced
- Security-first organization
-
Infrastructure Limitations
- User namespaces cannot be enabled on nodes
- Legacy Kubernetes versions (<1.21)
- Restricted node configuration access
-
Minimal Change Required
- Existing Kaniko pipelines work well
- No time for migration
- Team familiarity with Kaniko
-
Quick Start Priority
- Need immediate deployment
- No time for user namespace setup
- Testing/development environments only
# Check user namespace support
kubectl run test --rm -it --image=busybox --restart=Never -- \
cat /proc/sys/user/max_user_namespaces
# Should return > 0 (typically 15000)Run both builders in parallel to compare:
Kaniko Job:
apiVersion: batch/v1
kind: Job
metadata:
name: kaniko-test
spec:
template:
spec:
containers:
- name: kaniko
image: gcr.io/kaniko-project/executor:latest
args:
- --context=git://github.com/org/repo.git
- --destination=myregistry.io/myapp:kaniko
volumeMounts:
- name: docker-config
mountPath: /kaniko/.docker/
volumes:
- name: docker-config
secret:
secretName: registry-credentialsKimia Job:
apiVersion: batch/v1
kind: Job
metadata:
name: kimia-test
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: kimia
image: ghcr.io/rapidfort/kimia:latest
args:
- --context=git://github.com/org/repo.git
- --destination=myregistry.io/myapp:kimia
securityContext:
allowPrivilegeEscalation: true
capabilities:
drop: [ALL]
add: [SETUID, SETGID]
volumeMounts:
- name: docker-config
mountPath: /home/kimia/.docker/
volumes:
- name: docker-config
secret:
secretName: registry-credentialsKey changes needed in your manifests:
# Before (Kaniko)
spec:
containers:
- name: kaniko
image: gcr.io/kaniko-project/executor:latest
# After (Kimia)
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000 # Important for cache permissions
containers:
- name: kimia
image: ghcr.io/rapidfort/kimia:latest
securityContext:
allowPrivilegeEscalation: true
capabilities:
drop: [ALL]
add: [SETUID, SETGID]# Before (Kaniko)
volumeMounts:
- name: docker-config
mountPath: /kaniko/.docker/
# After (Kimia)
volumeMounts:
- name: docker-config
mountPath: /home/kimia/.docker/If your Dockerfile uses Docker-specific instructions:
env:
- name: BUILDAH_FORMAT
value: "docker"# Deploy Kimia build
kubectl apply -f kimia-build.yaml
# Monitor logs
kubectl logs -f job/kimia-build
# Verify image
docker pull myregistry.io/myapp:kimia
docker inspect myregistry.io/myapp:kimia# Kaniko build time
kubectl logs job/kaniko-test | grep "Built"
# Kimia build time
kubectl logs job/kimia-test | grep "Built"
# Compare image sizes
docker images myregistry.io/myapp --format "table {{.Tag}}\t{{.Size}}"graph LR
A[Development] --> B[Staging]
B --> C[Production Canary]
C --> D[Production Full]
- Development: Test Kimia with dev builds
- Staging: Run Kimia for staging deployments
- Production Canary: 10% of production builds
- Production Full: Complete migration
- Verify user namespaces enabled on nodes
- Test sample build with Kimia
- Update security contexts in manifests
- Change volume mount paths
- Add Docker format if needed (HEALTHCHECK, SHELL)
- Test cache directory permissions
- Verify registry authentication works
- Compare build times and sizes
- Update CI/CD pipelines
- Train team on new configuration
- Update documentation
- Monitor for issues
Based on typical builds:
| Metric | Kimia | Kaniko | Notes |
|---|---|---|---|
| Build Time | ~Equal | ~Equal | Both use native builds |
| Memory Usage | 2-8 GB | 2-8 GB | Similar resource usage |
| Image Size | Same | Same | Identical output |
| Cache Efficiency | ✅ Excellent | ✅ Excellent | Both support layer caching |
| Startup Time | ~Equal | ~Equal | Similar initialization |
Verdict: Performance is comparable; choose based on security requirements.
- ✅ Free and open-source (MIT License)
- ✅ No licensing costs
- ✅ Community support
- ✅ Cloud-agnostic
- ✅ Free and open-source (Apache 2.0)
- ✅ No licensing costs
- ✅ Community support
- ✅ Cloud-agnostic
Verdict: Both are free and open-source; no cost difference.
- ✅ ArgoCD Workflows
- ✅ Flux
- ✅ Tekton
- ✅ Jenkins
- ✅ GitHub Actions
- ✅ GitLab CI
- ✅ Buildah ecosystem
- ✅ ArgoCD Workflows
- ✅ Flux
- ✅ Tekton
- ✅ Jenkins
- ✅ GitHub Actions
- ✅ GitLab CI
- ✅ Google Cloud Build
Verdict: Both integrate well with major CI/CD platforms.
- 🔒 Enhanced Security - Rootless, user namespaces
- 📋 Compliance - Pod Security Standards (Restricted)
- 🔧 Complex Builds - Better chown support
- ♻️ Reproducibility - Native reproducible builds
- 🛡️ Defense-in-Depth - Multiple security layers
- ⚡ Quick Start - Simpler initial setup
- 🔒 Node Restrictions - Can't enable user namespaces
- 📦 Existing Pipeline - Already using Kaniko successfully
- 👥 Team Familiarity - Team knows Kaniko well
Many organizations use both:
- Kimia for production builds (security-critical)
- Kaniko for development/testing (faster setup)
- 📖 Installation Guide - Setup instructions
- 🎯 Examples - Migration examples
- 🔧 Troubleshooting - Common issues
- ❓ FAQ - Frequently asked questions