인사이트

인사이트리포트

디지털프렌스포메이션 최신 정보 및 트렌드를 제공합니다.

클라우드 플랫폼

스프링 클라우드(Spring cloud)를 활용한 클라우드 네이티브 애플리케이션 개발

2021.03.31하태준
다운로드

스프링 프레임워크(Spring Framework)는 오늘날 자바(Java) 기반 웹 애플리케이션 개발의 표준으로 인식되고 있다. 스프링 프레임워크를 기반으로 한 다수의 상용 프레임워크가 출시되었고 스프링과 함께 많은 발전을 이뤄냈다. 이같은 상황에서 스프링 프로젝트는 보다 향상된 개발 환경을 위한 스프링 부트(Spring boot), 보안 및 인증 모듈 등을 추가하였고 새로운 기술을 지원하고자 다양한 서브 프로젝트를 개발해오고 있다.

이제 클라우드가 시대적 대세라는 사실에 이견을 제시하는 사람은 없을 것이다. 스프링 역시 이같은 변화에 맞춰 스프링 클라우드(Spring cloud)라는 서브 프로젝트를 만들어 발전시키고 있다. 스프링은 영리하게도 모든 것을 자신이 직접 개발하기보다는 오픈소스의 개념에 맞게 이미 발전하고 있는 다른 모듈과 스프링을 연계하는 것에 많은 관심을 기울이고 있다.

본 아티클에서는 스프링 클라우드가 어떻게 클라우드 네이티브(Cloud native)한 프로그램 개발을 지원하는지에 대해 알아보겠다.

 

클라우드 네이티브 애플리케이션

먼저 클라우드 네이티브 애플리케이션에 대해서 간략하게 살펴보자.

 

12 요소 앱
클라우드 네이티브를 이해하기 위해서는 먼저 클라우드 환경에서 실행하는 SaaS(Software as a service) 애플리케이션의 특징을 알아야 한다. 잘 만들어진 SaaS 애플리케이션은 아래의 특징을 가지고 있다.

  • 설정 자동화 절차(Declarative)를 체계화 하여 새로운 개발자가 프로젝트에 참여하는데 드는 시간과 비용을 최소화한다.
  • OS에 따라 달라지는 부분을 명확히 하고 실행 환경 사이의 이식성을 극대화 한다.
  • 최근 등장한 클라우드 플랫폼에 적합하고 서버와 시스템의 관리가 필요 없다.
  • 개발 환경과 운영 환경의 차이를 최소화하고 민첩성을 극대화하기 위해 지속적인 배포가 가능하다.
  • 툴, 아키텍처 및 개발 방식을 크게 바꾸지 않고 확장(Scale up) 할 수 있다.

 

잘만들어진 SaaS 어플리케이션은 핸드폰 노트북 데스크탑 등 다양한 디바이스에 손쉬운 확장이 가능해야 합니다.

 

