はじめに (対象読者・この記事でわかること)

この記事は、既存のWebシステムを運用しており、以下のような課題を感じている開発者やエンジニアの方を対象にしています。

  • 開発環境の構築に時間がかかる、環境差異によるバグが多い
  • システムの一部だけをアップデートしたいが、全体への影響が大きく踏み切れない
  • 新しいメンバーのオンボーディングが大変
  • CI/CDの導入を検討しているが、環境整備が進まない

この記事を読むことで、既存のWebシステムをDockerコンテナとして動かすための具体的な手順、考慮すべき点、そしてよくある課題とその解決策がわかります。結果として、環境構築の効率化、開発環境の統一、システムのポータビリティ向上に繋がる一歩を踏み出せるでしょう。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 * Dockerの基本的な概念: イメージ、コンテナ、ボリューム、ネットワークなどの用語理解 * Dockerコマンドの基本的な操作: docker run, docker build, docker ps, docker logs など * Linuxコマンドの基本的な操作: ファイルシステム、パーミッションなど * 対象となるシステムの基本的な知識: 使用しているプログラミング言語、フレームワーク、ミドルウェアの構成

なぜ今、既存システムをDocker化するのか?メリットと課題

既存システムをDocker化することには、多くのメリットがあります。しかし、同時に考慮すべき課題も存在します。このセクションでは、その両面について掘り下げていきます。

Docker化がもたらすメリット

  1. 環境構築の容易化と統一: 開発者ごとに異なるOSやツールバージョンによる環境差異は、デバッグの複雑化や「私の環境では動くのに…」といった問題を引き起こしがちです。Dockerを使えば、Dockerfiledocker-compose.ymlによって環境をコード化し、誰でも同じ環境を素早く構築できるようになります。これは新しいメンバーのオンボーディング時間短縮にも大きく貢献します。

  2. ポータビリティの向上: 開発環境、テスト環境、本番環境といった異なる環境間でのデプロイが容易になります。一度Dockerイメージを作成すれば、Dockerが稼働するどの環境でも同じようにアプリケーションを実行できます。これにより、デプロイ時の予期せぬトラブルを減らすことができます。

  3. スケーラビリティとリソース効率: コンテナは軽量であり、仮想マシンと比較して起動が速く、少ないリソースで多くのアプリケーションを動かせます。また、需要に応じて特定のサービスだけをスケールアウトするといった柔軟な運用も可能になります。

  4. CI/CDパイプラインとの親和性: DockerイメージはCI/CDパイプラインに非常に組み込みやすい形式です。テスト環境の構築、テストの実行、本番環境へのデプロイまでを自動化しやすくなり、開発からリリースまでのサイクルを高速化できます。

  5. 依存関係の隔離: アプリケーションとその依存関係(ライブラリ、ミドルウェアなど)をコンテナ内に完全に隔離できます。これにより、ホストOSや他のアプリケーションへの影響を気にすることなく、特定のコンポーネントだけを更新したり、異なるバージョンのミドルウェアを共存させたりすることが可能になります。

既存システムDocker化の課題と考慮点

一方で、既存システムをDocker化する際には、以下のような課題に直面する可能性があります。

  1. 既存システムへの影響: 特にデータベースなどの永続化データを持つコンポーネントの移行は慎重に行う必要があります。データ損失のリスクを最小限にするため、十分なバックアップとテスト計画が不可欠です。

  2. 学習コスト: Dockerの基本的な概念やDockerfiledocker-compose.ymlの書き方、コンテナネットワークの理解など、一定の学習コストがかかります。チーム全体のスキルアップが求められます。

  3. 初期設計と移行計画: 既存のモノリシックなシステムをどのようにコンテナに分割するか、どのコンポーネントからDocker化を進めるかなど、綿密な計画が必要です。一気に全てをDocker化しようとすると、かえって混乱を招く可能性があります。

  4. ファイルパーミッションやネットワーク: 既存システムがファイルシステムやネットワーク構成に強く依存している場合、Dockerコンテナ内でのパスやパーミッション、ポートマッピングの調整が必要になります。これらは特にエラーが発生しやすい箇所です。

これらのメリットと課題を理解した上で、既存システムをDocker化する計画を立てることが成功への鍵となります。

既存システムをDocker化する具体的なステップ

ここからは、既存のWebアプリケーション(例として、Apache + PHP + MySQLの構成を想定)をDocker化する具体的な手順を解説します。

ステップ1: システム構成の理解と依存関係の洗い出し

まず、既存システムの全体像を把握し、Docker化の対象となるコンポーネントとそれらの依存関係を明確にします。

  1. 主要コンポーネントの特定:

    • Webサーバー: Apache, Nginx など
    • アプリケーション実行環境: PHP, Node.js, Python, Java などとそのバージョン
    • データベース: MySQL, PostgreSQL, MongoDB などとそのバージョン
    • キャッシュサーバー: Redis, Memcached など
    • その他のミドルウェア: メッセージキュー、検索エンジンなど
    • OS: CentOS, Ubuntu など
  2. 依存関係の洗い出し:

    • アプリケーションに必要なライブラリやパッケージ: composer.json, package.json, requirements.txt、あるいはapt list --installedなどで確認
    • OSレベルのパッケージ: build-essential, libjpeg-dev など、ビルド時に必要となるもの
    • ファイルシステム: アプリケーションがファイルを書き込むパス、設定ファイルのパスなど
    • 環境変数: データベース接続情報、APIキーなど
  3. 構成図の作成: 手書きでも良いので、主要コンポーネント間の関係性(どのコンテナがどのポートで通信するか、どのコンテナが永続データを必要とするか)を可視化しておくと、後の設計がスムーズになります。

