2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ラクスパートナーズAdvent Calendar 2024

Day 21

Kubeflow環境を構築してみた

Last updated at Posted at 2024-12-20

はじめに

この記事はラクスパートナーズ Advent Calendar 2024の21日目の記事です。

Kubernetesにまともに触れてこなかったエンジニアが、アドベントカレンダー参加を機にKubeflowの環境構築を行ってみました。

簡単にですが、その手順をまとめていこうと思います。

内容について誤りがございましたら、優しい言葉でご指摘いただけますと幸いです。

本記事のゴール

VMインスタンス上にシンプルなKubeflowの環境を構築すること。

Kubeflowってなに?

Kubernetes上で機械学習(ML)ワークフローを管理するためのオープンソースプラットフォームです。
モデルの開発、学習、デプロイといった MLライフサイクルのプロセスを自動化し、スケーラブルで再現性のある環境を実現することができます。
Kubeflowにおける各コンポーネントが、どのプロセスに対応するかは公式サイトの説明が理解しやすいです。

また、前提となる「MLOps」の考え方についてはこちらで非常に分かりやすくまとめてくださっています。

環境情報

マシン情報

今回はアカウント作成時にもらったクレジットが余っていたので、GCP上にVMインスタンスを構築しました。

項目 
OS Ubuntu, 24.04 LTS
CPUコア数 8コア
メモリサイズ 32GB
ディスクサイズ 64GB
プロセッサアーキテクチャ AMD64

バージョン情報

項目 
Kubernetes v1.31
Kubeflow v1.90

前提

Kubeflow環境を構築するにあたり、個人利用の範疇ということを加味してKubeflow Manifestsを利用することにしました。

また、GitHubの手順では Kind (Kubernetes in Docker) を利用してクラスターを構築していますが、今回はマシンスペックの都合によりパブクラ上のVMに構築するため、外部からの通信設定が比較的行いやすい kubeadm で構築することにしました。

手順

Swapの無効化

Kubeadmでクラスターを作成する際、Swapメモリが検出されると起動に失敗してしまうため、Swapの無効化を行います。

swapoff -a

# Swap領域の確認
free

IPv4 パケットのフォワーディング(転送)を有効にする

この設定により、Pod間通信を実現できるようになります。

PodはLinuxのNetwork Namespaceで分離されており、それぞれが独立した仮想的なネットワーク空間を持っています。
これらの仮想インターフェースは同一ノード上の他Podや、ホスト側の実ネットワークインターフェースとは直接的に一体化されていないため、パケットを正しいインターフェースへ「フォワーディング」する機能が必要となります。

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
EOF

# 設定の適用
sudo sysctl --system

# 設定値の確認
sysctl net.ipv4.ip_forward

br_netfilterモジュールをロード

br_netfilterモジュールとは?
Linuxカーネルモジュールの1つで、Linuxブリッジ経由のトラフィックにNetfilterのルールを適用する機能を提供します。

このモジュールをロードしておくことで、Pod間通信にパケットフィルタリングルールを適用できるようになります。
この辺りの話はこちらの記事が大変参考になりました。

また、後述するflannelではbr_netfilterをロードしておかないと以下のようなエラーが発生してしまいます。

Failed to check br_netfilter: stat /proc/sys/net/bridge/bridge-nf-call-iptables: no such file or directory
# モジュールがシステム起動時に自動的にロードされるようにしておく
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF

# モジュールのロード
sudo modprobe br_netfilter

# モジュールがロードされていることを確認
lsmod | grep br_netfilter

CRI (Container Runtime Interface) のインストール

今回はDockerを利用する必要がないため、CRIにcontainerdを採用しました。

sudo apt-get update
sudo apt-get install -y containerd
sudo mkdir -p /etc/containerd

# デフォルトのconfigファイルを作成
containerd config default | sudo tee /etc/containerd/config.toml

containerdコンフィグファイルの修正

Ubuntu, 24.04 LTS の initシステムがsystemdのため、cgroupドライバーとしてsystemd ドライバーを利用するようにcontainerdコンフィグファイルの一部を修正します。

cgroupsの話はこちらの記事が分かりやすかったです。

また、このままではkubeadmによってクラスターを作成する際、下記のような警告メッセージが表示されるため、こちらも該当箇所を修正していきます。

W1219  detected that the sandbox image "registry.k8s.io/pause:3.8" of the container runtime is inconsistent with that used by kubeadm.It is recommended to use "registry.k8s.io/pause:3.10" as the CRI sandbox image.

修正箇所

[plugins."io.containerd.grpc.v1.cri"]

- sandbox_image = "registry.k8s.io/pause:3.8"
+ sandbox_image = "registry.k8s.io/pause:3.10"
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  ...
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]

-     SystemdCgroup = false
+     SystemdCgroup = true
# initシステムの確認
systemctl --version

# コンフィグファイルの修正
sudo vi /etc/containerd/config.toml

