Table of Contents |
---|
...
지원하는 애플리케이션의 유형을 제약하지 않는다.
소스 코드를 배포하지 않으며 애플리케이션을 빌드하지 않는다.
애플리케이션 레벨의 서비스를 제공하지 않는다.
로깅, 모니터링 또는 경보 솔루션을 포함하지 않는다. 즉, 메트릭을 수집하고 노출하는 메커니즘을 제공한다.
K8s는 단순한 오케스트레이션 시스템이 아니다. 사실, K8s는 오케스트레이션의 필요성을 없애준다. 오케스트레이션의 기술적인 정의는 A를 먼저 한 다음, B를 하고, C를 하는 것과 같이 정의된 워크플로우를 수행하는 것이다. 반면에, K8s는 독립적이고 조합 가능한 제어 프로세스들로 구성되어 있다. 이 프로세스는 지속적으로 현재 상태를 입력받은 의도한 상태로 나아가도록 한다. A에서 C로 어떻게 갔는지는 상관이 없다. 중앙화된 제어도 필요치 않다. 이로써 시스템이 보다 더 사용하기 쉬워지고, 강력해지며, 견고하고, 회복력을 갖추게 되며, 확장 가능해진다.
...
kubelet
cluster의 각 노드에서 실행되는 에이전트.
Kubelet은 파드에서 컨테이너가 확실하게 동작하도록 관리.Kubelet은 8s를 통해 생성되지 않는 컨테이너는 관리하지 않는다.
kube-proxy
kube-proxy는 cluster의 각 노드에서 실행되는 네트워크 프록시로, K8s의 서비스 개념의 구현부
kube-proxy는 노드의 네트워크 규칙을 유지 관리한다. 이 네트워크 규칙이 내부 네트워크 세션이나 cluster 바깥에서 파드로 네트워크 통신을 할 수 있도록 해준다.
kube-proxy는 운영 체제에 가용한 패킷 필터링 계층이 있는 경우, 이를 사용한다. 그렇지 않으면, kube-proxy는 트래픽 자체를 포워드(forward)한다.
Container runtime
컨테이너 실행을 담당하는 소프트웨어
도커(Docker), containerd, CRI-O 그리고 Kubernetes CRI (컨테이너 런타임 인터페이스)를 구현한 모든 소프트웨어 지원.
...
DNS
K8s에 의해 구동되는 컨테이너는 DNS 검색에서 이 DNS 서버를 자동으로 포함한다
웹 UI (대시보드)
컨테이너 resource 모니터링
컨테이너 resource 모니터링은 중앙 데이터베이스 내의 컨테이너들에 대한 포괄적인 시계열 매트릭스를 기록하고 그 데이터를 열람하기 위한 UI를 제공해 준다.
cluster-레벨 로깅
cluster-레벨 로깅 메커니즘은 검색/열람 인터페이스와 함께 중앙 로그 저장소에 컨테이너 로그를 저장하는 책임을 진다.
Understanding Terms(중요)
Info |
---|
여기서는 아래 블로그를 포함하여 각종 관련 사이트 및 K8s 공식 사이트 문서를 참고하여, 보다 간략히 k8s에 대한 이해에 반드시 필요한 개념 위주로 추려서 기술한다. 내용 中 일부 출처: https://bcho.tistory.com/1256?category=731548 [조대협의 블로그] |
...
실제 환경에서는 replica 수만 유지하는 것만 필요한 것이 아니라, 배포 방식 및 업데이트 방식과 함께 정책을 정하고 이를 반영해야 한다. 이를 위해 Deployment라는 선언적/추상적 상위 개념이 존재한다.
따라서, 사용자 지정 오케스트레이션이 필요하거나 업데이트가 전혀 필요하지 않은 경우라면 Replica Set을 직접적으로 사용하기 보다는 Deployment를 사용하는 것을 권장한다.
Blue/Green 배포 방식
가장 단순한 업데이트 배포 방식으로, 블루(예전)버전으로 서비스 하고 있던 시스템을 그린(새로운)버전을 배포한 후, 트래픽을 블루에서 그린으로 한번에 돌리는 방식이다.
...
위 그림에서 보는 바와 같이 이 방식을 사용하기 위해서는 일시적으로 나마 시스템 리소스가 (대략) 2배가 필요하다.
즉, 항상 업데이트 할 수 있는 정도의 여유 Stage가 필요하다.
Rolling update
가장 많이 사용되는 배포 방식 중의 하나 이며, 단순화된 과정은 다음 그림과 같다.
(아래 예에서는 RC를 사용하였으나, RS(Replica Set)으로 대체해도 무관하다, 최근에는 RS가 대세로 사용된다.)
먼저 RC를 하나 만들어서 기존 RC에서 replica 수를 하나 줄이고, 새로운 RC에는 replica 수를 하나만 준다.
...
마찬가지 작업을 반복하게 되면, 아래 그림과 같이 예전 버전의 Pod가 모두 빠지고 새 버전의 Pod만 서비스 되게 된다.
...
Rollback
만약에 배포가 잘못되었을 경우에는 기존 RC의 replica 수를 원래대로 올리고, 새 버전의 replica 수를 0으로 만들어서 예전 버전의 Pods로 Rollback이
...
가능하다.
Deployment controller
여러가지 배포 방식을 RC나 RS를 이용해서 구현할 수 있지만, 운영이 복잡해지는 단점이 있다. 그래서 쿠k8s에서는 일반적으로 RC나 RS를 이용해서 배포하지 않고 Deployment라는 개념을 사용한다.
...
위 rolling update에서의 과정을 아래 그림과 같이 Deployment controller가 대신하여 자동으로 관리해 준다.
...
Deployment에서의 Rollback 또한 매우 간단히, API 혹은 kubectl 명령으로 Rollout history를 조회할 수 있고, 또 원하는 버전으로 Rollback API 혹은 명령 또한 지원한다.
Info |
---|
위에서 각 RC[S]와 Pod들, 서비스들, deployment들 간의 연결 구조 즉, 포함 관계는 label 및 seletor라는 개념으로 서로 간에 매핑한다. 이들 label은 각 yaml spec에 정의하도록 되어 있다. |
Volume
K8s의 볼륨은 여러가지 종류가 있는데, 로컬 디스크 뿐 아니라, NFS, iSCSI, Fiber Channel과 같은 일반적인 외장 디스크 인터페이스는 물론, GlusterFS나, Ceph와 같은 오픈 소스 분산 파일 시스템, AWS EBS, GCP Persistent 디스크와 같은 퍼블릭 클라우드에서 제공되는 디스크, VsphereVolume과 같이 프라이비트 클라우드 솔루션에서 제공하는 디스크 볼륨까지 다양한 볼륨을 지원한다.
이 볼륨 타입을 구별해보면 크게 임시 디스크, 로컬 디스크 그리고 네트워크 디스크 등으로 분류할 수 있다.
지원되는 모든 Storage type은 여기를 참고한다.
Temp | Local | Network |
---|---|---|
emptyDir | hostPath | GlusterFS |
gitRepo | ||
NFS | ||
iSCSI | ||
gcePersistentDisk | ||
AWS EBS | ||
azureDisk | ||
Fiber Channel | ||
Secret | ||
VSphereVolume |
emptyDir
emptyDir은 Pod가 생성될 때 생성되고, Pod가 삭제 될 때 같이 삭제되는 임시 볼륨이다.
단, Pod 내의 컨테이너 크래쉬되어 삭제되거나 재시작 되더라도 emptyDir의 생명주기는 컨테이너 단위가 아니라, Pod 단위이기 때문에, emptyDir은 삭제 되지 않고 계속해서 사용이 가능하다.
생성 당시에는 디스크에 아무 내용이 없기 때문에, emptyDir 이라고 한다.
emptyDir의 물리적으로 노드에서 할당해주는 디스크에 저장이 되는데, (각 환경에 따라 다르다. 노드의 로컬 디스크가 될 수 도 있고, 네트워크 디스크 등이 될 수 도 있다.) emptyDir.medium 필드에 “Memory”라고 지정해주면, emptyDir의 내용은 물리 디스크 대신 메모리에 저장이 된다.
만일 한 Pod 내에 Nginx 컨테이너 + fluentd(로그 수집 에이전트) 컨테이너 + emptyDir 볼륨이 있다면, 이 두 컨테이너는 할당된 emptyDir 볼륨을 공유하여 사용하게 된다.(메모리라 하더라도…)
또한 앞서 언급한 바와 같이, 생명 주기도 Pod에 따른다.
hostPath
hostPath는 노드의 로컬 디스크의 directory path를 Pod에서 마운트해서 사용한다. emptyDir과 달리, 같은 hostPath에 있는 볼륨은 여러 Pod 사이에서 공유되어 사용된다.
또한 Pod가 삭제 되더라도 hostPath에 있는 파일들은 삭제되지 않고 다른 Pod가 같은 hostPath를 마운트하게 되면, 남아 있는 파일을 액세스할 수 있다.
...
Note |
---|
주의할 점 중의 하나는 Pod가 재시작되서 다른 노드에서 기동될 경우, 그 노드의 hostPath를 사용하기 때문에, 이전에 다른 노드에서 사용한 hostPath의 파일 내용은 액세스가 불가능하다. 따라서, hostPath를 사용할 경우는 |
gitRepo
이 볼륨은 생성 시에 지정된 git repository의 특정 revision의 내용을 clone을 이용해서 내려 받은 후에 디스크 볼륨을 생성하는 방식이다. 물리적으로는 emptyDir이 생성되고, git repository 내용을 clone으로 다운 받는다.
...
HTML, 각종 설정 파일과 같은 정적 파일이나 Ruby on rails, PHP, node.js, python과 같은 스크립트 언어 기반의 코드들은 gitRepo 볼륨을 이용하여 손쉽게 배포할 수 있다.
PV(PersistentVolume)and PVC(PersistentVolumeClaim)
위에 언급한 세 개의 볼륨 타입을 제외하고는 대부분 디스크 볼륨을 설정하려면 물리적 디스크를 생성해야 하고, 이러한 물리적 디스크에 대한 설정을 자세하게 이해할 필요가 있다.(Cloud 제공 업체의 스토리지 서비스도 마찬가지다)
K8s는 인프라에 대한 복잡성을 추상화를 통해서 간단하게 하고, 개발자들이 손쉽게 필요한 인프라 (컨테이너,디스크, 네트워크)를 설정할 수 있도록 하는 개념을 가지고 있다.
그래서 인프라에 종속적인 부분은 시스템 관리자가 설정하도록 하고, 개발자는 이에 대한 이해 없이 간단하게 사용할 수 있도록 디스크 볼륨 부분에 PersistentVolumeClaim(이하 PVC라고 명명)와 PersistentVolume(이하 PV라고 명명)라는 개념을 도입하였다.
다시 말해서, 시스템 관리자가 실제 물리 디스크를 생성한 후에, 이 디스크를 PersistentVolume
이라는 이름으로 k8s에 등록한다.
개발자는 Pod를 생성할 때, 볼륨을 정의하고, 이 볼륨 정의 부분에 물리적 디스크에 대한 특성을 정의하는 것이 아니라, PVC를 지정하여, 관리자가 생성한 PV와 연결한다.
...
Note |
---|
PV의 생명 주기는 k8s 클러스터에 의해서 관리되며, Pod의 생성 또는 삭제에 상관없이 별도로 관리 된다. 즉, Pod와 상관없이 직접 생성하고 삭제해야 한다.(여타의 클라우드 볼륨 서비스(AWS EBS 등)와 유사한 개념이다.) |
Dynamic Provisioning
앞에서 본 것과 같이 PV를 수동으로 생성한 후 PVC에 바인딩 한 후에 Pod에서 사용할 수 있지만, k8s 1.6 이상에서 Dynamic Provisioning 기능을 지원한다. 이 Dynamic Provisioning 기능은 시스템 관리자가 별도로 디스크를 생성하고 PV를 생성할 필요 없이, PVC만 정의하면 이에 맞는 물리 디스크 생성 및 PV 생성을 자동화해주는 기능이다.
...
위에서 물리적인 스토리지를 생성하기 위해서는, 어떤 종류의 스토리지 스펙으로 생성해야 할 지를 k8s controller가 미리 알고 있어야 한다.
이를 위해, StorageClass
를 정의할 수 있다.
예를 들면, 아래는 AWS EBS 디스크에 대한 스토리지 클래스를 지정한 예로, slow 라는 이름으로 스토리지 클래스를 지정하고. EBS 타입은 io1을 사용하고, GB당 IOPS는 10을 할당하도록 하고, 존은 us-east-1d와 us-east-1c에 디스크를 생성하도록 한다.
...
또, 아래는 구글 클라우드의 Persistent Disk (pd)의 예로, slow라는 이름으로 스토리지 클래스를 지정하고, pd-standard (HDD)타입으로 디스크를 생성하되 us-central1-a와 us-central1-b 존에 디스크를 생성하도록 한다.
...
이와 같이, 만일 NFS, FC, iSCSI와 같은 표준 스토리지 프로토콜이 아닌 경우에도, 현재 대부분의 클라우드 제공자, 가상화 제품 벤더사 및 스토리지 벤더사가 k8s addon을 이미 제공하고 있으며, 각각 제공하는 규격에 맞게 정의하면 된다.
Service
Service는 주로 네트워킹에 관련된 오브젝트이다.
물리적인 L2, L3 layer 네트워킹 뿐 아니라, DNS lookup, Service discovery, L4 layer load balancing 등 pod들 간 혹은 내/외부 간 다양한 네트워킹 서비스들을 정의/관장한다.
(해서, 가장 종류도 많고 어렵다)
예를 들어, Pod의 경우에 지정되는 IP가 동적으로 랜덤하게 지정이 되고 리스타트 때마다 변하기 때문에 고정된 end point로 호출이 어렵다, 또한 여러 Pod에 같은 애플리케이션을 운용할 경우 이 Pod 간의 로드밸런싱을 지원해줘야 하는데, 서비스가 이러한 역할을 한다.
서비스는 지정된 IP로 생성이 가능하고, 여러 Pod를 묶어서 로드밸런싱이 가능하며, 고유한 DNS 이름을 가질 수 있다.
서비스는 다음과 같이 구성이 가능하며, label selector
를 이용하여, 관리하고자 하는 Pod 들을 정의할 수 있다. (또한 아래 예와 같이 동시에 여러 개의 포트 지정을 지원한다.)
즉, pod든 replica set이든, deployment든 간에 같은 label라면 해당(label selector
에 지정된) 서비스에 묶는다.(아래의 경우는 “hello-node” label을 가진 pod들을 묶어서 80과 443 포트로 load balancing한다.)
Code Block | ||
---|---|---|
| ||
apiVersion: v1
kind: Service
metadata:
name: hello-node-svc
spec:
selector:
app: hello-node
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
- name: https
port: 443
protocol: TCP
targetPort: 8082
type: LoadBalancer |
서비스가 Pod들에 부하를 분산할 때, Default 알고리즘은 Pod 간에 랜덤으로 부하를 분산하도록 한다.
만약에 특정 클라이언트가 특정 Pod로 지속적으로 연결이 되게 하려면 Session Affinity를 사용하면 되는데, 서비스의 spec 부분에 sessionAffinity: ClientIP
로 지정하면 된다.
서비스는 IP 주소 할당 방식과 연동 서비스 등에 따라 크게 4가지로 구별할 수 있다.
ClusterIP
: Default 설정으로, 서비스에 클러스터 IP (내부 IP)를 할당한다. K8s 클러스터 내에서는 이 서비스에 접근이 가능하지만, 클러스터 외부에서는 외부 IP를 할당 받지 못했기 때문에, 접근이 불가능하다.LoadBalancer
: 보통의 클라우드 벤더에서 제공하는 설정 방식으로, 외부 IP를 가지고 있는LoadBalancer
를 할당한다. 외부 IP를 가지고 있기 때문에, 클러스터 외부에서 접근이 가능하다.NodePort
: 클러스터 IP로만 접근이 가능한 것이 아니라, 모든 노드의 IP와 포트를 통해서도 접근이 가능하게 된다.
예를 들어 아래와 같이 hello-node-svc 라는 서비스를NodePort
타입으로 선언을 하고,nodePort
를 30036으로 설정하면, 아래 설정에 따라 클러스터 IP의 80포트로도 접근이 가능하지만, 모든 노드의 30036 포트로도 서비스를 접근할 수 있다.주의할 점은 위의 80 포트도 cluster IP이기 때문에 Cluster 내에서만 접속이 가능하다.
즉, 위의ClusterIP
+ “각 노드에 port forwarding” 기능이라 생각하면 무리가 없을 것이다.ExternalName
:ExternalName
은 외부 서비스를 k8s 내부에서 호출하고자 할 때 사용할 수 있다.K8s cluster 내의 Pod들은 클러스터 IP를 가지고 있기 때문에 - 즉, 외부로 통하는 gateway를 가지고 있지 않다 - 클러스터 IP 대역 밖의 서비스를 호출하고자 하면, NAT 설정 등의 복잡한 설정이 필요하다.
특히, AWS나 GCP와 같은 클라우드 환경을 사용할 경우 DB나, 또는 클라우드에서 제공되는 매지니드 서비스(RDS, CloudSQL)등을 사용하고자 할 경우에는 k8s 클러스터 밖이기 때문에, 호출이 어려운 경우가 있는데, 이를 쉽게 해결할 수 있는 방법이
ExternalName
타입이다.
이 방식도 다시 두 가지 방식으로 설정할 수 있는데,
첫 번째는 DNS 방식이고, 두 번째는 IP를 지정하는 방식이다.
DNS 방식은 Service object의spec
에 아래와 같이
type: ExternalName
externalName: my.database.example.com
ExternalName
과 함께 직접 지정하면 되고, 이 Service는 들어오는 모든 요청을 “my.database.example.com”으로 forwarding 해준다.IP를 지정하는 방식은
ClusterIP
로 service를 하나 생성하고,Endpoints
라고 하는 object를 하나 더 생성하여, forwarding될 IP와 port를 지정하고 이를 연결하여 사용한다.
그림으로 나타내면 다음과 같다.
Info |
---|
이 외에도 Service에는, 이들에 대해서는 k8s 外에도 위에 나열한 것처럼, 리눅스 네트워킹 관련 지식 및 모던 서비스 아키텍쳐 뿐만 아니라, 이후에 다루게 되는 Installing a Pod network add-on에 관련하여, Pod 간 네트워킹을 위한 CNI 네트워킹 모델 호환 네트워킹 솔루션들 등 매우 많은 종류의 지식이 필요하다. |
Ingress
URL path/http(s) 기반 L7 layer routing/load balancing …to do
Config Map
Secret
Service Account
Role & Cluster Role
...