Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
352 changes: 352 additions & 0 deletions 4_클라우드_네이티브_스프링/14_클라우드_구성_관리.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,352 @@
# 14. 클라우드 구성 관리

Created: 2023년 2월 15일 오후 11:02
Status: 정리완료
최종 편집 일시: 2023년 3월 21일 오후 10:52

스프링 클라우드의 Config Server를 구축하게 되면 모든 마이크로서비스들에 대해 중앙 집중식의 구성을 할 수 있다.

구성 서버를 사용하게 되면 모든 구성을 한 곳에서 관리할 수 있게된다.

# 14.1 구성 공유하기

구성 속성이 런타임 환경을 변경하거나 런타임 환경에 고유한 것이라고 한다면,

해당 구성들은 `자바 시스템 속성` 이나 `운영체제의 환경변수` 를 구성 속성으로 사용하는 것이 좋다.

근데 이 환경변수들로 구성 속성을 사용하게 되면 변경이 된다면 애플리케이션이 다시 시작되어야 한다.

그리고 jar파일 내부에 구성을 포함하는 경우는 해당 속성을 변경하거나 원래 값으로 되돌릴 때 애플리케이션을 다시 빌드하여 배포해야 한다.

애플리케이션을 이 때문에 재배포나 재시작을 하는 것은 너무 불편하다. 이 변경으로 결함이 생길수도 있기 때문이다.

그리고 MSA구성인 경우 모든 서비스 인스턴스에 동일한 변경을 적용하는 것이 불합리적이다.

암호같은 보안에 민감한 값들은 속성값으로 넣어줄 때 물론 암호화를 해주겠지만, 복호화에 대한 코드 자체도 `Configuration` 자바 파일에 설정해주기 마련이다. (ex - jasypt)

그러면서 동시에 구성 속성들을 개발자 조차 접근할 수 없게 하려면 환경변수에 저장하는 방식은 **지양해야 한다.**

> 중앙 집중식으로 구성하면?
>
- 구성이 더 이상 애플리케이션 코드에 패키징되어 배포되지 않는다.
- 애플리케이션을 다시 빌드하거나 배포하지 않고 구성을 변경하거나 값을 되돌릴 수 있다.
- 재시작 하지 않아도 실행 중 구성을 변경할 수 있다.
- 공통적인 구성을 공유하는 마이크로서비스가 자신의 속성 설정으로 유지 관리하지 않고 동일한 속성을 공유할 수 있다.
- 속성 변경은 한곳에서 하나만 변경해도 모든 서비스에 적용시킬 수 있다.
- 보안에 민감한 구성 속성은 별도로 암호화하고 유지관리 할 수 있다.
- 복호화된 속성 값을 언제든지 애플리케이션에서 사용할 수 있기에 코드로 복호화로직을 갖고있을 필요가 없다.

# 14.2 구성 서버 실행하기

스프링 클라우드 구성 서버는 집중화된 구성 데이터 소스를 제공한다.

구성 서버는 다른 서비스들이 구성 속성을 사용할 수 있도록 REST API를 제공한다.

구성 속성값들을 Git과 같은 저장소에 저장을 하여 사용한다.

## 14.2.1 구성 서버 활성화하기

spring cloud version 설정은 예전에 다른것들과 동일하게 설정해주면 된다.

그리고 항상 구성 서버를 활성화시켜주는 annotation이 설정되어야 한다.

`@EnableConfigServer` 를 설정해주자.

