파드는 쿠버네티스에서 컨테이너를 실행하는 역할
쿠버네티스의 여러 오브젝트 중 가장 중요한게 파드이다(파드가 주인공)
나머지는 파드를 사용하거나 관리하거나 노출시키는 역할 수행할 뿐
쿠버네티스는 컨테이너를 직접 배포하지 않음. 파드를 배포하고 파드를 운영함
컨테이너가 노드에 배포되는게 아니라 파드가 노드에 배포되는 것
파드는 하나 이상의 컨테이너를 포함 (주로 파드 하나에 컨테이너 하나만 포함하긴 함..)
의문)
파드 같은거 없이 컨테이너를 직접 배포하고 실행하면 안되나?
왜 여러 컨테이너를 같이 실행할 필요가 있지?
모든 프로세스를 단일 컨테이너에 넣을 수 없나?
답)
함께 실행되고 관리되어야하는 프로세스들이 있음
컨테이너는 단일 프로세스를 실행하는 것을 목적으로 설계됨
-> 같이 실행되어야 하는 프로세스들이 있다면, 각자 컨테이너로 싼 다음 이 컨테이너들이 함께 실행되도록 해야함 -> 그래서 파드 두둥장!
즉, 파드는 여러 컨테이너를 하나의 단위로 묶어 관리하기 위한 상위 개념
한 그룹 안에 있는 컨테이너가 특정 리소스를 공유하게 하기 위해 각 컨테이너가 완벽히 격리되지 않도록 해야함
-> 이를 위해 쿠버네티스는 한 파드안의 컨테이너들은 자신만의 리눅스 네임스페이스가 아닌 파드의 리눅스 네임스페이스를 공유하도록 도커를 설정한다
-> 컨테이너 당 네임스페이스? NO! 파드 당 네임스페이스!
한 파드 안의 컨테이너들은 동일한 '네트워크 네임스페이스'와 'UTS 네임스페이스' 안에서 실행됨 (호스트 네임, 네트워크 인터페이스 공유한다는 뜻)
또한 동일 IPC 네임스페이스 아래에서 실행되기 때문에 컨테이너 간 IPC 로 통신 가능
파드안의 컨테이너 들은 '네트워크 네임스페이스' 공유하기 때문에 동일한 IP, PORT 공간 공유
쿠버네티스 클러스터의 모든 파드는 하나의 플랫한 공유 네트워크 주소 공간에 상주
파드는 논리적인 호스트
컨테이너가 아닌 환경에서의 VM 과 매우 유사하게 동작
하나의 파드에는 하나의 어플리케이션만을 호스팅한다
한 어플리케이션을 여러 파드에 호스팅한다
밀접하게 연관된 구성요소나 프로세스만 하나의 파드에 넣어야 한다
한가지 예시를 들어 파드 안에 어떤 컨테이너들을 함께 넣거나 따로 넣어야하는지 판단 기준을 생각해보자.
만약 프론트엔드 어플리케이션 서버, 백엔드 DB서버가 있다고 할 때 이 두 컨테이너를 하나의 파드에 넣는게 맞는가?
답은 따로 파드를 구성하는게 더 좋다
리소스 활용 측면
만약 2개의 워커 노드를 가진 클러스터가 있다고 할 때, 2개의 컨테이너를 한 파드에 배치했다면 노드 한 개는 빈 상태로 두어야한다.
2개의 각각 파드를 구성했다면 2개의 노드를 FULL 로 사용할 수 있다
스케일링 측면
파드 단위로 스케일링 하기 때문에, 2개의 컨테이너를 따로 파드로 구성하여야 각자 유연한 스케일링이 가능하다.
스케일링 요구사항이 항상 같지 않다면 따로 스케일링이 가능한 구성이 맞는 구성이다
어플리케이션이 하나의 주요 프로세스와 하나 이상의 보완 프로세스로 구성된 경우
지원 컨테이너는 다른 말로는 사이드카 컨테이너로 불리며 로그 로테이터, 수집기, 데이터 프로세서, 통신 어댑터 등이 있다.
종합적으로 판단했을 때 판단 기준은 아래의 질문에 답을 구하며 정해볼 수 있다
1. 컨테이너를 꼭 같은 논리적 호스트에서 함께 실행해야하나?
2. 여러 컨테이너가 모여 하나의 구성요소를 나타내는가? 아니면 개별적인 구성요소인가?
3. 컨테이너가 함께 스케일링되어야 하는가?
기본적으로는 각각의 파드를 구성하되 꼭 같이 구성해야하는 경우에만 단일 파드 구성을 고려해 본다
쿠버네티스 리소스(오브젝트)들은 아래 방법으로 생성할 수 있다
메니페스트 전송 방식은 여러 종합적인 오브젝트들에 대한 정보를 담아 작성하고 이를 git에서 관리할 수 있기 때문에 더 효율적인 방법이다
각 유형별 리소스 구성은 쿠버네티스 API 오브젝트 정의를 알고 이해하고 써야한다
apiVersion: v1 # 이 디스크립터는 쿠버네티스 API 버전 v1 을 준수함
kind: Pod
metadata:
name: kubia-manual # 파드 이름
spec:
containers:
- image: luksa/kubia
name: kubia # 컨테이너 이름. 이 포트를 통해 파드에 연결할 수 있는지 여부는 상관없음 (단지 정보를 명시할 뿐)
ports:
- containerPort: 8080 # Application 이 수신하는 port
protocol: TCP
파드 생성, 생성 메니페스트 확인, 현재 파드들 보기
$ kubectl create -f kubia-manual.yaml
$ kubectl get po kubia-manual -o yaml
$ kubectl get pods
컨테이너화된 어플리케이션은 로그를 파일에 쓰기보다 표준 출력과 표준 에러에 로그를 남기는 게 일반적이다
사용자는 서로 다른 어플리케이션들의 로그를 간단하고 동일한 방식으로 볼 수 있다
컨테이너 런타임은 이러한 스트림을 파일로 전달하고 다음 명령을 이용해 컨테이너 로그를 가져온다
$ docker logs <container id>
ssh로 파드가 실행중인 노드에 접속해 위 명령을 사용하여 로그를 가져올 수 있지만, 쿠버네티스는 좀 더 쉬운 방법을 제공한다
pod 로그 (좀 더 정확히 컨테이너 로그) 를 보기 위해 로컬 머신에서 다음 명령 실행
$kubectl logs kubia-manual
$kubectl logs kubia-manual -c kubia # 컨테이너 이름 지정
원래 kubectl expose 명령으로 외부에서 파드에 접속할 수 있게 해주는 서비스를 만들어야 한다
하지만 디버깅 목적으로 파드에 서비스 없이 연결할 수 있는 방법이 있다
$kubectl port-forward kubia-manual 8888:8080
$curl localhost:8888
로컬 포트 8888 로 파드의 포트 8080 으로 연결할 수 있다
마이크로 서비스 아키텍처 하에서 여러 파드들이 필요하고 각각의 파드들은 레플리케이션을 가지며 또한 여러 릴리즈(안정, 베타, 카나리)가 동시에 수행된다
즉 클러스터에 파드들 수백 수천개가 새겨 난장판이 될 수 있다.
어떤 파드가 어떤 것인지 쉽게 알 수 있도록 기준에 따라 그룹화 하는 방법이 필요
각 파드 개별에 대해 작업하기 보단 특정 그룹에 속한 모든 파드에 한 번에 작업하길 원한다
이를 가능하게 해주는 개념이 '레이블' 이다
레이블을 통해 파드와 기타 다른 쿠버네티스 오브젝트의 조직화가 이뤄진다
일반적으로 리소스 생성시 레이블을 부여하지만, 나중에 추가, 삭제, 수정이 가능함
레이블을 보고 이게 어떤 파드인지를 파악할 수 있다
ex) 아 이 pod는 account service를 위한 것이고 stable 환경을 위한 pod구나!
특정 레이블로 태그된 파드의 부분 집합을 선택해 원하는 작업 수행
특정 값과 레이블을 갖는지 여부에 따라 리소스를 필터링하는 기준이 됨
$ kubectl get po -l creation_method=manual
$ kubectl get po -l env
$ kubectl get po -l '!env'
$ kubectl get po -l creation_method!=manual
$ kubectl get po -l env in (prod, devel)
$ kubectl get po -l env notin (prod, devel)
레이블 셀렉터는 만족하는 파드 목록을 나열하는 것 뿐 아니라 파드 부분집합에 작업을 한번에 수행할 때도 유용 (ex, 특정 파드 그룹 삭제)
기본적으로 파드를 생성하면 워커노드 전체에 걸쳐 무작위로 스케줄링된다
기본적으로 파드는 요청한 만큼의 리소스를 할당받기만 하면 어느 노드에 스케줄링 되는지는 전혀 중요하지 않다
하지만 예외상황은 늘 있다
워커노드들의 하드웨어 인프라가 동일하지 않은 경우
1. 워커노드 일부는 HDD를, 일부는 SSD를 가지고 있는 경우
2. 워커노드 일부는 GPU를 사용, 나머지는 아닌 경우
쿠버네티스의 아이디어 자체가 '실행되는 어플리케이션이 실제 인프라에 대한 정보를 모르게 하는 것' 이기 때문에 어떤 노드에 스케줄링 되어야 한다 라고 구체적으로 지정하지 않는다.
정확한 노드를 지정하는 대신 노드 요구사항을 기술하고 쿠버네티스가 요구사항을 충족하는 노드를 선택하게 만들어야 한다. 이를 위해 노드 레이블과 레이블 셀렉터를 사용한다
운영팀은 새 노드를 클러스터에 추가할 때 노드에 대한 정보를 레이블로 지정해 분류할 수 있다.
$ kubectl label node gke-ubia-85f6-node-0rrx gpu=true
$ kubectl get nodes -l gpu=true
apiVersion: v1 # 이 디스크립터는 쿠버네티스 API 버전 v1 을 준수함
kind: Pod
metadata:
name: kubia-gpu # 파드 이름
spec:
nodeSelector: # 이 레이블을 포함한 노드에 이 파드를 배포(스케줄링)하도록 지시한다.
gpu: "true"
containers:
- image: luksa/kubia
name: kubia # 컨테이너 이름. 이 포트를 통해 파드에 연결할 수 있는지 여부는 상관없음 (단지 정보를 명시할 뿐)
ports:
- containerPort: 8080 # Application 이 수신하는 port
protocol: TCP
cf) 모든 노드들은 kubernetes.io/hostname 키와 호스트 이름을 값으로 가진 레이블을 가진다. 이를 이용해 nodeSelector 에 실제 노드의 호스트이름을 지정할 수도 있지만 이는 올바른 방법은 아니다.
레이블 셀렉터로 지정한 특정 기준을 만족하는 노드의 논리적인 그룹을 생각하고 사용해야 한다. (쿠버네티스는 선언적 방식)
어노테이션은 레이블과 비슷하면서도 다른 개념이다
어노테이션은 파드 뿐만 아니라 다른 쿠버네티스 오브젝트에도 사용할 수 있다
자동으로 추가될 수도 있고 사용자가 수동으로 추가할 수도 있다
키-값 쌍
식별정보를 갖지 않음
오브젝트를 묶는데 (그룹화) 사용하지 않음 -> 어노테이션 셀렉터? 란거 없음
훨씬 더 많은 정보를 보유할 수 있음 (상대적으로 긴 데이터 저장)
주로 도구들(tools)에서 사용됨
오브젝트를 만든 사람 이름을 어노테이션으로 지정 -> 클러스터에서 작업하는 사람들이 좀 더 쉽게 협업할 수 있음
kubernetes.io/created-by 라는 어노테이션은 자동으로 생성되며, 이 오브젝트를 생성하는데 사용된 JSON 데이터를 보여준다 (1.8 버전까지만 쓰임)
처음 파드 생성시 추가 하거나 이미 생성된 파드에 어노테이션 추가/수정이 가능하다
키 값 충돌방지를 위해 고유 접두사를 사용한다
$ kubectl annotate pod kubia-manual mycompany.com/someanno="foo bar"
오브젝트를 겹치지 않는 그룹으로 분할하고자 할때 사용
한번에 하나의 그룹 안에 속한 리소스에만 작업하고 싶다는 요구사항 충족시켜줌
리눅스 네임스페이스와는 다름
오브젝트 이름의 범위를 제공
같은 리소스 이름을 다른 네임 스페이스에 걸쳐 여러번 사용할 수 있게 해줌
많은 구성요소를 가진 복잡한 시스템을 작은 개별 그룹으로 분리할 수 있음
대부분의 리소스 유형은 네임스페이스 안에 속하지만 일부는 그렇지 않음
$ kubectl get ns # 클러스터에 있는 namespace 나열
# 기본적으로 default, kube-public, kube-system 이 생성되어 있음
$ kubectl get po --namespace kube-system # 특정 ns에 있는 pods 나열
# ns 명시하지 않으면 'default' ns 가 사용됨
kube-system는 쿠버네티스 시스템 자체와 관련된 리소스들
네임스페이스를 통해 리소스를 깔끔하게 분리하여 관리
네임스페이스는 리소스 격리이외에도 특정 사용자가 지정된 리소스에 접근할 수 있도록 허용하고 개별 사용자의 사용가능 컴퓨팅 리소스를 제한하는 데에 사용된다
YAML 파일 작성 후 제출
kubectl 이용
$ kubectl create namespace custom-namespace
생성한 ns안에 리소스를 만들고 싶으면?
$ kubectl create -f kubia-manual.yaml -n custom-namespace
네임스페이스를 지정하지 않으면 kubectl은 현재 kubectl 컨텍스트에 구성된 기본 네임스페이스에서 작업을 수행함
현재 컨텍스트와 현재 컨텍스트의 ns는 'kubectl config' 명령으로 변경할 수 있음
네임스페이스는 실행중인 오브젝트에 대한 격리는 제공하지 않음
즉, 서로 다른 ns에 있는 pod들이 통신을 할 수도 있다. 네트워크가 꼭 격리되는 것은 아니다.ns에서 네트워크 격리를 제공하는지는 '쿠버네티스와 함께 배포하는 네트워킹 솔루션'에 따라 다르다. 해당 솔루션이 ns간 격리를 제공하지 않으면 둘은 통신이 가능하다
default ns에 4개의 pod, custom-namespace에 1개의 pod를 삭제해 보자
pod 삭제시, 안에 있는 모든 컨테이너 종료됨
$ kubectl delete po kubia-gpu # 이름으로 삭제
$ kubectl delete po -l rel=canary # 레이블 셀렉터로 삭제
네임스페이스를 삭제하면 그 안에 있는 모든 파드는 자동으로 삭제된다
$ kubectl delete ns custom-namespace
$ kubectl delete po -all # 현재 네임스페이스의 모든 파드 삭제
# 현재 네임스페이스의 모든 오브젝트 삭제
# all 키워드로 모든 것을 삭제하려 해도 삭제안되는 것들도 있다 (시크릿 등)
# 이것들은 명시적으로 삭제가 필요함
$ kubectl delete all -all