서론
쿠버네티스의 컴포넌트의 설정을 도와주는 yaml 파일에 대해서 알아보자.
yaml 파일이 보기에 엄청 길고 복잡해 보여도, 실상은 간단하고 논리적인 구조로 되어있기 때문에 겁먹을 필요 없다.
설정 파일의 세 부분
모든 쿠버네티스 설정파일은 3개의 부분으로 나눌 수 있다.
# nginx-deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
spec:
replicas: 2
selector:
ports:
templates:
1. metadata
컴포넌트를 서로 구분 지어줄 수 있는 이름과 설명을 입력할 수 있다.
2. specification
kind에 적힌 컴포넌트에 대한 구체적인 내용을 정의하는 spec 부분이다.
spec에 대한 포맷은 쿠버네티스 컴포넌트 종류마다 다르다.
3. status
status는 자동적으로 생성되고, 쿠버네티스에 자동 등록된다.
desired state(목표 상태)와 actual state(실제 상태)로 구분될 수 있다.
Desired?
컴포넌트에 대해 어떤 상태를
쿠버네티스 클러스터는 각 컴포넌트가 목표로 하는 상태를 인지하고 그 상태를 유지하려고 노력한다.
컴포넌트 self-healing의 기본 개념이 된다.
예를 들어 위 yaml 파일로 deployment를 apply 명령어를 사용해서 생성했다고 가정하자.
쿠버네티스는 deployment에 대한 status를 자동으로 추가해서 지속적으로 업데이트 할 것이다.
만약 status의 replica가 1이라면, yaml파일의 spec부분의 replicas와 비교한 후 문제가 있다고 판단하고 새로운 replica를 생성한다.
그렇다면 쿠버네티스는 컴포넌트의 status data를 어디서 얻어서 업데이트를 할까?
바로 마스터 노드에 존재하고 클러스터의 두뇌라고 할 수 있는 etcd에서 가져온다.
etcd는 언제나 모든 쿠버네티스 컴포넌트의 실시간 정보를 유지하고 있기 때문이다.
공식 홈페이지에서 가져온 추가 설명(https://kubernetes.io/ko/docs/concepts/overview/working-with-objects/kubernetes-objects/)
거의 모든 쿠버네티스 오브젝트는 오브젝트의 구성을 결정해주는 두 개의 중첩된 오브젝트 필드를 포함하는데 오브젝트 spec 과 오브젝트 status 이다. spec을 가진 오브젝트는 오브젝트를 생성할 때 리소스에 원하는 특징(의도한 상태)에 대한 설명을 제공해서 설정한다.
status 는 쿠버네티스 시스템과 컴포넌트에 의해 제공되고 업데이트된 오브젝트의 현재 상태 를 설명한다. 쿠버네티스 컨트롤 플레인은 모든 오브젝트의 실제 상태를 사용자가 의도한 상태와 일치시키기 위해 끊임없이 그리고 능동적으로 관리한다.
예를 들어, 쿠버네티스 디플로이먼트는 클러스터에서 동작하는 애플리케이션을 표현해줄 수 있는 오브젝트이다. 디플로이먼트를 생성할 때, 디플로이먼트 spec에 3개의 애플리케이션 레플리카가 동작되도록 설정할 수 있다. 쿠버네티스 시스템은 그 디플로이먼트 spec을 읽어 spec에 일치되도록 상태를 업데이트하여 3개의 의도한 애플리케이션 인스턴스를 구동시킨다. 만약, 그 인스턴스들 중 어느 하나가 어떤 문제로 인해 멈춘다면(상태 변화 발생), 쿠버네티스 시스템은 보정(이 경우에는 대체 인스턴스를 시작하여)을 통해 spec과 status간의 차이에 대응한다.
오브젝트 명세, 상태, 그리고 메타데이터에 대한 추가 정보는, Kubernetes API Conventions 를 참조한다.
쿠버네티스 오브젝트 기술하기
쿠버네티스에서 오브젝트를 생성할 때, (이름과 같은)오브젝트에 대한 기본적인 정보와 더불어, 의도한 상태를 기술한 오브젝트 spec을 제시해 줘야만 한다. 오브젝트를 생성하기 위해(직접이든 또는 kubectl을 통해서든) 쿠버네티스 API를 이용할 때, API 요청은 요청 내용 안에 JSON 형식으로 정보를 포함시켜 줘야만 한다. 대부분의 경우 정보를 .yaml 파일로 kubectl에 제공한다. kubectl은 API 요청이 이루어질 때, JSON 형식으로 정보를 변환시켜 준다.
여기 쿠버네티스 디플로이먼트를 위한 필수 필드와 오브젝트 spec을 보여주는 .yaml 파일 예시가 있다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
위 예시와 같이 .yaml 파일을 이용하여 디플로이먼트를 생성하기 위한 하나의 방식으로는 kubectl 커맨드-라인 인터페이스에 인자값으로 .yaml 파일을 건네 kubectl apply 커맨드를 이용하는 것이다. 다음 예시와 같다.
kubectl apply -f https://k8s.io/examples/application/deployment.yaml --record
그 출력 내용은 다음과 유사하다.
deployment.apps/nginx-deployment created
요구되는 필드
생성하고자 하는 쿠버네티스 오브젝트에 대한 .yaml 파일 내, 다음 필드를 위한 값들을 설정해 줘야한다.
- apiVersion - 이 오브젝트를 생성하기 위해 사용하고 있는 쿠버네티스 API 버전이 어떤 것인지
- kind - 어떤 종류의 오브젝트를 생성하고자 하는지
- metadata - 이름 문자열, UID, 그리고 선택적인 네임스페이스를 포함하여 오브젝트를 유일하게 구분지어 줄 데이터
- spec - 오브젝트에 대해 어떤 상태를 의도하는지
오브젝트 spec에 대한 정확한 포맷은 모든 쿠버네티스 오브젝트마다 다르고, 그 오브젝트 특유의 중첩된 필드를 포함한다. 쿠버네티스 API 레퍼런스 는 쿠버네티스를 이용하여 생성할 수 있는 오브젝트에 대한 모든 spec 포맷을 살펴볼 수 있도록 해준다.
예를 들어, API 내 파드에 대한 상세 정보는 spec 필드에 대한 레퍼런스에서, 디플로이먼트에 대한 상세 정보는 spec 필드에 대한 레퍼런스에서 확인할 수 있다. 해당 API 레퍼런스 페이지에서 PodSpec과 DeploymentSpec에 대해 언급된 내용을 볼 수 있다.
YAML 파일 포맷
사람이 이해하기 쉬운 직렬화 포맷이다.
들여쓰기를 매우 중요시 하므로 조심해야한다. (strict indentation)
위 사이트는 yaml 파일 작성할 때 사용하면 좋다.
설정파일은 배포가 필요한 애플리케이션 코드와 같은 디렉토리에 저장하자. 이는 코드의 전체 구조를 잘 설명해줄 수 있다.
또는 따로 깃 레포를 만들어서 관리해도 좋다.
파드의 청사진
deployment는 파드를 생성하고 관리한다. 파드를 생성하고 싶다면 deployment를 생성해야 하고, 이를 안정적으로 유지해야 한다.
그렇다면 파드에 관한 부분은 어디서 설정하는 것일까?
sepc: 의 template부분이 파드의 청사진을 관리하는 부분이다.
template는 또한 자신만의 metadata와 spec을 가지고 있다. 그래서 설정파일 내부의 설정파일이라고 할 수 있다.
파드를 생성할 때 어떤 이미지로 생성할 지, 어떤 포트를 오픈할 지를 결정해 준다.
컴포넌트간 연결
Service와 Deployment, Deployment와 Pod의 연결을 구성해 주는 부분은 lables과 selector 이다.
lables은 metadata 파트에 속해있으며 selector는 spec 파트에 속해있다.
Deployment와 파드의 연결
먼저 Deployment 설정파일을 살펴보자. (이 부분은 이해가 가질 않아서 따로 찾아보았다.)
metadata의 labels에 app: nginx라고 적혀있다. 이는 nginx-deployment가 app: nginx 라는 이름의 key-value 쌍으로 관리된다는 것이다. 첫 번째 app: nginx는 Deployment 자신을 나타내는 의미로 사용된다.
spec의 selector 부분을 보자.
matchLabels밑에 app: nginx가 한 번 더 나온다. 분명 위에서 app: nginx라고 설정했는데?
Deployment는 파드를 관리한다. 그래서 파드를 생성할 때 주로 Deloyment를 통해서 생성한다고 했다.
그렇다면 Deployment가 어떤 파드를 생성하고 관리하는지를 명시해 주어야 할 것이다. 이것이 selector가 하는 역할이다. 두 번째 app: nginx는 Deployment가 관리할 파드를 선택하는 의미로 사용된다.
파드의 청사진이 적혀있는 template 부분을 보자.
또다시 metadata의 밑에 labels가 적혀있다. 그리고 똑같이 app: nginx라고 적혀있다. 이번 app: nginx는 파드에 대한 label 이다. 세 번째 app: nginx는 파드를 나타내는 의미로 사용된다.
이제 selector의 matchLabels에 왜 app: nginx로 적어놓았는지 알 수 있을 것이다. Deployment와 파드는 이렇게 연결된다.
Service와 Deployment의 연결
Service에는 matchLabels가 없다. 단지 selector만 있을 뿐이다.
Service의 spec의 selector에 있는 app: nginx는 자신이 관리할 Deployment 또는 파드를 나타내는 의미로 사용된다.
서비스와 파드의 Port
Service의 port 설정
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
# Make the service externally visible via the node
type: NodePort
ports:
# Which port on the node is the service available through?
- nodePort: 31000
# Inside the cluster, what port does the service expose?
- port: 80
# Which port do pods selected by this service expose?
- targetPort: 80
selector:
# ...
nodePort
이는 서비스가 쿠버네티스 클러스터 외부에서 노드의 IP 주소와 이 속성에 정의된 포트로 보일수 있도록 한다.
이 때, 서비스는 type: NodePort로 지정해야 한다 이 필드는 정의되어 있지 않을 경우 쿠버네티스가 자동으로 할당한다.
일반적으로 nodePort를 통해서 애플리케이션을 배포하지 않는다고 한다. 나중에 공부할 Ingress를 통해서 해결할 수 있다.
port
서비스를 클러스터 안에서 지정된 포트를 통해 내부적으로 노출한다.(EXPOSE) 즉, 서비스는 이 포트에 대해서 보일 수 있게 되며 이 포트로 보내진 요청은 서비스에 의해 선택된 파드로 전달된다.
targetPort
이 포트는 파드로 전달되는 요청이 도달하는 포트이다. 서비스가 동작하기 위해서는 어플리케이션이 이 포트에 대해 네트워크 요청을 listening을 하고 있어야 한다.
파드의 port 설정
...
template: # pod의 blueprint
metadata:
labels: # pod의 label
app: nginx
spec: # pod의 스펙을 정의
containers: # 컨테이너 설정
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
containerPort
파드가 요청을 받는 포트를 설정해준다. nginx 파드는 80번 포트를 통해서 요청을 받기 때문에 80을 열어준다.
Service에서 파드로 요청을 전달해 주기 때문에 Service의 targetPort와 파드의 containerPort를 일치시켜 줘야지 통신이 가능하다.
실제로 Service와 Deployment를 생성해서 port의 연결을 알아보자
# nginx-deployment.yaml
apiVersion: apps/v1 # 쿠버네티스 api 버전
kind: Deployment # 생성할 컴포넌트 종류
metadata:
name: nginx-deployment # deployment의 이름
labels:
app: nginx # label 지정
spec: # deployment의 스펙을 정의
replicas: 2 # 2개의 pod 설정
selector: # deployment가 관리할 pod를 찾는 방법을 정의
matchLabels:
app: nginx
template: # pod의 blueprint
metadata:
labels: # pod의 label
app: nginx
spec: # pod의 스펙을 정의
containers: # 컨테이너 설정
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
# nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 8080
실습 환경에 위 2개의 파일을 생성한다.
kubectl apply -f nginx-deployment.yaml
kubectl apply -f nginx-service.yaml
순서대로 실행해서 Deployment와 Service를 생성한다.
생성되었다면 서비스의 정보를 알아보기 위해서 아래 decribe를 실행해보자.
kubectl describe service nginx-service
nginx-service.yaml에서 설정했던 Port와 TargetPort를 확인할 수 있다.
Endpoints는 서비스로 들어온 요청이 전달될 주소가 적혀있다.
Deployment에서 Replica를 2개 만들었기 때문에 2개가 적혀있는 것이다.
kubectl get pod -o wide
kubectl get pod 명령어에 자세한 정보를 출력하기 위해서 -o wide 옵션을 붙였다.
IP 부분을 보면 Endpoint에 적힌 주소와 동일한 IP임을 알 수 있다.
status의 자동생성
kubectl get deployment nginx-deployment -o yaml
위 명령어는 nginx-deployment에 대한 모든 정보를 출력한다. etcd가 가지고 있는 정보를 출력하는 것이다.
...
status:
availableReplicas: 2
conditions:
- lastTransitionTime: "2022-03-01T00:47:42Z"
lastUpdateTime: "2022-03-01T00:47:57Z"
message: ReplicaSet "nginx-deployment-9456bbbf9" has successfully progressed.
reason: NewReplicaSetAvailable
status: "True"
type: Progressing
- lastTransitionTime: "2022-03-02T05:59:59Z"
lastUpdateTime: "2022-03-02T05:59:59Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
observedGeneration: 2
readyReplicas: 2
replicas: 2
updatedReplicas: 2
실제로 status가 적혀있음을 볼 수 있다.
yaml 파일로 Deployment, Service를 생성했다면 똑같이 yaml 파일로 삭제할 수도 있다.
만들었던 컴포넌트를 삭제하자.
kubectl delete -f nginx-deployment.yaml
kubectl delete -f nginx-service.yaml
출처 : https://www.youtube.com/watch?v=X48VuDVv0do
번역 : 나
Chapter : K8s YAML Configuration File
'DevOps > Kubernetes' 카테고리의 다른 글
[kubernetes] #8 네임스페이스를 통해 컴포넌트 구성하기 (0) | 2022.03.06 |
---|---|
[kubernetes] #7 Demo 프로젝트: MongoDB + MongoExpress (0) | 2022.03.03 |
[kubernetes] #5 핵심 kubectl 명령어 (0) | 2022.03.01 |
[kubernetes] #4 Minikube와 kubectl - 클러스터 구축 (0) | 2022.02.28 |
[kubernetes] #3 쿠버네티스 아키텍처 (0) | 2022.02.27 |