InfoGrab DocsInfoGrab Docs

Custom executor에서 libvirt 사용하기

요약

libvirt를 사용하면 Custom executor 드라이버가 실행하는 모든 작업에 대해 새 디스크와 VM을 생성하고, 작업 완료 후 디스크와 VM을 삭제합니다. 이 문서는 libvirt 설정 방법은 다루지 않습니다.

libvirt를 사용하면 Custom executor 드라이버가 실행하는 모든 작업에 대해 새 디스크와 VM을 생성하고, 작업 완료 후 디스크와 VM을 삭제합니다.

이 문서는 libvirt 설정 방법은 다루지 않습니다. 해당 내용은 범위를 벗어나기 때문입니다. 다만, 이 드라이버는 GCP Nested Virtualization을 사용하여 테스트되었으며, 여기에는 브리지 네트워킹이 포함된 libvirt 설정 방법에 대한 세부 정보도 포함되어 있습니다. 이 예제는 libvirt 설치 시 제공되는 default 네트워크를 사용하므로 해당 네트워크가 실행 중인지 확인하세요.

이 드라이버는 각 VM이 고유한 IP 주소를 가져야 GitLab Runner가 SSH로 접속하여 명령을 실행할 수 있으므로 브리지 네트워킹이 필요합니다. SSH 키는 다음 명령어를 사용하여 생성할 수 있습니다.

기본 이미지 빌드#

매 빌드마다 의존성을 다운로드하지 않도록 기본 디스크 VM 이미지를 생성합니다. 실행하는 게스트 운영 체제 계열에 맞게 빌드합니다.

Debian 및 Ubuntu (virt-builder)#

virt-builder는 템플릿에서 직접 기본 이미지를 생성합니다:

virt-builder debian-12 \
    --size 8G \
    --output /var/lib/libvirt/images/gitlab-runner-base.qcow2 \
    --format qcow2 \
    --hostname gitlab-runner-bookworm \
    --network \
    --install curl \
    --run-command 'curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | bash' \
    --run-command 'curl -s "https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh" | bash' \
    --run-command 'useradd -m -p "" gitlab-runner -s /bin/bash' \
    --install gitlab-runner,git,git-lfs,openssh-server \
    --run-command "git lfs install --skip-repo" \
    --ssh-inject gitlab-runner:file:/root/.ssh/id_rsa.pub \
    --run-command "echo 'gitlab-runner ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers" \
    --run-command "sed -E 's/GRUB_CMDLINE_LINUX=\"\"/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/' -i /etc/default/grub" \
    --run-command "grub-mkconfig -o /boot/grub/grub.cfg" \
    --run-command "echo 'auto eth0' >> /etc/network/interfaces" \
    --run-command "echo 'allow-hotplug eth0' >> /etc/network/interfaces" \
    --run-command "echo 'iface eth0 inet dhcp' >> /etc/network/interfaces"

이전 명령어는 앞서 명시된 모든 필수 소프트웨어를 설치합니다.

virt-builder는 루트 비밀번호를 자동으로 설정하며 마지막에 출력합니다. 직접 비밀번호를 지정하려면 --root-password password:$SOME_PASSWORD를 전달하세요.

RHEL, CentOS 및 AlmaLinux (virt-customize)#

virt-builder에는 라이선스가 있는 RHEL 게스트 템플릿이 제공되지 않습니다. 배포판의 GenericCloud qcow2를 다운로드하고 virt-customize를 사용하여 오프라인에서 사용자 정의합니다. 이 예제에서는 AlmaLinux 9 x86_64 이미지를 사용하며, 필요에 따라 RHEL 또는 CentOS Stream 9 이미지 또는 다른 아키텍처로 대체합니다.

IMAGES=/var/lib/libvirt/images
BASE="$IMAGES/gitlab-runner-base.qcow2"

curl -fL "https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2" -o "$BASE"
qemu-img resize "$BASE" 12G

virt-customize -a "$BASE" \
    --run-command 'curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | bash' \
    --run-command 'curl -L "https://packagecloud.io/install/repositories/github/git-lfs/script.rpm.sh" | bash' \
    --install gitlab-runner,git,git-lfs,openssh-server \
    --run-command 'git lfs install --skip-repo' \
    --run-command 'id gitlab-runner >/dev/null 2>&1 || useradd -m -s /bin/bash gitlab-runner' \
    --ssh-inject gitlab-runner:file:/root/.ssh/id_rsa.pub \
    --run-command 'echo "gitlab-runner ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/gitlab-runner' \
    --run-command 'systemctl enable sshd' \
    --selinux-relabel

