본문 바로가기

프로그래밍/kubernetes

Kubernetes Mock Exam 정리(Mock Exam 3)

누군가 이 동영상 강좌의 후기를 CKA 후기에 같이 써놓은게 있어서 본적이 있었다. 그때 Mock Exam에 대한 내용도 언급했었는데 난이도가 1,2,3 순으로 어렵다고 하더니만 진짜 그러했다. 솔까말(이게 솔직히 까놓고 말해서..의 줄임말란걸 얼마전에 알았음..얼마나 쉰세대가 되어가고 있는지..) 이 시험을 전혀 우습게 보지 않고 대비한건데..그래도 1달 빡씨게 준비하고 시험에 응하면 될꺼라 생각했다. 근데 Mock Exam 3를 보고 아직도 나는 갈길이 멀었음을 깨달았다. 프리 일 끝나고 다른 일 구하는 동안 1달만 투자해서 따야지 하는 마인드였는데..공부하며 정리하다보니 시간도 벌써 3주차에 들어섰다. 원래 이거 강좌 한번 정리해놓고 다시 한번 첨부터 동영상 복습하면서 정리한 내용보고 문제 다시 풀고 마무리 할 요량이었는데..정리하는데 시간이 많이 투자되었다. 한 달 더 봐야 할 요량도 하고 있다. 대신 그거 한달 더 추가하면서 CKAD 까정 같이 할 생각이다.

어쨌든 초반 얘기가 길었는데 이 Mock Exam 3는 9문제가 나왔는데 나는 3문제를 풀었고 그나마 그 3문제 중에 1개는 틀렸다..쩝..하지만 Mock Exam 3는 다양한 내용을 다루어서 공부를 할 가치는 있었다. 내가 못풀거나 틀린 문제에 대해 다뤄보도록 하겠다.

 

1. 문제의 내용은 이랬다

 

Create a new service account with the name pvviewer. 

Grant this Service account access to list all PersistentVolumes in the cluster by creating an appropriate cluster role called pvviewer-role and ClusterRoleBinding called pvviewer-role-binding.
Next, create a pod called pvviewer with the image: redis and serviceAccount: pvviewer in the default namespace

 

내가 문제를 이해한 바로는 이랬다

 

pvviewer 라는 이름의 ServiceAccount를 만든다

PersistentVolume을 list 하는 cluster role인 pvviewer-role과 pvviewer-role-binding 으로 불리는 ClusterRoleBinding에 ServiceAccount가 접근한다

다음에 redis 이미지와 ServiceAccount pvviewer를 가지고 default namespace에 pvviewer라 불리는 Pod을 생성한다.

 

정리하자면 ServiceAccount 만들고, PersistentVolumes의 list를 허용하는 Cluster Role 인 pvviewer-role을 만들고 ClusterRoleBing인 pvviewer-role-binding을 만들어 ServiceAccount와 연결을 시킨뒤 redis 이미지를 사용하고 ServiceAccount를 사용하는 pvviewer 라는 Pod을 default namespace에 만드는 것이다. 설명상으로는 장황하지만 한단계씩 풀어나가면 그리 어렵지는 않다.

 

나는 처음에 이것을 kubernetes의 문서에서 검색해서 일일이 yaml을 만들어서 진행했는데 kubectl 명령으로도 ServiceAccount와 ClusterRole, ClusterRoleBinding을 모두 만들수 있었다. 아래는 kubectl을 이용해서 만드는 방법이다.

kubectl create serviceaccount pvviewer
kubectl create clusterrole pvviewer-role --verb=list --resource=pv
kubectl create clusterrolebinding pvviewer-role-binding --clusterrole=pvviewer-role --serviceaccount=default:pvviewer

이렇게 ServiceAccount와 ClusterRole, ClusterRoleBinding을 만들면 이제 이렇게 연결관계가 형성된 ServiceAccount를 사용하는 Pod을 만들면 된다. 다만 Imperative 한 방법으로 생성할 경우 ServiceAccount 관련 설정을 할 수 없기 때문에 이 부분에 대한 설정을 하기 위해 yaml 파일로 뺀 뒤 yaml 파일 안에서 ServiceAccount 관련 설정을 진행한다.

