서두
운영 중인 네트워크 대역을 변경하는 일은 매우 높은 위험을 동반하기에 권장하지 않으며, 공식 문서 또한 노드 정보 변경 시 재등록을 권장합니다.
노드 이름 고유성 섹션에서 언급했듯이, 노드 구성을 업데이트해야 하는 경우 API 서버에 노드를 다시 등록하는 것이 좋다. 예를 들어 kubelet이 --node-labels 의 새로운 구성으로 다시 시작되더라도, 동일한 노드 이름이 사용된 경우 레이블이 해당 노드의 등록에 설정되기 때문에 변경 사항이 적용되지 않는다. (공식 문서 발췌)
( 공식 사이트에서 발췌한 내용을 기반으로 작성하였으나, 일부는 경험을 토대로 정리했습니다. 정확하지 않을 수 있음을 알려드립니다. )
공식 사이트
광고 클릭은 큰 힘이 됩니다!
노드
쿠버네티스는 컨테이너를 파드내에 배치하고 노드 에서 실행함으로 워크로드를 구동한다. 노드는 클러스터에 따라 가상 또는 물리적 머신일 수 있다. 각 노드는 컨트롤 플레인에 의해 관리되며
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
중요
잘못된 정보나, 문의 등은 댓글로 메일과 함께 남겨주시면 감사하겠습니다.
'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 |