You are currently viewing GL-Docker & Kubernetes week2

GL-Docker & Kubernetes week2

1. Intro

2주차에서는 Kubernetes 소개 & Kubernetes 기본 활용을 다룬다.

2. 쿠버네티스 개요

2.1. 쿠버네티스 소개

Kubernetes (k8s)

Evolution of Containers and How Managed EKS Service solves Kubernetes challenges

  • 2014년, Google의 내부 시스템 Borg를 기반으로 발전.
  • 2015년 오픈소스로 공개됨. → Borg 소개 블로그

개요

  • 컨테이너를 쉽고 빠르게 배포하고 확장할 수 있도록 돕는 컨테이너 관리 자동화 오픈소스 플랫폼.
  • Container Orchestration(컨테이너 조율 및 관리) 역할을 수행.

명칭

  • Kubernetes는 그리스어로 “조타수, 파일럿”을 뜻하는 Kybernetes에서 유래.
    • → 여러 컨테이너(배)를 통제하고 관리하는 존재.
  • K8s: 맨 앞의 k와 맨 끝의 s 사이에 8글자가 있어서 줄여 부름.

해양 관련 네이밍

  • Kubernetes 관련 도구들은 바다와 항해에서 영감을 받은 이름과 아이콘을 가짐.
    • Helm
      • 배의 키(조타륜)를 조종하는 장치 → Kubernetes 애플리케이션 배포를 쉽게 해주는 패키지 관리자.
    • ArgoCD
      • 그리스 신화 속 탐험선 Argo 호 + CD(Continuous Deployment) + 문어(지능, 유연함, 멀티태스킹) → 여러 컨테이너 배포를 동시에 처리하는 도구.
    • Istio
      • 고대 그리스어 Histion(돛)에서 유래 → 서비스 간 트래픽을 제어하고, 네트워크 관리를 돕는 서비스 메시.
    • Harbor
      • 항구 → 컨테이너를 배에 싣기 전 머무르는 장소 → 컨테이너 이미지 저장소 역할.

“The naming process basically involved three hours of Greek dictionary search,” says Varun. “Both of us had a mental model of weaving things together. …The idea of the sailboat is that it’s not just about who is in control. You can’t get anywhere without the boat.”

“이름 짓기 과정에는 기본적으로 그리스어 사전 검색 3시간이 필요했습니다.”라고 바룬은 말합니다. “우리 둘 다 물건을 엮는 정신적 모델을 가지고 있었습니다. …돛배의 개념은 단순히 누가 조종하느냐에 관한 것이 아닙니다. 배 없이는 어디에도 갈 수 없습니다.”

How Istio got its name

용어집

  • master (control-plane, leader) : 마스터, 컨트롤 플레인, 리더
    • Kubernetes 클러스터를 관리하고 전체 상태를 통제하는 핵심 컴포넌트.
    • 참고: “master/slave”는 차별적 뉘앙스로 slave는 지양하지만, master는 관습적으로 여전히 일부 사용.
  • node (worker node) : 노드, 워커노드
    • 실제 컨테이너(Pod)를 실행하는 서버.
    • 과거에는 “minion(미니언)”이라고도 불렸음.
  • k8s (kubernetes) : 쿠버네티스, 케이에잇츠, 케이팔에스
    • Kubernetes의 약칭. ‘k’와 ‘s’ 사이에 8글자가 있어 k8s로 부름.
  • De facto (라틴어) : 데 팍토
    • ‘사실상의, 사실상 인정된’이라는 의미.
    • 예시: Kubernetes has become a de facto standard.
  • kubectl : 큐브 컨트롤, 큐버 컨트롤, 큐브 시티엘, 큐버 시티엘
    • Kubernetes 클러스터를 조작하기 위한 CLI(Command Line Interface) 도구.
  • etcd : 엣시디, 이티시디
    • Kubernetes 클러스터의 모든 상태 정보를 저장하는 분산 키-값 데이터베이스.
  • flannel : 플라넬
    • Kubernetes 클러스터 내 Pod 간 통신을 위한 간단한 오버레이 네트워크 솔루션.
  • calico : 칼리코, 캘리코
    • 고성능, 보안 중심의 Kubernetes 네트워킹 솔루션. 네트워크 정책 관리와 BGP 기반 통신 지원.
  • istio : 이스티오
    • Kubernetes 기반 서비스 간 통신을 관리하는 서비스 메쉬 솔루션.
  • helm : 헬름, 핾, 햄
    • Kubernetes 애플리케이션을 쉽고 일관성 있게 배포하고 관리할 수 있게 해주는 패키지 매니저.
  • pod : 파드, 포드
    • Kubernetes에서 가장 작은 배포 단위. 하나 이상의 컨테이너를 포함할 수 있음.
  • label : 레이블, 라벨
    • Kubernetes 오브젝트(예: Pod)에 부여하는 키-값 쌍. 오브젝트를 분류하고 선택할 때 사용.

k8s-diagrams

  • k8s 내부 컴포넌트간 관계 간단한 이미지로 설명

쿠버네티스(컨테이너 오케스트레이션) 필요성

컨테이너란?

  • 컨테이너는 클라우드 네이티브 애플리케이션을 위한 표준 컴퓨팅 단위
  • 컨테이너는 애플리케이션 코드와 함께 라이브러리, 의존성까지 모두 패키징하여
    어디서든 일관되게 실행될 수 있도록 보장
  • 가장 대표적인 컨테이너 런타임은 Docker


Docker만 사용할 때의 한계

개발 환경에서는 docker run 명령어 하나로 컨테이너를 쉽게 실행 가능

그러나 운영 환경에서는 컨테이너를 단독으로 사용할 경우 여러 문제에 직면

  • 트래픽 증가에 따라 수백, 수천 개의 컨테이너를 수작업으로 관리
  • 컨테이너가 죽으면 수동으로 재시작
  • 버전 배포(롤아웃) 및 되돌리기(롤백)를 일일이 수작업으로 처리
  • 컨테이너 간 통신, 네트워킹, 로드밸런싱 설정을 직접 복잡하게 구성

결과적으로, Docker 단독 사용은 소규모에서는 문제없지만, 대규모 확장성과 자동 복구에는 한계 O


Kubernetes의 등장

Kubernetes를 사용하면,

  • 애플리케이션의 확장(Scale-out)
  • 장애 발생 시 자동 복구(Self-healing)
  • 배포 자동화 및 롤백(Rollout/Rollback)
  • 서비스 디스커버리 및 로드밸런싱(Service Discovery & Load Balancing)

를 자동으로 처리할 수 있어 Kubernetes는 컨테이너 기반 애플리케이션을 안정적이고 유연하게 운영하기 위한 핵심 솔루션