kubectl run pvviewer --image=redis --dry-run=client -o yaml > pvviewer.yaml
apiVersion: v1
metadata:
  labels:
    run: pvviewer
  name: pvviewer
spec:
  containers:
  - image: redis
    name: pvviewer
    resources: {}
  serviceAccountName: pvviewer

근데 이게 좀 이상한것이 처음에 이대로 했을때는 대략 이런 에러가 발생하면서 Pod이 만들어지지 않았다. 실제로 이런 에러가 발생한다고 질문들이 올라왔었다.

 

Error from server (ServerTimeout): error when creating "pvviewer.yaml": No API token found for service account "pvviewer", retry after the token is automatically created and added to the service account

 

그러다가 시험환경이 타임아웃이 되어서 다시 시험환경을 만들어서 똑같이 진행해보니 에러가 발생하질 않았다. 풀이는 맞는거 같긴 한데..모르겠다

 

2. 문제의 내용은 이랬다.

 

List the InternalIP of all nodes of the cluster. Save the result to a file /root/CKA/node_ips

Answer should be in the format: InternalIP of master<space>InternalIP of node1<space>InternalIP of node2<space>InternalIP of node3 (in a single line)

 

내가 문제를 이해한바로는 이랬다.

 

모든 Node들의 InternalIP 항목을 조회해서 /root/CKAnode_ips 파일에 저장한다.

답안은 master InternalIP 공백 node1 InternalIP 공백 node2 internalIP 공백 node3 internalIP

이렇게 한줄로 표현하는 것이다.

 

jsonpath로 질의하는것이었는데 구조까지는 파악했으나 이걸 jsonpath 형태의 질의문으로 만들지를 못했다. 근데 답안은 정말 엉뚱한 곳에 있었다

 

kubectl cheet sheet 문서에 보면 각 노드의 ExternalIP를 구하는 방법으로 다음과 같은 것이 있었다.

# Get ExternalIPs of all nodes
kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'

여기서 ExternalIP를 InternalIP로 바꾸면 된다. 구조도 items 배열 안에서 status.address 배열에 있는 값들의 각 항목에서 type 항목이 InternalIP 인것의 address를 출력하면 맞다. 그래서 정답은 다음과 같다.

kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="InternalIP")].address}' > /root/CKA/node_ips

근데 나는 이것을 정답이라 인정하기가 어렵다. 왜냐면 이 풀이법은 node 출력 결과가 master node, node1, node2, node3 이런식으로 정렬이 되어서 나온다는 전제하에서 성립되기 때문이다. 만약 node 출력 결과가 저 순서대로 나오지 않을 경우 이 방법으로 문제를 풀면 원하는 답이 나오지 않게 된다. 만약 문제에서 출력 순서를 정하지 않고 그냥 나오는대로 출력하라고 했으면 이게 답이 되지만 저렇게 출력 순서를 정했을경우에 저 답안은 각 node의 출력 결과가 저 순서대로 나온다는 보장도 없는 상황에서는 사용할 수 없다. 내가 저것때문에 각각을 따로따로 구하는 jsonpath를 만들려고 고민하다가 하지를 못했었다. 그러나 이것과 관련이 있는 댓글은 아니지만 문제를 푸는 방법이 이렇게 하든 저렇게 하든 답안에서 원하는 결과만 나오면 채택된다는 식의 답변이 있기는 하다. 

 

3. 문제의 내용은 이랬다.

 

Create a pod called multi-pod with two containers.
Container 1, name: alpha, image: nginx
Container 2: beta, image: busybox, command sleep 4800.

Environment Variables:
container 1:
name: alpha

Container 2:
name: beta

 

내가 문제를 이해한바로는 이랬다.

 

multi-pod 이란 이름으로 2개의 container가 있는 pod을 만든다.

container1의 이름은 alpha, nginx 이미지를 사용하고

container2의 이름은 beta, busybox 이미지를 사용하고 sleep 4800을 사용한다

 

container1 에는 name=alpha 란 환경변수를 주고

container2 에는 name=neta 란 환경변수를 준다.

 

이거는 내가 풀었지만 결국 틀렸다. 환경변수 주는 부분을 잘못 설정했다.

문제 자체는 어려운 것이 아니다 1개의 container가 실행되는 Pod의 yaml 에서 container를 1개 더 추가하면 되니까..

다만 환경변수 설정하는 부분에서 실수를 했다. 

 

다음과 같이 진행하면 된다. 먼저 1개의 container만 실행되는 Pod의 yaml 파일을 만든다.

kubectl run multi-pod --image=nginx --dry-run=client -o yaml > multi-pod.yaml

그러면 문제에서 nginx 이미지를 실행하는 container 1개가 있는 이름이 multi-pod인 pod을 만드는 yaml 파일이 생성된다. 이제 이 파일을 열어서 나머지 조건을 충족하게끔 yaml 파일을 수정하면 된다. 최종 yaml 파일은 다음과 같다.

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: multi-pod
  name: multi-pod
spec:
  containers:
  - image: nginx
    name: alpha
    env:
    - name: name
      value: alpha
  - image: busybox
    name: beta
    command: ["sleep", "4800"]
    env:
    - name: name
      value: beta

이 yaml 로 Pod을 만들면 된다. 여기서 내가 실수한 부분은 env를 설정하는 부분이었다. alpha container에 환경변수 name=alpha를 줄때 나는 다음과 같이 했다

    env:
    - name: alpha

이렇게 설정하고 Pod을 만들어도 에러가 발생하지 않는다. 다만 kubectl describe로 해당 Pod을 보게 되면 환경변수가 alpha: 

이런 식으로 보인다. describe를 한번 실행해서 저걸 본거 같았는데 저때 잘못된걸 알았어야 했는데 잘 챙기지를 못했다. 문제에서 환경변수 이름을 name으로 준것도 저런 함정(?)을 판거라고 생각한다.

 

4. 문제의 내용은 이러했다

 

Create a Pod called non-root-pod , image: redis:alpine
runAsUser: 1000
fsGroup: 2000

 

내가 문제를 이해한바로는 이랬다

 

redis:alpine 이미지를 사용하는 이름이 non-root-pod인 Pod을 생성한다

 

나머지 runAsUser: 1000 과 fsGroup: 2000 이 부분은 Mock Exam 2에서 SecurityContext 항목 설정시 참고했던 Pod 생성하는 yaml 에 저것들을 설정하던 부분이 생각나서 그 문서를 다시 kubernetes 문서에서 검색해서 구현했다. 먼저 다음을 실행해서 pod을 생성하는 yaml 파일을 만든다

kubectl run non-root-pod --image=redis:alpine --dry-run=client -o yaml > non-root-pod.yaml

그리고 만들어진 yaml 파일의 내용을 다음과 같이 수정한다

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: non-root-pod
  name: non-root-pod
spec:
  securityContext:
    runAsUser: 1000
    fsGroup: 2000
  containers:
  - image: redis:alpine
    name: non-root-pod

이렇게 yaml 파일 내용을 수정한뒤 이 yaml 로 Pod을 만들면 된다(kubectl create -f non-root-pod.yaml) 이걸 검증하는 방법은 만들어진 Pod에서 실행중인 container 안으로 들어가서 id를 실행하면 된다. container 안으로 들어가는 방법은 다음의 명령을 실행하면 된다. 

kubectl exec -it non-root-pod -- sh

이걸 실행하면 shell script prompt가 뜨는 상태에서 입력을 기다리게 되는데 이때 id를 입력하면 다음과 같은 결과가 나온다.

/data $ id
uid=1000 gid=0(root) groups=2000

securityContext를 설정하지 않았으면 root 계정으로 들어가지기 때문에 uid 항목이 0으로 나와야 하지만 Pod을 생성할때 runAsUser를 1000 으로 설정했기 때문에 uid가 1000으로 나오게 된다.

 

5. 문제의 내용은 이러했다

 

