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 - 다중 스케줄러 설정
쿠버네티스는 여기에서 설명한 스케줄러를 기본 스케줄러로 사용한다. 만일 기본 스케줄러가 사용자의 필요를 만족시키지 못한다면 직접 스케줄러를 구현하여 사용할 수 있다. 이에 더해, 기본 스케줄러와 함께 여러 스케줄러를 동시에 사용하여 쿠버네티스가 각 파드에 대해 어떤 스케줄러를 적용할지에 대한 설정도 할 수 있다. 예제와 함께 쿠버네티스에서 다중 스케줄러를 사용하는 방법에 대해 배워보도록 하자.
스케줄러를 구현하는 방법에 대한 자세한 설명은 해당 문서에서 다루지 않는다. kube-scheduler 구현을 다루는 공식 예시는 쿠버네티스 소스 디렉토리에 있는 pkg/scheduler 를 참고한다.
시작하기 전에
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.스케줄러 패키징
스케줄러 바이너리를 컨테이너 이미지로 패키징한다. 해당 예제를 통해 기본 스케줄러 (kube-scheduler)를 두 번째 스케줄러로 사용할 수 있다. GitHub 쿠버네티스 소스코드를 클론하고 소스를 빌드하자.
git clone https://github.com/kubernetes/kubernetes.git
cd kubernetes
make
kube-scheduler 바이너리를 담은 컨테이너 이미지를 생성하자.
이미지를 빌드 하기 위한 Dockerfile
은 다음과 같다.
FROM busybox
ADD ./_output/local/bin/linux/amd64/kube-scheduler /usr/local/bin/kube-scheduler
파일을 Dockerfile
로 저장하고 이미지를 빌드한 후 레지스트리로 푸시하자. 해당 예제에서는 이미지를
Google Container Registry (GCR)로
푸시하고 있다.
이에 대한 자세한 내용은 GCR
문서를 참고하자.
docker build -t gcr.io/my-gcp-project/my-kube-scheduler:1.0 .
gcloud docker -- push gcr.io/my-gcp-project/my-kube-scheduler:1.0
스케줄러에서 사용할 쿠버네티스 디플로이먼트 정의하기
이제 스케줄러 컨테이너 이미지가 있으니, 해당 이미지를 포함하는 파드 구성을 생성하고
쿠버네티스 클러스터 내에서 실행해보자. 해당 예제에서는, 클러스터 내에 직접 파드를 생성하는 대신에
디플로이먼트를 사용해도 된다.
디플로이먼트는
레플리카 셋을 관리하며,
이는 또 파드를 관리하기 때문에 스케줄러에 대한 회복 탄력성을 제공한다.
다음은 디플로이먼트에 대한 구성 파일이다. 이 파일을 my-scheduler.yaml
으로 저장한다.
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-scheduler
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: my-scheduler-as-kube-scheduler
subjects:
- kind: ServiceAccount
name: my-scheduler
namespace: kube-system
roleRef:
kind: ClusterRole
name: system:kube-scheduler
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: my-scheduler-as-volume-scheduler
subjects:
- kind: ServiceAccount
name: my-scheduler
namespace: kube-system
roleRef:
kind: ClusterRole
name: system:volume-scheduler
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: ConfigMap
metadata:
name: my-scheduler-config
namespace: kube-system
data:
my-scheduler-config.yaml: |
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: my-scheduler
leaderElection:
leaderElect: false
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
component: scheduler
tier: control-plane
name: my-scheduler
namespace: kube-system
spec:
selector:
matchLabels:
component: scheduler
tier: control-plane
replicas: 1
template:
metadata:
labels:
component: scheduler
tier: control-plane
version: second
spec:
serviceAccountName: my-scheduler
containers:
- command:
- /usr/local/bin/kube-scheduler
- --config=/etc/kubernetes/my-scheduler/my-scheduler-config.yaml
image: gcr.io/my-gcp-project/my-kube-scheduler:1.0
livenessProbe:
httpGet:
path: /healthz
port: 10259
scheme: HTTPS
initialDelaySeconds: 15
name: kube-second-scheduler
readinessProbe:
httpGet:
path: /healthz
port: 10259
scheme: HTTPS
resources:
requests:
cpu: '0.1'
securityContext:
privileged: false
volumeMounts:
- name: config-volume
mountPath: /etc/kubernetes/my-scheduler
hostNetwork: false
hostPID: false
volumes:
- name: config-volume
configMap:
name: my-scheduler-config
해당 매니페스트에서는 KubeSchedulerConfiguration을
사용하여 구현할 스케줄러의 특성을 정의한다. 이러한 설정은 초기화 과정에서 --config
옵션을 통해 kube-scheduler
에게 전달된다.
해당 구성 파일은 my-scheduler-config
컨피그맵에 저장된다. my-scheduler
디플로이먼트의 파드에서는 my-scheduler-config
컨피그맵을 볼륨으로 마운트 시킨다.
앞서 언급한 스케줄러 구성에서는, 구현한 스케줄러가 KubeSchedulerProfile의 형식으로 나타나게 된다.
참고:
스케줄러가 특정 파드에 대한 스케줄링을 수행하는지 판단하기 위해서는, PodTemplate 또는 파드 매니페스트의spec.schedulerName
필드가 KubeSchedulerProfile
의 schedulerName
필드와 일치하는지 확인해야 한다.
클러스터 내 실행되고 있는 모든 스케줄러는 고유한 이름을 가져야 한다.또한, kube-scheduler
와 같은 권한을 부여받기 위해서는 전용 서비스 어카운트 my-scheduler
를 생성하고
해당 서비스 어카운트를 클러스터롤 system:kube-scheduler
와 바인딩해야 한다.
이외의 커맨드 라인 인자에 대한 자세한 설명은
kube-scheduler 문서에서 참고하고
이외의 사용자 정의 kube-scheduler
구성에 대한 자세한 설명은
스케줄러 구성 레퍼런스
에서 참고한다.
두 번째 스케줄러를 클러스터에서 실행하기
쿠버네티스 클러스터에서 스케줄러를 실행하기 위해서, 위의 구성 파일에서 명시한 디플로이먼트를 쿠버네티스 클러스터 내에 생성한다.
kubectl create -f my-scheduler.yaml
스케줄러 파드가 실행되고 있는지 확인한다.
kubectl get pods --namespace=kube-system
NAME READY STATUS RESTARTS AGE
....
my-scheduler-lnf4s-4744f 1/1 Running 0 2m
...
기본 kube-scheduler 파드와 더불어, my-scheduler 파드가 실행("Running")되고 있다는 것을 목록에서 볼 수 있을 것이다.
리더 선출 활성화
리더 선출이 활성화된 상태로 다중 스케줄러를 실행하기 위해서는 다음과 같은 작업을 수행해야 한다.
my-scheduler-config
컨피그맵의 YAML 파일에서 KubeSchedulerConfiguration의 다음과 같은 필드들을 갱신한다.
leaderElection.leaderElect
를true
로leaderElection.resourceNamespace
를<lock-object-namespace>
로leaderElection.resourceName
을<lock-object-name>
으로
참고:
컨트롤 플레인이 잠금 오브젝트를 생성해 주지만, 해당 네임스페이스가 존재하는 상태이어야 한다.kube-system
네임스페이스를 사용해도 된다.클러스터 내에 RBAC가 활성화되어 있는 상태라면, system:kube-scheduler
클러스터롤을 업데이트 해야 한다.
다음 예시와 같이, 구현한 스케줄러의 이름을 endpoints
와 leases
리소스에 적용되는 룰의 resourceNames에 추가하자.
kubectl edit clusterrole system:kube-scheduler
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:kube-scheduler
rules:
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- apiGroups:
- coordination.k8s.io
resourceNames:
- kube-scheduler
- my-scheduler
resources:
- leases
verbs:
- get
- update
- apiGroups:
- ""
resourceNames:
- kube-scheduler
- my-scheduler
resources:
- endpoints
verbs:
- delete
- get
- patch
- update
파드의 스케줄러를 지정하기
이제 두 번째 스케줄러가 실행되고 있으니, 파드를 몇 개 생성하여 기본 스케줄러 또는 새로 배치한 스케줄러에 의해 스케줄링이 되도록 설정해 보자. 특정 스케줄러를 이용하여 파드를 스케줄링하기 위해서는 해당 파드의 명세에 해당 스케줄러의 이름을 명시해야 한다. 세 가지 예시를 참고해 보자.
스케줄러 이름을 명시하지 않은 파드 명세
apiVersion: v1 kind: Pod metadata: name: no-annotation labels: name: multischeduler-example spec: containers: - name: pod-with-no-annotation-container image: registry.k8s.io/pause:2.0
스케줄러 이름을 제공받지 못했다면, 파드는 자동으로 기본 스케줄러에 의해 스케줄링이 수행된다.
해당 파일을
pod1.yaml
로 저장하고 쿠버네티스 클러스터에 제출해 보자.kubectl create -f pod1.yaml
default-scheduler
를 명시한 파드 명세apiVersion: v1 kind: Pod metadata: name: annotation-default-scheduler labels: name: multischeduler-example spec: schedulerName: default-scheduler containers: - name: pod-with-default-annotation-container image: registry.k8s.io/pause:2.0
spec.schedulerName
의 값으로 스케줄러 이름을 제공함으로써 스케줄러가 정해진다. 이와 같은 경우에서는, 기본 스케줄러의 이름인default-scheduler
를 명시하고 있다.해당 파일을
pod2.yaml
로 저장하고 쿠버네티스 클러스터에 제출해 보자.kubectl create -f pod2.yaml
my-scheduler
를 명시한 파드 명세apiVersion: v1 kind: Pod metadata: name: annotation-second-scheduler labels: name: multischeduler-example spec: schedulerName: my-scheduler containers: - name: pod-with-second-annotation-container image: registry.k8s.io/pause:2.0
이와 같은 경우에서는, 직접 배치한 스케줄러 -
my-scheduler
를 통해 해당 파드의 스케줄링이 수행되어야 한다는 것을 명시하고 있다.spec.schedulerName
의 값은KubeSchedulerProfile
매핑의schedulerName
필드와 일치해야 한다.해당 파일을
pod3.yaml
로 저장하고 쿠버네티스 클러스터에 제출해 보자.kubectl create -f pod3.yaml
세 개의 파드가 모두 실행되고 있는지 확인해 보자.
kubectl get pods
파드가 원하는 스케줄러에 의해 스케줄링 되었는지 확인해보기
이번 예제들을 수월하게 진행하기 위해,
파드가 실제로 원하는 스케줄러에 의해 스케줄링되고 있는지 확인해 보지 않았다.
해당 사항은 파드와 디플로이먼트 구성 파일의 제출 순서를 바꿔보면 확인해 볼 수 있다.
만일 스케줄러 디플로이먼트 구성 파일을 제출하기 전에 모든 파드의 구성 파일을 쿠버네티스 클러스터에 제출한다면,
다른 두 개의 파드는 스케줄링 되는 와중에 annotation-second-scheduler
파드는
무기한 "Pending" 상태에 머무르는 것을 관찰할 수 있다.
스케줄러 디플로이먼트 구성 파일을 제출하여 새로운 스케줄러가 실행되기 시작하면,
annotation-second-scheduler
파드도 스케줄링 된다.
다른 방법으로는, 이벤트 로그에서 "Scheduled" 항목을 찾아 파드가 원하는 스케줄러에 의해 스케줄링 되었는지 확인해 볼 수 있다.
kubectl get events
또한, 관련된 컨트롤 플레인 노드들의 스태틱 파드 매니페스트를 수정하면 클러스터의 메인 스케줄러로 사용자 정의 스케줄러 구성 또는 사용자 정의 컨테이너 이미지를 사용할 수도 있다.
3 - HTTP 프록시를 사용하여 쿠버네티스 API에 접근
이 페이지는 쿠버네티스 API에 접근하기 위해 HTTP 프록시를 사용하는 방법을 설명한다.
시작하기 전에
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.클러스터에서 실행 중인 애플리케이션이 없다면, 아래 명령을 입력하여 Hello world 애플리케이션을 시작한다.
kubectl create deployment node-hello --image=gcr.io/google-samples/node-hello:1.0 --port=8080
kubectl을 사용하여 프록시 서버 시작
아래 커맨드는 쿠버네티스 API 서버의 프록시를 시작한다.
kubectl proxy --port=8080
Kubernetes API 탐색
프록시 서버가 실행 중일 때 curl
, wget
또는 브라우저를 사용하여 API를 탐색할 수 있다.
API 버전 가져오기.
curl http://localhost:8080/api/
출력은 다음과 유사하다.
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.0.2.15:8443"
}
]
}
파드 목록 가져오기.
curl http://localhost:8080/api/v1/namespaces/default/pods
출력은 다음과 유사하다.
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "33074"
},
"items": [
{
"metadata": {
"name": "kubernetes-bootcamp-2321272333-ix8pt",
"generateName": "kubernetes-bootcamp-2321272333-",
"namespace": "default",
"uid": "ba21457c-6b1d-11e6-85f7-1ef9f1dab92b",
"resourceVersion": "33003",
"creationTimestamp": "2016-08-25T23:43:30Z",
"labels": {
"pod-template-hash": "2321272333",
"run": "kubernetes-bootcamp"
},
...
}
다음 내용
kubectl 프록시에 대해 더 배우기.
4 - SOCKS5 프록시를 사용하여 쿠버네티스 API에 접근
Kubernetes v1.24 [stable]
이 문서는 SOCKS5 프록시를 사용하여 원격 쿠버네티스 클러스터의 API에 접근하는 방법을 설명한다. 이 기능은 접근하려는 클러스터의 API를 공용 인터넷에 직접 노출하지 않으려고 할 때 유용하다.
시작하기 전에
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
쿠버네티스 서버의 버전은 다음과 같거나 더 높아야 함. 버전: v1.24. 버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.SSH 클라이언트 소프트웨어(ssh
도구)와 원격 서버에서 실행되는 SSH 서비스가 필요하다.
원격 서버의 SSH 서비스에 로그인할 수 있어야 한다.
작업 내용
참고:
아래 예시는 SSH 클라이언트 및 서버가 SOCKS 프록시 역할을 하는 SSH를 사용하여 트래픽을 터널링(tunnel)한다. 다른 종류의 SOCKS5 프록시를 대신 사용할 수 있다.그림 1은 이 작업에서 달성하고자 하는 목표를 나타낸다.
- 우선 쿠버네티스 API와 통신을 시작하는 로컬 클라이언트 컴퓨터가 있다.
- 쿠버네티스 서버/API는 원격 서버에서 호스팅된다.
- SSH 클라이언트와 서버 소프트웨어를 사용하여 로컬 서버와 원격 서버 간에 보안 SOCKS5 터널을 생성한다. 클라이언트와 쿠버네티스 API 간의 HTTPS 트래픽은 SOCKS5 터널을 통해 전송되며, 터널은 SSH를 통해 터널링된다.
그림 1. SOCKS5 튜토리얼 구성 요소
ssh를 사용하여 SOCKS5 프록시 생성하기
아래 커맨드(command)는 클라이언트 컴퓨터와 원격 서버 간에 SOCKS5 프록시를 시작한다. SOCKS5 프록시를 사용하여 클러스터의 API 서버에 연결할 수 있다.
# 아래 커맨드를 실행한 후 SSH 터널은 포그라운드(foreground)에서 실행된다.
ssh -D 1080 -q -N username@kubernetes-remote-server.example
-D 1080
: SOCKS 프록시를 로컬 포트 1080으로 연다.-q
: quiet 모드. 경고 및 진단 메시지 대부분을 표시하지 않는다.-N
: 원격 커맨드를 실행하지 않는다. 포트 포워딩에 유용.username@kubernetes-remote-server.example
: 쿠버네티스 클러스터가 실행 중인 원격 SSH 서버.
클라이언트 환경 설정
쿠버네티스 API를 사용하려면 먼저, 클라이언트에게 앞에서 만든 SOCKS5 프록시를 통해 쿼리를 전송하도록 지시해야 한다.
https_proxy
환경 변수를 설정하고 실행하는 커맨드를 커맨드라인 툴에 전달한다.
export https_proxy=socks5h://localhost:1080
https_proxy
변수를 설정하면 curl
과 같은 툴은 구성한 프록시를 통해 HTTPS 트래픽을 라우팅한다.
툴이 SOCKS5 프록시를 지원해야 이 기능이 동작한다.
참고:
URL https://localhost:6443/api에서localhost
는 로컬 클라이언트 컴퓨터를 참조하지 않는다.
대신 localhost
라고 알려진 원격 서버의 엔드포인트(endpoint)를 가리킨다.
curl
툴은 호스트 이름을 HTTPS URL에서 SOCKS를 통해 전송하고,
원격 서버는 이것을 로컬(루프백 인터페이스에 속하는 주소)로 처리한다.curl -k -v https://localhost:6443/api
프록시와 함께 공식 쿠버네티스 클라이언트 kubectl
을 사용하려면, ~/.kube/config
파일에서 관련 cluster
항목에 대한 proxy-url
요소를 설정한다.
예시:
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LRMEMMW2 # 가독성을 위해서 축약함
server: https://<API_SERVER_IP_ADRESS>:6443 # "쿠버네티스 API" 서버, 쿠버네티스-원격-서버의 IP 주소
proxy-url: socks5://localhost:1080 # 위 다이어그램의 "SSH SOCKS5 프록시" (SOCKS를 통한 DNS 확인 기능 빌트-인)
name: default
contexts:
- context:
cluster: default
user: default
name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
user:
client-certificate-data: LS0tLS1CR== # 가독성을 위해서 축약함
client-key-data: LS0tLS1CRUdJT= # 가독성을 위해서 축약함
터널이 동작 중이고 이 클러스터를 사용하는 컨텍스트에서 kubectl
을 사용하는 경우 프록시를 통해 클러스터와 상호 작용할 수 있다. 예시:
kubectl get pods
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-85cb69466-klwq8 1/1 Running 0 5m46s
정리하기
SSH 포트 포워딩 프로세스가 실행 중인 터미널에서 CTRL+C
를 눌러 프로세스를 중지한다.
터미널에 unset https_proxy
를 입력하여 프록시를 통한 http 트래픽 전송을 중지한다.
더 읽어보기
5 - Konnectivity 서비스 설정
Konnectivity 서비스는 컨트롤 플레인에 클러스터 통신을 위한 TCP 수준 프록시를 제공한다.
시작하기 전에
쿠버네티스 클러스터가 있어야 하며, kubectl 명령줄 도구가 클러스터와 통신하도록 설정되어 있어야 한다. 컨트롤 플레인 호스트가 아닌 두 개 이상의 노드로 구성된 클러스터에서 이 튜토리얼을 수행하는 것을 권장한다. 클러스터가 없다면, minikube를 이용하여 생성할 수 있다.
Konnectivity 서비스 설정
다음 단계에는 송신(egress) 설정이 필요하다. 예를 들면 다음과 같다.
apiVersion: apiserver.k8s.io/v1beta1
kind: EgressSelectorConfiguration
egressSelections:
# 클러스터에 대한 송신(egress) 트래픽을 제어하기 위해
# "cluster"를 name으로 사용한다. 기타 지원되는 값은 "etcd" 및 "controlplane"이다.
- 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 서버를 구성해야 한다.
- Service Account Token Volume Projection 기능이 활성화되어 있는지 확인한다. 쿠버네티스 v1.20부터는 기본적으로 활성화되어 있다.
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
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: registry.k8s.io/kas-network-proxy/proxy-server:v0.0.32
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