CKAD - Lightning LAB-1 - solution

choong·2023년 1월 17일
3

CKAD exam

목록 보기
1/2

CKA시험 합격 이후 CKAD 시험을 앞두고 KodeKloud의 CKAD - Lightning lab-1의 풀이를 첫 게시글로 작성해보고자 한다.

📖문제 1번

Create a Persistent Volume called log-volume. It should make use of a storage class name manual. It should use RWX as the access mode and have a size of 1Gi. The volume should use the hostPath /opt/volume/nginx.

Next, create a PVC called log-claim requesting a minimum of 200Mi of storage. This PVC should bind to log-volume.

Mount this in a pod called logger at the location /var/www/nginx. This pod should use the image nginx:alpine.

RWO - ReadWriteOnce / ROX - ReadOnlyMany
RWX - ReadWriteMany / RWOP - ReadWriteOncePod 입니다.

✍문제 1번 - 풀이

우리는 앞으로 https://kubernetes.io/docs/를 자주 사용하게 될 것입니다. 해당 URL을 앞으로 docs라고 부르겠습니다. docs에 pv hostpath라고 검색하면 Configure a Pod to Use a PersistentVolume for Storage가 나옵니다. 해당 문서에 들어가서 오른쪽에 각 목차를 나타낸 곳을 보면 순서대로 Create a PersistentVolume, Create a PersistentVolumeClaim, Create a Pod가 있습니다. 해당 예시를 참고하여 문제를 풀어보도록 하겠습니다.

Create a PersistentVolume 예시

apiVersion: v1
kind: PersistentVolume
metadata:
  name: task-pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"

문제에서 name, storage class name, access mode, size, hostpath에 대한 언급이 있었기 때문에 해당 부분 변경해주도록 합니다.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: log-volume
spec:
  storageClassName: manual
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  hostPath:
    path: "/opt/volume/nginx"

다음은 pvc를 생성해보도록 하겠습니다.

Create a PersistentVolumeClaim 예시

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: task-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi

문제에서 name, size, bind 되어야 할 pv의 이름을 알려주었습니다. 해당 부분 바꿔주도록 하겠습니다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: log-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 200Mi

pvc는 생성할 때 연결되어야 할 pv의 정보와 같아야 합니다. storageClassName, accessModes를 pv와 동일하게 작성해줍니다.

마지막으로 Pod를 생성할 차례입니다.

Create a Pod 예시

apiVersion: v1
kind: Pod
metadata:
  name: task-pv-pod
spec:
  volumes:
    - name: task-pv-storage
      persistentVolumeClaim:
        claimName: task-pv-claim
  containers:
    - name: task-pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: task-pv-storage

문제에서는 Pod의 name, location 그리고 image에 대한 언급이 있었습니다. 그 외에도 pvc name, image, mountPath 정보 적용하도록 하겠습니다.

apiVersion: v1
kind: Pod
metadata:
  name: logger
spec:
  volumes:
    - name: task-pv-storage
      persistentVolumeClaim:
        claimName: log-claim
  containers:
    - name: task-pv-container
      image: nginx:alpine
      volumeMounts:
        - mountPath: "/var/www/nginx"
          name: task-pv-storage

pv, pvc, pod 생성하고 bound 상태, pod 상태 확인해주면 되겠습니다.

📖문제 2번

We have deployed a new pod called secure-pod and a service called secure-service. Incoming or Outgoing connections to this pod are not working.
Troubleshoot why this is happening.

Make sure that incoming connection from the pod webapp-color are successful.

Important: Don't delete any current objects deployed.

✍문제 2번 - 풀이

이 문제에서 말하기를 secure-pod와 secuer-service를 배포하였으나 secure-pod로 들어가거나 나오는 연결이 안 된다고 합니다.

먼저 Service를 확인해보도록 하겠습니다.

# kubectl describe service sercure-service

Name:              secure-service
Namespace:         default
Labels:            run=secure-pod
Annotations:       <none>
Selector:          run=secure-pod
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.101.127.155
IPs:               10.101.127.155
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.0.7:80
Session Affinity:  None
Events:            <none>

확인해보니 service는 secure-pod에 적용되어 있고 80/TCP로 설정되어 있습니다.

그럼, 이제 network policy를 확인해보겠습니다.

#k get networkpolicies.networking.k8s.io

NAME           POD-SELECTOR   AGE
default-deny   <none>         13s

#k describe networkpolicies.networking.k8s.io default-deny 

Name:         default-deny
Namespace:    default
Created on:   2023-01-17 02:44:55 -0500 EST
Labels:       <none>
Annotations:  <none>
Spec:
  PodSelector:     <none> (Allowing the specific traffic to all pods in this namespace)
  Allowing ingress traffic:
    <none> (Selected pods are isolated for ingress connectivity)
  Not affecting egress traffic
  Policy Types: Ingress

