

!!! 만약 redis 서버가 netstat -nlpt 에서 127.0.0.1:6379로 바인딩 돼있으면 외부통신이 불가하므로/etc/redis.conf 파일에서 bind 0.0.0.0으로 수정하고 restart 해주자
cat <<EOF | tee /etc/hosts
10.10.100.6 ldk-k8s-master
10.10.100.7 ldk-k8s-worker1
10.10.100.11 ldk-k8s-worker2 setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter cat <<EOF | tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF swapoff -a
sed -i '/ swap / s/^/#/' /etc/fstab
sysctl --system Kubernetes Cluster에서 리눅스 컨트롤 그룹(cgroups)을 관리하는 방식에 대해 결정하는 역할
시스템 리소스(예: CPU, 메모리, 디스크 I/O 등)를 제한 및 각 프로세스나 서비스에 할당 방법을 감독하는 기능을 제공
일관된 환경: Kubernetes 클러스터의 각 노드에서 systemd를 사용함으로써 부팅 스크립트, 서비스 관리 및 로깅 시스템 등에서 일관된 환경을 제공 -> 용이한 관리 및 트러블슈팅
보다 나은 통합: systemd는 cgroups를 사용하여 리소스 제한과 프로세스 관리를 수행. Kubernetes는 이러한 기능을 활용하여 컨테이너의 리소스 사용을 제어 및 systemd와의 통합을 통해 강력하고 일관된 방식으로 관리 가능
에러 최소화: 서로 다른 초기화 시스템이나 프로세스 관리자를 사용 시, 설정 차이나 호환성 문제로 인해 예기치 않은 에러가 발생할 수 있는데 systemd를 통일함으로써 호환성 문제를 최소화 가능
systemd (k8s 공식 문서 권장, 필자가 사용한 Cgroup Driver )
시스템 서비스와의 일관성: Kubernetes가 시스템의 다른 서비스와 동일한 cgroup 계층을 사용하게 되어 리소스 관리에서 충돌을 방지 및 전체 시스템의 리소스 할당을 일관되게 관리 가능
보다 나은 자원 제어: cgroup을 더 체계적으로 관리하고, 시스템 리소스를 더 효율적으로 할당 및 모니터링할 수 있는 기능을 제공
보안과 안정성: 보안 업데이트와 시스템 통합이 더 자주 이루어지므로, 보안과 안정성 측면에서 이점을 제공
cgroupfs
간단한 구성과 직접적인 제어
각 cgroup을 파일 시스템으로 직접 제어할 수 있는 인터페이스를 제공하여 관리자가 리소스 관리를 직접적으로 수행할 수 있게 해주며, 복잡한 계층적 구조 없이도 세밀한 리소스 제어가 가능
운영 체제와의 독립성
systemd를 사용하지 않는 리눅스 배포판에서도 일관된 환경을 제공하여 다양한 리눅스 환경에서의 포터빌리티(portability)를 향상시킴
환경의 단순화
특정 시스템에 systemd의 복잡한 설정과 관리 로직이 필요 없을 경우, cgroupfs를 사용하면 시스템 단순화 및 시스템 오버헤드 감소로 더 가벼운 환경을 만드는 데 유리함
PROJECT_PATH=prerelease:/maincat <<EOF | tee /etc/yum.repos.d/cri-o.repo
[cri-o]
name=CRI-O
baseurl=https://pkgs.k8s.io/addons:/cri-o:/$PROJECT_PATH/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/addons:/cri-o:/$PROJECT_PATH/rpm/repodata/repomd.xml.key
EOF
yum install -y container-selinux cri-o iproute-tc
systemctl enable --now crio cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/repodata/repomd.xml.key
exclude=kube*
EOF
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable --now kubelet

kubeadm init --apiserver-advertise-address=10.10.100.6 --pod-network-cidr=10.244.0.0/16

mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl completion bash | tee /etc/bash_completion.d/kubectl > /dev/null
echo 'alias k=kubectl' >>~/.bashrc
echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
exec bash
kubeadm init 하면서 얻은 토큰값으로 워커노드 전체에 kubeadm join
kubeadm join 10.10.100.6:6443 --token jl7n01.taovls0ekgbmrlb8 \
--discovery-token-ca-cert-hash sha256:171e155dd22b904e0827a8e262a54d777e9f4becf0aa24f066e2dcd3575e217c

도커 서버에서 insecure-registry 설정을 해줘도 k8s cluster와 이미지 관련 통신 때
cluster에서는 pod 생성 중 image pulling 과정에서 https 통신을 요청하기에 CRI에 insecure-registry 설정을 주어
k8s와 docker 사이의 통신을 맞춰준다. (https 통신을 원할경우 서로간의 ssl 인증설정이 추가적으로 필요)
cat << EOF|tee /etc/containers/registries.conf.d/crio.conf
unqualified-search-registries = ["docker.io", "quay.io"]
[[registry]]
prefix = ""
location = "10.10.100.8:5000"
insecure = true
EOF
systemctl restart crio
calico
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
flannel ( 필자가 사용한 CNI )
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
etc ...


# 이미지는 내가 보여주고자 하는 내용을 담은 내가 만든 tomcat 9.0 이미지다.
Dev.yaml
apiVersion: v1
kind: Namespace
metadata:
name: dev
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dev-nginx-deployment
namespace: dev
labels:
app: dev-nginx
spec:
replicas: 2
selector:
matchLabels:
app: dev-nginx
template:
metadata:
labels:
app: dev-nginx
spec:
containers:
- name: dev-nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: dev-nginx-conf-volume
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: dev-nginx-conf-volume
configMap:
name: dev-nginx-config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: dev-nginx-config
namespace: dev
data:
nginx.conf: |
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
location / {
proxy_pass http://dev-tomcat-clusterip-service:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
---
apiVersion: v1
kind: Service
metadata:
name: dev-nginx-clusterip-service
namespace: dev
spec:
selector:
app: dev-nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: dev-nginx-nodeport-service
namespace: dev
spec:
type: NodePort
selector:
app: dev-nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30007
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dev-tomcat-deployment
namespace: dev
spec:
replicas: 2
selector:
matchLabels:
app: dev-tomcat
template:
metadata:
labels:
app: dev-tomcat
spec:
containers:
- name: dev-tomcat
image: 10.10.100.8:5000/tomcat-custom:dev
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: dev-tomcat-clusterip-service
namespace: dev
spec:
type: ClusterIP
selector:
app: dev-tomcat
ports:
- protocol: TCP
port: 8080
targetPort: 8080
k get all -n dev -o wide






dev와 비슷한 구조로 namespace와 이미지를 다르게 해서 스테이징 환경 ( stg ), 프로덕션 환경 ( prd )을 배포해준다
stg.yaml
apiVersion: v1
kind: Namespace
metadata:
name: stg
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: stg-nginx-deployment
namespace: stg
labels:
app: stg-nginx
spec:
replicas: 2
selector:
matchLabels:
app: stg-nginx
template:
metadata:
labels:
app: stg-nginx
spec:
containers:
- name: stg-nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: stg-nginx-conf-volume
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: stg-nginx-conf-volume
configMap:
name: stg-nginx-config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: stg-nginx-config
namespace: stg
data:
nginx.conf: |
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
location / {
proxy_pass http://stg-tomcat-clusterip-service:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
---
apiVersion: v1
kind: Service
metadata:
name: stg-nginx-clusterip-service
namespace: stg
spec:
selector:
app: stg-nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: stg-nginx-nodeport-service
namespace: stg
spec:
type: NodePort
selector:
app: stg-nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30008
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: stg-tomcat-deployment
namespace: stg
spec:
replicas: 2
selector:
matchLabels:
app: stg-tomcat
template:
metadata:
labels:
app: stg-tomcat
spec:
containers:
- name: stg-tomcat
image: 10.10.100.8:5000/tomcat-custom:stg
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: stg-tomcat-clusterip-service
namespace: stg
spec:
type: ClusterIP
selector:
app: stg-tomcat
ports:
- protocol: TCP
port: 8080
targetPort: 8080


prd.yaml
apiVersion: v1
kind: Namespace
metadata:
name: prd
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: prd-nginx-deployment
namespace: prd
labels:
app: prd-nginx
spec:
replicas: 2
selector:
matchLabels:
app: prd-nginx
template:
metadata:
labels:
app: prd-nginx
spec:
containers:
- name: prd-nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: prd-nginx-conf-volume
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: prd-nginx-conf-volume
configMap:
name: prd-nginx-config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: prd-nginx-config
namespace: prd
data:
nginx.conf: |
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
location / {
proxy_pass http://prd-tomcat-clusterip-service:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
---
apiVersion: v1
kind: Service
metadata:
name: prd-nginx-clusterip-service
namespace: prd
spec:
selector:
app: prd-nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: stg-nginx-nodeport-service
namespace: stg
spec:
type: NodePort
selector:
app: stg-nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30009
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: prd-tomcat-deployment
namespace: prd
spec:
replicas: 2
selector:
matchLabels:
app: prd-tomcat
template:
metadata:
labels:
app: prd-tomcat
spec:
containers:
- name: prd-tomcat
image: 10.10.100.8:5000/tomcat-custom:prd
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: prd-tomcat-clusterip-service
namespace: prd
spec:
type: ClusterIP
selector:
app: prd-tomcat
ports:
- protocol: TCP
port: 8080
targetPort: 8080


Nginx Ingress Controller 설치
k apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.6.4/deploy/static/provider/cloud/deploy.yaml
이후 Master Node의 IP를 할당해준다.
!!! 공인 IP를 할당받은 VM이기에 가능하므로 로컬에서 연습할 시 metallb를 추가해 진행할 것
k patch svc -n ingress-nginx ingress-nginx-controller -p '{"spec": {"type": "LoadBalancer", "externalIPs":["110.165.18.225"]}}'

각 namespace에 ingress 배포
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx
namespace: dev
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
spec:
ingressClassName: "nginx"
rules:
- http:
paths:
- path: /dev
pathType: Prefix
backend:
service:
name: dev-nginx-clusterip-service
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx
namespace: stg
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
spec:
ingressClassName: "nginx"
rules:
- http:
paths:
- path: /stg
pathType: Prefix
backend:
service:
name: stg-nginx-clusterip-service
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-nginx
namespace: prd
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
spec:
ingressClassName: "nginx"
rules:
- http:
paths:
- path: /prd
pathType: Prefix
backend:
service:
name: prd-nginx-clusterip-service
port:
number: 80



리눅스 컨트롤 그룹(cgroups) 관리 방식 결정
컨테이너 리소스 제한 및 모니터링 기능 제공
systemd의 특징:
journal을 사용한 통합 로깅 시스템cgroupfs의 특징:
systemd vs cgroupfs:
컨테이너 런타임과 오케스트레이션 시스템 연결 표준 인터페이스
컨테이너 생성, 시작, 정지, 삭제 API 제공
CRI-O 특징:
containerd 특징:
CRI-O vs containerd 차이:
Kubernetes의 컨테이너 간 네트워킹 설정을 위한 Plugin Interface
네트워크 연결과 IP 주소 할당 등을 관리
Calico의 특징:
Cilium의 특징:
Flannel의 특징:
CNI들의 차이점:
쿠버네티스에서 외부 요청을 내부 서비스로 연결
규칙 기반 라우팅 제공
NGINX Ingress Controller 특징:
ALB Ingress Controller 특징:
차이점:
flannel 설치 에러
error validating data: failed to download openapi: Get "https://10.10.100.6:6443/openapi/v2?timeout=32s": tls: failed to verify certificate: x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "kubernetes"); if you choose to ignore these errors, turn validation off with --validate=false
보통 기존 kubeadm reset 이후 $HOME/.kube를 삭제하지 않아서 생기는 오류
막연하게 덮어쓰기 식으로 복붙 명령문 실행이 아닌
rm -rf $HOME/.kube
라는 명령어를 통해 삭제 후 진행해보자