빌드 노드(Build Nodes)

참고

Zuul은 이전에 빌드 노드를 관리하기 위해 보조 프로그램인 Nodepool을 사용했습니다. Nodepool은 현재 사용 중단되었으며, 여기에서 설명하는 시스템으로 대체되어야 합니다.

Zuul은 클라우드의 가상 머신, Kubernetes 파드, 또는 정적 호스트와 같은 빌드용 리소스를 빌드 노드`(또는 간단히 `노드)라고 부르며, 잡과 파이프라인에 사용되는 것과 동일한 설정 시스템을 통해 관리합니다. Zuul은 원격 시스템과 상호 작용하며 실제 리소스를 사용하기 때문에(비용이 발생할 수 있음) 몇 가지 차이점이 존재하지만, 대부분의 설정은 Git 저장소에 포함되며 Zuul 시스템 관리자에 의해 관리되거나 사용자에게 위임될 수 있습니다.

Zuul에는 빌드 노드의 생명 주기를 관리하는 전용 컴포넌트인 `zuul-launcher`가 있습니다. 또한 빌드 노드에 사용되는 사용자 정의 가상 머신 이미지의 빌드도 관리할 수 있습니다.

노드 및 이미지 관리와 관련된 여러 Zuul 구성 객체가 있습니다:

Provider 객체는 노드 및 이미지 관리와 관련된 핵심 설정 객체입니다. 이는 쿠버네이트 클러스터, 클라우드의 특정 리전, 또는 정적 노드의 집합을 나타낼 수 있으며, 이러한 리소스는 테넌트에 제공됩니다. 하나 이상의 클라우드나 클라우드 리전을 사용하는 경우, 각 클라우드 또는 리전마다 최소 하나의 제공자(provider)가 필요하다. 여러 테넌트가 동일한 클라우드 리전을 공유해야 한다면 해당 제공자를 여러 테넌트에 포함시킬 수 있고, 리소스를 공유해서는 안된다면 테넌트별로 고유한 제공자를 생성할 수 있습니다.

Section 객체는 제공자와 관련된 다양한 구성을 유연하게 표현하기 위한 설정 시스템입니다. 섹션(section)은 제공자의 일부(예: 클라우드 리전)를 나타낸다. 제공자는 섹션으로부터 설정을 상속받아 구성되며, 섹션은 또 다른 섹션을 상속할 수 있어 여러 단계의 추상화를 구성할 수 있습니다.

궁극적으로 섹션은 하나의 Zuul connection 과 연결되며, 이를 통해 클라우드에 대한 실제 인증된 연결이 이루어집니다. 다음은 섹션과 제공자를 구성하는 방법에 대한 예시입니다:

digraph foo {
  bgcolor="transparent";
  rankdir="LR";
  node [shape=box];
  edge [dir=back];

  subgraph cluster_connection {
    label="Connection";
    style=filled;
    color=lightgrey;
    node [style=filled,color=black,fillcolor=white];
    aws_conn [label="aws"];
  }

  subgraph cluster_section {
    label="Sections";
    style=filled;
    color=lightgrey;
    node [style=filled,color=black,fillcolor=white];
    aws_eu_north_1 [label="aws-eu-north-1"];
    aws_eu_central_1 [label="aws-eu-central-1"];
    aws -> aws_eu_north_1;
    aws -> aws_eu_central_1;
  }

  subgraph cluster_provider {
    label="Providers";
    style=filled;
    color=lightgrey;
    node [style=filled,color=black,fillcolor=white];
    aws_eu_north_1_main [label="aws-eu-north-1-main"];
    aws_eu_north_1_restricted [label="aws-eu-north-1-restricted"];
    aws_eu_central_1_main [label="aws-eu-central-1-main"];
  }

  aws_conn -> aws;
  aws_eu_north_1 -> aws_eu_north_1_main;
  aws_eu_north_1 -> aws_eu_north_1_restricted;
  aws_eu_central_1 -> aws_eu_central_1_main;
}

이 예시는 세 개의 제공자로 구성된 시스템을 보여줍니다. 이 중 두 개의 제공자는 eu-north-1 리전을 사용하고, 하나는 eu-central-1 리전을 사용합니다. 이들 섹션은 모두 aws`라는 단일 섹션을 상속하며, 해당 섹션은 `aws 연결을 참조합니다. aws 섹션은 AWS 전반에 공통으로 적용되는 설정을 구성하는 데 사용되며, north`와 `central 섹션은 각 리전에만 적용되는 설정을 추가할 수 있습니다. 마지막으로 제공자는 이러한 설정을 기반으로 추가적인 세부 조정을 할 수 있습니다.

노드 재사용(Node Reuse)

일반적으로 Zuul은 노드를 생성한 후 하나의 잡 빌드에 한 번 사용하고, 빌드가 완료되면 해당 노드를 삭제하는 것을 기본 동작으로 합니다. 드라이버에 따라 reuse 옵션을 사용하여 노드를 재사용하도록 Zuul을 설정할 수 있습니다. 이 옵션이 설정되면, 노드는 빌드 완료 후 다시 서비스에 투입됩니다. 그러나 이 옵션은 보안상 위험할 수 있는데, 이전 잡이 노드의 보안을 침해했을 경우 이후에 실행되는 잡이 정보나 자격 증명을 획득할 수 있기 때문입니다. static 드라이버에서는 이 동작이 자동으로 활성화되며 비활성화할 수 없습니다.

관련 옵션으로 slots 옵션이 있으며, 이는 하나의 노드에서 동시에 실행될 수 있는 빌드의 수를 설정합니다. 1 보다 큰 값으로 설정할 경우, 하나의 기본 노드 (VM, static host 등)가 Zuul에서 여러 하위 노드의 호스트 역할을 하게 되며, 각 하위 노드는 서로 다른 빌드에서 동시에 사용될 수 있습니다. 이는 reuse 와 유사한 보안 영향을 가지므로 사용 시 주의가 필요합니다.

