はじめに
Docker Composeで3層アーキテクチャの開発環境を構築していきます。
- プレゼンテーション層はJavaScript
- アプリケーション層はPython
- データ層はMySQL
を使用します。
ソースコードはこちら
開発環境
- MacBook M2
- Docker v.25.0.3
- Docker Compose v2.24.5
ディレクトリ構成
root/
├ web/
| └ sample.js
├ app/
| ├ api.py
| └ con_db.py
├ docker/
| ├ web_context/
| | └ Dockerfile
| ├ app_context/
| | ├ Dockerfile
| | └ requirements.txt
| ├ db_context/
| ├ Dockerfile
| └ init/
| └ init.sql
└ docker-compose.yml
手順
1. Webコンテナイメージの作成
./docker/web_context/
にDockerfile
を作成します。
# 元イメージを定義
FROM node:20.12-bullseye-slim
# apt-getの更新
RUN apt-get update && apt-get -y install
2. Appコンテナイメージの作成
./docker/app_context/
にrequirements.txt
を作成します。
今回は、APIをFastAPIで作成するので、fastapi
とuvicorn
を追加します。
また、MySQLと通信するためにmysql-connector-python
も追加します。
fastapi==0.110.1
uvicorn==0.29.0
mysql-connector-python==8.3.0
./docker/app_context/
にDockerfile
を作成します。
# 元イメージを定義
FROM python:3.11.9-slim-bullseye
# apt-getの更新とユーザを追加
RUN apt-get update && apt-get -y install && \
groupadd -g 1100 pyuser && \
useradd -m -s /bin/bash -u 1100 -g 1100 pyuser
# ホスト上のrequirements.txtをコピー
COPY requirements.txt /home/pyuser
# 作業ディレクトリを変更
WORKDIR /home/pyuser
# パッケージをインストール
RUN pip install -r requirements.txt
Dockerイメージの軽量化のため、今回はslimを使用します。
pyuser
はDocker Composeで実行ユーザとして使用します。
3. DBコンテナイメージの作成
./docker/db_context/
にDockerfile
を作成します。
# 元イメージを定義
FROM mysql:8.3.0
# ユーザを追加 (mysqluser)
RUN groupadd -g 1100 mysqluser && \
useradd -m -s /bin/bash -u 1100 -g 1100 mysqluser
mysqluser
はDocker Composeで実行ユーザとして使用します。
4. Docker Composeの作成
Docker Composeで先ほど作成したイメージを使ってコンテナを構築します。
ルートディレクトリにdocker-compose.yml
を作成します。
# Docker Composeのバーション
version: '3'
# サービスの定義
services:
# Webコンテナ
web:
container_name: web
build:
context: ./docker/web_context/
dockerfile: ./Dockerfile
user: node
working_dir: /home/node/web
volumes:
- ./web:/home/node/web
ports:
- 3000:3000
tty: true
depends_on:
- app
networks:
- client
# Appコンテナ
app:
container_name: app
build:
context: ./docker/app_context/
dockerfile: ./Dockerfile
user: pyuser
working_dir: /home/pyuser/app
volumes:
- ./app:/home/pyuser/app
command: uvicorn api:app --host=0.0.0.0 --reload
ports:
- 8000:8000
tty: true
depends_on:
- db
networks:
- client
- server
# DBコンテナ
db:
container_name: db
build:
context: ./docker/db_context/
dockerfile: ./Dockerfile
user: mysqluser
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: sample_db
MYSQL_USER: sample_user
MYSQL_PASSWORD: sample_user
volumes:
- ./docker/db_context/init:/docker-entrypoint-initdb.d
ports:
- 3006:3006
networks:
- server
networks:
client:
driver: bridge
server:
driver: bridge
Webコンテナ
イメージは./docker/web_context/Dockerfile
を使用するので、
ビルド情報のコンテキストは./docker/web_context/
のディレクトリを指定します。
作業ユーザはNodeイメージにはnode
というユーザが用意されているので、それを使います。
作業ディレクトリはnode
ユーザのホームディレクトリである./home/node/
の中にweb/
というディレクトリを作成して使用します。
working_dir: /home/node/web
と記述すると、web
ディレクトリが存在しないときは、自動で作成してくれます。
ボリュームマウント( volumes: - ./web:/home/node/web
)することで、ファイルを永続化しています。
ポート番号はReactを想定して、3000
にしています。Vue.jsはports: -8080:8080
など、適宜変更してください。
WebコンテナはAppコンテナのAPIと通信する想定のため、Appコンテナが起動してから、Webコンテナを起動するようにします( depends_on: - app
)。
また、WebコンテナがDBコンテナと通信できないようにするため、client
というネットワークを作り、Appコンテナにだけ接続するようにしています。
Appコンテナ
FastAPIを使用しているので、コンテナ起動時にサーバが立ち上がるようにするため、command: uvicorn api:app --host=0.0.0.0 --reload
を設定しています。
コンテナ起動時に、APIが作成されていないと、このコマンドでエラーが発生するので、FastAPIで簡単なコードを作成しておきます。
./app/api.py
を作成します。
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
AppコンテナはDBコンテナとデータのやり取りとするので、DBコンテナが起動してから、Appコンテナが起動するようにしています( depends_on: - db
)。
また、AppコンテナはWebコンテナ、DBコンテナ両方と通信するため、両方のネットワークと接続するようにしています。
DBコンテナ
環境変数でMySQLの設定を追加しています。
-
MYSQL_ROOT_PASSWORD
ルートユーザのパスワード -
MYSQL_DATABASE
データベースの作成 -
MYSQL_USER
ユーザの作成 -
MYSQL_PASSWORD
作成したユーザのパスワード
初期データの作成
MySQLでは、docker-entrypoint-initdb.d
ディレクトリにソースコードを置くことで、コンテナ起動時に自動で初期データを作成することができます。
今回はホスト上の./docker/db_context/init/
にソースコードを作成して、コンテナ内のdocker-entrypoint-initdb.d
とボリュームマウントさせて、初期データを作成します。
./docker/db_context/init/init.sql
を作成します。
初期データの例
use sample_db;
create table sample_table(
id integer not null,
name char(20) not null,
primary key (id)
);
insert into sample_table(
id,name
)
values(
1,"sample_user"
);
ネットワークの作成
-
clientネットワーク
Webコンテナ - Appコンテナ間の通信に使用します。 -
serverネットワーク
Appコンテナ - DBコンテナ間の通信に使用します。
5. コンテナの起動
以下のコマンドでコンテナを起動します。
$ docker compose up --build
6. コンテナ間の通信
Webコンテナ - Appコンテナ
WebコンテナからAppコンテナにあるAPIを叩いてみます。
-
./web/sample.js
を作成
Dockerではコンテナ間でネットワークが繋がっているとサービス名を使って名前解決してくれます。
WebコンテナからAppコンテナはネットワークが繋がっているので、
URLはhttp://app
、ポート番号はFastAPIのデフォルトポート番号の8000を使います。
* ブラウザで動かす時( ReactやVue.jsなど )は名前解決してくれないので、http://localhost:8000/
を使います。
const appUrl="http://app:8000";
const fetchApp=async()=>{
const response= await fetch(appUrl);
const data=response.json();
return data;
};
(async()=>{
try{
const data= await fetchApp();
console.log(data);
}catch(error){
console.log(error);
};
})();
2.Webコンテナに入る
$ docker compose exec web bash
- Webコンテナ内で
sample.js
を実行
$ node sample.js
{"Hello":"World"}
がコンソールに表示されれば成功!
Appコンテナ - DBコンテナ
AppコンテナでDBコンテナからデータを取り出します。
-
./app/
にcon_db.py
を作成
import mysql.connector
cnx = mysql.connector.connect(
user='sample_user',
password='sample_user',
host='db',
database='sample_db')
with cnx.cursor() as cursor:
result = cursor.execute("SELECT * FROM sample_table")
rows = cursor.fetchall()
print("sample_table")
for rows in rows:
print(rows)
- Appコンテナに入る
$ docker compose exec app bash
-
con_db.py
を実行
$ python3 con_db.py
sample_table
(1, 'sample_user')
がコンソールに表示されれば成功!
まとめ
Docker Composeで Javascript・Python ( FastAPI )・MySQLのコンテナ作成と通信方法についてまとめました。
全体のソースコードはGitHubを参照してください!