매니페스트 파일(manifest file)은 컴퓨팅에서 집합의 일부 또는 논리정연한 단위인 파일들의 그룹을 위한 메타데이터를 포함하는 파일이다. 예를 들어, 컴퓨터 프로그램의 파일들은 이름, 버전 번호, 라이선스, 프로그램의 구성 파일들을 가질 수 있다.
이 용어는 화물 목록(ship manifest)이 선원 및 화물을 나열하는 화물 수송 절차로부터 가져온 것이다.[link]
Docker에서는 docker run ...
명령어로, docker swarm에서는 docker service create ...
명령어로 container를 생성할 수 있는 것 같이 kubernetes에서도 kubectl
명령어로 대 부분의 작업을 할 수 있다.
하지만 매번 직접 kubectl 명령어로 모든 object를 배포하고 업데이트 한다면 Human error
[link]의 발생 확율이 높고 또 여러 환경에 배포시 일관성이 저하 될 수 있다.
그렇기 때문에 kubernetes를 잘 사용하려면 YAML
파일을 작 작성하는 것이라고 해도 과언이 아니다.
Kubernetes는 아주 많은 수의 Component가 존재한다. 그중에서 Application을 구동하기 위해 반드시 알아야 할 몇 가지 Object가 있다.
Kubernetes에서는 Container Application의 기본 단위를 Pod라고 한다. Pod는 1개 이상의 Container로 구성된 Container의 집합이다.
다음은 nginx pod이다.
apiVersion: v1
kind: Pod
metadata:
name: my-nginx
spec:
containers:
- name: my-nginx
image: nginx:latest
ports:
- containerPort: 80
protocol: TCP
Kubernetes의 YAML 파일은 일반적으로 apiVersion
, kind
, metadata
, spec
네 가지 항목으로 구성된다.
Kubernetes의 기본 단위인 Pod는 여러 개의 Container를 추상화해 하나의 Application으로 동작하도록 만드는 Container 묶음이다. 그러나 YAML에 Pod만 정의해 생성하면 이 Pod의 Lifecyle은 어떻게 될까?
예를 들어 kubectl delete ...
명령어로 Pod를 삭제하면 그 Pod의 Container 또한 삭제된 뒤 Kubernetes에서 영원히 사라지게 된다. 이처럼 YAML 파일에 Pod만 정의하면 해당 Pod는 오직 Kubernetes 사용자에 의해 관리
된다.
또 여러개의 동일한 Pod를 생성해야 할 경우는 해당 YAML파일이 다음과 같을 것이다.
apiVersion: v1
kind: Pod
metadata:
name: my-nginx-a
spec:
containers:
- name: my-nginx
image: nginx:latest
ports:
- containerPort: 80
protocol: TCP
---
apiVersion: v1
kind: Pod
metadata:
name: my-nginx-b
spec:
containers:
- name: my-nginx
image: nginx:latest
ports:
- containerPort: 80
protocol: TCP
이와 같이 정의할 경우 Pod가 어떠한 이유로 삭제되거나, Pod이 위치한 Node에 장애가 발생해 더 이상 Pod에 접근하지 못하게 될 경우, 관리자가 직접 Pod를 삭제하고 다시 생성하지 않는 한 해당 Pod는 다시 복구되지 않는다.
이러한 한계점을 해결해주는 것이 바로 Replica Set
이라는 Kubernetes object이다.
Replica Set의 역할은 다음과 같다.
Replica Set을 사용하여 위 YAML 파일을 다시 정의해보겠다.
Label은 Kubernetes Resource의 부가적인 정보를 표현할 수 있을 뿐만 아니라, 서로 다른 Object가 서로를 찾아야 할 때 사용하기도 한다. Replica Set은 spec.selector.matcheLabel에 정의된 Label을 통해 생성해야 하는 Pod를 찾는다.
Replica Set만 사용해도 충분히 Microservice 구조의 Container를 구성할 수 있을 것 같지만, 실제 Kubernetes 운영 환경에서 Replica Set을 YAML 파일에서 사용하는 경우는 거의 없다.
대부분은 Replicaset과 Pod의 정보를 정의하는 Deployment라는 이름의 Object를 YAML 파일에 정의해 사용한다.
Deployment는 Replica Set의 상위 Object이기 때문에 Deployment를 생성하면 해당 Deployment에 대응하는 Replica Set도 함께 생성된다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: my-nginx
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
name: my-nginx-pod
labels:
app: my-nginx
spec:
containers:
- name: nginx
image: nginx:1.10
ports:
- containerPort: 80
위 이미지에서와 같이 Deployment를 생성함으로써 Replica Set이 생성됐고, Replica Set이 Pod를 생성한다. 따라서 Deployment를 삭제하면 Replica Set과 Pod도 삭제된다.
Application의 업데이트와 배포를 편하게 만들기 위해 사용된다.
Kubernetes에서는 Pod에 접근하도록 정의하는 방법이 Docker와 약간 다르다. docker run -p ...
명령어와 달리 Kubernetes는 Deployment를 생성할 때 Pod를 외부로 노출하지 않으며, Deployment의 YAML 파일에는 단지 Pod의 Application이 사용할 내부 Port만 정의한다.
Port를 외부로 노출해 사용자들이 접근하거나, 다른 Deployment의 Pod들이 내부적으로 접근하려면 Service
라고 부르는 별도의 Kubernetes Object를 생성해야 한다.
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-clusterip
spec:
ports:
- name: web-port
port: 8080
targetport: 80
selector:
app: webserver
type: ClusterIP
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-nodeport
spec:
ports:
- name: web-port
port: 8080
targetport: 80
nodePort: 31880 # 포트 범위는 30000~31768
selector:
app: webserver
type: NodePort
실제 운영환경에서 NodePort로 서비스를 외부에 제공하는 경우는 많지 않다. NodePort에서 Port 번호를 80 또는 443으로 설정하기에는 적절하지 않으며, SSL 인증서 적용, 라우팅 등과 같은 복잡한 설정을 서비스에 적용하기가 어렵기 때문이다. 따라서 NodePort 서비스 그 자체를 통해 서비스를 외부로 제공하기보다는 Ingress라고 부르는 kubernetes의 Object에서 간접적으로 사용되는 경우가 많다.
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-lb
spec:
ports:
- name: web-port
port: 80
targetPort: 80
selector:
app: webserver
type: LoadBalancer
1. LoadBalancer 타입의 서비스가 생성됨과 동시에 모든 Node는 Pod에 접근할 수 있는 랜덤한 Port를 개방한다.
2. Cloud Platform에서 생성된 LoadBalancer로 요청이 들어오면 이 요청은 Kubernetes의 Worker Node 중 하나로 전달되며, 이 때 사용되는 Port는 1번에서 개방된 Port이다.
3. Worker Node로 전달된 요청은 Pod 중 하나로 전달되어 처리된다.
apiVersion: v1
kind: Service
metadata:
name: externalname-svc
spec:
type: ExternalName
externalName: my.database.com
Kuternetes를 외부 시스템과 연동해야 할 때 ExternalName 타입의 서비스를 사용할 수 있다.
ExternalName 타입을 사용해 서비스를 생성하면 서비스가 외부 Domain을 가리키도록 설정 할 수 있다.
예를 들어 Kubernetes 내부의 Pod들이 externalname-svc
라는 이름으로 요청을 보낼 경우, Kubernetes의 DNS는 my.database.com으로 접근할 수 있도록 CNAME Record를 반환한다.