고가용성 Kubernetes 1.16.0 클러스터 배포 및 관리

이 문서는 단순하고 안정적인 Kubernetes 고가용성 클러스터 설치 도구인 SealOS를 활용하여 Kubernetes 1.16.0 버전을 배포하는 방법에 대해 다룹니다. SealOS는 최소한의 의존성으로 유연하고 확장 가능한 Kubernetes 환경을 구축할 수 있도록 설계되었습니다.

SealOS는 다음과 같은 핵심 원칙과 장점을 기반으로 개발되었습니다:

  • 오프라인 설치 지원: 도구와 리소스 패키지(바이너리, 설정 파일, 이미지, YAML 등)가 분리되어 있어, 다양한 버전의 Kubernetes를 오프라인으로 쉽게 설치할 수 있습니다.
  • 인증서 유효 기간 연장: 기본 Kubernetes 인증서의 유효 기간을 자동으로 연장하여 관리 편의성을 높입니다.
  • 사용 편의성: 복잡한 절차 없이 간결한 명령어로 클러스터를 구축하고 관리할 수 있습니다.
  • 사용자 정의 설정: 필요에 따라 Kubernetes 구성을 유연하게 조정할 수 있습니다.
  • 커널 기반 로드 밸런싱: 높은 안정성을 제공하며, 문제 발생 시 진단이 용이합니다.

기존 방식과 SealOS의 차별점

Ansible를 사용하지 않는 이유

초기 버전의 SealOS는 Ansible을 활용했지만, 사용자가 Ansible과 Python 및 관련 의존성을 별도로 설치해야 하는 불편함이 있었습니다. 또한, SSH 키 없이 사용자 이름과 비밀번호를 사용할 경우 ssh-pass와 같은 추가 도구가 필요해 설치 과정이 복잡해지는 문제가 있었습니다. SealOS는 이러한 의존성을 제거하고 단일 바이너리 형태로 제공되어, 어떤 추가 설치 없이 원격 명령 실행 및 파일 배포를 SDK를 통해 처리합니다. 이는 "극단적인 단순성"이라는 SealOS의 철학을 충족시키기 위함입니다.

Keepalived 및 HAProxy를 사용하지 않는 이유

HAProxy는 Static Pod으로 실행할 경우 관리가 용이하지만, Keepalived는 대부분의 오픈 소스 스크립트에서 yum 또는 apt와 같은 시스템 패키지 관리자를 통해 설치됩니다. 이 방식은 다음과 같은 문제점을 야기할 수 있습니다:

  • 패키지 저장소의 불일치로 인한 버전 차이는 설정 파일마저 다르게 만들어 문제 해결을 어렵게 합니다.
  • 특정 환경에서는 시스템 의존성 문제로 설치 자체가 실패할 수 있습니다.
  • 많은 스크립트가 단순히 HAProxy 프로세스 존재 여부만 확인하지만, 실제로는 APIServer의 /healthz 상태를 확인해야 진정한 고가용성을 보장할 수 있습니다.
  • 시스템 systemd로 관리되는 구성 요소는 Prometheus와 같은 모니터링 시스템에 통합하기 어렵고, 재시작 등 관리가 복잡합니다. Static Pod으로 관리하는 것이 더 일관적입니다.
  • 과거에 Keepalived가 CPU 사용률을 급증시켜 클러스터 안정성을 해친 사례도 있었습니다.

이러한 문제들을 해결하기 위해 SealOS는 Keepalived를 컨테이너화하여 사용합니다. 그러나 더 단순하고 안정적인 대안을 모색한 결과, 로컬 커널 기반 로드 밸런싱 방식을 채택하게 되었습니다.

Envoy 또는 Nginx 대신 로컬 커널 로드 밸런싱(IPVS)을 사용하는 이유

각 노드에 Envoy나 Nginx와 같은 프록시를 실행하면 추가적인 자원을 소모합니다. SealOS는 커널 레벨의 IPVS(IP Virtual Server)를 사용하여 로컬 로드 밸런싱을 구현합니다. IPVS는 lvscare라는 Static Pod에 의해 관리되며, kube-proxy와 유사하게 규칙을 관리하지만 실제 트래픽 처리는 안정적인 커널에서 이루어지므로 사용자 공간으로 패킷이 이동하는 오버헤드가 없습니다.

