Zenn
🌟

第2回 クラウド基盤mdxでKubenetes環境を構築する

2025/03/09に公開

この記事について

こんにちは、東京大学鈴村研究室で、インフラエンジニアとしてお手伝いさせていただいています、福田と申します。

https://sites.google.com/view/toyolab/鈴村研究室概要

今回のこの記事は、クラウド基盤mdxの上で、Kubernetes環境を構築する方法について、説明していきます。

前提

この記事では、構築されたmdxの仮想マシン上でKubernetes環境を構築する方法を中心に説明するため、前提である仮想マシンを立ち上げるための手順については、詳しくは説明しません。
mdxで仮想マシンを立ち上げるための詳しい手順については、以下の記事一覧の第1回を参照ください。

https://zenn.dev/suzumura_lab/articles/627b5063d6884d

本記事で使用するソースコードについて

本記事では、以下のGitHub repositoryのコードを使用します。
https://github.com/fukumame/k8s-configs

なお、上記のレポジトリは、a-sugiki氏のレポジトリをforkして、より安定して動くように改良させていただきました。
a-sugiki氏には、心からの感謝と敬意を表したいと思います。

mdx仮想マシン上でkubernetesを立ち上げる手順

さて、本題に入りたいと思います。

前回の記事では、mdx上で踏み台(bastion)サーバを構築する手順を説明しました。

今回、Kubernetesを構築するためには、1台のmaster nodeと、少なくとも1台以上のworker nodeが必要です。

また、最終的には、構築したKubernetes環境で、複数のインスタンスを用いた深層学習の分散学習や、LLMをRest APIとしてServingすると行った事を行って行きますので、worker nodeはGPUインスタンスを使用することを前提とします。
一方、master nodeはGPUは不要ですので、CPUインスタンスで問題ありません。

まとめると、最低限以下の仮想マシンが必要になります。

種別 必要台数 必要スペック OS
master node 1台 CPUインスタンス
CPU8コア以上
ストレージ容量50GB以上
ubuntu 22.04
worker node 1台以上 GPUインスタンス
GPU1コア以上
ストレージ容量100GB以上
ubuntu 22.04

これらの仮想マシンについて、前回の記事をもとに、デプロイを行います。

踏み台サーバから、これらのサーバに対してsshアクセスする際、sshキーやパスワードの入力をしなくても、アクセスできるようにしたいため、踏み台サーバと同じssh公開鍵を設定します。

踏み台サーバへのsshアクセス

次に、踏み台サーバにsshコマンドでアクセスします。
その際、踏み台サーバから、他のサーバにssk秘密鍵の入力なしでアクセスできるように、ssh-agentを有効にします。 sshコマンドにAオプションをつけると、このsshの転送エージェントが有効になります。

eval `ssh-agent`
ssh-add
ssh -A (踏み台サーバのIPアドレス)

必要なライブラリのインストール

踏み台サーバにアクセスしたら、以下のコマンドでAnsibleをインストールします。

sudo apt update
sudo apt install ansible

そして、Pythonのパッケージマネージャーである、uvをインストールします。

curl -LsSf https://astral.sh/uv/install.sh | sh

先述の、mdxでKubernetesを構築するためのAnsible playbookが格納されている、k8s-configをgit cloneします。

git clone https://github.com/fukumame/k8s-configs.git

cloneしたk8s-configsのディレクトリに移動します

cd k8s-configs

uvを使って、必要なPython packageのインストールと、Python仮想環境の構築を行います。

uv sync

以下のコマンドを実行し、その他必要なライブラリをインストールします。

sh install_dep_packages.sh

inventory.iniの作成

inventory.ini.templateをコピーして、inventory.iniの雛形を作成します。

cp inventory.ini.template inventory.ini

inventory.iniの中身は以下の通りです。
このファイルに対して、Kubernetes構築に必要な項目を入力していきます。
編集にあたっては、VimやEmacs, nanoなど、好きなeditorを使ってください。

[bastion_host]
bastion ansible_host=

[registry]
harbor ansible_host=

[kube_master]
kube-master ansible_host=

[kube_node]
kube-node1 ansible_host= roce_host=
kube-node2 ansible_host= roce_host=

[kube_gpu]
kube-gpu1 ansible_host= roce_host=
kube-gpu2 ansible_host= roce_host=

[kube_worker:children]
kube_node
kube_gpu

[kube_cluster:children]
kube_master
kube_worker

[kube_master:vars]
roce_netif = ens160np0

