1 - 쿠버네티스 대시보드를 배포하고 접속하기

웹 UI(쿠버네티스 대시보드)를 배포하고 접속한다.

대시보드는 웹 기반 쿠버네티스 유저 인터페이스이다. 대시보드를 통해 컨테이너화 된 애플리케이션을 쿠버네티스 클러스터에 배포할 수 있고, 컨테이너화 된 애플리케이션을 트러블슈팅할 수 있으며, 클러스터 리소스들을 관리할 수 있다. 대시보드를 통해 클러스터에서 동작 중인 애플리케이션의 정보를 볼 수 있고, 개별적인 쿠버네티스 리소스들을(예를 들면 디플로이먼트, 잡, 데몬셋 등) 생성하거나 수정할 수 있다. 예를 들면, 디플로이먼트를 스케일하거나, 롤링 업데이트를 초기화하거나, 파드를 재시작하거나 또는 배포 마법사를 이용해 새로운 애플리케이션을 배포할 수 있다.

또한 대시보드는 클러스터 내 쿠버네티스 리소스들의 상태와 발생하는 모든 에러 정보를 제공한다.

Kubernetes Dashboard UI

대시보드 UI 배포

대시보드 UI는 기본으로 배포되지 않는다. 배포하려면 다음 커맨드를 실행한다.

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.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 네임스페이스이 동작중인 시스템 애플리케이션을 볼 수 있다.

Kubernetes Dashboard welcome page

컨테이너화 된 애플리케이션 배포

대시보드를 이용하여 컨테이너화 된 애플리케이션을 디플로이먼트와 간단한 마법사를 통한 선택적인 서비스로 생성하고 배포할 수 있다. 애플리케이션 세부 정보를 수동으로 지정할 수 있고, 또는 애플리케이션 구성을 포함한 YAML 또는 JSON 매니페스트(manifest) 파일을 업로드할 수 있다.

시작하는 페이지의 상위 오른쪽 코너에 있는 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 파일 업로드

쿠버네티스는 선언적인 설정을 제공한다. 이 방식에서는 모든 설정이 매니페스트(YAML 또는 JSON 설정 파일)에 저장된다. 매니페스트는 쿠버네티스 API 리소스 스키마를 사용한다.

배포 마법사를 통해 애플리케이션 세부 사항들을 지정하는 대신, 애플리케이션을 하나 이상의 매니페스트로 정의할 수 있고 대시보드를 이용해서 파일을 업로드할 수 있다.

대시보드 사용

다음 섹션들은 어떻게 제공하고 어떻게 사용할 수 있는지에 대한 쿠버네티스 대시보드 UI의 모습을 보여준다.

탐색

클러스터에 정의된 쿠버네티스 오프젝트가 있으면, 대시보드는 초기화된 뷰를 제공한다. 기본적으로 기본 네임스페이스의 오프젝트만이 보이는데, 이는 탐색 창에 위치한 네임스페이스 셀렉터를 이용해 변경할 수 있다.

대시보드는 몇 가지 메뉴 카테고리 중에서 대부분의 쿠버네티스 오브젝트 종류와 그룹을 보여준다.

어드민 개요

클러스터와 네임스페이스 관리자에게 대시보드는 노드, 네임스페이스 그리고 퍼시스턴트 볼륨과 세부사항들이 보여진다. 노드는 모든 노드를 통틀어 CPU와 메모리 사용량을 보여준다. 세부사항은 각 노드들에 대한 사용량, 사양, 상태, 할당된 리소스, 이벤트 그리고 노드에서 돌아가는 파드를 보여준다.

워크로드

선택된 네임스페이스에서 구동되는 모든 애플리케이션을 보여준다. 애플리케이션의 워크로드 종류(예시: 디플로이먼트, 레플리카셋(ReplicaSet), 스테이트풀셋(StatefulSet))를 보여주고 각각의 워크로드 종류는 따로 보여진다. 리스트는 예를 들어 레플리카셋에서 준비된 파드의 숫자 또는 파드의 현재 메모리 사용량과 같은 워크로드에 대한 실용적인 정보를 요약한다.

워크로드에 대한 세부적인 것들은 상태와 사양 정보, 오프젝트들 간의 관계를 보여준다. 예를 들어, 레플리카셋으로 관리하는 파드들 또는 새로운 레플리카셋과 디플로이먼트를 위한 Horizontal Pod Autoscalers 이다.

서비스

외부로 노출되는 서비스들과 클러스터 내에 발견되는 서비스들을 허용하는 쿠버네티스 리소스들을 보여준다. 이러한 이유로 서비스와 인그레스는 클러스터간의 연결을 위한 내부 엔드포인트들과 외부 사용자를 위한 외부 엔드포인트들에 의해 타게팅된 파드들을 보여준다.

스토리지

스토리지는 애플리케이션이 데이터를 저장하기 위해 사용하는 퍼시턴트볼륨클레임 리소스들을 보여준다.

컨피그맵과 시크릿

클러스터에서 동작 중인 애플리케이션의 라이브 설정을 사용하는 모든 쿠버네티스 리소스들을 보여준다. 컨피그 오브젝트들을 수정하고 관리할 수 있도록 허용하며, 기본적으로는 숨겨져 있는 시크릿들을 보여준다.

로그 뷰어

파드 목록과 세부사항 페이지들은 대시보드에 구현된 로그 뷰어에 링크된다. 뷰어는 단일 파드에 있는 컨테이너들의 로그들을 내려가면 볼 수 있도록 한다.

Logs viewer

다음 내용

더 많은 정보는 쿠버네티스 대시보드 프로젝트 페이지를 참고한다.

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에 프로그래밍 방식으로 접근

쿠버네티스는 공식적으로 GoPython 클라이언트 라이브러리를 지원한다.

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 서버에 연결하는 방법을 소개하였다. 쿠버네티스 클러스터에서 실행되는 다른 서비스에 연결하는 방법은 클러스터 접근 페이지를 참조한다.

redirect 요청하기

redirect 기능은 deprecated되고 제거 되었다. 대신 (아래의) 프록시를 사용하기를 바란다.

다양한 프록시들

쿠버네티스를 사용하면서 당신이 접할 수 있는 몇 가지 다른 프록시들이 존재한다.

  1. kubectl proxy:

    • 사용자의 데스크탑이나 파드 내에서 실행한다
    • localhost 주소에서 쿠버네티스 apiserver로 프록시한다
    • 프록시하는 클라이언트는 HTTP를 사용한다
    • apiserver의 프록시는 HTTPS를 사용한다
    • apiserver를 위치지정한다
    • 인증 header들을 추가한다
  2. apiserver proxy:

    • apiserver 내의 빌트인 bastion이다
    • 다른 방식으로는 연결할 수 없는 클러스터 외부의 사용자를 클러스터 IP로 연결한다
    • apiserver process들 내에서 실행된다
    • 프록시하는 클라이언트는 HTTPS를 사용한다(또는 apiserver가 http로 구성되었다면 http)
    • 타겟으로의 프록시는 가용정보를 사용하는 프록시에 의해서 HTTP 또는 HTTPS를 사용할 수도 있다
    • 노드, 파드, 서비스에 접근하는 데 사용될 수 있다
    • 서비스에 접근하는 데 사용되면 load balacing한다
  3. kube proxy:

    • 각 노드 상에서 실행된다
    • UDP와 TCP를 프록시한다
    • HTTP를 인지하지 않는다
    • load balancing을 제공한다
    • 서비스에 접근하는 데에만 사용된다
  4. apiserver(s) 전면의 Proxy/Load-balancer:

    • 존재내용과 구현사항은 클러스터 별로 다양하다(예. nginx)
    • 모든 클라이언트와 하나 이상의 apiserver들의 사이에 위치한다
    • apiserver가 여러 대 존재한다면 load balancer로 동작한다
  5. 외부 서비스의 Cloud Load Balancer들:

    • Cloud provider들에 의해서 제공된다(예. AWS ELB, Google Cloud Load Balancer)
    • 쿠버네티스 서비스의 타입이 LoadBalancer라면 자동으로 생성된다
    • UDP/TCP 만 사용한다
    • cloud provider마다 구현된 내용이 상이하다