We have deployed a new pod called np-test-1 and a service called np-test-service. 

Incoming connections to this service are not working. 

Troubleshoot and fix it.
Create NetworkPolicy, by the name ingress-to-nptest that allows incoming connections to the service over port 80

 

Important: Don't delete any current objects deployed.

 

np-test1이라는 새로운 Pod과 np-test-service 라는 service를 만들어서 배포했다.

이 서비스 안으로 접속하는 것이 동작하지 않는다. 

이 오류를 고쳐라.

80 포트를 통해 안으로 들어오는 통신을 허용하는 ingress-to-nptest 라 이름이 불리우는 NetworkPolicy를 생성한다

중요: 그 어떤 객체로 삭제하지 말것

 

이 얘기인 즉슨 객체를 삭제(삭제 후 재생성도 포함)하지 않고 문제를 해결하라는 뜻이다. 네트워크 연결이 안되니 먼저 생각해볼 지점은 Service와 Pod이 제대로 연결되었는지 확인해보는 것이다. 아래의 그림을 보자

np-test-1 pod과 np-test-service의 연결이 잘 이뤄졌는지 확인

문제를 이렇게 냈을때는 적어도 둘사이의 연결 설정 자체는 잘 했을꺼라고 생각하지만 혹시나 하는 맘에 확인해본다. pod을 출력할때 --show-labels 옵션을 줘서 label로 같이 출력하게 했는데 np-test-1 pod의 label을 보면 run=np-test-1으로 되어 있다. 이제 Service인 np-test-service가 np-test-1 pod으로의 연결 설정이 되어 있는지 확인해보자. describe로 np-test-service를 확인해보면 Selector 항목에 nrun-np-test-1 으로 되어 있음을 확인할 수 있다. Pod의 label이 Service의 Selector에 설정되어야 Pod이 Service와 연결이 되기 때문에 지금까지의 상황만 놓고 보면 정상적인 설정이라 볼 수 있다. 그림에서는 누락되어 있는데 Pod에서 사용된 이미지는 nginx 이미지를 사용했기 때문에 80포트를 사용한다.

 

그러면 네트워크 통신 문제라는건데..이를 확인하기 위해 Mock Exam 2에서 DNS lookup 테스트 용도로 임시용 Pod을 만든것처럼 네트워크 통신을 체크하기 위한 Test용 Pod을 만들어서 테스트를 해본다. 아래의 그림은 그런 테스트 과정을 보여준다.

Network Test Pod을 이용해서 Service와 Pod을 대상으로 한 통신 테스트

위의 그림에서와 같이 busybox:1.28 이미지를 이용해서 임시 테스트용 Pod을 만들고 sh 명령을 실행시켜서 shell script 명령을 입력받을수 있는 상태로 해놓은뒤 2개의 명령을 실행했다. Service 이름인 np-test-service는 kubernetes cluster 안에서 동작하는 DNS 서버에 Domain 이름으로도 등록되기 때문에 서비스 이름 자체로 통신 체크가 가능하여서 nc 명령어로 Service 이름을 이용한 Service 로의 연결 체크를 확인했고, 두번째는 np-test-1 Pod이 가지고 있는 IP가 10.40.0.1 이기 때문에 이 ip를 이용한 Pod의 직접 연결 테스트를 진행해봤다. 둘다 모두 실패했다. 정리하자면 Pod 안으로 들어가는 통신이 막혀있으니 그 Pod과 연결되어 있는 Service를 통한 접근도 같이 안되는 것이다. 

 

이렇게 Kubernetes 에서 방향성(Inbound, Outnoud)을 가지고 통신을 제어할 수 있는 Resource는 NetworkPolicy(netpol)이다. 이제는 이것을 확인해볼 차례다. 아래의 그림을 보자.

NetworkPolicy 확인

