2023. 2. 21. 13:51ㆍjava
모놀리스 애플리케이션에서 마이크로 서비스로 전환

- 모놀리스 애플리케이션
- 전체가 하나의 운영체제 프로세스로 실행되기 때문에 하나의 개체로 개발, 배포, 관리된다.
- 하나의 변경 사항을 적용하기 위해 전체를 다시 빌드/테스트/배포 해야한다.
- 애플리케이션 확장이 어렵다.
이러한 문제로
모놀리스 애플리케이션을 마이크로 서비스라는 독립적으로 배포할 수 있는 작은 구성 요소로 분할했다.
- 마이크로 서비스
- 각 마이크로 서비스는 독립적인 프로세스로 실행되며 api로 또 다른 마이크로 서비스와 통신한다.
- 새로 추가되거나 변경 사항이 있는 서비스만 빠르게 빌드/테스트/배포가 가능하다.
- 리소스가 더 필요한 서비스만 별도로 확장 가능하다.
[문제 상황 1] 마이크로 서비스의 단점 : 종속성의 충돌

마이크로 서비스 아키텍쳐의 구성 요소는 독립적인 방식으로 개발된다.
각 구성 요소를 개발하는 별도의 팀이 있는 것이 일반적인데
각각의 개발자가 자신의 노트북으로 애플리케이션은 개발 중인 상황을 떠올려보자.
각각의 어플리케이션은 서로 다른 라이브러리, 종속성 및 파일에 의존하고 있으며,
동시에 회사는 자체 설정과 지원 파일 세트에 준하여 표준화된 개발 및 프로덕션 환경을 갖추고 있다.
이때, 서버 환경을 재구축하는 부가적인 작업 없이 가능한 한 로컬에서 이러한 환경을 에뮬레이션하려고 한다. 그렇다면 이러한 환경 전체에서 애플리케이션이 작동되게 하고, 품질 검사를 통과하고, 큰 문제나 수정 없이 애플리케이션을 배포할 수 있을까?
동일한 호스트에 배포해야하는 구성 요소 수가 많을 수록 모든 종속성을 관리하기 매우 어려워진다.
[문제 상황 2] 일관된 환경의 중요성 : 개발, 프로덕션 환경
개발, 배포하는 구성 요소의 수에 상관없이, 개발팀과 운영팀이 해결해야 하는 큰 문제가 있다.
애플리케이션을 실행하는 환경이 매번 다르다는 것이다.
개발자의 로컬 환경에서는 잘 운영되던 코드가
운영팀이 운영하는 프로덕션 환경에서는 오류가 생길 수도 있다.
프로덕션 환경에서만 나타나는 문제를 줄이기 위해
애플리케이션 개발과 프로덕션이 정확히 동일한 환경에서 실행돼
운영체제, 라이브러리, 시스템 구성, 네트워킹 환경 등 모든 것이 동일한 환경으로 만들어야 한다.
[문제 상황 3] 개발자와 시스템 관리자의 동상이몽
- 개발자와 시스템 관리자의 공통 목표
고객이 성공적으로 실행할 수 있는 애플리케이션을 제공하는 것 - 개발자는
새로운 기능을 만들고 사용자 경험 향상에 중요도를 둔다. - 시스템 운영자는
개발자에게 우선순위가 낮은 시스템 보안, 사용률과 같은 측면에 중요도를 둔다.
해답은 쿠버네티스
앞서 언급한 문제 상황을
쿠버네티스가 어떻게 해결해주는지 살펴보자!🔍
컨테이너 소개 📦
컨테이너의 개요
[문제 상황 1] 마이크로 서비스의 단점! 에서
한 호스트에 마이크로 서비스 애플리케이션을 개발한다고 가정할 때,
구성 요소의 구성(라이브러리 버전 등)은 다를 수 있다는 종속성 차이에 대해 언급했다.
이에 대한 답은 바로 '컨테이너'를 사용하는 것이다.
애플리케이션을 실행하는 컨테이너는 각각의 필수 라이브러리, 종속 요소와 파일을 사용하므로
문제없이 원활하게 애플리케이션을 프로덕션으로 진행할 수 있다.
뿐만 아니라 이식성, 구성 가능성, 격리가 필요한 경우 리눅스 컨테이너를 다양한 문제에 적용할 수 있다.
컨테이너는 동일한 호스트 시스템에서
동시에 서로 다른 환경을 만들어주어 가상머신과 유사하게 격리한다.
하지만 가상머신보다 오버헤드가 훨씬 적은 기술이다.
컨테이너와 가상머신 비교