확인해보니 network policy는 default-deny가 있었고 default-deny는 따로 PodSelector, port 설정이 되어있지 않았습니다.
때문에 pod와 서비스가 연결이 되어있어도 통신이 되지 않았던 겁니다.

그럼 webapp-color와 secure-pod가 통신할 수 있도록 network policy를 생성해보도록 하겠습니다.

이번엔 network policy를 검색해서 network policies로 들어가서 The NetworkPolicy resource로 가줍니다.

The NetworkPolicy resource 예시

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - ipBlock:
            cidr: 172.17.0.0/16
            except:
              - 172.17.1.0/24
        - namespaceSelector:
            matchLabels:
              project: myproject
        - podSelector:
            matchLabels:
              role: frontend
      ports:
        - protocol: TCP
          port: 6379
  egress:
    - to:
        - ipBlock:
            cidr: 10.0.0.0/24
      ports:
        - protocol: TCP
          port: 5978

저희는 secure-pod가 webapp-color의 신호를 받을 수 있게 하는 설정만 놔두고 싹 지워보도록 합니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      run: secure-pod
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              name: webapp-color
      ports:
        - protocol: TCP
          port: 80

label에 대한 정보는 아래와 같이 pod의 label을 확인하고 적어줍니다.

#k get pod --show-labels

NAME           READY   STATUS    RESTARTS   AGE   LABELS
secure-pod     1/1     Running   0          10m   run=secure-pod
webapp-color   1/1     Running   0          10m   name=webapp-color

이제 webapp-color가 secure-service를 80번 포트로 통신할 수 있는지 확인합니다.

# k exec -it webapp-color -- nc -z -v -w 1 secure-service 80
secure-service (10.110.11.172:80) open

위와 같이 nc명령어를 사용하여 service로 향한 포트가 열려있는 것이 확인하고 80번 포트가 허용되어있음을 알 수 있습니다.

추가로 nc(Netcat) 명령어는 포트가 열려있는지 확인하는 명령어입니다. 보통 telnet을 이용하여 포트 오픈을 확인하지만, net-tools가 안 깔려 있는 상황이거나 netcat이 설치된 상황에 대체하여 오픈 확인을 합니다.
-z 옵션 : 포트만 검색하도록 하는 옵션
-v 옵션 : 자세한 정보 제공
-w 옵션 : 뒤에 '-w 1'과 같이 숫자를 적어주면 최대 1초 동안 연결을 한다.
저는 vwxyz에서 xy만 빼는 거로 외웠습니다.

📖문제 3번

Create a pod called time-check in the dvl1987 namespace. This pod should run a container called time-check that uses the busybox image.
Create a config map called time-config with the data TIME_FREQ=10 in the same namespace.
The time-check container should run the command: while true; do date; sleep $TIME_FREQ;done and write the result to the location /opt/time/time-check.log.
The path /opt/time on the pod should mount a volume that lasts the lifetime of this pod.

✍문제 3번 - 풀이

이 문제는 다음과 같은 사냥의 pod, configmap을 생성하라고 합니다.
Pod
namespace: dvl1987 / pod: time-check / container: time-check / image: busybox / command: while true; do date; sleep $TIME_FREQ;done > /opt/time/time-check.log / mountPath: /opt/time

configmap
configmap: time-config / data: TIME_FREQ=10 / namespace: dvl1987

먼저 configmap부터 생성해주도록 하겠습니다.
docs에 configmap을 검색하고 configmaps로 들어가 ConfigMaps and Pods에 예시를 확인해줍니다.

ConfigMaps and Pods 예시

apiVersion: v1
kind: ConfigMap
metadata:
  name: game-demo
data:
  # property-like keys; each key maps to a simple value
  player_initial_lives: "3"
  ui_properties_file_name: "user-interface.properties"

  # file-like keys
  game.properties: |
    enemy.types=aliens,monsters
    player.maximum-lives=5    
  user-interface.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true 

namespace 관련 내용을 추가하고 data 내용에 TIME_FREQ=10 내용을 추가해줍니다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: time-config
  namespace: dvl1987
data:
  TIME_FREQ: "10"

다음은 Pod 예시를 봐볼까요?

apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo-pod
spec:
  containers:
    - name: demo
      image: alpine
      command: ["sleep", "3600"]
      env:
        # Define the environment variable
        - name: PLAYER_INITIAL_LIVES # Notice that the case is different here
                                     # from the key name in the ConfigMap.
          valueFrom:
            configMapKeyRef:
              name: game-demo           # The ConfigMap this value comes from.
              key: player_initial_lives # The key to fetch.
        - name: UI_PROPERTIES_FILE_NAME
          valueFrom:
            configMapKeyRef:
              name: game-demo
              key: ui_properties_file_name
      volumeMounts:
      - name: config
        mountPath: "/config"
        readOnly: true
  volumes:
  # You set volumes at the Pod level, then mount them into containers inside that Pod
  - name: config
    configMap:
      # Provide the name of the ConfigMap you want to mount.
      name: game-demo
      # An array of keys from the ConfigMap to create as files
      items:
      - key: "game.properties"
        path: "game.properties"
      - key: "user-interface.properties"
        path: "user-interface.properties"

