!!! 만약 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
라는 명령어를 통해 삭제 후 진행해보자