책 쿠버네티스 패턴을 읽고 나 혼자 정리한 글
6장 자동 배치 패턴
자동 배치 패턴 = 스케줄러의 핵심 기능
스케줄러의 기능 = 노드에 신규 파드를 할당해주는 기능
컨테이너는
컨테이너 서로 간의 의존성
컨테이너와 노드간의 의존성
자원 요구사항
변경사항등등 시간이 지남에 따라 다양하게 변하기 때문에
스케줄링을 하는 것 = 이동 목표물에 과녁을 조준하는 것과도 같다고 말한다.
스케줄러의 주요 업무
API서버로부터 새로 생성된 파드 정의를 조회, 파드를 노드에 할당.
스케줄링이 정상적으로 진행되려면 몇 가지의 요구 조건이 충족되어야 한다.
1. 충분히 가용가능한 노드 자원
모든 노드에는 파드를 실행할 수 있는 용량이 있고,
스케줄러는 파드가 요청한 자원의 총합이 할당 가능한 노드의 용량보다 작다는 것을 확인해야 한다.
2. 컨테이너의 자원 요구량이 얼마인지
컨테이너가 런타임 의존성과 자원 요구 정의를 갖는 것이다.컨테이너에 요청과 제한을 갖는 자원 프로파일과 스토리지 또는 포트 같은 환경 의존성을 선언해야한다.
3. 배치 정책
- 노드 셀렉터
노드에 레이블로 존재하는 key-value 쌍의 맵이 지정되어 있다면
파드 spec에 nodeSelector를 이용해 직접 node를 지정할 수 있다.
파드를 특정 노드에 강제로 할당시키고싶다면 이 방법을 사용하면 된다.
- 노드 어피니티
노드 셀렉터 접근 방식을 일반화한 것으로, 필수 혹은 선호 규칙을 지정할 수 있다.필수 규칙은 파드가 노드에 스케줄되기 위해서 반드시 충족되어야 한다.선호 규칙은 반드시 충족되어야 하는 것은 아니며 일치하는 노드의 가중치를 증가시켜 노드가 선택되게 한다.
아래는 필수 규칙을 가지는 pod의 예시이다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
선호 규칙
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
- 파드 어피니티 & 파드 안티어피니티
노드 어피니티는 노드 셀렉터로는 부족할 때 사용하고파드가 실행될 수 있는 노드를 제한한다. 또한 이 메커니즘은 하나의 파드가 또 다른 파드의상대적 위치를 지정하는 파드 간의 의존성을 표현할 수 없는데,
파드 간의 의존성을 표현하고 싶을 때 사용하는 것이 파드 어피니티와 파드 안티어피니티이다.
파드 어피니티 & 안티어피니티는 다중 토포롤지 레벨에서 규칙을 표현할 수 있다.
파드 어피니티에 대한 예시이다.
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: cloud/zone
containers:
- name: with-pod-affinity
image: k8s.gcr.io/pause:2.0
출처: https://bcho.tistory.com/1346 [조대협의 블로그]
파드 안티어피니티에 대한 예시이다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cache
spec:
selector:
matchLabels:
app: store
replicas: 3
template:
metadata:
labels:
app: store
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- store
topologyKey: "kubernetes.io/hostname"
containers:
- name: redis-server
image: redis:3.2-alpine
출처: https://bcho.tistory.com/1346 [조대협의 블로그]
- 테인트 & 톨러레이션
노드 어피니티는 파드가 노드를 선택할 수 있는 속성인 반면,
테인트와 톨러레이션은 그 반대이다.
테인트와 톨러레이션은 파드가 스케줄되어야 하는지 혹은 되지 말아야하는지를 노드가 제어하게 한다.
테인트는 노드의 특성 테인트의 뜻은 한국어로 "오염"이라는 뜻이다.
톨러레이션은 파드의 특성으로 톨러레이션은 "관용"이라는 뜻이다.
노드에 테인트의 값이 존재할 때 파드가 이 테인트에 대한 톨러레이션이 없다면 이 파드는 노드에 스케줄될 수 없다.
쉽게 설명하면 노드의 오염에 견딜 수 있는 톨러레이션이 없는 파드는 오염이 있는 노드에 스케줄될 수 없다고 생각하면 쉽다.
노드에 테인트 추가
kubectl taint nodes node1 key=value:NoSchedule
파드에 톨러레이션 추가
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
tolerations:
- key: "example-key"
operator: "Exists"
effect: "NoSchedule"
11장 스테이트풀 서비스 패턴
분산 스테이트풀 어플리케이션은 퍼시스턴트 식별자, 네트워킹, 스토리지 등과 같은 기능이 요구됩니다.
이런 관리에 이상적이고 강력한 보장을 해주는 스테이트풀 세트 기본 요소에 대해 설명을 하고있습니다.
어플리케이션의 배치와 회복성, 스케일 등을 처리등 스테이트풀 애플리케이션의 모든 인스턴스는
고유하며 오래 지속되는 특성을 가집니다.
스테이트풀 애플리케이션의 일반적인 요구사항은
디플로이먼트를 사용해 mysql 같은 스테이트풀 애플리케이션을 배포하고
이를 통해 replicas = 1로 레플리카세트를 생성해 신뢰성을 확보하고,
서비스를 활용해 해당 종단점을 디스커버리하며
PVC, PV 같은 해당 상태의 영구적인 저장소로 사용을 할 수 있을 것 입니다.
스토리지
항상 필요한 것은 아니지만 대부분의 스테이트풀 애플리케이션은 상태를 저장하므로
인스턴스마다 전용 PV가 필요하다.
레플리카세트와 스테이트풀세트의 차이점은
레플리카세트는 미리 정의되어 있는 PVC를 참조하는 대신
스테이트풀세트는 PVC를 필요로 하는 POD가 있으면 PVC를 즉시 생성한다는 것이다.
PV는 PVC가 Bind하기전에 이미 정의가 되어있다는 것을 전제로 한다.
그래서 스테이트풀 세트를 스케일 업(레플리카 수를 늘리기)하면 새로운 파드와 PVC가 같이 생성된다.
또한 스케일 다운을 하면 파드는 삭제되지만 PVC는 삭제되지 않으므로 PV를 재사용하거나
삭제할 수 없으며, 이는 의도적으로 설계된 것으로, 스테이트풀 애플리케이션의 스토리지가
중요하고 실수로 인한 스케일 다운으로 인해 데이터 손실이 없어야 한다는 추정에 의해 만들어졌다고 한다.
네트워킹
스테이트풀세트에 의해 생성된 각 파드에는 스테이트풀세트의 이름과,
순서를 나타내는 인덱스(0에서 시작됨)로 만들어진 고정된 식별자가 있다.
파드 이름은 임의의 접미사가 포함된 레플리카세트의 파드 이름 생성 메커니즘과는 달리
예측 가능한 형식으로 만들어진다.
레플리카세트를 통해 생성된 파드들은 동일하다고 가정하며 요청이 어느 파드에 도달하든
상관이 없다. 그래서 일반 서비스로 로드 밸런싱을 한다.
그러나 스테이트풀 파드는 서로 다르므로 좌표로 특정 파드에 도착을 해야한다.
관리 서비스는 스테이트풀세트가 생성되기 전에 존재해야 하며 세트의 네트워크 식별자를 담당한다.
식별자
스테이트풀세트의 이름을 기반으로 파드이름과 식별자를 예측할 수 있다.
그래서 필요하다면 애플리케이션 자체에서 식별자를 사용할 수 있다.
순서성
스테이트풀 애플리케이션은 고유하고 교체할 수 없는 여러 인스턴스로 구성된다.
순서성은 오직 스케일할 때에만 적용된다.
파드는 순서를 나타내는 접미어(0부터 시작)를 붙인 이름을 가지며,
순서는 스케일 업과 다운되는 순서를 정의한다.
레플리카세트는 다수의 레플리카로 파드들을 생성하면
모든 파드는 함께 스케줄되고 시작된다.
즉 파드가 시작되고 준비될 때 순서를 보장하지 않는다.
하지만 스테이트풀세트 애플리케이션은 기본적으로 순차적 시작 및 종료를 수행한다.
인덱스 0인 파드부터 시작되고 해당 파드가 성공적으로 시작된 경우에만 다음 스케줄된 파드 인덱스1이 시작되고
그 다음으로 순차적으로 시작되는 것이다.
종료될 때에는 반대로 진행된다. 인덱스가 가장 높은 파드가 종료가되고 성공적으로 종료되었을 때에만 다음 하위 인덱스가
종료되는 방식으로 진행된다.
하지만 선택적으로 병렬 배포(레플리카세트처럼 동작)을 할 수 있다.
spec.podManagementPolicy를 Parallel로 설정하면
스테이트풀 애플리케이션에서 운영 절차의 속도를 높일 수 있다.
기타 기능
분할된 업데이트
기본 롤링업데이트를 지원하고
나머지 인스턴스에 업데이트를 적용하는 동안 특정 수의 인스턴스가 그대로 유지되도록 보장하는
단계적 롤아웃(ex: 카나리아 릴리스)를 허용한다.
병렬 배포
순서성에서 나오는 설명.
최대한 하나 보장
스테이트풀세트 = 최대한 하나 보장(at-most-one)
레플리카세트 = 최소한 X개 보장(at-least-X-Guarantee)
스테이트풀세트는 두 파드가 동일한 식별자를 갖거나 동일한 PV에 바인딩되지 않게 한다.
레플리카세트는 항상 2개 이상의 인스턴스를 실행 상태로 유지하려고 한다.
스테이트풀세트는 이전 인스턴스가 완전히 종료된 것으로 확인되지 않으면
스테이트풀세트 컨트롤러는 파드를 다시 시작하지 않는다.
스테이트풀세트는 파드가 종료되었음을 확인할 수 없으면, 스테이트풀세트의 컨트롤러는
다른 노드에 새로운 파드를 스케줄하지 않는다.
12장 서비스 디스커버리 패턴
클라이언트가 서비스를 제공하는 인스턴스에 접근할 수 있는 안정적인 종단점을 제공한다.
클러스터내의 다른 파드나 외부 시스템에서 들어오는 HTTP 연결 형식의 외부 자극을 기다리며장기간 실행되는 서비스가 있을 경우에 서비스 컨슈머는,동적으로 배치되고 때로는 탄력적으로 스케일 업 및 다운되는 파드를 디스커버리하는 메커니즘이 필요하다.
간단한 서비스
apiVersion: v1
kind: Service
metadata:
name: random-generator
spec:
selector:
app: random-generator
ports:
- port: 80
targetPort: 8080
protocol: TCP
random-generator라는 이름의 서비스를 생성하는데
포트 80번으로 TCP연결을 받아들이고
셀렉터 app: random-generator 라고 설정된 모든 파드에 포트 8080으로 라우팅한다.
평범한 서비스는 selector와 일치하는 pod에 대한 종단점을 제공하지만
selector 없는 service도 있다.
외부종단점을 제공하는 서비스
이 서비스는 외부 시스템의 종단점을 제공한다.
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
이런 서비스는 외부 종단점을 수동으로 생성해주어야 한다.
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- ip: 192.0.2.42
ports:
- port: 9376
이와 비슷하게 외부 시스템에 대한 또 다른 추상화방법으로 ExternalName 타입이 있다.
type : ExternalName
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
이 방법은 IP주소로 프록시를 통하지 않고 DNS CNAME을 사용해 외부 종단점에 대한 alias(별명)를 생성한다.
지금까지 설명한 서비스 디스커버리 매커니즘들은 모두 파드 또는 외부 종단점을 가리키는
가상 IP주소를 사용하며, 이 주소 자체는 클러스터 내부에서만 접근할 수 있다.
하지만 외부 애플리케이션이 파드에서 제공하는 종단점에 접근하길 원할수도 있고
파드에서 외부로 연결되어 있어야 할수도있다.
클러스터를 외부에 노출시키는 방법,
그에 대한 첫번째 방법은 NodePort 타입이다.
type : NodePort
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app: MyApp
ports:
# 기본적으로 그리고 편의상 `targetPort` 는 `port` 필드와 동일한 값으로 설정된다.
- port: 80
targetPort: 80
# 선택적 필드
# 기본적으로 그리고 편의상 쿠버네티스 컨트롤 플레인은 포트 범위에서 할당한다(기본값: 30000-32767)
nodePort: 30007
노드포트의 특성
1. 포트 번호
특정 포트를 직접 선택하는 대신, 쿠버네티스가 특정 범위 내에서 사용가능한 포트를 직접 선택하게 할 수 있다.
2. 방화벽 규칙
모든 노드에서 포트를 열기 때문에, 방화벽 규칙을 설정해야 할 수도있다.
3. 노드 선택
정상적인 노드를 연결하는 것은 클라이언트 애플리케이션이 해야하는 일이다.
이 역할을 하는 로드 밸런서는 노드 앞에 배치하는 것이 좋다.
4. 파드 선택
클라이언트는 연결이 열린 동일한 노드 또는 다른 노드에 있을 수 있는 임의의 파드로 라우팅된다.
일정한 파드를 선택하게 할 수 있지만, 이 옵션이 설정되면 다른 노드에 있는 파드에 연결할 수 없다.
그래서 모든 노드에 파드를 배포(데몬 서비스) 하거나 어느 노드에 정상적인 파드가 배포되어 있는지를 클라이언트가 알게 해야 한다.
type : LoadBalancer
NodePort 외에도 클라우드 제공업체의 로드 밸런서를 사용해 외부로 서비스를 노출할 수 있다.
로드 밸런서는 클러스터의 게이트웨이 역할을 한다.
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 192.0.2.127
Ingress
ingress는 앞에서 설명 된 메커니즘들과 다르게 서비스의 타입이 아닌,
서비스 앞쪽에 위치하며 스마트 라우터 및 클러스터의 진입점 역할을 하는 별도의 쿠버네티스 자원이다.
인그레스는 일반적으로 외부에서 접근 가능한 URL, 로드 밸런싱, 이름 기반 가상호스팅 등등을 통해 서비스에 대한
HTTP 기반 접근을 제공하지만 그 밖의 특수한 인그레스도 있다.
인그레스가 작동하려면 클러스터에 작동하는 인그레스 컨트롤러가 있어야 한다.
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
serviceName: test
servicePort: 80
'Kubernetes & Docker' 카테고리의 다른 글
[Kubernetes 공식문서 파헤치기] 고가용성 테스트(pod 부하분산, auto scaler 적용하기) (2) | 2020.08.13 |
---|---|
[Kubernetes 공식문서 파헤치기] Redis를 사용한 PHP 방명록 애플리케이션 배포하기 + PV, PVC, Affinity 사용해보기 (0) | 2020.08.10 |
Kubespray와 Ansible을 이용한 Kubernetes 설치하기 - 4편 (2) | 2020.08.05 |
Kubespray와 Ansible을 이용한 Kubernetes 설치하기 - 3편 (0) | 2020.07.31 |
Kubespray와 Ansible을 이용한 Kubernetes 설치하기 - 2편 (0) | 2020.07.29 |