Custom executorでlibvirtを使用する
- プラン: Free、Premium、Ultimate
- 提供形態: GitLab.com、GitLab Self-Managed、GitLab Dedicated
libvirtを使用すると、Custom executorドライバーは、実行するジョブごとに新しいディスクとVMを作成します。その後、ディスクとVMは削除されます。
このドキュメントでは、スコープ外であるため、libvirtのセットアップ方法については説明しません。ただし、このドライバーはGCP Nested仮想化を使用してテストされており、ブリッジネットワーキングでlibvirtをセットアップする方法の詳細も記載されています。この例では、libvirtのインストール時に付属するdefaultネットワークを使用するため、実行されていることを確認してください。
このドライバーにはブリッジネットワーキングが必要です。各VMは専用のIPアドレスを持つ必要があり、GitLab RunnerはSSH内でコマンドを実行できます。SSHキーは、次のコマンドを使用して生成できます。
ベースディスクVMイメージが作成されるため、dependenciesがすべてのビルドでダウンロードされることはありません。次の例では、virt-builderを使用してディスクVMイメージを作成します。
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を渡します。
設定
次に、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" # Path to a bash script to create VM.
run_exec = "/opt/libvirt-driver/run.sh" # Path to a bash script to run script inside of VM over ssh.
cleanup_exec = "/opt/libvirt-driver/cleanup.sh" # Path to a bash script to delete VM and disks.ベース
各ステージング(prepare 、run 、およびcleanup)は、以下のベーススクリプトを使用して、他のスクリプト全体で使用される変数を生成します。
このスクリプトは、他のスクリプトと同じディレクトリ(この場合は/opt/libivirt-driver/)に配置されていることが重要です。
#!/usr/bin/env bash
# /opt/libvirt-driver/base.sh
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スクリプト:
- ディスクを新しいパスにコピーします。
- コピーされたディスクから新しいVMをインストールします。
- VMがIPを取得するのを待ちます。
- SSHがVM上で応答するのを待ちます。
#!/usr/bin/env bash
# /opt/libvirt-driver/prepare.sh
currentDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source ${currentDir}/base.sh # Get variables from base script.
set -eo pipefail
# trap any error, and mark it as a system failure.
trap "exit $SYSTEM_FAILURE_EXIT_CODE" ERR
# Copy base disk to use for Job.
qemu-img create -f qcow2 -b "$BASE_VM_IMAGE" "$VM_IMAGE" -F qcow2
# Install the VM
virt-install \
--name "$VM_ID" \
--os-variant debian11 \
--disk "$VM_IMAGE" \
--import \
--vcpus=2 \
--ram=2048 \
--network default \
--graphics none \
--noautoconsole
# Wait for VM to get IP
echo 'Waiting for VM to get IP'
for i in $(seq 1 30); do
VM_IP=$(_get_vm_ip)
if [ -n "$VM_IP" ]; then
echo "VM got IP: $VM_IP"
break
fi
if [ "$i" == "30" ]; then
echo 'Waited 30 seconds for VM to start, exiting...'
# Inform GitLab Runner that this is a system failure, so it
# should be retried.
exit "$SYSTEM_FAILURE_EXIT_CODE"
fi
sleep 1s
done
# Wait for ssh to become available
echo "Waiting for sshd to be available"
for i in $(seq 1 30); 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" == "30" ]; then
echo 'Waited 30 seconds for sshd to start, exiting...'
# Inform GitLab Runner that this is a system failure, so it
# should be retried.
exit "$SYSTEM_FAILURE_EXIT_CODE"
fi
sleep 1s
done実行
これにより、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 # Get variables from base script.
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
# Exit using the variable, to make the build as failure in GitLab
# CI.
exit "$BUILD_FAILURE_EXIT_CODE"
fiクリーンアップ
このスクリプトは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 # Get variables from base script.
set -eo pipefail
# Destroy VM.
virsh shutdown "$VM_ID"
# Undefine VM.
virsh undefine "$VM_ID"
# Delete VM disk.
if [ -f "$VM_IMAGE" ]; then
rm "$VM_IMAGE"
fi