mirror of
https://github.com/calofmijuck/blog.git
synced 2025-12-06 14:53:50 +00:00
* [PUBLISHER] upload files #175 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 03. Symmetric Key Cryptography (2).md * DELETE FILE : _posts/lecture-notes/modern-cryptography/2023-09-18-symmetric-key-cryptography-2.md * DELETE FILE : _posts/lecture-notes/modern-cryptography/2023-09-19-symmetric-key-encryption.md * [PUBLISHER] upload files #177 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 03. Symmetric Key Cryptography (2).md * DELETE FILE : _posts/lecture-notes/modern-cryptography/2023-09-18-symmetric-key-cryptography-2.md * DELETE FILE : _posts/lecture-notes/modern-cryptography/2023-09-19-symmetric-key-encryptio.md * [PUBLISHER] upload files #178 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 03. Symmetric Key Cryptography (2).md * DELETE FILE : _posts/lecture-notes/modern-cryptography/2023-09-18-symmetric-key-cryptography-2.md * [PUBLISHER] upload files #179 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 03. Symmetric Key Cryptography (2).md * DELETE FILE : _posts/lecture-notes/modern-cryptography/2023-09-18-symmetric-key-cryptography-2.md * [PUBLISHER] upload files #180 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 03. Symmetric Key Cryptography (2).md * DELETE FILE : _posts/lecture-notes/modern-cryptography/2023-09-18-symmetric-key-cryptography-2.md * [PUBLISHER] upload files #181 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 03. Symmetric Key Cryptography (2).md * DELETE FILE : _posts/lecture-notes/modern-cryptography/2023-09-18-symmetric-key-cryptography-2.md * [PUBLISHER] upload files #182 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 03. Symmetric Key Cryptography (2).md * [PUBLISHER] upload files #183 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 03. Symmetric Key Cryptography (2).md * DELETE FILE : _posts/lecture-notes/modern-cryptography/2023-09-18-symmetric-key-cryptography-2.md * [PUBLISHER] upload files #184 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 03. Symmetric Key Cryptography (2).md * DELETE FILE : _posts/lecture-notes/modern-cryptography/2023-09-18-symmetric-key-cryptography-2.md * [PUBLISHER] upload files #185 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 03. Symmetric Key Cryptography (2).md * DELETE FILE : _posts/lecture-notes/modern-cryptography/2023-09-18-symmetric-key-cryptography-2.md * [PUBLISHER] upload files #186 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 03. Symmetric Key Cryptography (2).md * [PUBLISHER] upload files #187 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 14. Secure Multiparty Computation.md * DELETE FILE : _posts/Lecture Notes/Modern Cryptography/2023-09-19-symmetric-key-encryption.md * DELETE FILE : _posts/lecture-notes/modern-cryptography/2023-09-18-symmetric-key-cryptography-2.md * [PUBLISHER] upload files #188 * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH NOTE : 14. Secure Multiparty Computation.md * DELETE FILE : _posts/Lecture Notes/Modern Cryptography/2023-09-19-symmetric-key-encryption.md * chore: remove files * [PUBLISHER] upload files #197 * PUSH NOTE : 수학 공부에 대한 고찰.md * PUSH NOTE : 09. Lp Functions.md * PUSH ATTACHMENT : mt-09.png * PUSH NOTE : 08. Comparison with the Riemann Integral.md * PUSH ATTACHMENT : mt-08.png * PUSH NOTE : 04. Measurable Functions.md * PUSH ATTACHMENT : mt-04.png * PUSH NOTE : 06. Convergence Theorems.md * PUSH ATTACHMENT : mt-06.png * PUSH NOTE : 07. Dominated Convergence Theorem.md * PUSH ATTACHMENT : mt-07.png * PUSH NOTE : 05. Lebesgue Integration.md * PUSH ATTACHMENT : mt-05.png * PUSH NOTE : 03. Measure Spaces.md * PUSH ATTACHMENT : mt-03.png * PUSH NOTE : 02. Construction of Measure.md * PUSH ATTACHMENT : mt-02.png * PUSH NOTE : 01. Algebra of Sets and Set Functions.md * PUSH ATTACHMENT : mt-01.png * PUSH NOTE : Rules of Inference with Coq.md * PUSH NOTE : 블로그 이주 이야기.md * PUSH NOTE : Secure IAM on AWS with Multi-Account Strategy.md * PUSH ATTACHMENT : separation-by-product.png * PUSH NOTE : You and Your Research, Richard Hamming.md * PUSH NOTE : 10. Digital Signatures.md * PUSH ATTACHMENT : mc-10-dsig-security.png * PUSH ATTACHMENT : mc-10-schnorr-identification.png * PUSH NOTE : 9. Public Key Encryption.md * PUSH ATTACHMENT : mc-09-ss-pke.png * PUSH NOTE : 8. Number Theory.md * PUSH NOTE : 7. Key Exchange.md * PUSH ATTACHMENT : mc-07-dhke.png * PUSH ATTACHMENT : mc-07-dhke-mitm.png * PUSH ATTACHMENT : mc-07-merkle-puzzles.png * PUSH NOTE : 6. Hash Functions.md * PUSH ATTACHMENT : mc-06-merkle-damgard.png * PUSH ATTACHMENT : mc-06-davies-meyer.png * PUSH ATTACHMENT : mc-06-hmac.png * PUSH NOTE : 5. CCA-Security and Authenticated Encryption.md * PUSH ATTACHMENT : mc-05-ci.png * PUSH ATTACHMENT : mc-05-etm-mte.png * PUSH NOTE : 1. OTP, Stream Ciphers and PRGs.md * PUSH ATTACHMENT : mc-01-prg-game.png * PUSH ATTACHMENT : mc-01-ss.png * PUSH NOTE : 4. Message Authentication Codes.md * PUSH ATTACHMENT : mc-04-mac.png * PUSH ATTACHMENT : mc-04-mac-security.png * PUSH ATTACHMENT : mc-04-cbc-mac.png * PUSH ATTACHMENT : mc-04-ecbc-mac.png * PUSH NOTE : 3. Symmetric Key Encryption.md * PUSH ATTACHMENT : is-03-ecb-encryption.png * PUSH ATTACHMENT : is-03-cbc-encryption.png * PUSH ATTACHMENT : is-03-ctr-encryption.png * PUSH NOTE : 2. PRFs, PRPs and Block Ciphers.md * PUSH ATTACHMENT : mc-02-block-cipher.png * PUSH ATTACHMENT : mc-02-feistel-network.png * PUSH ATTACHMENT : mc-02-des-round.png * PUSH ATTACHMENT : mc-02-DES.png * PUSH ATTACHMENT : mc-02-aes-128.png * PUSH ATTACHMENT : mc-02-2des-mitm.png * PUSH NOTE : 18. Bootstrapping & CKKS.md * PUSH NOTE : 17. BGV Scheme.md * PUSH NOTE : 16. The GMW Protocol.md * PUSH ATTACHMENT : mc-16-beaver-triple.png * PUSH NOTE : 15. Garbled Circuits.md * PUSH NOTE : 14. Secure Multiparty Computation.md * PUSH NOTE : 13. Sigma Protocols.md * PUSH ATTACHMENT : mc-13-sigma-protocol.png * PUSH ATTACHMENT : mc-13-okamoto.png * PUSH ATTACHMENT : mc-13-chaum-pedersen.png * PUSH ATTACHMENT : mc-13-gq-protocol.png * PUSH NOTE : 12. Zero-Knowledge Proofs (Introduction).md * PUSH ATTACHMENT : mc-12-id-protocol.png * PUSH NOTE : 11. Advanced Topics.md * PUSH NOTE : 0. Introduction.md * PUSH NOTE : 02. Symmetric Key Cryptography (1).md * PUSH NOTE : 09. Transport Layer Security.md * PUSH ATTACHMENT : is-09-tls-handshake.png * PUSH NOTE : 08. Public Key Infrastructure.md * PUSH ATTACHMENT : is-08-certificate-validation.png * PUSH NOTE : 07. Public Key Cryptography.md * PUSH NOTE : 06. RSA and ElGamal Encryption.md * PUSH NOTE : 05. Modular Arithmetic (2).md * PUSH NOTE : 03. Symmetric Key Cryptography (2).md * PUSH ATTACHMENT : is-03-feistel-function.png * PUSH ATTACHMENT : is-03-cfb-encryption.png * PUSH ATTACHMENT : is-03-ofb-encryption.png * PUSH NOTE : 04. Modular Arithmetic (1).md * PUSH NOTE : 01. Security Introduction.md * PUSH ATTACHMENT : is-01-cryptosystem.png * PUSH NOTE : Search Time in Hash Tables.md * PUSH NOTE : 랜덤 PS일지 (1).md * chore: rearrange articles * feat: fix paths * feat: fix all broken links * feat: title font to palatino
529 lines
36 KiB
Markdown
529 lines
36 KiB
Markdown
---
|
|
share: true
|
|
toc: true
|
|
categories: [Development, Kubernetes]
|
|
path: "_posts/development/kubernetes"
|
|
tags: [kubernetes, sre, devops]
|
|
title: "11. Understanding Kubernetes Internals"
|
|
date: "2021-05-30"
|
|
github_title: "2021-05-30-11-k8s-internals"
|
|
image:
|
|
path: /assets/img/posts/development/kubernetes/k8s-11.jpeg
|
|
attachment:
|
|
folder: assets/img/posts/development/kubernetes
|
|
---
|
|
|
|
 _The chain of events that unfolds when a Deployment resource is posted to the API server (출처: https://livebook.manning.com/book/kubernetes-in-action/chapter-11)_
|
|
|
|
### 주요 내용
|
|
|
|
- Kubernetes 클러스터를 구성하는 컴포넌트의 기능과 역할에 대한 이해
|
|
- Pod 생성시 일어나는 일에 대한 이해
|
|
- Kubernetes 내부 네트워크와 Service 의 동작 방식 이해
|
|
|
|
Kubernetes 리소스들이 어떻게 구현되었는지 살펴보자!
|
|
|
|
## 11.1 Understanding the architecture
|
|
|
|
---
|
|
|
|
Kubernetes 클러스터는 다음과 같이 구성되어 있음을 1장에서 배웠다!
|
|
|
|
- Kubernetes Control Plane: 클러스터의 상태를 저장하고 관리한다
|
|
- etcd distributed persistent storage
|
|
- API server
|
|
- Scheduler
|
|
- Controller Manager
|
|
- (Worker) Node(s): 실제로 컨테이너를 동작하게 한다
|
|
- Kubelet
|
|
- Kubernetes Service Proxy (kube-proxy)
|
|
- Container Runtime (Docker 등)
|
|
|
|
이와 별개로도 리소스들을 관리하거나 사용하기 위해서는 이하의 것들이 추가로 필요하다.
|
|
|
|
- Kubernetes DNS server
|
|
- Dashboard
|
|
- Ingress controller
|
|
- Heapster (14장)
|
|
- Container Network Interface network plugin
|
|
|
|
### 11.1.1 The distributed nature of Kubernetes components
|
|
|
|
위에서 언급한 컴포넌트들은 각각 별도의 프로세스로 실행된다!
|
|
|
|
#### 컴포넌트의 통신 방식
|
|
|
|
컴포넌트들은 반드시 API server 와만 통신하고, 서로 직접 통신하지 않는다. 그리고 etcd 와 통신하는 유일한 컴포넌트는 API server 이다. 클러스터의 상태를 변경하기 위해서는 무조건 API server 를 거쳐야 한다.
|
|
|
|
#### 컴포넌트의 인스턴스 여러 개 만들기
|
|
|
|
Control Plane 의 컴포넌트들은 여러 개의 서버 사이에 분리될 수 있으며, Control Plane 을 여러 개 만들어 주면 high availability (HA/고가용성) 을 달성할 수 있다.
|
|
|
|
또한 etcd 와 API server 의 경우 병렬적인 작업 처리가 가능하지만, Scheduler 와 Controller Manager 의 경우 작업을 한 번에 한 인스턴스만 실행할 수 있다. 나머지는 standby 상태가 된다.
|
|
|
|
#### 컴포넌트들의 실행 방식
|
|
|
|
Kubelet 만 시스템에서 실행하고 나머지는 Kubelet 이 pod 의 형태로 실행한다. (물론 Control Plane 의 컴포넌트들은 시스템에서 직접 실행 할수도 있다)
|
|
|
|
### 11.1.2 How Kubernetes uses etcd
|
|
|
|
Kubernetes 를 사용하면서 리소스를 생성하고 수정하게 되면 이러한 정보가 persistent 하게 어딘가에 저장되어야 한다. 그래야만 API server 가 재시작하는 등의 경우에도 리소스들이 유지될 수 있기 때문이다. Kubernetes 에서는 클러스터의 정보와 메타데이터를 저장하는 *유일한* 저장소가 etcd 이다. etcd 는 fast, distributed, consistent key-value store 이다. (Distributed 이므로 HA 를 위해 여러 개 생성 가능)
|
|
|
|
etcd 와 통신하는 유일한 컴포넌트는 API server 이고, 나머지 컴포넌트들은 API server 를 통해 간접적으로 etcd 에 접근하게 된다. 이렇게 구현된 이유는 validation 과 more robust optimistic locking system, 그리고 저장소와의 통신을 API server 에게 맡겨서 abstraction 의 효과를 얻기 위해서이다.
|
|
|
|
> **Optimistic Concurrency Control** (Optimistic Locking): 데이터에 lock 을 걸어서 read/write 를 제한하지 않고, 데이터에 버전을 추가하는 방식이다. 대신 데이터가 수정될 때마다 버전이 증가하게 되며, 클라이언트가 데이터를 수정하려 할 때 데이터를 읽을 때와 쓰려고 할 때 버전을 비교하여 만약 다르다면 업데이트가 기각당하는 방식이다. 이 때 클라이언트는 데이터를 다시 읽어와서 업데이트를 다시 시도해야 한다.
|
|
>
|
|
> 모든 Kubernetes 리소스에는 `metadata.resourceVersion` field 가 있어 클라이언트 쪽에서 API server 에 업데이트 요청을 보낼 때 반드시 함께 전달해야 한다. 만약 etcd 에 저장된 버전과 다르다면, 업데이트가 기각된다.
|
|
|
|
#### etcd 에 리소스가 저장되는 방식
|
|
|
|
etcd v2 에서는 key 를 계층적으로 저장해서 (hierarchical key space) key-value pair 가 파일 시스템처럼 관리 되었다. 그래서 key 는 다른 key 를 포함하는 폴더이거나, 그냥 value 를 가졌다.
|
|
|
|
etcd v3 에서는 폴더를 지원하지 않는데, 대신 key 의 형태는 변하지 않고 유지되었다. `/` 를 포함할 수 있는 것이므로 폴더처럼 계층적으로 나뉘어 있다고 봐도 괜찮다.
|
|
|
|
Kubernetes 에서는 etcd 의 `/registry` 안에 정보를 저장한다.
|
|
|
|
> etcd 설치하고 etcdctl 로 확인해보려 했으나 실패... 아래 내용은 책의 내용이다. May be outdated.
|
|
|
|
```
|
|
$ etcdctl ls /registry
|
|
/registry/configmaps
|
|
/registry/daemonsets
|
|
/registry/deployments
|
|
/registry/events
|
|
/registry/namespaces
|
|
/registry/pods
|
|
...
|
|
```
|
|
|
|
각 리소스 별로 저장되어 있음을 알 수 있다. 만약 pod 의 정보를 보고 싶다면
|
|
|
|
```
|
|
$ etcdctl ls /registry/pods
|
|
/registry/pods/default
|
|
/registry/pods/kube-system
|
|
```
|
|
|
|
Namespace 별로 구분이 되어있는 것을 확인할 수 있고, 더욱 자세히 확인하면
|
|
|
|
```
|
|
$ etcdctl ls /registry/pods/default
|
|
/registry/pods/default/kubia-159041347-xk0vc
|
|
/registry/pods/default/kubia-159041347-wt6ga
|
|
/registry/pods/default/kubia-159041347-hp2o5
|
|
```
|
|
|
|
Pod 마다 key 가 하나씩 존재하고 있음을 알 수 있다. Value 를 가져와 보면 pod definition 이 JSON 형태로 저장되어 있는 것을 확인할 수 있다.
|
|
|
|
#### Consistency and validity of stored objects
|
|
|
|
Kubernetes 에서는 다른 Control Plane 컴포넌트들이 무조건 API server 를 거쳐서 etcd 와 통신하기 때문에, optimistic locking 을 이용하여 항상 consistent 한 업데이트를 할 수 있게 된다. 또한 API server 가 validation 을 해주기 때문에 etcd 에 저장되는 정보는 항상 valid 하며, 업데이트 요청이 인증된 클라이언트로부터만 이뤄지도록 하고 있다.
|
|
|
|
#### Consistency when etcd is clustered
|
|
|
|
HA 를 위해 etcd 가 여러 개인 경우, 동기화가 이뤄져야 한다. etcd 에서는 RAFT 알고리즘을 사용하여 etcd 간의 상태를 동기화한다. 그래서 항상 노드의 상태는 다수의 노드가 동의한 현재 상태이거나, 과거에 동의했던 상태가 된다.
|
|
|
|
이 알고리즘은 consensus 알고리즘이기 때문에 '다수'가 동의해야 다음 상태로 나아갈 수 있게 된다. 그래서 만약 클러스터가 분리되어 두 그룹이 생긴다고 해도, 둘 중 한 그룹에는 분명 '다수'의 노드가 포함되어 있을 것이므로 해당 그룹만 상태를 변경할 수 있고, 다른 그룹은 상태를 변경할 수 없게 된다. 즉, 각 그룹의 상태는 diverge 할 수 없다.
|
|
|
|
나중에 클러스터가 다시 합쳐지게 되면 '다수'가 아니었던 노드들은 '다수'의 노드 상태를 확인하고 그에 맞게 자신의 상태를 변경하면 된다.
|
|
|
|
따라서 etcd 인스턴스의 개수는 홀수개로 정하는 것이 좋다!
|
|
|
|
### 11.1.3 What the API server does
|
|
|
|
API server 는 기본적인 CRUD interface 를 제공하여 RESTful API 로 클러스터 상태를 조회하거나 수정할 수 있도록 한다. 그리고 그 정보를 etcd 에 저장하며, 저장할 때 validation 을 수행하여 잘못된 데이터가 저장되지 않도록 한다. 또한 optimistic locking 을 이용해 동시성도 관리하고 있다.
|
|
|
|
`kubectl` 을 사용하게 되면 요청이 API server 로 오게 되는데, 이 과정을 상세하게 살펴본다.
|
|
|
|
우선 `kubectl` 을 이용해 리소스를 생성하게 되면 HTTP POST 요청이 API server 에 가게 된다.
|
|
|
|
#### Authenticating the client with authentication plugins
|
|
|
|
API server 입장에서는, 요청을 보낸 사람이 누구인지 먼저 확인할 필요가 있다. 내부에 authentication plugin 이 존재하므로, 이 plugin 을 사용해서 누가 요청을 보낸 것인지 판단한다. (HTTP 요청을 분석하는 것)
|
|
|
|
#### Authorizing the client with authorization plugins
|
|
|
|
요청을 어떤 사용자가 보냈는지 판단했다면, 해당 사용자가 요청의 내용을 실제로 수행할 수 있는지 확인한다. 이 때는 authorization plugin 을 사용하게 된다.
|
|
|
|
#### Validating and/or modifying the resource in the request with admission control plugins
|
|
|
|
요청이 리소스 생성/수정/삭제라면, Admission Control 로 요청이 전달된다. 이 또한 plugin 을 사용하게 되는데, 요청의 리소스 spec 에서 누락된 field 값을 채워주거나 (기본값으로 설정하거나) 다른 관련된 리소스의 값을 수정하기도 하며, 요청을 기각할 수도 있다.
|
|
|
|
> 리소스 읽기는 Admission Control 에 전달되지 않는다!
|
|
|
|
> Docs: https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
|
|
|
|
#### Validating the resource and storing it persistently
|
|
|
|
위 과정을 모두 거친 뒤에는 validation 을 수행하고 etcd 에 저장하여 클라이언트에게 응답을 돌려준다.
|
|
|
|
### 11.1.4 Understanding how the API server notifies clients of resource changes
|
|
|
|
Controller Manager 의 경우 ReplicaSet 을 관리하거나 service 의 endpoint 를 관리해야 하는데, 이를 위해서는 리소스의 정보가 필요하고, 리소스가 변경되었다면 변경 사실을 알 수 있어야 한다.
|
|
|
|
그래서 API server 는 리소스 변경사항을 다른 컴포넌트가 확인할 수 있도록 해준다. Control Plane 의 컴포넌트들은 리소스가 생성/수정/삭제될 때 알림을 받도록 요청할 수 있다. 이를 통해 다른 컴포넌트들은 클러스터 상태 변경에 대응할 수 있게 되는 것이다.
|
|
|
|
클라이언트(변경사항을 지켜보는 다른 컴포넌트)는 API server 에 HTTP 연결을 하게 된다. 이 연결을 통해 요청한 리소스의 수정 내역이 전달된다. 그래서 리소스 변경이 일어나면, 이 리소스의 변경 내역을 요청한 (watch 하고 있는) 모든 클라이언트에게 수정 내역이 전달된다.
|
|
|
|
### 11.1.5 Understanding the Scheduler
|
|
|
|
Scheduler 의 동작은 비교적 간단한 편이다. API server 의 watch 를 이용해 새로운 pod 가 생기면 pod 가 띄워질 노드를 하나 골라주면 된다.
|
|
|
|
Scheduler 는 노드에게 pod 를 띄우라고 절대 알려주지 않는다. Scheduler 가 하는 일은 API server 에 요청을 보내 pod definition 을 수정하는 것이다. 그러면 해당 노드의 Kubelet 이 watch 를 이용해 보고있다가 pod 가 schedule 되었음을 알게 되는 것이다. 이제 Kubelet 은 띄워야 할 pod 가 생긴 것이므로 pod 를 실행하게 된다.
|
|
|
|
큰 그림은 간단하지만, 노드를 고르는 일은 생각보다 복잡하다.
|
|
|
|
#### Default scheduling algorithm
|
|
|
|
- Scheduling 이 가능한 노드(acceptable nodes)의 리스트를 만든다.
|
|
- 만든 리스트의 노드들 중에서 가장 적합한 노드를 고르고, 만약 가장 적합한 노드가 여러 개라면, round-robin 을 이용하여 균등하게 scheduling 되도록 한다.
|
|
|
|
#### Finding acceptable nodes
|
|
|
|
Acceptable 인지 아닌지 판단하기 위해서는 미리 정의된 조건들을 확인한다. 몇 가지만 살펴보면..
|
|
|
|
- Pod 가 요구하는 하드웨어 리소스가 노드에 충분한가?
|
|
- 노드에 리소스가 거의 바닥나지는 않았는지?
|
|
- Pod 에서 특정한 노드로의 scheduling 을 요청하지는 않았는지?
|
|
- Node selector label 이 맞는지?
|
|
- Pod 가 특정 포트로 요청을 받는다면 해당 포트가 노드에서 이미 bind 되어 있지는 않은지?
|
|
- Pod 가 요구하는 volume 이 이 노드에서 mount 될 수 있는지?
|
|
- Pod 에 node affinity/anti-affinity 설정이 있는지?
|
|
|
|
이러한 조건들을 모두 만족해야 acceptable node 가 된다.
|
|
|
|
#### Selecting the best node for the pod
|
|
|
|
위에서 다양한 조건으로 검사를 했지만, 그럼에도 불구하고 어떤 노드는 더 나은 선택일 수도 있다. 2-노드 클러스터가 있다고 하면, 둘다 acceptable 인데 한 노드가 10개의 pod 를 이미 실행하고 있는 반면 나머지 하나는 실행 중인 pod 가 없다고 하자. 그러면 자연스럽게 실행 중인 pod 가 없는 쪽으로 scheduling 을 할 것이다.
|
|
|
|
하지만 클라우드에서 실행하는 경우라면, 그냥 10개 pod 를 실행 중인 노드에 scheduling 하고 나머지 node 는 없애서 cloud provider 에게 메모리를 돌려주는 것이 나을 수도 있다.
|
|
|
|
#### Multiple schedulers
|
|
|
|
여러 개의 scheduler 를 사용할 수도 있으며, `schedulerName` field 를 사용해 어떤 scheduler 를 사용할지 정할 수 있다.
|
|
|
|
### 11.1.6 Introducing the controllers running in the Controller Manager
|
|
|
|
앞에서 언급한 것처럼 API server 는 etcd 에 저장하고 클라이언트에게 알리며, scheduler 는 노드를 선택하기만 하기 때문에, 변경 사항이 생겼을 때 실제로 변경된 클러스터 상태에 다가가도록 일할 컴포넌트가 필요하다. 이 일은 Controller Manager 안의 controller 들이 수행한다.
|
|
|
|
Controller 종류는 거의 모든 리소스 별로 하나씩 있는 느낌이다.
|
|
|
|
- Replication Manager (ReplicationController)
|
|
- ReplicaSet, DaemonSet, Job controllers
|
|
- Deployment, StatefulSet controllers
|
|
- Node controller
|
|
- Service, Endpoints controller
|
|
- Namespace controller
|
|
- PersistentVolume controller
|
|
- Others
|
|
|
|
즉 리소스는 클러스터 내부에서 돌아가야 하는 것들의 정보/명세이며 controller 는 그 정보를 바탕으로 실제로 실행하는 역할을 한다고 생각하면 된다.
|
|
|
|
#### Understanding what controllers do and how they do it
|
|
|
|
결국에는 API server 를 watch 하고 있다가 변경 내역이 생기면 일을 한다고 생각하면 된다. Controller 들은 서로의 존재를 모르며 각자 API server 와 통신할 뿐이다.
|
|
|
|
추가로 controller 들은 reconciliation loop 을 사용하여 목표 상태와 현재 상태를 비교한다. 또 `status` 에 현재 상태를 기록하며, API server 의 watch 기능이 모든 변경 이벤트를 준다는 보장은 없으므로 주기적으로 re-list operation 을 수행하여 놓친 변경 내역이 없는지 확인한다.
|
|
|
|
#### Replication Manager
|
|
|
|
ReplicationController 를 관리한다.
|
|
|
|
API server 에 ReplicationController 리소스를 watch 하고 있으며, replica count 에 변경 사항이 생기면 알림을 받게 된다. 또한 pod 리소스도 watch 하고 있어서 실제로 몇 개의 replica 가 실행 중인지 확인할 수 있다.
|
|
|
|
만약 replica count 와 실제 replica 수가 다르다면, POST/DELETE 요청을 API server 에게 보내서 pod 를 생성/삭제하도록 한다. 실제 생성과 삭제는 Scheduler 와 노드의 Kubelet 이 담당하게 된다.
|
|
|
|
#### ReplicaSet, DaemonSet, Job controllers
|
|
|
|
ReplicaSet 의 경우 Replication Manager 와 비슷하다.
|
|
|
|
한편 DaemonSet 과 Job controller 는 비슷한데, 자신들이 watch 하고 있는 리소스의 pod template 를 참고하여 API server 에게 pod 생성 요청을 보낸다. 마찬가지로 실제 pod 생성은 Kubelet 이 하게 된다.
|
|
|
|
#### Deployment controller
|
|
|
|
실행 중인 Deployment 의 상태가 리소스 정보와 동일하도록 계속 동기화하는 역할을 담당한다.
|
|
|
|
Deployment 리소스의 정보가 수정될 때마다 controller 는 새 버전을 rollout 을 하게 되는데, 이는 ReplicaSet 을 이용해서 한다. 그리고 deployment strategy 에 따라 각 ReplicaSet 의 replica 수를 적절히 조절하여 모든 pod 이 새로운 pod 로 교체되도록 한다.
|
|
|
|
9장에서 언급했듯이 Deployment 가 pod 를 직접 만들지 않는다.
|
|
|
|
#### StatefulSet Controller
|
|
|
|
(Deployment 에 state 가 추가된 것이니...) ReplicaSet controller 와 유사하다. 하지만 ReplicaSet controller 는 pod 만 관리하는 반면 StatefulSet controller 는 pod 의 PVC 까지 같이 관리하게 된다.
|
|
|
|
#### Node controller
|
|
|
|
클러스터의 worker node 정보를 담고있는 Node 리소스를 관리한다. 또한 노드의 health 를 확인하고 도달할 수 없는 (unreachable) 노드의 pod 는 제거한다.
|
|
|
|
#### Service controller
|
|
|
|
`LoadBalancer` service 를 관리하는 controller 이다.
|
|
|
|
#### Endpoints controller
|
|
|
|
Service object 들은 endpoints 를 확인하여 요청을 분산하는데, 이 endpoint 를 관리한다. Service 를 watch 하고 있고, label selector 에 맞는 pod 들을 watch 하고 있다가 pod 가 `READY` 상태가 되면 Endpoints 리소스에 pod 의 IP 와 포트를 추가한다.
|
|
|
|
Endpoints 는 standalone object 이므로 controller 가 직접 생성하고 삭제한다.
|
|
|
|
#### Namespace controller
|
|
|
|
Namespace 가 삭제될 때, 해당 namespace 안의 모든 리소스를 삭제하는 역할을 담당한다.
|
|
|
|
#### PersistentVolume controller
|
|
|
|
사용자가 PVC 를 생성했을 때, 적절한 PV 를 찾아 bind 해주는 역할을 담당한다.
|
|
|
|
PVC 가 생성됐을 때 access mode 를 만족하는 가장 작은 PV 를 찾아준다. 내부적으로 용량으로 정렬된 PV 목록을 가지고 있다.
|
|
|
|
### 11.1.7 What the Kubelet does
|
|
|
|
처음에 노드가 생성될 때는 API server 에 Node 리소스를 생성한다. 그리고 APi server 에 watch 하여 자신의 노드로 scheduling 된 pod 가 있으면 pod 의 컨테이너를 실행한다. Kubelet 은 실행중인 컨테이너들을 지속적으로 모니터링하여 상태와 이벤트 그리고 (하드웨어) 리소스 사용량을 API server 에 보고한다.
|
|
|
|
Liveness probe 를 실행하는 것도 Kubelet 이다. 실패하면 Kubelet 이 재시작 명령을 내린다.
|
|
|
|
#### Running static pods without the API server
|
|
|
|
일반적으로는 API server 에 pod definition 을 요청하여 pod 를 생성하겠지만, 로컬 저장소에 있는 definition 으로부터 pod 를 생성할 수도 있다. Pod manifest 를 Kubelet 의 manifest 폴더에 넣어주면 Kubelet 이 그것을 실행하고 관리해준다.
|
|
|
|
이 방식을 이용해서 Control Plane 의 컴포넌트들을 pod 형태로 실행할 수 있는 것이다.
|
|
|
|
### 11.1.8 The role of the Kubernetes service proxy
|
|
|
|
kube-proxy 는 클라이언트들이 생성된 service 에 연결될 수 있도록 해준다. Service IP 와 port 로 들어오는 요청이 service endpoints 중 하나의 pod 로 연결되도록 보장하며, 만약 endpoint 가 여러 개라면 로드 밸런싱도 해준다.
|
|
|
|
#### Why it's called a proxy
|
|
|
|
예전에는 리눅스 `iptables` 를 수정하여 kube-proxy 서버로 요청이 오도록 한 다음 처리하여 pod 에게 전달했었기 때문이다. 현재는 `iptables` 규칙을 수정하여 proxy 서버를 거치지 않고 바로 endpoint pod 중 랜덤한 하나에게 요청이 가도록 하고 있다. (packet redirection) 후자가 성능이 더 좋다.
|
|
|
|
### 11.1.9 Introducing Kubernetes add-ons
|
|
|
|
#### How add-ons are deployed
|
|
|
|
Pod 로 띄워지기도 하고 Deployment 나 ReplicationController 로 띄워지기도 한다. 결국 YAML 파일을 API server 에 POST 하는 점은 동일하다.
|
|
|
|
> `minikube` 에서는 Ingress controller 와 coredns 가 deployment 로 띄워져있는 것을 확인했다.
|
|
|
|
#### How the DNS server works
|
|
|
|
DNS server pod 는 `kube-dns` service 를 통해 expose 되어 있으며, service 의 IP 주소는 pod 의 모든 컨테이너 내부의 `/etc/resolv.conf` 파일 안에 `nameserver` 로 들어가 있다.
|
|
|
|
`kube-dns` pod 는 Service 와 Endpoints 리소스를 watch 하고 있어서 변경 사항이 생기면 DNS record 를 업데이트한다. 이 업데이트에는 약간의 지연이 있을 수 있다.
|
|
|
|
#### How (most) Ingress controllers work
|
|
|
|
구현체마다 조금씩 다를 수 있지만 대부분 reverse proxy server 를 둔다. 그리고 reverse proxy server 의 세팅을 Ingress, Service, Endpoints 에 맞게 해준다. (API server 의 watch 기능 이용)
|
|
|
|
Ingress 를 사용하게 되면 service 를 거치지 않고 endpoint 로 바로 요청이 전달되는 것도 이 때문이다. 더불어 client IP 가 유지되는 장점도 있다.
|
|
|
|
### 11.1.10 Bringing it all together
|
|
|
|
Kubernetes 시스템이 각 역할과 책임을 가진 개별적인 컴포턴트들로 잘 분리되어있음을 알게 되었다.
|
|
|
|
사용자가 정의한 목표 상태에 클러스터가 도달할 수 있도록 컴포넌트들이 협동한다.
|
|
|
|
## 11.2 How controllers cooperate
|
|
|
|
---
|
|
|
|
Pod 를 생성할 때 어떤 일이 일어나는지 자세히 살펴본다. Pod 를 직접 생성하는 경우는 잘 없으므로, Deployment 를 생성하는 경우를 살펴볼 것이다.
|
|
|
|
### 11.2.1 Understanding which components are involved
|
|
|
|
시작하기 전, controllers, Scheduler, Kubelet 이 API server 를 watch 하고 있다는 사실을 기억해야 한다.
|
|
|
|
### 11.2.2 The chain of events
|
|
|
|
`kubectl` 을 이용해서 Deployment 를 생성하게 되면, Kubernetes API server 는 POST 요청을 받게 된다.
|
|
|
|
API server 는 spec 을 validation 하고, etcd 에 저장하며, `kubectl` 에 응답을 돌려준다.
|
|
|
|
그 다음부터는 연쇄적으로 반응이 일어난다.
|
|
|
|
#### Deployment controller creates the ReplicaSet
|
|
|
|
Deployment 리소스를 watch 하고 있던 모든 클라이언트들은 새롭게 생성된 deployment 에 대해 알게 된다. 이 클라이언트 중에 Deployment controller 가 있으므로, controller 는 새로운 deployment 를 감지하고 현재 specification 에 맞는 ReplicaSet 을 생성한다. 이 또한 API server 에 요청하는 것이다.
|
|
|
|
#### ReplicaSet controller creates the pod resources
|
|
|
|
ReplicaSet controller 가 새로운 ReplicaSet 을 감지하고, pod selector 의 값을 이용해서 replica count 와 같은 pod 개수가 존재하고 있는지 확인한다.
|
|
|
|
(새로 생성하면 당연히 개수가 부족하므로) 이제 controller 는 ReplicaSet spec 의 pod template 을 참고하여 API server 에 pod 생성을 요청한다.
|
|
|
|
#### Scheduler assigns a node to the newly created pods
|
|
|
|
새롭게 생성된 pod 는 etcd 에 저장되어 있지만 아직 노드가 결정되지 않은 상태라 `nodeName` field 가 없다. Scheduler 는 이렇게 `nodeName` field 가 없는 pod 들을 watch 하고 있다가 발견하면 scheduling 을 해준다. 이제 pod 정보에 `nodeName` 이 존재하게 된다.
|
|
|
|
여기까지는 Control Plane 에서 일어나는 일이다. Controller 들은 단지 API server 와 통신하여 리소스를 업데이트하기만 했다.
|
|
|
|
#### Kubelet runs the pod's containers
|
|
|
|
이제 worker node 들의 차례이다. Kubelet 은 자신의 노드에 schedule 된 pod 를 watch 하고 있으므로 pod definition 을 가져와 Docker (혹은 container runtime) 에게 특정 이미지를 기반으로 컨테이너를 실행하라고 명령한다. 이제 container runtime 이 컨테이너를 실행하게 된다.
|
|
|
|
### 11.2.3 Observing cluster events
|
|
|
|
위 작업이 수행되는 과정에서 Control Plane 컴포넌트와 Kubelet 은 API server 에 event 가 발생했다고 알려준다. Event 리소스를 생성하여 알려주며, 이는 `kubectl get events` 로 확인할 수 있다.
|
|
|
|
> 참고로 `kubectl describe` 하면 밑에 event 가 나왔었다.
|
|
|
|
명령어를 입력해 보면 `SOURCE` 에 어떤 컴포넌트/controller 가 event 를 발생시켰는지, `KIND`, `NAME` 에서 event 가 영향을 미친 리소스의 종류와 이름을 확인할 수 있다. `REASON` 과 `MESSAGE` 에서는 상세한 설명을 확인할 수 있게 된다.
|
|
|
|
## 11.3 Understanding what a running pod is
|
|
|
|
---
|
|
|
|
Pod 를 실행했으므로, *실행중인 pod* 가 무엇인지 살펴보자. Kubelet 이 컨테이너를 실행하는 것은 알았는데, 더 할 일이 있을까?
|
|
|
|
Pod 를 실행한 뒤, *노드*에 `ssh` 연결하여 `docker ps` 를 입력해 보면 `COMMAND` 가 `/pause` 인 컨테이너가 하나 있는데, 이 컨테이너가 한 pod 내의 컨테이너를 하나로 묶는 역할을 해준다.
|
|
|
|
Pod 내의 컨테이너는 linux namespace 와 네트워크를 공유하기 때문에, `/pause` 컨테이너는 이 linux namespace 를 붙잡고 있는 infrastructure 컨테이너인 것이다.
|
|
|
|
Pod 내의 컨테이너는 재시작 되는 경우가 많다. 이 때 같은 linux namespace 로 재시작 되어야 하는데, 위와 같이 infrastructure 컨테이너가 존재하기 때문에 같은 linux namespace 를 사용할 수 있게 된다. 이 infrastructure 컨테이너는 pod 와 lifecycle 이 같기 때문에 pod 가 삭제될 때 같이 지워진다. 만약 infrastructure 컨테이너를 삭제하면 Kubelet 이 다시 만들어 주고, pod 의 컨테이너도 전부 다시 만든다.
|
|
|
|
## 11.4 Inter-pod networking
|
|
|
|
---
|
|
|
|
Pod 들은 고유 IP 를 가지며, NAT 없이 flat network 구조를 갖는다. 작동 원리를 살펴본다.
|
|
|
|
### 11.4.1 What the network must be like
|
|
|
|
Kubernetes 는 특정 네트워크 기술을 요구하지는 않지만, 컨테이너들끼리는 어떤 노드에 있을지라도 서로 통신이 가능해야 한다.
|
|
|
|
또한 통신에 사용하는 IP 는 NAT 가 적용되지 않아서, 어디서 바라보더라도 자신의 IP 가 동일해야 한다. 이렇게 되야 하는 이유는 마치 같은 네트워크에 연결된 머신에서 동작하는 것처럼 보이고 또 간단해지기 때문이다.
|
|
|
|
이러한 요구사항을 만족하는 네트워크 기술은 많지만 구현체마다 다르고 상황에 따라 장단점이 다르기 때문에, 일반적인 방법에 대해 다룰 것이다.
|
|
|
|
### 11.4.2 Diving deeper into how networking works
|
|
|
|
Infrastructure 컨테이너에 IP 주소와 network namespace 가 설정된다는 것을 11.3 에서 확인했다. Pod 의 컨테이너는 해당 network namespace 를 사용하게 된다.
|
|
|
|
#### Enabling communication between pods on the same node
|
|
|
|
Infrastructure 컨테이너가 시작되기 전에 virtual Ethernet (veth) 인터페이스 pair 가 컨테이너에 생성된다. 한쪽은 노드의 namespace 에 남아있고, 다른 쪽은 컨테이너 안의 namespace 가 되어 `eth0` 으로 이름이 변경된다.
|
|
|
|
이제 노드의 namespace 에 남아있는 인터페이스는 container runtime 이 사용하는 network bridge 에 연결된다. 이제 `eth0` 인터페이스는 bridge 의 IP 대역 중 하나를 할당받아 IP 로 사용하게 된다.
|
|
|
|
컨테이너 내부에서 요청이 나가는 경우 `eth0` -> `vethXXX` -> Bridge 의 순서로 가게 된다.
|
|
|
|
만약 이 요청의 destination 이 노드 내의 다른 pod 라면 Bridge -> `vethYYY` -> `eth0` 의 경로로 다른 pod 에 요청이 전달된다.
|
|
|
|
#### Enabling communication between pods on different nodes
|
|
|
|
다른 노드의 pod 와 통신하는 방법은 다양하지만, layer 3 routing 방법을 살펴볼 것이다.
|
|
|
|
우선 Pod IP 는 클러스터 내에서 유일해야 하므로, 노드의 network bridge 에 할당된 IP 대역은 서로 겹치지 않아야 한다.
|
|
|
|
각 노드에 layer 3 networking 을 적용하여 노드의 physical network interface 가 bridge 에 연결되도록 해주면 된다. 그리고 각 노드에서 routing table 을 설정해주면 된다.
|
|
|
|
이제 다른 노드로 통신하려는 경우 패킷의 이동 경로는 `eth0` -> `vethXXX` -> Bridge -> Node's physical adapter -> Network Wire -> Other node's physical adapter -> Bridge -> `vethYYY` -> `eth0` 가 된다.
|
|
|
|
이 방법은 물론 노드가 같은 네트워크 스위치에 연결된 경우, 사이에 라우터가 없을 때만 유효하다. 물론 라우터를 사용하여 노드 사이에 오고가는 패킷을 routing 할 수 있겠지만, 노드 개수가 많아지거나 노드 사이의 라우터 개수가 많아지면 어렵고 오류가 발생하기 쉽다. 이러한 이유로 Software Defined Network (SDN) 을 사용하는 것이 편하다.
|
|
|
|
SDN 을 사용하게 되면 노드들이 같은 네트워크 스위치에 연결된 것처럼 보이게 되며, pod 에서 나가는 패킷은 캡슐화되어서 다른 pod 에 전달되고 un-캡슐화된다.
|
|
|
|
### 11.4.3 Introducing the Container Network Interface
|
|
|
|
컨테이너가 네트워크에 연결하는 것을 쉽게 하기 위해 Container Network Interface (CNI) 프로젝트가 시작되었다. Kubernetes 에서 해당 CNI 플러그인을 사용하도록 할 수 있다.
|
|
|
|
종류에는 Calico, Flannel, Romana, Weave Net 등이 있다.
|
|
|
|
플러그인 설치는DaemonSet 과 기타 리소스를 포함한 YAML 파일을 생성하면 된다. 참고로 Kubelet 실행시 `--network-plugin=cni` 로 옵션을 줘야 한다.
|
|
|
|
## 11.5 How services are implemented
|
|
|
|
---
|
|
|
|
복습!
|
|
|
|
- 각 service 는 stable IP 주소와 포트를 갖고, 클라이언트는 이 주소로 연결하여 service 를 사용한다.
|
|
- IP 주소는 가상 IP 주소로, 네트워크 인터페이스에 할당되어있지 않고, 노드 밖으로 나가는 패킷에 source/destination IP 로 들어가지 않는다.
|
|
|
|
### 11.5.1 Introducing the kube-proxy
|
|
|
|
Service 와 관련된 모든 것들은 각 노드에서 실행중인 kube-proxy 프로세스에 의해 관리된다.
|
|
|
|
예전에는 `userspace` proxy mode 를 통해 진짜 pod 로 연결을 proxy 해주는 역할을 했으나, 현재는 `iptables` 를 사용하고 있다.
|
|
|
|
### 11.5.2 How kube-proxy uses iptables
|
|
|
|
API server 가 service 생성 요청을 받으면, service 에 가상 IP 주소가 바로 할당된다. 그 다음, API server 는 worker node 의 kube-proxy 에게 새로운 service 가 생성됐음을 알린다. 그 다음 kube-proxy 는 해당 service 가 참조 가능하도록 자신의 노드의 `iptables` 규칙을 수정한다.
|
|
|
|
`iptables` 규칙을 수정하게 되면 service 를 목적지로 갖는 패킷을 가로채 목적지 주소가 변경되고 endpoint 중 한 곳으로 패킷이 연결된다.
|
|
|
|
kube-proxy 는 service 의 변화만 watch 하고 있는 것은 아니고, Endpoints 의 변화도 지켜보고 있다. 그래서 pod 가 생성/삭제되거나 readiness 상태가 바뀌거나 label 이 수정되었는지 확인한다.
|
|
|
|
#### 예시
|
|
|
|
예를 들어, pod A 에서 172.30.0.1:80 에 있는 service 로 패킷을 보낸다고 하면, 패킷의 목적지 주소는 172.30.0.1:80 일 것이다. 네트워크로 패킷이 보내지기 전에, 노드의 `iptables` 규칙을 먼저 적용하게 된다.
|
|
|
|
규칙 중에서 적용할 규칙이 있는지 확인하게 되는데, service 가 생성된 상태이므로 '목적지가 172.30.0.1:80 인 패킷의 목적지는 임의로 선택된 pod 의 IP 로 교체되어야 한다'는 규칙이 있을 것이다.
|
|
|
|
그러므로 이 패킷의 목적지는 service 의 endpoint 중 한 pod 의 주소와 포트로 변경된다. 이때부터는 마치 클라이언트에서 선택된 pod 로 직접 (directly) 요청을 보낸 것처럼 보이게 된다.
|
|
|
|
## 11.6 Running highly available clusters
|
|
|
|
---
|
|
|
|
Kubernetes 를 사용하는 이유 중 하나로 인프라에 문제가 생겨도 중단 없이 서비스를 유지할 수 있다는 점이 있다. 중단 없이 서비스를 유지하기 위해서는 앱이 계속 실행되고 있어야 하기도 하지만, 노드에 있는 Control Plane 컴포넌트들이 잘 작동해 줘야 한다. 고가용성 (HA) 를 달성하기 위해 어떤 것들이 관련되어 있는지 살펴볼 것이다.
|
|
|
|
### 11.6.1 Making your apps highly available
|
|
|
|
노드에 문제가 생기더라도 Kubernetes 의 다양한 controller 덕분에 우리의 애플리케이션은 안정적으로 돌아갈 수 있게 된다. 애플리케이션의 HA 를 위해서는 Deployment 를 사용해서 충분한 replica 수를 정해주면, 나머지는 Kubernetes 가 알아서 해줄 것이다.
|
|
|
|
#### Running multiple instances to reduce the likelihood of downtime
|
|
|
|
당연히 여러 인스턴스를 만들어두면 downtime 이 줄어들 것이다. 물론 애플리케이션이 horizontally scalable 해야한다는 조건이 있다. 만약 scalable 하지 않더라도 Deployment 를 이용해 replica count 를 1로 설정해서 배포하는 것이 좋다. 문제가 생겼을 때 어쩔 수 없이 약간의 지연이 있긴 하겠지만 알아서 생성해주긴 할 것이다.
|
|
|
|
#### Using leader-election for non-horizontally scalable apps
|
|
|
|
Downtime 을 회피하기 위해서는 비활성 상태의 replica 를 몇 개 더 만들어두고, leader-election 방법을 이용해 replica 들 중 반드시 하나만 작동하도록 해주면 된다.
|
|
|
|
만약 나머지도 전부 동작한다면, 하나의 replica 만 write 가 가능하고 나머지는 read 만 가능하게 해도 괜찮을 것이다. 중요한 것은 인스턴스끼리 동기화 문제가 발생하지 않도록 하면 된다는 점이다.
|
|
|
|
그리고 이 leader-election 을 애플리케이션에 구현할 필요는 없고, sidecar 컨테이너에 담을 수 있도록 이미 구현체가 존재한다.
|
|
|
|
### 11.6.2 Making Kubernetes Control Plane components highly available
|
|
|
|
만약 Kubernetes 에 문제가 생기면 진짜 답이 없어지는데, 이런 경우를 위해서는 Control Plane 컴포넌트들에 HA 를 달성해야 한다. 이를 위해서는 마스터 노드를 여러개 띄워야 하는데, 각 노드들은 API server, etcd, Controller Manager, Scheduler 를 각각 가지고 있어야 한다.
|
|
|
|
#### Running an etcd cluster
|
|
|
|
etcd 는 애초에 분산 시스템을 위해 설계되었기 때문에 여러 개의 etcd 를 띄워도 괜찮다. 홀수 개의 etcd 만 유지하고, 각 etcd 인스턴스가 다른 노드에 있는 etcd 인스턴스의 존재를 알고 있으면 된다. 이는 각 인스턴스의 설정에 다른 인스턴스들의 리스트를 넘겨줘서 설정한다. (다른 etcd 의 IP/포트 정보를 넘겨준다)
|
|
|
|
etcd 는 앞에서 설명한 RAFT 로 데이터를 모든 인스턴스에 복제할 것이기 때문에, 인스턴스 몇 개에 문제가 생겨도 괜찮다. HA 를 위해서는 5~7개의 etcd 를 띄워서 2~3개 정도의 etcd failure 를 감당할 수 있도록 하면 된다.
|
|
|
|
#### Running multiple instances of the API server
|
|
|
|
API server 를 복제하는 것은 더 쉽다! API server 는 거의 stateless 하다. 물론 약간의 caching 이 있지만 데이터는 전부 etcd 에 저장되기 때문에 여러 인스턴스를 띄울 수 있게 된다. 인스턴스끼리 서로의 존재를 알 필요도 없다.
|
|
|
|
다만 API server 의 앞단에 로드 밸런서를 두어 API server 중 healthy 한 쪽으로만 클라이언트의 요청이 가도록 조절할 필요가 있다.
|
|
|
|
#### Ensuring high availability of the controllers and the Scheduler
|
|
|
|
얘네 둘은 간단하지 않다. Controller 와 Scheduler 는 클러스터의 상태를 계속 모니터링하고 상태가 변할 때 일하기 때문에 클러스터 상태가 변한 것을 감지한 다수의 controller 가 한꺼번에 반응하게 될 수도 있다. (예를 들면 replica count 가 변경된 것을 보고 5개의 controller 가 한꺼번에 pod 생성 요청을 보내면 pod 가 5개 추가될 것이다)
|
|
|
|
위와 같은 이유로 controller 와 Scheduler 는 한 번에 한 인스턴스씩 일을 할수 있도록 이미 설계되어 있다. 내부적으로 leader-election 알고리즘을 가지고 있어서, 자신이 leader 일 때만 작업을 수행한다. 나머지 인스턴스들은 leader 에게 문제가 생길 때까지 가만히 있는다.
|
|
|
|
#### Understanding the leader election mechanism used in Control Plane components
|
|
|
|
여기서 흥미로운 점은 leader election 을 위해 컴포넌트들이 서로 통신하지 않아도 된다는 점이다. Leader election 의 동작 과정을 보면 API server 에 Endpoints 리소스를 만들어서 한다. (저자는 Endpoints 리소스를 그렇게 쓰는거 아니라는 의미에서 *abused* 라고 표현했다. 다른 리소스를 사용했어도 괜찮았을 것이라고 한다.)
|
|
|
|
`kube-scheduler` 라는 이름을 가진 Endpoints 리소스를 확인해 보면 annotation 으로 `control-plane.alpha.kubernetes.io/leader` 를 가지고 있는 것을 확인할 수 있다. 여기에 `holderIdentity` 라는 필드가 있는데, 여기에 현재 leader 의 이름이 들어간다.
|
|
|
|
Optimistic locking 때문에 여러 개의 Scheduler 가 자신을 `holderIdentity` 에 넣으려고 하겠지만, 오직 한 인스턴스만 성공하며, 그 인스턴스가 leader 가 된다. 또한 자신이 계속 살아있음을 증명해야 하기 때문에 주기적으로(2초마다) 이 Endpoints 리소스를 업데이트하여 다른 Scheduler 에게 알린다. Leader 가 실패했음을 알게된다면 다른 인스턴스들은 모두 자신의 이름을 `holderIdentity` 에 넣고 leader 가 되기 위해 또다시 경쟁한다.
|
|
|
|
---
|
|
|
|
## Discussion & Additional Topics
|
|
|
|
### RAFT
|
|
|
|
- https://en.wikipedia.org/wiki/Raft_(algorithm)
|
|
- https://raft.github.io/
|
|
|
|
### Authentication vs Authorization
|
|
|
|
### Leader Election Algorithm
|
|
|
|
- https://en.wikipedia.org/wiki/Leader_election
|