컨트롤러

컨트롤러 (Controllers)

로보틱스와 자동화에서 *제어 루프(control loop)*는 시스템의 상태를 조절하는 끝나지 않는 루프예요.

제어 루프의 예를 하나 들어볼게요: 방 안의 온도 조절기(thermostat).

온도를 설정하면 그게 온도 조절기에게 *원하는 상태(desired state)*를 알려주는 거예요. 실제 방 온도는 *현재 상태(current state)*입니다. 온도 조절기는 장비를 켜거나 꺼서 현재 상태를 원하는 상태에 더 가깝게 만들도록 작동해요.

Kubernetes에서 컨트롤러는 클러스터의 상태를 감시하고, 필요할 때 변경을 만들거나 요청하는 제어 루프예요. 각 컨트롤러는 현재 클러스터 상태를 원하는 상태에 더 가깝게 옮기려고 노력합니다.

출처: Kubernetes 공식 문서 — Controllers

컨트롤러 패턴 (Controller pattern)

컨트롤러는 최소 한 가지 Kubernetes 리소스 유형을 추적해요. 이 객체는 원하는 상태를 나타내는 spec 필드를 가지고 있어요. 그 리소스에 대한 컨트롤러는 현재 상태를 그 원하는 상태에 더 가깝게 만드는 책임을 집니다.

컨트롤러가 그 행동을 스스로 수행할 수도 있지만, Kubernetes에서 더 흔한 건 컨트롤러가 유용한 부수 효과(side effects)를 가진 메시지를 API 서버로 보내는 거예요. 아래에서 그 예시를 볼 수 있어요.

API 서버를 통한 제어

Job 컨트롤러는 Kubernetes 내장 컨트롤러의 예시예요. 내장 컨트롤러는 클러스터 API 서버와 상호작용해서 상태를 관리합니다.

Job은 작업을 수행하고 멈추기 위해 Pod 하나 또는 여러 개를 실행하는 Kubernetes 리소스예요.

(스케줄링되면 Pod 객체는 kubelet의 원하는 상태의 일부가 돼요).

Job 컨트롤러는 새 작업을 보면 클러스터 어딘가의 일련의 Node에 있는 kubelet들이 작업을 완료할 만큼의 정확한 수의 Pod를 실행하고 있는지 확인해요. Job 컨트롤러는 Pod나 컨테이너를 직접 실행하지는 않아요. 대신 Job 컨트롤러는 API 서버에 Pod를 생성하거나 제거하라고 지시합니다. 컨트롤 플레인의 다른 컴포넌트가 이 새 정보(스케줄링하고 실행할 새 Pod가 있다는 정보)에 따라 행동하고, 결국 작업이 완료돼요.

새 Job을 만든 후의 원하는 상태는 그 Job이 완료되는 거예요. Job 컨트롤러는 그 Job의 현재 상태를 원하는 상태에 더 가깝게 만듭니다: 그 Job에 원했던 작업을 수행할 Pod를 생성해서 Job이 완료에 더 가까워지게 해요.

컨트롤러는 자신을 구성하는 객체도 업데이트해요. 예를 들어: Job의 작업이 완료되면 Job 컨트롤러는 그 Job 객체를 업데이트해서 Finished로 표시합니다.

(이건 일부 온도 조절기가 설정한 온도에 도달했음을 표시하려고 불을 끄는 것과 비슷해요).

직접 제어 (Direct control)

Job과는 대조적으로 일부 컨트롤러는 클러스터 밖의 것들을 변경해야 해요.

예를 들어 클러스터에 Node가 충분한지 확인하는 제어 루프를 쓴다면, 그 컨트롤러는 필요할 때 새 Node를 설정하려면 현재 클러스터 밖의 무언가가 필요해요.

외부 상태와 상호작용하는 컨트롤러는 API 서버에서 원하는 상태를 찾은 다음, 외부 시스템과 직접 통신해서 현재 상태를 가깝게 만듭니다.

(실제로 클러스터의 노드를 수평 확장하는 컨트롤러가 있어요).