주요 차이점 | 단일 하드웨어 시스템에서 여러 운영 체제가 동시에 실행될 수 있도록 한다. | 호스트 OS에서 실행되는 커널을 공유하고, 동일한 커널에서 시스템 콜을 수행한다. |
동일한 하드웨어에서 실행할 수 있는 구성요소 양 비교 | 적다. 구성요소 프로세스 뿐만 아니라 시스템 프로세스를 실행하기 때문에 추가 컴퓨팅 리소스가 필요하기 때문이다. | 많다. 컨테이너는 모두 동일한 OS에서 실행되기 때문에 오버헤드가 낮기 때문이다. |
격리 수준 비교 | 가상머신은 자체 리눅스 커널을 실행하기 때문에 호스트와 완전한 격리를 제공한다. | 컨테이너는 동일한 OS의 커널을 호출함으로 완전한 격리를 제공하지 않는다. 따라서 보안 위험이 발생할 가능성이 있다. |
컨테이너 격리를 가능하게 하는 매커니즘
컨테이너는 동일한 호스트의 OS를 공유하고 있는데, 어떤 매커니즘으로 격리를 제공하고 있을까?
⑴ namespace
각 프로세스가 시스템(파일, 프로세스, 네트워크 인터페이스, 호스트 이름 등)에 대한 독립적인 뷰만 볼 수 있도록 한다.
현재 리눅스 커널에서는 다음 6가지 namespace를 지원하고 있다:
- mnt (파일시스템 마운트): 호스트 파일시스템에 구애받지 않고 독립적으로 파일시스템을 마운트하거나 언마운트 가능
- pid (프로세스): 독립적인 프로세스 공간을 할당
- net (네트워크): namespace간에 network 충돌 방지 (중복 포트 바인딩 등)
- ipc (SystemV IPC): 프로세스간의 독립적인 통신통로 할당
- uts (hostname): 독립적인 hostname 할당
- user (UID): 독립적인 사용자 할당
기본적으로 리눅스 시스템에 하나의 네임스페이스가 있다.
그러나 추가 네임 스페이스를 생성하고 구성할 수 있다.
프로세스를 실행할 때 네임스페이스 중 하나에서 프로세스를 실행한다.
(프로세스는 하나의 네임스페이스에만 속하는 것이 아니라 여러 네임스페이스에 속할 수도 있다.)
⑵ cgroups
프로세스가 사용할 수 있는 리소스의 양을 제한하게 해주는 리눅스의 기능이다.
cgroups는 다음 리소스를 제어할 수 있다:
- 메모리
- CPU
- I/O
- 네트워크
- device 노드(/dev/)
프로세스는 설정된 양 이상의 리소스를 사용할 수 없다.
이런 방식으로 프로세스는 다른 프로세스 용으로 설정된(예약해 놓은) 리소스를 사용할 수 없으며
이는 프로세스가 별도의 시스템에서 실행될 때와 비슷하다.
Docker
도커는 애플리케이션을 패키징, 배포, 실행하기 위한 플랫폼이다.
애플리케이션에 필요한 전체 환경을 패키지화 하여,
중앙 저장소로 전송할 수 있으며,
도커를 실행하는 모든 컴퓨터에서 사용할 수 있다.
이러한 도커의 세가지 주요 개념은 다음과 같다.
- 이미지 : 애플리케이션과 해당 환경을 패키지화 한 것이다.
- 레지스트리 : 이미지를 저장하고, 공유할 수 있는 저장소이다.
- 컨테이너 : 도커 기반 컨테이너 이미지에서 생성된 리눅스 컨테이너로, 호스트에서 실행되는 프로세스이지만 격리돼 있다. 프로세스는 cgroups로 리소스 양이 제한되어 있으므로 할당된 양만 사용 가능하다.
쿠버네티스 소개 ⚙️
결론적으로 쿠버네티스가 해결해주는것은 무엇일까?
- [문제 상황 3] 개발자와 시스템 관리자의 동상이몽
개발자는 기능 개발을,
시스템 관리자는 보안과 같은사용률과 같은 측면에 중요도를 둔다고 했었다.
- 쿠버네티스를 이용하면
개발자는 특정 인프라 관련 서비스를 애플리케이션에 구현하지 않아도 된다.
따라서 실제 기능을 개발하는 것에만 집중할 수 있다. - 또한 시스템 관리자는 쿠버네티스가 애플리케이션을 재배치하고 조합함으로 리소스를 훨씬 더 효율적으로 이용할 수 있게 된다.
뿐만아니라 고장 난 노드를 자동으로 처리하도록 함으로써 따라서 운영팀은 더 편하게 잠을 잘 수 있다...ㅎ
쿠버네티스 핵심
우선 쿠버네티스의 핵심적인 구조와 워크 플로우에 대해서만 정리했다.
쿠버네티스는 컨테이너화된 애플리케이션을 쉽게 배포하고 관리할 수 있게 해주는 소프트웨어 시스템이다.

