第3章:Dockerfile
はじめに
Dockerfileは、イメージをビルドするための命令書です。本章では、Dockerfileの記法とベストプラクティスを学びます。
---
1. Dockerfileの基本
1.1 構文
# コメント
命令 引数
# 例
FROM alpine:3.18
RUN apk update && apk add nginx
COPY nginx.conf /etc/nginx/
EXPOSE 443
CMD ["nginx", "-g", "daemon off;"]
1.2 主要な命令
# ベースイメージ
FROM <image>:<tag>
# 環境変数
ENV <key>=<value>
# 作業ディレクトリ
WORKDIR /path/to/dir
# ファイルコピー
COPY <src> <dest>
ADD <src> <dest> # URL対応、tar展開
# コマンド実行
RUN <command>
# ポート公開
EXPOSE <port>
# ボリューム
VOLUME ["/data"]
# ユーザー
USER <user>
# 実行コマンド
CMD ["executable", "param1"]
ENTRYPOINT ["executable", "param1"]
---
2. FROM命令
2.1 ベースイメージの選択
# 公式イメージ
FROM nginx:1.25-alpine
FROM php:8.2-fpm-alpine
FROM mariadb:10.11
# Alpine Linux(軽量)
FROM alpine:3.18
# Debian(互換性重視)
FROM debian:bullseye-slim
# 注意: :latest は禁止(Inception要件)
FROM alpine # NG: 暗黙の:latest
FROM alpine:3.18 # OK: バージョン指定
2.2 Alpine vs Debian
Alpine Linux:
+ サイズ: 約5MB
+ セキュリティ(musl libc)
+ パッケージマネージャ: apk
- 一部互換性問題(glibc依存)
Debian:
+ 互換性が高い(glibc)
+ 豊富なパッケージ
+ パッケージマネージャ: apt
- サイズ: 約100MB
Inception推奨:
- Alpine または Debian
- penultimate stable version
---
3. RUN命令
3.1 シェル形式 vs Exec形式
# シェル形式(シェル経由)
RUN apk update && apk add nginx
# Exec形式(直接実行)
RUN ["apk", "add", "nginx"]
# シェル形式の展開
RUN echo "Hello, $USER" # 変数展開される
RUN ["echo", "Hello, $USER"] # 文字列リテラル
3.2 レイヤー最適化
# NG: 複数レイヤー
RUN apk update
RUN apk add nginx
RUN apk add php
RUN rm -rf /var/cache/apk/*
# OK: 単一レイヤー
RUN apk update && \
apk add --no-cache nginx php && \
rm -rf /var/cache/apk/*
# 理由:
# - レイヤー数削減
# - キャッシュのクリーンアップ
# - イメージサイズ削減
3.3 キャッシュ活用
# 変更頻度の低いものを先に
FROM alpine:3.18
# システムパッケージ(変更少ない)
RUN apk add --no-cache nginx php
# 設定ファイル(時々変更)
COPY nginx.conf /etc/nginx/
# アプリケーションコード(頻繁に変更)
COPY app/ /var/www/html/
# キャッシュが有効な限り再ビルド不要
---
4. COPY vs ADD
4.1 違い
# COPY: 単純なファイルコピー
COPY local/file.txt /container/file.txt
COPY dir/ /container/dir/
# ADD: 追加機能あり
ADD https://example.com/file.tar.gz /tmp/ # URL対応
ADD archive.tar.gz /app/ # 自動展開
# 推奨: 基本はCOPYを使用
# ADDはtar展開が必要な場合のみ
4.2 .dockerignore
# .dockerignore
.git
.gitignore
Dockerfile*
docker-compose*.yml
*.md
*.log
.env*
node_modules
__pycache__
# 効果:
# - ビルドコンテキスト削減
# - 不要ファイルの除外
# - ビルド高速化
---
5. CMD vs ENTRYPOINT
5.1 違い
# CMD: デフォルトコマンド(上書き可能)
CMD ["nginx", "-g", "daemon off;"]
# docker run image → nginx -g daemon off;
# docker run image /bin/sh → /bin/sh(上書き)
# ENTRYPOINT: 固定のエントリーポイント
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
# docker run image → nginx -g daemon off;
# docker run image -v → nginx -v(引数追加)
5.2 使い分け
# パターン1: 実行ファイルとして
ENTRYPOINT ["python", "app.py"]
# docker run image --port 8080
# パターン2: ラッパースクリプト
COPY entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
# パターン3: デフォルトコマンド
CMD ["nginx", "-g", "daemon off;"]
# 柔軟だが意図しない上書きに注意
---
6. Inceptionサービス用Dockerfile
6.1 Nginx
FROM alpine:3.18
# パッケージインストール
RUN apk update && \
apk add --no-cache nginx openssl && \
rm -rf /var/cache/apk/*
# SSL証明書生成
RUN mkdir -p /etc/nginx/ssl && \
openssl req -x509 -nodes -days 365 \
-newkey rsa:2048 \
-keyout /etc/nginx/ssl/nginx.key \
-out /etc/nginx/ssl/nginx.crt \
-subj "/C=JP/ST=Tokyo/L=Tokyo/O=42/CN=login.42.fr"
# 設定ファイル
COPY conf/nginx.conf /etc/nginx/nginx.conf
# ポート公開
EXPOSE 443
# フォアグラウンドで実行
CMD ["nginx", "-g", "daemon off;"]
6.2 WordPress (PHP-FPM)
FROM alpine:3.18
# PHP と依存関係
RUN apk update && \
apk add --no-cache \
php82 \
php82-fpm \
php82-mysqli \
php82-json \
php82-curl \
php82-dom \
php82-exif \
php82-fileinfo \
php82-mbstring \
php82-openssl \
php82-xml \
php82-zip \
php82-phar \
wget \
mariadb-client && \
rm -rf /var/cache/apk/*
# WP-CLI インストール
RUN wget https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
chmod +x wp-cli.phar && \
mv wp-cli.phar /usr/local/bin/wp
# PHP-FPM 設定
COPY conf/www.conf /etc/php82/php-fpm.d/www.conf
# セットアップスクリプト
COPY tools/setup.sh /setup.sh
RUN chmod +x /setup.sh
WORKDIR /var/www/html
EXPOSE 9000
ENTRYPOINT ["/setup.sh"]
6.3 MariaDB
FROM alpine:3.18
# MariaDB インストール
RUN apk update && \
apk add --no-cache mariadb mariadb-client && \
rm -rf /var/cache/apk/*
# 設定ファイル
COPY conf/my.cnf /etc/my.cnf.d/mariadb-server.cnf
# 初期化スクリプト
COPY tools/init.sh /init.sh
RUN chmod +x /init.sh
# データディレクトリ
RUN mkdir -p /var/lib/mysql && \
chown -R mysql:mysql /var/lib/mysql
EXPOSE 3306
ENTRYPOINT ["/init.sh"]
---
7. 初期化スクリプト
7.1 WordPress setup.sh
#!/bin/sh
# WordPressがなければダウンロード
if [ ! -f /var/www/html/wp-config.php ]; then
# ダウンロード
wp core download --allow-root
# wp-config.php 生成
wp config create \
--dbname="${MYSQL_DATABASE}" \
--dbuser="${MYSQL_USER}" \
--dbpass="${MYSQL_PASSWORD}" \
--dbhost="${WORDPRESS_DB_HOST}" \
--allow-root
# データベース接続待機
while ! mariadb -h"${WORDPRESS_DB_HOST}" -u"${MYSQL_USER}" \
-p"${MYSQL_PASSWORD}" -e "SELECT 1" > /dev/null 2>&1; do
echo "Waiting for MariaDB..."
sleep 2
done
# WordPress インストール
wp core install \
--url="${DOMAIN_NAME}" \
--title="${WP_TITLE}" \
--admin_user="${WP_ADMIN_USER}" \
--admin_password="${WP_ADMIN_PASSWORD}" \
--admin_email="${WP_ADMIN_EMAIL}" \
--allow-root
# 追加ユーザー作成
wp user create "${WP_USER}" "${WP_USER_EMAIL}" \
--user_pass="${WP_USER_PASSWORD}" \
--role=author \
--allow-root
fi
# PHP-FPM 起動
exec php-fpm82 -F
7.2 MariaDB init.sh
#!/bin/sh
# 初回起動時のみ初期化
if [ ! -d "/var/lib/mysql/mysql" ]; then
# データベース初期化
mysql_install_db --user=mysql --datadir=/var/lib/mysql
# 一時的にサーバー起動
mysqld --user=mysql --datadir=/var/lib/mysql &
pid=$!
# 起動待機
while ! mysqladmin ping --silent; do
sleep 1
done
# データベースとユーザー作成
mysql -u root <<EOF
CREATE DATABASE IF NOT EXISTS ${MYSQL_DATABASE};
CREATE USER IF NOT EXISTS '${MYSQL_USER}'@'%' IDENTIFIED BY '${MYSQL_PASSWORD}';
GRANT ALL PRIVILEGES ON ${MYSQL_DATABASE}.* TO '${MYSQL_USER}'@'%';
ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}';
FLUSH PRIVILEGES;
EOF
# サーバー停止
mysqladmin -u root -p"${MYSQL_ROOT_PASSWORD}" shutdown
fi
# 通常起動
exec mysqld --user=mysql --datadir=/var/lib/mysql
---
8. マルチステージビルド
8.1 概念
# ビルドステージ
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 実行ステージ
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
# 結果:
# - ビルドツール不要
# - 最終イメージが軽量
# - セキュリティ向上
8.2 Inceptionでの応用
# ビルドステージ(ツール準備)
FROM alpine:3.18 AS builder
RUN apk add --no-cache curl
RUN curl -O https://wordpress.org/latest.tar.gz
RUN tar xzf latest.tar.gz
# 実行ステージ
FROM alpine:3.18
RUN apk add --no-cache php82 php82-fpm
COPY --from=builder /wordpress /var/www/html
---
まとめ
本章で学んだこと:
- 基本命令: FROM, RUN, COPY, CMD
- ベースイメージ: Alpine vs Debian
- レイヤー最適化: キャッシュ活用
- COPY vs ADD: 使い分け
- CMD vs ENTRYPOINT: 実行形式
- サービス別Dockerfile: Nginx, WordPress, MariaDB
- 初期化スクリプト: エントリーポイント
- マルチステージビルド: イメージ最適化
次章では、Docker Composeを学びます。