본문 바로가기
CloudNetaStudy/[Study] DOIK

[1주차] Kubernetes 기초

by HeeWorld 2023. 10. 17.

이 글은 CloudNet@ 팀 gasida님의 스터디 DOIK 과제로 작성된 글입니다.

 


 

K8s(Kubernetes) 이란?

 

  • Kubernetes는 컨테이너화된 application의 deploy, management, extend 등을 자동화하는 오픈소스 컨테이너 오케스트레이션 플랫폼
  • K8s라는 표기는 K와 s 그 사이에 있는 8글자(ubernete)를 의미하는 약식 표기

 

  • 쿠버네티스는 Google 엔지니어들이 개발하고 설계한 플랫폼으로 내부에서 사용하던 컨테이너 클러스터 관리 도구인 Borg와 Omega의 아이디어를 바탕으로 만들어졌다.
  • Google에서 개발한 언어인 고로 작성되었고 쿠버네티스는 2014년에 해당 프로젝트를 오픈소스화 했으며, Google의 오랜 경험과 커뮤니티의 아이디어, 적용사례가 합쳐져 발전되었다.
  • 이후 Google이 LCNCF(Cloud Native Computing Foundation)에 코드를 기부하였다.

   

Application 배포 환경의 변화

https://kubernetes.io/ko/docs/concepts/overview/

 

  • Traditional Deployment(전통적 배포): 오래전 부터 사용되던 방식으로 물리적인 컴퓨터/장비 한 대에 하나의 OS를 설치하여 여러가지 Application을 실행했었다.
    예를 들면 우리는 컴퓨터 한대에 Window10-11 OS설치하고, 카카오톡, 엑셀, 파워포인트, 포토샵 등의 다양한 프로그램을 사용하여 설치한다. 지금 우리가 사용하는 컴퓨터/노트북이랑 비슷한 맥락으로 생각하면 될 것 같다.

    • 하지만 해당 방식은 한 개의 Application이 실행하면 하나의 물리서버 전체의 리소스를 사용해야 하는 경우가 있을 수 있으며 이런 경우 결과적으로 같은 서버에서 실행되고 있는 다른 Application의 성능 저하가 발생할 수 있다.
      이런 현상 해결을 위해 하나의 물리서버에 하나의 Application만 실행하면 되지만, 이는 리소스가 충분하지 않으니 확장에 어려움이 있고, 규모가 있는 기업에서는 많은 물리서버 유지를 위한 비용이 많이 소요되었을 것이다.

  • Virtualized Deployment(가상화 배포): 위의 전통적 배포 방식을 해결하기 위해 나온 방식이 가상화 배포 방식이다.
    말 그대로 가상머신(Virtual Machine)을 기반으로 배포하는 방법이다.
    예를 들면 컴퓨터 한 대에 각각 카카오톡, 엑셀, 보안프로그램 등을 사용하는 것이 아니라 이것들을 가상머신(VM)에 각각 띄운다면 무거운 프로그램 (ex. 포토샵)을 실행시켰을 때 다른 프로그램은 영향을 받지 않는다고 생각하면 될 것 같다.

    • 가상머신(Virtual Machine)은 가상 컴퓨터로 CPU, Memory, Disk 등을 개별적으로 할당 할 수 있다. 하나의 물리적인 장비에 여러 개의 가상머신을 만들어 각각 OS를 올리고 Application을 실행 시킨다면, Application간의 간섭은 발생되지 않으니 성능 저하의 걱정은 어느 정도 해소 될 것이다.
      그리고 가상머신은 CPU, Memory 등을 유연하게 조절하여 Application 특성에 맞춰 리소스를 할당하여 사용할 수 있으니 리소스 상황에 따라 가상 머신의 스펙을 올리는 것도, 새로운 가상머신을 만드는 것도 가능하다.
    • 하이퍼바이저(Hyperviosr): 하나의 물리적 장비에서 여러 개의 논리적 가상머신(VM)을 실행시키는데 사용하는 소프트웨어를 의미한다.
  • Container Deployment(컨테이너 중심 배포): 컨테이너 기반 배포는 가상화 배포와 달리 프로그램 기동을 위해 OS를 매번 설치하지 않아도 된다. OS위에 그려진 컨테이너 런타임(Container runtime)은 루트 파일 시스템과 메타 데이터를 받아 컨테이너를 실행하는 엔진이다. 가상 머신(VM)은 하나의 물리적인 장비에 논리적으로 Guest OS를 각각 설치해 분리된 컴퓨터라고 생각하면 될 것인데, 컨테이너는 하나의 OS에 여러 개의 컨테이너로 프로그램을 실행 시킬 수 있다. 그리고 자원은 독립적으로 사용할 수 있도록 할당하고 관리한다.
    컨테이너를 사용 시 주의할 점은 하나의 OS를 여러 개의 컨테이너가 공유하기 때문에 OS에 문제가 발생될 경우 컨테이너 전체가 영향을 받아 문제가 될 가능성이 있다.

 

Kubernetes에서 제공하는 기능

 

  1.  Service Discovery와 Load Balancing: K8S는 DNS를 사용하거나 본인의 IP 주소를 사용하여 컨테이너를 노출할 수 있고, 네트워크 트래픽을 로드밸런싱하여 배포에 안정적.

  2. Storage Orchestration: 원하는 스토리지를 Mount할 수 있음(ex. Local 저장소, NFS 등)

  3. 자동화된 Rollouts과 Rollbacks: 어플리케이션의 상태를 모니터링하면서 인스턴스가 종료되지 않도록 구성 변경사항을 서서히 배치하며 배치가 잘못 된 경우 롤백을 즉시 수행할 수 있음.

  4. 자동화된 Bin Packing: 리소스 요구사항에 따라 컨테이너를 자동으로 배치할 수 있음.

  5. Self-Healing(자동화 복구): 서비스되고 있는 컨테이너가 갑자기 종료되거나 사용자가 정의한 헬스 체크가 실패되면 자동으로 컨테이너를 복구(재생성)할 수 있음.

  6. Secret과 구성관리(Configuration Management): SSH key, OAuth Token, 암호 등의 민감 정보를 저장하고 관리할 수 있음.

 

Kubernetes Architecture


쿠버네티스 클러스터는 Control Plane(Master Node)와 Node Components(Worker Node)로 이루어 진다.

 클러스터(Cluster)란, 컨테이너 형태의 Application을 호스팅하는 물리/가상 환경의 노드들로 이루어진 집합을 의미

