1 - 확장 API 서버 설정
애그리게이션 레이어(aggregation layer)와 작동하도록 확장 API 서버를 설정하면 쿠버네티스 API 서버를 쿠버네티스의 핵심 API의 일부가 아닌 추가 API로 확장할 수 있다.
시작하기 전에
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.
- 애그리게이션 레이어를 구성하고 apiserver 플래그를 활성화해야 한다.
애그리게이션 레이어와 작동하도록 확장 API 서버 설정
다음 단계는 확장 API 서버를 높은 수준 으로 설정하는 방법을 설명한다. 이 단계는 YAML 구성을 사용하거나 API를 사용하는 것에 상관없이 적용된다. 둘 사이의 차이점을 구체적으로 식별하려고 시도한다. YAML 구성을 사용하여 구현하는 방법에 대한 구체적인 예를 보려면, 쿠버네티스 리포지터리에서 sample-apiserver를 참고할 수 있다.
또는, apiserver-builder와 같은 기존의 타사 솔루션을 사용하여 스켈레톤(skeleton)을 생성하고 다음 단계를 모두 자동화해야 한다.
- API서비스(APIService) API가 활성화되어 있는지 확인한다(
--runtime-config
확인). 클러스터에서 일부러 해제하지 않았다면, 기본적으로 활성화되어 있어야 한다. - API서비스 오브젝트를 추가하거나 클러스터 관리자가 작성하도록 RBAC 규칙을 작성해야 할 수도 있다. (API 확장은 전체 클러스터에 영향을 주기 때문에, 운영 중인 클러스터에서 API 확장에 대한 테스트/개발/디버깅을 수행하지 않는 것이 좋다.)
- 확장 API 서비스를 실행하려는 쿠버네티스 네임스페이스를 생성한다.
- HTTPS를 위해 확장 API 서버가 사용하는 서버 인증서에 서명하는 데 사용할 CA 인증서를 생성하거나 가져온다.
- HTTPS를 위해 API 서버가 사용할 서버 인증서/키를 생성한다. 이 인증서는 위의 CA 인증서에 의해 서명해야 한다. 또한 Kube DNS 이름의 CN이 있어야 한다. 이것은 쿠버네티스 서비스에서 파생되었으며
<service name>.<service name namespace>.svc
형식이다. - 네임스페이스에 서버 인증서/키를 사용하여 쿠버네티스 시크릿을 생성한다.
- 확장 API 서버에 대한 쿠버네티스 디플로이먼트를 생성하고 시크릿을 볼륨으로 로드하는지 확인한다. 확장 API 서버의 작동하는(working) 이미지에 대한 참조를 포함해야 한다. 디플로이먼트는 네임스페이스에도 있어야 한다.
- 확장 API 서버가 해당 볼륨에서 해당 인증서를 로드하고 HTTPS 핸드셰이크에 사용되는지 확인한다.
- 네임스페이스에서 쿠버네티스 서비스 어카운트를 생성한다.
- 리소스에 허용하려는 작업에 대한 쿠버네티스 클러스터 롤(role)을 생성한다.
- 네임스페이스의 서비스 어카운트에서 방금 만든 클러스터 롤로 쿠버네티스 클러스터 롤 바인딩을 생성한다.
- 네임스페이스의 서비스 어카운트에서
system:auth-delegator
클러스터 롤로 쿠버네티스 클러스터 롤 바인딩을 만들어 인증 결정을 쿠버네티스 핵심 API 서버에 위임한다. - 네임스페이스의 서비스 어카운트에서
extension-apiserver-authentication-reader
롤로 쿠버네티스 롤 바인딩을 생성한다. 이를 통해 확장 API 서버가extension-apiserver-authentication
컨피그맵(configmap)에 접근할 수 있다. - 쿠버네티스 API 서비스를 생성한다. 위의 CA 인증서는 base64로 인코딩되어, 새로운 라인이 제거되고 API 서비스에서 spec.caBundle로 사용되어야 한다. 이것은 namespaced가 아니어야 한다. kube-aggregator API를 사용하는 경우, base64 인코딩이 수행되므로 PEM 인코딩된 CA 번들만 통과한다.
- kubectl을 사용하여 리소스를 얻는다. kubectl을 실행하면, "No resources found."가 반환된다. 이 메시지는 모든 것이 작동됐지만 현재 해당 리소스 유형의 오브젝트가 생성되지 않았음을 나타낸다.
다음 내용
- API 애그리게이션 레이어를 구성하고 apiserver 플래그를 활성화하는 단계를 수행한다.
- 높은 수준의 개요에 대해서는, 애그리게이션 레이어로 쿠버네티스 API 확장하기를 참고한다.
- 커스텀 리소스 데피니션을 사용하여 쿠버네티스 API 확장하는 방법에 대해 알아본다.
2 - Konnectivity 서비스 설정
Konnectivity 서비스는 컨트롤 플레인에 클러스터 통신을 위한 TCP 수준 프록시를 제공한다.
시작하기 전에
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
Konnectivity 서비스 설정
다음 단계에는 송신(egress) 설정이 필요하다. 예를 들면 다음과 같다.
apiVersion: apiserver.k8s.io/v1beta1
kind: EgressSelectorConfiguration
egressSelections:
# 클러스터에 대한 송신(egress) 트래픽을 제어하기 위해
# "cluster"를 name으로 사용한다. 기타 지원되는 값은 "etcd" 및 "master"이다.
- name: cluster
connection:
# API 서버와 Konnectivity 서버 간의 프로토콜을
# 제어한다. 지원되는 값은 "GRPC" 및 "HTTPConnect"이다. 두 모드 간에
# 최종 사용자가 볼 수 있는 차이점은 없다. 동일한 모드에서 작동하도록
# Konnectivity 서버를 설정해야 한다.
proxyProtocol: GRPC
transport:
# API 서버가 Konnectivity 서버와 통신하는 데 사용하는
# transport를 제어한다. Konnectivity 서버가 API 서버와 동일한 시스템에
# 있는 경우 UDS를 사용하는 것이 좋다. 동일한 UDS 소켓에서
# 수신 대기하도록 Konnectivity 서버를 구성해야 한다.
# 지원되는 다른 전송은 "tcp"이다. TCP 전송을 보호하려면 TLS 구성을 설정해야 한다.
uds:
udsName: /etc/kubernetes/konnectivity-server/konnectivity-server.socket
Konnectivity 서비스를 사용하고 네트워크 트래픽을 클러스터 노드로 보내도록 API 서버를 구성해야 한다.
ServiceAccountTokenVolumeProjection
기능 게이트(feature gate)가 활성화되어 있는지 확인한다. kube-apiserver에 다음과 같은 플래그를 제공하여 서비스 어카운트 토큰 볼륨 보호를 활성화할 수 있다.--service-account-issuer=api --service-account-signing-key-file=/etc/kubernetes/pki/sa.key --api-audiences=system:konnectivity-server
admin/konnectivity/egress-selector-configuration.yaml
과 같은 송신 구성 파일을 생성한다.- API 서버의
--egress-selector-config-file
플래그를 API 서버 송신 구성 파일의 경로로 설정한다. - UDS 연결을 사용하는 경우 kube-apiserver에 볼륨 구성을 추가한다.
spec: containers: volumeMounts: - name: konnectivity-uds mountPath: /etc/kubernetes/konnectivity-server readOnly: false volumes: - name: konnectivity-uds hostPath: path: /etc/kubernetes/konnectivity-server type: DirectoryOrCreate
konnectivity-server에 대한 인증서 및 kubeconfig를 생성하거나 얻는다.
예를 들어 OpenSSL 커맨드라인 툴을 사용하여 컨트롤 플레인 호스트에서
클러스터 CA 인증서 /etc/kubernetes/pki/ca.crt
를 사용하여 X.509 인증서를 발급할 수 있다.
openssl req -subj "/CN=system:konnectivity-server" -new -newkey rsa:2048 -nodes -out konnectivity.csr -keyout konnectivity.key -out konnectivity.csr
openssl x509 -req -in konnectivity.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out konnectivity.crt -days 375 -sha256
SERVER=$(kubectl config view -o jsonpath='{.clusters..server}')
kubectl --kubeconfig /etc/kubernetes/konnectivity-server.conf config set-credentials system:konnectivity-server --client-certificate konnectivity.crt --client-key konnectivity.key --embed-certs=true
kubectl --kubeconfig /etc/kubernetes/konnectivity-server.conf config set-cluster kubernetes --server "$SERVER" --certificate-authority /etc/kubernetes/pki/ca.crt --embed-certs=true
kubectl --kubeconfig /etc/kubernetes/konnectivity-server.conf config set-context system:konnectivity-server@kubernetes --cluster kubernetes --user system:konnectivity-server
kubectl --kubeconfig /etc/kubernetes/konnectivity-server.conf config use-context system:konnectivity-server@kubernetes
rm -f konnectivity.crt konnectivity.key konnectivity.csr
다음으로 Konnectivity 서버와 에이전트를 배포해야 한다. kubernetes-sigs/apiserver-network-proxy에서 구현을 참조할 수 있다.
컨트롤 플레인 노드에 Konnectivity 서버를 배포한다. 제공된
konnectivity-server.yaml
매니페스트는
쿠버네티스 구성 요소가 클러스터에 스태틱 파드(static Pod)로 배포되었다고 가정한다. 그렇지 않은 경우에는 Konnectivity
서버를 데몬셋(DaemonSet)으로 배포할 수 있다.
apiVersion: v1
kind: Pod
metadata:
name: konnectivity-server
namespace: kube-system
spec:
priorityClassName: system-cluster-critical
hostNetwork: true
containers:
- name: konnectivity-server-container
image: us.gcr.io/k8s-artifacts-prod/kas-network-proxy/proxy-server:v0.0.16
command: ["/proxy-server"]
args: [
"--logtostderr=true",
# 이것은 egressSelectorConfiguration에 설정된 값과 일치해야 한다.
"--uds-name=/etc/kubernetes/konnectivity-server/konnectivity-server.socket",
# 다음 두 줄은 Konnectivity 서버가 apiserver와
# 동일한 시스템에 배포되고 API 서버의 인증서와
# 키가 지정된 위치에 있다고 가정한다.
"--cluster-cert=/etc/kubernetes/pki/apiserver.crt",
"--cluster-key=/etc/kubernetes/pki/apiserver.key",
# 이것은 egressSelectorConfiguration에 설정된 값과 일치해야 한다.
"--mode=grpc",
"--server-port=0",
"--agent-port=8132",
"--admin-port=8133",
"--health-port=8134",
"--agent-namespace=kube-system",
"--agent-service-account=konnectivity-agent",
"--kubeconfig=/etc/kubernetes/konnectivity-server.conf",
"--authentication-audience=system:konnectivity-server"
]
livenessProbe:
httpGet:
scheme: HTTP
host: 127.0.0.1
port: 8134
path: /healthz
initialDelaySeconds: 30
timeoutSeconds: 60
ports:
- name: agentport
containerPort: 8132
hostPort: 8132
- name: adminport
containerPort: 8133
hostPort: 8133
- name: healthport
containerPort: 8134
hostPort: 8134
volumeMounts:
- name: k8s-certs
mountPath: /etc/kubernetes/pki
readOnly: true
- name: kubeconfig
mountPath: /etc/kubernetes/konnectivity-server.conf
readOnly: true
- name: konnectivity-uds
mountPath: /etc/kubernetes/konnectivity-server
readOnly: false
volumes:
- name: k8s-certs
hostPath:
path: /etc/kubernetes/pki
- name: kubeconfig
hostPath:
path: /etc/kubernetes/konnectivity-server.conf
type: FileOrCreate
- name: konnectivity-uds
hostPath:
path: /etc/kubernetes/konnectivity-server
type: DirectoryOrCreate
그런 다음 클러스터에 Konnectivity 에이전트를 배포한다.
apiVersion: apps/v1
# 에이전트를 Deployment(디플로이먼트)로 배포할 수도 있다. 각 노드에 에이전트가
# 있을 필요는 없다.
kind: DaemonSet
metadata:
labels:
addonmanager.kubernetes.io/mode: Reconcile
k8s-app: konnectivity-agent
namespace: kube-system
name: konnectivity-agent
spec:
selector:
matchLabels:
k8s-app: konnectivity-agent
template:
metadata:
labels:
k8s-app: konnectivity-agent
spec:
priorityClassName: system-cluster-critical
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
containers:
- image: us.gcr.io/k8s-artifacts-prod/kas-network-proxy/proxy-agent:v0.0.16
name: konnectivity-agent
command: ["/proxy-agent"]
args: [
"--logtostderr=true",
"--ca-cert=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt",
# konnectivity 서버는 hostNetwork=true로 실행되기 때문에,
# 이것은 마스터 머신의 IP 주소이다.
"--proxy-server-host=35.225.206.7",
"--proxy-server-port=8132",
"--admin-server-port=8133",
"--health-server-port=8134",
"--service-account-token-path=/var/run/secrets/tokens/konnectivity-agent-token"
]
volumeMounts:
- mountPath: /var/run/secrets/tokens
name: konnectivity-agent-token
livenessProbe:
httpGet:
port: 8134
path: /healthz
initialDelaySeconds: 15
timeoutSeconds: 15
serviceAccountName: konnectivity-agent
volumes:
- name: konnectivity-agent-token
projected:
sources:
- serviceAccountToken:
path: konnectivity-agent-token
audience: system:konnectivity-server
마지막으로 클러스터에서 RBAC가 활성화된 경우 관련 RBAC 규칙을 생성한다.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:konnectivity-server
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: system:konnectivity-server
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: konnectivity-agent
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile