第2回 クラウド基盤mdxでKubenetes環境を構築する
この記事について
こんにちは、東京大学鈴村研究室で、インフラエンジニアとしてお手伝いさせていただいています、福田と申します。
今回のこの記事は、クラウド基盤mdxの上で、Kubernetes環境を構築する方法について、説明していきます。
前提
この記事では、構築されたmdxの仮想マシン上でKubernetes環境を構築する方法を中心に説明するため、前提である仮想マシンを立ち上げるための手順については、詳しくは説明しません。
mdxで仮想マシンを立ち上げるための詳しい手順については、以下の記事一覧の第1回を参照ください。
本記事で使用するソースコードについて
本記事では、以下のGitHub repositoryのコードを使用します。
なお、上記のレポジトリは、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_host
とroce_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マネージャー、メモリーマネージャーなどの設定を行います。
実際に設定されている値としては、以下のファイルに記載されていますので、必要に応じて変更してください。
次に、以下のコマンドを実行します。
ansible-playbook -i inventory.ini site.yaml --tags k8s_gpu --ask-vault-pass
このコマンドでは、nvidia-container-runtime、GDRCopy、nv-peer-memoryなど、GPU仮想マシンに必要なライブラリのインストールを行います。
ライブラリのバージョンなどは、以下の変数ファイルで設定されているので、必要に応じて変更ください。
次に以下のコマンドを実行します
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の設定などを行います。
デフォルトでインストールされるライブラリ、サービスは以下の通りです。
他にインストールしたいライブラリがあれば、適宜コメントアウトを外してください。
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クラスタを管理するための方法について説明しています。
気になる方は、以下の記事を参照ください。
東京大学鈴村研究室について
Discussion