데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      [3기 스터디] 딥다이브 쿠버네티스 두번째 스터디 (06.20)

      강만쥬 24.07.02
      1,432 3 2
      DEVOTEE 요약
      이번 포스팅은 쿠버네티스 딥다이브 두 번째 스터디 후기로, 쿠버네티스 철학과 아키텍처, 그리고 주요 컴포넌트에 대한 내용을 다룹니다. 워커 노드와 컨트롤 플레인의 역할, API 흐름 등을 쉽게 이해할 수 있도록 정리해보았습니다.
      DEVOTEE 추천 블로그

      안녕하세요, 데보션영 3기 강대훈입니다 🐈


      지난 6월 20일 영특한 스터디 : 쿠버네티스 딥다이브 두번째 스터디가 진행되었습니다.

      이번 스터디는 내용이 많아서 조금씩 작성하다보니 업로드가 많이 늦었네요,, 반성중입니다 😅

      두 번째 스터디인데도 멘토님께서 벌써 많은 분들의 이름을 외우시고, 또 외우려고 노력하시는 모습이 너무 감동이었습니다.. 🥹

      더욱 열심히 하게되는 동기가 되는 것 같습니다.


      저번 메밀 후토마끼에 이어 이번에도 식사를 지원해주셔서 감사히 먹었습니다 ㅎㅎ

      김밥이었는데 너무 맛있더라구요 ,,, 😭 폭풍식사


      휴게실?도 열려있어서 커피나 티 등도 마실 수 있었습니다.

      이번에는 일찍 도착해 여유롭게 둘러보았네요 👍🏻


      저번 컨테이너의 원리에 이어서, 이번 스터디부터는 본격적으로 쿠버네티스에 대해 다루었습니다.


      지난 스터디는 스터디 후기와 내용을 분리해서 작성했는데,

      이번 회차는 쿠버네티스를 처음 접하는 사람도 이 강의만 들어도 쿠버네티스를 이해할 수 있겠다! 싶어서 내용도 같이 정리하려고 합니다.

      (* 원활한 이해를 위해 제가 따로 공부한 내용도 추가되어 있어 잘못된 부분은 지적 부탁드립니다.)


      쿠버네티스의 철학

      모든 소프트웨어에는 철학이 있고, 그 철학은 굉장히 중요하다고 하셨습니다. 이 소프트웨어를 왜 만들었는지? 왜 쓰는지? 를 알아야 이해가 빠르기 때문입니다.

      따라서 쿠버네티스에 대해 알아보기 전에 쿠버네티스의 철학을 살펴보겠습니다.

      k8s api는 선언적이다. (not imperative)

      • desire state: 모든 컴포넌트가 desire state를 맞추려고 한다.

      • control plane이 워커 노드에 명령하지 않는다.

      기존 명령형(imperative) 방식의 단점은 가용성이 떨어지고, 명령을 실행하는 중간 시스템의 상태를 보장하기가 어렵습니다. (시스템이 살아있는지 알기 힘들기 때문에)

      하지만 선언적 방식을 사용함에 따라 자동화된 상태 관리와 분산 환경에서의 일관성 유지, 변경 용이성 등의 장점을 가지게 됩니다.

      k8s 컨트롤 플레인은 transparent하다. (모든 API는 노출되어 있다.)

      • 모든 컴포넌트는 api server를 통해서 정보를 안다.

      • 상태값 vs 값의 변경

      • simpler, easily recovery, composible, extensible

      api server로 정보를 알 수 있는 이유는, 모든 API가 노출되었고, 사용자가 사용하는 API와 컴포넌트가 사용하는 API는 동일하기 때문입니다.

      따라서 etcd와 통신하는 것도 api server뿐입니다. 이는 추후 그림을 통해 자세히 알아보겠습니다.


      상태값 (level triggered) : 레벨 1,2,3가 있을 때, 현재 해당되는 상태를 봅니다.

      현재의 상태가 1인지 2인지 지속적으로 이벤트를 감지합니다.

      만약 내 상태를 받는 상대 컴포넌트가 죽어도 상관이 없습니다.

      상대가 다시 작동할 때에도 내 상태를 계속 보내기 때문이다.

      단점은 상태가 변하는 즉시 알릴 수 없다는 것이지만, (시점은 조금 늦어도) 결국은 상태를 맞출 수 있습니다.


      값의 변경(edge trigger) 는 레벨 1,2,3이 있을 때 상태가 1에서 2로 변경되는 그 순간을 잡아내는 것입니다.

      변경된 순간에 내 상태를 받는 상대가 죽어있으면 상대는 이후 다시 작동하더라도 내 상태를 영원히 알 수 없습니다.

      요약

      특성

      레벨 트리거 (Level Trigger)

      엣지 트리거 (Edge Trigger)

      감지 방식

      신호의 상태

      신호의 변화

      이벤트 발생

      신호 상태가 유지되는 동안 지속적

      신호 변화 시 한 번만 발생

      장점

      신호 상태를 확실히 감지 가능

      신호 변화에 즉각적 반응 가능

      단점

      즉각적 반응 불가

      신호 변화를 놓칠 수 있음

      레벨 트리거와 엣지 트리거 두개를 다 사용하는 것이 쿠버네티스의 scheduling이다.

      fetching kubernetes api data

      쿠버네티스는 다양한 방법으로 API 데이터를 가져올 수 있습니다.

      여기엔 secrets, configmap, downwardAPI 등이 있고 뒤에서 자세히 살펴 보겠습니다.

      Workload Portability

      워크로드 포터빌리티는 애플리케이션을 다양한 클러스터 환경에서 쉽게 이동하고 실행하는 능력을 의미합니다.

      • CSI(Container Storage Interface) : CSI는 쿠버네티스 클러스터에서 스토리지를 추상화하여 다양한 스토리지 솔루션을 통합할 수 있게 해줍니다.

        이를 위해서 PV(Persistent Volume), PVC(Persistent Volume Claim)이 사용되는데, 뒤에서 자세히 살펴 보겠습니다.


      쿠버네티스 아키텍처

      이제 쿠버네티스의 컴포넌트, 데이터 및 API 요청의 흐름을 보면서 쿠버네티스 아키텍처에 대해 알아보겠습니다.


      먼저 일반적인 쿠버네티스 아키텍처에 대한 그림은 다음과 같습니다.


      쿠버네티스를 배포하면 클러스터를 얻습니다.


      그리고 쿠버네티스 클러스터는 컨트롤 플레인 컴포넌트와 워커 노드 컴포넌트로 이루어지고,

      모든 클러스터는 최소 하나 이상의 컨트롤 플레인 노드(마스터 노드)와 최소 한 개의 워커 노드를 가집니다.


      또한 컨트롤 플레인은 일반적으로 여러 컴퓨터에 걸쳐 실행되어 내결함성과 고가용성이 제공됩니다.

      우리가 개발해서 배포하는 애플리케이션과 서비스들을 워크로드라 부르며, 이 워크로드들이 파드로서 워커노드에서 돌아가게 됩니다.

      즉, 워커 노드는 애플리케이션의 구성요소인 파드를 호스트하며 컨트롤 플레인은 워커 노드와 클러스터 내 파드를 관리합니다.

      (컨트롤 플레인에서도 워크로드를 띄울 수는 있습니다. 당연히 권장 X)


      쿠버네티스 컴포넌트 (컨트롤 플레인)

      컨트롤 플레인의 컴포넌트들은 위 그림처럼 여러 개를 띄워도, 그 중 리더를 선출해서 사실상 일하는 것은 하나 뿐입니다. 나머지는 가용성을 위해서 존재합니다.

      클러스터를 구성하는 HCI 장비나 Elasticsearch가 그러하듯 마스터 선출을 위해 최소 3개부터 구성이 되는 듯 합니다.

      kube-apiserver

      API 서버는 쿠버네티스 API를 노출하는 쿠버네티스 컨트롤 플레인 컴포넌트입니다.

      쿠버네티스 API 서버의 주요 구현은 kube-apiserver이고, 수평 확장이 가능합니다.

      그러나 apiserver는 가용성을 위해 로드밸런서가 있어야하는데, 외부 로드 밸런서(ELB 등)을 사용하거나 뒤에서 나오는 서비스단에서 로드밸런싱을 합니다.

      (API 목록이 공개되어 있어클라이언트 측에서도 가능하다곤 합니다)

      etcd(엣시디)

      모든 클러스터 데이터를 담는 쿠버네티스 뒷단의 저장소로 사용되는 일관성-고가용성 키-값 저장소로서,

      분산 시스템에서 노드 사이의 상태를 공유하는 합의 알고리즘 중 하나인 raft알고리즘을 구현한 것입니다.

      etcd는 서버 하나당 프로세스를 1개만 사용할 수 있고 etcd 자체를 클러스터링한 후 여러 개 마스터 서버에 분산해서 실행해 안정성을 보장하도록 구성하는 것이 좋다고 합니다.

      etcd에는 모든 클러스터 데이터가 담아져 있다. 그렇다면 쿠버네티스를 백업한다는 것은 etcd를 백업하는 것인가?

      만약 클러스터를 옮기기 위해 etcd만 백업 후, 다른 클러스터에서 띄우는 경우엔 실패한다고 합니다.

      그 원인은 워크로드의 내부 ip도 etcd에 저장되어 있으나, 클러스터를 변경하면서 내부 ip도 변경되기 때문입니다.

      만약 리스타트를 해서 새로운 클러스터의 내부 ip 정보를 etcd에 업데이트한다면, 정상적으로 뜰 것이라고 합니다.

      kube-scheduler

      노드가 배정되지 않는 새로 생성된 파드를 감지하고, 실행할 노드를 선택하는 컴포넌트입니다.

      파드에는 리소스 및 노드에 대한 다양한 조건이 있고, kube-scheduler는 이를 분석해 조건에 맞는 노드를 찾습니다.

      조건에는 리소스, 어피니티, 안티 어피니티, 노드셀렉터 등이 있을 수 있습니다.

      kube-controller-manager

      컨트롤러 프로세스를 실행하는 컴포넌트.

      각 컨트롤러는 분리된 프로세스이지만, 모두 단일 바이너리로 컴파일되고 단일 프로세스 내에서 실행된다.

      컨트롤러 종류는 다음과 같다.

      • 노드 컨트롤러: 노드가 다운되었을 때 통지와 대응에 관한 책임을 가진다.

      • 잡 컨트롤러: 일회성 작업을 나타내는 잡 오브젝트를 감시한 다음, 해당 작업을 완료할 때까지 동작하는 파드를 생성한다.

      • 엔드포인트슬라이스 컨트롤러: (서비스와 파드 사이의 연결고리를 제공하기 위해) 엔드포인트슬라이스(EndpointSlice) 오브젝트를 채운다

      • 서비스어카운트 컨트롤러: 새로운 네임스페이스에 대한 기본 서비스어카운트(ServiceAccount)를 생성한다.

      cloud-controller-manager

      클라우드별 컨트롤 로직을 포함하는 컴포넌트입니다.

      이를 통해 클러스터를 클라우드 공급자의 API에 연결하고, 해당 클라우드 플랫폼과 상호 작용하는 컴포넌트와 클러스터와 상호 작용하는 컴포넌트를 구분할 수 있게 해줍니다.

      이 컴포넌트는 클라우드 제공자 전용 컨트롤러만 실행하고, 온프레미스로 쿠버네티스를 실행할 경우 클러스터에 클라우드 컨트롤 매니저가 없습니다 (그래서 optional).

      보통 네가지 컨트롤러 컴포넌트를 관리합니다.

      • 노드 컨트롤러: 노드를 관리하는 데 사용

      • 라우트 컨트롤러 : 각 클라우드 서비스 안의 네트워크 라우팅을 관리하는 데 사용

      • 서비스 컨트롤러 : 각 클라우드 서비스에서 제공하는 로드밸런서를 생성, 갱신, 삭제하는 데 사용

      • 볼륨 컨트롤러: 클라우드 서비스에서 생성한 볼륨을 노드에 연결하거나 마운트하는 등에 사용


      쿠버네티스 컴포넌트 (워커 노드)

      kubelet

      kubelet은 워커 노드와 컨트롤 플레인에 존재하는데, 컨테이너를 실행시키는 역할을 맡습니다.

      사실상 모든 컴포넌트를 kubelet이 관리하고 모니터링한다고 볼 수 있습니다.


      yaml로 선언해야 하는데, api 서버가 요청을 받아서 etcd에 저장하고, 스케쥴러가 etcd값을 보고, api서버를 통해서 pod 값을 본다.

      그리고 노드가 결정이 안되어있으면 스케쥴러가 어느 노드에 설치할지를 세팅한다.

      거기까지 결정되면 해당되는 노드의 kubelet이 파드(컨테이너)를 띄웁니다. (자세한 흐름은 바로 뒤에서)


      Kubelet은 다양한 메커니즘을 통해 제공된 파드 스펙(PodSpec)의 집합을 받아서 컨테이너가 해당 파드 스펙에 따라 건강하게 동작하는 것을 확실히 합니다.

      단, Kubelet은 쿠버네티스를 통해 생성되지 않는 컨테이너는 관리하지 않습니다.


      kubelet의 컨테이너 진단

      컨테이너가 실행된 후 kubelet은 컨테이너를 주기적으로 진단합니다.

      그리고 진단 방법은 다음 두 가지가 있습니다.

      livenessProbe

      컨테이너가 실행됐는지 확인합니다.

      이 진단이 실패하면 kubelet은 컨테이너를 종료시키고, 재시작 정책에 따라 컨테이너를 재시작합니다.

      readinessProbe

      컨테이너가 실행된 후 실제로 서비스 요청에 응답할 수 있는지 진단합니다.

      이 진단이 실패하면 엔드포인트 컨트롤러는 해당 파드에 연결된 모든 서비스를 대상으로 엔드포인트 정보를 제거합니다.


      만약 readinessProbe를 지원하는 컨테이너라면 컨테이너가 실행된 후 바로 서비스에 투입되는 것이 아닌, 트래픽을 받을 준비가 된 후 트래픽을 받기 시작합니다.

      이는 자바 스프링과 같이 앱이 초기화될 떄까지 시간이 걸리는 상황에 유용합니다.



      틈새 퀴즈

      컨테이너를 띄우려면 kubelet이 필요합니다. 즉, 컨트롤 노드에도 kubelet이 존재합니다.

      apiserver, 스케쥴러 다 뜨기 전인데 kubelet을 가지고 그 노드들을 어떻게 띄울까요? apiserver가 없으니 요청을 날릴 수 없지 않을까요?

      이를 해결하기 위해 쿠버네티스에서 static pod를 운영합니다. kubelet이 뜰 때 static 파드의 yaml을 읽고, 꼭 필요한 컴포넌트들을 생성합니다.

      따라서 static 파드는 어디에 위치한다는 약속이 있습니다. (각 노드의 /etc/kubernetes/manifests)


      🚨만약 '도커 데스크톱'을 사용중이라면 도커가 실행한 리눅스 가상 머신에 접속 후 확인 가능합니다.🚨

      저는 minikube를 사용 중이므로 다음과 같이 접속 후 static 파드의 yaml파일 들을 확인할 수 있었습니다.



      kubeproxy

      kubeproxy는 iptables 혹은 ipvs를 사용합니다.

      요즘은 ipvs를 사용해서 ip를 로드밸런싱 해준다.


      iptables는 리눅스 커널에서 제공하는 패킷 필터링 및 네트워크 주소 변환(NAT) 프레임워크입니다.

      sNAT, dNAT등의 작업을 iptables에서 해줄 수 있씁니다.


      IPVS(IP Virtual Server)는 리눅스 커널의 로드 밸런싱 기술로, 더 효율적이고 확장성이 뛰어난 네트워크 트래픽 처리를 제공합니다.

      kube-proxy는 IPVS를 사용하여 서비스 트래픽을 처리할 수 있습니다.


      그리고 이것들을 핸들링하는 것이 kubeproxy입니다.


      kubeproxy는 데몬셋으로 실행되어 모든 노드에 존재하며, 쿠버네티스의 서비스 개념의 구현부입니다.

      또한 네트워크 규칙을 통해 네트워크 세션이나 클러스터 바깥에서 파드로 네트워크 통신을 할 수 있도록 해줍니다.


      kube-proxy가 사용하는 모드는 쿠버네티스 클러스터를 구성할 때 다음과 같이 파일로 설정할 수 있습니다.

      apiVersion: kubeproxy.config.k8s.io/v1alpha1
      kind: KubeProxyConfiguration
      mode: "ipvs"


      네트워크 컴포넌트?

      쿠버네티스는 네트워크 통신 관련 컴포넌트는 써드 파티에 맡기며, CNI만 지원합니다. 테스트용 네트워크 컴포넌트는 있으나 운영에 적합하지 않습니다.

      네임스페이스를 만들거나 하는건, 쿠버네티스가 관여하지 않습니다. (스펙만 정의)

      eBPF 기반의 Cilium과 Calico 등이 주요 네트워킹 플러그인입니다.


      두 플러그인의 특징은 다음과 같습니다. 출처링크

      (당장은 몰라도 될 것 같으나 참고용으로 넣어봤습니다)

      특성

      Calico

      Cilium

      핵심 기술

      eBPF, Linux IP Tables, Windows HNS 및 VPP 데이터플레인 지원.

      eBPF 기반 데이터플레인에만 의존.

      네트워크 보안

      애플리케이션 및 네트워크 수준에서 네트워크 보안 정책 제공.

      유사한 네트워크 보안 정책 기능 제공.

      로드 밸런싱 및 네트워킹

      eBPF 데이터플레인으로 효율적인 로드 밸런싱 및 라우팅과 오버레이 네트워크 제공.

      유사한 로드 밸런싱 및 네트워킹 접근 방식.

      컨테이너 오케스트레이터 통합

      쿠버네티스, 오픈시프트, Docker EE 등과의 광범위한 통합.

      쿠버네티스 및 컨테이너 오케스트레이션 플랫폼에 중점.

      관찰 가능성 및 모니터링

      Prometheus, Grafana, Istio, Jaeger 등의 통합 옵션을 통한 광범위한 가시성 제공.

      관찰 가능성을 위해 Hubble 사용, 데이터 내보내기에 제한이 있을 수 있음.

      확장성 및 성능

      최소한의 성능 오버헤드로 높은 확장성 제공, 대규모 배포 지원.

      확장 가능하지만 패킷 헤더와 eBPF 맵 크기에 제한이 있음.

      암호화

      WireGuard 및 mTLS(Istio 사용) 지원.

      WireGuard 및 IPsec 지원.

      아키텍처

      여러 데이터플레인 옵션을 갖춘 유연한 아키텍처.

      단일 eBPF 기반 데이터플레인, 보안 아이덴티티에 중점.

      정책 관리

      Calico API, Calicoctl 및 엔터프라이즈와 클라우드 버전에서 강화된 옵션을 통한 고급 정책 관리.

      기본 정책 관리, 고급 수명 주기 관리는 부족함.

      쿠버네티스 플랫폼 지원

      다양한 플랫폼을 지원하고 쿠버네티스 버전과의 호환성 유지.

      주로 쿠버네티스 지원.

      멀티 클러스터 관리

      특히 엔터프라이즈와 클라우드 버전에서 고급 멀티 클러스터 관리.

      kubectl 및 Hubble을 통한 표준 멀티 클러스터 관리.

      클러스터 메쉬

      BGP 프로토콜을 사용한 유연한 멀티 클러스터 설정.

      클러스터 메쉬에서 최대 255개의 클러스터 지원.

      배포 및 구성

      Calico 매니페스트를 사용한 배포.

      Cilium CLI 유틸리티를 통한 배포.


      쿠버네티스 API 흐름

      이제 이러한 컴포넌트들 사이에서 데이터와 API의 흐름을 살펴보겠습니다.

      쿠버네티스에서는 모든 API가 kube-apiserver를 거쳐갑니다.


      • 먼저 USER가 커맨드를 통해 API 서버에게 파드를 실행시켜 달라 요청합니다.

      • API 서버는 해당 요청을 검증하고, 컨트롤 플레인 노드의 스케쥴러에게 전달합니다.

      • 스케쥴러는 클러스터 정보를 API 서버에게 접근합니다.

      • API 서버는 etcd store에 클러스터 정보를 요청합니다. (etcd에는 API 서버만이 접근 가능합니다.)

      • etcd는 클러스터 정보를 API 서버에게 전달합니다.

      • API 서버는 클러스터 정보를 다시 스케쥴러에게 전달합니다.

      • 스케쥴러는 해당 정보를 기반으로 노드를 선택하고, 파드를 노드에 바인딩하고 해당 정보를 API 서버에게 전달합니다.

      • API 서버는 해당 노드에 존재하는 kubelet에게 파드를 실행하도록 요청합니다.

      • kubelet은 파드를 실행합니다.

      • API 서버는 변경된 내용을 etcd에 저장합니다.

      • 컨트롤러 매니저는 클러스터의 Current state와 Desired state를 지속적으로 API 서버(etcd)에게 전달 받아서 두 상태가 일치하는지 체크합니다.

      TIP) Pod에는 항상 pause 컨테이너가 존재한다!

      pause 컨테이너란?

      프로세스를 관리하는 컨테이너가 필요하기 때문에, 무조건 namespace가 만들어지고 프로세스가 할당이 되어야합니다.

      pause는 인프라 컨테이너라고도하며, 무조건 생성됩니다. (다만 겉에선 안보입니다.)


      쿠버네티스 리소스

      쿠버네티스 리소스에는 기본적으로 네임스페이스라는 개념이 있습니다. (리눅스 네임스페이스랑은 다름)

      마치 SQL문을 사용하듯이 , A라는 조직(네임스페이스)가 있고, 거기 있는 정보만 가져오고싶어라고 명령을 내리거나 할 때 사용합니다.

      (즉 물리적으로 나눈건 아니고, 논리적으로 나눈 것)


      실습 : namespace , pod 생성

      먼저 네임스페이스를 하나 생성해보겠습니다.



      namespace 목록을 보면 정상 생성된 것을 확인 가능합니다.



      다음 명령을 통해서 pod 생성을 테스트해봅니다.

      kubectl run nginx-pod -n ask --image=nginx --port 80 --dry-run=client -o yaml > 01-nginx.pod.yaml

      TIP) 위와 같이 yaml을 생성하는 방식은 yaml을 직접 작성하는 것에 비해 많은 시간을 단축시켜주어서 실무 외에도 CKA같은 자격증 시험을 볼 때 유용하다고 하셨습니다.

      --dry-run=client 명령으로 인해 실제로 pod를 생성하진 않고 다음과 같이 파일만 생성합니다.



      apiversion: 버전을 의미

      kind: 리소스의 종류를 의미.

      metadata: 쿠버네티스의 스펙.

      image: 컨테이너 이미지, 도메인이 없으면 도커허브에서 가져옴.

      ports: 컨테이너 내부에서의 포트.


      도커에서는 expose로 포트를 띄웠지만 쿠버네티스에서는 yaml의 컨테이너포트에 작성합니다.


      --dry-run=client 을 제외하고 실제로 pod를 생성해봅니다.



      pod의 정보를 읽을 때 -o yaml 옵션을 통해 자세한 정보를 yaml 형식으로 출력할 수도 있습니다.


      다음 명령을 통해 pod의 bash 셸에 접속할 수도 있습니다.

      kubectl exec -it nginx-pod -n ask -- bash


      request와 limit

      request는 파드를 만들때 이렇게만 만들라는 뜻이고,

      limit은 최대 리밋까지만 쓰고, 그다음엔 리소스를 더 못쓴다는 뜻입니다.


      리퀘스트와 리밋이 작성돼있으면 스케쥴러는 이를 상대적으로 중요한 파드라고 판단합니다.

      만약 파드로부터 cpu와 메모리 요청이 계속 들어오면, 해당 파드를 이젝션시키고, 노드 정보를 지웁니다.

      그리고 스케쥴러는 해당 파드를 다른 노드로 보냅니다.

      이때, 파드를 죽이는 우선순위를 정할 때 리퀘스트와 리밋의 유무로 판단합니다.


      limit은 보통 주는게 좋고, 애매하면 많이 주는게 낫다고 하셨습니다.


      실전 🍯팁

      그러나 파드에 메모리 limit을 줘도, 약간이라도 그 메모리 이상을 쓸 수 있다고 합니다.

      즉, node os가 써야하는 최소한의 메모리를 남기지 않고 사용해버려서 node os가 다운되는 불상사가 일어날 수 있으니 메모리를 할당할 때는 너무 빡빡하게 하지 않는 것이 중요하다고 하셨고,

      이건 항상 알고 있으라고 강조하셨습니다. (책 같은데 잘 안나오는 꿀팁!! )


      그리고 쿠버네티스 워커노드에서는 스왑메모리를 끄는 것이 권장된다고 하셨습니다. (노드가 느려지면 안되니까 안정성을 위해서)


      labels & selector

      구글의 제품에는 항상 레이블과 셀렉터가 있다고 합니다.

      이것도 마치 sql처럼 셀렉터를 이용해 원하는 파드만 조회하거나 지정할때 사용합니다.

      사용자 뿐만 아니라 컴포넌트들도 레이블과 셀렉터를 이용해 작업을 하곤 합니다.


      다음과 같이 파드에 레이블을 설정해줄 수 있습니다.



      그리고 다음과 같이 레이블을 활용합니다.

      여기서는 쿼리로 사용한 레이블에 해당하는 파드만 선별해서 볼 수 있습니다.



      레플리카셋

      레플리카셋은 레플리케이션 컨트롤러의 발전형으로, 같은 동작을 하지만 집합 기반의 셀렉터를 지원하는 차이점이 있습니다.

      예를 들어 레플리케이션 컨트롤러는 셀렉터가 레이블을 선택할 때 같은지(=) 다른지(!=)만 확인하지만, 집합 기반 셀렉터는 in , notin 같은 연산자를 지원합니다.


      레플리카셋은 가용성을 보장하기 위해 pod와 특정 개수의 pod 복제본을 유지하고, 항상 지정된 수의 pod+replicas가 실행되고 있는지 확인합니다.



      디플로이먼트

      디플로이먼트는 레플리카셋 + 히스토리로, 히스토리를 관리하기 위해서 디플로이먼트를 씁니다.

      디플로이먼트를 수정하고 apply하면 새로운 레플리카셋이 나옵니다.

      디플로이먼트에서 matchlables의 app 이름과 metadata labels의 앱이름은 같아야 합니다.

      또한 파드 안에서는 컨테이너의 볼륨을 공유할 수 있습니다.



      실습 : deployment 생성

      우선 다음 명령어로 yaml을 생성해줍니다.

      kubectl create deployment nginx-deployment -n ask --image=nginx --replicas=2 --dry-run=client -o yaml > 02-nginx-deployment.yaml

      그리고 해당 yaml을 apply 해줍니다.



      파드가 레플리카 설정으로 인해 파드가 두 개 생긴 것을 확인 가능합니다.



      다음과 같이 각 파드의 자세한 정보를 확인할 수도 있습니다.



      📝TIP) 디플로이먼트를 배포할 때 레플리카셋 이름에 난수가 생기는 이유는,

      디플로이먼트가 수정될 때 새로운 레플리카셋이 생기면서 레플리카 셋이 여러 개 존재하는 상황이 만들어지는 경우가 있습니다.

      따라서 뒤에 난수가 붙는 것입니다.


      레플리카셋이 업데이트되면, 당연히 파드도 업데이트 될 것입니다. 그렇다면 파드의 이름은 어떻게 될까요?

      레플리카셋에 난수가 붙고, 뒤에 파드마다 난수가 또 붙게 됩니다.


      다음과 같이 이름에 점점 난수가 붙으며 길어지는 것을 볼 수 있습니다.





      파드 재시작?

      파드를 재시작하고 싶다면, 파드를 delete하는 것이 가장 쉽습니다. 파드가 삭제되면 스케쥴러가 desired state와 비교해 다시 파드를 띄워줍니다.

      만약 지우고 싶지않다면 rollout의 restart를 해주면, deployment를 restart합니다.

      ⚠️디플로이먼트로 배포한 경우, 파드를 edit하면 안됩니다. 항상 디플로이먼트의 상태(desired state)를 따라가기 때문에 최상위 컨트롤러를 edit해주어야 합니다.⚠️


      실습 : scale in / out & rollout

      scale in

      이번엔 이미 배포중인 deployment의 replica 수를 줄이는 scale in을 해보겠습니다.


      위와 같이 배포 중인 파드의 개수가 1개로 줄어든 것을 확인할 수 있습니다.

      버전 변경

      다음 명령을 통해 이미 실행 중인 deployment의 컨테이너 이미지를 변경할 수도 있습니다.

      kubectl set image deploy nginx-deployment -n ask nginx=nginx:1.21


      위와 같이 기존 실행 중이던 파드를 종료하고 새로운 이미지의 파드를 실행하는 것을 볼 수 있습니다.

      rollout

      쿠버네티스에서는 리소스의 롤아웃을 통해 애플리케이션을 새로운 버전으로 변경하거나 업데이트를 관리할 수 있습니다.

      다음은 사용 예시입니다.



      configmap

      twelve factors 방법론에도 config에 대한 내용이 나옵니다.


      configmap은 컨테이너에 필요한 환경 설정을 컨테이너와 분리해서 제공하는 기능입니다.

      클라우드 네이티브 아키텍처에서 컨테이너는 변하지 않는 자원이어야 합니다.

      이는 즉 개발할 때 사용하는 컨테이너와 상용 서비스에서 사용하는 컨테이너가 같아야 한다는 것입니다.


      그러나 개발용과 상용 서비스에 다른 설정이 필요한 경우가 많습니다.

      사용하는 데이터베이스나, 로그 출력 방식 등 다른 설정으로 컨테이너를 실행해야 할 때 사용하는 것이 컨피그맵입니다.


      configmap을 쓰는 방법은 크게 두가지가 있습니다.

      먼저 첫번째로는 configmap을 직접 작성하고 설정하는 것입니다.

      다음과 같이 config-dev.yaml 파일을 작성해줍니다.

      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: app-config
        namespace: ask
      data:
        app.config : |
          url: nginx-service:8080
          log_level: debug


      그리고 적용시 위와 같이 configMap이 등록됩니다.


      두번째 방법으로는 볼륨 마운트를 하는 것입니다.

      노드에 있는 kubelet이 램디스크에 저장하고 볼륨에 마운트를 합니다.

      다음 그림과 같이 실제 마운트된 컨테이너의 app.config파일안에는 url, log_level등이 적혀있습니다.


      그리고 deployment에서는 볼륨 마운트를 통해 config 파일을 마운트하고, configMap에 등록합니다.

      간단히 확인하기 위해 마운트 했다고 가정하고, 호스트에서 config.yaml 파일을 다음과 같이 작성합니다.

      url: nginx-service:8080
      log_level: debug

      그리고 다음 명령으로 디플로이먼트 yaml 파일을 생성합니다.

      kubectl create configmap app-config -n ask --from-file=app.config --dry-run=client -o yaml > 05-configmap-deployment-mount.yaml

      yaml 파일을 확인하면 다음과 같이 config 정보가 잘 적용된 것을 확인할 수 있습니다.



      네트워크 (service/endpoint)

      파드에 접근하려면 무조건 서비스가 있어야합니다.

      서비스를 만들면 서비스 명 자체가 dns가 됩니다.

      서비스를 생성하는 순간 내부적으로 vIP를 주고, 서비스명으로 dns를 등록합니다.

      이 때 coredns가 쿠버네티스 클러스터의 DNS서버 역할을 합니다.

      그리고 네트워크모듈은 파드 -> 파드 통신만 생각하고,

      kubeproxy는 서비스 -> 파드 연결을 iptables에 세팅합니다. (userspace,iptables,ipvs 지원)

      만약 내부적으로 서비스의 ip가 호출이되면 kubeproxy가 해당 ip의 포트(컨테이너)로 가라고 iptable에 등록합니다.


      서비스 타입에는 크게 네 가지가 있습니다.

      • ClusterIP: 기본 서비스 타입으로, 클러스터 안 노드나 파드에서 클러스터IP를 이용해 서비스에 연결된 파드에 접근한다. 클러스터 외부에서는 이용할 수 없다. (마치 사설IP)

      • NodePort: 서비스 하나에 모든 노드의 지정된 포트를 할당한다. 노드에 상관없이 똑같은 포트를 부여해, 서비스에 지정된 포트 번호만 사용하면 파드에 접근할 수 있다. 클러스터 외부에서도 접근 가능하다.

      • LoadBalancer: 클라우드에서 쿠버네티스를 지원하는 로드밸런서 장비에서 사용한다. 클라우드에서 제공하는 로드밸런서와 파드를 연결한 후 해당 로드밸런서의 IP를 이용해 클러스터 외부에서 파드에 접근할 수 있다.

      • ExternalName: 서비스를 .spec.externalName 필드에 설정한 값과 연결해, 클러스터 안에서 외부로 접근할 때 주로 사용한다.

      서비스가 파드를 제대로 연결했는지 알려주려면 ? 내부적으로 엔드포인트라는 리소스를 만들어서 잘 지정됐는지 알려준다 ! 사실 엔드포인트를 보고 iptable을 세팅하겠지만.


      실습 : 서비스

      파드쪽으로 네트워크 호출하려면 무조건 서비스가 필요한데, 노드 내부 호출이기 때문에 clusterip로 서비스를 생성하면 됩니다.


      먼저 다음과 같이 서비스를 생성해줍니다.



      kubectl get ep -n ask명령어로 ask 네임스페이스에 있는 엔드포인트를 조회할 수 있습니다.



      여기서 엔드포인트는 서비스와 연결된 실제 파드의 IP 주소와 포트 번호를 나타냅니다.

      서비스가 생성되면 쿠버네티스는 자동으로 해당 서비스의 엔드포인트를 생성하고 관리합니다.

      다음 명령으로 클러스터 내에서 nettool이라는 디플로이먼트를 생성해줍니다.

      kubectl create deploy nettool -n ask --image=praqma/network-multitool

      해당 이미지는 네트워크 디버깅 및 테스트용 네트워크 도구 컨테이너입니다.


      해당 파드에 접속해 bash 쉘에서 curl nginx-service:8080을 보내서 정상적으로 답변이 오면, 클러스터 내부의 네트워크와 서비스가 올바르게 구성된 것입니다.



      엔드포인트를 수동으로 만들어주면, 바깥에 있는 것도 서비스를 통해 내부 파드에 접속 가능합니다.

      여기서 로드밸런싱 역할은 iptables덕분에 가능합니다.


      (📸 사진 제공 꼬마집사 상기님)


      다들 너무 열심히 경청하시고 필기 하셔서 저도 덩달아 동기부여가 되는 것 같습니다 😤

      책 한 권을 온전히 봐야 겨우 이해하고 습득하는 지식의 양인데, 강의력이 뛰어나셔서 2시간이라는 짧은 시간에도 불구하고 많은 공부가 된 것 같습니다.

      오늘은 부득이한 사정으로 못 오신 분들도 조금 계셨지만 후기를 보고 도움이 되셨으면 좋겠습니다.


      다음 스터디는 약 3주 후이니, 그때까지 공부할 시간이 많다는게 조금의 위안인 것 같습니다. 🥹


      감사합니다 🙇🏻‍♂️

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      강만쥬 님의 최신 블로그

      더보기

      DEVOTEE 추천 블로그

      동영상 기고하기