Second Korean l10n work for release 1.18

* Translate /concepts/cluster-administration/kubelet-garbage-collection in Korean (#20274)
* Translate cluster-administration/logging.md in Korean (#20409)
* Translate tasks/configure-pod-container/assign-memory-resource.md in … (#20167)
* Translate community/_index.html in Korean. (#20317)
* Translate storage/storage-classes.md in Korean. (#20310)
* Translate configuration/resource-bin-packing.md in Korean. (#20276)
* Translate extend-kubernetes/compute-storage-net/device-plugins.md (#20406)
* Translate compute-storage-net/network-plugins.md in Korean (#20407)
* Translate concepts/cluster-administration/certificates.md (#20330)
* Translate assign-pods-nodes-using-node-affinity to Korean (#20307)
* Translate cluster-administration/manage-deployment.md in Korean (#20366)
* Translate configuration/taint-and-toleration.md in Korean (#20404)
* Translate logging-elasticsearch-kibana.md in Korean (#20300)
* add anchors of subtitle in ko/docs/concepts/policy/pod-security-policy (#20399)
* Translate task/scheduling-gpus in Korean (#20212)
* Translate conceps/storage/volume-snapshots in Korean (#19955)
* Translate network/validate-dual-stack.md in Korean (#20271)
* Update to Outdated files in the dev-1.18-ko.2 branch. (#20244)
* Update to a link to the newly translated document. (#20247)

Co-Authored-By: bluefriday <bluefriday86@gmail.com>
Co-Authored-By: cometrojan <d.gweon@samsung.com>
Co-Authored-By: coolguyhong <podolsmith@naver.com>
Co-Authored-By: DongMoon Kim <dmoons.kim@gmail.com>
Co-Authored-By: Jerry Park <jaehwa@gmail.com>
Co-Authored-By: jmyung <jesang.myung@gmail.com>
Co-Authored-By: June Yi <june.yi@samsung.com>
Co-Authored-By: seokho-son <shsongist@gmail.com>
Co-Authored-By: sunminjeon <sunmin.jeon@samsung.com>
Co-Authored-By: Yuk, Yongsu <ysyukr@gmail.com>
This commit is contained in:
June Yi
2020-04-24 00:07:32 +09:00
parent dc3ce88f55
commit c74ce882ec
76 changed files with 4892 additions and 614 deletions
@@ -0,0 +1,252 @@
---
title: 인증서
content_template: templates/concept
weight: 20
---
{{% capture overview %}}
클라이언트 인증서로 인증을 사용하는 경우 `easyrsa`, `openssl` 또는 `cfssl`
을 통해 인증서를 수동으로 생성할 수 있다.
{{% /capture %}}
{{% capture body %}}
### easyrsa
**easyrsa** 는 클러스터 인증서를 수동으로 생성할 수 있다.
1. easyrsa3의 패치 버전을 다운로드하여 압축을 풀고, 초기화한다.
curl -LO https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz
tar xzf easy-rsa.tar.gz
cd easy-rsa-master/easyrsa3
./easyrsa init-pki
1. 새로운 인증 기관(CA)을 생성한다. `--batch` 는 자동 모드를 설정한다.
`--req-cn` 는 CA의 새 루트 인증서에 대한 일반 이름(Common Name (CN))을 지정한다.
./easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass
1. 서버 인증서와 키를 생성한다.
`--subject-alt-name` 인수는 API 서버에 접근이 가능한 IP와 DNS
이름을 설정한다. `MASTER_CLUSTER_IP` 는 일반적으로 API 서버와
컨트롤러 관리자 컴포넌트에 대해 `--service-cluster-ip-range` 인수로
지정된 서비스 CIDR의 첫 번째 IP이다. `--days` 인수는 인증서가 만료되는
일 수를 설정하는데 사용된다.
또한, 아래 샘플은 기본 DNS 이름으로 `cluster.local`
사용한다고 가정한다.
./easyrsa --subject-alt-name="IP:${MASTER_IP},"\
"IP:${MASTER_CLUSTER_IP},"\
"DNS:kubernetes,"\
"DNS:kubernetes.default,"\
"DNS:kubernetes.default.svc,"\
"DNS:kubernetes.default.svc.cluster,"\
"DNS:kubernetes.default.svc.cluster.local" \
--days=10000 \
build-server-full server nopass
1. `pki/ca.crt`, `pki/issued/server.crt` 그리고 `pki/private/server.key` 를 디렉터리에 복사한다.
1. API 서버 시작 파라미터에 다음 파라미터를 채우고 추가한다.
--client-ca-file=/yourdirectory/ca.crt
--tls-cert-file=/yourdirectory/server.crt
--tls-private-key-file=/yourdirectory/server.key
### openssl
**openssl** 은 클러스터 인증서를 수동으로 생성할 수 있다.
1. ca.key를 2048bit로 생성한다.
openssl genrsa -out ca.key 2048
1. ca.key에 따라 ca.crt를 생성한다(인증서 유효 기간을 사용하려면 -days를 사용한다).
openssl req -x509 -new -nodes -key ca.key -subj "/CN=${MASTER_IP}" -days 10000 -out ca.crt
1. server.key를 2048bit로 생성한다.
openssl genrsa -out server.key 2048
1. 인증서 서명 요청(Certificate Signing Request (CSR))을 생성하기 위한 설정 파일을 생성한다.
파일에 저장하기 전에 꺾쇠 괄호(예: `<MASTER_IP>`)로
표시된 값을 실제 값으로 대체한다(예: `csr.conf`).
`MASTER_CLUSTER_IP` 의 값은 이전 하위 섹션에서
설명한 대로 API 서버의 서비스 클러스터 IP이다.
또한, 아래 샘플에서는 `cluster.local` 을 기본 DNS 도메인
이름으로 사용하고 있다고 가정한다.
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[ dn ]
C = <국가(country)>
ST = <도(state)>
L = <시(city)>
O = <조직(organization)>
OU = <조직 단위(organization unit)>
CN = <MASTER_IP>
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.default.svc.cluster.local
IP.1 = <MASTER_IP>
IP.2 = <MASTER_CLUSTER_IP>
[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth,clientAuth
subjectAltName=@alt_names
1. 설정 파일을 기반으로 인증서 서명 요청을 생성한다.
openssl req -new -key server.key -out server.csr -config csr.conf
1. ca.key, ca.crt 그리고 server.csr을 사용해서 서버 인증서를 생성한다.
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out server.crt -days 10000 \
-extensions v3_ext -extfile csr.conf
1. 인증서를 본다.
openssl x509 -noout -text -in ./server.crt
마지막으로, API 서버 시작 파라미터에 동일한 파라미터를 추가한다.
### cfssl
**cfssl** 은 인증서 생성을 위한 또 다른 도구이다.
1. 아래에 표시된 대로 커맨드 라인 도구를 다운로드하여 압축을 풀고 준비한다.
사용 중인 하드웨어 아키텍처 및 cfssl 버전에 따라 샘플
명령을 조정해야 할 수도 있다.
curl -L https://github.com/cloudflare/cfssl/releases/download/v1.4.1/cfssl_1.4.1_linux_amd64 -o cfssl
chmod +x cfssl
curl -L https://github.com/cloudflare/cfssl/releases/download/v1.4.1/cfssljson_1.4.1_linux_amd64 -o cfssljson
chmod +x cfssljson
curl -L https://github.com/cloudflare/cfssl/releases/download/v1.4.1/cfssl-certinfo_1.4.1_linux_amd64 -o cfssl-certinfo
chmod +x cfssl-certinfo
1. 아티팩트(artifact)를 보유할 디렉터리를 생성하고 cfssl을 초기화한다.
mkdir cert
cd cert
../cfssl print-defaults config > config.json
../cfssl print-defaults csr > csr.json
1. CA 파일을 생성하기 위한 JSON 설정 파일을 `ca-config.json` 예시와 같이 생성한다.
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "8760h"
}
}
}
}
1. CA 인증서 서명 요청(CSR)을 위한 JSON 설정 파일을
`ca-csr.json` 예시와 같이 생성한다. 꺾쇠 괄호로 표시된
값을 사용하려는 실제 값으로 변경한다.
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names":[{
"C": "<국가(country)>",
"ST": "<도(state)>",
"L": "<시(city)>",
"O": "<조직(organization)>",
"OU": "<조직 단위(organization unit)>"
}]
}
1. CA 키(`ca-key.pem`)와 인증서(`ca.pem`)을 생성한다.
../cfssl gencert -initca ca-csr.json | ../cfssljson -bare ca
1. API 서버의 키와 인증서를 생성하기 위한 JSON 구성파일을
`server-csr.json` 예시와 같이 생성한다. 꺾쇠 괄호 안의 값을
사용하려는 실제 값으로 변경한다. `MASTER_CLUSTER_IP`
이전 하위 섹션에서 설명한 API 서버의 클러스터 IP이다.
아래 샘플은 기본 DNS 도메인 이름으로 `cluster.local`
사용한다고 가정한다.
{
"CN": "kubernetes",
"hosts": [
"127.0.0.1",
"<MASTER_IP>",
"<MASTER_CLUSTER_IP>",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [{
"C": "<국가(country)>",
"ST": "<도(state)>",
"L": "<시(city)>",
"O": "<조직(organization)>",
"OU": "<조직 단위(organization unit)>"
}]
}
1. API 서버 키와 인증서를 생성하면, 기본적으로
`server-key.pem``server.pem` 파일에 각각 저장된다.
../cfssl gencert -ca=ca.pem -ca-key=ca-key.pem \
--config=ca-config.json -profile=kubernetes \
server-csr.json | ../cfssljson -bare server
## 자체 서명된 CA 인증서의 배포
클라이언트 노드는 자체 서명된 CA 인증서를 유효한 것으로 인식하지 않을 수 있다.
비-프로덕션 디플로이먼트 또는 회사 방화벽 뒤에서 실행되는
디플로이먼트의 경우, 자체 서명된 CA 인증서를 모든 클라이언트에
배포하고 유효한 인증서의 로컬 목록을 새로 고칠 수 있다.
각 클라이언트에서, 다음 작업을 수행한다.
```bash
sudo cp ca.crt /usr/local/share/ca-certificates/kubernetes.crt
sudo update-ca-certificates
```
```
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....
done.
```
## 인증서 API
`certificates.k8s.io` API를 사용해서
[여기](/docs/tasks/tls/managing-tls-in-a-cluster)에
설명된 대로 인증에 사용할 x509 인증서를 프로비전 할 수 있다.
{{% /capture %}}
@@ -17,7 +17,6 @@ weight: 10
가이드를 고르기 전에, 몇 가지 고려사항이 있다.
- 단지 자신의 컴퓨터에 쿠버네티스를 테스트를 하는지, 또는 고가용성의 멀티 노드 클러스터를 만들려고 하는지에 따라 니즈에 가장 적절한 배포판을 고르자.
- **만약 고가용성을 만들려고 한다면**, [여러 영역에서의 클러스터](/ko/docs/concepts/cluster-administration/federation/) 설정에 대해 배우자.
- [구글 쿠버네티스 엔진](https://cloud.google.com/kubernetes-engine/)과 같은 **호스팅된 쿠버네티스 클러스터** 를 사용할 것인지, **자신의 클러스터에 호스팅할 것인지**?
- 클러스터가 **온프레미스** 인지, 또는 **클라우드(IaaS)** 인지? 쿠버네티스는 하이브리드 클러스터를 직접적으로 지원하지는 않는다. 대신에, 사용자는 여러 클러스터를 구성할 수 있다.
- **만약 온프레미스에서 쿠버네티스를 구성한다면**, 어떤 [네트워킹 모델](/docs/concepts/cluster-administration/networking/)이 가장 적합한지 고려한다.
@@ -35,7 +34,7 @@ weight: 10
* 어떻게 [노드 관리](/ko/docs/concepts/architecture/nodes/)를 하는지 배워보자.
* 공유된 클러스터의 [자원 할당량](/docs/concepts/policy/resource-quotas/) 어떻게 셋업하고 관리할 것인지 배워보자.
* 공유된 클러스터의 [리소스 쿼터](/ko/docs/concepts/policy/resource-quotas/) 어떻게 셋업하고 관리할 것인지 배워보자.
## 클러스터 보안
@@ -0,0 +1,86 @@
---
title: kubelet 가비지(Garbage) 수집 설정하기
content_template: templates/concept
weight: 70
---
{{% capture overview %}}
가비지 수집은 사용되지 않는 이미지들과 컨테이너들을 정리하는 kubelet의 유용한 기능이다. Kubelet은 1분마다 컨테이너들에 대하여 가비지 수집을 수행하며, 5분마다 이미지들에 대하여 가비지 수집을 수행한다.
별도의 가비지 수집 도구들을 사용하는 것은, 이러한 도구들이 존재할 수도 있는 컨테이너들을 제거함으로써 kubelet 을 중단시킬 수도 있으므로 권장하지 않는다.
{{% /capture %}}
{{% capture body %}}
## 이미지 수집
쿠버네티스는 cadvisor와 imageManager를 통하여 모든 이미지들의
라이프사이클을 관리한다.
이미지들에 대한 가비지 수집 정책에는 다음 2가지 요소가 고려된다:
`HighThresholdPercent``LowThresholdPercent`. 임계값을 초과하는
디스크 사용량은 가비지 수집을 트리거 한다. 가비지 수집은 낮은 입계값에 도달 할 때까지 최근에 가장 적게 사용한
이미지들을 삭제한다.
## 컨테이너 수집
컨테이너에 대한 가비지 수집 정책은 세 가지 사용자 정의 변수들을 고려한다: `MinAge` 는 컨테이너를 가비지 수집 할 수 있는 최소 연령이다. `MaxPerPodContainer` 는 모든 단일 파드 (UID, 컨테이너 이름) 쌍이 가질 수 있는
최대 비활성 컨테이너의 수량이다. `MaxContainers` 죽은 컨테이너의 최대 수량이다. 이러한 변수는 `MinAge` 를 0으로 설정하고, `MaxPerPodContainer``MaxContainers` 를 각각 0 보다 작게 설정해서 비활성화 할 수 있다.
Kubelet은 미확인, 삭제 또는 앞에서 언급 한 플래그가 설정 한 경계를 벗어나거나, 확인되지 않은 컨테이너에 대해 조치를 취한다. 일반적으로 가장 오래된 컨테이너가 먼저 제거된다. `MaxPerPodContainer``MaxContainer` 는 파드 당 최대 컨테이너 수 (`MaxPerPodContainer`)가 허용 가능한 범위의 전체 죽은 컨테이너의 수(`MaxContainers`)를 벗어나는 상황에서 잠재적으로 서로 충돌할 수 있습니다. 이러한 상황에서 `MaxPerPodContainer` 가 조정된다: 최악의 시나리오는 `MaxPerPodContainer` 를 1로 다운그레이드하고 가장 오래된 컨테이너를 제거하는 것이다. 추가로, 삭제된 파드가 소유 한 컨테이너는 `MinAge` 보다 오래된 컨테이너가 제거된다.
kubelet이 관리하지 않는 컨테이너는 컨테이너 가비지 수집 대상이 아니다.
## 사용자 설정
사용자는 후술될 kubelet 플래그들을 통하여 이미지 가비지 수집을 조정하기 위하여 다음의 임계값을 조정할 수 있다.
1. `image-gc-high-threshold`, 이미지 가비지 수집을 발생시키는 디스크 사용량의 비율로
기본값은 85% 이다.
2. `image-gc-low-threshold`, 이미지 가비지 수집을 더 이상 시도하지 않는 디스크 사용량의 비율로
기본값은 80% 이다.
또한 사용자는 다음의 kubelet 플래그를 통해 가비지 수집 정책을 사용자 정의 할 수 있다.
1. `minimum-container-ttl-duration`, 종료된 컨테이너가 가비지 수집
되기 전의 최소 시간. 기본 값은 0 분이며, 이 경우 모든 종료된 컨테이너는 바로 가비지 수집의 대상이 된다.
2. `maximum-dead-containers-per-container`, 컨테이너가 보유할 수 있는 오래된
인스턴스의 최대 수. 기본 값은 1 이다.
3. `maximum-dead-containers`, 글로벌하게 보유 할 컨테이너의 최대 오래된 인스턴스의 최대 수.
기본 값은 -1이며, 이 경우 인스턴스 수의 제한은 없다.
컨테이너들은 유용성이 만료되기 이전에도 가비지 수집이 될 수 있다. 이러한 컨테이너들은
문제 해결에 도움이 될 수 있는 로그나 다른 데이터를 포함하고 있을 수 있다. 컨테이너 당 적어도
1개의 죽은 컨테이너가 허용될 수 있도록 `maximum-dead-containers-per-container`
값을 충분히 큰 값으로 지정하는 것을 권장한다. 동일한 이유로 `maximum-dead-containers`
의 값도 상대적으로 더 큰 값을 권장한다.
자세한 내용은 [해당 이슈](https://github.com/kubernetes/kubernetes/issues/13287)를 참고한다.
## 사용 중단(Deprecation)
문서에 있는 몇 가지 kubelet의 가비지 수집 특징은 향후에 kubelet 축출(eviction) 기능으로 대체될 예정이다.
포함:
| 기존 Flag | 신규 Flag | 근거 |
| ------------- | -------- | --------- |
| `--image-gc-high-threshold` | `--eviction-hard` or `--eviction-soft` | 기존의 축출 신호로 인하여 이미지 가비지 수집이 트리거 될 수 있음 |
| `--image-gc-low-threshold` | `--eviction-minimum-reclaim` | 축출 리클레임 기능이 동일한 행동을 수행 |
| `--maximum-dead-containers` | | 컨테이너의 외부 영역에 오래된 로그가 저장되어 사용중단(deprecated)됨 |
| `--maximum-dead-containers-per-container` | | 컨테이너의 외부 영역에 오래된 로그가 저장되어 사용중단(deprecated)됨 |
| `--minimum-container-ttl-duration` | | 컨테이너의 외부 영역에 오래된 로그가 저장되어 사용중단(deprecated)됨 |
| `--low-diskspace-threshold-mb` | `--eviction-hard` or `eviction-soft` | 축출이 다른 리소스에 대한 디스크 임계값을 일반화 함 |
| `--outofdisk-transition-frequency` | `--eviction-pressure-transition-period` | 축출이 다른 리소스로의 디스크 압력전환을 일반화 함 |
{{% /capture %}}
{{% capture whatsnext %}}
자세한 내용은 [리소스 부족 처리 구성](/docs/tasks/administer-cluster/out-of-resource/)를 본다.
{{% /capture %}}
@@ -0,0 +1,267 @@
---
title: 로깅 아키텍처
content_template: templates/concept
weight: 60
---
{{% capture overview %}}
애플리케이션과 시스템 로그는 클러스터 내부에서 발생하는 상황을 이해하는 데 도움이 된다. 로그는 문제를 디버깅하고 클러스터 활동을 모니터링하는 데 특히 유용하다. 대부분의 최신 애플리케이션에는 일종의 로깅 메커니즘이 있다. 따라서, 대부분의 컨테이너 엔진은 일종의 로깅을 지원하도록 설계되었다. 컨테이너화된 애플리케이션에 가장 쉽고 가장 널리 사용되는 로깅 방법은 표준 출력과 표준 에러 스트림에 작성하는 것이다.
그러나, 일반적으로 컨테이너 엔진이나 런타임에서 제공하는 기본 기능은 완전한 로깅 솔루션으로 충분하지 않다. 예를 들어, 컨테이너가 크래시되거나, 파드가 축출되거나, 노드가 종료된 경우에도 여전히 애플리케이션의 로그에 접근하려고 한다. 따라서, 로그는 노드, 파드 또는 컨테이너와는 독립적으로 별도의 스토리지와 라이프사이클을 가져야 한다. 이 개념을 _클러스터-레벨-로깅_ 이라고 한다. 클러스터-레벨 로깅은 로그를 저장하고, 분석하고, 쿼리하기 위해 별도의 백엔드가 필요하다. 쿠버네티스는 로그 데이터를 위한 네이티브 스토리지 솔루션을 제공하지 않지만, 기존의 많은 로깅 솔루션을 쿠버네티스 클러스터에 통합할 수 있다.
{{% /capture %}}
{{% capture body %}}
클러스터-레벨 로깅 아키텍처는 로깅 백엔드가
클러스터 내부 또는 외부에 존재한다고 가정하여 설명한다. 클러스터-레벨
로깅에 관심이 없는 경우에도, 노드에서 로그를 저장하고
처리하는 방법에 대한 설명이 여전히 유용할 수 있다.
## 쿠버네티스의 기본 로깅
이 섹션에서는, 쿠버네티스에서 표준 출력 스트림으로 데이터를
출력하는 기본 로깅의 예시를 볼 수 있다. 이 데모에서는
일부 텍스트를 초당 한 번씩 표준 출력에 쓰는 컨테이너와 함께
[파드 명세](/examples/debug/counter-pod.yaml)를 사용한다.
{{< codenew file="debug/counter-pod.yaml" >}}
이 파드를 실행하려면, 다음의 명령을 사용한다.
```shell
kubectl apply -f https://k8s.io/examples/debug/counter-pod.yaml
```
출력은 다음과 같다.
```
pod/counter created
```
로그를 가져오려면, 다음과 같이 `kubectl logs` 명령을 사용한다.
```shell
kubectl logs counter
```
출력은 다음과 같다.
```
0: Mon Jan 1 00:00:00 UTC 2001
1: Mon Jan 1 00:00:01 UTC 2001
2: Mon Jan 1 00:00:02 UTC 2001
...
```
컨테이너가 크래시된 경우, `kubectl logs``--previous` 플래그를 사용해서 컨테이너의 이전 인스턴스에 대한 로그를 검색할 수 있다. 파드에 여러 컨테이너가 있는 경우, 명령에 컨테이너 이름을 추가하여 접근하려는 컨테이너 로그를 지정해야 한다. 자세한 내용은 [`kubectl logs` 문서](/docs/reference/generated/kubectl/kubectl-commands#logs)를 참조한다.
## 노드 레벨에서의 로깅
![노드 레벨 로깅](/images/docs/user-guide/logging/logging-node-level.png)
컨테이너화된 애플리케이션이 `stdout(표준 출력)``stderr(표준 에러)` 에 쓰는 모든 것은 컨테이너 엔진에 의해 어딘가에서 처리와 리디렉션 된다. 예를 들어, 도커 컨테이너 엔진은 이 두 스트림을 [로깅 드라이버](https://docs.docker.com/engine/admin/logging/overview)로 리디렉션 한다. 이 드라이버는 쿠버네티스에서 json 형식의 파일에 작성하도록 구성된다.
{{< note >}}
도커 json 로깅 드라이버는 각 라인을 별도의 메시지로 취급한다. 도커 로깅 드라이버를 사용하는 경우, 멀티-라인 메시지를 직접 지원하지 않는다. 로깅 에이전트 레벨 이상에서 멀티-라인 메시지를 처리해야 한다.
{{< /note >}}
기본적으로, 컨테이너가 다시 시작되면, kubelet은 종료된 컨테이너 하나를 로그와 함께 유지한다. 파드가 노드에서 축출되면, 해당하는 모든 컨테이너도 로그와 함께 축출된다.
노드-레벨 로깅에서 중요한 고려 사항은 로그 로테이션을 구현하여,
로그가 노드에서 사용 가능한 모든 스토리지를 사용하지 않도록 하는 것이다. 쿠버네티스는
현재 로그 로테이션에 대한 의무는 없지만, 디플로이먼트 도구로
이를 해결하기 위한 솔루션을 설정해야 한다.
예를 들어, `kube-up.sh` 스크립트에 의해 배포된 쿠버네티스 클러스터에는,
매시간 실행되도록 구성된 [`logrotate`](https://linux.die.net/man/8/logrotate)
도구가 있다. 예를 들어, 도커의 `log-opt` 를 사용하여 애플리케이션의 로그를
자동으로 로테이션을 하도록 컨테이너 런타임을 설정할 수도 있다.
`kube-up.sh` 스크립트에서, 후자의 접근 방식은 GCP의 COS 이미지에 사용되며,
전자의 접근 방식은 다른 환경에서 사용된다. 두 경우 모두,
기본적으로 로그 파일이 10MB를 초과하면 로테이션이 되도록 구성된다.
예를 들어, `kube-up.sh` 가 해당 [스크립트][cosConfigureHelper]에서
GCP의 COS 이미지 로깅을 설정하는 방법에 대한 자세한 정보를 찾을 수 있다.
기본 로깅 예제에서와 같이 [`kubectl logs`](/docs/reference/generated/kubectl/kubectl-commands#logs)를
실행하면, 노드의 kubelet이 요청을 처리하고
로그 파일에서 직접 읽은 다음, 응답의 내용을 반환한다.
{{< note >}}
현재, 일부 외부 시스템에서 로테이션을 수행한 경우,
`kubectl logs` 를 통해 최신 로그 파일의 내용만
사용할 수 있다. 예를 들어, 10MB 파일이 있으면, `logrotate`
로테이션을 수행하고 두 개의 파일이 생긴다(크기가 10MB인 파일 하나와 비어있는 파일).
그 후 `kubectl logs` 는 빈 응답을 반환한다.
{{< /note >}}
[cosConfigureHelper]: https://github.com/kubernetes/kubernetes/blob/{{< param "githubbranch" >}}/cluster/gce/gci/configure-helper.sh
### 시스템 컴포넌트 로그
시스템 컴포넌트에는 컨테이너에서 실행되는 것과 컨테이너에서 실행되지 않는 두 가지 유형이 있다.
예를 들면 다음과 같다.
* 쿠버네티스 스케줄러와 kube-proxy는 컨테이너에서 실행된다.
* Kubelet과 컨테이너 런타임(예: 도커)은 컨테이너에서 실행되지 않는다.
systemd를 사용하는 시스템에서, kubelet과 컨테이너 런타임은 journald에 작성한다.
systemd를 사용하지 않으면, `/var/log` 디렉터리의 `.log` 파일에 작성한다.
컨테이너 내부의 시스템 컴포넌트는 기본 로깅 메커니즘을 무시하고,
항상 `/var/log` 디렉터리에 기록한다. 그것은 [klog][klog]
로깅 라이브러리를 사용한다. [로깅에 대한 개발 문서](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md)에서
해당 컴포넌트의 로깅 심각도(severity)에 대한 규칙을 찾을 수 있다.
컨테이너 로그와 마찬가지로, `/var/log` 디렉터리의 시스템 컴포넌트 로그를
로테이트해야 한다. `kube-up.sh` 스크립트로 구축한 쿠버네티스 클러스터에서
로그는 매일 또는 크기가 100MB를 초과하면
`logrotate` 도구에 의해 로테이트가 되도록 구성된다.
[klog]: https://github.com/kubernetes/klog
## 클러스터 레벨 로깅 아키텍처
쿠버네티스는 클러스터-레벨 로깅을 위한 네이티브 솔루션을 제공하지 않지만, 고려해야 할 몇 가지 일반적인 접근 방법을 고려할 수 있다. 여기 몇 가지 옵션이 있다.
* 모든 노드에서 실행되는 노드-레벨 로깅 에이전트를 사용한다.
* 애플리케이션 파드에 로깅을 위한 전용 사이드카 컨테이너를 포함한다.
* 애플리케이션 내에서 로그를 백엔드로 직접 푸시한다.
### 노드 로깅 에이전트 사용
![노드 레벨 로깅 에이전트 사용](/images/docs/user-guide/logging/logging-with-node-agent.png)
각 노드에 _노드-레벨 로깅 에이전트_ 를 포함시켜 클러스터-레벨 로깅을 구현할 수 있다. 로깅 에이전트는 로그를 노출하거나 로그를 백엔드로 푸시하는 전용 도구이다. 일반적으로, 로깅 에이전트는 해당 노드의 모든 애플리케이션 컨테이너에서 로그 파일이 있는 디렉터리에 접근할 수 있는 컨테이너이다.
로깅 에이전트는 모든 노드에서 실행해야 하므로, 이를 데몬셋 레플리카, 매니페스트 파드 또는 노드의 전용 네이티브 프로세스로 구현하는 것이 일반적이다. 그러나 후자의 두 가지 접근법은 더 이상 사용되지 않으며 절대 권장하지 않는다.
쿠버네티스 클러스터는 노드-레벨 로깅 에이전트를 사용하는 것이 가장 일반적이며 권장되는 방법으로, 이는 노드별 하나의 에이전트만 생성하며, 노드에서 실행되는 애플리케이션을 변경할 필요가 없기 때문이다. 그러나, 노드-레벨 로깅은 _애플리케이션의 표준 출력과 표준 에러에 대해서만 작동한다_ .
쿠버네티스는 로깅 에이전트를 지정하지 않지만, 쿠버네티스 릴리스에는 두 가지 선택적인 로깅 에이전트(Google 클라우드 플랫폼과 함께 사용하기 위한 [스택드라이버(Stackdriver) 로깅](/docs/user-guide/logging/stackdriver)과 [엘라스틱서치(Elasticsearch)](/ko/docs/tasks/debug-application-cluster/logging-elasticsearch-kibana/))가 패키지로 함께 제공된다. 전용 문서에서 자세한 정보와 지침을 찾을 수 있다. 두 가지 다 사용자 정의 구성이 된 [fluentd](http://www.fluentd.org/)를 에이전트로써 노드에서 사용한다.
### 로깅 에이전트와 함께 사이드카 컨테이너 사용
다음 중 한 가지 방법으로 사이드카 컨테이너를 사용할 수 있다.
* 사이드카 컨테이너는 애플리케이션 로그를 자체 `stdout` 으로 스트리밍한다.
* 사이드카 컨테이너는 로깅 에이전트를 실행하며, 애플리케이션 컨테이너에서 로그를 가져오도록 구성된다.
#### 사이드카 컨테이너 스트리밍
![스트리밍 컨테이너가 있는 사이드카 컨테이너](/images/docs/user-guide/logging/logging-with-streaming-sidecar.png)
사이드카 컨테이너를 자체 `stdout``stderr` 스트림으로
스트리밍하면, 각 노드에서 이미 실행 중인 kubelet과 로깅 에이전트를
활용할 수 있다. 사이드카 컨테이너는 파일, 소켓
또는 journald에서 로그를 읽는다. 각 개별 사이드카 컨테이너는 자체 `stdout`
또는 `stderr` 스트림에 로그를 출력한다.
이 방법을 사용하면 애플리케이션의 다른 부분에서 여러 로그 스트림을
분리할 수 ​​있고, 이 중 일부는 `stdout` 또는 `stderr`
작성하기 위한 지원이 부족할 수 있다. 로그를 리디렉션하는 로직은
미미하기 때문에, 큰 오버헤드가 거의 없다. 또한,
`stdout``stderr` 가 kubelet에서 처리되므로, `kubectl logs` 와 같은
빌트인 도구를 사용할 수 있다.
다음의 예를 고려해보자. 파드는 단일 컨테이너를 실행하고, 컨테이너는
서로 다른 두 가지 형식을 사용하여, 서로 다른 두 개의 로그 파일에 기록한다. 파드에 대한
구성 파일은 다음과 같다.
{{< codenew file="admin/logging/two-files-counter-pod.yaml" >}}
두 컴포넌트를 컨테이너의 `stdout` 스트림으로 리디렉션한 경우에도, 동일한 로그
스트림에 서로 다른 형식의 로그 항목을 갖는 것은
알아보기 힘들다. 대신, 두 개의 사이드카 컨테이너를 도입할 수 있다. 각 사이드카
컨테이너는 공유 볼륨에서 특정 로그 파일을 테일(tail)한 다음 로그를
자체 `stdout` 스트림으로 리디렉션할 수 있다.
다음은 사이드카 컨테이너가 두 개인 파드에 대한 구성 파일이다.
{{< codenew file="admin/logging/two-files-counter-pod-streaming-sidecar.yaml" >}}
이제 이 파드를 실행하면, 다음의 명령을 실행하여 각 로그 스트림에
개별적으로 접근할 수 있다.
```shell
kubectl logs counter count-log-1
```
```
0: Mon Jan 1 00:00:00 UTC 2001
1: Mon Jan 1 00:00:01 UTC 2001
2: Mon Jan 1 00:00:02 UTC 2001
...
```
```shell
kubectl logs counter count-log-2
```
```
Mon Jan 1 00:00:00 UTC 2001 INFO 0
Mon Jan 1 00:00:01 UTC 2001 INFO 1
Mon Jan 1 00:00:02 UTC 2001 INFO 2
...
```
클러스터에 설치된 노드-레벨 에이전트는 추가 구성없이
자동으로 해당 로그 스트림을 선택한다. 원한다면, 소스 컨테이너에
따라 로그 라인을 파싱(parse)하도록 에이전트를 구성할 수 있다.
참고로, CPU 및 메모리 사용량이 낮음에도 불구하고(cpu에 대한 몇 밀리코어의
요구와 메모리에 대한 몇 메가바이트의 요구), 로그를 파일에 기록한 다음
`stdout` 으로 스트리밍하면 디스크 사용량은 두 배가 될 수 있다. 단일 파일에
쓰는 애플리케이션이 있는 경우, 일반적으로 스트리밍
사이드카 컨테이너 방식을 구현하는 대신 `/dev/stdout` 을 대상으로
설정하는 것이 더 낫다.
사이드카 컨테이너를 사용하여 애플리케이션 자체에서 로테이션할 수 없는
로그 파일을 로테이션할 수도 있다. 이 방법의 예로는
정기적으로 logrotate를 실행하는 작은 컨테이너를 두는 것이다.
그러나, `stdout``stderr` 을 직접 사용하고 로테이션과
유지 정책을 kubelet에 두는 것이 권장된다.
#### 로깅 에이전트가 있는 사이드카 컨테이너
![로깅 에이전트가 있는 사이드카 컨테이너](/images/docs/user-guide/logging/logging-with-sidecar-agent.png)
노드-레벨 로깅 에이전트가 상황에 맞게 충분히 유연하지 않은 경우,
애플리케이션과 함께 실행하도록 특별히 구성된 별도의 로깅 에이전트를 사용하여
사이드카 컨테이너를 생성할 수 있다.
{{< note >}}
사이드카 컨테이너에서 로깅 에이전트를 사용하면
상당한 리소스 소비로 이어질 수 있다. 게다가, kubelet에 의해
제어되지 않기 때문에, `kubectl logs` 명령을 사용하여 해당 로그에
접근할 수 없다.
{{< /note >}}
예를 들어, 로깅 에이전트로 fluentd를 사용하는 [스택드라이버](/docs/tasks/debug-application-cluster/logging-stackdriver/)를
사용할 수 있다. 여기에 이 방법을 구현하는 데 사용할 수 있는
두 가지 구성 파일이 있다. 첫 번째 파일에는
fluentd를 구성하기 위한 [컨피그맵](/docs/tasks/configure-pod-container/configure-pod-configmap/)이 포함되어 있다.
{{< codenew file="admin/logging/fluentd-sidecar-config.yaml" >}}
{{< note >}}
fluentd의 구성은 이 문서의 범위를 벗어난다.
fluentd를 구성하는 것에 대한 자세한 내용은,
[공식 fluentd 문서](http://docs.fluentd.org/)를 참고한다.
{{< /note >}}
두 번째 파일은 fluentd가 실행되는 사이드카 컨테이너가 있는 파드를 설명한다.
파드는 fluentd가 구성 데이터를 가져올 수 있는 볼륨을 마운트한다.
{{< codenew file="admin/logging/two-files-counter-pod-agent-sidecar.yaml" >}}
얼마 후 스택드라이버 인터페이스에서 로그 메시지를 찾을 수 있다.
이것은 단지 예시일 뿐이며 실제로 애플리케이션 컨테이너 내의
모든 소스에서 읽은 fluentd를 로깅 에이전트로 대체할 수 있다는 것을
기억한다.
### 애플리케이션에서 직접 로그 노출
![애플리케이션에서 직접 로그 노출](/images/docs/user-guide/logging/logging-from-application.png)
모든 애플리케이션에서 직접 로그를 노출하거나 푸시하여 클러스터-레벨 로깅을
구현할 수 있다. 그러나, 이러한 로깅 메커니즘의 구현은
쿠버네티스의 범위를 벗어난다.
{{% /capture %}}
@@ -0,0 +1,457 @@
---
title: 리소스 관리
content_template: templates/concept
weight: 40
---
{{% capture overview %}}
애플리케이션을 배포하고 서비스를 통해 노출했다. 이제 무엇을 해야 할까? 쿠버네티스는 확장과 업데이트를 포함하여, 애플리케이션 배포를 관리하는 데 도움이 되는 여러 도구를 제공한다. 더 자세히 설명할 기능 중에는 [구성 파일](/ko/docs/concepts/configuration/overview/)과 [레이블](/ko/docs/concepts/overview/working-with-objects/labels/)이 있다.
{{% /capture %}}
{{% capture body %}}
## 리소스 구성 구성하기
많은 애플리케이션들은 디플로이먼트 및 서비스와 같은 여러 리소스를 필요로 한다. 여러 리소스의 관리는 동일한 파일에 그룹화하여 단순화할 수 있다(YAML에서 `---` 로 구분). 예를 들면 다음과 같다.
{{< codenew file="application/nginx-app.yaml" >}}
단일 리소스와 동일한 방식으로 여러 리소스를 생성할 수 있다.
```shell
kubectl apply -f https://k8s.io/examples/application/nginx-app.yaml
```
```shell
service/my-nginx-svc created
deployment.apps/my-nginx created
```
리소스는 파일에 표시된 순서대로 생성된다. 따라서, 스케줄러가 디플로이먼트와 같은 컨트롤러에서 생성한 서비스와 관련된 파드를 분산시킬 수 있으므로, 서비스를 먼저 지정하는 것이 가장 좋다.
`kubectl apply` 는 여러 개의 `-f` 인수도 허용한다.
```shell
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-svc.yaml -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
```
그리고 개별 파일 대신 또는 추가로 디렉터리를 지정할 수 있다.
```shell
kubectl apply -f https://k8s.io/examples/application/nginx/
```
`kubectl` 은 접미사가 `.yaml`, `.yml` 또는 `.json` 인 파일을 읽는다.
동일한 마이크로서비스 또는 애플리케이션 티어(tier)와 관련된 리소스를 동일한 파일에 배치하고, 애플리케이션과 연관된 모든 파일을 동일한 디렉터리에 그룹화하는 것이 좋다. 애플리케이션의 티어가 DNS를 사용하여 서로 바인딩되면, 스택의 모든 컴포넌트를 일괄로 배포할 수 있다.
URL을 구성 소스로 지정할 수도 있다. 이는 github에 체크인된 구성 파일에서 직접 배포하는 데 편리하다.
```shell
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/application/nginx/nginx-deployment.yaml
```
```shell
deployment.apps/my-nginx created
```
## kubectl에서의 대량 작업
`kubectl` 이 대량으로 수행할 수 있는 작업은 리소스 생성만이 아니다. 또한 다른 작업을 수행하기 위해, 특히 작성한 동일한 리소스를 삭제하기 위해 구성 파일에서 리소스 이름을 추출할 수도 있다.
```shell
kubectl delete -f https://k8s.io/examples/application/nginx-app.yaml
```
```shell
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted
```
두 개의 리소스만 있는 경우, 리소스/이름 구문을 사용하여 커맨드 라인에서 둘다 모두 쉽게 지정할 수도 있다.
```shell
kubectl delete deployments/my-nginx services/my-nginx-svc
```
리소스가 많을 경우, `-l` 또는 `--selector` 를 사용하여 지정된 셀렉터(레이블 쿼리)를 지정하여 레이블별로 리소스를 필터링하는 것이 더 쉽다.
```shell
kubectl delete deployment,services -l app=nginx
```
```shell
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted
```
`kubectl` 은 입력을 받아들이는 것과 동일한 구문으로 리소스 이름을 출력하므로, `$()` 또는 `xargs` 를 사용하여 작업을 쉽게 연결할 수 있다.
```shell
kubectl get $(kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service)
```
```shell
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-nginx-svc LoadBalancer 10.0.0.208 <pending> 80/TCP 0s
```
위의 명령을 사용하여, 먼저 `examples/application/nginx/` 에 리소스를 생성하고 `-o name` 출력 형식으로 생성한 리소스를 출력한다(각 리소스를 resource/name으로 출력).
그런 다음 "service"만 `grep` 한 다음 `kubectl get` 으로 출력한다.
특정 디렉터리 내의 여러 서브 디렉터리에서 리소스를 구성하는 경우, `--filename,-f` 플래그와 함께 `--recursive` 또는 `-R` 을 지정하여, 서브 디렉터리에 대한 작업을 재귀적으로 수행할 수도 있다.
예를 들어, 리소스 유형별로 구성된 개발 환경에 필요한 모든 {{< glossary_tooltip text="매니페스트" term_id="manifest" >}}를 보유하는 `project/k8s/development` 디렉터리가 있다고 가정하자.
```
project/k8s/development
├── configmap
│   └── my-configmap.yaml
├── deployment
│   └── my-deployment.yaml
└── pvc
└── my-pvc.yaml
```
기본적으로, `project/k8s/development` 에서 대량 작업을 수행하면, 서브 디렉터리를 처리하지 않고, 디렉터리의 첫 번째 레벨에서 중지된다. 다음 명령을 사용하여 이 디렉터리에 리소스를 생성하려고 하면, 오류가 발생할 것이다.
```shell
kubectl apply -f project/k8s/development
```
```shell
error: you must provide one or more resources by argument or filename (.json|.yaml|.yml|stdin)
```
대신, 다음과 같이 `--filename,-f` 플래그와 함께 `--recursive` 또는 `-R` 플래그를 지정한다.
```shell
kubectl apply -f project/k8s/development --recursive
```
```shell
configmap/my-config created
deployment.apps/my-deployment created
persistentvolumeclaim/my-pvc created
```
`--recursive` 플래그는 `kubectl {create,get,delete,describe,rollout}` 등과 같이 `--filename,-f` 플래그를 허용하는 모든 작업에서 작동한다.
`--recursive` 플래그는 여러 개의 `-f` 인수가 제공될 때도 작동한다.
```shell
kubectl apply -f project/k8s/namespaces -f project/k8s/development --recursive
```
```shell
namespace/development created
namespace/staging created
configmap/my-config created
deployment.apps/my-deployment created
persistentvolumeclaim/my-pvc created
```
`kubectl` 에 대해 더 자세히 알고 싶다면, [kubectl 개요](/docs/reference/kubectl/overview/)를 참조한다.
## 효과적인 레이블 사용
지금까지 사용한 예는 모든 리소스에 최대 한 개의 레이블만 적용하는 것이었다. 세트를 서로 구별하기 위해 여러 레이블을 사용해야 하는 많은 시나리오가 있다.
예를 들어, 애플리케이션마다 `app` 레이블에 다른 값을 사용하지만, [방명록 예제](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/guestbook/)와 같은 멀티-티어 애플리케이션은 각 티어를 추가로 구별해야 한다. 프론트엔드는 다음의 레이블을 가질 수 있다.
```yaml
labels:
app: guestbook
tier: frontend
```
Redis 마스터와 슬레이브는 프론트엔드와 다른 `tier` 레이블을 가지지만, 아마도 추가로 `role` 레이블을 가질 것이다.
```yaml
labels:
app: guestbook
tier: backend
role: master
```
그리고
```yaml
labels:
app: guestbook
tier: backend
role: slave
```
레이블은 레이블로 지정된 차원에 따라 리소스를 분할하고 사용할 수 있게 한다.
```shell
kubectl apply -f examples/guestbook/all-in-one/guestbook-all-in-one.yaml
kubectl get pods -Lapp -Ltier -Lrole
```
```shell
NAME READY STATUS RESTARTS AGE APP TIER ROLE
guestbook-fe-4nlpb 1/1 Running 0 1m guestbook frontend <none>
guestbook-fe-ght6d 1/1 Running 0 1m guestbook frontend <none>
guestbook-fe-jpy62 1/1 Running 0 1m guestbook frontend <none>
guestbook-redis-master-5pg3b 1/1 Running 0 1m guestbook backend master
guestbook-redis-slave-2q2yf 1/1 Running 0 1m guestbook backend slave
guestbook-redis-slave-qgazl 1/1 Running 0 1m guestbook backend slave
my-nginx-divi2 1/1 Running 0 29m nginx <none> <none>
my-nginx-o0ef1 1/1 Running 0 29m nginx <none> <none>
```
```shell
kubectl get pods -lapp=guestbook,role=slave
```
```shell
NAME READY STATUS RESTARTS AGE
guestbook-redis-slave-2q2yf 1/1 Running 0 3m
guestbook-redis-slave-qgazl 1/1 Running 0 3m
```
## 카나리(canary) 디플로이먼트
여러 레이블이 필요한 또 다른 시나리오는 동일한 컴포넌트의 다른 릴리스 또는 구성의 디플로이먼트를 구별하는 것이다. 새 릴리스가 완전히 롤아웃되기 전에 실제 운영 트래픽을 수신할 수 있도록 새로운 애플리케이션 릴리스(파드 템플리트의 이미지 태그를 통해 지정됨)의 *카나리* 를 이전 릴리스와 나란히 배포하는 것이 일반적이다.
예를 들어, `track` 레이블을 사용하여 다른 릴리스를 구별할 수 있다.
기본(primary), 안정(stable) 릴리스에는 값이 `stable``track` 레이블이 있다.
```yaml
name: frontend
replicas: 3
...
labels:
app: guestbook
tier: frontend
track: stable
...
image: gb-frontend:v3
```
그런 다음 서로 다른 값(예: `canary`)으로 `track` 레이블을 전달하는 방명록 프론트엔드의 새 릴리스를 생성하여, 두 세트의 파드가 겹치지 않도록 할 수 있다.
```yaml
name: frontend-canary
replicas: 1
...
labels:
app: guestbook
tier: frontend
track: canary
...
image: gb-frontend:v4
```
프론트엔드 서비스는 레이블의 공통 서브셋을 선택하여(즉, `track` 레이블 생략) 두 레플리카 세트에 걸쳐 있으므로, 트래픽이 두 애플리케이션으로 리디렉션된다.
```yaml
selector:
app: guestbook
tier: frontend
```
안정 및 카나리 릴리스의 레플리카 수를 조정하여 실제 운영 트래픽을 수신할 각 릴리스의 비율을 결정한다(이 경우, 3:1).
확신이 들면, 안정 릴리스의 track을 새로운 애플리케이션 릴리스로 업데이트하고 카나리를 제거할 수 있다.
보다 구체적인 예시는, [Ghost 배포에 대한 튜토리얼](https://github.com/kelseyhightower/talks/tree/master/kubecon-eu-2016/demo#deploy-a-canary)을 확인한다.
## 레이블 업데이트
새로운 리소스를 만들기 전에 기존 파드 및 기타 리소스의 레이블을 다시 지정해야 하는 경우가 있다. 이것은 `kubectl label` 로 수행할 수 있다.
예를 들어, 모든 nginx 파드에 프론트엔드 티어로 레이블을 지정하려면, 간단히 다음과 같이 실행한다.
```shell
kubectl label pods -l app=nginx tier=fe
```
```shell
pod/my-nginx-2035384211-j5fhi labeled
pod/my-nginx-2035384211-u2c7e labeled
pod/my-nginx-2035384211-u3t6x labeled
```
먼저 "app=nginx" 레이블이 있는 모든 파드를 필터링한 다음, "tier=fe" 레이블을 지정한다.
방금 레이블을 지정한 파드를 보려면, 다음을 실행한다.
```shell
kubectl get pods -l app=nginx -L tier
```
```shell
NAME READY STATUS RESTARTS AGE TIER
my-nginx-2035384211-j5fhi 1/1 Running 0 23m fe
my-nginx-2035384211-u2c7e 1/1 Running 0 23m fe
my-nginx-2035384211-u3t6x 1/1 Running 0 23m fe
```
그러면 파드 티어의 추가 레이블 열(`-L` 또는 `--label-columns` 로 지정)과 함께, 모든 "app=nginx" 파드가 출력된다.
더 자세한 내용은, [레이블](/ko/docs/concepts/overview/working-with-objects/labels/) 및 [kubectl label](/docs/reference/generated/kubectl/kubectl-commands/#label)을 참고하길 바란다.
## 어노테이션 업데이트
때로는 어노테이션을 리소스에 첨부하려고 할 수도 있다. 어노테이션은 도구, 라이브러리 등과 같은 API 클라이언트가 검색할 수 있는 임의의 비-식별 메타데이터이다. 이는 `kubectl annotate` 으로 수행할 수 있다. 예를 들면 다음과 같다.
```shell
kubectl annotate pods my-nginx-v4-9gw19 description='my frontend running nginx'
kubectl get pods my-nginx-v4-9gw19 -o yaml
```
```shell
apiVersion: v1
kind: pod
metadata:
annotations:
description: my frontend running nginx
...
```
더 자세한 내용은, [어노테이션](/ko/docs/concepts/overview/working-with-objects/annotations/) 및 [kubectl annotate](/docs/reference/generated/kubectl/kubectl-commands/#annotate) 문서를 참고하길 바란다.
## 애플리케이션 스케일링
애플리케이션의 로드가 증가하거나 축소되면, `kubectl` 을 사용하여 쉽게 스케일링할 수 있다. 예를 들어, nginx 레플리카 수를 3에서 1로 줄이려면, 다음을 수행한다.
```shell
kubectl scale deployment/my-nginx --replicas=1
```
```shell
deployment.extensions/my-nginx scaled
```
이제 디플로이먼트가 관리하는 파드가 하나만 있다.
```shell
kubectl get pods -l app=nginx
```
```shell
NAME READY STATUS RESTARTS AGE
my-nginx-2035384211-j5fhi 1/1 Running 0 30m
```
시스템이 필요에 따라 1에서 3까지의 범위에서 nginx 레플리카 수를 자동으로 선택하게 하려면, 다음을 수행한다.
```shell
kubectl autoscale deployment/my-nginx --min=1 --max=3
```
```shell
horizontalpodautoscaler.autoscaling/my-nginx autoscaled
```
이제 nginx 레플리카가 필요에 따라 자동으로 확장되거나 축소된다.
더 자세한 내용은, [kubectl scale](/docs/reference/generated/kubectl/kubectl-commands/#scale), [kubectl autoscale](/docs/reference/generated/kubectl/kubectl-commands/#autoscale) 및 [horizontal pod autoscaler](/ko/docs/tasks/run-application/horizontal-pod-autoscale/) 문서를 참고하길 바란다.
## 리소스 인플레이스(in-place) 업데이트
때로는 자신이 만든 리소스를 필요한 부분만, 중단없이 업데이트해야 할 때가 있다.
### kubectl apply
구성 파일 셋을 소스 제어에서 유지하는 것이 좋으며([코드로서의 구성](http://martinfowler.com/bliki/InfrastructureAsCode.html) 참조),
그렇게 하면 구성하는 리소스에 대한 코드와 함께 버전을 지정하고 유지할 수 있다.
그런 다음, [`kubectl apply`](/docs/reference/generated/kubectl/kubectl-commands/#apply)를 사용하여 구성 변경 사항을 클러스터로 푸시할 수 있다.
이 명령은 푸시하려는 구성의 버전을 이전 버전과 비교하고 지정하지 않은 속성에 대한 자동 변경 사항을 덮어쓰지 않은 채 수정한 변경 사항을 적용한다.
```shell
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx configured
```
참고로 `kubectl apply` 는 이전의 호출 이후 구성의 변경 사항을 판별하기 위해 리소스에 어노테이션을 첨부한다. 호출되면, `kubectl apply` 는 리소스를 수정하는 방법을 결정하기 위해, 이전 구성과 제공된 입력 및 리소스의 현재 구성 간에 3-way diff를 수행한다.
현재, 이 어노테이션 없이 리소스가 생성되므로, `kubectl apply` 의 첫 번째 호출은 제공된 입력과 리소스의 현재 구성 사이의 2-way diff로 대체된다. 이 첫 번째 호출 중에는, 리소스를 생성할 때 설정된 특성의 삭제를 감지할 수 없다. 이러한 이유로, 그 특성들을 삭제하지 않는다.
`kubectl apply` 에 대한 모든 후속 호출, 그리고 `kubectl replace``kubectl edit` 와 같이 구성을 수정하는 다른 명령은, 어노테이션을 업데이트하여, `kubectl apply` 에 대한 후속 호출이 3-way diff를 사용하여 삭제를 감지하고 수행할 수 있도록 한다.
### kubectl edit
또는, `kubectl edit`로 리소스를 업데이트할 수도 있다.
```shell
kubectl edit deployment/my-nginx
```
이것은 먼저 리소스를 `get` 하여, 텍스트 편집기에서 편집한 다음, 업데이트된 버전으로 리소스를 `apply` 하는 것과 같다.
```shell
kubectl get deployment my-nginx -o yaml > /tmp/nginx.yaml
vi /tmp/nginx.yaml
# 편집한 다음, 파일을 저장한다.
kubectl apply -f /tmp/nginx.yaml
deployment.apps/my-nginx configured
rm /tmp/nginx.yaml
```
이를 통해 보다 중요한 변경을 더 쉽게 ​​수행할 수 있다. 참고로 `EDITOR` 또는 `KUBE_EDITOR` 환경 변수를 사용하여 편집기를 지정할 수 있다.
더 자세한 내용은, [kubectl edit](/docs/reference/generated/kubectl/kubectl-commands/#edit) 문서를 참고하길 바란다.
### kubectl patch
`kubectl patch` 를 사용하여 API 오브젝트를 인플레이스 업데이트할 수 있다. 이 명령은 JSON 패치,
JSON 병합 패치 그리고 전략적 병합 패치를 지원한다.
[kubectl patch를 사용한 인플레이스 API 오브젝트 업데이트](/docs/tasks/run-application/update-api-object-kubectl-patch/)와
[kubectl patch](/docs/reference/generated/kubectl/kubectl-commands/#patch)를
참조한다.
## 파괴적(disruptive) 업데이트
경우에 따라, 한 번 초기화하면 업데이트할 수 없는 리소스 필드를 업데이트해야 하거나, 디플로이먼트에서 생성된 손상된 파드를 고치는 등의 재귀적 변경을 즉시 원할 수도 있다. 이러한 필드를 변경하려면, `replace --force` 를 사용하여 리소스를 삭제하고 다시 만든다. 이 경우, 원래 구성 파일을 간단히 수정할 수 있다.
```shell
kubectl replace -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml --force
```
```shell
deployment.apps/my-nginx deleted
deployment.apps/my-nginx replaced
```
## 서비스 중단없이 애플리케이션 업데이트
언젠가는, 위의 카나리 디플로이먼트 시나리오에서와 같이, 일반적으로 새 이미지 또는 이미지 태그를 지정하여, 배포된 애플리케이션을 업데이트해야 한다. `kubectl` 은 여러 가지 업데이트 작업을 지원하며, 각 업데이트 작업은 서로 다른 시나리오에 적용할 수 있다.
디플로이먼트를 사용하여 애플리케이션을 생성하고 업데이트하는 방법을 안내한다.
nginx 1.14.2 버전을 실행한다고 가정해 보겠다.
```shell
kubectl create deployment my-nginx --image=nginx:1.14.2
```
```shell
deployment.apps/my-nginx created
```
3개의 레플리카를 포함한다(이전과 새 개정판이 공존할 수 있음).
```shell
kubectl scale deployment my-nginx --current-replicas=1 --replicas=3
```
```
deployment.apps/my-nginx scaled
```
1.16.1 버전으로 업데이트하려면, 위에서 배운 kubectl 명령을 사용하여 `.spec.template.spec.containers[0].image``nginx:1.14.2` 에서 `nginx:1.16.1` 로 간단히 변경한다.
```shell
kubectl edit deployment/my-nginx
```
이것으로 끝이다! 디플로이먼트는 배포된 nginx 애플리케이션을 배후에서 점차적으로 업데이트한다. 업데이트되는 동안 특정 수의 이전 레플리카만 중단될 수 있으며, 원하는 수의 파드 위에 특정 수의 새 레플리카만 생성될 수 있다. 이에 대한 더 자세한 내용을 보려면, [디플로이먼트 페이지](/ko/docs/concepts/workloads/controllers/deployment/)를 방문한다.
{{% /capture %}}
{{% capture whatsnext %}}
- [애플리케이션 검사 및 디버깅에 `kubectl` 을 사용하는 방법](/docs/tasks/debug-application-cluster/debug-application-introspection/)에 대해 알아본다.
- [구성 모범 사례 및 팁](/ko/docs/concepts/configuration/overview/)을 참고한다.
{{% /capture %}}