はじめに
今回は、Kubernetesで異なるアーキテクチャのNodeを一元管理するための設定を試します。多くのユーザは、サーバやPCで多く利用されているIntel互換の命令セットのアーキテクチャ(以降amd64と略します)のCPUと、RaspberryPiなど小型PCで利用されているARMの命令セットのアーキテクチャ(以降armと略します)のCPUを持っている人が多いのではないでしょうか。
これまで、クラスタ環境(サーバの集中管理も含む)を組むためには、アーキテクチャを統一するのがセオリーでした。しかし、時代はIoT時代。センサーなどの情報を取得する小型PCなどで構成されているEdgeコンピューティングと、集めたセンサーデータを分析する大型サーバ/クラウドコンピューティング(Coreコンピューティング)を併せて一つのEdge-Coreのサービスを構築しているケースが増えてきました。つまり、サービスの観点からみるとEdgeとCoreのコンピューティングを併せてサービスを実行するためのひとつのコンピューティング環境なのです。また、これらのコンピュータを管理する管理者視点で見ると、同じアーキテクチャの機器の台数が増えても、監視方法やソフトウェアのアップデートなどが同じやり方であれば負担はあまり変わりません。負担が激増するのは、異なるアーキテクャの種類が増えることです。アーキテクチャの種類毎に監視方法やアップデートなどのやり方が変わることは、管理者にとって悪夢でしかありません。そのため、管理者は、IoTの要望に応えるべく色々な機器をサポート/管理したいが、手が出せないと言うのが現実ではないでしょうか。
そこで、今回は異なるアーキテクチャを混在させたKubernetes Cluserを構築し、Kubernesにて一元管理できる環境を目指します。具体的には、Mac(Intel Core i7: amd64アーキテクチャ)上のVirtualBox上に構築したKubernetesのMasterに、Raspberry Pi(ARMv8: armアーキテクチャ)をNodeとして追加します。amd64のみ(又はarmのみ)の単一なアーキテクチャ(ホモジーニアス)のハードウェアで構築されたKubernetes Clusterの環境ではなく、マルチなアーキテクチャ(ヘテロジーニアス)で構築されたKubernetes Clusterを作成します(下図参照)。これにより、アーキテクチャの異なるNodeをKubernetesで一元管理することが出来ます。
設定
今回の設定で用いる環境は次の環境です。
- Mac(amd64)のVirtualBox上に構築されたKubernetes Cluster
- kubeadm にてセットアップ
- Master, Node x 2 のKubernetes Cluster
- Pod NetworkにFlannelを使用
- Mac上にインストールされたkubectl
- 上記のKubernetes Clusterを管理
- Raspberry Pi3 ModuleB+(arm)
-
Raspberry PI と kubeadm で自宅 Kubernetes クラスタを構築する
を参考に"kubeadmのインストール"までを実施
-
Raspberry PI と kubeadm で自宅 Kubernetes クラスタを構築する
次節より、Mac上のVirtualBoxのamd64アーキテクチャで構築されたKubernetes Clusterに、armアーキテクチャ(Raspberry Pi)のノードを追加します。
Raspberry Pi(arm)のNodeを追加
初めにRaspberry PiのNodeを追加します。
kubeadmを使いMac上にKubernetes masterをセットアップした際に、出力されたNode追加のコマンドをRaspberry Pi上で実行します。
$ sudo kubeadm join 192.168.0.23:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxx
<snip>
[discovery] Successfully established connection with API Server "192.168.0.23:6443"
This node has joined the cluster:
* Certificate signing request was sent to master and a response
was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the master to see this node join the cluster.
Nodeが追加されたかどうかをkubectl
コマンドにて確認します。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s Ready master 7d v1.10.2
k8s-node1 Ready <none> 7d v1.10.2
k8s-node2 Ready <none> 7d v1.10.2
k8s-node3 NotReady <none> 17s v1.10.2
masterのk8s,k8s-node1,k8s-node2がMac上(amd64)で動いているNodeになります。
k8s-node3がRaspberry Pi(arm)で動いているNodeになります。
単にkubeadm join
コマンドでNodeを追加しただけではSTATUSはNotReadyのままとなります。
これは、kube-systemネームスペースのkube-proxyとkube-flannnel-dsがarmアーキテクチャ上のNodeで実行されていないためです。
kubectl get ds
コマンドで確認すると、両DaemonSetが3つづつ起動しており、amd64アーキテクチャのNode数(Master含む)しか起動していないのがわかります。
$ kubectl get ds -n kube-system
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
kube-flannel-ds 3 3 3 3 3 beta.kubernetes.io/arch=amd64 7d
kube-proxy 3 3 3 3 3 beta.kubernetes.io/arch=amd64 7d
kube-proxy(arm)を追加
armに対応したkube-proxyをセットアップします。
使用するkube-proxyのYAMLファイルを次に記します。
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
creationTimestamp: null
generation: 1
labels:
k8s-app: kube-proxy-arm
name: kube-proxy-arm
selfLink: /apis/extensions/v1beta1/namespaces/kube-system/daemonsets/kube-proxy-arm
namespace: kube-system
spec:
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: kube-proxy-arm
template:
metadata:
creationTimestamp: null
labels:
k8s-app: kube-proxy-arm
spec:
nodeSelector:
beta.kubernetes.io/arch: arm
containers:
- command:
- /usr/local/bin/kube-proxy
- --kubeconfig=/var/lib/kube-proxy/kubeconfig.conf
image: gcr.io/google_containers/kube-proxy-arm:v1.10.2
imagePullPolicy: IfNotPresent
name: kube-proxy-arm
resources: {}
securityContext:
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/lib/kube-proxy
name: kube-proxy
- mountPath: /run/xtables.lock
name: xtables-lock
- mountPath: /lib/modules
name: lib-modules
readOnly: true
dnsPolicy: ClusterFirst
hostNetwork: true
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: kube-proxy
serviceAccountName: kube-proxy
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
- effect: NoSchedule
key: node.cloudprovider.kubernetes.io/uninitialized
value: "true"
volumes:
- configMap:
defaultMode: 420
name: kube-proxy
name: kube-proxy
- hostPath:
path: /run/xtables.lock
type: FileOrCreate
name: xtables-lock
- hostPath:
path: /lib/modules
type: ""
name: lib-modules
templateGeneration: 4
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
status:
currentNumberScheduled: 0
desiredNumberScheduled: 0
numberMisscheduled: 0
numberReady: 0
kubectl get ds kube-proxy -n kube-system -o yaml
コマンドで出力されるYAMLを改良し上記のYAMLファイルを作成します。
metadata.name
,metadata.labels
などは、任意の名前を設定します。
設定のキーポイントは、spec.nodeSelector
です。
Nodeがarmアーキテクチャの場合に、このDaemonSetが立ち上がるようにbeta.kubernetes.io/arch: arm
と指定します。
併せて、armアーキテクチャのコンテナイメージを指定します。
spec.containers.image
にgcr.io/google_containers/kube-proxy-arm:v1.10.2
を指定します。これにより、armアーキテクチャのNodeでkibe-proxy-armのコンテナイメージが実行されるようになります。
作成したkube-proxy-arm.yamlをkubectl
コマンドでデプロイします。
$ kubectl create -f kube-proxy-arm.yaml
daemonset.extensions "kube-proxy-arm" created
$ kubectl get ds -n kube-system
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
kube-flannel-ds 3 3 3 3 3 beta.kubernetes.io/arch=amd64 7d
kube-proxy 3 3 3 3 3 beta.kubernetes.io/arch=amd64 7d
kube-proxy-arm 1 1 1 1 1 beta.kubernetes.io/arch=arm 16s
kube-proxy-armがarmアーキテクチャ上で動作しているのがわかります。これで、amd64のNodeで3つ、armのNodeで1つのkube-proxyが実行します。
kube-flannel-ds(arm)を追加
続いて、armに対応したkube-flannel-dsをセットアップします。
使用するkube-flannel-dsのYAMLファイルを次に記します。
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: kube-flannel-ds-arm
namespace: kube-system
labels:
tier: node
app: flannel
spec:
template:
metadata:
labels:
tier: node
app: flannel
spec:
hostNetwork: true
nodeSelector:
beta.kubernetes.io/arch: arm
tolerations:
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
serviceAccountName: flannel
initContainers:
- name: install-cni
image: quay.io/coreos/flannel:v0.9.1-arm
command:
- cp
args:
- -f
- /etc/kube-flannel/cni-conf.json
- /etc/cni/net.d/10-flannel.conf
volumeMounts:
- name: cni
mountPath: /etc/cni/net.d
- name: flannel-cfg
mountPath: /etc/kube-flannel/
containers:
- name: kube-flannel
image: quay.io/coreos/flannel:v0.9.1-arm
command: [ "/opt/bin/flanneld", "--ip-masq", "--kube-subnet-mgr" ]
securityContext:
privileged: true
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumeMounts:
- name: run
mountPath: /run
- name: flannel-cfg
mountPath: /etc/kube-flannel/
volumes:
- name: run
hostPath:
path: /run
- name: cni
hostPath:
path: /etc/cni/net.d
- name: flannel-cfg
configMap:
name: kube-flannel-cfg
ここでのキーポイントもspec.template.spec.nodeSelector
にbeta.kubernetes.io/arch: arm
を指定する点です。
併せてコンテナイメージもquay.io/coreos/flannel:v0.9.1-arm
を指定します。
作成したkube-flannel-ds-arm.yamlをkubectl
コマンドでデプロイします。
$ kubectl create -f kube-flannel-ds-arm.yaml
daemonset.extensions "kube-flannel-ds-arm" created
$ kubectl get ds -n kube-system
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
kube-flannel-ds 3 3 3 3 3 beta.kubernetes.io/arch=amd64 7d
kube-flannel-ds-arm 1 1 1 1 1 beta.kubernetes.io/arch=arm 13s
kube-proxy 3 3 3 3 3 beta.kubernetes.io/arch=amd64 7d
kube-proxy-arm 1 1 1 1 1 beta.kubernetes.io/arch=arm 11m
kube-flannel-dsがarmアーキテクチャ上で動作しているのがわかります。これで、amd64のNodeで3つ、armのNodeで1つのkube-flannel-dsが実行します。
Nodeの確認
kube-proxy,kube-flannel-dsがarmアーキテクチャのNode(k8s-node3)で実行された後、kubectl
コマンドでNodeのSTATUSを確認します。
k8s-node3のSTATUSがReadyに変更され、無事に動作しているのがわかります。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s Ready master 7d v1.10.2
k8s-node1 Ready <none> 7d v1.10.2
k8s-node2 Ready <none> 7d v1.10.2
k8s-node3 Ready <none> 55m v1.10.2
以上で構築完了です。
感想
今回、amd64とarmアーキテクチャのヘテロジーニアスなハードウェアのKubernetes Cluster環境を構築しました。これにより、管理者はkubectl
コマンドにて一元管理することが可能となります。Kubernetesの利用者は、アプリケーションをamd64, armアーキテクャの何で動作させるかを選択する必要があります。選択には、nodeSelector
にbeta.kubernetes.io/arch: arm
を指定します。これにより、amd64, armの環境を容易に指定できます。
また、今回とは異なるヘテロジーニアスなハードウェアの管理方法として、amd64,arm毎に別々にKubernetes Clusterを構築する方法もあるかと思います。その場合、管理者は複数のKubernetes Clusterを管理することになり、複数のネットワークやAPIのアクセスポイント、証明書などの管理が必要となります。そのため、amd64,arm毎に運用するサービスが異なる場合には、ネットワーク分割なども併せて考慮すると有効かと思います。
一方で、amd64,arm環境が連携し動作するようなサービスを運用する場合には、今回のKubernetes Clusterの環境が有効かもしれません。例えば、文頭で述べたように、IoT環境で利用するセンサーなどをRaspberry Piといった小型PCをEdge(armアーキテクャ)で動作させ、センサーから得たデータをセンター側のコンピュータ(amd64アーキテクチャ)で分析を行うといったサービスです。
運用するサービスにより、Kubernetes Clusterをどう構築・運用するのか悩ましいところですが、少なくともKubernetesは、どちらの選択肢を取ることも可能であり、提供するサービスと運用形態によりマッチした環境を選べます。今後カンファレンスなどで面白いKubernetes Clusterの環境が発表されることを期待します。