여기서 중요한 점은 컨트롤러가 원하는 상태를 만들기 위해 몇 가지 변경을 수행한 다음, 현재 상태를 클러스터의 API 서버에 다시 보고한다는 거예요. 다른 제어 루프는 그 보고된 데이터를 관찰해서 자신의 행동을 취할 수 있습니다.

온도 조절기 예시에서 방이 매우 춥다면 다른 컨트롤러가 동결 방지 히터(frost protection heater)를 켤 수도 있어요. Kubernetes 클러스터에서는 컨트롤 플레인이 Kubernetes 확장을 통해 IP 주소 관리 도구, 스토리지 서비스, 클라우드 제공자 API, 기타 서비스와 간접적으로 협력해 그런 기능을 구현합니다.

원하는 상태와 현재 상태 (Desired versus current state)

Kubernetes는 시스템을 클라우드 네이티브 관점으로 바라보며, 끊임없는 변화를 처리할 수 있어요.

작업이 발생하고 제어 루프가 장애를 자동으로 고치면서 클러스터는 언제든 변할 수 있어요. 이는 잠재적으로 클러스터가 절대 안정된 상태에 도달하지 않을 수도 있다는 뜻입니다.

클러스터의 컨트롤러가 실행 중이고 유용한 변경을 만들 수 있다면, 전체 상태가 안정적이든 아니든 상관없어요.

설계 (Design)

설계의 원칙으로서 Kubernetes는 클러스터 상태의 특정 측면을 각각 관리하는 많은 컨트롤러를 사용해요. 대부분의 경우 특정 제어 루프(컨트롤러)는 한 종류의 리소스를 원하는 상태로 사용하고, 그 원하는 상태가 일어나도록 관리하는 다른 종류의 리소스를 가져요. 예를 들어 Job용 컨트롤러는 Job 객체(새 작업 발견)와 Pod 객체(Job 실행, 작업 완료 시점 확인)를 추적해요. 이 경우 Job은 다른 무언가가 만들고, Job 컨트롤러는 Pod를 만듭니다.

서로 연결된 하나의 거대한(monolithic) 제어 루프 집합보다는 단순한 컨트롤러를 쓰는 게 유용해요. 컨트롤러는 실패할 수 있으므로 Kubernetes는 그걸 허용하도록 설계되어 있어요.

참고:

같은 종류의 객체를 생성하거나 업데이트하는 컨트롤러가 여럿 있을 수 있어요. 배후에서 Kubernetes 컨트롤러는 자신이 제어하는 리소스에 연결된 리소스에만 주의를 기울이도록 보장합니다.

예를 들어 Deployment와 Job이 있을 수 있는데, 둘 다 Pod를 생성해요. Job 컨트롤러는 Deployment가 만든 Pod를 삭제하지 않아요. 컨트롤러가 그 Pod들을 구분하는 데 쓸 수 있는 정보(라벨)가 있기 때문이에요.

컨트롤러 실행 방법 (Ways of running controllers)

Kubernetes는 kube-controller-manager 안에서 실행되는 내장 컨트롤러 집합을 제공해요. 이 내장 컨트롤러들은 중요한 핵심 동작을 제공합니다.

Deployment 컨트롤러와 Job 컨트롤러는 Kubernetes 자체에 포함된("내장" 컨트롤러) 컨트롤러의 예시예요. Kubernetes는 탄력적인(resilient) 컨트롤 플레인을 실행할 수 있게 해줘서, 내장 컨트롤러 중 하나가 실패하면 다른 부분이 그 작업을 인계받습니다.

컨트롤러는 컨트롤 플레인 밖에서 실행되어 Kubernetes를 확장할 수 있어요. 또는 원한다면 직접 새 컨트롤러를 작성할 수도 있어요. 자신만의 컨트롤러를 Pod 집합으로 실행하거나 Kubernetes 외부에서 실행할 수 있습니다. 무엇이 가장 잘 맞는지는 그 컨트롤러가 하는 일에 따라 달라져요.

다음으로 볼 것 (What's next)

더 알아보기 (Learn more)