Dockerで通信の流れを学んだ
Dockerの仕組みを学ぼうと思い、以下のサイトを参考にしてシンプルなプロジェクトにとりくんだ
学んだこと
- Dockerの構成
- 3つの間での通信方法
- WebページとWebサーバー間
- WebサーバーとバックエンドAPI間
- バックエンドサーバーとAPI間
今回のスタック
- Docker - バックエンドとフロントエンドのネットワークを共有する
- Express.js - Webサーバーとして、バックエンドAPIとの通信を可能にする
- Flask - Flask APIを使用して、APIとの通信を可能にする
- DEEPL API - 翻訳したテキストをバックエンドAPIに返す
Dockerの構成
Dockerfile
フロントエンド用のサーバーとバックエンド用のサーバーを用意する必要があります。
バックエンド・フロントエンドを扱っているそれぞれのフォルダのルートにそれぞれDockerfileを作成する必要があります。
以下のサイトのDockerfileを参考にしました。
ここでは、ローカルの環境をDockerの仮想環境にコピーするために必要なものを指定しています。
- スタック
- ディレクトリ
- コード
- コマンド
- ポート番号
docker-compose.yml
このファイルを使用して、フロントエンドとバックエンドが共有のインターネットを使用できるようにします。なので、このファイルの配置は、プロジェクトのルートに位置しないといけません。
version: '3.8'
services:
front:
build:
context: ./front
ports:
- 3000:3000
networks:
- app-network
depends_on:
- back
back:
build:
context: ./back
ports:
- 4000:4000
environment:
- DEEPL_API_KEY=${DEEPL_API_KEY}
networks:
- app-network
networks:
app-network:
driver: bridge
1. 共有ネットワーク
app-network
が共有ネットワークとして設定されています。これにより、front
とback
のサービスが同じネットワークに所属し、互いにアクセス可能になります。
yamlコードをコピーする
networks:
app-network:
driver: bridge
2. ネットワークドライバ
driver: bridge
はDockerのブリッジネットワークを使用することを示しています。ブリッジネットワークは、同じDockerネットワーク内のコンテナ間での通信を可能にします。
3. サービス間の通信
フロントエンドからバックエンドへの通信
- フロントエンドのExpress.jsサーバーがバックエンドのFlask APIにリクエストを送信する際、バックエンドサービスのホスト名
back
を使用します。 - これは、
app-network
内での名前解決により、http://back:4000
のようにアクセス可能になります。
3つの間での通信方法
自分なりの今回のプロジェクトの通信の流れを図にしてみました
通信の流れ
-
index.htmlとWebサーバー(express.js)間
- ユーザーがブラウザ上でindex.htmlを表示し、ボタンをクリックすると、ブラウザはExpress.jsサーバーにPOSTリクエストを送信します。
- Express.jsサーバーはこのリクエストを受け取り、適切なレスポンスを返します。
-
Webサーバー(express.js)とバックエンドAPI(Flask API)間
- Express.jsサーバーはaxiosライブラリを使用して、バックエンドのFlask APIに対してGETリクエストを送信します。
- Flask APIは、このリクエストを受け取り、処理を行います。
-
バックエンドAPI(Flask API)とDEEPL API間
- Flask APIは、DeepL APIに対してテキストの翻訳リクエストを送信します(GETリクエスト)。
- DeepL APIはリクエストを処理し、翻訳されたテキストをFlask APIに返します。
ファイルを見てみよう
front/public/index.html
<!DOCTYPE html>
<html>
<head>
<title>Hello World Page</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.16/dist/tailwind.min.css" rel="stylesheet">
#htmxを使用している
<script src="https://unpkg.com/htmx.org@1.6.1"></script>
</head>
<body class="grid items-center justify-items-center h-screen gap-4 bg-gray-200">
#ここにレスポンスで帰ってきたテキストがくる
<div id="response" class="text-center">Waiting for response...</div>
#hx-post="/api"によってwebサーバー(express.js)にPostリクエストが送られる
<button class="px-4 py-2 font-bold text-white bg-blue-500 rounded hover:bg-blue-700" hx-post="/api" hx-trigger="click" hx-swap="innerHTML" hx-target="#response">Click me!</button>
</body>
</html>
front/index.js
const express = require('express');
const axios = require('axios');
const app = express();
const port = 3000;
app.use(express.static('public')); // 静的ファイルを提供
// フロントエンドからのAPIリクエストを受け取る
app.post('/api', async (req, res) => {
try {
#axiosというライブラリを使用し、バックエンドに Getリクエストを送る
const response = await axios.get('http://back:4000');
console.log(response.data.translated_text)
#レスポンスをwebページに返す
res.send(response.data.translated_text);
} catch (error) {
console.error(`Error: ${error}`);
res.status(500).send('Internal Server Error');
}
});
app.listen(port, () => {
console.log(`App running on http://localhost:${port}`);
})
back/app.py
from flask import Flask, Response, request
import deepl
import os
import json
app = Flask(__name__)
#getリクエストをDeepl Apiに送る
@app.route('/', methods=['GET'])
def translate():
deepl_api_key = os.getenv('DEEPL_API_KEY')
translator = deepl.Translator(deepl_api_key)
#request.args.getを使用して、クエリパラメータから翻訳するテキストとターゲット言語を取得しています。
text = request.args.get('text', default="Hello, how are you?", type=str)
target_lang = request.args.get('target_lang', default='JA', type=str)
result = translator.translate_text(text, target_lang=target_lang)
response_data = {'translated_text': result.text}
response_json = json.dumps(response_data, ensure_ascii=False)
return Response(response_json, content_type='application/json; charset=utf-8')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=4000)
まとめ
動けばいいとか、他の人のコードを真似してできたっていう感じで開発していたから、エラーが出てきた時にどこに問題があるのかを見極めるのに時間がかかった。今回通信の方法を理解することができたので、今後の開発で問題の原因を以前よりも早く見つけられそう。
次は、データベースサーバーがここに加わるとどうなるのかについて勉強したい。
Discussion