https://kubernetes.io/ko/docs/concepts/overview/components/

 

  • Control Plane(Master Node): 클러스터에 관련된 전반적인 기능을 제어하는 역할(ex. 스케쥴링, 모니터링 등)을 수행한다. Control Plane은 실제 서비스와 무관하고 쿠버네티스 클러스터 운영에 관련된 컴포넌트들로 구성되어있다.

    • Kube-apiserver: API 서버는 클러스터 (모든)구성 요소들의 상호 통신에 필요한 API를 관리하는 컴포넌트로 외부와 내부의 요청을 처리하며 서로 통신할 수 있도록 HTTP API를 제공.
      REST, kubectl 명령어 등을 사용하여 실행
      유저 인증, 요청사항 검증, 데이터 수신, etcd 업데이트, 스케쥴링, kubelet 통신 등의 다양한 역할을 담당
    • etcd: 클러스터 안에 각 구성 요소들에 대한 정보가 key-value 형태로 저장된 저장소이며 쿠버네티스에서 필요한 데이터를 계층적 key 구조로 저장하는 실질적인 데이터 베이스
      etcd는 분산된 아키텍처 형태를 가질 수 있고 이를 통해 고가용성 및 빠른 성능을 제공
      클러스터에 노드가 몇 개인지, 각 Pod가 어떤 컨테이너를 가지고 어떤 노드에서 어떻게 동작하는지 모두 기록

      안전성을 위해 여러 개의 노드에 분산해서 구성하는 것이 일반적

    • Kube-Scheduler: 클라이언트가 생성한 Pod를 노드의 리소스를 고려해서 어떤 노드에 배치할지 결정하는 쿠버네티스의 기본 스케줄러이며 컨트롤 플레인 컴포넌트
      새로 생성된 Pod를 실행할 최적의 노드를 선택하고, 스케쥴링 결정을 위해 고려해야 할 요소는 개별 및 집단 리소스 요구사항, 하드웨어/소프트웨어 정책 제한 조건, 어피니티(affinity) 및 안티-어피니티(anti-affinity) 명세, 데이터 지역성, 워크로드 간의 간섭 등을 포함.

    • Kube-Controller-manager: Scheduler를 통해 Pod이 스케쥴링 된 후에 해당 리소스를 원하는 상태로 만드는 작업을 하며, 다양하 컨트롤러를 실행하는 역할
      • Controller: 클러스터의 상태를 체크한 다음 필요한 때에 생성, 변경하는 작업을 담당
    • Cloud-Controller-manager: 클라우드 서비스를 제공하는 곳에 컨트롤러들을 자신의 서비스와 연계하는 역할
      kube-controller-manager와 마찬가지로 논리적으로 독립적인 여러 컨트롤 루프를 단일 프로세스로 실행하는 단일 바이너리로 결합.

  • Node Coponents(Worker Node): 동작 중인 Pod를 유지시키고 K8S 런타임 환경을 제공하며 관리를 위해 필요한 요소들

    • Kubelet: 클러스터의 각 노드에서 Pod 속 컨테이너들이 정상적으로 실행되도록 조율하는 에이전트.
      Master Node의 스케쥴러(Scheduler)가 Pod를 노드에 할당하면, Kubelet이 그 Pod와 컨테이너를 배치함.
      Pod와 컨테이너의 상태를 주기적으로 헬스체크하여 결과를 API 서버에 전송하는 역할.
    • Kube-Proxy: 클러스터의 각 노드에서 구동되는 K8S 네트워크 프록시.
      서비스의 IP 나 포트로 들어온 내/외부의 트래픽을 어떤 Pod로 보낼 것인지에 대한 규칙을 생성하고 관리하는 역할.

    • Container Runtime: 클러스터 내부에 컨테이너 이미지를 가져와 구동하는 엔진
      Pod가 노드 안에서 작동하려면 반드시 필요하며 쿠버네티스 버전 기준 별로 지원하는 런타임은 버전 별로 상이하여 공식문서 참고.
      - v1.23까지는 Docker Engine, Containerd, CRI-O, Mirantis COntainer Runtime을 지원

      - v1.24부터는 Docker Engine은 지원을 중단하였고, 현재는 Containerd 등으로 대체되고 있으며 런타임 엔진에서만 제외되는 것

 

서비스(Service) 란?

 

  • 쿠버네티스에서 서비스(Service)는 Pod를 통해 실행중인 Application을 네트워크 서비스로 노출시키는 가상의 컴포넌트이다.
  • 쿠버네티스의 Pod는 구동 중인 상태 유지를 위해 동원되는 일회성 자원으로 언제든 삭제되거나, 다른 노드로 옮겨질 수 있으며, Pod가 새롭게 생성될 때마다 내부 IP를 새롭게 받게 되므로 클러스터의 내/외부 통신을 지속적으로 유지하기 어렵다. 이를 해결하기 위해 클러스터 내부에서 고정 IP를 갖는 서비스(Serivce)를 사용한다.

    • targetPort: Pod의 Application에 오픈된 Port를 의미하며, 서비스를 통해 들어온 프래픽은 Pod의 <내부 IP>:<target port>로 통신됨.
    • port: 서비스에서 Pod를 향해 오픈된 Port를 의미

 

Service Type

 

1. Cluster IP (Defulat)

  • 클러스터 내부에서 내부 통신을 위한 IP
  • Cluster IP로 들어온 내부 트래픽을 Pod의 <Pod IP>:<target port>로 보내며, 클러스터 내부에서만 접근할 수 있음.
  • 서비스 유형을 지정하지 않은 경우 사용되는 K8S의 기본 서비스.
    ex) service.yaml
apiVersion: v1
kind: Service
metadata:
  name: service
spec:
  type: ClusterIP		
  ports:
  - protocol: TCP
    targetPort: 8080	     # Pod 노출 포트
    port: 80     	# 서비 노출 포트

 

