개발/Kubernetes
Kubernetes 환경에 affinity, anti-affinity 적용하기
말고기
2021. 7. 4. 20:20
728x90
반응형
개요
- kubernetes 환경에서 작업을 하다보면 특정 node에 pod가 쏠리는 현상이 발생할 수 있다.
- 이를 방지하기 위해서 affinity 설정을 추가할 수 있다.
Node isolation / restriction
Affinity를 설명하기 이전에 isolation과, restriction에 대해서 설명한다.
- node object에 label을 추가하게 되면, 특정 노드 또는 노드 그룹에 pod가 배치되도록 할 수 있다.
- node 자체에는 표준 label, annotation, taints들이 존재한다.
- NodeRestriction admission plugin이 있는데, 이 plugin을 활성화하게 되면, 노드를 쉽게 격리시킬 수 있다.
- 특정 node의 label을 사용하여 nodeSelector를 지정할 수 있다.
Affinity, Anti-affinity란
- nodeSelector보다 확장된 방식으로, 특정 노드에 pod를 위치시키게 고정하거나 또는 제외시킬 수 있다.
- 기존 nodeSelector의 경우에는 AND 조건으로 매칭을 지원하는 반면 affinity는 더 많은 매칭 규칙을 제공한다.
- 엄격한 요구사항이 아닌 선호 (preference)로 설정이 가능하다. 따라서 조건을 만족 못시키더라도 POD가 계속 스케줄 될 수 있도록 한다.
- 노드 자체의 레이블로도 가능하지만 해당 노드의 다른 pod의 레이블을 제한할 수도 있다. ( 이를 통해 어떤 pod가 함께 위치할 수 있도록 설정할 수 있다. )
Affinity 종류
1. node affinity
- nodeSelector와 유사하다. 노드 레이블을 기반으로 POD를 스케줄할 수 있는 노드를 제한할 수 있다.
- 현재는 requiredDuringSchedulingIgnoredDuringExecution ( hard mode ), preferredDuringSchedulingIgnoredDuringExecution (soft mode) 이 두 종류가 있다.
2. scheduling profile당 node affinity
- 해당 내용은 node affinity plugin에 추가하는 형태로 pod 자체의 affinity 뿐만아니라 addedAffinity를 설정 가능하다. (추가 조건 같은 개념)
- 하지만 이렇게 기본적으로 셋팅되면 까먹기도 쉽고, 예상치 못한 상황이 벌어질 수 있으므로 주의해서 사용하도록 하자.
Isolation vs Affinity
결국 pod가 어떤 node에 위치할 수 있는가에 대한 설정을 할 수 있으나 affinity가 좀 더 유연한 방식을 지원한다고 볼 수 있다. (하지만 단순한 설정만 필요하다면 node selector 방식으로 하는 것이 관리 측면에서 편할 것이라고 생각한다.)
실습
- Affinity가 어떤 내용인지는 개략적으로 이해했으니, 실제로 어떤 방식으로 동작이 되는지 한 번 살펴보자.
- 현재는 scheduling profile당 affinity는 따로 설정안하고, hard와 soft로 해보고 테스트를 진행해보도록 하자.
- node는 총 2대 준비하고 테스트를 진행해보자.
1. Multi node 환경 셋팅
# malgogi-test라는 cluster를 생성한다.
# docker runtime에서는 ingress addon을 사용할 수 없어 vm mode로 수행한다.
minikube start --nodes 2 --vm=true -p malgogi-test
# 이미 생성된 경우
minikube node add 2 -p malgogi-test
# ingress addon 설치 ( 굳이 할 필요 없습니다. )
minikube addons enable ingress
# node 확인
kubectl get nodes
# nginx ingress 확인 ( 굳이 할 필요 없습니다. )
kubectl get pods -n kube-system
2. deployment 구성
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
namespace: default
labels:
app: hello-world
spec:
replicas: 2
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- hello-world
topologyKey: kubernetes.io/hostname
containers:
- name: hello-world
image: nginx
resources:
requests:
cpu: 10m
memory: 0.5G
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /
port: 80
timeoutSeconds: 3
initialDelaySeconds: 300
failureThreshold: 3
periodSeconds: 30
3. svc 구성
kind: Service
apiVersion: v1
metadata:
name: hello-world-svc
namespace: default
spec:
selector:
app: hello-world
ports:
- port: 80
targetPort: 80
type: NodePort
4. 결과 확인
4.1. hard mode (requiredDuringSchedulingIgnoredDuringExecution)
우선 우리는 아래와 같이 hard mode로 설정을 했다.
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- hello-world
topologyKey: kubernetes.io/hostname
그리고 실행을 해보면
kubectl apply -f malgogi-test.yaml
아래와 같이 각각 node에 pod가 할당된 것을 볼 수 있다.
그렇다면 이제 3개로 pod를 늘려보면 어떻게 될까?
replica option 3개로 늘리고, 적용을 하면 다음과 같은 event를 볼 수 있다.
0/2 nodes are available: 2 node(s) didn't match pod affinity/anti-affinity, 2 node(s) didn't match pod anti-affinity rules.
4.2. soft mode (preferredDuringSchedulingIgnoredDuringExecution)
즉 affinity rule에 의해서 더이상 할당할 수 있는 node가 없기 때문에 아예 할당이 되지 않는다.
그렇다면 requiredDuringSchedulingIgnoredDuringExecution => preferredDuringSchedulingIgnoredDuringExecution로 변경해보자.
여러개의 값들이 다르므로 아래와 같이 설정을 변경해야한다.
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- hello-world
topologyKey: kubernetes.io/hostname
이렇게 적용을 하고, 다시 실행해보면 3개가 할당이 되고, 4개로 늘리게 될 경우 각각 node당 2대씩 할당된 것을 볼 수 있다.
출처
728x90
반응형