2
2
お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

⑥1日10分で理解するコンテナ技術入門 - Docker Composeの概要 -

Last updated at Posted at 2024-06-19

前回までで、コンテナ(docker)の基本的な使い方を説明しました。ここからは、複数コンテナの管理に使える、docker composeの使い方について説明していきたいと思います。
コード-> https://github.com/sogawa-yk/simple-knowledge-sharing-platform/tree/6-article

Docker Composeとは

Docker Composeは、複数のコンテナを使ったアプリケーションを定義して実行するためのツールです。設定ファイル(docker-compose.yaml)を使って、複数のコンテナとアプリケーションの構成を定義して、その構成に基づいて一括でコンテナをビルド・実行・停止などが行えます。

どんなアプリケーションに使える?

例えば、以前の記事で作成した、ウェブサーバ用のコンテナと、DBのコンテナを使ったアプリケーションにも使えます。以前の記事では、起動する順番に注意しながら各コンテナに対してdocker image buildコマンドと、docker container runコマンドを使いましたが、docker composeを用いると、一括でこれらの操作を行うことができます。

基本的な書き方

yamlファイルなので、インデントを使って構造化して記述します。例えば以下のような具合です。

docker-compose.yamlのサンプル
version: '3'
services:
  web:
    image: my-web-app:latest
    build: .
    ports:
      - "5000:5000"
    environment:
      - DATABASE_URL=postgres://user:password@db:5432/mydatabase
    depends_on:
      - db

  db:
    image: postgres:13
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=mydatabase

volumes:
  db-data:

docker-compose.yamlに記述する内容を、上位レイヤーから順に説明していきます。

最上位レイヤー

最上位レイヤーには、version, services, networks, volumesなどを記述します。

  • version
    composeファイルのバージョンを記述
  • services
    各サービスの定義を記述
  • networks
    カスタムネットワークの定義を記述
  • volumes
    カスタムボリュームの定義を記述
    ここからは、この最上位レイヤーの各レイヤーごとに、その中身に記述する内容を説明します。

servicesレイヤー

ここには各サービスを定義します。各サービスには任意の名前を付けることができます。docker-compose.yamlのサンプルの例では、以下の部分です。

services:
  web:         # サービス名
    # サービスの詳細設定はここに続きます
  db:          # 別のサービス名
    # サービスの詳細設定はここに続きます

サービスの詳細設定のレイヤー

各サービスの設定には、コンテナイメージ、ビルド、ポート、環境変数、依存関係などの詳細を定義します。

services:
  web:
    image: my-web-app:latest           # 使用するDockerイメージ
    build: .                           # Dockerfileがあるディレクトリ
    ports:
      - "5000:5000"                    # ポートマッピング
    environment:
      - DATABASE_URL=postgres://user:password@db:5432/mydatabase # 環境変数
    depends_on:
      - db                             # 起動順序の依存関係
    networks:
      - app-network                    # 使用するネットワーク

  db:
    image: postgres:13                 # 使用するDockerイメージ
    volumes:
      - db-data:/var/lib/postgresql/data # ボリュームマッピング
    environment:
      - POSTGRES_USER=user             # 環境変数
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=mydatabase
    networks:
      - app-network                    # 使用するネットワーク

portsで行えるポートのマッピングは、docker container runコマンド時と同様、[ホストのポート]:[コンテナのポート]の順に指定します。

また、depends_onで指定するのはdocker-compose.yaml内で指定したサービス名です。ここに指定したサービスが起動するまで、depends_onが設定されたサービスは起動しないようになります。このようにすることで、コンテナの起動順序を制御することができます。

ネットワークレイヤー

カスタムネットワークの定義を記述します。サービスの詳細設定レイヤーで、そのサービスが配置されるネットワークを指定できますが、そのネットワークはこのネットワークレイヤーで定義しておく必要があります。

networks:
  app-network:                         # ネットワーク名を指定
    driver: bridge                     # ネットワークドライバを指定
    driver_opts:                       # ドライバ固有のオプションも指定可能
      com.docker.network.bridge.name: my-custom-bridge

ネットワークドライバには以下のようなものが設定できます。

ネットワークドライバ 説明
bridge デフォルトのネットワークドライバ。ネットワーク作成時にドライバを指定しなければこのネットワークが使われる。通常、スタンドアロンコンテナが通信するために使用。
host スタンドアロンコンテナ用。コンテナとDockerホスト間のネットワーク隔離を解除し、ホスト側のネットワーク機能を直接使用。
overlay 複数のDockerデーモンを接続し、swarmサービスが相互に通信可能にする。OSレベルのルーティング設定が不要。
ipvlan IPv4とIPv6のアドレス割り当てをまとめてコントロール。レイヤー2 VLANタギングやIPvlan L3ルーティングも完全に操作可能。
macvlan コンテナにMACアドレスを割り当て、物理デバイスとして見えるようにする。物理ネットワークへの直接接続が想定される場合に最適。
none コンテナの全てのネットワーク機能を無効化。通常、カスタムネットワークドライバとの競合を避けるために使用。swarmサービスでは利用不可。
ネットワークプラグイン サードパーティ製のネットワークプラグインをインストールして利用可能。Docker Hubやサードパーティベンダーから提供。ベンダーのドキュメントを参照。

