0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Hyper-V で Podman + docker-compose 環境を作る

0
Last updated at Posted at 2026-10-31

1. 概要

自分用に、Hyper-V 上に Rocky Linux の VM を作る手順をまとめます。

この VM は、GitLab コンテナを動かす土台や、VSCode の DevContainer の基盤として使うことを想定しています。職場に近いコンテナ環境(Podman + docker-compose)を手元に用意しておくのが狙いです。

本記事では、仮想スイッチの作成から、VM の作成・OS インストール・NAT 設定・Podman / docker-compose の導入までを扱います(GitLab コンテナの構築自体は別記事に分けます)。

2. Hyper-V で VM を作る

なお、自動化等が可能だと思うので、コマンドで実施していますが、GUI でも設定可能な内容です。

UEFI の設定や Hyper-V の有効化など、VM 作成の根本的な部分は省きますので、ご了承ください。

2.1. 構築の準備

職場の環境は、コンテナエンジンにPodmanを使用しており、コンテナの構成管理にdocker-composeを使用し、設定内容が見える(秘伝のタレにならない)ようになっています。それに近い環境の構築を目指したいと思います。

2.1.1. イメージの入手

手元にあるのが、Rocky Linux 10.1なのでこれを使用します。

職場のディストリビューション(RHEL9系)とはやや異なりますが、大きな差分にはならないと考えています。

2.1.2. docker-compose の入手

これは手順の中で実施しますが、GitHub から取得する必要があります。

この手順はLegacyとして扱われているので、あまり良い方法ではありませんが、職場の環境を再現するために実施します。

というより、そもそもRHEL標準リポジトリではDockerは配布されていない(Podmanに置換された)ので、標準リポジトリでdocker-composeを組み合わせるにはこの方法しかなさそう?(Docker 社の外部リポジトリから導入は可能だが Red Hat のサポート外)

ということで、以下を参考に standalone の docker-compose を Podman の Docker 互換ソケット(DOCKER_HOST)に向けて使うように設定します。

2.2. VM 構築手順

以降のコマンドは 「管理者として実行」した PowerShell で行います。

2.2.1. 仮想スイッチの作成

今回の検証では、外部からの接続は行わないので、内部仮想スイッチを作ります。

$SwitchName = "InternalSwitch"
New-VMSwitch `
-Name $SwitchName `
-SwitchType Internal
# 以下は出力結果

Name           SwitchType NetAdapterInterfaceDescription
----           ---------- ------------------------------
InternalSwitch Internal

仮想スイッチのIPアドレスを192.168.100.1/24設定します。

