0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【移行・設計】almalinuxへのkubernetes導入Tips(k3d編②)

Last updated at Posted at 2024-04-29

※ 自分用メモのため、誤字脱字は後ほど修正します。
また、いくつか未完了部分は:construction: にしています。 ※

目的

  • 下記記事で、AlmaLinux8.9の仮想サーバの新設とminikubeのインストールを行いましたが、ノートPC環境下(メモリ8GB、CPU4GB)において、オーバーヘッドが生じました。
  • 影響として、下記事象が発生しています。
    • インターネット検索、ウイルススキャンといった動作が遅延する
    • ワーカノードの起動時間に10分ほどかかっている
    • リソース不足になると、kubectlコマンドのレスポンスが遅い
  • スペックの高いPCに変更しない限り解消ができないため、別なkubernetesのディストリビューションを入れることを検討しました
  • また、収支管理目的で構築したLAMPサーバ(Apache、Java、MySQL等)の新たなモダンアーキテクチャ構成も考えることとしました

内容

  • minikubeよりも軽量なKubernetesディストリビューション(k3s、k3d)を候補としました。
    • k3sの場合、ワーカーノードを同一仮想マシンに構築できないという制約があるのに対し、k3dでは、ワーカノードを同一仮想マシンに構築することが可能です。
    • k3dの実態は、ワーカノードをコンテナとして作成し、k3sのプロセスを起動し、コンテナ内部でPodを作成しています。
    • 反面、StatefulSetが実現できず、レプリカデータベース用のPodを作成することはできません。
    • データ永続化・冗長化の要件を実現したい場合、代替構成の検討が必要です。
    • deploymentを3つ構成し、マスタデータベースでの障害発生時、他のデータベースへ接続先を手動切替する方針で検討しました。
  • 上記を踏まえて、k3dでの構築する方針としています。

構築の大まかな流れ


構築のイメージ図

  • イメージ図は以下の通りです
  • 仮想サーバ1台をノートPC上に作成しています。
  • ディスク使用率を節約するため、コンテナイメージはalpineLinuxをベースとします

k3dとしてのアーキテクチャ

  • 1つの仮想サーバに下記のコンテナ(Loadbalancer、MasterNode、WorkerNode1、WorkerNode2)が搭載されています。

k3dのアーキテクチャ(Pod含む)

  • Deployment、Service、Pod、PersistenVolumeを含む構成としては下記の通りとなっております。
  • SharedDiskの箇所は、仮想マシンの共有ディレクトリをマウントしています。

Webサーバ

  • :white_check_mark:Webサーバ:ApacheからNginxに変更
    • 選定理由
      • Nginxはアクセスを振り分ける負荷分散やApacheよりも処理性能が高いため
    • 用途・役割
      • 外部アクセスをhttps通信で受付し、PythonPodへhttpリスエストするようプロキシします
      • nginxのPodからservice経由で、PythonのPodへ接続します。
        • serviceの名前解決を利用し、nginxからPythonへの接続設定を行います
      • パスベースで転送先を設定します

APサーバ

  • :white_check_mark:APサーバ:TomcatからPythonに変更
    • 選定理由
      • PCのオーバーヘッド防止
        • javaからpythonにすることで、メモリ消費量の削減を期待したため
        • Metabaseの内部結合処理で、JavaVMで使用するメモリを多く消費するため
      • Pythonでの実装はGoogle Colaboratryでスマートフォンでの動作検証も手軽に実施できるため
      • 将来性の期待
        • データ分析やAI、機械学習分野の知識習得も視野に入れたため
      • 参考
    • 用途・役割
      • Flask、SQLAlchemy、Pandasといったシンプルながらも拡張性・実装がしやすいモジュールを利用します
      • 自作アプリケーションを作成することも視野に入れます
    • 工夫点
      • 機能の細分化
        • アプリケーションの機能がわかるよう、フォルダ、ファイルを分けます
      • アプリケーション間の紐づけ
        • Web-APサーバ間:Flaskのblueprintを利用
        • AP-DBサーバ間:SQLAlchemyを利用
      • SQLalchemyを利用することで、pythonのソースコードにSQL文を実装しない設計にします
      • 操作の種類単位にクラスを作ります
      • テーブルとクラスを1対1で対応させ、Modelsを用います。
      • データフレームやピボット、プロットの作成が可能なpandas、plotlyを導入します

DBサーバ(deploymentとserviceを構築)

  • :white_check_mark:DBサーバ:MySQLで現状維持(バージョンアップは行う)
    • 選定理由
      • 既存SQLの作りこみもあり、他のDBMSへの移行が難しくなるため、MySQLを採用します
    • 用途・役割
      • データの保管・集計を行います
    • 工夫点
      • デフォルトではソケット通信が採用され、3306ポートがListenせず、localhostのみアクセスができません
      • そこで、下記を変更することで、MySQLコンテナ上で3306ポートをListenしています
        • MySQLのbind-address = 0.0.0.0に変更
        • MySQLのskip-network設定は除外
        • 3306ポート及びソケットファイルを定義
      • 更新・参照のServiceは別々とします(masterデータベースのみ書き込みできるようにするため)
        • データベース読込用と書込用とでServicePortを分ける
          • R/W用 Service Port:3306→TargetPort:3306
            (Selectorでマスターデータベースのみに接続制限)
          • R/O用 Service Port:3307→TargetPort:3306
      • データ更新
        • 下記で扱ったダンプファイルをエクスポートし、MySQLマスターデータベースに対して、インポートしています。

DBサーバのストレージ

  • PersistentVolume、PerisitentVolumeClaimを個々のMySQLpodに1つ割り当てます
  • MySQL-1、MySQL-2、MySQL-3に分け、ストレージもmysqlpv1、mysqlpv2、mysqlpv3と分けていきます

Pythonの実装方針

  • Flask、Pandas、SQLAlchemy、plotlyをpip installし導入します。
  • 作成するアプリケーションは下記の通り
    • flaskAPI

      • :white_check_mark: flaskをベースとしたアプリケーションにする
      • :white_check_mark: ページの動的作成
    • BIツール専用データベース管理

      • :white_check_mark: 給与
      • :white_check_mark: ライフライン
      • :white_check_mark: 支出
      • :white_check_mark: 収入
      • :white_check_mark: 健康管理
      • :white_check_mark: 株価
      • :white_check_mark: サーバ稼働情報
      • :white_check_mark: ログ保管
      • :white_check_mark: 待機系データベース状態確認
    • AP-DB間のマッピング

      • :white_check_mark: SQLはキーワードごとにまとめて、マッピングファイル化する
      • :white_check_mark: マッピングはFlaskのBlueprintで実装
      • イメージ図は下記の通り
      • :white_check_mark:MySQL1、MySQL2、MySQL3はpod。障害発生時、Pod(Kubernetes)の仕様により再起動し、既存のデータベースに再接続が可能
    • :white_check_mark:BIツール(フォーマット可変)

      • :white_check_mark: Plotlyによるデータベース可視化ツール作成
      • :white_check_mark: グラフの拡大・縮小
    • :construction: wordpress風のドキュメント作成ツール(markdownか、他で検討中)

    • Web-AP間のマッピング

      • :white_check_mark: APIの実装(各URLより、適切なテーブル・グラフを表示)
    • :construction: 外部から接続できるようにする

      • :white_check_mark: ロードバランサーでhttpsで待ち受けて、httpで受付する。
      • :white_check_mark: 証明書は以前から使っているSSL証明書を流用する
      • :construction: 外部接続をするために踏み台をもう一つ作る

構築方法

構築方法の流れをまとめました。

レジストリを登録

k3dでカスタムイメージを作成する場合、
コンテナベースのレジストリを登録する必要があるので作成します。

  • ディレクトリ作成
    mkdir -pv /datamnt/data ~/.k3d_t_kyn
  • ボリューム作成
    docker volume create local_registry docker volume ls | grep local_registrylocal
  • レジストリ用のコンテナ作成
    docker container run -d --name tkynregistry.local -v local_registry:/datamnt/imgs --restart always -p 5000:5000 registry:2.8.3

k3dクラスタ作成

k3dでクラスタ作成を行います。クラスタ作成時に下記も同時に作成します。
共有ボリュームと共有レジストリは、ワーカノードとホストマシンのディレクトリやファイルをマッピングします。
最上位のディレクトリを共有マウントとして利用します。
まとめると下記図表になります。

内容 構成
コントロールプレーン 1台構成
ワーカノード 2台構成
ロードバランサ 1台構成
共有ボリューム /datamnt/data=/datamnt/data
ローカルレジストリ ~/.k3d_t_kyn/t_kyn_config.tmplate=/var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl

上記の設定で、下記コマンドでクラスタ作成します。

  • クラスタ作成

    k3d cluster create --agents 2 --port "8080:30000@loadbalancer" --wait 0 --volume ~/.k3d_t_kyn/t_kyn_config.tmplate:/var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl --volume /datamnt/data:/datamnt/data
    
  • コンテナレジストリを作成し、起動・ホストOS上で名前解決できるようにします。
    これを行うことで、k3dのワーカノード上にカスタムイメージを利用したPodを、ワーカノード上に作成することが可能になります。

    # コンテナのネットワークを確認する+クラスタの名前を確認する
    docker network ls
    kubectl config get-contexts
    
    # クラスタをコンテナとネットワークを接続する
    docker network connect k3d-0 tkynregistry.local
    
    # コンテナレジストリへの起動確認
    curl -kv http://tkynregistry.local:5000
    
    # ホストへの登録をします。
    cat /etc/hosts | grep tkynregistry.local
    

コンテナのイメージ登録

  • コンテナのイメージを登録します。

NGINXのPod、Deployment、Service作成

PythonのPod、Deployment、Service作成

  • pythonのデフォルトコンテナイメージをpullします

    docker pull python:alpine3.18
    
  • Dockerfile及び、pythonファイルをカスタマイズします。

    ls -lrt /home/kubeuser/podmultinode/imagepython/Dockerfile
    vi /home/kubeuser/podmultinode/imagepython/Dockerfile
    →5000番はregistryでつかうので、5520に変更。
    →pip installするモジュールを選定し、必要なパッケージを入れてください。
    
  • Dockerfileをもとにデプロイします。

    # Dockerfileをもとにデプロイ
    cd /home/kubeuser/podmultinode/imagepython;docker build -t imagepython:v1.0.0 .;cd ~
    # ビルドしたイメージの登録(タグ付け)
    docker tag imagepython:v1.0.0 tkynregistry.local:5000/imagepython:v1.0.0
    # ローカルレジストリへpush
    docker push tkynregistry.local:5000/imagepython:v1.0.0
    
  • コンテナの動作確認をします

    docker images
    docker run -d --name testpythoncontaner imagepython:v1.0.0
    docker exec -it testpythoncontaner hostname -i
    curl http://CONTENANOIP:5520
    
  • pythonPod、Deploymentを起動します。

    ###事前にtestapp.pyを配置
    cp -pv /home/kubeuser/podmultinode/imagepython/testapp.py /datamnt/data/pyscripts/
    kubectl get pod
    kubectl apply -f /home/kubeuser/podmultinode/podpython.yml
    kubectl get pod
    
  • ※テスト確認

    kubectl describe service
    kubectl get pod,svc -o wide
    kubectl exec -it python-app-pod /bin/sh
    apk add curl
    hostname -i
    curl http://localhost:5520
    

参考:https://docs.docker.jp/engine/reference/commandline/build.html

Nginx→Pythonへの疎通確認

  • それぞれ下記コマンドで疎通確認可能です
    # コンテナ内部から
    curl http://nginx:30000/t_kyn_py_test/
    # コンテナホストから
    curl http://172.23.0.3:30000/t_kyn_py_test/
    

MySQLのPod、Deployment、Service作成

MySQLの性能を念のため確認

  • テスト用のテーブルを作成します
  • データを1万行挿入するプロシージャを作成し、繰り返し実行できる関数を作成します。
