⭐ 가시다(gasida) 님이 진행하는 KANS(**K**ubernetes **A**dvanced **N**etworking **S**tudy)3기 실습 게시글입니다.
게시글 상 소스코드, 사진에서 ****굵게**** '''코드쉘''' 에 대한 부분이 들어가있을수도 있습니다.
⭐코드에서 실습 시 사용하는 변수가 들어갈 수 있습니다. 아래의 정보를 사용하고있습니다.
#route53 Domain: jjongguet.com
#AWS Secret Key: jjongkey
#Aws .pem Key: jjong-key.pem
Kuberntes?
Kubernetes 구성
Kubernetes 는 Control Plane + Node 로 구성.
컴포넌트 간 통신이 모두 api 서버 를 통해서 통신한다는것에 주목
Control Plane(마스터 노드) 핵심 컴포넌트
: 마스터는 단일 서버 혹은 고가용성을 위한 클러스터 마스터로 구축
- kube-apiserver : 마스터로 전달되는 모든 요청을 받아 드리는 API 서버 - (심화) 링크1 링크2 링크3
- etcd : 클러스터내 모든 메타 정보를 저장하는 서비스
- kube-scheduler : 사용자의 요청에 따라 적절하게 컨테이너를 워커 노드에 배치하는 스케줄러
- kube-controller-manager : 현재 상태와 바라는 상태를 지속적으로 확인하며 특정 이벤트에 따라 특정 동작을 수행하는 컨트롤러 - 링크
- cloud-controller-manager : 클라우드 플랫폼(AWS, GCP, Azure 등)에 특화된 리소스를 제어하는 클라우드 컨트롤러 - 링크
워커 노드
- 링크
- kubelet : 마스터의 명령에 따라 컨테이너의 라이프 사이클을 관리하는 노드 관리자
- kube-proxy : 컨테이너의 네트워킹을 책임지는 프록시, 네트워크 규칙을 유지 관리
- Container Runtime : 실제 컨테이너를 실행하는 컨테이너 실행 환경, (
Docker& containerD & CRI-O)
runC
Kubernetes 는 container-d, CRI-O 를 사용하여 통신할 수 있는데, 모두 runC 라는 로우레벨 명령어로 변환되서 사용됨
Kind
Kind?
kind 는 docker in docker 라는 방식을 발전시켜서 사용하는데.
Kind 는 kind or kubernetes in docker is a suite of tooling for local Kubernetes “clusters” where each “node” is a Docker container 의 약자.
Kind 설치
Docker Desktop 설치 - Link
- 실습 환경 : Kind 사용하는 도커 엔진 리소스에 최소 vCPU 4, Memory 8GB 할당을 권고 - 링크
kind 및 툴 설치
# Install Kind
brew install kind
kind --version
# Install kubectl
brew install kubernetes-cli
kubectl version --client=true
# Install Helm
brew install helm
helm version
# Install Wireshark : 캡처된 패킷 확인
brew install --cask wireshark
kind 로 기본클러스터 배포
# 클러스터 배포 전 확인
docker ps
# Create a cluster with kind
**kind create cluster**
# 클러스터 배포 확인
kind get clusters
kind get nodes
kubectl cluster-info
# 노드 정보 확인
kubectl get node -o wide
# 파드 정보 확인
kubectl get pod -A
kubectl get componentstatuses
# 컨트롤플레인 (컨테이너) 노드 1대가 실행
docker ps
docker images
# kube config 파일 확인
cat ~/.kube/config
혹은
cat $KUBECONFIG # KUBECONFIG 변수 지정 사용 시
# nginx 파드 배포 및 확인 : 컨트롤플레인 노드인데 파드가 배포 될까요?
**kubectl run nginx --image=nginx**:alpine
kubectl get pod -owide
# 노드에 Taints 정보 확인
**kubectl describe node | grep Taints**
Taints: <none>
# 클러스터 삭제
**kind delete cluster**
# kube config 삭제 확인
cat ~/.kube/config
혹은
cat $KUBECONFIG # KUBECONFIG 변수 지정 사용 시
- kind는 kindnet 이라고 부르는 경량CNI가 함께설치된다
Kind 동작원리: Docker in Docker
기본정보 확인하기
# 클러스터 배포 전 확인
docker ps
# kind 는 별도 도커 네트워크 생성 후 사용 : 기본값 172.18.0.0/16
docker network ls
docker inspect kind | jq
# Create a cluster with kind
cat << EOT > kind-2node.yaml
# two node (one workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
EOT
**kind create cluster --config kind-2node.yaml --name myk8s**
# 확인
kind get nodes --name **myk8s**
# k8s api 주소 확인 : 어떻게 로컬에서 접속이 되는 걸까?
kubectl cluster-info
docker ps # 포트 포워딩 정보 확인
docker exec -it myk8s-control-plane ss -tnlp | grep 6443
kubectl get pod -n kube-system -l component=kube-apiserver -owide # 파드 IP 확인
kubectl describe pod -n kube-system -l component=kube-apiserver
docker exec -it myk8s-control-plane curl -k https://localhost:6443/livez ;echo
docker exec -it myk8s-control-plane curl -k https://localhost:6443/readyz ;echo
# 노드 정보 확인 : CRI 는 containerd 사용
kubectl get node -o wide
# 파드 정보 확인 : CNI 는 kindnet 사용
kubectl get pod -A -owide
# 네임스페이스 확인 >> 도커 컨테이너에서 배운 네임스페이스와 다릅니다!
kubectl get namespaces
# 컨트롤플레인, 워커 컨테이너 각각 1대씩 실행 : 도커 컨테이너 이름은 **myk8s**-control-plane , **myk8s**-worker 임을 확인
docker ps
docker images
# 디버그용 내용 출력에 ~/.kube/config 권한 인증 로드
kubectl get pod -v6
# kube config 파일 확인
cat ~/.kube/config
혹은
cat $KUBECONFIG
# local-path 라는 StorageClass 가 설치, local-path 는 노드의 로컬 저장소를 활용함
# 로컬 호스트의 path 를 지정할 필요 없이 local-path provisioner 이 볼륨을 관리
kubectl get sc
kubectl get deploy -n local-path-storage
# 툴 설치
docker exec -it **myk8s-control-plane sh -c '**apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump htop git nano -y'
docker exec -it **myk8s-worker sh -c '**apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump htop git nano -y'
kind 는 docker network 를 172.18.0.0/16 대역을 만들어서 사용하는데, 이는 kind 에서만든 docker 내부의 control-plane, worker-node 가 각각 172.18.0.* 대역을 사용함을 의미한다.
kind 에서 control-plane, worker-node 가 함께있는 yaml파일을 명세하여 배포했더니, Joining Worker node 가 확인 된 모습
현재 사용중인 kubecontext 를 확인했더니 control plane 이 (정확히말하면 kube-apiserver) 포트 52024 를 사용중인걸 확인가능.
원래 K8s 에서는 6443 을 사용, 그러나 kind 에서 배포했기때문에 임의의다른포트(이 경우 52024) 를 6443 에 바인딩(포트포워딩 비슷?) 해서 사용함
- 쿠버네티스 관련 정보 조사
# static pod manifest 위치 찾기
docker exec -it myk8s-control-plane **grep staticPodPath /var/lib/kubelet/config.yaml**
staticPodPath: /etc/kubernetes/manifests
# **static pod** 정보 확인 : kubectl 및 control plane 에서 관리되지 않고 kubelet 을 통해 지정한 컨테이너를 배포
docker exec -it myk8s-**control-plane tree /etc/kubernetes/manifests/**
/etc/kubernetes/manifests/
├── etcd.yaml
├── kube-apiserver.yaml
├── kube-controller-manager.yaml
└── kube-scheduler.yaml
docker exec -it myk8s-**worker tree /etc/kubernetes/manifests/**
...
# 워커 노드(컨테이너) bash 진입
docker exec -it myk8s-**worker bash**
---------------------------------
whoami
# kubelet 상태 확인
systemctl status kubelet
# 컨테이너 확인
docker ps
crictl ps
# kube-proxy 확인
pstree
pstree -p
ps afxuwww |grep proxy
iptables -t **filter** -S
iptables -t **nat** -S
iptables -t **mangle** -S
iptables -t raw -S
iptables -t security -S
# tcp listen 포트 정보 확인
ss -tnlp
# 빠져나오기
exit
---------------------------------
docker 의 배쉬쉘로 진입해서 /var/lib/kubelet 을 직접확인했더니 관련파일이 존재하는 모습확인가능
마찬가지로 /etc/kubernetes/manifests 에 매니페스트 파일이 존재함을 확인가능했음
worker node 에 접근했더니 kubelet 이 system daemon으로 띄워져있음
포트열린거 확인하니 10248,10249,10250 열린거 확인(kubelet 아키텍쳐와 동일)
crictl 명령어는 컨테이너런타임인터페이스에만 해당되는것.
kind는 container runtime 만 존재하기때문에 crictl사용가능. docker 명령어는 사용불가능
파드 생성 및 확인
# 파드 생성
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: **Pod**
metadata:
name: **netpod**
spec:
containers:
- name: netshoot-pod
image: **nicolaka/netshoot**
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: **Pod**
metadata:
name: **nginx**
spec:
containers:
- name: nginx-pod
image: **nginx:alpine**
terminationGracePeriodSeconds: 0
EOF
# 파드 확인
kubectl get pod -owide
# netpod 파드에서 nginx 웹 접속
kubectl exec -it **netpod** -- curl -s $(kubectl get pod nginx -o jsonpath={.status.podIP}) | grep -o "<title>.*</title>"
*<title>Welcome to nginx!</title>*
두개의 노드는 control plane 을 제외한 workernode 에 배포된다
컨트롤플레인 컨테이너 정보 확인 : 아래 “Node” Container 은 ‘myk8s-control-plane’ 컨테이너 (그림에 빨간색) 입니다
해당 “Node” 컨테이너 내부에 쿠버네티스 관련 파드(컨테이너)가 기동되는 구조 → Docker in Docker (DinD)
# 도커 컨테이너 확인
docker ps
docker inspect **myk8s**-control-plane | jq
...
"**Entrypoint**": [
"**/usr/local/bin/entrypoint**",
"**/sbin/init**"
],
...
# 컨트롤플레인 컨테이너 bash 접속 후 확인
docker exec -it **myk8s**-control-plane bash
-------------------------------------------
# CPU 정보 확인
**arch**
***aarch64***
# 기본 사용자 확인
**whoami**
***root***
# 네트워크 정보 확인
ip -br -c -4 addr
ip -c route
cat /etc/resolv.conf
# Entrypoint 정보 확인
cat /usr/local/bin/entrypoint
# 프로세스 확인 : PID 1 은 /sbin/init
**ps -ef**
# 컨테이터 런타임 정보 확인
**systemctl status containerd**
# DinD 컨테이너 확인 : crictl 사용
crictl version
crictl info
crictl ps -o json | jq -r '.containers[] | {NAME: .metadata.name, POD: .labels["io.kubernetes.pod.name"]}'
**crictl ps**
*CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD
ff3d3a53905fd 9d6767b714bf1 12 minutes ago Running **nginx-pod** 0 20328fe63d512 nginx
bebe6b14d1ab3 eead9e442471d 13 minutes ago Running **netshoot-pod** 0 28cd918f0561a netpod
...*
# 파드 이미지 확인
**crictl images**
*IMAGE TAG IMAGE ID SIZE
docker.io/library/nginx alpine 9d6767b714bf1 20.2MB
docker.io/nicolaka/netshoot latest eead9e442471d 178MB
...*
# kubectl 확인
**kubectl get node -v6**
cat /etc/kubernetes/admin.conf
exit
-------------------------------------------
# 도커 컨테이너 확인 : 다시 한번 자신의 호스트PC에서 도커 컨테이너 확인, DinD 컨테이너가 호스트에서 보이는지 확인
docker ps
docker port myk8s-control-plane
# kubectl 확인 : k8s api 호출 주소 확인
**kubectl get node -v6**
컨테이너 내부에서 1번 프로세스가 /sbin/init 이다. (마치 리눅스 비슷하다)
containerd 는 설치되어 crictl 사용가능, docker 는 socket binding이 되어있지않아서 불가능.
runc 로 구동되는 crictl 은 저수준 레벨에서의 사용. containerd로 구동되는 docker 는 고수준레벨에서의 사용.
클러스터 삭제
# 클러스터 삭제
**kind delete cluster --name myk8s**
docker ps
Kind: Multi-Node Cluster (Control-plane, Nodes) with kube-ops-view & Mapping ports
# '컨트롤플레인, 워커 노드 1대' 클러스터 배포 : 파드에 접속하기 위한 포트 맵핑 설정
cat <<EOT> **kind-2node.yaml**
# two node (one workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
**- role: control-plane
- role: worker**
extraPortMappings:
- **containerPort: 31000
hostPort: 31000**
listenAddress: "0.0.0.0" # Optional, defaults to "0.0.0.0"
protocol: tcp # Optional, defaults to tcp
- **containerPort: 31001
hostPort: 31001**
EOT
CLUSTERNAME=myk8s
kind create cluster --config **kind-2node.yaml** --name $CLUSTERNAME
# 배포 확인
kind get clusters
kind get nodes --name $CLUSTERNAME
# 노드 확인
kubectl get nodes -o wide
# 노드에 Taints 정보 확인
**kubectl describe node** $CLUSTERNAME**-control-plane | grep Taints**
Taints: node-role.kubernetes.io/control-plane:NoSchedule
**kubectl describe node** $CLUSTERNAME**-worker | grep Taints**
Taints: <none>
# 컨테이너 확인 : 컨테이너 갯수, 컨테이너 이름 확인
# kind yaml 에 포트 맵핑 정보 처럼, 자신의 PC 호스트에 31000 포트 접속 시, 워커노드(실제로는 컨테이너)에 TCP 31000 포트로 연결
# 즉, 워커노드에 NodePort TCP 31000 설정 시 자신의 PC 호스트에서 접속 가능!
docker ps
**docker port $CLUSTERNAME-worker**
*31000/tcp -> 0.0.0.0:31000
31001/tcp -> 0.0.0.0:31001*
# 컨테이너 내부 정보 확인 : 필요 시 각각의 노드(?)들에 bash로 접속하여 사용 가능
docker exec -it **$CLUSTERNAME-control-plane** ip -br -c -4 addr
docker exec -it **$CLUSTERNAME-worker** ip -br -c -4 addr
노드에서 control-plane, worker node 가 함께 배포되었을때에는 Taint(오염) 이 control plane 에 설정됨 ⇒ 파드를 노드구분없이 배포시킬때에 Taint 되어있는 노드를 제외하고 배포되게하는 설정
kind 를 배포할때에 binding 시켜놓으면, docker network 에서 binding 시켜서 배포한다.
Mapping ports to the host machine - 링크
kube-ops-view : NodePort 31000
https://www.eksworkshop.com/beginner/080_scaling/install_kube_ops_view/
# kube-ops-view
*# helm show values geek-cookbook/kube-ops-view*
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=**NodePort**,service.main.ports.http.nodePort=**31000** --set env.TZ="Asia/Seoul" --namespace kube-system
# 설치 확인
kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view
# kube-ops-view 접속 URL 확인 (1.5 , 2 배율)
echo -e "KUBE-OPS-VIEW URL = http://localhost:31000/#scale=1.5"
echo -e "KUBE-OPS-VIEW URL = http://localhost:31000/#scale=2"
31000 으로 접근하면, kind 내부에서 띄운 8080 을 연결해서 사용한다
kubeopsview 는 내부적으로 8080을 사용함⇒ 이를 외부의 31000에 연결한것 + kind자체가 31000이 연결되어있음
- nginx : NodePort 31001
# 디플로이먼트와 서비스 배포
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: **Deployment**
metadata:
name: **deploy-websrv**
spec:
replicas: 2
selector:
matchLabels:
app: deploy-websrv
template:
metadata:
labels:
app: deploy-websrv
spec:
terminationGracePeriodSeconds: 0
containers:
- name: deploy-websrv
image: **nginx:alpine**
ports:
- containerPort: 80
---
apiVersion: v1
kind: **Service**
metadata:
name: **deploy-websrv**
spec:
ports:
- name: svc-webport
port: 80
targetPort: 80
nodePort: **31001**
selector:
app: deploy-websrv
type: NodePort
EOF
# 확인
**docker ps**
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
117a1145a676 kindest/node:v1.29.2 "/usr/local/bin/entr…" 7 minutes ago Up 7 minutes **0.0.0.0:31000-31001->31000-31001/tcp** **myk8s-worker**
...
**kubectl get deploy,svc,ep deploy-websrv**
...
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/deploy-websrv NodePort 10.96.204.112 <none> 80:**31001**/TCP 55s
...
# 자신의 PC에 호스트 포트 31001 접속 시 쿠버네티스 서비스에 접속 확인
**open http://localhost:31001**
**curl -s localhost:31001 | grep -o "<title>.*</title>"**
<title>Welcome to nginx!</title>
# 디플로이먼트와 서비스 삭제
**kubectl delete deploy,svc deploy-websrv**
- 이렇게 쿠버네티스 파드에 접속 시 NodePort <포트넘버> 고정하고, kind 배포 시 사용할 포트들은 추가하여 사용하시면 됩니다.
- kind 삭제 :
kind delete cluster --name $CLUSTERNAME
'외부활동' 카테고리의 다른 글
[OSSCA] LoxiLB 1주차: yaml, swagger, cmd, api (0) | 2024.09.28 |
---|---|
[KANS3] Pod & Pause container (1) | 2024.09.07 |
[KANS3] 도커 없이 컨테이너 만들기 (5) | 2024.09.01 |
[KANS3] Docker (2) | 2024.09.01 |
[T101] 4기 스터디: OpenTofu (1) | 2024.08.03 |