DevOps/Kubernetes

[CKA] CKA 자격증 준비 자료 정리 1 (Core Concepts)

KIM DEON 2021. 11. 15. 00:01

본 포스팅은 CKA 자격증 준비를 위해 해당 강의를 보고 정리한 자료입니다.

일부 생략되었으니 꼭 강의를 수강하시고 내용 정리 용도로만 참고하시길 바랍니다. 

 


Cluster Architecture

쿠버네티스의 구조에 대한 내용으로, 구성 요소에 대한 간략한 설명을 포함.

-> 강의 자료 또는 쿠버네티스 문서 참고


ETCD

정보를 key-value 형태로 저장하는 데이터베이스로, 컨테이너가 어떤 ship에 있는지,언제 load되었는지 등 각기 다른 ship들에 대한 정보를 저장

ETCD in K8S

  • nodes, pods, configs, secrets, accounts, roles, bindings .. 등 cluster에 관한 정보 저장
  • kubectl 의 모든 정보들은 ETCD 서버에서 오는 것
  • 모든 변화(노드 추가, 파드 배포 등) 또한 ETCD 서버에 업데이트

ETCD pod

  • kubeadm으로 설치했다면 kube-system 에 etcd-master라는 이름으로 배포됨
  • 다음 명령어로 저장된 key들 확인 가능
$ kubectl exec etcd-master -n kube-system etcdctl get / --prefix -keys-only

ETCD in High Availability Environment

  • 여러 master 노드의 환경이면, 여러 instance가 있을 것
  • 각 ETCD instance가 서로를 알 수 있도록 etcd.service에 올바른 파라미터를 지정해야함

Kube-API server

클러스터 내 변화를 수행하기 위한 모든 다양한 작업들의 중심 역할

  1. Authenticate User
  2. Validate Request
  3. Retrieve data
  4. Update ETCD
  5. Scheduler
  6. Kubelet

Kube API server work pattern

kubectl 사용시 kube api 서버 동작

kube api 서버는 request를 인증/확인 후 etcd cluster에서 데이터를 검색해 반환

Pod 생성시 kube api 서버 동작

  1. api 서버는 pod object 생성 (노드에 할당하지 않고)
  2. etcd 서버에 pod이 생성되었음을 업데이트
  3. scheduler는 api 서버를 모니터링 하고 있으므로, 새로운 pod이 생겼음을 인지, 배포할 노드 확인
  4. api 서버는 etcd에 정보 업데이트
  5. api 서버가 해당 정보를 적합한 노드의 kubelet에 전달
  6. kubelet이 노드에 pod 생성, container runtime engine에 application image을 배포하도록 지시
  7. kubelet 은 api 서버에 상태 업데이트, api 서버는 data를 etcd 에 저장

⇒ pod 생성을 예시로 들었지만, pod 생성 뿐만 아니라 모든 변화가 이러한 패턴을 따름


Kube API server Pod

kubeadm으로 설치한 경우

  • kube-system의 kube-apiserver-master
  • apiserver 정의 파일 : /etc/kubernetes/manifests/kube-apiserver.yaml

다른 방법으로 설치한 경우

  • apiserver 정의 파일 : /etc/systemd/system/kube-apiserver.service.yaml

Process 확인

master node process의 kube-apiserver 통해 실행중인 process 확인 및 effective option 확인

$ ps -aux | grep kube-apiserver

Kube Controller Manager

  • 시스템 내 다양한 구성 요소의 상태를 지속적으로 모니터링하고, 전체 시스템을 원하는 상태로 만들기 위해 작동하는 프로세스
  • Kube Controller Manager는 여러 controller가 하나의 프로세스로 패키징되어 실행되는 형태
    • Node Controller, Namespace-Controller, Replication-Controller ... 등등

Node Controller

  • 노드들의 상태를 모니터링, application이 계속 실행될 수 있도록 필요한 조치를 수행

Node Controller Parameters

  • --node-monitor-periods=5s : 노드 컨트롤러가 5초마다 노드의 상태를 체크
  • --node-monitor-grace-period=40s : 노드의 상태가 정상적이지 않은 경우, 40초를 기다린 후 unreachble 상태로 표기
  • --pod-eviction-timeout=5m0s : 노드가 5분안에 정상화 되지 않을 경우, 해당 노드에 할당된 pod을 삭제하고 다른 정상 노드에 생성할 수 있도록 함

Replication Controller

  • replica set의 상태를 모니터링하고, 의도된 수의 pod이 available한지 확인하는 역할
  • pod이 하나 삭제되면, 하나 더 생성

Kube Controller Manager pod