이와 같은 애플리케이션을 만들기 위해 웹 애플리케이션 개발 PaaS 사업자인 헤로쿠(Heroku)社의 엔지니어들은 12 요소 앱(Twelve-Factor App)이라는 SaaS 앱 개발 방법론을 정의했다. 이를 기반으로 개발하면 시간이 지나면서 앱이 유기적으로 성장할 수 있다. 12 요소 앱의 주요 내용은 다음과 같다. (보다 자세한 사항은 https://12factor.net에서 확인할 수 있다.)

 

1. 코트 베이스 : 버전 관리되는 하나의 코드 베이스와 다양한 배포| 어플리케이션당 하나의 코드 베이스만 존재하고 이를 CI/CD를 통해서 다양한 환경에 배포한다., 2. 종속성 : 명사적으로 선언되고 분리된 종속성| 메이븐과 같은 종속성 관리 도구를 사용한다., 3. 설정 : 환경에 저장된 설정| 설정과 코드를 명시적으로 분리하여 실행 환경에 맞는 설정으로 유연하게 변경이 가능해야 한다., 4. 백엔드 서비스 : 백엔드 서비스를 연결된 리소스를 취급| 네트웍을 통해서 사용하는 외부의 서비스를리소스로 간주한다. 설정 시스템에 저장된 값을 읽어 해당 리소스에 접근하도록 한다., 5. 빌드·릴리즈·실행 : 철저하게 분리한 빌드와 실행 단계| 클라우드에서 연산은 상태가 없어야 한다., 6. 프로세스 : 애플리케이션을 하나 또는 여러 개의 상태가 없는 프로세스로 실행| 클라우드에서 연산은 상태가 없어야한다., 7. 포트 바인딩 : 포트 바인딩을 사용해 서비스 공개| 앱은 독립적이여야 한다. 실행 환경에 대한 런타임 인젝션에 의존하지 않는다. 각 서비스는 HTTP 환경으로 제공되며 API를 통해서만 접근한다. 데이터는 공요하지 않는다., 8. 동시성: 프로세스 모델을 사용한 확장| 확장과 자원 사용량 개선을 위해서 각 서비스와 함수는 독립적이고 수평적으로 동작한다., 9. 폐기 기능 : 빠른 시작과 그레이스풀 셧다운을 통한 안정성 극대화| 개별 프로세스들은 쉡게 종료할 수 있고 빠른 시작 시간을 제공한다., 10. 개발·운영 환경 일치: 개발, 스테이징, 실서비스 환경을 최대한 비슷하게 유지| 각각의 환경 차이를 줄임으로써 지속적인 배포가 가능하도록 지원한다., 11. 로그 : 로그를 이벤트 스트림으로 취급| 분산 시스템에서 로그를 관리하는 것은 중요하다. 개별 앱들은 이를 관리하지 않고 외부 시스템으로 전달하기만 한다., 12. Admin 프로세스 : Admin-Maintenance 작업을 일회성 프로세스로 실행| 관리를 위한 코드와 작업을 분리하지 않고 동일한 환경에서 배포·실행한다.

 

물론 이런 규칙이 클라우드 네이티브 애플리케이션과 완전히 일치하지는 않는다. 이후로도 계속해서 개발, 발전이 진행되었기 때문이다. 그럼에도 불구하고 이는 클라우드 네이티브의 기반이 되는 원칙으로 여전히 고려해야 할 요소인 것은 분명하다.

 

CNCF(Cloud Native Computing Foundation)
IaaS(Infrastructure as a service) 와 PaaS(Platform as a service) 환경으로 넘어오면서 소프트웨어 개발은 많은 방식으로 변화했다. 위의 12 요소 앱에서 설명했듯이 수평적으로 확장 가능하고, 프로세스 단위로 분리하여 독립성을 유지하며, 쉽게 종료하고 다시 생성할 수 있어야 한다. 이런 변화의 핵심은 클라우드이다. 도커(Docker), 컨테이너(Container), 컨테이너 오케스트레이션(Container orchestration), 이런 용어들이 어느새 우리에게 익숙해졌다. 그만큼 빠르게 발전하는 분야에서 표준화를 위해 노력하는 단체들이 있고 그 중 가장 유명한 곳이 CNCF이다.

CNCF는 다양한 클라우드 네이티브 애플리케이션 개발에 도움을 주기 위해 아키텍처를 제안하고 관련된 영역을 정의하며 개별 영역에서 유효한 제품과 기술을 소개하고 있다. (CNCF Cloud Native Interactive Landscape) 그리고 이를 좀 더 쉽게 가이드 하기 위해 다음과 같은 CNCF 트레일 맵을 제공한다.

 

CLOUD NATIVE TRAIL MAP, HElP ALONG THE WAY | A.Traing and Certification, B. Consulting Help, C. Join CNCF's End User Community | 1. Containerization, 2. CI/CD, 3. Orchestration & Application Definition, 4. Observability & Analysis, 5. Service proxy / Discovery / & Mesh, 6. Networking / Policy / & Security, 7. Distributed DATABASE & Storage, 8. Streaming & Messaging, 9. Container registry & Runtime, 10. Software distribution

 

위의 트레일 맵을 보면 12 요소 앱에서 설명한 기술에 클라우드가 필요로 하는 기술이 포함된 것을 확인할 수 있다.

 

 

스프링 클라우드

앞서 클라우드 네이티브 어플리케이션에 필요한 기술을 살펴봤다. 이어서 스프링 클라우드에서 위의 요소들을 어떻게 지원하는지, 또한 어떤 외부 제품을 연계하여 개발을 진행할 수 있는지 설명하겠다.

분산∙버전 설정(Spring cloud config)
애플리케이션이 동작할 때 설정 파일을 읽어서 처리하는 것은 매우 일반적이다. 만약 이런 설정이 없다면 ‘개발∙운영 환경 일치’라는 요소를 만족하기 어려워질 것이다. 대부분의 경우 설정 파일은 바이너리와 함께 배포되며 환경 혹은 실행 옵션으로 실제 값이 선택된다. 그러나 클라우드 환경에서 마이크로 서비스를 지원하는 경우 환경 자체의 값들이 자유롭게 변경∙처리될 수 있어야 한다. 즉 중앙 저장소에서 모든 설정 값을 관리하고 개별 서비스는 설정 값을 해당 저장소에 문의하여 가져와야 한다.

스프링 클라우드 Config는 ‘외부화 된 구성(Cofnig)’에 대해 서버 및 클라이언트측 지원을 제공한다. 기본적으로 설정은 키-값(Key-value)의 쌍으로 되어 있고 필요시 암호화도 할 수 있다.

 

서비스 등록 및 조회
기존 환경에서는 특정 서비스가 다른 서비스를 호출해야 하는 경우 ‘어디에’ ‘어떻게’ 호출하는지를 명확히 알고 있다. 하지만 클라우드 환경에서는 ‘어디’가 실시간으로 변경되고 ‘어떻게’ 역시 자유롭게 바뀔 수 있다. 여기서 ‘어디에’에 대한 부분이 바로 서비스 등록 및 조회이다. 각각의 서비스는 중앙 저장소에 자신의 정보와 제공하는 ‘서비스의 이름’을 등록한다. 서비스 내에서 다른 서비스를 호출할 때는 이 서비스 이름으로 ‘어디에’ 문의해야 할지 정보를 가져와서 호출하게 된다. 바로 위에서 설명한 ‘분산∙버전 설정’과 매우 유사하다. 서비스 이름이 키가 되고 호출 위치가 값이 되는 것이다. 따라서 설정에 대한 정보 처리와 서비스 정보 처리를 모두 제공하는 제품도 많이 있다.

이런 서비스 등록 및 조회 기능은 다양한 솔루션에서 지원한다 스프링 클라우드는 Spring cloud Netflix(Eureka), Spring cloud Consul(Hashicorp’s Consul), Spring cloud Zookeeper(Apache Zookeeper)의 프로젝트에서 개별 솔루션과의 연동을 지원한다. 물론 이런 솔루션이 단순히 키-값의 정보만을 제공하는 건 아니고 복제, 고가용성 등의 다른 기능도 가지고 있다. 각자의 운영 환경에 적합한 프로젝트를 선택하여 활용하면 된다.

 

라우팅
라우팅은 특정 네트워크 내부에서 목적지를 찾아가는 과정을 의미한다. 이 때 사용되는 것이 API 게이트웨이(API Gateway)이다. API 게이트웨이는 원래 다양한 네트워크를 사용하는 모듈 사이에서 중계와 필요한 변환 및 추가 처리 작업을 하는 모듈을 의미한다. 즉 API 게이트웨이를 사용해서 라우팅을 하는 것이다. API 게이트웨이는 외부에 노출하는 포인트를 하나로 만들어 관리가 편해지고 인증 혹은 SSL 처리를 담당하여 게이트웨이 내부의 모듈을 더 간단하게 만들 수 있도록 도와준다. 아울러 필요한 경우 필터를 추가할 수 있다.
스프링 클라우드는 Spring cloud Netflix(Zuul)를 지원하고 내부 프로젝트인 Spring cloud Gateway 또한 제공하고 있다.

 

서비스 간 호출
마이크로 서비스 환경에서 서비스 간 호출은 매우 빈번하게 발생한다. 위의 API 게이트웨이를 활용해 작업을 수행할 수 있지만 신뢰할 수 있는 내부망에서 SSL, 필터링 처리 등 불필요한 부하가 발생한다. 또한 이러한 호출은 일대일 호출과 일대다 호출로 구분할 수 있다. 일대일 호출의 경우 직접 서비스 주소를 찾아서 호출하거나 클라이언트 사이드 부하 분산 솔루션인 리본(Ribbon)을 활용하는 것이 일반적이다. 일대다 호출의 경우 다시 설명할 분산 메시징을 활용할 수 있다.
스프링 클라우드는 Spring cloud Netflix(Ribbon)를 지원한다.

 

부하 분산
클라우드 환경에서는 동일한 서비스를 처리하는 인스턴스가 많을 수 있다. 이 중에서 적합한 인스턴스로 호출하는 것, 그리고 부하를 분산시키는 것은 중요하다. API 게이트웨이나 클라이언트 사이드 부하 분산 솔루션은 다양한 알고리즘으로 이를 지원한다. 리본을 예로 들면 기본적인 라운드 로빈(Round Robin) 이외에 평균 응답 시간을 기록해서 활용하는 방법, 현재 연결된 서비스 수를 받아서 활용하는 방법 등이 있다.
리본 외에도 스프링은 클라이언트의 부하 분산을 위한 모듈을 제공한다. 스프링 클라우드 로드 밸런서(Load balancer)인데 리본에서 발생했던 단점과 사용성이 개선되었다.

 

스프링 클라우드 클라이언트의 부하 분산을 위한 로드 밸런서 모듈을 제공한다.

 

서킷 브레이커(Circuit Breakers)
지금까지 서비스 간 커뮤니케이션을 쉽고 빠르게 할 수 있는 방법에 대해서 알아보았다. 중요한 요소 중 하나는 장애 발생 시 이를 회피하는 방법이다. 동일한 서비스를 제공하는 여러 인스턴스 중 하나에서 장애가 발생할 경우 해당 인스턴스에 계속 요청을 보내 타임아웃(Timeout)까지 기다리는 것은 전체 시스템에 부하를 주게 된다. 따라서 장애가 발생한 인스턴스로 가는 요청을 ‘중단’시킬 필요가 있다. 서킷 브레이커가 그런 역할을 한다. 리본이나 주울(Zuul) 모두 이런 기능을 갖추고 있다.

 

Global locks, Leadership election and Cluster state
클라우드 네이티브 환경에서 특정 리소스에 하나의 모듈만 접근해야 하는 경우가 종종 발생할 수 있다. 이 때 필요한 것이 글로벌 락(Global lock)이다. 해당 리소스에 접근한 모듈이 잠금(Lock)을 생성하고, 이후 접근한 모듈이 잠금 상태라면 대기, 잠금이 없다면 자신이 잠금을 잡는 방식이다. 각각의 인스턴스가 개별로 동작하므로 이런 잠금은 하나의 시스템이 아닌 전체를 대상으로 관리되어야 한다. 그리고 특정 서비스 사이에서 리더(Leader)를 선출하고 관리하는 것도 일반적인 요구 조건이다. 이런 기능은 자세히 보면 키-값 관리 기능의 확장으로 생각할 수 있다. 전체 시스템에서 하나의 키를 이용해 잠금을 관리할 수 있고 리더 역시 특정 키를 조회해 값이 없다면 조회한 모듈이 자신으로 값을 설정하고, 값이 있다면 해당 모듈을 리더로 판단하면 된다. 리더 대체나 잠금 자동 해제 등 실제 서비스는 키-값 관리 기능 외에 추가 기능을 지원한다. 콘술(Consul)이나 주키퍼(Zookeeper) 모두 이런 기능을 제공하고 있다.

 

분산 메시징
앞서 서비스 호출 단계에서 목표한 서비스를 찾아 호출하는 방식에 대해 설명했다. 런데 클라우드 네이티브 애플리케이션에서는 메시지를 이용하는 방식도 자주 사용된다. 예를 들어 배달 서비스를 개발하는 경우 고객의 주문이 완료되면 고객에게 문자로 결과를 보내고, 배달자에게도 같은 내용을 전송하며, 서비스 메인 모듈에도 전달한다. 그리고 필요한 경우 프로모션 담당 모듈에도 메시지 전달할 수 있다. 이렇게 메시지 큐(Message queue)를 이용하거나 게시∙구독 모델을 사용해 분산 메시징을 지원할 수 있다. 세부적으로 들어가면 컨슈머 그룹(Consumer group)을 활용해 중복 처리를 방지하거나 파티셔닝(Partitioning) 기능을 활용할 수 있다.
Spring cloud Stream은 래빗MQ(RabbitMQ), 아파치 카프카(Apache Kafka), 구글 펍섭(Google PubSub) 등의 제품과 연계하여 분산 메시징을 지원한다.

 

 

마치며
지금까지 클라우드 네이티브 애플리케이션을 개발하기 위해 어떤 요소를 고려해야 하는지, 그리고 스프링 클라우드가 어떤 기능을 제공하는지에 대해 알아보았다. 개별 기능은 스프링에서 직접 개발했거나 다른 유용한 제품들과 연계하여 개발자가 애플리케이션을 쉽게 개발할 수 있도록 도와준다. 스프링 클라우드에서 지원한다는 것은 스타터(Starter)를 이용해 쉽게 구성하고, 간단한 설정과 코드 내 어노테이션(Annotation) 만으로 기능을 활용하며, 개발 도중에 다양한 샘플을 이용할 수 있다는 의미이다.

스프링 클라우드가 개발자가 맞닥뜨리는 모든 문제를 해결해 줄 수는 없다. 그러나 스프링 프레임워크가 그러했듯이 스프링 클라우드 역시 꼭 필요한 요소들을 쉽고 빠르게 개발할 수 있도록 도움을 줄 것이다. 그리고 지금까지와 같이 가까운 미래에도 계속해서 발전해나갈 것이다.

 

# References

- https://12factor.net/
- https://landscape.cncf.io/
- https://github.com/cncf/trailmap
- https://spring.io/projects/spring-cloud
- https://spring.io/blog/2020/03/25/spring-tips-spring-cloud-loadbalancer
- 클라우드 네이티브, 보리스 숄 외 저/정원천 역, 한빛미디어, 2020년 6월
- 마스터링 스프링 클라우드, 피요트르 민코프스키 저/김민석 역, 위키북스, 2018년 11월

하태준 프로

하태준 프로

에스코어(주) 소프트웨어사업부 개발플랫폼그룹

클라우드와 Spring cloud에 관심이 많은 개발자입니다. 현재 Anyframe 개발 및 유지보수를 담당하고 있습니다.

연관 아티클

  • 오픈소스 SW2022.09.26

    Kaniko로 docker 없이 컨테이너 이미지 빌드하기

    자세히 보기
  • SW 테크놀로지2022.09.22

    우리는 왜 웹 환경에서 Noto Sans를 사용하는가?

    자세히 보기
  • SW 테크놀로지2022.09.07

    SaaS 도입과 활용의 Governance

    자세히 보기