README.mdwaffle-world
[K8S] everything in wafflestudio-cluster
wafflestudio-cluster 의 선언적 관리와 GitOps 를 위한 repository 입니다.
cluster 의 현 상태를 정확하고 투명하게 파악하며, 누가 언제 어떤 변경을 적용했는지 기록하는 것을 목표로 합니다.
Structures of Directory
/apps/*
- Argo CD 로 관리하는 서비스 Application 들의 manifest 파일들이 위치합니다. admin 도
kubectl등의 도구로 수동 적용하지 않습니다.- App Of Apps Pattern 을 적용하여, autodeploy-app 에 의해 대부분의 Argo CD Application 이 관리됩니다.
- 대부분 서비스가
/apps/templates/*에 Application 을 정의,/apps/{namespace}/{name}/*에 Application 에 포함될 manifest 파일들을 정의하고 있습니다. (manifest 예시:snutt-prod/snutt-timetable)- autodeploy-app 이 관리하는
/apps/templates/*의 Application 들은mainbranch 의 변경이 Argo CD 에 의해 cluster 에 자동 적용됩니다.
/charts/*
- Helm 으로 관리하는 Chart 들이 정의되어 있습니다. Argo CD, Istio, Prometheus, Grafana 등 일반 서비스보다는 핵심적인 clsuter infra 와 관련되어 있습니다.
- 오픈소스의 Chart 를 바로 사용하지 않고,
dependencies에 이들을 포함한 새로운 Chart 를 정의하고,values.yaml로 필요한 부분을 override 하고 있습니다. (values.yaml예시: argocd)helm install,helm upgrade등의 커맨드로 admin 이 관리합니다.
/misc/*
- admin 이
kubectl로 수동으로 관리하는 manifest 들이 위치합니다. load-balancer-controller, cluster-autoscaler, cert-manager 등 핵심적인 clsuter infra 와 관련되어 있습니다.
/apps/templates/autodeploy-app.yamlRoot AppapiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
namespace: argocd
name: autodeploy-app
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: {{ .Values.spec.source.repoURL }} # https://github.com/wafflestudio/waffle-world.git
targetRevision: HEAD
path: apps # /apps 디렉토리 전체를 감시(재귀)
destination:
# Argo CD가 설치된 클러스터에 배포(In-Cluster 배포)
server: {{ .Values.spec.destination.server }} # https://kubernetes.default.svc
namespace: argocd # 모든 Child App도 argocd 네임스페이스에 배포됨
syncPolicy:
{{- .Values.spec.syncPolicy | toYaml | nindent 4 }}
# syncPolicy:
# automated:
# prune: false # Git에서 리소스가 제거되어도 클러스터에서 삭제 X
# selfHeal: false # 클러스터 상태가 Git과 달라도 자동 복구 X
# syncOptions:
# - Validate=false
/apps/templates/values.yamlautodeploy-app.yaml에서 사용된 value가 정의됨spec:
source:
repoURL: https://github.com/wafflestudio/waffle-world.git
destination:
server: https://kubernetes.default.svc
syncPolicy:
automated:
prune: false
selfHeal: false
syncOptions:
- Validate=false
/charts/argocd/chart.yamlchart.yaml로 의존성을 다운로드한 후 그 결과가 chart.lock에 자동에 기록됨apiVersion: v2
name: argocd
version: 1.2.1
dependencies:
- name: argo-cd
version: 5.46.3
repository: https://argoproj.github.io/argo-helm
/charts/argocd/values.yamlvalues.yaml에 override하여 ArgoCD Chart를 설치app:
metadata:
namespace: argocd
argo-cd:
configs:
cm:
url: https://argocd.wafflestudio.com # ArgoCD의 웹 주소
timeout.reconciliation: 15s
dex.config: | # 로그인 방식(Github)
connectors:
- type: github
id: github
name: GitHub
config:
clientID: fa41a9ad8f42f7e4be31
clientSecret: $dex.github.clientSecret
orgs:
- name: wafflestudio
admin.enabled: false
exec.enabled: true
rbac: # 권한 설정(읽기 전용)
policy.default: role:readonly
policy.csv: | # 팀별 권한 정책을 csv로 정의
g, wafflestudio:waffle-k8s-admin, role:waffle-k8s-admin
p, role:waffle-k8s-admin, applications, *, */*, allow
p, role:waffle-k8s-admin, clusters, get, *, allow
...
params:
server.insecure: true
# 각 컴포넌트가 사용할 CPU, 메모리의 양 설정
server:
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 100m
memory: 128Mi
...
waffle-world/charts/ 내부의 istio-ingressgateway, istio, prometheusargocd 디렉토리와 동일하게 기존 chart를 의존성 + values.yaml로 속성 설정 = ArgoCD에 필요한 Chart를 설치각 Chart 별 설명 by Gemini
- istio: 서비스 메쉬(Service Mesh) 인프라 = "쇼핑몰의 모든 내부 통신망과 보안 시스템"
- 서비스 간의 모든 네트워크 통신을 제어하고 관리하는 플랫폼
- 트래픽 라우팅, 보안, 트래픽과 서비스 상태 추적 및 기록
- istio-ingressgateway: Istio 서비스 메쉬의 공식 트래픽 진입점(Entry Point) = "쇼핑몰의 정문, 안내 데스크"
- 클러스터 외부에서 들어오는 모든 HTTP/HTTPS 트래픽을 가장 먼저 수신하는 로드 밸런서 역할
- 외부 트래픽 수신, 라우팅 규칙에 따라 istio를 거쳐 서비스로 트래픽 전달
- Prometheus: 오픈소스 모니터링 및 경고(Alerting) 시스템 = "쇼핑몰의 중앙 관제실"
- 시스템의 상태를 수집, 저장, 조회하는 모니터링 시스템
- 메트릭 수집, 데이터베이스, 쿼리 및 경고
⇒ 모든 트래픽은 istio-ingressgateway에 도달해 istio를 거쳐 적절한 서비스로 전달됨. 이 모든 정보를 istio가 기록하고, Prometheus가 이 기록을 수집하며 모니터링을 수행
# 트래픽 흐름: 외부 요청 → istio-ingressgateway (수신 및 라우팅) → istio (내부망 제어 및 관리) → 개별 서비스 # 모니터링 데이터 흐름: istio (모든 트래픽 정보 기록/노출) → Prometheus (데이터 수집 및 저장) → 관리자 (조회 및 경고)
.github/CODEOWNERSapps/areyouhere/ @wafflestudio/areyouhere
apps/areyouhere/ 폴더 하위에서 변경이 일어날 경우, @wafflestudio/areyouhere에 속한 사람들이 PR 리뷰어로 자동 할당됨apps/templates/areyouhere-server.yamlapps/values.yaml 값을 그대로 사용apps/areyouhere/areyouhere-server 경로에 있는 배포 설정을 Argo CD가 자동으로 sync# Argo CD 전용 리소스 - GitOps 방식으로 자동 배포를 수행
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
namespace: argocd # Argo CD가 설치된 네임스페이스(argocd)
name: areyouhere-server # Argo CD 웹 UI에서 보일 이름이자, 이 앱을 식별하는 키
finalizers: # 해당 앱을 삭제할 때 관련 리소스도 삭제됨(cascade)
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source: # 어디서 가져올지
repoURL: {{ .Values.spec.source.repoURL }} # Git repo 주소(waffle-world)
targetRevision: HEAD
path: apps/areyouhere/areyouhere-server # Git repo 내부에서 배포용 YAML이 들어있는 경로
destination: # 어디에 배포할지
# Argo CD가 설치된 클러스터에 배포(In-Cluster 배포)
server: {{ .Values.spec.destination.server }} # https://kubernetes.default.svc
namespace: argocd # ArgoCD가 설치된 네임스페이스와 동일
syncPolicy: # 동기화 정책
{{- .Values.spec.syncPolicy | toYaml | nindent 4 }}
# syncPolicy:
# automated:
# prune: false # Git에서 리소스가 제거되어도 클러스터에서 삭제 X
# selfHeal: false # 클러스터 상태가 Git과 달라도 자동 복구 X
# syncOptions:
# - Validate=false
apps/areyouhere/areyouhere-server/areyouhere-server.yamlDeployment, Service, VirtualService 리소스를 정의# Deployment: 앱(Pod)을 배포하는 방식과 버전을 관리해주는 k8s 리소스
apiVersion: apps/v1
kind: Deployment
metadata:
name: areyouhere-server
labels:
app: areyouhere-server # Service, Istio가 사용할 식별 태그
namespace: areyouhere # 배포될 namespace
# spec
spec:
replicas: 1 # Pod 한 개만
selector:
matchLabels:
app: areyouhere-server # label이 app: areyouhere-server인 Pod들을 해당 deployment가 관리
strategy: # 기존 Pod을 하나씩 교체하면서 새 버전으로 롤링 배포
type: RollingUpdate
rollingUpdate: # 무중단 배포용
maxSurge: 25% # 올림 - 기존 replica 수의 25%만큼 새 Pod을 더 생성(1개)
maxUnavailable: 25% # 내림 - 업데이트 중 서비스 불가능한 Pod 수는 전체의 25%까지 허용(0개)
revisionHistoryLimit: 4 # ReplicaSet 버전 중 몇 개를 보관할지 설정
template: # Pod Template
metadata:
labels: # 생성한 pod에 붙는 라벨 -> deployment가 인식, 관리
app: areyouhere-server
spec:
nodeSelector:
phase: dev # dev라는 label이 붙은 노드에만 이 Pod을 배치
# tolerations: 특정 Taint가 있는 노드도 허용 → dev 노드만 타겟팅함을 명시
# taint : 특정 노드에 아무 Pod이나 올라가는 걸 막고,
# 조건을 만족하는 Pod만 허용할 수 있게 해주는 필터링 장치
# "phase=dev" & NoSchedule(키가 일치하지 않으면 절대 올라가지 않음)
tolerations:
- effect: NoSchedule
key: phase
operator: Equal
value: dev
containers: # Pod 내부의 컨테이너 설정
# ECR (Elastic Container Registry)에 저장된 Docker 이미지
# docker hub 이미지도 사용 가능
- image: 405906814034.dkr.ecr.ap-northeast-2.amazonaws.com/areyouhere/areyouhere-server:142
name: areyouhere-server
resources:
requests:
cpu: 100m # 최소/최대 CPU 및 메모리 사용량 정의.
memory: 256Mi
limits:
cpu: 200m
memory: 256Mi
ports: # 컨테이너 내부 포트(앱이 트래픽을 받아들일 포트)
- containerPort: 8080
# Probe
# Spring Boot Actuator 엔드포인트를 주기적으로 호출해서 컨테이너 상태 확인
startupProbe:
httpGet:
path: /actuator/health/startup
port: 8080
initialDelaySeconds: 10
failureThreshold: 20
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
---
# Service: 클러스터 내에서 앱을 접근할 수 있게 해주는 엔드포인트 역할.
apiVersion: v1
kind: Service
metadata:
namespace: areyouhere # deployment와 동일한 namespace
name: areyouhere-server
spec:
type: ClusterIP # Cluster 내부에서만 접근되는 Service
selector:
app: areyouhere-server
ports:
# 클러스터 내부에서 서비스에 80 포트로 접근하면, selector로 선택한 pod의 8080 포트로 연결
# Istio나 다른 내부 Pod들이 이 서비스로 트래픽을 전달할 때 사용
- port: 80
targetPort: 8080 # Pod으로 전달하는데 사용될 포트
---
# VirtualService (Istio): 외부에서 트래픽을 받을 수 있도록 설정
# Charts 내부에서 설치한 Istio의 컨트롤 플레인(istiod)가 규칙을 감지해 라우팅 정책에 추가
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
namespace: areyouhere
name: areyouhere-server
spec: # 어디서 들어오는 트래픽을 받을지 정의
gateways:
- istio-ingress/waffle-ingressgateway # 외부 요청을 받을 게이트웨이 (ALB 통해 접근)
- mesh # 클러스터 내부의 서비스 간 통신도 허용
hosts:
- areyouhere-api.wafflestudio.com # ALB를 통해 들어오는 요청 중 Host 헤더가 일치하는 것만
http:
- route:
- destination:
host: areyouhere-server # areyouhere-server 서비스로 트래픽을 라우팅
AWS ALB, istio, istio-ingressgateway가 작동하는 과정 by Gemini
- Application Load Balancer(ALB): AWS에서 제공하는 클라우드 로드 밸런서 서비스
- 사용자가 브라우저에
areyouhere-api.wafflestudio.com를 입력- 도메인 주소는 AWS ALB의 IP 주소로 연결
- ALB는 이 요청을 수신하여, 미리 설정된 규칙에 따라 EKS 클러스터 내부에서 실행 중인
waffle-ingressgateway라는istio-ingressgateway로 트래픽을 전달(istio-ingressnamespace)istio-ingressgateway는VirtualService에서 정의한 hosts 규칙(areyouhere-api.wafflestudio.com)을 확인하고,- 요청을 최종 목적지인
areyouhere-server서비스로 라우팅
- 네트워크 흐름
[ 사용자 브라우저 ] | | https://areyouhere-api.wafflestudio.com v [ AWS ALB ] ← (HTTPS → HTTP 전환, Host 헤더 유지) | [ istio-ingressgateway (waffle-ingressgateway) ] | [ VirtualService (host 매칭: areyouhere-api...) ] | [ Kubernetes Service: areyouhere-server ] | [ Pod: areyouhere-server (8080) ]
waffle-world/misc/apps/namespace.yaml...
---
apiVersion: v1
kind: Namespace
metadata:
name: areyouhere
labels:
istio-injection: enabled
areyouhere 추가.istio-injection: enabled: Istio 사이드카 프록시가 자동 주입됨(auto-injection)Envoy 프록시 컨테이너: 모든 트래픽을 가로채고 제어함apps/hodu-dev/hodu/hodu-server.yamlapiVersion: apps/v1
kind: Deployment
metadata:
name: hodu-server
labels:
app: hodu-server
namespace: hodu-dev
spec:
replicas: 1
selector:
matchLabels:
app: hodu-server
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
revisionHistoryLimit: 4
template:
metadata:
labels:
app: hodu-server
spec:
serviceAccountName: hodu-server
...
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: hodu-server
namespace: hodu-dev
annotations: # ISRA 방식
eks.amazonaws.com/role-arn: arn:aws:iam::405906814034:role/DevHoduAccessRole
---
ServiceAccount : Pod가 k8s API나 외부 리소스에 접근할 때 사용하는 계정(토큰)default ServiceAccount가 할당됨IRSA (IAM Roles for Service Accounts) : Service Account에 AWS의 IAM Role을 연결DevHoduAccessRole의 권한을 가지고 AWS 리소스에 접근할 수 있음