ローカルのサーバー環境がよくなったので、ローカルでAzure Pipelines / GitHub Actionsのセルフホストランナーを作ろうとしています。最初はpackerでactions-runnerのレポジトリの内容を書き換えてローカルで動くようにしようと思っていたのですが、Ansibleでやったほうがよくないか?ということで(hclはほとんどCopilotに書き換えてもらった)、AnsibleのためにHyper-VのVMをほぼ自動でやるために環境を用意したのでそのメモです。大半はCopilotに書いてもらいましたがテストは自分でやりました。
必要なものは Windows Server 2025(2022でもたぶん大丈夫) と WSL2のみです。WSL2の入れ方はこちらを見てください。
cloud-initにはmeta-dataとnetwork-config、user-dataの3つのファイルが必要です。meta-dataはこのPowerShellスクリプト内で作るので不要です。
実行のためのPowerShellスクリプト
# 初期化作業
$seeddata = <cloud-initで使うファイルひな形を置いているところ>
$suffix = [system.datetime]::Today.Year.tostring()+[system.datetime]::Today.Month.ToString("00")+[system.datetime]::Today.Day.ToString("00")
$vmName = "ubuntuagent"+$suffix
$workDir = Join-Path "D:\HyperV\agent" -ChildPath $suffix
$vSwitch = <Hyper-Vの仮想スイッチ名>
$cpu = 4
$memoryGB = 16
$seediso = Join-Path $workDir -ChildPath "seed.iso"
#metadata作成
New-Item -ItemType Directory -Force -Path $workDir | Out-Null
$metadata = Join-Path $workDir -ChildPath "meta-data"
new-item $metadata -ItemType File -Force | Out-Null
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
"instance-id: ubuntu-agent-"+$suffix, "`nlocal-hostname: agent-" + $suffix+"`n" | Set-Content -Path $metadata -Encoding $utf8NoBom
# workfolderにコピー
$userdata = Join-Path $seeddata -ChildPath "user-data"
copy-item $userdata -Destination $workDir -Force
$networkconfig = Join-Path $seeddata -ChildPath "network-config"
Copy-Item $networkconfig -Destination $workDir -Force
Set-Location $workDir
wsl.exe -e bash -lc "sudo apt update && sudo apt install -y qemu-utils cloud-image-utils"
# ubuntu
$imgUrl = "https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img"
Invoke-WebRequest -Uri $imgUrl -OutFile "$workDir\ubuntu-24.04-amd64.img"
$disk = $vmName + "-amd64.vhdx"
wsl.exe -e bash -lc "qemu-img convert -p -f qcow2 -O vhdx ubuntu-24.04-amd64.img $disk"
$vhdx = Join-Path $workDir -ChildPath $disk
Resize-VHD -Path $vhdx -SizeBytes 64GB
# このフォルダに user-data / network-config を保存済みとする
wsl.exe -e bash -lc "cloud-localds -v --network-config=network-config seed.iso user-data meta-data"
# VM 作成
New-VM -Name $vmName -MemoryStartupBytes ${memoryGB}GB -Generation 2 -SwitchName $vSwitch | Out-Null
Set-VM -Name $vmName -ProcessorCount $cpu
Get-VMHardDiskDrive -VMName $vmName | Remove-VMHardDiskDrive
Add-VMHardDiskDrive -VMName $vmName -Path $vhdx
# Secure Boot: Linux(Microsoft UEFI CA)
Set-VMFirmware -VMName $vmName -EnableSecureBoot On -SecureBootTemplate "MicrosoftUEFICertificateAuthority"
Add-VMDvdDrive -VMName $vmName -Path $seediso | Out-Null
$disk = Get-VMHardDiskDrive -VMName $vmName
Set-VMFirmware -VMName $vmName -FirstBootDevice $disk
# ゲストサービス(Guest Service Interface)を有効化
## 英語版OSはこちら
Enable-VMIntegrationService -VMName $vmName -Name "Guest Service Interface"
## 日本語版OSはこちら
Enable-VMIntegrationService -VMName $vmName -Name "ゲスト サービス インターフェイス"
network-config
version: 2
ethernets:
any:
# Hyper-V でインターフェイス名が変動しても拾えるようにワイルドカードでマッチして eth0 にリネーム
match:
name: "e*"
set-name: eth0
addresses: [IPアドレス]
nameservers:
addresses: [DNSサーバー]
routes:
- to: default
via: <デフォルトゲートウェイ>
IPアドレスはお好みで。最初使っていないやつ一覧から取得して…とか考えていましたがやめました。
#cloud-config
locale: en_US.UTF-8
ssh_pwauth: false
hostname: <ホスト名>
users:
- name: agent
gecos: Azure Pipeline Agent
groups: [sudo]
sudo: "ALL=(ALL) NOPASSWD:ALL"
shell: /bin/bash
ssh_authorized_keys:
- 公開鍵
package_update: true
package_upgrade: true
apt:
sources:
ansible-ppa:
source: "ppa:ansible/ansible"
git-core-ppa:
source: "ppa:git-core/ppa"
package_update: true
packages:
- linux-virtual
- linux-cloud-tools-virtual
- linux-tools-virtual
- curl
- git
- python3-venv
- python3-pip
- software-properties-common
- ansible
# ルートパーティションとファイルシステムを自動拡張(64GB VHDX に合わせて)
growpart:
mode: auto
resize_rootfs: true
runcmd:
- systemctl enable --now hv-kvp-daemon.service || true
- systemctl enable --now hv-fcopy-daemon.service || true
- systemctl enable --now hv-vss-daemon.service || true
- bash -lc "git config --system init.defaultBranch main"
- bash -lc "mkdir -p /etc/ansible && printf '[defaults]\nhost_key_checking = False\n' > /etc/ansible/ansible.cfg"
- bash -lc "curl -LsSf https://astral.sh/uv/install.sh | sh"
- bash -lc "~/.local/bin/uv tool install ansible-core"
- bash -lc "~/.local/bin/uv tool install ansible-dev-tools --with-executables-from ansible-core,ansible-lint,ansible-navigator"
- systemctl restart ssh
ホスト名はスクリプトで直せば(書き換えれば)よかったですね。これはめんどくさがらずにやるべきだった…。
start-vm $vmnameでVMが起動するので、指定したIPアドレスでssh接続できるはずです。WSLでsudoするときにパスワード聞かれるので、まぁそこだけうまいことやってください。
これでVMが作成できたので、次はansibleでactions-runner相当のものを入れてみます。