New-NetIPAddress `
-InterfaceAlias "vEthernet ($SwitchName)" `
-IPAddress 192.168.100.1 `
-PrefixLength 24
# 以下は出力結果

IPAddress         : 192.168.100.1
InterfaceIndex    : 38
InterfaceAlias    : vEthernet (InternalSwitch)
AddressFamily     : IPv4
Type              : Unicast
PrefixLength      : 24
PrefixOrigin      : Manual
SuffixOrigin      : Manual
AddressState      : Tentative
ValidLifetime     : Infinite ([TimeSpan]::MaxValue)
PreferredLifetime : Infinite ([TimeSpan]::MaxValue)
SkipAsSource      : False
PolicyStore       : ActiveStore

作成後、NIC の設定を確認してください。追加したネットワークアダプタ(仮想スイッチ)が表示されれば問題ありません。

ipconfig /all
# 以下は出力結果
# 該当部分のみ掲載

イーサネット アダプター vEthernet (InternalSwitch):

   接続固有の DNS サフィックス . . . . .:
   説明. . . . . . . . . . . . . . . . .: Hyper-V Virtual Ethernet Adapter #4
   物理アドレス. . . . . . . . . . . . .: 00-15-5D-20-86-11
   DHCP 有効 . . . . . . . . . . . . . .: いいえ
   自動構成有効. . . . . . . . . . . . .: はい
   リンクローカル IPv6 アドレス. . . . .: fe80::1390:7148:87d3:67fc%38(優先)
   IPv4 アドレス . . . . . . . . . . . .: 192.168.100.1(優先)
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .:
   DHCPv6 IAID . . . . . . . . . . . . .: 637539677
   DHCPv6 クライアント DUID. . . . . . .: 00-01-01-00-30-E6-D2-3A-34-5A-60-66-C2-A9
   NetBIOS over TCP/IP . . . . . . . . .: 有効

2.2.1.1. 外部スイッチの追加(任意)

今回の検証は内部スイッチ+NAT だけで完結しますが、「VM を物理 LAN に直結して、ホスト以外の端末からも VM に触りたい」場合は、内部スイッチに加えて外部スイッチも作れます(不要な方は読み飛ばしてください)。

外部スイッチは、VM を物理 NIC 経由で物理 LAN へ直結します(ホストと同一セグメント)。ここでは ホストと NIC を共有する方針 で作ります。こうすると、物理 NIC が 1 枚でもホスト側の通信(インターネット)が維持され、ホスト ↔ VM も外部スイッチ経由でそのまま通ります。

参考(仮想スイッチの作成):Create a virtual switch for Hyper-V virtual machines

まず、バインドする物理 NIC 名を確認します。

Get-NetAdapter

外部スイッチを作成します。-NetAdapterName を指定すると種別は自動的に「外部」になり、-AllowManagementOS を省略すると既定でホストと共有になります。<NIC名> は上で確認した物理 NIC(有線を推奨)に置き換えてください。

New-VMSwitch `
-Name "ExternalSwitch" `
-NetAdapterName "<NIC名>"

外部スイッチの作成時は、その NIC のネットワーク接続が一時的に中断されます(作成後にホスト側 vEthernet (ExternalSwitch) が IP を取り直します)。

外部スイッチの使い方は、目的によって次の 2 通りに分かれます。なお、VM のアダプター操作(Add-VMNetworkAdapter / Connect-VMNetworkAdapter)は VM を作成した後(2.2.3. VM の作成 以降)に実行してください($VmName も 2.2.2.1. VMの情報 で定義します)。

(a) 内部スイッチと両立させる(VM に NIC を 2 枚持たせる)

内部スイッチ側(192.168.100.10)はホスト ↔ VM の管理用として残し、外部スイッチ側でインターネット/LAN に出ます。VM 作成後、2 枚目のアダプターを追加します。

Add-VMNetworkAdapter `
-VMName $VmName `
-SwitchName "ExternalSwitch"

VM 側では、外部側の NIC を DHCP(デフォルト経路を持つ側)、内部側の NIC を静的 IP(デフォルトゲートウェイなし)に設定します。

※デフォルトルートを 2 本持たせると経路が二重化して不安定になります。デフォルトゲートウェイは外部側の 1 本だけにしてください。

(b) 外部スイッチだけにする(内部スイッチをやめる)

VM の接続先を外部スイッチへ切り替えます。アダプター名は Get-VMNetworkAdapter -VMName $VmName で確認できます。

Connect-VMNetworkAdapter `
-VMName $VmName `
-Name "ネットワーク アダプター" `
-SwitchName "ExternalSwitch"

VM 側の IP は物理 LAN に合わせて DHCP で取り直します(本手順の静的 IP 192.168.100.10 は内部スイッチ専用なので、そのままでは通りません)。

※(a)(b) いずれも、インターネットは外部スイッチ直結で出られるので、2.4. NAT 設定 は不要です。

2.2.2. VM 設定用のシェル変数の準備

2.2.2.1. VMの情報

以降で使用するシェル変数を準備しておきます。

$VmName = "Rocky-Podman"
$ISO = "C:\ISO\RockyLinux10.1.iso" # iso ファイルがあるパスに書き換えること
$DefaultSaveFolder = (Get-VMHost).VirtualHardDiskPath
$VhdFullPath = "$DefaultSaveFolder\$VmName.vhdx"

2.2.2.2. メモリ割り当て量