또한, Envoy와 같은 사용자 공간 로드 밸런서를 사용할 경우, 노드가 클러스터에 합류(join)하기 전에 로드 밸런서가 먼저 설정되어야 하는 상호 의존성 문제가 발생할 수 있습니다. 이는 Static Pod으로 관리하기 어렵게 만들며, 논리적 데드락으로 이어질 수 있습니다. 반면 IPVS는 노드가 클러스터에 합류하기 전에 IPVS 규칙을 미리 설정할 수 있어 이러한 문제를 피할 수 있습니다. APIServer에 장애가 발생하면 해당 IPVS 규칙이 자동으로 정리되고, APIServer가 복구되면 다시 추가됩니다.

Kubeadm을 사용자 정의하는 이유

SealOS는 Kubeadm을 최소한으로 수정하여 사용합니다:

  • 인증서 유효 기간 연장: Kubeadm의 기본 인증서 유효 기간을 99년으로 늘려 재갱신 부담을 줄였습니다.
  • 로컬 로드 밸런싱 통합: 노드 합류 시 IPVS 규칙 생성 및 lvscare Static Pod 생성을 Kubeadm 내부 로직에 통합하여, 외부 도구에 대한 의존성 없이 클러스터 설정이 가능하도록 만들었습니다. 이 과정에서 Kubeadm의 SDK를 활용하여 깔끔하게 구현되었습니다.

이러한 사용자 정의를 통해 핵심 기능이 Kubeadm에 내장되어 SealOS는 패키지 배포 및 상위 명령어 실행을 담당하는 경량 도구로 기능합니다. 노드 추가와 같은 작업도 Kubeadm을 직접 활용할 수 있게 됩니다.

SealOS 사용 가이드

필수 요구 사항

  • Docker 설치 및 실행
  • Kubernetes 오프라인 설치 패키지 다운로드
  • 최신 SealOS 바이너리 다운로드
  • Kubernetes 1.14.0 이상 버전 지원
  • 모든 서버의 시간 동기화 필수

클러스터 설치

다중 마스터(HA) 클러스터 구성:

sealos init --master 192.168.10.10 \
    --master 192.168.10.11 \
    --master 192.168.10.12 \
    --node 192.168.10.20 \
    --user root \
    --passwd 'your-secure-password' \
    --version v1.16.0 \
    --pkg-url /opt/k8s-offline/kube-1.16.0.tar.gz

단일 마스터 다중 노드 클러스터 구성:

sealos init --master 192.168.10.10 \
    --node 192.168.10.20 \
    --user root \
    --passwd 'your-secure-password' \
    --version v1.16.0 \
    --pkg-url /opt/k8s-offline/kube-1.16.0.tar.gz

SSH 키(비밀번호 없이)를 사용하여 설치하는 경우:

sealos init --master 172.16.10.10 \
    --node 172.16.10.20 \
    --pkg-url https://your-http-server.com/kube-1.16.0.tar.gz \
    --pk /root/.ssh/id_rsa \
    --version v1.16.0

주요 명령어 옵션:

  • --master: 마스터 서버 IP 주소 목록
  • --node: 워커 노드 서버 IP 주소 목록
  • --user: SSH 접속 사용자 이름
  • --passwd: SSH 접속 비밀번호
  • --pkg-url: 오프라인 패키지 경로 (로컬 경로 또는 HTTP 서버 URL)
  • --version: Kubernetes 버전
  • --pk: SSH 프라이빗 키 파일 경로 (기본값: /root/.ssh/id_rsa)

기타 옵션:

  • --kubeadm-config string: 사용자 정의 Kubeadm 설정 YAML 파일 경로
  • --vip string: 가상 IP 주소 (기본값: "10.103.97.2"). 클러스터 외부에서 접근 불가. 변경은 권장하지 않습니다.

설치 검증

