본문 바로가기
AWS Cloud School 8기/쿠버네티스

[쿠버네티스] Kubernetes/ 클러스터/ CRI/ 매니패스트

by YUNZEE 2025. 4. 10.
728x90

✅ 쿠버네티스

🎯 한 줄 정의

  • 쿠버네티스는 컨테이너화된 애플리케이션을 자동으로 배포, 스케일링, 운영, 복구하는 플랫폼임
  • 도커 같은 컨테이너 기술만으로는 수십, 수백 개의 컨테이너를 관리하기 어려움
  • 그래서 이런 걸 자동으로 처리해 주는 컨테이너 오케스트레이터가 필요함

🎯 시작은 Google

  • 2003~2004년: 구글은 내부적으로 Borg라는 컨테이너 관리 시스템을 개발
  • 이건 구글의 수많은 서버에서 수많은 애플리케이션을 안정적으로 돌리기 위해 만든 시스템
  • 그걸 바탕으로 2014년에 오픈소스 프로젝트로 공개한 게 바로 쿠버네티스(Kubernetes)!

실습 - 환경 설정

더보기

환경 만들기

ubuntu tem clone해서 master vm 만들기

1. docker 설치 - 이미지빌드를 하기 위한 도구로 사용하기 위함 - 도커 재시작 스크립트 스케줄링

curl -fsSL https://get.docker.com -o get-docker.sh

chmod +x get-docker.sh

./get-docker.sh

- 도커 재시작 스크립트 스케줄링

sudo tee /root/check_ip_and_restart_docker.sh<<EOF
#!/bin/bash
 
if ! ip add | grep -q 172.17; then
	systemctl restart docker
fi
EOF
chmod 777 /root/check_ip_and_restart_docker.sh
crontab -e
# 스케쥴 관리. 2번 기본 vim 편집기

* * * * * /root/check_ip_and_restart_docker.sh

2. 디스크 40GB 확장

vgextend ubuntu-vg /dev/sdb

lvextend -l +100%FREE -n /dev/mapper/ubuntu--vg-ubuntu--lv

resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv

 

도커 설치

curl -fsSL https://get.docker.com -o get-docker.sh

chmod +x get-docker.sh

./get-docker.sh

3. yaml 수정도구

vi ~/.vimrc

" Enable file type detection
filetype on

" Enable syntax highlighting
syntax on

" Enable auto-indentation for YAML files
autocmd FileType yaml setlocal autoindent smartindent expandtab shiftwidth=2 tabstop=2
autocmd FileType yml setlocal autoindent smartindent expandtab shiftwidth=2 tabstop=2

 

 master에 설정해 둔 환경을 그대로 복제

템플릿은 두고 worker-1 , 2 노드를 복제하자

 vm ip 변경하는 방법 (혹시 몰라 추가)

root@ubun-tem:/home/user1# vi /etc/netplan/00-installer-config.yaml

root@ubun-tem:~# netplan apply

- 호스트네임은 vm이름과 같게 구성

클러스터 공통 설정

1. 네트워크 설정

더보기

# 방화벽의 상태가 inactive인지 확인. 만약 액티브라면 ufw disable

modprobe overlay

modprobe br_netfilter

# 네트워크 관련 모듈을 불러오는 명령어

tee /etc/sysctl.d/kubernetes.conf<<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

 

tee /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF

 

# 쿠버네티스와 컨테이너런타임의 네트워크 트래픽을 제어하기 위한 설정 파일 생성.

sysctl --system

# 설정 반영

2. 가상메모리 중지 및 비활성화

더보기

- 쿠버네티스 클러스터는 가상메모리가 활성화되어있으면 클러스터가 구성이 안됨.

root@master:~# swapoff -a

# 가상메모리 중지. 

root@master:~# vi /etc/fstab

# 클러스터가 재시작 됐을 때도 스왑이 off상태여야 하므로, 자동마운트 해제

3. CRI(Container Runtime Interface) 설치 - containerd

pod - 쿠버네티스 기본 단위 = 한 개 이상의 컨테이너

내부 pod에 있을 때 아이피는 동일하지만 포트는 다름

더보기

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# gpg키 다운로드. gpg키? = 내가 설치할 패키지의 무결성을 검증하기 위한 키.

 

add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# 레포지토리에 목록 추가.

 

apt-get update -y

