Kubernetes/쿠버네티스 모범 사례 스터디

지속적 통합, 테스트, 배포

막이86 2023. 11. 14. 15:19
728x90

쿠버네티스 모범 사례을 요약한 내용입니다.

  • CI/CD를 적용 하는 방법, 도구, 절차를 알아 보기
  • CI/CD의 목표는 코드 검토부터 운영 롤아웃까지 완전히 자동화된 프로세스를 갖추는 것
  • 쿠버네티스에서 배포된 앱을 수동으로 업데이트하면 오류가 자주 발생함
    • 설정 표류(configuration drfit)를 발생 가능성이 높아짐
    • 배포 업데이트가 불안정해짐
    • 배포 속도가 둔화됨

5.1 버전 관리

  • CI/CD 파이프라인은 버전관리부터 시작
  • 브랜치 전략을 세우는 방법을 조직 구조와 업무에 따라 설정해야 함
    • 운영 코드가 포함된 마스터 브랜치(Master Branch)
    • 기능과 개발을 위한 기능 브랜치(feature)
  • 개발자와 운영 엔지니어가 단일 스토리지에서 공동의 작업을 수행하게 되면 운영에 전달하는 팀에 대한 신뢰도가 높아짐

5.2 지속적 통합

  • CI는 코드 변경을 버전 관리 리포지터리에 지속적으로 통합하는 과정
  • 코드를 리포지토리에 커밋할 때는 큰 코드 변경을 가끔씩 하는 것보다 작은 코드 변경을 자주 하는 것이 좋음
  • 데브옵스 문화에서 운영팀도 코드와 소프트웨어 개발 워크플로를 알아야 함
  • CI의 대표적인 제품으로는 젠킨스(Jenkins)가 있음

5.3 테스트

  • 파이프라인에서 테스트를 실행하는 이유는 코드 변경으로 빌드가 실패할 때 빠르게 피드백을 받기 위함
  • 폭넓은 테스트 집합이 있으면 나쁜 코드가 운영 환경에 배포되는 것을 막을 수 있음
    • 테스트 실패시 빌드도 실패 함
    • 컨테이너 이미지가 빌드되어 레지스트리에 푸시 되면 안됨
  • 인프라와 애플리케이션을 자동으로 운영에 배포하려면 모든 코드베이스를 자동으로 테스트하는 방안을 찾아야함
  • 단위 테스트와 같은 일부는 개발자의 책임이지만 스모크 테스트와 같은 일부는 공동의 협력이 필요
  • 코드베이스를 테스트하여 운영에 전달하는 것은 팀 단위의 노력이 필요함

5.4 컨테이너 빌드

  • 이미지를 빌드할 때는 이미지의 크기를 최적화 해야함
    • 이미지가 작을수록 이미지를 가져오고 배포하는 시간이 줄어 듬
    • 이미지가 줄어들면 보안도 강화됨
  • 이미지 최적화 방법에 여러가지가 있지만 그 중 몇몇은 트레이드오프를 가지고 있음

다중 단계 빌드

  • 애플리케이션 실행시 불필요한 의존 관계를 제거
    • Go 언어 사용시 정적 바이너리를 빌드할 때 사용되는 모든 도구가 필요하지 않음
  • 다중 단계 빌드를 사용하여 도커파일로 실행에 필요한 정적 바이너리만 포함하는 최종 이미지를 빌드 할 수 있음
    • 애플리케이션 빌드를 위한 이미지에서 빌드 후 바이너리 생성
    • 바이너리를 실행할 이미지 생성

배포판이 없는 기본 이미지

  • 불필요한 바이너리와 셸(Shell)은 이미지에서 제거
    • 이미지 크기 최적화 및 보안 강화
  • 배포판이 없는 이미지는 셸이 없으므로 이미지에 디버거를 붙일 수 없다는 단점을 가지고 있음
    • 패키지 관리자, 셸, 기타 일반적인 OS 패키지가 없음
  • OS에서 친숙한 디버그 도구를 사용할 수 없음

최적화된 기반 이미지

  • OS 계층에서 불필요한 것을 제거하고 군살을 뺀 이미지
    • 알파인 리눅스(Alpine Linux)는 10MB의 기반 이미지와 로컬 개발을 위한 디버거를 제공
    • 데비안과 같은 리눅스 배포판 역시 최적화된 기반 이미지를 기본 제공
  • 기반 이미지는 개발할 때 필요한 기능을 제공하면서 이미지 크기 최적화와 보안 위험도 낮추기 때문에 훌륭한 선택지

