Next.js Logo

docker compose入門:WEBアプリケーションを構築

thumbnail

※この記事で使用しているリソースを一括でダウンロードすることができます。

これまでDockerに関する記事をいくつか書いてきました。今回は開発していくにあたって必ずと言っていいほど使う「docker compose」について解説していきます。

docker composeを使用することで簡単に複数コンテナやネットワーク設定、volume設定などを一括で行うことができます。

前提

Dockerにおけるポートフォアーディング設定については理解していること。

作成するアプリのイメージは「Webアプリケーション(front)からバックグラウンドアプリケーションを呼び出し、データベース(postgresql)からユーザー一覧を取得して、Web画面に出力する」という内容になります。

リソースの準備

postgresのコンテナpythonのコンテナについて準備していきましょう。ディレクトリ構成は以下のようになります。

ディレクトリ構成

. ├── docker │ ├── front │ │ └── Dockerfile # アプリケーション(フロントエンド)のDockerfile │ ├── back │ │ └── Dockerfile # アプリケーション(バックエンド)のDockerfile │ └── db │ └── Dockerfile # データベース用のDockerfile ├── src/ # アプリケーションのソースコード │ ├── front │ │ └── index.html # フロントエンド用のhtmlファイル │ └── back | ├── app.py # バックエンド用のソースコード │ └── get_user.py # データベースからuserデータ取得する処理を記載 └── docker-compose.yml # Docker Compose 設定ファイル

pythonのコンテナ用のDockerfile

こちらはメインではないので軽く説明します。 pythonの3.11.10のイメージを使用して、psycopg2-binaryとFlask、flask-corsをpipインストールしています。

./docker/back/Dockerfile

FROM python:3.11.10 RUN pip install psycopg2-binary RUN pip install Flask RUN pip install flask-cors

postgresのコンテナ用のDockerfile

こちらもメインではないので軽く説明します。 postgresのイメージを作成するためににDockerfileを作成します。

docker-entrypoint-initdb.dディレクトリにsqlファイルを入れておくことで、コンテナ作成時にテーブル作成や初期データの投入などを行うことができます。これを利用してpostgresコンテナ作成時にusersテーブルとユーザのデータを入るようにしておきます。

./docker/db/Dockerfile

FROM postgres:17.0 ENV POSTGRES_PASSWORD=postgres # 初期化用SQLスクリプトを作成 RUN echo "CREATE TABLE users (id SERIAL PRIMARY KEY, username TEXT NOT NULL);" \ > /docker-entrypoint-initdb.d/init.sql \ && echo "INSERT INTO users (username) VALUES ('admin'),('user1'),('user2');" \ >> /docker-entrypoint-initdb.d/init.sql

pythonソースコードの準備

こちらもメインではないので軽く説明します。 get_user.pyではDB(postgres)に接続してユーザの一覧を取得しています。

./src/back/get_user.py

import psycopg2 def get_user(): try: # `with`で接続を管理 with psycopg2.connect(host="db", database="postgres", user="postgres", password="postgres", port=5432) as connection: # `with`でカーソルを管理 with connection.cursor() as cursor: # SQLクエリを実行 query = "SELECT * FROM users;" cursor.execute(query) # 結果を取得して処理 rows = cursor.fetchall() users = [] for row in rows: print(row) id, name = row users.append({"id": id, "name": name}) return users except psycopg2.Error as e: print("データベース操作中にエラーが発生しました:", e) if __name__ == "__main__": id, name = get_user() print(id) print(name)

app.pyでは「/user」にアクセスされたときにget_user.pyを使用してユーザ情報を取得して呼び元に返します。 特に重要なのは「port=3000」の個所でこれによって3000番ポートで待ち受けることになります。

./src/back/app.py

from flask import Flask, jsonify from flask_cors import CORS from get_user import get_user app = Flask(__name__) # 特定のオリジンだけを許可する cors = CORS(app, resources={r"/*": {"origins": ["http://localhost"]}}) @app.route("/user") def user(): users = get_user() return jsonify(users), 200 if __name__ == "__main__": app.run(port=3000, host='0.0.0.0', debug=True)

Webソースコードの準備

こちらもメインではないので軽く説明します。 Webでアクセスしたときに「pythonソースコード」で書いたバックエンドアプリケーションの「/user」にリクエストしています。 そして結果を画面に出力するという内容になっています。

./src/front/index.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="user"></div> <script> const xhr = new XMLHttpRequest(); xhr.open("GET", "http://localhost:8080/user"); xhr.send(); xhr.responseType = "json"; xhr.onload = () => { if (xhr.readyState == 4 && xhr.status == 200) { const data = xhr.response; const container = document.getElementById('user'); console.log(container); console.log(data); // データをループして要素を作成 data.forEach((item, index) => { console.log(item) const div = document.createElement('div'); div.textContent = `ユーザID : ${item.id}、ユーザ名 : ${item.name}` container.appendChild(div); }); } else { console.log(`Error: ${xhr.status}`); } }; </script> </body> </html>

docker-compose.ymlの準備

今回のメインの内容になります。

全体としては、3つのコンテナ(back、front、db)が立ち上がるように設定しています。

./docker-compose.yml

services: # バックエンドアプリケーション用のコンテナ back: build: ./docker/back ports: - "8080:3000" volumes: - ./src/back/:/app working_dir: /app command: python app.py tty: true # Web(フロントエンド)アプリケーション用のコンテナ front: image: httpd:2.4 ports: - "80:80" volumes: - ./src/front/:/usr/local/apache2/htdocs/ # データベース用のコンテナ db: build: ./docker/db ports: - "5432:5432" volumes: - postgres-volume:/var/lib/postgresql/data volumes: postgres-volume:

それぞれ詳しく説明していきます。まずbackから見ていきましょう。

docker-compose.ymlのback部分

back: build: ./docker/back ports: - "8080:3000" volumes: - ./src/back/:/app working_dir: /app command: python app.py tty: true

次にfrontを見て行きます

docker-compose.ymlのfront部分

front: image: httpd:2.4 ports: - "80:80" volumes: - ./src/front/:/usr/local/apache2/htdocs/

最後にdbを見て行きます

docker-compose.ymlのdb部分

db: build: ./docker/db ports: - "5432:5432" volumes: - postgres-volume:/var/lib/postgresql/data volumes: postgres-volume:

docker-composeを実行

起動時はdocker-composeコマンドで起動することができます。

--buildでDockerfileに変更などがあった場合ビルドしてくれます。 -dでバックグラウンド実行してくれます。

ターミナル(docker-compose.ymlがある階層)

docker-compose up --build -d

コマンドでdocker-compose

vscodeを使用している場合、docker-compose.ymlを右クリックしてコンテナを立ち上げえることもできます。 UIからdocker-compose

Webアプリケーションに接続する

Webアプリケーションは80ポートで上がっているのでブラウザから接続してみましょう。

ブラウザ

http://localhost/

以下のようにユーザ情報が出力されていればOKです。これによって複数コンテナの連携設定をしつつ一括で起動することが確認できました。 お疲れさまでした!

Webアプリケーションに接続する

最後に

今回はなかなかのボリュームになりましたが、今回の内容でdocker-composeがとても便利だということがわかったのではないでしょうか?

今回の記事が役に立った、ほかにも記事が見たいという方は最新情報を公式Xで配信しているのでフォローお願いします!