“서비스 컨테이너를 100개 띄워서 이중화할 거야. Docker CLI(docker run)로 관리한다면?”

  • 100개 컨테이너를 수동으로 띄우는 것부터가 비효율적
  • 만약 서비스 트래픽이 급증해서 추가로 100개 컨테이너가 더 필요하면?
    • 일일이 docker run 명령어를 입력할 것인가?
    • 스케줄링, 배치, 리소스 분산은 어떻게 할 것인가?

사람이 수동으로 대응하는 것은 현실적으로 불가능

Kubernetes를 사용하면

  • yaml 파일 하나로 100개 컨테이너를 배포할 수 있다.
  • 오토스케일링 설정을 통해 트래픽에 따라 Pod 수를 자동 조절할 수 있다.
  • 노드 장애 시에도 자동 복구가 진행되며 운영자가 개입할 필요가 없다.

쿠버네티스 핵심 개념

애완동물 vs 가축

  • 쿠버네티스는 서버를 애완동물(Pet)보다는 가축(Cattle)에 비유
  • 애완동물은 세심한 관리, 개별 이름, 끼니 챙김, 예방접종 필요
  • 가축은 이름 없이 무리로 관리, 일부 죽어도 전체 운영에 영향 없음
  • 쿠버네티스는 서버를 특별 관리하지 않고 무리로 다루는 방식

서버에 특별한 이름을 부여하지 않음

  • 특정 서버를 빌드 서버, 웹 서버, 모니터링 서버로 고정하지 않음
  • 모든 서버를 워커 서버로 통일하여 유동적으로 작업 분배
  • 역할이 고정되지 않아 상황에 따라 다양한 작업 할당 가능

서버 장애에 대한 유연한 대응

  • 한두 대 워커 노드 장애 시에도 서비스 지속 가능
  • 다른 워커 서버가 역할을 이어받아 무중단 운영
  • 쿠버네티스는 마스터와 워커로만 서버를 구분
  • 마스터는 클러스터 제어 컴포넌트 담당, 워커는 컨테이너 실행 담당
  • 컨테이너 고립화 덕분에 특정 워커 장애 시 대체 가능
  • 대량 서버 환경에서 효율적인 운영 가능

원하는 상태(Desired State)

  • 사용자가 원하는 애플리케이션 실행 환경을 정의
  • 예시: Nginx 서버 2개를 80 포트로 서비스 설정
  • 쿠버네티스가 현재 상태를 감시하고 원하는 상태로 자동 조정

선언형 명령어

  • 서버에 직접 명령하지 않고 원하는 상태를 선언
  • 쿠버네티스가 목표 상태를 맞추기 위해 작업 수행
  • docker run 같은 명령형과 대비되는 방식

YAML 형식

  • YAML (YAML Ain’t Markup Language)
  • YAML은 사람이 읽기 쉬운 데이터 표현 포맷
  • 쿠버네티스 설정을 구조적이고 직관적으로 작성 가능
  • 복잡한 환경도 간결하게 기술 가능

쿠버네티스 아키텍처

Kubernetes Components

  • K8S 클러스터는 Controle Plane(마스터)와 Node(노드)로 구성
What is Kubernetes Architecture?

Control Plane(마스터 노드) 핵심 컴포넌트
마스터는 단일 서버 또는 고가용성을 위해 여러 대(3대 이상)로 구성할 수 있다.
Control Plane은 Kubernetes 클러스터를 관리하는 중앙 서버 역할을 한다.

kube-apiserver

  • 클러스터로 전달되는 모든 요청을 받아들이는 API 서버
  • 사용자, 시스템, 다른 컴포넌트들이 Kubernetes와 통신할 때 항상 API 서버를 통해 요청을 주고받음

etcd

  • 클러스터 내 모든 메타 정보를 저장하는 분산 키-값 데이터베이스
  • 오직 API 서버와만 직접 통신하며, 다른 모듈은 API 서버를 통해 etcd에 접근
  • Kubernetes의 최종적인 상태 정보를 보관하는 저장소 역할

kube-scheduler

  • 새롭게 생성된, 아직 어디에도 할당되지 않은 Pod를 워커 노드에 배치하는 역할
  • 리소스 사용량, 태그(Label), 어피니티 규칙 등 여러 조건을 고려해 최적의 노드를 선택

controller-manager

  • 클러스터의 현재 상태와 사용자가 원하는 상태를 비교하고, 차이를 맞추기 위한 작업을 수행
  • 지속적으로 클러스터를 감시하고 필요한 조치를 자동으로 수행
  • 주요 구성요소로 Kube-Controller-Manager와 Cloud-Controller-Manager가 있다

Kube-Controller-Manager

  • Deployment, ReplicaSet, Job, ServiceAccount 등 대부분의 Kubernetes 리소스 상태를 관리

Cloud-Controller-Manager

  • 클라우드 환경(AWS, GCP, Azure 등)에 특화된 리소스 제어
  • 로드밸런서 생성, 볼륨(Storage) 생성 및 연결, 클라우드 인프라 자원 자동 제어 담당
  • 예를 들어, Ingress를 통해 ELB 생성, StorageClass를 통한 EBS 볼륨 연결, EC2 인스턴스 추가 및 삭제 관리

Worker Node(워커 노드)
Worker Node는 Control Plane과 통신하여 필요한 Pod와 볼륨을 생성하고, 실제 컨테이너를 실행하는 서버이다.
컨테이너 수가 늘어나면 워커 노드를 추가하여 확장할 수 있다.

Kubelet

  • Control Plane의 명령을 받아 워커 노드에 할당된 Pod의 생명주기(Lifecycle)를 관리
  • Pod가 정상적으로 작동하는지 주기적으로 점검하고, 그 결과를 API 서버에 보고
  • 컨테이너 생성, 상태 확인, 로그 수집, 명령 실행 등을 담당

kube-proxy

  • Pod 간 네트워킹을 설정하고 관리하는 프록시 서버
  • 클러스터 내에서 네트워크 트래픽을 적절하게 전달하며, 네트워크 규칙(iptables 또는 IPVS 기반)을 유지 관리

Container Runtime

  • 실제로 컨테이너를 실행하는 소프트웨어
  • 과거에는 주로 Docker를 사용했으나, Kubernetes 1.24 버전부터 Dockershim이 제거되면서 containerd, CRI-O와 같은 다른 런타임을 사용
  • 초창기 Kubernetes는 Docker 엔진 위에서만 동작했지만, 이후 OCI(Open Container Initiative) 표준을 따르는 다양한 런타임 지원으로 확장
  • 기존 Docker 엔진이 표준을 완벽히 따르지 않아 별도의 호환 모듈(Dockershim)이 필요했는데, 유지 관리의 부담을 줄이기 위해 Dockershim을 제거하고 표준화된 런타임에 집중

