OpenShiftとCluster Autoscalerで、リソース逼迫により自動的にワーカーノードが追加されるクラスタを構築する

OpenShiftソリューションアーキテクトの林です。

本記事は、OpenShiftとAWSのAuto Scaling Groupで伸縮自在なKubernetesクラスタを構築するの続きです。

前回は、OpenShiftのbootstrapを利用して、

  • VMを立ち上げるだけで既存のクラスタにワーカーノードとして参加させる
  • AWSのAuto Scaling Groupで構成することで、簡単にOpenShiftのワーカーノードを増減させる

を実現しました。

本記事では、さらにCluster Autoscalerをクラスタに導入してみます。

これにより、Podを立てるときに十分なリソース(メモリ量など)がない場合に、自動的にAuto Scaling GroupのVM数が増えてワーカーノードが追加されるようになります。

Cluster Autoscalerは、OpenShiftのv3.11でGAとなりサポートされています(現在はAWS上のみサポート)。

Cluster Autoscalerのインストールについて

前回までの手順で、Auto Scaling Groupでワーカーノードを追加、削除できるようになっていれば、Cluster Autoscalerの導入は比較的簡単です。

  • Cluster Autoscalerの動作に必要なRBACをクラスタに設定する
  • AWSのAuto Scaling Groupを操作できるIAMを作成する
  • 上記IAMのAccess Key IDとSecret Access Key、およびAuto Scaling Groupの名前を指定して、Cluster Autoscalerをクラスタにインストールする

そういうわけで、さっそくCluster Autoscalerをクラスタに設定してみましょう。

Auto Scaling Groupの作成

AWSのAuto Scaling Groupは、起動設定または起動テンプレートから作成することになっており、AWSの推奨は新しい方法である起動テンプレートを使った方法です。

しかし、OpenShiftで現在サポートされているCluster Autoscalerは、現在起動設定の方しかサポートしていませんでした。。。

https://github.com/kubernetes/autoscaler/blob/cluster-autoscaler-1.2.0/cluster-autoscaler/cloudprovider/aws/aws_manager.go#L367

そういうわけで、以下に注意しながら起動設定を作成します。

  • 前回の記事を参考に、同じ設定でAWSの起動設定を作成する
  • 起動設定からAuto Scaling Groupを作成し、以下のようにタグ付けする。また、「新しいインスタンスにタグ付けする」を有効にする
    • k8s.io/cluster-autoscaler/node-template/label/node-role.kubernetes.io/compute : true
    • kubernetes.io/cluster/<クラスタ名> : owned

f:id:literalice:20181225104218p:plain
Cluster Autoscaler用AWSタグ

Cluster Autoscaler用の権限設定

Cluster Autoscalerの動作に必要なService AccountおよびRBACを設定します。

以下、Cluster Roleの設定を行う場面があるので、cluster-admin権限のあるOpenShiftユーザーで実施してください。

Cluster Autoscaler用のプロジェクトを作成する

以下コマンドでプロジェクトを作成します。このプロジェクトに、Cluster AutoscalerのPodを導入します。

oc apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
  name: cluster-autoscaler
  annotations:
    openshift.io/node-selector: ""
EOF

oc project cluster-autoscaler

なお、OpenShift v3.11では、デフォルトのNode Selectorがnode-role.kubernetes.io/compute=trueとなっており、普通にoc new-projectでプロジェクトを作成すると中のPodはComputeノードにデプロイされます。

ここでは、Cluster AutoscalerをInfraノードにデプロイしたいので、上記のようにプロジェクトのNode Selectorを明示的に指定しています。

Cluster Autoscaler用のService Accountを作成する

Cluster AutoscalerのPodに割り当てるService Accountを作成します。

以下yamlを作成して、 oc apply -fコマンドで適用してください。

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
  name: cluster-autoscaler
  namespace: cluster-autoscaler

Cluster Autoscalerに必要な権限の設定

上記で作成したService Accountに権限を設定します。

まず、クラスタのリソース監視などに必要なCluster Roleを作成します。以下yamlファイルを作成して、oc apply -fで適用してください。

apiVersion: v1
kind: ClusterRole
metadata:
  name: cluster-autoscaler
rules:
- apiGroups:
  - ""
  resources:
  - persistentvolumeclaims
  - persistentvolumes
  - pods
  - replicationcontrollers
  - services
  verbs:
  - get
  - list
  - watch
  attributeRestrictions: null
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - get
  - list
  - watch
  - patch
  - create
  attributeRestrictions: null
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
  - list
  - watch
  - patch
  - update
  attributeRestrictions: null