RHEL 계열 관련 세부 사항:

  • .rpm.sh 패키지 저장소 스크립트와 dnf를 사용합니다. virt-customizevirt-install을 제공하는 도구는 guestfs-tools 패키지에 있습니다.

  • 작업에 필요한 런타임을 기본 이미지에 설치합니다. 이 예제에서는 gitlab-runner, git, git-lfs, openssh-server를 설치합니다. 작업이 VM 내부에서 이미지를 빌드하는 경우 podman과 같은 컨테이너 엔진을 추가합니다.

  • 게스트가 강제 모드(enforcing) SELinux에서 깔끔하게 부팅되도록 --selinux-relabel을 전달하고, 이미지가 virt_image_t SELinux 레이블을 갖도록 /var/lib/libvirt/images/ 아래에 이미지를 유지합니다.

  • Debian 레시피와 달리 GenericCloud 이미지에는 net.ifnames/etc/network/interfaces가 필요하지 않습니다. cloud-initNetworkManager로 부팅됩니다. 커널 명령줄을 변경하는 경우 grub2-mkconfig로 GRUB을 다시 생성합니다.

  • libvirt 데몬을 시작하고 virt-host-validate로 중첩 가상화를 확인합니다. libvirt 9 이상은 모듈형 데몬(virtqemud 및 관련 데몬)을 제공합니다. 모놀리식 libvirtd 호환성 유닛도 작동하며 이미 소켓 활성화되어 있을 수 있습니다. 설치 환경에서 제공하는 데몬을 활성화하고 활성 상태인지 확인합니다.

  • Custom executor 스크립트는 이러한 VM이 있는 시스템 libvirt 인스턴스와 통신해야 합니다. base 스크립트는 이 연결을 위해 export LIBVIRT_DEFAULT_URI="qemu:///system"을 설정합니다.

  • prepare 스크립트에서 --os-variantosinfo-db가 인식하는 ID로 설정합니다. 이 예제에서는 rhel9.0을 사용합니다. osinfo-db에 포함되어 있으면 almalinux9 또는 centos-stream9도 작동합니다. 사용 가능한 ID는 osinfo-query os로 나열합니다.

구성#

다음은 libvirt를 위한 GitLab Runner 구성 예제입니다:

concurrent = 1
check_interval = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "libvirt-driver"
  url = "https://gitlab.com/"
  token = "xxxxx"
  executor = "custom"
  builds_dir = "/home/gitlab-runner/builds"
  cache_dir = "/home/gitlab-runner/cache"
  [runners.custom_build_dir]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]
  [runners.custom]
    prepare_exec = "/opt/libvirt-driver/prepare.sh" # VM을 생성하는 bash 스크립트 경로.
    run_exec = "/opt/libvirt-driver/run.sh" # SSH를 통해 VM 내부에서 스크립트를 실행하는 bash 스크립트 경로.
    cleanup_exec = "/opt/libvirt-driver/cleanup.sh" # VM과 디스크를 삭제하는 bash 스크립트 경로.

Base#

각 단계(prepare, run, cleanup)는 아래의 base 스크립트를 사용하여 다른 스크립트에서 사용하는 변수를 생성합니다.

이 스크립트는 다른 스크립트와 동일한 디렉터리, 이 경우 /opt/libvirt-driver/에 위치해야 합니다.

#!/usr/bin/env bash

# /opt/libvirt-driver/base.sh

# Talk to the system libvirt instance, where these VMs live, rather than the
# per-user session instance.
export LIBVIRT_DEFAULT_URI="qemu:///system"

VM_IMAGES_PATH="/var/lib/libvirt/images"
BASE_VM_IMAGE="$VM_IMAGES_PATH/gitlab-runner-base.qcow2"
VM_ID="runner-$CUSTOM_ENV_CI_RUNNER_ID-project-$CUSTOM_ENV_CI_PROJECT_ID-concurrent-$CUSTOM_ENV_CI_CONCURRENT_PROJECT_ID-job-$CUSTOM_ENV_CI_JOB_ID"
VM_IMAGE="$VM_IMAGES_PATH/$VM_ID.qcow2"