ボリュームレイヤー

ボリュームレイヤーも書き方はネットワークレイヤーと同様です。

volumes:
  db-data:                      # ボリューム名を指定
    driver: local               # ボリュームドライバを指定
    driver_opts:                # ドライバ固有のオプションを指定
      type: nfs
      o: addr=192.168.1.100,rw
      device: ":/path/to/dir"

使用例

それでは、前回作成したウェブアプリケーションのdocker-compose.yamlを書いてみます。
まず、作成したウェブアプリケーションを少し編集します。DBへの接続をハードコーディングしていましたが、その部分を環境変数から取得する形に変更します。

app.pyの一部
def init_db():
    conn = mysql.connector.connect(
        host=os.environ.get('DATABASE_HOST', 'db'),
        port='3306',
        user=os.environ.get('DATABASE_USER', 'root'),
        password=os.environ.get('DATABASE_PASSWORD', 'password'),
        database=os.environ.get('DATABASE_NAME', 'flask_app')
    )
    cursor = conn.cursor()
    cursor.execute('CREATE TABLE IF NOT EXISTS articles (id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255), content TEXT)')
    conn.commit()
    cursor.close()
    conn.close()

init_db()

def get_db_connection():
    conn = mysql.connector.connect(
        host=os.environ.get('DATABASE_HOST', 'db'),
        port='3306',
        user=os.environ.get('DATABASE_USER', 'root'),
        password=os.environ.get('DATABASE_PASSWORD', 'password'),
        database=os.environ.get('DATABASE_NAME', 'flask_app')
    )
    return conn

前回のウェブアプリケーション起動時に使ったdockerコマンドは、

$ docker network create flask-net
$ docker build -t simple-knowledge-sharing-platform .
$ docker run --name mysql -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=flask_app --network flask-net -d mysql:8.0
$ docker run -d -p 8080:5000 --network flask-net -v $(pwd)/uploads:/app/uploads simple-knowledge-sharing-platform

でした。これらの操作をdocker-composeに落としていきます。
まず、以下のようなひな型を作成します。

version: '3.8'

services:
  db:

  web:

networks:

volumes:

services

MySQL

MySQLのコンテナ起動コマンドは$ docker run --name mysql -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=flask_app --network flask-net -d mysql:8.0でした。これをdocker-compose.yamlに落とすと、

  db:
    image: mysql:8.0
    container_name: mysql
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=flask_app
    networks:
      - flask-net
    volumes:
      - db-data:/var/lib/mysql
    restart: unless-stopped

となります。

webアプリ

webアプリ側の起動コマンドは、$ docker run -d -p 8080:5000 --network flask-net -v $(pwd)/uploads:/app/uploads simple-knowledge-sharing-platformでした。これをdocker-compose.yamlに落とすと、

  web:
    build: .
    container_name: web
    ports:
      - "8080:5000"
    networks:
      - flask-net
    volumes:
      - ./uploads:/app/uploads
    depends_on:
      - db
    environment:
      - DATABASE_HOST=db
      - DATABASE_USER=root
      - DATABASE_PASSWORD=password
      - DATABASE_NAME=flask_app
    restart: unless-stopped

となります。environmentDATABASE_HOSTには、docker-compose.yaml内で定義しているサービス名を指定します。

networks

ネットワーク作成時のコマンドは、$ docker network create flask-netでした。これをdocker-compose.yamlに落とすと、

networks:
  flask-net:
    driver: bridge

となります。

volumes

アップロードされた画像ファイルを保存するために、ボリュームはウェブ側のみ用意しています。以下のように記述します。

volumes:
  web-data:
    driver: local

全体

ここまで加えた変更をみると、以下のようなdocker-compose.yamlになります。

version: '3.8'

services:
  db:
    image: mysql:8.0
    container_name: mysql
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=flask_app
    networks:
      - flask-net
    restart: unless-stopped

  web:
    build: .
    container_name: web
    ports:
      - "8080:5000"
    networks:
      - flask-net
    volumes:
      - web-data:/app/uploads
    depends_on:
      - db
    environment:
      - DATABASE_HOST=db
      - DATABASE_USER=root
      - DATABASE_PASSWORD=password
      - DATABASE_NAME=flask_app
    restart: unless-stopped

networks:
  flask-net:
    driver: bridge

volumes:
  web-data:
    driver: local

docker-compose.yamlからサービスを起動

docker-compose.yamlがあるディレクトリに移動し、以下のコマンドを実行します。

$ docker compose up -d --build #docker composeを使っている場合
$ podman-compose up -d --build #podmanを使っている場合

サービスを停止

$ docker compose down # docker composeを使っている場合
$ podman-compose down # podman-composeを使っている場合

まとめ

基本的なdocker compose (podman-compose)の使い方を何となく理解できたかと思います。次回は、ボリュームを使ったデータ永続化について、もう少し深掘りしていきます。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2