2.2. 쿠버네티스 설치

다양한 쿠버네티스 배포 도구들

운영 환경용

개발/테스트용

  • Kind vs Minikube: 차이점은 무엇인가요? – link
    • 요약 : Kind – 경량 개발 및 테스트 / Minikube – 포괄적인 로컬 k8s 환경 제공
    • 둘 다 사용해 본 경험으로는 minikube 는 확장 플러그인이 다양하여 지원되는 기능이 많고, kind 는 가볍고 빠르게 테스트하고 지울 수 있음
    • 스터디에서는 k8s 기초에 대해 공부하기 때문에 가볍고 빠른 kind 선택 !

kind 소개 및 설치

소개 : ‘도커 IN 도커 docker in docker’로 쿠버네티스 클러스터 환경을 구성

  • kind or kubernetes in docker is a suite of tooling for local Kubernetes “clusters” where each “node” is a Docker container
  • kind is targeted at testing Kubernetes , kind supports multi-node (including HA) clusters
  • kind uses kubeadm to configure cluster nodes.
  • 이후 kind create cluster 기본 클러스터 활용

3. 쿠버네티스 기본 활용

3.1. kubectl

  • kubectl
    • kubernetes + control (큐브컨트롤, 큐브씨티엘)
    • 쿠버네티스를 제어하는 명령을 API Server 로 전달

쿠버네티스 정보 확인

kubectl api-resources

  • 현재 쿠버네티스 클러스터에서 사용할 수 있는 API 리소스
  • 리소스 약어 확인 가능
kubectl api-resources

# 대표적인 쿠버네티스 리소스 약어
# pods - po
kubectl api-resources | grep pods

# deployments - deploy
kubectl api-resources | grep deployments

# namespaces - ns
kubectl api-resources | grep namespaces

# configmaps - cm
kubectl api-resources | grep configmaps

kubectl get <리소스>

  • 쿠버네티스 클러스터 내부 리소스에 대한 조회 명령어
# 노드 조회
kubectl get node
kubectl get node -o wide

# 파드 조회
kubectl get pods
kubectl get pods -A

# 디플로이먼트 조회
kubectl get deployment
kubectl get deployment -A

# 네임스페이스 조회
kubectl get namespace

kubectl describe <리소스>

  • 쿠버네티스 클러스터 내부 리소스에 대한 상세 정보 조회
# 파드 상세 조회
kubectl describe pod -n kube-system coredns-668d6bf9bc-5jgbj

# 디플로이먼트 조회
kubectl describe deployment -n kube-system coredns

# 네임스페이스 조회
kubectl describe namespace kube-system

결과 확인

  • kubectl api-resources
    • SHORTNAMES 필드에서 축약어 확인가능
  • kubectl get pods -A
    • 모든 네임스페이스의 pod 조회

  • coreDNS pod의 상세내용 확인

쿠버네티스 컨텍스트 확인

  • ContextLink
    • kubectl 명령어를 수행할 때 어떤 클러스터, 어떤 사용자, 어떤 네임스페이스를 대상으로 동작할 지 지정하는 설정
    • 컨텍스트를 통해 쿠버네티스에 접근하는 과정을 인증(Authentication) 이라고 지칭
    • 멀티 클러스터를 다룰 때 유용
    • Context 구성 요소
      • Cluster : 연결할 쿠버네티스 클러스터
      • User: 클러스터 인증에 사용할 사용자 정보 (토큰, 인증서)
      • Namespace: 기본으로 사용할 네임스페이스

Context 확인

  • 현재 사용중인 context 확인
# 현재 설정된 컨텍스트 확인
kubectl config current-context

# 모든 컨텍스트 확인
kubectl config get-contexts

# 다른 컨텍스트 전환
kubectl config use-context <Context Name>

# 컨텍스트 삭제
kubectl config delete-context <Context Name>
  • 컨텍스트 정보는 어디서 가져오는 걸까?
    • ~/.kube/config 에 저장
cat ~/.kube/config
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /home/nasir/.minikube/ca.crt
    extensions:
    - extension:
        last-update: Sun, 30 Mar 2025 20:26:18 KST
        provider: minikube.sigs.k8s.io
        version: v1.35.0
      name: cluster_info
    server: https://127.0.0.1:32769
  name: minikube
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJQ0ZUanB6c0Y2aWN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TlRBME1qWXhOakEzTVRaYUZ3MHpOVEEwTWpReE5qRXlNVFphTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUUMyR1E4RGs1QUpabzBYTkIvNEJnQnk1SHJPVkxPOVhkTnNmSjM2dHY4b1A4SGEvUkNZWW5aT3RXWHYKdFNtdXRDVFA3TVdEclA2SjJHcWlBYkxrcThob3Zwbmdoc0Z5RXpNaTV5bGRiWStiQmlkQlgwUWxXcDZHOEJsTgo3d2NxRGRoditBYS9oMWFoQlhuUkF2dFI2SFNGeEpzTTM4dytVNWVGc2J1QmJ6Ris1V0RBS1doNzJ5WlhBYitLCnJZeEJPQUg1M01nNjVpVnczTjg3QzdvTVRjYVA3MjUzeENWbFIrTlFzSzVYdzRxMnA5dDhScitTMUN4QzNjQTkKL1ZYdWxhVmJyQVFFVW9QbjNsS3BMUGl2czlQNnR2dDZhMlZndjFDNnp2enVRcVlzdkdEdE9WK21CbWpHcUtBZwpVRnpLS2JYOW81cCs1emt1Mk5ZK2tRdis1b0dkQWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJSRDA1a1NycnBpQkw3ZG9QajZNM1ppN0lSQjNqQVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQ0RBeWtnNmUzSgp4QXlRUDZqSDFHSCtNVWwzYXA4ZEZUem04b1ZiVTdwS1QxN1ZmN1BPMEVKUkE1NjhjT1lsRGttQ0kvN2lpK1BDCjZYWUhVL3hrN0dZd0k2d3ptZGNsVHBRSHNFVmlLYWo2b1lqOVp6UlBBbm5JaUhnWmZNYjZTVjVla3lLRUIwV2oKcTJhbWtldTEwY0orNjFOZUxaSCt1YzNtQWQvM09XalFyb2RIZ2UyMkpsMEZ5VHUrek5UNFJmS2hzcWROZHZMeAp3K1BNakNoWlBocjBDNUFxN3hSMzdHZStjTGY0M3VWU2Roeml3aXVxbi8xWC9LSkNNQ1M3Z3dBUUo2MXZzeEZyCjJjK3VXaVpWNjJKaUU0KytmcVBUSzhpMkRWQ2V6VlRXZjAycUVzTEhibUhqTjQrMjlHS2xJbDhWeGViWFlvdHkKSXZPcGZ5OE5wSE5HCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
    server: https://127.0.0.1:32981
  name: kind-kind
contexts:
- context:
    cluster: minikube
    extensions:
    - extension:
        last-update: Sun, 30 Mar 2025 20:26:18 KST
        provider: minikube.sigs.k8s.io
        version: v1.35.0
      name: context_info
    namespace: default
    user: minikube
  name: minikube
- context:
    cluster: kind-kind
    user: kind-kind
  name: kind-kind
current-context: kind-kind
kind: Config
preferences: {}
users:
- name: minikube
  user:
    client-certificate: /home/nasir/.minikube/profiles/minikube/client.crt
    client-key: /home/nasir/.minikube/profiles/minikube/client.key
- name: kind-kind
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLVENDQWhHZ0F3SUJBZ0lJSmxGOHg4cDlYdU13RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TlRBME1qWXhOakEzTVRaYUZ3MHlOakEwTWpZeE5qRXlNVFphTUR3eApIekFkQmdOVkJBb1RGbXQxWW1WaFpHMDZZMngxYzNSbGNpMWhaRzFwYm5NeEdUQVhCZ05WQkFNVEVHdDFZbVZ5CmJtVjBaWE10WVdSdGFXNHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDZkZadVMKZTY5ZFRqbUFUMkloNlpPWXorSWNYdG4xczgyUVB1TDY0Z3dycm4zZm9oUGNmbTZxYUV2VVVmN28rU2kyMnRuVgpraGZ4aGxVZFNPMGFqWmdObXNxbHMrbmlIR3lSSTlEa0lKamZRaHB1ajlCZUlzejFoSmNvVkRXVXFqd3ZJQ3I5CmM1Q0k2OEVUbXNOcTdtQlFHaEt0dG5iL3U2dzdGem5scE5uNEovTHhvZmYybUV4YVd4T2xpb2p0L0h5SnNQQlkKQjhCK3FqT1JRS3hoU0RoOEkyK2tpWmVqTTJYL1BSbklHTE1hN3BPb0VjMkhpMjVacDF2cXRwQi9NV3FEdXpIeQpjcmFMelFHZnAxMGd2VXBnWi9ZUHMxZjNJZmt1WjB4ZnF6UnVnejlRY05FUGJXSnRXVy9aeUpzTm01dWlvUGQ1CjJpdk1GbFRWdFVrSzdsTlJBZ01CQUFHalZqQlVNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUsKQmdnckJnRUZCUWNEQWpBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZEl3UVlNQmFBRkVQVG1SS3V1bUlFdnQyZworUG96ZG1Mc2hFSGVNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUFsanVOUm1GU2ZqZy9iZzU3aGNaTGxYWDhhCm5ENy9uK29GMW9EOGVZUEFYK0djVEN0bSt3blo3cG5hNytoSXg4ZzFuc2FBSytST1FTcGUxTTE1Ung0Mnd5NEYKOGNmWUhrM2NESmlDR1ZrUXF1NGxPRHZKUHluY05oaHJjZHlLcGVOVDNKUU9BMG9mQURtSU9ZSXRZbm1sOWJXbwpuNGRwMlE5Q2Vzc01jbHpyTDlPeEZaOEZlSm9OWkoyYTRSTGY1dUZhNi9ZS1hJZWVYR21zVjZEc3g3NXFSbUV1ClBrZkF2TnNEM3RMZHJPUjdwT2ZOUG5NUThaK1IrNjFDSFljU2hCaER6R2FNeVFDcTJ1YWhhNXpMMnppb1lBWkoKRUxqT1V5dHpVSUp4NHo3b3lXTG45ZFFFVmdIcHQvNFJIcmUxbzI1dktYSkFLYmR1WXg4bUJBQ3RFMkNrCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
    client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBbnhXYmtudXZYVTQ1Z0U5aUllbVRtTS9pSEY3WjliUE5rRDdpK3VJTUs2NTkzNklUCjNINXVxbWhMMUZIKzZQa290dHJaMVpJWDhZWlZIVWp0R28yWURacktwYlBwNGh4c2tTUFE1Q0NZMzBJYWJvL1EKWGlMTTlZU1hLRlExbEtvOEx5QXEvWE9RaU92QkU1ckRhdTVnVUJvU3JiWjIvN3VzT3hjNTVhVForQ2Z5OGFIMwo5cGhNV2xzVHBZcUk3Zng4aWJEd1dBZkFmcW96a1VDc1lVZzRmQ052cEltWG96TmwvejBaeUJpekd1NlRxQkhOCmg0dHVXYWRiNnJhUWZ6RnFnN3N4OG5LMmk4MEJuNmRkSUwxS1lHZjJEN05YOXlINUxtZE1YNnMwYm9NL1VIRFIKRDIxaWJWbHYyY2liRFp1Ym9xRDNlZG9yekJaVTFiVkpDdTVUVVFJREFRQUJBb0lCQUdjOEhXM3NwN3QwQk9xWQpHVVdLajBhT09OeFNUVDBlQmxzQ0JFZnNveHRCcTl1UkVUUjRNNWFRQWcxeGZHdHhMUk9rWjlJcGNUSkNDei9xCjBEcjRBZUZxUHZGVEZJYXdEV0FPandOTGlBanhtN2Q5eWlrY2lrY1ZXUVpKeDArSFBYRVRmZkpscVRqQlROVk4KREYxNi9iTmRpQnVFbWlxUWZrOEdYb01BL0pZRlNHNE1TSTFMakliL25NOFZONk1QQy9lOXNaQnRRS1p0WmUxKwpicGhXQnY3TmkxNFBWVTNYQjAzbHFJUlY5QjkwZk44V1NCTllSRXZIZHBUTE9xeEVXcG1rMFNuZExndXV0WjE4CmtXTTFiTVBLcVRWeHJjWElZTWZzcWR2cVpMNEhNbk9UcHV3RlFDdk02Ukt6Yk1wQ1FoZE01dUZQTnZoMkhxcVcKUTVGZ0NIRUNnWUVBMCtubXBoMU5scm1uekZ3TTNEenRyU0xIaHRqQXJSd3B2cHhLMm9KSFprbU9rN2MyYjlYNQpVakJQdHFzWGN4V3JwaEtmMTFGbTNNRHIyaWlPTjBESXFvazNpWTF6YWQ3bERNT0xPaEN5NGRqTWcrMVg5c0hOCjBpTmMrMjRuYnN6dytHbXU2Y01nYW1JdStDdlRseWQwNlF6TGxOUkZmRTBGbTQrZ2gweVdUQ1VDZ1lFQXdDNGcKRk12Y3BUby91QUNwYWRPRDBsRVJ2eFNoOU55NTBkK1NNUnNVVGRBK3RVWFA1K0xyT21Tc05OUjY1TkZkUkYvVgoxRHBqOTZyc3NnYlE5OFk1cVNpeFdqWE5qSzVHSW5NaFRXa2ZpdXhqU04xS2NKUkNseWk0S2hjd1U2bXlyc0YvCklJYlRrdmNWcUx2djdRVm5XYUI4NnJQWXBLT21uTkpiclR6TzdMMENnWUF5Q3FZQXpDS3FXU1VheVJId1lDTHcKSTZwaVdZVUdYQVF2a3RES1VNRnpraU10RnJLd0xpTTJHVnA1bEdWeE04alk2c1Q4SDZqZXNHQUJvRm9WQ2lOWQp3aFp2VVF2VUVHS2VaUDdYczJIS20xdVFPOWZ0MlU0MU5VeWJ3eU5rc3Rpa2tMQlJXMWFvU0k4MjQ0S1B5eTE4CmF4MFlCQmgwaGV1eEZIV2YvYUh3VVFLQmdRQ0d3NUdobzdlTmNnUmV2ckFPVXRHOHVUYk5uT1ZaZFRNbEZqZEoKRWlreHk5YzlmTUFuWnZ2M0RjT29wRnV0ZTVlQXJBZWhkSFRIcDJlbUM1dWNOTGdZaEQyaCtkcXpUVDVIU0I3UgpUdWRjbnhtY2JmbVdhcEVydU5VMFJ1Q1B1bzlmZHJiMEV6Zm9kallOQmdWZ1c0cTIwaERtOE1qNTR2eWlPZTBwCjFWdHhyUUtCZ0VBK1ZKNDNhaXlWK01UZy9OUXQ2NHNuVFJaOVRjZVRiK1ZrR2hGWm8rVTF5Y05jakQ1dGRlYk0KSTBCd2pNdXBJSkxpOUNEdlNTdW5OWHZXVVBabkVVcE1FTnVSMjF3R2h5WExsOUdSUUh4Vml6MGxDMVk2ZDB0UwpnL09YbEduSURCYXlKRUNFWG5YZUMwamh1Wm5iNEN1NGtWV2FQYmlOYnNBNndQZzVCNVVrCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