_get_vm_ip() {
    virsh -q domifaddr "$VM_ID" | awk '{print $4}' | sed -E 's|/([0-9]+)?$||'
}

Prepare#

prepare 스크립트는 다음을 수행합니다:

  • 디스크를 새 경로에 복사합니다.
  • 복사한 디스크에서 새 VM을 설치합니다.
  • VM이 IP를 획득할 때까지 대기합니다.
  • VM에서 SSH가 응답할 때까지 대기합니다.
#!/usr/bin/env bash

# /opt/libvirt-driver/prepare.sh

currentDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source ${currentDir}/base.sh # base 스크립트에서 변수 가져오기.

set -eo pipefail

# 모든 오류를 트랩하고 시스템 오류로 표시합니다.
trap "exit $SYSTEM_FAILURE_EXIT_CODE" ERR

# 작업에 사용할 기본 디스크 복사.
qemu-img create -f qcow2 -b "$BASE_VM_IMAGE" "$VM_IMAGE" -F qcow2

# VM 설치
# UEFI 모드로 VM을 부팅하려면 다음을 추가하세요: --boot uefi
virt-install \
    --name "$VM_ID" \
    --os-variant debian12 \
    --disk "$VM_IMAGE" \
    --import \
    --vcpus=2 \
    --ram=2048 \
    --network default \
    --graphics none \
    --noautoconsole

# VM이 IP를 획득할 때까지 대기
echo 'Waiting for VM to get IP'
for i in $(seq 1 300); do
    VM_IP=$(_get_vm_ip)

    if [ -n "$VM_IP" ]; then
        echo "VM got IP: $VM_IP"
        break
    fi

    if [ "$i" == "300" ]; then
        echo 'Waited 300 seconds for VM to start, exiting...'
        # GitLab Runner에 시스템 오류임을 알려
        # 재시도하도록 합니다.
        exit "$SYSTEM_FAILURE_EXIT_CODE"
    fi

    sleep 1s
done

# ssh가 사용 가능해질 때까지 대기
echo "Waiting for sshd to be available"
for i in $(seq 1 300); do
    if ssh -i /root/.ssh/id_rsa -o StrictHostKeyChecking=no gitlab-runner@$VM_IP >/dev/null 2>/dev/null; then
        break
    fi

    if [ "$i" == "300" ]; then
        echo 'Waited 300 seconds for sshd to start, exiting...'
        # GitLab Runner에 시스템 오류임을 알려
        # 재시도하도록 합니다.
        exit "$SYSTEM_FAILURE_EXIT_CODE"
    fi

    sleep 1s
done

Run#

GitLab Runner가 생성한 스크립트의 내용을 SSH를 통해 STDIN으로 VM에 전송하여 스크립트를 실행합니다.

#!/usr/bin/env bash

# /opt/libvirt-driver/run.sh

currentDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source ${currentDir}/base.sh # base 스크립트에서 변수 가져오기.

VM_IP=$(_get_vm_ip)

ssh -i /root/.ssh/id_rsa -o StrictHostKeyChecking=no gitlab-runner@$VM_IP /bin/bash < "${1}"
if [ $? -ne 0 ]; then
    # 변수를 사용하여 종료하면 GitLab CI에서
    # 빌드가 실패로 표시됩니다.
    exit "$BUILD_FAILURE_EXIT_CODE"
fi

Cleanup#

이 스크립트는 VM을 제거하고 디스크를 삭제합니다.

#!/usr/bin/env bash

# /opt/libvirt-driver/cleanup.sh

currentDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source ${currentDir}/base.sh # base 스크립트에서 변수 가져오기.

set -eo pipefail

# VM을 종료하고 300초 대기합니다.
for i in $(seq 1 300); do
  virsh destroy "$VM_ID" >/dev/null 2>&1
  if [[ "$(virsh domstate "$VM_ID" 2>/dev/null | tr '[:upper:]' '[:lower:]')" =~ shut\ off|destroyed|^$ ]]; then
      break
  fi
  if [ $i -eq 300 ]; then
     exit "$SYSTEM_FAILURE_EXIT_CODE"
  fi
  sleep 1
done

# VM 정의를 해제합니다.
virsh undefine "$VM_ID" || virsh undefine "$VM_ID" --nvram

# VM 디스크를 삭제합니다.
if [ -f "$VM_IMAGE" ]; then
    rm "$VM_IMAGE"
fi

