- 1. 序論: コンテナエコシステムの二大潮流
- 2. アーキテクチャ比較: Docker vs Podman
- 3. インストールと初期設定
- 4. イメージ管理コマンド
- 5. イメージのビルド
- 6. コンテナライフサイクルのコマンド
- 7. コンテナの監視とデバッグ
- 8. ネットワーク管理
- 9. ボリュームとストレージの管理
- 10. Docker Compose vs Podman Compose
- 11. Podman 固有の機能
- 12. セキュリティ関連のコマンドと設定
- 13. システム管理と整理
- 14. 実践チートシート: よく使うコマンド30選
- 15. トラブルシューティングガイド
- 16. 参考資料とリファレンス
1. 序論: コンテナエコシステムの二大潮流
1.1 Dockerの歴史と現在の位置
2013年にSolomon HykesがPyConで "The future of Linux Containers" という5分間のライトニングトークで世に公開したDockerは、コンテナ技術の大衆化を牽引し、ソフトウェア配布のあり方そのものを刷新した。Docker以前にもLXC(Linux Containers)、FreeBSD Jail、Solaris Zonesといったコンテナ技術は存在したが、Dockerはイメージレイヤーシステム、Dockerfileベースの宣言的ビルド、Docker Hubという中央レジストリを組み合わせ、"Build once, run anywhere" というビジョンを現実のものにした。
Dockerはその後OCI(Open Container Initiative)標準の基盤となり、Kubernetesエコシステムの中核ランタイムとして定着した。しかし2020年にKubernetesがdockershimをdeprecatedとし、Docker Desktopの商用ライセンス方針の変更(250人以上の企業は有料化)が発表されると、業界は代替を探し始めた。
現在もDockerは開発環境の事実上の標準(de facto standard)であり、Docker Hubは世界最大のコンテナイメージレジストリとして君臨している。ただしプロダクション環境では、containerd、CRI-O、そしてPodmanが急速に領域を広げている。
1.2 Podmanが登場した背景
Podman(Pod Manager)はRed Hatが主導して開発したOCI(Open Container Initiative)互換のコンテナエンジンである。Red Hatは、Dockerの単一デーモン(daemon)アーキテクチャがセキュリティ、安定性、システム統合の面で根本的な限界を抱えていると判断し、これを解決するためにPodman、Buildah、Skopeoという三つのツールを開発した。
- Podman: コンテナの実行および管理 (docker CLIの代替)
- Buildah: イメージビルドに特化 (docker buildの代替)
- Skopeo: イメージのコピー、検査、署名 (レジストリ間のイメージ管理)
この三つのツールはそれぞれ独立して動作しながら、互いを補完する関係を形成する。Unix哲学である "ひとつのことをうまくやるツール" に忠実に従った設計だ。
1.3 なぜPodmanなのか
DockerからPodmanへの移行を検討すべき中心的な理由は次のとおりだ。
Daemonless Architecture: Dockerは常にバックグラウンドで dockerd デーモンが動いていなければならない。このデーモンが落ちるとコンテナ管理がすべて不可能になる(Single Point of Failure)。Podmanはデーモンなしで各コンテナを直接fork-execするため、この問題がない。
Rootless Containers: Dockerもrootlessモードをサポートするが、Podmanは最初からrootlessを基本の設計原則に据えていた。一般ユーザーがroot権限なしでコンテナを実行できるため、セキュリティが大きく向上する。
Fork-Exec Model: 伝統的なUnixプロセスモデルに従うため、systemd、audit、cgroupとの統合が自然だ。各コンテナはPodmanプロセスの子プロセスとして存在する。
Podのネイティブサポート: KubernetesのPodという概念をローカルでそのまま使うことができ、podman generate kube コマンドでKubernetes YAMLを自動生成できる。
CLI互換性: alias docker=podman を設定するだけで、ほとんどのDockerコマンドがそのまま動作する。
2. アーキテクチャ比較: Docker vs Podman
2.1 Dockerのアーキテクチャ: Client-Daemonモデル
Dockerは典型的なクライアント・サーバーアーキテクチャに従う。ユーザーが docker run を実行すると、Docker CLI(クライアント)がREST APIを通じてDocker Daemon(dockerd)にリクエストを送る。Daemonはこれを containerd に委譲し、containerd はさらに runc を呼び出して実際のコンテナを生成する。
┌─────────────────────────────────────────────────────────────────┐
│ Docker Architecture │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ REST API ┌──────────────────┐ │
│ │ Docker │───────────────▶│ Docker Daemon │ │
│ │ CLI │ /var/run/ │ (dockerd) │ │
│ │ │ docker.sock │ │ │
│ └──────────┘ │ ┌──────────────┐ │ │
│ │ │ containerd │ │ │
│ │ │ │ │ │
│ │ │ ┌────────┐ │ │ │
│ │ │ │ runc │ │ │ │
│ │ │ │ (OCI) │ │ │ │
│ │ │ └────┬───┘ │ │ │
│ │ └───────┼─────┘ │ │
│ └──────────┼───────┘ │
│ │ │
│ ┌─────────────────────┼──────────────────┐ │
│ │ Container 1 │ Container 2 │ │
│ │ (process) │ (process) │ │
│ └─────────────────────┴──────────────────┘ │
│ │
│ ⚠ dockerdが落ちるとコンテナ管理がすべて不可能 (SPOF) │
│ ⚠ docker.sock へのアクセス = root権限の取得が可能 │
└─────────────────────────────────────────────────────────────────┘
この構造の中心的な問題は、docker.sock へのアクセス権限が事実上root権限と同等だという点にある。dockerグループに属するユーザーは、ホストのファイルシステムをマウントしたり --privileged フラグでコンテナを実行したりして、ホストを完全に掌握できる。
2.2 Podmanのアーキテクチャ: Daemonless Fork-Execモデル
Podmanにはデーモンがない。podman run を実行すると、Podmanプロセスが直接 conmon(Container Monitor)をforkし、conmon がOCIランタイム(crun または runc)を実行してコンテナを生成する。
┌─────────────────────────────────────────────────────────────────┐
│ Podman Architecture │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ direct fork-exec ┌──────────┐ │
│ │ Podman │────────────────────▶│ conmon │ │
│ │ CLI │ (no daemon!) │(container │ │
│ │ │ │ monitor) │ │
│ └──────────┘ └─────┬────┘ │
│ │ │
│ ┌─────▼────┐ │
│ │ crun │ │
│ │ (OCI │ │
│ │ runtime) │ │
│ └─────┬────┘ │
│ │ │
│ ┌─────────────────────┼──────────────────┐ │
│ │ Container 1 │ Container 2 │ │
│ │ (child proc) │ (child proc) │ │
│ └─────────────────────┴──────────────────┘ │
│ │
│ ✅ デーモンなし → SPOFなし │
│ ✅ 各コンテナが独立プロセス → systemd統合が容易 │
│ ✅ Rootless を標準サポート │
└─────────────────────────────────────────────────────────────────┘
conmon はコンテナのstdout/stderrをキャプチャし、コンテナのexit codeを記録し、Podman CLIが終了した後もコンテナを監視し続ける軽量なモニタープロセスだ。
2.3 中核となる比較テーブル
| 比較項目 | Docker | Podman |
|---|---|---|
| アーキテクチャ | Client-Daemon (dockerd) | Daemonless (fork-exec) |
| デフォルトの実行権限 | root (daemon) | rootless (一般ユーザー) |
| OCIランタイム | runc | crun (デフォルト)、runcも対応 |
| イメージビルド | 内蔵 (BuildKit) | Buildah連携 |
| デーモンプロセス | 必須 (dockerd + containerd) | なし |
| systemd統合 | 限定的 | ネイティブ (Quadlet) |
| Podサポート | なし (Composeで代替) | ネイティブ対応 |
| K8s YAML生成 | なし | podman generate kube |
| K8s YAML実行 | なし | podman play kube |
| SocketベースAPI | docker.sock (常時有効) | podman.sock (必要時に有効) |
| コンテナモニター | containerd-shim | conmon |
| デフォルトレジストリ | docker.io 単一 | 複数レジストリ検索 |
| Composeサポート | Docker Compose (公式) | podman-compose / podman compose |
| ライセンス | Apache 2.0 + 商用(Desktop) | Apache 2.0 (完全オープンソース) |
| セキュリティ機構 | AppArmor/Seccomp | SELinux/AppArmor/Seccomp |
3. インストールと初期設定
3.1 Dockerのインストール
Ubuntu / Debian
# 既存のDockerパッケージを削除
sudo apt-get remove docker docker-engine docker.io containerd runc
# 必須パッケージのインストール
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release
# Docker公式GPGキーの追加
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Dockerリポジトリの追加
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Docker Engineのインストール
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
# 現在のユーザーをdockerグループに追加 (再ログインが必要)
sudo usermod -aG docker $USER
# サービスの起動と自動起動の設定
sudo systemctl start docker
sudo systemctl enable docker
# インストールの確認
docker version
docker run hello-world
CentOS / RHEL / Rocky Linux
# 既存パッケージの削除
sudo yum remove -y docker docker-client docker-client-latest \
docker-common docker-latest docker-latest-logrotate \
docker-logrotate docker-engine
# Dockerリポジトリの追加
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# Docker Engineのインストール
sudo yum install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
# サービスの起動
sudo systemctl start docker
sudo systemctl enable docker
# ユーザーをグループに追加
sudo usermod -aG docker $USER
macOS (Docker Desktop)
# Homebrew経由でのインストール
brew install --cask docker
# または Docker Desktop 公式サイトから .dmg をダウンロード
# https://www.docker.com/products/docker-desktop/
# インストール後にDocker Desktopアプリを起動 → Docker Engineが自動起動
docker version
3.2 Podmanのインストール
Ubuntu / Debian
# Ubuntu 22.04+ では標準リポジトリに含まれる
sudo apt-get update
sudo apt-get install -y podman
# 最新バージョンが必要な場合 (Ubuntu)
sudo mkdir -p /etc/apt/keyrings
curl -fsSL "https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/Release.key" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg > /dev/null
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg] \
https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/ /" \
| sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list > /dev/null
sudo apt-get update
sudo apt-get install -y podman
# インストールの確認
podman version
podman info
CentOS / RHEL / Rocky Linux
# RHEL 8+ / CentOS Stream 8+ では標準で同梱
sudo dnf install -y podman
# 追加ツールのインストール
sudo dnf install -y buildah skopeo podman-compose
# Podmanはデーモンがないので systemctl start は不要!
podman version
macOS (Podman Machine)
# Homebrew経由でのインストール
brew install podman
# Podman Machine の初期化 (Linux VM の生成)
podman machine init
# Machine の起動
podman machine start
# インストールの確認
podman version
podman machine list
# Machine の停止
podman machine stop
# Machine の削除
podman machine rm
参考: macOSとWindowsでは、Podmanは軽量なLinux VM(QEMUまたはApple Hypervisor Frameworkベース)を生成し、その中でコンテナを実行する。Docker Desktopと似た方式だが、Podman Desktopという無料のGUIツールも提供されている。
3.3 互換性の設定: alias docker=podman
既存のDockerベースのスクリプトやワークフローを変更せずに使いたいなら、簡単なalias設定だけで足りる。
# シェル設定ファイルに追加 (~/.bashrc または ~/.zshrc)
alias docker=podman
alias docker-compose=podman-compose
# 即時反映
source ~/.bashrc # または source ~/.zshrc
# RHEL/CentOSでは podman-docker パッケージが提供される
sudo dnf install -y podman-docker
# このパッケージは /usr/bin/docker → /usr/bin/podman のシンボリックリンクを生成する
# docker.sock のエミュレーションも含む
3.4 Docker Desktop vs Podman Desktop
| 比較項目 | Docker Desktop | Podman Desktop |
|---|---|---|
| ライセンス | 250人以上の企業は有料 ($5+/user/month) | 完全無料 (Apache 2.0) |
| GUI | 豊富なUI | 基本的なUI (急速に改善中) |
| Extension | Docker Extensions マーケットプレイス | Extension 対応 |
| Kubernetes | 内蔵K8sクラスタ | Kind/Minikube 連携 |
| VMバックエンド | Linux Kit (macOS), WSL2 (Windows) | QEMU / Apple Hypervisor |
| リソース管理 | CPU, Memory, Disk の設定 | podman machine init --cpus --memory |
4. イメージ管理コマンド
コンテナはイメージから生成される。イメージ管理はコンテナ運用の基本中の基本だ。
4.1 イメージの検索
# Docker Hub でイメージを検索
docker search nginx
podman search nginx
# 結果件数の制限
docker search --limit 5 nginx
podman search --limit 5 nginx
# 公式イメージのみ検索 (Docker)
docker search --filter is-official=true nginx
# Podmanは複数のレジストリを同時に検索 (registries.conf の設定に従う)
# /etc/containers/registries.conf
# unqualified-search-registries = ["docker.io", "quay.io", "ghcr.io"]
podman search --list-tags docker.io/library/nginx
4.2 イメージのプル (Pull)
# 基本のイメージダウンロード
docker pull nginx
podman pull nginx
# 特定のタグを指定
docker pull nginx:1.25-alpine
podman pull nginx:1.25-alpine
# 特定のレジストリからプル
docker pull ghcr.io/myorg/myapp:latest
podman pull quay.io/prometheus/prometheus:latest
# 特定のプラットフォーム(アーキテクチャ)を指定
docker pull --platform linux/arm64 nginx:latest
podman pull --platform linux/arm64 nginx:latest
# すべてのタグをダウンロード
docker pull --all-tags nginx
podman pull --all-tags nginx
# Digest で特定のビルドを指定 (不変な参照)
docker pull nginx@sha256:abc123...
podman pull nginx@sha256:abc123...
4.3 イメージ一覧の確認
# ローカルイメージの一覧
docker images
podman images
# 詳細形式 (同じコマンド)
docker image ls
podman image ls
# 特定イメージのフィルタリング
docker images nginx
podman images nginx
# dangling イメージのみ表示 (タグなしイメージ)
docker images -f dangling=true
podman images -f dangling=true
# イメージIDのみ出力
docker images -q
podman images -q
# カスタムフォーマットで出力
docker images --format "{{.Repository}}:{{.Tag}} - {{.Size}}"
podman images --format "{{.Repository}}:{{.Tag}} - {{.Size}}"
# JSON形式で出力 (Podman)
podman images --format json
4.4 イメージの詳細情報 (Inspect)
# イメージの詳細情報を確認
docker inspect nginx:latest
podman inspect nginx:latest
# 特定フィールドのみ抽出 (Go template)
docker inspect --format '{{.Config.ExposedPorts}}' nginx
podman inspect --format '{{.Config.ExposedPorts}}' nginx
# イメージサイズの確認
docker inspect --format '{{.Size}}' nginx
podman inspect --format '{{.Size}}' nginx
# 環境変数の確認
docker inspect --format '{{.Config.Env}}' nginx
podman inspect --format '{{.Config.Env}}' nginx
# Entrypoint および Cmd の確認
docker inspect --format '{{.Config.Entrypoint}} {{.Config.Cmd}}' nginx
podman inspect --format '{{.Config.Entrypoint}} {{.Config.Cmd}}' nginx
4.5 イメージの履歴 (History)
# イメージレイヤーの履歴を確認
docker history nginx
podman history nginx
# コマンド全文を表示 (切り詰めない)
docker history --no-trunc nginx
podman history --no-trunc nginx
# JSON形式 (Podman)
podman history --format json nginx
4.6 イメージのタグ (Tag)
# イメージに新しいタグを追加
docker tag nginx:latest myregistry.com/nginx:v1.0
podman tag nginx:latest myregistry.com/nginx:v1.0
# 複数のタグを追加
docker tag myapp:latest myapp:v2.1.0
docker tag myapp:latest myapp:stable
podman tag myapp:latest myapp:v2.1.0
podman tag myapp:latest myapp:stable
4.7 イメージの削除 (Remove)
# イメージの削除
docker rmi nginx:latest
podman rmi nginx:latest
# 同じコマンド (推奨)
docker image rm nginx:latest
podman image rm nginx:latest
# 強制削除 (実行中のコンテナがあっても)
docker rmi -f nginx:latest
podman rmi -f nginx:latest
# すべてのイメージを削除
docker rmi $(docker images -q)
podman rmi -a
# Dangling イメージのみ削除
docker image prune -f
podman image prune -f
# 使われていないすべてのイメージを削除
docker image prune -a -f
podman image prune -a -f
# 特定の条件でフィルタして削除 (24時間以上経過したイメージ)
docker image prune -a --filter "until=24h"
podman image prune -a --filter "until=24h"
4.8 イメージの保存/ロード (Save/Load)
エアギャップ(air-gapped)環境やオフライン転送のときに有用だ。
# イメージをtarファイルとして保存
docker save -o nginx.tar nginx:latest
podman save -o nginx.tar nginx:latest
# 複数のイメージをひとつのtarに保存
docker save -o images.tar nginx:latest redis:latest postgres:15
podman save -o images.tar nginx:latest redis:latest postgres:15
# gzip圧縮で保存
docker save nginx:latest | gzip > nginx.tar.gz
podman save nginx:latest | gzip > nginx.tar.gz
# tarファイルからイメージをロード
docker load -i nginx.tar
podman load -i nginx.tar
# gzip圧縮ファイルからロード
docker load -i nginx.tar.gz
podman load -i nginx.tar.gz
4.9 イメージの Import/Export
save/load がイメージのメタデータ(レイヤー、タグ、履歴)を含むのに対し、export/import はコンテナのファイルシステムだけを扱う。
# コンテナのファイルシステムをtarにエクスポート
docker export my-container -o container-fs.tar
podman export my-container -o container-fs.tar
# tarファイルからイメージを生成
docker import container-fs.tar myimage:imported
podman import container-fs.tar myimage:imported
# URLから直接import
docker import https://example.com/rootfs.tar.gz myimage:latest
podman import https://example.com/rootfs.tar.gz myimage:latest
4.10 レジストリへのログイン/プッシュ
# Docker Hub へのログイン
docker login
podman login docker.io
# 特定のレジストリへログイン
docker login ghcr.io
podman login quay.io
# ユーザー名/パスワードを直接指定
docker login -u username -p password registry.example.com
podman login -u username -p password registry.example.com
# ログアウト
docker logout
podman logout docker.io
# イメージのプッシュ
docker push myregistry.com/myapp:v1.0
podman push myregistry.com/myapp:v1.0
# すべてのタグをプッシュ
docker push --all-tags myregistry.com/myapp
podman push --all-tags myregistry.com/myapp
5. イメージのビルド
5.1 Dockerfile vs Containerfile
Dockerは Dockerfile という名前を使い、Podman/Buildahは Containerfile をデフォルトとして認識する。ただしPodmanはDockerfileも自動的に認識するため、名前を変えずに使える。内容と文法は完全に同一だ。
# Dockerfile または Containerfile — 文法は同一
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY /app/dist ./dist
COPY /app/node_modules ./node_modules
EXPOSE 3000
USER node
CMD ["node", "dist/main.js"]
| 項目 | Dockerfile | Containerfile |
|---|---|---|
| 使用ツール | Docker | Podman, Buildah |
| 文法 | 同一 | 同一 |
| デフォルトのファイル名 | Dockerfile | Containerfile |
| 相互互換 | PodmanはDockerfileを認識 | DockerはContainerfileを認識しない |
| 明示ビルド | docker build -f Containerfile . | podman build -f Dockerfile . |
5.2 docker build vs podman build
# 基本のビルド
docker build -t myapp:latest .
podman build -t myapp:latest .
# 特定のDockerfileを指定
docker build -f Dockerfile.prod -t myapp:prod .
podman build -f Containerfile.prod -t myapp:prod .
# Build argument の受け渡し
docker build --build-arg NODE_ENV=production -t myapp:prod .
podman build --build-arg NODE_ENV=production -t myapp:prod .
# キャッシュなしでビルド
docker build --no-cache -t myapp:latest .
podman build --no-cache -t myapp:latest .
# ターゲットステージの指定 (マルチステージ)
docker build --target builder -t myapp:builder .
podman build --target builder -t myapp:builder .
# マルチプラットフォームビルド (Docker BuildKit)
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest .
# Podman のマルチプラットフォームビルド
podman build --platform linux/amd64,linux/arm64 --manifest myapp:latest .
# ビルド時のメモリ制限
docker build --memory 2g -t myapp:latest .
# ビルドコンテキストのサイズ最小化 — .dockerignore の活用は必須
# .dockerignore (または .containerignore)
# node_modules
# .git
# *.md
# dist
# .env
5.3 マルチステージビルド (Multi-stage Build) の実践例
マルチステージビルドは、ビルド環境と実行環境を分離して最終イメージのサイズを劇的に減らす中核的な手法だ。
Go アプリケーションの例
# ============================================
# Stage 1: ビルド環境
# ============================================
FROM golang:1.22-alpine AS builder
# ビルドに必要なツールのインストール
RUN apk add --no-cache git ca-certificates
WORKDIR /app
# 依存関係を先にコピー (キャッシュの活用)
COPY go.mod go.sum ./
RUN go mod download
# ソースコードのコピーとビルド
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -ldflags="-w -s" -o /app/server ./cmd/server
# ============================================
# Stage 2: 実行環境 (scratch = 空のイメージ)
# ============================================
FROM scratch
# CA証明書のコピー (HTTPS通信用)
COPY /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
# バイナリのみコピー
COPY /app/server /server
# 非rootユーザーで実行
USER 65534:65534
EXPOSE 8080
ENTRYPOINT ["/server"]
Java (Spring Boot) の例
# ============================================
# Stage 1: ビルド
# ============================================
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
COPY gradle/ gradle/
COPY gradlew build.gradle.kts settings.gradle.kts ./
RUN ./gradlew dependencies --no-daemon
COPY src/ src/
RUN ./gradlew bootJar --no-daemon -x test
# JRE カスタムランタイムの生成 (jlink)
RUN jlink \
--add-modules java.base,java.logging,java.sql,java.naming,java.management,java.instrument,java.security.jgss,java.desktop \
--strip-debug \
--no-man-pages \
--no-header-files \
--compress=zip-6 \
--output /custom-jre
# ============================================
# Stage 2: 実行 (カスタムJRE)
# ============================================
FROM alpine:3.19
COPY /custom-jre /opt/java
COPY /app/build/libs/*.jar /app/app.jar
ENV JAVA_HOME=/opt/java
ENV PATH="${JAVA_HOME}/bin:${PATH}"
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
Python の例
# ============================================
# Stage 1: 依存関係のビルド
# ============================================
FROM python:3.12-slim AS builder
RUN pip install --no-cache-dir poetry
WORKDIR /app
COPY pyproject.toml poetry.lock ./
RUN poetry export -f requirements.txt --output requirements.txt --without-hashes
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
# ============================================
# Stage 2: 実行環境
# ============================================
FROM python:3.12-slim
# 必要なシステムライブラリだけをインストール
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
COPY /install /usr/local
WORKDIR /app
COPY . .
RUN useradd --create-home appuser
USER appuser
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
5.4 Build Cache 戦略
# ❌ 非効率: ソース変更のたびに npm install が再実行される
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
# ✅ 効率的: package.json が変わったときだけ npm install を再実行
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
キャッシュレイヤー順序の原則: 変更頻度の低いレイヤーを上に、変更頻度の高いレイヤーを下に配置する。
変更頻度が低い ─── FROM (ベースイメージ)
│ RUN apt-get install (システムパッケージ)
│ COPY package.json (依存関係の定義)
│ RUN npm ci (依存関係のインストール)
│ COPY . . (ソースコード)
変更頻度が高い ─── RUN npm run build (ビルド)
5.5 Buildah を活用したスクリプトベースのビルド
Buildah は Dockerfile なしでシェルスクリプトからイメージをビルドできる強力なツールだ。
#!/bin/bash
# buildah-build.sh — Dockerfile なしでイメージをビルド
# 新しいコンテナを生成 (空のイメージから開始)
container=$(buildah from scratch)
# またはベースイメージから開始
container=$(buildah from alpine:3.19)
# パッケージのインストール
buildah run $container -- apk add --no-cache nginx
# ファイルのコピー
buildah copy $container ./nginx.conf /etc/nginx/nginx.conf
buildah copy $container ./html /var/www/html
# 設定
buildah config --port 80 $container
buildah config --entrypoint '["/usr/sbin/nginx", "-g", "daemon off;"]' $container
buildah config --author "DevOps Team" $container
buildah config --label maintainer="devops@example.com" $container
# イメージとしてコミット
buildah commit $container myapp:latest
# 後片付け
buildah rm $container
# ビルド結果の確認
buildah images
5.6 Skopeo を活用したイメージのコピー/検査
Skopeo はイメージをダウンロードせずにレジストリ間で直接コピーしたり検査したりできる。
# レジストリ間でイメージを直接コピー (ローカルへのダウンロードなし!)
skopeo copy docker://docker.io/nginx:latest docker://quay.io/myorg/nginx:latest
# イメージのメタデータを検査 (ダウンロードなし)
skopeo inspect docker://docker.io/library/nginx:latest
# イメージのタグ一覧を確認
skopeo list-tags docker://docker.io/library/nginx
# イメージをローカルディレクトリに保存 (OCI形式)
skopeo copy docker://nginx:latest oci:./nginx-oci:latest
# イメージをtarファイルとして保存
skopeo copy docker://nginx:latest docker-archive:./nginx.tar:nginx:latest
# Private レジストリに認証してコピー
skopeo copy --src-creds user:pass --dest-creds user:pass \
docker://source-registry.com/app:v1 \
docker://dest-registry.com/app:v1
# イメージの削除 (レジストリから)
skopeo delete docker://myregistry.com/myapp:old-tag
6. コンテナライフサイクルのコマンド
6.1 コンテナの生成 (Create)
create はコンテナを生成するだけで起動はしない。あとから start で起動できる。
# コンテナの生成 (起動はしない)
docker create --name my-nginx nginx:latest
podman create --name my-nginx nginx:latest
# 生成されたコンテナの確認
docker ps -a
podman ps -a
# 生成されたコンテナの起動
docker start my-nginx
podman start my-nginx
6.2 コンテナの実行 (Run) — 主要オプションの総まとめ
run は create + start を一度に行う。コンテナ運用でもっとも頻繁に使うコマンドだ。
# ============================================
# 基本の実行
# ============================================
docker run nginx
podman run nginx
# ============================================
# バックグラウンド実行 (-d: detach)
# ============================================
docker run -d --name web nginx
podman run -d --name web nginx
# ============================================
# インタラクティブモード (-it: interactive + tty)
# ============================================
docker run -it ubuntu:22.04 bash
podman run -it ubuntu:22.04 bash
# ============================================
# 終了時に自動削除 (--rm)
# ============================================
docker run --rm -it alpine sh
podman run --rm -it alpine sh
# ============================================
# ポートマッピング (-p host:container)
# ============================================
docker run -d -p 8080:80 nginx # 特定のポート
docker run -d -p 80:80 -p 443:443 nginx # 複数ポート
docker run -d -p 127.0.0.1:8080:80 nginx # 特定のインターフェース
docker run -d -P nginx # ランダムポートの自動マッピング
podman run -d -p 8080:80 nginx
# ============================================
# ボリュームマウント (-v host:container[:options])
# ============================================
docker run -d -v /host/data:/container/data nginx # Bind mount
docker run -d -v myvolume:/container/data nginx # Named volume
docker run -d -v /host/data:/container/data:ro nginx # Read-only
docker run -d --mount type=tmpfs,destination=/tmp nginx # tmpfs
podman run -d -v /host/data:/container/data:Z nginx # SELinux ラベル (:Z)
# ============================================
# 環境変数 (-e, --env-file)
# ============================================
docker run -d -e MYSQL_ROOT_PASSWORD=secret mysql:8
docker run -d -e DB_HOST=db -e DB_PORT=5432 myapp
docker run -d --env-file .env myapp
podman run -d -e MYSQL_ROOT_PASSWORD=secret mysql:8
# ============================================
# リソース制限 (--memory, --cpus)
# ============================================
docker run -d --memory 512m --memory-swap 1g nginx
docker run -d --cpus 1.5 nginx
docker run -d --cpus 2 --memory 1g --memory-reservation 512m myapp
podman run -d --memory 512m --cpus 1.5 nginx
# ============================================
# 再起動ポリシー (--restart)
# ============================================
docker run -d --restart always nginx # 常に再起動
docker run -d --restart unless-stopped nginx # 手動停止を除いて再起動
docker run -d --restart on-failure:5 nginx # 失敗時に最大5回まで再起動
docker run -d --restart no nginx # 再起動しない (デフォルト)
podman run -d --restart always nginx
# ============================================
# ネットワーク設定 (--network)
# ============================================
docker run -d --network my-network nginx
docker run -d --network host nginx # ホストネットワークを直接使用
docker run -d --network none nginx # ネットワークなし
podman run -d --network my-network nginx
# ============================================
# PID / IPC ネームスペースの共有
# ============================================
docker run -d --pid host nginx # ホストのPIDネームスペース
docker run -d --pid container:other nginx # 他のコンテナのPIDを共有
docker run -d --ipc host nginx # ホストのIPCを共有
# ============================================
# その他の便利なオプション
# ============================================
docker run -d --hostname myhost nginx # ホスト名の設定
docker run -d --dns 8.8.8.8 nginx # DNSサーバーの指定
docker run -d --add-host mydb:10.0.0.5 nginx # /etc/hosts エントリの追加
docker run -d --workdir /app myapp # 作業ディレクトリ
docker run -d --user 1000:1000 myapp # 実行ユーザーの指定
docker run -d --read-only myapp # 読み取り専用ファイルシステム
docker run -d --log-driver json-file \
--log-opt max-size=10m --log-opt max-file=3 nginx # ログドライバの設定
6.3 コンテナ一覧 (ps)
# 実行中のコンテナ一覧
docker ps
podman ps
# すべてのコンテナ (停止中も含む)
docker ps -a
podman ps -a
# 直近に生成されたコンテナ n 個
docker ps -n 5
podman ps -n 5
# コンテナIDのみ出力
docker ps -q
podman ps -q
# カスタムフォーマット
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
podman ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
# 特定の状態でフィルタリング
docker ps -f status=exited
docker ps -f status=running
docker ps -f name=web
podman ps -f status=exited
6.4 コンテナの起動/停止/再起動
# コンテナの起動
docker start my-nginx
podman start my-nginx
# 複数コンテナの同時起動
docker start web db redis
podman start web db redis
# コンテナの停止 (SIGTERM → 10秒後に SIGKILL)
docker stop my-nginx
podman stop my-nginx
# タイムアウトの指定 (30秒後に強制終了)
docker stop -t 30 my-nginx
podman stop -t 30 my-nginx
# 実行中のコンテナをすべて停止
docker stop $(docker ps -q)
podman stop -a
# コンテナの強制終了 (SIGKILL)
docker kill my-nginx
podman kill my-nginx
# 特定シグナルの送信
docker kill -s SIGHUP my-nginx
podman kill -s SIGHUP my-nginx
# コンテナの再起動
docker restart my-nginx
podman restart my-nginx
# すべてのコンテナを再起動
docker restart $(docker ps -q)
podman restart -a
6.5 コンテナの一時停止/再開
# コンテナの一時停止 (SIGSTOP — プロセスの freeze)
docker pause my-nginx
podman pause my-nginx
# 一時停止の解除 (SIGCONT)
docker unpause my-nginx
podman unpause my-nginx
6.6 コンテナの削除
# 停止中のコンテナを削除
docker rm my-nginx
podman rm my-nginx
# 実行中のコンテナを強制削除
docker rm -f my-nginx
podman rm -f my-nginx
# ボリュームも一緒に削除
docker rm -v my-nginx
podman rm -v my-nginx
# 停止中のコンテナをすべて削除
docker container prune -f
podman container prune -f
# すべてのコンテナを削除 (実行中も含む)
docker rm -f $(docker ps -aq)
podman rm -f -a
6.7 コンテナのリネーム / コミット / 待機
# コンテナのリネーム
docker rename old-name new-name
podman rename old-name new-name
# コンテナをイメージとして保存 (現在の状態をスナップショット)
docker commit my-container myimage:snapshot
podman commit my-container myimage:snapshot
# コミット時にメタデータを追加
docker commit -m "Added config files" -a "Author" my-container myimage:v2
podman commit -m "Added config files" -a "Author" my-container myimage:v2
# コンテナの終了を待機 (exit code を返す)
docker wait my-container
podman wait my-container
7. コンテナの監視とデバッグ
7.1 ログの確認 (Logs)
# ログ全体を出力
docker logs my-container
podman logs my-container
# リアルタイムのログストリーミング (follow)
docker logs -f my-container
podman logs -f my-container
# 末尾 N 行のみ表示
docker logs --tail 100 my-container
podman logs --tail 100 my-container
# タイムスタンプを含める
docker logs -t my-container
podman logs -t my-container
# 指定時刻以降のログ
docker logs --since 2024-01-01T00:00:00 my-container
docker logs --since 30m my-container # 直近30分
docker logs --since 2h my-container # 直近2時間
podman logs --since 30m my-container
# 指定時刻より前のログ
docker logs --until 2024-01-01T12:00:00 my-container
podman logs --until 2024-01-01T12:00:00 my-container
# 組み合わせ: リアルタイム + 末尾50行 + タイムスタンプ
docker logs -f --tail 50 -t my-container
podman logs -f --tail 50 -t my-container
7.2 リソースのリアルタイム監視 (Stats)
# 実行中の全コンテナのリソース使用量をリアルタイム表示
docker stats
podman stats
# 特定のコンテナのみ監視
docker stats my-container
podman stats my-container
# 一度だけ出力 (スクリプト用)
docker stats --no-stream
podman stats --no-stream
# カスタムフォーマット
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"
podman stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"
出力例:
NAME CPU % MEM USAGE / LIMIT NET I/O BLOCK I/O
web 0.50% 45.2MiB / 512MiB 12.5kB / 8.3kB 4.1MB / 0B
db 2.30% 256MiB / 1GiB 45.2kB / 12.1kB 50MB / 120MB
redis 0.10% 12.5MiB / 256MiB 3.2kB / 1.1kB 0B / 0B
7.3 プロセスの確認 (Top)
# コンテナ内部のプロセス一覧
docker top my-container
podman top my-container
# ps オプションの受け渡し
docker top my-container -aux
podman top my-container -aux
# Podman 専用: 追加フィールドに対応
podman top my-container user pid ppid args %cpu %mem
podman top my-container huser hpid
7.4 詳細情報の確認 (Inspect)
# コンテナの全情報 (JSON)
docker inspect my-container
podman inspect my-container
# IPアドレスの確認
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-container
podman inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-container
# マウント情報の確認
docker inspect -f '{{json .Mounts}}' my-container | jq .
podman inspect -f '{{json .Mounts}}' my-container | jq .
# 状態の確認
docker inspect -f '{{.State.Status}}' my-container
podman inspect -f '{{.State.Status}}' my-container
# 再起動回数の確認
docker inspect -f '{{.RestartCount}}' my-container
# 環境変数の確認
docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' my-container
podman inspect -f '{{range .Config.Env}}{{println .}}{{end}}' my-container
# ログパスの確認 (Docker)
docker inspect -f '{{.LogPath}}' my-container
7.5 ファイルのコピー (cp)
# ホスト → コンテナ
docker cp ./config.yml my-container:/app/config.yml
podman cp ./config.yml my-container:/app/config.yml
# コンテナ → ホスト
docker cp my-container:/app/logs/error.log ./error.log
podman cp my-container:/app/logs/error.log ./error.log
# ディレクトリのコピー
docker cp ./configs/ my-container:/app/configs/
podman cp ./configs/ my-container:/app/configs/
# アーカイブモード (シンボリックリンクを保持)
docker cp -a my-container:/app/data ./backup/
podman cp -a my-container:/app/data ./backup/
7.6 コンテナへの接続 (Exec)
実行中のコンテナ内部でコマンドを実行する、中心的なデバッグ手段だ。
# インタラクティブシェルで接続
docker exec -it my-container bash
docker exec -it my-container sh # bash がない場合 (Alpine など)
podman exec -it my-container bash
# 単一コマンドの実行
docker exec my-container ls -la /app
podman exec my-container ls -la /app
# 環境変数を設定してから実行
docker exec -e DEBUG=true my-container node script.js
podman exec -e DEBUG=true my-container node script.js
# 特定のユーザーで実行
docker exec -u root my-container apt-get update
podman exec -u root my-container dnf update
# 作業ディレクトリの指定
docker exec -w /app my-container npm test
podman exec -w /app my-container npm test
# バックグラウンドでコマンドを実行 (detach)
docker exec -d my-container touch /tmp/healthcheck
podman exec -d my-container touch /tmp/healthcheck
7.7 コンテナの変更点 (Diff)
# コンテナのファイルシステムの変更点を確認
docker diff my-container
podman diff my-container
# 出力例:
# A /tmp/new-file (Added)
# C /etc/nginx/nginx.conf (Changed)
# D /var/log/old.log (Deleted)
7.8 ポートマッピングの確認 (Port)
# コンテナのポートマッピングを確認
docker port my-container
podman port my-container
# 特定ポートの確認
docker port my-container 80
podman port my-container 80
# 出力例:
# 80/tcp -> 0.0.0.0:8080
# 443/tcp -> 0.0.0.0:8443
7.9 イベントの監視 (Events)
# リアルタイムのイベントストリーミング
docker events
podman events
# 特定イベントタイプのフィルタ
docker events --filter event=start
docker events --filter event=stop
docker events --filter event=die
podman events --filter event=start
# 特定コンテナのイベントのみフィルタ
docker events --filter container=my-container
podman events --filter container=my-container
# 時間範囲の指定
docker events --since 1h --until 30m
podman events --since 1h
# JSON形式で出力
docker events --format '{{json .}}'
podman events --format json
8. ネットワーク管理
8.1 ネットワークの種類
| ネットワークドライバ | 説明 | Docker | Podman |
|---|---|---|---|
| bridge | デフォルトのネットワーク、仮想ブリッジ経由でのコンテナ間通信 | docker0 (デフォルトブリッジ) | Netavark (v4+) / CNI |
| host | ホストネットワークを直接使用、ポートマッピング不要 | 対応 | 対応 |
| none | ネットワークなし、完全に隔離 | 対応 | 対応 |
| macvlan | コンテナにMACアドレスを割り当て、物理ネットワークへ直接接続 | 対応 | 対応 |
| overlay | マルチホストネットワーク (Swarm) | 対応 | 非対応 |
| ipvlan | macvlanに似ているが同じMACを共有 | 対応 | 対応 |
8.2 ネットワークのCRUDコマンド
# ============================================
# ネットワークの生成 (Create)
# ============================================
# 基本の bridge ネットワークを生成
docker network create my-network
podman network create my-network
# サブネットとゲートウェイの指定
docker network create \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
my-network
podman network create \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
my-network
# IP範囲の指定
docker network create \
--subnet 172.20.0.0/16 \
--ip-range 172.20.240.0/20 \
--gateway 172.20.0.1 \
my-network
# 内部ネットワーク (外部からアクセス不可)
docker network create --internal internal-net
podman network create --internal internal-net
# 特定ドライバの指定
docker network create --driver macvlan \
--subnet 192.168.1.0/24 \
--gateway 192.168.1.1 \
-o parent=eth0 \
macvlan-net
# ============================================
# ネットワーク一覧 (List)
# ============================================
docker network ls
podman network ls
# ============================================
# ネットワークの詳細情報 (Inspect)
# ============================================
docker network inspect my-network
podman network inspect my-network
# 接続されているコンテナの確認
docker network inspect -f '{{range .Containers}}{{.Name}} {{end}}' my-network
# ============================================
# ネットワークの削除 (Remove)
# ============================================
docker network rm my-network
podman network rm my-network
# 未使用ネットワークの整理
docker network prune -f
podman network prune -f
8.3 ネットワークへの接続/切断
# 実行中のコンテナをネットワークに接続
docker network connect my-network my-container
podman network connect my-network my-container
# 固定IPで接続
docker network connect --ip 172.20.0.10 my-network my-container
podman network connect --ip 172.20.0.10 my-network my-container
# ネットワークから切り離す
docker network disconnect my-network my-container
podman network disconnect my-network my-container
8.4 コンテナ間通信の例
ユーザー定義ネットワークでは、コンテナ名でのDNS解決が自動的に行われる。
# ユーザー定義ネットワークの生成
docker network create app-net
podman network create app-net
# データベースコンテナ
docker run -d --name db --network app-net \
-e POSTGRES_PASSWORD=secret \
postgres:16-alpine
# アプリケーションコンテナ (DBに名前で接続できる)
docker run -d --name app --network app-net \
-e DATABASE_URL="postgresql://postgres:secret@db:5432/mydb" \
-p 3000:3000 \
myapp:latest
# テスト: app コンテナから db へ ping
docker exec app ping -c 3 db
# PING db (172.20.0.2): 56 data bytes
# 64 bytes from 172.20.0.2: icmp_seq=0 ttl=64 time=0.123 ms
注意: Docker/Podman のデフォルトの
bridgeネットワークでは、コンテナ名でのDNS解決が行われない。コンテナ名で通信するには、必ずユーザー定義ネットワーク(user-defined network) を生成しなければならない。
8.5 Docker: docker0 bridge vs Podman: Netavark/CNI
Dockerはデフォルトで docker0 という Linux bridge インターフェースを生成し、iptables ルールでネットワークを管理する。
Podmanはv4.0からデフォルトのネットワークスタックを CNI(Container Network Interface) から Netavark へ切り替えた。NetavarkはRustで書かれたコンテナネットワークスタックで、Aardvark-dns とともにDNS解決を提供する。
# Podman のネットワークバックエンドを確認
podman info --format '{{.Host.NetworkBackend}}'
# 出力: netavark
# Netavark + Aardvark-dns の構成:
# ┌──────────────┐ ┌──────────────┐
# │ Container A │ │ Container B │
# │ 172.20.0.2 │ │ 172.20.0.3 │
# └──────┬───────┘ └──────┬───────┘
# │ │
# ┌──────▼─────────────────────▼──────┐
# │ Netavark Bridge │
# │ (nftables基盤のネットワーク管理) │
# ├───────────────────────────────────┤
# │ Aardvark-dns │
# │ (コンテナ名 → IP 解決) │
# └───────────────────────────────────┘
9. ボリュームとストレージの管理
9.1 Named Volume の管理
# ============================================
# ボリュームの生成
# ============================================
docker volume create my-data
podman volume create my-data
# ドライバとオプションの指定
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/path/to/share \
nfs-volume
# ラベルの追加
docker volume create --label project=myapp --label env=prod my-data
podman volume create --label project=myapp --label env=prod my-data
# ============================================
# ボリューム一覧
# ============================================
docker volume ls
podman volume ls
# フィルタリング
docker volume ls -f label=project=myapp
podman volume ls -f label=project=myapp
# Dangling ボリューム (コンテナに接続されていないもの)
docker volume ls -f dangling=true
podman volume ls -f dangling=true
# ============================================
# ボリュームの詳細情報
# ============================================
docker volume inspect my-data
podman volume inspect my-data
# マウントポイントの確認
docker volume inspect -f '{{.Mountpoint}}' my-data
podman volume inspect -f '{{.Mountpoint}}' my-data
# ============================================
# ボリュームの削除
# ============================================
docker volume rm my-data
podman volume rm my-data
# 未使用ボリュームの整理
docker volume prune -f
podman volume prune -f
9.2 Bind Mount vs Named Volume vs tmpfs
| 比較項目 | Bind Mount | Named Volume | tmpfs |
|---|---|---|---|
| ホストパス | 直接指定 | Docker/Podmanが管理 | なし (メモリ) |
| データの永続性 | ホストに永続保存 | ボリュームに永続保存 | コンテナ終了時に削除 |
| 性能 | ホストFSに依存 | 最適化が可能 | 最高 (メモリベース) |
| 可搬性 | 低い (ホストパスに依存) | 高い | 高い |
| バックアップ | 直接管理 | docker volume コマンド | 不可 |
| 使用例 | ソースコードのマウント、設定ファイル | DBデータ、アップロードファイル | 一時ファイル、シークレット |
# Bind Mount
docker run -d -v /home/user/data:/app/data nginx
docker run -d --mount type=bind,source=/home/user/data,target=/app/data nginx
# Named Volume
docker run -d -v app-data:/app/data nginx
docker run -d --mount type=volume,source=app-data,target=/app/data nginx
# tmpfs (メモリベース、コンテナ終了時に削除)
docker run -d --tmpfs /tmp:rw,size=100m nginx
docker run -d --mount type=tmpfs,destination=/tmp,tmpfs-size=100m nginx
# 読み取り専用マウント
docker run -d -v /host/config:/app/config:ro nginx
docker run -d --mount type=bind,source=/host/config,target=/app/config,readonly nginx
# PodmanでのSELinuxラベル設定
podman run -d -v /host/data:/app/data:Z nginx # Z: プライベートラベル
podman run -d -v /host/data:/app/data:z nginx # z: 共有ラベル
9.3 データのバックアップ/復元パターン
# ============================================
# ボリュームデータのバックアップ
# ============================================
# 方法1: 一時コンテナを使ったバックアップ
docker run --rm \
-v my-data:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/my-data-backup.tar.gz -C /source .
podman run --rm \
-v my-data:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/my-data-backup.tar.gz -C /source .
# 方法2: 日付別バックアップ
docker run --rm \
-v postgres-data:/source:ro \
-v $(pwd)/backups:/backup \
alpine tar czf /backup/postgres-$(date +%Y%m%d).tar.gz -C /source .
# ============================================
# ボリュームデータの復元
# ============================================
# 新しいボリュームを作成してから復元
docker volume create restored-data
docker run --rm \
-v restored-data:/target \
-v $(pwd):/backup:ro \
alpine tar xzf /backup/my-data-backup.tar.gz -C /target
podman run --rm \
-v restored-data:/target \
-v $(pwd):/backup:ro \
alpine tar xzf /backup/my-data-backup.tar.gz -C /target
# ============================================
# ボリューム間のデータ移行
# ============================================
docker run --rm \
-v old-volume:/from:ro \
-v new-volume:/to \
alpine sh -c "cp -a /from/. /to/"
10. Docker Compose vs Podman Compose
10.1 docker-compose.yml の基本構造
# docker-compose.yml (または compose.yml)
version: '3.9' # Compose ファイル形式のバージョン (v2では任意)
services:
web:
build: ./app # Dockerfile のパス
image: myapp:latest # ビルドされたイメージ名
container_name: myapp-web # コンテナ名
ports:
- '3000:3000' # ポートマッピング
environment: # 環境変数
- NODE_ENV=production
- DB_HOST=db
env_file: # 環境変数ファイル
- .env
volumes: # ボリュームマウント
- ./app:/app
- node_modules:/app/node_modules
depends_on: # 依存関係
db:
condition: service_healthy
redis:
condition: service_started
networks: # ネットワーク
- app-net
restart: unless-stopped # 再起動ポリシー
deploy: # リソース制限
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
healthcheck: # ヘルスチェック
test: ['CMD', 'curl', '-f', 'http://localhost:3000/health']
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
db:
image: postgres:16-alpine
container_name: myapp-db
environment:
POSTGRES_DB: myapp
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
volumes:
- postgres-data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- app-net
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U admin -d myapp']
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: myapp-redis
command: redis-server --appendonly yes --maxmemory 256mb
volumes:
- redis-data:/data
networks:
- app-net
volumes:
postgres-data:
driver: local
redis-data:
driver: local
node_modules:
networks:
app-net:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/16
10.2 主要な Compose コマンド
# ============================================
# Docker Compose (v2: docker compose / v1: docker-compose)
# ============================================
# サービスの起動 (バックグラウンド)
docker compose up -d
docker compose -f docker-compose.prod.yml up -d
# ビルドしてからサービスを起動
docker compose up -d --build
# 特定のサービスのみ起動
docker compose up -d web db
# スケーリング (サービスインスタンス数の調整)
docker compose up -d --scale web=3
# サービスの停止とリソースの整理
docker compose down
# ボリュームまで削除
docker compose down -v
# イメージまで削除
docker compose down --rmi all
# サービス一覧と状態
docker compose ps
# サービスのログ
docker compose logs
docker compose logs -f web
docker compose logs --tail 100 web db
# サービス内部でのコマンド実行
docker compose exec web bash
docker compose exec db psql -U admin -d myapp
# 一回限りのコマンド実行 (run は新しいコンテナを生成)
docker compose run --rm web npm test
docker compose run --rm web python manage.py migrate
# サービスのビルド
docker compose build
docker compose build --no-cache web
# サービスの再起動
docker compose restart
docker compose restart web
# 設定の妥当性検証
docker compose config
# イメージのプル
docker compose pull
# ============================================
# Podman Compose
# ============================================
# podman-compose のインストール
pip3 install podman-compose
# または Podman 4.7+ では podman compose (プラグイン方式)
# 使い方は docker compose と同じ
podman compose up -d
podman compose down
podman compose ps
podman compose logs -f web
podman compose exec web bash
10.3 実践例: Webアプリ + DB + Redis の3層構成
# compose.yml — プロダクションの3層アーキテクチャ
services:
# ============================================
# Tier 1: Reverse Proxy (Nginx)
# ============================================
nginx:
image: nginx:1.25-alpine
container_name: proxy
ports:
- '80:80'
- '443:443'
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
depends_on:
app:
condition: service_healthy
networks:
- frontend
restart: unless-stopped
# ============================================
# Tier 2: Application (Node.js)
# ============================================
app:
build:
context: ./app
dockerfile: Dockerfile
args:
NODE_ENV: production
container_name: app
expose:
- '3000'
environment:
- NODE_ENV=production
- DB_HOST=postgres
- DB_PORT=5432
- DB_NAME=appdb
- DB_USER=appuser
- DB_PASS=${DB_PASSWORD}
- REDIS_URL=redis://redis:6379
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- frontend
- backend
healthcheck:
test:
[
'CMD',
'node',
'-e',
"require('http').get('http://localhost:3000/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1) })",
]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: '2.0'
memory: 1G
restart: unless-stopped
# ============================================
# Tier 3: Database (PostgreSQL)
# ============================================
postgres:
image: postgres:16-alpine
container_name: postgres
environment:
POSTGRES_DB: appdb
POSTGRES_USER: appuser
POSTGRES_PASSWORD: ${DB_PASSWORD}
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- postgres-data:/var/lib/postgresql/data
- ./db/init:/docker-entrypoint-initdb.d:ro
networks:
- backend
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U appuser -d appdb']
interval: 10s
timeout: 5s
retries: 5
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
restart: unless-stopped
# ============================================
# Cache: Redis
# ============================================
redis:
image: redis:7-alpine
container_name: redis
command: >
redis-server
--appendonly yes
--maxmemory 256mb
--maxmemory-policy allkeys-lru
--requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
networks:
- backend
healthcheck:
test: ['CMD', 'redis-cli', '-a', '${REDIS_PASSWORD}', 'ping']
interval: 10s
timeout: 5s
retries: 5
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
restart: unless-stopped
volumes:
postgres-data:
driver: local
redis-data:
driver: local
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 外部からのアクセスを遮断
10.4 環境別の構成 (Override)
# compose.override.yml — 開発環境 (自動ロード)
services:
app:
build:
args:
NODE_ENV: development
volumes:
- ./app/src:/app/src # ソースコードのホットリロード
environment:
- NODE_ENV=development
- DEBUG=app:*
ports:
- '3000:3000' # 開発時に直接アクセス
- '9229:9229' # Node.js デバッガのポート
postgres:
ports:
- '5432:5432' # 開発時に直接アクセス
# compose.prod.yml — プロダクション環境
services:
app:
build:
args:
NODE_ENV: production
deploy:
replicas: 3
resources:
limits:
cpus: '4.0'
memory: 2G
nginx:
deploy:
resources:
limits:
cpus: '1.0'
memory: 256M
# 開発環境 (compose.yml + compose.override.yml を自動マージ)
docker compose up -d
# プロダクション環境 (override を除外し prod 設定を使用)
docker compose -f compose.yml -f compose.prod.yml up -d
# 環境別の .env ファイルを使用
docker compose --env-file .env.production up -d
11. Podman 固有の機能
11.1 Pod の管理
PodmanのPodはKubernetesのPodと同じ概念だ。ひとつのPodの中にあるコンテナ同士はNetwork namespace、IPC namespace、PID namespaceを共有する。
# ============================================
# Pod の生成
# ============================================
# 基本の Pod を生成
podman pod create --name my-pod
# ポートマッピング付きで生成 (Pod レベルでポートを定義)
podman pod create --name web-pod -p 8080:80 -p 8443:443
# ネットワークの指定
podman pod create --name web-pod --network my-network
# ============================================
# Pod へのコンテナ追加
# ============================================
# Pod の中でコンテナを実行 (--pod オプション)
podman run -d --pod my-pod --name nginx nginx:latest
podman run -d --pod my-pod --name php php:8.2-fpm
# Pod 内のコンテナ同士は localhost で通信できる
# nginx → localhost:9000 → php-fpm
# ============================================
# Pod の管理
# ============================================
# Pod の一覧
podman pod list
podman pod ps
# Pod の詳細情報
podman pod inspect my-pod
# Pod の起動/停止/再起動
podman pod start my-pod
podman pod stop my-pod
podman pod restart my-pod
# Pod の一時停止/再開
podman pod pause my-pod
podman pod unpause my-pod
# Pod の削除 (コンテナも含む)
podman pod rm my-pod
podman pod rm -f my-pod # 強制削除
# すべての Pod を削除
podman pod rm -a -f
# Pod のプロセス確認
podman pod top my-pod
# Pod のリソース使用量
podman pod stats my-pod
11.2 Kubernetes YAML の生成 (podman generate kube)
ローカルでテストしたコンテナ/Pod構成を、Kubernetes YAMLへ自動変換できる。
# コンテナから K8s YAML を生成
podman generate kube my-container > deployment.yaml
# Pod から K8s YAML を生成
podman generate kube my-pod > pod.yaml
# Service 情報も含める
podman generate kube --service my-pod > pod-with-service.yaml
# 生成される YAML の例:
# apiVersion: v1
# kind: Pod
# metadata:
# name: my-pod
# spec:
# containers:
# - name: nginx
# image: nginx:latest
# ports:
# - containerPort: 80
# hostPort: 8080
# - name: php
# image: php:8.2-fpm
11.3 Kubernetes YAML の実行 (podman play kube)
逆に、Kubernetes YAML ファイルを Podman で直接実行することもできる。
# K8s YAML ファイルから Pod を生成
podman play kube deployment.yaml
# ConfigMap に対応
podman play kube pod.yaml --configmap configmap.yaml
# シークレットに対応
podman play kube pod.yaml --seccomp-profile-root ./profiles
# 既存リソースの置き換え (更新)
podman play kube --replace pod.yaml
# リソースの削除
podman play kube --down pod.yaml
# ビルドも含める
podman play kube --build pod.yaml
11.4 Systemd サービスの生成
# コンテナを systemd サービスとして生成
podman generate systemd --name my-container > ~/.config/systemd/user/my-container.service
# 新しい設定の反映 (ユーザーレベル)
systemctl --user daemon-reload
systemctl --user enable my-container.service
systemctl --user start my-container.service
# Pod を systemd サービスとして生成
podman generate systemd --name my-pod --files
# → pod-my-pod.service, container-nginx.service, container-php.service が生成される
# オプション
podman generate systemd --name my-container \
--restart-policy always \
--time 30 \
--new # 起動時に新しいコンテナを生成 (推奨)
11.5 Quadlet: systemd ネイティブなコンテナ管理
Podman 4.4+ で導入された Quadlet は、systemd unit ファイル形式でコンテナを宣言的に管理する方式だ。
# ~/.config/containers/systemd/webapp.container
[Unit]
Description=My Web Application
After=network-online.target
[Container]
Image=docker.io/library/nginx:latest
ContainerName=webapp
PublishPort=8080:80
Volume=webapp-data:/usr/share/nginx/html:ro
Environment=NGINX_WORKER_PROCESSES=auto
AutoUpdate=registry
HealthCmd=curl -f http://localhost/ || exit 1
HealthInterval=30s
[Service]
Restart=always
TimeoutStartSec=300
[Install]
WantedBy=default.target
# Quadlet ファイルを配置してから適用
# システムレベル: /etc/containers/systemd/
# ユーザーレベル: ~/.config/containers/systemd/
systemctl --user daemon-reload
systemctl --user start webapp.service
systemctl --user enable webapp.service
systemctl --user status webapp.service
# ログの確認
journalctl --user -u webapp.service -f
11.6 Rootless Containers の詳細
PodmanのrootlessコンテナはUser Namespaceを活用して、コンテナ内部のroot(UID 0)をホストの一般ユーザーのUIDにマッピングする。
# 現在のユーザーのUIDマッピングを確認
cat /etc/subuid
# user1:100000:65536
# → user1 はホストの UID 100000~165535 をコンテナ内部の UID として使う
cat /etc/subgid
# user1:100000:65536
# マッピングの構造:
# コンテナ UID 0 (root) → ホスト UID 100000 (一般ユーザー)
# コンテナ UID 1 → ホスト UID 100001
# コンテナ UID 65535 → ホスト UID 165535
# rootless 状態の確認
podman info --format '{{.Host.Security.Rootless}}'
# true
# rootless モードでの制約事項を確認
podman info | grep -A 5 rootless
# rootless コンテナの実行 (デフォルト)
podman run -d --name rootless-nginx -p 8080:80 nginx
# ホスト側でプロセスを確認 — root ではなく一般ユーザーとして動いている
ps aux | grep nginx
# user1 12345 ... nginx: master process
12. セキュリティ関連のコマンドと設定
12.1 Rootless モードの設定
# ============================================
# Docker Rootless モードの設定
# ============================================
# rootless Docker のインストール
curl -fsSL https://get.docker.com/rootless | sh
# 環境変数の設定 (~/.bashrc)
export PATH=$HOME/bin:$PATH
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
# rootless Docker の起動
systemctl --user start docker
systemctl --user enable docker
# ============================================
# Podman Rootless モードの設定 (デフォルトで有効)
# ============================================
# subuid/subgid の設定確認
grep $USER /etc/subuid /etc/subgid
# 設定がない場合は追加
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
# ネームスペースの移行 (既存イメージの再マッピング)
podman system migrate
12.2 Security Options
# ============================================
# Capability の管理
# ============================================
# すべての capability を削除してから必要なものだけ追加 (最小権限の原則)
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE nginx
podman run --cap-drop ALL --cap-add NET_BIND_SERVICE nginx
# デフォルトの capability を確認
docker run --rm alpine cat /proc/1/status | grep Cap
podman run --rm alpine cat /proc/1/status | grep Cap
# 主要な Capability の一覧:
# NET_BIND_SERVICE : 1024 未満のポートへのバインド
# SYS_PTRACE : プロセスのデバッグ (strace など)
# NET_RAW : RAW ソケットの使用 (ping など)
# CHOWN : ファイル所有権の変更
# DAC_OVERRIDE : ファイル権限の無視
# SETUID/SETGID : UID/GID の変更
# ============================================
# Security Options
# ============================================
# no-new-privileges: execve 時の権限昇格を防止
docker run --security-opt no-new-privileges:true myapp
podman run --security-opt no-new-privileges:true myapp
# Seccomp プロファイルの適用
docker run --security-opt seccomp=./custom-seccomp.json myapp
podman run --security-opt seccomp=./custom-seccomp.json myapp
# AppArmor プロファイル (Docker/Ubuntu)
docker run --security-opt apparmor=docker-default myapp
# SELinux ラベル (Podman/RHEL)
podman run --security-opt label=type:container_t myapp
podman run --security-opt label=disable myapp # SELinux を無効化
12.3 読み取り専用コンテナ
# ファイルシステムを読み取り専用に設定
docker run --read-only nginx
podman run --read-only nginx
# 書き込みが必要なディレクトリだけ tmpfs でマウント
docker run --read-only \
--tmpfs /tmp \
--tmpfs /var/run \
--tmpfs /var/cache/nginx \
nginx
podman run --read-only \
--tmpfs /tmp \
--tmpfs /var/run \
--tmpfs /var/cache/nginx \
nginx
12.4 イメージのセキュリティ検証
# ============================================
# Docker Content Trust (DCT)
# ============================================
# 署名済みイメージのみプル/実行を許可
export DOCKER_CONTENT_TRUST=1
docker pull nginx:latest # 署名が検証される
# イメージへの署名
docker trust sign myregistry.com/myapp:v1.0
# 署名の確認
docker trust inspect --pretty myregistry.com/myapp:v1.0
# ============================================
# Podman のイメージ署名 (GPGベース)
# ============================================
# 署名ポリシーファイルの確認
cat /etc/containers/policy.json
# GPGキーでイメージに署名
podman push --sign-by security@example.com myregistry.com/myapp:v1.0
# 署名ポリシーの設定例 (/etc/containers/policy.json)
# {
# "default": [{"type": "reject"}],
# "transports": {
# "docker": {
# "myregistry.com": [
# {
# "type": "signedBy",
# "keyType": "GPGKeys",
# "keyPath": "/etc/pki/rpm-gpg/RPM-GPG-KEY-myorg"
# }
# ],
# "docker.io": [{"type": "insecureAcceptAnything"}]
# }
# }
# }
# Skopeo を使ったイメージの完全性検証
skopeo inspect --raw docker://myregistry.com/myapp:v1.0 | jq .
12.5 セキュリティのベストプラクティス・チェックリスト
| 項目 | Docker のコマンド / 設定 | Podman のコマンド / 設定 |
|---|---|---|
| Root 実行の禁止 | USER nonroot in Dockerfile | デフォルトで rootless |
| Capability の最小化 | --cap-drop ALL --cap-add ... | --cap-drop ALL --cap-add ... |
| Read-only FS | --read-only | --read-only |
| 権限昇格の防止 | --security-opt no-new-privileges | --security-opt no-new-privileges |
| リソース制限 | --memory --cpus --pids-limit | --memory --cpus --pids-limit |
| ネットワーク隔離 | --network none / internal network | --network none / internal network |
| イメージ署名 | Docker Content Trust | GPG signing / sigstore |
| シークレット管理 | Docker Secrets / 環境変数 | Podman secrets / 環境変数 |
| ベースイメージ | distroless / scratch / alpine | distroless / scratch / alpine |
| イメージスキャン | docker scout / Trivy | Trivy / Grype |
13. システム管理と整理
13.1 ディスク使用量の確認 (system df)
# ディスク使用量のサマリ
docker system df
podman system df
# 詳細情報
docker system df -v
podman system df -v
# 出力例:
# TYPE TOTAL ACTIVE SIZE RECLAIMABLE
# Images 15 5 4.2GB 2.8GB (66%)
# Containers 8 3 120MB 80MB (66%)
# Local Volumes 10 4 1.5GB 800MB (53%)
# Build Cache 20 0 500MB 500MB (100%)
13.2 全体の整理 (system prune)
# 停止中のコンテナ + dangling イメージ + 未使用ネットワーク + ビルドキャッシュの整理
docker system prune
podman system prune
# 確認プロンプトなしで実行
docker system prune -f
podman system prune -f
# 未使用イメージまで含める (注意!)
docker system prune -a -f
podman system prune -a -f
# ボリュームまで含める (要注意! データを失う可能性がある)
docker system prune -a --volumes -f
podman system prune -a --volumes -f
# 一定期間以上経過したリソースのみ整理
docker system prune -a --filter "until=720h" -f # 30日以上
13.3 システム情報とバージョン
# システム全体の情報
docker info
podman info
# 主な確認項目:
# - Storage Driver
# - Cgroup Version (v1/v2)
# - Security Options
# - Kernel Version
# - OS/Architecture
# - Registry 設定
# バージョン情報
docker version
podman version
# クライアント/サーバーのバージョンを個別に確認
docker version --format '{{.Client.Version}}'
docker version --format '{{.Server.Version}}'
podman version --format '{{.Client.Version}}'
14. 実践チートシート: よく使うコマンド30選
以下は、コンテナ運用でもっとも頻繁に使う30のコマンドを一目で見られるようにまとめたテーブルだ。DockerとPodmanはどちらも同じ文法を使う。
| # | 操作 | コマンド |
|---|---|---|
| 1 | イメージのダウンロード | docker pull nginx:latest |
| 2 | イメージ一覧 | docker images |
| 3 | イメージの削除 | docker rmi nginx:latest |
| 4 | Dangling イメージの整理 | docker image prune -f |
| 5 | イメージのビルド | docker build -t myapp:latest . |
| 6 | コンテナの実行 (バックグラウンド) | docker run -d --name web -p 80:80 nginx |
| 7 | コンテナの実行 (インタラクティブ) | docker run -it --rm alpine sh |
| 8 | 実行中コンテナの一覧 | docker ps |
| 9 | すべてのコンテナの一覧 | docker ps -a |
| 10 | コンテナの停止 | docker stop web |
| 11 | コンテナの起動 | docker start web |
| 12 | コンテナの再起動 | docker restart web |
| 13 | コンテナの削除 | docker rm web |
| 14 | コンテナの強制削除 | docker rm -f web |
| 15 | 停止中コンテナをすべて削除 | docker container prune -f |
| 16 | コンテナのログ | docker logs -f --tail 100 web |
| 17 | コンテナへの接続 (exec) | docker exec -it web bash |
| 18 | ファイルのコピー (ホスト→コンテナ) | docker cp file.txt web:/app/ |
| 19 | ファイルのコピー (コンテナ→ホスト) | docker cp web:/app/log.txt ./ |
| 20 | リソースの監視 | docker stats |
| 21 | 詳細情報 (JSON) | docker inspect web |
| 22 | ネットワークの生成 | docker network create my-net |
| 23 | ネットワーク一覧 | docker network ls |
| 24 | ボリュームの生成 | docker volume create my-vol |
| 25 | ボリューム一覧 | docker volume ls |
| 26 | Compose サービスの起動 | docker compose up -d |
| 27 | Compose サービスの停止 | docker compose down |
| 28 | レジストリへのログイン | docker login registry.example.com |
| 29 | イメージのプッシュ | docker push myregistry.com/app:v1 |
| 30 | システム全体の整理 | docker system prune -a -f |
Tip: 上のすべてのコマンドで
dockerをpodmanに置き換えれば、そのまま動作する。
15. トラブルシューティングガイド
15.1 権限関連の問題 (Permission Issues)
Docker: "permission denied while trying to connect to the Docker daemon socket"
# 原因: 現在のユーザーが docker グループに属していない
# 解決:
sudo usermod -aG docker $USER
newgrp docker # または再ログイン
# 確認
groups $USER
docker ps # エラーなく動作するはず
Podman Rootless: "Error: could not get runtime: cannot re-exec process"
# 原因: subuid/subgid が未設定
# 解決:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
# ネームスペースの移行
podman system migrate
# 確認
podman unshare cat /proc/self/uid_map
Podman Rootless: ボリュームマウントのパーミッション問題
# 原因: ホストとコンテナのUIDマッピングの不一致
# 方法1: unshare で所有権を変更
podman unshare chown 1000:1000 /host/path/data
# 方法2: :U オプションで自動UIDマッピング (Podman 4.0+)
podman run -v /host/data:/data:U myapp
# 方法3: SELinux ラベルの追加 (RHEL/CentOS)
podman run -v /host/data:/data:Z myapp
15.2 ネットワーク接続の問題
コンテナから外部ネットワークにアクセスできない
# DNS の確認
docker exec my-container cat /etc/resolv.conf
docker exec my-container nslookup google.com
# 解決1: DNSサーバーを直接指定
docker run --dns 8.8.8.8 --dns 8.8.4.4 myapp
# 解決2: iptables/nftables ルールの確認
sudo iptables -L -n -t nat
sudo nft list ruleset
# 解決3: IPフォワーディングの有効化
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
# 永続設定: /etc/sysctl.conf に net.ipv4.ip_forward=1 を追加
コンテナ間で名前による通信ができない場合
# 原因: デフォルトの bridge ネットワークを使用中 (DNS解決に非対応)
# 解決: ユーザー定義ネットワークを生成
docker network create my-net
docker run -d --network my-net --name db postgres:16
docker run -d --network my-net --name app \
-e DB_HOST=db myapp # これで "db" でアクセスできる
Podman rootless で 1024 未満のポートへのバインドが失敗する
# 原因: rootless モードではデフォルトで 1024 未満のポートを使えない
# 解決1: 1024 以上のポートを使う
podman run -d -p 8080:80 nginx
# 解決2: sysctl で unprivileged ポート範囲を変更
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
# 永続設定: /etc/sysctl.conf
# 解決3: rootful モードを使う
sudo podman run -d -p 80:80 nginx
15.3 ストレージ/ディスク容量の問題
"no space left on device" エラー
# ディスク使用量の確認
docker system df -v
podman system df -v
# 段階的な整理:
# 第1段階: 停止中のコンテナを削除
docker container prune -f
# 第2段階: Dangling イメージを削除
docker image prune -f
# 第3段階: 未使用ボリュームを削除 (注意: データを確認してから!)
docker volume prune -f
# 第4段階: ビルドキャッシュを削除
docker builder prune -f
# 第5段階: 全体の整理 (最後の手段)
docker system prune -a --volumes -f
# 一定期間以上経過したイメージのみ整理
docker image prune -a --filter "until=720h" -f # 30日以上
Podman のストレージパスの変更
# Rootless Podman のデフォルトのストレージ位置
# ~/.local/share/containers/storage/
# ストレージパスの変更: ~/.config/containers/storage.conf
# [storage]
# driver = "overlay"
# graphroot = "/mnt/large-disk/containers/storage"
# 変更後の移行
podman system reset # 注意: すべてのコンテナ/イメージが削除される
15.4 イメージビルドの失敗
Multi-platform ビルドのエラー (Docker)
# QEMU エミュレータのインストールが必要
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# buildx ビルダーの生成
docker buildx create --name multiarch --use
docker buildx inspect multiarch --bootstrap
# マルチプラットフォームビルド
docker buildx build --platform linux/amd64,linux/arm64 \
-t myapp:latest --push .
ビルドコンテキストが大きすぎる場合
# .dockerignore ファイルの作成
cat > .dockerignore << 'EOF'
.git
node_modules
dist
*.log
.env
.DS_Store
**/*.test.js
**/*.spec.js
coverage
.nyc_output
EOF
# ビルドコンテキストのサイズを確認
du -sh . --exclude=.git --exclude=node_modules
# 特定のパスだけをビルドコンテキストとして使う
docker build -f Dockerfile -t myapp . --build-context src=./src
15.5 一般的なデバッグパターン
# ============================================
# すぐに終了してしまうコンテナのデバッグ
# ============================================
# 終了時のログを確認
docker logs my-container
docker inspect -f '{{.State.ExitCode}}' my-container
docker inspect -f '{{.State.Error}}' my-container
# entrypoint を上書きしてシェルに入る
docker run -it --entrypoint sh myapp:latest
podman run -it --entrypoint sh myapp:latest
# ============================================
# ネットワークのデバッグ
# ============================================
# ネットワークデバッグ専用のコンテナ
docker run --rm -it --network container:target-container \
nicolaka/netshoot bash
# 特定のネットワークでデバッグ
docker run --rm -it --network my-net nicolaka/netshoot bash
# → nslookup, dig, curl, tcpdump, iperf3, netstat などが使える
# ============================================
# ファイルシステムのデバッグ
# ============================================
# コンテナのファイルシステムの変更点を確認
docker diff my-container
# コンテナのファイルシステムを tar で抽出して分析
docker export my-container | tar -tf - | head -50
# ============================================
# リソース制限の確認
# ============================================
# コンテナの cgroup 設定を確認
docker exec my-container cat /sys/fs/cgroup/memory.max
docker exec my-container cat /sys/fs/cgroup/cpu.max
# OOM Killed の確認
docker inspect -f '{{.State.OOMKilled}}' my-container
16. 参考資料とリファレンス
公式ドキュメント
- Docker 公式ドキュメント: https://docs.docker.com/
- Docker CLI Reference: https://docs.docker.com/engine/reference/commandline/cli/
- Docker Compose Reference: https://docs.docker.com/compose/compose-file/
- Dockerfile Reference: https://docs.docker.com/engine/reference/builder/
- Podman 公式ドキュメント: https://docs.podman.io/
- Podman CLI Reference: https://docs.podman.io/en/latest/Commands.html
- Buildah 公式ドキュメント: https://buildah.io/
- Skopeo 公式ドキュメント: https://github.com/containers/skopeo
OCI 標準
- OCI Image Spec: https://github.com/opencontainers/image-spec
- OCI Runtime Spec: https://github.com/opencontainers/runtime-spec
- OCI Distribution Spec: https://github.com/opencontainers/distribution-spec
セキュリティガイド
- CIS Docker Benchmark: https://www.cisecurity.org/benchmark/docker
- NIST Container Security Guide (SP 800-190): https://csrc.nist.gov/publications/detail/sp/800-190/final
- Docker Security Best Practices: https://docs.docker.com/engine/security/
- Podman Rootless Tutorial: https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md
関連プロジェクト
- containerd: https://containerd.io/
- CRI-O: https://cri-o.io/
- Netavark: https://github.com/containers/netavark
- Quadlet: https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html
- Podman Desktop: https://podman-desktop.io/