클러스터가 정상적으로 설치되었는지 확인합니다:

[root@k8s-master-01 ~]# kubectl get node
NAME            STATUS   ROLES    AGE     VERSION
k8s-master-01   Ready    master   5m      v1.16.0
k8s-master-02   Ready    master   4m      v1.16.0
k8s-master-03   Ready    master   3m      v1.16.0
k8s-node-01     Ready    <none>   2m      v1.16.0

[root@k8s-master-01 ~]# kubectl get pod --all-namespaces
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-67b7f6c8d7-5p2q7   1/1     Running   0          5m
kube-system   calico-node-b8c7r                          1/1     Running   0          4m
kube-system   calico-node-d5s9x                          1/1     Running   0          5m
kube-system   calico-node-h2k1f                          1/1     Running   0          5m
kube-system   calico-node-l3x0z                          1/1     Running   0          4m
kube-system   coredns-7c6d7d6f5f-f7g8p                   1/1     Running   0          5m
kube-system   coredns-7c6d7d6f5f-z4x5q                   1/1     Running   0          5m
kube-system   etcd-k8s-master-01                         1/1     Running   0          5m
kube-system   etcd-k8s-master-02                         1/1     Running   0          4m
kube-system   etcd-k8s-master-03                         1/1     Running   0          3m
kube-system   kube-apiserver-k8s-master-01               1/1     Running   0          5m
kube-system   kube-apiserver-k8s-master-02               1/1     Running   0          4m
kube-system   kube-apiserver-k8s-master-03               1/1     Running   1          3m
kube-system   kube-controller-manager-k8s-master-01      1/1     Running   1          5m
kube-system   kube-controller-manager-k8s-master-02      1/1     Running   0          4m
kube-system   kube-controller-manager-k8s-master-03      1/1     Running   0          3m
kube-system   kube-proxy-8x7y6                           1/1     Running   0          4m
kube-system   kube-proxy-d4e5f                           1/1     Running   0          5m
kube-system   kube-proxy-g1h2i                           1/1     Running   0          3m
kube-system   kube-proxy-j3k4l                           1/1     Running   0          4m
kube-system   kube-scheduler-k8s-master-01               1/1     Running   1          5m
kube-system   kube-scheduler-k8s-master-02               1/1     Running   0          4m
kube-system   kube-scheduler-k8s-master-03               1/1     Running   0          3m
kube-system   kube-sealos-lvscare-k8s-node-01            1/1     Running   0          2m

클러스터 정리

클러스터를 제거하려면 sealos clean 명령어를 사용합니다:

sealos clean \
    --master 192.168.10.10 \
    --master 192.168.10.11 \
    --master 192.168.10.12 \
    --node 192.168.10.20 \
    --user root \
    --passwd 'your-secure-password'

노드 추가

기존 클러스터에 워커 노드를 추가하는 방법은 두 가지가 있습니다.

1. Kubeadm Join 명령 사용 (마스터 노드에서 Join Command 생성):

마스터 노드에서 다음 명령어를 실행하여 kubeadm join 명령을 생성합니다:

kubeadm token create --print-join-command

생성된 명령어를 노드에 맞게 수정하여 사용합니다. 특히, SealOS에 의해 커스터마이징된 kubeadm--master 파라미터를 추가로 지원합니다:

# /etc/hosts 파일에 가상 IP 주소와 APIServer 도메인 추가 (모든 노드에서 수행)
echo "10.103.97.2 apiserver.cluster.local" >> /etc/hosts

# 노드에서 kubeadm join 명령어 실행
kubeadm join 10.103.97.2:6443 --token abcdef.1234567890abcdef \
    --master 10.103.97.10:6443 \
    --master 10.103.97.11:6443 \
    --master 10.103.97.12:6443 \
    --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866

2. SealOS Join 명령어 사용:

SealOS는 노드 추가를 위한 전용 join 명령어를 제공합니다:

sealos join \
    --master 192.168.10.10 \
    --master 192.168.10.11 \
    --master 192.168.10.12 \
    --vip 10.103.97.2 \
    --node 192.168.10.21 \
    --user root \
    --passwd 'your-secure-password' \
    --pkg-url /opt/k8s-offline/kube-1.16.0.tar.gz

