Kubernetes 드라이버

Kubernetes 드라이버 (Kubernetes driver)

Kubernetes 드라이버는 로컬 개발 환경이나 CI 환경을 Kubernetes 클러스터의 빌더에 연결해, 더 강력한 컴퓨팅 리소스에 접근할 수 있게 해 주는 드라이버예요. 여러 네이티브 아키텍처를 선택적으로 사용할 수도 있어요.

출처: 문서

본문

Kubernetes 드라이버는 로컬 개발 또는 CI 환경을 Kubernetes 클러스터 안의 빌더에 연결해 더 강력한 컴퓨팅 리소스에 접근할 수 있게 해 줘요. 선택적으로 여러 네이티브 아키텍처를 사용할 수도 있어요.

동작 방식 (Synopsis)

kube라는 이름의, Kubernetes 드라이버를 쓰는 새 빌더를 만들려면 다음 명령을 실행해요:

$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=[key=value,...]

다음 표는 --driver-opt에 넘길 수 있는 드라이버별 옵션을 설명해요:

| Parameter | Type | Default | Description | | image | String | | BuildKit 실행에 사용할 이미지를 설정해요. | | namespace | String | 현재 Kubernetes 컨텍스트의 namespace | Kubernetes namespace를 설정해요. | | default-load | Boolean | false | 이미지를 Docker Engine 이미지 저장소에 자동으로 로드해요. | | replicas | Integer | 1 | 생성할 파드 레플리카 수를 설정해요. BuildKit 스케일링 참고. | | requests.cpu | CPU units | | 요청 CPU 값을 Kubernetes CPU 단위로 지정해요. 예: requests.cpu=100m 또는 requests.cpu=2 | | requests.memory | Memory size | | 요청 메모리 값을 바이트 또는 유효한 접미사로 지정해요. 예: requests.memory=500Mi 또는 requests.memory=4G | | requests.ephemeral-storage | Storage size | | 요청 임시 스토리지(ephemeral-storage) 값을 바이트 또는 유효한 접미사로 지정해요. 예: requests.ephemeral-storage=2Gi | | persistent-volume-claim.requests.storage | Storage size | | 영구 볼륨 클레임(persistent volume claim)의 요청 크기를 설정해요. 설정하면 Buildx가 StatefulSet을 만들고 BuildKit 빌드 캐시를 클레임에 저장해요. 예: persistent-volume-claim.requests.storage=20Gi | | limits.cpu | CPU units | | 제한 CPU 값을 Kubernetes CPU 단위로 지정해요. 예: requests.cpu=100m 또는 requests.cpu=2 | | limits.memory | Memory size | | 제한 메모리 값을 바이트 또는 유효한 접미사로 지정해요. 예: requests.memory=500Mi 또는 requests.memory=4G | | limits.ephemeral-storage | Storage size | | 제한 임시 스토리지 값을 바이트 또는 유효한 접미사로 지정해요. 예: requests.ephemeral-storage=100M | | buildkit-root-volume-memory | Memory size | 일반 파일 시스템 사용 | /var/lib/buildkit을 메모리 기반 emptyDir 볼륨에 마운트하고, SizeLimit을 값으로 사용해요. 예: buildkit-root-folder-memory=6G | | nodeselector | CSV string | | 파드의 nodeSelector 라벨을 설정해요. 노드 할당 참고. | | annotations | CSV string | | Deployment 또는 StatefulSet과 파드에 추가 annotation을 설정해요. | | labels | CSV string | | Deployment 또는 StatefulSet과 파드에 추가 라벨을 설정해요. | | tolerations | CSV string | | 파드의 taint 허용(toleration)을 구성해요. 노드 할당 참고. | | serviceaccount | String | | 파드의 serviceAccountName을 설정해요. | | schedulername | String | | 파드 스케줄링을 담당하는 스케줄러를 설정해요. | | timeout | Time | 120s | 빌드 전에 파드가 프로비저닝될 때까지 Buildx가 기다릴 시간 제한을 설정해요. | | rootless | Boolean | false | 컨테이너를 비-root 사용자로 실행해요. 루트리스 모드 참고. | | loadbalance | String | sticky | 로드 밸런싱 전략(sticky 또는 random)이에요. sticky로 설정하면 컨텍스트 경로의 해시로 파드를 선택해요. | | qemu.install | Boolean | false | 멀티 플랫폼 지원을 위한 QEMU 에뮬레이션을 설치해요. QEMU 참고. | | qemu.image | String | tonistiigi/binfmt:latest | QEMU 에뮬레이션 이미지를 설정해요. QEMU 참고. |