2. Node Port

  • 외부에서 노드 IP의 특정 Port로 인입되는 요청을 감지하여 해당 포트와 연결된 파드로 트래픽을 전달.(NAT와 비슷)
  • NodePort는 30000~32767 사용.
    ex) nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: service
spec:
  type: NodePort
  ports:
  - targetPort: 8080		# Pod 노출 포트
    port: 80			# 서비스 노출 포트
    nodePort: 30008		# 외부에서 접근할 때 사용하는 포트
  selector:				# 이 서비스를 통해 연결된 Pod 정보
    app: myapp
    type: frontend

 

3. LoadBlancer

  • 외부의 로드밸런서를 사용하여 해당 로드밸런서를 클러스터의 서비스로 프로비저닝 할 수 있음.
  • 외부 로드밸런서를 통해 들어온 트래픽은 서비스 설정 값에 따라 Pod로 연결, 분산 방식은 외부 로드밸런서의 설정에 따름.
    ex) loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - protocol: TCP
      port: 80       # 서비스 노출 포트
      targetPort: 8080     # Pod 노출 포트
  clusterIP: 10.0.171.239   # Cluster IP
  type: LoadBalancer
status:
  loadBalancer:    # 프로비저닝 Loadbalancer 정보
    ingress:
    - ip: 192.0.2.127

 

4. ExternalName

  • 서비스를 DNS name에 매핑하며, 필요한 DNS 주소를 기재 시 CNAME 레코드를 반환하도록 클러스터의 DNS서버를 구성ex) externalname.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

 

Service Nodeport 구조에 대해서 한번 그려봤습니다!

 

 

인그레스(Ingress) 란?

 

  • 클러스터 외부에서 내부로 접근하는 요청을 어떻게 분산할지 HTTP/HTTPS 기반의 L7 로드밸런싱 기능을 제공하는 컴포넌트이다.
    인그레스를 통해 외부에서 접근한 트래픽을 분산하는 간단 예시이다. (공식문서)인그레스는 외부에서 서비스 접속이 가능한 URL, LB Traffic, SSL/TLS, 도메인 기반 가상호스팅 제공, 특정 경로의 라우팅 등의 규칙을 정의한 자원이며, 실제로 동작을 하는 것은 Ingress-Controller이다.

https://kubernetes.io/ko/docs/concepts/services-networking/ingress/

 

  • K8S Node에 Ingress를 구성해서 curl test를 진행
    (시험 준비로 인해 연습하던 중 실습 진행했습니다.)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: test-ns
  name: test-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "fs-cookie"
    nginx.ingress.kubernetes.io/session-cookie-hash: "sha1"
spec:
  tls:
  - hosts:
    secretName: test-secret
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend-svc
            port:
              number: 80
              
              
k apply -f test-ingress.yaml

k get ingress -n test-ns
NAME           CLASS    HOSTS   ADDRESS   PORTS     AGE
test-ingress   <none>   *                 80, 443   108s

k describe ingress -n test-ns
Name:             test-ingress
Labels:           <none>
Namespace:        test-ns
Address:
Ingress Class:    <none>
Default backend:  <default>
TLS:
  fs-secret terminates
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /   frontend-svc:80 (192.168.194.75:80)
Annotations:  kubernetes.io/ingress.class: nginx
              nginx.ingress.kubernetes.io/affinity: cookie
              nginx.ingress.kubernetes.io/session-cookie-hash: sha1
              nginx.ingress.kubernetes.io/session-cookie-name: fs-cookie
Events:
  Type    Reason  Age                From                      Message
  ----    ------  ----               ----                      -------
  Normal  Sync    20s (x2 over 75s)  nginx-ingress-controller  Scheduled for sync


# curl test

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

 

 

참고:
https://kubernetes.io/ko/docs/concepts/overview/
https://kubernetes.io/docs/concepts/services-networking/service/?ref=seongjin.me#publishing-services-service-types\
https://kubernetes.io/ko/docs/concepts/services-networking/ingress/
https://seongjin.me/kubernetes-cluster-components/