- apiGroups:
  - extensions
  - apps
  resources:
  - daemonsets
  - replicasets
  - statefulsets
  verbs:
  - get
  - list
  - watch
  attributeRestrictions: null
- apiGroups:
  - policy
  resources:
  - poddisruptionbudgets
  verbs:
  - get
  - list
  - watch
  attributeRestrictions: null

Cluster Autoscalerは、スケーリングの情報をConfigMapに書き込むので、それに必要な権限も作成します。

apiVersion: v1
kind: Role
metadata:
  name: cluster-autoscaler
rules:
- apiGroups:
  - ""
  resources:
  - configmaps
  resourceNames:
  - cluster-autoscaler
  - cluster-autoscaler-status
  verbs:
  - create
  - get
  - patch
  - update
  attributeRestrictions: null
- apiGroups:
  - ""
  resources:
  - configmaps
  verbs:
  - create
  attributeRestrictions: null
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  attributeRestrictions: null

Roleの作成が終わったら、先ほど作成したService AccountにこれらのRoleとクラスタの読み込み権限を付与します。

$ oc adm policy add-cluster-role-to-user cluster-autoscaler system:serviceaccount:cluster-autoscaler:cluster-autoscaler -n cluster-autoscaler

$ oc adm policy add-role-to-user cluster-autoscaler system:serviceaccount:cluster-autoscaler:cluster-autoscaler --role-namespace cluster-autoscaler -n cluster-autoscaler

$ oc adm policy add-cluster-role-to-user cluster-reader system:serviceaccount:cluster-autoscaler:cluster-autoscaler -n cluster-autoscaler

IAMの設定

Cluster Autoscalerは、クラスタのリソース状況を見てAWSのAuto Scaling Groupを操作するので、それができる権限を付与する必要があります。

ここでは、AWSのIAMユーザーを新しく作成して、そこに適切なポリシーを設定することにします。

Cluster Autoscalerに必要なAWSの権限ポリシー

Cluster Autoscalerに必要なポリシーは、以下URLに記載のあるとおりAuto Scaling Groupに関するものです。

https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler/cloudprovider/aws

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:DescribeAutoScalingInstances",
                "autoscaling:DescribeTags",
                "autoscaling:SetDesiredCapacity",
                "autoscaling:TerminateInstanceInAutoScalingGroup",
                "autoscaling:DescribeLaunchConfigurations"
            ],
            "Resource": "*"
        }
    ]
}

AWSのコンソールなどから、上記のポリシーを適用しているIAMを作成します。

IAMのクレデンシャルをクラスタに設定

作成したIAMのクレデンシャルをクラスタのSecretとして設定します。

$ cat <<EOF > creds
[default]
aws_access_key_id = your-aws-access-key-id
aws_secret_access_key = your-aws-secret-access-key
EOF

$ oc create secret -n cluster-autoscaler generic autoscaler-credentials --from-file=creds

Cluster Autoscalerのデプロイ

これで、Cluster Autoscalerをデプロイする準備ができました。以下yamlを使って、Cluster Autoscalerをデプロイします。

.spec.template.spec.containers[0].args--nodes=0:6:<asgname>引数を<最小ワーカー数>:<最大ワーカー数>:<Auto Scaling Groupの名前>という記法で設定します。

ここには、前回の記事で作成したAuto Scaling Groupを設定してください。

また、.spec.template.spec.containers[0].envAWS_REGIONにクラスタのあるリージョンを設定します。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: cluster-autoscaler
  name: cluster-autoscaler
  namespace: cluster-autoscaler
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cluster-autoscaler
      role: infra
  template:
    metadata:
      labels:
        app: cluster-autoscaler
        role: infra
    spec:
      containers:
      - args:
        - /bin/cluster-autoscaler
        - --alsologtostderr
        - --v=4
        - --skip-nodes-with-local-storage=False
        - --leader-elect-resource-lock=configmaps
        - --namespace=cluster-autoscaler
        - --cloud-provider=aws
        - --nodes=0:6:<Auto Scaling Group名>
        env:
        - name: AWS_REGION
          value: ap-northeast-1
        - name: AWS_SHARED_CREDENTIALS_FILE
          value: /var/run/secrets/aws-creds/creds
        image: registry.redhat.io/openshift3/ose-cluster-autoscaler:v3.11.43
        name: autoscaler
        volumeMounts:
        - mountPath: /var/run/secrets/aws-creds
          name: aws-creds
          readOnly: true
      dnsPolicy: ClusterFirst
      nodeSelector:
        node-role.kubernetes.io/infra: "true"
      serviceAccountName: cluster-autoscaler
      terminationGracePeriodSeconds: 30
      volumes:
      - name: aws-creds
        secret:
          defaultMode: 420
          secretName: autoscaler-credentials