kubeadm으로 설치한 경우

  • kube-system의 kube-controller-manager-master
  • apiserver 정의 파일 : /etc/kubernetes/manifests/kube-controller-manager.yaml

다른 방법으로 설치한 경우

  • apiserver 정의 파일 : etc/systemd/system/kube-controller-manager.service

Process 확인

$ ps -aux | grep kube-controller-manager

Kube Scheduler

  • pod이 어떤 노드로 갈 것인지 결정하는 역할
    • 실제로 노드에 pod을 배치하는 것은 아니다. -> kubelet의 역할
  • 노드 선정 방식
    1. pod이 요구하는 resource를 보고 filtering
    2. pod을 배치하고 해당 노드에 더 많은 resource가 남는 경우를 상위로 rank 지정

Kube Scheduler pod

  • kube-scheduler 라는 이름으로 다른 controller들과 동일

Kubelet

  • master의 scheduler의 지시에 따라, 컨테이너를 load/unload하는 역할
  • 또한 컨테이너의 상태를 일정 간격에 따라 report
  • kubelet은 worker 노드에 pod을 생성하기 위해 container runtime(ex. docker) 에 요청을 전달
  • kubelet은 pod과 컨테이너의 상태를 지속적으로 모니터링하고, 결과를 kube-apiserver에 주기적으로 전송

kubelet 설치

  • kubeadm으로 worker 노드를 구성할 경우, kubelet이 자동으로 설치되지 않으므로 별도로 kubelet 을 설치해야함

Kube Proxy

  • 쿠버네티스 클러스터의 모든 pod은 서로 다른 pod과 통신할 수 있음
    • 클러스터 내 pod 네트워크를 담당하는 기능이 배포되어 있음
    • pod 네트워크는 모든 pod이 통신할 수 있도록 클러스터의 모든 노드에 생성되는 가상 네트워크
  • 특정 pod에서 다른 pod에 접근하기 위한 가장 좋은 방법은 service를 이용하는 것
    • service 도 ip를 할당 받으며, pod이 이 ip로 서비스에 접근하고자하면, traffic이 pod으로 forward 됨
    • 그렇다면 service가 무엇이며, ip를 어떻게 얻는 것인가?
      • service는 실제로 존재하는 것이 아님
      • pod과 같이 컨테이너 형태로 실행되지 않으며, 어떤 인터페이스나 요청을 기다리는 프로세스가 존재하는 것이 아님
      • 그저 쿠버네티스 메모리 상에 존재하는 가상 컴포넌트 개념
      • → 하지만 서비스는 접근 가능해야 하는데? → kube-proxy 를 통해 가능
  • Kube Proxy
    • 쿠버네티스 클러스터 내 모든 노드에서 실행되는 프로세스
    • 새로운 서비스를 찾는 역할
      • 서비스가 생성되면 어떤 서비스에 대해 어떤 pod으로 traffic을 forward 할지에 대한 rule을 생성함
      • → 이러한 네트워크 rule을 만드는 방법 중 하나가 IPTABLES 를 사용하는 것
        • 모든 노드에 service의 ip로 들어오는 트래픽에 대해 해당 pod으로 보낼 수 있는 규칙을 IPTABLES에 만들어줌

Kube proxy pod

  • kubeadm은 모든 노드에 kube-proxy를 배포하며, daemon set으로 배포된다.
    • 모든 클러스터의 노드마다 오직 하나의 kube-proxy pod이 실행될 수 있음
$ kubectl get daemonset -n kube-system

PODs

  • 쿠버네티스는 컨테이너를 직접적으로 worker 노드에 배포하지 않음
    • 컨테이너는 pod이라는 object로 캡슐화 되며, pod은 쿠버네티스에서 가장 작은 object에 해당
    • pod과 컨테이너는 기본적으로는 1:1
      • 클러스터 내 노드에 pod이 하나 배포된 상황에서, application을 scale up할 경우, 새로운 pod이 생성됨
      • 노드가 unsufficient할 경우, 새로운 노드에 pod을 추가하게 됨
      • (필요에 따라 pod이 컨테이너를 여러개 가지도록 할 수 있음)
$ kubectl run nginx —image nginx
$ kubectl get pods

PODs with YAML

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
    labels:
      app: myapp
      type: front-en
spec:
  containers:
  - name: nginx-container
    image: nginx

Practice

  • dry-run 으로 pod 생성 없이 yaml 뽑고 yaml 으로 pod 생성
$ kubectl run redis --image=redis123 --dry-run=client -o yaml > pod.yaml kubectl apply -f pod.yaml
  • pod 수정