[kube_node:vars]
roce_netif = ens160np0

[kube_gpu:vars]
roce_netif = ens192np0

まず、[bastion_host] の欄です。
ここには、踏み台サーバのIPアドレスを設定します。
踏み台サーバは自分自身のIPアドレスなので、127.0.0.1を設定します。

[bastion_host]
bastion ansible_host=127.0.0.1

[registry]の欄について、ここはprivateなDocker container registoryである、harborを構築するために必要な設定ですが、今回はharborを使うことは想定していないので、この項目は削除して大丈夫です。

[kube_master]の欄について、ここは、master nodeのIPアドレスを設定します。

[kube_master]
kube-master ansible_host=(master nodeのIPアドレス)

[kube_node] の欄について、ここは、worker nodeでCPUノードが必要な場合は記載しますが、本手順においては、GPUノードのみを使用するため、この項目は削除して大丈夫です。

[kube_gpu]の欄については、ansible_hostの設定は、masterノードと同様、workerGPUノードのIPアドレスを設定すれば大丈夫です。

次に、ここのroce_host=の記載方法について説明します。
RoCEとは、RDMA(Remote Direct Memory Access)をIPネットワーク越しに⾏う技術であり、mdxでは、このRoCEの機構が備わっています。

このRoCEを使用するためには、RoCE用のIPアドレスが必要ですが、これは、mdxのユーザーポータルにログインし、対象サーバの設定画面を見ることで確認できます。

以下の仮想マシン一覧の確認画面にある、「ストレージネットワーク 1」の「IPv4アドレス」がこのRoCEのIPアドレスに相当します。

このIPアドレスをコピーして、roce_host=の値として設定します。

ansible_hostroce_hostを合わせた、kube_gpuの欄の定義例は以下の通りです。
(IPアドレスはこの手順用にランダムな値を設定しています。)

[kube_gpu]
kube-gpu1 ansible_host=172.16.0.3 roce_host=192.168.0.3

[kube_worker:children]の項目について、今回は、GPU nodeだけを対象とするため、kube_nodeの部分は削除します。

次に、[kube_master:vars]roce_netifに設定すべき値について説明します。

まず、sshで対象サーバにログインします。
この場合、master nodeを対象としているので、master nodeに入ります。
ssh-agentを使って、sshの転送エージェントの設定をしているので、特に秘密鍵の入力はしなくても、ログインできます。

ssh (GPU nodeのIPアドレス)

コマンド ip -br addr を入力します。
すると、以下のような結果を得ます。 (IPアドレスについては、この手順用にランダムな値で書き換えています。)

ip -br addr
lo               UNKNOWN        127.0.0.1/8 ::1/128
ens990           UP             192.168.0.1/21 xxxx:xxxx:xxxx/64
ens991           UP             192.168.0.2/21 xxxx:xxxx:xxxx/64

この一覧で、[kube_master]の項目の、roce_host=で設定したIPアドレスと一致する行を探します。
この例で言えば、roce_host=192.168.0.2として設定されていた場合、ens991の行が一致する行となります。

ここで、ens991がネットワークインターフェース名として、roce_netifに設定すべき値となります。 定義の例は以下の通りです。

[kube_master:vars]
roce_netif = ens991

同様に、[kube_node:vars]roce_netifについても、GPU nodeにsshログインし、同じ手順に従って、ネットワークインターフェース名を取得し、設定します。
定義の例は以下の通りです。

[kube_gpu:vars]
roce_netif = ens891

[kube_node:vars] については、今回はWorkerノードはGPUインスタンスのみであるため、削除してOKです。


まとめると、全体としてinventory.iniは以下のようになります。

[bastion_host]
bastion ansible_host=127.0.0.1

[kube_master]
kube-master ansible_host=(masterノードのIPアドレス)

[kube_gpu]
kube-gpu1 ansible_host=(gpu workerノードのIPアドレス) roce_host=(gpu workerノードのストレージネットワーク1のIPv4アドレス)

[kube_worker:children]
kube_gpu

[kube_cluster:children]
kube_master
kube_worker

[kube_master:vars]
roce_netif = ens991 # このネットワークインターフェース名は適当です

[kube_gpu:vars]
roce_netif = ens891 # このネットワークインターフェース名は適当です

vault.yamlの作成

この手順では、Kubernetesのサーバ監視ツールである、Grafanaをインストールするため、Grafanaのパスワードをvault.yamlに設定し、安全に管理できるように暗号化します。