일반적으로 쿠버네티스 사용자들은 처음 두 타입이 아닌 다른 방식은 고려할 필요가 없지만 클러스터 관리자는 나머지 타입을 적절하게 구성해줘야 한다.

3 - 다중 클러스터 접근 구성

이 페이지에서는 구성 파일을 사용하여 다수의 클러스터에 접근할 수 있도록 설정하는 방식을 보여준다. 클러스터, 사용자, 컨텍스트가 하나 이상의 구성 파일에 정의된 다음 kubectl config use-context 커맨드를 사용하여 클러스터를 빠르게 변경할 수 있다.

시작하기 전에

쿠버네티스 클러스터가 필요하고, 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 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 디플로이먼트와 서비스 생성하기

  1. 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
    
  2. 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
    
  3. 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 포트이다.)

파드의 포트를 로컬 포트로 포워딩하기

  1. 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
    
  1. MongoDB 커맨드라인 인터페이스를 실행한다.

    mongosh --port 28015
    
  2. 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에 대해 더 알아본다.

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
  1. 클러스터 내 Hello World 애플리케이션을 실행하자. 위 파일을 사용하여 애플리케이션 디플로이먼트를 생성하자.

    kubectl apply -f https://k8s.io/examples/service/access/hello-application.yaml
    

    앞의 명령은 디플로이먼트 오브젝트와 연관된 레플리카셋(ReplicaSet) 오브젝트를 생성한다. 레플리카셋은 두 개의 파드를 갖고, 각각은 Hello World 애플리케이션을 실행한다.

  2. 디플로이먼트에 대한 정보를 보여준다.

    kubectl get deployments hello-world
    kubectl describe deployments hello-world
    
  3. 레플리카셋 오브젝트에 대한 정보를 보여준다.

    kubectl get replicasets
    kubectl describe replicasets
    
  4. 디플로이먼트를 노출하는 서비스 오브젝트를 생성한다.

    kubectl expose deployment hello-world --type=NodePort --name=example-service
    
  5. 서비스에 대한 정보를 보여준다.

    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이다.

  6. 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
    
  7. Hello World 파드가 실행 중인 노드들 중 하나의 노드에 대해 공용 IP 주소를 얻자. 이 주소를 얻는 방법은 어떻게 클러스터를 설치했는지에 따라 다르다. 예를 들어, Minikube를 사용하면, kubectl cluster-info를 실행하여 노드 주소를 알 수 있다. Google Compute Engine 인스턴스를 사용하면, gcloud compute instances list 명령어를 사용하여 노드들의 공용 주소를 알 수 있다.

  8. 선택한 노드에서 노드 포트에 대해 TCP 통신을 허용하도록 방화벽 규칙을 생성하자. 예를 들어, 서비스의 노드포트 값이 31568인 경우, 31568 포트로 TCP 통신을 허용하도록 방화벽 규칙을 생성하자. 다른 클라우드 공급자는 방화벽 규칙을 설정하는 다른 방법을 제공한다.

  9. 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: hellotier: 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

다음 내용

7 - NGINX 인그레스(Ingress) 컨트롤러로 Minikube에서 인그레스 설정하기

인그레스는 클러스터의 서비스에 대한 외부 액세스를 허용하는 규칙을 정의하는 API 객체이다. 인그레스 컨트롤러는 인그레스에 설정된 규칙을 이행한다.

이 페이지에서는 HTTP URI에 따라 요청을 Service web 또는 web2로 라우팅하는 간단한 인그레스를 설정하는 방법을 보여준다.

