리소스가 제한적인 환경에서 2대의 머신(192.168.0.193, 192.168.0.191)을 사용하여 Kubernetes 클러스터를 설치하는 방법을 설명합니다. 일반적으로 안정적인 클러스터 리더 선출을 위해서는 3대 이상의 홀수 노드가 권장됩니다. 아래 단계는 모든 노드에 적용됩니다.
1. 사전 환경 설정
중요 확인 사항
- CPU 코어 ≥ 2, 메모리 ≥ 2GB: k8s가 정상 작동하기 위한 최소 요구 사항입니다.
- 로컬 네트워크와 통신 가능한 DNS를 설정하십시오. 그렇지 않으면 이미지 다운로드가 실패할 수 있습니다.
- 버전 호환성: Docker 19는 Kubernetes 1.19.x, Docker 20은 Kubernetes 1.20.x와 호환됩니다. Kubernetes 1.21.1 이후 기본 컨테이너 런타임은 Docker가 아닌 Containerd입니다.
- 본 가이드는 Docker v20.10.8, Kubernetes v1.20.5, Go v1.13.15를 사용합니다.
1.1 호스트 이름 설정
[root@localhost ~]# hostnamectl set-hostname kmaster --static
[root@localhost ~]# hostnamectl set-hostname kworker1 --static
[root@localhost ~]# hostnamectl set-hostname kworker2 --static
1.2 고정 IP 구성
[root@localhost ~]# vi /etc/sysconfig/network-scripts/ifcfg-enp0s3
BOOTPROTO="static"
ONBOOT="yes"
IPADDR=192.168.3.10
GATEWAY=192.168.3.1
NETMASK=255.255.255.0
DNS1=114.114.114.114
DNS2=8.8.8.8
[root@localhost ~] reboot
1.3 IP-호스트 매핑
vi /etc/hosts
192.168.3.10 kmaster
192.168.3.11 kworker1
192.168.3.12 kworker2
1.4 필수 패키지 설치
yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wget vim net-tools git iproute lrzsz bash-completion tree bridge-utils unzip bind-utils gcc
1.5 방화벽 및 iptables 설정
systemctl stop firewalld && systemctl disable firewalld
yum -y install iptables-services && systemctl start iptables && systemctl enable iptables && iptables -F && service iptables save
1.6 SELinux 및 스왑 비활성화
swapoff -a && sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
setenforce 0 && sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
2. 커널 매개변수 및 시스템 설정
2.1 커널 매개변수 조정
cat > kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
net.ipv4.tcp_tw_recycle=0
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_instances=8192
fs.inotify.max_user_watches=1048576
fs.file-max=52706963
fs.nr_open=52706963
net.ipv6.conf.all.disable_ipv6=1
net.netfilter.nf_conntrack_max=2310720
EOF
cp kubernetes.conf /etc/sysctl.d/kubernetes.conf
sysctl -p /etc/sysctl.d/kubernetes.conf
</code>
2.2 시간대 설정
timedatectl set-timezone "Asia/Shanghai"
timedatectl set-local-rtc 0
systemctl restart rsyslog
systemctl restart crond
2.3 불필요 서비스 중지
systemctl stop postfix && systemctl disable postfix
2.4 로깅 설정
mkdir /var/log/journal
mkdir /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/99-prophet.conf <<EOF
[Journal]
Storage=persistent
Compress=yes
SyncIntervalSec=5m
RateLimitInterval=30s
RateLimitBurst=1000
SystemMaxUse=10G
SystemMaxFileSize=200M
MaxRetentionSec=2week
ForwardToSyslog=no
EOF
systemctl restart systemd-journald
echo "* soft nofile 65536" >> /etc/security/limits.conf
echo "* hard nofile 65536" >> /etc/security/limits.conf
2.5 IPVS 모듈 설정
modprobe br_netfilter
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4
</code>
3. Docker 설치
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum update -y && yum install docker-ce
mkdir /etc/docker
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://cr.console.aliyun.com/",
"https://reg-mirror.qiniu.com"
],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
systemctl daemon-reload && systemctl restart docker && systemctl enable docker
</code>
4. kubeadm, kubelet, kubectl 설치
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
EOF
yum install -y kubelet-1.20.5 kubeadm-1.20.5 kubectl-1.20.5 --disableexcludes=kubernetes
systemctl enable kubelet && systemctl start kubelet
5. 마스터 노드 초기화
5.1 기본 설정 파일 생성
kubeadm config print init-defaults > kubeadm-init.yaml
kubeadm-init.yaml 파일에서 다음 두 항목을 수정합니다:
advertiseAddress: 1.2.3.4를 마스터 노드의 실제 IP (예: 192.168.3.191)로 변경합니다.imageRepository: k8s.gcr.io를imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers로 변경합니다.
최종 파일 예시는 다음과 같습니다:
apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.3.191
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: kmaster
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/master
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: v1.20.1
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
podSubnet: 10.244.0.0/16
scheduler: {}
5.2 이미지 Pull 및 클러스터 초기화
kubeadm config images pull --config kubeadm-init.yaml
kubeadm init --config kubeadm-init.yaml
초기화가 완료되면 다음과 유사한 출력이 나타납니다. 이 토큰을 워커 노드 연결에 사용합니다.
kubeadm join 192.168.3.10:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:13aff926...
5.3 kubectl 설정
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
6. 네트워크 플러그인 설치 (Calico)
curl https://docs.projectcalico.org/v3.20/manifests/calico.yaml -O
calico.yaml 파일을 편집하여 IP 자동 감지 설정을 추가합니다:
- name: CLUSTER_TYPE
value: "k8s,bgp"
- name: IP_AUTODETECTION_METHOD
value: "interface=en.*"
- name: IP
value: "autodetect"
- name: CALICO_IPV4POOL_IPIP
value: "Never"
kubectl apply -f calico.yaml
잠시 후 마스터 노드의 상태가 Ready로 변경됩니다:
[root@kmaster ~]$ kubectl get node
NAME STATUS ROLES AGE VERSION
kmaster Ready control-plane,master 48m v1.20.5
7. 워커 노드 추가
각 워커 노드에서 마스터 초기화 시 출력된 kubeadm join 명령어를 실행합니다.
kubeadm join 192.168.3.10:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:37eb59b...
8. 클러스터 상태 확인
[root@kmaster ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
kmaster Ready control-plane,master 26m v1.20.5
kworker1 Ready <none> 5m v1.20.5
kworker2 Ready <none> 4m v1.20.5
[root@kmaster ~]# kubectl get pod -n kube-system -o wide
모든 kube-system 네임스페이스의 파드가 Running 상태인지 확인합니다.
Kubernetes Dashboard 설치 (선택 사항)
대시보드 배포 파일 다운로드 및 수정
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml
recommended.yaml 파일에서 kubernetes-dashboard 서비스의 스펙을 편집하여 type: NodePort와 nodePort: 30443을 추가합니다.
kubectl apply -f recommended.yaml
관리자 사용자 생성
cat > dashboard-admin.yaml << EOF
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: admin
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: admin
namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
EOF
kubectl apply -f dashboard-admin.yaml
로그인 토큰 확인
kubectl -n kube-system get secret | grep admin-token
kubectl -n kube-system describe secret admin-token-w94tz
# 또는 JSONPath를 이용하여 직접 추출
kubectl -n kube-system get secret admin-token-w94tz -o jsonpath={.data.token} | base64 -d
획득한 토큰을 사용하여 브라우저에서 https://{노드_IP}:30443 주소로 접속합니다.
대시보드 접속 시 인증서 오류 해결 (선택 사항, 크롬 브라우저)
openssl genrsa -out dashboard.key 2048
openssl req -new -out dashboard.csr -key dashboard.key -subj '/CN={Master_IP}'
openssl x509 -req -in dashboard.csr -signkey dashboard.key -out dashboard.crt
kubectl delete secret kubernetes-dashboard-certs -n kubernetes-dashboard
kubectl create secret generic kubernetes-dashboard-certs --from-file=dashboard.key --from-file=dashboard.crt -n kubernetes-dashboard
kubectl get pod -n kubernetes-dashboard | grep -v NAME | awk '{print "kubectl delete po " $1 " -n kubernetes-dashboard"}' | sh