이 섹션의 다중 페이지 출력 화면임. 여기를 클릭하여 프린트.
클러스터 내 어플리케이션 접근
- 1: 웹 UI (대시보드)
- 2: 클러스터 접근
- 3: 다중 클러스터 접근 구성
- 4: 포트 포워딩을 사용해서 클러스터 내 애플리케이션에 접근하기
- 5: 클러스터 내 애플리케이션에 접근하기 위해 서비스 사용하기
- 6: 서비스를 사용하여 프론트엔드를 백엔드에 연결
- 7: 클러스터 내 모든 컨테이너 이미지 목록 보기
- 8: 공유 볼륨을 이용하여 동일한 파드의 컨테이너 간에 통신하기
- 9: 클러스터의 DNS 구성하기
1 - 웹 UI (대시보드)
대시보드는 웹 기반 쿠버네티스 유저 인터페이스이다. 대시보드를 통해 컨테이너화 된 애플리케이션을 쿠버네티스 클러스터에 배포할 수 있고, 컨테이너화 된 애플리케이션을 트러블슈팅할 수 있으며, 클러스터 리소스들을 관리할 수 있다. 대시보드를 통해 클러스터에서 동작 중인 애플리케이션의 정보를 볼 수 있고, 개별적인 쿠버네티스 리소스들을(예를 들면 디플로이먼트, 잡, 데몬셋 등) 생성하거나 수정할 수 있다. 예를 들면, 디플로이먼트를 스케일하거나, 롤링 업데이트를 초기화하거나, 파드를 재시작하거나 또는 배포 마법사를 이용해 새로운 애플리케이션을 배포할 수 있다.
또한 대시보드는 클러스터 내 쿠버네티스 리소스들의 상태와 발생하는 모든 에러 정보를 제공한다.
대시보드 UI 배포
대시보드 UI는 기본으로 배포되지 않는다. 배포하려면 다음 커맨드를 동작한다.
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml
대시보드 UI 접근
클러스터 데이터를 보호하기 위해, 대시보드는 기본적으로 최소한의 RBAC 설정을 제공한다. 현재, 대시보드는 Bearer 토큰으로 로그인 하는 방법을 제공한다. 본 시연을 위한 토큰을 생성하기 위해서는, 샘플 사용자 만들기 가이드를 따른다.
커맨드 라인 프록시
kubectl 커맨드라인 도구를 이용해 다음 커맨드를 실행함으로써 대시보드를 사용할 수 있다.
kubectl proxy
kubectl은 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/에 대시보드를 사용하는 것을 가능하게 해줄 것이다.
UI는 커맨드가 실행된 머신에서 오직 접근 가능하다. 상세 내용은 kubectl proxy --help
옵션을 확인한다.
웰컴 뷰
초기 클러스터 대시보드에 접근하면, 환영 페이지를 볼 수 있다.
이 페이지는 첫 애플리케이션을 배포하는 버튼이 있을 뿐만 아니라, 이 문서의 링크를 포함하고 있다.
게다가, 대시보드가 있는 클러스터에서 기본적으로 kube-system
네임스페이스이 동작중인 시스템 애플리케이션을 볼 수 있다.
컨테이너화 된 애플리케이션 배포
대시보드를 이용하여 컨테이너화 된 애플리케이션을 디플로이먼트와 간단한 마법사를 통한 선택적인 서비스로 생성하고 배포할 수 있다. 애플리케이션 세부 정보를 수동으로 지정할 수 있고, 또는 애플리케이션 구성을 포함한 YAML, JSON 파일을 업로드할 수 있다.
시작하는 페이지의 상위 오른쪽 코너에 있는 CREATE 버튼을 클릭한다.
애플리케이션 세부 정보 지정
배포 마법사는 다음 정보를 제공한다.
-
앱 이름 (필수): 애플리케이션 이름. 레이블 이름은 배포할 모든 디플로이먼트와 서비스에 추가되어야 한다.
애플리케이션 이름은 선택된 쿠버네티스 네임스페이스 안에서 유일해야 한다. 소문자로 시작해야 하며, 소문자 또는 숫자로 끝나고, 소문자, 숫자 및 대쉬(-)만을 포함해야 한다. 24 문자만을 제한한다. 처음과 끝의 스페이스는 무시된다.
-
컨테이너 이미지 (필수): 레지스트리에 올라간 퍼블릭 도커 컨테이너 이미지 또는 프라이빗 이미지(대체로 Google Container Registry 또는 도커 허브에 올라간)의 URL. 컨테이너 이미지 사양은 콜론으로 끝난다.
-
파드의 수 (필수): 배포하고 싶은 애플리케이션의 원하는 목표 파드 개수. 값은 양의 정수만 허용됩니다.
클러스터에 의도한 파드의 수를 유지하기 위해서 디플로이먼트가 생성될 것이다.
-
서비스 (선택): 일부 애플리케이션의 경우, (예를 들어, 프론트엔드) 아마도 클러스터 바깥의 퍼블릭 IP 주소를 가진 (외부 서비스) 외부에 서비스를 노출시키고 싶을 수 있다.
참고: 외부 서비스들을 위해, 한 개 또는 여러 개의 포트를 열어 둘 필요가 있다.클러스터 내부에서만 보고 싶은 어떤 서비스들이 있을 것이다. 이를 내부 서비스라고 한다.
서비스 타입과는 무관하게, 서비스 생성을 선택해서 컨테이너의 (들어오는 패킷의) 포트를 리슨한다면, 두 개의 포트를 정의해야 한다. 서비스는 컨테이너가 바라보는 타겟 포트와 (들어오는 패킷의) 맵핑하는 포트가 만들어져야 할 것이다. 서비스는 배포된 파드에 라우팅 될 것이다. 지원하는 프로토콜은 TCP와 UDP이다. 서비스가 이용하는 내부 DNS 이름은 애플리케이션 이름으로 지정한 값이 될 것이다.
만약 필요하다면, 더 많은 세팅을 지정할 수 있는 자세한 옵션 보기 섹션에서 확장할 수 있다.
-
설명: 입력하는 텍스트값은 디플로이먼트에 어노테이션으로 추가될 것이고, 애플리케이션의 세부사항에 표시될 것이다.
-
레이블: 애플리케이션에 사용되는 기본적인 레이블은 애플리케이션 이름과 버전이다. 릴리스, 환경, 티어, 파티션, 그리고 릴리스 트랙과 같은 레이블을 디플로이먼트, 서비스, 그리고 파드를 생성할 때 추가적으로 정의할 수 있다.
예를 들면:
release=1.0 tier=frontend environment=pod track=stable
-
네임스페이스: 쿠버네티스는 동일한 물리 클러스터를 바탕으로 여러 가상의 클러스터를 제공한다. 이러한 가상 클러스터들을 네임스페이스라고 부른다. 논리적으로 명명된 그룹으로 리소스들을 분할할 수 있다.
대시보드는 드롭다운 리스트로 가능한 모든 네임스페이스를 제공하고, 새로운 네임스페이스를 생성할 수 있도록 한다. 네임스페이스 이름은 최대 63개의 영숫자 단어와 대시(-)를 포함하고 있지만 대문자를 가지지 못한다. 네임스페이스 이름은 숫자로만 구성할 수 없다. 만약 이름을 10이라는 숫자로 세팅한다면, 파드는 기본 네임스페이스로 배정하게 될 것이다.
네임스페이스 생성이 성공하는 경우, 생성된 네임스페이스가 기본으로 선택된다. 만약 생성에 실패하면, 첫 번째 네임스페이스가 선택된다.
-
이미지 풀(Pull) 시크릿: 특정 도커 컨테이너 이미지가 프라이빗한 경우, 풀(Pull) 시크릿 자격 증명을 요구한다.
대시보드는 가능한 모든 시크릿을 드롭다운 리스트로 제공하며, 새로운 시크릿을 생성할 수 있도록 한다. 시크릿 이름은 예를 들어
new.image-pull.secret
과 같이 DNS 도메인 이름 구문으로 따르기로 한다. 시크릿 내용은 base64 인코딩 방식이며,.dockercfg
파일로 정의된다. 시크릿 이름은 최대 253 문자를 포함할 수 있다.이미지 풀(Pull) 시크릿의 생성이 성공한 경우, 기본으로 선택된다. 만약 생성에 실패하면, 시크릿은 허용되지 않는다.
-
CPU 요구 사항 (cores) 와 메모리 요구 사항 (MiB): 컨테이너를 위한 최소 리소스 상한을 정의할 수 있다. 기본적으로, 파드는 CPU와 메모리 상한을 두지 않고 동작한다.
-
커맨드 실행 와 커맨드 인수 실행: 기본적으로, 컨테이너는 선택된 도커 이미지의 기본 엔트리포인트 커맨드를 실행한다. 커맨드 옵션과 인자를 기본 옵션에 우선 적용하여 사용할 수 있다.
-
특권을 가진(privileged) 상태로 실행: 다음 세팅은 호스트에서 루트 권한을 가진 프로세스들이 특권을 가진 컨테이너의 프로세스들과 동등한지 아닌지 정의한다. 특권을 가진(privileged) 컨테이너는 네트워크 스택과 디바이스에 접근하는 것을 조작하도록 활용할 수 있다.
-
환경 변수: 쿠버네티스 서비스를 환경 변수를 통해 노출한다. 환경 변수 또는 인자를 환경 변수들의 값으로 커맨드를 통해 구성할 수 있다. 애플리케이션들이 서비스를 찾는데 사용된다. 값들은
$(VAR_NAME)
구문을 사용하는 다른 변수들로 참조할 수 있다.
YAML 또는 JSON 파일 업로드
쿠버네티스는 선언적인 설정을 제공한다. 이 방식으로 모든 설정은 쿠버네티스 API 리소스 스키마를 이용하여 YAML 또는 JSON 설정 파일에 저장한다.
배포 마법사를 통해 애플리케이션 세부사항들을 지정하는 대신, 애플리케이션을 YAML 또는 JSON 파일로 정의할 수 있고 대시보드를 이용해서 파일을 업로드할 수 있다.
대시보드 사용
다음 섹션들은 어떻게 제공하고 어떻게 사용할 수 있는지에 대한 쿠버네티스 대시보드 UI의 모습을 보여준다.
탐색
클러스터에 정의된 쿠버네티스 오프젝트가 있으면, 대시보드는 초기화된 뷰를 제공한다. 기본적으로 기본 네임스페이스의 오프젝트만이 보이는데, 이는 탐색 창에 위치한 네임스페이스 셀렉터를 이용해 변경할 수 있다.
대시보드는 몇가지 메뉴 카테고리 중에서 대부분의 쿠버네티스 오브젝트 종류와 그룹을 보여준다.
어드민 개요
클러스터와 네임스페이스 관리자에게 대시보드는 노드, 네임스페이스 그리고 퍼시스턴트 볼륨과 세부사항들이 보여진다. 노드는 모든 노드를 통틀어 CPU와 메모리 사용량을 보여준다. 세부사항은 각 노드들에 대한 사용량, 사양, 상태, 할당된 리소스, 이벤트 그리고 노드에서 돌아가는 파드를 보여준다.
워크로드
선택된 네임스페이스에서 구동되는 모든 애플리케이션을 보여준다. 애플리케이션의 워크로드 종류(예를 들어, 디플로이먼트, 레플리카셋(ReplicaSet), 스테이트풀셋(StatefulSet) 등)를 보여주고 각각의 워크로드 종류는 따로 보여진다. 리스트는 예를 들어 레플리카셋에서 준비된 파드의 숫자 또는 파드의 현재 메모리 사용량과 같은 워크로드에 대한 실용적인 정보를 요약한다.
워크로드에 대한 세부적인 것들은 상태와 사양 정보, 오프젝트들 간의 관계를 보여준다. 예를 들어, 레플리카셋으로 관리하는 파드들 또는 새로운 레플리카셋과 디플로이먼트를 위한 Horizontal Pod Autoscalers 이다.
서비스
외부로 노출되는 서비스들과 클러스터 내에 발견되는 서비스들을 허용하는 쿠버네티스 리소스들을 보여준다. 이러한 이유로 서비스와 인그레스는 클러스터간의 연결을 위한 내부 엔드포인트들과 외부 사용자를 위한 외부 엔드포인트들에 의해 타게팅된 파드들을 보여준다.
스토리지
스토리지는 애플리케이션이 데이터를 저장하기 위해 사용하는 퍼시턴트 볼륨 클레임 리소스들을 보여준다.
컨피그 맵과 시크릿
클러스터에서 동작 중인 애플리케이션의 라이브 설정을 사용하는 모든 쿠버네티스 리소스들을 보여준다. 컨피그 오브젝트들을 수정하고 관리할 수 있도록 허용하며, 기본적으로는 숨겨져 있는 시크릿들을 보여준다.
로그 뷰어
파드 목록과 세부사항 페이지들은 대시보드에 구현된 로그 뷰어에 링크된다. 뷰어는 단일 파드에 있는 컨테이너들의 로그들을 내려가면 볼 수 있도록 한다.
다음 내용
더 많은 정보는 쿠버네티스 대시보드 프로젝트 페이지를 참고한다.
2 - 클러스터 접근
여기에서는 클러스터와 통신을 하는 다양한 방식에 대해서 다룰 것이다.
처음이라면 kubectl을 사용하여 접근
최초로 쿠버네티스 API에 접근할 때 우리는
쿠버네티스 CLI인 kubectl
을 사용하는 것을 추천한다.
클러스터에 접근하려면 클러스터의 위치정보를 알아야 하고 클러스터에 접속하기 위한 인증정보를 가져야 한다. 일반적으로 이는 당신이 Getting started guide를 다 진행했을 때 자동으로 구성되거나, 다른 사람이 클러스터를 구성하고 당신에게 인증정보와 위치정보를 제공할 수도 있다.
kubectl이 인지하는 위치정보와 인증정보는 다음 커맨드로 확인한다.
kubectl config view
여기에서 kubectl 사용 예시를 볼 수 있으며, 완전한 문서는 kubectl 매뉴얼에서 확인할 수 있다.
REST API에 직접 접근
kubectl은 apiserver의 위치 파악과 인증을 처리한다. 만약 당신이 curl, wget 또는 웹브라우저와 같은 http 클라이언트로 REST API에 직접 접근하려고 한다면 위치 파악과 인증을 하는 몇 가지 방법이 존재한다.
- kubectl을 proxy 모드로 실행.
- 권장하는 접근 방식.
- 저장된 apiserver 위치를 사용.
- self-signed 인증서를 사용하여 apiserver의 identity를 검증. MITM은 불가능.
- apiserver 인증.
- 앞으로는 클라이언트 측의 지능형 load balancing과 failover가 될 것이다.
- 직접적으로 http 클라이언트에 위치정보와 인증정보를 제공.
- 대안적인 접근 방식.
- proxy 사용과 혼동되는 몇 가지 타입의 클라이언트 코드와 같이 동작한다.
- MITM로부터 보호를 위해 root 인증서를 당신의 브라우저로 임포트해야 한다.
kubectl proxy 사용
다음 커맨드는 kubectl을 리버스 프록시(reverse proxy)처럼 동작하는 모드를 실행한다. 이는 apiserver의 위치지정과 인증을 처리한다. 다음과 같이 실행한다.
kubectl proxy --port=8080
상세 내용은 kubectl proxy를 참조한다
이후에 당신은 curl, wget, 웹브라우저로 다음과 같이 API를 탐색할 수 있다. localhost는 IPv6 주소 [::1]로도 대체할 수 있다.
curl http://localhost:8080/api/
결괏값은 다음과 같을 것이다.
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.0.1.149:443"
}
]
}
kubectl proxy를 사용하지 않음
기본 서비스 어카운트의 토큰을 얻어내려면 kubectl describe secret...
을 grep/cut과 함께 사용한다.
APISERVER=$(kubectl config view --minify | grep server | cut -f 2- -d ":" | tr -d " ")
SECRET_NAME=$(kubectl get secrets | grep ^default | cut -f1 -d ' ')
TOKEN=$(kubectl describe secret $SECRET_NAME | grep -E '^token' | cut -f2 -d':' | tr -d " ")
curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
결과값은 다음과 같을 것이다.
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.0.1.149:443"
}
]
}
jsonpath
를 사용한다면 다음과 같다.
APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
SECRET_NAME=$(kubectl get serviceaccount default -o jsonpath='{.secrets[0].name}')
TOKEN=$(kubectl get secret $SECRET_NAME -o jsonpath='{.data.token}' | base64 --decode)
curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
결과값은 다음과 같을 것이다.
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.0.1.149:443"
}
]
}
위 예제에서는 --insecure
flag를 사용했다. 이는 MITM 공격을 받을 수 있는 상태로
두는 것이다. kubectl로 클러스터에 접속할 때 저장된 root 인증서와 클라이언트 인증서들을
서버 접속에 사용한다.
(이들은 ~/.kube
디렉터리에 설치된다.)
일반적으로 self-signed 인증서가 클러스터 인증서로 사용되므로 당신의 http 클라이언트가
root 인증서를 사용하려면 특수한 설정을 필요로 할 것이다.
localhost에서 제공되거나 방화벽으로 보호되는 몇몇 클러스터들에서는 apiserver가 인증을 요구하지 않지만 이는 표준이 아니다. API에 대한 접근 제어은 클러스터 관리자가 이를 어떻게 구성할 수 있는지를 설명한다.
API에 프로그래밍 방식으로 접근
쿠버네티스는 공식적으로 Go와 Python 클라이언트 라이브러리를 지원한다.
Go 클라이언트
- 라이브러리를 취득하려면
go get k8s.io/client-go@kubernetes-<kubernetes-version-number>
커맨드를 실행한다. INSTALL.md에서 상세한 설치 방법을 알 수 있다. https://github.com/kubernetes/client-go에서 어떤 버젼이 지원되는지 확인할 수 있다. - client-go 클라이언트 위에 애플리케이션을 작성하자. client-go는 자체적으로 API 오브젝트를 정의하므로 필요하다면 main 레포지터리보다는 client-go에서 API 정의들을 import하기를 바란다. 정확하게
import "k8s.io/client-go/kubernetes"
로 import하는 것을 예로 들 수 있다.
Go 클라이언트는 apiserver의 위치지정과 인증에 kubectl CLI와 동일하게 kubeconfig file을 사용할 수 있다. 예제를 참고한다.
만약 애플리케이션이 클러스터 내에 파드로 배포되었다면 다음 장을 참조하기를 바란다.
Python 클라이언트
Python 클라이언트를 사용하려면 pip install kubernetes
커맨드를 실행한다. 설치 옵션에 대한 상세 사항은 Python Client Library page를 참조한다.
Python 클라이언트는 apiserver의 위치지정과 인증에 kubectl CLI와 동일하게 kubeconfig file을 사용할 수 있다. 예제를 참조한다.
다른 언어
다른 언어에서 API를 접속하기 위한 클라이언트 라이브러리들도 존재한다. 이들이 어떻게 인증하는지는 다른 라이브러리들의 문서를 참조한다.
파드에서 API 접근
파드에서 API를 접속한다면 apiserver의 위치지정과 인증은 다소 다르다.
파드 내에서 apiserver의 위치를 지정하는데 추천하는 방식은
kubernetes.default.svc
DNS 네임을 사용하는 것이다.
이 DNS 네임은 apiserver로 라우팅되는 서비스 IP로 resolve된다.
apiserver 인증에 추천되는 방식은
서비스 어카운트
인증정보를 사용하는 것이다. kube-system에 의해 파드는 서비스 어카운트와 연계되며
해당 서비스 어카운트의 인증정보(토큰)은 파드 내 각 컨테이너의 파일시스템 트리의
/var/run/secrets/kubernetes.io/serviceaccount/token
에 위치한다.
사용 가능한 경우, 인증서 번들은 각 컨테이너 내 파일시스템 트리의
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
에 위치하며
apiserver의 인증서 제공을 검증하는데 사용되어야 한다.
마지막으로 네임스페이스 한정의 API 조작에 사용되는 기본 네임스페이스는 각 컨테이터 내의
/var/run/secrets/kubernetes.io/serviceaccount/namespace
파일로 존재한다.
파드 내에서 API에 접근하는데 권장되는 방식은 다음과 같다.
- 파드의 sidecar 컨테이너 내에서
kubectl proxy
를 실행하거나, 컨테이너 내부에서 백그라운드 프로세스로 실행한다. 이는 쿠버네티스 API를 파드의 localhost 인터페이스로 프록시하여 해당 파드의 컨테이너 내에 다른 프로세스가 API에 접속할 수 있게 해준다. - Go 클라이언트 라이브러리를 이용하여
rest.InClusterConfig()
와kubernetes.NewForConfig()
함수들을 사용하도록 클라이언트를 만든다. 이는 apiserver의 위치지정과 인증을 처리한다. 예제
각각의 사례에서 apiserver와의 보안 통신에 파드의 인증정보가 사용된다.
클러스터에서 실행되는 서비스로 접근
이전 장은 쿠버네티스 API server 접속에 대한 내용을 다루었다. 이번 장은 쿠버네티스 클러스터 상에서 실행되는 다른 서비스로의 연결을 다룰 것이다.
쿠버네티스에서, 노드, 파드 및 서비스는 모두 고유한 IP를 가진다. 당신의 데스크탑 PC와 같은 클러스터 외부 장비에서는 클러스터 상의 노드 IP, 파드 IP, 서비스 IP로 라우팅되지 않아서 접근을 할 수 없을 것이다.
통신을 위한 방식들
클러스터 외부에서 노드, 파드 및 서비스에 접속하기 위한 몇 가지 옵션이 있다.
- 공인 IP를 통해 서비스에 접근.
- 클러스터 외부에서 접근할 수 있도록
NodePort
또는LoadBalancer
타입의 서비스를 사용한다. 서비스와 kubectl expose 문서를 참조한다. - 클러스터 환경에 따라, 서비스는 회사 네트워크에만 노출되기도 하며, 인터넷에 노출되는 경우도 있다. 이 경우 노출되는 서비스의 보안 여부를 고려해야 한다. 해당 서비스는 자체적으로 인증을 수행하는가?
- 파드는 서비스 뒤에 위치시킨다. 레플리카들의 집합에서 특정 파드 하나에 debugging 같은 목적으로 접근하려면 해당 파드에 고유의 레이블을 붙이고 셀렉터에 해당 레이블을 선택하는 신규 서비스를 생성한다.
- 대부분의 경우에는 애플리케이션 개발자가 노드 IP를 통해 직접 노드에 접근할 필요는 없다.
- 클러스터 외부에서 접근할 수 있도록
- Proxy Verb를 사용하여 서비스, 노드, 파드에 접근.
- 원격 서비스에 접근하기에 앞서 apiserver의 인증과 인가를 받아야 한다. 서비스가 인터넷에 노출하기에 보안이 충분하지 않거나 노드 IP 상의 포트에 접근을 하려고 하거나 debugging을 하려면 이를 사용한다.
- 어떤 web 애플리케이션에서는 프록시가 문제를 일으킬 수 있다.
- HTTP/HTTPS에서만 동작한다.
- 여기에서 설명하고 있다.
- 클러스터 내 노드 또는 파드에서 접근.
- 파드를 실행한 다음, kubectl exec를 사용하여 해당 파드의 셸로 접속한다. 해당 셸에서 다른 노드, 파드, 서비스에 연결한다.
- 어떤 클러스터는 클러스터 내의 노드에 ssh 접속을 허용하기도 한다. 이런 클러스터에서는 클러스터 서비스에 접근도 가능하다. 이는 비표준 방식으로 특정 클러스터에서는 동작하지만 다른 클러스터에서는 동작하지 않을 수 있다. 브라우저와 다른 도구들이 설치되지 않았거나 설치되었을 수 있다. 클러스터 DNS가 동작하지 않을 수도 있다.
빌트인 서비스 검색
일반적으로 kube-system에 의해 클러스터에 실행되는 몇 가지 서비스가 있다.
kubectl cluster-info
커맨드로 이 서비스의 리스트를 볼 수 있다.
kubectl cluster-info
결괏값은 다음과 같을 것이다.
Kubernetes master is running at https://104.197.5.247
elasticsearch-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy
kibana-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kibana-logging/proxy
kube-dns is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kube-dns/proxy
grafana is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy
heapster is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-heapster/proxy
이는 각 서비스에 접근하기 위한 proxy-verb URL을 보여준다.
예를 들어 위 클러스터는 클러스터 수준의 logging(Elasticsearch 사용)이 활성화되었으므로 적절한 인증을 통과하여
https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/
로 접근할 수 있다. 예를 들어 kubectl proxy로
http://localhost:8080/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/
를 통해 logging에 접근할 수도 있다.
(인증을 통과하는 방법이나 kubectl proxy를 사용하는 것은 쿠버네티스 API를 사용해서 클러스터에 접근하기을 참조한다.)
수작업으로 apiserver proxy URL을 구축
위에서 언급한 것처럼 서비스의 proxy URL을 검색하는 데 kubectl cluster-info
커맨드를 사용할 수 있다. 서비스 endpoint, 접미사, 매개변수를 포함하는 proxy URL을 생성하려면 해당 서비스에
http://
kubernetes_master_address
/api/v1/namespaces/
namespace_name
/services/
service_name[:port_name]
/proxy
형식의 proxy URL을 덧붙인다.
당신이 포트에 이름을 지정하지 않았다면 URL에 port_name 을 지정할 필요는 없다. 이름이 있는 포트와 이름이 없는 포트 모두에 대하여, port_name 이 들어갈 자리에 포트 번호를 기재할 수도 있다.
기본적으로 API server는 http를 사용하여 서비스를 프록시한다. https를 사용하려면 다음과 같이 서비스 네임의 접두사에 https:
를 붙인다.
http://
kubernetes_master_address
/api/v1/namespaces/
namespace_name
/services/
https:service_name:[port_name]
/proxy
URL의 네임 부분에 지원되는 양식은 다음과 같다.
<service_name>
- http를 사용하여 기본값 또는 이름이 없는 포트로 프록시한다.<service_name>:<port_name>
- http를 사용하여 지정된 포트 이름 또는 포트 번호로 프록시한다.https:<service_name>:
- https를 사용하여 기본값 또는 이름이 없는 포트로 프록시한다. (마지막 콜론:에 주의)https:<service_name>:<port_name>
- https를 사용하여 지정된 포트 이름 또는 포트 번호로 프록시한다.
예제들
- Elasticsearch 서비스 endpoint
_search?q=user:kimchy
에 접근하려면http://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/_search?q=user:kimchy
를 사용할 수 있다. - Elasticsearch 클러스터 상태 정보
_cluster/health?pretty=true
에 접근하려면https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/_cluster/health?pretty=true
를 사용할 수 있다.
{
"cluster_name" : "kubernetes_logging",
"status" : "yellow",
"timed_out" : false,
"number_of_nodes" : 1,
"number_of_data_nodes" : 1,
"active_primary_shards" : 5,
"active_shards" : 5,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 5
}
클러스터 상에서 실행되는 서비스에 웹브라우저를 사용하여 접근
브라우저의 주소창에 apiserver proxy url을 넣을 수도 있다. 하지만
- 웹브라우저는 일반적으로 토큰을 전달할 수 없으므로 basic (password) auth를 사용해야 할 것이다. basic auth를 수용할 수 있도록 apiserver를 구성할 수 있지만, 당신의 클러스터가 basic auth를 수용할 수 있도록 구성되어 있지 않을 수도 있다.
- 몇몇 web app은 동작하지 않을 수도 있다. 특히 proxy path prefix를 인식하지 않는 방식으로 url을 구성하는 client side javascript를 가진 web app은 동작하지 않을 수 있다.
요청 redirect
redirect 기능은 deprecated되고 제거 되었다. 대신 (아래의) 프록시를 사용하기를 바란다.
다양한 프록시들
쿠버네티스를 사용하면서 당신이 접할 수 있는 몇 가지 다른 프록시들이 존재한다.
-
- 사용자의 데스크탑이나 파드 내에서 실행한다
- localhost 주소에서 쿠버네티스 apiserver로 프록시한다
- 프록시하는 클라이언트는 HTTP를 사용한다
- apiserver의 프록시는 HTTPS를 사용한다
- apiserver를 위치지정한다
- 인증 header들을 추가한다
-
- apiserver 내의 빌트인 bastion이다
- 다른 방식으로는 연결할 수 없는 클러스터 외부의 사용자를 클러스터 IP로 연결한다
- apiserver process들 내에서 실행된다
- 프록시하는 클라이언트는 HTTPS를 사용한다(또는 apiserver가 http로 구성되었다면 http)
- 타겟으로의 프록시는 가용정보를 사용하는 프록시에 의해서 HTTP 또는 HTTPS를 사용할 수도 있다
- 노드, 파드, 서비스에 접근하는 데 사용될 수 있다
- 서비스에 접근하는 데 사용되면 load balacing한다
-
- 각 노드 상에서 실행된다
- UDP와 TCP를 프록시한다
- HTTP를 인지하지 않는다
- load balancing을 제공한다
- 서비스에 접근하는 데에만 사용된다
-
apiserver(s) 전면의 Proxy/Load-balancer:
- 존재내용과 구현사항은 클러스터 별로 다양하다(예. nginx)
- 모든 클라이언트와 하나 이상의 apiserver들의 사이에 위치한다
- apiserver가 여러 대 존재한다면 load balancer로 동작한다
-
외부 서비스의 Cloud Load Balancer들:
- Cloud provider들에 의해서 제공된다(예. AWS ELB, Google Cloud Load Balancer)
- 쿠버네티스 서비스의 타입이
LoadBalancer
라면 자동으로 생성된다 - UDP/TCP 만 사용한다
- cloud provider마다 구현된 내용이 상이하다
일반적으로 쿠버네티스 사용자들은 처음 두 타입이 아닌 다른 방식은 고려할 필요가 없지만 클러스터 관리자는 나머지 타입을 적절하게 구성해줘야 한다.
3 - 다중 클러스터 접근 구성
이 페이지에서는 구성 파일을 사용하여 다수의 클러스터에 접근할 수 있도록
설정하는 방식을 보여준다. 클러스터, 사용자, 컨텍스트가 하나 이상의
구성 파일에 정의된 다음 kubectl config use-context
커맨드를
사용하여 클러스터를 빠르게 변경할 수 있다.
kubeconfig
라는 이름을 가진 파일이
반드시 존재해야 한다는 것을 의미하는 것은 아니다.
시작하기 전에
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
kubectl이 설치되었는지 확인하려면,
kubectl version --client
을 실행한다. kubectl 버전은 클러스터의 API 서버 버전과
마이너 버전 하나 차이 이내여야
한다.
클러스터, 사용자, 컨텍스트 정의
당신이 개발 작업을 위한 클러스터와 스크래치 작업을 위한 클러스터를 가지고 있다고 가정해보자.
development
클러스터에서는 프런트 엔드 개발자들이 frontend
라는 네임스페이스에서
작업을 하고 있고, 스토리지 개발자들은 storage
라는 네임스페이스에서 작업을 하고 있다.
scratch
클러스터에서는 개발자들이 default 네임스페이스에서 개발하거나 필요에 따라 보조
네임스페이스들을 생성하고 있다. development 클러스터에 접근하려면 인증서로 인증을 해야 하고,
scratch 클러스터에 접근하려면 사용자네임과 패스워드로 인증을 해야 한다.
config-exercise
라는 디렉터리를 생성한다. config-exercise
디렉터리에
다음 내용을 가진 config-demo
라는 파일을 생성한다.
apiVersion: v1
kind: Config
preferences: {}
clusters:
- cluster:
name: development
- cluster:
name: scratch
users:
- name: developer
- name: experimenter
contexts:
- context:
name: dev-frontend
- context:
name: dev-storage
- context:
name: exp-scratch
구성 파일은 클러스터들, 사용자들, 컨텍스트들을 기술한다. config-demo
파일은 두 클러스터들과
두 사용자들, 세 컨텍스트들을 기술하기 위한 프레임워크를 가진다.
config-exercise
디렉터리로 이동한다. 그리고 다음 커맨드들을 실행하여 구성 파일에 클러스터의
세부사항들을 추가한다.
kubectl config --kubeconfig=config-demo set-cluster development --server=https://1.2.3.4 --certificate-authority=fake-ca-file
kubectl config --kubeconfig=config-demo set-cluster scratch --server=https://5.6.7.8 --insecure-skip-tls-verify
사용자의 세부사항들을 구성 파일에 추가한다.
kubectl config --kubeconfig=config-demo set-credentials developer --client-certificate=fake-cert-file --client-key=fake-key-seefile
kubectl config --kubeconfig=config-demo set-credentials experimenter --username=exp --password=some-password
- 사용자를 삭제하려면
kubectl --kubeconfig=config-demo config unset users.<name>
를 실행한다. - 클러스터를 제거하려면
kubectl --kubeconfig=config-demo config unset clusters.<name>
를 실행한다. - 컨텍스트를 제거하려면
kubectl --kubeconfig=config-demo config unset contexts.<name>
를 실행한다.
컨텍스트 세부사항들을 구성 파일에 추가한다.
kubectl config --kubeconfig=config-demo set-context dev-frontend --cluster=development --namespace=frontend --user=developer
kubectl config --kubeconfig=config-demo set-context dev-storage --cluster=development --namespace=storage --user=developer
kubectl config --kubeconfig=config-demo set-context exp-scratch --cluster=scratch --namespace=default --user=experimenter
config-demo
파일을 열어서 세부사항들이 추가되었는지 확인한다. config-demo
파일을 열어보는
것 대신에 config view
커맨드를 사용할 수도 있다.
kubectl config --kubeconfig=config-demo view
두 클러스터, 두 사용자, 세 컨텍스트들이 출력 결과로 나온다.
apiVersion: v1
clusters:
- cluster:
certificate-authority: fake-ca-file
server: https://1.2.3.4
name: development
- cluster:
insecure-skip-tls-verify: true
server: https://5.6.7.8
name: scratch
contexts:
- context:
cluster: development
namespace: frontend
user: developer
name: dev-frontend
- context:
cluster: development
namespace: storage
user: developer
name: dev-storage
- context:
cluster: scratch
namespace: default
user: experimenter
name: exp-scratch
current-context: ""
kind: Config
preferences: {}
users:
- name: developer
user:
client-certificate: fake-cert-file
client-key: fake-key-file
- name: experimenter
user:
password: some-password
username: exp
위 fake-ca-file
, fake-cert-file
, fake-key-file
은 인증서 파일들의 실제 경로 이름을 위한
플레이스홀더(placeholder)이다.
당신의 환경에 맞게 이들을 실제 인증서 경로로 변경해줘야 한다.
만약 당신이 인증서 파일들의 경로 대신에 여기에 포함된 base64로 인코딩된 데이터를 사용하려고 한다면
이 경우 키에 -data
접미사를 추가해야 한다. 예를 들면 certificate-authority-data
,
client-certificate-data
, client-key-data
같이 사용할 수 있다.
컨텍스트는 세 가지(클러스터, 사용자, 네임스페이스) 요소들로 이뤄진다. 예를 들어
dev-frontend
컨텍스트는 "development
클러스터의 frontend
네임스페이스에 접근하는데
developer
사용자 자격증명을 사용하라고 알려준다."
현재 컨텍스트를 설정한다.
kubectl config --kubeconfig=config-demo use-context dev-frontend
이제 당신이 kubectl
커맨드를 입력할 때마다 dev-frontend
컨텍스트에 명시된 클러스터와
네임스페이스 상에서 동작하게 될 것이다. 그리고 커맨드는 dev-frontend
컨텍스트 내에 명시된
사용자 자격증명을 사용할 것이다.
현재 컨텍스트에 관련된 구성 정보만을 보려면
--minify
플래그를 사용한다.
kubectl config --kubeconfig=config-demo view --minify
dev-frontend
컨텍스트에 관련된 구성 정보가 출력 결과로 표시될 것이다.
apiVersion: v1
clusters:
- cluster:
certificate-authority: fake-ca-file
server: https://1.2.3.4
name: development
contexts:
- context:
cluster: development
namespace: frontend
user: developer
name: dev-frontend
current-context: dev-frontend
kind: Config
preferences: {}
users:
- name: developer
user:
client-certificate: fake-cert-file
client-key: fake-key-file
이제 당신이 잠시 scratch 클러스터에서 작업하려고 한다고 가정해보자.
현재 컨텍스트를 exp-scratch
로 변경한다.
kubectl config --kubeconfig=config-demo use-context exp-scratch
이제 당신이 실행하는 모든 kubectl
커맨드는 scratch
클러스터의
default 네임스페이스에 적용되며 exp-scratch
컨텍스트에 나열된
사용자의 자격증명을 사용할 것이다.
현재의 컨텍스트인 exp-scratch
에 관련된 설정을 보자.
kubectl config --kubeconfig=config-demo view --minify
마지막으로 당신이 development
클러스터의 storage
네임스페이스에서
잠시 작업을 하려고 한다고 가정해보자.
현재 컨텍스트를 dev-storage
로 변경한다.
kubectl config --kubeconfig=config-demo use-context dev-storage
현재 컨텍스트인 dev-storage
에 관련된 설정을 보자.
kubectl config --kubeconfig=config-demo view --minify
두 번째 구성 파일 생성
config-exercise
디렉터리에서 다음 내용으로 config-demo-2
라는 파일을 생성한다.
apiVersion: v1
kind: Config
preferences: {}
contexts:
- context:
cluster: development
namespace: ramp
user: developer
name: dev-ramp-up
위 구성 파일은 dev-ramp-up
이라는 신규 컨텍스트를 정의한다.
KUBECONFIG 환경 변수 설정
KUBECONFIG
라는 환경 변수를 가지고 있는지 확인해보자. 만약 가지고 있다면,
이후에 복원할 수 있도록 KUBECONFIG
환경 변수의 현재 값을 저장한다.
예:
리눅스
export KUBECONFIG_SAVED=$KUBECONFIG
윈도우 PowerShell
$Env:KUBECONFIG_SAVED=$ENV:KUBECONFIG
KUBECONFIG
환경 변수는 구성 파일들의 경로의 리스트이다. 이 리스트는
리눅스와 Mac에서는 콜론으로 구분되며 윈도우에서는 세미콜론으로 구분된다.
KUBECONFIG
환경 변수를 가지고 있다면, 리스트에 포함된 구성 파일들에
익숙해지길 바란다.
다음 예와 같이 임시로 KUBECONFIG
환경 변수에 두 개의 경로들을 덧붙여보자.
리눅스
export KUBECONFIG=$KUBECONFIG:config-demo:config-demo-2
윈도우 PowerShell
$Env:KUBECONFIG=("config-demo;config-demo-2")
config-exercise
디렉터리에서 다음 커맨드를 입력한다.
kubectl config view
당신의 KUBECONFIG
환경 변수에 나열된 모든 파일들이 합쳐진 정보가 출력 결과로
표시될 것이다. 특히, 합쳐진 정보가 config-demo-2
파일의 dev-ramp-up
컨텍스트와 config-demo
파일의 세 개의 컨텍스트들을
가지고 있다는 것에 주목하길 바란다.
contexts:
- context:
cluster: development
namespace: frontend
user: developer
name: dev-frontend
- context:
cluster: development
namespace: ramp
user: developer
name: dev-ramp-up
- context:
cluster: development
namespace: storage
user: developer
name: dev-storage
- context:
cluster: scratch
namespace: default
user: experimenter
name: exp-scratch
kubeconfig 파일들을 어떻게 병합하는지에 대한 상세정보는 kubeconfig 파일을 사용하여 클러스터 접근 구성하기를 참조한다.
$HOME/.kube 디렉터리 탐색
만약 당신이 이미 클러스터를 가지고 있고 kubectl
을 사용하여
해당 클러스터를 제어하고 있다면, 아마 $HOME/.kube
디렉터리에 config
라는
파일을 가지고 있을 것이다.
$HOME/.kube
로 가서 어떤 파일들이 존재하는지 보자.
보통 config
라는 파일이 존재할 것이다. 해당 디렉터리 내에는 다른 구성 파일들도 있을 수 있다.
간단하게 말하자면 당신은 이 파일들의 컨텐츠에 익숙해져야 한다.
$HOME/.kube/config를 KUBECONFIG 환경 변수에 추가
당신이 $HOME/.kube/config
파일을 가지고 있는데 KUBECONFIG
환경 변수에 나타나지 않는다면 KUBECONFIG
환경 변수에 추가해보자.
예:
리눅스
export KUBECONFIG=$KUBECONFIG:$HOME/.kube/config
윈도우 Powershell
$Env:KUBECONFIG="$Env:KUBECONFIG;$HOME\.kube\config"
이제 KUBECONFIG
환경 변수에 리스트에 포함된 모든 파일들이 합쳐진 구성 정보를 보자.
config-exercise 디렉터리에서 다음 커맨드를 실행한다.
kubectl config view
정리
KUBECONFIG
환경 변수를 원래 값으로 되돌려 놓자. 예를 들면:
리눅스
export KUBECONFIG=$KUBECONFIG_SAVED
윈도우 PowerShell
$Env:KUBECONFIG=$ENV:KUBECONFIG_SAVED
다음 내용
4 - 포트 포워딩을 사용해서 클러스터 내 애플리케이션에 접근하기
이 페이지는 kubectl port-forward
를 사용해서 쿠버네티스 클러스터 내에서
실행중인 MongoDB 서버에 연결하는 방법을 보여준다. 이 유형의 연결은 데이터베이스
디버깅에 유용할 수 있다.
시작하기 전에
-
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
쿠버네티스 서버의 버전은 다음과 같거나 더 높아야 함. 버전: v1.10. 버전 확인을 위해서, 다음 커맨드를 실행kubectl version
. -
MongoDB Shell을 설치한다.
MongoDB 디플로이먼트와 서비스 생성하기
-
MongoDB를 실행하기 위해 디플로이먼트를 생성한다.
kubectl apply -f https://k8s.io/examples/application/mongodb/mongo-deployment.yaml
성공적인 명령어의 출력은 디플로이먼트가 생성됐다는 것을 확인해준다.
deployment.apps/mongo created
파드 상태를 조회하여 파드가 준비되었는지 확인한다.
kubectl get pods
출력은 파드가 생성되었다는 것을 보여준다.
NAME READY STATUS RESTARTS AGE mongo-75f59d57f4-4nd6q 1/1 Running 0 2m4s
디플로이먼트 상태를 조회한다.
kubectl get deployment
출력은 디플로이먼트가 생성되었다는 것을 보여준다.
NAME READY UP-TO-DATE AVAILABLE AGE mongo 1/1 1 1 2m21s
디플로이먼트는 자동으로 레플리카셋을 관리한다. 아래의 명령어를 사용하여 레플리카셋 상태를 조회한다.
kubectl get replicaset
출력은 레플리카셋이 생성되었다는 것을 보여준다.
NAME DESIRED CURRENT READY AGE mongo-75f59d57f4 1 1 1 3m12s
-
MongoDB를 네트워크에 노출시키기 위해 서비스를 생성한다.
kubectl apply -f https://k8s.io/examples/application/mongodb/mongo-service.yaml
성공적인 커맨드의 출력은 서비스가 생성되었다는 것을 확인해준다.
service/mongo created
서비스가 생성되었는지 확인한다.
kubectl get service mongo
출력은 서비스가 생성되었다는 것을 보여준다.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mongo ClusterIP 10.96.41.183 <none> 27017/TCP 11s
-
MongoDB 서버가 파드 안에서 실행되고 있고, 27017번 포트에서 수신하고 있는지 확인한다.
# mongo-75f59d57f4-4nd6q 를 당신의 파드 이름으로 대체한다. kubectl get pod mongo-75f59d57f4-4nd6q --template='{{(index (index .spec.containers 0).ports 0).containerPort}}{{"\n"}}'
출력은 파드 내 MongoDB 포트 번호를 보여준다.
27017
(이는 인터넷 상의 MongoDB에 할당된 TCP 포트이다.)
파드의 포트를 로컬 포트로 포워딩하기
-
kubectl port-forward
명령어는 파드 이름과 같이 리소스 이름을 사용하여 일치하는 파드를 선택해 포트 포워딩하는 것을 허용한다.# mongo-75f59d57f4-4nd6q 를 당신의 파드 이름으로 대체한다. kubectl port-forward mongo-75f59d57f4-4nd6q 28015:27017
이것은
kubectl port-forward pods/mongo-75f59d57f4-4nd6q 28015:27017
또는
kubectl port-forward deployment/mongo 28015:27017
또는
kubectl port-forward replicaset/mongo-75f59d57f4 28015:27017
또는 다음과 같다.
kubectl port-forward service/mongo 28015:27017
위의 명령어들은 모두 동일하게 동작한다. 이와 유사하게 출력된다.
Forwarding from 127.0.0.1:28015 -> 27017 Forwarding from [::1]:28015 -> 27017
kubectl port-forward
는 프롬프트를 리턴하지 않으므로, 이 연습을 계속하려면 다른 터미널을 열어야 한다.
-
MongoDB 커맨드라인 인터페이스를 실행한다.
mongosh --port 28015
-
MongoDB 커맨드라인 프롬프트에
ping
명령을 입력한다.db.runCommand( { ping: 1 } )
성공적인 핑 요청을 반환한다.
{ ok: 1 }
선택적으로 kubectl 이 로컬 포트를 선택하게 하기
만약 특정 로컬 포트가 필요하지 않다면, kubectl
이 로컬 포트를 선택 및 할당하게 하여,
조금 더 단순한 문법으로 로컬 포트 충돌 관리를 위한
부담을 줄일 수 있다.
kubectl port-forward deployment/mongo :27017
kubectl
도구는 사용 중이 아닌 로컬 포트 번호를 찾는다 (낮은 포트 번호는
다른 애플리케이션에서 사용될 것이므로, 낮은 포트 번호를 피해서). 출력은 다음과 같을 것이다.
Forwarding from 127.0.0.1:63753 -> 27017
Forwarding from [::1]:63753 -> 27017
토의
로컬 28015 포트에 대한 연결은 MongoDB 서버가 실행중인 파드의 27017 포트로 포워딩된다. 이 연결로 로컬 워크스테이션에서 파드 안에서 실행 중인 데이터베이스를 디버깅하는데 사용할 수 있다.
kubectl port-forward
는 TCP 포트에서만 구현된다.
UDP 프로토콜에 대한 지원은
이슈 47862에서 추적되고 있다.
다음 내용
kubectl port-forward에 대해 더 알아본다.
5 - 클러스터 내 애플리케이션에 접근하기 위해 서비스 사용하기
이 문서는 외부 클라이언트가 클러스터에서 실행 중인 애플리케이션에 접근하기 위해 사용하는 쿠버네티스 서비스 오브젝트를 생성하는 방법을 설명한다. 서비스는 실행 중인 두 개의 인스턴스를 갖는 애플리케이션에 대한 로드 밸런싱을 제공한다.
시작하기 전에
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.
목적
- Hello World 애플리케이션 인스턴스 두 개를 실행한다.
- 노드 포트를 노출하는 서비스 오브젝트를 생성한다.
- 실행 중인 애플리케이션에 접근하기 위해 서비스 오브젝트를 사용한다.
두 개의 파드에서 실행 중인 애플리케이션에 대한 서비스 생성하기
다음은 애플리케이션 디플로이먼트(Deployment) 설정 파일이다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
spec:
selector:
matchLabels:
run: load-balancer-example
replicas: 2
template:
metadata:
labels:
run: load-balancer-example
spec:
containers:
- name: hello-world
image: gcr.io/google-samples/node-hello:1.0
ports:
- containerPort: 8080
protocol: TCP
-
클러스터 내 Hello World 애플리케이션을 실행하자. 위 파일을 사용하여 애플리케이션 디플로이먼트를 생성하자.
kubectl apply -f https://k8s.io/examples/service/access/hello-application.yaml
앞의 명령은 디플로이먼트 오브젝트와 연관된 레플리카셋(ReplicaSet) 오브젝트를 생성한다. 레플리카셋은 두 개의 파드를 갖고, 각각은 Hello World 애플리케이션을 실행한다.
-
디플로이먼트에 대한 정보를 보여준다.
kubectl get deployments hello-world kubectl describe deployments hello-world
-
레플리카셋 오브젝트에 대한 정보를 보여준다.
kubectl get replicasets kubectl describe replicasets
-
디플로이먼트를 노출하는 서비스 오브젝트를 생성한다.
kubectl expose deployment hello-world --type=NodePort --name=example-service
-
서비스에 대한 정보를 보여준다.
kubectl describe services example-service
결과는 아래와 같다.
Name: example-service Namespace: default Labels: run=load-balancer-example Annotations: <none> Selector: run=load-balancer-example Type: NodePort IP: 10.32.0.16 Port: <unset> 8080/TCP TargetPort: 8080/TCP NodePort: <unset> 31496/TCP Endpoints: 10.200.1.4:8080,10.200.2.5:8080 Session Affinity: None Events: <none>
서비스의 노드포트(NodePort) 값을 메모하자. 예를 들어, 앞선 결과에서, 노드포트 값은 31496이다.
-
Hello World 애플리케이션이 실행 중인 파드를 나열한다.
kubectl get pods --selector="run=load-balancer-example" --output=wide
결과는 아래와 같다.
NAME READY STATUS ... IP NODE hello-world-2895499144-bsbk5 1/1 Running ... 10.200.1.4 worker1 hello-world-2895499144-m1pwt 1/1 Running ... 10.200.2.5 worker2
-
Hello World 파드가 실행 중인 노드들 중 하나의 노드에 대해 공용 IP 주소를 얻자. 이 주소를 얻는 방법은 어떻게 클러스터를 설치했는지에 따라 다르다. 예를 들어, Minikube를 사용하면,
kubectl cluster-info
를 실행하여 노드 주소를 알 수 있다. Google Compute Engine 인스턴스를 사용하면,gcloud compute instances list
명령어를 사용하여 노드들의 공용 주소를 알 수 있다. -
선택한 노드에서 노드 포트에 대해 TCP 통신을 허용하도록 방화벽 규칙을 생성하자. 예를 들어, 서비스의 노드포트 값이 31568인 경우, 31568 포트로 TCP 통신을 허용하도록 방화벽 규칙을 생성하자. 다른 클라우드 공급자는 방화벽 규칙을 설정하는 다른 방법을 제공한다.
-
Hello World 애플리케이션 접근을 위해 노드 주소와 노드 포트를 사용하자.
curl http://<public-node-ip>:<node-port>
<public-node-ip>
는 노드의 공용 IP 주소이고,<node-port>
는 서비스의 노드포트 값이다. 성공적인 요청에 대한 응답은 hello 메시지이다.Hello Kubernetes!
서비스 설정 파일 사용하기
kubectl expose
를 사용하는 대신,
서비스 설정 파일을 사용해
서비스를 생성할 수 있다.
정리하기
서비스를 삭제하기 위해 다음 명령어를 입력하자.
kubectl delete services example-service
디플로이먼트, 레플리카셋, Hello World 애플리케이션이 실행 중인 파드를 삭제하기 위해 다음 명령어를 입력하자.
kubectl delete deployment hello-world
다음 내용
서비스와 애플리케이션 연결하기에 대해 더 알아본다.
6 - 서비스를 사용하여 프론트엔드를 백엔드에 연결
이 작업은 프론트엔드 와 백엔드 마이크로서비스를 어떻게 생성하는지를 설명한다. 백엔드 마이크로서비스는 인사하기(hello greeter)이다. 프론트엔드는 nginx 및 쿠버네티스 서비스 오브젝트를 사용해 백엔드를 노출한다.
목적
- 디플로이먼트(Deployment) 오브젝트를 사용해
샘플
hello
백엔드 마이크로서비스를 생성하고 실행한다. - 서비스 오브젝트를 사용하여 백엔드 마이크로서비스의 여러 복제본으로 트래픽을 보낸다.
- 디플로이먼트 오브젝트를 사용하여
nginx
프론트엔드 마이크로서비스를 생성하고 실행한다. - 트래픽을 백엔드 마이크로서비스로 보내도록 프론트엔드 마이크로서비스를 구성한다.
type=LoadBalancer
의 서비스 오브젝트를 사용해 클러스터 외부에 프론트엔드 마이크로서비스를 노출한다.
시작하기 전에
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.
이 작업은 지원되는 환경이 필요한 외부 로드밸런서가 있는 서비스를 사용한다. 만약, 이를 지원하지 않는 환경이라면, 노드포트 서비스 타입을 대신 사용할 수 있다.
디플로이먼트를 사용해 백엔드 생성하기
백엔드는 인사하기라는 간단한 마이크로서비스이다. 여기에 백엔드 디플로이먼트 구성 파일이 있다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
spec:
selector:
matchLabels:
app: hello
tier: backend
track: stable
replicas: 7
template:
metadata:
labels:
app: hello
tier: backend
track: stable
spec:
containers:
- name: hello
image: "gcr.io/google-samples/hello-go-gke:1.0"
ports:
- name: http
containerPort: 80
백엔드 디플로이먼트를 생성한다.
kubectl apply -f https://k8s.io/examples/service/access/backend-deployment.yaml
백엔드 디플로이먼트에 관한 정보를 본다.
kubectl describe deployment backend
결과는 아래와 같다.
Name: backend
Namespace: default
CreationTimestamp: Mon, 24 Oct 2016 14:21:02 -0700
Labels: app=hello
tier=backend
track=stable
Annotations: deployment.kubernetes.io/revision=1
Selector: app=hello,tier=backend,track=stable
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:
Labels: app=hello
tier=backend
track=stable
Containers:
hello:
Image: "gcr.io/google-samples/hello-go-gke:1.0"
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: hello-3621623197 (3/3 replicas created)
Events:
...
hello
서비스 오브젝트 생성하기
프론트엔드에서 백엔드로 요청을 보내는 핵심은 백엔드 서비스이다. 서비스는 백엔드 마이크로서비스에 언제든 도달하기 위해 변하지 않는 IP 주소와 DNS 이름 항목을 생성한다. 서비스는 트래픽을 보내는 파드를 찾기 위해 셀렉터를 사용한다.
먼저, 서비스 구성 파일을 살펴보자.
apiVersion: v1
kind: Service
metadata:
name: hello
spec:
selector:
app: hello
tier: backend
ports:
- protocol: TCP
port: 80
targetPort: http
구성 파일에서 hello
라는 이름의 서비스가 app: hello
및 tier: backend
레이블을 갖는
파드에 트래픽을 보내는 것을 볼 수 있다.
백엔드 서비스를 생성한다.
kubectl apply -f https://k8s.io/examples/service/access/backend-service.yaml
이 시점에서 hello
애플리케이션의 복제본 3개를 실행하는 backend
디플로이먼트가 있고, 해당 백엔드로 트래픽을 보내는 서비스가 있다. 그러나, 이
서비스는 클러스터 외부에서 사용할 수 없거나 확인할 수 없다.
프론트엔드 생성하기
이제 백엔드를 실행했으므로, 클러스터 외부에서 접근할 수 있는 프론트엔드를 만들고, 백엔드로의 요청을 프록시하여 백엔드에 연결할 수 있다.
프론트엔드는 백엔드 서비스에 지정된 DNS 이름을 사용하여 백엔드
워커 파드에 요청을 보낸다. DNS 이름은
examples/service/access/backend-service.yaml
구성 파일의
name
필드 값인 hello
이다.
프론트엔드 디플로이먼트 안의 파드는 hello
백엔드 서비스에 대한 요청을
프록시하도록 구성된 nginx 이미지를 실행한다. 다음은 nginx 구성 파일이다.
# The identifier Backend is internal to nginx, and used to name this specific upstream
upstream Backend {
# hello is the internal DNS name used by the backend Service inside Kubernetes
server hello;
}
server {
listen 80;
location / {
# The following statement will proxy traffic to the upstream named Backend
proxy_pass http://Backend;
}
}
백엔드와 같이, 프론트엔드는 디플로이먼트와 서비스를 갖고 있다. 백엔드
서비스와 프론트엔드 서비스 간에 주목해야 할 중요한 차이점은 프론트엔드
서비스의 구성에 type: LoadBalancer
가 있다는 것이다. 즉,
서비스가 클라우드 공급자가 프로비저닝한 로드 밸런서를 사용하고
클러스터 외부에서 접근할 수 있음을 의미한다.
---
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
selector:
app: hello
tier: frontend
ports:
- protocol: "TCP"
port: 80
targetPort: 80
type: LoadBalancer
...
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
selector:
matchLabels:
app: hello
tier: frontend
track: stable
replicas: 1
template:
metadata:
labels:
app: hello
tier: frontend
track: stable
spec:
containers:
- name: nginx
image: "gcr.io/google-samples/hello-frontend:1.0"
lifecycle:
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
...
프론트엔드 디플로이먼트와 서비스를 생성한다.
kubectl apply -f https://k8s.io/examples/service/access/frontend-deployment.yaml
kubectl apply -f https://k8s.io/examples/service/access/frontend-service.yaml
결과는 두 리소스가 생성되었음을 확인한다.
deployment.apps/frontend created
service/frontend created
프론트엔드 서비스와 통신하기
일단 로드밸런서 타입의 서비스를 생성하면, 이 명령어를 사용해 외부 IP를 찾을 수 있다.
kubectl get service frontend --watch
frontend
서비스의 구성을 보여주고, 변경 사항을
주시한다. 처음에, 외부 IP는 <pending>
으로 나열된다.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend LoadBalancer 10.51.252.116 <pending> 80/TCP 10s
하지만, 외부 IP가 생성되자마자 구성은
EXTERNAL-IP
제목 아래에 새로운 IP를 포함하여 갱신한다.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend LoadBalancer 10.51.252.116 XXX.XXX.XXX.XXX 80/TCP 1m
이제 해당 IP는 클러스터 외부에서 frontend
서비스와 통신하는데
사용된다.
프론트엔드 통해서 트래픽 보내기
이제 프론트엔드와 백엔드가 연결되었다. 프론트엔드 서비스의 외부 IP에서 curl 명령을 사용해 엔드포인트에 도달할 수 있다.
curl http://${EXTERNAL_IP} # 앞의 예에서 본 EXTERNAL-IP로 수정한다
결과로 백엔드에서 생성된 메시지가 보인다.
{"message":"Hello"}
정리하기
서비스를 삭제하기 위해, 아래 명령어를 입력하자.
kubectl delete services frontend backend
백엔드와 프론트엔드 애플리케이션에서 실행 중인 디플로이먼트, 레플리카셋, 파드를 삭제하기 위해, 아래 명령어를 입력하자.
kubectl delete deployment frontend backend
다음 내용
- 서비스에 대해 더 알아본다.
- 컨피그맵에 대해 더 알아본다.
- 서비스와 파드용 DNS에 대해 더 알아본다.
7 - 클러스터 내 모든 컨테이너 이미지 목록 보기
이 문서는 kubectl을 이용하여 클러스터 내 모든 컨테이너 이미지 목록을 조회하는 방법에 관해 설명한다.
시작하기 전에
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.
이 작업에서는 kubectl을 사용하여 클러스터 내 모든 파드의 정보를 조회하고, 결과값의 서식을 변경하여 각 파드에 대한 컨테이너 이미지 목록으로 재구성할 것이다.
모든 네임스페이스의 모든 컨테이너 이미지 가져오기
kubectl get pods --all-namespaces
를 사용하여 모든 네임스페이스의 모든 파드 정보를 가져온다.- 컨테이너 이미지 이름만 출력하기 위해
-o jsonpath={.items[*].spec.containers[*].image}
를 사용한다. 이 명령어는 결과값으로 받은 json을 반복적으로 파싱하여,image
필드만을 출력한다.- jsonpath를 사용하는 방법에 대해 더 많은 정보를 얻고 싶다면 Jsonpath 지원을 확인한다.
- 다음의 표준 툴을 이용해서 결과값을 처리한다.
tr
,sort
,uniq
tr
을 사용하여 공백을 줄 바꾸기로 대체한다.sort
를 사용하여 결과값을 정렬한다.uniq
를 사용하여 이미지 개수를 합산한다.
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" |\
tr -s '[[:space:]]' '\n' |\
sort |\
uniq -c
이 커맨드는 결과값으로 나온 모든 아이템 중에 image
라고 명명된 필드를
모두 출력한다.
이와 다른 방법으로 파드 이미지 필드 값의 절대 경로를 사용할 수 있다.
이것은 필드명이 반복될 때에도
정확한 값을 출력하도록 보장한다.
예) 결과값 중에 많은 필드들이 name
으로 명명되었을 경우,
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}"
이 jsonpath는 다음과 같이 해석할 수 있다.
.items[*]
: 각 결과값에 대하여.spec
: spec 값을 가져온다..containers[*]
: 각 컨테이너에 대하여.image
: image 값을 가져온다.
kubectl get pod nginx
라면,
jsonpath에서 .items[*]
부분은 생략해야 하는데, 이는 명령어가 아이템 목록이 아닌
단 한 개의 아이템(여기선 파드)으로 결과값을 주기 때문이다.
각 파드의 컨테이너 이미지 보기
range
연산을 사용하여 명령어의 결과값에서 각각의 요소들을
반복하여 출력할 수 있다.
kubectl get pods --all-namespaces -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |\
sort
파드 레이블로 필터링된 컨테이너 이미지 목록 보기
특정 레이블에 맞는 파드를 지정하기 위해서 -l 플래그를 사용한다. 아래의
명령어 결과값은 app=nginx
레이블에 일치하는 파드만 출력한다.
kubectl get pods --all-namespaces -o=jsonpath="{.items[*].spec.containers[*].image}" -l app=nginx
파드 네임스페이스로 필터링된 컨테이너 이미지 목록 보기
특정 네임스페이스의 파드를 지정하려면, 네임스페이스 플래그를 사용한다.
아래의 명령어 결과값은 kube-system
네임스페이스에 있는 파드만 출력한다.
kubectl get pods --namespace kube-system -o jsonpath="{.items[*].spec.containers[*].image}"
jsonpath 대신 Go 템플릿을 사용하여 컨테이너 이미지 목록 보기
jsonpath의 대안으로 Kubectl은 Go 템플릿을 지원한다. 다음과 같이 결과값의 서식을 지정할 수 있다.
kubectl get pods --all-namespaces -o go-template --template="{{range .items}}{{range .spec.containers}}{{.image}} {{end}}{{end}}"
다음 내용
참조
8 - 공유 볼륨을 이용하여 동일한 파드의 컨테이너 간에 통신하기
이 페이지에서는 동일한 파드에서 실행 중인 두 개의 컨테이너 간에 통신할 때에, 어떻게 볼륨을 이용하는지 살펴본다. 컨테이너 간에 프로세스 네임스페이스 공유하기를 통해 통신할 수 있는 방법을 참고하자.
시작하기 전에
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.
두 개의 컨테이너를 실행하는 파드 생성
이 실습에서 두 개의 컨테이너를 실행하는 파드를 생성한다. 이 컨테이너들은 통신에 사용할 수 있는 볼륨을 공유한다. 아래는 이 파드의 구성 파일이다.
apiVersion: v1
kind: Pod
metadata:
name: two-containers
spec:
restartPolicy: Never
volumes:
- name: shared-data
emptyDir: {}
containers:
- name: nginx-container
image: nginx
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: debian-container
image: debian
volumeMounts:
- name: shared-data
mountPath: /pod-data
command: ["/bin/sh"]
args: ["-c", "echo debian 컨테이너에서 안녕하세요 > /pod-data/index.html"]
이 구성 파일에는 파드가 shared-data
로 명명한 볼륨을 가진 것을
알 수 있다.
첫 번째 컨테이너에는 nginx 웹 서버를 실행하는 구성 파일이 나열되어 있다.
공유 볼륨의 마운트 경로는 /usr/share/nginx/html
이다.
두 번째 컨테이너는 debian 이미지 기반이고, 마운트 경로는 /pod-data
이다.
두 번째 컨테이너는 다음 명령어를 실행한 후에 종료한다.
echo debian 컨테이너에서 안녕하세요 > /pod-data/index.html
두 번째 컨테이너는 index.html
파일을
nginx 웹 서버에서 호스팅하는 문서의 루트 디렉터리(/usr/share/nginx/html/
)에 저장한다.
이제, 파드와 두 개의 컨테이너를 생성한다.
kubectl apply -f https://k8s.io/examples/pods/two-container-pod.yaml
파드와 컨테이너의 정보를 확인한다.
kubectl get pod two-containers --output=yaml
출력의 일부는 다음과 같다.
apiVersion: v1
kind: Pod
metadata:
...
name: two-containers
namespace: default
...
spec:
...
containerStatuses:
- containerID: docker://c1d8abd1 ...
image: debian
...
lastState:
terminated:
...
name: debian-container
...
- containerID: docker://96c1ff2c5bb ...
image: nginx
...
name: nginx-container
...
state:
running:
...
Debian 컨테이너가 종료되었음을 알 수 있고, nginx 컨테이너는 아직 실행 중이다.
nginx 컨테이너의 쉘(shell)을 실행한다.
kubectl exec -it two-containers -c nginx-container -- /bin/bash
쉘에서 nginx 웹 서버가 실행 중인지 확인한다.
root@two-containers:/# apt-get update
root@two-containers:/# apt-get install curl procps
root@two-containers:/# ps aux
출력은 아래와 유사하다.
USER PID ... STAT START TIME COMMAND
root 1 ... Ss 21:12 0:00 nginx: master process nginx -g daemon off;
Debian 컨테이너에서 nginx 웹 서버가 호스팅하는 문서의 루트 디렉터리에 index.html
파일을 생성했었음을 상기하자.
curl
을 이용하여 nginx 웹 서버에 HTTP GET 요청을 보낸다.
root@two-containers:/# curl localhost
출력을 보면, nginx 웹 서버에서 debian 컨테이너에서 쓰여진 웹 페이지를 제공하는 것을 알 수 있다.
debian 컨테이너에서 안녕하세요
토의
파드가 여러 컨테이너를 가질 수 있는 주요 이유는 기본 애플리케이션을 보조할 도우미(helper) 애플리케이션을 제공하기 위해서이다. 도우미 애플리케이션의 일반적인 예로는 데이터를 가지고 오는 경우(data puller)나 데이터를 보내주는 경우(data pusher)이거나 프록시가 있다. 도우미와 기본 애플리케이션은 종종 서로 간에 통신을 해야 할 수 있다. 일반적으로 이는 이번 예제에서 살펴본 것 같이, 공유 파일 시스템을 통하거나, 루프백 네트워크 인터페이스 곧 로컬 호스트(localhost)를 통해서 이뤄진다. 이 패턴의 한가지 예는 웹 서버가 도우미 프로그램과 함께 Git 저장소에서 새 업데이트를 받아오는 경우이다.
이 예제에서 볼륨은 파드의 생명 주기 동안 컨테이너를 위한 통신 방법으로 이용했다. 파드가 삭제되고 재생성되면, 공유 볼륨에 저장된 데이터는 잃어버린다.
다음 내용
-
합성 컨테이너(composite container) 패턴에 관하여 더 공부한다.
-
모듈 구조를 위한 합성 컨테이너 구조에 관하여 더 공부한다.
-
파드에서 저장소로 볼룸을 사용하도록 구성하기에 관하여 확인한다.
-
볼륨을 확인한다.
-
파드을 확인한다.
9 - 클러스터의 DNS 구성하기
쿠버네티스는 지원하는 모든 환경에서 기본으로 활성화된 DNS 클러스터 애드온을 제공한다. 쿠버네티스 1.11과 이후 버전에서는, CoreDNS가 권장되고 기본적으로 kubeadm과 함께 설치 된다.
쿠버네티스 클러스터의 CoreDNS 설정에 대한 더 많은 정보는, DNS 서비스 사용자화 하기을 본다. kube-dns와 함께 쿠버네티스 DNS를 사용하는 방법을 보여주는 예시는 쿠버네티스 DNS 샘플 플러그인을 본다.