쿠버네티스 위에서 도는 애플리케이션이 컨테이너 이미지를 빌드해야 할 때, 도커 데몬 소켓을 마운트하지 않고 처리하는 방법을 정리한다. 호스트의 /var/run/docker.sock 을 파드에 넣는 것은 그 노드 전체에 대한 권한을 주는 것과 같으므로 쓰지 않는다.
가장 먼저 피해야 할 구성이 "내 앱 + kaniko 실행 파일" 을 한 컨테이너에 담는 것이다. kaniko 는 자기가 실행되는 컨테이너의 파일시스템을 사용자 공간에서 직접 스냅샷하며 레이어를 만든다. 임의의 애플리케이션 이미지 위에 얹으면 앱이 깔아 둔 파일까지 레이어에 섞여 빌드 결과가 오염된다. 공식적으로도 지원되지 않는 사용법이다.
애플리케이션은 오케스트레이션만 하고 빌드는 별도 파드가 한다. 빌드 한 건이 Job 한 개이고, 끝나면 파드가 사라진다. 애플리케이션 이미지와 빌더 이미지가 수명주기까지 분리된다.
apiVersion: batch/v1
kind: Job
metadata:
name: image-build-<id>
namespace: builds
spec:
backoffLimit: 1
template:
spec:
restartPolicy: Never
containers:
- name: builder
image: <registry>/kaniko/executor:<tag>
args:
- --context=git://git.example.local/team/app.git#refs/heads/main
- --dockerfile=Dockerfile
- --destination=<registry>/team/app:<tag>
volumeMounts:
- name: docker-config
mountPath: /kaniko/.docker
volumes:
- name: docker-config
secret:
secretName: registry-credentials
items:
- key: .dockerconfigjson
path: config.json
애플리케이션은 쿠버네티스 클라이언트 라이브러리로 이 Job 을 만들고 상태를 지켜본다. 레지스트리 자격증명은 컨테이너 레지스트리 인증 정보 config.json 형식의 Secret 으로 넘긴다.
빌드 컨텍스트를 애플리케이션이 만들어 넘겨야 하는 구조라면, 같은 파드에 컨테이너를 분리해서 빌더를 넣고 emptyDir 로 Dockerfile 과 컨텍스트를 공유한다. 한 파드 안이어도 컨테이너가 분리돼 있으면 위의 금지 사항에 걸리지 않는다.
kaniko 는 원 저장소가 아카이브되면서 기존 배포 경로의 이미지가 더 이상 유지보수되지 않는다. 보안 패치가 나오지 않으므로 새로 구성하는 시스템에서 옛 이미지를 그대로 쓰지 않는다. 유지되는 포크가 몇 개 있으나 배포 형태가 제각각이라, 소스 태그만 공개하고 컨테이너 이미지는 배포하지 않는 쪽도 있다.
각 포크의 최신 버전과 이미지 배포 여부는 확인하지 못했다 (확인 필요). 채택 전에 해당 저장소의 릴리스 페이지에서 이미지 배포 여부와 마지막 갱신 시점을 직접 확인한다.
대안으로 Buildah 를 Job 안에서 돌려 소스 클론 → 빌드 → 푸시를 처리하는 구성도 널리 쓰인다. 데몬이 필요 없고 권한 없이 동작하는 성질은 같다. Buildah 설치와 사용법은 Podman 문서에 있다.