참고

reuseslots 의 조합은 metastatic Nodepool 드라이버와 유사한 기능을 제공할 수 있습니다.

이미지 생성(Image Creation)

일반 Zuul 잡을 사용하여 이미지를 빌드할 수 있으며, Zuul은 생성된 파일(qcow2, vhd 등)을 클라우드에 업로드하여 노드 실행에 사용할 수 있습니다.

이미지 빌드 잡은 특별한 리포터가 설정된 파이프라인에서 실행되어야 합니다. 해당 파이프라인은 일반적인 트리거로 실행될 수 있으며, 누락된 이미지 빌드를 위한 전용 트리거도 사용할 수 있습니다. 이미지 빌드에 필요한 리포터 설정은 다음과 같다:

- pipeline:
    success:
      zuul:
        image-built: true
        image-validated: true

(image-validated 에 대한 자세한 내용은 아래를 참조.)

다음은 누락된 이미지에 대해 Zuul이 빌드를 실행하도록 하는 트리거 설정입니다:

- pipeline:
    trigger:
     zuul:
       - event: image-build

잡이 이미지 빌드 잡임을 Zuul에 알리기 위해 job.image-name 속성을 사용하여 해당 잡이 지정된 이름의 이미지를 빌드함을 명시합니다. 이 이름은 Image 객체와 일치해야 하며, 잡은 이미지 객체와 동일한 저장소에 정의되어야 합니다. 해당 잡은 이미지를 빌드하고 이를 오브젝트 스토리지 시스템에 업로드할 책임이 있습니다. 또한 반환 값 를 사용하여 이미지가 저장된 위치에 대한 정보를 반환해야 합니다. 다음은 qcow2 이미지에 대해 기대되는 정보를 보여주는 zuul_return 설정 예시입니다:

- name: Return Image information to Zuul
  zuul_return:
    data:
      zuul:
        artifacts:
          - name: 'qcow2 image'
            url: '<url of image>'
            metadata:
              type: 'zuul_image'
              image_name: '<image name>'
              format: 'qcow2'
              sha256: '<sha256 value of image file>'
              md5sum: '<md5sum value of image file>'

드라이버는 이미지를 처리하기 위한 여러 가지 방법을 구현할 수 있습니다. 대부분의 드라이버는 빌드 잡이 HTTP로 접근 가능한 오브젝트 스토리지에 이미지를 업로드하면, 드라이버가 이를 다운로드한 후 클라우드에 업로드하는 단순한 방식을 지원합니다. 일부 드라이버는 잡이 클라우드의 오브젝트 스토리지 시스템에 직접 이미지를 업로드하고, Zuul이 이를 이미지로 바로 가져오는 구성을 지원합니다. 자세한 내용은 각 드라이버의 문서를 참조하라.

이미지 아티팩트를 생성하는 방식 외에도, 일부 드라이버는 스냅샷 기반 이미지 빌드를 지원합니다. 이 경우 이미지 빌드 잡은 실행 중인 노드를 설정한 뒤, 스냅샷을 생성할 준비가 되면 run 플레이북의 마지막 단계에서 해당 작업을 실행하여 Zuul에 스냅샷 생성을 요청해야 합니다:

- name: Return snapshot command to Zuul
  zuul_return:
    data:
      zuul:
        snapshot_nodes:
          - node: "{{ zuul_node.uuid }}"
            image_name: "<image name>"

이후 제어는 Zuul로 돌아가며, 스냅샷이 생성된 다음 post-run 플레이북이 정상적으로 실행됩니다.

이미지 검증(Image Validation)

Zuul은 이미지가 클라우드에 사용 가능 상태가 된 이후, 일반 Zuul 빌드에 사용되기 전에 해당 이미지에 대해 검증 잡을 실행하도록 설정할 수 있습니다. 이를 위해 이미지 빌드 파이프라인에서 image-validated 필드를 생략하고, 이미지 검증만을 위한 새로운 파이프라인을 생성합니다. 구성은 다음과 같다:

- pipeline:
    name: image-validate
    manager: independent
    trigger:
      zuul:
        - event: image-validate
    success:
      zuul:
        image-validated: true

그 다음 새로운 image-validate 파이프라인에 잡을 연결합니다. 해당 잡들이 성공하면 이미지는 검증된 것으로 간주되어 서비스에 투입되며, 실패할 경우 이미지는 삭제됩니다.

Nodepool 마이그레이션(Migration)

Zuul은 이전에 Nodepool이라는 보조 프로그램을 사용하여 노드와 이미지의 생명 주기를 관리했습니다. zuul-launcher`가 관리하는 새로운 시스템은 이러한 환경을 매끄럽게 마이그레이션할 수 있도록 설계되었습니다. Zuul이 잡을 실행하기 위해 특정 레이블의 노드를 필요로 할 때, 먼저 현재 테넌트에 해당 레이블이 :attr:`label 객체로 정의되어 있는지 확인합니다. 정의되어 있다면 새로운 zuul-launcher 시스템을 통해 노드가 제공되고, 그렇지 않다면 Nodepool로 폴백됩니다. 이 동작을 통해 Zuul 시스템은 테넌트 및 레이블 단위로 점진적인 마이그레이션이 가능합니다.

테넌트가 완전히 마이그레이션되면 tenant.use-nodepool 설정을 false 로 지정하여 Nodepool 폴백 동작을 비활성화해야 합니다. 이를 통해 Nodepool이 실행 중이지 않은 상태에서 Zuul이 Nodepool에 요청을 보내는 상황을 방지할 수 있습니다