사용자 정의 Kubeadm 설정

예를 들어, APIServer 인증서에 추가 SAN(Subject Alternative Name)을 포함시키고자 할 때 Kubeadm 설정 파일을 사용자 정의할 수 있습니다. 먼저 템플릿을 생성합니다:

sealos config -t kubeadm >>  custom-kubeadm-config.yaml.tmpl

custom-kubeadm-config.yaml.tmpl 파일을 열어 certSANs 섹션에 mycompany.com을 추가합니다. 다른 부분은 SealOS가 자동으로 채워주므로 변경하지 않는 것이 좋습니다:

apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: {{.Version}}
controlPlaneEndpoint: "apiserver.cluster.local:6443"
networking:
  podSubnet: 100.64.0.0/10
apiServer:
  certSANs:
    - mycompany.com # 추가된 SAN
    - 127.0.0.1
    - apiserver.cluster.local
    {{range .Masters -}}
    - {{.}}
    {{end -}}
    - {{.VIP}}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
  excludeCIDRs:
    - "{{.VIP}}/32"

이제 sealos init 명령어 실행 시 --kubeadm-config 옵션으로 사용자 정의 파일을 지정합니다:

sealos init --kubeadm-config custom-kubeadm-config.yaml.tmpl \
    --master 192.168.10.10 \
    --master 192.168.10.11 \
    --master 192.168.10.12 \
    --node 192.168.10.20 \
    --user root \
    --passwd 'your-secure-password' \
    --version v1.16.0 \
    --pkg-url /opt/k8s-offline/kube-1.16.0.tar.gz

클러스터 버전 업그레이드

이 가이드에서는 Kubernetes 1.15.0에서 1.16.0으로의 업그레이드를 예시로 설명합니다. 다른 버전의 경우에도 원리는 유사하며, 공식 문서를 참고할 수 있습니다.

업그레이드 절차:

  1. 모든 노드에 새로운 버전의 Kubeadm, Kubectl, Kubelet 바이너리 및 컨테이너 이미지를 배포합니다.
  2. 첫 번째 마스터 노드를 업그레이드합니다.
  3. 첫 번째 마스터 노드의 Kubelet을 업그레이드합니다.
  4. 다른 마스터 노드들을 순차적으로 업그레이드합니다.
  5. 워커 노드들을 순차적으로 업그레이드합니다.
  6. 클러스터 상태를 검증합니다.

1. Kubeadm 및 이미지 업그레이드:

새로운 오프라인 패키지를 모든 노드에 복사한 후, 해당 패키지 내의 스크립트를 실행하여 Kubeadm, Kubectl, Kubelet 바이너리를 업데이트하고, 새로운 버전의 컨테이너 이미지를 임포트합니다:

# 예시: 패키지 내 쉘 스크립트 실행
cd /opt/k8s-offline/kube-1.16.0/shell && sh init.sh

2. 첫 번째 마스터 노드 업그레이드:

첫 번째 마스터 노드에서 업그레이드 계획을 확인하고 적용합니다:

kubeadm upgrade plan
kubeadm upgrade apply v1.16.0

Kubelet 서비스를 재시작합니다:

systemctl restart kubelet

Kubelet 바이너리 업그레이드는 새 버전의 Kubelet 바이너리를 /usr/bin 경로에 복사하고 Kubelet 서비스를 재시작하는 방식으로 이루어집니다. Kubelet 바이너리는 일반적으로 오프라인 패키지의 conf/bin 디렉토리에 위치합니다.

3. 다른 마스터 노드 업그레이드:

첫 번째 마스터 노드를 제외한 다른 마스터 노드에서 다음 명령어를 실행합니다:

kubeadm upgrade apply

4. 워커 노드 업그레이드:

각 워커 노드에 대해 다음 단계를 수행합니다:

  • 노드 드레인 (선택 사항, 워크로드 중단을 피하려면):

    kubectl drain <NODE_NAME> --ignore-daemonsets
    
  • Kubelet 설정 업데이트:

    kubeadm upgrade node config --kubelet-version v1.16.0
    
  • Kubelet 바이너리 교체 및 서비스 재시작 (마스터 노드와 동일):

    # 새 Kubelet 바이너리 복사 (예시)
    # cp /opt/k8s-offline/kube-1.16.0/bin/kubelet /usr/bin/kubelet
    systemctl restart kubelet
    
  • 노드 복원:

    kubectl uncordon <NODE_NAME>
    

5. 클러스터 상태 검증:

모든 노드의 버전이 올바르게 업그레이드되었는지 확인합니다:

kubectl get nodes

버전 정보가 일치한다면 업그레이드가 성공적으로 완료된 것입니다.

kubeadm upgrade apply가 수행하는 주요 작업:

  • 클러스터 업그레이드 가능 여부 확인
  • 업그레이드 정책 및 호환성 검사
  • 필수 컨테이너 이미지 확인
  • 컨트롤 플레인 구성 요소(APIServer, Controller Manager, Scheduler 등) 업그레이드 및 실패 시 롤백
  • Kube-DNS 및 Kube-Proxy 업그레이드
  • 새 인증서 생성 및 기존 인증서 백업 (유효 기간이 180일을 초과하는 경우)

소스 코드 컴파일

SealOS는 netlink 라이브러리를 사용하므로, 컨테이너 환경에서 컴파일하는 것을 권장합니다:

docker run --rm -v $(pwd):/app -w /app golang:1.16 go build -o sealos main.go

go mod vendor를 사용하여 벤더링된 의존성으로 컴파일하는 경우:

go build -mod vendor

내부 작동 원리

실행 흐름

SealOS의 클러스터 설치 과정은 다음과 같이 진행됩니다:

  • SFTP 또는 wget을 통해 오프라인 설치 패키지를 모든 대상 머신(마스터 및 노드)으로 전송합니다.
  • 첫 번째 마스터 노드에서 kubeadm init을 실행하여 클러스터 초기화를 수행합니다.
  • 다른 마스터 노드에서는 kubeadm join 명령을 실행하여 컨트롤 플레인에 합류합니다. 이 과정에서 다른 마스터 노드에 Etcd가 시작되어 첫 번째 마스터의 Etcd와 클러스터를 구성하며, 컨트롤 플레인 구성 요소(APIServer, Controller Manager 등)도 함께 시작됩니다.
  • 워커 노드는 클러스터에 합류하며, 이 과정에서 IPVS 규칙 및 /etc/hosts 파일 구성이 이루어집니다. 중요한 점은 APIServer 접근이 모두 도메인 이름을 통해 이루어진다는 것입니다. 마스터 노드는 자체 APIServer에 직접 연결하고, 워커 노드는 가상 IP를 통해 여러 마스터에 연결해야 합니다. Kubelet 및 Kube-Proxy가 APIServer에 접근하는 주소는 노드마다 다를 수 있으며, Kubeadm 설정 파일에서는 단일 주소만 지정할 수 있으므로, 각 노드에서 이 도메인 이름이 다르게 해석되도록 설정합니다. 도메인 이름을 사용하는 이점은 IP 주소 변경 시 DNS 레코드만 수정하면 된다는 점입니다.

로컬 커널 로드 밸런싱

각 노드는 로컬 커널 로드 밸런서를 통해 마스터 노드들을 안정적으로 접근할 수 있도록 구성됩니다:

  +--------------+                       +---------------+  가상 서버: 127.0.0.1:6443
  | 마스터 노드 0 |<----------------------| IPVS 워커 노드 |    실제 서버:
  +--------------+                      |+---------------+            10.103.97.200:6443
                                        |                             10.103.97.201:6443
  +--------------+                      |                             10.103.97.202:6443
  | 마스터 노드 1 |<---------------------+
  +--------------+                      |
                                        |
  +--------------+                      |
  | 마스터 노드 2 |<---------------------+
  +--------------+

