# 22장. 애플리케이션 구성
이 책 전반에 걸쳐 쿠버네티스 기반 애플리케이션의 구성 요소를 살펴봤다.
- 프로그램을 컨테이너화
- 컨테이너를 파드로 배치
- 파드를 레플리카셋으로 복제
- 디플로이먼트를 통해 롤아웃
- 상태 저장과 실제 애플리케이션을 분산 시스템으로 배포
22장은 애플리케이션을 구성하는 컨피규레이션을 어떻게 배치, 공유, 관리, 업데이트할 수 있을까를 다룬다.
## 알아야 할 원칙
쿠버네티스에서 클라우드 네이티브 애플리케이션을 개발할 때 적용하는
신뢰성과 민첩성(agility)의 목표에 부합하는 구조를 설계하기 위한 원칙은 아래와 같다.
- 신뢰성 있는 원천 데이터로서의 파일 시스템을 취급
- 변경에 대한 품질을 보장하기 위한 코드 리뷰 수행
- 단계적 roll forward 및 roll back을 위한 기능 플래그 사용
### 신뢰성 있는 원천 데이터로서의 파일 시스템
YAML 객체의 파일 시스템을 신뢰성 있는 원천 데이터(Source of Truth)로 보아야한다.
쿠버네티스 클러스터에 배포된 API 객체는 신뢰성 있는 파일 시스템 원천 데이터를 반영한 결과다.
이것이 올바른 과점인 이유는 아래와 같다.
1. 클러스터를 불변 인프라(immutable infrastructure)로 취급할 수 있다.
변경 가능한 인프라는 배포에 따라 동작이 달라질 수 있다.
2. 파일 시스템을 통해 여러 팀 구성원과 쉽게 협업할 수 있다.
소스 컨트롤 시스템을 통해 동시 편집에 따른 충돌을 해결할 수 있다.
### 코드 리뷰의 역할
코드 리뷰는 고품질의 안정적인 코드를 생산할 수 있는 모범 사례다.
대부분의 서비스 중단은 오타나 기타 간단한 실수와 같은 예기치 못한 상황으로 인해 발생한다.
두 사람 이상이 컨피규레이션 변경을 확인할 경우 오류 가능성이 크게 줄어든다.
원천 데이터 파일 집합에 병합할(merge) 모든 변경 사항을 리뷰해야 한다.
### 피처 게이트
feature gate는 새로운 기능이 추가되는 경우 개발이 완료되기 전까지 테스트할 수 있게 활성화/비활성화하는 데 사용하는 것이다.
제어는 feature flag를 통해 가능하다.
```c
if (featureFlags.myFlag) {
// 여기서부터 피처 구현체 작성
}
```
피처 게이트 사용의 장점은 아래와 같다.
1. 기능을 제공할 준비가 되기 훨씬 전에운영 환경의 브랜치에 코드를 커밋할 수 있다.
오랜 시간 유지되는 브랜치 병합 시 발생할 수 있는 충돌을 피할 수 있다.
2. 새로운 기능 사용을 위해 컨피규레이션 변경만 수행하면 된다.
운영 환경에서 변경 사항을 명확하게 알 수 있으며, 문제 발생 시 롤백이 간단하다.
디버깅을 단순화할 수 있고 기능 비활성화 시 버그 수정 등이 포함된 최신 버전 코드 전체를 롤백할 필요가 없다.
## 소스 컨트롤에서의 애플리케이션 관리
파일 시스템에 파일을 실제로 배치하는 방법을 살펴본다.
파일 시스템의 계층적 디렉터리 구조와 소스 컨트롤 시스템의 태그와 브랜치 개념을 활용한다.
### 파일 시스템 레이아웃
애플리케이션을 특정한 구조로 체계화하려는 주된 이유는 의미 있는 구성 요소 또는 계층으로 나누기 위함이다.
파일 시스템의 계층적 디렉터리 구조를 통해 아래와 같이 활용할 수 있다.
```sh
/frontend
frontend-deployment.yaml
frontend-service.yaml
frontend-ingress.yaml
/service-1
service-1-deployment.yaml
service-1-service.yaml
service-1-ingress.yaml
/service-2
service-2-deployment.yaml
service-2-service.yaml
service-2-ingress.yaml
```
### 정기 버전 관리
장기적 릴리스 관리를 위해서는 배포의 예전 모습을 되돌아볼 수 있는 것이 유용하다.
따라서 여러 컨피규레이션의 버전을 동시에 저장하고 유지 관리하는 것이 편리하다.
이를 위한 두 가지 방식은 아래와 같다.
1. 태그, 브랜치, 소스 컨트롤의 기능을 사용
2. 파일을 복제 해 다른 개정판의 디렉터리를 사용
#### 브랜치와 태그를 사용한 버전 관리
브랜치와 태그를 사용해 컨피규레이션 리비전을 관리하는 경우 디렉터리 구조는 버전별 디렉터리를 따로 관리하지 않는다.
소스 컨트롤의 HEAD가 계속하며 변경된다.
릴리스 컨피규레이션을 업데이르하려면 HEAD에 변경 내용을 커밋하고, 새로운 브랜치 및 태그를 생성하면 된다.
원하는 변경 사항을 릴리스 브랜치로 체리픽(cherry-pick)하고 새로운 태그를 부여할 수도 있다.
롤백을 고려하면 hot fix와 같은 커밋은 필요한 모든 릴리스 태그에 체리픽을 해두어야한다.
```{figure} /images/kuar/ch22/cherry-pick.png
:alt: image
:width: 440px
cherry pick
```
#### 디렉터리를 사용한 버전 관리
이 방법에서는 버전이 지정된 각 디플로이먼트가 자체 디렉터리 내에 존재한다.
모든 배포는 특정 리비전이나 태그가 아닌 동일 HEAD에서 발생한다.
새로운 릴리스를 생성할 때는 current 디렉터리를 복사해 업데이트한다.
버그 수정 사항이 반영될 때 pull request는 모든 릴리스 디렉터리에서 YAML 파일을 수정해 진행한다.
```sh
/frontend
v1/
frontend-deployment.yaml
frontend-service.yaml
frontend-ingress.yaml
current/
frontend-deployment.yaml
frontend-service.yaml
frontend-ingress.yaml
/service-1
v1/
service-1-deployment.yaml
service-1-service.yaml
service-1-ingress.yaml
v2/
service-1-deployment.yaml
service-1-service.yaml
service-1-ingress.yaml
current/
service-1-deployment.yaml
service-1-service.yaml
service-1-ingress.yaml
```
## 개발, 테스트, 배포를 위한 애플리케이션 구조화
분산 애플리케이션을 신속하게 변경 및 테스트하고 변경 사항을 안전하게 배포하기 위한 구조화를 알아본다.
### 목표
개발 및 테스트 목표는 아래와 같다.
1. 각 개발자가 애플리케이션의 새로운 기능을 쉽게 개발할 수 있어야 한다.
개발자는 자신의 환경에서 작업할 대 모든 서비스를 사용할 수 있어야 한다.
2. 배포 전에 애플리케이션을 쉽고 정확하게 테스트할 수 있어야 한다.
높은 신뢰성을 유지하면서 빠른 기능 롤아웃에 있어 필수적이다.
### 릴리스 진행
릴리스가 나가기 까지의 단계는 아래와 같이 구분할 수 있다.