$ kubectl edit pod redis

ReplicaSets

Replica & Replication Controller

  • Replication Controller는 쿠버네티스 클러스터에서 단일 pod의 여러 instance가 가능하도록 해주고 이는 고가용성을 제공
    • 지정된 수의 pod을 보장하는 역할
  • Replication Controller가 필요한 또 다른 이유는, 여러 pod을 만들어 load를 공유하기 위함
    • 예를 들어 사용자 집합에 서비스를 제공하는 단일 pod이 있을 때, 사용자가 늘어나면 추가 pod을 배포하여 두 pod에 load balance를 맞추는 것

Replication Controller | Replica Set

  • Replication Controller는 Replica Set 으로 대체 됨

Replication Controller

apiVersion: v1
kind: ReplicationController
metadata:
  name: myapp-rc
  labels:
    app: myapp
    type: frontend
spec:                   # Replication Controller
  template:
    metadata:
      name: myapp-pod
      labels:
        app: myapp
        type: front-end
      spec:                 # Pod
        containers:
        - name: nginx-container
          image: nginx
    replicas: 3

 

Replica set

apiVersion: v1
kind: ReplicaSet
metadata:
  name: myapp-replicaset
  labels:
    app: myapp
    type: frontend
spec:                   # Replication Controller
  template:
    metadata:
      name: myapp-pod
      labels:
        app: myapp
        type: front-end
      spec:                 # Pod
        containers:
        - name: nginx-container
          image: nginx
    replicas: 3
    selector: 
      matchLabels:
        type: front-end

→ RC와 차이점은, ReplicaSet은 해당 ReplicaSet으로 생성되지 않은 pod에 대해서도, selector를 지정해서 일치하는 labels를 가진 pod에 대한 replica를 관리할 수 있다는 점

Labels & Selectors

  • Labels
    • ReplicaSet은 pod들을 모니터링하고, 누가 fail나면 새로운 pod을 배포한다. 모니터링할 pod들은 labeling으로 선택한다.

Scale 수정

$ kubectl replace -f replication-definition.yml
$ kubectl scale —replicas=6 -f replicaset-definition.yml
$ kubectl scale —replicas=6 replicaset myapp-replicas

Deployments

  • rolling update, undo change, pause, resume 과 같이 instance를 원활하게 업그레이드 할 수 있는 기능을 제공
  • Replication Controller 또는 Replica Set을 통해 pod을 배포하는 상위 object
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
  labels:
    app: myapp
    type: frontend
spec:           
  template:
    metadata:
      name: myapp-pod
      labels:
        app: myapp
        type: front-end
    spec: 
      containers:
      - name: nginx-container
        image: nginx
  replicas: 3
  selector: 
    matchLabels:
      type: front-end
deployment, rc, pod을 모두 보고싶을 땐 "kubectl get all" 을 활용한다.

+TIP : Use Kubectl RUN

Create an NGINX Pod

$ kubectl run nginx --image=nginx

 

Generate POD Manifest YAML file (-o yaml). Don't create it(--dry-run)

$ kubectl run nginx --image=nginx --dry-run=client -o yaml

Create a deployment

$ kubectl create deployment --image=nginx nginx

Generate Deployment YAML file (-o yaml). Don't create it(--dry-run)

$ kubectl create deployment --image=nginx nginx --dry-run=client -o yaml

Generate Deployment YAML file (-o yaml). Don't create it(--dry-run) with 4 Replicas (--replicas=4)

$ kubectl create deployment --image=nginx nginx --replicas=4 --dry-run=client -o yaml > nginx-deployment.yaml

파일로 저장하고, 필요한 변경을 수행한 다음 deployment 생성

$ kubectl create -f nginx-deployment.yaml

Namespace

  • 각 namespace는 그 만의 정책을 가지게됨
    • resource를 할당하여 특정 양의 resource를 보장할 수 있음
  • kube-system : networking solution 또는 dns 서비스 등을 위해 내부적인 목적을 가진 pod또는 서비스가 배포되며, 삭제할 수 없도록 방지함
  • kube-public : 모든 사용자에게 available한 resource가 생성되는 곳

DNS

  • namespace 내 pod들은 그들의 이름으로 서로를 알 수 있음
    • mysql.connect('db-service')
  • 다른 namespace 일 경우 servicename.namespace.svc.clutser.local 포맷 이용
    • mysql.connect('db-service.dev.svc.cluster.local')

Command

$ kubectl create namespace dev
$ kubectl create -f pod-def.yaml —namespace=dev
apiVersion: v1
kind: Namespace
metadata:
  name: dev

Namespace switch

default namespace 변경

