Kubernetes Internal Network 변경 절차

2025. 9. 24. 18:15·Kubernetes
728x90

서두

운영 중인 네트워크 대역을 변경하는 일은 매우 높은 위험을 동반하기에 권장하지 않으며, 공식 문서 또한 노드 정보 변경 시 재등록을 권장합니다.

노드 이름 고유성 섹션에서 언급했듯이, 노드 구성을 업데이트해야 하는 경우 API 서버에 노드를 다시 등록하는 것이 좋다. 예를 들어 kubelet이 --node-labels 의 새로운 구성으로 다시 시작되더라도, 동일한 노드 이름이 사용된 경우 레이블이 해당 노드의 등록에 설정되기 때문에 변경 사항이 적용되지 않는다. (공식 문서 발췌)

 

( 공식 사이트에서 발췌한 내용을 기반으로 작성하였으나, 일부는 경험을 토대로 정리했습니다. 정확하지 않을 수 있음을 알려드립니다. )


공식 사이트

광고 클릭은 큰 힘이 됩니다!

728x90

 

 

노드

쿠버네티스는 컨테이너를 파드내에 배치하고 노드 에서 실행함으로 워크로드를 구동한다. 노드는 클러스터에 따라 가상 또는 물리적 머신일 수 있다. 각 노드는 컨트롤 플레인에 의해 관리되며

kubernetes.io

 


필요

  • 통신 가능한 새 네트워크 인터페이스
다른 대역은 문제가 되지 않으나 초반 ETCD를 롤링하는 과정에서 대역끼리 통신이 되어야한다.
즉 다른 대역이라도 통신이 되는 이전 인터페이스가 통신이 상태를 유지하고, 새로운 인터페이스 또한 노드간 통신이 되어야 한다. 

현재환경(예시)

OLD 대역: 192.168.0.0/24 → NEW 대역: 172.0.0.0/24 

Client Version: v1.23.10
Server Version: v1.23.10

etcdctl version: 3.5.4
API version: 3.5

NAME    STATUS   ROLES                  AGE   VERSION    INTERNAL-IP     EXTERNAL-IP   OS-IMAGE                                      KERNEL-VERSION           CONTAINER-RUNTIME
node-1  Ready    control-plane,master   42d   v1.23.10   192.168.0.10    <none>        Red Hat Enterprise Linux Server 7.9 (Maipo)   3.10.0-1160.el7.x86_64   containerd://1.6.8
node-2  Ready    control-plane,master   42d   v1.23.10   192.168.0.11    <none>        Red Hat Enterprise Linux Server 7.9 (Maipo)   3.10.0-1160.el7.x86_64   containerd://1.6.8
node-3  Ready    control-plane,master   42d   v1.23.10   192.168.0.12    <none>        Red Hat Enterprise Linux Server 7.9 (Maipo)   3.10.0-1160.el7.x86_64   containerd://1.6.8
node-4  Ready    <none>                 42d   v1.23.10   192.168.0.13    <none>        Red Hat Enterprise Linux Server 7.9 (Maipo)   3.10.0-1160.el7.x86_64   containerd://1.6.8
node-5  Ready    <none>                 42d   v1.23.10   192.168.0.14    <none>        Red Hat Enterprise Linux Server 7.9 (Maipo)   3.10.0-1160.el7.x86_64   containerd://1.6.8

본 문서는 구버전 예시이지만, kubernetes 1.30~1.31에서도 절차적 차이는 거의 없습니다.
사견이지만 정말 오래된 버전 아니고서야 비슷한 프로세스를 통해 변경 가능할 듯 합니다.

 

1) 백업

# ETCD 환경변수 지정
export ETCDCTL_API=3
export CACERT=/etc/kubernetes/pki/etcd/ca.crt
export CERT=/etc/kubernetes/pki/etcd/healthcheck-client.crt
export KEY=/etc/kubernetes/pki/etcd/healthcheck-client.key
export EP="https://127.0.0.1:2379"

# 백업 파일명(날짜만)
export SNAP=/tmp/backup/etcd-$(date +%Y%m%d).db

# 백업 디렉토리
mkdir -p /tmp/backup

# 스냅샷 및 스냅샷 확인
etcdctl --endpoints="${EP}" --cacert="${CACERT}" --cert="${CERT}" --key="${KEY}" endpoint health
etcdctl --endpoints="${EP}" --cacert="${CACERT}" --cert="${CERT}" --key="${KEY}" snapshot save "${SNAP}"
etcdctl --write-out=table snapshot status "${SNAP}"