다음 내용을 문제에서 준 내용대로 바꿔보겠습니다.

apiVersion: v1
kind: Pod
metadata:
  name: time-check
  namespace: dvl1987
spec:
  containers:
  - name: time-check
    image: busybox
    command: ["/bin/sh", "-c", "while true; do date; sleep $TIME_FREQ;done > /opt/time/time-check.log"]
    env:
    - name: TIME_FREQ 
      valueFrom:
        configMapKeyRef:
          name: time-config
          key: TIME_FREQ
    volumeMounts:
    - name: config
      mountPath: "/opt/time"
  volumes:
  - name: config
    emptyDir: {}

📖문제 4번

Create a new deployment called nginx-deploy, with one single container called nginx, image nginx:1.16 and 4 replicas. The deployment should use RollingUpdate strategy with maxSurge=1, and maxUnavailable=2.
Next upgrade the deployment to version 1.17.
Finally, once all pods are updated, undo the update and go back to the previous version.

✍문제 4번 - 풀이

해당 문제는 deployment를 생성할 것을 요구하고 있다. 조건은 아래와 같다.
name: nginx-deploy / single container - name: nginx / image: nginx:1.16 / replicas: 4 / RollingUpdate strategy: maxSurge=1, maxUnavailable=2 / upgrade to 1.17 / undo the update and go back to the 1.16

deployment 예시

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

문제에서 원하는 대로 yaml파일을 수정해봅니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 4
  selector:
    matchLabels:
      app: nginx-deploy
  template:
    metadata:
      labels:
        app: nginx-deploy
    spec:
      containers:
      - name: nginx
        image: nginx:1.16
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 2

maxSurge와 maxUnavailable의 경우 해당 docs 문서 하단에 .spec.strategy.type==RollingUpdate, .spec.strategy.rollingUpdate.maxUnavailable, .spec.strategy.rollingUpdate.maxSurge
와 같이 어떤 위치에 적어주어야 하는지 나와 있기에 참고하여 작성하였습니다.

이후에는 deployment를 생성하고 이미지 업데이트 그리고 롤백하는 과정이 필요한데 롤백하기 위해서는 record가 필요합니다. 때문에 처음 생성할 때부터 --record를 붙여 생성해주도록 합니다

# k create -f dep.yaml --record

# k rollout history deployment nginx-deploy 
deployment.apps/nginx-deploy 
REVISION  CHANGE-CAUSE
1         kubectl create --filename=dep.yaml --record=true

# kubectl set image deployment/nginx-deploy nginx=nginx:1.17 --record

# k rollout history deployment nginx-deploy 
deployment.apps/nginx-deploy 
REVISION  CHANGE-CAUSE
1         kubectl create --filename=dep.yaml --record=true
2         kubectl set image deployment/nginx-deploy nginx=nginx:1.17 --record=true

# kubectl rollout undo deployment nginx-deploy --to-revision=1
deployment.apps/nginx-deploy rolled back

rollout undo 명령어를 통해 roll back을 하는데 revision을 명시해주어야 하므로 record를 하여 revision을 선택할 수 있도록 해야 합니다.

📖문제 5번

Create a redis deployment with the following parameters:
Name of the deployment should be redis using the redis:alpine image. It should have exactly 1 replica.
The container should request for .2 CPU. It should use the label app=redis.
It should mount exactly 2 volumes.

a. An Empty directory volume called data at path /redis-master-data.
b. A configmap volume called redis-config at path /redis-master.
c. The container should expose the port 6379.
The configmap has already been created.

✍문제 5번 - 풀이

문제에서 요구하는 내용은 다음과 같습니다.
name: redis / image: redis:alpine / replicas: 1 / request cpu: 0.2 / label: app=redis / mounted volume: 2 / volume(emptyDir) path: /redis-master-data / volume(configmap) path: /redis-master / container port: 6379

이제 아까와 같이 deployment 예시를 가져와서 수정해보도록 하겠습니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
  labels:
    app: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:alpine
        ports:
        - containerPort: 6379
        volumeMounts:
        - name: data
          mountPath: /redis-master-data
        - name: redis-config
          mountPath: /redis-master
        resources:
          requests:
            cpu: "0.2"
      volumes:
      - name: data
        emptyDir: {}
      - name: redis-config
        configMap:
          name: redis-config

cpu는 pod cpu 검색하여서 어디에 넣는지 찾아보고 configmap은 pod configmap 검색해서 volumes에 어떻게 적는지 찾아봐서 작성하였다. configMap의 이름은 k get configmaps하여서 찾도록 합니다.

profile
choong

0개의 댓글