Custom executor에서 libvirt 사용하기

GitLab v19.2
Tier: Free, Premium, Ultimate
Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
원문 보기
요약

libvirt를 사용하면 Custom executor 드라이버가 실행하는 모든 작업에 대해 새 디스크와 VM을 생성하고, 작업 완료 후 디스크와 VM을 삭제합니다. 이 문서는 libvirt 설정 방법은 다루지 않습니다.

libvirt를 사용하면 Custom executor 드라이버가 실행하는 모든 작업에 대해 새 디스크와 VM을 생성하고, 작업 완료 후 디스크와 VM을 삭제합니다.

이 문서는 libvirt 설정 방법은 다루지 않습니다. 해당 내용은 범위를 벗어나기 때문입니다. 다만, 이 드라이버는 GCP Nested Virtualization을 사용하여 테스트되었으며, 여기에는 브리지 네트워킹이 포함된 libvirt 설정 방법에 대한 세부 정보도 포함되어 있습니다. 이 예제는 libvirt 설치 시 제공되는 default 네트워크를 사용하므로 해당 네트워크가 실행 중인지 확인하세요.

이 드라이버는 각 VM이 고유한 IP 주소를 가져야 GitLab Runner가 SSH로 접속하여 명령을 실행할 수 있으므로 브리지 네트워킹이 필요합니다. SSH 키는 다음 명령어를 사용하여 생성할 수 있습니다.

기본 이미지 빌드#

매 빌드마다 의존성을 다운로드하지 않도록 기본 디스크 VM 이미지를 생성합니다. 실행하는 게스트 운영 체제 계열에 맞게 빌드합니다.

Debian 및 Ubuntu (virt-builder)#

virt-builder는 템플릿에서 직접 기본 이미지를 생성합니다:

virt-builder debian-12 \
    --size 8G \
    --output /var/lib/libvirt/images/gitlab-runner-base.qcow2 \
    --format qcow2 \
    --hostname gitlab-runner-bookworm \
    --network \
    --install curl \
    --run-command 'curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | bash' \
    --run-command 'curl -s "https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh" | bash' \
    --run-command 'useradd -m -p "" gitlab-runner -s /bin/bash' \
    --install gitlab-runner,git,git-lfs,openssh-server \
    --run-command "git lfs install --skip-repo" \
    --ssh-inject gitlab-runner:file:/root/.ssh/id_rsa.pub \
    --run-command "echo 'gitlab-runner ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers" \
    --run-command "sed -E 's/GRUB_CMDLINE_LINUX=\"\"/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/' -i /etc/default/grub" \
    --run-command "grub-mkconfig -o /boot/grub/grub.cfg" \
    --run-command "echo 'auto eth0' >> /etc/network/interfaces" \
    --run-command "echo 'allow-hotplug eth0' >> /etc/network/interfaces" \
    --run-command "echo 'iface eth0 inet dhcp' >> /etc/network/interfaces"

이전 명령어는 앞서 명시된 모든 필수 소프트웨어를 설치합니다.

virt-builder는 루트 비밀번호를 자동으로 설정하며 마지막에 출력합니다. 직접 비밀번호를 지정하려면 --root-password password:$SOME_PASSWORD를 전달하세요.

RHEL, CentOS 및 AlmaLinux (virt-customize)#

virt-builder에는 라이선스가 있는 RHEL 게스트 템플릿이 제공되지 않습니다. 배포판의 GenericCloud qcow2를 다운로드하고 virt-customize를 사용하여 오프라인에서 사용자 정의합니다. 이 예제에서는 AlmaLinux 9 x86_64 이미지를 사용하며, 필요에 따라 RHEL 또는 CentOS Stream 9 이미지 또는 다른 아키텍처로 대체합니다.

IMAGES=/var/lib/libvirt/images
BASE="$IMAGES/gitlab-runner-base.qcow2"

curl -fL "https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2" -o "$BASE"
qemu-img resize "$BASE" 12G

virt-customize -a "$BASE" \
    --run-command 'curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | bash' \
    --run-command 'curl -L "https://packagecloud.io/install/repositories/github/git-lfs/script.rpm.sh" | bash' \
    --install gitlab-runner,git,git-lfs,openssh-server \
    --run-command 'git lfs install --skip-repo' \
    --run-command 'id gitlab-runner >/dev/null 2>&1 || useradd -m -s /bin/bash gitlab-runner' \
    --ssh-inject gitlab-runner:file:/root/.ssh/id_rsa.pub \
    --run-command 'echo "gitlab-runner ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/gitlab-runner' \
    --run-command 'systemctl enable sshd' \
    --selinux-relabel

