클러스터에 대한 네트워킹 설정 방법에 대해 배운다.
파드의 /etc/hosts 파일에 항목을 추가하는 것은 DNS나 다른 방법들이 적용되지 않을 때 파드 수준의 호스트네임 해석을 제공한다. PodSpec의 HostAliases 항목을 사용하여 이러한 사용자 정의 항목들을 추가할 수 있다.
HostAliases를 사용하지 않은 수정은 권장하지 않는데, 이는 호스트 파일이 kubelet에 의해 관리되고, 파드 생성/재시작 중에 덮어쓰여질 수 있기 때문이다.
파드 IP가 할당된 Nginx 파드를 시작한다.
kubectl run nginx --image nginx
pod/nginx created
파드 IP를 확인해보자.
kubectl get pods --output=wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
호스트 파일의 내용은 아래와 같을 것이다.
kubectl exec nginx -- cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.200.0.4 nginx
기본적으로, hosts 파일은 localhost와 자기 자신의 호스트네임과 같은 IPv4와 IPv6
상용구들만 포함하고 있다.
기본 상용구 이외에, 추가 항목들을 hosts 파일에
추가할 수 있다.
예를 들어, foo.local, bar.local이 127.0.0.1로,
foo.remote, bar.remote가 10.1.2.3로 해석될 수 있도록, .spec.hostAliases 항목에서 정의하여 파드에
HostAliases를 추가하면 가능하다.
apiVersion: v1
kind: Pod
metadata:
name: hostaliases-pod
spec:
restartPolicy: Never
hostAliases:
- ip: "127.0.0.1"
hostnames:
- "foo.local"
- "bar.local"
- ip: "10.1.2.3"
hostnames:
- "foo.remote"
- "bar.remote"
containers:
- name: cat-hosts
image: busybox:1.28
command:
- cat
args:
- "/etc/hosts"
다음을 실행하여 해당 구성으로 파드를 실행할 수 있다.
kubectl apply -f https://k8s.io/examples/service/networking/hostaliases-pod.yaml
pod/hostaliases-pod created
파드의 세부 정보를 검토하여 IPv4 주소와 상태를 확인해보자.
kubectl get pod --output=wide
NAME READY STATUS RESTARTS AGE IP NODE
hostaliases-pod 0/1 Completed 0 6s 10.200.0.5 worker0
hosts 파일 내용은 아래와 같다.
kubectl logs hostaliases-pod
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.200.0.5 hostaliases-pod
# Entries added by HostAliases.
127.0.0.1 foo.local bar.local
10.1.2.3 foo.remote bar.remote
가장 마지막에 추가 항목들이 정의되어 있는 것을 확인할 수 있다.
컨테이너가 이미 시작되고 난 뒤에
컨테이너 런타임이 hosts 파일을 수정하는 것을 방지하기 위해,
Kubelet이 파드의 각 컨테이너의 hosts 파일을 관리한다.
역사적으로, 쿠버네티스는 컨테이너 런타임으로 계속 도커 엔진을 사용해 왔으며,
각 컨테이너가 시작된 뒤에 도커 엔진이 /etc/hosts 파일을 수정할 수 있었다.
현재 쿠버네티스는 다양한 컨테이너 런타임을 사용할 수 있으며,
kubelet이 각 컨테이너 내의 hosts 파일을 관리하므로
어떤 컨테이너 런타임을 사용하는지에 상관없이 동일한 결과를 얻을 수 있다.
컨테이너 내부의 호스트 파일을 수동으로 변경하면 안된다.
호스트 파일을 수동으로 변경하면, 컨테이너가 종료되면 변경 사항이 손실된다.
이 문서는 IPv4/IPv6 이중 스택이 활성화된 쿠버네티스 클러스터들을 어떻게 검증하는지 설명한다.
버전 확인을 위해서, 다음 커맨드를 실행 kubectl version.
각각의 이중 스택 노드는 단일 IPv4 블록 및 단일 IPv6 블록을 할당받아야 한다. IPv4/IPv6 파드 주소 범위를 다음 커맨드를 실행하여 검증한다. 샘플 노드 이름을 클러스터 내 검증된 이중 스택 노드로 대체한다. 본 예제에서, 노드 이름은 k8s-linuxpool1-34450317-0 이다.
kubectl get nodes k8s-linuxpool1-34450317-0 -o go-template --template='{{range .spec.podCIDRs}}{{printf "%s\n" .}}{{end}}'
10.244.1.0/24
2001:db8::/64
단일 IPv4 블록과 단일 IPv6 블록이 할당되어야 한다.
노드가 IPv4 및 IPv6 인터페이스를 가지고 있는지 검증한다. 노드 이름을 클러스터의 검증된 노드로 대체한다. 본 예제에서 노드 이름은 k8s-linuxpool1-34450317-0 이다.
kubectl get nodes k8s-linuxpool1-34450317-0 -o go-template --template='{{range .status.addresses}}{{printf "%s: %s\n" .type .address}}{{end}}'
Hostname: k8s-linuxpool1-34450317-0
InternalIP: 10.0.0.5
InternalIP: 2001:db8:10::5
파드가 IPv4 및 IPv6 주소를 할당받았는지 검증한다. 파드 이름을 클러스터에서 검증된 파드로 대체한다. 본 예제에서 파드 이름은 pod01 이다.
kubectl get pods pod01 -o go-template --template='{{range .status.podIPs}}{{printf "%s\n" .ip}}{{end}}'
10.244.1.4
2001:db8::4
status.podIPs fieldPath를 통한 다운워드(downward) API로 파드 IP들을 검증할 수도 있다. 다음 스니펫은 컨테이너 내 MY_POD_IPS 라는 환경 변수를 통해 파드 IP들을 어떻게 노출시킬 수 있는지 보여준다.
env:
- name: MY_POD_IPS
valueFrom:
fieldRef:
fieldPath: status.podIPs
다음 커맨드는 컨테이너 내 MY_POD_IPS 환경 변수의 값을 출력한다. 해당 값은 파드의 IPv4 및 IPv6 주소를 나타내는 쉼표로 구분된 목록이다.
kubectl exec -it pod01 -- set | grep MY_POD_IPS
MY_POD_IPS=10.244.1.4,2001:db8::4
파드의 IP 주소는 또한 컨테이너 내 /etc/hosts 에 적힐 것이다. 다음 커맨드는 이중 스택 파드의 /etc/hosts 에 cat을 실행시킨다. 출력 값을 통해 파드의 IPv4 및 IPv6 주소 모두 검증할 수 있다.
kubectl exec -it pod01 -- cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.244.1.4 pod01
2001:db8::4 pod01
.spec.ipFamilyPolicy 를 명시적으로 정의하지 않은 다음의 서비스를 생성한다. 쿠버네티스는 처음 구성된 service-cluster-ip-range 에서 서비스에 대한 클러스터 IP를 할당하고 .spec.ipFamilyPolicy 를 SingleStack 으로 설정한다.
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app.kubernetes.io/name: MyApp
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
kubectl 을 사용하여 서비스의 YAML을 확인한다.
kubectl get svc my-service -o yaml
이 서비스에서 .spec.ipFamilyPolicy 를 SingleStack 으로 설정하고 .spec.clusterIP 를 kube-controller-manager의 --service-cluster-ip-range 플래그를 통해 설정된 첫 번째 구성 범위에서 IPv4 주소로 설정한다.
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: default
spec:
clusterIP: 10.0.217.164
clusterIPs:
- 10.0.217.164
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- port: 80
protocol: TCP
targetPort: 9376
selector:
app.kubernetes.io/name: MyApp
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
.spec.ipFamilies 의 첫 번째 배열 요소로 IPv6 을 명시적으로 정의하는 다음 서비스를 생성한다. Kubernetes는 service-cluster-ip-range로 구성된 IPv6 범위에서 서비스용 클러스터 IP를 할당하고 .spec.ipFamilyPolicy 를 SingleStack 으로 설정한다.
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app.kubernetes.io/name: MyApp
spec:
ipFamilies:
- IPv6
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
kubectl 를 사용하여 서비스의 YAML을 확인한다.
kubectl get svc my-service -o yaml
이 서비스에서 .spec.ipFamilyPolicy 를 SingleStack 으로 설정하고 .spec.clusterIP 를 kube-controller-manager의 --service-cluster-ip-range 플래그를 통해 설정된 IPv6 범위에서 IPv6 주소로 설정한다.
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: MyApp
name: my-service
spec:
clusterIP: 2001:db8:fd00::5118
clusterIPs:
- 2001:db8:fd00::5118
ipFamilies:
- IPv6
ipFamilyPolicy: SingleStack
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app.kubernetes.io/name: MyApp
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
PreferDualStack 에 .spec.ipFamilyPolicy 을 명시적으로 정의하는 다음 서비스를 생성한다. 쿠버네티스는 IPv4 및 IPv6 주소를 모두 할당하고 (이 클러스터에는 이중 스택을 사용하도록 설정되었으므로) .spec.ipFamilies 배열에 있는 첫 번째 요소의 주소 계열을 기반으로.spec.ClusterIP 목록에서 .spec.ClusterIPs 를 선택한다.
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app.kubernetes.io/name: MyApp
spec:
ipFamilyPolicy: PreferDualStack
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
kubectl get svc 명령어는 오직 CLUSTER-IP 필드에 주요 IP만 표시한다.
kubectl get svc -l app.kubernetes.io/name: MyApp
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service ClusterIP 10.0.216.242 <none> 80/TCP 5s
서비스가 kubectl describe 를 사용하여 IPv4 및 IPv6 주소 블록에서 클러스터 IP를 가져오는지 확인한다. 그런 다음 IP 및 포트를 통해 서비스에 대한 접속을 확인할 수 있다.
kubectl describe svc -l app.kubernetes.io/name: MyApp
Name: my-service
Namespace: default
Labels: app.kubernetes.io/name: MyApp
Annotations: <none>
Selector: app.kubernetes.io/name: MyApp
Type: ClusterIP
IP Family Policy: PreferDualStack
IP Families: IPv4,IPv6
IP: 10.0.216.242
IPs: 10.0.216.242,2001:db8:fd00::af55
Port: <unset> 80/TCP
TargetPort: 9376/TCP
Endpoints: <none>
Session Affinity: None
Events: <none>
만약 클라우드 제공자가 IPv6 기반 외부 로드 밸런서 구성을 지원한다면 .spec.ipFamilyPolicy 의 PreferDualStack 과 .spec.ipFamilies 배열의 첫 번째 요소로 IPv6 및 LoadBalancer 로 설정된 type 필드를 사용하여 다음 서비스를 생성한다.
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app.kubernetes.io/name: MyApp
spec:
ipFamilyPolicy: PreferDualStack
ipFamilies:
- IPv6
type: LoadBalancer
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
Check the Service:
kubectl get svc -l app.kubernetes.io/name: MyApp
서비스가 IPv6 주소 블록에서 CLUSTER-IP 주소 및 EXTERNAL-IP 주소를 할당받는지 검증한다. 그리고 나서 IP 및 포트로 서비스 접근이 가능한지 검증할 수 있다.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service LoadBalancer 2001:db8:fd00::7ebc 2603:1030:805::5 80:30790/TCP 35s
Kubernetes v1.33 [stable](enabled by default)이 문서는 클러스터에 할당된 기존 서비스 IP 범위를 확장하는 방법을 설명한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
쿠버네티스 서버의 버전은 다음과 같거나 더 높아야 함. 버전: v1.29.버전 확인을 위해서, 다음 커맨드를 실행 kubectl version.
쿠버네티스 클러스터에서 MultiCIDRServiceAllocator
기능 게이트를
활성화한 kube-apiserver를 사용하고 networking.k8s.io/v1beta1 API 그룹이 활성화된 경우,
kubernetes라는 잘 알려진 이름을 가진 ServiceCIDR 오브젝트를 생성하며,
이는 kube-apiserver의 --service-cluster-ip-range 명령줄 인자 값에 기반하여 IP 주소 범위를 지정한다.
kubectl get servicecidr
NAME CIDRS AGE
kubernetes 10.96.0.0/28 17d
잘 알려진 kubernetes 서비스는 파드에 kube-apiserver 엔드포인트를 노출시키며,
기본 ServiceCIDR 범위에서 첫 번째 IP 주소를 계산하고
해당 IP 주소를 클러스터 IP로 사용한다.
kubectl get service kubernetes
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 17d
이 경우 기본 서비스는 해당 IPAdress 오브젝트와 연결된 ClusterIP 10.96.0.1을 사용한다.
kubectl get ipaddress 10.96.0.1
NAME PARENTREF
10.96.0.1 services/default/kubernetes
ServiceCIDR는 파이널라이저로 보호되어 서비스 ClusterIP가 고아 상태로 남는 것을 방지한다. 파이널라이저(finalizer)는 다른 서브넷에 해당 IPAddress가 포함되어 있거나 해당 서브넷에 속한 IPAddress가 전혀 없는 경우에만 제거된다.
사용자가 서비스에 사용 가능한 주소 수를 늘려야 하는 경우가 있는데, 이전에는 서비스 범위를 늘리는 작업이 데이터 손실을 초래할 수 있는 파괴적인 작업이었다. 이 새로운 기능을 통해 사용자는 사용할 수 있는 주소 수를 늘리기 위해 단순히 새로운 ServiceCIDR을 추가하면 된다.
서비스에 10.96.0.0/28 대역을 사용하는 클러스터에서는 2^(32-28) - 2 = 14개의
IP 주소만 사용할 수 있다. kubernetes.default 서비스는 항상 생성되므로, 이 예시에서는
실제로 13개의 서비스만 만들 수 있다.
for i in $(seq 1 13); do kubectl create service clusterip "test-$i" --tcp 80 -o json | jq -r .spec.clusterIP; done
10.96.0.11
10.96.0.5
10.96.0.12
10.96.0.13
10.96.0.14
10.96.0.2
10.96.0.3
10.96.0.4
10.96.0.6
10.96.0.7
10.96.0.8
10.96.0.9
error: failed to create ClusterIP service: Internal error occurred: failed to allocate a serviceIP: range is full
서비스에서 사용할 수 있는 IP 주소 수를 늘리려면, IP 주소 범위를 확장하거나 새 IP 주소 범위를 추가하는 새 ServiceCIDR을 생성하면 된다.
cat <EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1beta1
kind: ServiceCIDR
metadata:
name: newcidr1
spec:
cidrs:
- 10.96.0.0/24
EOF
servicecidr.networking.k8s.io/newcidr1 created
이렇게 하면 새 범위에서 ClusterIP를 할당받는 새로운 서비스를 생성할 수 있다.
for i in $(seq 13 16); do kubectl create service clusterip "test-$i" --tcp 80 -o json | jq -r .spec.clusterIP; done
10.96.0.48
10.96.0.200
10.96.0.121
10.96.0.144
해당 ServiceCIDR에 의존하는 IPAddresses가 존재하는 경우 해당 ServiceCIDR을 삭제할 수 없다.
kubectl delete servicecidr newcidr1
servicecidr.networking.k8s.io "newcidr1" deleted
쿠버네티스는 이러한 종속 관계를 추적하기 위해 ServiceCIDR에 파이널라이저를 사용한다.
kubectl get servicecidr newcidr1 -o yaml
apiVersion: networking.k8s.io/v1beta1
kind: ServiceCIDR
metadata:
creationTimestamp: "2023-10-12T15:11:07Z"
deletionGracePeriodSeconds: 0
deletionTimestamp: "2023-10-12T15:12:45Z"
finalizers:
- networking.k8s.io/service-cidr-finalizer
name: newcidr1
resourceVersion: "1133"
uid: 5ffd8afe-c78f-4e60-ae76-cec448a8af40
spec:
cidrs:
- 10.96.0.0/24
status:
conditions:
- lastTransitionTime: "2023-10-12T15:12:45Z"
message: There are still IPAddresses referencing the ServiceCIDR, please remove
them or create a new ServiceCIDR
reason: OrphanIPAddress
status: "False"
type: Ready
ServiceCIDR 삭제를 막고 있는 IP 주소를 포함하는 서비스를 제거함으로써
for i in $(seq 13 16); do kubectl delete service "test-$i" ; done
service "test-13" deleted
service "test-14" deleted
service "test-15" deleted
service "test-16" deleted
컨트롤 플레인이 해당 제거를 감지한다. 이어서, 컨트롤 플레인은 파이널라이저를 삭제하므로, 삭제 대기 상태였던 ServiceCIDR이 실제로 제거된다.
kubectl get servicecidr newcidr1
Error from server (NotFound): servicecidrs.networking.k8s.io "newcidr1" not found
클러스터 관리자는 클러스터 내에서 ServiceCIDR 리소스의 생성과 수정을 제어하는 정책을 구현할 수 있다. 이를 통해 서비스에 사용되는 IP 주소 범위를 중앙에서 관리하고 의도치 않거나 충돌하는 구성을 방지할 수 있다. 쿠버네티스는 이러한 규칙을 강제하기 위해 Validating Admission Policy와 같은 메커니즘을 제공한다.
클러스터 관리자는 허용할 수 있는 범위를 제한하거나, 클러스터 서비스 IP 범위에 대한 변경을 완전히 차단하고자 하는 상황이 있을 수 있다.
기본 "kubernetes" ServiceCIDR는 클러스터의 일관성을 유지하기 위해
kube-apiserver에 의해 생성되며, 클러스터가 동작하기 위해 필요하므로
항상 허용되어야 한다. ValidatingAdmissionPolicy가 기본 ServiceCIDR을
제한하지 않도록 하려면, 다음과 같이 절을 추가하면 된다.
matchConditions:
- name: 'exclude-default-servicecidr'
expression: "object.metadata.name != 'kubernetes'"
아래 예시에서처럼 적용할 수 있다.
다음은 allowed로 지정한 범위의 서브넷인 경우에만 ServiceCIDR을 생성할 수 있도록
허용하는 ValidatingAdmissionPolicy 예시이다. (예를 들어, 이 정책에서는
cidrs: ['10.96.1.0/24'] 또는 cidrs: ['2001:db8:0:0:ffff::/80', '10.96.0.0/20']를
가진 ServiceCIDR은 허용되지만, cidrs: ['172.20.0.0/16']를
가진 ServiceCIDR은 허용되지 않는다.) 이 정책을 복사하여 환경에 맞게
allowed 값을 변경해 사용할 수 있다.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: "servicecidrs.default"
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["networking.k8s.io"]
apiVersions: ["v1","v1beta1"]
operations: ["CREATE", "UPDATE"]
resources: ["servicecidrs"]
matchConditions:
- name: 'exclude-default-servicecidr'
expression: "object.metadata.name != 'kubernetes'"
variables:
- name: allowed
expression: "['10.96.0.0/16','2001:db8::/64']"
validations:
- expression: "object.spec.cidrs.all(newCIDR, variables.allowed.exists(allowedCIDR, cidr(allowedCIDR).containsCIDR(newCIDR)))"
# For all CIDRs (newCIDR) listed in the spec.cidrs of the submitted ServiceCIDR
# object, check if there exists at least one CIDR (allowedCIDR) in the `allowed`
# list of the VAP such that the allowedCIDR fully contains the newCIDR.
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: "servicecidrs-binding"
spec:
policyName: "servicecidrs.default"
validationActions: [Deny,Audit]
자체 검증 expression을 작성하려면
CEL 문서를 참고하면 된다.
아래 예시는 기본 "kubernetes" ServiceCIDR을 제외하고,
새로운 ServiceCIDR 범위 생성을 제한하기 위해 ValidatingAdmissionPolicy와 해당 바인딩을 사용하는 방법을 보여준다.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: "servicecidrs.deny"
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["networking.k8s.io"]
apiVersions: ["v1","v1beta1"]
operations: ["CREATE", "UPDATE"]
resources: ["servicecidrs"]
validations:
- expression: "object.metadata.name == 'kubernetes'"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: "servicecidrs-deny-binding"
spec:
policyName: "servicecidrs.deny"
validationActions: [Deny,Audit]
Kubernetes v1.33 [stable](enabled by default)이 문서는 클러스터에 할당된 기본 서비스 IP 범위를 재구성하는 방법을 다룬다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
쿠버네티스 서버의 버전은 다음과 같거나 더 높아야 함. 버전: v1.33.버전 확인을 위해서, 다음 커맨드를 실행 kubectl version.
이 문서는 쿠버네티스 클러스터 내 서비스 IP 주소 범위를 관리하는 방법을 설명하며, 이는 클러스터가 서비스에 대해 지원하는 IP 패밀리에도 영향을 준다.
서비스 ClusterIPs에 사용 가능한 IP 패밀리는 kube-apiserver의 --service-cluster-ip-range
플래그에 의해 결정된다. 서비스 IP 주소 할당에 대해 더 잘 이해하려면
가상 IP 및 서비스 프록시 문서를 참고한다.
쿠버네티스 1.33부터, 클러스터에 대해 설정된 서비스 IP 패밀리는
kubernetes라는 이름의 ServiceCIDR 오브젝트로 반영된다. kubernetes ServiceCIDR
오브젝트는 최초로 실행된 kube-apiserver 인스턴스가 자신에게 설정된 --service-cluster-ip-range 플래그를
기반으로 생성한다. 일관된 클러스터 동작을 보장하기 위해, 모든 kube-apiserver 인스턴스는 동일한 --service-cluster-ip-range 값으로 설정되어야 하며, 이는 기본 쿠버네티스 ServiceCIDR 오브젝트와 일치해야 한다.
서비스 CIDR 재구성은 다음과 같은 시나리오로 구분할 수 있다.
기존 서비스 CIDR 확장: 이는 kube-apiserver를 재구성할 필요 없이 새 ServiceCIDR 오브젝트를 추가하여 동적으로 수행할 수 있다. 자세한 내용은 [서비스 IP 범위 확장] (https://kubernetes.io/ko/docs/tasks/network/extend-service-ip-ranges/) 문서를 참고한다.
단일 스택에서 기본 서비스 CIDR을 유지한 채 이중 스택으로 전환: 이는 원래의 IP 패밀리를 기본으로 유지하면서 보조 IP 패밀리(IPv4 전용 클러스터에 IPv6 추가, 또는 IPv6 전용 클러스터에 IPv4 추가)를 도입하는 것을 의미한다. 이를 위해 kube-apiserver 구성을 업데이트해야 하며 이 추가된 IP 패밀리를 처리해야 하는 다양한 클러스터 컴포넌트들도 함께 수정해야 한다. 이러한 컴포넌트에는 kube-proxy, CNI 또는 네트워크 플러그인, 서비스 메시 구현체, DNS 서비스 등이 포함되지만 이에 국한되지는 않는다.
이중 스택에서 기본 서비스 CIDR을 유지한 채 단일 스택으로 전환: 이는 이중 스택 클러스터에서 보조 IP 패밀리를 제거하고, 원래의 기본 IP 패밀리를 유지한 채 단일 IP 패밀리로 되돌리는 것을 의미한다. 컴포넌트를 새 IP 패밀리에 맞게 재구성하는 것뿐 아니라, 제거된 IP 패밀리를 사용하도록 명시적으로 설정된 서비스들을 처리해야 할 수도 있다.
기본 서비스 CIDR를 변경하는 경우: 기본
ServiceCIDR 전체를 교체하는 것은 복잡한 작업이다. 새로운
ServiceCIDR이 기존 범위와 겹치지 않는다면 [기존 서비스들의
재번호 부여와 kubernetes.default 서비스의 변경]
(#illustrative-reconfiguration-steps)이 필요하다.
기본 IP 패밀리 자체가 변경되는 경우에는 훨씬 더 복잡해지며,
새로운 기본 IP 패밀리에 맞추기 위해 (kubelet, 네트워크 플러그인 등)
여러 클러스터 구성 요소를 변경해야 할 수도 있다.
기본 서비스 CIDR을 재구성하려면 클러스터 운영자, 관리자, 또는 클러스터 라이프사이클을 관리하는 소프트웨어가 수행하는 수동 절차가 필요하다. 일반적으로 다음과 같은 작업을 포함한다.
--service-cluster-ip-range 플래그를 수정한다.kubernetes.default
서비스는 새 서비스 CIDR에서 IP를 할당받도록 삭제 후 재생성해야
한다.다음 단계들은 기본 서비스 CIDR을 완전히 교체하고
kubernetes.default 서비스 재생성에 초점을
맞춘 제어된 재구성 절차를 설명한다.
--service-cluster-ip-range 값으로 kube-apiserver를 시작한다.kubernetes 기본 서비스 CIDR을 삭제 대상으로 표시한다(기존 IP와
파이널라이저(finalizer)로 인해 삭제 대기 상태로 남는다). 이렇게 하면 이전 범위에서
새 할당이 이루어지는 것을 방지한다.kubernetes.default 서비스를 삭제한다. 새 kube-apiserver가
이를 새 서비스 CIDR 내에서 재생성한다.