LoginSignup
0
1

【移行・設計】centos7からalmalinuxへの移行Tips(K8s編②)

Last updated at Posted at 2024-04-29

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

目的

  • 2024年4月で、centos7からalmalinuxへの移行において、docker+minikubeを入れる方針で、minikubeインストールまでを行いました。
  • メモリ8GB、CPU4GBのノートPC環境下において、minikubeを利用しています。
  • しかしながら、1つのワーカノードを起動する度にデフォルトで2200MBのメモリを使用するため、ノートPCがリソース不足となることが判明し、下記のような影響が生じました。
    • インターネット検索、ウイルススキャンといった動作が遅延する
    • ワーカノードの起動時間に10分ほどかかっている
    • リソース不足になると、kubectlコマンドのレスポンスが遅い
  • 上記解消にはよりスペックの高いPCに変更しない限り難しいため、別なkubernetesのディストリビューションを入れることを検討しました
  • また、同時に新たなモダンアーキテクチャ構成を考えることとしました

内容

  • 前提として、minikubeよりも軽量のディストリビューションを検討した結果、軽量な2つのKubernetesディストリビューション(k3s、k3d)を候補としました。
    • k3sの場合、ワーカーノードを同一の仮想マシンに構築できないという制約がある
    • k3dでは、同一の仮想マシンにk3sのワーカノードとしてdockerコンテナを作成し、配下にPodを仮想的に作成することができます。反面、StatefulSetが公式サイトへ記載されてない面もあるため、データを永続化したり、レプリカデータベースを作成し冗長化したい場合は代替構成の検討が必要
  • 上記を踏まえて、k3dでの構築で舵を切りました

構築の大まかな流れ


構築のイメージ図

  • イメージ図は以下の通りです

  • 以下の構成が含まれる仮想サーバをノートPC上に作成しています

  • ディスク軽量化するため、コンテナイメージはalpineLinuxをベースとします


Webサーバ

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

APサーバ

  • :white_check_mark:APサーバ:TomcatからPythonに変更
    • 選定理由
      • Javaの実行環境はノートPC上でしか作業ができないため不便なのに対し、
        Pythonでの実装はGoogle Colaboratryでスマートフォンでの動作検証も手軽にできるため。
      • Metabaseで内部結合処理のSQLで、多くのJVMを消費する事象が発生しました
      • javaからpythonにすることで、メモリ消費量の削減を期待しました
      • 将来伸びる分野であろうデータ分析やAI、機械学習といった分野に対しての勉強も視野に入れます
      • https://engineer-style.jp/articles/8766#JavaとPythonのデメリットとは
    • 用途・役割
      • Flask、SQLAlchemy、Flask-Securityといったシンプルながらも拡張性・実装がしやすいモジュールを利用します
      • 自作アプリケーションを作成することも視野に入れます
    • 工夫点
      • アプリケーションの機能がわかるよう、フォルダ、ファイルを分けます
      • 紐付けするため、flaskのblueprintを利用しました
      • SQLalchemyを利用することで、SQL文を実装しない設計にします
      • 操作の種類単位にクラスを作ります
      • テーブルとクラスを1対1で対応させます
      • データフレームやピボット、プロットの作成が可能なpandasを導入します
      • グラフの保存はmatplotlibが必要なので必要であればインストールして使います
      • https://note.com/tobeblogger/n/n2250f1338922

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

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

DBサーバのストレージ

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

Pythonの実装方針

  • :white_check_mark: Flask、Pandas、SQLAlchemy、Flask-security、Matplotlibをpip installし導入します。

  • :construction: 作成するアプリケーションは下記の通り

    • flaskAPI

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

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

      • :construction: SQLはキーワードごとにまとめて、マッピングファイル化する
      • マッピングは「key,モード,SQLalchemyのメソッド名,タイムアウト値、任意パラメータ1~10まで」とする
        →キーワードだと複雑化したため、modelとrouteを分離して作成
      • タイムアウト値を超えたら強制終了する
      • モードは、以下モードに応じて、挙動変更を行う
      • モード:summary、
        • summary:結果OK、NGのみを返却
        • detail:詳細な結果を表示
      • イメージ図は下記の通り
      • MySQL1、MySQL2、MySQL3はpod。PodはKubernetesの仕様により、障害発生時再起動され、既存のデータベースに再接続する
    • BIツール(フォーマット可変)
      *

    • :construction: wordpress風のドキュメント作成ツール(markdownか、他で検討中)

    • :white_check_mark: APIのパステスト用実装

  • :construction: グラフつくる

  • :white_check_mark: web表示できるようにする

  • :construction: 外部から接続できるようにする

    • :construction: ロードバランサーでhttpsで待ち受けて、httpで受付する。
    • :construction: 証明書は以前から使っているSSL証明書を流用する
    • :construction: 外部接続をするために踏み台をもう一つ作る
    • :construction: 最低スペックの仮想サーバを使い、squidでプロキシする

構築方法

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

レジストリを登録

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の場合

Pythonの場合

  • 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を起動します。

    ###事前に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の場合

MySQLの性能を念のため確認

  • 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用サーバから接続する

  • https→http(ノードIPに接続)接続するサーバを外部に建てる
  • 自己署名書(SSL署名書)
    • LAMPサーバからずっと使用している大谷翔名書を利用する。
  • 通信経路
    • 外部通信は内部の仮想マシン(k3d Internal)のDockerBuildでImageのダウンロードに失敗することがあるため、

カスタムイメージの更新

  • k3dではイメージがプッシュできない事象があるようです。(バグかと思います)
  • registryのAPIを実行するやり方では削除は不可でした。
  • そのため、k3dクラスタを削除→再作成すると、イメージが作成できます。
    https://gist.github.com/takenoco82/b9559a1abd57eb0845a77041860cd26e
    https://qiita.com/tororoMeshi/items/98eac9b202adaa266d61
  • 下記の方法でクラスタ再作成をします。
    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:で記載)

:exclamation:1.k3dのコンテナイメージが正しく登録できない。削除もできない。
  • 事象として、ノード上で古いimageがpullされたままになる
  • 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のバグだと思われる。解決はできてないです。
  • 負荷をかけないようにするしかない
:exclamation: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を採用しようと考えています。
    • 案1:◎マウント状態確認(kubectl describe pv,pvc)し、紐づいていなければpodのデプロイをやり直しする
    • 案2:△1⇒2⇒3の順に起動できるようにマニフェストファイルに待機時間を入れる

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

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

参考

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