결과 확인

  • context 조회 및 변경
    • 다른 context 변경시 해당 클러스터의 정보 확인 가능

3.2. Namespace

  • 쿠버네티스 클러스터 내에서 리소스를 격리하는 논리적 단위
  • kube- 접두사는 k8s 시스템용으로 예약되어 있기에 Namespace 로 생성할 수 없음
  • 모든 Object 가 Namespace 에 속하지는 않음 → 전체 클러스터 수준

  • 기본 구성된 namespaces
  1. default : 다른 Namespace가 없는 Object를 위한 기본 Namespace
  2. kube-system : k8s system 에서 생성한 Object를 위한 Namespace
  3. kube-public
    • 자동 생성, 인증되지 않은 사용자를 포함하여 모든 사용자가 읽기 권한으로 접근 가능
    • 전체 Cluster 중 공개적으로 드러나는 Resource를 위해 예약되어 있는 Namespace
  4. kube-node-lease
    • Node heartbeat 성능 향상을 위한 리스(lease) Object에 관한 Namespace
    • Node 장애 탐지를 위한 kubelet의 heartbeat 전송 내용

namespace 활용

# 네임스페이스 조회
kubectl get ns

# 네임스페이스 생성
kubectl create namespace knou
kubectl get ns

# 파트 생성
kubectl run nginx --image=nginx:alpine

#
kubectl get pods
kubectl describe pod nginx
kubectl describe pod nginx | grep Namespace

# knou 네임스페이스에 파드 생성
kubectl run nginx --image=nginx:alpine -n knou

#
kubectl get pods -n knou
kubectl get pods -A

# knou 네임스페이스에 다시 한 번 파드 배포
kubectl run nginx --image=nginx:alpine -n knou
Error from server (AlreadyExists): pods "nginx" already exists

# 논리적으로 격리되어 있기 때문에 다른 네임스페이스에는 동일한 이름의 파드를 배포할 수 있지만, 같은 네임스페이스에는 동일한 파드를 배포할 수 없다!
# -> 쿠버네티스 사용 시 가장 많이 하는 실수 중 하나. 다른 네임스페이스에 배포하는 것

# 테스트 파드 삭제
kubectl delete pods nginx
kubectl delete pods nginx -n knou

기본 namespace 변경

# 기본 네임스페이스 변경
## 현재 네임스페이스 정보 조회 (빈값: default)
kubectl config get-contexts
kubectl config view --minify
kubectl config view --minify --output 'jsonpath={.namespace}'

## 네임스페이스 변경 
kubectl config set-context --current --namespace=knou

kubectl config get-contexts
kubectl config view --minify
kubectl config view --minify --output 'jsonpath={.namespace}'

# 네임스페이스 지정 없이 파드 배포
kubectl run nginx2 --image=nginx:alpine
kubectl get pods -n knou

# 테스트 파드 삭제
kubectl delete pods nginx2

결과 조회

  • 동일 ns에 동일 pod 생성 불가 확인
  • kubectl config view –minify –output ‘jsonpath={.contexts[0].context.namespace}’
    • 현재 설정된 namespace 확인
    • 기본 default 대신 설정한 namespace에 kubectl 동작

3.3. Pod

  • k8s 에서 애플리케이션을 생성하고 관리할 수 있는 배포 가능한 가장 작은 단위
  • 1개 이상의 컨테이너로 구성
  • 동일한 파드 내의 컨테이너는 Storage, Network 를 공유
  • 동일한 파드 내의 컨테이너는 항상 함께 실행
  • 파드는 프로세스가 아닌 컨테이너를 실행하기 위한 환경
  • 파드는 직접 생성하지 않는다! – Bare Pod

Pod 기본 사용

Pod 배포하기

  • 기본 pod YAML 양식
apiVersion: v1
kind: Pod               # Pod 리소스 선언
metadata:
  name: nginx           # Pod Name
spec:
  containers:
  - name: nginx         # Container Name
    image: nginx:alpine # Container Image
    ports:              # Container Port
    - containerPort: 80
cat << EOF > pod.yaml
apiVersion: v1
kind: Pod               # Pod 리소스 선언
metadata:
  name: nginx           # Pod Name