하나만 백업해도 충분하지만, 원하면 각 마스터에서 별도로 받아도 됩니다.

 


2) kubeadm Configuration 추출 및 SAN 수정

kubectl -n kube-system get cm kubeadm-config \
  -o jsonpath='{.data.ClusterConfiguration}' | sed 's/\\n/\n/g' > ~/cluster-config.yaml

# 실제 Kubernetes 서비스 IP 확인 후 SAN에 반영
kubectl get svc kubernetes -o jsonpath='{.spec.clusterIP}'; echo

 

~/cluster-config.yaml (일부, certSANs 가 없다면 apiServer: 아래에 수기로 추가)

apiServer:
  certSANs:
  - kubernetes
  - kubernetes.default
  - kubernetes.default.svc
  - kubernetes.default.svc.cluster.local
  - <CLUSTER_IP>      # 예: 10.96.0.1 (반드시 실제 값으로 치환)
  - localhost
  - 127.0.0.1
  - ::1
  # VIP/DNS가 있으면 여기에 추가
  # OLD 마스터
  - 192.168.0.10
  - 192.168.0.11
  - 192.168.0.12
  # NEW 마스터
  - 172.0.0.10
  - 172.0.0.11
  - 172.0.0.12

3) kube-apiserver 인증서 재발급

# 백업
cp -a /etc/kubernetes/pki/apiserver.crt /etc/kubernetes/pki/apiserver.crt.bak || true
cp -a /etc/kubernetes/pki/apiserver.key /etc/kubernetes/pki/apiserver.key.bak || true
rm -f /etc/kubernetes/pki/apiserver.crt /etc/kubernetes/pki/apiserver.key

# 재발급
kubeadm init phase certs apiserver --config ~/cluster-config.yaml

# SAN 확인
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text | grep -A1 "Subject Alternative Name"

# kubelet 재시작
systemctl restart kubelet

 


4) kube-apiserver 매니페스트 수정(예시)

kube-api-server.yaml은 각 환경마다 설정이 다를 수 있습니다.
클러스터 환경에 맞춰 IP 수정을 진행하시면 됩니다.

 

위치: /etc/kubernetes/manifests/kube-apiserver.yaml

apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 172.0.0.11:6443 # NEW-IP
spec:
  containers:
  - name: kube-apiserver
    command:
    - kube-apiserver
    - --advertise-address=172.0.0.11 # NEW-IP
    - --etcd-servers=https://172.0.0.10:2379,https://172.0.0.11:2379,https://172.0.0.12:2379 # NEW-IP
    livenessProbe:
      failureThreshold: 8
      httpGet:
        host: 127.0.0.1 # Loopback으로 수정
        path: /livez
        port: 6443
        scheme: HTTPS
      initialDelaySeconds: 10
      periodSeconds: 10
      timeoutSeconds: 15
    name: kube-apiserver
    readinessProbe:
      failureThreshold: 3
      httpGet:
        host: 127.0.0.1 # Loopback으로 수정
        path: /readyz
        port: 6443
        scheme: HTTPS
      periodSeconds: 1
      timeoutSeconds: 15
    resources:
      requests:
        cpu: 250m
    startupProbe:
      failureThreshold: 24
      httpGet:
        host: 127.0.0.1 # Loopback으로 수정
        path: /livez
        port: 6443
        scheme: HTTPS
      initialDelaySeconds: 10
      periodSeconds: 10
      timeoutSeconds: 15
#상태 확인

curl -k https://127.0.0.1:6443/readyz?verbose

[+]ping ok
[+]log ok
[+]etcd ok
[+]informer-sync ok
[+]poststarthook/start-kube-apiserver-admission-initializer ok
[+]poststarthook/generic-apiserver-start-informers ok
[+]poststarthook/priority-and-fairness-config-consumer ok
[+]poststarthook/priority-and-fairness-filter ok
[+]poststarthook/start-apiextensions-informers ok
[+]poststarthook/start-apiextensions-controllers ok
[+]poststarthook/crd-informer-synced ok
[+]poststarthook/bootstrap-controller ok
[+]poststarthook/rbac/bootstrap-roles ok
[+]poststarthook/scheduling/bootstrap-system-priority-classes ok
[+]poststarthook/priority-and-fairness-config-producer ok
[+]poststarthook/start-cluster-authentication-info-controller ok
[+]poststarthook/aggregator-reload-proxy-client-cert ok
[+]poststarthook/start-kube-aggregator-informers ok
[+]poststarthook/apiservice-registration-controller ok
[+]poststarthook/apiservice-status-available-controller ok
[+]poststarthook/kube-apiserver-autoregistration ok
[+]autoregister-completion ok
[+]poststarthook/apiservice-openapi-controller ok
[+]shutdown ok
readyz check passed

