[ArgoCD] App-of-Apps 패턴
App-of-Apps
App들을 관리하기 위한 App이라는 의미로, argoCD와 같은 GitOps에서 '상위' App이 다수의 '하위' App들을 묶어서 관리하는 구조
App들 간의 계층을 둔 구조로 보면 된다. 이때, 상위 App을 "Root App"이라 하며, 하위 Application을 포함한 구조를 가진다.
간단하게 보면 계층화된 회사의 구조로 볼 수도 있다. CEO와 각 부서별로 부서장의 관계에서, CEO는 전사 전략을 세우고, 각 부서장들에 세부적인 수행내용을 지시하고, 부서장들은 각자 프론트엔드/백엔드/DB등의 세부적인 본인 부서들을 운영하는 것이다.
아래와 같은 서비스들을 배치하는 쿠버네티스 클러스터를 예로 들어보자.
.
└── deploy
└── kubernetes
├── backtest # 각 하위 서비스 들의 쿠버네티스 컴포넌트
│ ├── deployment.yml
│ └── service.yml
├── news
│ ├── README.md
│ ├── backup.sql
│ ├── cronjob.yml
│ ├── deployment.yml
│ └── service.yml
├── stocks
│ ├── README.md
│ ├── cronjob.yml
│ ├── deployment.yml
│ └── service.yml
└── ui
├── README.md
├── deployment.yml
├── ingress.yml
└── service.yml
이 경우 각 서비스들의 Application CR을 생성해서 개별적으로 클러스터에 적용시켜 관리할 것이다. 이러면 설정이 명확하고 단순하고 각 Application 별로 독립된 syncPolicy같은 자동화 설정을 적용할 수 있게 된다.
하지만, 새로 서비스를 추가하면 Application CR을 작성해서 수동으로 `kubectl apply` 해줘야하는 번거로움이 생기고, 그 과정에서 휴먼 에러가 발생해서 만약 CR 내의 자동화 설정을 빠뜨리면 그 부분은 수동으로 남게 된다는 이슈가 발생한다.
이제 이에 대해 아래와 같이 App-of-Apps 구조를 적용해본다
.
└── deploy
└── kubernetes
├── root-app.yml # Root App
├── apps # 하위 App들의 Application CR
│ ├── backtest-app.yml
│ ├── news-app.yml
│ ├── stocks-app.yml
│ └── ui-app.yml
├── backtest # 각 하위 서비스 들의 쿠버네티스 컴포넌트
│ ├── deployment.yml
│ └── service.yml
├── news
│ ├── README.md
│ ├── backup.sql
│ ├── cronjob.yml
│ ├── deployment.yml
│ └── service.yml
├── stocks
│ ├── README.md
│ ├── cronjob.yml
│ ├── deployment.yml
│ └── service.yml
└── ui
├── README.md
├── deployment.yml
├── ingress.yml
└── service.yml
이 구조에 따르면, root-app.yml에는 Root App의 Application 리소스를 정의하고, apps 디렉토리에는 App-of-Apps를 위한 나머지 하위 App들의 Application 리소스가 담겨있다.
그리고 나머지 디렉토리(backtest,news,stocks,ui)에는 각 서비스들의 쿠버네티스 리소스를 담아주는 것을 볼 수 있다.
먼저, Root App의 Application 리소스는 아래와 같다.
# App-of-apps 패턴을 위한 root app -> 나머지 서비스들을 하위로 관리
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argo
spec:
project: default
source:
repoURL: https://github.com/omoknooni/KubeStock.git
targetRevision: main
path: deploy/kubernetes/apps
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true
회사의 CEO로서, 각 부서장들을 관리하기 위해 묶은 임원급 단체 채팅방(Root Application)을 생성하는 것이다.
즉, 하위 App들의 Application 리소스가 정의된 'apps' 디렉토리를 path로 지정하며, 그 안에 존재하는 Application CR 파일들을 인식해서 하나의 Application으로 묶게 되는 것이다.
그리고 각 하위 App의 Application CR은 아래와 같다.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: ui-app
namespace: argo
spec:
project: default
source:
repoURL: https://github.com/omoknooni/KubeStock.git
targetRevision: main
path: deploy/kubernetes/ui
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true
각 부서별 부서장이 부서 내 지시를 위해 부서별 채팅방(하위 서비스 별 Application)을 개설하는 것이다.
각 서비스별 쿠버네티스 리소스가 디렉토리를 바라보며, 이들을 묶은 서비스 Application을 생성한다.
App-of-Apps 패턴을 채용하며 아래와 같은 이점들을 얻을 수 있다.
- 모듈화와 재사용
- 각 App들이 독립적으로 분리(모두 동일한 repo거나 분리된 repo)되어서 관리할 수 있다.
- 앱 확장성
- 새로운 App을 추가하는 상황에서도 Root app에 지정된 하위 App 경로 상에 새로 추가만 해주면서 쉽게 확장할 수 있다.
- 앞선 예시에서 서비스를 추가하려면, 새 서비스의 Application CR을 작성해서 apps 디렉토리에 배치만 해주면, Root App이 변경을 감지해서 동기화해준다.
- 즉, 별도의 kubectl 작업없이 커밋만으로도 확장할 수 있다는 점
- 관리 정책의 일관성
- Root App에서 적용한 정책(syncPolicy 등)을 하위 App에서도 동일하게 적용해서 일관성을 챙길 수 있다.
- 하위 Application CR에서 자동화 관련 정책을 누락해도, Root app의 정책을 상속받아 적용한다.