# 設定の反映
sudo systemctl restart containerd

inotifyの上限値を変更

inotifyとは?
Linux上で「ファイルやフォルダが変更されたかどうか」を監視するツールです。これにより、アプリケーションがファイルやディレクトリの変更を自動で検知できるようになります。

Kubeflowの環境を構築する上で、下記のように上限を変更しておかないとToo many open filesのエラーが発生し、立ち上がらないPodが出てきてしまいます。

# ユーザID毎に作成可能なinotifyインスタンスの上限を指定する
sudo sysctl fs.inotify.max_user_watches=1255360
# ユーザID毎に同時に監視できるファイル/ディレクトリの上限を指定する
sudo sysctl fs.inotify.max_user_instances=2280

kubectl, kubeadm, kubeletのインストール

ざっくりとですが、それぞれ以下のような役割を担います。

kubectl
Kubernetesクラスターを管理するためのコマンドラインツール。マニフェストの適用やログ収集を行うことができます。
kubelet
各ノードで動作し、コンテナの状態管理やPodのヘルスチェック・リソース管理などを担います。
kubeadm
Kubernetesクラスターを作成するためのツール。
sudo apt update
sudo apt-get install -y apt-transport-https ca-certificates curl

# Kubernetesリポジトリの追加
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

# kubectlの自動補完を有効にする(必須でない)
source /usr/share/bash-completion/bash_completion
echo 'source <(kubectl completion bash)' >>~/.bashrc
source ~/.bashrc

Kustomizeのインストール

Kustomizeとは
Kubernetesのマニフェストを管理するためのツール。主なユースケースとして、「環境共通となる設定と環境毎に差分となる設定を分けて管理する」などが挙げられます。

Kubeflow Manifestsは、Kustomizeによりマニフェストが管理されているためインストールしていきます。

sudo curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"  | bash
sudo  mv ./kustomize /usr/local/bin/kustomize

クラスターの初期化

ネットワークアドオンとしてflannelを利用するため、PodネットワークのCIDR範囲を10.244.0.0/16としてクラスターを作成します。

sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --kubernetes-version=1.31.0

# kubectl コマンドを使用してクラスターを管理できるようにする
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

ネットワークアドオンのインストール

以下にも記載がある通り、Pod間の通信を実現するためにCNI (Container Network Interface) をベースとするネットワークアドオンをインストールする必要があります。
今回はメジャーな CNI プラグインであるflannelを使用します。

kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

コントロールプレーンノードの隔離

デフォルトではコントロールプレーンノードに、Podがスケジューリングされることはありません。
今回はシングルノードで構築を行うため、設定を変更します。

# 設定を変更しない場合、下記のようなエラーが発生する。
# 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }. 

kubectl taint nodes --all node-role.kubernetes.io/control-plane-

kubectl describe nodes | grep -i taints

DVP (Dynamic Volume Provisoner) を有効にする

Kubeflow環境を立ち上げると複数のPodが作成されますが、その中にはPVCを必要とするPodも含まれます。
そのため、あらかじめ DVPを有効にしておくことで、動的にPVオブジェクトが作成されるようにしおきます。
今回は、DVPを有効にするためにストレージプロビジョナーとしてLocal Path Provisionerを利用していきます。

# DVPを有効にしておかないと以下のようなエラーが出る
# 0/1 nodes are available: pod has unbound immediate PersistentVolumeClaims. 

kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.30/deploy/local-path-storage.yaml

# デフォルトのStorageClassに設定
kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

kubectl get storageclass

Kubeflow Manifetsのクローン

git clone https://github.com/kubeflow/manifests.git
cd manifests

Kubeflow Platformの構築

全てのオブジェクトが構築されるまでに数分かかります。

while ! kustomize build example | kubectl apply --server-side --force-conflicts -f -; do echo "Retrying to apply resources"; sleep 20; done

kubectl get pods -n kubeflow

全てのPodのステータスがRunningとなっていれば完了です。

最後に

今回ハマったポイント

プロセッサアーキテクチャの違いによるエラー
当初ARM64のVMインスタンス上で環境構築を行っていたのですが、いくつかのPodがCrashLoopBackOFFの状態で再起動を繰り返していました。
出力されたエラーログから、どうやらアーキテクチャが原因そうということが分かったので、AMD64に変更してみたところ、無事すべてのPodを起動することができました。

ただ、ARM64だとダメだな理由が見つけられなかったので、この辺りに知見のある方がいらっしゃいましたらご教示いただきたいです。

今後やりたいこと

今回構築した環境を利用して、データの前処理、モデル学習、デプロイなど一連のMLライフサイクル管理を体験してみようと考えています。

また、Kubernetesについて色々調べていくうちに、「コンテナがLinuxカーネル上で動く仕組み」の一端を知れたことが個人的には大きな収穫でした。
とはいえ、まだまだ分かっていないことが多いためこの辺りも引き続き勉強していきたいです。

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?