-
쿠버네티스 모범 사례) Ch.1 - Ch.4 정리네트워크 & 인프라 2024. 3. 31. 13:57
최근 쿠버네티스 모범 사례 스터디를 시작했는데, 책을 보면서 정리한 내용을 정리했다.
책은 쿠버네티스 창시자가 작성했다고 한다!
Ch1. 기본 서비스 설치
1.2 설정 파일 관리
- 쿠버네티스에서는 모든 것을 선언적으로 표현
- 쿠버네티스는 YAML과 JSON을 지원
- YAML에서 들여쓰기를 주의
1.3.1 이미지 관리 모범 사례
- 컨테이너 이미지를 구축하는 과정은 ‘공급망 공격’(supply chain attack)에 취약
- 공급망 공격 : 신뢰할 수 있는 소스의 의존 이미지에 악의적인 사용자가 코드나 바이너리를 삽입하여 독자의 어플리케이션에 내장
- 해결방법
- 믿을 수 있는 이미지 공급자를 통해서 이미지 구축
- 밑바닥부터 이미지를 구축 (이때, 정적 바이너리를 구축할 수 있는 언어를 사용하는 것이 수월)
- 네이밍 모범 사례
- 버전태그를 변경하지 않기 위해서 의미론적 버전과 이미지가 빌드된 커밋의 sha 해시와 결합해 네이밍
- ex) v1.0.1-bfeda01f
- 버전태그를 명시하지 않으면 latest가 기본 설정
- 운영에서는 이미지 구축마다 이미지 자체가 변경되어 좋지 않음
- 버전태그를 변경하지 않기 위해서 의미론적 버전과 이미지가 빌드된 커밋의 sha 해시와 결합해 네이밍
1.3.2 어플리케이션 레플리카 생성
- 프론트엔드 앱은 stateless
- 예상치 못한 장애에 대응하거나 롤아웃을 위해 재시작 다운타임을 방지하기 위해 최소 두개의 레플리카를 실행하는 것이 좋음
- 쿠버네티스에서는 replicaSet보다 deployment 리소스를 사용하여 레플리카를 관리하는 것을 권장
- 컨테이너의 리소스 요청과 제한
- 요청 : 앱을 실행하는 호스트 장비가 보장해주는 리소스 크기
- 제한 : 컨테이너가 사용할 수 있는 최대 리소스 크기
- 동일한 값으로 설정이 리소스 이용률을 높일 수는 없지만, 앱이 에상대로 동작하므로 안정성을 얻을 수 있음
- 소스관리와 운영을 일치시키기 위해 gitOps로 CI와 CD를 자동화 하여 특정 브랜치에만 배포
1.4 HTTP 트래픽을 처리하는 외부 ingress 설정
- 클러스터 리소스는 기본적으로 오직 클러스터 내에서만 접근 가능
- 외부 노출을 위해서 외부 IP 주소를 할당해주는 서비스와 로드밸런서를 생성하고 컨테이너로 트래픽을 보내야함
- TCP 또는 UDP 트래픽을 로드밸런싱 하는 서비스 + Ingress 리소스
- Ingress 리소스 : HTTP 경로와 호스트 기반의 요청을 지능적으로 라우팅할 수 있는 HTTP(S) 로드 밸런싱 지원
- TCP 또는 UDP 트래픽을 로드밸런싱 하는 서비스 + Ingress 리소스
- 단순한 앱 조차도 두개의 다른 서비스의 HTTP 요청을 처리 → Ingress 선택 이유
- 클러스터에서 인그레스 동작을 위해서 서비스리소스와 달리 인그레스 컨트롤러 컨테이너가 필요
- Ingress 공급자 : nginx, haproxy 등
- 외부 노출을 위해서 외부 IP 주소를 할당해주는 서비스와 로드밸런서를 생성하고 컨테이너로 트래픽을 보내야함
1.5 ConfigMap으로 애플리케이션 설정
- 애플리케이션과 설정을 분리하는 것이 필요
- 바이너리 환경에 따라 달라지는 설정을 적용
- 새로운 기능 코드로 활성화한다면 매번 빌드해서 바이너리 배포해야함
- ConfigMap : 설정 정보나 파일을 나타내를 다중 키/값 쌍
- 변경된 설정을 정기적으로 Deployment에 적용해 롤아웃 → configmap의 이름에 버전 숫자를 넣어 deployment가 적절한 health check를 통해서 자동으로 멈췄다가 재시작
- 단순 configmap 자체를 변경하면 이미 존재하는 파드가 실제로 갱신되지 않고 파드를 재시작 해야 설정이 반영 → health check를 통해서가 아닌 불시에 또는 무작위로 롤아웃 될 수 있음
- 변경된 설정을 정기적으로 Deployment에 적용해 롤아웃 → configmap의 이름에 버전 숫자를 넣어 deployment가 적절한 health check를 통해서 자동으로 멈췄다가 재시작
1.6 시크릿 인증 관리
- Secret : 설정과는 다른 방식으로 접근 제어, 처리, 갱신
- 쿠버네티스는 시크릿 데이터를 다룰 수 있는 시크릿 리소스를 제공
- Microsoft Azure key vault나 해시코프 볼트와 같은 오픈 소스 프로젝트를 활용한 시크릿/키관리 서비스를 사용하는 것이 좋다
- 기본적으로 시크릿은 암호화 되지 않은 상태로 쿠버네티스에 저장됨
- 볼륨을 사용하여 배포 시점에 실행중이 애플리케이션과 시크릿을 결합해야 함
- 시크릿은 tmpfs 램 기반의 파일시스템으로 볼륨을 생성해 컨테이너에 마운트하여 장비가 물리적인 피해를 입더라도 공격자가 시크릿을 취득하기 어려움
- 쿠버네티스는 시크릿 데이터를 다룰 수 있는 시크릿 리소스를 제공
1.7 간단한 스테이트풀 데이터베이스 배포
- 쿠버네티스에서는 노드 상태, 업그레이드, 리밸런싱 등 여러 이유로 파드가 다시 스케줄링됨
- 데이터가 특정 장비나 컨테이너 자체에 존재하는 경우 컨테이너가 이관되거나 재시작될 때 데이터 손실발생
- ⇒ PersistentVolume을 사용해서 방지 가능
- 원격 스토리지에 존재
- 파일 기반의 네트워크 파일 시스템 (NFS), 서버 메세지 블록(SMB) 등 다양한 네트워크 프로토콜을 통해 마운트
- StatefulSet 리소스를 사용해 배포해 강한 일관성을 보장
- 싱글턴 패턴으로 배포할 때는 상대적으로 덜 중요하지만 상태 복제를 배포할 때는 유용
- 레디스는 PersistentVolumeClaim을 사용해서 PersistentVolume을 얻음
- 볼륨클레임을 사용해 작성한 템플릿은 복제가 가능하고 각 파드는 자신만의 persistentVolume을 할당 받을 수 있음
1.8 서비스를 이용한 TCP 로드 밸런서 생성
- 읽기 : statefulSet의 레플리카에 모두 데이터가 복제되어 있어 어디서 요청을 처리하든 상관 없음
- 쓰기 : 레디스 마스터에서 직접 처리, 클러스터 IP주소를 가지지 않는 헤드리스 서비스를 이용
- 대신, statefulSet안의 모든 파드에 대한 DNS를 설정
- 트랜잭션 읽기 / 쓰기를 위해 레디스에 연결하는 경우, 별도의 클라이언트를 구축하여 쓰기 서버에 연결
1.9 인그레스에 이용해 트래픽을 정적 파일 서버로 전달
- nginx 컨테이너 기반으로 정적 이미지를 구축해 각 레플리카에 배포
1.10 헬름을 이용한 애플리케이션 파라미터화
- 모든 파일을 서로 동기화 된 상태로 유지해야하기 때문에 쉽게 개발하기 위해서 브랜치와 버전관리를 사용
- 템플릿 시스템 : 애플리케이션 설정의 뼈대인 템플릿과 특정 환경 설정으로 템플릿을 특수하게 만들어주는 파라미터를 결합
- ex) helm (chart)
- 템플릿 시스템 : 애플리케이션 설정의 뼈대인 템플릿과 특정 환경 설정으로 템플릿을 특수하게 만들어주는 파라미터를 결합
1.11 서비스 배포 모범 사례
- 대부분의 서비스는 Deployment 리소스로 배포되어야 함
- Deployment는 로드 밸런서인 서비스를 통해 노출 , HTTP 애플리케이션을 노출하려면 인그레스 컨트롤러를 사용할 수 있으며 요청 라우팅과 SSL도 추가할 수 있음
- 애플리케이션의 설정을 다양한 환경에서 재사용하려면 애플리케이션을 파라미터화 해야함
Ch2. 개발자 워크플로
2.2 개발 클러스터 구축
- 대규모 단일 개발 클러스터는 개발자별 클러스터에 비해 효율적임
- 개발자 사이의 충돌은 충분히 관리가 가능
2.3 다중 개발자를 위한 공용 클러스터 구축
- 쿠버네티스의 네임 스페이스 이용
- 서비스 배포 범위를 제한하여 특정 사용자의 프론트엔드 서비스가 다른 사용자의 프론트엔드 서비스에 피해를 주지 않도록
2.3.1 사용자 온보딩
- 쿠버네티스 클러스터 접근 방법
- 증명 기반 인증
- 새로운 증명을 생성하여 로그인에 사용할 수 있는 kubeconfig파일 전달
- 외부 신원 시스템 ⇒ 신원 데이터를 한곳에서 관리할 수 있어 모범 사례
- aws Identity and Access Managament(IAM)을 이용해 클러스터 접근 설정
- 증명 기반 인증
2.3.2 네임스페이스 생성과 보안
- 일반적으로 annotation 형태
- 환경 안의 사용자에게 RoleBinding
- 클러스터의 시크릿 리소스에 접근할 수 있기 때문에 읽기 권한을 부여할 때에는 주의해야 함
- 틀정 네임스페이스의 리소스 사용량을 제한하고 싶다면 리소스 쿼터(ResourceQuota)를 사용
2.3.3 네임스페이스 관리
- 네임스페이스 할당 방법
- 개발자에게 네임스페이스 부여 → 가비지 컬렉션 어려움
- TTL (time to live)로 네임 스페이스를 임시로 생성하여 할당 → 네임스페이스 삭제 자동화 구축 가능
- 네임스페이스를 조사하여 TTL이 만료된 것들을 삭제하는 스크립드를 생성
- 쿠버네티스와 통합한다면 kubectl 도구를 이용하여 네임스페이스를 생성하고 할당할 수 있는 사용자 리소스 정의 (CRD) 구현 가능
- RBAC : 선언적으로 네임스페이스를 관리
2.3.4 클러스터 단위의 서비스
- 클러스터 단위의 서비스 : IAAS(Infrastructure As A Service)
- kubectl logs를 이용하여 로그에 접근이 가능하지만, 길이 제한이 있으며 검색이 불가
2.6 반복적 개발
- 컨테이너 이미지를 빌드하고 푸시한 후에는 이를 클러스터에서 실행
- 가용성이 중요하지 않기 때문에 새로운 코드를 배포하는 가장 쉬운 방법은 기존 Deployment를 삭제하고 새로운 이미지를 가르키는 Deployment를 생성하는 것 → 모범 사례
- 기존 Deployment를 직접 수정하면 디플로이먼트 리소스 롤아웃 로직이 동작하여 위험
- 가용성이 중요하지 않기 때문에 새로운 코드를 배포하는 가장 쉬운 방법은 기존 Deployment를 삭제하고 새로운 이미지를 가르키는 Deployment를 생성하는 것 → 모범 사례
2.8 개발 환경 설정 모범 사례
- 개발자 경험을 온보딩, 개발, 테스팅 세단계로 나누어 생각
- 대규모 단일 클러스터가 더 나은 방법
- 클러스터 사용자 추가시 사용자 신원을 추가하고 자신의 네임스페이스에만 접근 허용, 사용할 수 있는 리소스 크기는 제한
- 스크립트를 이용해 네임스페이스 정리 자동화
- 로그와 모니터링 같은 클러스터 수준의 서비스를 고민
Ch3. 모니터링과 로깅
3.1 메트릭 vs 로그
- 메트릭 : 특정 기간에 측정한 일련의 숫자
- 로그 : 시스템을 탐색적으로 분석하기 위해 사용
3.2 모니터링 기술
- 블랙박스 모니터링 : 애플리케이션 외부에 초점
- 인프라 수준의 모니터링에 유용
- 애플리케이션 동작을 파악하는데는 어려움
- 화이트박스 모니터링 : 애플리케이션 상태에 초점
3.3 모니터링 패턴
- 쿠버네티스에서는 파드가 매우 동적이며 라이프 사이클이 짧으므로 쿠버네티스만의 특성을 고려하여 모니터링을 진행해야 함
- 분산시스템 모니러팅 패턴 (USE와 RED는 서로 상호 보완적)
- USE : 인프라 컴포넌트에 초점
- Utilization : 사용률
- Saturation : 포화도
- Error : 오류율
- RED : 사용자의 서비스 사용 경험에 더욱 초점 (최종 UX 모니터링에 초점)
- Request : 요청
- Error : 오류율
- Duration : 소요 시간
- USE : 인프라 컴포넌트에 초점
3.4 쿠버네티스 메트릭 개요
- 쿠버네티스 컴포넌트
- 컨트롤 플레인 컴포넌트
- API 서버, etcd, 스케줄러, 컨트롤러 관리자
- 워커 노드
- kubelet, 컨테이너 런타임, kube-proxy, kube-dns 파드
- 컨트롤 플레인 컴포넌트
3.4.1 cAdvisor
- 실행중인 컨테이너의 리소스와 메트릭 수집
3.4.2 메트릭 서버
- 쿠버네티스 메트릭 서버와 API
- 리소스 메트릭 API의 표준 구현체가 메트릭 서버
- CPU와 메모리 같은 리소스 메트릭 수집
- HPA(horizontal pod autoscaler), VPA(vertical pod autoscaler)에서 사용됨
- 사용자 정의 메트릭 API를 이용해 모니터링 시스템에서 임의의 메트릭 수집 가능
- 리소스 메트릭 API의 표준 구현체가 메트릭 서버
3.4.3 kube-state-metrics
- 쿠버네티스에 저장된 오브젝트를 모니터링 할 수 있는 쿠버네티스 추가 기능
3.6 모니터링 도구
- 프로메테우스
- 시스템 모니터링과 알림, 툴킷 오픈 소스
- InfluxDB
- 높은 쓰기와 질의 부하를 처리하도록 설계된 시계열 데이터베이스
- 데이터 독
- 클라우드 규모의 애플리케이션을 위한 모니터링 시스셈 (SaaS 기반 데이터 분석 플랫폼을 통해 서버 모니터링 가능)
- 시스딕
- 컨테이너 네이티브 앱을 위한 도커와 쿠버네티스 모니터링 제공 상용 도구
- 클라우드 공급자 도구
- GCP 스택 드라이버
- 구글 쿠버네티스 엔진 클러스터를 모니터링하도록 설계
- 컨테이너를 위한 마이크로소프트 애저 모니터
- 컨테이너 워크로드의 성능을 모니터링
- AWS 컨테이너 인사이트
- 아마존 클라우드 워치 컨테이너 인사이트
- GCP 스택 드라이버
- ⇒ 시계열 데이터 베이스는 키/값 쌍으로 저장하기 때문에 높은 수준의 메트릭 속성을 보여줄 수 있음
3.7 프로메테우스 모니터링
- 메트릭 수집을 위해 풀 모델 사용
- 쿠버네티스는 프로메테우스 포맷으로 메트릭을 보내어 간단하게 메트릭 수집 가능
- 클러스터와 별도의 유틸리티 클러스터에서 모니터링 하는 것이 모범 사례
- 프로메테우스 서버
- 시스템으로부터 수집된 메트릭을 가져와 저장
- 프로메테우스 오퍼레이터
- 프로메테우스 설정을 쿠버네티스 네이티브로 만듦
3.8 로깅 개요
- 쿠버네티스 감사 로그는 보안 모니터링 앱
- 로그를 중앙레포지토리에 보내는 방법
- 모든 애플리케이션 로그를 표준 출력으로 보내기
- 통일된 방법으로 로깅 가능 → 모니터링 데몬은 도커 데몬으로 부터 직접 로그 수집
- 사이드카 패턴
- 쿠버네티스 파드 안의 애플리케이션 컨테이너 옆에 로그를 전달하는 컨테이너를 실행
- 모든 애플리케이션 로그를 표준 출력으로 보내기
3.10 EFK 스택을 사용한 로깅
- 로깅 플랫폼이 관리하는 것이 정말 가치있는 일인지 잘 생각해보기
3.11 알림
- 즉각 대응할 필요 없는 알림 처리 방법
- 자동으로 해결하도록 하기 (메모리 확보를 위한 로그 삭제, 생명성 프로브를 이용해서 응답없는 프로세스 자동 복원 등)
- 5분 이하의 알림 임계치를 적절하게 설정하여 거짓 알림을 최소화
Ch4. 설정, 시크릿, RBAC
4.1 컨피그맵과 시크릿을 통한 설정
- 쿠버네티스는 configmap과 secret resource를 이용해서 설정정보 전달
- 파드가 수신 정보를 저장하는 방식과 데이터가 etcd에 저장되는 방식이 다르다
4.1.1 ConfigMap
- 설정 정보를 파드에 전달 및 컨트롤러, CRD, 오퍼레이터 등 복잡한 시스템 서비스로도 정보를 제공
- 대상 : 민감하지 않은 문자열 데이터
- 파드에 볼륨을 마운트 하거나 환경 변수로 전달
4.1.2 Secret
- 시크릿 데이터는 보이지 않게 저장되고 처리되어야 함
- Base64로 인코딩 된 정보로 표현되는데, 암호화 되지 않음
- 타입
- generic : 일반적 키/값 쌍
- docker-registry : 개인 도커 레지스트리 인증에 필요한 신원, image Pullsecret에서 이 신원을 저장하면 kubelet이 파드 템플릿으로 전달
- tls : 공개/개인 키 쌍으로 전송 계층 보안(TLS) 시크릿을 생성
- 시크릿은 자신을 사용하는 파드가 있는 노드의 tmpfs에만 마운트 됨
- 파드가 종료될 때 시크릿은 삭제됨
- 기본적으로 시크릿은 etcd 데이터 스토리지에 평범한 텍스트로 저장되어 보안에 신경써야함
4.2 컨피그 맵과 시크릿 API 모범 사례
- 새로운 버전의 파드를 재배포 하지 않고 동적 변경을 위해서는 컨피그 맵과 시크릿을 볼륨으로 마운트
- 변경된 파일 데이터를 감지하고 필요에 따라서 재설정 하려면 애플리케이션을 파일 감시자로 설정
- 볼륨마운트 사용시 컨피그맵/ 시크릿이 생성되자마자 파드 명세서에 볼륨을 추가해야하고, volumeMounts.subPath 속성을 사용해서 컨피그맵/ 시크릿을 마운트 하면 안된다.
- Admission controller를 사용하여 특정 설정 데이터를 확인하고 특정 설정 값이 존재하지 않는 경우 배포를 막을 수 있음
- 헬름을 사용하여 사용자 환경에 앱을 배포하는 경우 라이프 사이클 훅을 통해 Deployment를 적용하기 전에 컨피그맵, 시크릿 템플릿이 배포되었는지 확인해야 함
- 일부 애플리 케이션은 JSON 이나 YAML 파일 등 단일 설정 파일로 만들어야 함
- 시스템 환경 변수를 이용해서 컨피그 맵 데이터 주입 가능
- envFrom, configMapRef or secretRef 통해 마운트
- 이때, 부적합 하다고 간주되는 환경 변수값은 건너뛰지만 파드는 시작할 수 있음
- envFrom, configMapRef or secretRef 통해 마운트
- configMapKeyRef 또는 secretKeyRef 방법을 사용할 때 실제 키가 존재하지 않는 다면 파드 시작 불가
- 환경 변수 형태로 전달하는 경우 configmap/secret을 업데이트 하더라도 파드안의 값은 업데이트 되지 않음
- 파드를 삭제하고 replicaSet controller가 새로운 파드를 생성하여 재시작하거나 적절한 애플리케이션 업데이트 전략을 Deployment 명세에 선언하고 Deployment 업데이트를 통해 재시작 해야함
- 시크릿 모범 사례
- 쿠버네티스보다 더 높은 수준의 암호화 및 감사기능을 제공하는 외부 스토리지 시스템 사용 가능
- 파드가 자동 마운트를 하기 위해서 imagePull Secrets를 service account에 할당
4.3 RBAC
- 대규모 분산 환경의 경우 특정 보안 매커니즘을 통해 중요시스템에 대한 무단 접근을 방지
- 대상 : 컴포넌트
- 사용자와 그룹은 권한 모듈을 이용해 쿠버네티스에서 관리
- 규칙
- 특정 객체 또는 객체 그룹에 실행할 수 있는 기능 목록
- 롤
- 정의된 규칙을 적용할 범위
- 롤바인딩을 통해 사용자, 그룹과 같은 대상을 특정 롤에 매핑 가능
4.3.2 RBAC 모범 사례
- 애플리케이션 코드가 실제로 쿠버네티스 API와 직접 상호작용할 때만 RBAC 설정 필요
- 단기간 권한 상향이 필요한 사용자들이 구체적인 작업을 진행할 수 있도록 해야함
- 배포될 CI/CD 도구를 위해 특정 서비스 계정을 사용해야함
- 네임스페이스에 대한 범위가 지정된 틸러(기본 서비스 계정) 전용 서비스 계정을 사용하여 각 네임스페이스에 틸러를 배포하는 것이 좋음
- 시크릿 API에 접근해야 한다면 직접 할당된 시크릿 이외의 것들에 대한 get 사용을 제한해야함
'네트워크 & 인프라' 카테고리의 다른 글
Docker /usr/local/Homebrew is not writable, Cannot connect to the Docker daemon 문제 해결 (0) 2024.06.04 Kotlin + SpringBoot + Kafka 연동해보기 ( + spring kafka 와 reactor kafka ) (0) 2022.11.25 AWS 컨테이너 ( ECS, EKS, 파게이트, ECR ) (0) 2022.11.04 ArgoCD (0) 2022.11.02 아파치 카프카 (0) 2022.10.26