RHEL 계열 관련 세부 사항:

  • .rpm.sh 패키지 저장소 스크립트와 dnf를 사용합니다. virt-customizevirt-install을 제공하는 도구는 guestfs-tools 패키지에 있습니다.

  • 작업에 필요한 런타임을 기본 이미지에 설치합니다. 이 예제에서는 gitlab-runner, git, git-lfs, openssh-server를 설치합니다. 작업이 VM 내부에서 이미지를 빌드하는 경우 podman과 같은 컨테이너 엔진을 추가합니다.

  • 게스트가 강제 모드(enforcing) SELinux에서 깔끔하게 부팅되도록 --selinux-relabel을 전달하고, 이미지가 virt_image_t SELinux 레이블을 갖도록 /var/lib/libvirt/images/ 아래에 이미지를 유지합니다.

  • Debian 레시피와 달리 GenericCloud 이미지에는 net.ifnames/etc/network/interfaces가 필요하지 않습니다. cloud-initNetworkManager로 부팅됩니다. 커널 명령줄을 변경하는 경우 grub2-mkconfig로 GRUB을 다시 생성합니다.

  • libvirt 데몬을 시작하고 virt-host-validate로 중첩 가상화를 확인합니다. libvirt 9 이상은 모듈형 데몬(virtqemud 및 관련 데몬)을 제공합니다. 모놀리식 libvirtd 호환성 유닛도 작동하며 이미 소켓 활성화되어 있을 수 있습니다. 설치 환경에서 제공하는 데몬을 활성화하고 활성 상태인지 확인합니다.

  • Custom executor 스크립트는 이러한 VM이 있는 시스템 libvirt 인스턴스와 통신해야 합니다. base 스크립트는 이 연결을 위해 export LIBVIRT_DEFAULT_URI="qemu:///system"을 설정합니다.

  • prepare 스크립트에서 --os-variantosinfo-db가 인식하는 ID로 설정합니다. 이 예제에서는 rhel9.0을 사용합니다. osinfo-db에 포함되어 있으면 almalinux9 또는 centos-stream9도 작동합니다. 사용 가능한 ID는 osinfo-query os로 나열합니다.

구성#

다음은 libvirt를 위한 GitLab Runner 구성 예제입니다:

concurrent = 1
check_interval = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "libvirt-driver"
  url = "https://gitlab.com/"
  token = "xxxxx"
  executor = "custom"
  builds_dir = "/home/gitlab-runner/builds"
  cache_dir = "/home/gitlab-runner/cache"
  [runners.custom_build_dir]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]
  [runners.custom]
    prepare_exec = "/opt/libvirt-driver/prepare.sh" # VM을 생성하는 bash 스크립트 경로.
    run_exec = "/opt/libvirt-driver/run.sh" # SSH를 통해 VM 내부에서 스크립트를 실행하는 bash 스크립트 경로.
    cleanup_exec = "/opt/libvirt-driver/cleanup.sh" # VM과 디스크를 삭제하는 bash 스크립트 경로.

Base#

각 단계(prepare, run, cleanup)는 아래의 base 스크립트를 사용하여 다른 스크립트에서 사용하는 변수를 생성합니다.

이 스크립트는 다른 스크립트와 동일한 디렉터리, 이 경우 /opt/libvirt-driver/에 위치해야 합니다.

#!/usr/bin/env bash

# /opt/libvirt-driver/base.sh

# Talk to the system libvirt instance, where these VMs live, rather than the
# per-user session instance.
export LIBVIRT_DEFAULT_URI="qemu:///system"

VM_IMAGES_PATH="/var/lib/libvirt/images"
BASE_VM_IMAGE="$VM_IMAGES_PATH/gitlab-runner-base.qcow2"
VM_ID="runner-$CUSTOM_ENV_CI_RUNNER_ID-project-$CUSTOM_ENV_CI_PROJECT_ID-concurrent-$CUSTOM_ENV_CI_CONCURRENT_PROJECT_ID-job-$CUSTOM_ENV_CI_JOB_ID"
VM_IMAGE="$VM_IMAGES_PATH/$VM_ID.qcow2"