5.5 컨테이너 이미지 테그

  • CI 파이프라인의 또 다른 단계는 도커 이미지를 빌드하여 배포할 이미지 산출물을 만드는 것
  • 운영에 배포할 이미지의 버전을 쉽게 분별하기 위한 이미지 태그 전략을 세우는 것이 중요
  • letest를 이미지 태그로 사용하지 않는 것이 중요
    • 버전이 아니기 때문에 롤아웃 이미지의 어떤 코드가 변경된 것인지 파악하기 어려움
  • CI 파이프라인에서 빌드된 모든 이미지는 고유한 태그를 가져야 함
  • CI 파이프라인에 효과적인 전략을 이용하는 것이 좋음
    • BuildID태그의 일부로 BuildID를 사용하면 어떤 빌드에서 이미지가 만들어졌는지 알 수 있음
    • CI 빌드를 시작할 때 연관된 BuildID가 생성됨
    • 빌드 시스템 - BuildID
    • 여러 빌드 시스템이 존재한다면 BuildID에 빌드 시스템을 추가
    • Git HashGit Hash를 태그로 사용하면 이미지를 생성한 커밋을 쉽게 알수 있음
    • 새로운 코드를 커밋하면 Git Hash가 생성됨
    • Git Hash - BuildID
    • 이미지를 생성한 커밋과 BuildID를 알수 있지만 태크가 길어질 수 있음

5.6 지속적 배포

  • CI 파이프라인을 성공적으로 통과했다면 CD는 변경 사항을 자동으로 운영에 배포
  • 컨테이너는 변경사항을 배포하는데 큰 이점을 제공
    • 이미지가 개발, 스테이지, 운영으로 옮겨갈 수 있도록 불변 객체가 됨
    • 일관된 환경을 유지하는 것이 중요한 이슈
  • 스테이지에서 잘 동작하던 디플로이먼트가 운영으로 옮겨간 후 배포에서 실패하는 경우가 많음
    • 라이브러리와 컴포넌트 버전의 차이 등의설정 표류 때문에 발생하는 현상
  • CD에 집중하기 전에 먼저 견고한 CI 파이프라인을 구축 해야함

5.7 배포 전략

  • 쿠버네티스는 애플리케이션이 새로운 버전을 롤아웃하기 위한 여러가지 전략을 제공
    • 롤링 업데이트
    • 블루/그린 배포
    • 카나리 배포
  • 롤링 업데이트를 사용하면 현재 실행중인 애플리케이션을 다운타임 없이 업데이트 할 수 있음
    • [그림 5-1] 롤링 업데이트로 frontend:v1 → frontend:v2로 업데이트 방법
    • 디플로이먼트 객체를 사용하면 한 번에 업데이트할 최대 레플리카 수와 사용할 수 없는 최대 파드 수를 롤아웃 과정에서 설정 할 수 있음
    • apiVersion: apps/v1 kind: Deployment metadata: name: frontend spec: replicas: 3 template: spec: containers: - name: frontend image: bredanburns/frontend:v1 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # 한 번에 업데이트할 최대 레플리카 수 maxUnavailable: 1 # 롤아웃 중간에 가용하지 않는 최대 레플리카 수
    • 클라이언트와의 연결이 끊어질 수 있으므로 주의 해야함
      • 준비성 프로브(readiness probe)와 preStop 라이프사이클 훅을 사용하여 해결 가능
    • 준비성 프로브는 배포된 새로운 버전이 트래픽을 수용할 준비가 되었는지 확인
    • preStop 훅은 현재 배포된 애플리케이션의 커넥션을 드레인(drain) 함
      • 컨테이너가 종료되기전에 동기 방식으로 호출되므로 마지막 종료 신호를 받기전에 완료되어야 함
    • 준비성 프로브와 라이프사이클 훅을 구현한 예
      • preStop 라이브사이클 훅은 정상적으로 NGINX를 종료하는 반면 SIGTERM은 빠르게 강제 종료 작업을 수행
      apiVersion: apps/v1
      kind: Deployment
      metadata:
      	name: frontend
      spec: 
      	replicas: 3
      	template:
      		spec:
      			containers:
      			- name: frontend
      				image: bredanburns/frontend:v1
      				livenessProbe:
      					#...
      				readinessProbe:
      					httpGet:
      						path: /rediness    # 프로브 엔드포인트
      						port: 8888
      				lifecycle:
      					preStop:
      						exec:
      						commend: ["/usr/sbin/nginx", "-s", "quit"]
      	strategy:
      		type: RollingUpdate
      		rollingUpdate:
      			maxSurge: 1        # 한 번에 업데이트할 최대 레플리카 수
      			maxUnavailable: 1  # 롤아웃 중간에 가용하지 않는 최대 레플리카 수 
      
    • 롤링 업데이트는 롤오버 중간에 두 가지 버전의 애플리케이션이 동시에 실행됨
      • 데이터베이스 스키마는 두가지 버전 모두를 지워 해야함
      • 스키마에 새로운 앱에 필요한 컬럼을 추가하는 기능 플래그 전략을 사용할 수 있음
        • 업데이트 완료후 불필요한 컬럼을 삭제할 수 있음
  • 블루/그린 배포를 사용해 예측 가능한 방식으로 애플리케이션을 배포할 수 있음
    • 트래픽이 새로운 환경으로 전환되는 시점을 조절할 수 있으므로 새 버전의 롤아웃을 효과적으로 통제 가능
    • 기존 환경과 새로운 환경을 동시에 배포할 만큼 충분한 용량이 필요함
    • 이번 버전으로 쉽게 전환되는 등의 많은 장점이 있지만 주의 할 점이 있음
      • 데이터베이스 ㅇ마이그레이션이 어려울 수 있음
      • 두 환경을 우연히 삭제할 위험이 있음
      • 두 환경을 위한 추가적인 용량이 필요
      • 하이브리드 배포의 경우 레거시 앱에서 발생하는 문제를 해결해야함
  • 카나리 배포는 블루/그린 배포와 상댕히 유사하지만 신규 배포로 트래픽을 전환한는 것에 대해 다양한 통제권을 제공
    • 신규 배포로 전달할 트래픽 비율을 정할 수 있는 기능이 있음
    • 배포 전략 구현에 필요한 여러 기능을 제공하는 이스티오, 링커디, 해시코프의 콘술, 서비스 메시 기술을 구현할 수 있음
    • 새로운 버전으로 전체 사용자의 10%에게만 우선 롤아웃 테스트 해볼 수 있음
      • 적은 수의 사용자에게 먼저 노출하여 잘못 배포하거나 기능이 동작하지 않는 위험성을 줄일 수 있음
      • 문제가 없다면 더 많은 트래픽 비율을 새로운 애플리케이션으로 이동
    • 특정 리전의 사용자나 특정 프로필을 가진 사용자만을 대상으로 카나리 배포를 할수 있는 고급 기술도 있음
    • 이러한 배포를 흔히 A/B 또는 다크 릴리스 라고 부름
    • 카나리 배포에는 블루/그린 배포 주의 사항을 포함하여 추가 고려 사항이 있음
      • 일부 사용자에게만 트랙픽을 전환하는 기능
      • 신규 배포 상태와 비교하기 위한 안정된 상태에 대한 확고한 지식
      • 신규 배포가 좋은 또는 나쁜 상태인지 알 수 있는 메트릭

