관리 메뉴

피터의 개발이야기

[Kubernetes] 쿠버네티스API 서버 CURL 접속 방법 본문

Kubernetes/Logging & Monitoring

[Kubernetes] 쿠버네티스API 서버 CURL 접속 방법

기록하는 백앤드개발자 2023. 1. 25. 00:06
반응형

 

[kubernetes] 쿠버네티스 목차

[kubernetes] 모니터링 방법 정리

ㅁ 개요 

 ㅇ 쿠버네티스 서버에 kubectl이 아닌 curl을 통해 API서버에 직접 접속하는 방법에 대해서 정리하였다.

 ㅇ 지난 글에서 말한 EKS fail-over 상황을 모니터링하는 방법을 모색하던 중, curl로 직접 접속하는 방법이 있지 찾게 되었다.

 ㅇ 이곳을 참고하여 공부를 하였다.

 

1편 [kubernetes] EKS fail-over 상황정리 및 방어방법
2편 [Kubernetes] 쿠버네티스API 서버 CURL 접속 방법
3편 [Kubernetes] Spring에서 쿠버네티스 Pod 정보조회
4편 [kubernetes] kubernetes event exporter

 

 

ㅁ kubectl은 결국 curl 호출

 kubectl get po -v 9

 ㅇ 위 명령어를 통해 kubectl이 실제로 구동되는 디버깅 로그를 확인 할 수 있다.

 

 ㅇ 우선 $HOME/.kube/config에서 설정정보를 조회한다.  

 ㅇ curl -k -v -XGET  -H 명령어를 통해 kube-apiserver와 통신을 하였고, Response Boby를 출력하였다.

 

{
	"kind": "Table",
	"apiVersion": "meta.k8s.io/v1",
	"metadata": {
		"resourceVersion": "1132997"
	},
	"columnDefinitions": [{
		"name": "Name",
		"type": "string",
		"format": "name",
		"description": "Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names",
		"priority": 0
	}, {
		"name": "Ready",
		"type": "string",
		"format": "",
		"description": "The aggregate readiness state of this pod for accepting traffic.",
		"priority": 0
	}, {
		"name": "Status",
		"type": "string",
		"format": "",
		"description": "The aggregate status of the containers in this pod.",
		"priority": 0
	}, {
		"name": "Restarts",
		"type": "integer",
		"format": "",
		"description": "The number of times the containers in this pod have been restarted.",
		"priority": 0
	}, {
		"name": "Age",
		"type": "string",
		"format": "",
		"description": "CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata",
		"priority": 0
	}, {
		"name": "IP",
		"type": "string",
		"format": "",
		"description": "IP address allocated to the pod. Routable at least within the cluster. Empty if not yet allocated.",
		"priority": 1
	}, {
		"name": "Node",
		"type": "string",
		"format": "",
		"description": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.",
		"priority": 1
	}, {
		"name": "Nominated Node",
		"type": "string",
		"format": "",
		"description": "nominatedNodeName is set only when this pod preempts other pods on the node, but it cannot be scheduled right away as preemption victims receive their graceful termination periods. This field does not guarantee that the pod will be scheduled on this node. Scheduler may decide to place the pod elsewhere if other nodes become available sooner. Scheduler may also decide to give the resources on this node to a higher priority pod that is created after preemption. As a result, this field may be different than PodSpec.nodeName when the pod is scheduled.",
		"priority": 1
	}, {
		"name": "Readiness Gates",
		"type": "string",
		"format": "",
		"description": "If specified, all readiness gates will be evaluated for pod readiness. A pod is ready when all its containers are ready AND all conditions specified in the readiness gates have status equal to \"True\" More info: https://git.k8s.io/enhancements/keps/sig-network/0007-pod-ready%2B%2B.md",
		"priority": 1
	}],
	"rows": [{
		"cells": ["kubectl-test-deploy-6dc65cd5c8-92vcz", "1/1", "Running", 0, "6d15h", "172.17.0.4", "minikube", "\u003cnone\u003e", "\u003cnone\u003e"],
		"object": {
			"kind": "PartialObjectMetadata",
			"apiVersion": "meta.k8s.io/v1",
			"metadata": {
				"name": "kubectl-test-deploy-6dc65cd5c8-92vcz",
				"generateName": "kubectl-test-deploy-6dc65cd5c8-",
				"namespace": "default",
				"uid": "d4f4970e-c013-434e-b6c1-b674e62968a0",
				"resourceVersion": "854888",
				"creationTimestamp": "2023-01-17T21:54:00Z",
				"labels": {
					"app": "kubectl-test",
					"pod-template-hash": "6dc65cd5c8"
				},
				"ownerReferences": [{
					"apiVersion": "apps/v1",
					"kind": "ReplicaSet",
					"name": "kubectl-test-deploy-6dc65cd5c8",
					"uid": "4f0bd30a-1e10-49f6-8933-e51bc35edd6c",
					"controller": true,
					"blockOwnerDeletion": true
				}],
				"managedFields": [{
					"manager": "kube-controller-manager",
					"operation": "Update",
					"apiVersion": "v1",
					"time": "2023-01-17T21:54:00Z",
					"fieldsType": "FieldsV1",
					"fieldsV1": {
						"f:metadata": {
							"f:generateName": {},
							"f:labels": {
								".": {},
								"f:app": {},
								"f:pod-template-hash": {}
							},
							"f:ownerReferences": {
								".": {},
								"k:{\"uid\":\"4f0bd30a-1e10-49f6-8933-e51bc35edd6c\"}": {
									".": {},
									"f:apiVersion": {},
									"f:blockOwnerDeletion": {},
									"f:controller": {},
									"f:kind": {},
									"f:name": {},
									"f:uid": {}
								}
							}
						},
						"f:spec": {
							"f:containers": {
								"k:{\"name\":\"kubectl-test\"}": {
									".": {},
									"f:command": {},
									"f:image": {},
									"f:imagePullPolicy": {},
									"f:name": {},
									"f:resources": {},
									"f:terminationMessagePath": {},
									"f:terminationMessagePolicy": {},
									"f:volumeMounts": {
										".": {},
										"k:{\"mountPath\":\"/etc/localtime\"}": {
											".": {},
											"f:mountPath": {},
											"f:name": {}
										}
									}
								}
							},
							"f:dnsPolicy": {},
							"f:enableServiceLinks": {},
							"f:restartPolicy": {},
							"f:schedulerName": {},
							"f:securityContext": {},
							"f:terminationGracePeriodSeconds": {},
							"f:volumes": {
								".": {},
								"k:{\"name\":\"tz-config\"}": {
									".": {},
									"f:hostPath": {
										".": {},
										"f:path": {},
										"f:type": {}
									},
									"f:name": {}
								}
							}
						}
					}
				}, {
					"manager": "kubelet",
					"operation": "Update",
					"apiVersion": "v1",
					"time": "2023-01-17T21:54:04Z",
					"fieldsType": "FieldsV1",
					"fieldsV1": {
						"f:status": {
							"f:conditions": {
								"k:{\"type\":\"ContainersReady\"}": {
									".": {},
									"f:lastProbeTime": {},
									"f:lastTransitionTime": {},
									"f:status": {},
									"f:type": {}
								},
								"k:{\"type\":\"Initialized\"}": {
									".": {},
									"f:lastProbeTime": {},
									"f:lastTransitionTime": {},
									"f:status": {},
									"f:type": {}
								},
								"k:{\"type\":\"Ready\"}": {
									".": {},
									"f:lastProbeTime": {},
									"f:lastTransitionTime": {},
									"f:status": {},
									"f:type": {}
								}
							},
							"f:containerStatuses": {},
							"f:hostIP": {},
							"f:phase": {},
							"f:podIP": {},
							"f:podIPs": {
								".": {},
								"k:{\"ip\":\"172.17.0.4\"}": {
									".": {},
									"f:ip": {}
								}
							},
							"f:startTime": {}
						}
					}
				}]
			}
		}
	}]
}

 ㅇ Response Body를 정렬한 것이다.

 ㅇ pod의 정보 뿐 아니라 컬럼의 정의와 다른 메타 정보를 확인할 수 있었다.

 ㅇ kubectl은 여기서 필요한 정보만을 간결하게 추출하여 표출하였다.

 

 

ㅁ JWT 추출

 ㅇ kube-apiserver도 여느 API서버와 같이 통신을 위해서는 JWT 토큰이 필요하다. 

TOKEN=$(kubectl get secret $(kubectl get sa default \
    -ojsonpath="{.secrets[0].name}") \
    -ojsonpath="{.data.token}" | base64 -d)

 

 

ㅁ Pod 정보 조회 테스트

curl -k \
     -X GET \
     -H "Authorization: Bearer $TOKEN" \
     https://192.168.64.3:8443/api/v1/namespaces/default/pods
     
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "pods is forbidden: User \"system:serviceaccount:default:default\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
  "reason": "Forbidden",
  "details": {
    "kind": "pods"
  },
  "code": 403
}%

 ㅇ message의 내용에서 default에는 API를 호출할 수 있는 권한이 없음을 알 수 있다.

 

 

 

 

ㅁ 권한 부여 방법

$ kubectl create clusterrolebinding default-cluster-admin --clusterrole cluster-admin --serviceaccount default:default
clusterrolebinding.rbac.authorization.k8s.io/default-cluster-admin created

 ㅇ default 사용자에게 cluster-admin  권한을 부여하였다.

 ㅇ 권한부여 방법은 이곳에서 더 자세히 확인 할 수 있다.

 

 ㅇ 이후 pod 정보 조회가 정상작동하였다.

 

 

ㅁ 정리

  kubectl은 kube-apiserver와의 통신 쉽게 해 줄 수 있는 client 툴이다. 실질적인 동작은 token 정보를 획득하여 curl로 통신하고 있음을 알게 되었다. 근본적인 원리는 kube-apiserver는 API 서버이고, REST API호출로 쿠버네티스와 통신하는 것이다. 이 원리를 이해하고 응용한다면, shell을 통해 간단한 eks 모니터링 프로그램을 만들 수도 있고, Kubernetes SDK를 이용하여 Spring으로 직접 구현할 수도 있을 것이다. 

 

 

ㅁ 함께 보면 좋은 사이트

 

쿠버네티스 API서버는 정말 그냥 API서버라구욧

쿠버네티스 API서버에 대해서 한층 더 가까워지는 시간을 가져봅시다.

coffeewhale.com

 

[K8S] RBAC 의 개념과 Role, RoleBinding, ClusterRole, ClusterRoleBinding

API 서버에 접근하기 위해서는 인증 작업이 필요합니다.Role-based access control(RBAC. 역할 기반 액세스 제어)사용자의 역할에 따라 리소스에 대한 접근 권한을 가짐User: 클러스터 외부에서 쿠버네티스

velog.io

 

반응형
Comments