# 레포 갱신

 

apt-get install -y containerd.io

# CRI 설치

 

mkdir -p /etc/containerd

# containerd 설정파일 디렉터리 생성

 

containerd config default>/etc/containerd/config.toml

# 기본 설정을 포함한 설정파일 생성.

 

systemctl restart containerd

systemctl enable containerd

4. 쿠버네티스 v1.30 설치(kubectl, kubelet, kubeadm)

kubectl - k8s 클러스터에 REST API요청(https로 api요청) 하기 위한 명령어

이 명령어와 인증/ 인가 파일만 있다면 어디서든 내 클러스터에 요청할 수 있음

 

kubeadm - kubectl이 클러스터에 요청을 하기 위한 명령어라면, kubeadm은 클러스터 자체를 구성하고 관리하는 도구라고 생각하면 좋음

더보기

https://kubernetes.io/ko/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

# 설치 방법

 

apt-get install -y apt-transport-https ca-certificates curl

# 필요한 패키지 설치.

 

mkdir -p /etc/apt/keyrings

# 위 경로가 없으면 생성

 

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

# gpg키 다운


echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

# 레포 목록 추가

 

apt-get update -y

# 레포 목록 업데이트

 

apt-get install -y kubelet kubeadm kubectl

# 명령어 설치.

지금까지 공통 설정 - master, worker-1, worker-2

이제부터 마스터 노드를 구성할 예정

더보기

클러스터 설치를 위한 이미지 풀링

kubeadm config images pull --cri-socket unix:///run/containerd/containerd.sock --kubernetes-version v1.30.3

 

kubeadm <이 명령을 쓸 때는 뒤에 노란색 형광 밑줄이 필수> config images pull --cri-socket unix:///run/containerd/containerd.sock --kubernetes-version v1.30.3

 - kubeadm을 사용해서 쿠버네티스 클러스터를 초기화하거나 준비할 때 필요한 컨테이너 이미지들을 풀링 했다는 의미의 메시지임

#이미지 풀링 분석을 해보자
[config/images] Pulled registry.k8s.io/kube-apiserver:v1.30.3
#클러스터의 중심, 모든 컴포넌트가 이 API서버를 통해 통신함, 사용자와 인터페이스 역할
[config/images] Pulled registry.k8s.io/kube-controller-manager:v1.30.3
# 클러스터 상태를 원하는 상태로 유지하기 위한 컨트롤러 모음
[config/images] Pulled registry.k8s.io/kube-scheduler:v1.30.3
# 새로운 Pod이 생성되면 어떤 노드에 할당할지 결정
[config/images] Pulled registry.k8s.io/kube-proxy:v1.30.3
# 각 노드에서 서비스와 Pod간의 네트워크 트래픽을 처리해주는 역할
[config/images] Pulled registry.k8s.io/coredns/coredns:v1.11.3
# DNS 서버 역할, 클러스터 내에서 서비스 이름으로 통신할 수 있게 도와줌
[config/images] Pulled registry.k8s.io/pause:3.9
# 모든 Pod에서 기본 네트워크 네임스페이스를 유지하기 위한 컨테이너 일종의 "빈 컨테이너"
[config/images] Pulled registry.k8s.io/etcd:3.5.15-0
# 쿠버네티스의 모든 클러스터 상태 데이터를 저장하는 key-value DB 고가용성을 위한 핵심 컴포넌트

 

kubeadm init --pod-network-cidr=10.244.0.0/16 --upload-certs --kubernetes-version=v1.30.3  --cri-socket unix:///run/containerd/containerd.sock --ignore-preflight-errors=all

# 클러스터 초기화 + control plane 구성.

# --ignore-preflight-errors=all : 에러 생기면 무시.

# --pod-network-cidr=10.244.0.0/16 : 나중에 네트워크 애드온의 대역과 맞춰줘야 함. 10.244.0.0/16 대역은 flannel이라는 네트워크애드온의 대역임

# --upload-certs : 인증, 인가하기 위한 파일을 자동으로 배포할 수 있게 해주는 옵션.

위의 join 명령을 워커노드에 복붙

kubeadm join 211.183.3.20:6443 --token bjssez.pk6q5zm33toux4so \
--discovery-token-ca-cert-hash sha256:a833cfdbf53917cb2592bdfb8e9028b77808a475b8aea73d0ab3004a75df4ddc 

# kubectl이라는 명령을 치면, ~/.kube/config 파일에 있는 정보를 토대로 클러스터에 API 요청을 함. ~/.kube/config 파일에는 클러스터의 주소 + 인증/인가인증/인가에 대한 정보가 들어있음.

 

# kubectl 명령을 치려면 결국 kubectl 명령어 설치는 물론 config 파일도 구성을 해줘야 됨.

root@master:~# mkdir -p $HOME/ .kube
root@master:~# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
root@master:~# sudo chown $(id -u):$(id -g) $HOME/  .kube/config
root@master:~# kubectl get nodes

- 같은 명령어를 입력했지만 바뀐 걸 확인할 수 있음.

 워커노드 구성

더보기

kubeadm join 211.183.3.20:6443 --token bjssez.pk6q5zm33toux4so --discovery-token-ca-cert-hash sha256:a833cfdbf53917cb2592bdfb8e9028b77808a475b8aea73d0ab3004a75df4ddc --cri-socket unix:///run/containerd/containerd.sock

- master token파일에 넣은 내용을 그대로 파일을 만드는 게 아니라 그대로 복붙 하면 worker-1,-2에 넣으면 

이렇게 뜨면 잘 된 걸 확인 가능

 

혹시 클러스터 깨지거나 했을 때, 

kubeadm reset --cri-socket unix:///run/containerd/containerd.sock

이 명령을 통해 3개의 노드를 전부 리셋하고 다시 init 해서 클러스터를 재구성(최악의 경우)

 

네트워크 애드온의 종류 

 

-> Pod 간 통신이 어떻게 가능한가?라는 핵심이 CNI

이런 애드온들을 CNI(Container Network Interface)라고도 부른다.

 

✅ 1. CNI란 무엇인가?

- 컨테이너 네트워크를 설정하는 플러그인 시스템

- 쿠버네티스에서 Pod가 생성될 때 자동으로 IP주소를 할당하고, 다른 Pod들과 통신할 수 있게 네트워크 설정을 해줌

- 이걸 쿠버네티스가 직접 처리하는 게 아니라, 외부 플러그인(CNI)들이 담당함

 

CNI 설치 - 마스터 노드에서만

# 이런 것들을 설치해 줬으면 좋겠어.

# 원하는 상태(Desired state) = 바람 = 매니페스트 파일.

더보기

root@master:~# kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

# 한 줄짜리 명령.

# 파일(-f)에 담긴 나의 바람(yml 파일)을 내 클러스터에 반영(apply) 시키고 싶음

 

wget https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
# 나중에 클러스터에 네트워크 문제가 생겼을 경우 재설치할 수도 있기 때문에 파일도 저장함

 

root@master:~# kubectl get nodes

- ready가 안 나온다면 한 번 더 입력해 주기

- 바로 적용이 안될 수도 있음

- notready에서 ready로 바뀐 걸 확인할 수 있음

# kubeadm에서 파드네트워크를 정한 이유.

# 정상적인 클러스터. 0/1이라면 뭔가 문제가 있음

쿠버네티스 컴포넌트

🧠 1. Control Plane(클러스터의 두뇌)

쿠버네티스 클러스터를 관리하고 지시를 내리는 중심 뇌

 

kube-apiserver : 내/외부의 모든 요청을 받는 서버. controller 나 scheduler의 주시대상. + 인증/인가 정보. ex) 호텔지배인

-> 모든 명령/ 요청은 여기로 오고 다른 컴포넌트들과 통신 중간다리 역할을 수행함

kube-scheduler : 생성될 리소스들을 어떤 노드에 배치할지 결정(스케줄링)

-> 새로 만든 Pod가 어느 노드에 가야 할지 결정함

💡Pod란?

쿠버네티스에서 컨테이너를 실행하는 가장 작은 단위임

kube-controller : 다양한 컨트롤러들이 존재. 원하는 상태(Desired state, 바람)에 현재상태(status)가 수렴하도록 계속 모니터링. 문제가 생기면 고치거나 리소스를 재생성.

-> AWS, GCP 등 클라우드 자원과 연동할 때 사용함(로컬에선 거의 없음)

etcd : 클러스터 및 모든 리소스에 대한 정보를 key : value 형태로 저장하는 일종의 데이터베이스.

