フロントエンドはJava Scriptフレームワークの Next.jsをベースに作りました
バックエンド側は FlaskをAPIゲートウェイ的にたてて、Pythonでデータのやりとりの中心として作っていきます
開発環境全体像
Githubリポジトリ
GitHub - konchangakita/blog-loghoi: Nutanix log hoihoi
今日のブログ分は最終形態は blog/0821配下で
Docker Compose で起動してやると挙動を確認できます
# docker-compose -f "docker-compose.yml" up -d --build
バックエンドコンテナをつくる
Dockerhub の Python Official image をベースに必要なモジュール追加していきます
black:python用コードフォーマッター
elastic:Elasticsearch用
flask:FlaskでAPIゲートウェイとする
jupyter:ちょっとしたPythonコード確認用
paramiko:CVM へ ssh する用
requests:Prism REST API する用
こんな感じの requirements.txt を準備
black==23.7.0 elastic-transport==8.4.0 elasticsearch==8.9.0 Flask==2.3.2 Flask-Cors==4.0.0 Flask-SocketIO==5.3.5 jupyter-events==0.7.0 jupyter-lsp==2.2.0 jupyter_client==8.3.0 jupyter_core==5.3.1 jupyter_server==2.7.1 jupyter_server_terminals==0.4.4 jupyterlab==4.0.5 jupyterlab-pygments==0.2.2 jupyterlab_server==2.24.0 paramiko==3.3.1 requests==2.31.0
開発中のコンテナはこんな感じで
FROM python:3.11.4-slim RUN apt-get update -y RUN apt-get install -y curl RUN apt-get install -y ssh-client RUN pip install -U pip WORKDIR /tmp COPY ./requirements.txt . RUN pip install -r requirements.txt #CMD ["tail", "-f", "/dev/null"] #WORKDIR /usr/src/flaskr #CMD ["python", "app.py"]
今回もリアルタイムでコードを書きながら開発していきたいので、docker-compose.ymlファイルで、ローカルファイルシステムをマウントしておきます
version: "3.8" services: backend: build: context: ./backend dockerfile: dockerfile container_name: loghoi-backend ports: - 7776:7776 volumes: - ./backend/flaskr:/usr/src/flaskr:z command: bash -c "cd /usr/src/flaskr && tail -f /dev/null" working_dir: /usr/src/flaskr networks: - local frontend: build: context: ./frontend dockerfile: dockerfile container_name: loghoi-frontend ports: - 7777:7777 volumes: - ./frontend/next-app:/usr/src/next-app:z command: bash -c "cd /usr/src/next-app/loghoi && yarn && tail -f /dev/null" working_dir: /usr/src/next-app/loghoi networks: - local networks: local: driver: bridge
Flaskで初期設定
最小構成はこれだけでよいはず
./flaskr ├── app.py ├── static │ └── style.css └── templates └── index.html
まずは動作確認の為、シンプルに Webサーバたててみます
適当に style.cssを作って、 index.html を呼び出すだけの簡単な app.py を作ります
app.py
from flask import Flask from flask import render_template app = Flask(__name__) # Just for GUI @app.route("/") def index(): return render_template("index.html") if __name__ == "__main__": app.run(host="0.0.0.0", port=7776, debug=True)
Flask の起動
# python app.py * Serving Flask app 'app' * Debug mode: on WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:7776 Press CTRL+C to quit * Restarting with stat * Debugger is active! * Debugger PIN: 963-107-412
ブラウザにてhttp://開発サーバIP:7776/へアクセス
Flask で REST APIする
フロントエンドからのHTTPリクエストに応じてデータを返す REST API サーバを作ります
URI と メソッド(GET, POST など)の組み合わせで、Python内の関数を呼び出します
GET用, POST用の関数を作る
GET /get/test、POST /post/testそれぞれでテキストを返す簡単な関数です
from flask import Flask from flask import render_template from flask import request from flask import make_response, jsonify app = Flask(__name__) # Just for GUI @app.route("/") def index(): return render_template("index.html") # Rest API Test GET @app.route("/get/test", methods=["GET"]) def get_test(): data = 'GET saremashita' print(">>>>> response: ", data) return make_response(jsonify(data)) # Rest API Test POST @app.route("/post/test", methods=["POST"]) def post_test(): data = request.json print(">>>>> POST sareta: ", data) return make_response(jsonify(data)) if __name__ == "__main__": app.run(host="0.0.0.0", port=7776, debug=True)
REST APIのテストには、Postmanを使います
ブラウザ版を使うには、「Postman Agent」をインストールしておきましょう
Postman Agent: For Mac, Windows, & Linux
Elasticsearchとの連携
docker-compose.ymlに elasticsearch と kibana コンテナを追記します
(ゼロから作る場合は、「./elastic/es-data/node/.gitkeep」 を作っておきましょう)
version: "3.8" services: elasticsearch: image: elasticsearch:7.17.9 container_name: elasticsearch environment: - discovery.type=single-node ports: - 9200:9200 - 9300:9300 ulimits: memlock: soft: -1 hard: -1 volumes: - ./elastic/es-data:/usr/share/elasticsearch/data:z networks: - local kibana: image: kibana:7.17.9 container_name: kibana ports: - 5601:5601 ulimits: memlock: soft: -1 hard: -1 networks: - local backend: build: context: ./backend dockerfile: dockerfile container_name: loghoi-backend ports: - 7776:7776 volumes: - ./backend/flaskr:/usr/src/flaskr:z command: bash -c "cd /usr/src/flaskr && tail -f /dev/null" working_dir: /usr/src/flaskr networks: - local frontend: build: context: ./frontend dockerfile: dockerfile container_name: loghoi-frontend ports: - 7777:7777 volumes: - ./frontend/next-app:/usr/src/next-app:z command: bash -c "cd /usr/src/next-app/loghoi && yarn && tail -f /dev/null" working_dir: /usr/src/next-app/loghoi networks: - local networks: local: driver: bridge
REST API して Elasticsearch とやりとり
GET で Elasticsearch の インデックス一覧を返し
POST で インデックス名を送ると存在しなければ、インデックスを作る
というのを作ってみます
app.py
from flask import Flask from flask import render_template from flask import request from flask import make_response, jsonify from elasticsearch import Elasticsearch ELASTIC_SERVER = "http://elasticsearch:9200" es = Elasticsearch(ELASTIC_SERVER) app = Flask(__name__) # Just for GUI @app.route("/") def index(): return render_template("index.html") # Rest API Test @app.route("/get/test", methods=["GET"]) def get_test(): data = es.cat.indices(index="*", h="index").splitlines() print(">>>>> response: ", data) return make_response(jsonify(data)) # Rest API Test @app.route("/post/test", methods=["POST"]) def post_test(): data = request.json index_name = data['index'] indices = es.cat.indices(index="*", h="index").splitlines() if index_name not in indices: es.indices.create(index=index_name) res = index_name + " created" return make_response(res) print(">>>>> POST sareta: ", data) res = index_name + " is already exists" return make_response(res) if __name__ == "__main__": app.run(host="0.0.0.0", port=7776, debug=True)
これを実行してみます
python app.py
GET でインデックス一覧取得
POST でインデックス作成
new_index というインデックス名を POSTしてみます
インデックス名を GET すると「new_index」というのが作られています
まとめ
ここまでで開発に使うコンテナたちのベースが作られました
・フロントエンド:Next.jsをベースに JavaScriptでGUIを作る
・バックエンド:Flaskをベースに、フロントエンドからREST APIを受けて、Nutanixクラスタ、Elasticsearchからデータ入出力を行う
・Elasticsearch:外部データベース、サーチエンジンとして利用
次回からいよいよ各ページを作っていきます
まずは入口のページからです