ステップ2: Docker環境の準備と概念設計

既存システムの構成を理解したら、Docker環境を準備し、どのようにコンテナ化するかを設計します。

  1. Docker Desktopのインストール: 開発環境でDockerを使うために、Docker公式サイトからDocker Desktopをインストールします。

  2. コンテナ分割の検討:

    • Webサーバーとアプリケーション: 一般的には同じコンテナにまとめるか、Webサーバー(Nginxなど)とアプリケーションサーバー(PHP-FPMなど)を分離するかの選択肢があります。既存システムがApacheとPHPを密に連携させている場合は、同じコンテナにまとめるのが手軽です。
    • データベース: 必ず独立したコンテナとして用意します。データ永続化のためにDocker Volumeを使用します。
    • キャッシュ、メッセージキューなど: これらも独立したコンテナとします。
  3. Dockerfileの基本的な構成を考える: 各コンポーネント(例: Web+PHP、MySQL)ごとにどのようなDockerfileが必要になるか、おおまかなイメージをします。

  4. docker-compose.ymlの役割を理解する: 複数のコンテナを連携させて起動するためにdocker-compose.ymlを使用します。サービス間のネットワーク設定やボリュームマウントなどを定義します。

ステップ3: Dockerfileの作成とイメージビルド

各コンポーネントに対応するDockerfileを作成し、カスタムイメージをビルドします。ここではPHP+Apacheの例を挙げます。

プロジェクトルートに docker ディレクトリを作成し、その中に apache-php ディレクトリを作成します。

/your-project
├── docker
│   └── apache-php
│       └── Dockerfile
│       └── 000-default.conf # Apache設定ファイル
├── src # 既存のWebアプリケーションコード
│   └── index.php
│   └── ...
└── docker-compose.yml

docker/apache-php/Dockerfile の例:

Dockerfile
# ベースイメージの選択 FROM php:7.4-apache # 必要なOSパッケージのインストール # apt-get update && apt-get install -y --no-install-recommends \ # libzip-dev \ # libjpeg-dev \ # libpng-dev \ # && rm -rf /var/lib/apt/lists/* # PHP拡張機能のインストール(例: mysqli, pdo_mysql, gd, zip) # docker-php-ext-install -j$(nproc) mysqli pdo_mysql gd zip # ApacheのRewriteモジュールを有効化 RUN a2enmod rewrite # カスタムApache設定ファイルをコピー # 既存のApache設定に合わせて、VirtualHostなどの設定を記述 COPY docker/apache-php/000-default.conf /etc/apache2/sites-available/000-default.conf # アプリケーションコードをコンテナ内にコピー # ホストの /src ディレクトリをコンテナの /var/www/html にマウントする場合は不要だが、 # イメージ内にコードを含めたい場合はここでコピーする。 # COPY ../src /var/www/html # コンテナ起動時のデフォルトコマンド(php:apacheイメージでは既に設定されていることが多い) # CMD ["apache2-foreground"]

docker/apache-php/000-default.conf の例:

Apache
<VirtualHost *:80> DocumentRoot /var/www/html <Directory /var/www/html> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>

イメージのビルド: your-project ディレクトリに移動し、以下を実行します。

Bash
docker build -t your-php-app:1.0 ./docker/apache-php

-t オプションでイメージにタグ(名前とバージョン)を付けます。

ステップ4: docker-compose.ymlによるコンテナ連携

次に、docker-compose.ymlを作成し、Webアプリケーションコンテナとデータベースコンテナを連携させます。

your-project/docker-compose.yml の例:

Yaml
version: '3.8' services: # Webアプリケーションサービス web: build: context: . # docker-compose.ymlがあるディレクトリをビルドコンテキストとする dockerfile: ./docker/apache-php/Dockerfile # Dockerfileのパスを指定 container_name: your_app_web ports: - "80:80" # ホストの80番ポートをコンテナの80番ポートにマッピング volumes: - ./src:/var/www/html # ホストの./srcディレクトリをコンテナの/var/www/htmlにマウント # Apacheのログをホストに永続化したい場合 # - ./docker/logs/apache:/var/log/apache2 environment: # アプリケーションで使用する環境変数を設定(例: DB接続情報) MYSQL_HOST: db # DBサービスのホスト名(docker-composeのサービス名) MYSQL_USER: user MYSQL_PASSWORD: password MYSQL_DATABASE: your_database depends_on: - db # dbサービスが起動してからwebサービスを起動する # データベースサービス (MySQLの例) db: image: mysql:5.7 # MySQLの公式イメージを使用 container_name: your_app_db ports: - "3306:3306" # ホストの3306番ポートをコンテナの3306番ポートにマッピング environment: MYSQL_ROOT_PASSWORD: root_password # ルートユーザーのパスワード MYSQL_USER: user # 作成するユーザー名 MYSQL_PASSWORD: password # 作成するユーザーのパスワード MYSQL_DATABASE: your_database # 作成するデータベース名 volumes: - db_data:/var/lib/mysql # データベースのデータを永続化するためのボリューム # 初期SQLスクリプトを実行したい場合 # - ./docker/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql # 永続化ボリュームの定義 volumes: db_data:

