Kubernetes の CronJob と RBAC を活用して Deployment レプリカ数を定期的にスケールインする方法

## 📌記事の概要
Kubernetes を運用していると「夜間や特定の時間帯に Deployment のレプリカ数を縮退（スケールイン）したい」と思うことはありませんか？本記事では、**RBAC（Role-Based Access Control）を活用し、CronJob を使って定期的に Deployment のスケールインを行う方法**を解説します。

## 🔹RBACとは
RBAC（Role-Based Access Control）は、**Kubernetes のリソースに対するアクセス権限を管理する仕組み** です。
これにより、特定のユーザーや ``ServiceAccount`` に対して、**どのリソースにどの操作（例: get, patch, delete）を許可するか** を細かく設定できます。

Kubernetes では RBAC を設定する際に 2種類の Role を使います：
* ``Role``:1つの Namespace に限定された権限を付与する
* ``ClusterRole``:クラスタ全体で利用できる権限を付与する

今回は、Namespace ``pra1`` にある ``CronJob`` から、Namespace ``pra2`` の Deployment をスケールインするアーキテクチャを構築するため、**ClusterRole** を利用します。

## 🏗アーキテクチャ
本記事で構築するアーキテクチャは以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4000068/fb10ac2c-811f-4453-8a64-a23301c9bb02.png)

* ``pra1`` Namespace には ``CronJob`` と ``ServiceAccount``（``cron-sa``）が存在
* ``pra2`` Namespace にはスケールイン対象の ``Deployment``（``deploy``）が存在
* ``ServiceAccount`` に対して、``ClusterRoleBinding`` を通じて ``ClusterRole`` を適用し、``Deployment`` のスケール権限を付与

## 🛠構築手順
### 1.Namespaceを作成
```
kubectl create ns pra1
kubectl create ns pra2
```
### 2.Scale In対象のDeploymentを作成
```
kubectl create deploy deploy --image=nginx -n pra2 --replicas=3
```

### 3.ServiceAccountを作成
```
kubectl create sa cron-sa -n pra1
```

### 4.ClusterRoleを作成
Deployment の ``get`` 権限と ``scale``（``patch``）権限を持つ ``ClusterRole`` を作成します。

```
kubectl create clusterrole scale-cluster-role \
  --verb=get --verb=patch \
  --resource=deployments --resource=deployments/scale
```

### 5.ClusterRoleBindingを作成
``ClusterRole``と``ServiceAccount``をバインディングします。
```
kubectl create clusterrolebinding scale-cluster-rolebinding \
  --clusterrole=scale-cluster-role \
  --serviceaccount=pra1:cron-sa
```

### 6.Scaleコマンドを定期実行するCronJobを作成
``Deployment`` に対してScaleコマンドを定期実行（今回は3分おき）する``CronJob`` のマニフェストファイルを作成します。
```
kubectl create cj scale-in \
  --image=bitnami/kubectl \
  -n pra1 \
  --schedule='*/3 * * * *' \
  --dry-run=client -o yaml \
  -- /bin/sh -c 'kubectl scale deploy/deploy -n pra2 --replicas=1' > cj.yaml
```
作成したマニフェストファイルを編集し、``ServiceAccount``をアタッチします。
```sh:cj.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  creationTimestamp: null
  name: scale-in
  namespace: pra1
spec:
  jobTemplate:
    metadata:
      creationTimestamp: null
      name: scale-in
    spec:
      template:
        metadata:
          creationTimestamp: null
        spec:
          serviceAccountName: cron-sa #ServiceAccountを追記
          containers:
          - command:
            - /bin/sh
            - -c
            - kubectl scale deploy/deploy -n pra2 --replicas=1
            image: bitnami/kubectl
            name: scale-in
            resources: {}
          restartPolicy: OnFailure
  schedule: '*/3 * * * *'
status: {}
```
適用：
```
kubectl create -f cj.yaml
```
### 7.DeploymentがScale Inされることの確認
```
kubectl get deploy deploy -n pra2 -w
```
数分待つと、以下のような実行結果が出力され、Scale Inが正常に実行されたことを確認できました。
```
$ kubectl get deploy deploy -n pra2 -w
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
deploy   3/3     3            3           13m
deploy   3/1     3            3           15m
deploy   3/1     3            3           15m
deploy   1/1     1            1           15m

```
> **⚠️ 注意**
> スケール変更時の動作は `Deployment` の `strategy` によって変わることがあります。


:::note warn
## 🔍トラブルシューティング
### ✅Jobが作成されているか確認
```
kubectl get job -n pra1
```
**Job が作成されていない場合、CronJob の設定に問題がある可能性が高い！**

```
kubectl describe job <Job名> -n pra1
```

### ✅Podが作成されているか確認
```
kubectl get po -n pra1
```
**Pod が作成されていない場合、``CronJob`` の詳細を確認**
```
kubectl describe cj scale-in -n pra1
```

### ✅Podのログを確認
```
kubectl logs <CronJobによって作成されたPodの名前> -n pra1
```
**以下のようなエラーが出ている場合、RBAC の設定を見直す！**
```
Error from server (Forbidden): deployments.apps "deploy" is forbidden: User "system:serviceaccount:pra1:cron-sa" cannot patch resource "deployments/scale" in API group "apps" in the namespace "pra2"
```
:::

## 📌まとめ
✅ ``CronJob`` を使えば ``Deployment`` の自動スケールインが可能！
✅ RBAC 設定で ``ServiceAccount`` に適切な権限を付与する！
✅ ``kubectl logs`` と ``kubectl describe`` を活用してデバッグ！

## 追記
hpaがDeploymentに設定されている場合は、別途hpaの最小レプリカ数の変更を行うpatchコマンドを実行するCronJob が必要です。