이 섹션의 다중 페이지 출력 화면임. 여기를 클릭하여 프린트.
개요
- 1: 쿠버네티스란 무엇인가?
- 2: 쿠버네티스 컴포넌트
- 3: 쿠버네티스 API
- 4: 쿠버네티스 오브젝트로 작업하기
- 4.1: 쿠버네티스 오브젝트 이해하기
- 4.2: 쿠버네티스 오브젝트 관리
- 4.3: 오브젝트 이름과 ID
- 4.4: 네임스페이스
- 4.5: 레이블과 셀렉터
- 4.6: 어노테이션
- 4.7: 필드 셀렉터
- 4.8: 권장 레이블
1 - 쿠버네티스란 무엇인가?
이 페이지에서는 쿠버네티스 개요를 설명한다.
쿠버네티스는 컨테이너화된 워크로드와 서비스를 관리하기 위한 이식성이 있고, 확장가능한 오픈소스 플랫폼이다. 쿠버네티스는 선언적 구성과 자동화를 모두 용이하게 해준다. 쿠버네티스는 크고, 빠르게 성장하는 생태계를 가지고 있다. 쿠버네티스 서비스, 기술 지원 및 도구는 어디서나 쉽게 이용할 수 있다.
쿠버네티스란 명칭은 키잡이(helmsman)나 파일럿을 뜻하는 그리스어에서 유래했다. K8s라는 표기는 "K"와 "s"와 그 사이에 있는 8글자를 나타내는 약식 표기이다. 구글이 2014년에 쿠버네티스 프로젝트를 오픈소스화했다. 쿠버네티스는 프로덕션 워크로드를 대규모로 운영하는 15년 이상의 구글 경험과 커뮤니티의 최고의 아이디어와 적용 사례가 결합되어 있다.
여정 돌아보기
시간이 지나면서 쿠버네티스가 왜 유용하게 되었는지 살펴보자.
전통적인 배포 시대: 초기 조직은 애플리케이션을 물리 서버에서 실행했었다. 한 물리 서버에서 여러 애플리케이션의 리소스 한계를 정의할 방법이 없었기에, 리소스 할당의 문제가 발생했다. 예를 들어 물리 서버 하나에서 여러 애플리케이션을 실행하면, 리소스 전부를 차지하는 애플리케이션 인스턴스가 있을 수 있고, 결과적으로는 다른 애플리케이션의 성능이 저하될 수 있었다. 이에 대한 해결책은 서로 다른 여러 물리 서버에서 각 애플리케이션을 실행하는 것이 있다. 그러나 이는 리소스가 충분히 활용되지 않는다는 점에서 확장 가능하지 않았으므로, 물리 서버를 많이 유지하기 위해서 조직에게 많은 비용이 들었다.
가상화된 배포 시대: 그 해결책으로 가상화가 도입되었다. 이는 단일 물리 서버의 CPU에서 여러 가상 시스템 (VM)을 실행할 수 있게 한다. 가상화를 사용하면 VM간에 애플리케이션을 격리하고 애플리케이션의 정보를 다른 애플리케이션에서 자유롭게 액세스 할 수 없으므로, 일정 수준의 보안성을 제공할 수 있다.
가상화를 사용하면 물리 서버에서 리소스를 보다 효율적으로 활용할 수 있으며, 쉽게 애플리케이션을 추가하거나 업데이트할 수 있고 하드웨어 비용을 절감할 수 있어 더 나은 확장성을 제공한다. 가상화를 통해 일련의 물리 리소스를 폐기 가능한(disposable) 가상 머신으로 구성된 클러스터로 만들 수 있다.
각 VM은 가상화된 하드웨어 상에서 자체 운영체제를 포함한 모든 구성 요소를 실행하는 하나의 완전한 머신이다.
컨테이너 개발 시대: 컨테이너는 VM과 유사하지만 격리 속성을 완화하여 애플리케이션 간에 운영체제(OS)를 공유한다. 그러므로 컨테이너는 가볍다고 여겨진다. VM과 마찬가지로 컨테이너에는 자체 파일 시스템, CPU 점유율, 메모리, 프로세스 공간 등이 있다. 기본 인프라와의 종속성을 끊었기 때문에, 클라우드나 OS 배포본에 모두 이식할 수 있다.
컨테이너는 다음과 같은 추가적인 혜택을 제공하기 때문에 인기가 있다.
- 기민한 애플리케이션 생성과 배포: VM 이미지를 사용하는 것에 비해 컨테이너 이미지 생성이 보다 쉽고 효율적임.
- 지속적인 개발, 통합 및 배포: 안정적이고 주기적으로 컨테이너 이미지를 빌드해서 배포할 수 있고 (이미지의 불변성 덕에) 빠르고 효율적으로 롤백할 수 있다.
- 개발과 운영의 관심사 분리: 배포 시점이 아닌 빌드/릴리스 시점에 애플리케이션 컨테이너 이미지를 만들기 때문에, 애플리케이션이 인프라스트럭처에서 분리된다.
- 가시성(observability): OS 수준의 정보와 메트릭에 머무르지 않고, 애플리케이션의 헬스와 그 밖의 시그널을 볼 수 있다.
- 개발, 테스팅 및 운영 환경에 걸친 일관성: 랩탑에서도 클라우드에서와 동일하게 구동된다.
- 클라우드 및 OS 배포판 간 이식성: Ubuntu, RHEL, CoreOS, 온-프레미스, 주요 퍼블릭 클라우드와 어디에서든 구동된다.
- 애플리케이션 중심 관리: 가상 하드웨어 상에서 OS를 실행하는 수준에서 논리적인 리소스를 사용하는 OS 상에서 애플리케이션을 실행하는 수준으로 추상화 수준이 높아진다.
- 느슨하게 커플되고, 분산되고, 유연하며, 자유로운 마이크로서비스: 애플리케이션은 단일 목적의 머신에서 모놀리식 스택으로 구동되지 않고 보다 작고 독립적인 단위로 쪼개져서 동적으로 배포되고 관리될 수 있다.
- 리소스 격리: 애플리케이션 성능을 예측할 수 있다.
- 자원 사용량: 리소스 사용량: 고효율 고집적.
쿠버네티스가 왜 필요하고 무엇을 할 수 있나
컨테이너는 애플리케이션을 포장하고 실행하는 좋은 방법이다. 프로덕션 환경에서는 애플리케이션을 실행하는 컨테이너를 관리하고 가동 중지 시간이 없는지 확인해야 한다. 예를 들어 컨테이너가 다운되면 다른 컨테이너를 다시 시작해야 한다. 이 문제를 시스템에 의해 처리한다면 더 쉽지 않을까?
그것이 쿠버네티스가 필요한 이유이다! 쿠버네티스는 분산 시스템을 탄력적으로 실행하기 위한 프레임 워크를 제공한다. 애플리케이션의 확장과 장애 조치를 처리하고, 배포 패턴 등을 제공한다. 예를 들어, 쿠버네티스는 시스템의 카나리아 배포를 쉽게 관리 할 수 있다.
쿠버네티스는 다음을 제공한다.
- 서비스 디스커버리와 로드 밸런싱 쿠버네티스는 DNS 이름을 사용하거나 자체 IP 주소를 사용하여 컨테이너를 노출할 수 있다. 컨테이너에 대한 트래픽이 많으면, 쿠버네티스는 네트워크 트래픽을 로드밸런싱하고 배포하여 배포가 안정적으로 이루어질 수 있다.
- 스토리지 오케스트레이션 쿠버네티스를 사용하면 로컬 저장소, 공용 클라우드 공급자 등과 같이 원하는 저장소 시스템을 자동으로 탑재 할 수 있다.
- 자동화된 롤아웃과 롤백 쿠버네티스를 사용하여 배포된 컨테이너의 원하는 상태를 서술할 수 있으며 현재 상태를 원하는 상태로 설정한 속도에 따라 변경할 수 있다. 예를 들어 쿠버네티스를 자동화해서 배포용 새 컨테이너를 만들고, 기존 컨테이너를 제거하고, 모든 리소스를 새 컨테이너에 적용할 수 있다.
- 자동화된 빈 패킹(bin packing) 컨테이너화된 작업을 실행하는데 사용할 수 있는 쿠버네티스 클러스터 노드를 제공한다. 각 컨테이너가 필요로 하는 CPU와 메모리(RAM)를 쿠버네티스에게 지시한다. 쿠버네티스는 컨테이너를 노드에 맞추어서 리소스를 가장 잘 사용할 수 있도록 해준다.
- 자동화된 복구(self-healing) 쿠버네티스는 실패한 컨테이너를 다시 시작하고, 컨테이너를 교체하며, '사용자 정의 상태 검사'에 응답하지 않는 컨테이너를 죽이고, 서비스 준비가 끝날 때까지 그러한 과정을 클라이언트에 보여주지 않는다.
- 시크릿과 구성 관리 쿠버네티스를 사용하면 암호, OAuth 토큰 및 SSH 키와 같은 중요한 정보를 저장하고 관리 할 수 있다. 컨테이너 이미지를 재구성하지 않고 스택 구성에 시크릿을 노출하지 않고도 시크릿 및 애플리케이션 구성을 배포 및 업데이트 할 수 있다.
쿠버네티스가 아닌 것
쿠버네티스는 전통적인, 모든 것이 포함된 Platform as a Service(PaaS)가 아니다. 쿠버네티스는 하드웨어 수준보다는 컨테이너 수준에서 운영되기 때문에, PaaS가 일반적으로 제공하는 배포, 스케일링, 로드 밸런싱과 같은 기능을 제공하며, 사용자가 로깅, 모니터링 및 알림 솔루션을 통합할 수 있다. 하지만, 쿠버네티스는 모놀리식(monolithic)이 아니어서, 이런 기본 솔루션이 선택적이며 추가나 제거가 용이하다. 쿠버네티스는 개발자 플랫폼을 만드는 구성 요소를 제공하지만, 필요한 경우 사용자의 선택권과 유연성을 지켜준다.
쿠버네티스는:
- 지원하는 애플리케이션의 유형을 제약하지 않는다. 쿠버네티스는 상태 유지가 필요 없는(stateless) 워크로드, 상태 유지가 필요한(stateful) 워크로드, 데이터 처리를 위한 워크로드를 포함해서 극단적으로 다양한 워크로드를 지원하는 것을 목표로 한다. 애플리케이션이 컨테이너에서 구동될 수 있다면, 쿠버네티스에서도 잘 동작할 것이다.
- 소스 코드를 배포하지 않으며 애플리케이션을 빌드하지 않는다. 지속적인 통합과 전달과 배포, 곧 CI/CD 워크플로우는 조직 문화와 취향에 따를 뿐만 아니라 기술적인 요구사항으로 결정된다.
- 애플리케이션 레벨의 서비스를 제공하지 않는다. 애플리케이션 레벨의 서비스에는 미들웨어(예, 메시지 버스), 데이터 처리 프레임워크(예, Spark), 데이터베이스(예, MySQL), 캐시 또는 클러스터 스토리지 시스템(예, Ceph) 등이 있다. 이런 컴포넌트는 쿠버네티스 상에서 구동될 수 있고, 쿠버네티스 상에서 구동 중인 애플리케이션이 Open Service Broker 와 같은 이식 가능한 메커니즘을 통해 접근할 수도 있다.
- 로깅, 모니터링 또는 경보 솔루션을 포함하지 않는다. 개념 증명을 위한 일부 통합이나, 메트릭을 수집하고 노출하는 메커니즘을 제공한다.
- 기본 설정 언어/시스템(예, Jsonnet)을 제공하거나 요구하지 않는다. 선언적 명세의 임의적인 형식을 목적으로 하는 선언적 API를 제공한다.
- 포괄적인 머신 설정, 유지보수, 관리, 자동 복구 시스템을 제공하거나 채택하지 않는다.
- 추가로, 쿠버네티스는 단순한 오케스트레이션 시스템이 아니다. 사실, 쿠버네티스는 오케스트레이션의 필요성을 없애준다. 오케스트레이션의 기술적인 정의는 A를 먼저 한 다음, B를 하고, C를 하는 것과 같이 정의된 워크플로우를 수행하는 것이다. 반면에, 쿠버네티스는 독립적이고 조합 가능한 제어 프로세스들로 구성되어 있다. 이 프로세스는 지속적으로 현재 상태를 입력받은 의도한 상태로 나아가도록 한다. A에서 C로 어떻게 갔는지는 상관이 없다. 중앙화된 제어도 필요치 않다. 이로써 시스템이 보다 더 사용하기 쉬워지고, 강력해지며, 견고하고, 회복력을 갖추게 되며, 확장 가능해진다.
다음 내용
- 쿠버네티스 구성요소 살펴보기
- 시작하기 준비가 되었는가?
2 - 쿠버네티스 컴포넌트
쿠버네티스를 배포하면 클러스터를 얻는다.
쿠버네티스 클러스터는 컨테이너화된 애플리케이션을 실행하는 노드라고 하는 워커 머신의 집합. 모든 클러스터는 최소 한 개의 워커 노드를 가진다.
워커 노드는 애플리케이션의 구성요소인 파드를 호스트한다. 컨트롤 플레인은 워커 노드와 클러스터 내 파드를 관리한다. 프로덕션 환경에서는 일반적으로 컨트롤 플레인이 여러 컴퓨터에 걸쳐 실행되고, 클러스터는 일반적으로 여러 노드를 실행하므로 내결함성과 고가용성이 제공된다.
이 문서는 완전히 작동하는 쿠버네티스 클러스터를 갖기 위해 필요한 다양한 컴포넌트들에 대해 요약하고 정리한다.
컨트롤 플레인 컴포넌트
컨트롤 플레인 컴포넌트는 클러스터에 관한 전반적인 결정(예를 들어, 스케줄링)을 수행하고 클러스터 이벤트(예를 들어, 디플로이먼트의 replicas
필드에 대한 요구 조건이 충족되지 않을 경우 새로운 파드를 구동시키는 것)를 감지하고 반응한다.
컨트롤 플레인 컴포넌트는 클러스터 내 어떠한 머신에서든지 동작할 수 있다. 그러나 간결성을 위하여, 구성 스크립트는 보통 동일 머신 상에 모든 컨트롤 플레인 컴포넌트를 구동시키고, 사용자 컨테이너는 해당 머신 상에 동작시키지 않는다. 여러 VM에서 실행되는 컨트롤 플레인 설정의 예제를 보려면 kubeadm을 사용하여 고가용성 클러스터 만들기를 확인해본다.
kube-apiserver
API 서버는 쿠버네티스 API를 노출하는 쿠버네티스 컨트롤 플레인 컴포넌트이다. API 서버는 쿠버네티스 컨트롤 플레인의 프론트 엔드이다.
쿠버네티스 API 서버의 주요 구현은 kube-apiserver 이다. kube-apiserver는 수평으로 확장되도록 디자인되었다. 즉, 더 많은 인스턴스를 배포해서 확장할 수 있다. 여러 kube-apiserver 인스턴스를 실행하고, 인스턴스간의 트래픽을 균형있게 조절할 수 있다.
etcd
모든 클러스터 데이터를 담는 쿠버네티스 뒷단의 저장소로 사용되는 일관성·고가용성 키-값 저장소.
쿠버네티스 클러스터에서 etcd를 뒷단의 저장소로 사용한다면, 이 데이터를 백업하는 계획은 필수이다.
etcd에 대한 자세한 정보는, 공식 문서를 참고한다.
kube-scheduler
노드가 배정되지 않은 새로 생성된 파드 를 감지하고, 실행할 노드를 선택하는 컨트롤 플레인 컴포넌트.
스케줄링 결정을 위해서 고려되는 요소는 리소스에 대한 개별 및 총체적 요구 사항, 하드웨어/소프트웨어/정책적 제약, 어피니티(affinity) 및 안티-어피니티(anti-affinity) 명세, 데이터 지역성, 워크로드-간 간섭, 데드라인을 포함한다.
kube-controller-manager
컨트롤러 프로세스를 실행하는 컨트롤 플레인 컴포넌트.
논리적으로, 각 컨트롤러는 분리된 프로세스이지만, 복잡성을 낮추기 위해 모두 단일 바이너리로 컴파일되고 단일 프로세스 내에서 실행된다.
이들 컨트롤러는 다음을 포함한다.
- 노드 컨트롤러: 노드가 다운되었을 때 통지와 대응에 관한 책임을 가진다.
- 레플리케이션 컨트롤러: 시스템의 모든 레플리케이션 컨트롤러 오브젝트에 대해 알맞은 수의 파드들을 유지시켜 주는 책임을 가진다.
- 엔드포인트 컨트롤러: 엔드포인트 오브젝트를 채운다(즉, 서비스와 파드를 연결시킨다.)
- 서비스 어카운트 & 토큰 컨트롤러: 새로운 네임스페이스에 대한 기본 계정과 API 접근 토큰을 생성한다.
cloud-controller-manager
클라우드별 컨트롤 로직을 포함하는 쿠버네티스 컨트롤 플레인 컴포넌트이다. 클라우드 컨트롤러 매니저를 통해 클러스터를 클라우드 공급자의 API에 연결하고, 해당 클라우드 플랫폼과 상호 작용하는 컴포넌트와 클러스터와만 상호 작용하는 컴포넌트를 구분할 수 있게 해 준다.cloud-controller-manager는 클라우드 제공자 전용 컨트롤러만 실행한다. 자신의 사내 또는 PC 내부의 학습 환경에서 쿠버네티스를 실행 중인 경우 클러스터에는 클라우드 컨트롤러 매니저가 없다.
kube-controller-manager와 마찬가지로 cloud-controller-manager는 논리적으로 독립적인 여러 컨트롤 루프를 단일 프로세스로 실행하는 단일 바이너리로 결합한다. 수평으로 확장(두 개 이상의 복제 실행)해서 성능을 향상시키거나 장애를 견딜 수 있다.
다음 컨트롤러들은 클라우드 제공 사업자의 의존성을 가질 수 있다.
- 노드 컨트롤러: 노드가 응답을 멈춘 후 클라우드 상에서 삭제되었는지 판별하기 위해 클라우드 제공 사업자에게 확인하는 것
- 라우트 컨트롤러: 기본 클라우드 인프라에 경로를 구성하는 것
- 서비스 컨트롤러: 클라우드 제공 사업자 로드밸런서를 생성, 업데이트 그리고 삭제하는 것
노드 컴포넌트
노드 컴포넌트는 동작 중인 파드를 유지시키고 쿠버네티스 런타임 환경을 제공하며, 모든 노드 상에서 동작한다.
kubelet
클러스터의 각 노드에서 실행되는 에이전트. Kubelet은 파드에서 컨테이너가 확실하게 동작하도록 관리한다.
Kubelet은 다양한 메커니즘을 통해 제공된 파드 스펙(PodSpec)의 집합을 받아서 컨테이너가 해당 파드 스펙에 따라 건강하게 동작하는 것을 확실히 한다. Kubelet은 쿠버네티스를 통해 생성되지 않는 컨테이너는 관리하지 않는다.
kube-proxy
kube-proxy는 클러스터의 각 노드에서 실행되는 네트워크 프록시로, 쿠버네티스의 서비스 개념의 구현부이다.
kube-proxy는 노드의 네트워크 규칙을 유지 관리한다. 이 네트워크 규칙이 내부 네트워크 세션이나 클러스터 바깥에서 파드로 네트워크 통신을 할 수 있도록 해준다.
kube-proxy는 운영 체제에 가용한 패킷 필터링 계층이 있는 경우, 이를 사용한다. 그렇지 않으면, kube-proxy는 트래픽 자체를 포워드(forward)한다.
컨테이너 런타임
컨테이너 런타임은 컨테이너 실행을 담당하는 소프트웨어이다.
쿠버네티스는 여러 컨테이너 런타임을 지원한다. 도커(Docker), containerd, CRI-O 그리고 Kubernetes CRI (컨테이너 런타임 인터페이스)를 구현한 모든 소프트웨어.
애드온
애드온은 쿠버네티스 리소스(데몬셋,
디플로이먼트 등)를
이용하여 클러스터 기능을 구현한다. 이들은 클러스터 단위의 기능을 제공하기 때문에
애드온에 대한 네임스페이스 리소스는 kube-system
네임스페이스에 속한다.
선택된 일부 애드온은 아래에 설명하였고, 사용 가능한 전체 확장 애드온 리스트는 애드온을 참조한다.
DNS
여타 애드온들이 절대적으로 요구되지 않지만, 많은 예시에서 필요로 하기 때문에 모든 쿠버네티스 클러스터는 클러스터 DNS를 갖추어야만 한다.
클러스터 DNS는 구성환경 내 다른 DNS 서버와 더불어, 쿠버네티스 서비스를 위해 DNS 레코드를 제공해주는 DNS 서버다.
쿠버네티스에 의해 구동되는 컨테이너는 DNS 검색에서 이 DNS 서버를 자동으로 포함한다.
웹 UI (대시보드)
대시보드는 쿠버네티스 클러스터를 위한 범용의 웹 기반 UI다. 사용자가 클러스터 자체뿐만 아니라, 클러스터에서 동작하는 애플리케이션에 대한 관리와 문제 해결을 할 수 있도록 해준다.
컨테이너 리소스 모니터링
컨테이너 리소스 모니터링은 중앙 데이터베이스 내의 컨테이너들에 대한 포괄적인 시계열 매트릭스를 기록하고 그 데이터를 열람하기 위한 UI를 제공해 준다.
클러스터-레벨 로깅
클러스터-레벨 로깅 메커니즘은 검색/열람 인터페이스와 함께 중앙 로그 저장소에 컨테이너 로그를 저장하는 책임을 진다.
다음 내용
- 노드에 대해 더 배우기
- 컨트롤러에 대해 더 배우기
- kube-scheduler에 대해 더 배우기
- etcd의 공식 문서 읽기
3 - 쿠버네티스 API
쿠버네티스 컨트롤 플레인의 핵심은 API 서버이다. API 서버는 최종 사용자, 클러스터의 다른 부분 그리고 외부 컴포넌트가 서로 통신할 수 있도록 HTTP API를 제공한다.
쿠버네티스 API를 사용하면 쿠버네티스의 API 오브젝트(예: 파드(Pod), 네임스페이스(Namespace), 컨피그맵(ConfigMap) 그리고 이벤트(Event))를 질의(query)하고 조작할 수 있다.
대부분의 작업은 kubectl 커맨드 라인 인터페이스 또는 API를 사용하는 kubeadm과 같은 다른 커맨드 라인 도구를 통해 수행할 수 있다. 그러나, REST 호출을 사용하여 API에 직접 접근할 수도 있다.
쿠버네티스 API를 사용하여 애플리케이션을 작성하는 경우 클라이언트 라이브러리 중 하나를 사용하는 것이 좋다.
OpenAPI 명세
완전한 API 상세 내용은 OpenAPI를 활용해서 문서화했다.
OpenAPI 규격은 /openapi/v2
엔드포인트에서만 제공된다.
다음과 같은 요청 헤더를 사용해서 응답 형식을 요청할 수 있다.
Header | Possible values | Notes |
---|---|---|
Accept-Encoding |
gzip |
not supplying this header is also acceptable |
Accept |
application/[email protected]+protobuf |
mainly for intra-cluster use |
application/json |
default | |
* |
serves application/json |
쿠버네티스는 주로 클러스터 내부 통신을 위해 대안적인 Protobuf에 기반한 직렬화 형식을 구현한다. 이 형식에 대한 자세한 내용은 쿠버네티스 Protobuf 직렬화 디자인 제안과 API 오브젝트를 정의하는 Go 패키지에 들어있는 각각의 스키마에 대한 IDL(인터페이스 정의 언어) 파일을 참고한다.
지속성
쿠버네티스는 오브젝트의 직렬화된 상태를 etcd에 기록하여 저장한다.
API 그룹과 버전 규칙
필드를 쉽게 제거하거나 리소스 표현을 재구성하기 위해,
쿠버네티스는 각각 /api/v1
또는 /apis/rbac.authorization.k8s.io/v1alpha1
과
같은 서로 다른 API 경로에서 여러 API 버전을 지원한다.
버전 규칙은 리소스나 필드 수준이 아닌 API 수준에서 수행되어 API가 시스템 리소스 및 동작에 대한 명확하고 일관된 보기를 제공하고 수명 종료 및/또는 실험적 API에 대한 접근을 제어할 수 있도록 한다.
보다 쉽게 발전하고 API를 확장하기 위해, 쿠버네티스는 활성화 또는 비활성화가 가능한 API 그룹을 구현한다.
API 리소스는 API 그룹, 리소스 유형, 네임스페이스 (네임스페이스 리소스용) 및 이름으로 구분된다. API 서버는 API 버전 간의 변환을 투명하게 처리한다. 서로 다른 모든 버전은 실제로 동일한 지속 데이터의 표현이다. API 서버는 여러 API 버전을 통해 동일한 기본 데이터를 제공할 수 있다.
예를 들어, 동일한 리소스에 대해 v1
과 v1beta1
이라는 두 가지 API 버전이
있다고 가정한다. 원래 API의 v1beta1
버전을 사용하여 오브젝트를
만든 경우, 나중에 v1beta1
또는 v1
API 버전을 사용하여 해당 오브젝트를
읽거나, 업데이트하거나, 삭제할 수 있다.
API 변경 사항
성공적인 시스템은 새로운 유스케이스가 등장하거나 기존 사례가 변경됨에 따라 성장하고 변화해야 한다. 따라서, 쿠버네티스는 쿠버네티스 API가 지속적으로 변경되고 성장할 수 있도록 설계했다. 쿠버네티스 프로젝트는 기존 클라이언트와의 호환성을 깨지 않고 다른 프로젝트가 적응할 기회를 가질 수 있도록 장기간 해당 호환성을 유지하는 것을 목표로 한다.
일반적으로, 새 API 리소스와 새 리소스 필드는 자주 추가될 수 있다. 리소스 또는 필드를 제거하려면 API 지원 중단 정책을 따라야 한다.
쿠버네티스는 일반적으로 API 버전 v1
에서 안정 버전(GA)에 도달하면, 공식 쿠버네티스 API에
대한 호환성 유지를 강력하게 이행한다. 또한,
쿠버네티스는 가능한 경우 베타 API 버전에서도 호환성을 유지한다.
베타 API를 채택하면 기능이 안정된 후에도 해당 API를 사용하여 클러스터와
계속 상호 작용할 수 있다.
API 버전 수준 정의에 대한 자세한 내용은 API 버전 레퍼런스를 참조한다.
API 확장
쿠버네티스 API는 다음 두 가지 방법 중 하나로 확장할 수 있다.
- 커스텀 리소스를 사용하면 API 서버가 선택한 리소스 API를 제공하는 방법을 선언적으로 정의할 수 있다.
- 애그리게이션 레이어(aggregation layer)를 구현하여 쿠버네티스 API를 확장할 수도 있다.
다음 내용
- 자체 CustomResourceDefinition을 추가하여 쿠버네티스 API를 확장하는 방법에 대해 배우기.
- 쿠버네티스 API 접근 제어하기는 클러스터가 API 접근을 위한 인증 및 권한을 관리하는 방법을 설명한다.
- API 레퍼런스를 읽고 API 엔드포인트, 리소스 유형 및 샘플에 대해 배우기.
- API 변경 사항에서 호환 가능한 변경 사항을 구성하고, API를 변경하는 방법에 대해 알아본다.
4 - 쿠버네티스 오브젝트로 작업하기
4.1 - 쿠버네티스 오브젝트 이해하기
이 페이지에서는 쿠버네티스 오브젝트가 쿠버네티스 API에서 어떻게 표현되고, 그 오브젝트를 어떻게 .yaml
형식으로 표현할 수 있는지에 대해 설명한다.
쿠버네티스 오브젝트 이해하기
쿠버네티스 오브젝트 는 쿠버네티스 시스템에서 영속성을 가지는 오브젝트이다. 쿠버네티스는 클러스터의 상태를 나타내기 위해 이 오브젝트를 이용한다. 구체적으로 말하자면, 다음같이 기술할 수 있다.
- 어떤 컨테이너화된 애플리케이션이 동작 중인지 (그리고 어느 노드에서 동작 중인지)
- 그 애플리케이션이 이용할 수 있는 리소스
- 그 애플리케이션이 어떻게 재구동 정책, 업그레이드, 그리고 내고장성과 같은 것에 동작해야 하는지에 대한 정책
쿠버네티스 오브젝트는 하나의 "의도를 담은 레코드"이다. 오브젝트를 생성하게 되면, 쿠버네티스 시스템은 그 오브젝트 생성을 보장하기 위해 지속적으로 작동할 것이다. 오브젝트를 생성함으로써, 여러분이 클러스터의 워크로드를 어떤 형태로 보이고자 하는지에 대해 효과적으로 쿠버네티스 시스템에 전한다. 이것이 바로 여러분의 클러스터에 대해 의도한 상태 가 된다.
생성이든, 수정이든, 또는 삭제든 쿠버네티스 오브젝트를 동작시키려면, 쿠버네티스 API를 이용해야 한다. 예를 들어, kubectl
커맨드-라인 인터페이스를 이용할 때, CLI는 여러분 대신 필요한 쿠버네티스 API를 호출해 준다. 또한, 여러분은 클라이언트 라이브러리 중 하나를 이용하여 여러분만의 프로그램에서 쿠버네티스 API를 직접 이용할 수도 있다.
오브젝트 명세(spec)와 상태(status)
거의 모든 쿠버네티스 오브젝트는 오브젝트의 구성을 결정해주는
두 개의 중첩된 오브젝트 필드를 포함하는데 오브젝트 spec
과 오브젝트 status
이다.
spec
을 가진 오브젝트는 오브젝트를 생성할 때 리소스에
원하는 특징(의도한 상태)에 대한 설명을
제공해서 설정한다.
status
는 쿠버네티스 시스템과 컴포넌트에 의해 제공되고
업데이트된 오브젝트의 현재 상태 를 설명한다. 쿠버네티스
컨트롤 플레인은 모든 오브젝트의
실제 상태를 사용자가 의도한 상태와 일치시키기 위해 끊임없이 그리고
능동적으로 관리한다.
예를 들어, 쿠버네티스 디플로이먼트는 클러스터에서 동작하는 애플리케이션을 표현해줄 수 있는 오브젝트이다. 디플로이먼트를 생성할 때, 디플로이먼트 spec에 3개의 애플리케이션 레플리카가 동작되도록 설정할 수 있다. 쿠버네티스 시스템은 그 디플로이먼트 spec을 읽어 spec에 일치되도록 상태를 업데이트하여 3개의 의도한 애플리케이션 인스턴스를 구동시킨다. 만약, 그 인스턴스들 중 어느 하나가 어떤 문제로 인해 멈춘다면(상태 변화 발생), 쿠버네티스 시스템은 보정(이 경우에는 대체 인스턴스를 시작하여)을 통해 spec과 status간의 차이에 대응한다.
오브젝트 명세, 상태, 그리고 메타데이터에 대한 추가 정보는, Kubernetes API Conventions 를 참조한다.
쿠버네티스 오브젝트 기술하기
쿠버네티스에서 오브젝트를 생성할 때, (이름과 같은)오브젝트에 대한 기본적인 정보와 더불어, 의도한 상태를 기술한 오브젝트 spec을 제시해 줘야만 한다. 오브젝트를 생성하기 위해(직접이든 또는 kubectl
을 통해서든) 쿠버네티스 API를 이용할 때, API 요청은 요청 내용 안에 JSON 형식으로 정보를 포함시켜 줘야만 한다. 대부분의 경우 정보를 .yaml 파일로 kubectl
에 제공한다. kubectl
은 API 요청이 이루어질 때, JSON 형식으로 정보를 변환시켜 준다.
여기 쿠버네티스 디플로이먼트를 위한 필수 필드와 오브젝트 spec을 보여주는 .yaml
파일 예시가 있다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
위 예시와 같이 .yaml 파일을 이용하여 디플로이먼트를 생성하기 위한 하나의 방식으로는
kubectl
커맨드-라인 인터페이스에 인자값으로 .yaml
파일을 건네
kubectl apply
커맨드를 이용하는 것이다. 다음 예시와 같다.
kubectl apply -f https://k8s.io/examples/application/deployment.yaml --record
그 출력 내용은 다음과 유사하다.
deployment.apps/nginx-deployment created
요구되는 필드
생성하고자 하는 쿠버네티스 오브젝트에 대한 .yaml
파일 내, 다음 필드를 위한 값들을 설정해 줘야한다.
apiVersion
- 이 오브젝트를 생성하기 위해 사용하고 있는 쿠버네티스 API 버전이 어떤 것인지kind
- 어떤 종류의 오브젝트를 생성하고자 하는지metadata
-이름
문자열,UID
, 그리고 선택적인네임스페이스
를 포함하여 오브젝트를 유일하게 구분지어 줄 데이터spec
- 오브젝트에 대해 어떤 상태를 의도하는지
오브젝트 spec
에 대한 정확한 포맷은 모든 쿠버네티스 오브젝트마다 다르고, 그 오브젝트 특유의 중첩된 필드를 포함한다. 쿠버네티스 API 레퍼런스 는 쿠버네티스를 이용하여 생성할 수 있는 오브젝트에 대한 모든 spec 포맷을 살펴볼 수 있도록 해준다.
예를 들어, API 내 파드에 대한 상세 정보는 spec
필드에 대한 레퍼런스에서,
디플로이먼트에 대한 상세 정보는 spec
필드에 대한 레퍼런스에서 확인할 수 있다.
해당 API 레퍼런스 페이지에서 PodSpec과 DeploymentSpec에 대해 언급된 내용을 볼 수 있다. 이 이름들은 쿠버네티스가 API를 구현하는데 사용한 Go 언어 코드 구현의 세부 내용이다.
다음 내용
- 파드와 같이, 가장 중요하고 기본적인 쿠버네티스 오브젝트에 대해 배운다.
- 쿠버네티스의 컨트롤러에 대해 배운다.
- API 개념의 더 많은 설명은 쿠버네티스 API 사용을 본다.
4.2 - 쿠버네티스 오브젝트 관리
kubectl
커맨드라인 툴은 쿠버네티스 오브젝트를 생성하고 관리하기 위한
몇 가지 상이한 방법을 지원한다. 이 문서는 여러가지 접근법에 대한 개요을
제공한다. Kubectl로 오브젝트 관리하기에 대한 자세한 설명은
Kubectl 서적에서 확인한다.
관리 기법
관리기법 | 대상 | 권장 환경 | 지원하는 작업자 수 | 학습 난이도 |
---|---|---|---|---|
명령형 커맨드 | 활성 오브젝트 | 개발 환경 | 1+ | 낮음 |
명령형 오브젝트 구성 | 개별 파일 | 프로덕션 환경 | 1 | 보통 |
선언형 오브젝트 구성 | 파일이 있는 디렉터리 | 프로덕션 환경 | 1+ | 높음 |
명령형 커맨드
명령형 커맨드를 사용할 경우, 사용자는 클러스터 내 활성 오브젝트를 대상으로
직접 동작시킨다. 사용자는 실행할 작업을 인수 또는 플래그로 kubectl
커맨드에
지정한다.
이것은 클러스터에서 일회성 작업을 개시시키거나 동작시키기 위한 추천 방법이다. 이 기법은 활성 오브젝트를 대상으로 직접적인 영향을 미치기 때문에, 이전 구성에 대한 이력을 제공해 주지 않는다.
예시
디플로이먼트 오브젝트를 생성하여 nginx 컨테이너의 인스턴스를 구동시킨다.
kubectl create deployment nginx --image nginx
트레이드 오프
오브젝트 구성에 비해 장점은 다음과 같다.
- 커맨드는 하나의 동작을 나타내는 단어로 표현된다.
- 커맨드는 클러스터를 수정하기 위해 단 하나의 단계만을 필요로 한다.
오브젝트 구성에 비해 단점은 다음과 같다.
- 커맨드는 변경 검토 프로세스와 통합되지 않는다.
- 커맨드는 변경에 관한 감사 추적(audit trail)을 제공하지 않는다.
- 커맨드는 활성 동작 중인 경우를 제외하고는 레코드의 소스를 제공하지 않는다.
- 커맨드는 새로운 오브젝트 생성을 위한 템플릿을 제공하지 않는다.
명령형 오브젝트 구성
명령형 오브젝트 구성에서는 kubectl 커맨드로 작업(생성, 교체 등), 선택적 플래그, 그리고 최소 하나의 파일 이름을 지정한다. 그 파일은 YAML 또는 JSON 형식으로 오브젝트의 완전한 정의를 포함해야만 한다.
오브젝트 정의에 대한 더 자세한 내용은 API 참조를 참고한다.
replace
커맨드는 기존 spec을 새로 제공된 spec으로 바꾸고
구성 파일에서 누락된 오브젝트의 모든 변경 사항을 삭제한다.
이 방법은 spec이 구성 파일과는 별개로 업데이트되는 리소스 유형에는
사용하지 말아야한다.
예를 들어 LoadBalancer
유형의 서비스는 클러스터의 구성과 별도로
externalIPs
필드가 업데이트된다.
예시
구성 파일에 정의된 오브젝트를 생성한다.
kubectl create -f nginx.yaml
두 개의 구성 파일에 정의된 오브젝트를 삭제한다.
kubectl delete -f nginx.yaml -f redis.yaml
활성 동작하는 구성을 덮어씀으로써 구성 파일에 정의된 오브젝트를 업데이트한다.
kubectl replace -f nginx.yaml
트레이드 오프
명령형 커맨드에 비해 장점은 다음과 같다.
- 오브젝트 구성은 Git과 같은 소스 컨트롤 시스템에 보관할 수 있다.
- 오브젝트 구성은 푸시와 감사 추적 전에 변경사항을 검토하는 것과 같은 프로세스들과 통합할 수 있다.
- 오브젝트 구성은 새로운 오브젝트 생성을 위한 템플릿을 제공한다.
명령형 커맨드에 비해 단점은 다음과 같다.
- 오브젝트 구성은 오브젝트 스키마에 대한 기본적인 이해를 필요로 한다.
- 오브젝트 구성은 YAML 파일을 기록하는 추가적인 과정을 필요로 한다.
선언형 오브젝트 구성에 비해 장점은 다음과 같다.
- 명령형 오브젝트 구성의 동작은 보다 간결하고 이해하기 쉽다.
- 쿠버네티스 버전 1.5 부터는 더 성숙한 명령형 오브젝트 구성을 제공한다.
선언형 오브젝트 구성에 비해 단점은 다음과 같다.
- 명령형 오브젝트 구성은 디렉터리가 아닌, 파일에 가장 적합하다.
- 활성 오브젝트에 대한 업데이트는 구성 파일에 반영되어야 한다. 그렇지 않으면 다음 교체 중에 손실된다.
선언형 오브젝트 구성
선언형 오브젝트 구성을 사용할 경우, 사용자는 로컬에 보관된 오브젝트
구성 파일을 대상으로 작동시키지만, 사용자는 파일에서 수행 할
작업을 정의하지 않는다. 생성, 업데이트, 그리고 삭제 작업은
kubectl
에 의해 오브젝트마다 자동으로 감지된다. 이를 통해 다른 오브젝트에 대해
다른 조작이 필요할 수 있는 디렉터리에서 작업할 수 있다.
replace
API를
사용하는 대신, patch
API를 사용하여 인지되는 차이만
작성하기 때문에 가능하다.
예시
configs
디렉터리 내 모든 오브젝트 구성 파일을 처리하고 활성 오브젝트를
생성 또는 패치한다. 먼저 어떠한 변경이 이루어지게 될지 알아보기 위해 diff
하고 나서 적용할 수 있다.
kubectl diff -f configs/
kubectl apply -f configs/
재귀적으로 디렉터리를 처리한다.
kubectl diff -R -f configs/
kubectl apply -R -f configs/
트레이드 오프
명령형 오브젝트 구성에 비해 장점은 다음과 같다.
- 활성 오브젝트에 직접 작성된 변경 사항은 구성 파일로 다시 병합되지 않더라도 유지된다.
- 선언형 오브젝트 구성은 디렉터리에서의 작업 및 오브젝트 별 작업 유형(생성, 패치, 삭제)의 자동 감지에 더 나은 지원을 제공한다.
명령형 오브젝트 구성에 비해 단점은 다음과 같다.
- 선언형 오브젝트 구성은 예상치 못한 결과를 디버깅하고 이해하기가 더 어렵다.
- diff를 사용한 부분 업데이트는 복잡한 병합 및 패치 작업을 일으킨다.
다음 내용
4.3 - 오브젝트 이름과 ID
클러스터의 각 오브젝트는 해당 유형의 리소스에 대하여 고유한 이름 을 가지고 있다. 또한, 모든 쿠버네티스 오브젝트는 전체 클러스터에 걸쳐 고유한 UID 를 가지고 있다.
예를 들어, 이름이 myapp-1234
인 파드는 동일한 네임스페이스 내에서 하나만 존재할 수 있지만, 이름이 myapp-1234
인 파드와 디플로이먼트는 각각 존재할 수 있다.
유일하지 않은 사용자 제공 속성의 경우 쿠버네티스는 레이블과 어노테이션을 제공한다.
이름
/api/v1/pods/some-name
과 같이, 리소스 URL에서 오브젝트를 가리키는 클라이언트 제공 문자열.
특정 시점에 같은 종류(kind) 내에서는 하나의 이름은 하나의 오브젝트에만 지정될 수 있다. 하지만, 오브젝트를 삭제한 경우, 삭제된 오브젝트와 같은 이름을 새로운 오브젝트에 지정 가능하다.
다음은 리소스에 일반적으로 사용되는 네 가지 유형의 이름 제한 조건이다.
DNS 서브도메인 이름
대부분의 리소스 유형에는 RFC 1123에 정의된 대로 DNS 서브도메인 이름으로 사용할 수 있는 이름이 필요하다. 이것은 이름이 다음을 충족해야 한다는 것을 의미한다.
- 253자를 넘지 말아야 한다.
- 소문자와 영숫자
-
또는.
만 포함한다. - 영숫자로 시작한다.
- 영숫자로 끝난다.
RFC 1123 레이블 이름
일부 리소스 유형은 RFC 1123에 정의된 대로 DNS 레이블 표준을 따라야 한다. 이것은 이름이 다음을 충족해야 한다는 것을 의미한다.
- 최대 63자이다.
- 소문자와 영숫자 또는
-
만 포함한다. - 영숫자로 시작한다.
- 영숫자로 끝난다.
RFC 1035 레이블 이름
몇몇 리소스 타입은 자신의 이름을 RFC 1035에 정의된 DNS 레이블 표준을 따르도록 요구한다. 이것은 이름이 다음을 만족해야 한다는 의미이다.
- 최대 63개 문자를 포함
- 소문자 영숫자 또는 '-'만 포함
- 알파벳 문자로 시작
- 영숫자로 끝남
경로 세그먼트 이름
일부 리소스 유형에서는 이름을 경로 세그먼트로 안전하게 인코딩 할 수 있어야 한다. 즉 이름이 "." 또는 ".."이 아닐 수 있으며 이름에는 "/" 또는 "%"가 포함될 수 없다.
아래는 파드의 이름이 nginx-demo
라는 매니페스트 예시이다.
apiVersion: v1
kind: Pod
metadata:
name: nginx-demo
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
UID
오브젝트를 중복 없이 식별하기 위해 쿠버네티스 시스템이 생성하는 문자열.
쿠버네티스 클러스터가 구동되는 전체 시간에 걸쳐 생성되는 모든 오브젝트는 서로 구분되는 UID를 갖는다. 이는 기록상 유사한 오브젝트의 출현을 서로 구분하기 위함이다.
쿠버네티스 UID는 보편적으로 고유한 식별자이다(또는 UUID라고 한다). UUID는 ISO/IEC 9834-8 과 ITU-T X.667 로 표준화 되어 있다.
다음 내용
- 쿠버네티스의 레이블에 대해 읽기.
- 쿠버네티스의 식별자와 이름 디자인 문서 읽기.
4.4 - 네임스페이스
쿠버네티스에서, 네임스페이스 는 단일 클러스터 내에서의 리소스 그룹 격리 메커니즘을 제공한다. 리소스의 이름은 네임스페이스 내에서 유일해야 하며, 네임스페이스 간에서 유일할 필요는 없다. 네임스페이스 기반 스코핑은 네임스페이스 기반 오브젝트 (예: 디플로이먼트, 서비스 등) 에만 적용 가능하며 클러스터 범위의 오브젝트 (예: 스토리지클래스, 노드, 퍼시스턴트볼륨 등) 에는 적용 불가능하다.
여러 개의 네임스페이스를 사용하는 경우
네임스페이스는 여러 개의 팀이나, 프로젝트에 걸쳐서 많은 사용자가 있는 환경에서 사용하도록 만들어졌다. 사용자가 거의 없거나, 수 십명 정도가 되는 경우에는 네임스페이스를 전혀 고려할 필요가 없다. 네임스페이스가 제공하는 기능이 필요할 때 사용하도록 하자.
네임스페이스는 이름의 범위를 제공한다. 리소스의 이름은 네임스페이스 내에서 유일해야하지만, 네임스페이스를 통틀어서 유일할 필요는 없다. 네임스페이스는 서로 중첩될 수 없으며, 각 쿠버네티스 리소스는 하나의 네임스페이스에만 있을 수 있다.
네임스페이스는 클러스터 자원을 (리소스 쿼터를 통해) 여러 사용자 사이에서 나누는 방법이다.
동일한 소프트웨어의 다른 버전과 같이 약간 다른 리소스를 분리하기 위해 여러 네임스페이스를 사용할 필요는 없다. 동일한 네임스페이스 내에서 리소스를 구별하기 위해 레이블을 사용한다.
네임스페이스 다루기
네임스페이스의 생성과 삭제는 네임스페이스 관리자 가이드 문서에 기술되어 있다.
kube-
접두사로 시작하는 네임스페이스는 쿠버네티스 시스템용으로 예약되어 있으므로, 사용자는 이러한 네임스페이스를 생성하지 않는다.
네임스페이스 조회
사용 중인 클러스터의 현재 네임스페이스를 나열할 수 있다.
kubectl get namespace
NAME STATUS AGE
default Active 1d
kube-node-lease Active 1d
kube-public Active 1d
kube-system Active 1d
쿠버네티스는 처음에 네 개의 초기 네임스페이스를 갖는다.
default
다른 네임스페이스가 없는 오브젝트를 위한 기본 네임스페이스kube-system
쿠버네티스 시스템에서 생성한 오브젝트를 위한 네임스페이스kube-public
이 네임스페이스는 자동으로 생성되며 모든 사용자(인증되지 않은 사용자 포함)가 읽기 권한으로 접근할 수 있다. 이 네임스페이스는 주로 전체 클러스터 중에 공개적으로 드러나서 읽을 수 있는 리소스를 위해 예약되어 있다. 이 네임스페이스의 공개적인 성격은 단지 관례이지 요구 사항은 아니다.kube-node-lease
클러스터가 스케일링될 때 노드 하트비트의 성능을 향상시키는 각 노드와 관련된 리스(lease) 오브젝트에 대한 네임스페이스kube-node-lease
이 네임스페이스는 각 노드와 연관된 리스 오브젝트를 갖는다. 노드 리스는 kubelet이 하트비트를 보내서 컨트롤 플레인이 노드의 장애를 탐지할 수 있게 한다.
요청에 네임스페이스 설정하기
현재 요청에 대한 네임스페이스를 설정하기 위해서 --namespace
플래그를 사용한다.
예를 들면,
kubectl run nginx --image=nginx --namespace=<insert-namespace-name-here>
kubectl get pods --namespace=<insert-namespace-name-here>
선호하는 네임스페이스 설정하기
이후 모든 kubectl 명령에서 사용하는 네임스페이스를 컨텍스트에 영구적으로 저장할 수 있다.
kubectl config set-context --current --namespace=<insert-namespace-name-here>
# 확인하기
kubectl config view --minify | grep namespace:
네임스페이스와 DNS
서비스를 생성하면 해당
DNS 엔트리가 생성된다.
이 엔트리는 <서비스-이름>.<네임스페이스-이름>.svc.cluster.local
의 형식을 갖는데,
이는 컨테이너가 <서비스-이름>
만 사용하는 경우, 네임스페이스 내에 국한된 서비스로 연결된다.
개발, 스테이징, 운영과 같이 여러 네임스페이스 내에서 동일한 설정을 사용하는 경우에 유용하다.
네임스페이스를 넘어서 접근하기 위해서는, 전체 주소 도메인 이름(FQDN)을 사용해야 한다.
모든 오브젝트가 네임스페이스에 속하지는 않음
대부분의 쿠버네티스 리소스(예를 들어, 파드, 서비스, 레플리케이션 컨트롤러 외)는 네임스페이스에 속한다. 하지만 네임스페이스 리소스 자체는 네임스페이스에 속하지 않는다. 그리고 노드나 퍼시스턴트 볼륨과 같은 저수준 리소스는 어느 네임스페이스에도 속하지 않는다.
다음은 네임스페이스에 속하지 않는 쿠버네티스 리소스를 조회하는 방법이다.
# 네임스페이스에 속하는 리소스
kubectl api-resources --namespaced=true
# 네임스페이스에 속하지 않는 리소스
kubectl api-resources --namespaced=false
자동 레이블링
Kubernetes 1.21 [beta]
쿠버네티스 컨트롤 플레인은 NamespaceDefaultLabelName
기능 게이트가
활성화된 경우 모든 네임스페이스에 변경할 수 없는(immutable) 레이블
kubernetes.io / metadata.name
을 설정한다.
레이블 값은 네임스페이스 이름이다.
다음 내용
- 신규 네임스페이스 생성에 대해 더 배우기.
- 네임스페이스 삭제에 대해 더 배우기.
4.5 - 레이블과 셀렉터
레이블 은 파드와 같은 오브젝트에 첨부된 키와 값의 쌍이다. 레이블은 오브젝트의 특성을 식별하는 데 사용되어 사용자에게 중요하지만, 코어 시스템에 직접적인 의미는 없다. 레이블로 오브젝트의 하위 집합을 선택하고, 구성하는데 사용할 수 있다. 레이블은 오브젝트를 생성할 때에 붙이거나 생성 이후에 붙이거나 언제든지 수정이 가능하다. 오브젝트마다 키와 값으로 레이블을 정의할 수 있다. 오브젝트의 키는 고유한 값이어야 한다.
"metadata": {
"labels": {
"key1" : "value1",
"key2" : "value2"
}
}
레이블은 UI와 CLI에서 효율적인 쿼리를 사용하고 검색에 사용하기에 적합하다. 식별되지 않는 정보는 어노테이션으로 기록해야 한다.
사용 동기
레이블을 이용하면 사용자가 느슨하게 결합한 방식으로 조직 구조와 시스템 오브젝트를 매핑할 수 있으며, 클라이언트에 매핑 정보를 저장할 필요가 없다.
서비스 배포와 배치 프로세싱 파이프라인은 흔히 다차원의 엔티티들이다(예: 다중 파티션 또는 배포, 다중 릴리스 트랙, 다중 계층, 계층 속 여러 마이크로 서비스들). 관리에는 크로스-커팅 작업이 필요한 경우가 많은데 이 작업은 사용자보다는 인프라에 의해 결정된 엄격한 계층 표현인 캡슐화를 깨트린다.
레이블 예시:
"release" : "stable"
,"release" : "canary"
"environment" : "dev"
,"environment" : "qa"
,"environment" : "production"
"tier" : "frontend"
,"tier" : "backend"
,"tier" : "cache"
"partition" : "customerA"
,"partition" : "customerB"
"track" : "daily"
,"track" : "weekly"
이 예시는 일반적으로 사용하는 레이블이며, 사용자는 자신만의 규칙(convention)에 따라 자유롭게 개발할 수 있다. 오브젝트에 붙여진 레이블 키는 고유해야 한다는 것을 기억해야 한다.
구문과 캐릭터 셋
레이블 은 키와 값의 쌍이다. 유효한 레이블 키에는 슬래시(/
)로 구분되는 선택한 접두사와 이름이라는 2개의 세그먼트가 있다. 이름 세그먼트는 63자 미만으로 시작과 끝은 알파벳과 숫자([a-z0-9A-Z]
)이며, 대시(-
), 밑줄(_
), 점(.
)과 함께 사용할 수 있다. 접두사는 선택이다. 만약 접두사를 지정한 경우 접두사는 DNS의 하위 도메인으로 해야 하며, 점(.
)과 전체 253자 이하, 슬래시(/
)로 구분되는 DNS 레이블이다.
접두사를 생략하면 키 레이블은 개인용으로 간주한다. 최종 사용자의 오브젝트에 자동화된 시스템 컴포넌트(예: kube-scheduler
, kube-controller-manager
, kube-apiserver
, kubectl
또는 다른 타사의 자동화 구성 요소)의 접두사를 지정해야 한다.
kubernetes.io/
와 k8s.io/
접두사는 쿠버네티스의 핵심 컴포넌트로 예약되어 있다.
유효한 레이블 값은 다음과 같다.
- 63 자 이하여야 하고 (공백일 수도 있음),
- (공백이 아니라면) 시작과 끝은 알파벳과 숫자(
[a-z0-9A-Z]
)이며, - 알파벳과 숫자, 대시(
-
), 밑줄(_
), 점(.
)을 중간에 포함할 수 있다.
다음의 예시는 파드에 environment: production
과 app: nginx
2개의 레이블이 있는 구성 파일이다.
apiVersion: v1
kind: Pod
metadata:
name: label-demo
labels:
environment: production
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
레이블 셀렉터
이름과 UID와 다르게 레이블은 고유하지 않다. 일반적으로 우리는 많은 오브젝트에 같은 레이블을 가질 것으로 예상한다.
레이블 셀렉터를 통해 클라이언트와 사용자는 오브젝트를 식별할 수 있다. 레이블 셀렉터는 쿠버네티스 코어 그룹의 기본이다.
API는 현재 일치성 기준 과 집합성 기준 이라는 두 종류의 셀렉터를 지원한다.
레이블 셀렉터는 쉼표로 구분된 다양한 요구사항 에 따라 만들 수 있다. 다양한 요구사항이 있는 경우 쉼표 기호가 AND(&&
) 연산자로 구분되는 역할을 하도록 해야 한다.
비어있거나 지정되지 않은 셀렉터는 상황에 따라 달라진다. 셀렉터를 사용하는 API 유형은 유효성과 의미를 문서화해야 한다.
||
) 연산자가 없다. 필터 구문이 적절히 구성되어 있는지 확인해야 한다.
일치성 기준 요건
일치성 기준 또는 불일치 기준 의 요구사항으로 레이블의 키와 값의 필터링을 허용한다. 일치하는 오브젝트는 추가 레이블을 가질 수 있지만, 레이블의 명시된 제약 조건을 모두 만족해야 한다.
=
,==
,!=
이 세 가지 연산자만 허용한다. 처음 두 개의 연산자의 일치성(그리고 동의어), 나머지는 불일치 를 의미한다. 예를 들면,
environment = production
tier != frontend
전자는 environment
를 키로 가지는 것과 production
을 값으로 가지는 모든 리소스를 선택한다.
후자는 tier
를 키로 가지고, 값을 frontend
를 가지는 리소스를 제외한 모든 리소스를 선택하고, tier
를 키로 가지며, 값을 공백으로 가지는 모든 리소스를 선택한다.
environment=production,tier!=frontend
처럼 쉼표를 통해 한 문장으로 frontend
를 제외한 production
을 필터링할 수 있다.
일치성 기준 레이블 요건에 대한 하나의 이용 시나리오는 파드가 노드를 선택하는 기준을 지정하는 것이다.
예를 들어, 아래 샘플 파드는 "accelerator=nvidia-tesla-p100
"
레이블을 가진 노드를 선택한다.
apiVersion: v1
kind: Pod
metadata:
name: cuda-test
spec:
containers:
- name: cuda-test
image: "k8s.gcr.io/cuda-vector-add:v0.1"
resources:
limits:
nvidia.com/gpu: 1
nodeSelector:
accelerator: nvidia-tesla-p100
집합성 기준 요건
집합성 기준 레이블 요건에 따라 값 집합을 키로 필터링할 수 있다. in
,notin
과 exists
(키 식별자만 해당)의 3개의 연산자를 지원한다. 예를 들면,
environment in (production, qa)
tier notin (frontend, backend)
partition
!partition
- 첫 번째 예시에서 키가
environment
이고 값이production
또는qa
인 모든 리소스를 선택한다. - 두 번째 예시에서 키가
tier
이고 값이frontend
와backend
를 가지는 리소스를 제외한 모든 리소스와 키로tier
를 가지고 값을 공백으로 가지는 모든 리소스를 선택한다. - 세 번째 예시에서 레이블의 값에 상관없이 키가
partition
을 포함하는 모든 리소스를 선택한다. - 네 번째 예시에서 레이블의 값에 상관없이 키가
partition
을 포함하지 않는 모든 리소스를 선택한다.
마찬가지로 쉼표는 AND 연산자로 작동한다. 따라서 partition,environment notin (qa)
와 같이 사용하면 값과 상관없이 키가 partition
인 것과 키가 environment
이고 값이 qa
와 다른 리소스를 필터링할 수 있다.
집합성 기준 레이블 셀렉터는 일반적으로 environment=production
과 environment in (production)
을 같은 것으로 본다. 유사하게는 !=
과 notin
을 같은 것으로 본다.
집합성 기준 요건은 일치성 기준 요건과 조합해서 사용할 수 있다. 예를 들어 partition in (customerA, customerB),environment!=qa
API
LIST와 WATCH 필터링
LIST와 WATCH 작업은 쿼리 파라미터를 사용해서 반환되는 오브젝트 집합을 필터링하기 위해 레이블 셀렉터를 지정할 수 있다. 다음의 두 가지 요건 모두 허용된다(URL 쿼리 문자열을 그대로 표기함).
- 일치성 기준 요건:
?labelSelector=environment%3Dproduction,tier%3Dfrontend
- 집합성 기준 요건:
?labelSelector=environment+in+%28production%2Cqa%29%2Ctier+in+%28frontend%29
두 가지 레이블 셀렉터 스타일은 모두 REST 클라이언트를 통해 선택된 리소스를 확인하거나 목록을 볼 수 있다. 예를 들어, kubectl
로 apiserver
를 대상으로 일치성 기준 으로 하는 셀렉터를 다음과 같이 이용할 수 있다.
kubectl get pods -l environment=production,tier=frontend
또는 집합성 기준 요건을 사용하면
kubectl get pods -l 'environment in (production),tier in (frontend)'
앞서 안내한 것처럼 집합성 기준 요건은 더 보여준다. 예시에서 다음과 같이 OR 연산자를 구현할 수 있다.
kubectl get pods -l 'environment in (production, qa)'
또는 exists 연산자에 불일치한 것으로 제한할 수 있다.
kubectl get pods -l 'environment,environment notin (frontend)'
API 오브젝트에서 참조 설정
services
와
replicationcontrollers
와 같은
일부 쿠버네티스 오브젝트는 레이블 셀렉터를 사용해서
파드와 같은 다른 리소스 집합을 선택한다.
서비스와 레플리케이션 컨트롤러
services
에서 지정하는 파드 집합은 레이블 셀렉터로 정의한다. 마찬가지로 replicationcontrollers
가 관리하는 파드의 오브젝트 그룹도 레이블 셀렉터로 정의한다.
서비스와 레플리케이션 컨트롤러의 레이블 셀렉터는 json
또는 yaml
파일에 매핑된 일치성 기준 요구사항의 셀렉터만 지원한다.
"selector": {
"component" : "redis",
}
or
selector:
component: redis
json
또는 yaml
서식에서 셀렉터는 component=redis
또는 component in (redis)
모두 같은 것이다.
세트-기반 요건을 지원하는 리소스
Job
,
Deployment
,
ReplicaSet
그리고
DaemonSet
같은
새로운 리소스들은 집합성 기준 의 요건도 지원한다.
selector:
matchLabels:
component: redis
matchExpressions:
- {key: tier, operator: In, values: [cache]}
- {key: environment, operator: NotIn, values: [dev]}
matchLabels
는 {key,value}
의 쌍과 매칭된다. matchLabels
에 매칭된 단일 {key,value}
는 matchExpressions
의 요소와 같으며 key
필드는 "key"로, operator
는 "In" 그리고 values
에는 "value"만 나열되어 있다. matchExpressions
는 파드 셀렉터의 요건 목록이다. 유효한 연산자에는 In, NotIn, Exists 및 DoNotExist가 포함된다. In 및 NotIn은 설정된 값이 있어야 한다. matchLabels
와 matchExpressions
모두 AND로 되어 있어 일치하기 위해서는 모든 요건을 만족해야 한다.
노드 셋 선택
레이블을 통해 선택하는 사용 사례 중 하나는 파드를 스케줄 할 수 있는 노드 셋을 제한하는 것이다. 자세한 내용은 노드 선택 문서를 참조한다.
4.6 - 어노테이션
쿠버네티스 어노테이션을 사용하여 임의의 비-식별 메타데이터를 오브젝트에 첨부할 수 있다. 도구 및 라이브러리와 같은 클라이언트는 이 메타데이터를 검색할 수 있다.
오브젝트에 메타데이터 첨부
레이블이나 어노테이션을 사용하여 쿠버네티스 오브젝트에 메타데이터를 첨부할 수 있다. 레이블을 사용하여 오브젝트를 선택하고, 특정 조건을 만족하는 오브젝트 컬렉션을 찾을 수 있다. 반면에, 어노테이션은 오브젝트를 식별하고 선택하는데 사용되지 않는다. 어노테이션의 메타데이터는 작거나 크고, 구조적이거나 구조적이지 않을 수 있으며, 레이블에서 허용되지 않는 문자를 포함할 수 있다.
어노테이션은 레이블과 같이 키/값 맵이다.
"metadata": {
"annotations": {
"key1" : "value1",
"key2" : "value2"
}
}
다음은 어노테이션에 기록할 수 있는 정보의 예제이다.
-
필드는 선언적 구성 계층에 의해 관리된다. 이러한 필드를 어노테이션으로 첨부하는 것은 클라이언트 또는 서버가 설정한 기본 값, 자동 생성된 필드, 그리고 오토사이징 또는 오토스케일링 시스템에 의해 설정된 필드와 구분된다.
-
빌드, 릴리스, 또는 타임 스탬프, 릴리스 ID, git 브랜치, PR 번호, 이미지 해시 및 레지스트리 주소와 같은 이미지 정보.
-
로깅, 모니터링, 분석 또는 감사 리포지터리에 대한 포인터.
-
디버깅 목적으로 사용될 수 있는 클라이언트 라이브러리 또는 도구 정보: 예를 들면, 이름, 버전, 그리고 빌드 정보.
-
다른 생태계 구성 요소의 관련 오브젝트 URL과 같은 사용자 또는 도구/시스템 출처 정보.
-
경량 롤아웃 도구 메타데이터. 예: 구성 또는 체크포인트
-
책임자의 전화번호 또는 호출기 번호, 또는 팀 웹 사이트 같은 해당 정보를 찾을 수 있는 디렉터리 진입점.
-
행동을 수정하거나 비표준 기능을 수행하기 위한 최종 사용자의 지시 사항.
어노테이션을 사용하는 대신, 이 유형의 정보를 외부 데이터베이스 또는 디렉터리에 저장할 수 있지만, 이는 배포, 관리, 인트로스펙션(introspection) 등을 위한 공유 클라이언트 라이브러리와 도구 생성을 훨씬 더 어렵게 만들 수 있다.
문법과 캐릭터 셋
어노테이션 은 키/값 쌍이다. 유효한 어노테이션 키에는 두 개의 세그먼트가 있다. 두 개의 세그먼트는 선택적인 접두사와 이름(name)이며, 슬래시(/
)로 구분된다. 이름 세그먼트는 필수이며, 영문 숫자([a-z0-9A-Z]
)로 시작하고 끝나는 63자 이하이어야 하고, 사이에 대시(-
), 밑줄(_
), 점(.
)이 들어갈 수 있다. 접두사는 선택적이다. 지정된 경우, 접두사는 DNS 서브도메인이어야 한다. 점(.
)으로 구분된 일련의 DNS 레이블은 총 253자를 넘지 않고, 뒤에 슬래시(/
)가 붙는다.
접두사가 생략되면, 어노테이션 키는 사용자에게 비공개로 간주된다. 최종 사용자 오브젝트에 어노테이션을 추가하는 자동화된 시스템 구성 요소(예 :kube-scheduler
, kube-controller-manager
, kube-apiserver
, kubectl
, 또는 다른 써드파티 자동화)는 접두사를 지정해야 한다.
kubernetes.io/
와 k8s.io/
접두사는 쿠버네티스 핵심 구성 요소를 위해 예약되어 있다.
다음은 imageregistry: https://hub.docker.com/
어노테이션이 있는 파드의 구성 파일 예시이다.
apiVersion: v1
kind: Pod
metadata:
name: annotations-demo
annotations:
imageregistry: "https://hub.docker.com/"
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
다음 내용
레이블과 셀렉터에 대해 알아본다.
4.7 - 필드 셀렉터
필드 셀렉터 는 한 개 이상의 리소스 필드 값에 따라 쿠버네티스 리소스를 선택하기 위해 사용된다. 필드 셀렉터 쿼리의 예시는 다음과 같다.
metadata.name=my-service
metadata.namespace!=default
status.phase=Pending
다음의 kubectl
커맨드는 status.phase
필드의 값이 Running
인 모든 파드를 선택한다.
kubectl get pods --field-selector status.phase=Running
kubectl
쿼리인 kubectl get pods
와 kubectl get pods --field-selector ""
는 동일하다.
사용 가능한 필드
사용 가능한 필드는 쿠버네티스의 리소스 종류에 따라서 다르다. 모든 리소스 종류는 metadata.name
과 metadata.namespace
필드 셀렉터를 사용할 수 있다. 사용할 수 없는 필드 셀렉터를 사용하면 다음과 같이 에러를 출력한다.
kubectl get ingress --field-selector foo.bar=baz
Error from server (BadRequest): Unable to find "ingresses" that match label selector "", field selector "foo.bar=baz": "foo.bar" is not a known field selector: only "metadata.name", "metadata.namespace"
사용 가능한 연산자
필드 셀렉터에서 =
, ==
, !=
연산자를 사용할 수 있다 (=
와 ==
는 동일한 의미이다). 예를 들면, 다음의 kubectl
커맨드는 default
네임스페이스에 속해있지 않은 모든 쿠버네티스 서비스를 선택한다.
kubectl get services --all-namespaces --field-selector metadata.namespace!=default
연계되는 셀렉터
레이블을 비롯한 다른 셀렉터처럼, 쉼표로 구분되는 목록을 통해 필드 셀렉터를 연계해서 사용할 수 있다. 다음의 kubectl
커맨드는 status.phase
필드가 Running
이 아니고, spec.restartPolicy
필드가 Always
인 모든 파드를 선택한다.
kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always
여러 개의 리소스 종류
필드 셀렉터를 여러 개의 리소스 종류에 걸쳐 사용할 수 있다. 다음의 kubectl
커맨드는 default
네임스페이스에 속해있지 않은 모든 스테이트풀셋(StatefulSet)과 서비스를 선택한다.
kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default
4.8 - 권장 레이블
kubectl과 대시보드와 같은 많은 도구들로 쿠버네티스 오브젝트를 시각화 하고 관리할 수 있다. 공통 레이블 셋은 모든 도구들이 이해할 수 있는 공통의 방식으로 오브젝트를 식별하고 도구들이 상호 운용적으로 작동할 수 있도록 한다.
권장 레이블은 지원 도구 외에도 쿼리하는 방식으로 애플리케이션을 식별하게 한다.
메타데이터는 애플리케이션 의 개념을 중심으로 정리된다. 쿠버네티스는 플랫폼 서비스(PaaS)가 아니며 애플리케이션에 대해 공식적인 개념이 없거나 강요하지 않는다. 대신 애플리케이션은 비공식적이며 메타데이터로 설명된다. 애플리케이션에 포함된 정의는 유연하다.
공유 레이블과 주석에는 공통 접두사인 app.kubernetes.io
가 있다.
접두사가 없는 레이블은 사용자가 개인적으로 사용할 수 있다.
공유 접두사는 공유 레이블이 사용자 정의 레이블을 방해하지 않도록 한다.
레이블
레이블을 최대한 활용하려면 모든 리소스 오브젝트에 적용해야 한다.
키 | 설명 | 예시 | 타입 |
---|---|---|---|
app.kubernetes.io/name |
애플리케이션 이름 | mysql |
문자열 |
app.kubernetes.io/instance |
애플리케이션의 인스턴스를 식별하는 고유한 이름 | mysql-abcxzy |
문자열 |
app.kubernetes.io/version |
애플리케이션의 현재 버전 (예: a semantic version, revision hash 등.) | 5.7.21 |
문자열 |
app.kubernetes.io/component |
아키텍처 내 구성요소 | database |
문자열 |
app.kubernetes.io/part-of |
이 애플리케이션의 전체 이름 | wordpress |
문자열 |
app.kubernetes.io/managed-by |
애플리케이션의 작동을 관리하는 데 사용되는 도구 | helm |
문자열 |
app.kubernetes.io/created-by |
이 리소스를 만든 컨트롤러/사용자 | controller-manager |
문자열 |
위 레이블의 실제 예시는 다음 스테이트풀셋 오브젝트를 고려한다.
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app.kubernetes.io/name: mysql
app.kubernetes.io/instance: mysql-abcxzy
app.kubernetes.io/version: "5.7.21"
app.kubernetes.io/component: database
app.kubernetes.io/part-of: wordpress
app.kubernetes.io/managed-by: helm
app.kubernetes.io/created-by: controller-manager
애플리케이션과 애플리케이션 인스턴스
애플리케이션은 동일한 쿠버네티스 클러스터에, 심지어는 동일한 네임스페이스에도 한번 또는 그 이상 설치될 수 있다. 예를 들어, 하나의 쿠버네티스 클러스터에 WordPress가 여러 번 설치되어 각각 서로 다른 웹사이트를 서비스할 수 있다.
애플리케이션의 이름과 애플리케이션 인스턴스 이름은 별도로 기록된다.
예를 들어 WordPress는 애플리케이션 이름으로 app.kubernetes.io/name
이라는 레이블에 wordpress
라는 값을 가지며,
애플리케이션 인스턴스 이름으로는 app.kubernetes.io/instance
라는 레이블에
wordpress-abcxzy
라는 값을 가진다. 이를 통해 애플리케이션과 애플리케이션 인스턴스를
식별할 수 있다. 모든 애플리케이션 인스턴스는 고유한 이름을 가져야 한다.
예시
위 레이블을 사용하는 다른 방식에 대한 예시는 다양한 복잡성이 있다.
단순한 스테이트리스 서비스
Deployment
와 Service
오브젝트를 통해 배포된 단순한 스테이트리스 서비스의 경우를 보자. 다음 두 식별자는 레이블을 가장 간단한 형태로 사용하는 방법을 나타낸다.
Deployment
는 애플리케이션을 실행하는 파드를 감시하는 데 사용한다.
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: myservice
app.kubernetes.io/instance: myservice-abcxzy
...
Service
는 애플리케이션을 노출하기 위해 사용한다.
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: myservice
app.kubernetes.io/instance: myservice-abcxzy
...
데이터베이스가 있는 웹 애플리케이션
Helm을 이용해서 데이터베이스(MySQL)을 이용하는 웹 애플리케이션(WordPress)을 설치한 것과 같이 좀 더 복잡한 애플리케이션을 고려할 수 있다. 다음 식별자는 이 애플리케이션을 배포하는 데 사용하는 오브젝트의 시작을 보여준다.
WordPress를 배포하는 데 다음과 같이 Deployment
로 시작한다.
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: wordpress
app.kubernetes.io/instance: wordpress-abcxzy
app.kubernetes.io/version: "4.9.4"
app.kubernetes.io/managed-by: helm
app.kubernetes.io/component: server
app.kubernetes.io/part-of: wordpress
...
Service
는 애플리케이션을 노출하기 위해 사용한다.
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: wordpress
app.kubernetes.io/instance: wordpress-abcxzy
app.kubernetes.io/version: "4.9.4"
app.kubernetes.io/managed-by: helm
app.kubernetes.io/component: server
app.kubernetes.io/part-of: wordpress
...
MySQL은 StatefulSet
에 MySQL의 소속과 상위 애플리케이션에 대한 메타데이터가 포함되어 노출된다.
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app.kubernetes.io/name: mysql
app.kubernetes.io/instance: mysql-abcxzy
app.kubernetes.io/version: "5.7.21"
app.kubernetes.io/managed-by: helm
app.kubernetes.io/component: database
app.kubernetes.io/part-of: wordpress
...
Service
는 WordPress의 일부로 MySQL을 노출하는 데 이용한다.
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: mysql
app.kubernetes.io/instance: mysql-abcxzy
app.kubernetes.io/version: "5.7.21"
app.kubernetes.io/managed-by: helm
app.kubernetes.io/component: database
app.kubernetes.io/part-of: wordpress
...
MySQL StatefulSet
과 Service
로 MySQL과 WordPress가 더 큰 범위의 애플리케이션에 포함되어 있는 것을 알게 된다.