🛠️ 2. Node(Worker Node) (Pod가 실제로 돌아가는 곳)

kubelet : 노드관리자. 실질적으로 각 노드에 리소스를 관리 (ex) 현장 관리자)

-> Control Plane의 명령을 받아서 실제 컨테이너(Pod)를 실행시킴

 

kube-proxy : 노드 안과 밖을 넘나드는 수직적인 트래픽을 관리 (ex) 네트워크 연결 담당자)

-> 서비스 접근, 로드밸런싱 등 네트워크 라우팅을 담당

+ 네드워크 애드온(CNI) = 네트워크에 관련된 coredns와 kube-proxy를 위해 필요한 부가 기능.

더보기

root@master:~# kubectl run test-pod --image public.ecr.aws/docker/library/nginx:alpine
pod/test-pod created

# test-pod라는 이름을 갖는 pod를 생성하고 싶음


root@master:~# kubectl get pod
NAME       READY   STATUS              RESTARTS   AGE
test-pod   0/1     ContainerCreating   0          13s

# pod 정보를 보고(get) 싶음


root@master:~# kubectl get pod --watch
NAME       READY   STATUS              RESTARTS   AGE
test-pod   0/1     ContainerCreating   0          32s

# pod 정보를 보고(get) 싶음


root@master:~# kubectl delete pod test-pod
pod "test-pod" deleted

# test-pod 지우기


root@master:~# kubectl get pod
No resources found in default namespace.

# 잘 지워진 걸 확인할 수 있음

 

root@master:~# kubectl get pod -o wide

# 아웃풋(-o)을 좀 폭넓게 보고 싶다. 배치된 노드. ip 확인

# 오버레이네트워크가 구성되어 있고, 노드들이 pod 네트워크를 알고 있기 때문에 master노드에서 worker1 노드에 있는 pod와 통신이 가능함.

# kubectl get pod -n kube-system을 쳤을 때 0/1 이런 pod들이 존재한다면, 클러스터가 비정상일 확률이 높고, 위와 같은 방법으로도 클러스터의 정상여부를 확인 가능함.

 

=> 쿠버네티스 수업에서 '클러스터 키세요~' 하면 일단 저걸 확인해 보면 좋음.

오류 /문제 해결 - ip가 안 생성되는 이슈

더보기

ip가 생성 안 된 걸 확인할 수 있음

이럴 때는 일단 nodes가 ready 상태인지 확인해야 됨

root@master:~# kubectl get pod -n kube-system

 - 잘 러닝 된 상태인 걸 확인할 수 있음

root@master:~# kubectl describe pod test-pod

이렇게 나와야 정상이지만 failed가 많은 걸 확인할 수 있음

  Warning  FailedCreatePodSandBox  9s    kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "3d3bd9bb829b1cae4db7fbfec748e5d7fed20525417b721c23b2f5112f75c6f9": plugin type="flannel" failed (add): loadFlannelSubnetEnv failed: open /run/flannel/subnet.env: no such file or directory

-> 자세히 보면 flannel이 failed 된 거라고 나옴

 

root@master:~# kubectl delete -f kube-flannel.yml

root@master:~# kubectl apply -f kube-flannel.yml

-> 그래서 지웠다가 다시 apply 해줬음

 

root@master:~# kubectl get pod -n kube-flannel

- 그래도 error가 발생하는 걸 확인할 수 있음

 

- 그래서 그냥 재부팅하고 실행해 보니까 잘 되는 걸 확인할 수 있음

(아오...)

여기서 다시 시작

더보기

root@master:~# kubectl run bad-pod --image=pcmin-jjang

# 존재하지 않는 이미지로 pod를 생성해 보자.

root@master:~# kubectl describe pod bad-pod

root@master:~# kubectl delete pod bad-pod test-pod

root@master:~# kubectl run test-pod --image public.ecr.aws/docker/library/nginx:alpine --dry-run=client -o yaml > test-pod.yml

# --dry-run=client. 서버엔 전달을 안 하고 리허설을 해보겠다(가짜)

# -o yaml : yaml형태로 출력해서 

# test.pod.yml이라는 매니페스트(명세표) 파일로 리다이렉션 해서 만들겠다.

# status는 매니페스트에는 존재하지 않고, etcd 같은 곳에 존재한다.

# x 친 부분들을 삭제.

