From edc8a4d3e8ed42c5b09af7adbedaf752070508a2 Mon Sep 17 00:00:00 2001 From: Jongwoo Han Date: Fri, 16 Aug 2024 10:39:00 +0900 Subject: [PATCH 1/2] Replace windows crlf to unix lf Signed-off-by: Jongwoo Han --- .../run-replicated-stateful-application.md | 1096 ++++++++--------- 1 file changed, 548 insertions(+), 548 deletions(-) diff --git a/content/ko/docs/tasks/run-application/run-replicated-stateful-application.md b/content/ko/docs/tasks/run-application/run-replicated-stateful-application.md index 71394849bf..77fc346eca 100644 --- a/content/ko/docs/tasks/run-application/run-replicated-stateful-application.md +++ b/content/ko/docs/tasks/run-application/run-replicated-stateful-application.md @@ -1,548 +1,548 @@ ---- -# reviewers: -# - enisoc -# - erictune -# - foxish -# - janetkuo -# - kow3ns -# - smarterclayton -title: 복제 스테이트풀 애플리케이션 실행하기 -content_type: tutorial -weight: 30 ---- - - - -이 페이지에서는 {{< glossary_tooltip term_id="statefulset" >}} 으로 복제 -스테이트풀 애플리케이션을 실행하는 방법에 대해 소개한다. -이 애플리케이션은 복제 MySQL 데이터베이스이다. 이 예제의 토폴로지는 -단일 주 서버와 여러 복제 서버로 이루어져있으며, row-based 비동기 복제 방식을 -사용한다. - -{{< note >}} -**해당 설정은 프로덕션 설정이 아니다**. 쿠버네티스에서 스테이트풀한 애플리케이션을 실행하기 위한 일반적인 패턴에 -집중하기 위해 MySQL 세팅이 안전하지 않은 기본 설정으로 되어 있다. -{{< /note >}} - -## {{% heading "prerequisites" %}} - - -* {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} -* {{< include "default-storage-class-prereqs.md" >}} -* 이 튜토리얼은 - [퍼시스턴트볼륨](/ko/docs/concepts/storage/persistent-volumes/) - 그리고 [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/), - [파드](/ko/docs/concepts/workloads/pods/), - [서비스](/ko/docs/concepts/services-networking/service/), - [컨피그맵(ConfigMap)](/docs/tasks/configure-pod-container/configure-pod-configmap/)와 같은 핵심 개념들에 대해 알고 있다고 가정한다. -* MySQL에 대한 지식이 있으면 도움이 되지만, 이 튜토리얼은 다른 시스템을 활용하였을 때도 - 도움이 되는 일반적인 패턴을 다루는데 중점을 둔다. -* default 네임스페이스를 사용하거나, 다른 오브젝트들과 충돌이 나지 않는 다른 네임스페이스를 사용한다. - - - -## {{% heading "objectives" %}} - - -* 스테이트풀셋을 이용한 복제 MySQL 토폴로지를 배포한다. -* MySQL 클라이언트에게 트래픽을 보낸다. -* 다운타임에 대한 저항력을 관찰한다. -* 스테이트풀셋을 확장/축소한다. - - - - - -## MySQL 배포하기 - -MySQL 디플로이먼트 예시는 컨피그맵과, 2개의 서비스, 그리고 스테이트풀셋으로 -구성되어 있다. - -### 컨피그맵 생성하기 {#configmap} - -다음 YAML 설정 파일로부터 컨피그맵을 생성한다. - -{{% codenew file="application/mysql/mysql-configmap.yaml" %}} - -```shell -kubectl apply -f https://k8s.io/examples/application/mysql/mysql-configmap.yaml -``` - -이 컨피그맵은 당신이 독립적으로 주 MySQL 서버와 레플리카들의 설정을 컨트롤할 수 있도록 -`my.cnf` 을 오버라이드한다. -이 경우에는, 주 서버는 복제 로그를 레플리카들에게 제공하고 -레플리카들은 복제를 통한 쓰기가 아닌 다른 쓰기들은 거부하도록 할 것이다. - -컨피그맵 자체가 다른 파드들에 서로 다른 설정 영역이 -적용되도록 하는 것이 아니다. -스테이트풀셋 컨트롤러가 제공해주는 정보에 따라서, -각 파드들은 초기화되면서 설정 영역을 참조할지 결정한다. - -### 서비스 생성하기 {#services} - -다음 YAML 설정 파일로부터 서비스를 생성한다. - -{{% codenew file="application/mysql/mysql-services.yaml" %}} - -```shell -kubectl apply -f https://k8s.io/examples/application/mysql/mysql-services.yaml -``` - -헤드리스 서비스는 스테이트풀셋 -{{< glossary_tooltip text="컨트롤러" term_id="controller" >}}가 집합의 일부분인 -파드들을 위해 생성한 DNS 엔트리들(entries)의 위한 거점이 된다. -헤드리스 서비스의 이름이 `mysql`이므로, 파드들은 -같은 쿠버네티스 클러스터나 네임스페이스에 존재하는 다른 파드들에게 `.mysql`라는 이름으로 -접근될 수 있다. - -`mysql-read`라고 불리우는 클라이언트 서비스는 고유의 클러스터 IP를 가지며, -Ready 상태인 모든 MySQL 파드들에게 커넥션을 분배하는 일반적인 서비스이다. -잠재적인 엔드포인트들의 집합은 주 MySQL 서버와 해당 -레플리카들을 포함한다. - -오직 읽기 쿼리들만 로드-밸런싱된 클라이언트 서비스를 이용할 수 있다는 사실에 주목하자. -하나의 주 MySQL 서버만이 존재하기 떄문에, 클라이언트들은 쓰기 작업을 실행하기 위해서 -주 MySQL 파드에 (헤드리스 서비스 안에 존재하는 DNS 엔트리를 통해) -직접 접근해야 한다. - -### 스테이트풀셋 생성하기 {#statefulset} - -마지막으로, 다음 YAML 설정 파일로부터 스테이트풀셋을 생성한다. - -{{% codenew file="application/mysql/mysql-statefulset.yaml" %}} - -```shell -kubectl apply -f https://k8s.io/examples/application/mysql/mysql-statefulset.yaml -``` - -다음을 실행하여, 초기화되는 프로세스들을 확인할 수 있다. - -```shell -kubectl get pods -l app=mysql --watch -``` - -잠시 뒤에, 3개의 파드들이 `Running` 상태가 되는 것을 볼 수 있다. - -``` -NAME READY STATUS RESTARTS AGE -mysql-0 2/2 Running 0 2m -mysql-1 2/2 Running 0 1m -mysql-2 2/2 Running 0 1m -``` - -**Ctrl+C**를 입력하여 watch를 종료하자. - -{{< note >}} -만약 아무 진행 상황도 보이지 않는다면, [시작하기 전에](#before-you-begin) 에 언급된 -동적 퍼시스턴트볼륨 프로비저너(provisioner)가 활성화되어 있는지 확인한다. -{{< /note >}} - -해당 메니페스트에는 스테이트풀셋의 일부분인 스테이트풀 파드들을 관리하기 위한 다양한 기법들이 -적용되어 있다. 다음 섹션에서는 스테트풀셋이 파드들을 생성할 때 일어나는 일들을 이해할 수 있도록 -일부 기법들을 강조하여 설명한다. - -## 스테이트풀 파드 초기화 이해하기 - -스테이트풀셋 컨트롤러는 파드들의 인덱스에 따라 -순차적으로 시작시킨다. -컨트롤러는 다음 파드 생성 이전에 각 파드가 Ready 상태가 되었다고 알려줄 때까지 기다린다. - -추가적으로, 컨트롤러는 각 파드들에게 `<스테이트풀셋 이름>-<순차적 인덱스>` 형태의 -고유하고 안정적인 이름을 부여하는데, 결과적으로 파드들은 `mysql-0`, `mysql-1`, -그리고 `mysql-2` 라는 이름을 가지게 된다. - -스테이트풀셋 매니페스트의 파드 템플릿은 해당 속성들을 통해 -순차적인 MySQL 복제의 시작을 수행한다. - -### 설정 생성하기 - -파드 스펙의 컨테이너를 시작하기 전에, 파드는 순서가 정의되어 있는 -[초기화 컨테이너](/ko/docs/concepts/workloads/pods/init-containers/)들을 -먼저 실행시킨다. - -`init-mysql`라는 이름의 첫 번째 초기화 컨테이너는, 인덱스에 따라 -특별한 MySQL 설정 파일을 생성한다. - -스크립트는 인덱스를 `hostname` 명령으로 반환되는 파드 이름의 -마지막 부분에서 추출하여 결정한다. -그리고 인덱스(이미 사용된 값들을 피하기 위한 오프셋 숫자와 함께)를 -MySQL의 `conf.d` 디렉토리의 `server-id.cnf` 파일에 저장한다. -이는 스테이트풀셋에게서 제공된 고유하고, 안정적인 신원을 같은 속성을 -필요로 하는 MySQL 서버 ID의 형태로 바꾸어준다. - -또한 `init-mysql` 컨테이너의 스크립트는 컨피그맵을 `conf.d`로 복사하여, -`primary.cnf` 또는 `replica.cnf`을 적용한다. -이 예제의 토폴로지가 하나의 주 MySQL 서버와 일정 수의 레플리카들로 이루어져 있기 때문에, -스크립트는 `0` 인덱스를 주 서버로, 그리고 나머지 값들은 -레플리카로 지정한다. -스테이트풀셋 컨트롤러의 -[디플로이먼트와 스케일링 보증](/ko/docs/concepts/workloads/controllers/statefulset/#디플로이먼트와-스케일링-보증)과 -합쳐지면, 복제를 위한 레플리카들을 생성하기 전에 주 MySQL 서버가 Ready 상태가 되도록 -보장할 수 있다. - -### 기존 데이터 복제(cloning) - -일반적으로, 레플리카에 새로운 파드가 추가되는 경우, 주 MySQL 서버가 -이미 데이터를 가지고 있다고 가정해야 한다. 또한 복제 로그가 첫 시작점부터의 로그들을 -다 가지고 있지는 않을 수 있다고 가정해야 한다. -이러한 보수적인 가정들은 스테이트풀셋이 초기 크기로 고정되어 있는 것보다, 시간에 따라 -확장/축소하게 할 수 있도록 하는 중요한 열쇠가 된다. - -`clone-mysql`라는 이름의 두 번째 초기화 컨테이너는, 퍼시스턴트볼륨에서 처음 초기화된 -레플리카 파드에 복제 작업을 수행한다. -이 말은 다른 실행 중인 파드로부터 모든 데이터들을 복제하기 때문에, -로컬의 상태가 충분히 일관성을 유지하고 있어서 주 서버에서부터 복제를 시작할 수 있다는 의미이다. - -MySQL 자체가 이러한 메커니즘을 제공해주지는 않기 때문에, 이 예제에서는 XtraBackup이라는 -유명한 오픈소스 도구를 사용한다. -복제 중에는, 복제 대상 MySQL 서버가 성능 저하를 겪을 수 있다. -주 MySQL 서버의 이러한 충격을 최소화하기 위해, 스크립트는 각 파드가 자신의 인덱스보다 -하나 작은 파드로부터 복제하도록 지시한다. -이것이 정상적으로 동작하는 이유는 스테이트풀셋 컨트롤러가 파드 `N+1`을 실행하기 전에 -항상 파드 `N`이 Ready 상태라는 것을 보장하기 때문이다. - -### 복제(replication) 시작하기 - -초기화 컨테이너들의 성공적으로 완료되면, 일반적인 컨테이너가 실행된다. -MySQL 파드는 `mysqld` 서버를 구동하는 `mysql` 컨테이너로 구성되어 있으며, -`xtrabackup` 컨테이너는 -[사이드카(sidecar)](/blog/2015/06/the-distributed-system-toolkit-patterns)로서 작동한다. - -`xtrabackup` 사이드카는 복제된 데이터 파일들을 보고 레플리카에 MySQL 복제를 시작해야 할 -필요가 있는지 결정한다. -만약 그렇다면, `mysqld`이 준비될 때까지 기다린 후 `CHANGE MASTER TO`, -그리고 `START SLAVE`를 XtraBackup 복제(clone) 파일들에서 -추출한 복제(replication) 파라미터들과 함께 실행시킨다. - -레플리카가 복제를 시작하면, 먼저 주 MySQL 서버를 기억하고, 서버가 재시작되거나 -커넥션이 끊어지면 다시 연결한다. -또한 레플리카들은 주 서버를 안정된 DNS 이름 -(`mysql-0.mysql`)으로 찾기 때문에, 주 서버가 리스케쥴링에 의해 새로운 -파드 IP를 받아도 주 서버를 자동으로 찾는다. - -마지막으로, 복제를 시작한 후에는, `xtrabackup` 컨테이너는 데이터 복제를 요청하는 -다른 파드들의 커넥션을 리스닝한다. -이 서버는 스테이트풀셋이 확장하거나, 다음 파드가 퍼시스턴트볼륨클레임을 잃어서 다시 복제를 -수행해햐 할 경우를 대비하여 독립적으로 존재해야 한다. - -## 클라이언트 트래픽 보내기 - -임시 컨테이너를 `mysql:5.7` 이미지로 실행하고 `mysql` 클라이언트 -바이너리를 실행하는 것으로 테스트 쿼리를 주 MySQL 서버(`mysql-0.mysql` 호스트네임)로 -보낼 수 있다. - -```shell -kubectl run mysql-client --image=mysql:5.7 -i --rm --restart=Never --\ - mysql -h mysql-0.mysql <`를 이전 단계에서 찾았던 노드의 이름으로 바꾸자. - -{{< caution >}} -노드 드레인은 해당 노드에서 실행 중인 다른 워크로드와 애플리케이션들에게 -영향을 줄 수 있다. 테스트 클러스터에만 -다음 단계를 수행하자. -{{< /caution >}} - -```shell -# 위에 명시된 다른 워크로드들이 받는 영향에 대한 주의사항을 확인한다. -kubectl drain --force --delete-emptydir-data --ignore-daemonsets -``` - -이제 파드가 다른 노드에 리스케줄링되는 것을 관찰할 수 있다. - -```shell -kubectl get pod mysql-2 -o wide --watch -``` - -출력은 다음과 비슷할 것이다. - -``` -NAME READY STATUS RESTARTS AGE IP NODE -mysql-2 2/2 Terminating 0 15m 10.244.1.56 kubernetes-node-9l2t -[...] -mysql-2 0/2 Pending 0 0s kubernetes-node-fjlm -mysql-2 0/2 Init:0/2 0 0s kubernetes-node-fjlm -mysql-2 0/2 Init:1/2 0 20s 10.244.5.32 kubernetes-node-fjlm -mysql-2 0/2 PodInitializing 0 21s 10.244.5.32 kubernetes-node-fjlm -mysql-2 1/2 Running 0 22s 10.244.5.32 kubernetes-node-fjlm -mysql-2 2/2 Running 0 30s 10.244.5.32 kubernetes-node-fjlm -``` - -그리고, 서버 ID `102`가 `SELECT @@server_id` 루프 출력에서 잠시 -사라진 후 다시 보이는 것을 확인할 수 있을 것이다. - -이제 노드의 스케줄 방지를 다시 해제(uncordon)해서 정상으로 돌아가도록 조치한다. - -```shell -kubectl uncordon -``` - -## 레플리카 스케일링하기 - -MySQL 레플리케이션을 사용하면, 레플리카를 추가하는 것으로 -읽기 쿼리 용량을 키울 수 있다. -스테이트풀셋을 사용하면, 단 한 줄의 명령으로 달성할 수 있다. - -```shell -kubectl scale statefulset mysql --replicas=5 -``` - -명령을 실행시켜서 새로운 파드들이 올라오는 것을 관찰하자. - -```shell -kubectl get pods -l app=mysql --watch -``` - -파드들이 올라오면, `SELECT @@server_id` 루프 출력에 서버 ID `103` 과 `104`가 나타나기 -시작할 것이다. - -그리고 해당 파드들이 존재하기 전에 추가된 데이터들이 해당 새 서버들에게도 존재하는 것을 -확인할 수 있다. - -```shell -kubectl run mysql-client --image=mysql:5.7 -i -t --rm --restart=Never --\ - mysql -h mysql-3.mysql -e "SELECT * FROM test.messages" -``` - -``` -Waiting for pod default/mysql-client to be running, status is Pending, pod ready: false -+---------+ -| message | -+---------+ -| hello | -+---------+ -pod "mysql-client" deleted -``` - -축소하는 것도 간단하게 할 수 있다. - -```shell -kubectl scale statefulset mysql --replicas=3 -``` - -{{< note >}} -확장은 퍼시스턴트볼륨클레임을 자동으로 생성하지만, -축소에서는 해당 PVC들이 자동으로 삭제되지 않는다. - -이로써 확장을 빠르게 하기 위해 초기화된 PVC들을 보관해 두거나, -삭제하기 전에 데이터를 추출하는 선택을 할 수 있다. -{{< /note >}} - -다음 명령을 실행하여 확인할 수 있다. - -```shell -kubectl get pvc -l app=mysql -``` - -스테이트풀셋을 3으로 축소했음에도 PVC 5개가 -아직 남아있음을 보여준다. - -``` -NAME STATUS VOLUME CAPACITY ACCESSMODES AGE -data-mysql-0 Bound pvc-8acbf5dc-b103-11e6-93fa-42010a800002 10Gi RWO 20m -data-mysql-1 Bound pvc-8ad39820-b103-11e6-93fa-42010a800002 10Gi RWO 20m -data-mysql-2 Bound pvc-8ad69a6d-b103-11e6-93fa-42010a800002 10Gi RWO 20m -data-mysql-3 Bound pvc-50043c45-b1c5-11e6-93fa-42010a800002 10Gi RWO 2m -data-mysql-4 Bound pvc-500a9957-b1c5-11e6-93fa-42010a800002 10Gi RWO 2m -``` - -만약 여분의 PVC들을 재사용하지 않을 것이라면, 이들을 삭제할 수 있다. - -```shell -kubectl delete pvc data-mysql-3 -kubectl delete pvc data-mysql-4 -``` - - - -## {{% heading "cleanup" %}} - - -1. `SELECT @@server_id` 루프를 끝내기 위해, 터미널에 **Ctrl+C**를 입력하거나, - 해당 명령을 다른 터미널에서 실행시키자. - - ```shell - kubectl delete pod mysql-client-loop --now - ``` - -1. 스테이트풀셋을 삭제한다. 이것은 파드들 또한 삭제할 것이다. - - ```shell - kubectl delete statefulset mysql - ``` - -1. 파드들의 삭제를 확인한다. - 삭제가 완료되기까지 시간이 걸릴 수 있다. - - ```shell - kubectl get pods -l app=mysql - ``` - - 위와 같은 메세지가 나타나면 파드들이 삭제되었다는 것을 알 수 있다. - - ``` - No resources found. - ``` - -1. 컨피그맵, 서비스, 그리고 퍼시스턴트볼륨클레임들을 삭제한다. - - ```shell - kubectl delete configmap,service,pvc -l app=mysql - ``` - -1. 만약 수동으로 퍼시스턴스볼륨들을 프로비저닝했다면, 수동으로 삭제하면서, - 그 밑에 존재하는 리소스들을 또한 삭제해야 한다. - 만약 동적 프로비저너를 사용했다면, 당신이 퍼시스턴트볼륨클레임으로 삭제하면 - 자동으로 퍼시스턴트볼륨을 삭제한다. - 일부 (EBS나 PD와 같은) 동적 프로비저너들은 퍼시스턴트볼륨을 삭제 - 하면 그 뒤에 존재하는 리소스들도 삭제한다. - - - -## {{% heading "whatsnext" %}} - -* [스테이트풀셋(StatefulSet) 확장하기](/ko/docs/tasks/run-application/scale-stateful-set/)에 대해 더 배워보기. -* [스테이트풀셋 디버깅하기](/ko/docs/tasks/debug/debug-application/debug-statefulset/)에 대해 더 배워보기. -* [스테이트풀셋(StatefulSet) 삭제하기](/ko/docs/tasks/run-application/delete-stateful-set/)에 대해 더 배워보기. -* [스테이트풀셋(StatefulSet) 파드 강제 삭제하기](/ko/docs/tasks/run-application/force-delete-stateful-set-pod/)에 대해 더 배워보기. -* [Helm Charts 저장소](https://artifacthub.io/)를 통해 - 다른 스테이트풀 애플리케이션 예제들을 확인해보기. +--- +# reviewers: +# - enisoc +# - erictune +# - foxish +# - janetkuo +# - kow3ns +# - smarterclayton +title: 복제 스테이트풀 애플리케이션 실행하기 +content_type: tutorial +weight: 30 +--- + + + +이 페이지에서는 {{< glossary_tooltip term_id="statefulset" >}} 으로 복제 +스테이트풀 애플리케이션을 실행하는 방법에 대해 소개한다. +이 애플리케이션은 복제 MySQL 데이터베이스이다. 이 예제의 토폴로지는 +단일 주 서버와 여러 복제 서버로 이루어져있으며, row-based 비동기 복제 방식을 +사용한다. + +{{< note >}} +**해당 설정은 프로덕션 설정이 아니다**. 쿠버네티스에서 스테이트풀한 애플리케이션을 실행하기 위한 일반적인 패턴에 +집중하기 위해 MySQL 세팅이 안전하지 않은 기본 설정으로 되어 있다. +{{< /note >}} + +## {{% heading "prerequisites" %}} + + +* {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} +* {{< include "default-storage-class-prereqs.md" >}} +* 이 튜토리얼은 + [퍼시스턴트볼륨](/ko/docs/concepts/storage/persistent-volumes/) + 그리고 [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/), + [파드](/ko/docs/concepts/workloads/pods/), + [서비스](/ko/docs/concepts/services-networking/service/), + [컨피그맵(ConfigMap)](/docs/tasks/configure-pod-container/configure-pod-configmap/)와 같은 핵심 개념들에 대해 알고 있다고 가정한다. +* MySQL에 대한 지식이 있으면 도움이 되지만, 이 튜토리얼은 다른 시스템을 활용하였을 때도 + 도움이 되는 일반적인 패턴을 다루는데 중점을 둔다. +* default 네임스페이스를 사용하거나, 다른 오브젝트들과 충돌이 나지 않는 다른 네임스페이스를 사용한다. + + + +## {{% heading "objectives" %}} + + +* 스테이트풀셋을 이용한 복제 MySQL 토폴로지를 배포한다. +* MySQL 클라이언트에게 트래픽을 보낸다. +* 다운타임에 대한 저항력을 관찰한다. +* 스테이트풀셋을 확장/축소한다. + + + + + +## MySQL 배포하기 + +MySQL 디플로이먼트 예시는 컨피그맵과, 2개의 서비스, 그리고 스테이트풀셋으로 +구성되어 있다. + +### 컨피그맵 생성하기 {#configmap} + +다음 YAML 설정 파일로부터 컨피그맵을 생성한다. + +{{% codenew file="application/mysql/mysql-configmap.yaml" %}} + +```shell +kubectl apply -f https://k8s.io/examples/application/mysql/mysql-configmap.yaml +``` + +이 컨피그맵은 당신이 독립적으로 주 MySQL 서버와 레플리카들의 설정을 컨트롤할 수 있도록 +`my.cnf` 을 오버라이드한다. +이 경우에는, 주 서버는 복제 로그를 레플리카들에게 제공하고 +레플리카들은 복제를 통한 쓰기가 아닌 다른 쓰기들은 거부하도록 할 것이다. + +컨피그맵 자체가 다른 파드들에 서로 다른 설정 영역이 +적용되도록 하는 것이 아니다. +스테이트풀셋 컨트롤러가 제공해주는 정보에 따라서, +각 파드들은 초기화되면서 설정 영역을 참조할지 결정한다. + +### 서비스 생성하기 {#services} + +다음 YAML 설정 파일로부터 서비스를 생성한다. + +{{% codenew file="application/mysql/mysql-services.yaml" %}} + +```shell +kubectl apply -f https://k8s.io/examples/application/mysql/mysql-services.yaml +``` + +헤드리스 서비스는 스테이트풀셋 +{{< glossary_tooltip text="컨트롤러" term_id="controller" >}}가 집합의 일부분인 +파드들을 위해 생성한 DNS 엔트리들(entries)의 위한 거점이 된다. +헤드리스 서비스의 이름이 `mysql`이므로, 파드들은 +같은 쿠버네티스 클러스터나 네임스페이스에 존재하는 다른 파드들에게 `.mysql`라는 이름으로 +접근될 수 있다. + +`mysql-read`라고 불리우는 클라이언트 서비스는 고유의 클러스터 IP를 가지며, +Ready 상태인 모든 MySQL 파드들에게 커넥션을 분배하는 일반적인 서비스이다. +잠재적인 엔드포인트들의 집합은 주 MySQL 서버와 해당 +레플리카들을 포함한다. + +오직 읽기 쿼리들만 로드-밸런싱된 클라이언트 서비스를 이용할 수 있다는 사실에 주목하자. +하나의 주 MySQL 서버만이 존재하기 떄문에, 클라이언트들은 쓰기 작업을 실행하기 위해서 +주 MySQL 파드에 (헤드리스 서비스 안에 존재하는 DNS 엔트리를 통해) +직접 접근해야 한다. + +### 스테이트풀셋 생성하기 {#statefulset} + +마지막으로, 다음 YAML 설정 파일로부터 스테이트풀셋을 생성한다. + +{{% codenew file="application/mysql/mysql-statefulset.yaml" %}} + +```shell +kubectl apply -f https://k8s.io/examples/application/mysql/mysql-statefulset.yaml +``` + +다음을 실행하여, 초기화되는 프로세스들을 확인할 수 있다. + +```shell +kubectl get pods -l app=mysql --watch +``` + +잠시 뒤에, 3개의 파드들이 `Running` 상태가 되는 것을 볼 수 있다. + +``` +NAME READY STATUS RESTARTS AGE +mysql-0 2/2 Running 0 2m +mysql-1 2/2 Running 0 1m +mysql-2 2/2 Running 0 1m +``` + +**Ctrl+C**를 입력하여 watch를 종료하자. + +{{< note >}} +만약 아무 진행 상황도 보이지 않는다면, [시작하기 전에](#before-you-begin) 에 언급된 +동적 퍼시스턴트볼륨 프로비저너(provisioner)가 활성화되어 있는지 확인한다. +{{< /note >}} + +해당 메니페스트에는 스테이트풀셋의 일부분인 스테이트풀 파드들을 관리하기 위한 다양한 기법들이 +적용되어 있다. 다음 섹션에서는 스테트풀셋이 파드들을 생성할 때 일어나는 일들을 이해할 수 있도록 +일부 기법들을 강조하여 설명한다. + +## 스테이트풀 파드 초기화 이해하기 + +스테이트풀셋 컨트롤러는 파드들의 인덱스에 따라 +순차적으로 시작시킨다. +컨트롤러는 다음 파드 생성 이전에 각 파드가 Ready 상태가 되었다고 알려줄 때까지 기다린다. + +추가적으로, 컨트롤러는 각 파드들에게 `<스테이트풀셋 이름>-<순차적 인덱스>` 형태의 +고유하고 안정적인 이름을 부여하는데, 결과적으로 파드들은 `mysql-0`, `mysql-1`, +그리고 `mysql-2` 라는 이름을 가지게 된다. + +스테이트풀셋 매니페스트의 파드 템플릿은 해당 속성들을 통해 +순차적인 MySQL 복제의 시작을 수행한다. + +### 설정 생성하기 + +파드 스펙의 컨테이너를 시작하기 전에, 파드는 순서가 정의되어 있는 +[초기화 컨테이너](/ko/docs/concepts/workloads/pods/init-containers/)들을 +먼저 실행시킨다. + +`init-mysql`라는 이름의 첫 번째 초기화 컨테이너는, 인덱스에 따라 +특별한 MySQL 설정 파일을 생성한다. + +스크립트는 인덱스를 `hostname` 명령으로 반환되는 파드 이름의 +마지막 부분에서 추출하여 결정한다. +그리고 인덱스(이미 사용된 값들을 피하기 위한 오프셋 숫자와 함께)를 +MySQL의 `conf.d` 디렉토리의 `server-id.cnf` 파일에 저장한다. +이는 스테이트풀셋에게서 제공된 고유하고, 안정적인 신원을 같은 속성을 +필요로 하는 MySQL 서버 ID의 형태로 바꾸어준다. + +또한 `init-mysql` 컨테이너의 스크립트는 컨피그맵을 `conf.d`로 복사하여, +`primary.cnf` 또는 `replica.cnf`을 적용한다. +이 예제의 토폴로지가 하나의 주 MySQL 서버와 일정 수의 레플리카들로 이루어져 있기 때문에, +스크립트는 `0` 인덱스를 주 서버로, 그리고 나머지 값들은 +레플리카로 지정한다. +스테이트풀셋 컨트롤러의 +[디플로이먼트와 스케일링 보증](/ko/docs/concepts/workloads/controllers/statefulset/#디플로이먼트와-스케일링-보증)과 +합쳐지면, 복제를 위한 레플리카들을 생성하기 전에 주 MySQL 서버가 Ready 상태가 되도록 +보장할 수 있다. + +### 기존 데이터 복제(cloning) + +일반적으로, 레플리카에 새로운 파드가 추가되는 경우, 주 MySQL 서버가 +이미 데이터를 가지고 있다고 가정해야 한다. 또한 복제 로그가 첫 시작점부터의 로그들을 +다 가지고 있지는 않을 수 있다고 가정해야 한다. +이러한 보수적인 가정들은 스테이트풀셋이 초기 크기로 고정되어 있는 것보다, 시간에 따라 +확장/축소하게 할 수 있도록 하는 중요한 열쇠가 된다. + +`clone-mysql`라는 이름의 두 번째 초기화 컨테이너는, 퍼시스턴트볼륨에서 처음 초기화된 +레플리카 파드에 복제 작업을 수행한다. +이 말은 다른 실행 중인 파드로부터 모든 데이터들을 복제하기 때문에, +로컬의 상태가 충분히 일관성을 유지하고 있어서 주 서버에서부터 복제를 시작할 수 있다는 의미이다. + +MySQL 자체가 이러한 메커니즘을 제공해주지는 않기 때문에, 이 예제에서는 XtraBackup이라는 +유명한 오픈소스 도구를 사용한다. +복제 중에는, 복제 대상 MySQL 서버가 성능 저하를 겪을 수 있다. +주 MySQL 서버의 이러한 충격을 최소화하기 위해, 스크립트는 각 파드가 자신의 인덱스보다 +하나 작은 파드로부터 복제하도록 지시한다. +이것이 정상적으로 동작하는 이유는 스테이트풀셋 컨트롤러가 파드 `N+1`을 실행하기 전에 +항상 파드 `N`이 Ready 상태라는 것을 보장하기 때문이다. + +### 복제(replication) 시작하기 + +초기화 컨테이너들의 성공적으로 완료되면, 일반적인 컨테이너가 실행된다. +MySQL 파드는 `mysqld` 서버를 구동하는 `mysql` 컨테이너로 구성되어 있으며, +`xtrabackup` 컨테이너는 +[사이드카(sidecar)](/blog/2015/06/the-distributed-system-toolkit-patterns)로서 작동한다. + +`xtrabackup` 사이드카는 복제된 데이터 파일들을 보고 레플리카에 MySQL 복제를 시작해야 할 +필요가 있는지 결정한다. +만약 그렇다면, `mysqld`이 준비될 때까지 기다린 후 `CHANGE MASTER TO`, +그리고 `START SLAVE`를 XtraBackup 복제(clone) 파일들에서 +추출한 복제(replication) 파라미터들과 함께 실행시킨다. + +레플리카가 복제를 시작하면, 먼저 주 MySQL 서버를 기억하고, 서버가 재시작되거나 +커넥션이 끊어지면 다시 연결한다. +또한 레플리카들은 주 서버를 안정된 DNS 이름 +(`mysql-0.mysql`)으로 찾기 때문에, 주 서버가 리스케쥴링에 의해 새로운 +파드 IP를 받아도 주 서버를 자동으로 찾는다. + +마지막으로, 복제를 시작한 후에는, `xtrabackup` 컨테이너는 데이터 복제를 요청하는 +다른 파드들의 커넥션을 리스닝한다. +이 서버는 스테이트풀셋이 확장하거나, 다음 파드가 퍼시스턴트볼륨클레임을 잃어서 다시 복제를 +수행해햐 할 경우를 대비하여 독립적으로 존재해야 한다. + +## 클라이언트 트래픽 보내기 + +임시 컨테이너를 `mysql:5.7` 이미지로 실행하고 `mysql` 클라이언트 +바이너리를 실행하는 것으로 테스트 쿼리를 주 MySQL 서버(`mysql-0.mysql` 호스트네임)로 +보낼 수 있다. + +```shell +kubectl run mysql-client --image=mysql:5.7 -i --rm --restart=Never --\ + mysql -h mysql-0.mysql <`를 이전 단계에서 찾았던 노드의 이름으로 바꾸자. + +{{< caution >}} +노드 드레인은 해당 노드에서 실행 중인 다른 워크로드와 애플리케이션들에게 +영향을 줄 수 있다. 테스트 클러스터에만 +다음 단계를 수행하자. +{{< /caution >}} + +```shell +# 위에 명시된 다른 워크로드들이 받는 영향에 대한 주의사항을 확인한다. +kubectl drain --force --delete-emptydir-data --ignore-daemonsets +``` + +이제 파드가 다른 노드에 리스케줄링되는 것을 관찰할 수 있다. + +```shell +kubectl get pod mysql-2 -o wide --watch +``` + +출력은 다음과 비슷할 것이다. + +``` +NAME READY STATUS RESTARTS AGE IP NODE +mysql-2 2/2 Terminating 0 15m 10.244.1.56 kubernetes-node-9l2t +[...] +mysql-2 0/2 Pending 0 0s kubernetes-node-fjlm +mysql-2 0/2 Init:0/2 0 0s kubernetes-node-fjlm +mysql-2 0/2 Init:1/2 0 20s 10.244.5.32 kubernetes-node-fjlm +mysql-2 0/2 PodInitializing 0 21s 10.244.5.32 kubernetes-node-fjlm +mysql-2 1/2 Running 0 22s 10.244.5.32 kubernetes-node-fjlm +mysql-2 2/2 Running 0 30s 10.244.5.32 kubernetes-node-fjlm +``` + +그리고, 서버 ID `102`가 `SELECT @@server_id` 루프 출력에서 잠시 +사라진 후 다시 보이는 것을 확인할 수 있을 것이다. + +이제 노드의 스케줄 방지를 다시 해제(uncordon)해서 정상으로 돌아가도록 조치한다. + +```shell +kubectl uncordon +``` + +## 레플리카 스케일링하기 + +MySQL 레플리케이션을 사용하면, 레플리카를 추가하는 것으로 +읽기 쿼리 용량을 키울 수 있다. +스테이트풀셋을 사용하면, 단 한 줄의 명령으로 달성할 수 있다. + +```shell +kubectl scale statefulset mysql --replicas=5 +``` + +명령을 실행시켜서 새로운 파드들이 올라오는 것을 관찰하자. + +```shell +kubectl get pods -l app=mysql --watch +``` + +파드들이 올라오면, `SELECT @@server_id` 루프 출력에 서버 ID `103` 과 `104`가 나타나기 +시작할 것이다. + +그리고 해당 파드들이 존재하기 전에 추가된 데이터들이 해당 새 서버들에게도 존재하는 것을 +확인할 수 있다. + +```shell +kubectl run mysql-client --image=mysql:5.7 -i -t --rm --restart=Never --\ + mysql -h mysql-3.mysql -e "SELECT * FROM test.messages" +``` + +``` +Waiting for pod default/mysql-client to be running, status is Pending, pod ready: false ++---------+ +| message | ++---------+ +| hello | ++---------+ +pod "mysql-client" deleted +``` + +축소하는 것도 간단하게 할 수 있다. + +```shell +kubectl scale statefulset mysql --replicas=3 +``` + +{{< note >}} +확장은 퍼시스턴트볼륨클레임을 자동으로 생성하지만, +축소에서는 해당 PVC들이 자동으로 삭제되지 않는다. + +이로써 확장을 빠르게 하기 위해 초기화된 PVC들을 보관해 두거나, +삭제하기 전에 데이터를 추출하는 선택을 할 수 있다. +{{< /note >}} + +다음 명령을 실행하여 확인할 수 있다. + +```shell +kubectl get pvc -l app=mysql +``` + +스테이트풀셋을 3으로 축소했음에도 PVC 5개가 +아직 남아있음을 보여준다. + +``` +NAME STATUS VOLUME CAPACITY ACCESSMODES AGE +data-mysql-0 Bound pvc-8acbf5dc-b103-11e6-93fa-42010a800002 10Gi RWO 20m +data-mysql-1 Bound pvc-8ad39820-b103-11e6-93fa-42010a800002 10Gi RWO 20m +data-mysql-2 Bound pvc-8ad69a6d-b103-11e6-93fa-42010a800002 10Gi RWO 20m +data-mysql-3 Bound pvc-50043c45-b1c5-11e6-93fa-42010a800002 10Gi RWO 2m +data-mysql-4 Bound pvc-500a9957-b1c5-11e6-93fa-42010a800002 10Gi RWO 2m +``` + +만약 여분의 PVC들을 재사용하지 않을 것이라면, 이들을 삭제할 수 있다. + +```shell +kubectl delete pvc data-mysql-3 +kubectl delete pvc data-mysql-4 +``` + + + +## {{% heading "cleanup" %}} + + +1. `SELECT @@server_id` 루프를 끝내기 위해, 터미널에 **Ctrl+C**를 입력하거나, + 해당 명령을 다른 터미널에서 실행시키자. + + ```shell + kubectl delete pod mysql-client-loop --now + ``` + +1. 스테이트풀셋을 삭제한다. 이것은 파드들 또한 삭제할 것이다. + + ```shell + kubectl delete statefulset mysql + ``` + +1. 파드들의 삭제를 확인한다. + 삭제가 완료되기까지 시간이 걸릴 수 있다. + + ```shell + kubectl get pods -l app=mysql + ``` + + 위와 같은 메세지가 나타나면 파드들이 삭제되었다는 것을 알 수 있다. + + ``` + No resources found. + ``` + +1. 컨피그맵, 서비스, 그리고 퍼시스턴트볼륨클레임들을 삭제한다. + + ```shell + kubectl delete configmap,service,pvc -l app=mysql + ``` + +1. 만약 수동으로 퍼시스턴스볼륨들을 프로비저닝했다면, 수동으로 삭제하면서, + 그 밑에 존재하는 리소스들을 또한 삭제해야 한다. + 만약 동적 프로비저너를 사용했다면, 당신이 퍼시스턴트볼륨클레임으로 삭제하면 + 자동으로 퍼시스턴트볼륨을 삭제한다. + 일부 (EBS나 PD와 같은) 동적 프로비저너들은 퍼시스턴트볼륨을 삭제 + 하면 그 뒤에 존재하는 리소스들도 삭제한다. + + + +## {{% heading "whatsnext" %}} + +* [스테이트풀셋(StatefulSet) 확장하기](/ko/docs/tasks/run-application/scale-stateful-set/)에 대해 더 배워보기. +* [스테이트풀셋 디버깅하기](/ko/docs/tasks/debug/debug-application/debug-statefulset/)에 대해 더 배워보기. +* [스테이트풀셋(StatefulSet) 삭제하기](/ko/docs/tasks/run-application/delete-stateful-set/)에 대해 더 배워보기. +* [스테이트풀셋(StatefulSet) 파드 강제 삭제하기](/ko/docs/tasks/run-application/force-delete-stateful-set-pod/)에 대해 더 배워보기. +* [Helm Charts 저장소](https://artifacthub.io/)를 통해 + 다른 스테이트풀 애플리케이션 예제들을 확인해보기. From 384a2c559436eab65044a873234249029710d92b Mon Sep 17 00:00:00 2001 From: Jongwoo Han Date: Fri, 16 Aug 2024 11:09:57 +0900 Subject: [PATCH 2/2] [ko] Update outdated files in dev-1.27-ko.1 (M198-M206) Signed-off-by: Jongwoo Han --- .../ko/docs/tasks/run-application/_index.md | 2 +- .../run-application/access-api-from-pod.md | 37 ++-- .../run-application/delete-stateful-set.md | 40 ++-- .../force-delete-stateful-set-pod.md | 62 +++--- .../horizontal-pod-autoscale.md | 35 ++-- .../run-replicated-stateful-application.md | 41 ++-- ...un-single-instance-stateful-application.md | 181 ++++++++---------- .../run-stateless-application-deployment.md | 166 ++++++++-------- .../run-application/scale-stateful-set.md | 34 ++-- 9 files changed, 296 insertions(+), 302 deletions(-) diff --git a/content/ko/docs/tasks/run-application/_index.md b/content/ko/docs/tasks/run-application/_index.md index 13039181be..0640b49766 100644 --- a/content/ko/docs/tasks/run-application/_index.md +++ b/content/ko/docs/tasks/run-application/_index.md @@ -1,5 +1,5 @@ --- title: "애플리케이션 실행" description: 스테이트리스와 스테이트풀 애플리케이션 모두를 실행하고 관리한다. -weight: 40 +weight: 80 --- diff --git a/content/ko/docs/tasks/run-application/access-api-from-pod.md b/content/ko/docs/tasks/run-application/access-api-from-pod.md index b9a0a8c55e..4bbdd2aeef 100644 --- a/content/ko/docs/tasks/run-application/access-api-from-pod.md +++ b/content/ko/docs/tasks/run-application/access-api-from-pod.md @@ -27,25 +27,36 @@ weight: 120 파드 내에서, 쿠버네티스 API에 연결하는 권장 방법은 다음과 같다. - - Go 클라이언트의 경우, 공식 [Go 클라이언트 라이브러리](https://github.com/kubernetes/client-go/)를 사용한다. - `rest.InClusterConfig()` 기능은 API 호스트 검색과 인증을 자동으로 처리한다. - [여기 예제](https://git.k8s.io/client-go/examples/in-cluster-client-configuration/main.go)를 참고한다. +- Go 클라이언트의 경우, 공식 + [Go 클라이언트 라이브러리](https://github.com/kubernetes/client-go/)를 사용한다. + `rest.InClusterConfig()` 기능은 API 호스트 검색과 인증을 자동으로 처리한다. + [여기 예제](https://git.k8s.io/client-go/examples/in-cluster-client-configuration/main.go)를 참고한다. - - Python 클라이언트의 경우, 공식 [Python 클라이언트 라이브러리](https://github.com/kubernetes-client/python/)를 사용한다. - `config.load_incluster_config()` 기능은 API 호스트 검색과 인증을 자동으로 처리한다. - [여기 예제](https://github.com/kubernetes-client/python/blob/master/examples/in_cluster_config.py)를 참고한다. +- Python 클라이언트의 경우, 공식 + [Python 클라이언트 라이브러리](https://github.com/kubernetes-client/python/)를 사용한다. + `config.load_incluster_config()` 기능은 API 호스트 검색과 인증을 자동으로 처리한다. + [여기 예제](https://github.com/kubernetes-client/python/blob/master/examples/in_cluster_config.py)를 참고한다. - - 사용할 수 있는 다른 라이브러리가 많이 있다. [클라이언트 라이브러리](/ko/docs/reference/using-api/client-libraries/) 페이지를 참고한다. +- 사용할 수 있는 다른 라이브러리가 많이 있다. + [클라이언트 라이브러리](/ko/docs/reference/using-api/client-libraries/) 페이지를 참고한다. 각각의 경우, 파드의 서비스 어카운트 자격 증명은 API 서버와 안전하게 통신하는 데 사용된다. ### REST API에 직접 접근 -파드에서 실행되는 동안, 쿠버네티스 apiserver는 `default` 네임스페이스에서 `kubernetes`라는 -서비스를 통해 접근할 수 있다. 따라서, 파드는 `kubernetes.default.svc` -호스트 이름을 사용하여 API 서버를 쿼리할 수 있다. 공식 클라이언트 라이브러리는 -이를 자동으로 수행한다. +파드에서 실행되는 동안, 컨테이너는 `KUBERNETES_SERVICE_HOST` 및 `KUBERNETES_SERVICE_PORT_HTTPS` +환경 변수를 가져와 쿠버네티스 API 서버에 대한 HTTPS URL을 +생성할 수 있다. API 서버의 클러스터 내 주소는 `default` 네임스페이스의 +`kubernetes`라는 이름의 서비스에도 게시되어 있으므로, 파드는 로컬 API 서버에 대한 +DNS 이름으로 `kubernetes.default.svc`를 참조할 수 있다. + +{{< note >}} +쿠버네티스는 API 서버가 `kubernetes.default.svc` 호스트네임에 대해 유효한 인증서를 +가지고 있음을 보장하지 않는다. +그러나 컨트롤 플레인**은** `$KUBERNETES_SERVICE_HOST`가 나타내는 +호스트네임 또는 IP 주소에 대해 유효한 인증서를 제공할 것으로 예상된다. +{{< /note >}} API 서버를 인증하는 권장 방법은 [서비스 어카운트](/docs/tasks/configure-pod-container/configure-service-account/) 자격 증명을 사용하는 것이다. @@ -99,9 +110,7 @@ curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISE ```json { "kind": "APIVersions", - "versions": [ - "v1" - ], + "versions": ["v1"], "serverAddressByClientCIDRs": [ { "clientCIDR": "0.0.0.0/0", diff --git a/content/ko/docs/tasks/run-application/delete-stateful-set.md b/content/ko/docs/tasks/run-application/delete-stateful-set.md index 69b0ae2cf7..722d4b58b9 100644 --- a/content/ko/docs/tasks/run-application/delete-stateful-set.md +++ b/content/ko/docs/tasks/run-application/delete-stateful-set.md @@ -14,20 +14,16 @@ weight: 60 이 작업은 {{< glossary_tooltip term_id="StatefulSet"text="스테이트풀셋">}}을 삭제하는 방법을 설명한다. - - ## {{% heading "prerequisites" %}} - -* 이 작업은 클러스터에 스테이트풀셋으로 표시되는 애플리케이션이 있다고 가정한다. - - +- 이 작업은 클러스터에 스테이트풀셋으로 표시되는 애플리케이션이 있다고 가정한다. ## 스테이트풀셋 삭제 -쿠버네티스에서 다른 리소스를 삭제하는 것과 같은 방식으로 스테이트풀셋을 삭제할 수 있다. `kubectl delete` 명령어를 사용하고 파일 또는 이름으로 스테이트풀셋을 지정하자. +쿠버네티스에서 다른 리소스를 삭제하는 것과 같은 방식으로 스테이트풀셋을 삭제할 수 있다. +`kubectl delete` 명령어를 사용하고 파일 또는 이름으로 스테이트풀셋을 지정하자. ```shell kubectl delete -f @@ -43,14 +39,17 @@ kubectl delete statefulsets kubectl delete service ``` -kubectl을 통해 스테이트풀셋을 삭제하면, 스테이트풀셋의 크기가 0으로 설정되고 이로 인해 스테이트풀셋에 포함된 모든 파드가 삭제된다. 파드가 아닌 스테이트풀셋만 삭제하려면, `--cascade=orphan` 옵션을 사용한다. -예시는 다음과 같다. +kubectl을 통해 스테이트풀셋을 삭제하면, 스테이트풀셋의 크기가 0으로 설정되고 +이로 인해 스테이트풀셋에 포함된 모든 파드가 삭제된다. 파드가 아닌 스테이트풀셋만 삭제하려면, +`--cascade=orphan` 옵션을 사용한다. 예시는 다음과 같다. ```shell kubectl delete -f --cascade=orphan ``` -`kubectl delete` 에 `--cascade=orphan` 를 사용하면 스테이트풀셋 오브젝트가 삭제된 후에도 스테이트풀셋에 의해 관리된 파드는 남게 된다. 만약 파드가 `app.kubernetes.io/name=MyApp` 레이블을 갖고 있다면, 다음과 같이 파드를 삭제할 수 있다. +`kubectl delete` 에 `--cascade=orphan` 를 사용하면 스테이트풀셋 오브젝트가 +삭제된 후에도 스테이트풀셋에 의해 관리된 파드는 남게 된다. 만약 파드가 +`app.kubernetes.io/name=MyApp` 레이블을 갖고 있다면, 다음과 같이 파드를 삭제할 수 있다. ```shell kubectl delete pods -l app.kubernetes.io/name=MyApp @@ -58,7 +57,11 @@ kubectl delete pods -l app.kubernetes.io/name=MyApp ### 퍼시스턴트볼륨(PersistentVolume) -스테이트풀셋의 파드들을 삭제하는 것이 연결된 볼륨을 삭제하는 것은 아니다. 이것은 볼륨을 삭제하기 전에 볼륨에서 데이터를 복사할 수 있는 기회를 준다. 파드가 종료된 후 PVC를 삭제하면 스토리지 클래스와 반환 정책에 따라 백업 퍼시스턴트볼륨 삭제가 트리거될 수 있다. 클레임 삭제 후 볼륨에 접근할 수 있다고 가정하면 안된다. +스테이트풀셋의 파드들을 삭제하는 것이 연결된 볼륨을 삭제하는 것은 아니다. +이것은 볼륨을 삭제하기 전에 볼륨에서 데이터를 복사할 수 있는 기회를 준다. +파드가 종료된 후 PVC를 삭제하면 스토리지 클래스와 반환 정책에 따라 백업 +퍼시스턴트볼륨 삭제가 트리거될 수 있다. 클레임 삭제 후 볼륨에 접근할 수 있다고 +가정하면 안된다. {{< note >}} PVC를 삭제할 때 데이터 손실될 수 있음에 주의하자. @@ -66,7 +69,8 @@ PVC를 삭제할 때 데이터 손실될 수 있음에 주의하자. ### 스테이트풀셋의 완벽한 삭제 -연결된 파드를 포함해서 스테이트풀셋의 모든 것을 삭제하기 위해 다음과 같이 일련의 명령을 실행한다. +연결된 파드를 포함해서 스테이트풀셋의 모든 것을 삭제하기 위해 다음과 같이 +일련의 명령을 실행한다. ```shell grace=$(kubectl get pods --template '{{.spec.terminationGracePeriodSeconds}}') @@ -76,15 +80,17 @@ kubectl delete pvc -l app.kubernetes.io/name=MyApp ``` -위의 예에서 파드에는 `app.kubernetes.io/name=MyApp` 라는 레이블이 있다. 사용자에게 적절한 레이블로 대체하자. +위의 예에서 파드에는 `app.kubernetes.io/name=MyApp` 라는 레이블이 있다. +사용자에게 적절한 레이블로 대체하자. ### 스테이트풀셋 파드의 강제 삭제 -스테이트풀셋의 일부 파드가 오랫동안 'Terminating' 또는 'Unknown' 상태에 있는 경우, apiserver에 수동적으로 개입하여 파드를 강제 삭제할 수도 있다. 이것은 잠재적으로 위험한 작업이다. 자세한 설명은 [스테이트풀셋 파드 강제 삭제하기](/ko/docs/tasks/run-application/force-delete-stateful-set-pod/)를 참고한다. - - +스테이트풀셋의 일부 파드가 오랫동안 'Terminating' 또는 'Unknown' 상태에 있는 경우, +apiserver에 수동적으로 개입하여 파드를 강제 삭제할 수도 있다. +이것은 잠재적으로 위험한 작업이다. 자세한 설명은 +[스테이트풀셋 파드 강제 삭제하기](/ko/docs/tasks/run-application/force-delete-stateful-set-pod/)를 +참고한다. ## {{% heading "whatsnext" %}} - [스테이트풀셋 파드 강제 삭제하기](/ko/docs/tasks/run-application/force-delete-stateful-set-pod/)에 대해 더 알아보기. diff --git a/content/ko/docs/tasks/run-application/force-delete-stateful-set-pod.md b/content/ko/docs/tasks/run-application/force-delete-stateful-set-pod.md index 1a6af4d8d1..3d318e992d 100644 --- a/content/ko/docs/tasks/run-application/force-delete-stateful-set-pod.md +++ b/content/ko/docs/tasks/run-application/force-delete-stateful-set-pod.md @@ -11,25 +11,33 @@ weight: 70 -이 페이지에서는 {{< glossary_tooltip text="스테이트풀셋" term_id="StatefulSet" >}}의 일부인 파드를 삭제하는 방법을 보여주고 +이 페이지에서는 {{< glossary_tooltip text="스테이트풀셋" term_id="StatefulSet" >}} +의 일부인 파드를 삭제하는 방법을 보여주고 이 과정에서 고려해야 할 사항을 설명한다. - ## {{% heading "prerequisites" %}} - -* 이것은 상당히 고급 태스크이며 스테이트풀셋 고유의 속성 중 일부를 위반할 가능성이 있다. -* 계속하기 전에 아래 나열된 고려 사항을 숙지하도록 한다. - - +- 이것은 상당히 고급 태스크이며 스테이트풀셋 고유의 속성 중 일부를 위반할 + 가능성이 있다. +- 계속하기 전에 아래 나열된 고려 사항을 숙지하도록 한다. ## 스테이트풀셋 고려 사항 -정상적인 스테이트풀셋의 작동에서는 스테이트풀셋 파드를 강제로 삭제할 필요가 **절대** 없다. [스테이트풀셋 컨트롤러](/ko/docs/concepts/workloads/controllers/statefulset/)는 스테이트풀셋의 멤버 생성, 스케일링, 삭제를 담당한다. 서수 0부터 N-1까지 지정된 수의 파드가 활성 상태이고 준비되었는지 확인한다. 스테이트풀셋은 언제든지 클러스터에서 실행 중인 지정된 신원을 가진 최대 하나의 파드가 있는지 확인한다. 이를 스테이트풀셋에서 제공하는 *최대 하나* 의미론이라고 한다. +정상적인 스테이트풀셋의 작동에서는 스테이트풀셋 파드를 강제로 삭제할 필요가 **절대** 없다. +[스테이트풀셋 컨트롤러](/ko/docs/concepts/workloads/controllers/statefulset/)는 스테이트풀셋의 멤버 +생성, 스케일링, 삭제를 담당한다. 서수 0부터 N-1까지 지정된 수의 파드가 +활성 상태이고 준비되었는지 확인한다. 스테이트풀셋은 언제든지 클러스터에서 실행 중인 +지정된 신원을 가진 최대 하나의 파드가 있는지 확인한다. 이를 스테이트풀셋에서 제공하는 +*최대 하나* 의미론이라고 한다. -수동 강제 삭제는 스테이트풀셋 고유의 최대 하나 의미론을 위반할 가능성이 있으므로 주의해서 수행해야 한다. 스테이트풀셋은 안정적인 네트워크 신원과 안정적인 스토리지가 필요한 분산 클러스터 애플리케이션을 실행하는 데 사용할 수 있다. 이러한 애플리케이션은 종종 고정된 신원을 가진 고정된 수의 구성원 앙상블에 의존하는 구성을 가진다. 여러 구성원이 동일한 신원을 갖는 것은 재앙이 될 수 있으며 데이터 손실로 이어질 수 있다(예: 쿼럼 기반 시스템의 스플릿 브레인(split-brain) 시나리오). +수동 강제 삭제는 스테이트풀셋 고유의 최대 하나 의미론을 위반할 가능성이 있으므로 +주의해서 수행해야 한다. 스테이트풀셋은 안정적인 네트워크 신원과 안정적인 스토리지가 +필요한 분산 클러스터 애플리케이션을 실행하는 데 사용할 수 있다. +이러한 애플리케이션은 종종 고정된 신원을 가진 고정된 수의 구성원 앙상블에 의존하는 +구성을 가진다. 여러 구성원이 동일한 신원을 갖는 것은 재앙이 될 수 있으며 데이터 손실로 +이어질 수 있다(예: 쿼럼 기반 시스템의 스플릿 브레인(split-brain) 시나리오). ## 파드 삭제 @@ -52,19 +60,33 @@ kubectl delete pods 사용자가 연결할 수 없는 노드에서 파드를 단계적으로 삭제하려고 하면 파드가 이러한 상태에 들어갈 수도 있다. 이러한 상태의 파드를 apiserver에서 제거할 수 있는 유일한 방법은 다음과 같다. -* 노드 오브젝트가 삭제된다(사용자 또는 [노드 컨트롤러](/ko/docs/concepts/architecture/nodes/#노드-컨트롤러)에 의해). -* 응답하지 않는 노드의 kubelet이 응답을 시작하고 파드를 종료하여 apiserver에서 항목을 제거한다. -* 사용자가 파드를 강제로 삭제한다. +- 노드 오브젝트가 삭제된다(사용자 또는 + [노드 컨트롤러](/ko/docs/concepts/architecture/nodes/#노드-컨트롤러)에 의해). +- 응답하지 않는 노드의 kubelet이 응답을 시작하고 파드를 종료하여 apiserver에서 + 항목을 제거한다. +- 사용자가 파드를 강제로 삭제한다. -권장되는 모범 사례는 첫 번째 또는 두 번째 방법을 사용하는 것이다. 노드가 죽은 것으로 확인되면(예: 네트워크에서 영구적으로 연결이 끊기거나 전원이 꺼진 경우 등) 노드 오브젝트를 삭제한다. 노드에 네트워크 파티션이 있는 경우 이를 해결하거나 해결될 때까지 기다린다. 파티션이 복구되면 kubelet은 파드 삭제를 완료하고 apiserver에서 해당 이름을 해제한다. +권장되는 모범 사례는 첫 번째 또는 두 번째 방법을 사용하는 것이다. 노드가 죽은 것으로 +확인되면(예: 네트워크에서 영구적으로 연결이 끊기거나 전원이 꺼진 경우 등) +노드 오브젝트를 삭제한다. 노드에 네트워크 파티션이 있는 경우 이를 해결하거나 +해결될 때까지 기다린다. 파티션이 복구되면 kubelet은 파드 삭제를 완료하고 +apiserver에서 해당 이름을 해제한다. -일반적으로 시스템은 파드가 노드에서 더 이상 실행되지 않거나 노드가 관리자에 의해 삭제되면 삭제를 완료한다. 파드를 강제로 삭제하여 이를 재정의할 수 있다. +일반적으로 시스템은 파드가 노드에서 더 이상 실행되지 않거나 노드가 관리자에 의해 삭제되면 +삭제를 완료한다. 파드를 강제로 삭제하여 이를 재정의할 수 있다. ### 강제 삭제 -강제 삭제는 파드가 종료되었다는 kubelet의 확인을 기다리지 **않는다**. 강제 삭제가 파드를 죽이는 데 성공했는지 여부와 관계없이 즉시 apiserver에서 이름을 해제한다. 이렇게 하면 스테이트풀셋 컨트롤러가 동일한 신원으로 대체 파드를 생성할 수 있다. 이것은 여전히 실행 중인 파드와 중복될 수 있으며, 해당 파드가 여전히 스테이트풀셋의 다른 멤버와 통신할 수 있다면 스테이트풀셋이 보장하도록 설계된 최대 하나 의미론을 위반할 것이다. +강제 삭제는 파드가 종료되었다는 kubelet의 확인을 기다리지 **않는다**. +강제 삭제가 파드를 죽이는 데 성공했는지 여부와 관계없이 즉시 apiserver에서 +이름을 해제한다. 이렇게 하면 스테이트풀셋 컨트롤러가 동일한 신원으로 대체 파드를 +생성할 수 있다. 이것은 여전히 실행 중인 파드와 중복될 수 있으며, 해당 파드가 여전히 +스테이트풀셋의 다른 멤버와 통신할 수 있다면 스테이트풀셋이 보장하도록 설계된 +최대 하나 의미론을 위반할 것이다. -스테이트풀셋 파드를 강제로 삭제하는 것은 문제의 파드가 스테이트풀셋의 다른 파드와 다시는 접촉하지 않으며 대체 생성을 위해 해당 이름을 안전하게 해제할 수 있다고 주장하는 것이다. +스테이트풀셋 파드를 강제로 삭제하는 것은 문제의 파드가 스테이트풀셋의 다른 파드와 다시는 +접촉하지 않으며 대체 생성을 위해 해당 이름을 안전하게 해제할 수 있다고 +주장하는 것이다. kubectl 버전 >= 1.5를 사용하여 파드를 강제로 삭제하려면, 다음을 수행한다. @@ -78,7 +100,8 @@ kubectl <= 1.4 버전을 사용하는 경우, `--force` 옵션을 생략하고 kubectl delete pods --grace-period=0 ``` -이러한 명령 후에도 파드가 `Unknown` 상태에서 멈추면, 다음 명령을 사용하여 클러스터에서 파드를 제거한다. +이러한 명령 후에도 파드가 `Unknown` 상태에서 멈추면, 다음 명령을 사용하여 클러스터에서 +파드를 제거한다. ```shell kubectl patch pod -p '{"metadata":{"finalizers":null}}' @@ -86,11 +109,6 @@ kubectl patch pod -p '{"metadata":{"finalizers":null}}' 항상 관련된 위험에 대해 완전히 이해한 상태에서 주의 깊게 스테이트풀셋 파드의 강제 삭제를 수행한다. - - ## {{% heading "whatsnext" %}} - [스테이트풀셋 디버깅하기](/ko/docs/tasks/debug/debug-application/debug-statefulset/)에 대해 더 알아보기. - - diff --git a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md index 13c4a99fb4..9bdf6b255c 100644 --- a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md +++ b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md @@ -84,7 +84,7 @@ class pod1,pod2,pod3 pod 리소스 메트릭 API(파드 단위 리소스 메트릭 용) 또는 커스텀 메트릭 API(그 외 모든 메트릭 용)로부터 메트릭을 수집한다. -* 파드 단위 리소스 메트릭(예 : CPU)의 경우 컨트롤러는 HorizontalPodAutoscaler가 +- 파드 단위 리소스 메트릭(예 : CPU)의 경우 컨트롤러는 HorizontalPodAutoscaler가 대상으로하는 각 파드에 대한 리소스 메트릭 API에서 메트릭을 가져온다. 그런 다음, 목표 사용률 값이 설정되면, 컨트롤러는 각 파드의 컨테이너에 대한 동등한 [자원 요청](/ko/docs/concepts/configuration/manage-resources-containers/#요청-및-제한)을 @@ -99,10 +99,10 @@ class pod1,pod2,pod3 pod 해당 메트릭에 대해 아무런 조치도 취하지 않는다. 오토스케일링 알고리즘의 작동 방식에 대한 자세한 내용은 아래 [알고리즘 세부 정보](#알고리즘-세부-정보) 섹션을 참조하기 바란다. -* 파드 단위 사용자 정의 메트릭의 경우, 컨트롤러는 사용률 값이 아닌 원시 값을 사용한다는 점을 +- 파드 단위 사용자 정의 메트릭의 경우, 컨트롤러는 사용률 값이 아닌 원시 값을 사용한다는 점을 제외하고는 파드 단위 리소스 메트릭과 유사하게 작동한다. -* 오브젝트 메트릭 및 외부 메트릭의 경우, 문제의 오브젝트를 표현하는 +- 오브젝트 메트릭 및 외부 메트릭의 경우, 문제의 오브젝트를 표현하는 단일 메트릭을 가져온다. 이 메트릭은 목표 값과 비교되어 위와 같은 비율을 생성한다. `autoscaling/v2` API 버전에서는, 비교가 이루어지기 전에 해당 값을 파드의 개수로 @@ -156,7 +156,7 @@ HorizontalPodAutoscaler 컨트롤러는 스케일링을 지원하는 상응하 같이 누락된 메트릭이 있는 모든 파드는 최종 스케일 량을 조정하는데 사용된다. CPU를 스케일할 때, 파드가 아직 Ready되지 않았거나(여전히 -초기화중이거나, unhealthy하여서) *또는* 파드의 최신 메트릭 포인트가 준비되기 +초기화중이거나, unhealthy하여서) _또는_ 파드의 최신 메트릭 포인트가 준비되기 전이라면, 마찬가지로 해당 파드는 나중에 처리된다. 기술적 제약으로 인해, HorizontalPodAutoscaler 컨트롤러는 @@ -189,7 +189,7 @@ CPU를 스케일할 때, 파드가 아직 Ready되지 않았거나(여전히 컨트롤러가 스케일링을 건너뛴다. 그렇지 않으면, 새로 계산한 사용률를 이용하여 파드 수 변경 결정을 내린다. -평균 사용량에 대한 *원래* 값은 새로운 사용 비율이 사용되는 +평균 사용량에 대한 _원래_ 값은 새로운 사용 비율이 사용되는 경우에도 아직-준비되지-않은 파드 또는 누락된 메트릭에 대한 고려없이 HorizontalPodAutoscaler 상태를 통해 다시 보고된다. @@ -227,7 +227,7 @@ API 오브젝트에 대한 자세한 내용은 HorizontalPodAutoscaler를 사용하여 레플리카 그룹의 크기를 관리할 때, 측정하는 메트릭의 동적 특성 때문에 레플리카 수가 계속 자주 요동칠 수 있다. -이는 종종 *thrashing* 또는 *flapping*이라고 불린다. +이는 종종 _thrashing_ 또는 _flapping_이라고 불린다. 이는 사이버네틱스 분야의 *이력 현상(hysteresis)* 개념과 비슷하다. @@ -276,7 +276,7 @@ resource: ### 컨테이너 리소스 메트릭 -{{< feature-state for_k8s_version="v1.20" state="alpha" >}} +{{< feature-state for_k8s_version="v1.27" state="beta" >}} HorizontalPodAutoscaler API는 대상 리소스를 스케일링하기 위해 HPA가 파드 집합에서 개별 컨테이너의 리소스 사용량을 추적할 수 있는 컨테이너 메트릭 소스도 지원한다. @@ -316,7 +316,6 @@ HorizontalPodAutoscaler가 추적하는 컨테이너의 이름을 변경하는 이전 컨테이너 이름을 제거하여 정리한다. {{< /note >}} - ## 사용자 정의 메트릭을 이용하는 스케일링 {{< feature-state for_k8s_version="v1.23" state="stable" >}} @@ -347,17 +346,17 @@ HorizontalPodAutoscaler는 새롭게 제안된 스케일링 크기 중 가장 기본적으로 HorizontalPodAutoscaler 컨트롤러는 일련의 API에서 메트릭을 검색한다. 이러한 API에 접속하려면 클러스터 관리자는 다음을 확인해야 한다. -* [API 애그리게이션 레이어](/docs/tasks/extend-kubernetes/configure-aggregation-layer/) 활성화 +- [API 애그리게이션 레이어](/docs/tasks/extend-kubernetes/configure-aggregation-layer/) 활성화 -* 해당 API 등록: +- 해당 API 등록: - * 리소스 메트릭의 경우, 일반적으로 이것은 [메트릭-서버](https://github.com/kubernetes-sigs/metrics-server)가 제공하는 `metrics.k8s.io` API이다. + - 리소스 메트릭의 경우, 일반적으로 이것은 [메트릭-서버](https://github.com/kubernetes-sigs/metrics-server)가 제공하는 `metrics.k8s.io` API이다. 클러스터 애드온으로 실행할 수 있다. - * 사용자 정의 메트릭의 경우, 이것은 `custom.metrics.k8s.io` API이다. 메트릭 솔루션 공급 업체에서 제공하는 "어댑터" API 서버에서 제공한다. + - 사용자 정의 메트릭의 경우, 이것은 `custom.metrics.k8s.io` API이다. 메트릭 솔루션 공급 업체에서 제공하는 "어댑터" API 서버에서 제공한다. 사용 가능한 쿠버네티스 메트릭 어댑터가 있는지 확인하려면 사용하고자 하는 메트릭 파이프라인을 확인한다. - * 외부 메트릭의 경우, 이것은 `external.metrics.k8s.io` API이다. 위에 제공된 사용자 정의 메트릭 어댑터에서 제공될 수 있다. + - 외부 메트릭의 경우, 이것은 `external.metrics.k8s.io` API이다. 위에 제공된 사용자 정의 메트릭 어댑터에서 제공될 수 있다. 이런 다양한 메트릭 경로와 각각의 다른 점에 대한 상세 내용은 관련 디자인 제안서인 [HPA V2](https://git.k8s.io/design-proposals-archive/autoscaling/hpa-v2.md), @@ -537,7 +536,7 @@ Horizontal Pod Autoscaler는 모든 API 리소스와 마찬가지로 `kubectl` 또한 Horizontal Pod Autoscaler를 생성할 수 있는 `kubectl autoscale`이라는 특별한 명령이 있다. 예를 들어 `kubectl autoscale rs foo --min=2 --max=5 --cpu-percent=80`을 -실행하면 레플리카셋 *foo* 에 대한 오토스케일러가 생성되고, 목표 CPU 사용률은 `80 %`, +실행하면 레플리카셋 _foo_ 에 대한 오토스케일러가 생성되고, 목표 CPU 사용률은 `80 %`, 그리고 2와 5 사이의 레플리카 개수로 설정된다. ## 암시적 점검 모드(maintenance-mode) 비활성화 @@ -595,8 +594,8 @@ HPA가 활성화되어 있으면, 디플로이먼트, 스테이트풀셋 모두 HorizontalPodAutoscaler에 대한 더 많은 정보는 아래를 참고한다. -* horizontal pod autoscaling에 대한 [연습 예제](/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/)를 확인한다. -* [`kubectl autoscale`](/docs/reference/generated/kubectl/kubectl-commands/#autoscale) 문서를 확인한다. -* 커스텀 메트릭 어댑터를 직접 작성하고 싶다면, +- horizontal pod autoscaling에 대한 [연습 예제](/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/)를 확인한다. +- [`kubectl autoscale`](/docs/reference/generated/kubectl/kubectl-commands/#autoscale) 문서를 확인한다. +- 커스텀 메트릭 어댑터를 직접 작성하고 싶다면, [샘플](https://github.com/kubernetes-sigs/custom-metrics-apiserver)을 확인한다. -* HorizontalPodAutoscaler [API 레퍼런스](/docs/reference/kubernetes-api/workload-resources/horizontal-pod-autoscaler-v2/)를 확인한다. +- HorizontalPodAutoscaler [API 레퍼런스](/docs/reference/kubernetes-api/workload-resources/horizontal-pod-autoscaler-v2/)를 확인한다. diff --git a/content/ko/docs/tasks/run-application/run-replicated-stateful-application.md b/content/ko/docs/tasks/run-application/run-replicated-stateful-application.md index 77fc346eca..a6efb13b10 100644 --- a/content/ko/docs/tasks/run-application/run-replicated-stateful-application.md +++ b/content/ko/docs/tasks/run-application/run-replicated-stateful-application.md @@ -26,30 +26,24 @@ weight: 30 ## {{% heading "prerequisites" %}} - -* {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} -* {{< include "default-storage-class-prereqs.md" >}} -* 이 튜토리얼은 +- {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} +- {{< include "default-storage-class-prereqs.md" >}} +- 이 튜토리얼은 [퍼시스턴트볼륨](/ko/docs/concepts/storage/persistent-volumes/) 그리고 [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/), [파드](/ko/docs/concepts/workloads/pods/), [서비스](/ko/docs/concepts/services-networking/service/), [컨피그맵(ConfigMap)](/docs/tasks/configure-pod-container/configure-pod-configmap/)와 같은 핵심 개념들에 대해 알고 있다고 가정한다. -* MySQL에 대한 지식이 있으면 도움이 되지만, 이 튜토리얼은 다른 시스템을 활용하였을 때도 +- MySQL에 대한 지식이 있으면 도움이 되지만, 이 튜토리얼은 다른 시스템을 활용하였을 때도 도움이 되는 일반적인 패턴을 다루는데 중점을 둔다. -* default 네임스페이스를 사용하거나, 다른 오브젝트들과 충돌이 나지 않는 다른 네임스페이스를 사용한다. - - +- default 네임스페이스를 사용하거나, 다른 오브젝트들과 충돌이 나지 않는 다른 네임스페이스를 사용한다. ## {{% heading "objectives" %}} - -* 스테이트풀셋을 이용한 복제 MySQL 토폴로지를 배포한다. -* MySQL 클라이언트에게 트래픽을 보낸다. -* 다운타임에 대한 저항력을 관찰한다. -* 스테이트풀셋을 확장/축소한다. - - +- 스테이트풀셋을 이용한 복제 MySQL 토폴로지를 배포한다. +- MySQL 클라이언트에게 트래픽을 보낸다. +- 다운타임에 대한 저항력을 관찰한다. +- 스테이트풀셋을 확장/축소한다. @@ -492,13 +486,10 @@ kubectl delete pvc data-mysql-3 kubectl delete pvc data-mysql-4 ``` - - ## {{% heading "cleanup" %}} - 1. `SELECT @@server_id` 루프를 끝내기 위해, 터미널에 **Ctrl+C**를 입력하거나, - 해당 명령을 다른 터미널에서 실행시키자. + 해당 명령을 다른 터미널에서 실행시키자. ```shell kubectl delete pod mysql-client-loop --now @@ -536,13 +527,11 @@ kubectl delete pvc data-mysql-4 일부 (EBS나 PD와 같은) 동적 프로비저너들은 퍼시스턴트볼륨을 삭제 하면 그 뒤에 존재하는 리소스들도 삭제한다. - - ## {{% heading "whatsnext" %}} -* [스테이트풀셋(StatefulSet) 확장하기](/ko/docs/tasks/run-application/scale-stateful-set/)에 대해 더 배워보기. -* [스테이트풀셋 디버깅하기](/ko/docs/tasks/debug/debug-application/debug-statefulset/)에 대해 더 배워보기. -* [스테이트풀셋(StatefulSet) 삭제하기](/ko/docs/tasks/run-application/delete-stateful-set/)에 대해 더 배워보기. -* [스테이트풀셋(StatefulSet) 파드 강제 삭제하기](/ko/docs/tasks/run-application/force-delete-stateful-set-pod/)에 대해 더 배워보기. -* [Helm Charts 저장소](https://artifacthub.io/)를 통해 +- [스테이트풀셋(StatefulSet) 확장하기](/ko/docs/tasks/run-application/scale-stateful-set/)에 대해 더 배워보기. +- [스테이트풀셋 디버깅하기](/ko/docs/tasks/debug/debug-application/debug-statefulset/)에 대해 더 배워보기. +- [스테이트풀셋(StatefulSet) 삭제하기](/ko/docs/tasks/run-application/delete-stateful-set/)에 대해 더 배워보기. +- [스테이트풀셋(StatefulSet) 파드 강제 삭제하기](/ko/docs/tasks/run-application/force-delete-stateful-set-pod/)에 대해 더 배워보기. +- [Helm Charts 저장소](https://artifacthub.io/)를 통해 다른 스테이트풀 애플리케이션 예제들을 확인해보기. diff --git a/content/ko/docs/tasks/run-application/run-single-instance-stateful-application.md b/content/ko/docs/tasks/run-application/run-single-instance-stateful-application.md index 9362167247..cd301c46e0 100644 --- a/content/ko/docs/tasks/run-application/run-single-instance-stateful-application.md +++ b/content/ko/docs/tasks/run-application/run-single-instance-stateful-application.md @@ -10,28 +10,17 @@ weight: 20 사용하여, 단일 인스턴스 스테이트풀 애플리케이션을 실행하는 방법을 보인다. 해당 애플리케이션은 MySQL이다. - - - ## {{% heading "objectives" %}} - -* 사용자 환경의 디스크를 참조하는 퍼시스턴트볼륨 생성하기 -* MySQL 디플로이먼트 생성하기 -* 알려진 DNS 이름으로 클러스터의 다른 파드에 MySQL 서비스 노출하기 - - - +- 사용자 환경의 디스크를 참조하는 퍼시스턴트볼륨 생성하기 +- MySQL 디플로이먼트 생성하기 +- 알려진 DNS 이름으로 클러스터의 다른 파드에 MySQL 서비스 노출하기 ## {{% heading "prerequisites" %}} -* {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} - -* {{< include "default-storage-class-prereqs.md" >}} - - - +- {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} +- {{< include "default-storage-class-prereqs.md" >}} @@ -54,81 +43,89 @@ MySQL을 실행하고 퍼시스턴트볼륨클레임을 참조하는 디플로 {{% codenew file="application/mysql/mysql-pv.yaml" %}} 1. YAML 파일의 PV와 PVC를 배포한다. - - kubectl apply -f https://k8s.io/examples/application/mysql/mysql-pv.yaml - + ```shell + kubectl apply -f https://k8s.io/examples/application/mysql/mysql-pv.yaml + ``` 1. YAML 파일의 다른 오브젝트들을 배포한다. - - kubectl apply -f https://k8s.io/examples/application/mysql/mysql-deployment.yaml - + ```shell + kubectl apply -f https://k8s.io/examples/application/mysql/mysql-deployment.yaml + ``` 1. 디플로이먼트에 관한 정보를 확인한다. + ```shell + kubectl describe deployment mysql + ``` - kubectl describe deployment mysql + 출력은 다음과 유사하다. - 출력은 다음과 유사하다. - - Name: mysql - Namespace: default - CreationTimestamp: Tue, 01 Nov 2016 11:18:45 -0700 - Labels: app=mysql - Annotations: deployment.kubernetes.io/revision=1 - Selector: app=mysql - Replicas: 1 desired | 1 updated | 1 total | 0 available | 1 unavailable - StrategyType: Recreate - MinReadySeconds: 0 - Pod Template: - Labels: app=mysql - Containers: - mysql: - Image: mysql:5.6 - Port: 3306/TCP - Environment: - MYSQL_ROOT_PASSWORD: password - Mounts: - /var/lib/mysql from mysql-persistent-storage (rw) - Volumes: - mysql-persistent-storage: - Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) - ClaimName: mysql-pv-claim - ReadOnly: false - Conditions: - Type Status Reason - ---- ------ ------ - Available False MinimumReplicasUnavailable - Progressing True ReplicaSetUpdated - OldReplicaSets: - NewReplicaSet: mysql-63082529 (1/1 replicas created) - Events: - FirstSeen LastSeen Count From SubobjectPath Type Reason Message - --------- -------- ----- ---- ------------- -------- ------ ------- - 33s 33s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set mysql-63082529 to 1 + ``` + Name: mysql + Namespace: default + CreationTimestamp: Tue, 01 Nov 2016 11:18:45 -0700 + Labels: app=mysql + Annotations: deployment.kubernetes.io/revision=1 + Selector: app=mysql + Replicas: 1 desired | 1 updated | 1 total | 0 available | 1 unavailable + StrategyType: Recreate + MinReadySeconds: 0 + Pod Template: + Labels: app=mysql + Containers: + mysql: + Image: mysql:5.6 + Port: 3306/TCP + Environment: + MYSQL_ROOT_PASSWORD: password + Mounts: + /var/lib/mysql from mysql-persistent-storage (rw) + Volumes: + mysql-persistent-storage: + Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) + ClaimName: mysql-pv-claim + ReadOnly: false + Conditions: + Type Status Reason + ---- ------ ------ + Available False MinimumReplicasUnavailable + Progressing True ReplicaSetUpdated + OldReplicaSets: + NewReplicaSet: mysql-63082529 (1/1 replicas created) + Events: + FirstSeen LastSeen Count From SubobjectPath Type Reason Message + --------- -------- ----- ---- ------------- -------- ------ ------- + 33s 33s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set mysql-63082529 to 1 + ``` 1. 디플로이먼트로 생성된 파드를 나열한다. + ```shell + kubectl get pods -l app=mysql + ``` - kubectl get pods -l app=mysql - - 출력은 다음과 유사하다. - - NAME READY STATUS RESTARTS AGE - mysql-63082529-2z3ki 1/1 Running 0 3m + 출력은 다음과 유사하다. + ``` + NAME READY STATUS RESTARTS AGE + mysql-63082529-2z3ki 1/1 Running 0 3m + ``` 1. 퍼시스턴트볼륨클레임을 살펴본다. + ```shell + kubectl describe pvc mysql-pv-claim + ``` - kubectl describe pvc mysql-pv-claim + 출력은 다음과 유사하다. - 출력은 다음과 유사하다. - - Name: mysql-pv-claim - Namespace: default - StorageClass: - Status: Bound - Volume: mysql-pv-volume - Labels: - Annotations: pv.kubernetes.io/bind-completed=yes - pv.kubernetes.io/bound-by-controller=yes - Capacity: 20Gi - Access Modes: RWO - Events: + ``` + Name: mysql-pv-claim + Namespace: default + StorageClass: + Status: Bound + Volume: mysql-pv-volume + Labels: + Annotations: pv.kubernetes.io/bind-completed=yes + pv.kubernetes.io/bound-by-controller=yes + Capacity: 20Gi + Access Modes: RWO + Events: + ``` ## MySQL 인스턴스 접근하기 @@ -140,7 +137,7 @@ MySQL을 실행하고 퍼시스턴트볼륨클레임을 참조하는 디플로 서버에 접속하기 위하여 MySQL 클라이언트를 실행한다. -``` +```shell kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword ``` @@ -161,11 +158,11 @@ mysql> 이미지나 다른 부분을 변경할 수 있다. 스테이트풀 애플리케이션과 관련하여 몇 가지 주의 사항이 있다. -* 애플리케이션을 스케일링하지 않는다. 이 설정은 단일 인스턴스 애플리케이션 전용이다. +- 애플리케이션을 스케일링하지 않는다. 이 설정은 단일 인스턴스 애플리케이션 전용이다. 기본적인 퍼시스턴트볼륨은 하나의 파드에서만 마운트할 수 있다. 클러스터 형태의 스테이트풀 애플리케이션에 대해서는 [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/)을 보자. -* 디플로이먼트 구성 YAML 파일에서 `strategy:` +- 디플로이먼트 구성 YAML 파일에서 `strategy:` `type: Recreate` 를 사용한다. 이는 쿠버네티스가 롤링 업데이트를 사용하지 _않도록_ 지시한다. 동시에 두 개 이상의 파드를 생성할 수 없으므로, 롤링 업데이트는 일어나지 않게 된다. `Recreate` 전략을 사용하면 @@ -175,7 +172,7 @@ mysql> 이름으로 배포된 오브젝트를 삭제한다. -``` +```shell kubectl delete deployment,svc mysql kubectl delete pvc mysql-pv-claim kubectl delete pv mysql-pv-volume @@ -188,20 +185,12 @@ kubectl delete pv mysql-pv-volume 일부 동적 프로비저너(EBS 와 PD와 같은)는 퍼시스턴트볼륨을 삭제할 때에 기본 리소스도 해제한다. - - - ## {{% heading "whatsnext" %}} +- [디플로이먼트 오브젝트](/ko/docs/concepts/workloads/controllers/deployment/)에 대해 더 배워 보기 -* [디플로이먼트 오브젝트](/ko/docs/concepts/workloads/controllers/deployment/)에 대해 더 배워 보기 - -* [애플리케이션 배포하기](/ko/docs/tasks/run-application/run-stateless-application-deployment/)에 대해 더 배워보기 - -* [kubectl run 문서](/docs/reference/generated/kubectl/kubectl-commands/#run) - -* [볼륨](/ko/docs/concepts/storage/volumes/)과 [퍼시스턴트 볼륨](/ko/docs/concepts/storage/persistent-volumes/) - - +- [애플리케이션 배포하기](/ko/docs/tasks/run-application/run-stateless-application-deployment/)에 대해 더 배워보기 +- [kubectl run 문서](/docs/reference/generated/kubectl/kubectl-commands/#run) +- [볼륨](/ko/docs/concepts/storage/volumes/)과 [퍼시스턴트 볼륨](/ko/docs/concepts/storage/persistent-volumes/) \ No newline at end of file diff --git a/content/ko/docs/tasks/run-application/run-stateless-application-deployment.md b/content/ko/docs/tasks/run-application/run-stateless-application-deployment.md index a8a103396b..a6df1a9847 100644 --- a/content/ko/docs/tasks/run-application/run-stateless-application-deployment.md +++ b/content/ko/docs/tasks/run-application/run-stateless-application-deployment.md @@ -9,27 +9,16 @@ weight: 10 이 페이지에서는 쿠버네티스 디플로이먼트 오브젝트를 사용하여 애플리케이션을 실행하는 방법을 설명한다. - - - ## {{% heading "objectives" %}} - -* nginx 디플로이먼트 생성하기 -* kubectl을 사용하여 디플로이먼트 정보 나열하기 -* 디플로이먼트 업데이트하기 - - - +- nginx 디플로이먼트 생성하기 +- kubectl을 사용하여 디플로이먼트 정보 나열하기 +- 디플로이먼트 업데이트하기 ## {{% heading "prerequisites" %}} - {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} - - - ## nginx 디플로이먼트 생성하고 탐색하기 @@ -40,60 +29,63 @@ nginx:1.14.2 도커 이미지를 실행하는 디플로이먼트에 대한 명 {{% codenew file="application/deployment.yaml" %}} - 1. YAML 파일을 기반으로 디플로이먼트를 생성한다. - - kubectl apply -f https://k8s.io/examples/application/deployment.yaml - + ```shell + kubectl apply -f https://k8s.io/examples/application/deployment.yaml + ``` 1. 디플로이먼트에 대한 정보를 살펴본다. + ```shell + kubectl describe deployment nginx-deployment + ``` - kubectl describe deployment nginx-deployment - - 출력은 다음과 유사하다. - - Name: nginx-deployment - Namespace: default - CreationTimestamp: Tue, 30 Aug 2016 18:11:37 -0700 - Labels: app=nginx - Annotations: deployment.kubernetes.io/revision=1 - Selector: app=nginx - Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable - StrategyType: RollingUpdate - MinReadySeconds: 0 - RollingUpdateStrategy: 1 max unavailable, 1 max surge - Pod Template: - Labels: app=nginx - Containers: - nginx: - Image: nginx:1.14.2 - Port: 80/TCP - Environment: - Mounts: - Volumes: - Conditions: - Type Status Reason - ---- ------ ------ - Available True MinimumReplicasAvailable - Progressing True NewReplicaSetAvailable - OldReplicaSets: - NewReplicaSet: nginx-deployment-1771418926 (2/2 replicas created) - No events. + 출력은 다음과 유사하다. + ``` + Name: nginx-deployment + Namespace: default + CreationTimestamp: Tue, 30 Aug 2016 18:11:37 -0700 + Labels: app=nginx + Annotations: deployment.kubernetes.io/revision=1 + Selector: app=nginx + Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable + StrategyType: RollingUpdate + MinReadySeconds: 0 + RollingUpdateStrategy: 1 max unavailable, 1 max surge + Pod Template: + Labels: app=nginx + Containers: + nginx: + Image: nginx:1.14.2 + Port: 80/TCP + Environment: + Mounts: + Volumes: + Conditions: + Type Status Reason + ---- ------ ------ + Available True MinimumReplicasAvailable + Progressing True NewReplicaSetAvailable + OldReplicaSets: + NewReplicaSet: nginx-deployment-1771418926 (2/2 replicas created) + No events. + ``` 1. 디플로이먼트에 의해 생성된 파드를 나열한다. + ```shell + kubectl get pods -l app=nginx + ``` - kubectl get pods -l app=nginx - - 출력은 다음과 유사하다. - - NAME READY STATUS RESTARTS AGE - nginx-deployment-1771418926-7o5ns 1/1 Running 0 16h - nginx-deployment-1771418926-r18az 1/1 Running 0 16h + 출력은 다음과 유사하다. + ``` + NAME READY STATUS RESTARTS AGE + nginx-deployment-1771418926-7o5ns 1/1 Running 0 16h + nginx-deployment-1771418926-r18az 1/1 Running 0 16h + ``` 1. 파드에 대한 정보를 살펴본다. - - kubectl describe pod - - ``은 파드 중 하나의 이름이다. + ```shell + kubectl describe pod + ``` + ``은 파드 중 하나의 이름이다. ## 디플로이먼트 업데이트하기 @@ -103,13 +95,13 @@ nginx 1.16.1을 사용하도록 디플로이먼트를 업데이트해야 함을 {{% codenew file="application/deployment-update.yaml" %}} 1. 새 YAML 파일을 적용한다. - - kubectl apply -f https://k8s.io/examples/application/deployment-update.yaml - + ```shell + kubectl apply -f https://k8s.io/examples/application/deployment-update.yaml + ``` 1. 디플로이먼트가 새 이름으로 파드를 생성하고 이전 파드를 삭제하는 것을 확인한다. - - kubectl get pods -l app=nginx - + ```shell + kubectl get pods -l app=nginx + ``` ## 레플리카 수를 늘려 애플리케이션 확장하기 새 YAML 파일을 적용하여 디플로이먼트의 파드 수를 늘릴 수 있다. @@ -119,27 +111,29 @@ nginx 1.16.1을 사용하도록 디플로이먼트를 업데이트해야 함을 {{% codenew file="application/deployment-scale.yaml" %}} 1. 새 YAML 파일을 적용한다. - - kubectl apply -f https://k8s.io/examples/application/deployment-scale.yaml - + ```shell + kubectl apply -f https://k8s.io/examples/application/deployment-scale.yaml + ``` 1. 디플로이먼트에 4개의 파드가 있는지 확인한다. + ```shell + kubectl get pods -l app=nginx + ``` - kubectl get pods -l app=nginx - - 출력은 다음과 유사하다. - - NAME READY STATUS RESTARTS AGE - nginx-deployment-148880595-4zdqq 1/1 Running 0 25s - nginx-deployment-148880595-6zgi1 1/1 Running 0 25s - nginx-deployment-148880595-fxcez 1/1 Running 0 2m - nginx-deployment-148880595-rwovn 1/1 Running 0 2m + 출력은 다음과 유사하다. + ``` + NAME READY STATUS RESTARTS AGE + nginx-deployment-148880595-4zdqq 1/1 Running 0 25s + nginx-deployment-148880595-6zgi1 1/1 Running 0 25s + nginx-deployment-148880595-fxcez 1/1 Running 0 2m + nginx-deployment-148880595-rwovn 1/1 Running 0 2m + ``` ## 디플로이먼트 삭제하기 이름으로 디플로이먼트를 삭제한다. - - kubectl delete deployment nginx-deployment - + ```shell + kubectl delete deployment nginx-deployment + ``` ## ReplicationControllers -- 예전 방식 애플리케이션을 복제하여 생성하는 기본적인 방법은 내부적으로 레플리카셋(ReplicaSet)을 활용하는 디플로이먼트를 @@ -147,14 +141,6 @@ nginx 1.16.1을 사용하도록 디플로이먼트를 업데이트해야 함을 [레플리케이션컨트롤러(ReplicationController)](/ko/docs/concepts/workloads/controllers/replicationcontroller/)를 사용하여 복제 애플리케이션을 구성했었다. - - - ## {{% heading "whatsnext" %}} - -* [디플로이먼트 오브젝트](/ko/docs/concepts/workloads/controllers/deployment/)에 대해 더 배워보기 - - - - +- [디플로이먼트 오브젝트](/ko/docs/concepts/workloads/controllers/deployment/)에 대해 더 배워보기 diff --git a/content/ko/docs/tasks/run-application/scale-stateful-set.md b/content/ko/docs/tasks/run-application/scale-stateful-set.md index 26da727f33..b5753aa451 100644 --- a/content/ko/docs/tasks/run-application/scale-stateful-set.md +++ b/content/ko/docs/tasks/run-application/scale-stateful-set.md @@ -13,22 +13,21 @@ weight: 50 --- -이 작업은 스테이트풀셋을 확장하는 방법을 보여준다. 스테이트풀셋 확장은 레플리카 수를 늘리거나 줄이는 것을 의미한다. - +이 작업은 스테이트풀셋을 확장하는 방법을 보여준다. 스테이트풀셋 확장은 레플리카 수를 +늘리거나 줄이는 것을 의미한다. ## {{% heading "prerequisites" %}} - -* 스테이트풀셋은 쿠버네티스 버전 1.5 이상에서만 사용할 수 있다. +- 스테이트풀셋은 쿠버네티스 버전 1.5 이상에서만 사용할 수 있다. 쿠버네티스 버전을 확인하려면 `kubectl version`을 실행한다. -* 모든 스테이트풀 애플리케이션이 제대로 확장되는 것은 아니다. 스테이트풀셋을 확장할지 여부가 확실하지 않은 경우에 자세한 내용은 [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/) 또는 [스테이트풀셋 튜토리얼](/ko/docs/tutorials/stateful-application/basic-stateful-set/)을 참조한다. +- 모든 스테이트풀 애플리케이션이 제대로 확장되는 것은 아니다. 스테이트풀셋을 확장할지 + 여부가 확실하지 않은 경우에 자세한 내용은 [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/) + 또는 [스테이트풀셋 튜토리얼](/ko/docs/tutorials/stateful-application/basic-stateful-set/)을 참조한다. -* 스테이트풀 애플리케이션 클러스터가 완전히 정상이라고 확신할 때만 +- 스테이트풀 애플리케이션 클러스터가 완전히 정상이라고 확신할 때만 확장을 수행해야 한다. - - ## 스테이트풀셋 확장하기 @@ -49,7 +48,9 @@ kubectl scale statefulsets --replicas= ### 스테이트풀셋 인플레이스(in-place) 업데이트 -대안으로 스테이트풀셋에 [인플레이스 업데이트](/ko/docs/concepts/cluster-administration/manage-deployment/#in-place-updates-of-resources)를 수행할 수 있다. +대안으로 스테이트풀셋에 +[인플레이스 업데이트](/ko/docs/concepts/cluster-administration/manage-deployment/#in-place-updates-of-resources)를 +수행할 수 있다. 스테이트풀셋이 처음에 `kubectl apply`로 생성된 경우, 스테이트풀셋 매니페스트의 `.spec.replicas`를 업데이트한 다음 `kubectl apply`를 수행한다. @@ -74,10 +75,12 @@ kubectl patch statefulsets -p '{"spec":{"replicas": 1인 경우 쿠버네티스는 비정상 파드의 원인을 결정할 수 없다. 영구적인 오류 또는 일시적인 오류의 결과일 수 있다. 일시적인 오류는 업그레이드 또는 유지 관리에 필요한 재시작으로 인해 발생할 수 있다. +spec.replicas > 1인 경우 쿠버네티스는 비정상 파드의 원인을 결정할 수 없다. +영구적인 오류 또는 일시적인 오류의 결과일 수 있다. 일시적인 오류는 +업그레이드 또는 유지 관리에 필요한 재시작으로 인해 발생할 수 있다. 영구적인 오류로 인해 파드가 비정상인 경우 오류를 수정하지 않고 확장하면 스테이트풀셋 멤버십이 올바르게 작동하는 데 필요한 @@ -90,11 +93,6 @@ spec.replicas > 1인 경우 쿠버네티스는 비정상 파드의 원인을 결 애플리케이션 수준에서 확장 작업에 대해 추론하고 스테이트풀 애플리케이션 클러스터가 완전히 정상이라고 확신할 때만 확장을 수행하는 것이 좋다. - - ## {{% heading "whatsnext" %}} - -* [스테이트풀셋 삭제하기](/ko/docs/tasks/run-application/delete-stateful-set/)에 대해 더 배워보기 - - +- [스테이트풀셋 삭제하기](/ko/docs/tasks/run-application/delete-stateful-set/)에 대해 더 배워보기