K8sでServiceAccountをPodから確実に取り外す方法
以前、ServiceAccountを取り外すのと同時に、不要となるServiceAccountリソースを削除しようとしたことがありました。この時はDeploymentからserviceAccountName
フィールドを削除して対応しようとしましたが、ServiceAccountが外れず想定通りにいきませんでした。それを解決するためにServiceAccountの取り外し方について調べたので、今回はそれをまとめました。
ServiceAccountの取り外し方
ServiceAccountをDeploymentやJobsなどのリソースにアタッチするためにはPodテンプレート内のserviceAccountName
フィールドを利用します。しかし、すでにアタッチされているServiceAccountを外したい場合、単にテンプレートからserviceAccountName
フィールドを削除するだけでは外せません。このフィールドを削除しても後方互換性の維持のためにDeploymentやReplicaSetは更新されないためです。
すでにServiceAccountがアタッチされているリソースからServiceAccountを外したい場合は、下記いずれかの対応をする必要があります。
-
serviceAccountName
とserviceAccount
フィールドにnull
を設定してマニフェストを適用する (基本的にこの対応を推奨) -
serviceAccountName
フィールドにdefault
を設定してマニフェストを適用する -
kubectl edit
を用いて、DeploymentやJobsの設定から直接serviceAccountName
フィールドを削除する
1つずつ見ていきましょう。
null
を設定する方法
フィールドにこれは公式ドキュメントにも記載されている方法になります。Podテンプレート内のserviceAccountName
とserviceAccount
フィールドにnull
を明示的に設定することで、既存リソースの更新が行われます。通常の設定更新時と同様に、新しい設定のPodが立ち上がり古いPodは削除されます。
The
.spec.serviceAccount
field is a deprecated alias for.spec.serviceAccountName
. If you want to remove the fields from a workload resource, set both fields to empty explicitly on the pod template.
Configure Service Accounts for Pods | Kubernetes
この方法の場合、適用後に2つの不要なフィールドがマニフェストに残ります。しかし、ServiceAccountを外した後ならば、フィールドをマニフェストから削除できるので、最終的なマニフェストの見通しは良くなります。
検証
まずは検証用の環境を用意します。ローカル環境にkind
を利用してKubernetesクラスタを立ち上げます。今回利用する環境は下記となります。この環境は後続の検証でも利用します。
$ kind version
kind v0.24.0 go1.22.6 darwin/arm64
$ kind create cluster
$ kubectl version
Client Version: v1.31.0
Kustomize Version: v5.4.2
Server Version: v1.31.0
次に、ServiceAccountをアタッチしたDeploymentを作成します。以下のマニフェストをmanifest.yaml
として保存します。
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
serviceAccountName: my-service-account
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
マニフェストファイルを作成したらkubectl apply
コマンドでリソースを作成し、ServiceAccountがアタッチされていることを確認します。
$ kubectl apply -f manifest.yaml
serviceaccount/my-service-account created
deployment.apps/nginx created
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 39s
$ kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-5864c46b87-sfcx7 1/1 Running 0 41s
# DeploymentにServiceAccountがアタッチされていることを確認
$ kubectl describe deploy nginx | grep "Service Account"
Service Account: my-service-account
# PodにもServiceAccountがアタッチされていることを確認
$ kubectl describe po nginx-5864c46b87-sfcx7 | grep "Service Account"
Service Account: my-service-account
※1: ここまでの手順は後続の検証でも行います。
ServiceAccountがアタッチされているリソースが作成できたので、次にServiceAccountを外すためにマニフェストを更新します。serviceAccountName
とserviceAccount
フィールドにnull
を設定します。
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
serviceAccountName: null # 変更
serviceAccount: null # 追加
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
kubectl apply
コマンドで更新したマニフェストを適用し、ServiceAccountが外されていることを確認します。
$ kubectl apply -f manifest.yaml
serviceaccount/my-service-account unchanged
deployment.apps/nginx configured
$ kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-54b9c68f67-7vs2t 1/1 Running 0 22s
# DeploymentからServiceAccountが外されていることを確認
$ kubectl describe deploy nginx | grep "Service Account"
# 何も表示されない
# PodからServiceAccount(my-service-account)が外されていることを確認
# *PodはServiceAccountが無くなることはなく、defaultがアタッチされる。
$ kubectl describe po nginx-54b9c68f67-7vs2t | grep "Service Account"
Service Account: default
これで、ServiceAccountを問題なく取り外すことができました。
default
を設定する方法
フィールドに「フィールドにnull
を設定する方法」の検証で確認した通り、serviceAccountName
フィールドを指定しない場合、デフォルトでdefault
ServiceAccountが適用されます。ServiceAccountは「なし」にはなりません。
すなわち、「すでに適用しているServiceAccountを外す」は「default
ServiceAccountを代わりに適用する」と同じです。これを利用して、serviceAccountName
にdefault
を明示的に指定することで、既存のServiceAccountを取り外すことができます。
この方法も「フィールドにnull
を設定する方法」と同様に不要なフィールドが一時的に残りますが、のちにそのフィールドをマニフェストから削除することで、最終的なマニフェストの見通しをよくできます。しかし、Kubernetes上のDeploymentやJobsのリソース情報にはdefault
ServiceAccountがアタッチされているように表示されます。そのため、ServiceAccountを外したというよりかは、default
に切り替えたように見えます。(実際のリソースの挙動は外した場合と変わりません)
検証
まず、検証の下準備として、先ほどの検証で行った※1までの手順を行います。
$ kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-5864c46b87-sg4fg 1/1 Running 0 18s
$ kubectl describe deploy nginx | grep "Service Account"
Service Account: my-service-account
$ kubectl describe po nginx-5864c46b87-sg4fg | grep "Service Account"
Service Account: my-service-account
ServiceAccountがアタッチされているリソースが作成できたので、次にServiceAccountを外すためにマニフェストを更新します。serviceAccountName
フィールドにdefault
を設定します。
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
serviceAccountName: default # 変更
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
更新したマニフェストをkubectl apply
コマンドで適用し、ServiceAccountが外されていることを確認します。
$ kubectl apply -f manifest.yaml
serviceaccount/my-service-account unchanged
deployment.apps/nginx configured
$ kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-54b9c68f67-7vs2t 1/1 Running 0 22s
# DeploymentからServiceAccount(my-service-account)が外されていることを確認
# ServiceAccount情報が無くなるわけではなく、defaultがアタッチされていることになる。
$ kubectl describe deploy nginx | grep "Service Account"
Service Account: default
# PodからServiceAccount(my-service-account)が外されていることを確認
k describe po nginx-bd49b995-bbncn | grep "Service Account"
Service Account: default
PodからServiceAccountが外されていることが確認できました。しかし、前述した通りDeploymentにはService Account: default
と表示されフィールド自体は残ってしまいます。
kubectl edit
を用いて直接削除する方法
すでにデプロイされているDeploymentやJobsから直接ServiceAccountを外す方法もあります。kubectl edit
コマンドを用いて、リソースの設定からserviceAccountName
とserviceAccount
フィールドを直接削除することで外すことができます。
$ kubectl edit deployment <deployment-name>
この場合、マニフェストファイル側からは単にserviceAccountName
フィールドを削除するだけで良くなります。次回以降のマニフェスト適用時には、すでにリソースとマニフェストからServiceAccountが外されているため、変更が発生しません。また、マニフェストに不要なフィールドが残ることもありません。しかし、kubectl edit
コマンドを用いるため、手動操作が必要な点はデメリットと言えます。
検証
先ほどと同様にまずは※1までの手順を行います。
$ kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-5864c46b87-8cwd4 1/1 Running 0 33s
$ kubectl describe deploy nginx | grep "Service Account"
Service Account: my-service-account
$ kubectl describe po nginx-5864c46b87-8cwd4 | grep "Service Account"
Service Account: my-service-account
リソースの準備ができたら、kubectl edit
コマンドを用いてServiceAccountを外します。(serviceAccountName
とserviceAccount
フィールドを削除します)
$ kubectl edit deploy nginx
deployment.apps/nginx edited
削除後にはPodが再生成され、ServiceAccountが外されているはずです。
$ kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-54b9c68f67-fxrz7 1/1 Running 0 19s
# DeploymentからServiceAccountが外されていることを確認
$ kubectl describe deploy nginx | grep "Service Account"
# 何も表示されない
# PodからServiceAccount(my-service-account)が外されていることを確認
$ kubectl describe po nginx-54b9c68f67-fxrz7 | grep "Service Account"
Service Account: default
なお、すでにDeploymentやPodからServiceAccountが外されているので、下記のようにマニフェストを更新しても変更が発生しません。
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
# serviceAccountName: my-service-account # 削除
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
kubectl apply
コマンドで更新後のマニフェストを適用してもPodが再生成されることはありません。
なお、出力結果にdeployment.apps/nginx configured
と表示されていますが、実リソースには変更が発生していません。これはKubernetesが前回適用されたマニフェストを覚えており、そこから差分(serviceAccountName
フィールドが削除された)が発生しているため表示されています。
$ kubectl apply -f manifest.yaml
serviceaccount/my-service-account unchanged
deployment.apps/nginx configured
$ kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-54b9c68f67-fxrz7 1/1 Running 0 1m45s
終わりに
ServiceAccountを確実に取り外すための3つの方法を見てきました。
一般的にはKubernetes上のリソース管理にArgoCDなどのCDツールを利用していることが多いはずです。その場合、kubectl edit
を用いて直接ServiceAccountを外す方法は避けるべきです。そのため、serviceAccountName
とserviceAccount
フィールドにnull
を設定する方法が推奨されます。default
ServiceAccountを代わりに適用する方法もありますが、リソースの情報からはServiceAccountが適用されているように見えてしまうので、個人的にはあまりお勧めしません。
Discussion