BuildKit 스케일링 (Scaling BuildKit)

Kubernetes 드라이버의 주요 장점 중 하나는 빌더 레플리카 수를 늘렸다 줄였다 해서 늘어난 빌드 부하를 처리할 수 있다는 거예요. 스케일링은 다음 드라이버 옵션으로 구성할 수 있어요:

  • replicas=N — BuildKit 파드 수를 원하는 크기로 조정해요. 기본적으로 파드를 하나만 만들 뿐이지만, 레플리카 수를 늘리면 클러스터의 여러 노드를 활용할 수 있어요.
  • requests.cpu, requests.memory, requests.ephemeral-storage, limits.cpu, limits.memory, limits.ephemeral-storage — 공식 Kubernetes 문서에 따라 각 BuildKit 파드가 사용할 수 있는 리소스를 요청·제한할 수 있게 해 줘요.

예를 들어 BuildKit 파드 4개를 만들려면:

$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=namespace=buildkit,replicas=4

파드를 나열하면 이렇게 보여요:

$ kubectl -n buildkit get deployments
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
kube0   4/4     4            4           8s

$ kubectl -n buildkit get pods
NAME                     READY   STATUS    RESTARTS   AGE
kube0-6977cdcb75-48ld2   1/1     Running   0          8s
kube0-6977cdcb75-rkc6b   1/1     Running   0          8s
kube0-6977cdcb75-vb4ks   1/1     Running   0          8s
kube0-6977cdcb75-z4fzs   1/1     Running   0          8s

또한 레플리카가 여러 개일 때 로드 밸런싱 동작을 제어하려면 loadbalance=(sticky|random) 옵션을 사용할 수 있어요. random은 노드 풀에서 무작위 노드를 선택해 레플리카 간에 워크로드를 고르게 분산해요. sticky(기본값)는 동일한 빌드를 여러 번 수행해도 매번 같은 노드에 연결하도록 시도해 로컬 캐시를 더 잘 활용해요.

스케일링에 대한 자세한 내용은 docker buildx create의 옵션을 참고하세요.

영구 스토리지 (Persistent storage)

persistent-volume-claim.requests.storage 드라이버 옵션을 설정하면 BuildKit 빌드 캐시를 파드 파일시스템이 아니라 영구 볼륨 클레임에 저장해요. 이 옵션을 설정하면 Buildx는 Deployment 대신 StatefulSet을 만들어요.

replicas도 설정하면 각 레플리카가 각자 자신의 영구 볼륨 클레임을 가져요. 이렇게 하면 재시작 후에도 빌드 캐시가 각 파드에 로컬하게 유지돼요.

예를 들어 레플리카당 20GiB 영구 스토리지를 가진 빌더를 만들려면:

$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=namespace=buildkit,replicas=4,persistent-volume-claim.requests.storage=20Gi

노드 할당 (Node assignment)

Kubernetes 드라이버는 nodeSelectortolerations 드라이버 옵션으로 BuildKit 파드의 스케줄링을 제어할 수 있게 해 줘요. 아예 커스텀 스케줄러를 쓰고 싶다면 schedulername 옵션도 설정할 수 있어요.

annotationslabels 드라이버 옵션으로 빌더를 호스팅하는 Deployment 또는 StatefulSet과 파드에 추가 메타데이터를 적용할 수 있어요.