다음 그림은 쿠버네티스의 구조이다.
크게 마스터 노드와 워커노드로 구성된다.
- 마스터 노드 : 전체 쿠버네티스 시스템을 제어하고 관리하는 쿠버네티스 컨트롤 플레인을 실행
- 워커 노드 : 실제 배포되는 컨테이너 애플리케이션을 실행
큰 워크 플로우는
개발자가 애플리케이션 매니페스트를 작성
➡️ 매니페스트를 마스터 노드에 배포
➡️ 쿠버네티는 해당 애플리케이션을 워커 노드 클러스터에 배포한다.
구조를 더 자세히 살펴 보자.

컨트롤 플레인
- 마스터 노드가 실행시킨다.
- 클러스터를 제어하고 작동시킨다.
- 구성요소
- kube-apiserver : K8S API를 노출하는 컨트롤 플레인의 프론트엔드
- etcd : 클러스터의 모든 데이터를 보관하는 일관성, 고가용성을 보장하는 키-값 저장소
어떤 노드가 존재하고 클러스터에 어떤 리소스가 존재하는지와 같은 정보
- kube-scheduler : 새로운 POD 생성을 감지하고, 실행시킬 워커 노드를 선택하는 역할
- kube-controller-manager : 디플로이먼트 같은 리소스 컨트롤러를 관리. API 서버를 통해 클러스터의 공유된 상태를 감지하고, 현재 상태를 원하는 상태로 이행하는 컨트롤 루프를 관리
- cloud-controller-manager : 클라우드 업체와 연동하여 로드 밸런서나 디스크 볼륨 같은 자원을 관리
이 컨트롤 플레인의 구성요소는 클러 스터 상태를 유지하고 제어하지만 애플리케이션을 실행시키지는 않는다.
노드
워커 노드는 컨테이너화 된 애플리케이션을 실행하는 시스템이다.
- kubelet : 각 노드에서 실행되는 에이전트, 컨테이너 런타임을 관리하고 상태를 모니터링, POD에서 컨테이너가 확실하게 동작하도록 관리
- kube-proxy : 각 노드에서 실행되는 네트워크 프록시. Service 개념의 구현부. 서로 다른 노드에 있는 POD 간 통신이나 POD와 인터넷 사이의 네트워크 트래픽을 라우팅
- 컨테이너 런타임 : 테이너를 시작하고, 중지. 대표적으로 Docker
출처
- 책 - Kubernetes in action
- https://velog.io/@cclare/%EB%AA%A8%EB%86%80%EB%A6%AC%EC%8B%9D-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4
- https://kubernetes.io/ko/docs/concepts/overview/what-is-kubernetes/
- https://www.redhat.com/ko/topics/containers/whats-a-linux-container
- https://tech.ssut.me/what-even-is-a-container/
- https://bcho.tistory.com/1256
'java' 카테고리의 다른 글
CI/CD 개념 , Gitops introduction (0) | 2023.02.21 |
---|---|
Test a REST API with Java (0) | 2023.02.10 |
전자정부 클라우드 플랫폼 - MSA 템플릿 실행환경 (0) | 2023.02.09 |
[Java] 중복 키 허용 MultiValueMap 와 HashMap 차이 (0) | 2023.01.18 |
(고민중) 한글문서 썸네일파일 만들기 (0) | 2023.01.13 |