目的
- 「QOL向上」を目的として旧LAMPサーバを構築してきました。
- 旧LAMPサーバでは、収支管理、健康管理目的で使用しておりますが、新機能を今後追加していくため、機能が膨大になり管理できなくなる懸念があるため、今までの機能も見直しを進めていきます。
- また、旧LAMPサーバは、定期的なセキュリティバージョンアップとモジュール管理ができてないため、下記も検討しています。
- コンテナイメージを作成・定期的なバージョンアップをする。
- k3dベースへのアーキテクチャシフトする
- モジュール管理として、Github(プライベートリポジトリ)で構成管理する
- 旧LAMPサーバでは、BIツールでJavaVMのメモリを多く使用し、OSがフリーズする事象が発生していました。
- 対策として、BIツールをCPU負荷をメインとしたpythonベースの自作アプリケーションに変更します。(JavaよりもPythonのほうがデータ分析やAI、機械学習と幅広く使われている点と、googlecolaboratoryでの実行も可能なため、学習範囲が広げやすい点より、新機能をより円滑にエンハンスするという狙いもあります。)
- PCのディスク使用量削減のため、新LAMPサーバと旧Kubernetesサーバは廃止し、k3dサーバを搭載したサーバに統合します。(下図イメージ)
- アーキテクチャ変更により、詳細な設計・実装を行います
前提
- 本来、要件整理後、アーキテクチャ構築を進めるべきですが、動作検証を優先するため、アーキテクチャ構築を先にしています。
- k3dクラスタベースの下記アーキテクチャを構築しております。
- ロードバランサ(k3dベース)
- Nginx(Deployment)
- Python(Deployment)
- MySQL(Deployment)
- 上記アーキテクチャを構築した前提で、アプリケーションの実装まで検討します。
システム化の方針
- 要件定義以前に、そもそも何を実現していくか
- まず、今までの構築したLAMPサーバとして、何が必要か不要かを判断し、システム化の方針を立てます
誰に対しての開発か
- 自分のみならず、妻、家族
目的の再確認
- 目的は「QOL向上」ですが、もう少し分類します。
- スキルや趣味の開発(個人スキル向上)
- 健康への配慮(睡眠時間、メンタルケア)
- 家族のコミュニケーション向上(アルバム作成)
- 時間の管理(優先順位付けの向上)
システム化の方針の整理
- 具体的にすると以下の4つで、個人開発としてどういう技術でアプローチしていくかを考えます
- 整理した結果、下記3つは必要なので、
- スキルや趣味の開発(個人スキル向上)
- 健康への配慮(睡眠時間、メンタルケア)
- 家族のコミュニケーション向上(アルバム作成)
スキルや趣味の開発(重要度:★★★)
- 目標:個人のスキルアップ
- 現状:個人開発での、技術要件定義スキル強化が乏しい
- 課題:マネジメント業務が重きとなっており、業務でのモダンな技術経験が希薄
- 解決策:個人でのアプリ開発向上、データ分析、運用スキルの向上
- 期待値①:アプリ開発・運用管理での上記機能が使いこなせること。
- 期待値②:新規機能追加(写真管理のアルバム管理+旅行・レシピなどの提案企画支援)
- 使用技術:既に利用している下記を利用
- Nginx(html、css、javascript)
- python(Flask、FastAPI、SQLAlchemy、Pandas)
- MySQL
- k3d
- Github(構成管理、スケジュール管理)
健康への配慮(重要度:★★☆)
- 目標:メンタルヘルスのケア、リラックスする時間を確保
- 現状:勤怠管理から勤務時間を割り出したり、iPhoneの行動記録やジムでのトレーニング実績の分析は可能
- 課題:個人および妻のメンタルケアが必要不可欠。
- 解決策:メンタルヘルスの情報サイト一覧作成、睡眠・トレーニング記録管理
- 期待値①:ジム通いを週2~3は維持できること。
- 期待値②:個人開発の時間を減らし、睡眠・趣味の時間に充てられること。
- 使用技術:既に利用している下記を利用
- Nginx(html、css、javascript)
- python(Flask、FastAPI、SQLAlchemy、Pandas、Plotly)
- MySQL
- k3d
- Github(スケジュール管理)
家族のコミュニケーション向上(重要度:★★★)
- 目標:家族との団欒を増やす
- 現状:家族とのコミュニケーションを維持できてない
- 課題:現状の通り
- 解決策:維持できるためのツール導入(アルバムとチャット機能作成)
- 期待値:家族とのコミュニケーションを支援するコンテンツ作成
- 役割:アルバム、データ分析などを通じたつながりの維持支援
- 使用技術:既に利用している下記を利用
- Nginx(html、css、javascript)
- python(Flask、FastAPI、SQLAlchemy、Pandas)
- MySQL
- k3d
- Github(スケジュール管理)
時間の管理(重要度:対象外)
時間管理に関しては、Github(ProjectによるBacklog利用)で事足りるため、
対象から外すことにしました。
- 目標:時間を有効活用する
- 現状:メモとかで管理している
- 課題:プライベートでの時間管理ができてない
- 解決策:行動履歴と優先順位を立てるとともに、タスクに対して時間記録と分析をする
- 期待値①:タスク優先順位設定の判断が早まること
- 期待値②:タスクの時間記録
システム化の方針から機能要件・非機能要件整理
機能要件
- 下記を1つのサーバで行います
- スキルや趣味の開発(個人スキル向上)
- 健康への配慮(睡眠時間、メンタルケア)
- 家族のコミュニケーション向上(アルバム作成)
- システム化の方針から機能要件を大枠レベルで整理します。
- 画面設計(画面一覧、画面遷移、画面レイアウト)
- ログイン機能
- 画面遷移(ログイン→Top画面→各メニューの画面一覧)
- 収支計算、健康管理の画面
- アルバムコンテンツ作成
- URL一覧
- API設計(URL一覧、処理内容)
- 収支計算、健康管理の表、グラフURL
- アルバムコンテンツのURL
- URL一覧
- 外部インターフェース設計(外部サイトとのやりとり、通信フロー)
- アルバムコンテンツの保管先サーバへの通信
- URL一覧
- DB設計(テーブル定義)
- 収支計算、健康管理のテーブル定義
- 処理パターン(オンライン、バッチ)
- オンライン:スマホからの打鍵
- バッチ:各種メンテナンス
- ログバックアップ・削除・圧縮
- 統計情報収集(k3d、OS、コンテナ)
- k3d起動・停止、k3dクラスタ再作成
- イメージアップデート(難易度高め)
- データベースエクスポート・インポート
- 画面設計(画面一覧、画面遷移、画面レイアウト)
非機能要件
- AWSのWell Archtected Flameworkの考え方を参考にしていますが、セキュリティ、可用性、性能、メンテナンス、コストの5観点に加え、移植性についての要件になります。
- セキュリティ要件(アクセス制御、データの暗号化など)
- ログイン、FlaskAPI、TFA
- Nginxでのアクセス制御
- システムの信頼性や可用性(障害時の復旧能力、システムの稼働時間など)
- k3dの導入(Kubernetesアーキテクチャ環境)
- ファイルバックアップ
- 制約:データベースが単一障害点となるため、その考慮点と対策
- データベースバックアップ・リストア・エクスポート・インポート機能
- パフォーマンス(応答時間、処理能力など)
- FlaskAPIとFastAPIベースのPythonフレームワークを利用
- 運用(メンテナンス)
- 汎用化するため、Blueprint、オブジェクト指向プログラミングを活用する
- ソースコードをGithubで管理する
- k3dの起動停止スクリプトを開発する
- k3dはバグだらけなので、バグを受容しつつ、回避策用のスクリプトを開発する
- コスト
- 無料で使うため、OSSを利用する。
- 移植性
- 異なるOSに移行することを考慮し、マニフェストファイルを管理する
- データエクスポートはmysqldumpコマンド、インポートはmysqlコマンドを利用
- セキュリティ要件(アクセス制御、データの暗号化など)
- 使用する技術やプラットフォームの制約
(ハードウェアの仕様、ソフトウェアのバージョンなど)- 仮想マシンは、VMWareを引き続き利用。OSはAlmaLinux8.9を採用する。
- システムの利用環境に関する要件(言語、地域、ユーザーの文化的背景など)
- 特にないが、日本語ベースとする。地域も日本。
考慮すること
- 実テーブルを複数使用する場合、内部結合したビューを作成し、管理します。
- データベース破損に備え、データベースをファイルエクスポートし、Slaveデータベースへインポートする処理を定期実行します。
- PythonのCPU、メモリ負荷を減らすため、loggerによるログ出力は必要最小限とします。
- ブラウザからの接続は秘匿情報の盗聴を防ぐため、https接続のみ許可します。
詳細設計(実装方針・イメージ)
- pythonでの実装方法を検討します。
モジュール
- flask,flasksecurity,pandas,sqlalchemy,plotlyが必要そうです
- plotlyとはデータからグラフ描画・可視化をする機能です。
- Matplotlibとは違い、plotlyではマウス操作での拡大縮小も可能なのが特徴です。
ライブラリ | 用途 |
---|---|
Flask | ウェブアプリケーションやAPIの開発 |
SQLAlchemy | SQLデータベースとの対話、オブジェクトリレーショナルマッピング(ORM) |
plotly | グラフの描画や可視化 |
Pandas | 表形式のデータ操作や解析 |
NumPy | 数値計算や配列操作、科学技術計算、データ分析 |
openai | 各種提案※外部APIの利用 |
ディレクトリ構成
-
下記役割を分けるようディレクトリ作成し、pythonスクリプトを作成し、配置ています。
pyscripts ├testapp.py(メインスクリプト) └content ├t_kyn_connection(データベース接続) ├t_kyn_models(データモデル定義) ├t_kyn_operations(データ操作) ├t_kyn_routes(URLとAPI操作とのマッピング) └t_kyn_views(表示テンプレート定義)
-
データモデル定義
- pythonのSQLAlchemyのmodelsで定義します(以下は一例)
from sqlalchemy import Column, Integer, String, DateTime, BigInteger, Numeric, Float, Date from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class ActPlanHouserepaircostsTotalView(Base): __tablename__ = 'act_plan_houserepaircosts_total_view' #id = Column(Integer, primary_key=True) aphc_year = Column(Integer, primary_key=True) aphc_month = Column(Integer, primary_key=True) aphc_payment = Column(Numeric)
- pythonのSQLAlchemyのmodelsで定義します(以下は一例)
-
データ操作
- 操作単位で定義します。例えば、データベースのデータをSELECTする場合、下記pandasを利用します(以下は一例)
import pandas as pd from t_kyn_connection.create_session import get_session import os import logging import matplotlib.pyplot as plt # ログ設定 logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) class DataViewer: def __init__(self): # セッションを取得 self.session = get_session() def view_all_data_as_html(self, table_class): try: # 全データを検索 logger.debug("データベースからデータを取得します") results = self.session.query(table_class).all() logger.debug(f"取得したデータの数: {len(results)}") if results: # 検索結果をデータフレームに変換 logger.debug("データフレームに変換します") columns = table_class.__table__.columns.keys() data = [tuple(getattr(result, column) for column in columns) for result in results] df = pd.DataFrame(data, columns=columns) logger.debug("データフレームの内容:\n%s", df) # データフレームをHTML形式で表示 html_table = df.to_html(index=False) logger.debug("HTML形式のデータ:\n%s", html_table) return html_table else: logger.debug("No data found in the table.") return "No data found in the table." except Exception as e: logger.error("Error occurred while viewing data: %s", e) return f"Error occurred while viewing data: {e}" finally: # セッションをクローズ self.session.close()
- 操作単位で定義します。例えば、データベースのデータをSELECTする場合、下記pandasを利用します(以下は一例)
-
URLとAPI操作とのマッピング・データ表示
- FlaskのBlueprint, render_templateを用いて、テンプレート用のhtmlファイルを利用し、動的ページを作成します。(以下は一例)
import sys from flask import Blueprint, render_template # Create a Blueprint act_plan_houserepaircosts_total_view_bp = Blueprint('act_plan_houserepaircosts_total_view_bp', __name__) act_plan_houserepaircosts_total_view_graph_bp = Blueprint('act_plan_houserepaircosts_total_view_graph_bp', __name__) sys.path.append('/app') @act_plan_houserepaircosts_total_view_bp.get('/') def execute_sample_task(): sys.path.append('/app/content') from t_kyn_operations.select_args_10desc import DataViewer from t_kyn_models.models_t_kyn_act_plan_houserepaircosts_total_view import ActPlanHouserepaircostsTotalView data_viewer = DataViewer() html_table = data_viewer.view_all_data_as_html(ActPlanHouserepaircostsTotalView) return render_template('data.html', table=html_table)
- FlaskのBlueprint, render_templateを用いて、テンプレート用のhtmlファイルを利用し、動的ページを作成します。(以下は一例)
-
表示テンプレート定義
- data.htmlを定義します。これにより、各テーブルごとにhtmlファイルを用意する必要がなくなります(以下は一例)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Data Table</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> </head> <body> <div class="container mt-5"> <h1>Data Table</h1> <div class="table-responsive"> {{ table|safe }} </div> <div class="mt-3"> <button class="btn btn-primary" onclick="goBack()">戻る</button> </div> </div> <script> // 戻るボタンの関数 function goBack() { window.history.back(); } </script> </body> </html>
- data.htmlを定義します。これにより、各テーブルごとにhtmlファイルを用意する必要がなくなります(以下は一例)
-
グラフ表示
- plotlyを用いて、グラフ作成します(以下は一例)
@act_plan_houserepaircosts_total_view_graph_bp.route('/') def execute_sample_plotgraphtask(): sys.path.append('/app/content') from t_kyn_operations.select_args_10desc import DataViewer from t_kyn_models.models_t_kyn_act_plan_houserepaircosts_total_view import ActPlanHouserepaircostsTotalView data_viewer = DataViewer() # データを取得してデータフレームに変換 df = data_viewer.get_data_as_dataframe(ActPlanHouserepaircostsTotalView) graphtitle = ActPlanHouserepaircostsTotalView.__tablename__ if df is not None: # グラフをプロット data_viewer.plot_data(df, 'aphc_month', 'aphc_payment', graphtitle) return 'Sample graph plot task executed successfully.'
- plotlyを用いて、グラフ作成します(以下は一例)
-
データアップロードダウンロード
- 実装方法を確認中
-
データエクスポート、インポート
MySQLのPodからデータベースをエクスポートし、MasterデータベースではないMYSQLのPodへデータインポートを行います。- MySQLダンプファイルをエクスポートするbashスクリプト
- MySQLダンプファイルからインポートするbashスクリプト
-
ログイン機能
- 実装方法を確認中
改善したい機能
- 住宅ローンのシミュレーション
- 1シミュレーション1テーブルとしており、複数のシミュレーション結果をグラフにする際、複数テーブルを結合してました。しかし、結合処理は応答時間が長くなるため、非効率です。
- 単一テーブルとし、シミュレーション毎に計算で出すようカラムを分けるよう変更します。
今後
- 画面遷移、データモデルをもう少し詳細化します
- 2024/9より、ローカルPC上のVMに構築ではリソースが足りないことが判明しました。ディスクサイズは問題ないとしても、CPUとメモリは共用で利用されることから、PC上から、クラウド(github codespaceかgoogle colabにデプロイ)する方針に梶をとります
- 2024/10 運用機能をいくつか追加するため、以下を対応しています。詳細事項は後続で記載予定です。
- ログ集約化(fluentdによる agentpod→serverpod )
- 監視要件として統計用スクリプトの追加
- デプロイ機能スクリプト追加
- codespaceによる接続確認(localhostでの接続確認)
参考
- flask-security
- セキュリティ
- パフォーマンス