spec:
  containers:
  - name: nginx         # Container Name
    image: nginx:alpine # Container Image
    ports:              # Container Port
    - containerPort: 80
EOF

# 현재 pod 상태 확인
kubectl get pods -A

# pod 배포
kubectl apply -f pod.yaml

#
kubectl get pods
kubectl describe pods nginx

# 삭제
kubectl delete -f pod.yaml

Pod 로그 확인하기

  • pod yaml
apiVersion: v1
kind: Pod
metadata:
  name: knou
  namespace: knou
spec:
  containers:
  - name: knou
    image: busybox
    env:                      # Pod 내부 변수 선언
    - name: NAME              # 변수 Key
      value: "jongjin kim"   # 변수 Value
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo \"Hello My Name is $(NAME)\"; date; sleep 2; done"]
cat << EOF > pod-log.yaml
apiVersion: v1
kind: Pod
metadata:
  name: knou
  namespace: knou
spec:
  containers:
  - name: knou
    image: busybox
    env:                      # Pod 내부 변수 선언
    - name: NAME              # 변수 Key
      value: "jongjin kim"   # 변수 Value
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo \"Hello My Name is \$(NAME)\"; date; sleep 2; done"]
EOF


# 현재 pod 상태 확인
kubectl get pods -A

# pod 배포
kubectl apply -f pod-log.yaml

#
kubectl get pods
kubectl describe pods knou

# 로그 조회
kubectl logs knou
kubectl logs knou -f

# 삭제
kubectl delete -f pod-log.yaml --force

결과 확인

  • 복붙은 실습의 미덕이기에 복붙가능하도록 변경

Pod 심화 사용

내부 컨테이너가 여러개인 Pod 배포

  • pod yaml
apiVersion: v1
kind: Pod
metadata:
  name: knou-multi
spec:
  containers:
  - name: nginx
    image: nginx
  - name: redis
    image: redis
# 바로실행
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: knou-multi
spec:
  containers:
  - name: nginx
    image: nginx
  - name: redis
    image: redis
EOF


# 현재 pod 상태 확인
kubectl get pods -A

# pod 배포
kubectl apply -f multi.yaml

#
kubectl get pods
kubectl describe pods knou-multi

# 
kubectl delete -f multi.yaml

Sidecar 패턴 활용

  • pod-yaml
apiVersion: v1
kind: Pod
metadata:
  name: knou-mart
spec:
  volumes:
  - emptyDir: {}
    name: varlog
  containers:
  - name: knou-mart
    image: busybox
    command:
    - /bin/sh
    - -c
    - 'i=1; while :;do echo -e "$i: Price: $((RANDOM % 10000 + 1))" >> /var/log/knou-mart.log; i=$((i+1)); sleep 2; done'
    volumeMounts:
    - mountPath: /var/log
      name: varlog
  - name: price
    image: busybox
    args: [/bin/sh, "-c", 'tail -n+1 -f /var/log/knou-mart.log']
    volumeMounts:
    - mountPath: /var/log
      name: varlog
kubectl apply -f - << EOF
apiVersion: v1
kind: Pod
metadata:
  name: knou-mart
spec:
  volumes:
  - emptyDir: {}
    name: varlog
  containers:
  - name: knou-mart
    image: busybox
    command:
    - /bin/sh
    - -c
    - 'i=1; while :;do echo -e "\$i: Price: \$((RANDOM % 10000 + 1))" >> /var/log/knou-mart.log; i=\$((i+1)); sleep 2; done'
    volumeMounts:
    - mountPath: /var/log
      name: varlog
  - name: price
    image: busybox
    args: [/bin/sh, "-c", 'tail -n+1 -f /var/log/knou-mart.log']
    volumeMounts:
    - mountPath: /var/log
      name: varlog
EOF

# 현재 pod 상태 확인
kubectl get pods -A

# pod 배포
kubectl apply -f sidecar.yaml

#
kubectl get pods
kubectl describe pods knou-mart

# price 컨테이너 로그 조회
kubectl logs knou-mart -c price -f

# 
kubectl delete -f sidecar.yaml

# 사이드카 패턴을 사용하는 대표적인 서비스가 Istio
## Envoy Proxy 가 Side Car 로 동작하여 Container 의 모든 네트워크 패킷을 감시하고 제어

결과 확인

  • kubectl 바로 먹여서 nginx,redis 2개의 컨테이너있는 pod 확인
  • 바로 생성시 $변수 interpolation에는 escape 문자열 필요
  • 사이드카 컨테이너의 로그 확인

Pod 단점

Pod를 직접 사용하면 안되는 이유?

  • Pod 단독 사용 시 고가용성 및 자가 치유가 불가 → 다른 배포 방식 사용
# 앞에서 배포했던 파드 1개 선언
kubectl apply -f pod.yaml

#
kubectl get pods

# kubectl 명령으로 파드 삭제
kubectl delete pods nginx

#
kubectl get pods

Pod 배포의 다양한 방법

  • Deployment : Pod 를 배포하는 기본적인 방법, 다양한 배포 전략 사용 가능
  • StatefulSets : 실행 순서 보장, Host Name & Volume 을 일정하게 사용 가능, 순서 & 데이터가 중요한 경우
  • DaemonSet : 현재 클러스터의 모든 노드에 배포, Log & Monitoring 등 모든 노드에 배포가 되어야 하는 경우
  • Job, CronJob : 배치성 작업

3.4 Deployment

deployment 기본 사용법

  • 파드와 레플리카셋에 대한 선언적 업데이트 제공
    • 레플리카셋 : 명시된 파드 개수에 대한 가용성 보장 (ex. pod 2개, 3개)
    • 디플로이먼트가 관리하는 레플리카셋은 건드리지 말아야함
  • 파드 배포에 대한 다양한 전략 설정 (롤아웃, 배포 전략)
  • 파드 배포 핵심 리소스
  • Deployment 안에는 PodTemplate 포함
    • 배포하고자 하는 Pod 정보

deployment 사용하기

  • deployment YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-v1
spec:
  selector:
    matchLabels:            # PodTemplate 에 선언된 Label 을 지정하여 Deployment 적용
      app: nginx
  replicas: 2               # Pod 개수
  template:                 # PodTemplate 시작
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        env:
        - name: APP_MODE
          value: "v1"
        ports:
        - containerPort: 80 # PodTemplate 종료
cat << EOF > deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-v1
spec:
  selector:
    matchLabels:            # PodTemplate 에 선언된 Label 을 지정하여 Deployment 적용
      app: nginx
  replicas: 2               # Pod 개수
  template:                 # PodTemplate 시작
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        env:
        - name: APP_MODE
          value: "v1"
        ports:
        - containerPort: 80 # PodTemplate 종료
EOF