# status는 매니페스트에는 존재하지 않고, etcd 같은 곳에 존재한다.

# x 친 부분들을 삭제.

매니패스트 파일의 필수 항목

더보기

# apiVersion: '과자'라는 카테고리

# kind: '새우깡'. 새우깡은 '과자'라는 카테고리에 속해있다. 그밖에 감자깡, 고구마깡, 매운 새우깡 등도 있을 수 있음

 

root@master:~# kubectl apply -f test-pod.yml

# test-pod.yml 파일(-f)에 담겨있는 나의 바람이 클러스터에 반영(apply)됐으면 좋겠음 

실습 1) worker1 노드에서 kubectl로 master노드의 apiserver에 요청 가능한 상태를 만들어보세요. 요청이 가능하다면, 

apiserver

-> kuber-apiserver는 쿠버네티스 클러스터와 대화하는 관문임

-> 모든 명령은 kubectl은 결국 apiserver로 전달돼서 처리됨

-> kubectl get pods라고 치면, 결국 apiserver한테 '야 지금 Pod 목록 줘' 요청 보내는 거야 하고 전달

즉, apiserver가 클러스터의 중심이라서, worker1에서 kubectl을 써서 제대로 요청하려면 apiserver와 통신이 돼야 함

1. cli명령으로 ECR갤러리의 httpd:latest 이미지로 구성된 pod를 한번 띄워보세요.

2. --dry-run으로 ECR갤러리의 httpd:latest 이미지로 구성된 pod를 생성하기 위한 매니페스트 파일(my-httpd.yml)을 만들어보세요.

3. my-httpd.yml파일을 적절하게 수정하여 pod의 이름이 test인 파드를 만들어보세요.

더보기

풀이)

root@master:~# cat ~/.kube/config

# 이 파일의 내용만 worker1로 옮기고, kubectl 명령을 설치만 하면 

- 여기에 있는 내용을 복사해서 worker-1에 넣어서 복붙 하기

 

# worker-1에서 kubectl 명령을 쳐보면 요청에 제대로 안감

root@worker-1:~# mkdir -p ~/.kube

root@worker-1:~# vi ~/.kube/config

- 여기 내용 전부를 다 복붙 하기

root@worker-1:~# chown $(id -u):$(id -g) $HOME/.kube/config

 

# 아까 마스터에서 복사한 config 파일의 내용을 붙여넣기

1-1.

ECR?

컨테이너 이미지 저장소- httpd:latest 이미지를 기반으로, Apache 웹서버 컨테이너를 쿠버네티스 Pod로 띄우는 것

 

실습 문제의 의도

- worker1 노드에서 apiserver와 연결되었는지 확인하고, 연결되었다면 CLI로 Pod하나를 띄워보라는 의미

 

kubectl run my-httpd --image public.ecr.aws/docker/library/httpd:latest

 

1-2. 드라이런

- kubectl 명령어를 사용해서 --dry-run옵션으로 httpd:latest이미지를 사용하는 Pod매니페스트 파일을 생성하라는 의미

 

--dry-run란?

kubectl에서 실제로 리소스를 생성하지 않고, 매니페스트를 생성해 주는 옵션임

 

-o yaml 형태가 매니페스트 파일 형태임

 

kubectl run my-httpd --image public.ecr.aws/docker/library/httpd:latest --dry-run=client -o yaml > my-httpd.yml

vi my-httpd.yml

 

apiVersion: v1
kind: Pod
metadata:
  name: my-httpd
spec:
  containers:
  - image: public.ecr.aws/docker/library/httpd:latest
    name: my-httpd

 

1-3. pod의 이름 수정

- 간단하게 기존에 만든 Pod 정의 YAML파일에서 metadata.name을 test로 바꾸고, 그걸 적용해서 새로운 Pod를 생성하는 것

 

apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - image: public.ecr.aws/docker/library/httpd:latest
    name: test-con

 

root@worker-1:~# kubectl apply -f my-httpd.yml

- 여기서 위의 명령어를 바로 입력하고 get pod를 해주면 바로 생성되는 걸 확인 할 수 있음

- 그게 바로 쿠버네티스 선언적 방식으로 동작하기 때문에 yaml파일 내용을 읽고 해당 리소스가 없으면 생성하고 있으면 필요한 부분만 수정해서 갱신해 주는 특징이 있음

 

728x90