HPAをArgo CDの管理対象としたときに発生するスケーリングループの回避方法

# はじめに

Horizontal Pod Autoscaler (HPA)をArgo CDの管理対象（GitOpsの対象）としたときに、replica数がループする現象が発生しました。
本記事では、そのトラブルの回避方法を紹介します。

# 環境情報

* Kubernetes
    * Docker Desktop 2.3.0.4
    * v1.16.6
* Argo CD v1.8.2

# トラブル詳細

## 再現方法

以下マニフェストのようなdeploymentとHPAをArgo CDの管理対象とする。

* [Deployment](https://github.com/nakkoh/argocd_hpa/blob/master/nginx/deployment.yaml)

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: argocd-hpa
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
```



* [HPA](https://github.com/nakkoh/argocd_hpa/blob/master/nginx/hpa.yaml)

```yaml
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: nginx
  namespace: argocd-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      targetAverageValue: 1
```



* [Application](https://github.com/nakkoh/argocd_hpa/blob/master/application.yaml)

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/nakkoh/argocd_hpa.git
    targetRevision: master
    path: nginx
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd-hpa
```

## トラブルの内容

マニフェストのreplicasとHPAが競合してしまうので、deploymentのステータスが`Sync OK`、`OutOfSync`を繰り替えし、その度にdeploymentのreplica数が1, 2に変化し続けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350260/ce01e68e-29f6-5779-e556-97273330362c.png)

# 回避方法

以下の2通りの方法があります。


## replicasを定義しない

以下のマニフェストのようにdeploymentの`spec.replicas`を定義しないことで、本トラブルを回避することができます。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: argocd-hpa
  labels:
    app: nginx
spec:
  # replicas: 1 ★ 定義しない
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
```

## replicasだけArgo CDの管理対象から外す

以下[applicationのマニフェスト](https://raw.githubusercontent.com/nakkoh/argocd_hpa/master/application.yaml)のように`spec.ignoreDifferences`を定義することでreplicasのみArgo CDの管理下から除外することで、本トラブルを回避できます。

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/nakkoh/argocd_hpa.git
    targetRevision: master
    path: nginx
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd_hpa
  ignoreDifferences:      # ★ 以下行を追加
  - group: apps           # 
    kind: Deployment      # 
    name: nginx           # 
    namespace: argocd-hpa # 
    jsonPointers:         # 
    - /spec/replicas      # 
syncPolicy:
  automated: {}
```

Helm chart使用時に本トラブルに遭遇した場合は、[replicasを定義しない](#replicasを定義しない)の方法が使えないことがあるため、[replicasだけArgo CDの管理対象から外す](#replicasだけargo-cdの管理対象から外す)の方法を使用する必要があります。

# 参考文献

* <https://github.com/argoproj/argo-cd/discussions/5105>
* <https://argoproj.github.io/argo-cd/user-guide/best_practices/#leaving-room-for-imperativeness>
* <https://argoproj.github.io/argo-cd/user-guide/diffing/#application-level-configuration>