VMに割り当てるメモリサイズもシェル変数として準備しておきます(2MB の倍数にしないとエラーになります)。

なお、メモリのサイズについては、Windows 11 の最低要件である4GBを残すため、$MaxVmMemory は、$TotalHostMemory から4GB引いた値を割り当てています。

また、$MinVmMemoryを小さくしすぎると、メモリひっ迫時に VM が設定値通りの最小 RAM 付近まで搾られる可能性がありますので、最小とはいえ、なるべくシステムが落ちないような値を設定しましょう。

$TotalHostMemory = (Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory
$MaxVmMemory = [math]::Floor(($TotalHostMemory - 4GB) / 2MB) * 2MB
$MinVmMemory = 4GB # 要件に応じて要調整

やや分かりにくいので、計算例を書いておきます(RAM: 32GB の場合)。

$MaxVmMemory: 32GB - 4GB = 28GB → ÷2MB = 14,336 個(今回は割り切れているので、Floor後も変化なし)
Floor → 14,336 個 ×2MB = 28GB

2.2.2.3. CPU コア数

VM に割り当てる CPU のコア数も割り当てます。

最近の Intel CPU は P コア/E コア混在で、どのコアを使うか手動指定できないこともあるので(私が使用しているのは Ryzen 7 5700X ですが)、全論理コアを割り当て、使用率設定でリソースを共有することで、E コアだけで動く(遅くなる)のを避けられるようにしようと思います。

$TotalHostCores = (Get-ComputerInfo).CsNumberOfLogicalProcessors

2.2.2.4. 仮想ハードディスク

仮想ハードディスクのオブジェクトを生成します。なお、動的 VHDX にするので、サイズを大きめに取っても即座に占有はしません。

$VHD = New-VHD `
-Path $VhdFullPath `
-SizeBytes 128GB `
-Dynamic

2.2.3. VM の作成

これまでに準備したシェル変数をもとに、仮想マシンを作成します。

New-VM `
-Name $VmName `
-MemoryStartupBytes 4GB `
-Generation 2 `
-SwitchName $SwitchName `
-VHDPath $VHD.Path

2.2.4. CPU 使用率の割り当て

少数コアを 100% 占有させるのではなく、使用率(優先度) で共有します。最低 50%・最大 80% を割り当てます。

Set-VMProcessor `
-VMName $VmName `
-Count $TotalHostCores `
-Reserve 50 `
-Maximum 80

※-Reserve/-Maximum は「常に占有」ではなく、スケジューリング(CPU を時間で分け合う仕組み)上の優先度の下限(必要時の最低保証)・上限を指します。

2.2.5. 動的メモリの設定

ホストと VM でメモリを効率的に融通するために、動的メモリを使用します。

Set-VMMemory `
-VMName $VmName `
-DynamicMemoryEnabled $true `
-MinimumBytes $MinVmMemory `
-MaximumBytes $MaxVmMemory `
-Buffer 30

※-Buffer 30は、VM が必要とする量に対し 30%の空きを確保するよう動的に増やすこと。大きすぎるとホストのメモリが枯渇するので注意。

2.2.6. Secure Boot の有効化

OS イメージの正規性を検証でき、起動前の不正コード実行を防ぐことが可能です。今回の検証ではあまり意味はないおと思いますが、有効化しておきます。

Linux ディストリビューションでは MicrosoftUEFICertificateAuthority テンプレートの選択が必須です。間違うと起動しません。

Set-VMFirmware `
-VMName $VmName `
-EnableSecureBoot On `
-SecureBootTemplate MicrosoftUEFICertificateAuthority

2.2.7. チェックポイント種別の設定

現状では、ゲストエージェント(hyperv-daemons)を導入しないので、ここでは標準チェックポイントを使用します。

Set-VM `
-Name $VmName `
-CheckpointType Standard

2.2.8. ISO のマウントとブート順の設定

DVD-ISO をマウントします。

Add-VMDvdDrive `
-VMName $VmName `
-Path $ISO

DVD ドライブを最優先で起動するよう、ブート順を設定します。

Set-VMFirmware `
-VMName $VmName `
-FirstBootDevice (Get-VMDvdDrive -VMName $VmName)

2.2.9. OS 起動前のエクスポート(バックアップ)

初回起動やOSのインストールに失敗した場合のため、起動前の状態(やり直しが効く状態)をエクスポートしておきます。

$ExportPath = "C:\EXAMPLE" # 任意のパスを指定してください
Export-VM `
-Name $VmName `
-Path $ExportPath
# ファイルが出力されたことを確認する
explorer $ExportPath

2.3. OS インストール手順

以下のコマンドで VM を起動します。

vmconnect.exe localhost $VmName
Start-VM -Name $VmName

2.3.1. インストーラーでの設定内容

インストーラーで次のような設定を行います。

設定項目 本手順の値 補足
言語 / キーボード 日本語 or English(任意) GUI は入らないので好みで可
時刻と日付 アジア/東京 —
ソフトウェアの選択 最小限のインストール(Minimal Install) 軽量化のために GUI を入れない。アドオンも選択しない。
インストール先 対象ディスクを選択 → 完了(自動構成) 単一ディスクを使用
KDUMP 無効化(任意) メモリ節約。チェックを外す
ネットワークとホスト名 手順 2.3.2. 静的 IP
root アカウント 手順 2.3.3. root SSH は禁止
ユーザーの作成  手順 2.3.4. wheel(管理者)付き

2.3.2. ネットワークとホスト名

まず、画面左下のホスト名に rocky-podman と入力して適用します。

その後、右上の Ethernet(eth0)トグルをオンにし、以降の手順でインタフェースの設定を行います。

  1. 設定 → IPv4 Settings タブ:
  2. Method:Manual
  3. Add で以下を入力:
    • Address:192.168.100.10
    • Netmask:255.255.255.0(または 24)
    • Gateway:192.168.100.1 (2.2.1. 仮想スイッチの作成 で設定した IP アドレスを使用)
    • DNS サーバー:8.8.8.8(NAT 経由で到達できるもの)
  4. Save → 左上の「完了」ボタンを押す

2.3.3. root アカウント

「root アカウントを有効化」を選び、強いパスワードを設定します(「良好」以上)。

この検証ではあまり関係ありませんが、「総当たり攻撃で root を直接狙われないようする」、ということを心がけようと思うので、root の SSH ログインは無効にします。

よって、「パスワードによる root SSH ログインを許可」のチェックは外しましょう。

2.3.4. ユーザーの作成

以下のように設定します。

  1. フルネーム:人間が読むための名称。任意に入力する(ユーザー名と同じでも良い)
  2. ユーザー名:ssh や su などで使用。英小文字・空白なし・英字始まりで、任意に入力する
  3. 「ユーザーアカウントに管理者権限を付与する(wheel グループに加える)」にチェックを入れる
  4. 2.2.3. root アカウントと同様に、強いパスワードを設定する
  5. 左上の「完了」ボタンを押す

2.3.5. インストール開始と再起動

設定の抜けがないか見直し、右下の「インストールの開始」を押下します。

なお、SMT(同時マルチスレッディング)に関する警告が出ても、本用途では、非本番・限定ネットワークなので無視します。

完了後、「システムの再起動」を押下してください。

また、ISO からの再起動ループを避けるため、再起動後に、以下のコマンドで ISO を外しておきます。

Set-VMDvdDrive -VMName $VmName -Path $null

2.3.6. 初回ログイン

次のような画面が表示されますので、ユーザー名とパスワードを入力し、ログインします。

rocky-podman login: # 設定したユーザー名を入力
Password: # 設定したパスワードを入力

動作確認として次のコマンドを入力します。

cat /etc/rocky-release

すると、次の内容が出力されるはずです。

Rocky Linux release 10.1 (Red Quartz)

2.3.7. ホスト(Windows)からの SSH 疎通確認

最小構成でも OpenSSH サーバーは既定で起動し、firewalld も SSH を許可しているはずですが、念のため確認しておきます。

# SSH サーバーが稼働中か
systemctl is-active sshd
# active なら稼働中
# SSH サーバーが自動起動するか
systemctl is-enabled sshd
# enabled なら自動起動
# 22番ポートを待ち受けているか
ss -tlnp | grep ':22'
# 以下は出力結果
# :22 の LISTEN 行が出れば問題なし
LISTEN 0  128   0.0.0.0:22   0.0.0.0:* ← IPv4・全インターフェースで :22 を待ち受けている
LISTEN 0  128   [::]:22      [::]:*    ← IPv6・全インターフェースで :22 を待ち受けている
# firewalld が動作しているか
sudo firewall-cmd --state
# パスワードを尋ねられたら入力
# 稼働中の場合、running が出力される
# ファイアウォールで許可(開放)されているサービスの一覧を確認する
sudo firewall-cmd --list-services
# 出力例:cockpit dhcpv6-client ssh
# 上記の出力の場合、一番左に ssh があるため、SSHが使用可能である。
# 自分のIPが 192.168.100.10 になっているか
ip -brief addr

上記で問題ないことを確認できたら、ssh を実行しましょう。

ssh <ユーザー名>@192.168.100.10

SSH 接続ができたら Hyper-V のコンソールを閉じます。

Stop-Process -Name vmconnect

2.4. NAT 設定

2.2.1. 仮想スイッチの作成 で内部スイッチとホスト側 IP(192.168.100.1)は作成済みです。しかし、内部スイッチ単体では VM はインターネットに出られません(通信できるのは「ホスト ↔ VM」だけで、物理 NIC には直接つながらない)。

そこで、ホストが VM の通信を外へ中継する(送信元を書き換えて転送する=SNAT) NAT を作成します。

これで、以下の経路でインターネットにつながるようになります。

VM → ゲートウェイ(192.168.100.1=ホスト) → NAT → 物理NIC → インターネット

参考(NAT ネットワークの考え方):Set up a NAT network

2.4.1. NAT の作成

以降のコマンドは 「管理者として実行」した PowerShell で行います。

内部ネットワークの範囲(192.168.100.0/24)に対する NAT を作成します。

New-NetNat `
-Name "HyperV-NAT" `
-InternalIPInterfaceAddressPrefix 192.168.100.0/24

作成できたか確認します。

Get-NetNat
# 以下は出力結果
# Active が True、プレフィックスが 192.168.100.0/24 であれば OK

Name                             : HyperV-NAT
InternalIPInterfaceAddressPrefix : 192.168.100.0/24
Store                            : Local
Active                           : True

2.4.2. 疎通確認

VM に戻り、「ホスト到達 → インターネット到達(名前解決)」の順に確認します。

まず、ゲートウェイ(ホスト)に届くか。これが通れば NAT の土台(内部スイッチ+ホスト IP)は正常です。

ping -c 3 192.168.100.1
# ホスト(ゲートウェイ)に届けば、内部スイッチ側は OK

次に、名前解決(DNS)ができるかを確認します。

ping -c 3 rockylinux.org
# 応答があれば OK

2.5. 初期設定とPodman導入

2.5.1. システム更新

インターネットに接続できることを確認できたら、システムを更新します。

sudo dnf update -y

2.5.2. Hyper-V 連携デーモン

この手順は任意です。

時刻同期・ホストからの正常シャットダウン・IP 情報の通知・(将来の)運用チェックポイントの有効化に効くので、Hyper-V 連携デーモン(hyperv-daemons)を導入します。

sudo dnf install -y hyperv-daemons

デーモンの有効化および起動を行います。

sudo systemctl enable --now hypervkvpd hypervvssd hypervfcopyd

2.2.7. チェックポイント種別の設定では、標準チェックポイントを選択しましたが、運用チェックポイントに切り替えたい場合は、PowerShell で以下のコマンドを実行します。

Set-VM `
-Name $VmName `
-CheckpointType ProductionOnly

ゲスト サービス インターフェイスも有効化します。

Get-VMIntegrationService -VMName $VmName
# 出力例
VMName       Name                             Enabled PrimaryStatusDescription SecondaryStatusDescription
------       ----                             ------- ------------------------ --------------------------
Rocky-Podman ゲスト サービス インターフェイス  False   OK
Rocky-Podman ハートビート                    True    OK
Rocky-Podman キー値ペア交換                  True    OK
Rocky-Podman シャットダウン                  True    OK
Rocky-Podman 時刻の同期                      True    OK
Rocky-Podman VSS                            True    OK
Enable-VMIntegrationService `
-VMName $VmName `
-Name "ゲスト サービス インターフェイス"

2.5.3. 基本ツールと Podman の導入

(VM に戻り、)次のパッケージを導入します。任意に追加しても良いです。

sudo dnf install -y podman git curl tar

バージョンを確認します。

podman --version
# 表示されれば OK

2.5.4. チェックポイント作成(Podman導入完了)

ここまでの状態を保存したいので、念のため、チェックポイントを作成しておきます。PowerShell で以下のコマンドを実行してください。

Checkpoint-VM `
-Name $VmName `
-SnapshotName "Podman インストール完了"

2.5.5. Docker API 互換ソケットの作成

これは「Podman を Docker のふりをさせて、docker-compose から使えるようにする」ための手順です。

ユーザーソケットを有効化します。

systemctl --user enable --now podman.socket
# 出力例

Created symlink '/home/ユーザー名/.config/systemd/user/sockets.target.wants/podman.socket' → '/usr/lib/systemd/user/podman.socket'.

ユーザーソケットは、docker-compose が命令を送る“受け口”(差込口)となります。

--user は「そのユーザー」専用の systemd で開くことを意味します。Podman 自体は一般ユーザー(=rootless)のまま動くので、特別な"rootless化"は不要です。ここで行っているのは、docker-compose がつなぐための「Docker 互換ソケット」を、そのユーザー権限で有効化することです。

ソケット作成後、DOCKER_HOST 変数を設定します。

echo 'export DOCKER_HOST=unix://${XDG_RUNTIME_DIR}/podman/podman.sock' >> ~/.bashrc
source ~/.bashrc

実行後、状態を確認します。

systemctl --user status podman.socket
# 出力例
# Active: active (listening) になっていれば OK

podman.socket - Podman API Socket
    Loaded: loaded (/usr/lib/systemd/user/podman.socket; enabled; preset: disabled)
    Active: active (listening) since Sun 2026-10-25 19:40:33 JST; 7min ago

rootless のユーザーサービスは、既定ではログアウトで止まるので、ログアウト後もコンテナが動くようにします。

loginctl enable-linger $USER

2.5.6. docker-compose の導入

事情は 2.1.2. docker-compose の入手 にも書きましたが、Docker 公式の standalone インストール手順に従い、GitHub から docker-compose を入手します。

以下のコマンドを実行します。

# バージョン確認
COMPOSE_VER=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/') && echo $COMPOSE_VER
# ダウンロード実行
sudo curl -L "https://github.com/docker/compose/releases/download/${COMPOSE_VER}/docker-compose-linux-x86_64" -o /usr/local/bin/docker-compose
# 実行権限の付与
sudo chmod +x /usr/local/bin/docker-compose

動作確認としてバージョンを確認します。

docker-compose --version

先ほど設定したソケットを使って、コンテナエンジン(Podman)に問い合わせ可能かを確認します。

echo $DOCKER_HOST
# unix:///run/user/1000/podman/podman.sock
docker-compose ls
# エラーにならず、空のプロジェクト一覧が出れば OK

# NAME                STATUS              CONFIG FILES
# 出力なし

2.5.7. チェックポイント作成(Docker Compose導入完了)

ここまでの状態を保存したいので、念のため、チェックポイントを作成しておきます。PowerShell で以下のコマンドを実行してください。

Checkpoint-VM `
-Name $VmName `
-SnapshotName "Docker Compose インストール完了"
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?