$ kubectl config set-context $(kubectl config current-context) —namespace=dev

Resource Quota

namespace에 리소스 할당(제한)

apiVersion: v1
kind: Namespace
metadata:
  name: dev
spec:
  hard:
    pods: "10"
    requests.cpu: "4"
    requests.memory: 5Gi
    limits.cpu: "10"
    limits.memory: 10Gi

Services

  • 다양한 내부 component와 application 바깥이 통신할 수 있도록 도와줌
  • application을 다른 application 또는 user들과 연결할 수 있도록 도와줌

Service Types

NodePort

  • 노드에서 port로 들어오는 요청을 듣고 있다가, 요청이 오면 pod port로 전달
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  type: NodePort
  ports:
  - targetPort: 80 # app(pod)의 port 
    port: 80 # service port
    nodePort: 30008  # 없을 경우 자동 지정, 실제로 user가 app에 접근하기 위한 port
  selector:          # pod selection
    app: myapp
    type: front-end
  • 해당 label의 여러 pod이 있을 경우 service는 여러 pod을 외부 request를 전달할 endpoint로서 선택함
  • 한 노드의 여러 pod, 여러 노드에 있는 여러 pod의 경우에도 동일하게 service를 생성하면 됨

ClusterIP

service가 각기 다른 서비스들이 통신할 수 있도록 가상의 ip를 생성

  • pod의 ip는 바뀔 수 있기 때문에 application 통신에는 적합하지 않음
  • 쿠버네티스 서비스는 pod들을 그룹화하고 접근하기위한 하나의 interface를 제공
  • 각 service는 ip name을 할당받고, 해당 name은 다른 pod이 service에 접근하기 위해 사용됨
  • ⇒ 이런 type의 서비스가 ClusterIP
apiVersion: v1
kind: Service
metadata:
  name: back-end
spec:
  type: ClusterIP
  ports:
  - targetPort: 80  # pod expose
    port: 80        # service expose
  selector:
    app: my-app
    type: back-end

LoadBalancer

  • 지원되는 클라우드 제공 업체에서, 서비스에 대한 로드 밸런서를 공급
    • 여러 노드에 걸쳐 여러 pod이 있을 경우, 서비스를 통해 접근 할 수 있는 ip는 여러개
      • → 하나의 url을 통해 하나의 app에 접근하기 위해 load balancer 필요
    • Google Cloud 또는 A.W 또는 Azure와 같은 클라우드 플랫폼위에 있을 경우, native load balancer 사용 가능

Imperative vs Declarative

Imperative

  • step by step 지시
  • yaml 을 정의하지 않아도 빠르게 object를 만들 수 있음
  • functionality에 제한이 있고, 길고 복잡한 command가 될 수 있음
  • 한번 실행되고 저장되지 않으므로 다른 사람이 해당 obj가 어떻게 생성되었는지 파악 어려움
  • 현재의 configuration을 파악하고 있어야함

생성 command

$ kubectl run —image==nginx nginx
$ kubectl create deployment —image=nginx nginx
$ kubectl expose deployment nginx —port 80

업데이트 command

$ kubectl edit deployment nginx
$ kubectl scale deployment nginx —replicas=5
$ kubectl set image deployment nginx nginx=nginx:1.18
kubectl edit 은 K8s 메모리 상에 반영될 뿐 local yaml file에는 반영되지 않는다. local yaml file을 수정하고 replace 명령어를 쓰는게 나을 때도 있음. (kubectl replace -f nginx.yaml)

Declarative

  • final destination 정의, 그 과정은 system이 수행

생성 command

$ kubectl apply -f nginx.yaml
$ kubectl apply -f /path/to/config-files     # 한번에 여러 object apply

업데이트 command

$ kubectl apply -f nginx.yaml

Kubectl Apply Command

  1. local file을 통해 obect 생성
  2. local로 생성한 것과 비슷한 K8s memory 상에 object configuration 이 생성됨 ⇒ live configuration
    • 상태를 저장하기 위한 항목이 추가됨
  3. local obj configuration file이 json format으로 변환되고, 최근 apply된 configuration 으로 저장됨
    • → 이 내용 또한 live config 에 annotation으로 저장됨 (last-applied-configuration)
    • imperative command 사용시 해당 내용이 생기지 않으므로, create/replace 등 imerative command와 apply 를 혼용해서 사용하지 않는 게 좋음
    • 변경된 local file과 이 last updated config 의 차이를 통해 live obj config를 변경할 수 있음

[DevOps/Kubernetes] - [CKA] CKA 자격증 준비 자료 정리 2 (Scheduling)