kashinoki38 blog

something like tech blog

EKSでStatefulset+PVのMNG間移行を試してみる

大した検証じゃないけど、EKSでステートフルなワークロードをアップグレードする際の手順を試してみる。

Kubernetes のアップグレード

ZOZOさんのSpeakerdeckがよくまとまっているが、Kubernetesのバージョンアップグレードについて、大きくわけるとインプレースアップグレードとBlue/Greenアップグレードの2つになる。
さらにBlue/GreenアップグレードについてはNode Groupレベルで、新バージョンのNode Groupをクラスタ内に作って切り替えする方法と、クラスターレベルで新バージョンのクラスターを新た作り切り替えする方法(Cluster Migration)がある。

speakerdeck.com

それぞれの特徴は下記です。

①[インプレース]

②[B/G (Node Groupレベル) ]

  • 問題あった際にロールバックしやすい(古いバージョンのNode Groupがあるため)。
  • PodのNode Group間移動を自らの作業で実施する必要がある(NodeSelectorやNodeAffinityで)。
  • Control PlaneのバージョンとData Planeバージョンが一時的にズレ、それによりプラグインによっては問題がでる可能性がある。

③[B/G (Cluusterレベル) ]

  • Control Planeのバージョンも合わせて一気にバージョン変更が可能。
  • ロールバックしやすい。
  • 新規クラスタへの移行手順が複雑になる。(バックアップツール等の利用で効率化が必要)
  • トラフィックはALBのTGやCDNの向き先変更にて実施する。

安全重視で、クラスタ作成を自動化するツールを実装されたりして③を選ぶ企業が大規模だと多い印象。
※参考:https://creators-note.chatwork.com/entry/2021/07/14/150515
ただ、クラスタレベルのBlue/Greenアップグレードの作業の大変さを考え、①を選ぶ層も割といる。

ステートフルリソースありのノードインプレースアップグレード

MNGの場合

Karpenterの場合

ステートフルリソースありのEKS MNG B/Gアップグレード

MNG間のPod移行をNode Affinity等でやるイメージ。新NodeでもAZが同じであれば同じPVにてStatefulsetが起動する。
EKS MNG B/Gアップグレードを想定して、StatefulsetをMNG間でNodeAffinityで移行することを試してみる。

事前準備

EBS addon

マネコンからでも有効化できたが、IRSA作成が勝手にされなかったので、eksctlでやり直す。eksctl経由ならIRSAまでやってくれた

https://aws.amazon.com/jp/blogs/news/amazon-ebs-csi-driver-is-now-generally-available-in-amazon-eks-add-ons/

% aws eks describe-addon-versions --addon-name aws-ebs-csi-driver

% eksctl create addon --name aws-ebs-csi-driver --version v1.5.2-eksbuild.1 --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy --cluster

MNG作成

既存のMNGがあったので、検証用にもう1個MNGを追加。

eksctl create nodegroup -f nodegroup/mng.yaml
# dev-cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: keda-test
  region: ap-northeast-1

managedNodeGroups:
  - name: mng-2
    labels: { role: workers }
    instanceType: m6g.large
    desiredCapacity: 2
    minSize: 2
    maxSize: 2
    volumeSize: 80
    privateNetworking: false
    updateConfig:
      maxUnavailablePercentage: 100

Statefulset作成

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql-ebs
  namespace: ebs-test
  labels:
    app.kubernetes.io/created-by: eks-workshop
    app.kubernetes.io/team: database
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: mysql-ebs
      app.kubernetes.io/instance: mysql-ebs
      app.kubernetes.io/component: mysql-ebs
  serviceName: mysql
  template:
    metadata:
      labels:
        app.kubernetes.io/name: mysql-ebs
        app.kubernetes.io/instance: mysql-ebs
        app.kubernetes.io/component: mysql-ebs
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: eks.amazonaws.com/nodegroup
                    operator: In
                    values:
                      - ng-c5197504
                  - key: topology.kubernetes.io/zone
                    operator: In
                    values:
                      - ap-northeast-1c
      containers:
        - name: mysql
          image: "public.ecr.aws/docker/library/mysql:5.7"
          args:
            - "--ignore-db-dir=lost+found"
          imagePullPolicy: IfNotPresent
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: my-secret-pw
            - name: MYSQL_USER
              value: test
            - name: MYSQL_PASSWORD
              value: test
            - name: MYSQL_DATABASE
              value: catalog
          ports:
            - name: mysql
              containerPort: 3306
              protocol: TCP
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: gp2
        resources:
          requests:
            storage: 30Gi

NodeGroup移行のテスト

AZを同じにしてNodeAffinityで新NodeGroupになるように(eks.amazonaws.com/nodegroup)Statefulsetを移行したら、ちゃんとEBSは引き継がれた

% kg no -L topology.kubernetes.io/zone,eks.amazonaws.com/nodegroup
NAME                                                STATUS   ROLES    AGE    VERSION                ZONE              NODEGROUP
ip-192-168-13-124.ap-northeast-1.compute.internal   Ready    <none>   80s    v1.25.16-eks-ae9a62a   ap-northeast-1d   mng-2
ip-192-168-34-247.ap-northeast-1.compute.internal   Ready    <none>   301d   v1.25.11-eks-a5565ad   ap-northeast-1a   ng-c5197504
ip-192-168-65-238.ap-northeast-1.compute.internal   Ready    <none>   301d   v1.25.11-eks-a5565ad   ap-northeast-1c   ng-c5197504
ip-192-168-73-84.ap-northeast-1.compute.internal    Ready    <none>   81s    v1.25.16-eks-ae9a62a   ap-northeast-1c   mng-2

旧NodeGroupでPV書き込み

% kg po -n ebs-test -o wide
NAME          READY   STATUS    RESTARTS   AGE   IP               NODE                                                NOMINATED NODE   READINESS GATES
mysql-ebs-0   1/1     Running   0          3m30s   192.168.78.42   ip-192-168-65-238.ap-northeast-1.compute.internal   <none>           <none>

% kubectl exec mysql-ebs-0 -n ebs-test -- bash -c  "echo 123 > /var/lib/mysql/test.txt"

% kubectl exec mysql-ebs-0 -n ebs-test -- ls -larth /var/lib/mysql/ | grep -i test
-rw-r--r-- 1 root  root     4 Jun  2 04:02 test.txt

新NodeGroupへ移行、PVチェック

StatefulsetのNodeAffinityを新NGに変更

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql-ebs
  ...
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: eks.amazonaws.com/nodegroup
                    operator: In
                    values:
                      # - ng-c5197504
                      - mng-2
                  - key: topology.kubernetes.io/zone
                    operator: In
                    values:
                      - ap-northeast-1c
% kg po -n ebs-test -o wide -w
NAME          READY   STATUS              RESTARTS   AGE   IP       NODE                                               NOMINATED NODE   READINESS GATES
mysql-ebs-0   0/1     ContainerCreating   0          5s    <none>   ip-192-168-73-84.ap-northeast-1.compute.internal   <none>           <none>
mysql-ebs-0   1/1     Running             0          18s   192.168.85.105   ip-192-168-73-84.ap-northeast-1.compute.internal   <none>           <none>

% kubectl exec mysql-ebs-0 -n ebs-test -- ls -larth /var/lib/mysql/ | grep -i test
-rw-r--r-- 1 mysql root     4 Jun  2 04:02 test.txt

ちゃんと移行できたことを確認。

ステートフルリソースありのCluster Migration