新卒インフラエンジニア向けLinuC 101 試験対策シリーズの第5回です。前回は個別プロセスとハードウェアを観察しました。今回は視点を上に上げ、仮想マシンとコンテナという2大「実行レイヤー」を扱います。
仮想化技術は現代のあらゆるインフラ(クラウド・コンテナ基盤・社内検証環境)で前提となる知識です。本記事では概念整理から始め、KVM/libvirt の役割を理解し、最後に Podman で実際にコンテナを動かすところまで進みます。
環境前提
- ディストリビューション: AlmaLinux 9.6(Sage Margay)
- カーネル: 5.14.0-570.12.1.el9_6.x86_64
- ユーザー:
developer(sudo NOPASSWD設定済み) - 関連VM:
linuc-alma(10.0.10.132) - 仮想化基盤: Hyper-V 第2世代(VMBus基盤)
- 注意:linuc-alma 自身が仮想マシンのため、ネステッド仮想化が無効でKVM/libvirtの実機操作はできません。本記事のKVM部分はコマンド一覧と概念解説に留めます。
- 本記事で導入:
podman(dnf install)
今ここマップ
LinuC 101 試験対策シリーズ(全12回)
第1回 Linuxの起動・接続・停止
第2回 ブートプロセスの仕組み
第3回 systemdマスター講座
第4回 プロセス管理とハードウェア基礎
▶ 第5回 仮想マシンとコンテナの基礎 ← いまここ
第6回 パッケージ管理マスター
第7回 ファイル操作の実践
第8回 パーミッション・所有者・特殊権限
第9回 コマンドライン・リダイレクト・パイプ
第10回 テキスト処理(grep / sed / awk)
第11回 vi/vim 入門
第12回 ディスク・パーティション・ファイルシステム
この記事で身につくこと
- 物理マシン/ハイパーバイザ型仮想マシン/コンテナの違いを言葉で説明できる
- KVM・libvirt・QEMU の役割分担を理解し、主要コマンド(
virsh、virt-install)を識別できる - Podman でイメージを取得し、コンテナを起動・状態確認・停止・削除できる
podman execでコンテナ内に入って操作できる- Containerfile からイメージをビルドし、その内容を理解できる
3つの実行レイヤー
「サーバーでアプリを動かす」と一口に言っても、現代のインフラには 3つの実行レイヤーがあります。新卒エンジニアが最初に整理しておくべき視点です。
なぜ複数のレイヤーが必要か
各レイヤーには目的とトレードオフがあります。
| 項目 | 物理マシン | 仮想マシン | コンテナ |
|---|---|---|---|
| OS | 1物理に1OS | 1物理に複数OS | カーネル共有・ユーザー空間複数 |
| 隔離レベル | — | 強い(独立カーネル) | 軽め(同一カーネル) |
| 起動速度 | 分単位 | 分〜秒 | ミリ秒 |
| リソース効率 | 高(無駄なし) | 中(ゲストOS分のオーバーヘッド) | 高(プロセスとほぼ同じ) |
| 異種OS混在 | — | 可能(Linux + Windows等) | 不可(カーネル種類は1つ) |
| 主な用途 | HPC・性能最重視 | クラウドVM・検証環境・OS混在 | マイクロサービス・CI/CD・本番アプリ |
本記事の検証環境 linuc-alma もこの階層の中にあります。
ホストPC(物理)
└─ Hyper-V(ハイパーバイザ)
└─ linuc-alma(仮想マシン、AlmaLinux 9.6)
└─ Podman(コンテナランタイム)
└─ コンテナ(後述)