![%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-03-18_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_11 21 44](https://user-images.githubusercontent.com/74235102/226675799-61677293-adbc-4758-812c-1ac130c99196.png)

`http://localhost:8080/default/master` 로 실행해주었는데

tacocloud-config를 호출했을 때 결과이다.

api를 호출하는 양식은 다음과 같다.

- 구성 서버의 호스트 이름과 포트
- http://localhost:8080
- 애플리케이션 이름
- spring.application.name 속성
- spring profile
- default
- git 라벨/분기 (생략 가능)
![%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-03-18_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_11 45 54](https://user-images.githubusercontent.com/74235102/226675814-1e038170-8728-423f-ae2f-e5187e0f7aff.png)
- 지정하지 않는다면 main (스프링부트 3.x)

## 14.2.2 Git Repository에 구성 속성 저장하기

가장 기본적이고 쉬운 방법은 root 경로에 applicaiton.properties나 application.yaml 파일을 커밋하는 것

13장에서 유레카 서버를 등록할 때 사용했던 설정을 구성해주면

유레카의 클라이언트를 git에서부터 불러와 설정해줄 수 있다.

### Git 하위 경로로 구성 속성 저장하기

파일 이름만으로 구분하는게 아니라 폴더끼리 완전하게 구분해주고 싶은 경우에 아래의 설정을 진행해주면 된다.

```yaml
spring:
cloud:
config:
server:
git:
uri: http://localhost:8080/tacocloud/tacocloud-config
search-paths: config
```

잘보면 paths로 구성되어 있는데 `,` 로 구분하여 계속해서 디렉토리를 나열해주면 된다.

그래서 여러개를 설정하면 해당 경로 모두에서 속성들을 가져오게 된다.

와일드카드 `*` 도 지원하기에 더 잘 구성할 수 있다.

### Git Repository의 분기나 라벨에 구성 속성 저장하고 제공하기

기본 구성은 main 브랜치에서 구성 속성을 가져온다.

default-label 옵션을 통해 기본 브랜치를 어디로 할 것인지 설정해줄 수 있다.

근데 그냥 지정하지않고 url에서 요청해도 무방하다.

### Git 백엔드를 사용한 인증

Git Repository는 사용자 username과 password 로 인증될 수 있다.

git.username, git.password 속성으로 설정해줄 수있다.

# 14.3 공유되는 구성 데이터 사용하기

중앙 집중식 구성 서버를 제공하는 것에 추가하여 spring cloud config server는 client 라이브러리도 제공한다.

- build.gradle

```groovy
implementation 'org.springframework.cloud:spring-cloud-starter-config'
```

자동 구성으로 설정되면 localhost의 8888 포트에서 실행중인거로 default 포트가 잡혀있는데,

`spring.cloud.config.uri` 속성을 사용하면 구성 서버의 위치를 지정해줄 수 있다.

```groovy
spring:
cloud:
config:
uri: http://config-url:8888
```

해당 속성은 구성 서버의 클라이언트가 되는 애플리케이션 자체에 설정되어야 한다.

중앙에서 컨트롤하는 서버가 있는 경우에는 모든 구성이 이 서버에서 제공되기에 각 마이크로서비스는 자신의 구성을 가질 필요가 없다.

그래서 구성 서버의 위치를 지정하는 `spring.cloud.config.uri` 와 `spring.application.name` 속성만 지정해주면 된다.

### 구성 서버와 레지스트리 중 어느것을 먼저 찾아야 하는지?

- config-server로부터 eureka 서비스 레지스트리를 알아내도록 설정
- 이렇게 되면 각 마이크로서비스에서 서비스 레지스트리의 명세를 갖지 않게 한다.
- 구성 서버를 유레카에 등록한 후 각 마이크로서비스가 구성 서버를 찾게 할 수 있다.
- config-server를 클라이언트로 구성한 후 `spring.cloud.config.discovery.enabled=true` 속성을 구성해주어야 한다.
- 단점 - 마이크로 서비스가 시작될 때 2번 호출을 해야한다.
- 구성서버 찾기위한 유레카호출
- 구성 데이터를 가져오기 위한 구성 서버에 호출

Flow

1. 애플리케이션 시작
2. config-server 클라이언트가 제공하는 속성 소스가 config-server에 속성 값을 요청
3. 응답 받으면 이 속성들을 사용
1. 이 속성들은 캐싱이 되기에 실행이 중단 되더라도 사용할 수 있다.

# 14.4 애플리케이션이나 프로파일에 특정된 속성 제공하기

config-server가 시작될 때 애플리케이션 이름과 활성 profile 모두를 포함하는 요청 경로를 사용하여 서버에 속성을 요청한다.

애플리케이션의 이름은 `spring.application.name` 속성을 설정하여 지정한다.

활성할 프로필 설정은 다 알듯 `spring.profiles.active` 속성을 이용해서 구성할 수 있다.

## 14.4.1 애플리케이션에 특정된 속성 제공하기

마이크로서비스에서 공통적으로 사용하는 속성들을 공통으로 사용할 수 있는게 구성서버가 존재하는 이유인데,

하나의 서비스에만 공유하고 나머지는 공유받지 않아도 되는 속성들이 있다.

이런 경우 spring.application.name 속성값과 동일하게 구성 파일의 이름을 지정하는 방법이 좋다.

특정 서비스에만 적용하고 싶은 경우는 파일이름을 `서비스이름.yml` 로 만들어주면 된다.

공통 속성은 바로 `application.yaml` 로 적용하면 된다.

> 중복된 속성은 애플리케이션에 특정된 속성이 우선값으로 적용된다.
>

## 14.4.2 프로파일로부터 속성 제공하기

- profile에 특정된 `.properties` 나 `.yaml` 파일들을 제공한다.
- 하나의 yaml 파일 내부에 여러 개의 프로파일 구성 그룹을 포함한다.
- `---` 를 추가하고 `spring.profiles` 속성을 지정해주면 된다.

활성프로필을 prd로 한 경우 application.yaml, application-prod.yaml 두개를 모두 반환하는데,

이 때 중복되는 속성이 있다면 application-prod.yaml 의 속성이 우선시된다.

# 14.5 구성 속성들의 보안 유지하기

보안 구성을 사용할 때는 두가지 옵션이 존재한다.

- Git Repository의 구성 파일에 암호화 된 값 사용하기
- Git Repository에 추가하여 config-server의 백엔드 저장소로 해시코프의 Valut 사용하기

## 14.5.1 Git 백엔드의 속성들 암호화하기

암호화되지 않은 값들에 대해서 Git Repository에 저장된 구성 파일에 쓰는 암호화된 값들도 제공할 수 있다.

이것의 핵심은 **암호화 키**이다.

암호화된 속성을 사용하려면 당연히 암호화 키를 사용해서 구성해야 하고, 이는 복호화에 필요하다.

구성 서버는 대칭/비대칭 키 모두 지원하고, 대칭키를 설정하려면 `encrypt.key` 속성에 암,복호화 키 값을 설정해주면 된다.

암호화가 되면 서두에 `{cipher}` 가 붙어있는데 이게 바로 암호화된 값이라는걸 구성 서버에 알려주는 것이다.

구성이 된 후 다시 불러보게 되면 복호화된 값이 들어있게 된다.

→ 여기까지는 jasypt 라이브러리를 사용했을 때 처럼 같은 원리이다.

> 복호화하지 않고 그대로 제공받기를 원한다면?
>

`spring.cloud.config.server.encrypt.enabled=false` 를 구성해주면 된다.

이런 구성일 때에는 받아올 때까진 전부 위에서 설명한것처럼 cipher 가 그대로 넘어오게 되는데,

클라이언트 부분에서 이러한 값을 복호화해주면 된다.

## 14.5.2 Valut에 보안 속성 저장하기

Valut는 보안 관리 도구이다.

### Valut 서버 시작시키기

- 서버 실행이라 스킵

### 보안 데이터를 VALUT에 쓰기

```groovy
vault write secret/application spring.data.mongodb.password=password
```

secret/ 은 Vault 백엔드 서버를 나타낸다.

application은 애플리케이션을 특정할 수 있다.

`,` 뒤부분에 profile을 명시하면 해당 환경의 암호화값을 받아올 수 있다.

spring.profiles.active 속성에 vault를 추가해주면 사용가능하다.

spring.cloud.config.server.valut 내의 속성에 접속정보를 기입하면 valut를 연결할 수 있게 된다.

# 14.6 실시간으로 구성 속성 리프레시하기

일반적인 경우는 애플리케이션을 유지보수 할 때는 애플리케이션을 다시 배포하거나 최소한 다시 시작해야 한다.

근데 이부분을 스프링 클라우드 config 에서는 애플리케이션을 중단시키지 않고 구성 속성들을 refresh 해주는 기능을 제공한다.

- 수동식
- `/actuator/refresh`
- 스프링 액추에이터의 엔트포인트를 활성화
- 해당 엔드포인트로 POST 요청 시 클라이언트가 가장 최근 구성을 백엔드로부터 가져옴
- 자동식
- git repostiory의 commit hook 이 모든 서비스의 리프레시를 촉발할 수 있다.
- 이때는 클라이언트 <> 구성서버 간의 통신을 위한 spring-cloud-bus 프로젝트가 사용된다.

## 14.6.1 구성 속성을 수동으로 리프레시하기

- build.gradle

```groovy
implementation 'org.springframework.boot:spring-boot-starter-actuator'
```

1. 액추에이터 구성을 주입해준다.
2. `/actuator/refresh` 호출
3. 클라이언트에서 값 확인

## 14.6.2 구성 속성을 자동으로 리프레시하기

1. git push
2. git → spring cloud config server 적용
3. spring cloud config server kafka produce
4. 각 서비스 애플리케이션에서 해당 topic message consume

![%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-03-20_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_9 43 18](https://user-images.githubusercontent.com/74235102/226675819-20436e77-b524-4235-be21-dbd2813a39fc.png)
출처 - Spring in Action

### 고려할 사항

1. 메시지 처리에 사용할 수 있는 메시지 브로커가 하나 있어야 한다.
2. WebHook을 Git에 설정해주어야 한다.
3. 모니터 의존성(git webhook 요청처리), rabbitMq, spring cloud stream kafka와 함께 활성화
4. 로컬환경이 아니라면 세부 브로커 연결정보들을 구성서버와 클라이언트에 구성
5. spring-cloud-bus 의존성 추가

### 웹훅 생성하기

- 문서보고 그대로 구성해주면 되기에 스킵

### 구성 서버에서 웹훅 처리하기

- build.gradle

```groovy
implementation 'org.springframework.cloud:spring-cloud-config-monitor'

implementation 'org.springframework.cloud:spring-cloud-starter-stream-rabbit'
implementation 'org.springframework.cloud:spring-cloud-starter-stream-kafka'
```

`/monitor` 엔드포인트를 활성화 시킬 수 있다.

그러면서 동시에 스트림 의존성도 같이 넣어준다.

git webhook은 여러가지 방법으로 받아 처리할 수 있는데, 책에서는 Gogs를 사용했다.

### Gogs 알림 추출기 생성하기

spring cloud config server는 Github, GitLab, Bitbucket 등의 서버 지원 기능이 포함되어있다.

`PropertyPathNotificationExtractor` 를 구현해주면 해당 webhook 추출이 가능하다.

### 구성 서버 클라이언트에 자동 리프레시 활성화하기

```groovy
implementation 'org.springframework.cloud:spring-cloud-starter-bus-amqp'
implementation 'org.springframework.cloud:spring-cloud-starter-bus-kafka'
```

이 의존성 하나를 설정해준다.

이제는 구성이 되었으니 메시지 브로커에 자동으로 바인딩 된다.

(단, rabbitMQ나 Kafka의 접속정보를 설정해주는것은 잊지 말아야 한다.)

# 14.7 구성 서버와 구성 클라이언트 프로젝트의 빌드 및 실행

- 생략

방법은 찾아보진 않았지만 보안상 더 안전하게 만드려면 환경변수로 저장해주는게 낫지 않을까..?

- Github Environments
- K8s environment variable
- nhn forward 18분부터 k8s 로의 config 설정도 볼 수 있다.

[[NHN FORWARD 22] Spring Cloud 기반 MSA 환경을 쿠버네티스로 전환하기](https://www.youtube.com/watch?v=otss__0kf-g&ab_channel=NHNCloud)

# 요약

- 스프링 클라우드 구성 서버는 중앙 집중화된 구성 데이터 소스를 마이크로 서비스 기반의 더 큰 애플리케이션을 구성하는 모든 마이크로서비스에 제공한다.
- 구성 서버가 제공하는 속성들은 Git이나 Valut 리포지토리에서 유지 관리된다.
- 모든 구성 서버 클라이언트에 제공되는 전역 속성들에 추가하여 구성 서버는 프로파일에 특정된 속성과 애플리케이션에 특정된 속성도 제공이 가능하다.
- 보안에 민감한 속성들은 Git Repository에 암호화하여 저장하거나 Valut 백엔드의 보안 속성으로 저장하여 보안유지가 가능하다.
- 구성 서버 클라이언트는 새로운 속성으로 리프레시 할 수 있다.
- 액추에이터 엔드포인트 수동 리프레시
- Spring cloud bus, git webhook 자동 리프레시