5) etcd 인증서 재발급 

하기 작업은 모든 컨트롤러에서 순차적으로 진행합니다.

5-1) 백업

mkdir -p /tmp/backup/etcd-node-1
cp -a /etc/kubernetes/pki/etcd/server.crt /tmp/backup/etcd-node-1/server.crt.bak
cp -a /etc/kubernetes/pki/etcd/server.key /tmp/backup/etcd-node-1/server.key.bak
cp -a /etc/kubernetes/pki/etcd/peer.crt   /tmp/backup/etcd-node-1/peer.crt.bak
cp -a /etc/kubernetes/pki/etcd/peer.key   /tmp/backup/etcd-node-1/peer.key.bak

5-2) 새 인증서용 파일 생성 (node-1 예시)

cat > ~/etcd-server-ext-node-1.cnf <<'EOF'
[ req ]
prompt = no
distinguished_name = dn
req_extensions = ext
[ dn ]
CN = node-1 # 클러스터 상황에 맞게 설정
[ ext ]
extendedKeyUsage = serverAuth,clientAuth
subjectAltName = @alt
[ alt ]
DNS.1 = node-1 # 클러스터 상황에 맞게 설정
DNS.2 = localhost
IP.1  = 127.0.0.1
IP.2  = 192.168.0.10   # node-1 OLD-IP
IP.3  = 172.0.0.10     # node-1 NEW-IP
EOF


cat > ~/etcd-peer-ext-node-1.cnf <<'EOF'
[ req ]
prompt = no
distinguished_name = dn
req_extensions = ext
[ dn ]
CN = node-1 # 클러스터 상황에 맞게 설정
[ ext ]
extendedKeyUsage = serverAuth,clientAuth
subjectAltName = @alt
[ alt ]
DNS.1 = node-1 # 클러스터 상황에 맞게 설정
DNS.2 = localhost
IP.1  = 127.0.0.1
IP.2  = 192.168.0.10   # node-1 OLD-IP
IP.3  = 172.0.0.10     # node-1 NEW-IP
EOF

5-3) 인증서 재발급

# server cert
openssl req -new -nodes -newkey rsa:2048 \
  -keyout /etc/kubernetes/pki/etcd/server.key \
  -out    ~/server-node-1.csr -config ~/etcd-server-ext-node-1.cnf

openssl x509 -req -in ~/server-node-1.csr \
  -CA /etc/kubernetes/pki/etcd/ca.crt -CAkey /etc/kubernetes/pki/etcd/ca.key -CAcreateserial \
  -out /etc/kubernetes/pki/etcd/server.crt -days 36500 \
  -extensions ext -extfile ~/etcd-server-ext-node-1.cnf

# peer cert
openssl req -new -nodes -newkey rsa:2048 \
  -keyout /etc/kubernetes/pki/etcd/peer.key \
  -out    ~/peer-node-1.csr -config ~/etcd-peer-ext-node-1.cnf

openssl x509 -req -in ~/peer-node-1.csr \
  -CA /etc/kubernetes/pki/etcd/ca.crt -CAkey /etc/kubernetes/pki/etcd/ca.key -CAcreateserial \
  -out /etc/kubernetes/pki/etcd/peer.crt -days 36500 \
  -extensions ext -extfile ~/etcd-peer-ext-node-1.cnf

# 권한
chown etcd:etcd /etc/kubernetes/pki/etcd/server.key /etc/kubernetes/pki/etcd/peer.key
chmod 600       /etc/kubernetes/pki/etcd/server.key /etc/kubernetes/pki/etcd/peer.key

5-4) SAN 확인

openssl x509 -in /etc/kubernetes/pki/etcd/server.crt -noout -text | egrep -A2 'Subject:|Extended Key Usage|Subject Alternative Name'
openssl x509 -in /etc/kubernetes/pki/etcd/peer.crt   -noout -text | egrep -A2 'Subject:|Extended Key Usage|Subject Alternative Name'

5-5) /etc/etcd/etcd.conf (node-1 예시)

ETCD_NAME=node-1
ETCD_INITIAL_CLUSTER_STATE=existing
ETCD_INITIAL_ADVERTISE_PEER_URLS=https://172.0.0.10:2380
ETCD_LISTEN_PEER_URLS=https://0.0.0.0:2380
ETCD_ADVERTISE_CLIENT_URLS=https://172.0.0.10:2379
ETCD_LISTEN_CLIENT_URLS=https://0.0.0.0:2379

ETCD_INITIAL_CLUSTER=node-1=https://172.0.0.10:2380,node-2=https://172.0.0.11:2380,node-3=https://172.0.0.12:2380

ETCD_TRUSTED_CA_FILE=/etc/kubernetes/pki/etcd/ca.crt
ETCD_CERT_FILE=/etc/kubernetes/pki/etcd/server.crt
ETCD_KEY_FILE=/etc/kubernetes/pki/etcd/server.key
ETCD_PEER_TRUSTED_CA_FILE=/etc/kubernetes/pki/etcd/ca.crt
ETCD_PEER_CERT_FILE=/etc/kubernetes/pki/etcd/peer.crt
ETCD_PEER_KEY_FILE=/etc/kubernetes/pki/etcd/peer.key

5-6) etcd 재시작

systemctl daemon-reload && systemctl restart etcd

5-7) etcd 확인

# 상태/리더
etcdctl --endpoints=https://172.0.0.10:2379,https://172.0.0.11:2379,https://172.0.0.12:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
  --key=/etc/kubernetes/pki/etcd/healthcheck-client.key \
  endpoint status -w table

+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|         ENDPOINT         |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://172.0.0.10:2379  | ac33e3f6e2023cfe |   3.5.4 |   24 MB |      true |      false |      3393 |   12757790 |           12757790 |        |
| https://172.0.0.11:2379  | 39f35f0a38dd96d3 |   3.5.4 |   24 MB |     false |      false |      3393 |   12757791 |           12757791 |        |
| https://172.0.0.12:2379  | 4ac8d40e48d1cd0a |   3.5.4 |   24 MB |     false |      false |      3393 |   12757791 |           12757791 |        |
+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

# 멤버(피어 URL)
etcdctl --endpoints=https://172.0.0.10:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
  --key=/etc/kubernetes/pki/etcd/healthcheck-client.key \
  member list -w table
  
  +------------------+---------+--------+----------------------------+----------------------------+------------+
|        ID        | STATUS  |  NAME  |         PEER ADDRS         |        CLIENT ADDRS        | IS LEARNER |
+------------------+---------+--------+----------------------------+----------------------------+------------+
| 39f35f0a38dd96d3 | started | node-2 | https://172.0.0.11:2380    | https://172.0.0.11:2379    |     false  |
| 4ac8d40e48d1cd0a | started | node-3 | https://172.0.0.12:2380    | https://172.0.0.12:2379    |     false  |
| ac33e3f6e2023cfe | started | node-1 | https://172.0.0.10:2380    | https://172.0.0.10:2379    |     false  |
+------------------+---------+--------+----------------------------+----------------------------+------------+
peer URL이 OLD-IP 로 보이면 ID별로 NEW-IP로 업데이트
# 예시: node-2의 ID가 39f35f0a38dd96d3 이라면 → 172.0.0.11:2380

etcdctl --endpoints=https://172.0.0.10:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
  --key=/etc/kubernetes/pki/etcd/healthcheck-client.key \
  member update 39f35f0a38dd96d3 https://172.0.0.11:2380

 


6) kubeconfig 수정

kubectl config set-cluster "$(kubectl config current-context | awk -F/ '{print $1}')" \
  --server=https://172.0.0.10:6443

7) 워커 노드 롤링 (node-4, node-5 예시)

하기 작업은 모든 워커에서 순차적으로 진행합니다.
워커노드 /etc/kubernetes/kubelet.conf 및 kubelet 기동시 flag등이 저장된 파일은 각 클러스터마다 구성이 다릅니다.

현 문서에선 /etc/sysconfig/kubelet에 존재하는 kubelet 파일을 통해 KUBELET_EXTRA_ARGS를 사용하고 있습니다.