# 현재 pod 상태 확인
kubectl get pods -A

# pod 배포
kubectl apply -f deploy.yaml

# Pod, ReplicaSet, Deployment 조회
kubectl get deploy,rs,pods

# 
kubectl delete -f deploy.yaml

Pod 업데이트

  • pod yaml update
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-v1
spec:
  selector:
    matchLabels:            # PodTemplate 에 선언된 Label 을 지정하여 Deployment 적용
      app: nginx
  replicas: 2               # Pod 개수
  template:                 # PodTemplate 시작
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        env:
        - name: APP_MODE
          value: "v2"       # v1 -> v2 변경
        ports:
        - containerPort: 80 # PodTemplate 종료
cat << EOF > deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-v1
spec:
  selector:
    matchLabels:            # PodTemplate 에 선언된 Label 을 지정하여 Deployment 적용
      app: nginx
  replicas: 2               # Pod 개수
  template:                 # PodTemplate 시작
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        env:
        - name: APP_MODE
          value: "v2"       # v1 -> v2 변경
        ports:
        - containerPort: 80 # PodTemplate 종료
EOF

# 터미널 2
while true; do kubectl get pods -o wide; sleep 1; done

# 터미널 1
kubectl apply -f deploy.yaml


# 동작 방식 (기본 Rolling Update)
# 신규 pod 배포 -> 배포 완료 -> 기존 pod 1대 제거 -> 제거 완료 -> 신규 Pod 배포 -> 배포 완료 -> 기존 Pod 제거 -> 제거 완료 -> N번 반복

결과 확인

  • 기존 nginx-v1-7db9f4ff4c-cztss, nginx-v1-7db9f4ff4c-q4ddc pod에서
    • env 값 변경 (설정 업데이트)
    • j9x9c, wr582 로 신규 파드 생성 후, 기존 파드 제거

wr582

Guaranteed QoS

QoS (Quality of Service) : 파드의 자원 보장 수준 분류

노드 자원 부족 시, 어떤 파드를 먼저 죽일 시 결정 (BestEffort → Bustable → Guaranteed 순)

분류우선 순위상세
GuaranteedLimit, Request 동일
BurstableLimit, Request 다름
BestEffortLimit, Request 없음

BestEffort

  • pod YAML
# Request, Limit 없는 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: qos-besteffort
spec:
  replicas: 1
  selector:
    matchLabels:
      app: qos-besteffort
  template:
    metadata:
      labels:
        app: qos-besteffort
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
cat << EOF > besteffort.yaml
# Request, Limit 없는 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: qos-besteffort
spec:
  replicas: 1
  selector:
    matchLabels:
      app: qos-besteffort
  template:
    metadata:
      labels:
        app: qos-besteffort
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
EOF

# 배포
kubectl apply -f besteffort.yaml
kubectl get pods

BEST_EFFORT=$(kubectl get pods --no-headers -o custom-columns=":metadata.name" | grep qos-besteffort)

# QoS 확인
kubectl get pod ${BEST_EFFORT} -o jsonpath='{.status.qosClass}'
kubectl describe pod ${BEST_EFFORT}
#BestEffort

Burstable

  • pod YAML
# Request, Limit 존재하지만 값이 다름
apiVersion: apps/v1
kind: Deployment
metadata:
  name: qos-burstable
spec:
  replicas: 1
  selector:
    matchLabels:
      app: qos-burstable
  template:
    metadata:
      labels:
        app: qos-burstable
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "256Mi"
              cpu: "200m"
cat << EOF > burstable.yaml
# Request, Limit 존재하지만 값이 다름
apiVersion: apps/v1
kind: Deployment
metadata:
  name: qos-burstable
spec:
  replicas: 1
  selector:
    matchLabels:
      app: qos-burstable
  template:
    metadata:
      labels:
        app: qos-burstable
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "256Mi"
              cpu: "200m"
EOF

# 배포
kubectl apply -f burstable.yaml
kubectl get pods

BURSTARBLE=$(kubectl get pods --no-headers -o custom-columns=":metadata.name" | grep qos-burstable)

# QoS 확인
kubectl get pod ${BURSTARBLE} -o jsonpath='{.status.qosClass}'
kubectl describe pod ${BURSTARBLE}
Burstable

Guaranteed

  • pod YAML

# Request, Limit 존재. 값 동일
apiVersion: apps/v1
kind: Deployment
metadata:
  name: qos-guaranteed
spec:
  replicas: 1
  selector:
    matchLabels:
      app: qos-guaranteed
  template:
    metadata:
      labels:
        app: qos-guaranteed
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "128Mi"
              cpu: "100m"
cat << EOF > guaranteed.yaml
# Request, Limit 존재. 값 동일
apiVersion: apps/v1
kind: Deployment
metadata:
  name: qos-guaranteed
spec:
  replicas: 1
  selector:
    matchLabels:
      app: qos-guaranteed
  template:
    metadata:
      labels:
        app: qos-guaranteed
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "128Mi"
              cpu: "100m"
EOF

# 배포
kubectl apply -f guaranteed.yaml
kubectl get pods

GUARANTEED=$(kubectl get pods --no-headers -o custom-columns=":metadata.name" | grep qos-guaranteed)

# QoS 확인
kubectl get pod ${GUARANTEED} -o jsonpath='{.status.qosClass}'
kubectl describe pod ${GUARANTEED}
Guaranteed

결과 확인

  • 생성된 pod들의 QoS 조회
  • 노드폭주 테스트에 있어서, CPU는 쓰로틀링 되다보니 느려질지언정 죽지는 않는 느낌.. 메모리 limit을 걸고 OOM을 만들어야할거같네요
    • https://medium.com/idus-tech/kubernetes-pod-resources-cpu-limit-40626a4c235e
    • https://littlemobs.com/blog/kubernetes-cpu-request-limit-configuration/

4. 심화

4.1. RBAC

  • RBAC (Role Based Access Control)Link
    • 쿠버네티스 리소스에 대한 접근 제어
      • 해당 과정을 인가(Authorization) 라고 지칭
    • 각 리소스에 대한 CRUD 지정

Service Account

  • Service AccountLink
    • 쿠버네티스 파드가 사용하는 역할
    • Pod 배포 시 지정하지 않으면 default 사용
    • Role, ClusterRole 과 함께 사용하여 권한을 부여 받음
    • 네임스페이스에 종속

Service Account 확인

#
kubectl get serviceaccount
kubectl get sa

#
kubectl describe sa -n kube-system coredns

Role / ClusterRole

  • Role / ClusterRole
    • Service Account 혹은 User 에 부여하기 위한 권한
    • Role : 네임스페이스에 종속된 권한
    • ClusterRole : 클러스터 전체 권한