このYAMLをcluster-autoscaler.yamlなどの名前で保存し、クラスタに適用します。

$ oc apply -f cluster-autoscaler.yaml -n cluster-autoscaler
$ oc get pods -n cluster-autoscaler -w

NAME                                 READY     STATUS              RESTARTS   AGE
cluster-autoscaler-9b7f787f4-sw5gx   0/1       ContainerCreating   0          3s
cluster-autoscaler-9b7f787f4-sw5gx   1/1       Running   0         4s

Podが無事起動することを確認してください。

Cluster Autoscalerの動作確認

これで、Cluster Autoscalerの設定が完了しました。

クラスタの能力を超える量のPodをデプロイしようとすると、Auto Scaling GroupからVMが起動され、ワーカーノードが追加されていくはずです。

ここでは、以下のような無茶なDeploymentを作って、Podをデプロイしまくります。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: scale-up
  labels:
    app: scale-up
spec:
  replicas: 20 
  selector:
    matchLabels:
      app: scale-up
  template:
    metadata:
      labels:
        app: scale-up
    spec:
      containers:
      - name: origin-base
        image: openshift/origin-base
        resources:
          requests:
            memory: 2Gi
        command:
        - /bin/sh
        - "-c"
        - "echo 'this should be in the logs' && sleep 86400"
      terminationGracePeriodSeconds: 0

このファイルをscale-up.yamlなどの名前で保存し、以下のように適用してみましょう。

$ oc new-project autoscaler-demo
$ oc apply -f scale-up.yaml -n autoscaler-demo

もとのクラスタの能力によりますが、おそらく以下のように大量のPending状態なPodが発生すると思います。

$ oc get pods -n autoscaler-demo | grep Pending

scale-up-79684ff956-5jdnj             0/1       Pending   0          40s
scale-up-79684ff956-794d6             0/1       Pending   0          40s
scale-up-79684ff956-7rlm2             0/1       Pending   0          40s
scale-up-79684ff956-9m2jc             0/1       Pending   0          40s
scale-up-79684ff956-9m5fn             0/1       Pending   0          40s

Cluster Autoscalerは、この状態のPodを検知すると、ノードを追加して対応しようとします。

設定がうまくいっていれば、Auto Scaling Groupの希望インスタンス数が引き上げられ、以下のようにノードが追加されていくはずです。

$ oc get nodes
NAME                                             STATUS     ROLES          AGE       VERSION
ip-xx-xx-xx-xx.ap-northeast-1.compute.internal   Ready      compute        5d        v1.11.0+d4cacc0
ip-xx-xx-xx-xx.ap-northeast-1.compute.internal   Ready      compute        5d        v1.11.0+d4cacc0
ip-xx-xx-xx-xx.ap-northeast-1.compute.internal   Ready      infra,master   5d        v1.11.0+d4cacc0
ip-xx-xx-xx-xx.ap-northeast-1.compute.internal   Ready      compute        7s        v1.11.0+d4cacc0

まとめ

前回の記事では、AWSのAuto Scaling GroupとOpenShiftワーカーノードのBootstrapプロセスを用いて、Auto Scaling GroupでVM数を増減させるだけでクラスタを伸縮できるようにしました。

この記事では、さらにCluster Autoscalerをクラスタに設定して、リソースの利用状況に基づいて自動的にクラスタが伸縮されるように設定しました。

IaaSとコンテナプラットフォームを組み合わせ、条件を適切に設定すれば、事前にクラスタのサイジングを詰めるのではなく、動的に必要な量のリソースを確保することができます。

Cluster Autoscaler Operator

とはいえ、手順が複雑すぎるのでOperatorを使って簡単にインストールしたいところですね。

と思ってGitHubを探したら何かありました。

github.com

こいつは、AWSではなく、Cluster APIをCloud Providerとして使うことで、どのIaaSを使用していても利用できることを目指しているようです。

将来的には、このCluster Autoscaler Operatorもサポートされるようになるのかもしれませんね。

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。