본인 워커노드 kubelet  프로세스를 확인한 뒤 진행이 필요합니다.
# 노드 스케줄 중지 및 파드 제거
kubectl drain node-4 --ignore-daemonsets --delete-emptydir-data
# API 서버 주소 전환
sed -i 's#server: https://.*:6443#server: https://172.0.0.10:6443#' /etc/kubernetes/kubelet.conf

# 이 환경은 /etc/sysconfig/kubelet 사용(예: --node-ip 고정)
# node-4의 새 IP가 172.0.0.13 인 경우:
sed -i 's/--node-ip=[0-9\.]\+/--node-ip=172.0.0.13/' /etc/sysconfig/kubelet

systemctl daemon-reload && systemctl restart kubelet

# CSR 승인(있을 때만)
kubectl get csr --no-headers | awk '$2{print $1}' | xargs -r kubectl certificate approve

# 스케줄 재개 및 확인
kubectl uncordon node-4
kubectl get node node-4 -o wide

8) Calico IP autodetection 패치

이전 네트워크 인터페이스를 제거 한 뒤 calico-node 데몬셋을 재시작 해도 되지만,
아래 옵션을 추가하여 새로운 인터페이스를 바라보게 합니다.
# kubectl edit ds -n kube-system calico-node
spec:
  template:
    spec:
      containers:
      - name: calico-node
        env:
        - name: IP_AUTODETECTION_METHOD
          value: #새롭게 추가된 인터페이스
kubectl -n kube-system patch ds calico-node --type merge --patch-file calico-node-ip-autodetect-patch.yaml

9) 최종 점검

# 변경된 정보 확인
kubectl get nodes -o wide
kubectl -n kube-system get pods -o wide

# apiserver 헬스
kubectl get --raw='/readyz?verbose'

# etcd 헬스
etcdctl --endpoints=https://172.0.0.10:2379,https://172.0.0.11:2379,https://172.0.0.12:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
  --key=/etc/kubernetes/pki/etcd/healthcheck-client.key \
  endpoint status -w table

 


중요

잘못된 정보나, 문의 등은 댓글로 메일과 함께 남겨주시면 감사하겠습니다.

728x90
저작자표시 비영리 (새창열림)

'Kubernetes' 카테고리의 다른 글

Kubernetes Calico CNI와 스케줄링 실패 관계  (0) 2025.11.06
MinIO 공식 Docker 이미지 배포 중단 사태  (0) 2025.10.29
[Calico] calico-node Routing 경로 불일치로 인한 pod to pod 통신 실패  (0) 2025.09.19
Istio Mesh Network 그리고 Timeout  (0) 2025.09.02
Kubernetes Node Name - 불변(Immutable)  (2) 2025.08.04
'Kubernetes' 카테고리의 다른 글
  • Kubernetes Calico CNI와 스케줄링 실패 관계
  • MinIO 공식 Docker 이미지 배포 중단 사태
  • [Calico] calico-node Routing 경로 불일치로 인한 pod to pod 통신 실패
  • Istio Mesh Network 그리고 Timeout
MAGUJOB
MAGUJOB
Officially Kubestronaut 사파스러운 블로그 느립니다.
  • MAGUJOB
    마구잡
    MAGUJOB
  • 전체
    오늘
    어제
    • 분류 전체보기 (65) N
      • Kubernetes (54) N
        • Kubernetes 버전별 변경 이력 (8)
        • 작은팁-짧은글 (11) N
      • 운영체제 (1)
      • 오픈스택 (1)
      • 책 후기 (2)
      • 운동 (1)
        • 헬스 (0)
        • 클라이밍 (1)
      • 기타팁 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 링크드인
  • 공지사항

  • 인기 글

  • 태그

    POD
    AI
    1.35
    Calico
    virt-manager
    업데이트
    CKS
    k8s
    버전
    클라우드
    GPU
    kube-ai
    피카푸글램핑
    IT
    피카푸클램핑도봉산
    쿠버네티스기초
    캠핑
    gatewayAPI
    파드
    쿠버네티스
    kubernetes
    오블완
    쿠버네티스 생명주기
    피카푸캠핑도봉산
    v1.35
    글램핑
    KVM
    티스토리챌린지
    ingressnginx
    CKA
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
MAGUJOB
Kubernetes Internal Network 변경 절차
상단으로

티스토리툴바