AWS Cloud School 13기 118일차

Forever 김·2026년 6월 25일

AWS Cloud School

목록 보기
110/116

2026-06-24

Today

항목상태
[전제] Infra gitops/ 현재 구조 파악 — apps/dev·apps/prod 파일 목록, ArgoCD Application source path 확인
[1-1] gitops/charts/farmily-app/ 작성 — Chart.yaml + templates (farmily-app, eso, tgb, ai조건부, hpa조건부, keda조건부=ScaledObject+TriggerAuth+keda-pg-conn) + Namespace 생성(또는 ArgoCD CreateNamespace) + dev·prod 공통 SkipDryRunOnMissingResource 어노테이션(SecretStore·ExternalSecret·TGB, CRD 콜드스타트 첫 sync 실패 방지 — 차트가 무조건 적용)담당완료(브랜치)
[1-2] values-dev.yaml 작성 — app.image.tag(현재 운영 태그로 초기화=롤백 방지), replicas=1, dev role-arn, dev env, dev TG ARN담당완료(브랜치)
[1-3] values-prod.yaml 작성 — app.image.tag, replicas=2, prod role-arn, prod env, prod TG ARN, ai/hpa/keda enabled. AI는 prod only(ai.enabled: true, dev는 false)담당완료(브랜치)
[1-4] helm template 검증helm template -f values-dev.yaml vs 기존 apps/dev diff = 0 확인 (prod 동일)
[1-5] 워크로드 Application 추가 (방식 B)apps/{env}/farmily-workload.yaml = chart 가리키는 Application 1개 신설(path: charts/farmily-app + helm.valueFiles). 기존 root(recurse) 무수정 → 자동 발견(애드온 Application과 동일 패턴)담당완료(브랜치)
[1-5b] apps/{env} 워크로드 raw 매니페스트 제거 — farmily-app·app-secrets·tgb·ai·hpa·keda-scaler 삭제(chart 이관 → 이중 sync 충돌 방지). 애드온 Application만 잔류담당완료(브랜치)
[1-6] dev ArgoCD sync 정상 확인 — Helm 전환 후 pod running, health ✅
[2-1] ECR 구조 = 2개 유지 (farmily-api + farmily-api-dev, ECS 공존). EKS는 <sha> 불변 태그, prod 승격 = crane copy (재빌드 X)
[2-2] deploy.yml build-once 적용 — push 시 farmily-api-dev:<sha> 1번 빌드+push. prod 승격 = crane copy farmily-api-dev:<sha> → farmily-api:<sha> (재빌드 X) + [2-4] PR
[2-3] GitHub App farmily-gitops-bot 생성·Infra 설치 + GITOPS_APP_ID·GITOPS_APP_PRIVATE_KEY secret 등록(Backend·AgentCore) — PAT 아닌 App(단명 토큰·사람 무관·org 소유). org owner 권한 필요. 권한 Contents+Pull requests RW(Infra만)
[2-4] deploy.yml gitops-update-prod job 추가 — ① crane copy 스텝(farmily-api-dev:<sha>farmily-api:<sha>) + configure-aws-credentials(farmily-cicd-backend-role 재사용=결정 A, id-token: write) + crane CLI 설치(imjasonh/setup-crane) ② yq로 values-prod.yaml app.image.tag bump ③ peter-evans/create-pull-request@v7
[2-5] gitops-update E2E 확인 — main 머지 → Infra 레포에 PR 자동 생성 확인
[2-6] AgentCore deploy.yml gitops-update 추가 — Backend 복붙 + 키만 ai.image.tag, prod PR만 (dev 없음, AI는 prod only). App secret(GITOPS_APP_ID·GITOPS_APP_PRIVATE_KEY) AgentCore 레포에도 등록(App 설치에 Infra 포함)
[2-7] deploy.yml ECS job 제거 — deploy-prod/deploy-dev(ECS) 삭제(결정 301). ⚠️ ECS 실트래픽 cutover 시점과 동기화(선 제거 시 현 ECS 배포 중단)
[2-8] GHA OIDC sub 와일드카드 축소farmily-cicd-backend-role trust repo:Backend:* → 배포(main)·PR검증 분리(:ref:refs/heads/main / :pull_request). crane copy로 prod job이 AWS 역할 쓰게 돼 더 민감 → EKS 전환과 묶어 처리
[3-1] GHA gitops-update dev 직접 커밋 구현 — 빌드 job 끝에 Infra checkout → yq -i '.app.image.tag' values-dev.yaml → commit+push (PR 없이). GitHub App 토큰(create-github-app-token) 필요
[3-2] feat push → dev 자동 배포 E2E 확인 — GHA 빌드 → ECR push → values-dev.yaml 자동 커밋 → ArgoCD sync → pod running
[4-1] farmily-gitops-agent Dockerfile 작성 + ECR push — helm + kubeconform + conftest, AWS 권한 0
[4-2] Jenkinsfile.gitops 작성 — helm template → kubeconform → conftest (GITOPS_SKIP 포함)
[4-3] Jenkins gitops Job 등록 — Infra 레포 Jenkinsfile.gitops, gitops/ PR 트리거
[4-4] conftest policy/*.rego 작성 — requests 필수, latest 금지, runAsNonRoot 권장. soft(--no-fail)로 시작 → 신뢰 쌓이면 hard 전환
[4-5] gitops/ PR → Jenkins gitops CI ✅ 확인
[4-6] gitops Job Slack 알림 연동 — #farmily-인프라, 검증 ✅/❌ 발송 (Terraform 파이프라인과 대칭)
[5-1] prod 네임스페이스 istio-injection=enabledfarmily-prod 레이블, rolling restart✅ (ns 레이블+사이드카 2/2 확인)
[5-2] farmily-app prod Rollout 전환 — values-prod.yaml 또는 templates에서 kind: Deploymentkind: Rollout + 카나리 전략✅ PR#99 머지·prod 적용·Rollout Healthy 2/2 검증
[5-3] VirtualService + DestinationRule + AnalysisTemplate 추가 — Prometheus 에러율 게이트✅ PR#99 (VS/DR/Analysis 생성·HPA→Rollout 검증)
[5-4] prod 카나리 E2E 확인 — 이미지 승격 PR 머지 → 10%→50%→100% 단계 확인실주행 검증 — rev2(06-25 02:59 OTel env 변경 트리거, AnalysisRun step2·step5 Successful·100% 완주, 게이트 통과) + rev3(PR#104 이미지 bump e5ff39a 진행). north-south 실분배만 cut-over

Notes

  • 결정 A(이미지 repository/tag 분리) 완료 — PR #88 머지(45e9fad). app.image/ai.image 풀-URI 문자열 → repository+tag 2필드. [3-1]/[2-4]의 yq '.app.image.tag' 선행조건. helm 렌더 전후 byte 동일(dev·prod diff=0) → ArgoCD 리컨실해도 pod restarts=0(무재시작 검증).
  • [3-1] 완료 — Backend deploy.yml: deploy-dev(ECS) 제거 + gitops-update-dev job 추가(PR #58 머지 c91edf3). feat push → GitHub App(farmily-gitops-bot) 단명 토큰 → Infra main values-dev.yaml .app.image.tag yq 갱신 → 봇이 main에 직접 commit+push(봇·dev 한정 예외, ArgoCD가 main을 봐서). dev=직접 push / prod=PR 유지.
  • [3-2] 완료(E2E 실증) — feat push → run 28077471699 전 job ✅ → 봇 커밋 ed6b675(chore(dev): bump ... dev-c91edf3) → ArgoCD 45e9fad→ed6b675 리컨실 → 신규 pod IMAGE dev-c91edf3. feat push 한 번으로 빌드→봇커밋→ArgoCD sync→pod까지 전구간 자동 확인.
  • Jenkins plan 코멘트 PAT→봇 전환 완료(계획 외 추가) — terraform plan PR 코멘트가 개인 PAT(github-pat-token, gimyw 명의)로 게시되던 것 발견 → Jenkinsfile credential을 github-app-gitops-bot(GitHub App)로 교체(PR #90 머지 0cc4021). Jenkins App credential 등록(PKCS#8 변환·Test connection OK) → PR #90 빌드에서 plan 코멘트가 farmily-gitops-bot[bot](type=Bot)으로 게시 실증 → github-pat-token credential 삭제 완료. 개인 PAT 의존성 0.
  • pem 정리: farmily-gitops-bot private key 로컬 2개(PKCS#1·#8) 삭제(키는 GHA secret + Jenkins credential에만 잔류, 필요시 App에서 재발급).
  • [2-2]+[2-4]+[2-7] 완료 — Backend deploy.yml prod build-once GitOps 전환(PR #59 머지 5075f2f). ① [2-2] push-image feat 전용(main 재빌드 중단) ② [2-7] deploy-prod(ECS) 제거(prod ALB weight 실측 100% EKS — prod-eks-tg=100/prod-tg=0, 원본 ECS-4편 보존) ③ [2-4] gitops-update-prod: SRC_SHA(HEAD^2머지 2nd parent‖HEAD, fetch-depth 2) → crane copy dev-<sha>→prod-<sha>(재빌드X·동일digest, setup-crane@v0.6 SHA핀) → values-prod.yaml 태그 PR(사람 게이트) → ArgoCD prod-eks. 결정 C(dev 이미지 없으면 skip) + 계층화 Slack(앱변경O+이미지없음→⚠️/ci·docs 머지→조용히). SonarCloud ${{}}보간 인젝션 룰 FAILURE지만 비강제(ci만 필수)+오탐이라 머지.
  • 설계서 Kiro 반영 검토 — ②GitOps·③E2E·①Terraform에 오늘 결정 Kiro 반영. 검토 정확, PR# 오기 1건(②421행 #58#59)만 수정.
  • prod-eks AI 실태 확인 + EKS 접근 정리 — prod AI 의문 해소차 prod-eks 접근(kimyoungwon access entry 신규). 실측: farmily-app-ai 2 replica RUNNING(정적 태그 prod-4d3b38..., AgentCore가 ECS로만 배포해 미갱신). 접근 권한은 팀원 parity로 AdminView→ClusterAdmin(dev+prod) 상승, 수동 유지(팀 전원 TF 밖). ⚠️ prod ClusterAdmin = mutate 신중.
  • dev ECR lifecycle 10→30 완료farmily-api-dev countNumber 10→30(CLI). build-once에서 dev 이미지가 prod 승격 전 만료 방지. ⚠️ ECR은 TF 밖(수동) — Infra .tf에 정의 0건, IaC화는 import 별도 작업(백로그).
  • [2-8] OIDC sub 축소 완료farmily-cicd-backend-role trust repo:Backend:*(와일드카드) → [ref:refs/heads/feat, ref:refs/heads/main](정확매칭, CLI). 임의 브랜치/PR이 crane copy로 prod ECR push하던 갭 차단. AWS 쓰는 ref(feat=push-image, main=gitops-update-prod)만 허용. role도 TF 밖(수동).
  • ⚠️ prod AI staleness 격상 — 실측: prod 앱이 AGENTCORE_URL=http://farmily-app-ai:8080(EKS AI) 호출 → EKS AI 태그 동결(prod-4d3b38...)이라 prod가 구버전 AI 서비스 중. [2-6] "보류"가 아니라 최신화 필요(B=[2-6] 정석 / C=수동 태그 갱신 stopgap). 세윤 조율.
  • gitops-update-prod OIDC 버그 → 수정 + #60 수동승격 — 첫 실 앱변경(#60 세윤님 WebClient fix) 머지 시 gitops-update-prod가 OIDC 자격에서 실패(#59·#60). 원인: job permissions:contents:read가 워크플로 id-token:write 덮어씀 → 수정 Backend PR#61(b117364). #60은 수동 재승격: crane copy dev-ae0ed59→prod-ae0ed59(digest 동일) → Infra PR#92 머지 → ArgoCD prod-eks 롤링 완료. 교훈: [2-5] prod E2E 필요성 입증.
  • ECS에 #60 수동 배포 — ECS = 세윤님 AI 고도화 작업 환경(잔재 아님) 확인 → task def prod-app:33→34(prod-ae0ed59). HTTP weight 0이라 사용자 영향 0. 이번 1회 수동(자동화 X). ⚠️ ECS·EKS 스케줄러 중복은 앱팀 사안.
  • [4-1·2·4·6] gitops 검증 CI 완료 — Infra PR#94 머지(Dockerfile·Jenkinsfile.gitops·base.rego, helm→kubeconform→conftest, AWS 0). [4-1] 이미지 farmily-gitops-agent:1.0 ECR push(⚠️--platform linux/amd64). 블로그 16편 §3·설계서 ② 반영(Kiro)+보강.
  • [4-3] 완료 — Jenkins farmily-gitops Multibranch Job 등록(Script Path=Jenkinsfile.gitops). branch indexing SUCCESS.
  • [4-5] 완료 — probe PR #95(gitops/ 주석 1줄) → farmily-gitops Job 트리거 → helm→kubeconform→conftest SUCCESS → GitHub 체크 pr-head ✅ + Slack ✅ 실증 → PR close·브랜치 삭제(no-op). ⚠️ 발견①: terraform Job과 pr-head status context 공유(덮어씀) → 각 Job context 분리 필요(백로그). ⚠️ 발견②: gitops-only PR에 terraform plan 끼어듦 → 아래 TF_SKIP 수정.
  • TF_SKIP 3겹 수정 완료 — 발견②의 근본원인 3겹: ① 경로 불일치(루트 environments/ 매칭 → 실제 Desktop/VPC/ 밑이라 무력) ② 게이트 when{environment name:'TF_SKIP'}가 런타임 env.TF_SKIP 무시 → steps 안 if(env.TF_SKIP=='true')return(결정타) 선언형 environment{TF_SKIP='false'}가 매 스테이지 재적용돼 런타임 'true'를 리셋environment{}에서 제거. ①②만 고쳐도 ③이 값을 되돌려 안 됐음(단서=로그 "Check Changes서 TF_SKIP=true인데 Plan 돎"). PR #96 squash 머지(6a171b2) — 큐 비우고 단일 빌드로 plan 코멘트 0 실측. ⚠️detection 5회 헛수정(멀쩡한 곳)·③이 진짜 범인. 문서: 트러블슈팅 재작성·블로그 16편 [4-5] 섹션·설계서 §4 교정.
  • Status context 분리 완료 — 발견①(pr-head 공유) 처리. github-branch-source 옛 버전이라 "Custom GitHub Notification Context" trait가 UI에 없어서(코어 업글 필요=무거움) → Jenkinsfile ghStatus() 헬퍼로 GitHub Status API 직접 호출(curl+git ls-remote; gitops-agent엔 jq/gh 없음). Job 전용 context …/terraform·…/gitops. 디버깅: curl Content-Type 누락(422)→추가 · readFile /tmp 절대경로 throw→cat · HTTP 403 = github-app-gitops-bot에 Commit statuses:write 없음 → org 설치처 "new permissions 승인"(App 정의만 바꾸면 안 됨)·승인 후 201. PR #97 squash 머지(83fbcfa) — gitops=success·terraform=201 실측. ⚠️교훈: 빈 커밋(--allow-empty) 트리거는 changed=''→safe-fallback→terraform 풀실행 유발 → 검증은 실제 변경 커밋으로.
  • ⚠️ tf-agent 빌드 flapping → 원인 확정 (runc exec 버그, OOM 아님) — 멈춘 빌드 중 라이브 측정(SSM): 메모리 2.4GB 가용·load 0.00·dmesg OOM 0건·checkov 미실행OOM 가설 폐기. 진범 = dockerd 로그 OCI runtime exec failed: … current working directory is outside of container mount namespace root -- possible container breakout detected = Jenkins가 tf-agent 컨테이너에 docker exec(cwd=워크스페이스) 시 runc 거부 → sh 기동 실패 → 5분 재시도. 스택 Docker25.0.16+containerd2.2.4+runc1.3.5(AL2023 최신, 옛 CVE-2024-21626 회귀 아님) = 버전 스큐 + 빌드 중첩 teardown 경합(간헐 — 단독 브랜치 빌드는 통과, 중첩 PR/main은 멈춤). gitops Job은 통과(terraform Job만, 그나마 TF_SKIP이라 할 일도 없는데 걸림). 해결 결정 = B-lite(빌드 에이전트를 EKS 파드로 이전 = docker exec 제거; 컨트롤러는 EC2 유지=blast-radius 분리; tf-agent IRSA; 부수효과 executor 병목·메모리 해소). 임시(C) = executor 1 + push 자제. 손잡이=영원. 진단 여정: OOM 가설 → 라이브 측정 refute → dockerd 로그로 runc 확정.
  • 카나리 prod 적용·실주행 검증 완료 [5-2~5-4] ✅ — PR#99 머지 → Deployment→Rollout 전환(Healthy 2/2, VS·DR·Analysis·HPA→Rollout). [5-4] 실주행 검증됨: rev2(06-25 02:59, OTel env 변경이 파드템플릿 변경 → 카나리 트리거 → AnalysisRun step2·step5 Successful → 100% 완주, 에러율 게이트 통과) + rev3(PR#104 이미지 bump e5ff39a → 카나리 실시간 진행, 이미지 경로 확인). ⚠️"한 번도 안 돎" 가설 정정 — env 변경으로 이미 돌았었음. north-south 실 트래픽 분배만 cut-over 후(옵션 A).
  • Backend CI 버그 발견·수정farmily-cicd-backend-roleecr:DescribeImages 누락 → prod 자동승격이 dev이미지 확인 AccessDenied(2>/dev/null 삼킴)로 항상 skip = 그동안 수동승격한 진짜 원인([2-5] 미동작). 라이브 정책 확인 후 CLI로 추가·검증(백업 보관). ⚠️ 역할이 terraform 밖 → IaC화 백로그. 후속 gh run rerun 28143495808 미실행(대기).
  • ✅ prod AI staleness 해결 확인 — ECS=EKS=prod-0511ae7f(OTel 박힌 빌드로 bump). [2-6]/세윤 백로그 제거.
  • 공유용 대정비 — §8 "현재 상태" 삭제(상태=Daily/PROJECT_CONTEXT 담당)·§9→§8 재번호·카나리 §8.14 상세화·"완료된 것만"(계획/한계 제거) 정책. 메타 지시문서도 갱신.
  • 5개 레포 pull(AgentCore·Backend 갱신).
  • 남은 것: ① B-lite(다음 세션 大작업) · ② [5-4] 카나리 실검증(Backend 재실행→승격PR 머지→Rollout 관찰) · ③ Backend gh run rerun 28143495808 승격복구 · farmily-irsa-boundary(보안) · ignore_changes(민석) · ECS 정리 방침 · IaC화(ECR·EKS접근·cicd-role).

Learned

  • git checkout -- <파일> — 작업 디렉토리의 파일을 마지막 커밋 상태로 되돌림. staged(add한 것)는 안 건드리고 unstaged 변경만 취소. 파일 단위로 원복할 때 사용.
  • 온보딩(Onboarding) — 새로운 사람이 조직·시스템·프로젝트에 합류해 빠르게 적응하도록 돕는 과정. ① 팀원 온보딩(환경 셋업·코드 구조·배포법 익히기) ② 사용자 온보딩(앱 첫 사용법 안내) ③ 고객 온보딩(서비스 초기 설정 지원). 우리 맥락에선 "새 팀원이 CI/CD·인프라를 빨리 이해하게 하는 것" — 공유용 문서가 곧 온보딩 자료.
  • Push CD vs Pull CD (GitOps CD) — Push: CI가 클러스터에 직접 배포(우리 ECS 시대). Pull: ArgoCD가 Git을 보고 스스로 당겨와 반영(우리 EKS). Pull CD의 장점 = CI에 클러스터 권한 불필요(보안↑), drift 자동복구, Git이 진실.
  • 드리프트(Drift) — Git 선언 상태 ≠ 실제 클러스터 상태. 원인: 수동 kubectl, 사이드카 주입 등. ArgoCD가 자동 감지·복구(self-heal). Push CD에선 감지 자체가 불가.
  • App-of-Apps — ArgoCD 패턴. 부모 Application 1개(root-dev)가 디렉토리(gitops/apps/dev/)를 재귀 감시 → 그 안의 자식 Application YAML을 자동으로 등록·관리. 앱 추가 = 파일 push, 삭제 = 파일 delete. 선언적 앱 관리 + 환경 분리(root-dev/root-prod).
  • TGB (TargetGroupBinding) — ALB Target Group ↔ K8s Pod를 연결하는 CRD. 이게 있어야 ALB가 Pod IP를 알고 트래픽을 보냄. 없으면 503. dev/prod는 ARN이 달라 values-{env}.yaml에서 분리.
  • ESO (External Secrets Operator) — AWS Secrets Manager → K8s Secret 자동 동기화. Git에 비밀번호 안 넣고 AWS에서 가져옴. 앱이 DB 비번·API키를 환경변수로 받을 수 있게 해줌.
  • crane copy — 이미지를 재빌드 없이 ECR 리포 간 복사하는 CLI. 동일 digest 보장. ECR 2개 유지하면서 build-once를 지키는 핵심 도구. crane copy dev-repo:sha → prod-repo:sha.
  • Helm Chart — 앱 배포용 패키지. templates(빈칸 있는 YAML 틀) + values(환경별 값) = 최종 배포 YAML. 도입 이유: ① dev/prod 중복 제거(공통은 template 1번만) ② 환경 차이를 values 한 파일로 관리 ③ 이미지 태그 변경 = values 한 줄 수정 ④ 사람 실수를 구조적으로 방지. helm template = 렌더링 결과 미리보기.
  • 의존성 체인 (Dependency Chain) — A가 B에 의존, B가 C에 의존… 하위가 안 깔리면 상위도 못 하는 상태. 예: TGB 배포 → LBC CRD 필요 → LBC 미설치 → 막힘. 해결: 순서대로 설치하거나, SkipDryRunOnMissingResource로 "나중에 다시 시도" 허용.
  • EKS 접근 정책 (ViewPolicy vs AdminViewPolicy) — ViewPolicy: 표준 리소스(Pod/Deployment 등)만 read. AdminViewPolicy: CRD(ArgoCD Application 등) 포함 전부 read. ArgoCD Application 조회(kubectl get applications)가 필요하면 AdminViewPolicy 필수. 트레이드오프: Secret도 읽기 가능하지만 읽기 전용이라 위험도 낮음.

Prompt(회고)

profile
나를 한줄로

0개의 댓글