티스토리 뷰

728x90
반응형

서론

본 포스팅에서는 쿠버네티스에서 포드 기동 장애 발생 시 트러블슈팅에 활용할 수 있는 유용한 명령어에 대해 살펴본다.

쿠버네티스에서는 포드의 장애 발생 시 kubectl logs, kubectl describe 등의 명령어를 사용하여 어느 정도 수준은 분석이 1차로 가능하다.

다만 logs가 발생되지도 않으면서 describe에 표출되는 정보 역시 무관하거나, 막연한 정도의 수준으로 표출되는 경우 포드의 상태를 검증하는데 어려움이 있을 수 있다.

이때 포드 기동 문제를 검증하기 위해 아래와 같은 3가지 유용한 명령어를 활용하여 트러블슈팅을 진행할 수 있다.

본론

1) kubectl edit deployment [deployment_name]

먼저 kubectl edit를 활용하는 방법이다. 다음은 현재 Pod의 상태 정보이다.

[root@kubemaster sampleApp]# kubectl get pod
NAME                         READY   STATUS    RESTARTS   AGE
echodeploy-c84c54879-hgt5j   0/1     Running   0          73m
echodeploy-c84c54879-v8cw4   1/1     Running   0          73m
test-554b9c69db-2mjxn        1/1     Running   0          68m
[root@kubemaster sampleApp]# kubectl get deployment
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
echodeploy   1/2     2            1           74m
test         1/1     1            1           69m
[root@kubemaster sampleApp]#

위와 같이 특정 Pod에서 Container가 기동이 되지 않는 현상이 발생하였다.

이를 조치하기 위해 아래와 같이 Deployment에 sleep & args를 적용하여 Docker Container를 기동하는 Command를 대체하도록 구성한다.

[root@kubemaster sampleApp]# kubectl edit deployment echodeploy
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: "2020-03-12T06:35:56Z"
  generation: 1
  labels:
    app: echo
  name: echodeploy
  namespace: default
  resourceVersion: "12493"
  selfLink: /apis/apps/v1/namespaces/default/deployments/echodeploy
  uid: f49bd2eb-8477-49d4-9c52-86fdc6de5ff6
spec:
  progressDeadlineSeconds: 600
  replicas: 2
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: echo
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: echo
    spec:
      containers:
      - image: lbernail/echo:0.5
        imagePullPolicy: IfNotPresent
        name: echopod
        readinessProbe:
          failureThreshold: 2
          httpGet:
            path: /ready
            port: 5000
            scheme: HTTP
          periodSeconds: 2
          successThreshold: 2
          timeoutSeconds: 1
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        command: ["sleep"]
        args: ["3600"]
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
status:
  availableReplicas: 1
  conditions:
  - lastTransitionTime: "2020-03-12T06:35:56Z"
    lastUpdateTime: "2020-03-12T06:36:01Z"
    message: ReplicaSet "echodeploy-c84c54879" has successfully progressed.
"/tmp/kubectl-edit-d0eph.yaml" 79L, 2186C written
deployment.apps/echodeploy edited
[root@kubemaster sampleApp]#

위와 같이 command와 args를 적용하면

- spec.template.spec.containers.command: ["sleep"]

- spec.template.spec.containers.args: ["3600"]

해당 컨테이너는 다음과 같이 기동된다.

[root@kubemaster sampleApp]# kubectl get pod
sNAME                          READY   STATUS    RESTARTS   AGE
echodeploy-85779ff9c7-8cml7   0/1     Running   0          63s
echodeploy-c84c54879-hgt5j    0/1     Running   0          77m
echodeploy-c84c54879-v8cw4    1/1     Running   0          77m
test-554b9c69db-2mjxn         1/1     Running   0          72m
[root@kubemaster sampleApp]# kubectl exec -it echodeploy-85779ff9c7-8cml7 sh
/src # ps -ef
PID   USER     TIME   COMMAND
    1 root       0:00 sleep 3600
   11 root       0:00 sh
   16 root       0:00 ps -ef
/src #

위와 같이 sleep 3600이라는 args를 init process로 기동하여 container가 기동된다.

Init Process는 Docker Image의 Command가 실행된다. Command가 살아있는 동안 해당 컨테이너는 죽지 않고 살아 있게 된다. 일반적으로 bash, sh 등의 shell이 init 1로 기동되어 있는 경우 컨테이너는 직접 삭제하지 않는 이상 죽지 않는다.

위와 같이 sleep 3600으로 기동하면 1시간 동안 해당 컨테이너는 정상적으로 기동된 상태로 접근할 수 있게 된다. 접근한 후 Container 내부의 상태를 점검하는 것은 본인의 몫이다.

때로는 다음과 같은 문제를 유발할 수 있다. 분명 Dockerfile과 기동 스크립트(apache, tomcat, wildfly 등등)는 정상적으로 작성한 것 같은데, Container 기동 후 Complete에서 지속 Restart되는 현상이 발생하는 경우가 있다.

이는 CMD Script가 Init Process로 기동되는 경우에 ShellScript가 기동이 완료되고 종료되기 때문에 발생하는 문제이다. 이를 방지하기 위해 ShellScript가 실행되고 종료되지 않도록 구성해야 한다.

몇가지 방법이 있지만, 대표적인 방법은 바로 bash를 사용하는 방법이다. bash의 경우 종료되지 않기 때문에 다음과 같이 CMD Script를 BASH로 변경할 필요가 있다.

...
...
CMD ["/bin/bash", "-x", "/opt/jboss/wildfly/bin/wboot.sh"]

위와 같이 구성하면 bash shell이 종료되지 않고 유지된다.

2) docker run -it [docker_image] sleep 3600

다음은 쿠버네티스에서 진단이 어려울 경우 Docker Image 자체를 docker run으로 검증하는 방법이다.

동작하는 방식은 1번과 동일하다.

[root@kubeworker1 ~]# docker run -it -d lbernail/echo:0.5 sleep 3600
304b889336207810ea2bc2079052700a890a39ec27859e2afaa59095aa57860d
[root@kubeworker1 ~]# docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
304b88933620        lbernail/echo:0.5   "sleep 3600"        7 seconds ago       Up 6 seconds        5000/tcp            recursing_pike
[root@kubeworker1 ~]# docker exec -it 304b88933620 sh
/src # ps -ef
PID   USER     TIME   COMMAND
    1 root       0:00 sleep 3600
   11 root       0:00 sh
   16 root       0:00 ps -ef
/src #

위와 같이 docker run -it -d [docker_image] [command]의 command 위치에 sleep 3600을 넣고 기동하면 기존 Command가 sleep 3600으로 대체 된다.

이를 활용하면 Docker Container 내부에 접속하여 상태를 진단할 수 있다.

위와 같이 init process는 동일하게 sleep 3600이 된다.

3) docker exec -itu root [container_name] [command]

위 명령어의 특징은 -u root가 기존과 다르게 붙어 있다는 점이다.

이 옵션을 사용하면 Docker Image에 접근할 때 root 계정으로 접근할 수 있도록 해준다.

결론

위 세가지 옵션을 통해 Pod 기동 실패에 대한 원인을 분석할 수 있도록 각각 포드 내부로 접근하거나 권한을 변경할 수 있다. 이를 활용하면 보다 효과적인 트러블슈팅이 될 것이다.

728x90
반응형