RHEL 계열로 만든 클러스터에 Ubuntu 워커를 붙이는 것은 가능하다. Kubernetes 는 노드의 배포판을 가리지 않는다. 노드가 맞춰야 하는 것은 배포판이 아니라 kubelet 버전 · 컨테이너 런타임 · CNI · 커널 설정 이다.
kubelet 버전은 컨트롤 플레인과 같은 마이너 버전으로 맞춘다. kubelet 은 kube-apiserver 보다 최대 세 마이너 버전까지 낮을 수 있지만, 운영에서는 같은 버전으로 통일하는 편이 문제를 줄인다.
컨테이너 런타임은 같은 종류로 맞춘다. 한쪽이 containerd, 다른 쪽이 CRI-O 여도 동작은 하지만 로그 위치 · 이미지 저장 경로 · 설정 파일이 달라져 운영 부담만 커진다. cgroup 드라이버는 반드시 systemd 로 통일한다. 노드마다 다르면 자원 제한이 제대로 걸리지 않는다.
CNI 플러그인이 해당 커널과 배포판을 지원하는지 확인한다. Calico · Flannel · Cilium 모두 두 계열을 지원하지만, Cilium 은 eBPF 기능에 따라 요구 커널 버전이 다르다.
커널 파라미터와 모듈은 배포판과 무관하게 같은 값이어야 한다.
modprobe overlay && modprobe br_netfilter
cat > /etc/sysctl.d/99-kubernetes.conf <<'SYSCTL'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
SYSCTL
sysctl --system
swapoff -a
Ubuntu 노드에 런타임과 kubeadm 을 설치한 뒤 기존 클러스터의 조인 명령을 실행한다. 토큰이 만료됐다면 컨트롤 플레인에서 다시 만든다.
kubeadm token create --print-join-command
kubeadm join 192.0.2.10:6443 --token <토큰> \
--discovery-token-ca-cert-hash sha256:<해시>
붙은 뒤 확인한다.
kubectl get nodes -o wide
kubectl get nodes -o custom-columns=NAME:.metadata.name,OS:.status.nodeInfo.osImage,KUBELET:.status.nodeInfo.kubeletVersion,RUNTIME:.status.nodeInfo.containerRuntimeVersion
패키지 관리가 갈린다. RHEL 은 dnf, Ubuntu 는 apt 이므로 버전 고정 · 보안 패치 · 커널 업그레이드 절차를 두 벌 유지해야 한다.
방화벽과 보안 모듈이 다르다. RHEL 은 firewalld 와 SELinux, Ubuntu 는 ufw 와 AppArmor 를 쓴다. 파드가 특정 노드에서만 실패한다면 대개 이쪽이다.
로그와 경로가 다르다. 장애 대응 문서를 하나로 쓰기 어려워진다.
이런 이유로 배포판을 섞을 때는 라벨을 붙여 워크로드를 구분할 수 있게 해 둔다.
kubectl label node ubuntu-worker-01 node.example.com/os-family=ubuntu
spec:
nodeSelector:
node.example.com/os-family: ubuntu
kubernetes.io/os 는 linux · windows 만 들어가므로 배포판 구분에는 쓸 수 없다. 사용자 정의 라벨을 만든다.