<aside> 💡 카나리 배포는 동시에 여러 버전을 실행해야 하는 어려움이 있음. 데이터 베이스 스키마는 두 버전을 동시에 지원 해야함. 카나리 배포를 선택할 때는 의존된 서비스를 다루는 방법과 여러 버전을 실행하는 법을 제대로 파악해야 함

</aside>

5.8 운영에서의 테스트

  • 운영 환경에서 테스트를 수행하면 애플리케이션의 탄력성, 확장성, UIX에 대한 신뢰를 얻을 수 있음
  • 운영 테스트는 **도전적**이며 **위험**하지만 시스템의 안정성을 위해서 시도해볼 가치가 있습니다.
    • 운영 테스트의 효과를 파악할 수 있는 심층적인 관찰 전략이 필요함
    • 시스템의 복원력을 향상시키기 위한 명확한 지표가 필요함
    • 자동 복구를 위한 높은 수준의 자동화가 필요함
  • 효과적인 테스트를 위해서는 많은 도구를 사용 해야함
    • 분산 추적, 인스투르먼테이션, 카오스 엔지니어링, 트래픽 섀도 등이 필요

카오스 엔지니어링

  • 네플릭스(Netflix)에서 개발
  • 시스템에 실험을 배치해 시스템 내의 취약점을 발견
  • 통제된 실험 환경에서 동작을 관찰하고 파악 할 수 있음
  • 실험을 수행하기 전 구현하고자 하는 내용
    • 가설을 세우고 안정된 상태를 파악
    • 시스템에 영향을 미치는 현업의 다양한 이벤트를 모음
    • 통제 그룹을 구축하고 안정된 상태와 비교하는 실험을 함
    • 실험을 수행해 가설을 세
  • 실험을 수행할 때 폭팔 반경(blast radius)을 최소화해야 함
  • 실험 수행에 극심한 노동력이 필요함으로 자동화 해야함

스테이지에서 테스트 할 경우

  • 리소스 배포의 불일치
  • 운영과의 설정 차이
  • 모의 트래픽과 사용자 행위
  • 현업 워크로드와 유사한 요청을 재현하지 못함
  • 모니터링이 빈약함
  • 배포된 데이터 서비스는 운영과 다른 데이터와 부하를 가짐

<aside> ❗ 운영 모니터링에 대한 확고한 신뢰를 확보 해야함

</aside>

5.9 파이프라인 구축과 카오스 실험 수행