mysql -u root -p mysql
create table unko(id text);

DELIMITER //
CREATE PROCEDURE loop_insert()
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE max_count INT DEFAULT 10000;

WHILE i < max_count DO
INSERT INTO unko VALUES ('aaaaaaaaaa');
SET i = i + 1;
END WHILE;
END //

DELIMITER //
BEGIN
DECLARE i INT DEFAULT 0;
WHILE i < 1000 DO
CALL loop_insert();
SET i = i + 1;
END WHILE;
END //

CALL loop_insert(); CALL loop_insert(); CALL loop_insert(); CALL loop_insert(); CALL loop_insert(); CALL loop_insert(); CALL loop_insert(); CALL loop_insert(); CALL loop_insert(); CALL loop_insert(); CALL loop_insert(); CALL loop_insert(); CALL loop_insert(); CALL loop_insert(); CALL loop_insert();//
  • 結果としては、45万件の挿入は全く問題ありませんでした。

Loadbalancerについて

  • ロードバランサはk3dクラスタ作成時に
    「 --port "8080:30000@loadbalancer"」を指定して作成されるので、
    8080ポートでワーカノードの30000ポートに接続できるようにしていますので
    追加で行うことは特にしないです。
  • SSHポートフォワーディングすれば、ブラウザからの接続が可能になります。

:construction: ForwardProxy用サーバから接続する

  • nginxPodにhttps→http(ノードIPに接続)接続できるよう設定追加します
  • 自己証明書(SSL証明書)を利用します。
    • 旧LAMPサーバから利用しているSSL証明書を利用
  • 通信経路
    • 一般ユーザ(User)は、許可されたネットワーク機器からのみ接続可能
    • AdminUserはhttpsで直接接続する
    • AdminUser(PC)ではポートフォワーディング設定後、接続(非推奨)

カスタムイメージの更新

  • k3dではイメージがプッシュできないことがあります
  • 下記の方法でクラスタ再作成をします。
    kubectl delete -f /home/kubeuser/podmultinode/podnginx.yml
    kubectl delete -f /home/kubeuser/podmultinode/podpython.yml
    kubectl delete -f /home/kubeuser/podmultinode/podmysql.yml
    k3d stop cluster 0
    k3d cluster delete
    k3d create(同じコマンド)
    カスタムイメージのtag付け及びpush
    kubectl apply -f /home/kubeuser/podmultinode/podmysql.yml
    kubectl apply -f /home/kubeuser/podmultinode/podpython.yml
    kubectl apply -f /home/kubeuser/podmultinode/podnginx.yml
    
  • system pruneはイメージファイル含めて削除する可能性が高いため非推奨です。
    docker system prune -f

k3dクラスタの再起動

  • クラスタ再作成せず、継続利用する場合、下記コマンドでクラスタ再起動が可能です。
    # k3dクラスタの停止
    k3d cluster stop 0
    # k3dクラスタの起動
    k3d cluster start 0
    

PythonからMySQLへの接続確認

  • 事前に、pip install mysql.connector
    を行った後、下記コマンドでデータベース検索を行います。
  • つながらない場合はリスナーが起動していないと思われますので、下記対応
    • MySQLの設定ファイルより、bind-addressの設定を0.0.0.0にする
    • Python側で設定しているMySQL接続パスワードが正しいか確認する
      import mysql.connector
      
      # MySQLサーバーの接続情報を設定
      config = {
        'user': '★秘密★',
        'password': '★秘密★',
        'host': '★秘密★',
        'database': '★秘密★',
        'port': 秘密  # ポート番号を指定
      }
      
      # MySQLサーバーに接続
      try:
          conn = mysql.connector.connect(**config)
      
          if conn.is_connected():
              print('MySQLに接続しました')
      
              # クエリを実行するためのカーソルを作成
              cursor = conn.cursor()
      
              # クエリを実行
              cursor.execute('SELECT count(*) FROM user_tables;')
      
              # 結果を取得
              rows = cursor.fetchall()
              print('取得した行数:', len(rows))
              for row in rows:
                  print(row)
      
      except mysql.connector.Error as err:
          print('MySQLに接続でエラーが発生しました:', err)
      
      finally:
          # 接続をクローズ
          if 'conn' in locals() and conn.is_connected():
              cursor.close()
              conn.close()
              print('MySQL接続をクローズしました')
      