default namespace에 NetworkPolicy를 확인해보면 default-deny 란 이름의 NetworkPolicy가 있음을 확인할 수 있다. describe를 이용해서 상세내용을 확인해보면 Ingress Policy Type으로 지정된 상태에서 Annotations.PodSelector가 None으로 되어 있음을 확인할 수 있는데 항목 옆에 설명에도 있다시피 이 namespace의 모든 Pod들로의 특정 트래픽을 허용하는 것이 결국 없다(None)는 것이고 Allowing ingress traffic 이 none 이기 때문에 ingress 통신이 허용된 Pod이 없음을 뜻하게 된다. 정리하자면 이 namespace 안에 있는 자원들을 접속하는 통신이 모두 허용이 안되는 것이다. 그래서 Service와 Pod을 접속하는 통신을 할 수 없게 된 것이다. 그럼 어떻게 해결해야 할까? 단순하게 해결하는 방법은 default-deny Network Policy를 삭제하면 된다. 그러나 그럴수 없다. 문제에서 나왔듯이 자원을 삭제하지 말라고 했으니까..

 

그러면 이 부분은 이렇게 설계해야 한다. np-test-1만 Ingress 통신을 허용하고 그걸 제외한 나머지는 default-deny NetworkPolicy를 통해 Ingress 통신을 막으면 된다. 그러면 np-test-1의 Ingress 통신을 허용하는 NetworkPolicy를 다음과 같이 만들어보자.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: ingress-to-nptest
  namespace: default
spec:
  podSelector:
    matchLabels:
      run: np-test-1
  policyTypes:
  - Ingress
  ingress:
  - ports:
    - protocol: TCP
      port: 80

metadata.name 항목에 ingress-to-nptest로 설정함으로써 NetworkPolicy의 이름을 ingress-to-nptest로 등록하게 되고, 

metadata.namespace 항목에 default를 설정해서 이 NetworkPolicy가 default namespace에 등록되게끔 한다. spec.podSelector.matchLabels 항목에 np-test-1 Pod의 label인 run: np-test-1 을 설정함으로써 이 NetworkPolicy가 np-test-1 Pod에 적용되도록 설정하고 spec.policyTypes 항목에 Ingress 만 넣어서 Ingress 통신에만 적용되도록 했다. spec.ingress.ports 항목에 각각 TCP Protocol 과 80 포트를 설정해서 80포트로의 통신을 명시했다. 이 모든걸 정리해서 한 문장으로 요약하면

 

run: np-test-1 Label을 가지고 있는 Pod(np-test-1)에 80포트로의 Ingress 통신을 허용하는 ingress-to-nptest 란 이름의  NetworkPolicy 

 

이렇게 되는 것이다.

 

이제 이 yaml 파일을 kubectl을 통해 NetworkPolicy로 등록한뒤 위에서 진행했던 테스트 방법을 다시 해보면 아래 그림과 같은 결과를 얻을 수 있다.

Ingress NetworkPolicy 추가 한 뒤 테스트 결과 화면

np-test-1 Pod으로 직접 외부에서 연결을 시도하면 정상 동작 되고 이 Pod 과 연결되어 있는 Service인 np-test-service를 통해서 연결을 시도하면 정상 동작 되는 것을 확인할 수 있다

 

6. 문제의 내용은 이랬다

 

Taint the worker node node01 to be Unschedulable. 

Once done, create a pod called dev-redis, image redis:alpine to ensure workloads are not scheduled to this worker node.

Finally, create a new pod called prod-redis and image redis:alpine with toleration to be scheduled on node01.

 

내가 이해한 것은 이러했다

 

worker node node01에 Pod이 배포되지 않도록 taint를 설정한다

그런 후 redis:alpine을 이미지를 사용하는 dev-redis Pod을 만든뒤 이 worker node에 Pod이 배포되지 않도록 한다

마지막으로 redis:alpine 이미지를 사용하는 prod-redis Pod을 만든뒤 node01에 배포되도록 toleration을 설정한다

 

문제에서는 다음의 내용도 알려준다

 

key:env_type, value:production, operator: Equal and effect:NoSchedule

 

이것은 taint를 설정할때 key, value를 설정해야 하는데 그것을 어떤 값으로 설정하는지를 알려준다. 그리고 배포가 안되게끔 하기 위해 effect를 NoSchedule로 설정하라고 한다

 

