#0113（2025/05/01）Dockerのレイヤーとは

## はじめに

Dockerのレイヤー（Layer）は、コンテナ技術の根幹を支える重要な概念です。レイヤーを深く理解することで、ビルドの最適化やセキュリティ強化、効率的な運用が可能となり、上級エンジニアとしての腕が試されます。

---

## 1. レイヤーの基本構造

- **イメージ＝レイヤーの積み重ね**
  - 各命令（`RUN` / `COPY` / `ADD`）実行時の変更内容をスナップショットとして記録
  - 読み取り専用（immutable）で、再利用・キャッシュ効率に貢献
- **コンテナ＝イメージ＋書き込みレイヤー**
  - 创建時に一時的なWritable Layerが追加され、実行中のファイル変化を管理

### 1.1 Union File System

- OverlayFS, AUFS, btrfs などのストレージドライバを用いて複数のレイヤーを一つのファイルシステムとしてマウント
- 各レイヤーの`diff`ディレクトリを合成し、一貫したビューを提供

---

## 2. レイヤー保存場所と管理

### 2.1 デフォルトパス

```bash
/var/lib/docker/<storage-driver>/
```
- overlay2 の場合: `/var/lib/docker/overlay2/{ID}/diff`, `merged`, `work`

### 2.2 ストレージドライバの選択と特徴

| ドライバ    | 長所                           | 短所                         |
|------------|--------------------------------|------------------------------|
| overlay2   | カーネル標準、安定性高い       | カーネルバージョン依存       |
| aufs       | 柔軟なマージ                   | メンテナンス終了、非推奨     |
| btrfs      | スナップショット管理が得意     | 複雑なセットアップ           |
| zfs        | 高機能（圧縮・レプリケーション） | リソース消費大                |

---

## 3. レイヤー最適化テクニック

### 3.1 キャッシュ命中率向上

- 頻繁に変わらない命令はDockerfile上部に配置
- `apt-get update && apt-get install` を一つの`RUN`でまとめる

```Dockerfile
RUN apt-get update \
 && apt-get install -y --no-install-recommends \
    ca-certificates curl \
 && rm -rf /var/lib/apt/lists/*
```

### 3.2 マルチステージビルド

- ビルド用に大きな依存をインストールするステージと、最終ランタイムステージを分離
- イメージサイズを劇的に削減

```Dockerfile
FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o server

FROM scratch
COPY --from=builder /app/server /server
ENTRYPOINT ["/server"]
```

### 3.3 レイヤー数の抑制

- 不要な`RUN`命令を減らし、まとめる
- `--squash` オプションで中間レイヤーを一時的に結合（Docker Experimental）

---

## 4. レイヤーセキュリティ

- **最小権限原則**
  - 不要なパッケージを排除し、脆弱性を減少
  - `USER nonroot`で実行ユーザーを非rootに設定

- **脆弱性スキャン**
  - Trivy, Clair, Anchore などをCIに組み込み、イメージを自動検査

- **署名と検証**
  - Notary/TUFやCosignなどでイメージ署名・検証を実施

---

## 5. レイヤーの監視とトラブルシュート

### 5.1 レイヤーの可視化ツール

- `docker history` で各レイヤーのサイズ・命令を確認
- `dive` ツールでレイヤー内部のファイル構造とキャッシュ効率を分析

### 5.2 キャッシュミスの解析

- CIビルドでキャッシュが効かない場合の原因調査
  - コンテキストの不必要なファイルまでCOPYしていないか
  - ビルド引数や環境変数の変化をチェック

---

## 6. さらに深い領域：OCI仕様とBuildKit

### 6.1 OCI（Open Container Initiative）イメージ仕様

- **OCIイメージ仕様**は、コンテナイメージのプラットフォーム非依存フォーマットを定めるオープンスタンダード。
  - **マニフェスト（Manifest）**：層情報やメタデータ（プラットフォーム、アーキテクチャ、レイヤーダイジェスト）を記述
  - **レイヤーインデックス（Index）**：複数のマニフェストを参照し、マルチアーキテクチャイメージを実現
  - **Configオブジェクト**：コンテナ起動設定（環境変数、エントリポイント、ユーザー情報など）を保持

- **利点**：
  - ベンダーロックインの回避、異なるコンテナランタイム（Docker、containerd、CRI-Oなど）間の互換性を保証
  - プル／プッシュ時のHTTP APIやレイヤーのダウンロード形式を統一

### 6.2 Docker BuildKit

- **BuildKit**はDockerの次世代ビルドエンジンで、従来のビルドよりも高速・並列・キャッシュ効率に優れる
- **主な機能**：
  - **並列実行**：Dockerfile内の独立ステージやコマンドを並列処理
  - **高度キャッシュ制御**：ステージごとのキャッシュをリモートに保存・参照可能（リモートキャッシュプラグイン）
  - **実験的機能**：`--squash` や `--mount=type=cache` を使ったキャッシュマウント
  - **出力フォーマット**：標準OCI形式やDocker固有形式（`docker.io`、`oci-archive`、`docker-image`など）での出力切替

- **有効化方法**：
  1. Docker EngineでBuildKitを有効化
     ```bash
     export DOCKER_BUILDKIT=1
     ```
  2. `docker build` コマンドで利用
     ```bash
     docker build --progress=plain -t myapp .
     ```

### 6.3 Docker Buildx

- **Buildx**はBuildKitをベースにしたDocker公式ビルド拡張プラグイン
- **特徴**：
  - **マルチプラットフォームビルド**：異なるアーキテクチャ向けイメージを単一コマンドでビルド（例：`linux/amd64, linux/arm64`）
  - **カスタムビルダ**：複数ノードやクラウド上のビルダを使った分散ビルド
  - **イメージプッシュ**：ビルドと同時にレジストリへのプッシュをサポート
  - **Driver切替**：`docker-container`、`docker`、`ssh` など異なるドライバを選択可能

- **利用例**：
  ```bash
  # ビルダー作成
  docker buildx create --name multi-builder --use

  # マルチアーキテクチャビルド
  docker buildx build \
    --platform linux/amd64,linux/arm64 \
    --push \
    -t myrepo/myapp:latest .
  ```

---

## おわりに

Dockerのレイヤーを深く理解し、適切に設計・最適化・管理できることは、上級エンジニアとして欠かせないスキルです。本記事で紹介した技術を実践し、ぜひ自分のプロジェクトに役立ててください。さらにOCIやBuildKitに踏み込むことで、コンテナ運用の新たな可能性が広がります。