k8s 직접 해보기 (8) - waffle-world 레포 & PR 분석

Endermaru·2025년 6월 25일

k8s 직접 해보기

목록 보기
9/11

목표

  • 지금까지 minikube 상에서 여러 시도를 했다면, 이제 실제 AWS EKS에 우리 팀의 서버를 올려야 함.
    • 서버 앱에 맞는 manifest 파일들을 작성해서 PR하는 방식으로 진행
  • 실제 manifest 파일 작성에 앞서, ArgoCD가 소스로 삼고 있는 waffle-world의 구조가 어떻게 되어 있는지 간단히 살펴보고
  • 다른 팀이 먼저 올린 PR을 살펴보며 무엇이 필요한지 확인하는 과정도 선행

레포 살펴보기

README.md

waffle-world

[K8S] everything in wafflestudio-cluster

wafflestudio-cluster 의 선언적 관리GitOps 를 위한 repository 입니다.

cluster 의 현 상태를 정확하고 투명하게 파악하며, 누가 언제 어떤 변경을 적용했는지 기록하는 것을 목표로 합니다.

Structures of Directory

/apps/*

  • Argo CD 로 관리하는 서비스 Application 들의 manifest 파일들이 위치합니다. adminkubectl 등의 도구로 수동 적용하지 않습니다.
  • 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 들은 main branch 의 변경이 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/*

  • adminkubectl로 수동으로 관리하는 manifest 들이 위치합니다. load-balancer-controller, cluster-autoscaler, cert-manager 등 핵심적인 clsuter infra 와 관련되어 있습니다.

/apps/templates/autodeploy-app.yaml

  • App of Apps 패턴의 Root App
apiVersion: 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.yaml

  • autodeploy-app.yaml에서 사용된 value가 정의됨
  • cf. root app이 다시 자신이 들어있는 /apps를 감시하는 논리적인 순환 참조가 발생(정상 작동은 함)
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.yaml

  • ArgoCD를 설치하기 위한 Helm Chart
  • chart.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.yaml

  • 필요한 부분을 values.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, prometheus

  • argocd 디렉토리와 동일하게 기존 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 (데이터 수집 및 저장) → 관리자 (조회 및 경고)

PR 살펴보기

#162

.github/CODEOWNERS

apps/areyouhere/ @wafflestudio/areyouhere
  • CODEOWNERS 파일
    • 특정 폴더나 파일에 자동 reviewer(코드 소유자)를 지정할 수 있는 GitHub 기능
    • PR을 만들면, 해당 경로에 지정된 팀이나 사람이 자동 리뷰어로 할당
    apps/areyouhere/ 폴더 하위에서 변경이 일어날 경우, @wafflestudio/areyouhere에 속한 사람들이 PR 리뷰어로 자동 할당됨

apps/templates/areyouhere-server.yaml

  • Argo CD용 Application 정의 파일
  • 앞서 살펴봤던 apps/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.yaml

  • Deployment, 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에서 제공하는 클라우드 로드 밸런서 서비스
  1. 사용자가 브라우저에 areyouhere-api.wafflestudio.com를 입력
  2. 도메인 주소는 AWS ALB의 IP 주소로 연결
  3. ALB는 이 요청을 수신하여, 미리 설정된 규칙에 따라 EKS 클러스터 내부에서 실행 중인 waffle-ingressgateway라는 istio-ingressgateway로 트래픽을 전달(istio-ingress namespace)
  4. istio-ingressgatewayVirtualService에서 정의한 hosts 규칙(areyouhere-api.wafflestudio.com)을 확인하고,
  5. 요청을 최종 목적지인 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
  • 새로운 namespace areyouhere 추가.
  • istio-injection: enabled: Istio 사이드카 프록시가 자동 주입됨(auto-injection)
    = 하나의 Pod 안에 두 개의 컨테이너가 뜨게 됨
    • 하나는 앱 컨테이너
    • 하나는 Istio의 Envoy 프록시 컨테이너: 모든 트래픽을 가로채고 제어함
      → 트래픽 라우팅, 모니터링, 인증, 보안 기능 등 Istio가 제공하는 기능 사용

#190

  • 다른 부분은 #160과 거의 동일하지만, ServiceAccount 리소스가 추가됨

apps/hodu-dev/hodu/hodu-server.yaml

apiVersion: 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나 외부 리소스에 접근할 때 사용하는 계정(토큰)
    • 기본적으로 모든 Pod에는 default ServiceAccount가 할당됨
  • IRSA (IAM Roles for Service Accounts) : Service Account에 AWS의 IAM Role을 연결
    → hodu-server라는 ServiceAccount를 사용하는 Pod는 DevHoduAccessRole의 권한을 가지고 AWS 리소스에 접근할 수 있음
    → S3, SQS, DynamoDB 같은 IAM 기반 리소스

0개의 댓글