まず、vault.yaml.templateをコピーします。

cp vault.yaml.template vault.yaml

好みのエディタでvault.yamlを開きます。
harbor_admin_passwordとharbor_db_passwordについては、本手順ではharborを使わないため、設定しません。
Grafanaについては、任意のパスワードを設定します。

---
harbor_admin_password:
harbor_db_password:

grafana_password: (任意のパスワード)

以下のコマンドを実行し、vault.yamlファイルの暗号化を実施します。

uv run ansible-vault encrypt vault.yaml

コマンドを発行すると、パスワードの入力を求められるので、任意のパスワードを設定します。
ここで設定したパスワードは、ansible-playbookコマンドを実行し、Kubernetes環境を構築するときに、入力が求められるので、忘れないように記録しておきます。

ansible-playbookでのKubernetesクラスタの構築と設定

これで、ansibleを使って、Kubernetesクラスタを構築する準備が整ったので、これから、ansible-playbookコマンドにて、Kubernetesクラスタを構築していきます。

まず、以下のコマンドを実行し、各nodeのホスト名の設定や、aptパッケージのレポジトリの最新化を行います。
ここで、先ほどのvault.yamlの作成の手順で入力した、暗号化実施時のパスワードが求められますので、入力します。

ansible-playbook -i inventory.ini site.yaml --tags common --ask-vault-pass

コマンドが成功すると、以下のように、結果がokとして得られます。

PLAY RECAP ************************************************************************
kube-master              : ok=6   changed=4   unreachable=0   failed=0
kube-node1               : ok=3   changed=2   unreachable=0   failed=0

次に、以下のコマンドで、Kubernetesクラスタの構築を行います。

ansible-playbook -i inventory.ini site.yaml --tags k8s_base --ask-vault-pass

今回は少し実行に時間を要しますが、成功すると、同様にokとして結果が得られます。


次に以下のコマンドを実行します。

ansible-playbook -i inventory.ini site.yaml --tags k8s_worker --ask-vault-pass

このコマンドでは、RoCEを用いた分散ファイルシステムであるLustreの設定や、トポロジーマネージャー、CPUマネージャー、メモリーマネージャーなどの設定を行います。
実際に設定されている値としては、以下のファイルに記載されていますので、必要に応じて変更してください。

https://github.com/fukumame/k8s-configs/blob/417caec0884c66c5cd939dacb1148913ec76ce38/roles/k8s_worker/vars/main.yaml


次に、以下のコマンドを実行します。

ansible-playbook -i inventory.ini site.yaml --tags k8s_gpu --ask-vault-pass

このコマンドでは、nvidia-container-runtime、GDRCopy、nv-peer-memoryなど、GPU仮想マシンに必要なライブラリのインストールを行います。
ライブラリのバージョンなどは、以下の変数ファイルで設定されているので、必要に応じて変更ください。

https://github.com/fukumame/k8s-configs/blob/afa2bf023b02cf31b169b161ba260a0d370dd428/roles/k8s_gpu/vars/main.yaml


次に以下のコマンドを実行します

ansible-playbook -i inventory.ini site.yaml --tags service --ask-vault-pass

このコマンドでは、Exascaler CSI driver、NVIDIA GPU Operator、NVIDIA Network Operator、Prometheusのインストール、Exascaler CSI Driverを使用したStorageClassの設定などを行います。

デフォルトでインストールされるライブラリ、サービスは以下の通りです。
他にインストールしたいライブラリがあれば、適宜コメントアウトを外してください。
https://github.com/fukumame/k8s-configs/blob/af279ba47c492d9a90eded36083e56e0b1aeb7cf/roles/k8s_service/tasks/main.yaml

Kubernetes起動の確認

最後に、 kubectl get node を実行して、nodeが正しく起動されていることを確認します。

bastion:~$ kubectl get node
NAME         STATUS   ROLES    AGE    VERSION
kube-gpu1    Ready    <none>   6d9h   v1.23.3+k0s

今回のまとめと次回について

今回は、mdx上でKubernetesを構築するための手順について説明しました。

次回は、Lensというツールを使って、構築したKubenetes環境に接続し、GUIでKubernetesクラスタを管理するための方法について説明しています。

気になる方は、以下の記事を参照ください。
https://zenn.dev/suzumura_lab/articles/627b5063d6884d

東京大学鈴村研究室について

https://sites.google.com/view/toyolab/鈴村研究室概要

Discussion

ログインするとコメントできます