5.9.1 CI 구축

  • Drone(https://cloud.drone.io/)을 사용해서 Clone한 코드를 빌드
    • 회원 가입(Github ID)
    • Github에 포크한 레포지토리를 활성화
    • 도커 허브에 푸쉬 하기 위한 시크릿 설정을 추가
    • Drone 리포지터리 아래에서 Setting을 클릭하여 시크릿 추가
      • docker_username
      • docker_password
      • kubernetes_server
      • kubernetes_cert
      • kubernetes_token
    • 쿠버네티스 서버를 위해서는 공개된 쿠버네티스 API 엔드포인트가 필요
    • kubectl cluster-info

... 가입부터 막히네 ㅠㅠ

5.9.2 CD 설정

  • 파이프라인 배포 단계를 위해 쿠버네티스 클러스터에 애플리케이션을 푸시
  • 프론트엔드 앱 폴더 아래의 디플로이먼트 매니페스트를 사용
  • kubectl: image: dstrebel/drone-kubectl-helm secrets: [ kuberntes_server, kubernetes_cert, kubernetes_token ] kubectl: "apply -f ./frontend/deployment.yaml"
  • 파이프라인 배포가 완료된 후 클러스터에서 실행 중인 파드를 확인할 수 있음
  • kubectl get pads
  • Drone 파이프라인에 디플로이먼트 상태를 반환하는 테스트 단계를 추가 해보기
  • test-deployment: image: dstrebel/drone-kubectl-helm secrets: [ kuberntes_server, kubernetes_cert, kubernetes_token ] kubectl: "get deployment frontend"

5.9.3 롤링 업그레이드 수행

  • 프론트엔드 코드의 한 줄을 변경해서 롤링 업그레이드를 실행
  • 디플로이먼트가 롤아웃되고 기존 파드에 롤링 업데이트되는 것을 볼 수 있음

5.9.4 간단한 카오스 실험

  • 카오스 실험을 수행하는데 다양한 도구가 있음
  • 카오스 실험을 위한 대표적인 도구
    • Gremlin
      • 카오스 실험 실행과 관련된 고급 기능을 제공하는 호스팅 카오스 서비스
    • PowerfulSeal
      • 고급 카오스 시나리오가 포함된 오픈 소스 프로젝트
    • 카오스 툴킷
      • 다양한 형태의 카오스 엔지니어링 도구
      • 무료 공개 커뮤니티 기반의 툴킷 및 API 제공하는 것을 목표로 하는 오픈 소스 프로젝트
    • KubeMonkey
      • 파드의 기본적인 복원력 테스트를 위한 오픈 소스 도구
  • 자동으로 파드를 종료해서 애플리케이션의 탄력성을 테스트할 수 있는 카오스 실험을 설치
  • pip install -U chaostoolkit pip install chaostoolkit-kubernetes export FRONTEND_URL="<http://$>(kubectl get svc frontend -o jsonpath="{.status.loadBalancer.ingress[*].ip}"):8080/api/"") chaos run experiment.json

5.10 CI/CD 모범 사례

CI/CD 파이프라인이 하루 아침에 완벽해질 수는 없기 때문에 점진적으로 개선해야 함

  • CI를 이용한 자동화와 빠른 빌드에 집중 해야함
    • 실패시 빠른 피드백을 얻을 수 있음
  • 파이프라인에서 안정적으로 테스트하는 데 초점을 두세요.
    • 코드에 문제가 생겼을 때 빠른 피드백을 줄 수 있음
    • 빠른 피드백은 생산성을 향상시킴
  • CI/CD 도구를 결정했다면, 파이프라인을 코드로 정의할 수 있는지 확인
    • 파이프라인 코드도 버전관리를 해야함
  • 이미지 최적화가 되어 있는지 확인 필요
    • 빠른 빌드 및 보안성 향상
    • 다단계 도커 빌드를 사용하여 이미지 최적화 가능
  • latest 이미지 태그를 사용하지 말 것
    • BuildID와 Git Commit 을 참조할 수 있는 태그를 사용 해야함
  • CD가 익숙하지 않다면 쿠버네티스 롤링 업그레이드를 사용
    • 사용하기 쉽고 배포가 편리함
    • CD에 능숙해지면 블루/그린 배포와 카나리 배포 전략을 사용
  • CD를 이용해 클라이언트 연결과 데이터베이스 스키마가 어떻게 업그레이드되며 애플리케이션에서 어떻게 처리되는지 테스트 필요
  • 운영 테스트는 애플리케이션의 안정성에 도움을 줌
    • 훌륭한 모니터링 필요
    • 소규모로 시작하고 폭발 반경을 제한

5.11 마치며

  • CI/CD 파이프라인은 쿠버네티스에 애플리케이션을 전다할 때 위험을 줄이고 처리 속도를 높이는데 도움이 됨
  • 애플리케이션을 배포할때 적절한 배포 전략을 사용할 수 있음
728x90