このように現実の現場では、複数の層が組み合わさっています。「自分が今どの層にいるか」を意識する習慣が、トラブルシュートの初動を速めます。
📖 試験Tipsボックス:3つの実行レイヤー
主題:1.01.2 仮想マシン・コンテナの概念と利用(重要度:高)
出題パターン:「仮想マシンとコンテナの違いは?」「コンテナがホストと共有するものは何?」「異種OSを同居させたい場合、適切な技術は?」
暗記ポイント
- VM = 独立カーネル + 独立ユーザー空間(ハイパーバイザ経由でハードウェアを仮想化)
- コンテナ = ホストカーネル共有 + ユーザー空間のみ独立(ネームスペース・cgroup)
- 異種OS混在 ⇒ VM、軽量・大量起動 ⇒ コンテナ
- VMの起動は分〜秒単位、コンテナはミリ秒単位
第1章:KVM・libvirt・QEMU の役割
Linux 標準の仮想化スタックは、3つのコンポーネントで構成されています。
| コンポーネント | 位置 | 役割 |
|---|---|---|
| KVM | カーネルモジュール | CPU仮想化拡張(Intel VT-x / AMD-V)を使ってハードウェアレベルの仮想化を提供 |
| QEMU | ユーザー空間プロセス | I/Oエミュレーション・周辺デバイス仮想化。KVMと組み合わせて高速動作 |
| libvirt | 管理API/デーモン | VMの作成・起動・停止・スナップショットを統一的に扱う抽象層。virsh等のCLIから呼ぶ |
1.1 自分の環境がKVMを使えるか確認する
実行コマンド(linuc-almaで実行):
$ grep -E "vmx|svm" /proc/cpuinfo | head -1
実行結果:
(出力なし)
物理マシンや、ネステッド仮想化が有効な仮想マシンでは、Intel CPU は vmx、AMD CPU は svm がフラグとして見えます。今回の linuc-alma は Hyper-V Gen2 VM 上で動作しており、ホスト側でネステッド仮想化が有効化されていないため、CPU 拡張が露出されていません。
実行コマンド:
$ ls /dev/kvm
実行結果:
ls: '/dev/kvm' にアクセスできません: そのようなファイルやディレクトリはありません
/dev/kvm も存在しないため、本環境ではKVMハイパーバイザは動作しません。物理サーバーや、ネステッド仮想化を有効化したVMでは /dev/kvm が存在し、KVMが利用可能になります。
1.2 主要な libvirt コマンド(参考)
本環境では実行できませんが、KVM が使える環境では以下のコマンドが使えます。試験対策として押さえておきたい項目です。
# パッケージ導入(KVM環境)
$ sudo dnf install -y qemu-kvm libvirt virt-install
$ sudo systemctl enable --now libvirtd
# VM一覧
$ sudo virsh list --all
# VM作成(最小例)
$ sudo virt-install \
--name myvm \
--vcpus 2 --memory 2048 \
--disk size=10 \
--location http://repo.almalinux.org/almalinux/9/BaseOS/x86_64/os/ \
--os-variant almalinux9
# VM起動・停止・削除
$ sudo virsh start myvm
$ sudo virsh shutdown myvm
$ sudo virsh destroy myvm # 強制停止
$ sudo virsh undefine myvm # 定義削除
virsh は libvirt を CLI から操作する標準ツール。GUI で操作したい場合は virt-manager。
📖 試験Tipsボックス:KVM周辺
主題:1.01.2(重要度:高)
出題パターン:「Linux 標準のハイパーバイザは?」「libvirtのCLIは?」「KVMが要求するCPU機能は?」
暗記ポイント
- KVM = カーネルモジュール(カーネルにハイパーバイザ機能)
- QEMU = ユーザー空間エミュレータ(KVMと組み合わせ)
- libvirt = 管理API。CLIは
virsh、GUIはvirt-manager - 必要なCPU機能:Intel VT-x(vmxフラグ)/ AMD-V(svmフラグ)
- 確認:
grep -E "vmx\|svm" /proc/cpuinfo、/dev/kvmの存在
第2章:Podman — デーモンレスのコンテナエンジン
コンテナ運用の領域では Docker が長らく標準でしたが、Red Hat 系(RHEL/AlmaLinux/Rocky)では Podman が公式採用されています。
2.1 Podman の特徴
- デーモンレス:常駐プロセスがいない。コマンド実行のたびにプロセスを起動
- rootless 対応:root権限なしでコンテナを動かせる(ユーザー名前空間活用)
- Docker互換 CLI:
alias docker=podmanで大半のスクリプトが動く - pod 単位の管理:複数コンテナを「pod」としてまとめて扱える(Kubernetes Pod 概念に近い)
2.2 インストール
実行コマンド:
$ sudo dnf install -y podman
実行結果(末尾):
yajl-2.1.0-25.el9.x86_64
完了しました!
実行コマンド:
$ podman --version
実行結果:
podman version 5.6.0
2.3 既定レジストリの確認
イメージを取得する先は /etc/containers/registries.conf で設定されています。
実行コマンド:
$ grep ^unqualified-search /etc/containers/registries.conf
実行結果:
unqualified-search-registries = ["registry.access.redhat.com", "registry.redhat.io", "docker.io"]
イメージ名にレジストリを書かない場合(例:podman pull busybox)、この順番で検索されます。本記事では明示的に docker.io/library/busybox を指定して取得します。
第3章:Podman ライフサイクル — pull, run, exec, stop, rm
3.1 イメージを取得
実行コマンド:
$ podman pull docker.io/library/busybox:latest
実行結果:
Trying to pull docker.io/library/busybox:latest...
Getting image source signatures
Copying blob sha256:481282afbc4304ffee4792258ea114f09e423a4a082335b30695b50310394f47
Copying config sha256:925ff61909aebae4bcc9bc04bb96a8bd15cd2271f13159fe95ce4338824531dd
Writing manifest to image destination
925ff61909aebae4bcc9bc04bb96a8bd15cd2271f13159fe95ce4338824531dd
実行コマンド:
$ podman images
実行結果:
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/library/busybox latest 925ff61909ae 19 months ago 4.67 MB
busybox はわずか 4.67MB。Linuxの基本コマンドが詰まったミニマムイメージで、学習用途に最適です。
3.2 即実行 — run –rm
--rm オプションを付けると、コマンド終了とともにコンテナを自動削除します。
実行コマンド:
$ podman run --rm docker.io/library/busybox:latest echo "Hello from container"
実行結果:
Hello from container
これだけでも、新しいユーザー空間(namespace)でbusyboxのechoが実行されています。コンテナ内のプロセスはホストから隔離された環境で動作しています。
3.3 バックグラウンド起動 — run -d
長時間動かすコンテナは -d(detach、デタッチ)で起動します。--name で識別名を付けると操作しやすくなります。
実行コマンド:
$ podman run -d --name testweb docker.io/library/busybox:latest sh -c "while true; do echo running; sleep 5; done"
実行結果(コンテナID):
b9b6f8aff5de734ea6f109bd5862557607a19a2730e70f7d951c3d8bd8270b6e
5秒ごとに「running」と出力する無限ループのコンテナがバックグラウンドで動き始めました。
3.4 状態確認 — ps
実行コマンド:
$ podman ps
実行結果:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b9b6f8aff5de docker.io/library/busybox:latest sh -c while true;... 2 seconds ago Up 2 seconds testweb
停止中のコンテナも含めて見るには podman ps -a です(前回の ps と同じ命名)。
3.5 中で操作 — exec
動作中のコンテナ内で任意のコマンドを実行するのが podman exec です。
実行コマンド:
$ podman exec testweb echo "exec works"
実行結果:
exec works
対話的に shell を起動するなら:podman exec -it testweb sh。コンテナのデバッグや内部状態確認の主力ツールです。
3.6 ログ — logs
コンテナの標準出力/標準エラーは podman logs で取り出せます。
実行コマンド:
$ podman logs testweb | head -3
実行結果:
running
tail -f 相当(リアルタイム追跡)は podman logs -f testweb。Ctrl+C で抜けます。
3.7 停止と削除 — stop, rm
実行コマンド:
$ podman stop testweb
実行結果:
time="2026-05-09T22:57:08+09:00" level=warning msg="StopSignal SIGTERM failed to stop container testweb in 10 seconds, resorting to SIGKILL"
testweb
注目:busybox の sh -c "while true; ..." は SIGTERM をループ内の sleep に伝播しないため、10秒のタイムアウト後にSIGKILLで強制停止されました。前回(第4回)で学んだシグナル知識がここで活きます。本番のコンテナでは trap でシグナルを正しく扱うのがプロダクションコンテナの基本作法です。
実行コマンド:
$ podman rm testweb
実行結果:
testweb
停止したコンテナを削除しました。podman ps -a で空になっていることを確認できます。
3.8 イメージ削除 — rmi
使い終わったイメージは podman rmi で削除します。
実行コマンド:
$ podman rmi docker.io/library/busybox:latest
実行結果:
Untagged: docker.io/library/busybox:latest
Deleted: 925ff61909aebae4bcc9bc04bb96a8bd15cd2271f13159fe95ce4338824531dd
稼働中コンテナがイメージを使っている場合は削除を拒否されます。-f で強制ですが、現場では基本的に使わない方針です。
第4章:Containerfile からイメージをビルド
既存イメージを使うだけでなく、自分のアプリ用のイメージを作るのもインフラエンジニアの仕事です。Containerfile(Docker互換、Dockerfileと同一構文)でビルド方法を記述します。
4.1 Containerfile を書く
作業ディレクトリを作って Containerfile を作成します。
実行コマンド:
$ mkdir -p ~/hello-linuc && cd ~/hello-linuc
$ cat > Containerfile <<EOF
FROM docker.io/library/busybox:latest
RUN echo "Layer added at build time" > /etc/built.txt
CMD ["sh", "-c", "echo Hello from hello-linuc; cat /etc/built.txt"]
EOF
主要な命令の意味:
| 命令 | 意味 |
|---|---|
FROM <image> | ベースイメージ。多くは公式の軽量イメージから |
RUN <cmd> | ビルド時に実行するコマンド。レイヤー1つ作成 |
COPY <src> <dst> | ホストのファイルをイメージへコピー |
WORKDIR <path> | 以降の RUN/CMD のカレントディレクトリ |
ENV KEY=VALUE | 環境変数 |
EXPOSE <port> | ドキュメント目的のポート公開(実体はrun時の-p) |
CMD [...] | コンテナ起動時の既定コマンド |
ENTRYPOINT [...] | 常に実行される起点コマンド |
4.2 ビルド
実行コマンド:
$ cd ~/hello-linuc && podman build -t hello-linuc:1.0 .
実行結果(抜粋):
STEP 1/3: FROM docker.io/library/busybox:latest
STEP 2/3: RUN echo "Layer added at build time" > /etc/built.txt
--> 5ccd67c7abdf
STEP 3/3: CMD ["sh", "-c", "echo Hello from hello-linuc; cat /etc/built.txt"]
COMMIT hello-linuc:1.0
--> c533dc7678f9
Successfully tagged localhost/hello-linuc:1.0
c533dc7678f94dc2aa487ca02a5bfa747d347e2c0d412ffb629eece3aa1d7be2
-t hello-linuc:1.0 でタグ(名前:バージョン)を付与。. はビルドコンテキスト(Containerfileのある場所)。
4.3 動作確認
実行コマンド:
$ podman run --rm hello-linuc:1.0
実行結果:
Hello from hello-linuc
Layer added at build time
Containerfile の CMD が実行され、ビルド時に RUN で追加した /etc/built.txt も読めています。「Dockerfile を書ける」のはサーバーサイド職の基礎中の基礎。第6章の演習で実際に書いてみます。
📖 試験Tipsボックス:Podman / Docker 基本
主題:1.01.2(重要度:高)
出題パターン:「コンテナを起動するコマンドは?」「動作中コンテナを一覧するのは?」「イメージビルド定義ファイルは?」
暗記ポイント
- サブコマンド:
pull/run/ps/exec/logs/stop/rm/rmi/build - イメージ定義ファイル:
Dockerfile=Containerfile(同一構文) - 主要命令:FROM / RUN / COPY / WORKDIR / ENV / CMD / ENTRYPOINT
- Podmanの特徴:デーモンレス・rootless可能・Docker互換CLI・pod管理
- イメージタグ:
name:tag形式(タグ省略時はlatest)
第5章:コンテナ運用の周辺概念
本記事では基本サブコマンドだけでも十分ですが、現場では以下の3つも頻出します。試験対策として概要だけ押さえてください。
5.1 ボリューム — 永続化とホスト連携
$ podman run -v /host/data:/container/data:Z <image> ...
ホストの /host/data をコンテナ内 /container/data にマウント。コンテナ削除後もデータが残ります。:Z は SELinux ラベルの自動設定。
5.2 ポートフォワード — 外部公開
$ podman run -d -p 8080:80 nginx:latest
ホストの 8080/tcp をコンテナの 80/tcp に転送。ホスト外部から http://<host>:8080 でアクセスできるようになります。
5.3 環境変数 — 設定の注入
$ podman run -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=app mysql:8
-e KEY=VALUE でコンテナに環境変数を渡せます。設定情報・認証情報の注入で頻用。本番では --env-file やシークレット管理ツール経由が推奨。
⚠️ ヒヤリハット:「コンテナ内で rm -rf / してもホストは安全」と思い込んだ
新人E君は「コンテナはホストから隔離されているから、何でも試して大丈夫」と聞き、podman exec -it mycontainer sh で中に入って rm -rf / を実行。コンテナの中身は破壊されましたが、コンテナ削除で済みました——と思いきや、別件でボリューム(-v /home/developer/data:/data)をマウントしたコンテナで同じことをして、ホストの /home/developer/data も消失。
教訓:コンテナはユーザー空間のみ独立。ボリュームでマウントしたホストパスはコンテナ内からも書き込み・削除可能。「コンテナ内なら安全」は誤り。マウントしているパスは常に意識する。本番運用では:ro(read-only)マウントの活用、bind mount より名前付きボリュームの優先、を組み合わせる。
現場での使いどころ
- 検証環境の即時構築:「nginx 動かしたい」「PostgreSQLで検証したい」→
podman run -d -p ... nginxで即起動。物理マシンでもVMでも数分かかる作業が秒で終わる - CI/CDのジョブ実行:GitLab CI / GitHub Actions のランナーは大半がコンテナベース。
FROMでビルド環境を固定、RUNでテスト実行、というパターン - ローカル開発のクリーン環境:開発者ごとに違う環境差異を
FROM almalinux:9等のベースイメージで揃える - 本番のマイクロサービス基盤:Kubernetes/OpenShift 上のコンテナとして本番アプリを動かす流れが主流。Podmanはローカル開発からKubernetes本番までの橋渡し
- レガシーアプリの仮想マシン延命:コンテナ化が難しい既存システムは KVM/libvirt で VM として塩漬け運用。両技術の使い分けがインフラエンジニアの判断ポイント
やってみよう
検証環境(linuc-alma)で順番に実行してください。演習4までで全フローを体験できます。
演習1:自分の環境がKVMを使えるか確認
grep -E "vmx|svm" /proc/cpuinfo | head -1でCPU仮想化拡張を確認ls /dev/kvmでKVMデバイス確認lsmod | grep -i kvmでモジュール確認- linuc-alma では空・無 が正解(ネステッド未有効)
演習2:Podman導入と基本ライフサイクル
sudo dnf install -y podmanで導入podman --versionでバージョン確認podman pull docker.io/library/busybox:latestpodman imagesで取得確認podman run --rm docker.io/library/busybox:latest echo "Hello"
演習3:バックグラウンド・exec・logs・stop・rm
podman run -d --name testweb docker.io/library/busybox:latest sh -c "while true; do echo running; sleep 5; done"podman pspodman exec testweb echo OKpodman logs testweb | head -3podman stop testweb(10秒程度かかる理由を考察)podman rm testwebpodman ps -aで空を確認
演習4:Containerfile から build
mkdir -p ~/hello-linuc && cd ~/hello-linuc- 本文 4.1 のヒアドキュメントで Containerfile を作成
podman build -t hello-linuc:1.0 .podman run --rm hello-linuc:1.0で動作確認- クリーンアップ:
podman rmi hello-linuc:1.0 docker.io/library/busybox:latest cd ~ && rm -rf ~/hello-linuc
分からないオプションは man podman、man podman-run、man podman-build で調べる習慣を身につけてください。
理解度チェック
○か×で答えてください。回答と解説は次回冒頭で振り返ります。
- 仮想マシンとコンテナの最大の違いは「カーネルを共有するかどうか」である。
- KVM は Linux カーネルモジュールであり、ハイパーバイザとして CPU 仮想化拡張(VT-x / AMD-V)を要求する。
- Podman は Docker と異なり、デーモンプロセスを必要としない。
- Containerfile と Dockerfile は構文が完全に異なる別々の仕様である。
- コンテナにボリューム(
-v)でホストディレクトリをマウントしている場合、コンテナ内からrmするとホスト側のファイルも消える。
解答
- 1. ○ VMは独立カーネル、コンテナはホストカーネル共有
- 2. ○ Intel VT-x(vmx)/ AMD-V(svm)の有効が必須
- 3. ○ Podmanはデーモンレス。コマンド実行のたびにプロセス起動
- 4. × ContainerfileとDockerfileは同一構文(互換)
- 5. ○ bind mountは双方向。コンテナ内の操作がホストに反映される
次回予告
第6回は「パッケージ管理マスター:dnf / apt / rpm / dpkg の実践」です。本シリーズで唯一、AlmaLinux と Ubuntu の両方を行き来する回。RHEL系(dnf/rpm)と Debian系(apt/dpkg)の使い分け、リポジトリ設定、依存関係解決の仕組みを実機で学びます。
LinuC 101 試験対策シリーズ 全12回
- 第1回 Linuxの起動・接続・停止:systemctl・login・shutdownの基本
- 第2回 ブートプロセスの仕組み:BIOS/UEFI → GRUB → systemd の流れ
- 第3回 systemdマスター講座:サービス管理・unitファイル・ターゲット
- 第4回 プロセス管理とハードウェア基礎(ps, top, lsblk, lspci, lsusb)
- 第5回 仮想マシンとコンテナの基礎:KVM・Docker・Podman 入門(本記事)
- 第6回 パッケージ管理マスター:dnf / apt / rpm / dpkg の実践
- 第7回 ファイル操作の実践:cp, mv, find, リンク, FHS
- 第8回 パーミッション・所有者・特殊権限(SUID/SGID/Sticky)
- 第9回 コマンドライン・リダイレクト・パイプの基礎
- 第10回 テキスト処理の三種の神器:grep / sed / awk + 正規表現
- 第11回 vi/vim 入門:現場で使えるエディタ操作
- 第12回 ディスク・パーティション・ファイルシステム(fdisk, mkfs, mount, LVM)
