본문 바로가기

프로그래밍/kubernetes

Kubernetes Mock Exam 정리(Mock Exam 2)

여기서는 총 8문제가 주어졌는데 2개를 몰라서 풀지를 못했다. 하나는 아예 모르겠고, 남은 하나는 문제의 내용을 잘못 파악해서 틀렸다.

 

아예 몰랐던 문제는 이런 문제였다.

 

Create a new user called john. Grant him access to the cluster. John should have permission to create, list, get, update and delete pods in the development namespace. The private key exists in the location: /root/CKA/john.key and csr at /root/CKA/john.csr

 

Important Note: As of kubernetes 1.19, the CertificateSigningRequest object expects a signerName.

 

내가 파악한 의미로는

 

john이란 사용자를 만든다. cluster에 접근허용을 해준다. john은 develpoment namespace의 Pod에 대한 create, list, get,update, delete 권한이 있다. private key는 /root/CKA/john.key이고 csr은 /root/CKA/john.csr 이다.

주의할 점으로는 kubernetes 1.19 에서는 CertificateSigningRequest 객체는 signerName 속성을 갖는다.

 

이렇게 파악했다. 이 부분을 강좌시간때 공부를 했던 내용이고 이것도 내가 정리 내용을 기록한 글에 아마 있을텐데..

복습을 제대로 안했다보니 이게 어디서 본건데 정확히는 모르는 그런 문제였다. 

 

문제에서 주어지는 내용대로 일단 진행해보기로 했다. 문제를 풀지 못했으니 답을 보고 따라 했는데 이 답이 문제가 생겼다. 동영상에서 나오는 답대로 따라 했는데 그렇게 만든 CSR이 approve가 되지 않았던것..이런..

 

그래서 답변을 보니 사람들이 아예 답을 제시해줬다. 그래서 그거대로 따라 해서 성공..보니까 내가 북마크 해둔데에서 그대로 나왔다. 내가 해놓은 북마크는 여기였다. 이 Normal User에서 Create Private key와 Create CertificateSigningRequest 이 부분을 따라한다. 단 Create CertificateSigningRequest 부분을 할때 나는 john.yaml 파일을 별도로 만든뒤 그 파일 안에 Create CertificateSigningRequest 부분에 있는 yaml 내용을 넣었다. metadata.name 항목은 문제에서 csr 이름을 john-developer 로 하라고 지시한게 있어서 그걸로 했다. 그리고 spec.groups 항목을 뺐다(사람들이 답을 제시했을때 spec.groups 항목을 뺐다). spec.request 항목에 넣어야 하는 값은 문서에서도 설명이 있듯이 cat john.csr | base64 | tr -d "\n" 을 실행시켜 나온 결과를 넣었다. 그러면 yaml 모양새가 문제에 맞춰서 구성할 경우 전체적으로 이런 모양이 될 것이다.

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: john-developer
spec:
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBS....(cat john.csr | base64 | tr -d "\n" 를 실행한 결과로 나온 문자열을 넣는다. 길어서 생략)
  signerName: kubernetes.io/kube-apiserver-client
  usages:
  - client auth 

이렇게 yaml 파일을 만든뒤 kubectl create -f john.yaml 을 실행하면 john.yaml 파일을 기반으로 csr을 만들게 된다. 그리고 이렇게 만든 csr은 kubectl get csr 명령을 통해 확인할 수 있다. 이걸 확인해보면 john-developer csr 의 status가 Pending으로 나오게 되는데 이것은 우리가 방금 등록한 CSR에 대한 처리 즉 승인 할건지 거절할건지에 대한 작업을 하지 않아서 대기 상태로 나오게 되는것이다. 이걸 승인하기 위해 kubectl certificate approve john-developer 명령을 실행하자. 그런뒤 kubectl get csr 명령을 실행해보면 아래 그림과 같이 Pending이 아닌 Approved,Issued 로 나오는 것을 확인할 수 있다(Approved,Failed로 나오면 이건 실패한것이다. 풀이 동영상대로 진행하면 Approved,Failed로 나와서 문제가 있었던 것이다). 이 승인하는 과정은 문서의 Normal User에서 Approve certificate signing request 항목에도 나와있다. 이 항목대로 진행하면 된다.

승인된(Approved,Issued) john-developer csr

여기까지 하면 문제의 Create a new user called john. Grant him access to the cluster. 이 부분까지는 진행한 것이다. 이제 다음으로 해야 할 부분은 John should have permission to create, list, get, update and delete pods in the development namespace. 을 진행해야 한다. John이 development namespace에서 Pod에 대한 create, list, get, update, delete 권한을 갖도록 해야하는데 여기서 우리는 Role과 RoleBindings 이 두 가지를 만들어야 한다. Role은 development namespace에서 Pod에 대한 create, list, get, update, delete 권한을 갖고 있는것을 의미하는 것이고 RoleBindings 는 이렇게 만든 Role을 John과 연결시켜주는 것이다.

 

Role은 kubectl에서 다음과 같이 만든다(이거는 kubectl cheet sheet 문서에도 나오지 않는 부분이다)

kubectl create role developer --resource=pods --verb=create,list,get,update,delete --namespace=development

문제에서 role 이름을 developer라고 정의해주어서 developer를 사용했고 pod에 대한 권한이기 때문에 --resources 옵션에 pods 를 주었다. --verb 옵션도 문제에서 정의해준대로 주었고 --namespace 옵션은 문제에 development namespace의 pod이라고 주었기 때문에 development 로 값을 주었다.

 

이제 Role을 만들었으니 John과 Role을 연결시켜주는 RoleBinding을 만들 차례다. RoleBinding은 kubectl 에서 아래와 같이 만든다(이것도 kubectl cheet sheet 문서에는 없다)

kubectl create rolebinding developer-role-binding --role=developer --user=john --namespace=development

rolebinding 이름을 developer-role-binding이라 명명했고 --role 옵션에는 방금 만들었던 role인 developer를 설정했다. --user에는 john을 설정했고 --namespace 옵션에는 development를 사용했다(developer role이 development namespace에 있으니까..)

 

이렇게 해서 전체적인 작업 과정이 완료되었다. 이제 이것을 검증하는 작업을 진행하자. kubectl auth can-i 명령에 옵션을 주어서 이를 검증할 수 있다. 아래와 같이 주면 

kubectl auth can-i update pods --as=john

john 으로 pod을 수정할 수 있는지 체크하게 되는데 결과는 no로 나온다. 왜그러냐면 john 과 연결된 Role인 developer는 namespace가 development에서 동작하는 Role이기 때문이다. 그래서 다시 아래와 같이 namespace를 development로 지정해서 실행하면

kubectl auth can-i update pods -n development --as=john

결과는 yes로 나오게 된다. 이렇게 해서 문제를 풀었다.

 

문제의 내용을 잘못 파악해서 풀지 못한 그 문제는 아래와 같은 내용이었다.

 

Create an nginx pod called nginx-resolver using image nginx, expose it internally with a service called nginx-resolver-service.

Test that you are able to look up the service and pod names from within the cluster.

Use the image: busybox:1.28 for dns lookup.

Record results in /root/CKA/nginx.svc and /root/CKA/nginx.pod

 

내가 파악한 문제의 의미는

 

nginx 이미지를 사용하는 nginx-resolver 라는 Pod을 만들고 이 팟을 내부에서 노출시키는 nginx-resolver-service 라는 service를 만든다

cluster 내부에서 Service와 Pod 이름으로 찾을수 있는지 테스트한다

busybox:1.28 이미지를 사용해서 dns lookup을 한다

결과를 /root/CKA/nginx.svc와 /root/CKA/nginx.pod 으로 만든다.

 

이렇게 파악은 됐었는데..

Service와 Pod 이름으로 찾을수 있는지.. 이 부분에 대한 이해를 Pod을 직접 찾을수 있는지가 아닌 Service를 통해 연결된 Pod을 찾는걸로 생각하다보니..

그 후의 해석들이 전반적으로 꼬이기 시작했다.

그래서 결국엔 nginx.svc와 nginx.pod 파일에 쓰는 것을 Service와 Pod을 생성하는 yaml 을 쓰는걸로 잘못 해석해버렸다.

그러나 문제 풀이를 보고 이것이 무엇을 뜻하는지 알았다. Pod을 Service를 통해 연결되어져서 찾는게 아니라 Service 없이 내부에서 팟을 Direct로 찾는 것을 의미하는 것이었다. 그럼 이제 본격적으로 문제를 풀어보자.

 

Pod과 Service를 만드는 것은 어렵지 않다. 그냥 단순하게 이러면 되니까..

kubectl run nginx-resolver --image=nginx --port=80
kubectl expose pod nginx-resolver --name=nginx-resolver-service --port=80 --target-port=80 --type=ClusterIP

문제는 이 다음부터였다. 이렇게 만든 Pod과 Service가 연결이 되는지 Test 기능 역할을 하는 Pod을 만들어야 했다. busybox:1.28 이미지를 사용해서 Pod을 만들라고는 있지만 구체적으로 어떻게 해야 하는지를 모르겠다. 어떤 명령어를 쓰면 연결관계를 테스트 할 수 있는지..처음에 생각난건 curl이었다. Pod이 nginx 이미지를 사용하다보니 curl을 이용해서 연결해보면 결과로 html source가 나오니 그걸 저장해야 하는건가..하는 생각이 들었다. 그러나 문제 풀이를 보면서 이해를 할 수 있게 되었다. 결론적으로 말하면 리눅스 자체의 지식이 부족한 나의 문제였다. 문제풀이에서는 다음과 같이 Pod을 만들어서 테스트를 했다.

kubectl run test-nslookup --image=busybox:1.28 --restart=Never --rm -it -- nslookup nginx-resolver-service > /root/CKA/nginx.svc
kubectl run test-nslookup --image=busybox:1.28 --restart=Never --rm -it -- nslookup 10-244-2-2.default.pod > /root/CKA/nginx.pod

문제풀이 영상에서는 --restart 옵션을 붙이지 않아도 정상동작이 되었는데 막상 직접 해보니 안되어서 문제풀이 영상에 대한 질의응답을 보니까 --restart=Never 옵션을 붙여야 한다고 나왔다. --rm 옵션은 실행이 끝나면 자동으로 Pod이 삭제되게끔 하는 옵션인데 이게 동작할려면 -it 옵션을 같이 붙여야 한다(Pod이 이미 연결(attach)되어 있는 상태여야 한다는 의미). nslookup을 통해 파라미터로 전달된 이름에 대한 ip를 가져오는 방법을 통해 Service와 Pod을 찾아오는 방법으로 풀었다. 첫번째 줄은 Service인 nginx-resolver-service의 이름 자체를 nslookup의 파라미터로 전달하여 그 결과로 IP를 가져오게 된다. kubernetes는 그 안에 자체 DNS 서버를 운영하는데 Service의 경우 Service의 이름을 DNS에 등록해둔다. 그래서 nslookup 명령어를 사용할 때 서비스 이름만으로도 동작이 가능했던 것이다. 두번째 줄은 Pod인 nginx-resolver에 대해 문제를 풀은건데 Service와는 다른 구조로 되어 있다. 10-244-2-2.default.pod 을 던지는데 이것을 해석하는 방법은 Pod이 가지고 있는 IP.Pod이 속한 namespace.Resource 타입 으로 보면 된다. Pod이 가지고 있는 IP는 kubectl get pod -o wide 하면 나오게 되는데 이 Pod이 가지고 있던 IP는 10.244.2.2 이다. IP를 표현할때 . 대신 -를 사용한것이다(DNS 이름에서는 .은 이미 예약되어 있기 때문에 사용할 수 없으니까..) 그리고 이 Pod이 속한 namespace가 default여서 default가 들어간 것이고, 마지막엔 해당 Resource Type이 pod 이니까 pod을 넣은것이다. 그래서 이런식으로 문제를 풀게 되었다.