먼저 node01 에 다음의 명령을 실행하여 taint를 설정하자

kubectl taint nodes node01 env_type=production:NoSchedule

taint가 설정되었는지는 아래의 명령을 실행해보면 확인할 수 있다.

kubectl describe nodes node01 | grep -i taint

그 다음으로 해야 할 것은 redis-alpine 이미지를 사용하는 dev-redis Pod을 만들어서 이 Pod이 node01 에 배포되는지를 확인하는 것이다.

kubectl run dev-redis --image=redis:alpine

이렇게 한 뒤 kubectl get pod -o wide 를 실행하면 dev-redis Pod이 node01에는 배포되지 않는 것을 확인할 수 있다. node01에 taint 가 설정되어 있기 때문에 Pod에 해당 taint에 대한 toleration이 있지 않는 한에는 taint가 설정되어 있는 Node에 Pod 이 배포되지 않는다.

 

그러면 위에서 설정한 taint에 대응하는 toleration이 설정된 redis:alpine 이미지를 사용하는 prod-redis Pod을 만들어서 배포해보자. 현재 실행중인 Pod인 dev-redis를 이용해서 Pod을 생성하는 yaml을 만든뒤 아래와 같이 yaml 내용을 수정한다

apiVersion: v1
kind: Pod
metadata:
  name: prod-redis
spec:
  containers:
  - image: redis:alpine
    name: prod-redis
  tolerations:
  - effect: NoSchedule
    key: env_type
    value: production
    operator: Equal

이 파일을 이용해서 Pod을 배포한뒤에 kubectl get pods -o wide 를 실행해보면 prod-redis Pod이 node01에 배포된 것을 확인할 수 있다.

 

7. 문제의 내용은 이랬다

 

A kubeconfig file called super.kubeconfig has been created under /root/CKA. 

There is something wrong with the configuration. 

Troubleshoot and fix it.

 

내가 이해한 것은 이러했다

 

kubeconfig file인 super.kubeconfig 파일이 /root/CKA 디렉토리에 생성됐다

설정에 무언가 잘못된 것이 있다.

이를 찾아서 고친다.

 

현재 실행중인 kubernetes cluster 의 config 파일은 /root 디렉토리 밑에 hidden 디렉토리로 .kube 디렉토리가 있고 이 디렉토리 안에 있는 config 파일로 실행되고 있다.

이 config 파일과 예시로 나온 /root/CKA/super.kubeconfig 파일을 비교해보고 차이점을 찾으면 된다.

비교해보니 config 파일의 clusters.cluster.server 항목엔 https://172.17.0.31:6443으로 값이 설정되어 있으나 /root/CKA/super.config 파일에는 이 값이 https://172.17.0.31:2379로 값이 설정되어 있었다.

포트번호 부분을 수정 후 저장한뒤 다음의 명령어를 이용해서 설정파일을 검증해보면 확인할 수 있다

kubectl cluster-info --kubeconfig=/root/CKA/super.kubeconfig

8. 문제의 내용은 이랬다

 

We have created a new deployment called nginx-deploy. 

scale the deployment to 3 replicas. 

Has the replica's increased? Troubleshoot the issue and fix it.

 

내가 이해한 것은 이러했다

 

nginx-deploy로 불리는 deployment를 생성했다

deployment의 replicas를 3으로 설정한다

replicas에 설정된 수치로 Pod 갯수가 맞춰지는가? 문제의 이슈를 찾아서 고친다

 

먼저 다음의 명령어를 사용해서 nginx-deploy의 replicas 를 3으로 설정한다

kubectl scale deployment nginx-deploy --replicas=3