nodeSelector 파라미터의 값은 키-값 쌍의 쉼표로 구분된 문자열이에요. 여기서 키는 노드 라벨이고 값은 라벨 텍스트예요. 예: "nodeselector=kubernetes.io/arch=arm64"

tolerations 파라미터는 taint의 세미콜론으로 구분된 목록이에요. Kubernetes 매니페스트와 같은 값을 받아들여요. 각 tolerations 항목은 taint 키와 값, operator 또는 effect를 지정해요. 예: "tolerations=key=foo,value=bar;key=foo2,operator=exists;key=foo3,effect=NoSchedule"

이 옵션들은 CSV로 구분된 문자열을 값으로 받아요. 셸 명령의 따옴표 규칙 때문에 값을 작은따옴표로 감싸야 해요. --driver-opt 전체를 작은따옴표로 감쌀 수도 있어요. 예:

$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  '--driver-opt="nodeselector=label1=value1,label2=value2","tolerations=key=key1,value=value1"'

멀티 플랫폼 빌드 (Multi-platform builds)

Kubernetes 드라이버는 QEMU를 사용하거나 노드의 네이티브 아키텍처를 활용해 멀티 플랫폼 이미지를 만들 수 있어요.

QEMU

docker-container 드라이버처럼 Kubernetes 드라이버도 QEMU(사용자 모드)를 사용해 네이티브가 아닌 플랫폼용 이미지를 빌드할 수 있어요. --platform 플래그를 포함해 출력할 플랫폼을 지정해요.

예를 들어 amd64arm64용 리눅스 이미지를 빌드하려면:

$ docker buildx build \
  --builder=kube \
  --platform=linux/amd64,linux/arm64 \
  -t <user>/<image> \
  --push .

Warning

QEMU는 네이티브가 아닌 플랫폼에 대해 전체 CPU 에뮬레이션을 수행하므로 네이티브 빌드보다 훨씬 느려요. 컴파일이나 압축·해제처럼 계산량이 많은 작업은 성능 저하가 클 수 있어요.

커스텀 BuildKit 이미지를 사용하거나 빌드에서 네이티브가 아닌 바이너리를 호출할 때는 빌더를 만들 때 qemu.install 옵션으로 QEMU를 명시적으로 켜야 할 수 있어요:

$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=namespace=buildkit,qemu.install=true

네이티브 (Native)

다른 아키텍처의 클러스터 노드에 접근할 수 있다면 Kubernetes 드라이버가 이들을 네이티브 빌드에 활용할 수 있어요. 그러려면 docker buildx create--append 플래그를 사용해요.

먼저 단일 아키텍처(예: amd64)를 명시적으로 지원하는 빌더를 만들어요:

$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --platform=linux/amd64 \
  --node=builder-amd64 \
  --driver-opt=namespace=buildkit,nodeselector="kubernetes.io/arch=amd64"

그러면 builder-amd64라는 단일 빌더 노드를 가진 kube라는 Buildx 빌더가 만들어져요. --node로 노드 이름을 지정하는 건 선택사항이에요. 지정하지 않으면 Buildx가 무작위 노드 이름을 생성해요.

Buildx의 노드 개념은 Kubernetes의 노드 개념과 같지 않다는 점에 주의하세요. 이 경우 Buildx 노드는 같은 아키텍처의 Kubernetes 노드 여러 개를 함께 연결할 수 있어요.

kube 빌더가 만들어졌으면 --append로 다른 아키텍처를 추가할 수 있어요. 예를 들어 arm64를 추가하려면:

$ docker buildx create \
  --append \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --platform=linux/arm64 \
  --node=builder-arm64 \
  --driver-opt=namespace=buildkit,nodeselector="kubernetes.io/arch=arm64"

빌더를 나열하면 kube 빌더의 두 노드가 모두 보여요:

