쿠버네티스 기초 시리즈
What is Kubernetes Object?
이전 포스팅에서는 쿠버네티스가 무엇인지 간략하게 살펴보았습니다. 쿠버네티스는 시스템의 상태를 나타내는 오브젝트(Object)
라는 영구 엔티티라는 개념이 있습니다. 오브젝트는 의도를 담은 레코드로, 객체가 존재하도록 지속적으로 작동하게 됩니다. 오브젝트를 사용, 생성, 수정 또는 삭제하기 위해서 Kubernetes API를 사용하게 됩니다.
오브젝트는 크게 다음과 같은 의미를 갖습니다.
- 컨테이너화 된 애플리케이션이 실행중인 노드
- 해당 응용 프로그램에서 사용 가능한 리소스
- 재시작 정책, 업그레이드 및 내결함성과 같은 해당 응용 프로그램의 동작 방식에 대한 정책
가장 보편적으로 사용되는 오브젝트를 기술 방법은 .yaml
을 이용하게 됩니다.
apiVersion: apps/v1 # apps/v1beta2를 사용하는 1.9.0보다 더 이전의 버전용
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # 템플릿에 매칭되는 파드 2개를 구동하는 디플로이먼트임
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
Namespace
쿠버네티스는 동일 물리 클러스터를 기반으로 하는 복수의 가상 클러스터를 지원하는데, 이 가상 클러스터를 네이스페이스라고 칭합니다. 여러개의 팀이나 프로젝트에 걸쳐 많은 사용자가 있는 환경에서 사용하도록 만들어졌습니다.
Label
레이블은 목적에 따라 오브젝트들을 분류하고 분류된 오브젝트들만 따로 연결하기 위해 사용합니다. Pod와 같은 오브젝트에 첨부된 key&value로 이뤄집니다.
레이블은 오브젝트의 특성을 식별하는데 사용되어 사용자에게 중요하지만, 코어 시스템에게는 직접적인 의미가 없습니다. 이 레이블을 이용하면 오브젝트 하위 집합을 선택하는데 있어 용이합니다. 즉, 사용자가 느슨하게 결합한 방식으로 조직 구조와 시스템 오브젝트를 매핑할 수 있습니다.
더불어 레이블을 이용하면 dev zone과 production zone을 나눠서 셋팅할 수 있습니다.
Pod
Pod는 쿠버네티스의 최소 배포 단위로 클러스터에서의 Running Process를 나타냅니다.
Namespace는 이 Pod들을 연결해주고 각각 ip를 할당해주는 역할을 하고, 서로 다른 네임스페이스의 Pod들은 연결 할 수 없습니다.
- Pod안에는 여러 컨테이너가 들어갈 수 있으므로 여러 앱을 띄울 수 있습니다.
- 만약 Pod에 에러가 있어서 재생성되면 Pod내의 데이터가 날아갈 수 있습니다.
- 그래서 Volume을 따로 잡아서 데이터를 별도로 저장합니다.
쿠버네티스 클러스터 내부의 파드는 주로 두 가지 방법으로 사용되는데,
- 단일 컨테이너만 동작하는 파드
- 가장 많이 사용되는 사례로, 한 개의 파드가 단일 컨테이너를 감사고 있음
- 함께 동작하는 작업이 필요한 다중 컨테이너가 동작하는 파드
- 리소스 공유가 필요한 다중으로 함께 배치된 컨테이너로 구성됨
# Pod 명세 예시
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox
command: ["sh", "-c", "echo 안녕하세요 쿠버네티스! && sleep 3600"]
Container
하나의 Pod안에 여러 컨테이너를 가질 수 있습니다. 각 Container는 Port를 갖지만 서로 같은 Port를 가질 수는 없습니다.
Service
내부에서만 접근할 수 있는 Pod들을 응용 프로그램으로 표시하는 네트워크 서비스를 뜻합니다.
Pod는 각각의 고유한 ip주소를 갖지만 Auto-Healing 혹은 재배포 등으로 인해 재생성된 Pod는 때마다 새로운 ip를 부여
받게 됩니다. 새롭게 생성된 Pod 세트에 대한 단일 DNS이름을 제공하고 이들 간에 로드 밸런스를 수행합니다.
ClusterIP
- 쿠버네티스 클러스터 내에서만 접근이 가능한 IP
- → 운영자와 같은 인가된 사람만 접근
- → 내부 대쉬보드
- → 각 Pod 디버깅
- 클러스터 내에서 다른 오브젝트들이 접근 할 수있음
- Q. Pod에도 클러스터 내에서 접근 할 수 있는 IP가 있고 Service에는 자신의 클러스터 IP가 있는데 굳이 Serive를 다는 이유는?
- → Pod는 휘발성 IP, 언제든지 삭제 되고 재생성 될 수 있고, 그 때마다 ip가 새로 할당 됨
- → Service는 사용자가 직접 지우지 않는한 삭제되거나 재생성되지 않음. 항상 연결되어 있는 Pod에 접근 가능함
- → 여러개의 Pod를 연결시켰을 때 Service가 트래픽을 분산시킴
NodePort
- 내부망 연결, 클러스터 밖에 있지만 내부 네트워크 접근 전용
- 일부 데모 등을 위해 네트워크 중계기에 포트 포워딩을 통해 임시로 열어서 접근 하기도 함
- 기본적으로 ClusterIP가 할당되고 같은 기능을 함
- 쿠버네티스 클러스터한테 연결되어 있는 모든 노드한테 똑같은 Port를 할당함
- 어느 노드이던 간에 접근을 하면 Service로 연결이 되고 Service는 어느 노드로 들어왔다고 하더라도 자신한테 연결된 Pod에 트래픽을 전달
- Pod가 있는 노드만 포트가 생기는 것이 아니라 Pod가 없는 노드여도 포트 할당이 됨
externalTrafficPolicy: Local
→ 특정 노드 포트의 IP로 접근하는 트래픽은 해당 노드에 있는 POD로만 트래픽을 줌
Load Balancer
- 클라우드 공급자의 로드 밸랜서를 사용하여 서비스를 외부에 노출
- Node포트의 성격을 그대로 가지고 있음
- 각각의 Node에 트래픽 분산
- 로드밸런스에 접속하기 위한 외부 IP는 개별적으로 설치한경우 생기지 않고, 별도로 외부 IP를 할당하는 플러그인이 설치되어 있어야 함
→ GCP, AWS, Azure, OpenStack은ExternalIP를 지원함
Volume
Docker는 볼륨 개념이 있지만 다소 느슨하고 덜 관리됩니다. 단순히 디스크 또는 다른 컨테이너의 디렉토리입니다. 수명은 관리되지 않으며 최근까지는 로컬 디스크 백업 볼륨만 있었습니다.
하지만 쿠버네티스는 볼륨을 묶는 포도으와 동일하게 명시적인 수명을 갖습니다. 따라서 포드 내에서 실행되는 모든 컨테이너보다 수명이 길고 컨테이너를 다시 시작해도 데이터가 보존됩니다.
다음은 볼륨 유형들 중 emptyDir, hostPath, PVC/PV에 관해 간략히 살펴보겠습니다.
emptyDir
- Pod가 노드에 할당되고, 그 포드가 해당 노드에서 실행될 때 생성됨
- Pod 생성 시 만들어지고 삭제 시 없어지기 때문에 일시적임을 명심해야 함
- Container들 끼리 데이터를 공유하기 위해 볼륨을 사용하는 것으로 최초 생성 될 때 볼륨이 비어있기 떄문에 emptyDir이라고 명명됨
- Container1이 마운트된 볼륨에 파일을 올리면 Container2가 같은 볼륨을 쓴다고 했을 때 파일을 따로 업로드하거나 할 필요없이 공유하게 됨
- 용도
- 웹 서버 컨테이너가 데이터를 제공하는 동안 컨텐츠 관리자 컨테이너가 패치하는 파일 보유
- 충돌 복구를 위한 긴 계산을 체크 포인트
- 디스크 기반 병합 정렬과 같은 스크래치 공간
# emptyDir 명세 예시
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
hostPath
- 포드에 호스트 노드의 파일 시스템에서 파일이나 디렉토리를 마운트함
- Pod들이 올라가져 있는 Node의 Path를 Volume으로 사용 하기 때문에 Pod가 재생성 되어도 Volume이 유지됨
- 하지만 신규 생성된 Pod가 기존 Volume이 있던 Node에 생성된다는 보장이 없음
- 각각의 노드에는 기본 적으로 자신을 위해 사용되는 시스템 파일이나 설정 파일 등 자신의 호스트 데이터를 읽을 때 사용
- 반드시 host-path에 기존 path가 생성이 되어 있어야 함
# hostPath 명세 예시
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /data
# this field is optional
type: Directory
PV & PVC
PV
Persistent Volume은 관리자에 의해 제공된 이용 또는 동적 프로비저닝 된 클러스터에 저장하는 부분
- Local 혹은 Azuer, AWS 등의 저장소를 정의하고 연결을 함
PVC
Persistent Volume Clain은 사용자에 의해 어떤 저장소를 사용할지에 대한 요청 명세
- 포드와 비슷한 성격으로, 모드는 노드 리소스를 소비하고 PVC는 PV 리소스를 소비함
- 포드는 특정 수준의 리소스를 요청할 수 있고, PVC는 특정 크기 및 액세스 모드를 요청할 수 있음
storageClassName: ""
반드시 쌍따옴표로 설정해줘야 하고, 이 부분은 추후 다시 살펴보겠습니다.
쿠버네티스가 PVC 내용에 맞는 적절한 PV를 연결 해주는데 이때 PV의 spec - capacity & accessModes 로 판단 함