Merge pull request #33781 from jihoon-seo/220516_ko_Reorg_the_Debugging_section
[ko] Reorg pages in `dev-1.24-ko.1`
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
---
|
||||
title: "모니터링, 로깅, 및 디버깅"
|
||||
description: 클러스터를 트러블슈팅할 수 있도록 모니터링과 로깅을 설정하거나, 컨테이너화된 애플리케이션을 디버깅한다.
|
||||
weight: 20
|
||||
|
||||
|
||||
|
||||
content_type: concept
|
||||
no_list: true
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
때때로 문제가 발생할 수 있다. 이 가이드는 이러한 상황을 해결하기 위해 작성되었다. 문제 해결에는
|
||||
다음 두 가지를 참고해 볼 수 있다.
|
||||
|
||||
* [애플리케이션 디버깅하기](/ko/docs/tasks/debug/debug-application/) - 쿠버네티스에
|
||||
코드를 배포하였지만 제대로 동작하지 않는 사용자들에게 유용한 가이드이다.
|
||||
* [클러스터 디버깅하기](/ko/docs/tasks/debug/debug-cluster/) - 쿠버네티스 클러스터에
|
||||
문제를 겪고 있는 클러스터 관리자 혹은 기분이 나쁜 사람들에게 유용한 가이드이다.
|
||||
|
||||
여러분이 현재 사용중인 릴리스에 대한 알려진 이슈들을 다음의 [릴리스](https://github.com/kubernetes/kubernetes/releases)
|
||||
페이지에서 확인해 볼 수도 있다.
|
||||
|
||||
<!-- body -->
|
||||
|
||||
## 도움 받기
|
||||
|
||||
여러분의 문제가 위에 소개된 어떠한 가이드로도 해결할 수 없다면,
|
||||
쿠버네티스 커뮤니티로부터 도움을 받을 수 있는 다양한 방법들을 시도해 볼 수 있다.
|
||||
|
||||
### 질문
|
||||
|
||||
이 사이트의 문서들은 다양한 질문들에 대한 답변을 제공할 수 있도록 구성되어 있다.
|
||||
[개념](/ko/docs/concepts/)은 쿠버네티스의 아키텍처와 각 컴포넌트들이 어떻게 동작하는지에 대해 설명하고,
|
||||
[시작하기](/ko/docs/setup/)는 쿠버네티스를 시작하는 데 유용한 지침들을 제공한다.
|
||||
[태스크](/ko/docs/tasks/)는 흔히 사용되는 작업들을 수행하는 방법에 대해 소개하고,
|
||||
[튜토리얼](/ko/docs/tutorials/)은 실무, 산업 특화 혹은 종단간 개발에 특화된 시나리오를 통해 차근차근 설명한다.
|
||||
[레퍼런스](/ko/docs/reference/) 섹션에서는
|
||||
[쿠버네티스 API](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/)와
|
||||
[`kubectl`](/ko/docs/reference/kubectl/)과 같은 커맨드 라인 인터페이스(CLI)에 대한
|
||||
상세한 설명을 다룬다.
|
||||
|
||||
## 도와주세요! 내 질문이 다뤄지지 않았어요! 도움이 필요해요!
|
||||
|
||||
### 스택 오버플로우
|
||||
|
||||
여러분들이 겪고 있는 문제와 동일한 문제에 대한 도움을 위해 커뮤니티의 다른 사람들이 이미
|
||||
질문을 올렸을 수 있다. 쿠버네티스 팀은
|
||||
[쿠버네티스 태그가 등록된 글](https://stackoverflow.com/questions/tagged/kubernetes)들을 모니터링하고 있다.
|
||||
발생한 문제에 도움이 되는 기존 질문이 없다면,
|
||||
**[해당 질문이 스택 오버플로우에 적합한지](https://stackoverflow.com/help/on-topic)와 [새로운 질문을 올리는 방법](https://stackoverflow.com/help/how-to-ask)에 대한 가이드를 읽은 뒤에**
|
||||
[새로운 질문](https://stackoverflow.com/questions/ask?tags=kubernetes)을 올리자!
|
||||
|
||||
### 슬랙
|
||||
|
||||
쿠버네티스 슬랙의 `#kubernetes-users` 채널을 통해 쿠버네티스 커뮤니티의 여러 사람들을 접할 수도 있다.
|
||||
쿠버네티스 슬랙을 사용하기 위해서는 등록이 필요한데, 다음을 통해 [채널 초대 요청](https://slack.kubernetes.io)을 할 수 있다.
|
||||
(누구나 가입할 수 있다). 슬랙 채널은 여러분이 어떠한 질문을 할 수 있도록 언제나 열려있다.
|
||||
가입하고 나면 여러분의 웹 브라우저나 슬랙 앱을 통해 [쿠버네티스 슬랙](https://kubernetes.slack.com)
|
||||
에 참여할 수 있다.
|
||||
|
||||
쿠버네티스 슬랙에 참여하게 된다면, 다양한 주제의 흥미와 관련된 여러 채널들에 대해
|
||||
살펴본다. 가령, 쿠버네티스를 처음 접하는 사람이라면
|
||||
[`#kubernetes-novice`](https://kubernetes.slack.com/messages/kubernetes-novice) 채널에 가입할 수 있다. 혹은, 만약 당신이 개발자라면
|
||||
[`#kubernetes-dev`](https://kubernetes.slack.com/messages/kubernetes-dev) 채널에 가입할 수 있다.
|
||||
|
||||
또한 각 국가 및 사용 언어별 채널들이 여럿 존재한다. 사용하는 언어로 도움을 받거나 정보를
|
||||
얻기 위해서는 다음의 채널에 참가한다.
|
||||
|
||||
{{< table caption="국가 / 언어별 슬랙 채널" >}}
|
||||
국가 | 채널
|
||||
:---------|:------------
|
||||
China(중국) | [`#cn-users`](https://kubernetes.slack.com/messages/cn-users), [`#cn-events`](https://kubernetes.slack.com/messages/cn-events)
|
||||
Finland(핀란드) | [`#fi-users`](https://kubernetes.slack.com/messages/fi-users)
|
||||
France(프랑스) | [`#fr-users`](https://kubernetes.slack.com/messages/fr-users), [`#fr-events`](https://kubernetes.slack.com/messages/fr-events)
|
||||
Germany(독일) | [`#de-users`](https://kubernetes.slack.com/messages/de-users), [`#de-events`](https://kubernetes.slack.com/messages/de-events)
|
||||
India(인도) | [`#in-users`](https://kubernetes.slack.com/messages/in-users), [`#in-events`](https://kubernetes.slack.com/messages/in-events)
|
||||
Italy(이탈리아) | [`#it-users`](https://kubernetes.slack.com/messages/it-users), [`#it-events`](https://kubernetes.slack.com/messages/it-events)
|
||||
Japan(일본) | [`#jp-users`](https://kubernetes.slack.com/messages/jp-users), [`#jp-events`](https://kubernetes.slack.com/messages/jp-events)
|
||||
Korea(한국) | [`#kr-users`](https://kubernetes.slack.com/messages/kr-users)
|
||||
Netherlands(네덜란드) | [`#nl-users`](https://kubernetes.slack.com/messages/nl-users)
|
||||
Norway(노르웨이) | [`#norw-users`](https://kubernetes.slack.com/messages/norw-users)
|
||||
Poland(폴란드) | [`#pl-users`](https://kubernetes.slack.com/messages/pl-users)
|
||||
Russia(러시아) | [`#ru-users`](https://kubernetes.slack.com/messages/ru-users)
|
||||
Spain(스페인) | [`#es-users`](https://kubernetes.slack.com/messages/es-users)
|
||||
Sweden(스웨덴) | [`#se-users`](https://kubernetes.slack.com/messages/se-users)
|
||||
Turkey(터키) | [`#tr-users`](https://kubernetes.slack.com/messages/tr-users), [`#tr-events`](https://kubernetes.slack.com/messages/tr-events)
|
||||
{{< /table >}}
|
||||
|
||||
### 포럼
|
||||
|
||||
공식 쿠버네티스 포럼에 참여하는 것도 추천되는 방법이다. [discuss.kubernetes.io](https://discuss.kubernetes.io).
|
||||
|
||||
### 버그와 기능 추가 요청
|
||||
|
||||
만약 여러분이 버그처럼 보이는 것을 발견했거나, 기능 추가 요청을 하기 위해서는
|
||||
[GitHub 이슈 트래킹 시스템](https://github.com/kubernetes/kubernetes/issues)을 사용한다.
|
||||
|
||||
이슈를 작성하기 전에는, 여러분의 이슈가 기존 이슈에서 이미
|
||||
다뤄졌는지 검색해 본다.
|
||||
|
||||
버그를 보고하는 경우에는, 해당 문제를 어떻게 재현할 수 있는지에 관련된 상세한 정보를 포함한다.
|
||||
포함되어야 하는 정보들은 다음과 같다.
|
||||
|
||||
* 쿠버네티스 버전: `kubectl version`
|
||||
* 클라우드 프로바이더, OS 배포판, 네트워크 구성, 및 도커 버전
|
||||
* 문제를 재현하기 위한 절차
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: "애플리케이션 트러블슈팅하기"
|
||||
description: 일반적인 컨테이너화된 애플리케이션 이슈를 디버깅한다.
|
||||
weight: 20
|
||||
---
|
||||
|
||||
이 문서는 컨테이너화된 애플리케이션의 이슈를 해결하기 위한 자원을 담고 있다. 쿠버네티스 리소스(예: 파드, 서비스, 스테이트풀셋)의 일반적 이슈, 컨테이너 종료 메시지 이해에 대한 조언, 실행 중인 컨테이너를 디버그하는 방법 등을 다룬다.
|
||||
@@ -0,0 +1,130 @@
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
title: 초기화 컨테이너(Init Containers) 디버그하기
|
||||
content_type: task
|
||||
weight: 40
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
이 페이지는 초기화 컨테이너의 실행과 관련된 문제를
|
||||
조사하는 방법에 대해 보여준다. 아래 예제의 커맨드 라인은 파드(Pod)를 `<pod-name>` 으로,
|
||||
초기화 컨테이너를 `<init-container-1>` 과
|
||||
`<init-container-2>` 로 표시한다.
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
* 사용자는 [초기화 컨테이너](/ko/docs/concepts/workloads/pods/init-containers/)의
|
||||
기본 사항에 익숙해야 한다.
|
||||
* 사용자는 [초기화 컨테이너를 구성](/ko/docs/tasks/configure-pod-container/configure-pod-initialization/#초기화-컨테이너를-갖는-파드-생성)해야 한다.
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
## 초기화 컨테이너의 상태 체크하기
|
||||
|
||||
사용자 파드의 상태를 표시한다.
|
||||
|
||||
```shell
|
||||
kubectl get pod <pod-name>
|
||||
```
|
||||
|
||||
예를 들어, `Init:1/2` 상태는 두 개의 초기화 컨테이너 중
|
||||
하나가 성공적으로 완료되었음을 나타낸다.
|
||||
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
<pod-name> 0/1 Init:1/2 0 7s
|
||||
```
|
||||
|
||||
상태값과 그 의미에 대한 추가 예제는
|
||||
[파드 상태 이해하기](#파드의-상태-이해하기)를 참조한다.
|
||||
|
||||
## 초기화 컨테이너에 대한 상세 정보 조회하기
|
||||
|
||||
초기화 컨테이너의 실행에 대한 상세 정보를 확인한다.
|
||||
|
||||
```shell
|
||||
kubectl describe pod <pod-name>
|
||||
```
|
||||
|
||||
예를 들어, 2개의 초기화 컨테이너가 있는 파드는 다음과 같이 표시될 수 있다.
|
||||
|
||||
```
|
||||
Init Containers:
|
||||
<init-container-1>:
|
||||
Container ID: ...
|
||||
...
|
||||
State: Terminated
|
||||
Reason: Completed
|
||||
Exit Code: 0
|
||||
Started: ...
|
||||
Finished: ...
|
||||
Ready: True
|
||||
Restart Count: 0
|
||||
...
|
||||
<init-container-2>:
|
||||
Container ID: ...
|
||||
...
|
||||
State: Waiting
|
||||
Reason: CrashLoopBackOff
|
||||
Last State: Terminated
|
||||
Reason: Error
|
||||
Exit Code: 1
|
||||
Started: ...
|
||||
Finished: ...
|
||||
Ready: False
|
||||
Restart Count: 3
|
||||
...
|
||||
```
|
||||
|
||||
파드 스펙의 `status.initContainerStatuses` 필드를 읽어서
|
||||
프로그래밍 방식으로 초기화 컨테이너의 상태를 조회할 수도 있다.
|
||||
|
||||
|
||||
```shell
|
||||
kubectl get pod nginx --template '{{.status.initContainerStatuses}}'
|
||||
```
|
||||
|
||||
|
||||
이 명령은 원시 JSON 방식으로 위와 동일한 정보를 반환한다.
|
||||
|
||||
## 초기화 컨테이너의 로그 조회하기
|
||||
|
||||
초기화 컨테이너의 로그를 확인하기 위해
|
||||
파드의 이름과 초기화 컨테이너의 이름을 같이 전달한다.
|
||||
|
||||
```shell
|
||||
kubectl logs <pod-name> -c <init-container-2>
|
||||
```
|
||||
|
||||
셸 스크립트를 실행하는 초기화 컨테이너는, 초기화 컨테이너가
|
||||
실행될 때 명령어를 출력한다. 예를 들어, 스크립트의 시작 부분에
|
||||
`set -x` 를 추가하고 실행하여 Bash에서 명령어를 출력할 수 있도록 수행할 수 있다.
|
||||
|
||||
|
||||
|
||||
<!-- discussion -->
|
||||
|
||||
## 파드의 상태 이해하기
|
||||
|
||||
`Init:` 으로 시작하는 파드 상태는 초기화 컨테이너의
|
||||
실행 상태를 요약한다. 아래 표는 초기화 컨테이너를 디버깅하는
|
||||
동안 사용자가 확인할 수 있는 몇 가지 상태값의 예이다.
|
||||
|
||||
상태 | 의미
|
||||
------ | -------
|
||||
`Init:N/M` | 파드가 `M` 개의 초기화 컨테이너를 갖고 있으며, 현재까지 `N` 개가 완료.
|
||||
`Init:Error` | 초기화 컨테이너 실행 실패.
|
||||
`Init:CrashLoopBackOff` | 초기화 컨테이너가 반복적으로 실행 실패.
|
||||
`Pending` | 파드가 아직 초기화 컨테이너를 실행하지 않음.
|
||||
`PodInitializing` or `Running` | 파드가 이미 초기화 컨테이너 실행을 완료.
|
||||
@@ -0,0 +1,159 @@
|
||||
---
|
||||
|
||||
|
||||
|
||||
title: 파드 디버깅하기
|
||||
content_type: task
|
||||
weight: 10
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
이 가이드는 쿠버네티스에 배포되었지만 제대로 동작하지 않는 애플리케이션을 디버깅하는 방법을 소개한다.
|
||||
이 가이드는 클러스터 디버깅에 대한 것은 아니다.
|
||||
클러스터 디버깅에 대해서는 [이 가이드](/ko/docs/tasks/debug/debug-cluster/)를 참고한다.
|
||||
|
||||
<!-- body -->
|
||||
|
||||
## 문제 진단하기
|
||||
|
||||
트러블슈팅의 첫 단계는 문제를 파악하는 것이다.
|
||||
무엇이 문제인가? 파드인가, 레플리케이션 컨트롤러인가, 서비스인가?
|
||||
|
||||
* [파드 디버깅하기](#debugging-pods)
|
||||
* [레플리케이션컨트롤러 디버깅하기](#debugging-replication-controllers)
|
||||
* [서비스 디버깅하기](#debugging-services)
|
||||
|
||||
### 파드 디버깅하기 {#debugging-pods}
|
||||
|
||||
파드 디버깅의 첫 번째 단계는 파드를 살펴 보는 것이다. 다음의 명령어를 사용하여 파드의 현재 상태와 최근 이벤트를 점검한다.
|
||||
|
||||
```shell
|
||||
kubectl describe pods ${POD_NAME}
|
||||
```
|
||||
|
||||
파드 내부 컨테이너의 상태를 확인한다. 모두 `Running` 상태인가? 최근에 재시작 되었는가?
|
||||
|
||||
파드의 상태에 따라 디버깅을 계속한다.
|
||||
|
||||
#### 파드가 계속 pending 상태인 경우
|
||||
|
||||
파드가 `Pending` 상태로 멈춰 있는 경우는, 노드에 스케줄 될 수 없음을 의미한다.
|
||||
일반적으로 이것은 어떤 유형의 리소스가 부족하거나 스케줄링을 방해하는 다른 요인 때문이다.
|
||||
상단의 `kubectl describe ...` 명령의 결과를 확인하자.
|
||||
파드를 스케줄 할 수 없는 사유에 대한 스케줄러의 메세지가 있을 것이다. 다음과 같은 사유가 있을 수 있다.
|
||||
|
||||
* **리소스가 부족한 경우**: 사용자 클러스터의 CPU 나 메모리가 고갈되었을 수 있다.
|
||||
이러한 경우, 파드를 삭제하거나, 리소스 요청을 조정하거나, 클러스터에 노드를 추가해야 한다.
|
||||
[컴퓨트 자원 문서](/ko/docs/concepts/configuration/manage-resources-containers/)에서 더 많은 정보를 확인한다.
|
||||
|
||||
* **`hostPort`를 사용하고 있는 경우**: 파드를 `hostPort`에 바인딩할 때, 파드가 스케줄링될 수 있는 장소 수 제한이 존재한다.
|
||||
대부분의 경우 `hostPort`는 불필요하므로, 파드를 노출하기 위해서는 서비스(Service) 오브젝트 사용을 고려해 본다.
|
||||
`hostPort`가 꼭 필요하다면 클러스터의 노드 수 만큼만 파드를 스케줄링할 수 있다.
|
||||
|
||||
|
||||
#### 파드가 계속 waiting 상태인 경우
|
||||
|
||||
파드가 `Waiting` 상태에서 멈춘 경우는, 파드가 워커 노드에 스케줄링되었지만 해당 노드에서 실행될 수 없음을 의미한다.
|
||||
다시 말하지만, `kubectl describe ...` 명령은 유용한 정보를 제공한다. 파드가 `Waiting` 상태에서 멈추는 가장 흔한 원인은 이미지 풀링(pulling)에 실패했기 때문이다. 다음의 3가지 사항을 확인한다.
|
||||
|
||||
* 이미지 이름이 올바른지 확인한다.
|
||||
* 해당 이미지를 저장소에 푸시하였는가?
|
||||
* 이미지가 풀 될 수 있는지 확인하기 위해 수동으로 이미지를 풀 해본다.
|
||||
예를 들어, PC에서 도커를 사용하는 경우, `docker pull <image>` 명령을 실행한다.
|
||||
|
||||
#### 파드가 손상(crashing)되었거나 양호하지 않을(unhealthy) 경우
|
||||
|
||||
일단 사용자의 파드가 스케줄 되면, [구동중인 파드 디버그하기](/ko/docs/tasks/debug/debug-application/debug-running-pod/)에
|
||||
있는 방법을 사용하여 디버깅을 할 수 있다.
|
||||
|
||||
#### 파드가 running 상태이지만 해야 할 일을 하고 있지 않은 경우
|
||||
|
||||
파드가 예상과 다르게 동작 중이라면, 파드 상세(예: 로컬 머신에 있는 `mypod.yaml` 파일)에 에러가 있었는데
|
||||
파드 생성 시에 에러가 조용히 지나쳐진 경우일 수 있다.
|
||||
종종 파드 상세의 들여쓰기가 잘못되었거나,
|
||||
키 이름에 오타가 있어서 해당 키가 무시되는 일이 있을 수 있다.
|
||||
예를 들어, `command`를 `commnd`로 잘못 기재했다면
|
||||
해당 파드는 생성은 되지만 명시한 명령줄을 실행하지 않을 것이다.
|
||||
|
||||
가장 먼저 해야 할 일은 파드를 삭제한 다음, `--validate` 옵션을 사용하여 다시 만들어 보는 것이다.
|
||||
예를 들어, `kubectl apply --validate -f mypod.yaml` 를 실행한다.
|
||||
`command`를 `commnd`로 잘못 기재했다면 다음과 같은 에러가 발생할 것이다.
|
||||
|
||||
```shell
|
||||
I0805 10:43:25.129850 46757 schema.go:126] unknown field: commnd
|
||||
I0805 10:43:25.129973 46757 schema.go:129] this may be a false alarm, see https://github.com/kubernetes/kubernetes/issues/6842
|
||||
pods/mypod
|
||||
```
|
||||
|
||||
<!-- TODO: Now that #11914 is merged, this advice may need to be updated -->
|
||||
|
||||
다음으로 확인할 것은 apiserver를 통해 확인한 파드 상세가
|
||||
사용자가 의도한 파드 상세(예: 로컬 머신에 있는 yaml 파일)와 일치하는지 여부이다.
|
||||
예를 들어, `kubectl get pods/mypod -o yaml > mypod-on-apiserver.yaml` 를 실행한 다음,
|
||||
원본 파드 상세(`mypod.yaml`)와 apiserver를 통해 확인한 파드 상세(`mypod-on-apiserver.yaml`)를 수동으로 비교한다.
|
||||
보통 원본 버전에는 없지만 "apiserver" 버전에는 있는 줄들이 존재한다.
|
||||
이는 예상대로이다.
|
||||
하지만, 원본 버전에는 있지만 "apiserver" 버전에는 없는 줄들이 있다면,
|
||||
이는 원본 파드 상세에 문제가 있을 수도 있음을 의미한다.
|
||||
|
||||
## 레플리케이션컨트롤러 디버깅하기 {#debugging-replication-controllers}
|
||||
|
||||
레플리케이션컨트롤러의 경우에는 매우 직관적이다. 파드 생성이 가능하거나 또는 불가능한 경우 둘 뿐이다.
|
||||
레플리케이션컨트롤러가 파드를 생성할 수 없다면, [위의 지침](#debugging-pods)을 참고하여 파드를 디버깅한다.
|
||||
|
||||
사용자는 `kubectl describe rc ${CONTROLLER_NAME}` 을 사용하여
|
||||
레플리케이션 컨트롤러와 관련된 이벤트를 검사할 수도 있다.
|
||||
|
||||
### 서비스 디버깅하기 {#debugging-services}
|
||||
|
||||
서비스는 파드 집합에 대한 로드 밸런싱 기능을 제공한다. 일반적인 몇몇 문제들 때문에 서비스가 제대로 동작하지 않을 수 있다.
|
||||
다음 지침을 이용하여 서비스 문제를 디버깅할 수 있다.
|
||||
|
||||
먼저, 서비스를 위한 엔드포인트가 존재하는지 확인한다. 모든 서비스 오브젝트에 대해, apiserver는 `endpoints` 리소스를 생성하고 사용 가능한(available) 상태로 만든다.
|
||||
|
||||
다음 명령을 사용하여 이 리소스를 볼 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl get endpoints ${SERVICE_NAME}
|
||||
```
|
||||
|
||||
엔드포인트의 수가 해당 서비스에 속하는 파드의 수와 일치하는지 확인한다.
|
||||
예를 들어, 서비스가 레플리카 3개인 nginx 컨테이너를 위한 것이라면,
|
||||
서비스의 엔드포인트 항목에서 서로 다른 3개의 IP 주소가 확인되어야 한다.
|
||||
|
||||
#### 서비스에 엔드포인트가 없는 경우
|
||||
|
||||
엔드포인트가 없는 상태라면, 서비스가 사용 중인 레이블을 이용하여 파드 목록을 조회해 본다.
|
||||
다음과 같은 레이블을 갖는 서비스를 가정한다.
|
||||
|
||||
```yaml
|
||||
...
|
||||
spec:
|
||||
- selector:
|
||||
name: nginx
|
||||
type: frontend
|
||||
```
|
||||
|
||||
다음의 명령을 사용하여,
|
||||
|
||||
```shell
|
||||
kubectl get pods --selector=name=nginx,type=frontend
|
||||
```
|
||||
|
||||
이 셀렉터에 매치되는 파드 목록을 조회할 수 있다. 서비스에 속할 것으로 예상하는 파드가 모두 조회 결과에 있는지 확인한다.
|
||||
파드의 `containerPort`가 서비스의 `targetPort`와 일치하는지 확인한다.
|
||||
|
||||
#### 네트워크 트래픽이 포워드되지 않는 경우
|
||||
|
||||
[서비스 디버깅하기](/docs/tasks/debug/debug-application/debug-service/)에서 더 많은 정보를 확인한다.
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
위의 방법 중 어떤 것으로도 문제가 해결되지 않는다면,
|
||||
[서비스 디버깅하기 문서](/docs/tasks/debug/debug-application/debug-service/)를 참조하여
|
||||
`서비스`가 실행 중인지, 서비스에 `엔드포인트`가 있는지, `파드`가 실제로 서빙 중인지 확인한다.
|
||||
예를 들어, DNS가 실행 중이고, iptables 규칙이 설정되어 있고, kube-proxy가 정상적으로 동작하는 것으로 보이는 상황이라면,
|
||||
위와 같은 사항을 확인해 볼 수 있다.
|
||||
|
||||
[트러블슈팅 문서](/ko/docs/tasks/debug/)에서 더 많은 정보를 볼 수도 있다.
|
||||
@@ -0,0 +1,638 @@
|
||||
---
|
||||
|
||||
|
||||
|
||||
title: 동작 중인 파드 디버그
|
||||
content_type: task
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
이 페이지는 노드에서 동작 중인(혹은 크래시된) 파드를 디버그하는 방법에 대해 설명한다.
|
||||
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
|
||||
* 여러분의 {{< glossary_tooltip text="파드" term_id="pod" >}}는 이미 스케줄링 되어
|
||||
동작하고 있을 것이다. 만약 파드가 아직 동작중이지 않다면, [애플리케이션
|
||||
트러블슈팅](/ko/docs/tasks/debug/debug-application/)을 참고한다.
|
||||
* 일부 고급 디버깅 과정에서는 해당 파드가 어떤 노드에서 동작하고 있는지
|
||||
알아야 하고, 해당 노드에서 쉘 명령어를 실행시킬 수 있어야 한다.
|
||||
`kubectl`을 사용하는 일반적인 디버깅 과정에서는 이러한 접근 권한이 필요하지 않다.
|
||||
|
||||
## `kubectl describe pod` 명령으로 파드 상세사항 가져오기
|
||||
|
||||
이 예제에서는 앞의 예제와 비슷하게 두 개의 파드를 생성하기 위해 디플로이먼트를 사용할 것이다.
|
||||
|
||||
{{< codenew file="application/nginx-with-request.yaml" >}}
|
||||
|
||||
다음 명령을 실행하여 디플로이먼트를 생성한다.
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://k8s.io/examples/application/nginx-with-request.yaml
|
||||
```
|
||||
|
||||
```none
|
||||
deployment.apps/nginx-deployment created
|
||||
```
|
||||
|
||||
다음 명령을 실행하여 파드 상태를 확인한다.
|
||||
|
||||
```shell
|
||||
kubectl get pods
|
||||
```
|
||||
|
||||
```none
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-deployment-67d4bdd6f5-cx2nz 1/1 Running 0 13s
|
||||
nginx-deployment-67d4bdd6f5-w6kd7 1/1 Running 0 13s
|
||||
```
|
||||
|
||||
다음과 같이 `kubectl describe pod` 명령을 사용하여 각 파드에 대한 더 많은 정보를 가져올 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl describe pod nginx-deployment-67d4bdd6f5-w6kd7
|
||||
```
|
||||
|
||||
```none
|
||||
Name: nginx-deployment-67d4bdd6f5-w6kd7
|
||||
Namespace: default
|
||||
Priority: 0
|
||||
Node: kube-worker-1/192.168.0.113
|
||||
Start Time: Thu, 17 Feb 2022 16:51:01 -0500
|
||||
Labels: app=nginx
|
||||
pod-template-hash=67d4bdd6f5
|
||||
Annotations: <none>
|
||||
Status: Running
|
||||
IP: 10.88.0.3
|
||||
IPs:
|
||||
IP: 10.88.0.3
|
||||
IP: 2001:db8::1
|
||||
Controlled By: ReplicaSet/nginx-deployment-67d4bdd6f5
|
||||
Containers:
|
||||
nginx:
|
||||
Container ID: containerd://5403af59a2b46ee5a23fb0ae4b1e077f7ca5c5fb7af16e1ab21c00e0e616462a
|
||||
Image: nginx
|
||||
Image ID: docker.io/library/nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767
|
||||
Port: 80/TCP
|
||||
Host Port: 0/TCP
|
||||
State: Running
|
||||
Started: Thu, 17 Feb 2022 16:51:05 -0500
|
||||
Ready: True
|
||||
Restart Count: 0
|
||||
Limits:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
Requests:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
Environment: <none>
|
||||
Mounts:
|
||||
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-bgsgp (ro)
|
||||
Conditions:
|
||||
Type Status
|
||||
Initialized True
|
||||
Ready True
|
||||
ContainersReady True
|
||||
PodScheduled True
|
||||
Volumes:
|
||||
kube-api-access-bgsgp:
|
||||
Type: Projected (a volume that contains injected data from multiple sources)
|
||||
TokenExpirationSeconds: 3607
|
||||
ConfigMapName: kube-root-ca.crt
|
||||
ConfigMapOptional: <nil>
|
||||
DownwardAPI: true
|
||||
QoS Class: Guaranteed
|
||||
Node-Selectors: <none>
|
||||
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
|
||||
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
|
||||
Events:
|
||||
Type Reason Age From Message
|
||||
---- ------ ---- ---- -------
|
||||
Normal Scheduled 34s default-scheduler Successfully assigned default/nginx-deployment-67d4bdd6f5-w6kd7 to kube-worker-1
|
||||
Normal Pulling 31s kubelet Pulling image "nginx"
|
||||
Normal Pulled 30s kubelet Successfully pulled image "nginx" in 1.146417389s
|
||||
Normal Created 30s kubelet Created container nginx
|
||||
Normal Started 30s kubelet Started container nginx
|
||||
```
|
||||
|
||||
위 예시에서 컨테이너와 파드에 대한 구성 정보(레이블, 리소스 요구사항 등) 및 상태 정보(상태(state), 준비성(readiness), 재시작 횟수, 이벤트 등)를 볼 수 있다.
|
||||
|
||||
컨테이너의 상태(state)값은 Waiting, Running, 또는 Terminated 중 하나이다. 각 상태에 따라, 추가 정보가 제공될 것이다. 위 예시에서 Running 상태의 컨테이너에 대해서는 컨테이너의 시작 시각을 시스템이 표시해 주는 것을 볼 수 있다.
|
||||
|
||||
Ready 값은 컨테이너의 마지막 준비성 프로브(readiness probe) 통과 여부를 알려 준다. (위 예시에서는 컨테이너에 준비성 프로브가 설정되어 있지 않다. 컨테이너에 준비성 프로브가 설정되어 있지 않으면, 컨테이너는 준비(ready) 상태로 간주된다.)
|
||||
|
||||
'재시작 카운트'는 컨테이너가 재시작된 횟수를 보여 준다. 이 정보는 재시작 정책이 'always'로 설정된 컨테이너의 반복적인 강제 종료를 알아차리는 데에 유용하다.
|
||||
|
||||
위 예시에서 파드와 연관된 유일한 컨디션(Condition)은 True 또는 False 값을 갖는 Ready 컨디션이며, 이 값이 True라는 것은 파드가 요청을 처리할 수 있으며 모든 동일한 서비스를 묶는 로드 밸런싱 풀에 추가되어야 함을 의미한다.
|
||||
|
||||
마지막으로, 파드와 관련된 최근 이벤트 로그가 표시된다. 시스템은 동일한 여러 이벤트를 처음/마지막 발생 시간 및 발생 횟수만 압축적으로 표시한다. "From"은 이벤트 로그를 발생하는 구성 요소를 가리키고, "SubobjectPath"는 참조되는 개체(예: 파드 내 컨테이너)를 나타내며, "Reason" 및 "Message"는 발생한 상황을 알려 준다.
|
||||
|
||||
|
||||
## 예시: Pending 상태의 파드 디버깅하기
|
||||
|
||||
이벤트를 사용하여 감지할 수 있는 일반적인 시나리오는 노드에 할당될 수 없는 파드를 생성하는 경우이다. 예를 들어 파드가 노드에 사용 가능한 리소스보다 더 많은 리소스를 요청하거나, 또는 어떤 노드에도 해당되지 않는 레이블 셀렉터를 명시했을 수 있다. 예를 들어 4개 노드로 구성되며 각 (가상) 머신에 1 CPU가 있는 클러스터가 있는 상황에서, 위 예시 대신 2 레플리카가 아니라 5 레플리카를, 500 밀리코어가 아니라 600 밀리코어를 요청하는 디플로이먼트를 배포했다고 해 보자. 이러한 경우 5개의 파드 중 하나는 스케줄링될 수 없을 것이다. (각 노드에는 fluentd, skydns 등의 클러스터 애드온도 실행되고 있으므로, 만약 1000 밀리코어를 요청했다면 파드가 하나도 스케줄될 수 없었을 것이다.)
|
||||
|
||||
```shell
|
||||
kubectl get pods
|
||||
```
|
||||
|
||||
```none
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-deployment-1006230814-6winp 1/1 Running 0 7m
|
||||
nginx-deployment-1006230814-fmgu3 1/1 Running 0 7m
|
||||
nginx-deployment-1370807587-6ekbw 1/1 Running 0 1m
|
||||
nginx-deployment-1370807587-fg172 0/1 Pending 0 1m
|
||||
nginx-deployment-1370807587-fz9sd 0/1 Pending 0 1m
|
||||
```
|
||||
|
||||
nginx-deployment-1370807587-fz9sd 파드가 왜 실행되지 않는지를 알아 보려면, pending 상태의 파드에 대해 `kubectl describe pod` 명령을 실행하고 이벤트(event) 항목을 확인해 볼 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl describe pod nginx-deployment-1370807587-fz9sd
|
||||
```
|
||||
|
||||
```none
|
||||
Name: nginx-deployment-1370807587-fz9sd
|
||||
Namespace: default
|
||||
Node: /
|
||||
Labels: app=nginx,pod-template-hash=1370807587
|
||||
Status: Pending
|
||||
IP:
|
||||
Controllers: ReplicaSet/nginx-deployment-1370807587
|
||||
Containers:
|
||||
nginx:
|
||||
Image: nginx
|
||||
Port: 80/TCP
|
||||
QoS Tier:
|
||||
memory: Guaranteed
|
||||
cpu: Guaranteed
|
||||
Limits:
|
||||
cpu: 1
|
||||
memory: 128Mi
|
||||
Requests:
|
||||
cpu: 1
|
||||
memory: 128Mi
|
||||
Environment Variables:
|
||||
Volumes:
|
||||
default-token-4bcbi:
|
||||
Type: Secret (a volume populated by a Secret)
|
||||
SecretName: default-token-4bcbi
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
|
||||
--------- -------- ----- ---- ------------- -------- ------ -------
|
||||
1m 48s 7 {default-scheduler } Warning FailedScheduling pod (nginx-deployment-1370807587-fz9sd) failed to fit in any node
|
||||
fit failure on node (kubernetes-node-6ta5): Node didn't have enough resource: CPU, requested: 1000, used: 1420, capacity: 2000
|
||||
fit failure on node (kubernetes-node-wul5): Node didn't have enough resource: CPU, requested: 1000, used: 1100, capacity: 2000
|
||||
```
|
||||
|
||||
여기서 스케줄러가 기록한 이벤트를 통해, 파드가 `FailedScheduling` 사유로 인해 스케줄링되지 않았음을 알 수 있다(다른 이유도 있을 수 있음). 이 메시지를 통해 어떤 노드에도 이 파드를 실행하기 위한 충분한 리소스가 없었음을 알 수 있다.
|
||||
|
||||
이 상황을 바로잡으려면, `kubectl scale` 명령으로 디플로이먼트의 레플리카를 4 이하로 줄일 수 있다. (또는 한 파드를 pending 상태로 두어도 되며, 이렇게 해도 문제는 없다.)
|
||||
|
||||
`kubectl describe pod` 출력의 마지막에 있는 것과 같은 이벤트는 etcd에 기록되어 보존되며 클러스터에 어떤 일이 일어나고 있는지에 대한 높은 차원의 정보를 제공한다. 모든 이벤트의 목록을 보려면 다음 명령을 실행한다.
|
||||
|
||||
```shell
|
||||
kubectl get events
|
||||
```
|
||||
|
||||
그런데 이벤트는 네임스페이스 스코프 객체라는 것을 기억해야 한다. 즉 네임스페이스 스코프 객체에 대한 이벤트(예: `my-namespace` 네임스페이스의 파드에 어떤 일이 발생했는지)가 궁금하다면, 다음과 같이 커맨드에 네임스페이스를 명시해야 한다.
|
||||
|
||||
```shell
|
||||
kubectl get events --namespace=my-namespace
|
||||
```
|
||||
|
||||
모든 네임스페이스에 대한 이벤트를 보려면, `--all-namespaces` 인자를 사용할 수 있다.
|
||||
|
||||
`kubectl describe pod` 명령 외에도, `kubectl get pod` 이상의 정보를 얻는 다른 방법은 `kubectl get pod` 명령에 출력 형식 플래그 `-o yaml` 인자를 추가하는 것이다. 이렇게 하면 `kubectl describe pod` 명령보다 더 많은 정보, 원천적으로는 시스템이 파드에 대해 알고 있는 모든 정보를 YAML 형식으로 볼 수 있다. 여기서 어노테이션(레이블 제한이 없는 키-밸류 메타데이터이며, 쿠버네티스 시스템 구성 요소가 내부적으로 사용함), 재시작 정책, 포트, 볼륨과 같은 정보를 볼 수 있을 것이다.
|
||||
|
||||
```shell
|
||||
kubectl get pod nginx-deployment-1006230814-6winp -o yaml
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
creationTimestamp: "2022-02-17T21:51:01Z"
|
||||
generateName: nginx-deployment-67d4bdd6f5-
|
||||
labels:
|
||||
app: nginx
|
||||
pod-template-hash: 67d4bdd6f5
|
||||
name: nginx-deployment-67d4bdd6f5-w6kd7
|
||||
namespace: default
|
||||
ownerReferences:
|
||||
- apiVersion: apps/v1
|
||||
blockOwnerDeletion: true
|
||||
controller: true
|
||||
kind: ReplicaSet
|
||||
name: nginx-deployment-67d4bdd6f5
|
||||
uid: 7d41dfd4-84c0-4be4-88ab-cedbe626ad82
|
||||
resourceVersion: "1364"
|
||||
uid: a6501da1-0447-4262-98eb-c03d4002222e
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
imagePullPolicy: Always
|
||||
name: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
volumeMounts:
|
||||
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
|
||||
name: kube-api-access-bgsgp
|
||||
readOnly: true
|
||||
dnsPolicy: ClusterFirst
|
||||
enableServiceLinks: true
|
||||
nodeName: kube-worker-1
|
||||
preemptionPolicy: PreemptLowerPriority
|
||||
priority: 0
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
serviceAccount: default
|
||||
serviceAccountName: default
|
||||
terminationGracePeriodSeconds: 30
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/not-ready
|
||||
operator: Exists
|
||||
tolerationSeconds: 300
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/unreachable
|
||||
operator: Exists
|
||||
tolerationSeconds: 300
|
||||
volumes:
|
||||
- name: kube-api-access-bgsgp
|
||||
projected:
|
||||
defaultMode: 420
|
||||
sources:
|
||||
- serviceAccountToken:
|
||||
expirationSeconds: 3607
|
||||
path: token
|
||||
- configMap:
|
||||
items:
|
||||
- key: ca.crt
|
||||
path: ca.crt
|
||||
name: kube-root-ca.crt
|
||||
- downwardAPI:
|
||||
items:
|
||||
- fieldRef:
|
||||
apiVersion: v1
|
||||
fieldPath: metadata.namespace
|
||||
path: namespace
|
||||
status:
|
||||
conditions:
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: "2022-02-17T21:51:01Z"
|
||||
status: "True"
|
||||
type: Initialized
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: "2022-02-17T21:51:06Z"
|
||||
status: "True"
|
||||
type: Ready
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: "2022-02-17T21:51:06Z"
|
||||
status: "True"
|
||||
type: ContainersReady
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: "2022-02-17T21:51:01Z"
|
||||
status: "True"
|
||||
type: PodScheduled
|
||||
containerStatuses:
|
||||
- containerID: containerd://5403af59a2b46ee5a23fb0ae4b1e077f7ca5c5fb7af16e1ab21c00e0e616462a
|
||||
image: docker.io/library/nginx:latest
|
||||
imageID: docker.io/library/nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767
|
||||
lastState: {}
|
||||
name: nginx
|
||||
ready: true
|
||||
restartCount: 0
|
||||
started: true
|
||||
state:
|
||||
running:
|
||||
startedAt: "2022-02-17T21:51:05Z"
|
||||
hostIP: 192.168.0.113
|
||||
phase: Running
|
||||
podIP: 10.88.0.3
|
||||
podIPs:
|
||||
- ip: 10.88.0.3
|
||||
- ip: 2001:db8::1
|
||||
qosClass: Guaranteed
|
||||
startTime: "2022-02-17T21:51:01Z"
|
||||
```
|
||||
|
||||
## 파드의 로그 확인하기 {#examine-pod-logs}
|
||||
|
||||
먼저, 확인하고자 하는 컨테이너의 로그를 확인한다.
|
||||
|
||||
```shell
|
||||
kubectl logs ${POD_NAME} ${CONTAINER_NAME}
|
||||
```
|
||||
|
||||
만약 컨테이너가 이전에 크래시 되었다면, 다음의 명령을 통해 컨테이너의 크래시 로그를 살펴볼 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl logs --previous ${POD_NAME} ${CONTAINER_NAME}
|
||||
```
|
||||
|
||||
## exec를 통해 컨테이너 디버깅하기 {#container-exec}
|
||||
|
||||
만약 {{< glossary_tooltip text="컨테이너 이미지" term_id="image" >}}에
|
||||
디버깅 도구가 포함되어 있다면, `kubectl exec`을 통해 특정 컨테이너에서 해당 명령들을
|
||||
실행할 수 있다. (리눅스나 윈도우 OS를 기반으로 만들어진 이미지에는 대부분 디버깅 도구를 포함하고
|
||||
있다.)
|
||||
|
||||
```shell
|
||||
kubectl exec ${POD_NAME} -c ${CONTAINER_NAME} -- ${CMD} ${ARG1} ${ARG2} ... ${ARGN}
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
`-c ${CONTAINER_NAME}` 인자는 선택적이다. 만약 하나의 컨테이너만 포함된 파드라면 해당 옵션을 생략할 수 있다.
|
||||
{{< /note >}}
|
||||
|
||||
예를 들어, 동작 중인 카산드라 파드의 로그를 살펴보기 위해서는 다음과 같은 명령을 실행할 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl exec cassandra -- cat /var/log/cassandra/system.log
|
||||
```
|
||||
|
||||
`kubectl exec`에 `-i`와 `-t` 옵션을 사용해서 터미널에서 접근할 수 있는 쉘을 실행시킬 수도 있다.
|
||||
예를 들면 다음과 같다.
|
||||
|
||||
```shell
|
||||
kubectl exec -it cassandra -- sh
|
||||
```
|
||||
|
||||
더욱 상세한 내용은
|
||||
[동작중인 컨테이너의 쉘에 접근하기](/ko/docs/tasks/debug/debug-application/get-shell-running-container/)를 참고한다.
|
||||
|
||||
## 임시(ephemeral) 디버그 컨테이너를 사용해서 디버깅하기 {#ephemeral-container}
|
||||
|
||||
{{< feature-state state="beta" for_k8s_version="v1.23" >}}
|
||||
|
||||
컨테이너가 크래시 됐거나
|
||||
[distroless 이미지](https://github.com/GoogleContainerTools/distroless)처럼
|
||||
컨테이너 이미지에 디버깅 도구를 포함하고 있지 않아 `kubectl exec`로는 충분하지 않은 경우에는
|
||||
{{< glossary_tooltip text="임시(Ephemeral) 컨테이너" term_id="ephemeral-container" >}}를 사용하는 것이
|
||||
인터랙티브한 트러블슈팅에 유용하다.
|
||||
|
||||
### 임시 컨테이너를 사용한 디버깅 예시 {#ephemeral-container-example}
|
||||
|
||||
`kubectl debug` 명령어를 사용해서 동작 중인 파드에 임시 컨테이너를 추가할 수 있다.
|
||||
먼저, 다음과 같이 파드를 추가한다.
|
||||
|
||||
```shell
|
||||
kubectl run ephemeral-demo --image=k8s.gcr.io/pause:3.1 --restart=Never
|
||||
```
|
||||
|
||||
이 섹션의 예시에서는 디버깅 도구가 포함되지 않은 이미지의 사례를 보여드리기 위해
|
||||
`pause` 컨테이너 이미지를 사용했는데, 이 대신 어떠한 이미지를 사용해도
|
||||
될 것이다.
|
||||
|
||||
만약 `kubectl exec`을 통해 쉘을 생성하려 한다면 다음과 같은 에러를
|
||||
확인할 수 있을 텐데, 그 이유는 이 이미지에 쉘이 존재하지 않기 때문이다.
|
||||
|
||||
```shell
|
||||
kubectl exec -it ephemeral-demo -- sh
|
||||
```
|
||||
|
||||
```
|
||||
OCI runtime exec failed: exec failed: container_linux.go:346: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknown
|
||||
```
|
||||
|
||||
이 명령어 대신 `kubectl debug`을 사용해서 디버깅 컨테이너를 생성할 수 있다.
|
||||
만약 `-i`/`--interactive` 인자를 사용한다면, `kubectl`은 임시
|
||||
컨테이너의 콘솔에 자동으로 연결할 것이다.
|
||||
|
||||
```shell
|
||||
kubectl debug -it ephemeral-demo --image=busybox --target=ephemeral-demo
|
||||
```
|
||||
|
||||
```
|
||||
Defaulting debug container name to debugger-8xzrl.
|
||||
If you don't see a command prompt, try pressing enter.
|
||||
/ #
|
||||
```
|
||||
|
||||
이 명령어는 새로운 busybox 컨테이너를 추가하고 해당 컨테이너로 연결한다. `--target`
|
||||
파라미터를 사용하면 다른 컨테이너의 프로세스 네임스페이스를 대상으로 하게 된다. 여기서는
|
||||
이 옵션이 꼭 필요한데, `kubectl run`이 생성하는 파드에 대해
|
||||
[프로세스 네임스페이스 공유](/docs/tasks/configure-pod-container/share-process-namespace/)를
|
||||
활성화하지 않기 때문이다.
|
||||
|
||||
{{< note >}}
|
||||
`--target` 파라미터는 사용 중인
|
||||
{{< glossary_tooltip text="컨테이너 런타임" term_id="container-runtime" >}}에서
|
||||
지원해야지만 사용할 수 있다. 만일 지원되지 않는다면,
|
||||
임시 컨테이너가 시작되지 않을 수 있거나 독립적인 프로세스
|
||||
네임스페이스를 가지고 시작될 수 있다.
|
||||
{{< /note >}}
|
||||
|
||||
`kubectl describe` 명령을 사용하면 새롭게 생성된 임시 컨테이너의 상태를 확인할 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl describe pod ephemeral-demo
|
||||
```
|
||||
|
||||
```
|
||||
...
|
||||
Ephemeral Containers:
|
||||
debugger-8xzrl:
|
||||
Container ID: docker://b888f9adfd15bd5739fefaa39e1df4dd3c617b9902082b1cfdc29c4028ffb2eb
|
||||
Image: busybox
|
||||
Image ID: docker-pullable://busybox@sha256:1828edd60c5efd34b2bf5dd3282ec0cc04d47b2ff9caa0b6d4f07a21d1c08084
|
||||
Port: <none>
|
||||
Host Port: <none>
|
||||
State: Running
|
||||
Started: Wed, 12 Feb 2020 14:25:42 +0100
|
||||
Ready: False
|
||||
Restart Count: 0
|
||||
Environment: <none>
|
||||
Mounts: <none>
|
||||
...
|
||||
```
|
||||
|
||||
디버깅이 다 끝나면 `kubectl delete`을 통해 파드를 제거할 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl delete pod ephemeral-demo
|
||||
```
|
||||
|
||||
## 파드의 복제본을 이용해서 디버깅하기
|
||||
|
||||
때때로 파드의 설정 옵션에 따라 특정 상황에서 트러블슈팅을 하기가 어려울 수 있다.
|
||||
예를 들어, 만일 여러분의 컨테이너 이미지가 쉘을 포함하고 있지 않거나, 여러분의
|
||||
애플리케이션이 컨테이너 시작에서 크래시가 발생한다면 `kubectl exec`을 이용해서
|
||||
컨테이너를 트러블슈팅할 수 없을 수 있다. 이러한 상황에서는 `kubectl debug`을 사용해서
|
||||
파드의 복제본을 디버깅을 위한 추가적인 설정 옵션과 함께 생성할 수 있다.
|
||||
|
||||
### 새 컨테이너와 함께 파드의 복제본 생성하기
|
||||
|
||||
만일 여러분의 애플리케이션이 동작은 하고 있지만 예상과는 다르게 동작하는 경우,
|
||||
파드의 복제본에 새로운 컨테이너를 추가함으로써 추가적인 트러블슈팅 도구들을
|
||||
파드에 함께 추가할 수 있다.
|
||||
|
||||
가령, 여러분의 애플리케이션 컨테이너 이미지는 `busybox`를 기반으로 하고 있는데
|
||||
여러분은 `busybox`에는 없는 디버깅 도구를 필요로 한다고 가정해 보자. 이러한
|
||||
시나리오는 `kubectl run` 명령을 통해 시뮬레이션 해볼 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl run myapp --image=busybox --restart=Never -- sleep 1d
|
||||
```
|
||||
|
||||
다음의 명령을 실행시켜 디버깅을 위한 새로운 우분투 컨테이너와 함께 `myapp-debug`이란
|
||||
이름의 `myapp` 컨테이너 복제본을 생성할 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl debug myapp -it --image=ubuntu --share-processes --copy-to=myapp-debug
|
||||
```
|
||||
|
||||
```
|
||||
Defaulting debug container name to debugger-w7xmf.
|
||||
If you don't see a command prompt, try pressing enter.
|
||||
root@myapp-debug:/#
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
* 만일 여러분이 새로 생성되는 컨테이너의 이름을 `--container` 플래그와 함께 지정하지 않는다면,
|
||||
`kubectl debug`는 자동으로 새로운 컨테이너 이름을 생성한다.
|
||||
* `-i` 플래그를 사용하면 `kubectl debug` 명령이 새로운 컨테이너에 기본적으로 연결되게 된다.
|
||||
이러한 동작은 `--attach=false`을 지정하여 방지할 수 있다. 만일 여러분의 세션이
|
||||
연결이 끊어진다면 `kubectl attach`를 사용해서 다시 연결할 수 있다.
|
||||
* `--share-processes` 옵션은 이 파드에 있는 컨테이너가 해당 파드에 속한 다른 컨테이너의
|
||||
프로세스를 볼 수 있도록 한다. 이 옵션이 어떻게 동작하는지에 대해 더 알아보기 위해서는
|
||||
다음의 [파드의 컨테이너 간 프로세스 네임스페이스 공유](
|
||||
/docs/tasks/configure-pod-container/share-process-namespace/)를 참고하라.
|
||||
{{< /note >}}
|
||||
|
||||
사용이 모두 끝나면, 디버깅에 사용된 파드를 잊지 말고 정리한다.
|
||||
|
||||
```shell
|
||||
kubectl delete pod myapp myapp-debug
|
||||
```
|
||||
|
||||
### 명령어를 변경하며 파드의 복제본 생성하기
|
||||
|
||||
때때로 컨테이너의 명령어를 변경하는 것이 유용한 경우가 있는데, 예를 들면 디버그 플래그를 추가하기
|
||||
위해서나 애플리케이션이 크래시 되는 경우이다.
|
||||
|
||||
다음의 `kubectl run` 명령을 통해 즉각적으로 크래시가 발생하는 애플리케이션의
|
||||
사례를 시뮬레이션해 볼 수 있다.
|
||||
|
||||
```
|
||||
kubectl run --image=busybox myapp -- false
|
||||
```
|
||||
|
||||
`kubectl describe pod myapp` 명령을 통해 이 컨테이너에 크래시가 발생하고 있음을 확인할 수 있다.
|
||||
|
||||
```
|
||||
Containers:
|
||||
myapp:
|
||||
Image: busybox
|
||||
...
|
||||
Args:
|
||||
false
|
||||
State: Waiting
|
||||
Reason: CrashLoopBackOff
|
||||
Last State: Terminated
|
||||
Reason: Error
|
||||
Exit Code: 1
|
||||
```
|
||||
|
||||
이러한 경우에 `kubectl debug`을 통해 명령어를 지정함으로써 해당 파드의
|
||||
복제본을 인터랙티브 쉘로 생성할 수 있다.
|
||||
|
||||
```
|
||||
kubectl debug myapp -it --copy-to=myapp-debug --container=myapp -- sh
|
||||
```
|
||||
|
||||
```
|
||||
If you don't see a command prompt, try pressing enter.
|
||||
/ #
|
||||
```
|
||||
|
||||
이제 인터랙티브 쉘에 접근할 수 있으니 파일 시스템 경로를 확인하거나
|
||||
동작 중인 컨테이너의 명령어를 직접 확인하는 등의 작업이 가능하다.
|
||||
|
||||
{{< note >}}
|
||||
* 특정 컨테이너의 명령어를 변경하기 위해서는 `--container` 옵션을 통해 해당 컨테이너의
|
||||
이름을 지정해야만 한다. 이름을 지정하지 않는다면 `kubectl debug`은 이전에 지정한 명령어를
|
||||
그대로 사용해서 컨테이너를 생성할 것이다.
|
||||
* 기본적으로 `-i` 플래그는 `kubectl debug` 명령이 컨테이너에 바로 연결되도록 한다.
|
||||
이러한 동작을 방지하기 위해서는 `--attach=false` 옵션을 지정할 수 있다. 만약 여러분이 세션이
|
||||
종료된다면 `kubectl attach` 명령을 통해 다시 연결할 수 있다.
|
||||
{{< /note >}}
|
||||
|
||||
사용이 모두 끝나면, 디버깅에 사용된 파드들을 잊지 말고 정리한다.
|
||||
|
||||
```shell
|
||||
kubectl delete pod myapp myapp-debug
|
||||
```
|
||||
|
||||
### 컨테이너 이미지를 변경하며 파드의 복제본 생성하기
|
||||
|
||||
특정한 경우에 여러분은 제대로 동작하지 않는 파드의 이미지를
|
||||
기존 프로덕션 컨테이너 이미지에서 디버깅 빌드나 추가적인 도구를 포함한
|
||||
이미지로 변경하고 싶을 수 있다.
|
||||
|
||||
이 사례를 보여주기 위해 `kubectl run` 명령을 통해 파드를 생성하였다.
|
||||
|
||||
```
|
||||
kubectl run myapp --image=busybox --restart=Never -- sleep 1d
|
||||
```
|
||||
|
||||
여기서는 `kubectl debug` 명령을 통해 해당 컨테이너 이미지를 `ubuntu`로 변경하며
|
||||
복제본을 생성하였다.
|
||||
|
||||
```
|
||||
kubectl debug myapp --copy-to=myapp-debug --set-image=*=ubuntu
|
||||
```
|
||||
|
||||
`--set-image`의 문법은 `kubectl set image`와 동일하게 `container_name=image`
|
||||
형식의 문법을 사용한다. `*=ubuntu`라는 의미는 모든 컨테이너의 이미지를 `ubuntu`로
|
||||
변경하겠다는 의미이다.
|
||||
|
||||
사용이 모두 끝나면, 디버깅에 사용된 파드를 잊지 말고 정리한다.
|
||||
|
||||
```shell
|
||||
kubectl delete pod myapp myapp-debug
|
||||
```
|
||||
|
||||
## 노드의 쉘을 사용해서 디버깅하기 {#node-shell-session}
|
||||
|
||||
만약 위의 어떠한 방법도 사용할 수 없다면, 파드가 현재 동작 중인 노드를 찾아
|
||||
호스트의 네임스페이스로 동작하는 특권 파드를 생성할 수 있다.
|
||||
다음 `kubectl debug` 명령을 통해 해당 노드에서 인터랙티브한 쉘을 생성할 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl debug node/mynode -it --image=ubuntu
|
||||
```
|
||||
|
||||
```
|
||||
Creating debugging pod node-debugger-mynode-pdx84 with container debugger on node mynode.
|
||||
If you don't see a command prompt, try pressing enter.
|
||||
root@ek8s:/#
|
||||
```
|
||||
|
||||
노드에서 디버깅 세션을 생성할 때 유의해야 할 점은 다음과 같다.
|
||||
|
||||
* `kubectl debug`는 노드의 이름에 기반해 새로운 파드의 이름을
|
||||
자동으로 생성한다.
|
||||
* 컨테이너는 호스트 네임스페이스(IPC, 네트워크, PID 네임스페이스)에서 동작한다.
|
||||
* 노드의 루트 파일시스템은 `/host`에 마운트된다.
|
||||
|
||||
사용이 모두 끝나면, 디버깅에 사용된 파드를 잊지 말고 정리한다.
|
||||
|
||||
```shell
|
||||
kubectl delete pod node-debugger-mynode-pdx84
|
||||
```
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
title: 스테이트풀셋 디버깅하기
|
||||
content_type: task
|
||||
weight: 30
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
이 문서에서는 스테이트풀셋을 디버깅 방법에 대해 설명한다.
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
* 쿠버네티스 클러스터가 준비되어 있어야 하고, kubectl 커맨드 라인 도구가 클러스터와 통신할 수 있게 사전에 설정되어 있어야 한다.
|
||||
* 조사하고자 하는 스테이트풀셋이 사전에 준비되어 있어야 한다.
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
## 스테이트풀셋 디버깅하기
|
||||
|
||||
레이블이 `app=myapp`으로 지정된 스테이트풀셋 파드를 전부 나열하기 위해서는
|
||||
다음의 명령을 사용할 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl get pods -l app=myapp
|
||||
```
|
||||
|
||||
만약 오랜 시간동안 `Unknown`이나 `Terminating` 상태에 있는
|
||||
파드들을 발견하였다면, 이러한 파드들을 어떻게 다루는지 알아보기 위해
|
||||
[스테이트풀셋 파드 삭제하기](/ko/docs/tasks/run-application/delete-stateful-set/)를 참고하길 바란다.
|
||||
스테이트풀셋에 포함된 개별 파드들을 디버깅하기 위해서는
|
||||
[파드 디버그하기](/ko/docs/tasks/debug/debug-application/debug-pods/) 가이드를 참고하길 바란다.
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
[초기화 컨테이너(Init container) 디버그하기](/ko/docs/tasks/debug/debug-application/debug-init-containers/)를 참고하길 바란다.
|
||||
@@ -0,0 +1,128 @@
|
||||
---
|
||||
title: 파드 실패의 원인 검증하기
|
||||
content_type: task
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
이 페이지는 컨테이너 종료 메시지를 읽고 쓰는
|
||||
방법을 보여준다.
|
||||
|
||||
종료 메시지는 컨테이너가 치명적인 이벤트에 대한 정보를,
|
||||
대시보드나 모니터링 소프트웨어 도구와 같이
|
||||
쉽게 조회 및 표시할 수 있는 위치에
|
||||
기록하는 방법을 제공한다.
|
||||
대부분의 경우에 종료 메시지에 넣는 정보는
|
||||
일반
|
||||
[쿠버네티스 로그](/ko/docs/concepts/cluster-administration/logging/)에도 쓰여져야 한다.
|
||||
|
||||
|
||||
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
## 종료 메시지 읽기 및 쓰기
|
||||
|
||||
이 예제에서는, 하나의 컨테이너를 실행하는 파드를 생성한다.
|
||||
하단의 설정 파일은 컨테이너가 시작될 때 수행하는
|
||||
명령어를 지정한다.
|
||||
|
||||
{{< codenew file="debug/termination.yaml" >}}
|
||||
|
||||
1. 다음의 YAML 설정 파일에 기반한 파드를 생성한다.
|
||||
|
||||
kubectl apply -f https://k8s.io/examples/debug/termination.yaml
|
||||
|
||||
YAML 파일에 있는 `command` 와 `args` 필드에서 컨테이너가 10초 간 잠든 뒤에
|
||||
"Sleep expired" 문자열을 `/dev/termination-log` 파일에 기록하는
|
||||
것을 확인할 수 있다. 컨테이너는 "Sleep expired" 메시지를
|
||||
기록한 후에 종료된다.
|
||||
|
||||
1. 파드와 관련된 정보를 출력한다.
|
||||
|
||||
kubectl get pod termination-demo
|
||||
|
||||
파드가 더 이상 실행되지 않을 때까지 앞선 명령어를 반복한다.
|
||||
|
||||
1. 파드에 관한 상세 정보를 출력한다.
|
||||
|
||||
kubectl get pod termination-demo --output=yaml
|
||||
|
||||
결과는 "Sleep expired" 메시지를 포함한다.
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
...
|
||||
lastState:
|
||||
terminated:
|
||||
containerID: ...
|
||||
exitCode: 0
|
||||
finishedAt: ...
|
||||
message: |
|
||||
Sleep expired
|
||||
...
|
||||
|
||||
1. 종료 메시지만을 포함하는 출력 결과를 보기
|
||||
위해서는 Go 템플릿을 사용한다.
|
||||
|
||||
kubectl get pod termination-demo -o go-template="{{range .status.containerStatuses}}{{.lastState.terminated.message}}{{end}}"
|
||||
|
||||
여러 컨테이너를 포함하는 파드의 경우, Go 템플릿을 사용하여 컨테이너 이름도 출력할 수 있다. 이렇게 하여, 어떤 컨테이너가 실패하는지 찾을 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl get pod multi-container-pod -o go-template='{{range .status.containerStatuses}}{{printf "%s:\n%s\n\n" .name .lastState.terminated.message}}{{end}}'
|
||||
```
|
||||
|
||||
## 종료 메시지 사용자 정의하기
|
||||
|
||||
쿠버네티스는 컨테이너의 `terminationMessagePath` 필드에 지정된
|
||||
종료 메시지 파일에서 종료 메시지를 검색하며, 이 필드의 기본값은
|
||||
`/dev/termination-log` 이다. 이 필드를 사용자 정의 함으로써
|
||||
쿠버네티스가 종료 메시지를 검색할 때 다른 파일을 사용하도록 조정할 수 있다.
|
||||
쿠버네티스는 지정된 파일의 내용을 사용하여 컨테이너의 성공 및 실패에 대한 상태 메시지를 채운다.
|
||||
|
||||
종료 메시지는 assertion failure 메세지처럼 간결한 최종 상태로 생성된다.
|
||||
kubelet은 4096 바이트보다 긴 메시지를 자른다. 모든 컨테이너의 총 메시지 길이는
|
||||
12KiB로 제한된다. 기본 종료 메시지 경로는 `/dev/termination-log`이다.
|
||||
파드가 시작된 후에는 종료 메시지 경로를 설정할 수 없다.
|
||||
|
||||
다음의 예제에서 컨테이너는, 쿠버네티스가 조회할 수 있도록
|
||||
`/tmp/my-log` 파일에 종료 메시지를 기록한다.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: msg-path-demo
|
||||
spec:
|
||||
containers:
|
||||
- name: msg-path-demo-container
|
||||
image: debian
|
||||
terminationMessagePath: "/tmp/my-log"
|
||||
```
|
||||
|
||||
또한 사용자는 추가적인 사용자 정의를 위해 컨테이너의 `terminationMessagePolicy`
|
||||
필드를 설정할 수 있다. 이 필드의 기본 값은 `File` 이며,
|
||||
이는 오직 종료 메시지 파일에서만 종료 메시지가 조회되는 것을 의미한다.
|
||||
`terminationMessagePolicy` 필드의 값을 "`FallbackToLogsOnError` 으로
|
||||
설정함으로써, 종료 메시지 파일이 비어 있고 컨테이너가 오류와 함께 종료 되었을 경우
|
||||
쿠버네티스가 컨테이너 로그 출력의 마지막 청크를 사용하도록 지시할 수 있다.
|
||||
로그 출력은 2048 바이트나 80 행 중 더 작은 값으로 제한된다.
|
||||
|
||||
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
|
||||
* [컨테이너](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#container-v1-core)
|
||||
에 있는 `terminationMessagePath` 에 대해 읽어보기.
|
||||
* [로그 검색](/ko/docs/concepts/cluster-administration/logging/)에 대해 배워보기.
|
||||
* [Go 템플릿](https://golang.org/pkg/text/template/)에 대해 배워보기.
|
||||
@@ -0,0 +1,157 @@
|
||||
---
|
||||
|
||||
|
||||
|
||||
title: 동작중인 컨테이너의 셸에 접근하기
|
||||
content_type: task
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
이 페이지는 동작중인 컨테이너에 접근하기 위해 `kubectl exec`을 사용하는
|
||||
방법에 대해 설명한다.
|
||||
|
||||
|
||||
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}}
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
## 컨테이너의 셸에 접근하기
|
||||
|
||||
이 예시에서는 하나의 컨테이너를 가진 파드를 생성할 것이다. 이 컨테이너는
|
||||
nginx 이미지를 실행한다. 해당 파드에 대한 설정 파일은 다음과 같다.
|
||||
|
||||
{{< codenew file="application/shell-demo.yaml" >}}
|
||||
|
||||
파드를 생성한다.
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://k8s.io/examples/application/shell-demo.yaml
|
||||
```
|
||||
|
||||
다음을 통해 컨테이너가 동작하고 있는지 확인할 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl get pod shell-demo
|
||||
```
|
||||
|
||||
동작중인 컨테이너의 셸에 접근한다.
|
||||
|
||||
```shell
|
||||
kubectl exec --stdin --tty shell-demo -- /bin/bash
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
kubectl 명령어 인자와 사용하고자 하는 명령어의 인자를 구분하기 위해서는 이중 대시(`--`)를 사용할 수 있다.
|
||||
{{< /note >}}
|
||||
|
||||
셸에 접근해서 다음처럼 루트 디렉토리를 확인해 볼 수 있다.
|
||||
|
||||
```shell
|
||||
# Run this inside the container
|
||||
ls /
|
||||
```
|
||||
|
||||
접근한 셸에서 다른 명령어도 한번 실행해 보아라. 다음은 실행해 볼
|
||||
명령의 예시이다.
|
||||
|
||||
```shell
|
||||
# You can run these example commands inside the container
|
||||
ls /
|
||||
cat /proc/mounts
|
||||
cat /proc/1/maps
|
||||
apt-get update
|
||||
apt-get install -y tcpdump
|
||||
tcpdump
|
||||
apt-get install -y lsof
|
||||
lsof
|
||||
apt-get install -y procps
|
||||
ps aux
|
||||
ps aux | grep nginx
|
||||
```
|
||||
|
||||
## nginx의 최상단 페이지 작성하기
|
||||
|
||||
앞에서 생성한 파드에 대한 설정을 살펴보아라. 파드에는
|
||||
`emptyDir` 볼륨이 사용되었고, 이 컨테이너는 해당 볼륨을
|
||||
`/usr/share/nginx/html` 경로에 마운트하였다.
|
||||
|
||||
접근한 셸 환경에서 `/usr/share/nginx/html` 디렉터리에 `index.html` 파일을
|
||||
생성해 보아라.
|
||||
|
||||
```shell
|
||||
# Run this inside the container
|
||||
echo 'Hello shell demo' > /usr/share/nginx/html/index.html
|
||||
```
|
||||
|
||||
셸 환경에서 nginx 서버에 GET 요청을 시도해보면 다음과 같다.
|
||||
|
||||
```shell
|
||||
# Run this in the shell inside your container
|
||||
apt-get update
|
||||
apt-get install curl
|
||||
curl http://localhost/
|
||||
```
|
||||
|
||||
출력 결과는 여러분이 `index.html` 파일에 작성한 텍스트를 출력할 것이다.
|
||||
|
||||
```
|
||||
Hello shell demo
|
||||
```
|
||||
|
||||
셸 사용이 모두 끝났다면 `exit`을 입력해 종료하라.
|
||||
|
||||
```shell
|
||||
exit # To quit the shell in the container
|
||||
```
|
||||
|
||||
## 컨테이너에서 개별 명령어 실행하기
|
||||
|
||||
셸이 아닌 일반적인 커맨드 환경에서 다음처럼 동작중인 컨테이너의
|
||||
환경 변수를 출력할 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl exec shell-demo env
|
||||
```
|
||||
|
||||
다른 명령어도 한번 실행해 보아라. 다음은 실행해 볼 명령의 예시이다.
|
||||
|
||||
```shell
|
||||
kubectl exec shell-demo -- ps aux
|
||||
kubectl exec shell-demo -- ls /
|
||||
kubectl exec shell-demo -- cat /proc/1/mounts
|
||||
```
|
||||
|
||||
|
||||
|
||||
<!-- discussion -->
|
||||
|
||||
## 파드에 한 개 이상의 컨테이너가 있을 경우 셸에 접근하기
|
||||
|
||||
만일 파드에 한 개 이상의 컨테이너가 있을 경우, `kubectl exec` 명령어에
|
||||
`--container` 혹은 `-c` 옵션을 사용해서 컨테이너를 지정하라. 예를 들어,
|
||||
여러분이 my-pod라는 이름의 파드가 있다고 가정해 보자. 이 파드에는 _main-app_ 과
|
||||
_helper-app_ 이라는 이름의 두 컨테이너가 있다. 다음 명령어는 _main-app_
|
||||
컨테이너에 대한 셸에 접근할 것이다.
|
||||
|
||||
```shell
|
||||
kubectl exec -i -t my-pod --container main-app -- /bin/bash
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
축약형 옵션인 `-i` 와 `-t` 는 각각 `--stdin` 와 `--tty` 옵션에 대응된다.
|
||||
{{< /note >}}
|
||||
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
|
||||
* [kubectl exec](/docs/reference/generated/kubectl/kubectl-commands/#exec)를 참고한다.
|
||||
@@ -0,0 +1,316 @@
|
||||
---
|
||||
|
||||
|
||||
title: 클러스터 트러블슈팅
|
||||
description: 일반적인 클러스터 이슈를 디버깅한다.
|
||||
weight: 20
|
||||
no_list: true
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
이 문서는 클러스터 트러블슈팅에 대해 설명한다. 사용자가 겪고 있는 문제의 근본 원인으로서 사용자의 애플리케이션을
|
||||
이미 배제했다고 가정한다.
|
||||
애플리케이션 디버깅에 대한 팁은 [애플리케이션 트러블슈팅 가이드](/ko/docs/tasks/debug/debug-application/)를 참조한다.
|
||||
자세한 내용은 [트러블슈팅 문서](/ko/docs/tasks/debug/)를 참조한다.
|
||||
|
||||
<!-- body -->
|
||||
|
||||
## 클러스터 나열하기
|
||||
|
||||
클러스터에서 가장 먼저 디버그해야 할 것은 노드가 모두 올바르게 등록되었는지 여부이다.
|
||||
|
||||
다음을 실행한다.
|
||||
|
||||
```shell
|
||||
kubectl get nodes
|
||||
```
|
||||
|
||||
그리고 보일 것으로 예상되는 모든 노드가 존재하고 모두 `Ready` 상태인지 확인한다.
|
||||
|
||||
클러스터의 전반적인 상태에 대한 자세한 정보를 얻으려면 다음을 실행할 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl cluster-info dump
|
||||
```
|
||||
|
||||
### 예제: 다운(down) 상태이거나 통신이 닿지 않는(unreachable) 노드 디버깅하기
|
||||
|
||||
때때로 디버깅할 때 노드의 상태를 확인하는 것이 유용할 수 있다(예를 들어, 어떤 노드에서 실행되는 파드가 이상하게 행동하는 것을 발견했거나, 특정 노드에 파드가 스케줄링되지 않는 이유를 알아보기 위해). 파드의 경우와 마찬가지로, `kubectl describe node` 및 `kubectl get node -o yaml` 명령을 사용하여 노드에 대한 상세 정보를 볼 수 있다. 예를 들어, 노드가 다운 상태(네트워크 연결이 끊어졌거나, kubelet이 종료된 후 재시작되지 못했거나 등)라면 아래와 같은 출력이 나올 것이다. 노드가 NotReady 상태라는 것을 나타내는 이벤트(event)와, 더 이상 실행 중이 아닌 파드(NotReady 상태 이후 5분 뒤에 축출되었음)에 주목한다.
|
||||
|
||||
```shell
|
||||
kubectl get nodes
|
||||
```
|
||||
|
||||
```none
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
kube-worker-1 NotReady <none> 1h v1.23.3
|
||||
kubernetes-node-bols Ready <none> 1h v1.23.3
|
||||
kubernetes-node-st6x Ready <none> 1h v1.23.3
|
||||
kubernetes-node-unaj Ready <none> 1h v1.23.3
|
||||
```
|
||||
|
||||
```shell
|
||||
kubectl describe node kube-worker-1
|
||||
```
|
||||
|
||||
```none
|
||||
Name: kube-worker-1
|
||||
Roles: <none>
|
||||
Labels: beta.kubernetes.io/arch=amd64
|
||||
beta.kubernetes.io/os=linux
|
||||
kubernetes.io/arch=amd64
|
||||
kubernetes.io/hostname=kube-worker-1
|
||||
kubernetes.io/os=linux
|
||||
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /run/containerd/containerd.sock
|
||||
node.alpha.kubernetes.io/ttl: 0
|
||||
volumes.kubernetes.io/controller-managed-attach-detach: true
|
||||
CreationTimestamp: Thu, 17 Feb 2022 16:46:30 -0500
|
||||
Taints: node.kubernetes.io/unreachable:NoExecute
|
||||
node.kubernetes.io/unreachable:NoSchedule
|
||||
Unschedulable: false
|
||||
Lease:
|
||||
HolderIdentity: kube-worker-1
|
||||
AcquireTime: <unset>
|
||||
RenewTime: Thu, 17 Feb 2022 17:13:09 -0500
|
||||
Conditions:
|
||||
Type Status LastHeartbeatTime LastTransitionTime Reason Message
|
||||
---- ------ ----------------- ------------------ ------ -------
|
||||
NetworkUnavailable False Thu, 17 Feb 2022 17:09:13 -0500 Thu, 17 Feb 2022 17:09:13 -0500 WeaveIsUp Weave pod has set this
|
||||
MemoryPressure Unknown Thu, 17 Feb 2022 17:12:40 -0500 Thu, 17 Feb 2022 17:13:52 -0500 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
DiskPressure Unknown Thu, 17 Feb 2022 17:12:40 -0500 Thu, 17 Feb 2022 17:13:52 -0500 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
PIDPressure Unknown Thu, 17 Feb 2022 17:12:40 -0500 Thu, 17 Feb 2022 17:13:52 -0500 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
Ready Unknown Thu, 17 Feb 2022 17:12:40 -0500 Thu, 17 Feb 2022 17:13:52 -0500 NodeStatusUnknown Kubelet stopped posting node status.
|
||||
Addresses:
|
||||
InternalIP: 192.168.0.113
|
||||
Hostname: kube-worker-1
|
||||
Capacity:
|
||||
cpu: 2
|
||||
ephemeral-storage: 15372232Ki
|
||||
hugepages-2Mi: 0
|
||||
memory: 2025188Ki
|
||||
pods: 110
|
||||
Allocatable:
|
||||
cpu: 2
|
||||
ephemeral-storage: 14167048988
|
||||
hugepages-2Mi: 0
|
||||
memory: 1922788Ki
|
||||
pods: 110
|
||||
System Info:
|
||||
Machine ID: 9384e2927f544209b5d7b67474bbf92b
|
||||
System UUID: aa829ca9-73d7-064d-9019-df07404ad448
|
||||
Boot ID: 5a295a03-aaca-4340-af20-1327fa5dab5c
|
||||
Kernel Version: 5.13.0-28-generic
|
||||
OS Image: Ubuntu 21.10
|
||||
Operating System: linux
|
||||
Architecture: amd64
|
||||
Container Runtime Version: containerd://1.5.9
|
||||
Kubelet Version: v1.23.3
|
||||
Kube-Proxy Version: v1.23.3
|
||||
Non-terminated Pods: (4 in total)
|
||||
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
|
||||
--------- ---- ------------ ---------- --------------- ------------- ---
|
||||
default nginx-deployment-67d4bdd6f5-cx2nz 500m (25%) 500m (25%) 128Mi (6%) 128Mi (6%) 23m
|
||||
default nginx-deployment-67d4bdd6f5-w6kd7 500m (25%) 500m (25%) 128Mi (6%) 128Mi (6%) 23m
|
||||
kube-system kube-proxy-dnxbz 0 (0%) 0 (0%) 0 (0%) 0 (0%) 28m
|
||||
kube-system weave-net-gjxxp 100m (5%) 0 (0%) 200Mi (10%) 0 (0%) 28m
|
||||
Allocated resources:
|
||||
(Total limits may be over 100 percent, i.e., overcommitted.)
|
||||
Resource Requests Limits
|
||||
-------- -------- ------
|
||||
cpu 1100m (55%) 1 (50%)
|
||||
memory 456Mi (24%) 256Mi (13%)
|
||||
ephemeral-storage 0 (0%) 0 (0%)
|
||||
hugepages-2Mi 0 (0%) 0 (0%)
|
||||
Events:
|
||||
...
|
||||
```
|
||||
|
||||
```shell
|
||||
kubectl get node kube-worker-1 -o yaml
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Node
|
||||
metadata:
|
||||
annotations:
|
||||
kubeadm.alpha.kubernetes.io/cri-socket: /run/containerd/containerd.sock
|
||||
node.alpha.kubernetes.io/ttl: "0"
|
||||
volumes.kubernetes.io/controller-managed-attach-detach: "true"
|
||||
creationTimestamp: "2022-02-17T21:46:30Z"
|
||||
labels:
|
||||
beta.kubernetes.io/arch: amd64
|
||||
beta.kubernetes.io/os: linux
|
||||
kubernetes.io/arch: amd64
|
||||
kubernetes.io/hostname: kube-worker-1
|
||||
kubernetes.io/os: linux
|
||||
name: kube-worker-1
|
||||
resourceVersion: "4026"
|
||||
uid: 98efe7cb-2978-4a0b-842a-1a7bf12c05f8
|
||||
spec: {}
|
||||
status:
|
||||
addresses:
|
||||
- address: 192.168.0.113
|
||||
type: InternalIP
|
||||
- address: kube-worker-1
|
||||
type: Hostname
|
||||
allocatable:
|
||||
cpu: "2"
|
||||
ephemeral-storage: "14167048988"
|
||||
hugepages-2Mi: "0"
|
||||
memory: 1922788Ki
|
||||
pods: "110"
|
||||
capacity:
|
||||
cpu: "2"
|
||||
ephemeral-storage: 15372232Ki
|
||||
hugepages-2Mi: "0"
|
||||
memory: 2025188Ki
|
||||
pods: "110"
|
||||
conditions:
|
||||
- lastHeartbeatTime: "2022-02-17T22:20:32Z"
|
||||
lastTransitionTime: "2022-02-17T22:20:32Z"
|
||||
message: Weave pod has set this
|
||||
reason: WeaveIsUp
|
||||
status: "False"
|
||||
type: NetworkUnavailable
|
||||
- lastHeartbeatTime: "2022-02-17T22:20:15Z"
|
||||
lastTransitionTime: "2022-02-17T22:13:25Z"
|
||||
message: kubelet has sufficient memory available
|
||||
reason: KubeletHasSufficientMemory
|
||||
status: "False"
|
||||
type: MemoryPressure
|
||||
- lastHeartbeatTime: "2022-02-17T22:20:15Z"
|
||||
lastTransitionTime: "2022-02-17T22:13:25Z"
|
||||
message: kubelet has no disk pressure
|
||||
reason: KubeletHasNoDiskPressure
|
||||
status: "False"
|
||||
type: DiskPressure
|
||||
- lastHeartbeatTime: "2022-02-17T22:20:15Z"
|
||||
lastTransitionTime: "2022-02-17T22:13:25Z"
|
||||
message: kubelet has sufficient PID available
|
||||
reason: KubeletHasSufficientPID
|
||||
status: "False"
|
||||
type: PIDPressure
|
||||
- lastHeartbeatTime: "2022-02-17T22:20:15Z"
|
||||
lastTransitionTime: "2022-02-17T22:15:15Z"
|
||||
message: kubelet is posting ready status. AppArmor enabled
|
||||
reason: KubeletReady
|
||||
status: "True"
|
||||
type: Ready
|
||||
daemonEndpoints:
|
||||
kubeletEndpoint:
|
||||
Port: 10250
|
||||
nodeInfo:
|
||||
architecture: amd64
|
||||
bootID: 22333234-7a6b-44d4-9ce1-67e31dc7e369
|
||||
containerRuntimeVersion: containerd://1.5.9
|
||||
kernelVersion: 5.13.0-28-generic
|
||||
kubeProxyVersion: v1.23.3
|
||||
kubeletVersion: v1.23.3
|
||||
machineID: 9384e2927f544209b5d7b67474bbf92b
|
||||
operatingSystem: linux
|
||||
osImage: Ubuntu 21.10
|
||||
systemUUID: aa829ca9-73d7-064d-9019-df07404ad448
|
||||
```
|
||||
|
||||
|
||||
## 로그 보기
|
||||
|
||||
현재로서는 클러스터를 더 깊이 파고들려면 관련 머신에서 로그 확인이 필요하다. 관련 로그 파일
|
||||
위치는 다음과 같다. (systemd 기반 시스템에서는 `journalctl`을 대신 사용해야 할 수도 있다.)
|
||||
|
||||
### 컨트롤 플레인 노드
|
||||
|
||||
* `/var/log/kube-apiserver.log` - API 서버, API 제공을 담당
|
||||
* `/var/log/kube-scheduler.log` - 스케줄러, 스케줄 결정을 담당
|
||||
* `/var/log/kube-controller-manager.log` - 레플리케이션 컨트롤러를 담당하는 컨트롤러
|
||||
|
||||
### 워커 노드
|
||||
|
||||
* `/var/log/kubelet.log` - Kubelet, 노드에서 컨테이너 실행을 담당
|
||||
* `/var/log/kube-proxy.log` - Kube Proxy, 서비스 로드밸런싱을 담당
|
||||
|
||||
## 클러스터 장애 모드
|
||||
|
||||
아래에 일부 오류 상황 예시 및 문제를 완화하기 위해 클러스터 설정을 조정하는 방법을 나열한다.
|
||||
|
||||
### 근본 원인
|
||||
|
||||
- VM(들) 종료
|
||||
- 클러스터 내 또는 클러스터와 사용자 간의 네트워크 분할
|
||||
- 쿠버네티스 소프트웨어의 충돌
|
||||
- 데이터 손실 또는 퍼시스턴트 스토리지 사용 불가 (e.g. GCE PD 또는 AWS EBS 볼륨)
|
||||
- 운영자 오류, 예를 들면 잘못 구성된 쿠버네티스 소프트웨어 또는 애플리케이션 소프트웨어
|
||||
|
||||
### 특정 시나리오
|
||||
|
||||
- API 서버 VM 종료 또는 API 서버 충돌
|
||||
- 다음의 현상을 유발함
|
||||
- 새로운 파드, 서비스, 레플리케이션 컨트롤러를 중지, 업데이트 또는 시작할 수 없다.
|
||||
- 쿠버네티스 API에 의존하지 않는 기존 파드 및 서비스는 계속 정상적으로 작동할 것이다.
|
||||
- API 서버 백업 스토리지 손실
|
||||
- 다음의 현상을 유발함
|
||||
- API 서버가 구동되지 않을 것이다.
|
||||
- kubelet에 도달할 수 없게 되지만, kubelet이 여전히 동일한 파드를 계속 실행하고 동일한 서비스 프록시를 제공할 것이다.
|
||||
- API 서버를 재시작하기 전에, 수동으로 복구하거나 API서버 상태를 재생성해야 한다.
|
||||
- 지원 서비스 (노드 컨트롤러, 레플리케이션 컨트롤러 매니저, 스케쥴러 등) VM 종료 또는 충돌
|
||||
- 현재 그것들은 API 서버와 같은 위치에 있기 때문에 API 서버와 비슷한 상황을 겪을 것이다.
|
||||
- 미래에는 이들도 복제본을 가질 것이며 API서버와 별도로 배치될 수도 있다.
|
||||
- 지원 서비스들은 상태(persistent state)를 자체적으로 유지하지는 않는다.
|
||||
- 개별 노드 (VM 또는 물리적 머신) 종료
|
||||
- 다음의 현상을 유발함
|
||||
- 해당 노드의 파드가 실행을 중지
|
||||
- 네트워크 분할
|
||||
- 다음의 현상을 유발함
|
||||
- 파티션 A는 파티션 B의 노드가 다운되었다고 생각한다. 파티션 B는 API 서버가 다운되었다고 생각한다. (마스터 VM이 파티션 A에 있다고 가정)
|
||||
- Kubelet 소프트웨어 오류
|
||||
- 다음의 현상을 유발함
|
||||
- 충돌한 kubelet은 노드에서 새 파드를 시작할 수 없다.
|
||||
- kubelet이 파드를 삭제할 수도 있고 삭제하지 않을 수도 있다.
|
||||
- 노드는 비정상으로 표시된다.
|
||||
- 레플리케이션 컨트롤러는 다른 곳에서 새 파드를 시작한다.
|
||||
- 클러스터 운영자 오류
|
||||
- 다음의 현상을 유발함
|
||||
- 파드, 서비스 등의 손실
|
||||
- API 서버 백업 저장소 분실
|
||||
- API를 읽을 수 없는 사용자
|
||||
- 기타
|
||||
|
||||
### 완화
|
||||
|
||||
- 조치: IaaS VM을 위한 IaaS 공급자의 자동 VM 다시 시작 기능을 사용한다.
|
||||
- 다음을 완화할 수 있음: API 서버 VM 종료 또는 API 서버 충돌
|
||||
- 다음을 완화할 수 있음: 지원 서비스 VM 종료 또는 충돌
|
||||
|
||||
- 조치: API 서버+etcd가 있는 VM에 IaaS 제공자의 안정적인 스토리지(예: GCE PD 또는 AWS EBS 볼륨)를 사용한다.
|
||||
- 다음을 완화할 수 있음: API 서버 백업 스토리지 손실
|
||||
|
||||
- 조치: [고가용성](/docs/setup/production-environment/tools/kubeadm/high-availability/) 구성을 사용한다.
|
||||
- 다음을 완화할 수 있음: 컨트롤 플레인 노드 종료 또는 컨트롤 플레인 구성 요소(스케줄러, API 서버, 컨트롤러 매니저) 충돌
|
||||
- 동시에 발생하는 하나 이상의 노드 또는 구성 요소 오류를 허용한다.
|
||||
- 다음을 완화할 수 있음: API 서버 백업 스토리지(i.e., etcd의 데이터 디렉터리) 손실
|
||||
- 고가용성 etcd 구성을 사용하고 있다고 가정
|
||||
|
||||
- 조치: API 서버 PD/EBS 볼륨의 주기적인 스냅샷
|
||||
- 다음을 완화할 수 있음: API 서버 백업 스토리지 손실
|
||||
- 다음을 완화할 수 있음: 일부 운영자 오류 사례
|
||||
- 다음을 완화할 수 있음: 일부 쿠버네티스 소프트웨어 오류 사례
|
||||
|
||||
- 조치: 파드 앞에 레플리케이션 컨트롤러와 서비스 사용
|
||||
- 다음을 완화할 수 있음: 노드 종료
|
||||
- 다음을 완화할 수 있음: Kubelet 소프트웨어 오류
|
||||
|
||||
- 조치: 예기치 않은 재시작을 허용하도록 설계된 애플리케이션(컨테이너)
|
||||
- 다음을 완화할 수 있음: 노드 종료
|
||||
- 다음을 완화할 수 있음: Kubelet 소프트웨어 오류
|
||||
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
* [리소스 메트릭 파이프라인](/ko/docs/tasks/debug/debug-cluster/resource-metrics-pipeline/)에서 사용할 수 있는 메트릭에 대해 알아 본다.
|
||||
* [리소스 사용량 모니터링](/ko/docs/tasks/debug/debug-cluster/resource-usage-monitoring/)을 위한 추가 도구에 대해 알아 본다.
|
||||
* Node Problem Detector를 사용하여 [노드 헬스(health)를 모니터링](/docs/tasks/debug/debug-cluster/monitor-node-health/)한다.
|
||||
* `crictl`을 사용하여 [쿠버네티스 노드를 디버깅](/docs/tasks/debug/debug-cluster/crictl/)한다.
|
||||
* [쿠버네티스 감사(auditing)](/docs/tasks/debug/debug-cluster/audit/)에 대한 더 자세한 정보를 본다.
|
||||
* `telepresence`를 사용하여 [서비스를 로컬에서 개발 및 디버깅](/docs/tasks/debug/debug-cluster/local-debugging/)한다.
|
||||
@@ -0,0 +1,268 @@
|
||||
---
|
||||
|
||||
|
||||
|
||||
title: 리소스 메트릭 파이프라인
|
||||
content_type: concept
|
||||
weight: 15
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
쿠버네티스에서, _메트릭 API(Metrics API)_ 는 자동 스케일링 및 비슷한 사용 사례를 지원하기 위한 기본적인 메트릭 집합을 제공한다.
|
||||
이 API는 노드와 파드의 리소스 사용량 정보를 제공하며,
|
||||
여기에는 CPU 및 메모리 메트릭이 포함된다.
|
||||
메트릭 API를 클러스터에 배포하면, 쿠버네티스 API의 클라이언트는 이 정보에 대해 질의할 수 있으며,
|
||||
질의 권한을 관리하기 위해 쿠버네티스의 접근 제어 메커니즘을 이용할 수 있다.
|
||||
|
||||
[HorizontalPodAutoscaler](/ko/docs/tasks/run-application/horizontal-pod-autoscale/)(HPA) 및
|
||||
[VerticalPodAutoscaler](https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler#readme)(VPA)는
|
||||
사용자의 요구 사항을 만족할 수 있도록 워크로드 레플리카와 리소스를 조정하는 데에 메트릭 API의 데이터를 이용한다.
|
||||
|
||||
[`kubectl top`](/docs/reference/generated/kubectl/kubectl-commands#top)
|
||||
명령을 이용하여
|
||||
리소스 메트릭을 볼 수도 있다.
|
||||
|
||||
{{< note >}}
|
||||
메트릭 API 및 이것이 제공하는 메트릭 파이프라인은
|
||||
HPA / VPA 에 의한 자동 스케일링이 동작하는 데 필요한
|
||||
최소한의 CPU 및 메모리 메트릭만을 제공한다.
|
||||
더 많은 메트릭 집합을 제공하려면, _커스텀 메트릭 API_ 를 사용하는
|
||||
추가 [메트릭 파이프라인](/ko/docs/tasks/debug/debug-cluster/resource-usage-monitoring/#full-metrics-pipeline)을 배포하여
|
||||
기본 메트릭 API를 보충할 수 있다.
|
||||
{{< /note >}}
|
||||
|
||||
|
||||
그림 1은 리소스 메트릭 파이프라인의 아키텍처를 나타낸다.
|
||||
|
||||
{{< mermaid >}}
|
||||
flowchart RL
|
||||
subgraph cluster[클러스터]
|
||||
direction RL
|
||||
S[ <br><br> ]
|
||||
A[Metrics-<br>Server]
|
||||
subgraph B[노드]
|
||||
direction TB
|
||||
D[cAdvisor] --> C[kubelet]
|
||||
E[컨테이너<br>런타임] --> D
|
||||
E1[컨테이너<br>런타임] --> D
|
||||
P[파드 데이터] -.- C
|
||||
end
|
||||
L[API<br>서버]
|
||||
W[HPA]
|
||||
C ---->|요약<br>API| A -->|메트릭<br>API| L --> W
|
||||
end
|
||||
L ---> K[kubectl<br>top]
|
||||
classDef box fill:#fff,stroke:#000,stroke-width:1px,color:#000;
|
||||
class W,B,P,K,cluster,D,E,E1 box
|
||||
classDef spacewhite fill:#ffffff,stroke:#fff,stroke-width:0px,color:#000
|
||||
class S spacewhite
|
||||
classDef k8s fill:#326ce5,stroke:#fff,stroke-width:1px,color:#fff;
|
||||
class A,L,C k8s
|
||||
{{< /mermaid >}}
|
||||
|
||||
그림 1. 리소스 메트릭 파이프라인
|
||||
|
||||
그림의 오른쪽에서 왼쪽 순으로, 아키텍처 구성 요소는 다음과 같다.
|
||||
|
||||
* [cAdvisor](https://github.com/google/cadvisor): kubelet에 포함된 컨테이너 메트릭을
|
||||
수집, 집계, 노출하는 데몬
|
||||
* [kubelet](/ko/docs/concepts/overview/components/#kubelet): 컨테이너 리소스 관리를 위한 노드 에이전트.
|
||||
리소스 메트릭은 kubelet API 엔드포인트 `/metrics/resource` 및
|
||||
`/stats` 를 사용하여 접근 가능하다.
|
||||
* [요약 API](#summary-api-source): `/stats` 엔드포인트를 통해 사용할 수 있는
|
||||
노드 별 요약된 정보를 탐색 및 수집할 수 있도록 kubelet이 제공하는 API
|
||||
* [metrics-server](#metrics-server): 각 kubelet으로부터 수집한 리소스 메트릭을 수집 및 집계하는 클러스터 애드온 구성 요소.
|
||||
API 서버는 HPA, VPA 및 `kubectl top` 명령어가 사용할 수 있도록 메트릭 API를 제공한다.
|
||||
metrics-server는 메트릭 API에 대한 기준 구현(reference implementation) 중 하나이다.
|
||||
* [메트릭 API](#metrics-api): 워크로드 오토스케일링에 사용되는 CPU 및 메모리 정보로의 접근을 지원하는 쿠버네티스 API.
|
||||
이를 클러스터에서 사용하려면,
|
||||
메트릭 API를 제공하는 API 확장(extension) 서버가 필요하다.
|
||||
|
||||
{{< note >}}
|
||||
cAdvisor는 cgroups으로부터 메트릭을 가져오는 것을 지원하며, 리눅스의 일반적인 컨테이너 런타임은 이를 지원한다.
|
||||
만약 다른 리소스 격리 메커니즘(예: 가상화)을 사용하는 컨테이너 런타임을 사용한다면,
|
||||
kubelet이 메트릭을 사용할 수 있기 위해서는
|
||||
해당 컨테이너 런타임이
|
||||
[CRI 컨테이너 메트릭](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/cri-container-stats.md)을 지원해야 한다.
|
||||
{{< /note >}}
|
||||
|
||||
<!-- body -->
|
||||
|
||||
## 메트릭 API {#metrics-api}
|
||||
{{< feature-state for_k8s_version="1.8" state="beta" >}}
|
||||
|
||||
metrics-server는 메트릭 API에 대한 구현이다.
|
||||
이 API는 클러스터 내 노드와 파드의 CPU 및 메모리 사용 정보에 접근할 수 있게 해 준다.
|
||||
이것의 주 역할은 리소스 사용 메트릭을 쿠버네티스 오토스케일러 구성 요소에 제공하는 것이다.
|
||||
|
||||
다음은 `minikube` 노드에 대한 메트릭 API 요청 예시이며
|
||||
가독성 향상을 위해 `jq`를 활용한다.
|
||||
|
||||
```shell
|
||||
kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes/minikube" | jq '.'
|
||||
```
|
||||
|
||||
다음은 `curl`을 이용하여 동일한 API 호출을 하는 명령어다.
|
||||
|
||||
```shell
|
||||
curl http://localhost:8080/apis/metrics.k8s.io/v1beta1/nodes/minikube
|
||||
```
|
||||
|
||||
응답 예시는 다음과 같다.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "NodeMetrics",
|
||||
"apiVersion": "metrics.k8s.io/v1beta1",
|
||||
"metadata": {
|
||||
"name": "minikube",
|
||||
"selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/minikube",
|
||||
"creationTimestamp": "2022-01-27T18:48:43Z"
|
||||
},
|
||||
"timestamp": "2022-01-27T18:48:33Z",
|
||||
"window": "30s",
|
||||
"usage": {
|
||||
"cpu": "487558164n",
|
||||
"memory": "732212Ki"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
다음은 `kube-system` 네임스페이스 내의 `kube-scheduler-minikube` 파드에 대한
|
||||
메트릭 API 요청 예시이며 가독성 향상을 위해 `jq`를 활용한다.
|
||||
|
||||
```shell
|
||||
kubectl get --raw "/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube-scheduler-minikube" | jq '.'
|
||||
```
|
||||
|
||||
다음은 `curl`을 이용하여 동일한 API 호출을 하는 명령어다.
|
||||
|
||||
```shell
|
||||
curl http://localhost:8080/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube-scheduler-minikube
|
||||
```
|
||||
|
||||
응답 예시는 다음과 같다.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "PodMetrics",
|
||||
"apiVersion": "metrics.k8s.io/v1beta1",
|
||||
"metadata": {
|
||||
"name": "kube-scheduler-minikube",
|
||||
"namespace": "kube-system",
|
||||
"selfLink": "/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube-scheduler-minikube",
|
||||
"creationTimestamp": "2022-01-27T19:25:00Z"
|
||||
},
|
||||
"timestamp": "2022-01-27T19:24:31Z",
|
||||
"window": "30s",
|
||||
"containers": [
|
||||
{
|
||||
"name": "kube-scheduler",
|
||||
"usage": {
|
||||
"cpu": "9559630n",
|
||||
"memory": "22244Ki"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
메트릭 API는 [k8s.io/metrics](https://github.com/kubernetes/metrics) 저장소에 정의되어 있다.
|
||||
`metrics.k8s.io` API를 사용하기 위해서는
|
||||
[API 집계(aggregation) 계층](/docs/tasks/extend-kubernetes/configure-aggregation-layer/)을 활성화하고
|
||||
[APIService](/docs/reference/kubernetes-api/cluster-resources/api-service-v1/)를 등록해야 한다.
|
||||
|
||||
메트릭 API에 대해 더 알아보려면, [리소스 메트릭 API 디자인](https://github.com/kubernetes/design-proposals-archive/blob/main/instrumentation/resource-metrics-api.md),
|
||||
[metrics-server 저장소](https://github.com/kubernetes-sigs/metrics-server) 및
|
||||
[리소스 메트릭 API](https://github.com/kubernetes/metrics#resource-metrics-api)를 참고한다.
|
||||
|
||||
|
||||
{{< note >}}
|
||||
메트릭 API에 접근하려면 먼저 메트릭 API를 제공하는
|
||||
metrics-server 또는 대체 어댑터를 배포해야 한다.
|
||||
{{< /note >}}
|
||||
|
||||
## 리소스 사용량 측정 {#measuring-resource-usage}
|
||||
|
||||
### CPU
|
||||
|
||||
CPU는 `cpu` 단위로 측정된 평균 코어 사용량 형태로 보고된다. 쿠버네티스에서 1 cpu는
|
||||
클라우드 제공자의 경우 1 vCPU/코어에 해당하고, 베어메탈 인텔 프로세서의 경우 1 하이퍼-스레드에 해당한다.
|
||||
|
||||
이 값은 커널(Linux 및 Windows 커널 모두)에서 제공하는 누적 CPU 카운터에 대한
|
||||
비율을 취하여 얻어진다.
|
||||
CPU 값 계산에 사용된 타임 윈도우는 메트릭 API의 `window` 필드에 표시된다.
|
||||
|
||||
쿠버네티스가 어떻게 CPU 리소스를 할당하고 측정하는지 더 알아보려면,
|
||||
[CPU의 의미](/ko/docs/concepts/configuration/manage-resources-containers/#meaning-of-cpu)를 참고한다.
|
||||
|
||||
### 메모리
|
||||
|
||||
메모리는 메트릭을 수집하는 순간에 바이트 단위로 측정된 워킹 셋(working set) 형태로 보고된다.
|
||||
|
||||
이상적인 환경에서, "워킹 셋"은 메모리가 부족한 상태더라도 해제할 수 없는 사용 중인 메모리의 양이다.
|
||||
그러나 워킹 셋의 계산 방법은 호스트 OS에 따라 다르며
|
||||
일반적으로 추정치를 추출하기 위해 휴리스틱을 많이 사용한다.
|
||||
|
||||
컨테이너의 워킹 셋에 대한 쿠버네티스 모델은 컨테이너 런타임이 해당 컨테이너와 연결된 익명(anonymous) 메모리를 계산할 것으로 예상한다.
|
||||
호스트 OS가 항상 페이지를 회수할 수는 없기 때문에,
|
||||
워킹 셋 메트릭에는 일반적으로 일부 캐시된 (파일 기반) 메모리도 포함된다.
|
||||
|
||||
쿠버네티스가 어떻게 메모리 리소스를 할당하고 측정하는지 더 알아보려면,
|
||||
[메모리의 의미](/ko/docs/concepts/configuration/manage-resources-containers/#meaning-of-memory)를 참고한다.
|
||||
|
||||
## metrics-server {#metrics-server}
|
||||
|
||||
metrics-server는 kubelet으로부터 리소스 메트릭을 수집하고,
|
||||
이를 HPA(Horizontal Pod Autoscaler) 및 VPA(Vertical Pod Autoscaler)가 활용할 수 있도록 쿠버네티스 API 서버 내에서 메트릭 API(Metrics API)를 통해 노출한다.
|
||||
`kubectl top` 명령을 사용하여 이 메트릭을 확인해볼 수도 있다.
|
||||
|
||||
metrics-server는 쿠버네티스 API를 사용하여 클러스터의 노드와 파드를 추적한다.
|
||||
metrics-server는 각 노드에 HTTP를 통해 질의하여 메트릭을 수집한다.
|
||||
metrics-server는 또한 파드 메타데이터의 내부적 뷰를 작성하고, 파드 헬스(health)에 대한 캐시를 유지한다.
|
||||
이렇게 캐시된 파드 헬스 정보는 metrics-server가 제공하는 확장 API(extension API)를 통해 이용할 수 있다.
|
||||
|
||||
HPA 질의에 대한 예시에서, 예를 들어 HPA 질의에 대한 경우,
|
||||
metrics-server는 디플로이먼트의 어떤 파드가 레이블 셀렉터 조건을 만족하는지 판별해야 한다.
|
||||
|
||||
metrics-server는 각 노드로부터 메트릭을 수집하기 위해 [kubelet](/docs/reference/command-line-tools-reference/kubelet/) API를 호출한다.
|
||||
사용 중인 metrics-server 버전에 따라, 다음의 엔드포인트를 사용한다.
|
||||
|
||||
* v0.6.0 이상: 메트릭 리소스 엔드포인트 `/metrics/resource`
|
||||
* 이전 버전: 요약 API 엔드포인트 `/stats/summary`
|
||||
|
||||
metrics-server에 대한 더 많은 정보는
|
||||
[metrics-server 저장소](https://github.com/kubernetes-sigs/metrics-server)를 확인한다.
|
||||
|
||||
또한 다음을 참고할 수도 있다.
|
||||
|
||||
* [metrics-server 디자인](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/metrics-server.md)
|
||||
* [metrics-server 자주 묻는 질문](https://github.com/kubernetes-sigs/metrics-server/blob/master/FAQ.md)
|
||||
* [metrics-server 알려진 이슈](https://github.com/kubernetes-sigs/metrics-server/blob/master/KNOWN_ISSUES.md)
|
||||
* [metrics-server 릴리스](https://github.com/kubernetes-sigs/metrics-server/releases)
|
||||
* [Horizontal Pod Autoscaling](/ko/docs/tasks/run-application/horizontal-pod-autoscale/)
|
||||
|
||||
### 요약 API(Summary API) 소스 {#summary-api-source}
|
||||
|
||||
[Kubelet](/docs/reference/command-line-tools-reference/kubelet/)은
|
||||
노드, 볼륨, 파드, 컨테이너 수준의 통계를 수집하며,
|
||||
소비자(consumer)가 읽을 수 있도록 이 통계를
|
||||
[요약 API](https://github.com/kubernetes/kubernetes/blob/7d309e0104fedb57280b261e5677d919cb2a0e2d/staging/src/k8s.io/kubelet/pkg/apis/stats/v1alpha1/types.go)에 기록한다.
|
||||
|
||||
다음은 `minikube` 노드에 대한 요약 API 요청 예시이다.
|
||||
|
||||
```shell
|
||||
kubectl get --raw "/api/v1/nodes/minikube/proxy/stats/summary"
|
||||
```
|
||||
|
||||
다음은 `curl`을 이용하여 동일한 API 호출을 하는 명령어다.
|
||||
|
||||
```shell
|
||||
curl http://localhost:8080/api/v1/nodes/minikube/proxy/stats/summary
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
metrics-server 0.6.x 버전부터,
|
||||
요약 API `/stats/summary` 엔드포인트가 `/metrics/resource` 엔드포인트로 대체될 것이다.
|
||||
{{< /note >}}
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
|
||||
|
||||
content_type: concept
|
||||
title: 리소스 모니터링 도구
|
||||
weight: 15
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
애플리케이션을 스케일하여 신뢰할 수 있는 서비스를 제공하려면,
|
||||
애플리케이션이 배포되었을 때 애플리케이션이 어떻게 동작하는지를 이해해야 한다.
|
||||
컨테이너, [파드](/ko/docs/concepts/workloads/pods/),
|
||||
[서비스](/ko/docs/concepts/services-networking/service),
|
||||
그리고 전체 클러스터의 특성을 검사하여
|
||||
쿠버네티스 클러스터 내의 애플리케이션 성능을 검사할 수 있다. 쿠버네티스는 각 레벨에서
|
||||
애플리케이션의 리소스 사용량에 대한 상세 정보를 제공한다.
|
||||
이 정보는 애플리케이션의 성능을 평가하고
|
||||
병목 현상을 제거하여 전체 성능을 향상할 수 있게 해준다.
|
||||
|
||||
<!-- body -->
|
||||
|
||||
쿠버네티스에서 애플리케이션 모니터링은 단일 모니터링 솔루션에 의존하지 않는다.
|
||||
신규 클러스터에서는, [리소스 메트릭](#리소스-메트릭-파이프라인) 또는
|
||||
[완전한 메트릭](#완전한-메트릭-파이프라인) 파이프라인으로 모니터링 통계를 수집할 수 있다.
|
||||
|
||||
## 리소스 메트릭 파이프라인
|
||||
|
||||
리소스 메트릭 파이프라인은
|
||||
[Horizontal Pod Autoscaler](/ko/docs/tasks/run-application/horizontal-pod-autoscale)
|
||||
컨트롤러와 같은 클러스터 구성요소나
|
||||
`kubectl top` 유틸리티에 관련되어 있는
|
||||
메트릭들로 제한된 집합을 제공한다. 이 메트릭은 경량의 단기 인메모리 저장소인
|
||||
[metrics-server](https://github.com/kubernetes-sigs/metrics-server)에
|
||||
의해서 수집되며 `metrics.k8s.io` API를 통해 노출된다.
|
||||
|
||||
metrics-server는 클러스터 상의 모든 노드를 발견하고
|
||||
각 노드의 [kubelet](/docs/reference/command-line-tools-reference/kubelet/)에
|
||||
CPU와 메모리 사용량을 질의한다.
|
||||
Kubelet은 쿠버네티스 마스터와 노드 간의 다리 역할을 하면서
|
||||
머신에서 구동되는 파드와 컨테이너를 관리한다.
|
||||
Kubelet은 각각의 파드를 해당하는 컨테이너에 매치시키고
|
||||
컨테이너 런타임 인터페이스를 통해
|
||||
컨테이너 런타임에서 개별 컨테이너의 사용량 통계를 가져온다.
|
||||
Kubelet은 이 정보를 레거시 도커와의 통합을 위해 kubelet에 통합된 cAdvisor를 통해 가져온다.
|
||||
그 다음으로 취합된 파드 리소스 사용량 통계를 metric-server 리소스 메트릭 API를 통해 노출한다.
|
||||
이 API는 kubelet의 인증이 필요한 읽기 전용 포트 상의
|
||||
`/metrics/resource/v1beta1`에서 제공된다.
|
||||
|
||||
## 완전한 메트릭 파이프라인
|
||||
|
||||
완전한 메트릭 파이프라인은 보다 풍부한 메트릭에 접근할 수 있도록 해준다.
|
||||
쿠버네티스는 Horizontal Pod Autoscaler와 같은 메커니즘을 활용해서 이런 메트릭에
|
||||
대한 반응으로 클러스터의 현재 상태를 기반으로 자동으로 스케일링하거나 클러스터를
|
||||
조정할 수 있다. 모니터링 파이프라인은 kubelet에서 메트릭을 가져와서 쿠버네티스에
|
||||
`custom.metrics.k8s.io`와 `external.metrics.k8s.io` API를 구현한 어댑터를 통해
|
||||
노출한다.
|
||||
|
||||
CNCF 프로젝트인 [프로메테우스](https://prometheus.io)는 기본적으로 쿠버네티스, 노드, 프로메테우스 자체를 모니터링할 수 있다.
|
||||
CNCF 프로젝트가 아닌 완전한 메트릭 파이프라인 프로젝트는 쿠버네티스 문서의 범위가 아니다.
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
|
||||
다음과 같은 추가 디버깅 도구에 대해 더 알아본다.
|
||||
|
||||
* [로깅](/ko/docs/concepts/cluster-administration/logging/)
|
||||
* [모니터링](/ko/docs/tasks/debug/debug-cluster/resource-usage-monitoring/)
|
||||
* [`exec`를 통해 컨테이너에 접속하기](/ko/docs/tasks/debug/debug-application/get-shell-running-container/)
|
||||
* [프록시를 통해 컨테이너에 연결하기](/docs/tasks/extend-kubernetes/http-proxy-access-api/)
|
||||
* [포트 포워딩을 사용해서 클러스터 내 애플리케이션에 접근하기](/ko/docs/tasks/access-application-cluster/port-forward-access-application-cluster/)
|
||||
* [crictl을 사용하여 쿠버네티스 노드 조사하기](/docs/tasks/debug/debug-cluster/crictl/)
|
||||
Reference in New Issue
Block a user