Kaniko가 2025년 6월 공식 archived 되면서 BuildKit으로의 전환이 필요한 시점이다. BuildKit은 병렬 빌드, 향상된 캐싱, Multi-arch 지원 등 Kaniko 대비 우수한 성능과 기능을 제공한다.

Google Container Tools의 Kaniko 프로젝트가 2025년 6월 3일 공식 archived 되었다.
기존 Kaniko 파이프라인은 당장 문제없이 동작하지만, 장기적으로 BuildKit 전환을 권장한다.
| 항목 | Kaniko | BuildKit |
|---|---|---|
| 유지보수 상태 | Archived (2025.06) | Active (Docker 공식) |
| 빌드 방식 | Sequential (순차) | DAG 기반 병렬 처리 |
| 캐싱 | 기본적, 일관성 이슈 | Content-addressable, Registry 캐시 |
| Multi-arch | 미지원 | 네이티브 지원 |
| Rootless 지원 | 기본 rootless | rootless 옵션 |
| Privileged 필요 | 불필요 | rootless: 불필요 / privileged: 필요 |
| 빌드 속도 | 기준 | 약 2~3배 빠름 |
| 메모리 사용 | 대용량 이미지에서 높음 | 효율적 |
| Secrets 마운트 | 미지원 | RUN --mount=type=secret |
| SSH 마운트 | 미지원 | RUN --mount=type=ssh |
Kaniko 장점 (과거형)
Kaniko 단점
BuildKit 장점
BuildKit 단점
BuildKit은 여러 배포 패턴을 지원한다.
# buildkit-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: buildkit
---
# buildkit-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: buildkitd
namespace: buildkit
labels:
app: buildkitd
spec:
serviceName: buildkitd
podManagementPolicy: Parallel
replicas: 2
selector:
matchLabels:
app: buildkitd
template:
metadata:
labels:
app: buildkitd
spec:
containers:
- name: buildkitd
image: moby/buildkit:v0.18.1-rootless
args:
- --addr
- unix:///run/buildkit/buildkitd.sock
- --addr
- tcp://0.0.0.0:1234
- --oci-worker-no-process-sandbox
ports:
- containerPort: 1234
protocol: TCP
securityContext:
runAsUser: 1000
runAsGroup: 1000
readinessProbe:
exec:
command:
- buildctl
- debug
- workers
initialDelaySeconds: 5
periodSeconds: 30
livenessProbe:
exec:
command:
- buildctl
- debug
- workers
initialDelaySeconds: 5
periodSeconds: 30
volumeMounts:
- name: buildkitd-data
mountPath: /home/user/.local/share/buildkit
volumeClaimTemplates:
- metadata:
name: buildkitd-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 50Gi
---
# buildkit-service.yaml
apiVersion: v1
kind: Service
metadata:
name: buildkitd
namespace: buildkit
spec:
selector:
app: buildkitd
ports:
- port: 1234
targetPort: 1234
protocol: TCP
# jenkins-buildkit-rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: buildkit-user
namespace: buildkit
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jenkins-buildkit-binding
namespace: buildkit
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: buildkit-user
subjects:
- kind: ServiceAccount
name: jenkins
namespace: jenkins
# jenkins-agent-pod.yaml (podTemplate에서 사용)
apiVersion: v1
kind: Pod
metadata:
labels:
jenkins-agent: buildkit
spec:
serviceAccountName: jenkins
containers:
- name: docker
image: docker:27-cli
command: ["sleep"]
args: ["infinity"]
env:
- name: DOCKER_HOST
value: ""
volumeMounts:
- name: docker-config
mountPath: /root/.docker
readOnly: true
volumes:
- name: docker-config
secret:
secretName: docker-registry-credentials
pipeline {
agent {
kubernetes {
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: docker
image: docker:27-cli
command: ["sleep"]
args: ["infinity"]
volumeMounts:
- name: docker-config
mountPath: /root/.docker
readOnly: true
volumes:
- name: docker-config
secret:
secretName: docker-registry-credentials
'''
}
}
environment {
REGISTRY = 'your-registry.com'
IMAGE_NAME = 'your-app'
BUILDKIT_HOST = 'tcp://buildkitd.buildkit.svc.cluster.local:1234'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Setup BuildKit') {
steps {
container('docker') {
sh '''
# BuildKit remote driver 생성
docker buildx create \
--name kube-builder \
--driver remote \
${BUILDKIT_HOST} \
--use
# Builder 상태 확인
docker buildx inspect --bootstrap
'''
}
}
}
stage('Build & Push') {
steps {
container('docker') {
sh '''
docker buildx build \
--push \
--platform linux/amd64,linux/arm64 \
--cache-from type=registry,ref=${REGISTRY}/${IMAGE_NAME}:cache \
--cache-to type=registry,ref=${REGISTRY}/${IMAGE_NAME}:cache,mode=max \
-t ${REGISTRY}/${IMAGE_NAME}:${BUILD_NUMBER} \
-t ${REGISTRY}/${IMAGE_NAME}:latest \
.
'''
}
}
}
stage('Update Helm Values') {
steps {
script {
// Bitbucket Helm Chart repo 업데이트
withCredentials([usernamePassword(
credentialsId: 'bitbucket-credentials',
usernameVariable: 'GIT_USER',
passwordVariable: 'GIT_PASS'
)]) {
sh '''
git clone https://${GIT_USER}:${GIT_PASS}@bitbucket.org/your-org/helm-charts.git
cd helm-charts/your-app
# values.yaml 이미지 태그 업데이트
sed -i "s/tag:.*/tag: ${BUILD_NUMBER}/" values.yaml
git config user.email "jenkins@your-domain.com"
git config user.name "Jenkins CI"
git add values.yaml
git commit -m "Update image tag to ${BUILD_NUMBER}"
git push origin main
'''
}
}
}
}
}
post {
always {
container('docker') {
sh 'docker buildx rm kube-builder || true'
}
}
}
}
stage('Build with Kaniko') {
steps {
container('kaniko') {
sh '''
/kaniko/executor \
--dockerfile=Dockerfile \
--context=${WORKSPACE} \
--destination=${REGISTRY}/${IMAGE}:${TAG}
'''
}
}
}
stage('Build with BuildKit') {
steps {
container('docker') {
sh '''
docker buildx create --name builder --driver remote tcp://buildkitd.buildkit:1234 --use
docker buildx build --push \
-t ${REGISTRY}/${IMAGE}:${TAG} \
.
docker buildx rm builder
'''
}
}
}
docker buildx build \
--cache-from type=registry,ref=registry.example.com/myapp:cache \
--cache-to type=registry,ref=registry.example.com/myapp:cache,mode=max \
-t registry.example.com/myapp:v1 \
--push .
docker buildx build \
--cache-from type=local,src=/cache \
--cache-to type=local,dest=/cache,mode=max \
-t registry.example.com/myapp:v1 \
--push .
./create-certs.sh buildkitd.buildkit.svc.cluster.local
kubectl create secret generic buildkit-daemon-certs \
--from-file=ca.pem \
--from-file=cert.pem \
--from-file=key.pem \
-n buildkit
args:
- --addr
- tcp://0.0.0.0:1234
- --tlscacert=/certs/ca.pem
- --tlscert=/certs/cert.pem
- --tlskey=/certs/key.pem
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: buildkit-ingress
namespace: buildkit
spec:
podSelector:
matchLabels:
app: buildkitd
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: jenkins
ports:
- protocol: TCP
port: 1234
1. BuildKit 연결 실패
error: failed to dial gRPC: rpc error: connection refused
→ BuildKit Service 및 Pod 상태 확인, 포트 1234 연결 가능 여부 점검
2. Registry Push 실패
unauthorized: authentication required
→ Docker config secret 마운트 확인, imagePullSecrets 설정 점검
3. Rootless 모드 실패
failed to create container: permission denied
→ --oci-worker-no-process-sandbox 옵션 추가, securityContext 확인
4. 캐시 히트 안됨
→ StatefulSet 사용 시 consistent hash 적용 고려, Registry cache 설정 확인