모놀리식 앱을 모듈화하고 컨테이너화하는 방법을 안내하는 학습 과정의 두 번째 튜토리얼입니다.
학습 과정은 다음 튜토리얼로 구성됩니다.
- 개요
- 모놀리식 이해
- 모놀리식 모듈화(이 튜토리얼)
- 컨테이너화를 위한 모듈식 앱 준비
- 모듈식 앱 컨테이너화
- GKE 클러스터에 앱 배포
이전 튜토리얼인 모놀리식 이해하기에서는 Cymbal Books라는 모놀리식 앱에 대해 알아봤습니다. 로컬 머신에서 모놀리식을 실행해 보고 모놀리식의 여러 부분이 엔드포인트를 통해 서로 통신한다는 사실을 배웠습니다.
이 튜토리얼에서는 모놀리식 애플리케이션을 컨테이너화할 수 있도록 여러 모듈로 분리하는 방법을 살펴봅니다. 코드가 이미 업데이트되었으므로 모듈화 단계를 직접 수행할 필요는 없습니다. 튜토리얼을 따라 저장소에서 앱의 모듈식 버전을 살펴보고 원래 모놀리식과 어떻게 다른지 확인해 보겠습니다.
비용
이 튜토리얼을 무료로 완료할 수 있습니다. 하지만 이 시리즈의 마지막 튜토리얼에 나온 단계를 수행하면Trusted Cloud by S3NS 계정에 비용이 청구됩니다. GKE를 사용 설정하고 Cymbal Books 앱을 GKE 클러스터에 배포하면 비용이 청구되기 시작합니다. 이 비용에는 가격 책정 페이지에 설명된 대로 GKE의 클러스터당 요금과 Compute Engine VM 실행 요금이 포함됩니다.
불필요한 요금이 청구되지 않도록 이 튜토리얼을 완료한 후 GKE를 중지하거나 프로젝트를 삭제하세요.
시작하기 전에
이 튜토리얼을 시작하기 전에 첫 번째 튜토리얼인 모놀리식 이해하기를 완료해야 합니다. 이 튜토리얼에서는 Cymbal Books 앱의 모듈화된 버전을 로컬 머신에서 실행합니다. 이를 위해서는 이미 환경을 설정한 상태여야 합니다. 첫 번째 튜토리얼을 이미 완료했다면 GitHub 저장소를 클론한 상태입니다. Cymbal Books 앱의 세 가지 버전은 모두 해당 저장소의 다음 폴더에 있습니다.
monolith/
modular/
containerized/
계속하기 전에 이러한 폴더가 머신에 있는지 확인합니다. 또한 가상 환경 book-review-env
가 활성 상태인지 확인합니다. 활성화 방법을 다시 확인하려면 첫 번째 튜토리얼의 가상 환경 만들기 및 활성화를 참조하세요. 환경을 활성화하면 모듈 버전의 앱을 실행하는 데 필요한 모든 것이 갖춰지게 됩니다.
모듈화란?
이 튜토리얼에서는 모놀리식 앱을 컨테이너화할 수 있도록 모듈화하는 방법을 알아봅니다. 모듈화는 모놀리식을 모듈식 앱으로 전환하는 프로세스입니다. 이전 튜토리얼에서 배웠듯이 모놀리식의 특징은 구성요소를 독립적으로 실행하거나 확장할 수 없다는 점입니다. 모듈식 앱은 다릅니다. 기능이 독립적으로 실행하고 확장할 수 있는 모듈로 분할됩니다.
모듈화와 컨테이너화는 실무에서 종종 함께 수행되지만 이 튜토리얼 시리즈에서는 각 개념을 명확히 이해할 수 있도록 별도의 단계로 다룹니다. 이 튜토리얼에서는 모놀리식 앱을 모듈화하는 방법을 설명하며, 이후 튜토리얼에서는 모듈화된 앱을 컨테이너화하는 방법을 다룹니다.
점진적 모듈화
프로덕션 환경에서는 일반적으로 한 번에 하나의 구성요소만 모듈화합니다. 구성요소를 모듈화하고 모듈을 모놀리식과 통합하며 다음 구성요소를 작업하기 전에 모두 정상적으로 작동하는지 확인합니다. 일부 구성요소는 모듈화되고 다른 구성요소는 모놀리식의 일부로 남아 있는 이 하이브리드 상태를 마이크로리스(microlith)라고 합니다. 하지만 이 튜토리얼에서는 앱의 모든 구성요소가 한 번에 모듈화되어 있어, 앱을 모듈화하는 전체 과정을 예시로 보여줍니다.
모놀리식을 모듈화하는 방법
이 섹션에서는 Cymbal Books 모놀리식 앱이 어떻게 여러 개의 모듈로 분리되었는지 알아봅니다. 자체 앱에 적용할 수 있도록 모듈화 프로세스를 이해하는 데 도움이 되는 단계가 제공됩니다. 다만, 이 튜토리얼에서는 클론한 저장소에 이미 모듈화된 버전의 앱이 포함되어 있기 때문에 직접 해당 단계를 수행할 필요가 없습니다.
앱의 고유한 기능 식별
Cymbal Books 모놀리식을 모듈화하는 첫 번째 단계는 기본 기능을 식별하는 것입니다. Cymbal Books 샘플 애플리케이션의 경우 모놀리식에 다음과 같은 네 가지 고유한 기능이 있습니다.
- 홈페이지 제공
- 도서 세부정보 제공
- 도서 리뷰 제공
- 책 표지 이미지 제공
모듈 만들기
이전 튜토리얼에서 본 것처럼 모놀리식은 이전 섹션에서 식별된 네 가지 기능을 경로 핸들러로 구현하는 단일 Flask 앱입니다. 앱을 모듈화하려면 각 경로 핸들러를 가져와 자체 Flask 앱에 배치합니다. 경로 핸들러가 4개인 Flask 앱 1개가 아니라 각 앱에 경로 핸들러가 1개씩 있는 Flask 앱 4개를 얻게 됩니다.
다음 다이어그램은 단일 Flask 앱이 4개의 개별 Flask 앱으로 분리되는 과정을 보여줍니다.
모듈식 앱에서 각 Flask 앱은 독립적으로 실행되며 다이어그램과 같이 다른 포트(8080, 8081, 8082, 8083)에서 리슨합니다. 이렇게 설정하는 이유는, 이 튜토리얼의 뒷부분에서 모듈화된 앱을 테스트할 때 모든 모듈을 같은 머신에서 실행하게 되기 때문입니다. 충돌을 방지하려면 각 앱이 서로 다른 포트 번호를 사용해야 합니다.
홈페이지 모듈은 두 가지 역할을 수행합니다. 첫째, 홈페이지를 제공합니다. 둘째, 다른 모듈과 통신하여 웹페이지에 표시할 데이터를 수집합니다. 다른 각 모듈은 리뷰, 세부정보 또는 이미지를 제공하는 단일 기능에 중점을 둡니다. 이 모듈은 서로 직접 통신하지 않으며 오직 홈페이지 모듈에서 들어오는 요청에만 응답합니다.
홈페이지 모듈에 추가 조정 역할이 있지만 다른 모듈에 영향을 주지 않고 모듈을 업데이트할 수 있으므로 이 앱은 여전히 모듈식입니다. 단일 대규모 Flask 애플리케이션이 각각 특정 부분의 애플리케이션 기능을 처리하는 4개의 요소로 분할되었습니다.
모듈 간 통신 사용 설정
모듈을 생성한 다음 단계는, 모듈 간에 통신이 가능하도록 설정하는 것입니다. Cymbal Books 앱에서는 이러한 통신 로직이 이미 구현되어 있습니다. 다운로드한 코드의 modular/
폴더를 보면, 홈페이지, 도서 세부정보, 리뷰, 이미지 제공과 같은 앱의 각 주요 기능들이 각각 별도의 Flask 앱으로 구현되어 있는 것을 확인할 수 있습니다. 각 앱은 자체 HTTP 엔드포인트를 정의하고 있으며, 모듈은 이러한 엔드포인트에 HTTP 요청을 보내는 방식으로 서로 통신합니다.
Cymbal Books 모놀리식 앱의 모듈화는 비교적 단순했습니다. 이 모놀리식 앱은 명확하게 정의된 구성요소들로 이루어져 있고, 각 구성요소는 경로 핸들러로 구현되어 있으며, 각 경로 핸들러에는 명확하게 정의된 엔드포인트가 포함됩니다. 이러한 경로 핸들러를 개별 Flask 애플리케이션으로 분리하더라도, 각 핸들러는 엔드포인트를 통해 계속 통신할 수 있습니다. 경로 핸들러를 별도의 Flask 앱에 배치하는 간단한 작업으로 모듈이 생성되고 모듈이 서로 통신할 수 있게 됩니다.
모듈 간 통신에서 일반적으로 사용되는 방법은 모듈이 서로 HTTP 요청을 주고받을 수 있도록 REST API를 구현하는 것입니다. Cymbal Books 앱에서도 이와 같은 방식으로 작동합니다. 각 모듈은 Flask의 기본 제공 도구를 사용해 REST 엔드포인트를 정의합니다. 또 다른 인기 있는 접근 방식은 모듈이 서로의 기능을 직접 호출할 수 있는 gRPC입니다.
Cymbal Books에서 통신이 간단한 이유
모듈화된 앱의 각 모듈은 개별 Flask 애플리케이션으로, 웹 서버 내부에서 실행됩니다. 예를 들어 홈페이지 모듈은 홈페이지를 제공하고, 도서 세부정보 모듈은 도서 세부정보를 제공합니다. 웹 서버는 HTTP 요청과 응답을 처리하도록 설계되었으므로 모듈 간의 통신이 간단합니다. 각 모듈은 데이터를 요청받을 수 있도록 엔드포인트를 외부에 노출합니다.
각 모듈에 필요한 데이터에 대한 액세스 권한만 부여
모놀리식 앱을 올바르게 모듈화하려면, 각 모듈이 자신에게 필요한 데이터에만 액세스할 수 있도록 해야 합니다. 데이터 격리라고 불리는 이 원칙은 진정한 모듈형 아키텍처를 구현하는 데 있어 핵심 요소입니다.
모듈화를 진행할 때 자주 발생하는 실수 중 하나는, 여러 모듈이 단일 데이터베이스와 같은 동일한 데이터에 액세스하도록 허용하는 것입니다. 이러한 방식은 다음과 같은 문제를 일으킬 수 있습니다.
- 긴밀한 결합: 공유 데이터의 구조가 변경되면(예: 데이터베이스 테이블 이름이 변경되거나 열이 추가됨) 이 데이터를 사용하는 모든 모듈을 업데이트해야 합니다. 적절한 모듈화를 통해 이 문제를 방지할 수 있습니다.
- 내결함성 문제: 여러 모듈에서 동일한 데이터 소스를 사용하는 경우 하나의 모듈에서 발생한 런타임 오류(예: 잘못된 쿼리 또는 과도한 트래픽)로 인해 다른 모듈이 중단될 수 있습니다. 시스템의 한 부분에서 장애가 발생하면 시스템의 다른 부분으로 장애가 확산될 수 있습니다.
- 성능 병목 현상: 단일 공유 데이터 소스로 인해 병목 현상이 발생할 수 있습니다. 즉, 여러 모듈이 한 데이터 소스와 상호작용하려고 하면 전체 애플리케이션 속도가 느려질 수 있습니다.
이러한 문제를 방지하려면 각 모듈에 자체 데이터 소스가 있어야 합니다.
Cymbal Books에서 데이터베이스를 사용하여 데이터를 저장했다면 데이터베이스를 복제하거나 파티셔닝하여 데이터 격리를 적용하고 각 모듈이 필요한 데이터에만 액세스하도록 해야 합니다. 복제는 각 모듈이 별도의 데이터베이스 복사본을 유지하는 방식이며, 파티셔닝은 특정 테이블이나 행에 대한 액세스를 제한하는 방식입니다. 두 방식 모두 모듈 간 데이터 간섭을 방지하는 데 효과적입니다.
다음 다이어그램에서는 모놀리식 도서 앱 아키텍처와 도서 앱의 모듈식 아키텍처를 비교합니다.
모놀리식의 기능이 단일 data/
디렉터리에 액세스하므로 모놀리식의 구현은 데이터 격리의 원칙을 따르지 않습니다.
반면 모듈식 앱은 데이터를 별도의 디렉터리로 분할하고 각 모듈이 지정된 데이터와만 상호작용하도록 하여 어느 정도의 데이터 격리를 달성합니다.
- 도서 세부정보 모듈은
details_data/
디렉터리에서만 데이터를 가져옵니다. - 도서 리뷰 모듈은
reviews_data/
디렉터리에서만 데이터를 가져옵니다. - 이미지 모듈은
images/
디렉터리에서만 데이터를 가져옵니다.
후속 튜토리얼에서는 앱을 컨테이너화하여 데이터 격리를 더욱 향상하는 방법을 알아봅니다.
용어 설명
소프트웨어 개발 업계에서는 마이크로서비스와 분산 시스템이라는 용어를 자주 접하게 됩니다. 이 섹션에서는 이러한 용어가 Cymbal Books 앱의 모듈화 구현 방식과 어떤 관련이 있는지 설명합니다.
마이크로서비스
마이크로서비스는 특정 작업을 수행하는 자율적인 모듈입니다. 이러한 모듈은 엔드포인트와 같은 인터페이스를 통해 서로 통신합니다.
Cymbal Books의 모듈형 버전에서 각 모듈은 앞서 설명한 마이크로서비스 정의에 부합하므로 마이크로서비스라고 부를 수 있습니다. 후속 튜토리얼에서 모듈식 앱이 컨테이너화되면 컨테이너 내에서 실행되는 코드도 모듈 내에서 실행되는 동일한 코드이므로 마이크로서비스라고 할 수 있습니다.
분산 시스템
분산 시스템은 공통된 목표를 달성하기 위해 네트워크를 통해 통신하는 독립적인 모듈들로 구성됩니다. 이러한 모듈은 서로 다른 머신에서 실행될 수 있지만 , 전체적으로는 하나의 시스템처럼 동작합니다.
Cymbal Books 앱의 모듈형 구조 역시 분산 시스템의 정의에 부합합니다. 각 모듈은 독립적으로 실행되며, HTTP를 통해 데이터를 주고받지만, 전체적으로는 하나의 시스템처럼 동작합니다. 다음 섹션에서는 이해를 돕기 위해 모든 모듈을 하나의 머신에서 실행하지만, 반드시 그래야 할 필요는 없습니다. 각 모듈은 별도의 서버에서 실행될 수도 있으며, 이러한 이유로 Cymbal Books의 모듈형 앱은 분산 시스템으로 분류될 수 있습니다.
모듈화 구현 테스트
이제 Cymbal Books 앱의 모놀리식 구조가 모듈형 구조로 전환되고, 각 모듈이 Flask 앱으로 구성된 것을 확인했으므로, 실제로 애플리케이션을 실행하여 각 모듈이 독립적으로 동작하는지 테스트할 수 있습니다.
이 튜토리얼에서는 모든 모듈을 같은 머신에서 실행합니다. 하지만 각 모듈을 별도의 서버에서 실행할 수도 있습니다. 각 모듈은 자율적으로 동작하며, 다른 모듈의 엔드포인트를 통해 통신할 수 있기 때문입니다.
환경 설정
다음 단계에 따라 테스트를 준비하세요.
터미널에서 클론한 저장소 내의
modular
디렉터리로 이동합니다.cd modular
가상 환경
book-review-env
가 활성 상태인지 확인합니다. 활성화 단계를 다시 확인하려면 가상 환경 만들기 및 활성화를 참조하세요.
Flask 앱 시작
/modular
폴더에는 모든 Flask 애플리케이션을 동시에 시작하는 bash 스크립트가 포함되어 있습니다. 앱의 각 모듈은 8080 또는 8081과 같은 고유한 포트를 리슨합니다.
- 홈페이지 Flask 앱(home.py): 포트 8080
- 도서 세부정보 Flask 앱(book_details.py): 포트 8081
- 책 리뷰 Flask 앱(book_reviews.py): 포트 8082
- 이미지 Flask 앱(images.py): 포트 8083
각 모듈은 동일한 머신에서 실행되기 때문에, 고유한 포트 번호를 리슨해야 합니다. 각 모듈이 서로 다른 서버에서 실행된다면, 모든 모듈이 동일한 포트 번호를 사용해도 포트 충돌이 발생하지 않습니다.
다음 명령어를 사용해 bash 스크립트를 실행하세요.
bash ./start_services.sh
이 스크립트는 시작 문제를 식별하는 데 도움이 되도록 Flask 앱(예: home.py.log
, book_details.py.log
)마다 별도의 로그 파일을 만듭니다.
스크립트가 성공적으로 완료되면 다음 메시지가 표시됩니다.
All services have been started. Access the app at http://localhost:8080/
각 Flask 앱 테스트
브라우저에서 다음 URL을 방문하여 모듈을 테스트합니다.
- 홈페이지:
http://localhost:8080/
은 모듈화된 Cymbal Books 애플리케이션의 홈페이지를 표시합니다. 이 페이지는 다른 모듈에 요청을 보내어 도서 세부정보, 리뷰, 이미지를 가져옵니다. - 도서 세부정보:
http://localhost:8081/book/1
은 ID가 1인 도서의 세부정보를 반환합니다. 이 응답은 JSON 데이터이며 앱에서 형식을 지정하고 인간이 읽을 수 있는 방식으로 표시합니다. - 도서 리뷰:
http://localhost:8082/book/1/reviews
는 ID가 1인 도서의 리뷰를 가져와 반환합니다. 리뷰 데이터는 JSON 형식으로 제공됩니다. 홈페이지 모듈은 이 데이터를 요청하고, 도서 세부정보 페이지에 통합하여 표시합니다. - 이미지:
http://localhost:8083/images/fungi_frontier.jpg
는 Fungi Frontier 도서의 표지 이미지를 제공합니다. URL이 올바르다면, 해당 이미지가 브라우저에서 바로 표시되어야 합니다.
Flask 앱 중지
테스트가 끝나면 다음 명령어를 사용해 모든 Flask 앱을 중지하세요.
kill $(cat home.py.pid book_details.py.pid book_reviews.py.pid images.py.pid)
요약
이 튜토리얼에서는 Cymbal Books 모놀리식 앱을 모듈화하는 방법을 살펴보았습니다. 이 과정은 다음과 같은 단계로 이루어집니다.
- 앱의 고유한 구성요소를 식별합니다.
- 모듈을 만듭니다.
- 각 모듈이 필요한 데이터에만 액세스하도록 보장합니다.
이후, 로컬 머신에서 모듈화된 앱을 테스트해 보았습니다.
다음 단계
다음 튜토리얼인 컨테이너화를 위한 모듈식 앱 준비에서는 localhost
대신 Kubernetes 서비스 이름을 사용하도록 엔드포인트를 업데이트하여 컨테이너화를 위해 모듈식 앱을 준비하는 방법을 알아봅니다.