$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT                                         STATUS   PLATFORMS
kube            kubernetes
  builder-amd64 kubernetes:///kube?deployment=builder-amd64&kubeconfig= running  linux/amd64*, linux/amd64/v2, linux/amd64/v3, linux/386
  builder-arm64 kubernetes:///kube?deployment=builder-arm64&kubeconfig= running  linux/arm64*

이제 빌드 명령에서 플랫폼을 함께 지정해 멀티 아키텍처 amd64·arm64 이미지를 빌드할 수 있어요:

$ docker buildx build --builder=kube --platform=linux/amd64,linux/arm64 -t <user>/<image> --push .

지원하고 싶은 아키텍처 수만큼 docker buildx create --append 명령을 반복할 수 있어요.

루트리스 모드 (Rootless mode)

Kubernetes 드라이버는 루트리스 모드를 지원해요. 루트리스 모드가 동작하는 방식과 요구사항에 대한 자세한 내용은 루트리스 Buildkit 문서를 참고하세요.

클러스터에서 켜려면 rootless=true 드라이버 옵션을 사용해요:

$ docker buildx create \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=namespace=buildkit,rootless=true

그러면 securityContext.privileged 없이 파드가 만들어져요.

Kubernetes 버전 1.19 이상이 필요해요. 호스트 커널로 Ubuntu를 사용하는 것을 권장해요.

예시: Kubernetes에서 Buildx 빌더 만들기 (Creating a Buildx builder in Kubernetes)

이 가이드는 다음 방법을 보여줘요:

  • Buildx 리소스를 위한 namespace 만들기
  • Kubernetes 빌더 만들기
  • 사용 가능한 빌더 나열하기
  • Kubernetes 빌더로 이미지 빌드하기

사전 요구사항:

  • 기존 Kubernetes 클러스터가 있어야 해요. 없다면 minikube를 설치해 따라 하면 돼요.

  • 연결하려는 클러스터가 kubectl 명령으로 접근 가능해야 해요. 필요하면 KUBECONFIG 환경 변수를 적절히 설정해요.

  • buildkit namespace를 만들어요. 별도의 namespace를 만들면 Buildx 리소스를 클러스터의 다른 리소스와 분리해서 관리할 수 있어요.

    $ kubectl create namespace buildkit
    namespace/buildkit created
    
  • Kubernetes 드라이버로 새 빌더를 만들어요.

    $ docker buildx create \
      --bootstrap \
      --name=kube \
      --driver=kubernetes \
      --driver-opt=namespace=buildkit
    

    Note

    드라이버 옵션에 namespace를 반드시 지정하세요.

  • docker buildx ls로 사용 가능한 빌더를 나열해요.

    $ docker buildx ls
    NAME/NODE                DRIVER/ENDPOINT STATUS  PLATFORMS
    kube                     kubernetes
    kube0-6977cdcb75-k9h9m                 running linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
    default *                docker
    default                default         running linux/amd64, linux/386
    
  • kubectl로 빌드 드라이버가 만든 실행 중인 파드를 검사해요.

    $ kubectl -n buildkit get deployments
    NAME    READY   UP-TO-DATE   AVAILABLE   AGE
    kube0   1/1     1            1           32s
    $ kubectl -n buildkit get pods
    NAME                     READY   STATUS    RESTARTS   AGE
    kube0-6977cdcb75-k9h9m   1/1     Running   0          32s
    

    빌드 드라이버는 지정된 namespace(이 경우 buildkit)에 필요한 리소스를 클러스터에 만들어 주면서, 드라이버 구성 자체는 로컬에 유지해요.

  • Buildx 명령을 실행할 때 --builder 플래그를 포함해 새 빌더를 사용해요. 예:

    # Replace <registry> with your Docker username
    # and <image> with the name of the image you want to build
    docker buildx build \
      --builder=kube \
      -t <registry>/<image> \
      --push .
    

이제 끝이에요. Buildx를 사용해 Kubernetes 파드에서 이미지를 빌드했습니다.

더 알아보기 (Learn more)