フリーキーズ | 独学プログラミング

DockerでAlpineを使う理由とは?レイヤー削減でイメージサイズを最適化する方法

リンドくん

リンドくん

たなべ先生、Dockerを勉強してるんですけど、「Alpine」っていうのをよく見かけます。これって何なんですか?

たなべ

たなべ

いい質問だね!Alpine Linuxは、Dockerイメージを作るときにサイズを小さくするために使われる軽量なLinuxディストリビューションなんだ。
今日はAlpineを使う理由と、イメージサイズを最適化するテクニックを教えるね。

プログラミング学習でお悩みの方へ

HackATAは、エンジニアを目指す方のためのプログラミング学習コーチングサービスです。 経験豊富な現役エンジニアがあなたの学習をサポートします。

✓ 質問し放題

✓ β版公開中(2025年内の特別割引)

HackATAの詳細を見る

Dockerイメージのサイズが重要な理由

Dockerを使い始めると、必ず直面するのが「イメージサイズ」の問題です。
特にクラウド環境で開発していると、イメージサイズの大きさがコストやパフォーマンスに直結してくるため、無視できない要素となります。

イメージサイズが大きいことによる具体的な問題点として、以下のようなものがあります。

  • デプロイ時間の増加 → イメージのダウンロードに時間がかかり、デプロイが遅くなる
  • ストレージコストの増加 → コンテナレジストリでの保存容量が増え、クラウドコストが上がる
  • ネットワーク帯域の消費 → イメージの転送で帯域を圧迫する
  • セキュリティリスクの増加 → 不要なパッケージが多いほど、脆弱性の対象が増える

これらの問題を解決するために、多くのエンジニアがAlpine Linuxを選択しているのです。実際、同じアプリケーションでもベースイメージを変えるだけで、イメージサイズが数百MBから数MBまで削減できることも珍しくありません。

では、具体的にAlpine Linuxとは何なのか、そしてなぜここまで人気なのかを見ていきましょう。

Alpine Linuxとは何か?その特徴を理解しよう

リンドくん

リンドくん

Alpine Linuxって普通のLinuxと何が違うんですか?

たなべ

たなべ

一番の違いはサイズの小ささだね。通常のLinuxディストリビューション(UbuntuやCentOSなど)は数百MBあるけど、Alpine Linuxはたった5MB程度なんだ。

Alpine Linuxの主な特徴

Alpine Linuxは、セキュリティ、シンプルさ、リソース効率を重視して設計された軽量Linuxディストリビューションです。
以下のような特徴があります。

  • 極めて小さいサイズ → ベースイメージがわずか5MB程度
  • muslライブラリの使用 → 一般的なglibcの代わりに軽量なmuslを採用
  • BusyBoxの採用 → 多くのUnixツールを一つにまとめた軽量ツールセット
  • apkパッケージマネージャ → 高速で効率的なパッケージ管理システム
  • セキュリティ重視 → 必要最小限のパッケージのみで脆弱性を減らす

他のベースイメージとのサイズ比較

実際のイメージサイズを比較してみましょう。

# 各ベースイメージのサイズ
ubuntu:latest      → 約77MB
debian:latest      → 約124MB
centos:latest      → 約231MB
alpine:latest      → 約5MB

この圧倒的な軽さが、Alpine Linuxが広く使われている最大の理由です。特にマイクロサービスアーキテクチャでは、多数のコンテナを同時に動かすため、一つ一つのイメージサイズが全体のパフォーマンスに大きく影響します。

Alpine Linuxを使う際の注意点

ただし、Alpine Linuxを使う際にはいくつか注意すべき点もあります。

  • 互換性の問題 → glibcを前提としたバイナリが動かない場合がある
  • パッケージの違い → apt/yumではなくapkを使う必要がある
  • ツールの不足 → デフォルトで入っているツールが少ない

これらの注意点を理解した上で使えば、Alpine Linuxは非常に強力な選択肢となります。

Alpineを使った基本的なDockerfile

