さくらのクラウドでKubernetesを利用する場合、マネージドなLBなどを扱うためのcloud-controller-manager実装として sakura-cloud-controller-managerというものがあります。
こちらのデプロイでよく引っかかる点やトラブルシューティング方法についてメモを発掘したので整理がてら残しておきます。
さくらのクラウド上のリソースの構成
Kubernetesクラスタで利用するさくらのクラウド上のリソースの構成は以下の点に注意が必要です。
- ネットワーク構成
- スイッチ(ルータ)への
@k8s
タグ設定
ネットワーク構成
sakura-cloud-controller-managerはサーバをスイッチ+ルータ or スイッチに接続する必要があります。
共有セグメント(共有回線)はサポートしていませんので注意してください。
スイッチ(ルータ)への@k8s
タグ設定
sakura-cloud-controller-managerはさくらのクラウドAPIで取得したスイッチ(ルータ)の情報を元にどのスイッチを利用するかを決定します。
その際に@k8s
タグの付けられたリソースかで判定を行なっています。
タグの付け忘れにご注意ください。
クラスタの構成
次にKubernetesクラスタの構成についてですが、以下2点に注意する必要があります。
順番にみていきます。
--cloud-provider
オプションを適切に指定すること
Kubernetesでexternalなcloud-controller-managerを起動するには--cloud-provider
オプションを適切に指定する必要があります。
参考: Kubernetes Cloud Controller Manager - Kubernetes
具体的には以下2点です。
- kubeletのパラメータとして
--cloud-provider=external
を指定しておくこと - kube-apiserverとkube-controller-managerには
--cloud-provider
を指定しないこと
kubeadmを利用してクラスタのデプロイを行う場合は/var/lib/kubelet/kubeadm-flags.env
ファイルや/etc/default/kubelet
ファイルなどで適切に指定しましょう。
参考: Installing kubeadm - Kubernetes
Nodeに付与されるtaintsへの対応
先ほどの参考ドキュメントに書いてありますが、kubeletに--cloud-provider=external
を指定するとノードに対し以下のようなtaintsが設定されます。
- apiVersion: v1 kind: Node spec: taints: - effect: NoSchedule key: node.cloudprovider.kubernetes.io/uninitialized value: "true"
sakura-cloud-controller-managerをデプロイする際はこのtaintsに対するtolerationsが適切に設定されている必要があります。
# tolerationsの設定例 apiVersion: extensions/v1beta1 kind: Deployment metadata: name: sakura-cloud-controller-manager namespace: kube-system spec: replicas: 1 template: spec: containers: - name: sakura-cloud-controller-manager image: "sacloud/sakura-cloud-controller-manager:0.3.0" tolerations: # tolerationsを設定しておく - key: node.cloudprovider.kubernetes.io/uninitialized value: "true" effect: NoSchedule
もしkubeletに--cloud-provider
を指定しなかったらどうなるの?
この場合でもsakura-cloud-controller-managerのデプロイ自体はうまくいくように見えます。
が、ノードのExternalIPが適切に設定されないため、type: LoadBalancer
なサービスを作ってもロードバランサが作成されるものの実サーバが登録されないという状態になります。
serviceは作成されるけど、、、
実サーバは登録されていない
クラスタ内のノード名とさくらのクラウド上でのサーバ名が一致していること
これはsakura-cloud-controller-manager側の制約です。
sakura-cloud-controller-managerではノード名を条件にさくらのクラウドAPIで対象サーバの情報を取得しています。
このため、ノード名とサーバ名が異なるとうまくいきません。
kubeletの--hostname-override
オプションなどで適切に設定しましょう。
(kubeadmの場合は--node-name
フラグが利用できます。 参考: kubeadm init - Kubernetes)
もしノード名とサーバ名が違うとどうなるの?
sakura-cloud-controller-managerでのノード情報の取得が行えず、ノードのtaintsが残り続けます。
このためPodを起動しようとしてもPendingのままとなります。
(まずkube-dnsなどの主要コンポーネントについてもPendingのままとなっているはずです。)
# Podを起動しようとしてもPendingのまま $ kubectl get pod NAME READY STATUS RESTARTS AGE nginx-7cdbd8cdc9-8g8mw 0/1 Pending 0 3m1s # 主要コンポーネントもPendingのまま $ kubectl get pod -n kube-system --selector k8s-app=kube-dns NAME READY STATUS RESTARTS AGE kube-dns-58bd5b8dd7-swrlg 0/3 Pending 0 7m39s
さらにこの状態だとノードのInternalIP/ExternalIPが設定されず、kubectl logs
を実行するとError from server: no preferred addresses found; known addresses: []
などというエラーになります。
sakura-cloud-controller-managerのデプロイ
DeploymentまたはDaemonSetとしてデプロイしてください。
(現在Helmでデプロイする場合はDaemonSetのみサポートしています)
Deploymentとする場合のマニフェスト例は以下の通りです。 (この例はRKEを使ってデプロイしたKubernetesクラスタを利用しています。tolerationsやnodeSelectorsは環境に応じて適切に指定してください)
apiVersion: v1 kind: Secret metadata: name: sakuracloud-api-keys namespace: kube-system type: Opaque data: access-token: "<APIアクセストークン>" access-token-secret: "<APIアクセスシークレット>" --- --- apiVersion: v1 kind: ServiceAccount metadata: name: sakura-cloud-controller-manager namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: annotations: rbac.authorization.kubernetes.io/autoupdate: "true" name: system:sakura-cloud-controller-manager rules: - apiGroups: - "" resources: - events verbs: - create - patch - update - apiGroups: - "" resources: - nodes verbs: - '*' - apiGroups: - "" resources: - nodes/status verbs: - patch - apiGroups: - "" resources: - services verbs: - list - patch - update - watch - apiGroups: - "" resources: - services/status verbs: - list - patch - update - watch - apiGroups: - "" resources: - serviceaccounts verbs: - create - apiGroups: - "" resources: - persistentvolumes verbs: - get - list - update - watch - apiGroups: - "" resources: - configmaps verbs: - get - list - watch - apiGroups: - "" resources: - endpoints verbs: - create - get - list - watch - update --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: system:sakura-cloud-controller-manager roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:sakura-cloud-controller-manager subjects: - kind: ServiceAccount name: sakura-cloud-controller-manager namespace: kube-system --- apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: k8s-app: cloud-controller-manager name: sakura-cloud-controller-manager namespace: kube-system spec: replicas: 1 selector: matchLabels: k8s-app: cloud-controller-manager template: metadata: labels: k8s-app: cloud-controller-manager spec: dnsPolicy: Default hostNetwork: true serviceAccountName: sakura-cloud-controller-manager containers: - name: sakura-cloud-controller-manager image: "sacloud/sakura-cloud-controller-manager:0.3.0" resources: requests: cpu: 100m memory: 128Mi limits: cpu: 256m memory: 256Mi command: - /usr/local/bin/sakura-cloud-controller-manager - --cloud-provider=sakuracloud - --allocate-node-cidrs=false - --configure-cloud-routes=false env: - name: SAKURACLOUD_ACCESS_TOKEN valueFrom: secretKeyRef: name: sakuracloud-api-keys key: access-token - name: SAKURACLOUD_ACCESS_TOKEN_SECRET valueFrom: secretKeyRef: name: sakuracloud-api-keys key: access-token-secret - name: SAKURACLOUD_ZONE value: "<対象ゾーン(is1a or is1b or tk1a)>" - name: SAKURACLOUD_CLUSTER_ID value: "default" tolerations: - key: node.cloudprovider.kubernetes.io/uninitialized value: "true" effect: NoSchedule - key: "CriticalAddonsOnly" operator: "Exists" nodeSelector: node-role.kubernetes.io/controlplane: "true"
実行時によくあるトラブル
よくあるトラブルとして、Serviceを作成してもいつまでもPendingのままというものがあります。
この場合、sakura-cloud-controller-managerのログを参照すると何かヒントが得られることがあります。
# ログの参照例 $ kubectl logs -f -n kube-system sakura-cloud-controller-managerのpod名
私も引っかかったことがあるのは次のようなエラーメッセージが出るケースです。
Improper request. The parameters of the specified error or input rule violation. Please check your entries.\n実サーバのIPアドレス(xxx.xxx.xxx.xxx)は同一ネットワークである必要があります
このケースは@k8s
タグのついたスイッチ+ルータが複数存在している場合に発生します。
複数のスイッチ+ルータを使い分けたい場合はそれぞれのスイッチに対し識別用のタグを付与した上でk8s.usacloud.jp/router-selector
アノテーションをServiceに対して指定するようにすればOKです。
おまけ: RKEでデプロイするTerraformモジュール
こちらにTerraformのさくらのクラウドプロバイダー+RKEプロバイダーでクラスタ構築やsakura-cloud-controller-managerのデプロイまで行うモジュールを置いておきます。
以上です。