-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Chapter 8. 애플리케이션에서 파드 메타데이터와 그 외의 리소스에 액세스하기 #9
Comments
8.2 쿠버네티스 API 서버와 통신하기
8.2.1 쿠버네티스 REST API 살펴보기
$ kubectl cluster-info
Kubernetes control plane is running at https://34.68.118.85
GLBCDefaultBackend is running at https://34.68.118.85/api/v1/namespaces/kube-system/services/default-http-backend:http/proxy
KubeDNS is running at https://34.68.118.85/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
KubeDNSUpstream is running at https://34.68.118.85/api/v1/namespaces/kube-system/services/kube-dns-upstream:dns/proxy
Metrics-server is running at https://34.68.118.85/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy
$ curl https://34.68.118.85 -k
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
"reason": "Forbidden",
"details": {},
"code": 403
}
$ kubectl proxy
Starting to serve on 127.0.0.1:8001
$ curl http://localhost:8001
{
"paths": [
"/.well-known/openid-configuration",
"/api", # 리소스 타입들
"/api/v1",
"/apis",
"/apis/",
"/apis/admissionregistration.k8s.io",
"/apis/admissionregistration.k8s.io/v1",
"/apis/apiextensions.k8s.io",
"/apis/apiextensions.k8s.io/v1",
"/apis/apiregistration.k8s.io",
"/apis/apiregistration.k8s.io/v1",
"/apis/apps",
"/apis/apps/v1",
...
"/apis/batch", # 배치 API 그룹
"/apis/batch/v1",
...
$ curl http://localhost:8001/apis/batch
{
"kind": "APIGroup",
"apiVersion": "v1",
"name": "batch",
"versions": [ # 배치 API 그룹은 2가지 버전을 갖는다.
{
"groupVersion": "batch/v1",
"version": "v1"
},
{
"groupVersion": "batch/v1beta1",
"version": "v1beta1"
}
],
"preferredVersion": { # 클라이언트는 v1 버전을 사용해야 한다.
"groupVersion": "batch/v1",
"version": "v1"
}
$ curl http://localhost:8001/apis/batch/v1
{
"kind": "APIResourceList", # batch/v1 API 그룹내의 API 리소스 목록
"apiVersion": "v1",
"groupVersion": "batch/v1",
"resources": [
{
"name": "cronjobs", # 네임스페이스 지정된(true로 설정된) 잡 리소스에 관한 설명 (/apis/batch/v1/cronjobs)
"singularName": "",
"namespaced": true,
"kind": "CronJob",
"verbs": [ # 사용할 수 있는 동사(동작)
"create",
"delete",
"deletecollection",
"get",
"list",
"patch",
"update",
"watch"
],
},
{
"name": "cronjobs/status", # cronjobs 의 상태만 변경 가능한 API 엔드포인트
"singularName": "",
"namespaced": true,
"kind": "CronJob",
"verbs": [
"get",
"patch",
"update"
]
},
....
}
]
$ curl http://localhost:8001/apis/batch/v1/jobs
{
"kind": "JobList",
"apiVersion": "batch/v1",
"metadata": {
"resourceVersion": "449081"
},
"items": [] 처음엔 아무 잡도 없기 때문에 items 가 비어있다. apiVersion: batch/v1
kind: Job
metadata:
name: my-job
spec:
template:
metadata:
labels:
app: batch-job
spec:
restartPolicy: OnFailure
containers:
- name: main
image: luksa/batch-job # 교재에서 제공해주는 샘플 잡 $ kubectl apply -f my-job.yaml
Warning: Autopilot set default resource requests for Job default/my-job, as resource requests were not specified. See http://g.co/gke/autopilot-defaults
job.batch/my-job created
$ curl http://localhost:8001/apis/batch/v1/jobs
{
"kind": "JobList",
"apiVersion": "batch/v1",
"metadata": {
"resourceVersion": "451356"
},
"items": [
{
"metadata": {
"name": "my-job", # 방금 띄워준 my-job 이 Items에 조회된다.
"namespace": "default",
"uid": "0268927a-5050-480f-9423-826c1545f06e",
"resourceVersion": "451332",
"generation": 1,
"creationTimestamp": "2023-01-07T15:06:31Z",
"labels": {
"app": "batch-job"
},
....
]
}
$ curl http://localhost:8001/apis/batch/v1/namespaces/default/jobs/my-job
{
"kind": "Job",
"apiVersion": "batch/v1",
"metadata": {
"name": "my-job",
"namespace": "default",
"uid": "0268927a-5050-480f-9423-826c1545f06e",
"resourceVersion": "454271",
"generation": 1,
"creationTimestamp": "2023-01-07T15:06:31Z",
"labels": {
"app": "batch-job"
},
...
}
$ kubectl get job my-job -o json
{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"annotations": {
"autopilot.gke.io/resource-adjustment": "{\"input\":{\"containers\":[{\"name\":\"main\"}]},\"output\":{\"containers\":[{\"limits\":{\"cpu\":\"500m\",\"ephemeral-storage\":\"1Gi\",\"memory\":\"2Gi\"},\"requests\":{\"cpu\":\"500m\",\"ephemeral-storage\":\"1Gi\",\"memory\":\"2Gi\"},\"name\":\"main\"}]},\"modified\":true}",
"batch.kubernetes.io/job-tracking": "",
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"batch/v1\",\"kind\":\"Job\",\"metadata\":{\"annotations\":{},\"name\":\"my-job\",\"namespace\":\"default\"},\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"app\":\"batch-job\"}},\"spec\":{\"containers\":[{\"image\":\"luksa/batch-job\",\"name\":\"main\"}],\"restartPolicy\":\"OnFailure\"}}}}\n"
},
"creationTimestamp": "2023-01-07T15:06:31Z",
"generation": 1,
"labels": {
"app": "batch-job"
},
"name": "my-job",
"namespace": "default",
"resourceVersion": "454271",
"uid": "0268927a-5050-480f-9423-826c1545f06e"
},
...
} 8.2.2 파드 내에서 API 서버와 통신
apiVersion: v1
kind: Pod
metadata:
name: curl
spec:
containers:
- name: main
image: tutum/curl # 컨테이너에서 curl을 사용해야 하기 때문에 tutum/curl 이미지 사용
command: ["sleep", "9999999"] # 컨테이너가 계속 실행되도록 하려고 지연 시간이 길게 sleep 커맨드를 실행한다. 위와 같이 띄우면 Docker Image 를 pulling 해올때 아래와 같이 에러가 발생한다. kubectl get pods
NAME READY STATUS RESTARTS AGE
curl 0/1 ImagePullBackOff 0 4m1s
$ kubectl exec -it curl bash
root@curl:/# 위와 같이 bash 명령을 날리면 $PATH 경로를 찾을 수 없다고 나와서(아마도 환경변수 설정이 안되있는듯) /bin/sh 로 명령을 날려야 한다. $ kubectl exec -it curl /bin/sh
/ $
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.8.128.1 <none> 443/TCP 11h / $ env | grep KUBERNETES_SERVICE
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_HOST=10.8.128.1
$ kubectl exec -it curl /bin/sh
/ $ curl https://kubernetes
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above. 하지만 조회하려고 하면 위와 같이 서버 인증서 확인이 안되었기 때문에 조회가 실패한다.
/ $ ls /var/run/secrets/kubernetes.io/serviceaccount/
ca.crt namespace token 위 파일중 ca.crt 파일이 API 서버의 인증서를 서명하는 데 사용되는 인증 기관(CA)의 인증서이다. / $ curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt https://kubernetes
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
"reason": "Forbidden",
"details": {},
"code": 403
} 아직 인증에 실패한다.
/$ export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt 아래와 같이 동일한 명령을 간단하게 요청할 수 있다. (아직 인증은 안됨) / $ curl https://kubernetes
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
"reason": "Forbidden",
"details": {},
"code": 403
}
/$ TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) 환경변수 토큰을 활용해서 API 서버에 억세스 해본다. / $ curl -H "Authorization: Bearer $TOKEN" https://kubernetes
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "forbidden: User \"system:serviceaccount:default:default\" cannot get path \"/\"",
"reason": "Forbidden",
"details": {},
"code": 403
} 여전히 실패한다....
$ kubectl create clusterrolebinding permissive-binding --clusterrole=cluster-admin --group=system:serviceaccounts
clusterrolebinding.rbac.authorization.k8s.io/permissive-binding created 이제 아래와 같이 모든 API 서버를 정상 조회할 수 있다. 👍 / $ curl -H "Authorization: Bearer $TOKEN" https://kubernetes
{
"paths": [
"/.well-known/openid-configuration",
"/api",
"/api/v1",
"/apis",
"/apis/",
"/apis/admissionregistration.k8s.io",
"/apis/admissionregistration.k8s.io/v1",
"/apis/apiextensions.k8s.io",
"/apis/apiextensions.k8s.io/v1",
"/apis/apiregistration.k8s.io",
"/apis/apiregistration.k8s.io/v1",
"/apis/apps",
"/apis/apps/v1",
...
]
}
/ $ NS=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
/ $ curl -H "Authorization: Bearer $TOKEN" https://kubernetes/api/v1/namespaces/$NS/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "489452"
},
"items": [
{
"metadata": {
"name": "curl",
"namespace": "default",
...
},
...실행중인 모든 파드...
} 위와 같은 방식으로 다른 API 오브젝트를 검색하고 GET, PUT, PATCH 를 전송해 업데이트도 할 수 있다. 💯
8.2.3 앰배서더 컨테이너를 이용한 API 서버 통신 간소화
apiVersion: v1
kind: Pod
metadata:
name: curl-with-ambassador
spec:
containers:
- name: main
image: curlimages/curl # 여기도 curlimages/curl 로 바꿔준다
command: ["sleep", "9999999"]
- name: ambassador
image: luksa/kubectl-proxy:1.6.2 # kubectl-rpoxy 이미지를 실행하는 앰버서더 컨테이너 이미지 bash 명령도 /bin/sh 로 바꿔서 실행해본다. $ kubectl exec -it curl-with-ambassador -c main /bin/sh
/ $ 위처럼 컨테이너가 두개여서 -c옵션을 통해 main 컨테이너라는걸 명시해줘야 한다.
/ $ curl localhost:8001
{
"paths": [
"/.well-known/openid-configuration",
"/api",
"/api/v1",
"/apis",
"/apis/",
"/apis/admissionregistration.k8s.io",
"/apis/admissionregistration.k8s.io/v1",
"/apis/apiextensions.k8s.io",
"/apis/apiextensions.k8s.io/v1",
"/apis/apiregistration.k8s.io",
"/apis/apiregistration.k8s.io/v1",
"/apis/apps",
"/apis/apps/v1",
...
]
} 복잡성을 숨기고, 메인컨테이너를 단순화시킬 수 있고 여러 어플리케이션에서 재사용 할 수 있지만, 추가프로세스와 추가리소스를 소비한다는것이 단점이다. 8.2.4 클라이언트 라이브러리를 사용해 API 서버와 통신
import java.util.Arrays;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodList;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
public class Test {
public static void main(String[] args) throws Exception {
KubernetesClient client = new DefaultKubernetesClient();
// list pods in the default namespace
PodList pods = client.pods().inNamespace("default").list();
pods.getItems().stream()
.forEach(s -> System.out.println("Found pod: " +
s.getMetadata().getName()));
// create a pod
System.out.println("Creating a pod");
Pod pod = client.pods().inNamespace("default")
.createNew()
.withNewMetadata()
.withName("programmatically-created-pod")
.endMetadata()
.withNewSpec()
.addNewContainer()
.withName("main")
.withImage("busybox")
.withCommand(Arrays.asList("sleep", "99999"))
.endContainer()
.endSpec()
.done();
System.out.println("Created pod: " + pod);
// edit the pod (add a label to it)
client.pods().inNamespace("default")
.withName("programmatically-created-pod")
.edit()
.editMetadata()
.addToLabels("foo", "bar")
.endMetadata()
.done();
System.out.println("Added label foo=bar to pod");
System.out.println("Waiting 1 minute before deleting pod...");
Thread.sleep(60000);
// delete the pod
client.pods().inNamespace("default")
.withName("programmatically-created-pod")
.delete();
System.out.println("Deleted the pod");
}
}
|
8.3 요약
|
No description provided.
The text was updated successfully, but these errors were encountered: