ABEJA Arts Blog

株式会社ABEJAのメンバーが最先端の “Mechanical Arts” と、それを実際に社会に適用する中で必要な “Liberal Arts” について発信します

Kubernetes x AWS x GPUにハマった話

f:id:xwkns157:20180312102258p:plain

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とは

github.com

  • AWSとGCE(ベータ)でkubernetesクラスタのプロビジョニングを自動化
  • コマンドラインベースで高可用性kubernetesマスターをデプロイ
  • Terraformのコードを生成することも可能

使ってみた所感

AWSサポートしてるって言ってるけど、既存のkey pairを指定出来ない?(何度かやったけど他もアレだったので心折れた)や、既存のvpcにkubernetesクラスタを入れるのに少し工夫が必要だったり、userdata(cloud-init)も使えなかったり?と、AWS上で使うには細かいところで使いにくい感じがしました。

もうちょっとAWSライクに使えないものか、と他ツールを使ってみることにしました。

2. kube-aws

AWSで使いやすいものを探そう!ということで、次にkube-awsを触ってみました。

kube-awsとは

github.com

  • 日本人がメンテナーで日本語の情報も多い(他はGithub issueベース...)
  • Production-Ready(本番運用を目的とした)KubernetesクラスタをAWS上に構築するためのオープンソースのツール

使ってみた所感

kopsで痒いところに手が届いていないところは勿論対応していて、AWSユーザとしてはすごく扱いやすかったです。 しかもmasterの冗長性や特にetcdの冗長を自前で組むのは少し面倒なのですが、台数増やすだけで簡単に高可用性に出来ます。 configに説明やパラメータがほぼ書いてあるので、configを読みながら設定していくだけでほぼ完結します。

若干はまったところを共有します

qiita.com

ここで一つの問題が

kube-awsはすごく使いやすかったです。ただ一つ問題が、、。

kube-awsの対応OSはcoreOSでした。

GPU扱えるかな?と調べたらdocker run時にdeviceオプションを指定するやり方で実施することも出来ます。

しかし、あまりインフラの職人芸を増やすと後の人が困ることが多いので、出来るだけ標準的な抽象化された形でkubernetesからGPUを簡単に扱いたかったため、 k8s-device-plugin が使えることを利用条件にしました。

github.com

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とは

Your Enterprise Kubernetes Platform | Rancher Labs

  • GUIベースでkubernetesをデプロイ出来る
  • kubectlでやるようなことをGUIベースで利用できる
  • kubernetesだけじゃない他のオーケストレーションツールも管理対象(1系と2系で大きく変わってますが・・)
  • ググると日本語の情報たくさん出てくるので詳しくはそちらを参照ください

使ってみた所感

Rancherのシングル環境のインストールはRancherのdockerを動かすだけなのですごく簡単です。 しかも、高可用性(HA)構成等も公式ドキュメントに記載されているため、ここを参考に高可用性(HA)を組んでみましょう。

rancher.com

と思いきや、ここで書いてあるHAってRancher ServerのHAなんですよね。kubernetesじゃなくて・・。

Rancher Severは上の手順でHA組んだとして、kubernetesは別手順でHAを組む必要があります。

Rancher Serverの注意点として、HA組んでフロントにELBを置いた時はELBはTCPにして、Proxy Protocolに対応する必要があります。

rancher.com

RancherでのkubernetesのHA手順は簡単に説明すると以下の手順になります。

  • Rancherでk8sのテンプレートを編集し、[Plane Isolation] をrequiredにする
  • ホストを追加する時に
    • etcd用ホストは etcd=true のラベルを指定
    • k8s用ホストは orchestration=true のラベルを指定
    • worker用ホストは compute=true のラベルを指定

rancher.com

ここで三つの問題が

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のインストール方法

github.com

default runtimeの変更方法

github.com

よし、インストールして、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.

らしいです。良さそうですね

https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/kubernetes.io

使ってみた所感

シングルインストールはすごく簡単。本当に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を使う手順

この情報は他のところでは載っていないので、必見です。

  1. master / workerのEC2にKubernetesCluster=kubernetesのタグを付与する(KubernetesCluster=<クラスター名>で今回はクラスタ名kubernetesで作りました)
  2. master / workerのSecurityGroupにKubernetesCluster=kubernetesのタグを付与する
  3. master / workerの /etc/systemd/system/kubelet.service.d/10-kubeadm.confEnvironment="KUBELET_EXTRA_ARGS=--cloud-provider=aws を追加する
  4. 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構築時の手順としては以下になります。

  1. masterはubuntu16で起動
  2. workerは Deep Learning Base AMI (Ubuntu) Version 3.0 の p2.xlarge で起動
  3. master / workerのEC2にKubernetesCluster=kubernetesのタグを付与する
  4. master / workerのSecurityGroupにKubernetesCluster=kubernetesのタグを付与する
  5. 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の中の人と話ししたい!オフィス見学してみたいも随時受け付けておりますので、気軽にポチッとどうぞ↓↓