LabHub

ブログ

Docker & Podman コマンド完全ガイド: コンテナ運用のすべてを一枚にまとめる

한국어English日本語中文


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という三つのツールを開発した。

この三つのツールはそれぞれ独立して動作しながら、互いを補完する関係を形成する。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 1Container 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 1Container 2      │   │
    (child proc)       (child proc)     │   │
│                    └─────────────────────┴──────────────────┘   │
│                                                                 │
│  ✅ デーモンなし → SPOFなし                                    │
│  ✅ 各コンテナが独立プロセス → systemd統合が容易                │
│  ✅ Rootless を標準サポート                                     │
└─────────────────────────────────────────────────────────────────┘

conmon はコンテナのstdout/stderrをキャプチャし、コンテナのexit codeを記録し、Podman CLIが終了した後もコンテナを監視し続ける軽量なモニタープロセスだ。

2.3 中核となる比較テーブル

比較項目DockerPodman
アーキテクチャClient-Daemon (dockerd)Daemonless (fork-exec)
デフォルトの実行権限root (daemon)rootless (一般ユーザー)
OCIランタイムrunccrun (デフォルト)、runcも対応
イメージビルド内蔵 (BuildKit)Buildah連携
デーモンプロセス必須 (dockerd + containerd)なし
systemd統合限定的ネイティブ (Quadlet)
Podサポートなし (Composeで代替)ネイティブ対応
K8s YAML生成なしpodman generate kube
K8s YAML実行なしpodman play kube
SocketベースAPIdocker.sock (常時有効)podman.sock (必要時に有効)
コンテナモニターcontainerd-shimconmon
デフォルトレジストリdocker.io 単一複数レジストリ検索
ComposeサポートDocker Compose (公式)podman-compose / podman compose
ライセンスApache 2.0 + 商用(Desktop)Apache 2.0 (完全オープンソース)
セキュリティ機構AppArmor/SeccompSELinux/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 DesktopPodman Desktop
ライセンス250人以上の企業は有料 ($5+/user/month)完全無料 (Apache 2.0)
GUI豊富なUI基本的なUI (急速に改善中)
ExtensionDocker 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 --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
USER node
CMD ["node", "dist/main.js"]
項目DockerfileContainerfile
使用ツールDockerPodman, Buildah
文法同一同一
デフォルトのファイル名DockerfileContainerfile
相互互換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 --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# バイナリのみコピー
COPY --from=builder /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 --from=builder /custom-jre /opt/java
COPY --from=builder /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 --from=builder /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) — 主要オプションの総まとめ

runcreate + 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 ネットワークの種類

ネットワークドライバ説明DockerPodman
bridgeデフォルトのネットワーク、仮想ブリッジ経由でのコンテナ間通信docker0 (デフォルトブリッジ)Netavark (v4+) / CNI
hostホストネットワークを直接使用、ポートマッピング不要対応対応
noneネットワークなし、完全に隔離対応対応
macvlanコンテナにMACアドレスを割り当て、物理ネットワークへ直接接続対応対応
overlayマルチホストネットワーク (Swarm)対応非対応
ipvlanmacvlanに似ているが同じ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 MountNamed Volumetmpfs
ホストパス直接指定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 TrustGPG signing / sigstore
シークレット管理Docker Secrets / 環境変数Podman secrets / 環境変数
ベースイメージdistroless / scratch / alpinedistroless / scratch / alpine
イメージスキャンdocker scout / TrivyTrivy / 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
4Dangling イメージの整理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
26Compose サービスの起動docker compose up -d
27Compose サービスの停止docker compose down
28レジストリへのログインdocker login registry.example.com
29イメージのプッシュdocker push myregistry.com/app:v1
30システム全体の整理docker system prune -a -f

Tip: 上のすべてのコマンドで dockerpodman に置き換えれば、そのまま動作する。


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. 参考資料とリファレンス

公式ドキュメント

OCI 標準

セキュリティガイド

関連プロジェクト

コメント

まだコメントはありません。

ログインするとコメントできます