이 섹션의 다중 페이지 출력 화면임. 여기를 클릭하여 프린트.
쿠버네티스 오브젝트 관리
- 1: 구성 파일을 이용한 쿠버네티스 오브젝트의 선언형 관리
- 2: Kustomize를 이용한 쿠버네티스 오브젝트의 선언형 관리
- 3: 명령형 커맨드를 이용한 쿠버네티스 오브젝트 관리하기
- 4: 구성파일을 이용한 명령형 쿠버네티스 오브젝트 관리
1 - 구성 파일을 이용한 쿠버네티스 오브젝트의 선언형 관리
쿠버네티스 오브젝트는 여러 개의 오브젝트 구성 파일을
디렉터리에 저장하고 필요에 따라 kubectl apply
를
사용하여 재귀적으로 오브젝트를 생성하고 업데이트함으로써 생성, 업데이트 및 삭제할 수 있다.
이 방식은 변경사항을 되돌려 오브젝트 구성 파일에 병합하지 않고
활성 오브젝트에 가해진 기록을 유지한다. kubectl diff
는 또한
apply
가 어떠한 변경사항을 이루어질지에 대한 프리뷰를 제공한다.
시작하기 전에
kubectl
를 설치한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.
트레이드 오프
kubectl
툴은 세 가지 방식의 오브젝트 관리를 지원한다.
- 명령형 커맨드
- 명령형 오브젝트 구성
- 선언형 오브젝트 구성
오브젝트 관리 방식의 종류별 장단점에 대한 논의는 쿠버네티스 오브젝트 관리를 참고한다.
개요
선언형 오브젝트 구성은 쿠버네티스 오브젝트 정의와 구성에 대한 확실한 이해가 필요하다. 아직 그렇지 못하다면, 먼저 다음 문서를 읽고 이해한다.
다음은 이 문서에서 사용되는 용어에 대한 정의이다.
- 오브젝트 구성 파일 / 구성 파일: 쿠버네티스 오브젝트에 대한
구성을 정의하는 하나의 파일. 이 주제는 어떻게
kubectl apply
에 구성 파일을 전달하는지에 대해 보여준다. 구성 파일은 일반적으로 Git과 같은, 소스 컨트롤에 저장된다. - 활성 오브젝트 구성 / 활성 구성: 쿠버네티스 클러스터에 의해 관측된 오브젝트에 대한 활성 구성 값. 이것들은 쿠버네티스 클러스터 저장소에 유지된다. 일반적으로 etcd가 사용된다.
- 선언형 구성 작성자 / 선언형 작성자: 활성 오브젝트를 업데이트해 주는
사람이나 소프트웨어. 이 주제에서 언급하는 활성 작성자는 오브젝트 구성 파일에 변경을 가하고
kubectl apply
를 실행하여 변경사항을 기록한다.
오브젝트 생성 방법
기존에 존재하는 것을 제외한, 지정한 디렉터리 내 구성 파일에 의해 정의된 모든 오브젝트를 생성하기 위해 kubectl apply
를
사용한다.
kubectl apply -f <디렉터리>/
이것은 각 오브젝트에 대해 kubectl.kubernetes.io/last-applied-configuration: '{...}'
어노테이션을 설정한다. 해당 어노테이션은 오브젝트를 생성하기 위해 사용했던
오브젝트 구성 파일의 내용을 포함한다.
참고: 재귀적으로 디렉터리를 처리하기 위해서-R
플래그를 추가한다.
다음은 오브젝트 구성 파일에 대한 예시이다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
생성될 오브젝트를 출력하려면 kubectl diff
를 실행한다.
kubectl diff -f https://k8s.io/examples/application/simple_deployment.yaml
참고:
diff
는kube-apiserver
의 활성화가 필요한 서버사이드 dry-run을 사용한다.
diff
는 dry-run 모드에서 서버 측 적용 요청을 수행하므로,PATCH
,CREATE
, 그리고UPDATE
권한을 부여해야 한다. 자세한 것은 Dry-Run 인증을 본다.
kubectl apply
를 사용하여 오브젝트를 생성한다.
kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml
kubectl get
을 사용하여 활성 구성을 출력한다.
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
출력은 kubectl.kubernetes.io/last-applied-configuration
어노테이션이
활성 구성에 기록된 것을 보여주며, 그것은 구성 파일과 일치한다.
kind: Deployment
metadata:
annotations:
# ...
# This is the json representation of simple_deployment.yaml
# It was written by kubectl apply when the object was created
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
# ...
minReadySeconds: 5
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
# ...
name: nginx
ports:
- containerPort: 80
# ...
# ...
# ...
# ...
오브젝트 업데이트 방법
또한 오브젝트가 기존에 존재하더라도 디렉터리 내 정의된 모든 오브젝트를 업데이트하기 위해 kubectl apply
를
사용할 수 있다. 이러한 접근방식은 다음을 수행할 수 있게 해준다.
- 활성 구성 내 구성 파일에 나타나는 필드 설정
- 활성 구성 내 구성 파일로부터 제거된 필드 정리
kubectl diff -f <디렉터리>/
kubectl apply -f <디렉터리>/
참고: 재귀적으로 디렉터리를 처리하기 위해서-R
플래그를 추가한다.
다음은 구성 파일의 예시이다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
kubectl apply
를 사용하여 오브젝트를 생성한다.
kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml
참고: 설명을 위해, 앞선 명령은 디렉터리 대신 하나의 구성 파일을 참조한다.
kubectl get
을 사용하여 활성 구성을 출력한다.
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
출력은 kubectl.kubernetes.io/last-applied-configuration
어노테이션이
활성 구성에 기록된 것을 보여주며, 그것은 구성 파일과 일치한다.
kind: Deployment
metadata:
annotations:
# ...
# This is the json representation of simple_deployment.yaml
# It was written by kubectl apply when the object was created
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
# ...
minReadySeconds: 5
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
# ...
name: nginx
ports:
- containerPort: 80
# ...
# ...
# ...
# ...
kubectl scale
을 사용하여 활성 구성 내 replicas
필드를 직접 업데이트한다.
이는 kubectl apply
를 사용하지 않는다.
kubectl scale deployment/nginx-deployment --replicas=2
kubectl get
을 사용하여 활성 구성을 출력한다.
kubectl get deployment nginx-deployment -o yaml
출력은 replicas
필드가 2로 설정된 것을 보여주며, last-applied-configuration
어노테이션은 replicas
필드를 포함하지 않는다.
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# ...
# note that the annotation does not contain replicas
# because it was not updated through apply
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
replicas: 2 # written by scale
# ...
minReadySeconds: 5
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
# ...
name: nginx
ports:
- containerPort: 80
# ...
nginx:1.14.2
에서 nginx:1.16.1
로 이미지를 변경하기 위해 simple_deployment.yaml
구성 파일을 업데이트 하고, minReadySeconds
필드를 삭제한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.16.1 # update the image
ports:
- containerPort: 80
구성 파일에 이루어진 변경사항을 적용한다.
kubectl diff -f https://k8s.io/examples/application/update_deployment.yaml
kubectl apply -f https://k8s.io/examples/application/update_deployment.yaml
kubectl get
을 사용하여 활성 구성을 출력한다.
kubectl get -f https://k8s.io/examples/application/update_deployment.yaml -o yaml
출력은 활성 구성에 다음의 변경사항을 보여준다.
replicas
필드는kubectl scale
에 의해 설정된 값 2를 유지한다.
이는 구성 파일에서 생략되었기 때문에 가능하다.image
필드는nginx:1.14.2
에서nginx:1.16.1
로 업데이트되었다.last-applied-configuration
어노테이션은 새로운 이미지로 업데이트되었다.minReadySeconds
필드는 지워졌다.last-applied-configuration
어노테이션은 더 이상minReadySeconds
필드를 포함하지 않는다.
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# ...
# The annotation contains the updated image to nginx 1.11.9,
# but does not contain the updated replicas to 2
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
replicas: 2 # Set by `kubectl scale`. Ignored by `kubectl apply`.
# minReadySeconds cleared by `kubectl apply`
# ...
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.16.1 # Set by `kubectl apply`
# ...
name: nginx
ports:
- containerPort: 80
# ...
# ...
# ...
# ...
경고: 명령형 오브젝트 구성 커맨드create
와replace
와 함께kubectl apply
를 혼합하는 것은 지원하지 않는다. 이는kubectl apply
가 업데이트 사항을 계산하는데 사용하는kubectl.kubernetes.io/last-applied-configuration
을create
와replace
가 유지하지 하지 않기 때문이다.
오브젝트 삭제 방법
kubectl apply
에 의해 관리되는 오브젝트를 삭제하는데 2가지 접근 방법이 있다.
권장 방법: kubectl delete -f <파일명>
명령형 커맨드를 사용하여 오브젝트를 수동으로 삭제하는 것이 권장되는 방식인데, 무엇이 삭제되는지에 대해 더 명확하게 나타내므로 사용자가 의도하지 않게 무언가를 삭제할 가능성이 작아지기 때문이다.
kubectl delete -f <파일명>
대안: kubectl apply -f <디렉터리/> --prune -l your=레이블
무엇을 하는지 파악하는 경우에만 이를 사용한다.
경고:kubectl apply --prune
은 알파 상태이며, 후속 릴리스에서는 하위 호환되지 않는 변경 사항이 도입될 수 있다.
경고: 이 명령을 사용할 때는 의도하지 않게 오브젝트를 삭제하지 않도록 주의해야만 한다.
kubectl delete
에 대한 대안으로, 디렉터리로부터 구성 파일이 삭제된 후에 삭제될 오브젝트를 식별하기 위해 kubectl apply
를 사용할 수 있다.
--prune
을 사용하여 적용하면 일련의 레이블의 집합과 일치하는
모든 오브젝트에 대해API 서버에 쿼리하고, 반환된 활성 오브젝트
구성을 오브젝트 구성 파일에 일치시키려고 시도한다.
오브젝트가 쿼리에 일치하고, 해당 디렉터리 내 구성 파일이 없고
last-applied-configuration
어노테이션이 있는 경우,
삭제된다.
kubectl apply -f <디렉터리/> --prune -l <레이블>
경고: prune을 사용하여 적용하는 것은 오브젝트 구성 파일을 포함하는 루트 디렉터리에 대해서만 실행해야 한다. 하위 디렉터리에 대해 실행하게 되면,-l <레이블>
로 지정된 레이블 셀렉터에 의해 반환되고 하위 디렉터리에 나타나지 않는 경우, 오브젝트가 의도하지 않게 삭제될 수 있다.
오브젝트 확인 방법
활성 오브젝트의 구성을 확인하기 위해 -o yaml
과 함께 kubectl get
을 사용할 수 있다.
kubectl get -f <파일명|url> -o yaml
어떻게 apply가 차이를 계산하고 변경을 병합하는가
주의: patch 는 전체 오브젝트 대신 오브젝트의 특정 필드 범위의 오퍼레이션을 업데이트한다. 이는 먼저 오브젝트를 읽지 않고도 오브젝트의 특정 필드 집합만을 업데이트할 수 있도록 해준다.
kubectl apply
가 하나의 오브젝트에 대한 활성 구성을 업데이트할 때,
API 서버에 패치 요청을 보냄으로써 그것을 수행한다.
그 패치는 활성 오브젝트 구성의 특정 필드에 대한 범위의
업데이트로 한정한다. kubectl apply
커맨드는
구성 파일, 활성 구성, 그리고 활성 구성에 저장된
last-applied-configuration
어노테이션을 사용하여 이 패치 요청을 계산한다.
패치 계산 병합
kubectl apply
명령은
kubectl.kubernetes.io/last-applied-configuration
어노테이션에 구성 파일의 내용을 기록한다.
이것은 구성 파일로부터 제거되었고 활성 구성으로부터 지워질 필요가 있는
필드를 확인하는 데 사용된다. 다음은 어떤 필드가 삭제 또는 설정돼야 하는지
계산하기 위해 사용되는 단계이다.
- 삭제할 필드를 계산한다. 이것은
last-applied-configuration
내 존재하고 구성 파일로부터 유실된 필드이다. - 추가 또는 설정되어야 할 필드를 계산한다. 이것은 활성 구성과 불일치하는 값을 가지는 구성 파일 내 존재하는 필드이다.
다음은 예시이다. 디플로이먼트 오브젝트에 대한 구성 파일이라고 가정한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.16.1 # update the image
ports:
- containerPort: 80
또한, 이것은 동일한 디플로이먼트 오브젝트에 대한 활성 구성이라고 가정한다.
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# ...
# note that the annotation does not contain replicas
# because it was not updated through apply
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
replicas: 2 # written by scale
# ...
minReadySeconds: 5
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
# ...
name: nginx
ports:
- containerPort: 80
# ...
다음은 kubectl apply
에 의해 수행될 병합 계산이다.
last-applied-configuration
으로부터 값을 읽어 구성 파일의 값과 비교하여 삭제할 필드를 계산한다.last-applied-configuration
에 보이는 것과는 무관하게 로컬의 오브젝트 구성 파일 내 null이라고 명시적으로 설정된 필드를 지운다. 이 예시에서,minReadySeconds
은last-applied-configuration
어노테이션 내 나타나지만, 구성 파일 내에는 보여지지 않는다. 조치: 활성 구성으로부터minReadySeconds
을 지운다.- 구성 파일로부터 값을 읽어 활성 구성 내 값과
비교하여 설정할 필드를 계산한다. 이 예시에서,
구성 파일 내
image
값은 활성 구성 내 값과 불일치한다. 조치: 활성 구성 내image
값을 설정한다. - 구성 파일의 값과 일치시키기 위해
last-applied-configuration
어노테이션을 설정한다. - 1, 2, 3으로부터의 결과를 API 서버에 단일 패치 요청으로 병합한다.
다음은 병합의 결과인 활성 구성이다.
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# ...
# The annotation contains the updated image to nginx 1.11.9,
# but does not contain the updated replicas to 2
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
selector:
matchLabels:
# ...
app: nginx
replicas: 2 # Set by `kubectl scale`. Ignored by `kubectl apply`.
# minReadySeconds cleared by `kubectl apply`
# ...
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.16.1 # Set by `kubectl apply`
# ...
name: nginx
ports:
- containerPort: 80
# ...
# ...
# ...
# ...
어떻게 상이한 필드 타입이 병합되는가
구성 파일 내 특정 필드가 필드의 타입에 따라 어떻게 활성 구성과 함께 병합되는가. 여러 가지 필드 타입이 있다.
-
기본(primitives): 문자열, 숫자 또는 불리언 타입의 필드. 예를 들어,
image
와replicas
는 기본 필드다. 조치: 교체. -
맵, 또한 오브젝트 라 칭함: 맵 타입 또는 서브필드를 포함하는 복합 타입의 필드. 예를 들어,
레이블
,어노테이션
,스펙
및메타데이터
는 모두 맵이다. 조치: 구성요소 또는 서브필드 병합. -
리스트: 기본타입 또는 맵이 될 수 있는 아이템의 리스트를 포함하는 필드. 예를 들어,
컨테이너
,포트
, 그리고args
는 리스트다. 조치: 다양함.
kubectl apply
가 맵 또는 리스트 필드를 업데이트하는 경우,
일반적으로 전체 필드를 교체하는 대신, 개별 부 구성요소를 업데이트한다,
예를 들어, 디플로이먼트에 대한 spec
을 병합할 경우, 전체 spec
이
교체되지 않는다. 대신 replicas
와 같은 spec
의 서브필드가
비교되고 병합된다.
기본 필드에 대한 변경사항 병합하기
기본 필드는 교체되거나 지워진다.
참고:-
는 값이 사용되지 않기 때문에 "해당 없음"으로 사용된다.
Field in object configuration file | Field in live object configuration | Field in last-applied-configuration | Action |
---|---|---|---|
Yes | Yes | - | 구성 파일 값 활성으로 설정. |
Yes | No | - | 활성을 로컬 구성으로 설정. |
No | - | Yes | 활성 구성으로부터 지움. |
No | - | No | 아무것도 안함. 활성값 유지. |
맵 필드에 변경사항 병합하기
맵을 요청하는 필드는 서브필드의 각각 또는 맵의 구성요소를 비교함으로써 병합된다.
참고:-
는 값이 사용되지 않기 때문에 "해당 없음"으로 사용된다.
Key in object configuration file | Key in live object configuration | Field in last-applied-configuration | Action |
---|---|---|---|
Yes | Yes | - | 서브필드 값 비교. |
Yes | No | - | 활성을 로컬 구성으로 설정. |
No | - | Yes | 활성 구성으로부터 삭제. |
No | - | No | 아무것도 안함. 활성값 유지. |
타입 리스트의 필드에 대한 변경사항 병합하기
리스트에 대한 변경사항을 병합하는 것은 세 가지 전략 중 하나를 사용한다.
- 구성요소가 모두 기본형인 경우 리스트를 교체한다.
- 복합 구성요소의 리스트에서 개별 구성요소를 병합한다.
- 기초 구성요소의 리스트를 병합한다.
전략에 대한 선택은 필드별로 이루어진다.
구성요소가 모두 기본형인 경우 리스트 교체
기초 필드와 동일한 리스트로 취급한다. 전체 리스트를 교체 또는 삭제한다. 이것은 순서를 유지한다.
예시: 파드 내 컨테이너의 args
필드를 업데이트하기 위해 kubectl apply
를 사용한다.
이것은 활성 구성 내 args
의 값을 구성 파일 내 값으로 설정한다.
활성 구성에 추가했던 이전의 모든 args
구성요소들은 유실된다.
구성 파일 내 정의한 args
구성요소의 순서는
활성 구성 내 유지된다.
# last-applied-configuration value
args: ["a", "b"]
# configuration file value
args: ["a", "c"]
# live configuration
args: ["a", "b", "d"]
# result after merge
args: ["a", "c"]
설명: 병합은 새로운 리스트 값으로 구성 파일 값을 사용했다.
복합 구성요소 리스트에 대한 개별 구성요소 병합
리스트를 맵으로 취급하고 각 구성요소의 특정 필드를 키로 취급한다. 개별 구성요소를 추가, 삭제, 또는 업데이트 한다. 이것은 순서를 보존하지 않는다.
이 병합 전략은 각 필드에 patchMergeKey
라 칭하는 특별한 태그를 사용한다.
patchMergeKey
는 쿠버네티스 소스 코드:
types.go
의 각 필드에 대해 정의한다. 맵 리스트를 병합할 때, 주어진 구성요소에 대한 patchMergeKey
로
지정한 필드는 해당 구성요소에 대한 맵키와 같이 사용된다.
예시: kubectl apply
를 사용하여 PodSpec에 대한 containers
필드를 업데이트한다.
이렇게 하면 각 구성요소가
name
별로 키로 되어 있는 맵인 것처럼 리스트를 병합한다.
# last-applied-configuration value
containers:
- name: nginx
image: nginx:1.10
- name: nginx-helper-a # key: nginx-helper-a; will be deleted in result
image: helper:1.3
- name: nginx-helper-b # key: nginx-helper-b; will be retained
image: helper:1.3
# configuration file value
containers:
- name: nginx
image: nginx:1.10
- name: nginx-helper-b
image: helper:1.3
- name: nginx-helper-c # key: nginx-helper-c; will be added in result
image: helper:1.3
# live configuration
containers:
- name: nginx
image: nginx:1.10
- name: nginx-helper-a
image: helper:1.3
- name: nginx-helper-b
image: helper:1.3
args: ["run"] # Field will be retained
- name: nginx-helper-d # key: nginx-helper-d; will be retained
image: helper:1.3
# result after merge
containers:
- name: nginx
image: nginx:1.10
# Element nginx-helper-a was deleted
- name: nginx-helper-b
image: helper:1.3
args: ["run"] # Field was retained
- name: nginx-helper-c # Element was added
image: helper:1.3
- name: nginx-helper-d # Element was ignored
image: helper:1.3
설명:
- 구성 파일에 "nginx-helper-a"라는 이름을 가진 컨테이너가 나타나지 않았기 때문에 "nginx-helper-a"라는 컨테이너는 삭제되었다.
- "nginx-helper-b"라는 컨테이너는 활성 구성에
args
에
대한 변경사항을 유지했다.kubectl apply
는
필드 값이 다름에도 불구하고(구성 파일에args
가 없음) 활성 구성에
"nginx-helper-b"가 구성 파일과 동일한 "nginx-helper-b"임을 식별할 수 있었다. 이것은patchMergeKey
필드 값(이름)이 둘 다 같았기 때문이다.. - "nginx-helper-c"라는 이름의 컨테이너가 활성 구성에 나타나지 않았지만, 구성 파일에 그 이름을 가진 컨테이너가 나타났기 때문에 추가되었다.
- last-applied-configuration에 그 이름을 가진 구성요소가 없었기 때문에 "nginx-helper-d"라는 이름의 컨테이너는 유지되었다.
기초 구성요소 리스트 병합
쿠버네티스 1.5로부터 기초 구성요소 병합하기는 지원되지 않는다.
참고: 주어진 필드에 대해 위 전략 중 어떤 것을 선택할지에 대해서는 types.go의patchStrategy
태그에 의해 제어된다. 타입 필드에 대해patchStrategy
가 지정되지 않으면, 리스트는 대체된다.
기본 필드값
오브젝트가 생성될 때 값이 지정되지 않는 경우, API 서버는 활성 구성 내 특정 필드를 기본값으로 설정한다.
다음은 디플로이먼트에 대한 구성 파일이다. 파일에는 strategy
가 지정되지 않았다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
kubectl apply
를 사용하여 오브젝트를 생성한다.
kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml
kubectl get
을 사용하여 활성 구성을 출력한다.
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
출력은 API 서버가 활성 구성 내 여러 필드를 기본값으로 설정한 것을 보여준다. 이 필드들은 구성 파일에 지정되지 않았다.
apiVersion: apps/v1
kind: Deployment
# ...
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
replicas: 1 # defaulted by apiserver
strategy:
rollingUpdate: # defaulted by apiserver - derived from strategy.type
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate # defaulted by apiserver
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
imagePullPolicy: IfNotPresent # defaulted by apiserver
name: nginx
ports:
- containerPort: 80
protocol: TCP # defaulted by apiserver
resources: {} # defaulted by apiserver
terminationMessagePath: /dev/termination-log # defaulted by apiserver
dnsPolicy: ClusterFirst # defaulted by apiserver
restartPolicy: Always # defaulted by apiserver
securityContext: {} # defaulted by apiserver
terminationGracePeriodSeconds: 30 # defaulted by apiserver
# ...
패치 요청에서, 패치 요청의 부분으로서 명시적으로 지워지지 않은 경우 기본 처리된 필드는 다시 기본으로 설정되지 않는다. 이것은 다른 필드에 대한 값에 따라 기본 처리된 필드에 대해 예상하지 못한 동작을 유발할 수 있다. 다른 필드가 나중에 변경되면, 그로부터 기본 처리된 것이 명시적으로 지워지지 않은 한 업데이트되지 않을 것이다.
이러한 사유로, 의도한 값이 서버의 기본값과 일치하더라도, 서버에 의해 기본 처리된 특정 필드는 구성 파일 내 명시적으로 정의할 것을 권고한다. 이렇게 하면 서버에 의해 다시 기본 처리되지 않게 될 충돌하는 값을 보다 쉽게 인식할 수 있도록 해준다.
Example:
# last-applied-configuration
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
# configuration file
spec:
strategy:
type: Recreate # updated value
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
# live configuration
spec:
strategy:
type: RollingUpdate # defaulted value
rollingUpdate: # defaulted value derived from type
maxSurge : 1
maxUnavailable: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
# result after merge - ERROR!
spec:
strategy:
type: Recreate # updated value: incompatible with rollingUpdate
rollingUpdate: # defaulted value: incompatible with "type: Recreate"
maxSurge : 1
maxUnavailable: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
설명:
- 사용자가
strategy.type
을 정의하지 않고 디플로이먼트를 생성한다. - 서버는
strategy.type
을RollingUpdate
로 기본 설정하고strategy.rollingUpdate
값을 기본 값으로 처리한다. - 사용자가
strategy.type
를Recreate
로 변경한다. 서버에서 해당 값이 삭제될 거라 예상하지만strategy.rollingUpdate
값은 기본값으로 남아 있다.
strategy.rollingUpdate
값이 처음에 구성 파일에서 지정되었다면, 이것을 삭제해야 한다는 것이 더 분명했을 것이다. strategy.rollingUpdate
가 지워지지 않았기 때문에 적용은 실패한다.strategy.rollingupdate
필드는Recreate
의strategy.type
으로 정의될 수 없다.
권고: 이들 필드는 오브젝트 구성 파일 내 명시적으로 정의돼야 한다.
- 디플로이먼트, 스테이트풀셋, 잡, 데몬셋, 레플리카셋 및 레플리케이션컨트롤러와 같은 워크로드에 대한 셀렉터와 파드템플릿 레이블
- 디플로이먼트 롤아웃 전략
서버 기본 필드 또는 다른 작성자에 의해 설정된 필드 지우는 방법
구성 파일 내 나타나지 않는 필드는 그 값을
null
로 설정하고 나서 구성 파일을 적용함으로써 지워질 수 있다.
서버가 기본 값을 할당했던 필드에 대해서, 이는 다시 기본 값을
할당하도록 한다.
구성 파일과 직접 명령형 작성자 간의 필드 소유권을 변경시키는 방법
개별 오브젝트 필드를 변경시키는 데 사용해야 하는 유일한 방법은 다음과 같다.
kubectl apply
를 사용한다.- 구성 파일을 수정하지 않고 활성 구성을 직접 작성한다.
예를 들어,
kubectl scale
을 사용한다.
직접 명령형 작성자에서 구성 파일로 소유자 변경하기
구성 파일에 필드를 추가한다. 해당 필드의 경우
kubectl apply
를 거치지 않는 활성 구성에 대해 직접 업데이트를 적용하지 않는다.
구성 파일에서 직접 명령형 작성자로 소유자 변경하기
쿠버네티스 1.5로부터 구성 파일에서 명령형 작성자로 소유권을 변경하는데 수동 단계 필요하다.
- 구성 파일에서 필드를 제거한다.
- 활성 오브젝트 상의
kubectl.kubernetes.io/last-applied-configuration
어노테이션에서 필드를 제거한다.
관리 방법 변경하기
쿠버네티스 오브젝트는 한 번에 오직 하나의 방법을 사용하여 관리돼야 한다. 하나의 방법에서 다른 방법으로 전환하는 것은 가능하나, 수동 프로세스이다.
참고: 선언형 관리와 함께 명령형 삭제를 사용하는 것은 괜찮다.
명령형 커맨드 관리에서 오브젝트 구성으로 이전하기
명령형 커맨드 관리에서 오브젝트 구성으로 이전하는 것은 여러 수동 단계를 포함한다.
-
활성 오브젝트를 로컬 구성 파일로 내보낸다.
kubectl get <종류>/<이름> -o yaml > <종류>_<이름>.yaml
-
구성 파일에서 수동으로
status
필드를 제거한다.참고:kubectl apply
구성 파일에 존재한다고 하더라도 상태 필드가 업데이트되지 않기 때문에, 이 단계는 선택적이다. -
오브젝트의
kubectl.kubernetes.io/last-applied-configuration
어노테이션을 설정한다.kubectl replace --save-config -f <종류>_<이름>.yaml
-
오직 오브젝트를 관리하기 위해
kubectl apply
를 사용하도록 프로세스를 변경한다.
명령형 오브젝트 구성에서 선언형 오브젝트 구성으로 이전하기
-
오브젝트의
kubectl.kubernetes.io/last-applied-configuration
어노테이션을 설정한다.kubectl replace --save-config -f <종류>_<이름>.yaml
-
오직 오브젝트를 관리하기 위해
kubectl apply
를 사용하도록 프로세스를 변경한다.
컨트롤러 셀렉터와 파드템플릿 레이블 정의하기
경고: 컨트롤러에서 셀렉터를 업데이트하는 것은 추천되지 않는다.
권고되는 접근 방법은 다른 의미론적 의미를 가지지 않고 컨트롤러에 의해서만 사용되는 단일, 불변의 파드템플릿 레이블을 정의하는 것이다.
예시:
selector:
matchLabels:
controller-selector: "apps/v1/deployment/nginx"
template:
metadata:
labels:
controller-selector: "apps/v1/deployment/nginx"
다음 내용
2 - Kustomize를 이용한 쿠버네티스 오브젝트의 선언형 관리
Kustomize는 kustomization 파일을 통해 쿠버네티스 오브젝트를 사용자가 원하는 대로 변경하는(customize) 독립형 도구이다.
1.14 이후로, kubectl도 kustomization 파일을 사용한 쿠버네티스 오브젝트의 관리를 지원한다. kustomization 파일을 포함하는 디렉터리 내의 리소스를 보려면 다음 명령어를 실행한다.
kubectl kustomize <kustomization_directory>
이 리소스를 적용하려면 kubectl apply
를 --kustomize
또는 -k
플래그와 함께 실행한다.
kubectl apply -k <kustomization_directory>
시작하기 전에
kubectl
을 설치한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.
Kustomize 개요
Kustomize는 쿠버네티스 구성을 사용자 정의화하는 도구이다. 이는 애플리케이션 구성 파일을 관리하기 위해 다음 기능들을 가진다.
- 다른 소스에서 리소스 생성
- 리소스에 대한 교차 편집 필드 설정
- 리소스 집합을 구성하고 사용자 정의
리소스 생성
컨피그맵과 시크릿은 파드와 같은 다른 쿠버네티스 오브젝트에서 사용되는 설정이나 민감한 데이터를 가지고 있다. 컨피그맵이나 시크릿의 실질적인 소스는 일반적으로 .properties
파일이나 ssh key 파일과 같은 것들은 클러스터 외부에 있다.
Kustomize는 시크릿과 컨피그맵을 파일이나 문자열에서 생성하는 secretGenerator
와 configMapGenerator
를 가지고 있다.
configMapGenerator
파일에서 컨피그맵을 생성하려면 configMapGenerator
내의 files
리스트에 항목을 추가한다. 다음은 하나의 .properties
파일에서 데이터 항목으로 컨피그맵을 생성하는 예제이다.
# application.properties 파일을 생성
cat <<EOF >application.properties
FOO=Bar
EOF
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-1
files:
- application.properties
EOF
생성된 컨피그맵은 다음 명령어로 검사할 수 있다.
kubectl kustomize ./
생성된 컨피그맵은 다음과 같다.
apiVersion: v1
data:
application.properties: |
FOO=Bar
kind: ConfigMap
metadata:
name: example-configmap-1-8mbdf7882g
env 파일에서 컨피그맵을 생성하려면, configMapGenerator
의 envs
리스트에 항목을 추가한다. 다음은 .env
파일의 데이터 항목으로 컨피그맵을 생성하는 예시를 보여준다.
# .env 파일 생성
cat <<EOF >.env
FOO=Bar
EOF
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-1
envs:
- .env
EOF
생성된 컨피그맵은 다음 명령어로 검사할 수 있다.
kubectl kustomize ./
생성된 컨피그맵은 다음과 같다.
apiVersion: v1
data:
FOO=Bar
kind: ConfigMap
metadata:
name: example-configmap-1-8mbdf7882g
참고:.env
파일의 각 변수는 생성한 컨피그맵에서 분리된 키가 된다..properties
라는 이름의 파일을 내장하는 이전 예시(그리고 모든 항목들)는 단일 키를 위한 값이므로 이 예시와는 다르다.
컨피그맵은 문자로된 키-값 쌍들로도 생성할 수 있다. 문자로된 키-값 쌍에서 컨피그맵을 생성하려면, configMapGenerator 내의 literals
리스트에 항목을 추가한다. 다음은 키-값 쌍을 데이터 항목으로 받는 컨피그맵을 생성하는 예제이다.
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-2
literals:
- FOO=Bar
EOF
생성된 컨피그맵은 다음 명령어로 확인할 수 있다.
kubectl kustomize ./
생성된 컨피그맵은 다음과 같다.
apiVersion: v1
data:
FOO: Bar
kind: ConfigMap
metadata:
name: example-configmap-2-g2hdhfc6tk
디플로이먼트에서 생성된 컨피그맵을 사용하기 위해서는, configMapGenerator의 이름을 참조한다. Kustomize는 자동으로 해당 이름을 생성된 이름으로 교체할 것이다.
다음은 생성된 컨피그맵을 사용하는 디플로이먼트의 예시다.
# application.properties 파일을 생성한다.
cat <<EOF >application.properties
FOO=Bar
EOF
cat <<EOF >deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app
volumeMounts:
- name: config
mountPath: /config
volumes:
- name: config
configMap:
name: example-configmap-1
EOF
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
configMapGenerator:
- name: example-configmap-1
files:
- application.properties
EOF
컨피그맵과 디플로이먼트를 생성한다.
kubectl kustomize ./
생성된 디플로이먼트는 이름을 통해서 생성된 컨피그맵을 참조한다.
apiVersion: v1
data:
application.properties: |
FOO=Bar
kind: ConfigMap
metadata:
name: example-configmap-1-g4hk9g2ff8
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-app
name: my-app
spec:
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- image: my-app
name: app
volumeMounts:
- mountPath: /config
name: config
volumes:
- configMap:
name: example-configmap-1-g4hk9g2ff8
name: config
secretGenerator
파일 또는 문자로된 키-값 쌍들로 시크릿을 생성할 수 있다. 파일에서 시크릿을 생성하려면 secretGenerator
내의 files
리스트에 항목을 추가한다. 다음은 파일을 데이터 항목으로 받는 시크릿을 생성하는 예제이다.
# password.txt 파일을 생성
cat <<EOF >./password.txt
username=admin
password=secret
EOF
cat <<EOF >./kustomization.yaml
secretGenerator:
- name: example-secret-1
files:
- password.txt
EOF
생성된 시크릿은 다음과 같다.
apiVersion: v1
data:
password.txt: dXNlcm5hbWU9YWRtaW4KcGFzc3dvcmQ9c2VjcmV0Cg==
kind: Secret
metadata:
name: example-secret-1-t2kt65hgtb
type: Opaque
문자로된 키-값 쌍으로 시크릿을 생성하려면, secretGenerator
내의 literals
리스트에 항목을 추가한다. 다음은 키-값 쌍을 데이터 항목으로 받는 시크릿을 생성하는 예제이다.
cat <<EOF >./kustomization.yaml
secretGenerator:
- name: example-secret-2
literals:
- username=admin
- password=secret
EOF
생성된 시크릿은 다음과 같다.
apiVersion: v1
data:
password: c2VjcmV0
username: YWRtaW4=
kind: Secret
metadata:
name: example-secret-2-t52t6g96d8
type: Opaque
컨피그맵과 유사하게, 생성된 시크릿도 secretGenerator의 이름을 참조함으로써 디플로이먼트에서 사용될 수 있다.
# password.txt 파일을 생성한다.
cat <<EOF >./password.txt
username=admin
password=secret
EOF
cat <<EOF >deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app
volumeMounts:
- name: password
mountPath: /secrets
volumes:
- name: password
secret:
secretName: example-secret-1
EOF
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
secretGenerator:
- name: example-secret-1
files:
- password.txt
EOF
generatorOptions
생성된 컨피그맵과 시크릿은 콘텐츠 해시 접미사가 추가된다. 이는 콘텐츠가 변경될 때 새로운 컨피그맵 이나 시크릿이 생성되는 것을 보장한다. 접미사를 추가하는 동작을 비활성화하는 방법으로 generatorOptions
를 사용할 수 있다. 그밖에, 생성된 컨피그맵과 시크릿에 교차 편집 옵션들을 지정해주는 것도 가능하다.
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-3
literals:
- FOO=Bar
generatorOptions:
disableNameSuffixHash: true
labels:
type: generated
annotations:
note: generated
EOF
생성된 컨피그맵을 보려면 kubectl kustomize ./
를 실행한다.
apiVersion: v1
data:
FOO: Bar
kind: ConfigMap
metadata:
annotations:
note: generated
labels:
type: generated
name: example-configmap-3
교차 편집 필드 설정
프로젝트 내 모든 쿠버네티스 리소스에 교차 편집 필드를 설정하는 것은 꽤나 일반적이다. 교차 편집 필드를 설정하는 몇 가지 사용 사례는 다음과 같다.
- 모든 리소스에 동일한 네임스페이스를 설정
- 동일한 네임 접두사 또는 접미사를 추가
- 동일한 레이블들을 추가
- 동일한 어노테이션들을 추가
다음은 예제이다.
# deployment.yaml을 생성
cat <<EOF >./deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
EOF
cat <<EOF >./kustomization.yaml
namespace: my-namespace
namePrefix: dev-
nameSuffix: "-001"
commonLabels:
app: bingo
commonAnnotations:
oncallPager: 800-555-1212
resources:
- deployment.yaml
EOF
이 필드들이 디플로이먼트 리소스에 모두 설정되었는지 보려면 kubectl kustomize ./
를 실행한다.
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
oncallPager: 800-555-1212
labels:
app: bingo
name: dev-nginx-deployment-001
namespace: my-namespace
spec:
selector:
matchLabels:
app: bingo
template:
metadata:
annotations:
oncallPager: 800-555-1212
labels:
app: bingo
spec:
containers:
- image: nginx
name: nginx
리소스 구성과 사용자 정의
프로젝트 내 리소스의 집합을 구성하여 이들을 동일한 파일이나 디렉터리 내에서 관리하는 것은 일반적이다. Kustomize는 서로 다른 파일들로 리소스를 구성하고 패치나 다른 사용자 정의를 이들에 적용하는 것을 제공한다.
구성
Kustomize는 서로 다른 리소스들의 구성을 지원한다. kustomization.yaml
파일 내 resources
필드는 구성 내에 포함하려는 리소스들의 리스트를 정의한다. resources
리스트 내에 리소스의 구성 파일의 경로를 설정한다.
다음 예제는 디플로이먼트와 서비스로 구성된 NGINX 애플리케이션이다.
# deployment.yaml 파일 생성
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
# service.yaml 파일 생성
cat <<EOF > service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
EOF
# 이들을 구성하는 kustomization.yaml 생성
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
- service.yaml
EOF
kubectl kustomize ./
의 리소스에는 디플로이먼트와 서비스 오브젝트가 모두 포함되어 있다.
사용자 정의
패치는 리소스에 다른 사용자 정의를 적용하는 데 사용할 수 있다. Kustomize는
patchesStrategicMerge
와 patchesJson6902
를 통해 서로 다른 패치 메커니즘을 지원한다. patchesStrategicMerge
는 파일 경로들의 리스트이다. 각각의 파일은 전략적 병합 패치로 분석될 수 있어야 한다. 패치 내부의 네임은 반드시 이미 읽혀진 리소스 네임과 일치해야 한다. 한 가지 일을 하는 작은 패치가 권장된다. 예를 들기 위해 디플로이먼트 레플리카 숫자를 증가시키는 하나의 패치와 메모리 상한을 설정하는 다른 패치를 생성한다.
# deployment.yaml 파일 생성
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
# increase_replicas.yaml 패치 생성
cat <<EOF > increase_replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 3
EOF
# 다른 패치로 set_memory.yaml 생성
cat <<EOF > set_memory.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
template:
spec:
containers:
- name: my-nginx
resources:
limits:
memory: 512Mi
EOF
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
patchesStrategicMerge:
- increase_replicas.yaml
- set_memory.yaml
EOF
디플로이먼트를 보려면 kubectl kustomize ./
를 실행한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 3
selector:
matchLabels:
run: my-nginx
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- image: nginx
name: my-nginx
ports:
- containerPort: 80
resources:
limits:
memory: 512Mi
모든 리소스 또는 필드가 전략적 병합 패치를 지원하는 것은 아니다. 임의의 리소스 내 임의의 필드의 수정을 지원하기 위해,
Kustomize는 patchesJson6902
를 통한 JSON 패치 적용을 제공한다.
Json 패치의 정확한 리소스를 찾기 위해, 해당 리소스의 group, version, kind, name이
kustomization.yaml
내에 명시될 필요가 있다. 예를 들면, patchesJson6902
를 통해
디플로이먼트 오브젝트의 레플리카 개수를 증가시킬 수 있다.
# deployment.yaml 파일 생성
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
# json 패치 생성
cat <<EOF > patch.yaml
- op: replace
path: /spec/replicas
value: 3
EOF
# kustomization.yaml 생성
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: my-nginx
path: patch.yaml
EOF
kubectl kustomize ./
를 실행하여 replicas
필드가 갱신되었는지 확인한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 3
selector:
matchLabels:
run: my-nginx
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- image: nginx
name: my-nginx
ports:
- containerPort: 80
패치 기능에 추가로 Kustomize는 패치를 생성하지 않고 컨테이너 이미지를 사용자 정의하거나 다른 오브젝트의 필드 값을 컨테이너에 주입하는
기능도 제공한다. 예를 들어 kustomization.yaml
의 images
필드에 신규 이미지를 지정하여 컨테이너에서 사용되는 이미지를 변경할 수 있다.
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
images:
- name: nginx
newName: my.image.registry/nginx
newTag: 1.4.0
EOF
사용된 이미지가 갱신되었는지 확인하려면 kubectl kustomize ./
를 실행한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 2
selector:
matchLabels:
run: my-nginx
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- image: my.image.registry/nginx:1.4.0
name: my-nginx
ports:
- containerPort: 80
가끔, 파드 내에서 실행되는 애플리케이션이 다른 오브젝트의 설정 값을 사용해야 할 수도 있다. 예를 들어,
디플로이먼트 오브젝트의 파드는 Env 또는 커맨드 인수로 해당 서비스 네임을 읽어야 한다고 하자.
kustomization.yaml
파일에 namePrefix
또는 nameSuffix
가 추가되면 서비스 네임이 변경될 수 있다.
커맨드 인수 내에 서비스 네임을 하드 코딩하는 것을 권장하지 않는다. 이 용도에서 Kustomize는 vars
를 통해 containers에 서비스 네임을 삽입할 수 있다.
# deployment.yaml 파일 생성
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
command: ["start", "--host", "$(MY_SERVICE_NAME)"]
EOF
# service.yaml 파일 생성
cat <<EOF > service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
EOF
cat <<EOF >./kustomization.yaml
namePrefix: dev-
nameSuffix: "-001"
resources:
- deployment.yaml
- service.yaml
vars:
- name: MY_SERVICE_NAME
objref:
kind: Service
name: my-nginx
apiVersion: v1
EOF
kubectl kustomize ./
를 실행하면 dev-my-nginx-001
로 컨테이너에 삽입된 서비스 네임을 볼 수 있다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: dev-my-nginx-001
spec:
replicas: 2
selector:
matchLabels:
run: my-nginx
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- command:
- start
- --host
- dev-my-nginx-001
image: nginx
name: my-nginx
Base와 Overlay
Kustomize는 base 와 overlay 의 개념을 가지고 있다. base 는 kustomization.yaml
과 함께 사용되는 디렉터리다. 이는
사용자 정의와 관련된 리소스들의 집합을 포함한다. kustomization.yaml
의 내부에 표시되는 base는 로컬 디렉터리이거나 원격 리포지터리의 디렉터리가
될 수 있다. overlay 는 kustomization.yaml
이 있는 디렉터리로
다른 kustomization 디렉터리들을 bases
로 참조한다. base 는 overlay에 대해서 알지 못하며 여러 overlay들에서 사용될 수 있다.
한 overlay는 다수의 base들을 가질 수 있고, base들에서 모든 리소스를 구성할 수 있으며,
이들의 위에 사용자 정의도 가질 수 있다.
다음은 base에 대한 예이다.
# base를 가지는 디렉터리 생성
mkdir base
# base/deployment.yaml 생성
cat <<EOF > base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
EOF
# base/service.yaml 파일 생성
cat <<EOF > base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
EOF
# base/kustomization.yaml 생성
cat <<EOF > base/kustomization.yaml
resources:
- deployment.yaml
- service.yaml
EOF
이 base는 다수의 overlay에서 사용될 수 있다. 다른 namePrefix
또는 다른 교차 편집 필드들을
서로 다른 overlay에 추가할 수 있다. 다음 예제는 동일한 base를 사용하는 두 overlay들이다.
mkdir dev
cat <<EOF > dev/kustomization.yaml
bases:
- ../base
namePrefix: dev-
EOF
mkdir prod
cat <<EOF > prod/kustomization.yaml
bases:
- ../base
namePrefix: prod-
EOF
Kustomize를 이용하여 오브젝트를 적용/확인/삭제하는 방법
kustomization.yaml
에서 관리되는 리소스를 인식하려면 kubectl
명령어에 --kustomize
나 -k
를 사용한다.
-k
는 다음과 같이 kustomization 디렉터리를 가리키고 있어야 한다는 것을 주의한다.
kubectl apply -k <kustomization directory>/
다음 kustomization.yaml
이 주어지고,
# deployment.yaml 파일 생성
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
# kustomization.yaml 생성
cat <<EOF >./kustomization.yaml
namePrefix: dev-
commonLabels:
app: my-nginx
resources:
- deployment.yaml
EOF
디플로이먼트 오브젝트 dev-my-nginx
를 적용하려면 다음 명령어를 실행한다.
> kubectl apply -k ./
deployment.apps/dev-my-nginx created
디플로이먼트 오브젝트 dev-my-nginx
를 보려면 다음 명령어들 중에 하나를 실행한다.
kubectl get -k ./
kubectl describe -k ./
다음 명령을 실행해서 디플로이먼트 오브젝트 dev-my-nginx
를 매니페스트가 적용된 경우의 클러스터 상태와 비교한다.
kubectl diff -k ./
디플로이먼트 오브젝트 dev-my-nginx
를 삭제하려면 다음 명령어를 실행한다.
> kubectl delete -k ./
deployment.apps "dev-my-nginx" deleted
Kustomize 기능 리스트
필드 | 유형 | 설명 |
---|---|---|
namespace | string | 모든 리소스에 네임스페이스 추가 |
namePrefix | string | 모든 리소스 네임에 이 필드의 값이 접두사로 추가된다 |
nameSuffix | string | 모든 리소스 네임에 이 필드의 값이 접미사로 추가된다 |
commonLabels | map[string]string | 모든 리소스와 셀렉터에 추가될 레이블 |
commonAnnotations | map[string]string | 모든 리소스에 추가될 어노테이션 |
resources | []string | 이 리스트 내 각각의 항목은 반드시 존재하는 리소스 구성 파일로 해석되어야 한다. |
configMapGenerator | []ConfigMapArgs | 이 리스트의 각 항목은 컨피그맵을 생성한다. |
secretGenerator | []SecretArgs | 이 리스트의 각 항목은 시크릿을 생성한다. |
generatorOptions | GeneratorOptions | 모든 컨피그맵 및 시크릿 생성자(generator)의 동작을 수정한다. |
bases | []string | 이 리스트 내 각각의 항목은 kustomization.yaml 파일을 가지는 디렉터리로 해석되어야 한다. |
patchesStrategicMerge | []string | 이 리스트 내 각각의 항목은 쿠버네티스 오브젝트의 전략적 병합 패치로 해석되어야 한다. |
patchesJson6902 | []Patch | 이 리스트 내 각각의 항목은 쿠버네티스 오브젝트와 Json 패치로 해석되어야 한다. |
vars | []Var | 각각의 항목은 한 리소스의 필드에서 텍스트를 캡쳐한다. |
images | []Image | 각각의 항목은 패치를 생성하지 않고 하나의 이미지에 대한 name, tags 그리고/또는 digest를 수정한다. |
configurations | []string | 이 리스트 내 각각의 항목은 Kustomize 변환 설정을 포함하는 파일로 해석되어야 한다. |
crds | []string | 이 리스트 내 각각의 항목은 쿠버네티스 타입에 대한 OpenAPI 정의 파일로 해석되어야 한다. |
다음 내용
3 - 명령형 커맨드를 이용한 쿠버네티스 오브젝트 관리하기
쿠버네티스 오브젝트는 kubectl
커맨드 라인 툴 속에 내장된 명령형 커맨드를 이용함으로써
바로 신속하게 생성, 업데이트 및 삭제할 수 있다. 이 문서는 어떻게 커맨드가 구성되어 있으며,
이를 사용하여 활성 오브젝트를 어떻게 관리하는 지에 대해 설명한다.
시작하기 전에
kubectl
을 설치한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.
트레이드 오프
kubectl
툴은 3가지 종류의 오브젝트 관리를 지원한다.
- 명령형 커맨드
- 명령형 오브젝트 구성
- 선언형 오브젝트 구성
각 종류별 오브젝트 관리의 장점과 단점에 대한 논의는 쿠버네티스 오브젝트 관리 를 참고한다.
오브젝트 생성 방법
kubectl
툴은 가장 일반적인 오브젝트 타입을 생성하는데 동사 형태 기반의 커맨드를
지원한다. 쿠버네티스 오브젝트 타입에 익숙하지 않은 사용자가 인지할 수 있도록 커맨드
이름이 지어졌다.
run
: 컨테이너를 실행할 새로운 파드를 생성한다.expose
: 파드에 걸쳐 트래픽을 로드 밸런스하도록 새로운 서비스 오브젝트를 생성한다.autoscale
: 디플로이먼트와 같이, 하나의 컨트롤러에 대해 자동으로 수평적 스케일이 이루어 지도록 새로운 Autoscaler 오브젝트를 생성한다.
또한 kubectl
툴은 오브젝트 타입에 의해 구동되는 생성 커맨드를 지원한다.
이러한 커맨드는 더 많은 오브젝트 타입을 지원해주며 그 의도하는 바에 대해
보다 명확하게 해주지만, 사용자가 생성하고자 하는 오브젝트 타입에 대해
알 수 있도록 해야 한다.
create <오브젝트 타입> [<서브 타입>] <인스턴스명>
일부 오브젝트 타입은 create
커맨드 내 정의할 수 있는 서브 타입을 가진다.
예를 들어, 서비스 오브젝트는 ClusterIP, LoadBalancer 및 NodePort 등을
포함하는 여러 서브 타입을 가진다, 다음은 NodePort 서브 타입을 통해 서비스를
생성하는 예제이다.
kubectl create service nodeport <사용자 서비스 명칭>
이전 예제에서, create service nodeport
커맨드는
create service
커맨드의 서브 커맨드라고 칭한다.
-h
플래그를 사용하여 서브 커맨드에 의해 지원되는 인수 및 플래그를
찾아 볼 수 있다.
kubectl create service nodeport -h
오브젝트 업데이트 방법
kubectl
커맨드는 일반적인 몇몇의 업데이트 작업을 위해 동사 형태 기반의 커맨드를 지원한다.
이 커맨드는 쿠버네티스 오브젝트에 익숙하지 않은 사용자가 설정되어야
하는 특정 필드를 모르는 상태에서도 업데이트를 수행할 수 있도록
이름 지어졌다.
scale
: 컨트롤러의 레플리카 수를 업데이트 함으로써 파드를 추가 또는 제거하는 컨트롤러를 수평적으로 스케일한다.annotate
: 오브젝트로부터 어노테이션을 추가 또는 제거한다.label
: 오브젝트에서 레이블을 추가 또는 제거한다.
kubectl
커맨드는 또한 오브젝트 측면에서 구동되는 업데이트 커맨드를 지원한다.
이 측면의 설정은 다른 오브젝트 타입에 대한 다른 필드를 설정 할 수도 있다.
set
<field>
: 오브젝트의 측면을 설정한다.
참고: 쿠버네티스 1.5 버전에서는 모든 동사 형태 기반의 커맨드가 관련된 측면 중심의 커맨드를 가지는 것은 아니다.
kubectl
툴은 활성 오브젝트를 직접 업데이트하기 위해 추가적인 방법을 지원하지만,
쿠버네티스 오브젝트 스키마에 대한 추가적인 이해를 요구한다.
edit
: 편집기에서 구성을 열어 활성 오브젝트에 대한 원래 그대로의 구성을 바로 편집한다.patch
: 패치 문자열를 사용하여 활성 오브젝트를 바로 편집한다. 패치 문자열에 대한 보다 자세한 정보를 보려면 API 규정에서 패치 섹션을 참고한다.
오브젝트 삭제 방법
클러스터에서 오브젝트를 삭제하기 위해 delete
커맨드을 사용할 수 있다.
delete <타입>/<이름>
참고: 명령형 커맨드와 명령형 오브젝트 구성 모두kubectl delete
를 사용할 수 있다. 차이점은 커맨드에 전해지는 인수에 있다. 명령형 커맨드로kubectl delete
을 사용하기 위해, 삭제할 오브젝트를 인수로 전한다. 다음은 nginx라는 디플로이먼트 오브젝트를 전하는 예제이다.
kubectl delete deployment/nginx
오브젝트 확인 방법
오브젝트에 대한 정보를 출력하는 몇 가지 커맨드가 있다.
get
: 일치하는 오브젝트에 대한 기본 정보를 출력한다. 옵션 리스트를 확인하기 위해get -h
를 사용한다.describe
: 일치하는 오브젝트에 대해 수집한 상세한 정보를 출력한다.logs
: 파드에서 실행 중인 컨테이너에 대한 stdout과 stderr를 출력한다.
생성 전 오브젝트 수정을 위해 set
커맨드 사용하기
create
커맨드에 사용할 수 있는 플래그가 없는 몇 가지 오브젝트
필드가 있다. 이러한 경우, 오브젝트 생성 전에 필드에 대한 값을
정의하기 위해 set
과 create
을 조합해서 사용할 수 있다.
이는 set
커맨드에 create
커맨드의 출력을 파이프 함으로써 수행할 수 있다.
다음은 관련 예제이다.
kubectl create service clusterip my-svc --clusterip="None" -o yaml --dry-run=client | kubectl set selector --local -f - 'environment=qa' -o yaml | kubectl create -f -
kubectl create service -o yaml --dry-run=client
커맨드는 서비스에 대한 구성을 생성하지만, 이를 쿠버네티스 API 서버에 전송하는 대신 YAML 형식으로 stdout에 출력한다.kubectl set selector --local -f - -o yaml
커맨드는 stdin으로부터 구성을 읽어, YAML 형식으로 stdout에 업데이트된 구성을 기록한다.kubectl create -f -
커맨드는 stdin을 통해 제공된 구성을 사용하여 오브젝트를 생성한다.
생성 전 오브젝트 수정을 위해 --edit
사용하기
생성 전에 오브젝트에 임의의 변경을 가하기 위해 kubectl create --edit
을 사용할 수 있다.
다음은 관련 예제이다.
kubectl create service clusterip my-svc --clusterip="None" -o yaml --dry-run=client > /tmp/srv.yaml
kubectl create --edit -f /tmp/srv.yaml
kubectl create service
커맨드는 서비스에 대한 구성을 생성하고 이를/tmp/srv.yaml
에 저장한다.kubectl create --edit
커맨드는 오브젝트를 생성하기 전에 편집을 위해 구성파일을 열어준다.
다음 내용
4 - 구성파일을 이용한 명령형 쿠버네티스 오브젝트 관리
쿠버네티스 오브젝트는 YAML 또는 JSON으로 작성된 오프젝트 구성파일과 함께 kubectl
커맨드 라인 툴을 이용하여 생성, 업데이트 및 삭제할 수 있다.
이 문서는 구성파일을 이용하여 어떻게 오브젝트를 정의하고 관리할 수 있는지에 대해 설명한다.
시작하기 전에
kubectl
을 설치한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.
트레이드 오프
kubectl
툴은 3가지 종류의 오브젝트 관리를 지원한다.
- 명령형 커맨드
- 명령형 오브젝트 구성
- 선언형 오브젝트 구성
각 종류별 오브젝트 관리의 장점과 단점에 대한 논의는 쿠버네티스 오브젝트 관리를 참고한다.
오브젝트 생성 방법
구성파일로부터 오브젝트를 생성하기 위해 kubectl create -f
를 사용할 수 있다.
보다 상세한 정보는 쿠버네티스 API 참조를
참조한다.
kubectl create -f <파일명|url>
오브젝트 업데이트 방법
경고:replace
커맨드로 오브젝트를 업데이트 하게되면, 구성파일에 정의되지 않은 스펙의 모든 부분이 삭제된다. 이는externalIPs
필드가 구성파일로부터 독립적으로 관리되는LoadBalancer
타입의 서비스와 같이, 클러스터 의해 부분적으로 관리되는 스펙의 오브젝트와 함께 사용되어서는 안된다. 독립적으로 관리되는 필드는replace
로 삭제되는 것을 방지하기 위해 구성파일에 복사되어져야만 한다.
구성파일에 따라 활성 오브젝트를 업데이트하기 위해 kubectl replace -f
를 사용할 수 있다.
kubectl replace -f <파일명|url>
오브젝트 삭제 방법
구성파일에 정의한 오브젝트를 삭제하기 위해 kubectl delete -f
를
사용할 수 있다.
kubectl delete -f <파일명|url>
참고:구성 파일이
metadata
섹션에서name
필드 대신generateName
필드를 지정한 경우,kubectl delete -f <filename|url>
을 사용하여 오브젝트를 삭제할 수 없다. 오브젝트를 삭제하려면 다른 플래그를 사용해야 한다. 예를 들면, 다음과 같다.kubectl delete <type> <name> kubectl delete <type> -l <label>
오브젝트 확인 방법
구성파일에 정의한 오브젝트에 관한 정보 확인을 위해 kubectl get -f
명령을 사용할 수 있다.
kubectl get -f <파일명|url> -o yaml
-o yaml
플래그는 전체 오브젝트 구성이 출력되도록 정의한다. 옵션의 리스트를 확인하기
위해서는 kubectl get -h
를 사용한다.
제약사항
create
, replace
, 그리고 delete
명령은 각 오브젝트의 구성이
그 구성파일 내에 완전하게 정의되고 기록되어질 경우 잘 동작한다.
그러나 활성 오브젝트가 업데이트 되고, 구성파일 안에 병합되지 않으면,
업데이트 내용은 다음번 replace
가 실행될 때 삭제될 것이다.
이는 HorizontalPodAutoscaler와 같은 컨트롤러가
활성 오브젝트를 직접적으로 업데이트하도록 할 경우 발생한다.
여기 예시가 있다.
- 구성파일로부터 오브젝트를 생성할 경우
- 또 다른 소스가 일부 필드를 변경함으로써 오브젝트가 업데이트 되는 경우
- 구성파일로부터 오브젝트를 대체할 경우. 스텝 2에서의 다른 소스에 의해 이루어진 변경은 유실된다.
동일 오브젝트에 대해 여러 명의 작성자들로부터의 지원이 필요한 경우, 오브젝트를 관리하기 위해
kubectl apply
를 사용할 수 있다.
구성 저장 없이 URL로부터 오브젝트 생성과 편집하기
구성파일에 대한 URL을 가진다고 가정해보자.
kubectl create --edit
을 사용하여 오브젝트가 생성되기 전에
구성을 변경할 수 있다. 이는 독자가 수정할 수 있는 구성파일을
가르키는 튜토리얼과 작업에 특히 유용하다.
kubectl create -f <url> --edit
명령형 커맨드에서 명령형 오브젝트 구성으로 전환하기
령형 커맨드에서 명령형 오브젝트 구성으로 전환하기 위해 몇 가지 수동 단계를 포함한다.
-
다음과 같이 활성 오브젝트를 로컬 오브젝트 구성파일로 내보낸다.
kubectl get <종류>/<이름> -o yaml > <종류>_<이름>.yaml
-
수동으로 오브젝트 구성파일에서 상태 필드를 제거한다.
-
이후 오브젝트 관리를 위해,
replace
만 사용한다.kubectl replace -f <종류>_<이름>.yaml
컨트롤러 셀렉터와 PodTemplate 레이블 삭제하기
경고: 컨트롤러에서 셀렉터를 업데이트하지 않도록 강력하게 권고한다.
권고되는 접근방법은 다른 의미론적 의미가 없는 컨트롤러 셀렉터의 의해서만 사용되는 단일, 불변의 PodTemplate 레이블로 정의하는 것이다.
레이블 예시:
selector:
matchLabels:
controller-selector: "apps/v1/deployment/nginx"
template:
metadata:
labels:
controller-selector: "apps/v1/deployment/nginx"