リンドくん

リンドくん

実際にAlpineを使ったDockerfileってどう書くんですか?

たなべ

たなべ

基本的な書き方は他のベースイメージと変わらないよ。ただし、パッケージマネージャがapkになることと、いくつかのベストプラクティスがあるんだ。

シンプルなNode.jsアプリケーションの例

まずは基本的なDockerfileから見ていきましょう。

FROM node:20-alpine

# 作業ディレクトリの設定
WORKDIR /app

# package.jsonとpackage-lock.jsonをコピー
COPY package*.json ./

# 依存関係のインストール
RUN npm ci --only=production

# アプリケーションのソースコードをコピー
COPY . .

# アプリケーションの起動
CMD ["node", "index.js"]

このDockerfileは基本的な構造を持っていますが、まだ最適化の余地があります。次のセクションで、さらにサイズを削減するテクニックを見ていきましょう。

Pythonアプリケーションの例

Pythonの場合も同様にAlpineベースで作成できます。

FROM python:3.14-alpine

# 作業ディレクトリの設定
WORKDIR /app

# 必要なシステムパッケージのインストール
RUN apk add --no-cache gcc musl-dev

# requirements.txtをコピー
COPY requirements.txt .

# Pythonパッケージのインストール
RUN pip install --no-cache-dir -r requirements.txt

# アプリケーションのコピー
COPY . .

# アプリケーションの実行
CMD ["python", "app.py"]

このように、Alpine Linuxをベースにすることで、シンプルかつ軽量なDockerイメージを作成できます。

Dockerレイヤーの仕組みとレイヤー削減の重要性

リンドくん

リンドくん

「レイヤー」って何ですか?よく聞くんですけど...

たなべ

たなべ

Dockerイメージは複数の層(レイヤー)が重なってできているんだ。Dockerfile内の各命令(RUN、COPY など)が一つのレイヤーを作るんだよ。

レイヤーとは何か

Dockerイメージは、複数のレイヤー(層)が積み重なって構成されています。
各レイヤーは読み取り専用で、Dockerfileの命令ごとに新しいレイヤーが作成されます。

例えば、以下のようなDockerfileがあったとします。

FROM alpine:latest        # レイヤー1
RUN apk add --no-cache curl  # レイヤー2
RUN apk add --no-cache git   # レイヤー3
COPY app.js /app/         # レイヤー4

この場合、4つのレイヤーが作成されます。各レイヤーは前のレイヤーからの差分を保存するため、レイヤーが多いほどイメージサイズが大きくなる傾向があります。

レイヤーキャッシュのメリット

レイヤーにはキャッシュ機能があり、変更されていないレイヤーは再利用されます。
これにより、ビルド時間が短縮されるという大きなメリットがあります。

ただし、不要なレイヤーが増えすぎるとイメージサイズが肥大化するため、バランスが重要になってきます。

レイヤーを削減する基本テクニック

レイヤーを削減する最も基本的な方法は、複数のRUN命令を一つにまとめることです。

最適化前(レイヤーが多い)

FROM alpine:latest
RUN apk add --no-cache curl
RUN apk add --no-cache git
RUN apk add --no-cache vim

最適化後(レイヤーを削減)

FROM alpine:latest
RUN apk add --no-cache \
    curl \
    git \
    vim

この変更により、3つのレイヤーが1つにまとまり、イメージサイズが削減されます。

さらに重要なのは、不要なファイルを同じレイヤー内で削除することです。

効果の薄い例(別レイヤーで削除)

