서비스 오픈 준비 과정에서 nginx 파드가 서로 다른 worker node에 뜨지 않으면 패킷이 간헐적으로 유실되는 현상 발견
해결을 위해 affinity 설정을 진행하기로 결정. 이에 따라 affinity 설정에 대해 정리하고자 함.
단어의 뜻 그대로 파드를 노드에 배치함에 있어 선호도 설정을 하여 좀 더 유연하게 파드를 배포하기 위한 설정입니다.
nodeSelector
nodeSelector의 경우 pod를 특정 label이 있는 node에만 띄우도록 제한하는 방법
.spec.affinity.nodeAffinity 필드에 사용하고 기능은 nodeSelector와 유사합니다.
해당 설정을 사용하면 규칙이 만족되지 않으면 파드를 스케줄링 할 수 없고 Pending 상태가 됩니다. nodeSelector와 유사하지만 좀 더 다양한 기능을 제공합니다.
해당 설정은 조건을 만족하는 노드를 찾아 파드를 스케줄링하지만, 해당되는 노드가 없더라도 파드를 스케줄링하여 Pending 상태가 되지 않습니다.
requiredDuringSchedulingIgnoredDuringExecution보다는 조금 더 유연한 옵션입니다.
이제 nginx 파드를 nginx파드용 노드에 띄우는 상황을 가정하여 예시를 들어 알아보겠습니다.
< 예시 >
...
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- nginx
...
matchExpressions에 key, operator, values를 정의해줍니다.
key를 통해 node에 적용된 label을 찾고, operator를 통해 해당하는 키가 In, NotIN, Exists, DoesNotExists, Gt, Lt 연산자를 통해 values에 정의한 값과 비교하여 pod를 어느 노드에 배치할지 결정합니다.
위 yaml을 해석해보면 node에 적용된 label중 kubernetes.io/hostname의 value가 nginx인(hostname이 nginx인) 노드를 찾아 파드를 띄우는 설정입니다.
< 예시 >
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: node-role
operator: In
values:
- worker
추가적으로 preferredDuringSchedulingIgnoredDuringExecution 옵션을 살펴보면 weight 부분을 제외하면 requiredDuringSchedulingIgnoredDuringExecution와 거의 흡사합니다.
weight부분은 가중치로 1-100 범위의 숫자를 지정할 수 있고 점수가 높은 노드가 우선 순위를 갖게됩니다.
nodeAffinity와 거의 동일한 기능입니다. requiredDuringSchedulingIgnoredDuringExecution과 preferredDuringSchedulingIgnoredDuringExecution 옵션을 사용할 수 있습니다. 하지만 가장 중요한 것은 topology key(토폴로지 키) 입니다.
Topology Key
수행할 노드의 범위를 결정하는 역할을 하며 노드의 label key 값을 Topology Key로 설정합니다. 어떤 key 값을 넣어도 무관하지만 주로 다음 3가지 key를 주로 씁니다.
- 노드 단위 : kubernetes.io/hostname
- 존 단위 : topology.kubernetes.io/zone
- 리전 단위 : topology.kubernetes.io/region
< 예시 >
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- login
topologyKey: kubernetes.io/hostname
예시 yaml을 보고 nodeAffinity와 다른점을 찾으면 nodeAffinity가 podAffinity로 바뀐것과 topologyKey값이 생긴것입니다.
이 yaml을 배포하면 label에 app:login 이 정의 된 pod가 배포되어 있는 노드에만 해당 파드가 배포됩니다. required 설정이기 때문에 조건에 맞는 노드가 없다면 pending상태로 파드가 뜨지 못 합니다.
반대로 preferred일 경우는 nodeAffinity에서의 preferred 설정과 동일한 효과를 보입니다.
podAffinity와는 반대로 선호하지 않는 파드를 설정하는 방법입니다. 사용법은 podAffinity와 동일합니다.
< 예시 >
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
예시 yaml을 보면 podAffinity와 동일한 구성임을 알 수 있습니다.
이 yaml을 배포하면 podAffinity와는 반대로 label에 app:nginx 가 정의 된 pod가 배포되어 있는 노드를 피해서 파드를 배포합니다. 만약 모든 가용 노드에 app:nginx가 정의 된 pod가 있다면 pending 상태가 되어 배포되지 못합니다.
하지만 preferred로 설정을 할 경우에는 기존 nodeAffinity와 podAffinity에서와 같이 pending이 되지 않고 파드가 배포 됩니다.
실제로 워커 노드가 3대인 환경에서 각 노드에 nginx 파드를 한개씩 띄우기 위해 replicas가 3인 deployment yaml에 podAnitiAffinity 설정을 적용했습니다. (preferred로 적용. required로 적용시 재기동을 하게 되면 이미 가용한 노드에 nginx파드가 떠 있기 때문에 새로운 파드가 스케줄링 되지 못하는 현상 발생)