tl;dr
- 長文なので3行で
- kubernetesとAWSとGPUは超える壁が多かった。やるならkubeadmがオススメ。
- kubeadmでcloud-provider=awsの手順を後半に記載
はじめに
ABEJAのサービス系インフラを管理しているインフラエンジニアの村主です。
コンテナ周りは割とECSを中心に組むことが多かったのですが、あれだけkubernetesが持ち上げられると使ってみないとな。と言うことで、新しく追加する機能はkubernetesで開発することにしました。そこにkubernetesがあったから
kubernetesとAWSとGPU を組み合わせた時にすごくハマりどころが多かったので、ここに奮闘記を記載します。
まず、kubernetesを構築するためのプロビジョニングツールを何にしようか。と言うことで、特徴を知らないと工夫も出来ないので色々触ってみました。
1. kops
まずは調べたツールの中ではGithubのスターが4000超えで一番多かったのでまずはkopsからスタートしました。
kopsとは
- AWSとGCE(ベータ)でkubernetesクラスタのプロビジョニングを自動化
- コマンドラインベースで高可用性kubernetesマスターをデプロイ
- Terraformのコードを生成することも可能
使ってみた所感
AWSサポートしてるって言ってるけど、既存のkey pairを指定出来ない?(何度かやったけど他もアレだったので心折れた)や、既存のvpcにkubernetesクラスタを入れるのに少し工夫が必要だったり、userdata(cloud-init)も使えなかったり?と、AWS上で使うには細かいところで使いにくい感じがしました。
もうちょっとAWSライクに使えないものか、と他ツールを使ってみることにしました。
2. kube-aws
AWSで使いやすいものを探そう!ということで、次にkube-awsを触ってみました。
kube-awsとは
- 日本人がメンテナーで日本語の情報も多い(他はGithub issueベース...)
- Production-Ready(本番運用を目的とした)KubernetesクラスタをAWS上に構築するためのオープンソースのツール
使ってみた所感
kopsで痒いところに手が届いていないところは勿論対応していて、AWSユーザとしてはすごく扱いやすかったです。 しかもmasterの冗長性や特にetcdの冗長を自前で組むのは少し面倒なのですが、台数増やすだけで簡単に高可用性に出来ます。 configに説明やパラメータがほぼ書いてあるので、configを読みながら設定していくだけでほぼ完結します。
若干はまったところを共有します
ここで一つの問題が
kube-awsはすごく使いやすかったです。ただ一つ問題が、、。
kube-awsの対応OSはcoreOSでした。
GPU扱えるかな?と調べたらdocker run時にdeviceオプションを指定するやり方で実施することも出来ます。
しかし、あまりインフラの職人芸を増やすと後の人が困ることが多いので、出来るだけ標準的な抽象化された形でkubernetesからGPUを簡単に扱いたかったため、 k8s-device-plugin
が使えることを利用条件にしました。
k8s-device-pluginの要件は以下になります(2018/02時点)
- NVIDIA drivers ~= 361.93
- nvidia-docker version > 2.0 (see how to install and it's prerequisites)
- docker configured with nvidia as the default runtime.
- Kubernetes version = 1.9
- The DevicePlugins feature gate enabled
さらにここの要件を掘り下げるとnvidia-docker2の対応OSで引っかかりました
- Ubuntu Xenial x86_64 / Xenial ppc64le
- Debian Stretch x86_64
- CentOS,RHEL7 x86_64 / ppc64le
そう。coreOSは無いんですね。。
k8s-device-plugin / nvidia-docker2が使えないと言うことで、別れを惜しみながら次のプロビジョニングツールを探し始めました。
3. Rancher
次にターゲットになったのはRancherです。 Rancherはdockerが動けば対応OSはほぼ問わないため、Ubuntuなど柔軟選べるのが魅力的でした。
Rancherとは
- GUIベースでkubernetesをデプロイ出来る
- kubectlでやるようなことをGUIベースで利用できる
- kubernetesだけじゃない他のオーケストレーションツールも管理対象(1系と2系で大きく変わってますが・・)
- ググると日本語の情報たくさん出てくるので詳しくはそちらを参照ください
使ってみた所感
Rancherのシングル環境のインストールはRancherのdockerを動かすだけなのですごく簡単です。 しかも、高可用性(HA)構成等も公式ドキュメントに記載されているため、ここを参考に高可用性(HA)を組んでみましょう。
と思いきや、ここで書いてあるHAってRancher ServerのHAなんですよね。kubernetesじゃなくて・・。
Rancher Severは上の手順でHA組んだとして、kubernetesは別手順でHAを組む必要があります。
Rancher Serverの注意点として、HA組んでフロントにELBを置いた時はELBはTCPにして、Proxy Protocolに対応する必要があります。
RancherでのkubernetesのHA手順は簡単に説明すると以下の手順になります。
- Rancherでk8sのテンプレートを編集し、[Plane Isolation] をrequiredにする
- ホストを追加する時に
- etcd用ホストは
etcd=true
のラベルを指定 - k8s用ホストは
orchestration=true
のラベルを指定 - worker用ホストは
compute=true
のラベルを指定
- etcd用ホストは
ここで三つの問題が
Rancherの高負荷問題
よし、HA組めたぜ!と言うことで、実際にWorker Nodeを5台を増やしてみました。すると、Rancherのipsecが落ちる現象が発生しました。
調べると、Rancherに使うRDSがt2.smallだったんですね。masterもm3.mediumでCPU使用率が高騰していたので、Rancher Serverはm4.large x 3台、Rancher RDSはdb.m4.largeに変更してみました。
この状態で5台追加しました。すると落ちはしなかったけど、CPU使用率がEC2/RDS共に40~80%になってます・・・。
なんだこの重たい感・・。これRancher落ちるとkubernetes落ちるよね・・。と言う不安感満載になりました。 使い方悪いのかな・・?
nvidia-docker2を使うとrancher-agentが起動しない
nvidia-docker2はdockerのdefault runtimeをnvidia(nvidia-docker2)にする必要があります。
nvidia-docker2のインストール方法
default runtimeの変更方法
よし、インストールして、default runtimeをnvidiaにしてdockerを再起動だ! ・・・rancher-agentが起動してこない・・・。
調べても、nvidia-dockerに対応してないやら、GPUオプションをサポートしてないやら、 Rancherのことを言っているのか、Kubernetes on Rancherのことを言っているのか、、疲れてきました。
高負荷も心配だし、Rancherは諦めました。
4. kubeadm
満を辞しての公式一押しツール。まだベータで2018年中にはGAするらしい。 kubeadmはRancherと同じく対応OSは問わないので、これでGPUを扱えるはず・・・!と言うことで始まりました。
kubeadmとは
kubeadm is a toolkit that helps you bootstrap a best-practice Kubernetes cluster in an easy, reasonably secure and extensible way. It also supports managing Bootstrap Tokens for you and upgrading/downgrading clusters.
らしいです。良さそうですね
使ってみた所感
シングルインストールはすごく簡単。本当にDocument通りに進めるだけで作れます。 kubeadmはdockerが動けば好きなAMI上にkubernetesを立てれるから良い感じでした。 Using kubeadm to Create a Cluster | Kubernetes
と言うことで、サクッと作ってGPUを試してみました
1. masterにkubeadmをインストールし、kubernetesを構築
上記公式手順の Instructions
の通りにやれば問題なくインストール出来ます。ネットワークも忘れずに作りましょう。
私はubuntu16でネットワークはflannelで作りました。
参考までにコマンドを貼っておきます。flannnelの場合は、kube init時に --pod-network-cidr=10.244.0.0/16
を指定しましょう。
sudo apt-get update sudo apt-get install -y docker.io sudo apt-get update && sudo apt-get install -y apt-transport-https curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - sudo tee /etc/apt/sources.list.d/kubernetes.list <<EOF deb http://apt.kubernetes.io/ kubernetes-xenial main EOF sudo apt-get update sudo apt-get install -y kubelet kubeadm kubectl sudo kubeadm init --pod-network-cidr=10.244.0.0/16 mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml
2. workerにkubeadmをインストールし、join
インスタンスは Deep Learning Base AMI (Ubuntu) Version 3.0
を利用します。インスタンスタイプはp2.xlargeを選びましょう
masterと同じ手順でkubeadmをインストールしinitは行わずに、init後に表示されたjoinコマンドを実行します。 これだけでkubernetesのmaster/worker環境の構築は完了です。
3. workerにnvidia-docker2をインストール
基本は公式手順を見て欲しいですが、簡単には以下の手順です。
2回目のdocker infoでdefault runtimeがnvidiaになっていたら成功です。
nvidia-smiも正常に表示されたら成功です。
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | \ sudo apt-key add - curl -s -L https://nvidia.github.io/nvidia-docker/ubuntu16.04/amd64/nvidia-docker.list | \ sudo tee /etc/apt/sources.list.d/nvidia-docker.list sudo apt-get update sudo apt-get install -y nvidia-docker2 sudo pkill -SIGHUP dockerd sudo docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi ## enable nvidia-docker default runtime sudo tee /etc/docker/daemon.json <<EOF { "default-runtime": "nvidia", "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [] } } } sudo docker info sudo systemctl restart docker sudo docker info sudo docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi
4. workerのkubeletの設定を変更する
kubeletの起動オプションを指定する必要があり /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
に一行追加して再起動します。
これはworkerノードに設定が必要です。
sudo sed -i -e '9i Environment="KUBELET_EXTRA_ARGS=--feature-gates=DevicePlugins=true"' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf sudo systemctl daemon-reload sudo systemctl restart kubelet.service
5. masterでk8s-device-pluginをデプロイする
masterでk8s-device-pluginします
kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.9/nvidia-device-plugin.yml
ここで一つの問題が
ここまででkubernetesを構築が出来て、さらにkubernetes上のコンテナからGPUを扱える環境が出来ました。 しかし、GPU問題が大きすぎてすっかり忘れていました。
そう。Persistent Volumesを使いたかったのでした。
AWS上でkubernetesを動かすためにcloudproviderにawsを指定し起動します。これがないとPersistent VolumeとしてEBSを作成したりELBでサービスを公開するといった諸々のAWSの機能が使えません。
kube-awsやRancherはCloud Providersは簡単に利用出来たので問題ないわ。とタカくくってたらどハマりしました。
Cloud Providersの設定方法を探すの巻
まずどこ探してもインストール手順が一貫して書かれているところはありません。 引っかかるのはGithub issueで
Q「Cloud Providersでawsを使いたいんだけどどうすれば良い?」
Q「--cloud-provider=awsで渡すだけじゃダメなの?」
A「/etc/systemd/system/kubelet.service.d/10-kubeadm.confの編集が必要だよ」
A「/etc/kubernetes/cloud-configのファイルもいるよ」
A「init時に--cloud-provider=awsがいるよ」
A「EC2とSGに KubernetesCluster=kubernetes
のタグがいるよ」
とか書いてあるだけで具体的なパラメータとかは無くて、見つかる情報を寄せ集めても何度やっても何度やっても実現出来ませんでした。
俺はもうダメだ!と手を上げたら、メンバーがどこかにあった記事の下の方にちょろっと書いてある記述(init時にnodeNameのパラメータを渡す)を試したら成功したようです!
kubeadmのCloud Providersでawsを使う手順
この情報は他のところでは載っていないので、必見です。
- master / workerのEC2にKubernetesCluster=kubernetesのタグを付与する(KubernetesCluster=<クラスター名>で今回はクラスタ名kubernetesで作りました)
- master / workerのSecurityGroupにKubernetesCluster=kubernetesのタグを付与する
- master / workerの
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf
にEnvironment="KUBELET_EXTRA_ARGS=--cloud-provider=aws
を追加する - masterのkubeadm init時のパラメータに
cloudProvider: "aws"
とnodeName: ip-172-31-16-134.us-west-2.compute.internal
でmasterのprivate dnsを指定する
最終的にkubeadm+aws provider+GPUの環境を構築するコマンド
つまり、masterのkubeadm構築時の手順としては以下になります。
- masterはubuntu16で起動
- workerは
Deep Learning Base AMI (Ubuntu) Version 3.0
の p2.xlarge で起動 - master / workerのEC2にKubernetesCluster=kubernetesのタグを付与する
- master / workerのSecurityGroupにKubernetesCluster=kubernetesのタグを付与する
- masterとworker上で以下のコマンドを実行する
master
文中のnodeNameはmasterのprivate dnsを設定ください
sudo apt-get update sudo apt-get install -y docker.io sudo apt-get update && sudo apt-get install -y apt-transport-https curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - sudo tee /etc/apt/sources.list.d/kubernetes.list <<EOF deb http://apt.kubernetes.io/ kubernetes-xenial main EOF sudo apt-get update sudo apt-get install -y kubelet kubeadm kubectl sudo sed -i -e '9i Environment="KUBELET_EXTRA_ARGS=--cloud-provider=aws --feature-gates=DevicePlugins=true"' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf sudo systemctl daemon-reload sudo systemctl restart kubelet.service cat <<EOF > config.yaml apiVersion: kubeadm.k8s.io/v1alpha1 kind: MasterConfiguration cloudProvider: "aws" networking: podSubnet: 10.244.0.0/16 tokenTTL: 0s nodeName: ip-123-45-67-890.us-west-2.compute.internal EOF sudo kubeadm init --config config.yaml mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.9/nvidia-device-plugin.yml
worker
# nvidia-docker2にdocker17.12+が必要なため、dockerインストール手順は以下 sudo apt-get remove -y docker docker-engine docker.io sudo apt-get update sudo apt-get install -y \ apt-transport-https \ ca-certificates \ curl \ software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" sudo apt-get update sudo apt-get install -y docker-ce # nvidia-docker2のインストール手順 curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | \ sudo apt-key add - curl -s -L https://nvidia.github.io/nvidia-docker/ubuntu16.04/amd64/nvidia-docker.list | \ sudo tee /etc/apt/sources.list.d/nvidia-docker.list sudo apt-get update sudo apt-get install -y nvidia-docker2 sudo pkill -SIGHUP dockerd sudo docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi ## enable nvidia-docker default runtime sudo tee /etc/docker/daemon.json <<EOF { "default-runtime": "nvidia", "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [] } } } EOF sudo docker info sudo systemctl restart docker sudo docker info sudo docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi # kubeadmのインストール手順 sudo apt-get update && sudo apt-get install -y apt-transport-https curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - sudo tee /etc/apt/sources.list.d/kubernetes.list <<EOF deb http://apt.kubernetes.io/ kubernetes-xenial main EOF sudo apt-get update sudo apt-get install -y kubelet kubeadm kubectl sudo sed -i -e '9i Environment="KUBELET_EXTRA_ARGS=--cloud-provider=aws --feature-gates=DevicePlugins=true"' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf sudo systemctl daemon-reload sudo systemctl restart kubelet.service # kubernetesへjoin kubeadm join xxx
5. おまけ編 EKSへの期待
re:Invent 2017でAWSからkubernetesのマネージドサービスであるEKSが発表されました。 今回はAWS上でkubernetesのマスターを構築しました。ただAWS上でkubernetes作るだけなら大した事ないかもですが、GPUを扱おうとすると途端にツラミが多かったです。
EKSを利用する事でマスターのデプロイや特に高可用性、パフォーマンス、日々の監視や運用などを気にしなくて良い(と思ってる)のと、Cloud Providersでawsが簡単に使える(と期待している)だろうし、GPU周りの要件を満たせる状態になったらまず僕が喜びます。
終わりに
kubernetes + AWS + GPUの情報は非常に少ないです。
GKEでも2018/02からGPUが使えるようになったみたいなので、まだ手を出すのは早いかもしれません。
この情報が誰かの参考になることを心より心より願っています。
宣伝
ABEJAでは、SREエンジニアを募集しています!! www.wantedly.com
ABEJAが発信する最新テクノロジーに興味がある方は、是非ともブログの読者に!
ABEJAという会社に興味が湧いてきた方はWantedlyで会社、事業、人の情報を発信しているので、是非ともフォローを!! www.wantedly.com
ABEJAの中の人と話ししたい!オフィス見学してみたいも随時受け付けておりますので、気軽にポチッとどうぞ↓↓