トラブルシューティング

k3dクラスタもコンテナ全削除を削除するとき

  • k3d cluster delete 0
  • docker network disconnect k3d-0 t_kyn_registry_host
  • docker network rm k3d-0
  • それでも消えなかったら「docker system prune -f」する

k3dの様々なバグ

様々な不具合が出たので、検討のうえ対策を施しました。
一部は恒久的に難しい課題があるため、暫定対応で対処しています(:exclamation:で記載)

:white_check_mark:1.k3dのコンテナイメージが正しく登録できない。削除もできない(課題)
  • imageがRegistryに最新imageが登録されているのにもかかわらず、ワーカノード上で参照するイメージが最新化できない。
  • 暫定としては、k3dクラスタ再作成で今後も運用していきます
  • それでも解決しない場合、「docker system prune -f」で削除してから再登録
:white_check_mark:2.MySQLコンテナ起動時、CPUが高騰する
  • イメージファイルでのentrypoint.shでncコマンドでwhileループをかけている。その処理は不要にして削除しています。
  • ENTRYPOINT ["/entrypoint.sh"]
    CMD ["mysqld", "--user=mysql", "--datadir=/var/lib/mysql"]
    から、
    command: ["sh", "/entrypoint.sh"] とするように修正することで解決しています
:x:3.CPU Limits設定できない。
  • k3dのバグだと思われる。解決はできてないです。
  • 負荷をかけないようにする以外に解決策がないため、pod、node、仮想マシンのCPU使用率を1分間隔で取得し、結果を解析するようにしたいと思います(実装中です)
:x:4.k3dで使用できるカスタムイメージの削除APIが使えない。
  • 下記はサポートされてなかったので使えない。解決不可。
  • 暫定としては、「docker system prune -f」で削除
      curl -X GET -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -s -D - http://tkynregistry.local:5000/v2/imagemysql/manifests/v1.0.0| grep Docker-Content-Digest:
      curl -X DELETE -D - http://localhost:5000/v2/imagemysql/manifests/sha256:3d1243e60f980f5510c3642c60b596aa9750b846c15ee2ca957614fc9b32d00c
    
:white_check_mark:5.MySQLはデフォルトで外部接続設定は許可されてない。ポートもListenしない。
:white_check_mark:6.MySQLのデータベースで、AccessDenyで接続できない
  • Service名とPort指定で接続できた
  • MySQLのデータベースのPrivilageの設定を実施
:question: 7.MySQLのPod起動時、ymlに指定するPersistenVolumeが適切なPodへマウントできない(例)MySQL1⇒PV3にマウントされる)
  • Podの起動順序があっていない
  • 対処方法としては、下記2案で検討中ですが案1を採用し、スクリプト開発済みです。
    • :white_check_mark:案1:◎マウント状態確認(kubectl describe pv,pvc)し、紐づいていなければpodのデプロイをやり直しするスクリプトを開発
    • :x:案2:△1⇒2⇒3の順に起動できるようにマニフェストファイルに待機時間を入れる

Pythonでの実装検討(次回予告)

  • 「Pythonの実装方針」に記載はしている点と重複しますが、次章で下記内容を記載します
  • どの画面からどの画面(URL)に遷移するのかの図も整理していこうと思います
    • FlaskAPI
      • :white_check_mark:データ表示、データモデルの定義
      • :white_check_mark:クライアントからのリクエストを適切なテーブルへ割り振り
      • :construction:アプリケーションの認証機能
    • SQLAlchemy
      • :white_check_mark:SQL実行、データマッピング
    • Pandas
      • :white_check_mark:データフレーム・レイアウトの定義
    • Plotly
      • :white_check_mark:グラフ作成

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?