docker-compose.ymlで複数コンテナをラクラク管理!実践的な書き方ガイド

docker icon
Docker

こんにちは、とまだです。

Docker使っていて、「コンテナ増えてきて管理が大変...」と感じたことはありませんか?

私も最初は1つずつコンテナを起動していましたが、3つ4つと増えてくると、どのコンテナから起動すればいいのか混乱してしまいました。

今回は、そんな悩みを解決してくれるdocker-compose.ymlについて、実践的な書き方を解説していきます。

docker-compose.ymlとは?

簡単に言うと、複数のコンテナの設定をまとめて書いておけるレシピみたいなものです。

料理で例えると、カレーを作るときのレシピと同じです。

  • 野菜を切る
  • 肉を炒める
  • ルーを入れる

これらの手順を毎回思い出しながら作るより、レシピに書いておけば楽ですよね。

docker-compose.ymlも同じで、コンテナの起動手順や設定をファイルにまとめておけます。

なぜ複数コンテナの連携が必要なの?

Webアプリケーションを作るとき、実は複数の部品が協力し合っています。

例えば、こんな構成です。

  • Webサーバー(画面を表示する)
  • データベース(データを保存する)
  • キャッシュサーバー(処理を高速化する)

これらを別々に管理すると、起動順序を間違えたり、設定がズレたりしてエラーの原因になります。

そこで、docker-compose.ymlの出番というわけです。

基本的な書き方を見てみよう

まずは、WebアプリとDBを連携させる例を見てみましょう。

services:
  app:
    image: nginx:latest
    container_name: my-webapp
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    depends_on:
      - db

  db:
    image: mysql:latest
    container_name: my-db
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
      - MYSQL_DATABASE=my_database
      - MYSQL_USER=my_user
      - MYSQL_PASSWORD=my_password
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:

このファイルは「appというWebサーバーと、dbというデータベースを一緒に起動してね」という指示書です。

ポイントを見ていきましょう。

services:登場人物を決める

servicesの中に、使いたいコンテナを列挙します。

今回はappdbという2つのサービスを定義しています。

ports:外からアクセスできる窓口

"8080:80"という書き方は、「外の世界の8080番の窓口から、コンテナ内の80番の窓口につなげて」という意味です。

郵便ポストで例えると、マンションの集合ポスト(8080)から各部屋のポスト(80)に転送するイメージです。

volumes:データの保管場所

コンテナは気軽に作り直せる反面、中のデータも一緒に消えてしまいます。

大事なデータは、volumesを使って外部に保管します。

引っ越しで例えると、家具付き物件(コンテナ)から出ていくときに、自分の荷物(データ)だけは倉庫(volume)に預けておくようなものです。

depends_on:起動順序の指定

depends_on: - dbと書くことで、「dbを先に起動してからappを起動して」と指示できます。

朝の準備で例えると、「コーヒーメーカーのスイッチを入れてから、パンを焼き始める」みたいな順序指定です。

コンテナ同士の通信はどうなってる?

docker-composeの便利な点は、サービス名で通信できることです。

アプリからデータベースに接続するとき、IPアドレスではなくdb:3306のようにサービス名で指定できます。

これは、同じマンション内なら部屋番号だけで郵便物が届くのと似ています。

外部の住所(IPアドレス)を覚えなくても、内部では名前だけで通じるわけです。

よく使うコマンドを覚えよう

docker-compose.ymlを書いたら、実際に動かしてみましょう。

起動:docker-compose up

docker-compose up -d

-dをつけると、バックグラウンドで動作します。

テレビで例えると、録画予約みたいなものです。

停止:docker-compose down

docker-compose down

全てのコンテナを停止して片付けます。

状態確認:docker-compose ps

docker-compose ps

今どのコンテナが動いているか確認できます。

ログ確認:docker-compose logs

docker-compose logs app

コンテナが何をしているか、ログを見て確認できます。

エラーが起きたときの原因調査に便利です。

つまずきやすいポイントと解決策

DBが起動する前にアプリが接続しようとする

depends_onは起動順序を指定するだけで、DBの準備完了までは待ってくれません。

解決策は、アプリ側で再接続の仕組みを入れることです。

電話で例えると、相手が電話に出るまで何度かかけ直すイメージです。

ファイルの変更が反映されない

volumesの設定でパスを間違えていることが多いです。

相対パスと絶対パスの違いに注意しましょう。

「./html」は現在のディレクトリからの相対パス、「/home/user/html」は絶対パスです。

ポート番号がかぶってエラーになる

同じポート番号を複数のサービスで使うとエラーになります。

アパートで例えると、同じ部屋番号を2つ作ることはできないのと同じです。

実務での活用例

開発環境の共有

チーム全員が同じdocker-compose.ymlを使えば、環境の違いによるトラブルが減ります。

「私の環境では動くんだけど...」という問題から解放されます。

テスト環境の構築

本番に近い環境を手軽に作れます。

プロジェクトごとに異なるバージョンのDBを使い分けることも簡単です。

マイクロサービスの開発

複数のサービスを組み合わせたシステムも、docker-compose.ymlでまとめて管理できます。

セキュリティで気をつけること

パスワードの管理

docker-compose.ymlに直接パスワードを書くのは避けましょう。

代わりに.envファイルを使います。

# .envファイル
DB_PASSWORD=secret123
# docker-compose.yml
environment:
  - MYSQL_PASSWORD=${DB_PASSWORD}

これで、パスワードを別ファイルで管理できます。

不要なポートは開放しない

外部からアクセスする必要がないポートは、portsに書かないようにします。

家で例えると、使わない窓は閉めておくのと同じです。

さらに便利な使い方

環境ごとの設定分け

開発環境と本番環境で設定を分けたいときは、複数のymlファイルを組み合わせます。

# 開発環境
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up

# 本番環境
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up

自作イメージの利用

Dockerfileがあれば、buildオプションで自作イメージも使えます。

services:
  app:
    build: .
    # imageの代わりにbuildを指定

トラブルシューティングのコツ

問題が起きたら、まずログを確認します。

# 全体のログ
docker-compose logs

# 特定のサービスのログ
docker-compose logs db

# リアルタイムで追跡
docker-compose logs -f app

それでも原因がわからないときは、コンテナに入って調査します。

docker-compose exec db bash

これで、コンテナ内部を直接確認できます。

まとめ

docker-compose.ymlを使えば、複数コンテナの管理がグッと楽になります。

最初は簡単な構成から始めて、徐々に機能を追加していけば大丈夫です。

エラーが出ても、それは学習のチャンスです。

docker-compose.ymlを覚えて、快適な開発環境を作っていきましょう!

共有:

著者について

とまだ

とまだ

フルスタックエンジニア

Learning Next の創設者。Ruby on Rails と React を中心に、プログラミング教育に情熱を注いでいます。初心者が楽しく学べる環境作りを目指しています。

著者の詳細を見る →