コンテナの起動: your-project ディレクトリで以下を実行します。

Bash
docker-compose up -d

-d オプションでバックグラウンドで起動します。

ステップ5: 動作確認とデバッグ

コンテナが正常に起動したら、アプリケーションの動作を確認します。

  1. コンテナの起動状況確認: bash docker ps your_app_webyour_app_db コンテナが Up 状態であることを確認します。

  2. アプリケーションへのアクセス: Webブラウザで http://localhost/ にアクセスし、アプリケーションが正常に表示・動作するかを確認します。

  3. コンテナログの確認: エラーが発生した場合は、各コンテナのログを確認します。 bash docker logs your_app_web docker logs your_app_db

  4. コンテナ内でのコマンド実行: 必要に応じて、コンテナ内に入ってファイルを確認したり、コマンドを実行したりします。 bash docker exec -it your_app_web bash # webコンテナに入る # ls -l /var/www/html # php -v # exit データベースコンテナに入って、MySQLクライアントで接続確認も可能です。

ハマった点やエラー解決

既存システムのDocker化では、特に以下の点でエラーに遭遇しやすいです。

  • ファイルパーミッションの問題: アプリケーションがファイルを書き込もうとする際に、コンテナ内のユーザーに書き込み権限がない場合。
  • 環境変数の適用漏れ: データベース接続情報やAPIキーなどがアプリケーションに正しく渡されていない場合。
  • ポートの競合: ホストOSのポートが既に別のアプリケーションで使用されており、Dockerコンテナのポートマッピングが失敗する場合。
  • DB接続情報の間違い: アプリケーションがデータベースに接続できない(ホスト名、ユーザー名、パスワード、データベース名が誤っている)。
  • 必要なOSパッケージやPHP拡張機能の不足: Dockerfileにインストールが記述されていないため、アプリケーションが起動しない。

解決策

  • ファイルパーミッション: Dockerfile内でUSER命令を使って非rootユーザーで実行したり、RUN chown -R www-data:www-data /var/www/htmlのように適切な権限を設定したりします。あるいは、docker-compose.ymlのボリュームマウントでuserオプションを使用する方法もあります。

  • 環境変数の適用漏れ: docker-compose.ymlenvironmentセクションで全ての必要な環境変数を定義し、アプリケーションがそれらを正しく読み込めるようにします。PHPの場合、getenv()$_ENV, $_SERVERなどで読み込めることを確認します。

  • ポートの競合: docker-compose.ymlports設定で、ホスト側のポート番号を変更します(例: "8080:80")。

  • DB接続情報の間違い: docker-compose.ymlenvironmentで定義した環境変数や、アプリケーション内のDB接続設定を確認します。特にホスト名は、Dockerネットワーク内ではdb(サービス名)でアクセスできることに注意してください。

  • 必要なパッケージや拡張機能の不足: エラーメッセージを注意深く読み、不足しているパッケージや拡張機能を特定します。その後、DockerfileRUN apt-get installRUN docker-php-ext-installなどで追加し、再度イメージをビルドします。

これらの解決策を適用する際は、変更を加えるたびにdocker-compose build(Dockerfileを変更した場合)とdocker-compose up -dを実行し、docker logsで出力されるログを注意深く確認しながら進めることが重要です。

まとめ

本記事では、既存のWebシステムをDocker化するための具体的な手順と、その過程で直面しやすい課題とその解決策を解説しました。

  • Docker化のメリット: 環境構築の容易化、ポータビリティ向上、CI/CDとの連携など、既存システムの課題を解決する強力な手段となります。
  • 具体的な5ステップ: システム構成の理解、Docker環境準備、Dockerfile作成、docker-compose.ymlによる連携、動作確認とデバッグを通して、段階的にDocker化を進めることができます。
  • 課題解決: ファイルパーミッション、環境変数、ポート競合、DB接続といった、よくある問題に対して具体的な解決策を提示しました。

この記事を通して、既存システムのDocker化に対する具体的なイメージを持ち、実際に手を動かすことで開発効率の向上、環境差異の解消、そして将来的なシステム拡張への準備という大きなメリットが得られたことと思います。

今後は、Docker Composeを利用した本番環境へのデプロイ、CI/CDパイプラインへの組み込み、さらにはKubernetesなどのコンテナオーケストレーションツールへの移行といった、発展的な内容についても検討し、より堅牢でスケーラブルなシステム運用を目指していくと良いでしょう。

参考資料