RUN apk add --no-cache wget
RUN rm -rf /tmp/*

この場合、最初のRUN命令で作成されたレイヤーは削除されず、サイズに含まれたままになります。

正しい例(同じレイヤー内で削除)

RUN apk add --no-cache wget && \
    # 何か処理 && \
    rm -rf /tmp/* && \
    apk del wget

このように、インストール、使用、削除を一つのRUN命令内で完結させることで、中間ファイルがレイヤーに残らず、サイズを削減できます。

マルチステージビルドで最適化する

リンドくん

リンドくん

もっと効率的にイメージを小さくする方法ってないんですか?

たなべ

たなべ

あるよ!それがマルチステージビルドなんだ。これを使うと、ビルド用のツールを最終イメージに含めずに済むから、劇的にサイズを削減できるんだよ。

マルチステージビルドとは

マルチステージビルドは、Dockerfileの中で複数のFROM命令を使って、段階的にイメージを構築する手法です。
これにより、ビルドに必要なツールや中間ファイルを最終イメージに含めずに済みます。

Go言語アプリケーションでの実践例

Go言語は、コンパイル後の実行ファイルが単独で動作するため、マルチステージビルドの効果が特に大きい言語です。

マルチステージビルドを使わない場合:

FROM golang:1.24-alpine
WORKDIR /app
COPY . .
RUN go build -o myapp
CMD ["./myapp"]

このイメージサイズは約300MBになります。

マルチステージビルドを使った場合:

# ビルドステージ
FROM golang:1.24-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

# 実行ステージ
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]

このイメージサイズは約10MBまで削減できます!

Node.jsアプリケーションでの実践例

Node.jsでも同様にマルチステージビルドが有効です。

# ビルドステージ
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
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
COPY package*.json ./
CMD ["node", "dist/index.js"]

この方法により、devDependenciesやソースコードなど、実行時に不要なファイルを最終イメージから除外できます。

マルチステージビルドのメリット

  • イメージサイズの大幅削減 → ビルドツールや中間ファイルが含まれない
  • セキュリティの向上 → 不要なツールが入っていないため攻撃対象が減る
  • ビルドプロセスの明確化 → ビルドと実行を明確に分離できる

マルチステージビルドは、本番環境でのDockerイメージ作成において、必須のテクニックと言えるでしょう。

実践的な最適化テクニック集

リンドくん

リンドくん

他にもイメージを小さくするコツってありますか?

たなべ

たなべ

もちろん!細かいテクニックがたくさんあるんだ。これらを組み合わせることで、さらに効率的なイメージが作れるよ。

.dockerignoreファイルの活用

.dockerignoreファイルを使うと、不要なファイルをビルドコンテキストから除外できます。
これにより、ビルド時間の短縮とイメージサイズの削減が可能になります。

# Git関連
.git
.gitignore

# ドキュメント
README.md
docs/

# 開発用ファイル
.env.local
.vscode/
*.log

# 依存関係(再インストールするため)
node_modules/
__pycache__/

# ビルド成果物(ビルドステージで作るため)
dist/
build/

パッケージキャッシュの削除

Alpine Linuxでは、apkコマンド実行後にキャッシュを削除することが重要です。

# 良くない例(キャッシュが残る)
RUN apk add --no-cache python3

# 良い例(--no-cacheオプションを使用)
RUN apk add --no-cache python3

# さらに明示的にキャッシュを削除する場合
RUN apk add python3 && \
    rm -rf /var/cache/apk/*

--no-cacheオプションを使うことで、パッケージインデックスのキャッシュが作成されず、イメージサイズを削減できます。

必要最小限のパッケージのみインストール

不要なパッケージをインストールしないことも重要です。

# 必要なパッケージだけをインストール
RUN apk add --no-cache \
    python3 \
    py3-pip

# ビルドツールは使用後に削除
RUN apk add --no-cache --virtual .build-deps \
    gcc \
    musl-dev \
    && pip install some-package \
    && apk del .build-deps

--virtualオプションを使うと、一時的にインストールしたパッケージをグループ化して、後でまとめて削除できます。

COPYの順序を最適化する

Dockerのレイヤーキャッシュを最大限活用するため、変更頻度の低いファイルから順にCOPYします。

# 最適化された順序
FROM node:18-alpine
WORKDIR /app

# 1. 依存関係定義ファイル(変更頻度: 低)
COPY package*.json ./
RUN npm ci --only=production

# 2. ソースコード(変更頻度: 高)
COPY . .

CMD ["node", "index.js"]

この順序により、ソースコードが変更されても、依存関係のインストール部分はキャッシュが利用され、ビルド時間が短縮されます。

実行ユーザーの指定

セキュリティのため、rootユーザーではなく専用ユーザーでアプリケーションを実行します。

FROM node:20-alpine

# 専用ユーザーの作成
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

WORKDIR /app

# ファイルのコピーと権限設定
COPY --chown=nodejs:nodejs . .

# ユーザーの切り替え
USER nodejs

CMD ["node", "index.js"]

これらのテクニックを組み合わせることで、サイズが小さく、セキュアで、効率的なDockerイメージを作成できます。

最適化の効果を測定する

リンドくん

リンドくん

最適化の効果ってどうやって確認すればいいんですか?

たなべ

たなべ

いくつか便利なコマンドがあるよ。イメージのサイズやレイヤー構造を確認することで、最適化の効果を数値で見ることができるんだ。

イメージサイズの確認

まず基本となるのが、イメージサイズの確認です。

# イメージ一覧とサイズの表示
docker images

# 特定のイメージのサイズを確認
docker images myapp:latest

レイヤー構造の詳細確認

docker historyコマンドで、各レイヤーのサイズを確認できます。

# イメージの履歴とレイヤーサイズを表示
docker history myapp:latest

# 人間が読みやすい形式で表示
docker history --human myapp:latest --no-trunc

このコマンドにより、どの命令でサイズが増加しているかが一目でわかります。

dive ツールによる詳細分析

より詳細な分析には、diveというツールが便利です。

# diveのインストール(macOSの場合)
brew install dive

# イメージの分析
dive myapp:latest

diveを使うと、各レイヤーの内容を視覚的に確認でき、無駄なファイルを見つけやすくなります。

最適化前後の比較例

実際の最適化効果を数値で見てみましょう。

# 最適化前
REPOSITORY    TAG       SIZE
myapp         v1        450MB

# 最適化後(Alpine + マルチステージビルド)
REPOSITORY    TAG       SIZE
myapp         v2        15MB

この例では、約430MBの削減(96%以上の削減率)を達成しています。クラウド環境では、この差が直接コストとパフォーマンスに反映されます。

まとめ

リンドくん

リンドくん

Alpine Linuxとレイヤー最適化、よくわかりました!早速試してみます!

たなべ

たなべ

素晴らしいね!最初から完璧を目指さなくても大丈夫。少しずつ最適化を進めていけば、確実にスキルアップできるよ。

この記事では、DockerでAlpine Linuxを使う理由と、イメージサイズを最適化するためのテクニックについて解説しました。

重要なポイントをおさらいすると、以下のようになります。

  • Alpine Linuxは軽量 → わずか5MB程度のベースイメージで、大幅なサイズ削減が可能
  • レイヤーの仕組みを理解 → 不要なレイヤーを減らし、同じレイヤー内でクリーンアップを完結させる
  • マルチステージビルドが強力 → ビルドツールを最終イメージから除外し、劇的にサイズを削減
  • 細かな最適化の積み重ね → .dockerignore、パッケージキャッシュ削除、COPY順序の最適化など

これらのテクニックを組み合わせることで、数百MBのイメージを数MBまで削減することも可能です。

Dockerイメージの最適化は、単なるサイズ削減だけではありません。デプロイ速度の向上、コスト削減、セキュリティの向上など、様々なメリットをもたらします。
特にマイクロサービスアーキテクチャやCI/CD環境では、これらの最適化が開発プロセス全体の効率に大きく影響します。

最初はすべてを完璧にする必要はありません。まずはAlpine Linuxをベースイメージとして使ってみることから始めてみてください。
そして、少しずつレイヤーの削減やマルチステージビルドを取り入れていけば、自然とベストプラクティスが身についていきます。

この記事をシェア

関連するコンテンツ