kustomizeでoverlays側リソースを別Namespaceに書き換えたい

# はじめに
kustomize、便利ですよね。
複数環境でkubernetesを運用するとき、共通化などによりマニフェスト管理負荷を下げる目的に、利用している現場が多いかと思います。

kustomizeは直感的に使えて便利な反面、なんとなくで使えてしまうので、
この記事では名前空間を環境別で分けたい時に、地味にぶつかりそうなエラーとその解決策を書いてみました。

# 実行環境

```zsh
$ kustomize version
v5.4.2
```

# 本題
## 例示
例を挙げて考えてみます。
簡単に、以下のようなディレクトリ構成とします。（今回はdev環境のみ考慮）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577028/53d9b69c-074d-217a-ec8b-bb6d88904dfc.png)

baseでは`default名前空間`にdeploymentを定義しつつも、dev環境では`dev名前空間`にdeploymentをデプロイしたいケースを想定します。
（今回はついでにcpuのresource requestも書き換えます）


### base
```deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: default
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: "500m"
```


```kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
```

### overlays
```kustomization.yaml
resources:
  - ../../base
  - ./namespace-dev.yaml

patches:
  - path: deployment-patch.yaml
```

```namespace-dev.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: dev
```

overlaysのdeployment-patch.yamlは後述。

## NG例
patchesで名前空間も書き換えようと思い、deployment-patch.yamlを以下のように書くとエラーが出てビルドできません。

```overlays/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev
spec:
  template:
    spec:
      containers:
        - name: nginx
          resources:
            requests:
              cpu: "250m"
```

↓エラーメッセージ

`kustomize build overlays/dev
Error: no resource matches strategic merge patch "Deployment.v1.apps/nginx-deployment.dev": no matches for Id Deployment.v1.apps/nginx-deployment.dev; failed to find unique target for patch Deployment.v1.apps/nginx-deployment.dev`

つまりkustomizeは **`dev名前空間`にあるnginx-deploymentリソースをパッチ対象と認識しますが、baseではnginx-deploymentを`default名前空間`で定義しているので、パッチ（書き換え）対象リソースが無いという理由で**エラーになっています。


## OK例
patchesで名前空間を書き換えるのではなく、kustomization.yaml自体でnamespaceを指定することで解決できます。
**kustomization.yamlでnamespaceを書くことで、その配下の全リソースがそのnamespaceで作成されることになります。**

```overlays/kustomization.yaml
namespace: dev # これを追記

resources:
  - ../../base
  - ./namespace-dev.yaml

patches:
  - path: deployment-patch.yaml
```

```overlays/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  # namespace: dev # こっちのnamespaceは削除
spec:
  template:
    spec:
      containers:
        - name: nginx
          resources:
            requests:
              cpu: "250m"
```

:::note warn
patch側のnamespaceの記述は必ず削除する必要があります。
そうしないと、依然として前述のエラーが発生します。
:::

上記により、無事にビルド・デプロイできるようになりました。

```zsh
$ kustomize build overlays/dev

apiVersion: v1
kind: Namespace
metadata:
  name: dev
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 250m

$ kubectl apply -k overlays/dev
namespace/dev created
deployment.apps/nginx-deployment created
```


# さいごに
kustomization.yamlのnamespaceオプションの存在を知っていればこのエラーは回避できますが、patchesが便利なため名前空間も無理やり書き換えようとしてハマるパターンが多そうなので書いてみました。（実際に自分もハマりましたw）

個人的は、この一件でなんとなくkustomizeを使っていたのが露呈してしまったので、これを機にkustomizeを体系的に勉強しようと思いました。


# 参考
- [【ドキュメント】Kustomize Feature List](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/#kustomize-feature-list)