Role / ClusterRole 확인

# Role 조회
kubectl get role -A
kubectl describe role -n kube-system kube-proxy

# ClusterRole 조회
kubectl get clusterrole
kubectl describe clusterrole system:coredns

RoleBinding / ClusterRoleBinding

  • RoleBinding / ClusterRoleBinding
    • 선언된 Role, ClusterRole 을 User, SA 등과 연결하는 리소스
    • RoleBinding : Role 과 User, SA 간 연결
    • ClusterRoleBinding : ClusterRole 과 User, SA 간 연결

RoleBinding / ClusterRoleBinding 확인

# RoleBinding 조회
kubectl get rolebinding -A
kubectl describe rolebinding -n kube-system kube-proxy

# ClusterRoleBinding 조회
kubectl get clusterrolebinding
kubectl describe clusterrolebinding cluster-admin

4.2. RBAC fail

Service Account Token 마운트

  • Service Account 는 API Server 와 통신하기 위한 인증 Token 을 파드로 마운트
  • 마운트 위치 : /var/run/secrets/kubernetes.io/serviceaccount
  • 해당 디렉토리에는 인증서 및 토큰이 들어있어, 파드가 탈취 되었을 경우 쿠버네티스 클러스터 탈취가 가능

어드민 권한 파드 탈취 시나리오

쿠버네티스 어드민 권한을 가진 서비스 어카운트와 연결된 파드가 탈취

테스트 환경 배포

# 테스트 파드 배포
kubectl run nginx --image=nginx

# SA 마운트 확인
kubectl describe pod nginx | grep Mounts -A1

# 파드 접근
kubectl exec -it nginx -- /bin/bash

## 토큰 및 인증서 확인
cd /var/run/secrets/kubernetes.io/serviceaccount && ls -lah

# 클러스터 인증서 & 토큰 확인
cat ca.crt
cat token

# API Server 호출
APISERVER=https://kubernetes.default.svc
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
TOKEN=$(cat ${SERVICEACCOUNT}/token)
CACERT=${SERVICEACCOUNT}/ca.crt

curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api

# K8S Service 호출
APISERVER=https://kubernetes.default.svc
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
TOKEN=$(cat ${SERVICEACCOUNT}/token)
CACERT=${SERVICEACCOUNT}/ca.crt

curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/services

어드민 권한 부여

# 테스트를 위해 Service Account 에 클러스터 어드민 권한 부여
kubectl create clusterrolebinding default-sa-test \
	--clusterrole cluster-admin \
	--serviceaccount default:default

# 다시 호출 K8S Service 호출
APISERVER=https://kubernetes.default.svc
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
TOKEN=$(cat ${SERVICEACCOUNT}/token)
CACERT=${SERVICEACCOUNT}/ca.crt

curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/services

# Default Namespace 리소스 조회
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/namespaces/default/services

# API Server 호출을 통한 Pod 생성
cd /

cat > busy-box.json <<EOF
{
  "apiVersion": "v1",
  "kind": "Pod",
  "metadata": {
    "name": "busybox-1"
  },
  "spec": {
    "containers": [
      {
        "name": "busybox",
        "image": "busybox",
        "env": [
          {
            "name": "CREATE_LOCATION",
            "value": "Nginx Pod using token"
          }
        ],
        "command": [
          "/bin/sh"
        ],
        "args": [
          "-c",
          "while true; do echo \$(CREATE_LOCATION); sleep 10; done"
        ]
      }
    ]
  }
}
EOF

# API Server 호출
curl --cacert ${CACERT} -k -v -X POST -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" ${APISERVER}/api/v1/namespaces/default/pods -d@busy-box.json

5. 쿠버네티스 플러그인

  • 관리 편의성
  • 쿠버네티스 활용은 모두 CLI 로 이루어지기 때문에, CLI 를 편리하게 사용하기 위한 많은 플러그인이 존재
  • 실제 쿠버네티스 현업에서는 본인에게 맞는 도구를 설치하여 사용


krew

  • kubectl cli plug-in 설치 매니저
  • 설치 가이드 – Link

kubectl autocomplete

# Linux Bash
# 자동 완성 및 alias 축약 설정
source <(kubectl completion bash)
echo 'source <(kubectl completion bash)' >> ~/.bashrc

echo 'alias k=kubectl' >> ~/.bashrc
echo 'complete -F __start_kubectl k' >> ~/.bashrc

kubectl cli 플러그인 매니저 쿠버네티스 크루(krew) 설치

(
  set -x; cd "$(mktemp -d)" &&
  OS="$(uname | tr '[:upper:]' '[:lower:]')" &&
  ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')" &&
  KREW="krew-${OS}_${ARCH}" &&
  curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz" &&
  tar zxvf "${KREW}.tar.gz" &&
  ./"${KREW}" install krew
)

export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"

echo 'export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"' >> ~/.zshrc

krew 로 kube-ctx, kube-ns 설치 및 사용

  • kube-ctx : 쿠버네티스 컨텍스트 사용 간소화
# 설치
kubectl krew install ctx

# 컨텍스트 확인
kubectl ctx

# 컨텍스트 사용 
kubectl ctx <각자 자신의 컨텍스트 이름>
  • kube-ns : 네임스페이스(단일 클러스터 내에서 가상 클러스터) 사용
# 설치
kubectl krew install ns

# 네임스페이스 확인
kubectl ns

# kube-system 네임스페이스 선택 사용
kubectl ns kube-system

# default 네임스페이스 선택 사용
kubectl ns -
혹은
kubectl ns default
  • get-all : kubectl get all 로도 안보이는 쿠버네티스의 모든 리소스 조회
# 설치
kubectl krew install get-all

# 네임스페이스 확인
kubectl get-all -n kube-system

  • neat : kubectl yaml 파일 형태로 리소스 출력
# 설치
kubectl krew install neat

# 배포
k run nginx --image nginx

# 파드 정보 확인
k get pods nginx -o yaml | k neat

k9s 설치 및 사용

  • k9s install
    • ..지만 linux에서 익숙한 package manager(dnf/apt) 는 없음
    • github release에서 .rpm/.deb 설치 또는
    • binary 설치
wget https://github.com/derailed/k9s/releases/download/v0.50.4/k9s_linux_amd64.deb
sudo dpkg -i k9s_linux_amd64.deb
sudo apt-get install -f
k9s

or

curl -LO https://github.com/derailed/k9s/releases/download/v0.50.4/k9s_Linux_amd64.tar.gz
tar zxvf k9s_Linux_amd64.tar.gz
sudo mv k9s /usr/local/bin/
k9s version

결과 확인

  • krew
  • k9s

Leave a Reply