각 워커 노드에서는 lvscare라는 Static Pod이 실행되어 이 IPVS 로드 밸런싱 규칙을 감시하고 관리합니다. APIServer에 장애가 발생하면 lvscare가 모든 워커 노드의 해당 IPVS 규칙을 자동으로 정리하고, APIServer가 정상 복구되면 다시 규칙을 추가합니다.

결과적으로 워커 노드에는 세 가지 핵심 요소가 추가됩니다:

  • /etc/kubernetes/manifests: lvscare Static Pod 매니페스트 파일이 추가됩니다.
  • ipvsadm -Ln: 생성된 IPVS 규칙을 확인할 수 있습니다.
  • /etc/hosts: 가상 IP 주소에 대한 호스트 이름(apiserver.cluster.local) 해석 엔트리가 추가됩니다.

Kubeadm 사용자 정의 상세

Kubeadm에 대한 수정은 최소한이며, 주로 인증서 유효 기간 연장과 join 명령어 확장에 초점을 맞춥니다. join 명령어에 대한 주요 변경 사항은 다음과 같습니다:

join 명령어에 마스터 주소 목록을 지정하는 --master 파라미터가 추가되었습니다:

flagSet.StringSliceVar(
    &locallb.LVScare.Masters, "master", []string{},
    "A list of ha masters, --master 192.168.0.2:6443  --master 192.168.0.3:6443  --master 192.168.0.4:6443",
)

이 파라미터를 통해 마스터 주소 목록을 받아 IPVS 설정에 활용합니다.

컨트롤 플레인 노드가 아니면서 단일 마스터 클러스터가 아닌 경우, IPVS 규칙을 생성합니다 (컨트롤 플레인 노드는 자체 APIServer에 직접 연결하므로 IPVS 규칙이 필요 없습니다):

if data.cfg.ControlPlane == nil { // 컨트롤 플레인 노드가 아닌 경우
    fmt.Println("This is not a control plane node.")
    if len(locallb.LVScare.Masters) != 0 {
        locallb.CreateLocalLB(args[0]) // 로컬 로드 밸런서 생성
    }
}

이후 lvscare Static Pod을 생성하여 IPVS 규칙을 관리합니다:

if len(locallb.LVScare.Masters) != 0 {
    locallb.LVScareStaticPodToDisk("/etc/kubernetes/manifests") // lvscare Static Pod 생성
}

따라서 SealOS를 사용하지 않더라도, 사용자 정의된 Kubeadm을 직접 사용하여 클러스터를 설치할 수 있습니다 (다소 번거롭지만).

Kubeadm 직접 설치 예시 (SealOS 없이)

Kubeadm 설정 파일 (예: custom-cluster-config.yaml):

apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: v1.16.0
controlPlaneEndpoint: "apiserver.cluster.local:6443" # APIServer DNS 이름
apiServer:
  certSANs:
    - 127.0.0.1
    - apiserver.cluster.local
    - 172.20.241.205 # 모든 마스터 IP 포함
    - 172.20.241.206
    - 172.20.241.207
    - 172.20.241.208
    - 10.103.97.1 # 가상 IP (VIP)
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
  excludeCIDRs:
    - "10.103.97.1/32" # 중요: Kube-Proxy가 이 규칙을 삭제하지 않도록 제외

마스터 노드 0 (예: 10.103.97.100) 설정:

# APIServer 도메인을 마스터 0의 IP로 해석하도록 /etc/hosts 설정
echo "10.103.97.100 apiserver.cluster.local" >> /etc/hosts

# Kubeadm 초기화
kubeadm init --config=custom-cluster-config.yaml --upload-certs

# Kubeconfig 설정
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

# CNI (Calico) 설치
kubectl apply -f https://docs.projectcalico.org/v3.15/manifests/calico.yaml

마스터 노드 1 (예: 10.103.97.101) 설정:

# APIServer 도메인을 마스터 0의 IP로 해석하여 클러스터에 합류 (초기 연결을 위해)
echo "10.103.97.100 apiserver.cluster.local" >> /etc/hosts

# 컨트롤 플레인으로 Kubeadm 합류 (kubeadm token create 명령으로 얻은 토큰과 해시 사용)
# `--certificate-key`는 `--upload-certs` 실행 시 생성되는 키.
kubeadm join 10.103.97.100:6443 --token abcdef.1234567890abcdef \
    --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 \
    --control-plane \
    --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07

# 클러스터 합류 후, APIServer 도메인 해석을 마스터 1 자체 IP로 변경하여 master0에 대한 의존성 제거
sed -i "s/10.103.97.100/10.103.97.101/g" /etc/hosts

마스터 노드 2 (예: 10.103.97.102) 설정 (마스터 노드 1과 동일):

echo "10.103.97.100 apiserver.cluster.local" >> /etc/hosts

kubeadm join 10.103.97.100:6443 --token abcdef.1234567890abcdef \
    --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866 \
    --control-plane \
    --certificate-key f8902e114ef118304e561c3ecd4d0b543adc226b7a07f675f56564185ffe0c07

sed -i "s/10.103.97.100/10.103.97.102/g" /etc/hosts

워커 노드 설정:

# APIServer 도메인을 가상 IP (VIP)로 해석하도록 /etc/hosts 설정
echo "10.103.97.1 apiserver.cluster.local" >> /etc/hosts

# Kubeadm을 사용하여 워커 노드 합류
# `--master` 플래그로 마스터 IP 목록 지정 (사용자 정의 Kubeadm에 추가된 기능)
kubeadm join 10.103.97.1:6443 --token abcdef.1234567890abcdef \
    --master 10.103.97.100:6443 \
    --master 10.103.97.101:6443 \
    --master 10.103.97.102:6443 \
    --discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866

오프라인 패키지 구조 분석

SealOS의 오프라인 패키지는 다음과 같은 구조를 가집니다:

.
├── bin         # 특정 Kubernetes 버전의 바이너리 파일 (kubeadm, kubectl, kubelet)
│   ├── kubeadm
│   ├── kubectl
│   └── kubelet
├── conf        # 설정 파일 및 YAML 매니페스트
│   ├── 10-kubeadm.conf       # (최신 버전에서 사용되지 않음, 스크립트에서 동적 생성)
│   ├── dashboard             # Kubernetes Dashboard 관련 YAML
│   │   ├── dashboard-admin.yaml
│   │   └── kubernetes-dashboard.yaml
│   ├── heapster              # Heapster (레거시 모니터링) 관련 YAML
│   │   ├── grafana.yaml
│   │   ├── heapster.yaml
│   │   ├── influxdb.yaml
│   │   └── rbac
│   │       └── heapster-rbac.yaml
│   ├── kubeadm.yaml          # Kubeadm 초기화 설정 파일
│   ├── kubelet.service       # Kubelet systemd 서비스 파일
│   ├── net                   # CNI (Calico) 관련 YAML
│   │   └── calico.yaml
│   └── prometheus            # Prometheus (모니터링) 관련 YAML (예시)
├── images      # 모든 컨테이너 이미지 파일 (tar 형식)
│   └── images.tar
└── shell       # 설치 및 초기화 쉘 스크립트
    ├── init.sh   # 초기화 스크립트 (바이너리 복사, systemd 설정, 이미지 로드 등)
    └── master.sh # 마스터 노드 초기화 스크립트 (kubeadm init 실행)

init.sh 스크립트는 바이너리 파일을 $PATH로 복사하고, systemd 설정을 구성하며, swap 비활성화 및 방화벽 설정 등을 처리한 후 클러스터에 필요한 이미지를 로드합니다. master.sh는 주로 kubeadm init 명령을 실행합니다. conf 디렉토리에는 Kubeadm 설정, Calico YAML 파일 등 클러스터 구성에 필요한 파일들이 포함되어 있습니다. SealOS는 이 두 스크립트를 적절히 호출하여 클러스터를 구축합니다. 이처럼 모듈화된 구조 덕분에 다양한 Kubernetes 버전에 대한 호환성을 쉽게 관리할 수 있습니다.

태그: kubernetes high availability kubeadm SealOS IPVS

6월 6일 21:38에 게시됨