이렇게 한뒤 nginx-deploy를 확인해보면 replicas는 3으로 되어 있는것은 확인이 되었으나 Pod이 3개가 생성되어 있지 않았다. 기존의 1개만 생성되어 있는 상태로 유지되고 있는 상황이었다. 이 상황을 보고 처음에 문득 생각이 들었던건 다른 node에 taint가 걸려있어서 그런건가 생각했는데 그것도 아닌것이 만약 taint가 걸려있으면 현재 생성되어 있는 node로 3개가 생성되어 있어야 하는데 그것도 아니었다. nginx-deploy 에 대해 kubectl describe를 해봐도 딱히 나오는 내용이 없었고 이 deploy가 기존에 생성해 놓은 Pod에 대해 kubectl describe를 해봐도 또한 나오는게 없었다. 그러면 생각해볼것은 kube-system namespace에 있는 kubernetes cluster 운영과 관련된 Pod들이 문제가 있는지 확인해보야 할것 같아서 확인을 해보니 다음 그림과 같은 결과가 나왔다.

Pod을 일정 갯수만큼 유지시키는 역할을 해주는 kube-controller-manager-controlplane에 에러가 발생한 것이다. 그래서 에러를 좀더 알아보기 위해 kubectl describe를 다음과 같이 했다.

kubectl describe pod kube-controller-manager-controlplane -n kube-system

근데 Pod이 없다고 나온다. 어? 뭐지..? 몇번을 체크하고 입력해도 없다고 나온다. 그래서 결국 화면에서 Pod 이름을 드래그해서 복사한뒤 붙여서 실행해보니 정상적으로 동작한다. event 부분에 다음과 같은 내용이 있었다.

 

Failed to pull image "k8s.gcr.io/kube-contro1ler-manager:v1.19.0": rpc error: code = Unknown desc = Error response from daemon: manifest for k8s.gcr.io/kube-contro1ler-manager:v1.19.0 not found: manifest unknown: Failed to fetch "v1.19.0" from request "/v2/kube-contro1ler-manager/manifests/v1.19.0".

 

내용을 보면 /v2/kube-contro1ler-manager/manifests/v1.19.0 을 못찾았다는 식의 에러인거 같았다.

여기까지 진행한 상태에서 보면 먼가 이상하지 않나? 분명 나는 describe 명령을 실행할때 오타없이 입력했는데도 불구하고 Pod을 찾을수가 없었고 오히려 복사해서 붙이니 Pod에 대한 describe가 제대로 실행이 되었다. 위에 내가 그린 그림과 Pod이 없다고 했을때 입력한 명령어 라인을 비교해보면 뭔가 다른점을 찾을수 있다. 그것은 kube-controller-manager-controlplane이 아닌 kube-contro1ler-manager-controlplane 으로 그림에 나오는 점이다. 즉 Pod 이름을 교묘하게 오타를 내서 바꾼것이다. 근데 Pod의 이름만 바꾸었으면 적어도 event 에서는 이미지 에러는 나오지 않는게 맞는건데 event에서도 에러가 나오는 것을 보니 event 에러 메시지도 유심히 봤다. 그러니 거기서도 이미지를 k8s.gcr.io/kube-contro1ler-manager:v1.19.0 이렇게 오타를 낸것이었다. 원인을 알았으니 이제 해결을 해보자. kube-controller-manager Pod은 Static Pod 이기 때문에 /etc/kubernetes/manifests 디렉토리에 있는 kube-controller-manager.yaml 파일을 찾아서 이를 수정해야 한다. 이 파일을 열어보고 kube-contro1ler-manager 란 문구를 찾아보면 한 5군데에서 나오는 것을 확인할 수 있다. 그러면 아예 kube-contro1ler-manager 문자열을 kube-controller-manager로 한꺼번에 바꾸는 작업을 진행하는것이 더 나을 수 있다. 아래와 같이 sed 명령을 이용해서 바꾸도록 하자.

sed -i 's/kube-contro1ler-manager/kube-controller-manager/g' kube-controller-manager.yaml

이 명령을 실행한뒤 다시 kube-system에 있는 Pod을 조회해보면 kube-controller-manager-controlplane으로 이름이 정상적으로 나오며 상태로 Running으로 나오는 것을 확인할 수 있다. 그리고 kubectl get deploy nginx-deploy를 실행하면 replicas를 3으로 설정했기 때문에 Pod이 3개가 생성되었음을 확인할 수 있다.