시작하기 전에

쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.

쿠버네티스 서버의 버전은 다음과 같거나 더 높아야 함. 버전: 1.19. 버전 확인을 위해서, 다음 커맨드를 실행 kubectl version. 만약 이보다 더 이전 버전의 쿠버네티스를 사용하고 있다면, 해당 쿠버네티스 버전의 문서를 참고한다.

Minikube 클러스터 생성하기

Katacoda 활용하기
로컬에서 생성하기
이미 로컬에 Minikube를 설치했다면, minikube start를 실행하여 클러스터를 생성한다.

인그레스 컨트롤러 활성화

  1. NGINX 인그레스 컨트롤러를 활성화하기 위해 다음 명령을 실행한다.

    minikube addons enable ingress
    
  2. NGINX 인그레스 컨트롤러가 실행 중인지 확인한다.

    kubectl get pods -n ingress-nginx
    

    결과는 다음과 같다.

    NAME                                        READY   STATUS      RESTARTS    AGE
    ingress-nginx-admission-create-g9g49        0/1     Completed   0          11m
    ingress-nginx-admission-patch-rqp78         0/1     Completed   1          11m
    ingress-nginx-controller-59b45fb494-26npt   1/1     Running     0          11m
    

    kubectl get pods -n kube-system
    

    결과는 다음과 같다.

    NAME                                        READY     STATUS    RESTARTS   AGE
    default-http-backend-59868b7dd6-xb8tq       1/1       Running   0          1m
    kube-addon-manager-minikube                 1/1       Running   0          3m
    kube-dns-6dcb57bcc8-n4xd4                   3/3       Running   0          2m
    kubernetes-dashboard-5498ccf677-b8p5h       1/1       Running   0          2m
    nginx-ingress-controller-5984b97644-rnkrg   1/1       Running   0          1m
    storage-provisioner                         1/1       Running   0          2m
    

    nginx-ingress-controller-로 시작하는 파드가 있는지 확인한다.

hello, world 앱 배포하기

  1. 다음 명령을 사용하여 디플로이먼트(Deployment)를 생성한다.

    kubectl create deployment web --image=gcr.io/google-samples/hello-app:1.0
    

    결과는 다음과 같다.

    deployment.apps/web created
    
  2. 디플로이먼트를 노출시킨다.

    kubectl expose deployment web --type=NodePort --port=8080
    

    결과는 다음과 같다.

    service/web exposed
    
  3. 서비스(Service)가 생성되고 노드 포트에서 사용할 수 있는지 확인한다.

    kubectl get service web
    

    결과는 다음과 같다.

    NAME      TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
    web       NodePort   10.104.133.249   <none>        8080:31637/TCP   12m
    
  4. 노드포트(NodePort)를 통해 서비스에 접속한다.

    minikube service web --url
    

    결과는 다음과 같다.

    http://172.17.0.15:31637
    

    결과는 다음과 같다.

    Hello, world!
    Version: 1.0.0
    Hostname: web-55b8c6998d-8k564
    

    이제 Minikube IP 주소와 노드포트를 통해 샘플 앱에 액세스할 수 있다. 다음 단계에서는 인그레스 리소스를 사용하여 앱에 액세스할 수 있다.

인그레스 생성하기

다음 매니페스트는 hello-world.info를 통해 서비스로 트래픽을 보내는 인그레스를 정의한다.

  1. 다음 파일을 통해 example-ingress.yaml을 만든다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - host: hello-world.info
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 8080
  1. 다음 명령어를 실행하여 인그레스 오브젝트를 생성한다.

    kubectl apply -f https://k8s.io/examples/service/networking/example-ingress.yaml
    

    결과는 다음과 같다.

    ingress.networking.k8s.io/example-ingress created
    
  2. IP 주소가 설정되었는지 확인한다.

    kubectl get ingress
    

다음 예시와 같이, ADDRESS 열에서 IPv4 주소를 확인할 수 있다.

NAME              CLASS    HOSTS              ADDRESS        PORTS   AGE
example-ingress   <none>   hello-world.info   172.17.0.15    80      38s
  1. 호스트 컴퓨터의 /etc/hosts 파일 맨 아래에 다음 행을 추가한다 (관리자 권한 필요).

    172.17.0.15 hello-world.info
    

    이렇게 하면, 웹 브라우저가 hello-world.info URL에 대한 요청을 Minikube로 전송한다.

  2. 인그레스 컨트롤러가 트래픽을 전달하는지 확인한다.

    curl hello-world.info
    

    결과는 다음과 같다.

    Hello, world!
    Version: 1.0.0
    Hostname: web-55b8c6998d-8k564
    

두 번째 디플로이먼트 생성하기

  1. 다음 명령을 사용하여 두 번째 디플로이먼트를 생성한다.

    kubectl create deployment web2 --image=gcr.io/google-samples/hello-app:2.0
    

    결과는 다음과 같다.

    deployment.apps/web2 created
    
  2. 두 번째 디플로이먼트를 노출시킨다.

    kubectl expose deployment web2 --port=8080 --type=NodePort
    

    결과는 다음과 같다.

    service/web2 exposed
    

기존 인그레스 수정하기

  1. 기존 example-ingress.yaml 매니페스트를 편집하고, 하단에 다음 줄을 추가한다.

          - path: /v2
            pathType: Prefix
            backend:
              service:
                name: web2
                port:
                  number: 8080
    
  2. 변경 사항을 적용한다.

    kubectl apply -f example-ingress.yaml
    

    결과는 다음과 같다.

    ingress.networking/example-ingress configured
    

인그레스 테스트하기

  1. Hello World 앱의 첫 번째 버전에 액세스한다.

    curl hello-world.info
    

    결과는 다음과 같다.

    Hello, world!
    Version: 1.0.0
    Hostname: web-55b8c6998d-8k564
    
  2. Hello World 앱의 두 번째 버전에 액세스한다.

    curl hello-world.info/v2
    

    결과는 다음과 같다.

    Hello, world!
    Version: 2.0.0
    Hostname: web2-75cd47646f-t8cjk
    

다음 내용

8 - 클러스터 내 모든 컨테이너 이미지 목록 보기

이 문서는 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 값을 가져온다.

각 파드의 컨테이너 이미지 보기

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}}"

다음 내용

참조

9 - 공유 볼륨을 이용하여 동일한 파드의 컨테이너 간에 통신하기

이 페이지에서는 동일한 파드에서 실행 중인 두 개의 컨테이너 간에 통신할 때에, 어떻게 볼륨을 이용하는지 살펴본다. 컨테이너 간에 프로세스 네임스페이스 공유하기를 통해 통신할 수 있는 방법을 참고하자.

시작하기 전에

쿠버네티스 클러스터가 필요하고, 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 저장소에서 새 업데이트를 받아오는 경우이다.

이 예제에서 볼륨은 파드의 생명 주기 동안 컨테이너를 위한 통신 방법으로 이용했다. 파드가 삭제되고 재생성되면, 공유 볼륨에 저장된 데이터는 잃어버린다.

다음 내용

10 - 클러스터의 DNS 구성하기

쿠버네티스는 지원하는 모든 환경에서 기본으로 활성화된 DNS 클러스터 애드온을 제공한다. 쿠버네티스 1.11과 이후 버전에서는, CoreDNS가 권장되고 기본적으로 kubeadm과 함께 설치 된다.

쿠버네티스 클러스터의 CoreDNS 설정에 대한 더 많은 정보는, DNS 서비스 사용자화 하기을 본다. kube-dns와 함께 쿠버네티스 DNS를 사용하는 방법을 보여주는 예시는 쿠버네티스 DNS 샘플 플러그인을 본다.