_get_vm_ip() {
    virsh -q domifaddr "$VM_ID" | awk '{print $4}' | sed -E 's|/([0-9]+)?$||'
}

Prepare#

prepare 스크립트는 다음을 수행합니다:

  • 디스크를 새 경로에 복사합니다.
  • 복사한 디스크에서 새 VM을 설치합니다.
  • VM이 IP를 획득할 때까지 대기합니다.
  • VM에서 SSH가 응답할 때까지 대기합니다.
#!/usr/bin/env bash

# /opt/libvirt-driver/prepare.sh

currentDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source ${currentDir}/base.sh # base 스크립트에서 변수 가져오기.

set -eo pipefail

# 모든 오류를 트랩하고 시스템 오류로 표시합니다.
trap "exit $SYSTEM_FAILURE_EXIT_CODE" ERR

# 작업에 사용할 기본 디스크 복사.
qemu-img create -f qcow2 -b "$BASE_VM_IMAGE" "$VM_IMAGE" -F qcow2

# VM 설치
# UEFI 모드로 VM을 부팅하려면 다음을 추가하세요: --boot uefi
virt-install \
    --name "$VM_ID" \
    --os-variant debian12 \
    --disk "$VM_IMAGE" \
    --import \
    --vcpus=2 \
    --ram=2048 \
    --network default \
    --graphics none \
    --noautoconsole

# VM이 IP를 획득할 때까지 대기
echo 'Waiting for VM to get IP'
for i in $(seq 1 300); do
    VM_IP=$(_get_vm_ip)

    if [ -n "$VM_IP" ]; then
        echo "VM got IP: $VM_IP"
        break
    fi

    if [ "$i" == "300" ]; then
        echo 'Waited 300 seconds for VM to start, exiting...'
        # GitLab Runner에 시스템 오류임을 알려
        # 재시도하도록 합니다.
        exit "$SYSTEM_FAILURE_EXIT_CODE"
    fi

    sleep 1s
done

# ssh가 사용 가능해질 때까지 대기
echo "Waiting for sshd to be available"
for i in $(seq 1 300); do
    if ssh -i /root/.ssh/id_rsa -o StrictHostKeyChecking=no gitlab-runner@$VM_IP >/dev/null 2>/dev/null; then
        break
    fi

    if [ "$i" == "300" ]; then
        echo 'Waited 300 seconds for sshd to start, exiting...'
        # GitLab Runner에 시스템 오류임을 알려
        # 재시도하도록 합니다.
        exit "$SYSTEM_FAILURE_EXIT_CODE"
    fi

    sleep 1s
done

Run#

GitLab Runner가 생성한 스크립트의 내용을 SSH를 통해 STDIN으로 VM에 전송하여 스크립트를 실행합니다.

#!/usr/bin/env bash

# /opt/libvirt-driver/run.sh

currentDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source ${currentDir}/base.sh # base 스크립트에서 변수 가져오기.

VM_IP=$(_get_vm_ip)

ssh -i /root/.ssh/id_rsa -o StrictHostKeyChecking=no gitlab-runner@$VM_IP /bin/bash < "${1}"
if [ $? -ne 0 ]; then
    # 변수를 사용하여 종료하면 GitLab CI에서
    # 빌드가 실패로 표시됩니다.
    exit "$BUILD_FAILURE_EXIT_CODE"
fi

Cleanup#

이 스크립트는 VM을 제거하고 디스크를 삭제합니다.

#!/usr/bin/env bash

# /opt/libvirt-driver/cleanup.sh

currentDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source ${currentDir}/base.sh # base 스크립트에서 변수 가져오기.

set -eo pipefail

# VM을 종료하고 300초 대기합니다.
for i in $(seq 1 300); do
  virsh destroy "$VM_ID" >/dev/null 2>&1
  if [[ "$(virsh domstate "$VM_ID" 2>/dev/null | tr '[:upper:]' '[:lower:]')" =~ shut\ off|destroyed|^$ ]]; then
      break
  fi
  if [ $i -eq 300 ]; then
     exit "$SYSTEM_FAILURE_EXIT_CODE"
  fi
  sleep 1
done

# VM 정의를 해제합니다.
virsh undefine "$VM_ID" || virsh undefine "$VM_ID" --nvram

# VM 디스크를 삭제합니다.
if [ -f "$VM_IMAGE" ]; then
    rm "$VM_IMAGE"
fi