U E D R , A S I H C RSS

KubernetesINACTION/밑줄긋기 (rev. 1.209)

KubernetesINACTION/밑줄긋기

  1. KubernetesINACTION/밑줄긋기
  2. KubernetesINACTION/밑줄긋기/스터디

Contents

1. 쿠버네티스 소개
2. 도커와 쿠버네티스 첫걸음
2.1. 도커를 사용한 컨테이너 이미지 생성, 실행, 공유하기
2.2. 쿠버네티스 클러스터 설치
2.3. 쿠버네티스에 첫 번째 애플리케이션 실행하기
3. 파드: 쿠버네티스에서 컨테이너 실행
3.1. 파드 소개
3.2. YAML또는 JSON 디스크립터로 파드 생성
3.3. 레이블을 이용한 파드 구성
3.4. 레이블 셀렉터를 이용해 파드 부분 집합 나열
3.5. 파드에 어노테이션 달기
3.6. 네임스페이스를 사용한 리소스 그룹화
3.7. 파드 중지와 제거
4. 레플리케이션과 그 밖의 컨트롤러: 관리되는 파드 배포
4.1. 파드를 안정적으로 유지하기
4.2. 레플리케이션컨트롤러 소개
4.3. 레플리케이션컨트롤러 대신 레플리카셋 사용하기
4.4. 데몬셋을 사용해 각 노드에서 정확히 한개의 파드 실행하기
4.5. 완료 가능한 단일 태스크를 수행하는 파드 실행
4.6. 잡을 주기적으로 또는 한 번 실행되도록 스케줄링하기
5. 서비스: 클라이언트가 파드를 검색하고 통신을 가능하게 함
5.1. 서비스 소개
5.2. 클러스터 외부에 있는 서비스 연결
5.3. 외부 클라이언트에 서비스 노출
5.4. 인그레스 리소스로 서비스 외부 노출
5.5. 파드가 연결을 수락할 준비가 됐을 때 신호 보내기
5.6. 헤드리스 서비스로 개별 파드 찾기
5.7. 서비스 문제 해결
6. 볼륨: 컨테이너에 디스크 스토리지 연결
6.1. 볼륨 소개
6.2. 볼륨을 사용한 컨테이너 간 데이터 공유
6.3. 워커 노드 파일시스템의 파일 접근
6.4. 퍼시스턴트 스토리지 사용
6.5. 기반 스토리지 기술과 파드 분리
6.6. 퍼시스턴트볼륨의 동적 프로비저닝
7. 컨피그맵과 시크릿: 애플리케이션 설정
7.1. 컨테이너화된 애플리케이션 설정
7.2. 컨테이너에 명령줄 인자 전달
7.3. 컨테이너의 환경변수 설정
7.4. 컨피그맵으로 설정 분리
7.5. 시크릿으로 민감함 데이터를 컨테이너에 전달
8. 애플리케이션에서 파드 메타데이터와 그 외의 리소스에 액세스하기
8.1. Downward API로 메타데이터 전달
8.2. 쿠버네티스 API 서버와 통신하기
9. 디플로에먼트: 선언적 애플리케이션 업데이트
9.1. 파드에서 실행 중인 애플리케이션 업데이트
9.2. 레플리케이션컨트롤러로 자동 롤링 업데이트 수행
9.3. 애플리케이션을 선언적으로 업데이트하기 위한 디플로이먼트 사용하기
10. 스테이트풀셋: 복제된 스테이트풀 애플리케이션 배포하기
10.1. 스테이트풀 파드 복제하기
10.2. 스테이트풀셋 이해하기
10.3. 스테이트풀셋 사용하기
10.4. 스테이트풀셋의 피어 디스커버리
10.5. 스테이트풀셋이 노드 실패를 처리하는 과정 이해하기
11. 쿠버네티스 내부 이해
11.1. 아키텍쳐 이해
11.1.1. 쿠버네티스 구성 요소의 분산 특성
11.1.2. 쿠버네티스가 etcd를 사용하는 방법
11.1.3. API 서버의 기능
11.1.4. API 서버가 리소스 변경을 클라이언트에 통보하는 방법 이해
11.1.5. 스케줄러 이해
11.1.6. 컨트롤러 매니저에서 실행되는 컨트롤러 소개
11.1.7. Kubelet이 하는 일
11.1.8. 쿠버네티스 서비스 프록시의 역할
11.1.9. 쿠버네티스 애드온 소개
11.1.10. 모든 것을 함께 가져오기
11.2. 컨트롤러가 협업하는 방법
11.3. 실행 중인 파드에 관한 이해
11.4. 파드 간 네트워킹
11.5. 서비스 구현 방식
11.6. 고가용성 클러스터 실행
12. 쿠버네티스 API 서버 보안
12.1. 인증 이해
12.2. 역할 기반 액세스 제어로 클러스터 보안
13. 클러스터 노드와 네트워크 보안
13.1. 파드에서 호스트 노드의 네임스페이스 사용
13.2. 컨테이너의 보안 컨텍스트 구성
13.3. 파드의 보안 관련 기능 사용 제한
13.4. 파드 네트워크 격리
14. 파드의 컴퓨팅 리소스 관리
14.1. 파드 컨테이너의 리소스 요청
14.2. 컨테이너에 사용 가능한 리소스 제한
14.3. 파드 QoS 클래스 이해
14.4. 네임스페이스별 파드에 대한 기본 요청과 제한 설정
14.5. 네임스페이스의 사용 가능한 총 리소스 제한하기
14.6. 파드 리소스 사용량 모니터링
15. 파드와 클러스터 노드의 오토스케일링
15.1. 수평적 파드 오토스케일링
15.2. 수직적 파드 오토스케일링
15.3. 수평적 클러스터 노드 확장
16. 고급 스케줄링
16.1. 테인트와 톨러레이션을 사용해 특정 노드에서 파드 실행 제한
16.2. 노드 어피니티를 사용해 파드를 특정 노드로 유인하기
16.3. 파드 어피니티와 안티-어피니티를 이용해 파드 함께 배치하기
17. 애플리케이션 개발을 위한 모범 사례
18. 쿠버네티스의 확장

1. 쿠버네티스 소개

* p37
  • 몇 년 전만 하더라도 대부분의 소프트웨어 어플리케이션은 하나의 프로세스 또는 몇 개의 서버에분산된 프로세스로 실행되는 거대한 모놀리스(monolith)였다.
    • 쿠베 전에는 통합을 하려는 시도로 Hadoop등이 각광을 받긴했었지. 근데 이것도 모노리스라고해야하나 - 김준석
      • 저는 하둡 내에 여러 로직이 각기 atomic하게 별개에 service 로 구분 되어 있지 않아서 모노리스라고 생각합니다. 물론 플랫폼이라 애매하긴 합니다. - bluemir
* p38
  • 쿠버네티스는 개발자가 운영 팀의 도움 없이도 자신의 애플리케이션을 원하는 만큼 자주 배포할 수 있도록 한다.
* p39
  • 쿠버네티스는 하드웨어 인프라를 추상화하고 데이터 센터 전체를 하나의 거대한 컴퓨팅 리소스로 제공한다
    • 쿠버네티스가 하드웨어 인프라를 추상화하는 방법도 나중에 나오려나? 궁금하다 - 서지혜
      • yes, GCP 도 autopilot 이라는 것을 제공하고, VM layer 없이 바로 추상화 계층을 구성하는 경우도 있습니다. - bluemir
* p40
  • 모놀리스 어플리케이션의 일부분이 수평적으로 확장하기 매우 어렵거나 불가능하고, 어떻게든 분할할 수 없다면 전체 어플리케이션을 확장할 수 없다.
    • MSA의 가장 중요한 기본 사상이긴 한데.. 모놀리틱한 케이스에도 서비스가 이정도인건 거의 못본것 같고, DB에 대한 예시지.. - 김준석
      • 복잡한 케이스에서는 사실이기도 합니다. Message Queue 구조나, 혹은 Video encoding에서는 이게 불가능해서 문제가 되는 경우가 있더라구요. - bluemir
* p41
  • 마이크로서비스는 일반적으로 RESTFul API를 제공하는 HTTP와 같은 동기 프로토콜과 AMQP와 같은 비동기 프로토콜로 통신한다.
  • 각 마이크로서비스는 대체로 정적인 외부 API를 제공하는 독립형 프로세스이기 때문에 개별적으로 개발, 배포할 수 있다.
    • 이번에 MSA를 추진하면서 적당한 프로토콜을 살펴보고 있는데 AMQP도 찾아봐야겠다. MSA 지향하면서 왜 중앙화 시스템을 얘기하는건지.. - 서지혜
      • GRPC 쓰셔요.ㅎㅎ - AMQP 를 중앙화 해서 사용할수도 있지만 각 Service별로도 분리해서 다 따로 쓰는 케이스를 염두해 둔것 아닐까요? 그렇게 쓰는 경우도 있더라구요. -bluemir
* p44
  • 시스템 관리자가 최신 보안 패치를 사용해 시스템을 최신 상태로 유지하는 데 주안점을 두는 데 반해, 많은 개발자는 그렇지 않다는 점이 두 시스템 간의 큰 차이를 만들게 된다.
    • 우리 회사에서는 개발자들 간에 보수와 진보로 나뉘어져 싸우는걸 보느라면은... 암호나 일단 제대로 걸라고요 - 김준석
* p45
  • 개발자가 프로덕션 환경에서 애플리케이션을 실행하는 데 더 많이 관여하게 되면, 사용자가 무엇을 필요로 하고 어떤 문제가 있는지, 운영 팀이 애플리케이션을 유지하면서 직면하는 문제가 무엇인지 더 잘 이해할 수 있다.
    • 개발자가 운영도 하게되는 DevOps는 저주다 - 서지혜
    • 풀스택에 이은 총괄 노예의 새로운 단어 - 김준석
* p46
  • 하드웨어 인프라를 전혀 알지 못하더라도 운영 팀을 거치지 않고 개발자가 애플리케이션을 직접 배포하는 방식이 가장 이상적이다. 이를 노옵스(NoOPs)라고 한다.
* p47
  • 가상머신을 사용해 각 마이크로서비스의 환경을 격리하는 대신 개발자들은 리눅스 컨테이너 기술로 눈을 돌렸다.
  • 컨테이너에서 실행되는 프로세스는 다른 모든 프로세스와 마찬가지로 호스트 운영체제 내에서 실행된다. 그러나 컨테이너의 프로세스는 여전히 다른 프로세스와 격리돼 있다.
    • 가상머신과 컨테이너의 차이가 뭐지?! - 서지혜
  • 컨테이너를 가상머신과 비교하면 컨테이너는 훨씬 더 가벼워서 동일한 하드웨어에서 더 많은 수의 소프트웨어 구성 요소를 실행할 수 있다. 가상머신은 구성 요소 프로세스뿐만 아니라 시스템 프로세스를 실행해야 하기 때문에 추가 컴퓨팅 리소스가 필요하다.
    • 가상머신이 컨테이너보다 무거운가 보군! - 서지혜
      • 제일 큰 차이는 container는 kernel(및 커널 메모리, 디바이스 드라이버 등등)을 공유하지만, VM 은 그렇지 않다는것이죠. 당연히 구조상 container 가 훨씬 lightweight 합니다. 다만 container 는 그냥 환경 독립적인 Process 로 보는게 더 좋긴 해요. - bluemir
* p49
  • 컨테이너는 호스트 OS에서 실행되는 동일한 커널에서 시스템 콜을 수행한다.
    • 가상머신은 게스트OS가 하이퍼바이저로 추상화된 호스트OS를 사용하지만 컨테이너는 호스트OS를 직접 사용하기 때문에 더 가벼운 거구나 - 서지혜
  • 이 커널은 호스트의 CPU 에서 x86의 명령을 수행하는 유일한 커널이다.
    • 컨테이너가 커널에 의존성이 있는것으로 보이지만, 리눅스 규약상 컨테이너는 자신이 묶인 커널에 대한 소스를 이진 코드로 내부적으로 어떤 커널 버전에서도 호환되게 가지고 있기 때문에 커널 버전에 상관없이 내부 어플리케이션은 돌아갈수 있다.가 정론인데.. 쿠베 이미지가 우분투 14, 16, 18/ centOS 외에 본적이 없어서 뻑나는지도 모르겠네. - 김준석
      • syscall만 호환되면 되서요. 다른 이미지쓰는 경우도 많이 봤지만 뻑나는 경우는 못봤습니다. -bluemir
* p51
  • 컨테이너 격리를 가능하게 하는 메커니즘 소개
  • 두 가지 메커니즘으로 가능하다.
  • 첫 번째는 리눅스 네임스페이스(namespace)로 각 프로세스가 시스템에 대한 독립된 뷰만 볼 수 있도록 한다. 두 번째는 리눅스 컨트롤 그룹(cgroups)으로, 프로세스가 사용할 수 있는 리소스의 양을 제한한다.
    • 리눅스에서만 동작할 것 같은 느낌 - 서지혜
      • yes, linux kernel 기술이니까요. - bluemir
    • chroot와 다른점은 마운트 패스 뿐 아니라 모든 리소스에대해 적용한다는것 - 김준석
* p52
  • 컨테이너 기술은 오랫동안 사용돼 왔지만 도커 컨테이너 플랫폼의 등장으로 더 널리 알려지게 됐다.
    • Linux 컨테이너 기술은 2006년부터 연구되어왔고, 도커 초창기 라이브러리는 리눅스컨테이너 라이브러리를 참고하고있었다. 하지만 요즘은 linux 컨테이너에서 제공되지 않는 기능과 버전 종속성을 벗어나기 위해 독자적 라이브러리를 구축함 - 김준석
* p57
  • 컨테이너의 프로세스가 기본 레이어 중 하나에 있는 파일에 쓰면 전체 파일의 복사본의 최상위 레이어에 만들어지고 프로세스는 복사본에 쓴다.
    • 현재는 overlayFS2를 쓰고있는것으로 앎. 당근 버전업은 overlayFS에 스펙을 추가한거고 도커 버전이 업되면 신경쓸일 없음. - 김준석
* p58
  • 머신이 다른 버전의 리눅스 커널로 실행되거나 동일한 커널 모듈을 사용할 수 없는 경우 어플리케이션이 실행 될 수 없다.
    • 다른 커널 버전 OS에서 컨테이너가 전혀 돌아가지 않는다는 소리를 좀 해야할것 같은데. Linux Standard Base(LSB)로 ISO 표준 시스템 콜 API은 호환이 되어서 되긴할껀데.. 아마 minimum kernel 버전을 요구하는데도 있을거고.. https://en.wikipedia.org/wiki/Linux_Standard_Base - 김준석
* p59
  • 구글은 10년동안 보그와 오메가를 비밀로 유지하다가 2014년 보그, 오메가, 기타 내부 구글 시스템으로 얻은 경험을 기반으로 하는 오픈소스 시스템인 쿠버네티스를 출시했다.
    • 구글이 Hadoop으로 배운게 컸나보네 - 서지혜
* p61
  • 서비스 디스커버리, 스케일링, 로드밸런싱, 자가 치유, 리더 선출 같은 것들이 포함된다.
* p62
  • 마스터 노드는 전체 쿠버네이트 시스템을 제어하고 관리하는 쿠버네티스 컨트롤 플레인을 실행한다. 워커 노드는 실제 배포되는 컨테이너 애플리케이션을 실행한다
    • 마스터-워커 구성은 클러스터 시스템들의 기본 아키텍쳐로구만 - 서지혜
* p63
  • 저자는 (...) 동작 방식부터 설명하는 방식을 싫어한다.
    • 나는 지금 그게 알고싶은디 - 서지혜
      • k8s의 leader election은 그냥 근본은 etcd lease를 이용해서 timeout있는 lock을 주기적으로 갱신하는 것 입니다. raft와 유사합니다. - bluemir

* p66
  • kube-proxy는 서비스를 제공하는 모든 컨테이너에서 서비스 연결이 로드밸런싱되도록 한다.
    • 네트워크 설정에서 해방이다 만세!! - 김준석
      • 해보면 아니더라구요 ㅎㅎㅎ kubeproxy 의 네트워크 설정은 또 해줘야 합니다. - bluemir
* p68
  • 인프라에 장애가 발생한 노드가 없어도 정상적인 시스템 작동이 가능하도록 충분한 예비 자원이 있는 경우 운영 팀은 새벽 3시에 일어난 장애에 즉시 대응할 필요가 없다.
    • 동남아가 제발 하드좀 잘 관리해줬으면.. 예비 자원좀 - 김준석
    • 요건 트루입니다. 이러저런 운영 자동화를 통해서 95% 이상의 이벤트는 자동 처리할수 있고, 나머지는 다음날 봐도 될정도...

2. 도커와 쿠버네티스 첫걸음

2.1. 도커를 사용한 컨테이너 이미지 생성, 실행, 공유하기

  • p73
    • busybox( https://en.wikipedia.org/wiki/BusyBox)는 echo, ls, gzip 등과 같은 표준 UNIX 명령줄 도구들을 합쳐 놓은 단일 실행파일(executable)이라 할 수 있다.
      • busybox는 ubuntu 부팅할때 접해볼수 있는데 개별 명령어 대신 busybox로 대체한다. 부팅디스크를 이용한 OS 구동때는 ram에 공간을 만드는데, 빡빡하게 용량을 관리하기 때문에 busybox를 쓴다. - 김준석
  • p76



FROM node:7
ADD app.js /app.js
ENTRYPOINT ["node", "app.js"]
  • Dockerfile을 쓴지 오래되긴 했다. - 김준석
  • p79
    • 이미지라는 것이 하나의 큰 바이너리 덩어리가 아니라 여러개의 레이어로 구성된다는 것을 아마도 눈치챘을 것이다. 서로 다른 이미지가 여러 개의 레이어를 공유할 수 있기 때문에 이미지의 저장과 전송에 효과적이다.
    • 기본 이미지를 구성하는 모든 레이어는 단 한 번만 저장될 것이다. 또한 이미지를 가져올 때도 도커는 각 레이어를 개별적으로 다운로드 한다. 컴퓨터에 여러개의 레이어가 이미 저장돼 있다면 도커는 저장되지 않은 레이어만 다운로드 한다.
  • p80
    • Dockerfile을 이용하는 것이 훨씬 반복 가능하고 이미지 빌드를 자동화할 수 있는 방법이다.
      • image commit하는 사람도 의외로 많다. - 김준석
        • 그러면 나중에 CI는 어쩌려고... git도 아니고.. - bluemir
  • p82



$ docker exec -it kubia-container bash
  • 당연히 도커가 한번에 돌아가지 않기때문에 가장 많이 쓰는 구문 - 김준석
  • p84
    • 컨테이너는 자체 리눅스 PID 네임스페이스를 사용하며 고유의 시퀀스 번호를 가지고 완전히 분리된 프로세스 트리를 갖고 있다.
      • container의 PID 밑 Conatainer 내부 init 프로세스를 기준으로 tree가 생긴다. - 김준석
    • 격리된 프로세스를 가진 것과 마찬가지로 각 컨테이너는 격리된 파일시스템을 갖고 있다.
      • default 위치로 host에서 접근을 할수 있는것으로 알고있고 파일 교환을 위한 mount path지정도 가능 - 김준석
  • p85
    • 작업을 단순화하기 위해 사설 이미지 레지스트리를 설정하기보다는 공개적으로 사용할 수 있는 레지스트리 중 하나인 도커 허브에 이미지를 푸시한다.
      • 사설 이미지 레지스트리가 중요한데 - 김준석

2.2. 쿠버네티스 클러스터 설치

  • 직접 설치해보자 - 서지혜
  • p87
    • 세 번째 옵션은 kubeadm 도구를 사용해 클러스터를 설치하는 방법으로, 부록B에서 설명한다. 이 책의 11장까지 읽어본 뒤 시도해볼 것을 추천한다.
      • 이걸 제일 많이 쓰는것 같은데 - 김준석
    • 또 다른 옵션은 AWS에 쿠버네티스를 설치하는 것이다.
      • 로드 테스트할때 AWS에 구성된걸 사용하더라 - 김준석
  • p89
    • darwin을 windows로 변경하고 맨 뒤에 .exe를 추가한다.
      • 왜 mac의 darwin이 기본인가?
  • p91
    • 빌링을 활성화한다. 신용카드 정보가 필요하지만 구글은 12개월 무료 평가판을 제공한다.
  • p92
    • 각 노드는 도커, kubelet, kube-proxy를 실행한다.
      • 도커위에 kubelet, kube-proxy가 올라가있는거였던가 - 김준석
        • 구성에 따라 다를수는 있는데 일반적으로 kubelet 은 별도systemdaemon 으로 kube-proxy 는 pod으로 올라갑니다. - bluemir
  • p94
    • kubectl alias와 명령줄 자동완성 설정하기
      • kubectl kubectl 계속치면 k로 alias를 하게 되더라 - 김준석
    • k와 같은 짧은 별칭을 사용하더라도 생각보다 많은 명령어를 입력해야 한다.

2.3. 쿠버네티스에 첫 번째 애플리케이션 실행하기

  • p97
    • 쿠버네티스는 개별 컨테이너들을 직접 다루지 않는다. 대신 함꼐 배치된 다수의 컨테이너라는 개념을 사용한다. 이 컨테이너의 그룹의 이름을 파드라고 한다.
      • POD는 여러개의 컨테이너가 들어갈수 있음. - 김준석
    • 각 파드는 자체 IP, 호스트 이름, 프로세스 등이 있는 논리적으로 분리된 머신이다.
      • 머신이지만 os가 없는 느낌? 자원관리 등을 다 상위에서 해주니 논리적으로 머신이기만 함 - 김준석
      • 요건 오해의 소지가 있는 설명이긴 하네요. 이해를 돕기위해 의도적인 왜곡인것 같긴 하지만... - bluemir
  • p98
  • p99
    • kubectl 명령어를 실행하면 쿠버네티스의 API 서버로 REST HTTP 요청을 전달하고 클러스터에 새로운 레플리케이션컨트롤러 오브젝트를 생성한다.
      • 클라이언트 -> 서버 -> 명령 수행 - 김준석
  • p100
    • 외부에서 파드에 접근을 가능하게 하려면 서비스 오브젝트를 통해 노출해야 한다.
    • 파드와 마찬가지로 일반적인 서비스(Cluster IP 서비스)를 생성하면 이것은 클러스터 내부에서만 접근 가능하기 때문에 Load Balancer 유형의 특별한 서비스를 생성해야 한다.
      • 로드밸런서 생성은 처음 본듯 - 김준석
        • 외부에서 Traffic 받을려면 가장 simple한 방법이라... 오히려 node port 방식이 더 드물긴 합니다. - bluemir
  • p101
    • kubectl expose rc kubia --type=LoadBalancer --name kubia-http
    • kubernetes 서비스에 관한 설명은 생략
  • p103
    • kubectl run 명령을 수행하면 레플리케이션컨트롤러를 생성하고 레플리케이션컨트롤러가 실제 파드를 생성한다.
    • 마스터 노드가 단일 마스터 노드에서 호스팅 중인지 혹은 여러 대의 마스터 노드에 분산된 것인지 알 수 없다.
  • p104
    • 레플리케이션컨트롤러는 사라진 파드를 대체하기 위해 새로운 파드를 생성할 것이다.
    • 파드는 일시적(ephermeral)이다.
    • 새로운 파드는 다른 IP 주소를 할당받는다. 이것이 바로 서비스가 필요한 이유다.
  • p106
    • kubectl scale rc kubia --replicas=3
    • kubectl get rc

  • p107
    • 서비스는 다수 파드 앞에서 로드밸런서 역할을 한다. 파드가 하나만 있으면 서비스는 이 파드 하나에 정적 주소를 제공한다.

  • p109
    • 어떤 노드에 파드가 스케줄링됐는지 궁금할 수 있다. 쿠버네티스에서는 파드가 적절히 실행하는 데 필요한 CPU와 메모리를 제공하는 노드에 스케줄링됐다면, 어떤 노드에 파드가 실행 중인지는 중요하지 않다.
    • 파드를 조회할 때 파드 IP와 실행 중인 노드 표시하기
    • {{ $ kubectl get pods -o wide }}}
  • p110
    • 쿠버네티스 또한 꽤 멋진 웹 대시보드를 함께 제공한다는 점을 알게 되면 기뻐할 것이다.
      • 실제로 하드하게 써보면 별로 안기쁘더라구요 - bluemir

3. 파드: 쿠버네티스에서 컨테이너 실행

3.1. 파드 소개

  • p114
    • 파드는 함께 배치된 컨테이너 그룹이며 쿠버네티스의 기본 빌딩 블록이다.
    • 모든 컨테이너는 항상 하나의 워커 노드에서 실행되며 여러 워커 노드에 걸쳐 실행되지 않는다.
      • 궁금했던 부분. 리소스를 테트리스는 어려운거군 - 서지혜
    • IPC 혹은 로컬 파일을 통해 통신하는 여러 프로세스로 구성돼, 같은 노드에서 실행해야 하는 애플리케이션을 상상해보자.
    • 모든 프로세스는 동일한 표준 출력으로 로그를 기록하기 때문에 어떤 프로세스가 남긴 로그인지 파악하는 것이 매우 어렵다.
  • p116
    • UTC 네임스페이스
    • 비슷하게 파드의 모든 컨테이너는 동일한 IPC 네임스페이스 아래에서 실행되 IPC를 통해 서로 통신할 수 있다.
    • 플랫한 공유 네트워크 주소 공간에 상주하므로 모든 파드는 다른 파드의 IP주소를 사용해 접근하는 것이 가능하다.
  • p117
    • 파드 사이에서 통신은 항상 단순하다. 두 파드가 동일 혹은 서로 다른 워커 노드에 있는지는 중요하지 않으며, 두 경우 모두 파드 안에 있는 컨테이너는 NAT 없는 플랫 네트워크를 통해 서로 통신하는 것이 가능하다,
      • 이거 파드 하나 들어가서 다른 서비스들 다 털 수 있는거 아닙니까 - 서지혜
        • 실제 공격 기법입니다. 그래서 node를 분리하거나 gVisor를 쓰거나 policy based network 로 보완하거나 합니다. - bluemir
    • 이것은 실제 노드 간 네트워크 토폴로지와 관계없이, 근거리 네트워크에 있는 컴퓨터 간의 통신과 비슷하다.
    • 파드는 논리적인 호스트로서 컨테이너가 아닌 환경에서의 물리적 호스트 혹은 VM과 매우 유사하게 동작한다.
  • p118
    • 파드에서 컨테이너의 적절한 구성
    • 파드는 스케일링의 기본 단위다.
      • 최근에 여러 파드로 쪼개놓은 서버들을 굳이 굳이 한 파드로 만들어놓은 걸 보고 의아했던 기억 - 서지혜
        • 모놀리틱에 익숙한 분들을 자주 그렇게 구성하시더라구요. pod 을 하나의 가상머신이라고 설명하면 이런 오용/남용 들이 생기기 쉬운것 같습니다. - bluemir
  • p119
    • 프론트엔드 구성 요소는 백엔드와 완전히 다른 스케일링 요구 사항을 갖고있어 개별적으로 확장하는 경향이 있다.
    • 사이트카 컨테이너의 다른 예제로는 로그 로테이터와 수집기, 데이터 프로세서, 통신 어댑터 등이 있다.

3.2. YAML또는 JSON 디스크립터로 파드 생성

  • p121
    • $ kubectl get po kubia-zxzij -o yaml
  • p123
    • 거의 모든 쿠버네티스 리소스가 갖고 있는 세 가지 중요한 부분이 있다. Metadata, spec, status
    • Metadata: 이름, 네임스페이스, 레이블 및 파드에 관한 기타 정보를 포함한다.
    • Spec: 파드 컨테이너, 볼륨, 기타 데이터 등 파드 자체에 관한 실제 명세를 가진다.
    • Status: 파드 상태, 각 컨테이너 설명과 상태, 파드 내부 IP, 기타 기본 정보 등 현재 실행 중인 파드에 관한 현재 정보를 포함한다.
  • p125
    • kubectl explain
  • p126
    • $ kubectl create -f kubia-manual.yaml
  • p128
    • $ kubectl logs kubia-manual -c kubia

3.3. 레이블을 이용한 파드 구성

  • p130
    • 파드 수가 증가함에 따라 파드를 부분 집합으로 분류할 필요가 있다.
  • p131
    • 레이블은 리소스에 첨부하는 키-값 쌍으로, 이 쌍은 레이블 셀렉터를 사용해 리소스를 선택할 때 활용된다.
  • p133
    • kubectl get pods 명령은 레이블을 표시하지 않는 것이 기본값이라 --show-labels 스위치를 사용해 레이블을 볼 수 있다.
    • 모든 레이블을 나영하는 대신 특정 레이블에만 관심 있는 경우 해당 레이블을 -L 스위치로 지정해 각 레이블을 자체 열에 표시할 수 있다.

3.4. 레이블 셀렉터를 이용해 파드 부분 집합 나열

  • p135
    • $ kubectl get po -l creation_method=manual
    • $ kubectl get po -l '!env'
  • p137
    • 레이블 셀렉터는 파드 목록을 나열하는 것뿐만 아니라, 파드 부분 집합에 작업을 수행할 때도 유용하다.
  • p139
    • 쿠버네티스의 전체적인 아이디어는 그 위에 실행되는 애플리케이션으로부터 실제 인프라스트럭처를 숨기는 것에 있기에 파드가 어떤 노드에 스케줄링 돼야 하는지 구체적으로 지정하고 싶지는 않은 것이다. 그로 인해 애플리케이션이 인프라스트럭처에 결합되기 때문이다. 그러나 정확한 노드를 지정하는 대신 필요한 노드 요구 사항을 기술하고 쿠버네티스가 요구 사항을 만족하는 노드를 선택하도록 한다. 이는 노드 레이블과 레이블 셀렉터를 통해 할 수 있다.
    • 노드를 포함한 모든 쿠버네티스 오브젝트에 레이블을 부착할 수 있다.

3.5. 파드에 어노테이션 달기

  • p141
    • 레이블은 오브젝트를 묶는 데 사용할 수 있지만, 어노테이션은 그렇게 할 수 없다.
  • p142
    • 레이블에는 짧은 데이터를, 그에 비해 어노테이션에는 상대적으로 큰 데이터를 넣을 수 있다(총 256kb)까지.
      • 레이블은 63 char 로 제한되더라 - 김준석
        • ETCD 키 값이어서 그래요. 인덱싱하려다 보니... - bluemir

3.6. 네임스페이스를 사용한 리소스 그룹화

  • p143
    • 여러 네임스페이스를 사용하면 많은 구성 요소를 가진 복잡한 시스템을 좀 더 작은 개별 그룹으로 분리할 수 있다. 또한 멀티테넌트 환경처럼 리소스를 분리하는 데 사용된다.
    • 리소스 이름은 네임스페이스 안에서만 고유하면 된다.
  • p145
    • 네임스페이스를 사용해 서로 관계없는 리소스를 겹치지 않는 그룹으로 분리할 수 있다.

3.7. 파드 중지와 제거

  • p148
    • 쿠버네티스는 SIGTERM 신호를 프로세스에 보내고 지정된 시간(기본값 30초) 동안 기다린다. 시간 내에 종료되지 않으면 SIGKILL 신호를 통해 종료한다. 프로세스가 항상 정상적으로 종료되게 하기 위해서는 SIGTERM 신호를 올바르게 처리해야 한다.
  • p151
    • $ kubectl delete all -all

4. 레플리케이션과 그 밖의 컨트롤러: 관리되는 파드 배포

4.1. 파드를 안정적으로 유지하기

  • p154
    • 컨테이너의 주 프로세스에 크래시(crash)가 발생하면 Kubelet이 컨테이너를 다시 시작한다.
      • 컨테이너가 서브 Process라서 모니터링이 가능한듯 - 김준석
    • 애플리케이션이 무한 루프나 교착 상태에 빠져서 응답을 하지 않는 상황이라면 어떨까? 이런 경우 애플리케이션이 다시 시작되도록 하려면 애플리케이션 내부의 기능에 의존하지 말고 외부에서 애플리케이션의 상태를 체크해야한다.
      • 우리 회사사람들은 다 내부에서 가능한걸로 봄. - 김준석
  • p155
    • 파드의 스펙에 각 컨테이너의 라이브니스 프로브를 지정할 수 있다. 쿠버네티스는 주기적으로 프로브를 실행하고 프로브가 실패할 경우 컨테이너를 다시 시작한다.
    • 쿠버네티스는 세가지 매커니즘을 사용해 컨테이너에 프로브를 실행한다. HTTP GET / TCP 소켓 / Exec
      • 아무래도 HTTP GET이 REST에 맞겠지 - 김준석
        • 네, 특정버전의 exec 는 hang 되는 문제가 있고, TCP 는 단지 socket listen 이라 warmup 문제가 있습니다. - bluemir
    • 최근에는 startup Probe 라는 시작될때 warmup 상황등을 별도로 체크할수도 있어요 - bluemir
  • p157
    • $ kubectl logs mypod --previous
      • Cheat sheet 추가 - 김준석
        • kubectl logs -p 도 됩니다. kubectl logs -l {라벨}도 꽤 유용합니다. - bluemir
    • 숫자 137은 두 숫자를 합한 값으로, 128 + X 다.
      • 유용한 정보 +1 SIGTERM(15) SIGKILL(9) - 김준석

4.2. 레플리케이션컨트롤러 소개

  • p154
    • 컨테이너의 주 프로세스에 크래시가 발생하면 Kublelet이 컨테이너를 다시 시작한다.
      • 컨테이너 모니터링은 어떻게 하는걸까 - 서지혜
        • 내부 구현으로는 docker inspect 입니다. docker inspect 는 container 내의 1번 process의 종료여부로 종료를 판단합니다. - bluemir
  • p155
    • 애플리케이션이 더 이상 제대로 동작하지 않는다는 신호를 쿠버네티스에 보내서, 쿠버네이트가 애플리케이션을 다시 시작하도록 하는 방법이 있다면 좋을 것이다.
      • 그래서 라이브니스 프로브 설정을 해야하는군 - 서지혜
    • 쿠버네티스는 라이브니스 프로브를 통해 컨테이너가 살아 있는지 확인할 수 있다.
    • 쿠버네티스는 세 가지 메커니즘을 사용해 컨테이너에 프로브를 실행한다.
      • HTTP GET 프로브는 지정한 IP 주소, 포트, 경로에 HTTP GET 요청을 수행한다. ... 응답 코드가 오류를 나타내지 않는 경우에 프로브가 성공했다고 간주된다.
      • TCP 소켓 프로브는 컨테이너의 지정된 포트에 TCP 연결을 시도한다. 연결에 성공하면 프로브가 성공한 것
        • TCP는 응답까지는 보지 않는구나 - 서지혜
      • Exec 프로브는 컨테이너 내의 임의의 명령을 실행하고 명령의 종료 상태 코드를 확인한다. 상태 코드가 0이면 프로브가 성공한 것이다.
  • p158
    • 크래시된 컨테이너의 애플리케이션 로그 얻기 $ kubectl logs mypod --previous
  • p159
    • 숫자 137은 두 숫자를 합한 값으로, 128 + x다. ...이 예에서 x는 SIGKILL 시그널 번호인 9이며, 프로세스가 강제로 종료됐음을 의미한다.
  • p162
    • 프로브에 자체적인 재시도 루프를 구현하는 것은 헛수고다.
      • 그럼 왜 임계값 정하라고 하는건데 - 서지혜
      • kubelet 이 재시도 루프를 관리해주니까 http probe endpoint 등에서는 별개로 구현해주지 말라는 이야기 같은데, 사실 구현하는 사람 맘이죠 - bluemir
    • 파드들은 Kubelet 에서만 관리되는데, Kubelet은 노드에서 실행되기 때문에 노드 자체가 고장 나면 아무것도 할 수 없다.
  • p164
    • 레플리케이션컨트롤러는 실행 중인 파드 목록을 지속적으로 모니터링하고, 특정 "유형"의 실제 파드 수가 의도하는 수와 일치하는지 항상 확인한다.
      • deploy??랑 뭐가 다른건지 모르겠네 - 김준석
        • deployment 가 replicasSet을 만듭니다. replicasSet은 replicasController에 의해 설명된 동작을 합니다. 굳이 2단 구성인 이유는 deploy 단에서 배포 전략( blueGreen/rolling update) 등을 고를수 있기 때문입니다. 하지만 일반적으로는 (사용하는 사람 입장에서) 거의 같은거긴 합니다. 제가 딴거랑 헷갈렸군요. 잊어주세요. - bluemir
    • 레플리케이션컨트롤러는 파드 유형이 아니라 특정 레이블 셀렉터와 일치하는 파드 세트에 작동한다.
      • 강조 밑줄 - 김준석
      • 레이블은 다른 서비스에서 보통 옵셔널하게 다뤄지는데 쿠베에서는 중요함 - 서지혜
  • p165
  • p166
    • 레이블 셀렉터와 파드 템플릿을 변경해도 기존 파드에는 영향을 미치지 않는다.
      • 갯수 관리만 중시하고 변경으로 인해 범위를 벗어난 파드에 대한 삭제/정지는 안하는듯 - 김준석
      • label이 잘못 지정된 Service들을 변경하고 싶은데.. 하필 타입이 LoadBalancer 라 마음이 찢어지는 중.. - 서지혜
  • p172
    • 레플리케이션컨트롤러는 노드의 파드가 다운됐음을 감지하자마자 파드를 대체하기 위해 새 파드를 기동한다.
      • K8S를 쓰는 이유중 자동 복구 - 김준석
  • p173
    • 노드가 몇 분 동안 접속할 수 없는 상태로 유지될 경우 해당 노드에 스케줄된 파드는 상태가 알수 없음으로 변경된다.
      • Default로 통신하는 시간 때문에 node가 not ready로 바뀌는것과 별개로 시간이 걸리는듯 - 김준석
    • 즉각적인 인간의 개입이 필요하지 않다. 시스템이 자동으로 스스로 치유한다.
  • p175
    • $ kubectl label pod kubia-dmdck app=foo --overwrite
  • p177
    • 파드가 오작동한다는 것을 안다면 파드를 레플리케이션컨트롤러의 범위 밖으로 빼내 컨트롤러가 새 파드로 교체하도록 한 다음, 원하는 방식으로 파드를 디버그하거나 문제를 재연해볼 수 있다.
      • 3장에서 forwarding을 이용해 pod를 디버깅하자는것의 연장선인듯. 괜찮은 생각인것 같다 - 김준석
      • 아직 특정 pod만 오작동하는 경우는 만나지 못했지만 이런일이 있으면 사용해 봐야겠다. - 서지혜
      • 이거 안해봤는데 좋은 아이디어네요. - bluemir
  • p179
    • export KUBE_EXPORT ="/usr/bin/nano"
    • 파드를 수평으로 스케일링 하는 것이 무척 쉬운 일임을 의미한다.
      • 물론 기반시스템이 그렇게 만들어져있어야하겠지 - 김준석
    • kubectl scale rc kubia --replicas=10
    • kubectl scale rc kubia --cascade=false
      • cascade - 김준석
      • ReplicationController 이제 안쓰니까 의미 없는 옵션이 아닐지... - 서지혜

4.3. 레플리케이션컨트롤러 대신 레플리카셋 사용하기

  • p183
    • 레플리카셋이라는 유사한 리소스가 도입됐다. 이는 차세대 레플리케이션컨트롤러이며, 레플리케이션컨트롤러를 완전히 대체할 것이다.
    • 레플리카셋은 레플리케이션컨트롤러와 똑같이 동작하지만 좀 더 풍부한 표현식을 사용하는 파드 셀렉터를 갖고 있다.
      • 레이블이 없어도 셀렉트할 수 있게 된다 - 서지혜
  • p185
    • API버전 속성에 대해
      • 각 API (ReplicaSet / Deployment 등) API호환을 적어놓은 블로그들이 있는것로 기억함 - 김준석
      • 이 버전 관리하는거 너무 귀찮다... - 서지혜
  • p186
    • 셀렉터에 표현식을 추가할 수 있다. In / NotIn / Exsists / DoesNotExist
  • p188
    • 레플리카셋을 삭제하면 모든 파드가 삭제된다.
      • 레플리카셋은 cascade=false 옵션 없나? - 서지혜

4.4. 데몬셋을 사용해 각 노드에서 정확히 한개의 파드 실행하기

  • p188
    • 클러스터의 모든 노드에, 노드당 하나의 파드만 실행되길 원하는 경우
    • 시스템 수준의 작업을 수행하는 인프라 관련 파드가 이런 경우다. 예를 들면 모든 노드에서 로그 수집기와 리소스 모니터를 실행하려는 경우가 좋은 예다. 또 다른 좋은 예는 쿠버네티스의 kube-proxy 프로세스이며, 서비스를 작동시키기 위해 모든 노드에서 실행돼야 한다.
  • p189
    • 데몬셋은 그림 4.8과 노드 수만큼 파드를 만들고 각 노드에 배포된다.
    • 새 노드가 클러스터에 추가되면 데몬셋은 즉시 새 파드 인스턴스를 새 노드에 배포한다.
    • 데몬셋 정의의 일부인 파드 템플릿에서 node-selector 속성을 지정하면된다.
  • p192
    • $ kubectl get ds
      • 생각해보니 ds 검색해본적이 없네 - 김준석
      • 해봤으나 권한이 없었다고 합니다 - 서지혜

4.5. 완료 가능한 단일 태스크를 수행하는 파드 실행

  • p194
    • 작업을 완료한 후에는 종료되는 태스크만 실행하려는 경우가 있을 것이다.
    • 이러한 잡의 예로는 데이터를 어딘가에 저장하고 있고, 이 데이터를 변환해서 어딘가로 전송해야 하는 경우를 들 수있다.
      • 뒤에 cron이 나오지만 job은 데이터 백업 / 통계 / 업데이트 에 주로 사용됨. - 김준석
  • p196
    • 잡 파드는 무한정 실행하지 않으므로 기본 정책을 사용할 수 없다. 따라서 restartPolicy를 onFailure나 Never로 명시적으로 설정해야 한다.
  • p197
    • 잡은 두 개 이상의 파드 인스턴스를 생성해 병렬 또는 순차적으로 실행하도록 구성할 수 있다. 이는 잡 스펙에 completions와 parallelism 속성을 설정해 수행한다.
      • 몇번 완료해야해? 한번에 몇개 수행할까? - 김준석
      • 요거 활용해서 job queue, work queue 같은 것을 멋지게 만들수 있습니다. # - bluemir

    • activeDeadlineSeconds 속성을 설정해파드의 실행 시간을 제한할 수 있다.
      • 이걸 써야할때가 있나 싶음 - 김준석
      • hang 걸리는 잡 종료시킬 때 사용할 수 있을거같네요 - 서지혜


4.6. 잡을 주기적으로 또는 한 번 실행되도록 스케줄링하기

  • p200
    • 리눅스나 유닉스 같은 운영체제에서 이런 작업을 크론 작업이라 한다. 쿠버네티스에서도 이를 지원한다.
  • p201
    • 스케줄 설정하기
      • 분 시 일 월 요일
        • 콤마로 구분. 0은 일요일 0,30 * * * * 0,6 매달 일요일, 토요일 매시각 0분, 30분 마다. - 김준석
        • */30 * * * * 0,6 이렇게 할 수도 있습니다 - 서지혜
    • 일반적인 상황에서 크론잡은 스케줄에 설정한 각 실행에 항상 하나의 잡만 생성하지만 두 개의 잡이 동시에 생성되거나 전혀 생성되지 않을 수 있다.
      • 이 책의 버전이 1.8기준이라 그런가. cronjob의 경우 replace policy가 있어서 만약 앞서 존재하는 job이 끝나지 않았다면 replace를 하거나 해당 작업이 끝날때까지 pending 할 수 있다. - 김준석
      • 추가적으로 job이 제대로 끝났는지 completion 혹은 failure pod를 보관하는게 있는데 여기선 소개 안하네 - 김준석

5. 서비스: 클라이언트가 파드를 검색하고 통신을 가능하게 함

5.1. 서비스 소개

  • p206
    • 쿠버네티스의 서비스는 동일한 서비스를 제공하는 파드 그룹에 지속적인 단일 접점을 만들려고 할 때 생성하는 리소스다. 각 서비스는 서비스가 존재하는 동안 절대 바뀌지 않는 IP주소와 포트가 있다. 클라이언트는 해당 IP와 포트로 접속한 다음 해당 서비스를 지원하는 파드 중 하나로 연결된다.
  • p208
    • 서비스 연결은 서비스 뒷단의 모든 파드로 로드밸런싱된다. 레이블셀렉터를 기억할 것이다.
  • p210
    • 서비스의 클러스터 IP로 요청을 보내고 응답을 로그로 남기는 파드를 만드는 것이다.
    • 쿠버네티스 노드로 ssh 접속하고 curl 명령을 실행할 수 있따.
    • kubectl exec 명령어로 기존 파드에서 curl 명령을 실행할 수 있다.
      • 위 세개다 쓰는듯. 파드에서 curl을 하는것은 번거로워서 가장 늦게 하긴 함. - 김준석
  • p211
    • 명령어의 더블 대시(--)는 kubectl 명령줄 옵션의 끝을 의미한다.
      • 번역이 이상한데 공식 홈페이지의 Note: The double dash (--) separates the arguments you want to pass to the command from the kubectl arguments. kubectl 에서 넘기고싶은걸 -- 로 구분할수 있다는 거임. - 김준석
  • p212
    • 서비스의 세션 어피니티 속성을 기본값 None 대신 ClientIP로 구성한다.
      • 하.. 티맥스에서 음성 메세지를 받을때 계속 같은 파드로 붙게 해달라고해서 이걸 본적이 있긴했지 - 김준석
  • p213
    • 여러 포트가 있는 서비스를 만들 때는 각 포트의이름을 지정해야 한다.
  • p216
    • $ kubectl exec kubia-3inly env
      • KUBERNETES_SERVICE_HOST 와 KUBERNETEST_SERVICE_PORT 가 있는걸 첨알았네 - 김준석
  • p217
    • 서비스 이름의 대시(-)는 밑줄(_)로 변환되고 서비스 이름이 환경변수 이름의 접두어로 쓰이면서 모든 문자는 대문자로 표시된다.
    • DNS를 통한 서비스 검색
    • FQDN을 통한 서비스 연결
      • 서비스명.네임스페이스.svc.cluster.local0-9* 이었던가.. 여튼 DNS / FQDN을 쓰진 않지만 동작은 같은걸로 앎. DNS에서 가져오고 FQDN으로 서비스명 매치 - 김준석

5.2. 클러스터 외부에 있는 서비스 연결

  • p221
    • 서비스는 파드에 직접 연결되지 않는다. 대신 엔트포인트 리소스가 그 사이에 있다.
      • ep? 이거 또 번역이.. among us도 아니고 - 김준석
    • 엔드포인트 리소스는 서비스로 노출되는 파드의 IP 주소와 포트 목록이다.
      • svc가 ep 오브젝트를 들고있다고 하면 될것을.. - 김준석
  • p224
    • 외부 서비스의 별칭으로 사용되는 서비스를 만들려면 유형 필드를 ExternalName으로 설정해 서비스 리소스를 만든다.
      • 내부에서 Name을 설정해본 이력이 없어서.. - 김준석
    • ExternalName 서비스는 DNS 레벨에서만 구현된다. 서비스에 관한 간단한 CNAME DNS레코드가 생성된다.

5.3. 외부 클라이언트에 서비스 노출

  • 외부에서 서비스를 액세스할 수 있는 몇 가지 방법이 있다.
    1. 노드포트로 서비스 유형 설정
    2. 서비스 유형을 노드포트 유형의 확장인 로드밸러서로 설정
    3. 단일IP 주소로 여러 서비스를 노출하는 인그레스 리소스 만들기
    4. 정의 밑줄 - 김준석
  • 노드포트 서비스를 만들면 쿠버네티스는 모든 노드에 특정 포트를 할당하고 서비스를 구성하는 파드로 들어오는 연결을 전달한다.
    • 노드셀렉터로 설정된 노드? 모든 노드인가? - 김준석
  • 외부 로드밸런서로 서비스 노출
    • 이것도 사용해본적은 없는데.. 결국 노드를 열고 거기로 로드밸런서한테 패스받아서 자동으로 분배 해준단 얘기지? - 김준석
    • 구현에 따라 다른데, 외부 LoadBalancer에서 pod ip 로 직접 터널링 해주거나 할수 있습니다. - bluemir

5.4. 인그레스 리소스로 서비스 외부 노출

  • p245
    • 인그레이스는 비교적 새로운 쿠버네티스 기능이므로 향후 많은 개선과 새로운 기능를 기대할 수 있다.

5.5. 파드가 연결을 수락할 준비가 됐을 때 신호 보내기

  • p246
    • 쿠버네티스에서는 라이브니스 프로브와 비슷하게 파드에 레디니스 프로브를 정의할 수 있다.
      • 쿠버네티스가 아니라 서비스에서는 이라고 해야하지 않나 - 김준석
    • 레드니스 프로브 유형 / 프로세스 exec / http get / TCP 소켓
      • 이건 라이브니스랑 같네 - 김준석
    • 라이브니스 프로브와달리 컨테이너가 준비 상태 점검에 실패하더라도 컨테이너가 종료되거나 다시 시작되지 않는다.
    • 레디니스 프로브는 요청을 처리할 준비가 된 파드의 컨테이너만 요청을 수신하도록 한다
      • 이것도 나쁘지 않은 옵션이긴 한데 해본적이 없음 - 김준석
  • p252
    • 레디니스 프로브를 항상 정의하라
      • 연결자체가 안되면 뻗어버리는 서비스가 많은데 이건 좋은 선택일까? - 김준석
      • 부하상황에서 readiness가 안되면 Traffic이 인입되지 않으면서 부하상황이 자연스럽게 해소되면 다시 인입되는식으로 활용할수 있습니다. - bluemir

5.6. 헤드리스 서비스로 개별 파드 찾기


5.7. 서비스 문제 해결

  • p257
    • 서비스에 액세스 할수 있는지 확인하려고 서비스 IP로 핑을 할 필요 없다.
      • 첨에암것도 모를때 Ping 날리고 그랬지 - 김준석

6. 볼륨: 컨테이너에 디스크 스토리지 연결

  • p259
    • 파드 내부의 각 컨테이너는 고유하게 분리된 파일시스템을 가진다. 파일시스템은 컨테이너 이미지에서 제공되기 때문이다.
      • 도커 컨테이너 기본사이즈가 10gb를 받는다고한것 같은데 이걸 사용하는거던가? - 김준석
  • p260
    • 새로 시작한 컨테이너는 이전에 실행했던 컨테이너에 쓰여진 파일시스템의 어떤 것도 볼 수가 없다.
    • 이는 파드가 시작되면 볼륨이 생성되고, 파드가 삭제되면 볼륨이 삭제된다는 것을 의미한다.
      • 지금은 컨테이너 간의 파일 시스템 공유를 위해 파드의 라이프사이클을 따르는 볼륨을 생성하는듯 - 서지혜
      • 정의 밑줄 - 김준석

6.1. 볼륨 소개

  • p260
    • 쿠버네티스 볼륨은 파드의 구성 요소로 컨테이너와 동일하게 파드 스펙에서 정의된다.
      • spec: containers: volumnMount: 구조 리마인드 - 김준석
    • 볼륨은 쿠버네티스 오브젝트가 아니므로 자체적으로 생성, 삭제될 수 없다.
    • 볼륨은 파드의 모든 컨테이너에서 사용 가능하지만 접근하려는 컨테이너에서 각각 마운트 돼야한다. 각 컨테이너에서 파일시스템의 어느 경로에나 볼륨을 마운트할 수 있다.
  • p263
    • 볼륨을 채우거나 마운트하는 프로세스는 파드의 컨테이너가 시작되기 전에 수행된다.
      • preload같은? 이거 컨테이너의 init 보다 먼저인가? - 김준석
        • initContainer 보다 먼저입니다. 여기서 말하는 Process 는 VolumeDriver의 Process인듯 하네요(fuse 같은거요). - bluemir
    • 다양한 유형의 볼륨이 사용 가능하다.
      • emptyDir
      • hostPath
      • gitRepo
      • nfs
      • gcePersistentDisk, awsElasticBlockStore, azureDisk
      • cinder, cephfs, iscsi, flocker, glusterfs, quobyte, rbd, flexVolume, csphereVolume, photonPersistentDisk, scaleIO
      • configMap, secret, downwardAPI - 이것도 볼륨으로 치다니 김준석
      • persistentVolumeClaim

6.2. 볼륨을 사용한 컨테이너 간 데이터 공유

  • p264
    • emptyDir
      • 이름에서 알 수 있듯이 볼륨이 빈 디렉터리로 시작된다.
      • emptyDir 볼륨은 동일 파드에서 실행 중인 컨테이너 간 파일을 공유할 때 유용하다.
  • p268
    • 볼륨으로 사용한 emptyDir은 파드를 호스팅하는 워커 노드의 실제 디스크에 생성되므로 노드 디스크가 어떤 유형인지에 따라 성능이 결정됐다.
    • 이 작업을 위해 다음과 같이 emptyDir의 medium을 memory로 지정한다.
      • 빠르겠는데? - 김준석
      • memory limit 이 있다면 해당 DIR의 사용량이 포함되므로 주의 해야 합니다. - bluemir
  • p269
    • gitRepo 볼륨이 생성된 후에는 참조하는 리포지터리와 동기화하지 않는다.
  • p271
    • 사이트카 컨테이너 소개
    • 새로운 로직을 메인 애플리케이션 코드에 밀어 넣어 복잡성을 더하고 재사용성을 떨어뜨리는 대신에 파드에 사이드카를 추가하면 기존 컨테이너 이미지를 사용할 수 있다.
      • 이런거 좀 해설좀 자세히 해줬으면. 사이드카와 메인nginx사이 같은 공유공간을 가지고 있는데 사이드카 컨테이너가 gitRepo 볼륨을 가지고 주기적으로 밀어넣어서 웹페이지를 갱신한단 소리겠지? - 김준석
        • 그것보단 log stash 같은 로그 수집기를 한 Container 내에 넣는 대신 별개의 Container 로 분리하면 나중에 Log 설정을 바꿔야 할떄 Application Container를 바꾸는대신 별개의 logstash sidecar를 바꾸면 된다는 의미입니다. 예시는 log 지만 Network관련 설정이나 Monitoring 설정등도 가능합니다. 또한 Cluster Provider 가 Sidecar inject를 제공하는 경우 Sidecar의 버전등이 Application 과는 완전 별개로 돌아 갈수 있으므로 Applicaiton 개발자와 Cluster Provider의 마찰도 줄일수 있습니다. 이런 구조를 가장 잘 활용하는것은 Istio(service mesh)가 있습니다.- bluemir
  • p272
    • 프라이빗 깃 리포지터리를 컨테이너에 복제하려면.. 다른 유사 방법을 사용해야 한다

6.3. 워커 노드 파일시스템의 파일 접근

  • p273
    • 파일시스템을 통해 노드 디바이스를 접근하기 위해 노드의 파일시스템을 사용해야 한다.
    • hostPath 볼륨은 노드 파일시스템의 특정 파일이나 디렉터리를 가리킨다.
      • 특정 노드에 역할(log보관, db)를 지정해서 하기때문에 우리쪽에선 자주 쓰인다 - 김준석
    • hostPath 볼륨의 콘텐츠는 삭제되지 않는다.파드가 삭제되면 다음 파드가 호스트의 동일 경로를 가리키는 hostPath 볼륨을 사용하고, 이전 파드와 동일한 노드에 스케줄링된다는 조건에서 새로운 파드는 이전 파드가 남긴 모든 항목을 볼 수 있다.
      • 하지만 노드에만 남기 때문에 노드간 공유는 안된다 - 서지혜
    • 볼륨의 콘텐츠는 특정 노드의 파일시스템에 저장되므로 데이터베이스 파드가 다른 노드로 다시 스케줄링되면 더 이상 이전 데이터를 볼 수 없다. hostPath 볼륨은 파드가 어떤 노드에 스케줄링되느냐에 따라 민감하기 때문에 일반적인 파드에 사용하는 것은 좋은 생각이 아니다.
      • 잘 알려진 주의사항 밑줄 - 김준석
      • 모든 node에 공평하게 설치되는 Deamonset에서 자주 사용 됩니다. - bluemir
  • p275
    • 다른 파드를 살펴보면 대부분이 노드의 로그파일이나 kubeconfig, CA인증서를 접근하기 위해 이 유형의 볼륨을 사용한다는 것을 볼 수 있다.

6.4. 퍼시스턴트 스토리지 사용

  • p275
    • 파드에서 실행 중인 애플리케이션이 디스크에 데이터를 유지해야 하고 파드가 다른 노드로 재스케줄링된 경우에도 동일한 데이터를 사용해야 한다면 지금까지 언급한 볼륨 유형을 사용할 수 없다. 이러한 데이터는 어떤 클러스터 노드에서도 접근이 필요하기 때문에NAS 유형에 저장돼야한다.
  • p277
    • 파일시스템 유형은 EXT4(리눅스 파일시스템 유형 중 하나)이다.
      • 파일 시스템에도 여러 유형이 있구나. 리눅스 공부도 조만간 해야겠다 - 서지혜
  • p282
    • 이런 유형의 인프라스트럭처 관련 정보를 파드 정의에 포함한다는 것은 파드 정의가 특정 쿠버네티스 클러스터에 밀접하게 연결됨을 의미한다.
      • 개발자가 서버정보를 다 알아함 - 김준석

6.5. 기반 스토리지 기술과 파드 분리

  • p283
    • 이상적으로는 쿠버네티스에 애플리케이션을 배포하는 개발자는 기저에 어떤 종류의 스토리지 기술이 사용되는지 알 필요가 없어야 하고, 동일한 방식으로 파드를 실행하기 위해 어떤 유형의 물리 서버가 사용되는지 알 필요가 없어야 한다. 동일한 방식으로 파드를 실행하기 위해 어떤 유형의 물리 서버가 사용되는지 알 필요가 없어야 한다.
    • 인프라스트럭처의 세부 사항을 처리하지 않고 애플리케이션이 쿠버네티스 클러스터에 스토리지를 요청할 수 있도록 하기 위해 새로운 리소스 두개가 도입됐다. 바로 퍼시스턴트 볼륨( PersistentVolume)과 퍼시스턴트볼륨클레임( PersistentVolumeClaim)이다.
    • 클러스터 관리자가 퍼시스턴트볼륨을 프로비저닝하면 파드는 퍼시스턴트볼륨클레임을 통해 이를 사용한다.
      1. 클러스터 관리자는 네트워크 스토리지 유형을 설정한다.
      2. 관리자는 쿠버네티스 API에 PV 디스크립터를 게시해 퍼시스턴트볼륨을 생성한다.
      3. 사용자는 퍼시스턴트볼륨클레임을 생성한다.
      4. 쿠버네티스는 적정한 크기와 접근 모드의 PV를 찾고 PVC를 PV에 바인딩한다.
      5. 사용자는 PVC를 참조하는 볼륨을 가진 파드를 생성한다.
  • p285


         kind: PersistentVolume
        metadata:
          name: mongodb-pv
        spec:
          capacity:
            storage: 1Gi
          accessModes:
          - ReadWriteOnce
          - ReadOnlymany
          persistentVolumeReclaimPolicy: Retain
          gcePersistentDisk :
           pdName: mongodb
           fsType: ext4
  • p287
    • 이제 관리자의 모자를 내려놓고 개발자의 모자를 다시 써 보자.
    • 퍼시스턴트볼륨과 클러스터 노드는 파드나 퍼시스턴트볼륨클레임과 달리 특정 네임스페이스에 속하지 않는다.
    • 파드에 직접 사용할 수는 없고 클레임을 먼저 해야한다.
    • 퍼시스턴트볼륨에 대한 클레임은 파드를 생성하는 것과 별개의 프로세스다.
      • 파드는 언제든 재스케쥴링 될 수 있기 때문 - 서지혜
  • p288

    •         kind: PersistentVolumeClaim
              metadata:
                name: mongodb-pvc
              spec:
                resources:
                  requests:
                   storage: 1Gi
                accessModes:
                - ReadWriteOnce
                storageClassname: ""
      
    • kubectl get pvc
  • p289
    • 접근모드로 사용되는 약어다.
      • RWO(ReadWriteOnce): 단일 노드만이 읽기/쓰기용으로 볼륨을 마운트 할 수 있다.
      • ROX(ReadOnlyMany): 다수 노드가 읽기용으로 볼륨을 마운트 할 수 있다.
      • RWX(ReadWriteMany): 다수 노드가 읽기/쓰기용으로 볼륨을 마운트 할 수 있다.
      • 파드 수가 아닌 볼륨을 동시에 사용할 수 있는 워커 노드 수와 관련이 있다.
    • 퍼시스턴트볼륨은 클러스터 수준의 리소스이므로 특정 네임스페이스에 생성할 수 없다. 그리고 동일한 네임스페이스의 파드에서만 사용할 수 있다.
      • 이게 무슨말이지? - 서지혜
      • 클러스터는 최상위 수준이고 그 안에 네임스페이스등으로 나눠지는데 PV는 네임스페이스 안에 설정하는 리소스가 아니라 여러 클러스터에서 접근할수 있는거라고 얘기하는듯. -김준석
  • p290
    • 퍼시스턴트 볼륨 클레임 참조

  ..
      volumeMounts:
      - name: mongodb-data
        mountpath: /data/db
  ..
    volumes:
    - name: mongodb-data
      persistentVolumeClaim:
        claimName: mongodb-pvc
  • p293
    • 이미 볼륨을 사용했기 때문에 데이터를 가지고 있으므로 클러스터 관리자가 볼륨을 완전히 비우지 않으면 새로운 클레임에 바인딩할 수 없다.
      • pv를 비워야한단 소린가? - 김준석
    • persistentVolumeClaimPolicy를 Retain
    • 다른 두 가지 리클레임 정책은 Recycle과 Delete다.

6.6. 퍼시스턴트볼륨의 동적 프로비저닝

  • p294
    • 여전히 클러스터 관리자는 실제 스토리지를 미리 프로비저닝 해둬야 한다.
      • 일 량이 줄어들지는 않는다. 하지만 한번 해놓은게 더 의미를 가지게 된다. - 김준석
  • p295
    • 퍼시스턴트볼륨 프로비저너를 배포하고 사용자가 선택 가능한 퍼시스턴트볼륨의 타입을 하나 이상의 스토리지클래스 오브젝트로 정의할 수 있다. 사용자가 퍼시스턴트볼륨클레임에서 스토리지클래스를 참조하면 프로비저너가 퍼시스턴트 스토리지를 프로비저닝할때 이를 처리한다.
  • p298
    • 스토리지클래스의 좋은 점은 클레임 이름으로 이를 참조한다는 사실이다. 그러므로 다른 클러스터 간 스토리지클래스 이름을 동일하게 사용한다면 PVC 정의를 다른 클러스터로 이식 가능하다.
    • 프로비저너는 실제 스토리지도 프로비저닝했다.
    • kubectl get sc
  • p302
    • 빈 문자열을 스토리지클래스 이름으로 지정하면 PVC가 새로운 PV를 동적 프로비저닝 하는 대신 미리 프로비저닝 된 PV에 바인딩된다.
    • 동적 프로비저닝된 퍼시스턴트볼륨을 가져오는 것을 포함한 저체 절차를 그림에서 확인하자.
      1. 클러스터 관리자는 퍼시스턴트볼륨 프로비저너를 설정한다.
      2. 관리자는 하나 혹은 그 이상의 스토리지클래스를 생성하고 그중 하나를 기본값으로 정한다.
      3. 사용자는 스토리지클래스 중 하나를 참조해 PVC를 생성한다.
      4. 쿠버네티스는 스토리지클래스와 거기서 참조된 프로비저너를 살펴보고 프로비저너에게 pvc로 요청된 접근 모드, 스토리지 크기, 파라미터를 기반으로 새 PV를 프로비저닝하도록 요청한다.
      5. 프로비저너는 실제 스토리지를 프로비저닝하고 퍼시스턴트볼륨을 생성하고 PVC에 바인딩한다.
      6. 사용자는 PVC 이름으로 참조하는 볼륨과 파드를 생성한다.

7. 컨피그맵과 시크릿: 애플리케이션 설정

7.1. 컨테이너화된 애플리케이션 설정

  • p306
    • 파일을 이미지 안에 넣고 빌드하는 것은 애플리케이션 소스 코드에 설정 내용을 넣고 하드코딩하는 것과 비슷하다. 그로 인해 인증 정보나 암호화 키와 같이 비밀로 유지해야 하는 내용을 포함해 어떤 정보가 됐든, 해당 이미지에 접근할 수 있는 모든 사람이면 볼 수 있게 된다.
      • credentail키 컨테이너에 넣고 이미지 말았다가 이미지 히스토리 싹지우고 다시 말라고 시니어 엔지니어가 슬랙서 태그걸로 호출하던게 지지난달. 본인만의 보안정책때문에... - 김준석
    • 설정 데이터를 저장하는 쿠버네티스 리소스를 컨피그맵이라고 한다.
    • 컨피그맵을 사용해 설정 데이터를 저장할지 여부에 관계없이 다음 방법을 통해 애플리케이션을 구성할 수 있다.
      • 컨테이너에 명령줄 인수 전달
      • 각 컨테이너를 위한 사용자 정의 환경변수 지정
      • 특수한 유형의 불륨을 통해 설정 파일을 컨테이너에 마운트
        • 명령줄 인수 전달 CMD, ENTRYPOINT / 환경변수 $(INTERVAL) / '/app/nginx/config/' - 김준석

7.2. 컨테이너에 명령줄 인자 전달

  • p307
    • ENTRYPOINT와 CMD 이해
      • Dockerfile에서 두 개의 지침을 다음 두 부분을 정의한다.
        • ENTRYPOINT는 컨테이너가 시작될 때 호출될 명령어를 정의한다.
        • CMD는 ENTRYPOINT에 전달되는 인자를 정의한다.
  • p308
    • CMD 명령어를 사용해 이미지가 실행될때 실행할 명령어를 지정할 수 있지만, 올바른 방법은 ENTRYPOINT 명령어로 실행하고 기본 인자를 정의하려는 경우에만 CMD를 지정하는 것이다.
    • shell과 exec 형식 간의 차이점
      • 두명령어는 두 가지 서로 다른 형식을 지원한다.
        • shell형식 - 예: ENTRYPOINT node app.js
        • exec 형식 - 예: ENTRYPOINT [:node , "app.js"]
          • exec 형식을 사용하면 셸 내부가 아니라 컨테이너 내부에서 프로세스를 직접 실행한다는게 무슨 의미지 - 서지혜

    • 1 ? Ssl 0:00 node app.js 
          

    • 1 ? ss  0:00 /bin/sh -c node app.js 
      7 ? sl  0:00 node app.js
          
    • exec로 실행됐을때랑 shell형식으로 실행됐을때 차이 프로세스 뷰 - 김준석
  • p311

    • 도커 쿠버네티스 설명
      ENTRYPOINT command 컨테이너 안에서 실행되는 실행파일
      CMD args 실행파일에 전달되는 인자
      • 매핑되는 값. command: args: 로 차트에서는 쓰지 - 김준석
  • p312
    • 문자열 값을 따옴표로 묶을 필요는 없다(숫자는 묶어야 한다)
      • "15" 이렇게 인자 넘길땐 숫자는 묶어라 - 김준석

7.3. 컨테이너의 환경변수 설정

  • p314
    • 애플리케이션이 자바로 작성된 경우에는 System.getenv("INTERVAL"). NodeJS로 작성도니 경우에는 process.env.INTERVAL, 파이썬으로 작성된 경우네는 os.environ.['INTERVAL']을 사용하면 된다.

    •  env:
          - name: INTERVAL
            value: "30"
          
    • 환경변수는 파드 레벨이 아닌 컨테이너 정의 안에 설정한다.
  • p315
    • $(VAR) 구문을 사용해 이미 정의된 환경변수나 기타 기존 변수를 참조할 수도 있다.
    • $(VARIABLE_NAME) - 김준석
    • value 필드 대신 valueFrom 으로 환경변숫값의 원본 소스로 사용할 수 있다.

7.4. 컨피그맵으로 설정 분리

  • p316
    • 컨피그맵은 짧은 문자열에서 전체 설정 파일에 이르는 값을 가지는 키/값 쌍으로 궈성된 맵이다.
    • 파드는 컨피그맵을 이름으로 참조하기 때문에, 모든 환경에서 동일한 파드 정의를 사용해 각 환경에서 서로 다른 설정을 사용할수 있다.
      • 컨피그맵 이름은 같고 내용은 다르게? - 김준석
  • p318
    • kubectl create configmap fortune-config --from-literal=sleep-interval=25
    • 컨피그맵 키는 유효한 DNS 서브도메인(subdomain)이어야 한다(영숫자, 대시, 밑줄, 점만 포함 가능). 필요한 경우 점이 먼저 나올 수 있다.

    •     - image: luksa/fortune:env
            env:
            - name: INTERVAL
              valueFrom:
                configMapKeyRef:
                  name: fortune-config
                  key: sleep-interval
          
    • kubectl create configmap my-config --from-file=config-file.conf
  • p323
    • 파드를 생성할 때 존재하지 않는 컨피그맵을 지정하면 어떻게 되는지 궁금할 것이다.
      • config맵이 없습니다? 애초에 실행은 되나? - 김준석
    • 그런 다음 누락된 컨피그맵을 생성하면 실패했던 컨테이너는 파드를 다시 만들지 않아도 시작된다.
    • 컨피그맵 참조를 옵션으로 표시할 수도 있다(configMapKeyRef.optional: true로 지정). 이런 경우에는 컨피그맵이 존재하지 않아도 컨테이너는 시작한다.
    • envFrom 속성을 사용해 환경변수로 모두 노출할 수 있다.
      • 파일단위로 envFrom으로 환경변수 노출한단 뜻 - 김준석
  • p324
    • CONFIG_FOO-BAR는 대시를 가지고 있어 올바른 환경변수 이름이 아니기 때문이다. 이런 경우에 쿠버네티스는 어떤 형태로든 임의의 키로 변환하지 않는다.
  • p325
    • args: ["$(INTERVAL)"]
    • 앞에서 한 것과 동일하게 환경변수를 정의했지만 $(ENVVARIABLENAME) 문법을 사용해 쿠버네티스가 해당 변수의 값을 인자에 주입한다.
  • p326
    • 컨테이너에 노출시키려면, 6장에서 언급한 특수 볼륨 유형 중 하나인 컨피그맵 볼륨을 사용할 수 있다.
  • p329

    •     volumeMounts:
          ...
          - name: config
            mountPath: /etc/nginx/conf.d
            readOnly: true
          ...
         volumes:
          - name: config
            configMap:
              name: fortune-config
          ...
          
      • configMap을 volume으로 선언 후 volumeMount로 해당 config를 mount - 김준석
  • p331
    • 다행히 컨피그맵 볼륨을 컨피그맵 항목의 일부만으로 채울 수 있다.

    •     volumes:
          - name: config
            configMap:
              name: fortune-config
              items:
              - key: my-nginx-config.conf
                path: gzip.conf
          
    • 원래 있던 파일은 해당 파일시스템이 마운트돼 있는 동안 접근할 수 없게 된다.
    • 전체 볼륨을 마운트하는 대신 volumeMount에 subPath속성으로 파일이나 디렉터리 하나를 볼륨에 마운트할 수 있다.
  • p333
    • 하지만 개별 파일을 마운트하는 이 방법은 파일 업데이트와 관련해 상대적으로 큰 결함을 가지고 있다.
      • 이렇게 할수 있으나 쓰지마세요 - 김준석
  • p334
    • 환경변수 또는 명령줄 인수를 설정 소스로 사용할 때의 단점은 프로세스가 실행되고 있는 동안에 업데이트할 수 없다는 것이다.
      • command나 entry-point로는 별로 좋지 않다는 거지 - 김준석
    • 애플리케이션이 설정을 다시 읽는 기능을 지원하는 않는 경우에 심각한 문제가 발생한다. 이로 인해 서로 다른 설정을 가진 인스턴스가 실행되는 결과를 초래한다.
    • 애플리케이션이 다시 읽기를 지원한다면, 컨피그맵을 수정하는 것은 그리 큰문제는 아니다. 하지만 컨피그맵 볼륨의 파일이 실행 중인 모든 인스턴스에 걸쳐 동기적으로 업데이트되지 않기 때문에, 개별 파드의 파일이 최대 1분 동안 동기화되지 않는 상태로 있을 수 있음을 알고 있어야 한다.
      • command로 실행되는걸 env로 바꾸고 reload하는걸 생각해봤는데 생각보다 어렵겠네 - 김준석

7.5. 시크릿으로 민감함 데이터를 컨테이너에 전달

  • p337
    • 쿠버네티스는 시크릿이라는 별도 오브젝트를 제공한다.
    • 시크릿을 다음과 같은 상황에서 사용할 수 있다.
      • 환경변수로 시크릿 항목을 컨테이너에 전달
      • 시크릿 항목을 볼륨 파일로 노출
    • 또한 노드 자체적으로 시크릿을 항상 메모리에만 저장되게 하고 물리 저장소에 기록되지 않도록 한다.
      • 이건 개발자들이 실행할때만 안다는 그것 - 김준석
    • 마스터 노드에는 시크릿을 암호화되지 않은 형식으로 저장하므로, 시크릿에 저장한 민감한 데이터를 보호하려면 마스터 노드를 보호하는 것이 필요하다.(base64로 인코딩으로 바뀜)
      • base64로 인코딩해서 보관한다던데 - 김준석
        • api server option에 etcd에 저장시 암호화 적용을 할수 있는 옵션은 있습니다. 다만 kubectl get secret 하면 원본이 보이기 떄문에 아무나 API server에 접근 하지 못하도록 보호하라는 의미인것 같네요. - bluemir
  • p339
    • 시크릿이 갖고 있는 세 가지 항목은 파드 안에서 쿠버네티스 API 서버와 통신할 때 필요한 모든 것을 나타낸다.
  • p341
    • $ kubectl create secret generic fortune-https --from-file=https.key
    • 시크릿의 세 가지 유형에는 도커 레지스트리를 사용하기 위한 docker-registry, TLS 통신을 위한 tls, generic이 있다.
      • docker-registry / generic정도만 써본듯 - 김준석
  • p343
    • Base64 인코딩을 사용하는 까닭은 간단하다. 시크릿 항목에 일반 텍스트뿐만 아니라 바이너리 값도 담을 수 있기 때문이다.
      • 복호화도 쉽지 왜 썼냐.. - 김준석
  • p345

    •     ...
          - name: certs
          mountPath: /etc/nginx/certs/
          readOnly: true
          ...
          - name: certs
          secret:
            secretname: fortune-https
          
  • p348
    • 인증서와 개인 키를 secret 볼륨에 마운트해 파드에 성공적으로 전달했다. secret 볼륨은 시크릿 파일을 저장하는 데 인메모리 파일시스템(tmpfs)을 사용한다.
      • 메모리 파일 시스템. linux 설치할때도 씀 - 김준석

    •     env:
          - name: FOO_SECRET
            valueFrom:
              secretKeyRef:
                name: fortune-https
                key: foo
          
      • 이것은 INTERVAL 환경변수를 설정하는 것과 거의 비슷하다. 단지 이번에는 컨피그맵을 참조하는 데 confgMapKeyRef 대신 secretKeyRef를 사용해 시크릿을 참조한다는 점이 다르다.
  • p350

    •  $ kubectl create secret docker-registry mydockerhubsecret \ 
                --docker-username=myusername --docker-password=mypassword \ 
                --docker-email=my.email@provider.com 
          

    •     imagePullScrets:
          - name: mydockerhubsecret
          
    • 시크릿을 서비스어카운트에 추가해 모든 파드에 자동으로 추가될 수 있게 하는 법을 배울 것이다.

8. 애플리케이션에서 파드 메타데이터와 그 외의 리소스에 액세스하기

8.1. Downward API로 메타데이터 전달

  • p354
    • 그러나 파드의 IP, 호스트 노드 이름 파드 자체의 이름과 같이 실행 시점까지 알려지지 않은 데이터의 경우는 어떨까?
      • 이게 필요한 애플리케이션이 있나? - 김준석
      • Listen을 특정 Address 로 해야 한다거나 Leader Election의 Key로 써야 한다거나 log에 hostname이나 Node Name을 남겨야 한다거나 할수 있습니다. - bluemir
  • p355
    • Downward API를 사용하면 파드 자체의 메타데이터를 해당 파드 내에서 실행 중인 프로세스에 노출할 수 있다. 현재 다음 정보를 컨테이너에 전달 할 수 있다.
      • 파드의 이름
      • 파드의 주소
      • 파드가 속한 네임스페이스
      • 파드가 실행 중인 노드의 이름
      • 파드가 실행 중인 서비스 어카운트 이름
      • 각컨테이너의 CPU와 메모리 요청
      • 각 컨테이너의 CPU와 메모리 제한
      • 파드의 레이블
      • 파드의 어노테이션
        • CPU와 메모리 요청은 대부분 어플리케이션의 heap 사이즈 조정하는데 쓸수 있겠네 - 김준석
  • p356


  env:
  - name: POD_NAME
    valueFrom:
      fieldRef:
        fieldPath: metadata.name
...
  - name: POD_IP
    valueFrom:
      fieldRef:
        fieldPath: status.podIP
...
  • p359
    • 환경변수 대신 파일로 메타데이터를 노출하려는 경우 downwardAPI 볼륨을 정의해 컨테이너에 마운트할 수 있다.


  ...
  volumeMounts:
  - name: downward
    mountPath: /etc/downward
  volumes:
  - name: downard
    downwardAPI:
     items:
      - path: "podName"
        fieldRef:
          fieldPath: metadata.name
    ...
  • p362
    • 보다시피 각 레이블/어노테이션은 별도의 줄에 키=값 형식으로 저장된다. 값이 여러줄인 경우 줄 바꾸기 문자가 \n으로 표시돼 한 줄로 기록된다.
      • 그래서 값을 가져오면 꼭 vim이나 기타 프로그램에서 줄을 없애고 이상한게 없는지 봐야할때가 있지 - 김준석
  • p363
    • 환경변숫값은 나중에 업데이트 할 수 없기 때문에 파드의 레이블 또는 어노테이션이 환경변수로 노출된 경우 변경이 발생한 다음에 새로운 값을 노출할 수 있는 방법이 없다.
      • 이런 기능은 제공되지만 안쓰시는게 좋습니다 - 김준석
    • 컨테이너 리소스 제한 요청과 같은 컨테이너 수준의 메타데이터를 노출하는 경우 다음 예제에 표시된 것처럼 리소스 필드를 참조하는 컨테이너의 이름을 지정해야 한다.

8.2. 쿠버네티스 API 서버와 통신하기

  • p364
    • 애플리케이션이 다른 리소스의 정보가 필요하거나 가능한 한 최신 정보에 접근해야 하는 경우 API 서버와 직접 통신해야 한다.
      • 사실 어디다 사용하는건지 모르겠다. - 김준석
    • kubectl cluster-info를 실행해 URL을 얻을수 있다.
    • curl의 --insecure 옵션을 사용해 서버 인증서 확인을 건너뛰도록 시도해볼 수 있지만 원하는 결과를 얻지는 못한다.
      • --insecure 많이 쓰지 난 docker-registry 에 접근할때 많이 쓴듯 - 김준석
    • $ kubectl proxy and $ curl localhost:8001
    • 초기 버전의 쿠버네티스에 도입된 가장 일반적인 리소스 유형들은 특정 그룹에 속하지 않는다. APi 그룹은 나중에 도입됐다. API 그룹이 없는, 이런 초기 리소스 유형은 이제 core API 그룹에 속하는 것으로 간주된다.
      • v1 기준이 뭘까하는걸 풀어주는 항목이네 - 김준석
    • $ curl http://localhost:8001/apis/batch/v1
      • 호출할수 있는 create나 delete같은걸 보여줌. pod나 job의 status도 어떤 카테고리가 있는지 보여줌 - 김준석
    • $ curl http://localhost:8001/apis/batch/v1/jobs
      • kubectl의 get jobs 는 이런 API를 써서 보여주겠지? - 김준석
  • p371
    • 파드 내부에서 API서버와 통신하려면 다음 세 가지를 처리해야 한다.
      • API서버의 위치를 찾아야 한다.
      • API 서버와 통신하고 있는지 확인해야 한다.
      • API 서버로 인증해야 한다. 그렇지 않으면 볼 수도 없고 아무것도 할 수 없다.
        • https://kubernets / -k( -- insecure) / 인증서 및 토큰 필요 - 김준석
  • p377
    • 파드 내에서 실행 중인 애플리케이션이 쿠버네티스 API에 적절히 액세스 할 수 있는 방법을 정리해보자.
      • API서버의 인증서가 인증 기관으로부터 서명됐는지 검증, ca, cart 파일임.
      • 애플리케이션은 token을 Authroization 헤더에 bearer 토큰으로 넣어 전송해야함
      • namespace 파일은 파드의 네임스페이스 안에 있는 API오브젝트의 CRUD 작업을 수행할때 네임스페이스를 API서버로 전달하는데 사용해야 한다.
  • p378
    • https, 인증서, 인증 토큰을 다루는 일은 떄떄로 개발자에게 너무 복잡해 보일 때가 있다. 저자는 개발자가 서버 인증서의 유효성 검사를 비활성화하는 경우를 많이 봐왔다.
      • 프로젝트 초반에 보면 대부분 이런경우가 종종 - 김준석
    • API서버와 직접 통신하는 대신 메인 컨테이너의 애플리케이션은 HTTPS 대신 HTTP로 앰배서더에 연결하고 앰배서더 프록시가 API 서버에 대한 HTTPS 연결을 처리하도록해 보안을 투명하게 관리할 수 있다.
      • 메인 - > 앰버서더 : proxy 컨테이너 -> API 서버 - 김준석
  • p381
    • curl은 일반 HTTP 요청을 앰배서더 컨테이너 내에서 실행 중인 프록시로 전송한 다음, 프록시는 HTTPS 요청을 API 서버로 전송하며, 토큰을 전송해 클라이언트 인증을 처리하고 서버의 인증서를 검증해 서버의 신원을 확인한다.
      • ca는 proxy 컨테이너니까 인증 될테고, 시크릿에 있는 default-token으로 token의 역을 해서 처리한다는것 같네 - 김준석
  • p382
    • 그러나 단순한 API 요청 이상을 수행하려면 쿠버네티스 API 클라이언트 라이브러리 중 하나를 사용하는 것이 좋다.
      • 클라리언트 라이브러리가 참 많네 - 김준석

9. 디플로에먼트: 선언적 애플리케이션 업데이트

  • p389
    • 쿠버네티스 클러스터에서 실행되는 애플리케이션을 업데이트하는 방법과 쿠버네티스가 어떻게 무중단 업데이트 프로세스로 전환하는데 도움을 주는지 설명할 것이다.

9.1. 파드에서 실행 중인 애플리케이션 업데이트

  • p391
    • 모든 파드를 업데이트하는 방법에는 두 가지가 있다. 다음 중 하나를 수행할 수 있다.
      • 기본 파드를 모두 삭제한 다음 새 파드를 시작한다.
      • 새로운 파드를 시작하고, 가동하면 기존 파드를 삭제한다. 새 파드를 모두 추가한 다음 한꺼번에 기존 파드를 삭제하거나 순차적으로 새 파드를 추가하고 기존 파드를 점진적으로 제거해 이 작업을 수행할 수 있다.
        • 세가지 이미지 업데이트 방법 - 김준석
  • p392
    • 새 파드 모두 실행되면 그림과 같이 서비스의 레이블 셀렉터를 변경하고 서비스를 새 파드로 전환할 수 있다. 이것을 블루-그린 디플로이먼트라고 한다.
    • 새 파드가 모두 실행된 후 이전파드를 한 번에 삭제하는 방법 대신 파드를 단계별로 교체하는 롤링 업데이트를 수행할 수도 있다.

9.2. 레플리케이션컨트롤러로 자동 롤링 업데이트 수행

  • p394
    • kubectl을 사용해 업데이트를 수행하면 프로세스가 훨씬 간단해지지만 나중에 볼 수 있듯이 이방법도 이제는 애플리케이션을 업데이트하는 오래된 방법이 됐다.
      • 이건 문서로만봤지 한번도 실전서 못봄 - 김준석
  • p396
    • YAML 파일에는 대시 3개가 있는 줄로 구분해 여러 리소스 정의를 포함할 수 있다.
  • p397
    • 기본 imagePullPolicy는 이미지 태그에 따라 다르다. 컨테이너가 latest 태그를 명시적으로 참조하는 경우 imagePullPolicy의 기본값은 always이지만 컨테이너가 다른 태그를 참조하는 경우 정책의 기본값은 IfNotPresent이다.
  • p398
    • $ kubectl rolling-update kubia-v1 kubia-v2 --image=luksa/kubia:v2
      • kubia-v1 replicaset을 v2로 바꾸고 이미지는 v2 tag를 쓰자 - 김준석
  • p400
    • kubectl이 레플리케이션컨트롤러의 셀렉터를 변경하기 전에 실행 중인 파드의 레이블을 먼저 수정하기 때문이다.
    • 컨트롤러는 첫번째 v2파드를 만든다. kubectl은 이전 레플리케이션컨트롤러를 하나씩 스케일 다운한다.
    • kubectl이 롤링 업데이트를 계속하면 v2 파드에 대한 요청 비율이 점점 더 높아지기 시작한다. 결국 이전 레플리케이션 컨트롤러의 파드가 0으로 스케일 다운되며 마지막 v1 파드가 삭제돼 서비스가 이제 v2파드에 의해서만 지원된다는 것을 의미한다.
  • p403
    • 롤링 업데이트의 모든 단계를 수행하는 것이 kubectl 클라이언트라는 것을 알아차렸을 것이다.
    • 지금은 업데이트가 원활하게 진행됐지만 kubectl이 업데이트를 수행하는 동안 네트워크 연결이 진행됐지만 kubectl이 업데이트를 수행하는 동안 네트워크 연결이 끊어진다면 어떨까?
      • k8s도 이렇게 어설플때도 있었군 - 김준석
  • p404
    • 쿠버네티스에게 의도하는 시스템의 상태를 선언하고 쿠버네티스가 그것을 달성할 수 있는 가장 좋은 방법을 찾아냄으로써 스스로 그 상태를 달성하도록 하는지에 대해서 강조했다.
      • k8s가 스스로 배포 및 replica 관리를 해야 하는데 kubectl rolling-update는 사용자가 변경하게 되는 셈이라는 뜻이군 - 서지혜
    • 바로 이것이 현재 쿠버네티스에서 애플리케이션을 배포하는 가장 좋은 방법인 디플로이먼트라는 새로운 리소스를 도입하게 된 원동력이다.

9.3. 애플리케이션을 선언적으로 업데이트하기 위한 디플로이먼트 사용하기

  • 디플로이먼트는 낮은 수준의 개념으로 간주되는 레플리케이션컨트롤러 또는 레플리카셋을 통해 수행하는 대신 애플리케이션을 배포하고 선언적으로 업데이트하기 위한 높은 수준의 리소스다.
    • 좀더 추상적? 인 개념이겠지 - 김준석


apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: kubia
spec:
  replicas: 3
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      containers:
      - image: luksa/kubia:v1
        name: nodejs
  • p407
    • $ kubectl rollout status deployment kubia
      • rollout은 배포된걸 얘기하는건가 - 김준석
  • p408
    • 디플로이먼트는 파드를 직접 관리하지 않는다. 대신 레플리카셋을 생성하고 이들이 파드를 관리하도록 맡겨둔다.
  • p409
    • 디플로이먼트 리소스에 정의된 파드 템플릿을 수정하기만 하면 쿠버네티스가 실제 시스템 상태를 리소스에 정의된 산태로 만드는 데 필요한 모든 단계를 수행한다. 레플리케이션컨트롤러 또는 레플리카셋을 스케일 업 또는 스케일 다운하는 것과 마찬가지로 디플로이먼트 파드 템플릿에서 새 이미지 태그를 참조해 시스템이 의도하는 상태가 될수 있도록 쿠버네티스에 맡기면 된다.
      • kubectl이 아닌 k8s서버에 맡긴다는 의미도 포함이겠지? - 김준석
    • 새로운 상태를 달성하는 방법은 디플로이먼트에 구성된 디플로이먼트 전략에 의해 결정된다. 기본은 RollingUpdate라는 롤링 업데이트 전략이다. 대안으로 Recreate 전략이 있는데, 레플리케이션컨트롤러의 파드 템플릿을 수정한 후 모든 파드를 샂게하는 것과 마찬가지로 한 번에 기존 모든 파드를 삭제한 뒤 새로운 파드를 만든다.
  • p410
    • $ kubectl patch deployment kubia -p '{"spec": {"minReadySeconds": 10}}'
    • 디플로이먼트 오브젝트의 전체 YAML을 편집하거나 patch 명령어를 사용해 이미지를 변경하는 대신 kubectl set image 명령어를 사용해 컨테이너가 포함된 모든 리소스를 수정할 수 있다.
    • $ kubectl set image deployment kubia nodejs=luksa/kubia:v2
    • 디플로이먼트와 그 외의 리소스를 수정하는 방법
      • kubectl edit
      • kubectl patch
      • kubectl apply
      • kubectl replace
      • kubectl set image
  • p415
    • $ kubectl rollout status deployment kubia
  • p417
    • $ kubectl rollout history deployment kubia
    • $ kubectl rollout undo deployment kubia --to-revision=1
  • p419
    • 롤링 업데이트 속도 구성을 위한 속성
      • maxSurge : 디플로이먼트가 의도하는 레플리카 수보다 얼마나 많은 파드 인스턴스 수를 허용할 수 있는지 결정한다.백분률 or 절대값
      • maxUnavailable : 업데이트 중에 의도하는 레플리카 수를 기준으로 사용할 수 없는 파드 인스턴스 수를 결정. 백분률 or 절대값.
  • p422
    • $ kubectl rollout pause deployment kubia
    • 카나리 릴리스를 효과적으로 실행 할 수 있다.
    • $ kubectl rollout resume deployment kubia
  • p424
    • minReadySeconds가 지나기 전에 새 파드가 제대로 작동하지 않고 레디니스 프로브가 실패하기 시작하면 새 버전의 롤아웃이 효과적으로 차단된다.
      • maxSurge / maxUnavailable 규칙에 의해서 - 김준석
    • 적절하게 구성된 레드니스 프로브와 적절한 minReadySeconds 설정으로 쿠버네티스는 버그가 있는 버전 v3를 배포하지 못하게 했을 것이다.
  • p429
    • 기본적으로 롤아웃이 10분 동안 진행되지 않으면 실패한 것으로 간주된다. kubectl descirbe deployement 명령어를 사용하면 예제와 같이 ProgressDeadlineExceeded 조건이 표시된다.

10. 스테이트풀셋: 복제된 스테이트풀 애플리케이션 배포하기

10.1. 스테이트풀 파드 복제하기

  • p434
    • 각 인스턴스가 별도의 스토리지를 필요로 하는 분산 데이터 저장소를 실행하려면 레플리카셋을 사용할 수 없다.

10.2. 스테이트풀셋 이해하기

  • p438
    • 스테이트풀셋은 애플리케이션의 인스턴스가 각각 안정적인 이름과 상태를 가지며 개별적으로 취급돼야 하는 애플리케이션에 알맞게 만들어졌다.
      • 각 POD별 전용 Volume, 전용 네트워크를 가지게 해야하는듯 - 김준석
      • 전형적으로 ETCD 같은 Data Store Application이 딱 이런 케이스입니다. disk가 특정 갯수 만큼 있고, 딱 특정 이름의 pod이 특정 disk에 연결되야 되기 때문입니다. - bluemir
  • p439
    • 애플리케이션의 경우 새 인스턴스가 이전 인스턴스와 완전히 같은 상태와 아이덴티티를 가져야 함을 의미한다.
  • p440
    • 스테이트풀 파드가 종료되면 새로운 파드 인스턴스는 교체되는 파드와 동일한 이름, 네트워크 아이덴티티, 상태 그대로 다른 노드에서 되살아나야 한다.
    • 스테이트풀셋으로 생성된 파드는 서수 인덱스가 할당되고 파드의 이름과 호스트 이름, 안정적인 스토리지를 붙이는 데 사용된다.
  • p441
    • 스테이트풀셋은 거버닝 헤드리스 서비스를 생성해서 각 파드에게 실제 네트워크 아이덴티티를 제공해야 한다.
      • SRV 로 kubia.default.svc.cluster.local 를 기본으로 kubia-0.kubia... - 김준석
  • p442
    • 하지만 레플리카셋과 달리 교체된 파드는 사라진 파드와 동일한 이름과 호스트 이름을 갖는다.
      • kubia-0이 없어지면 kubia-0이 생성됨 - 김준석
  • p443
    • 스테이트 풀셋을 스케일링하면 사용하지 않는 다음 서수 인덱스를 갖는 새로운 파드 인스턴스를 생성한다. 인스턴스 두 개에서 세 개로 스케일업하면 새로운 인스턴스는 인덱스 2를 부여받는다.
  • p445
    • 스테이트 풀 파드의 스토리지는 영구적이어야 하고 파드와는 분리돼야 한다.
    • 스테이트풀셋이 파드를 생성하는 것과 같은 방식으로 퍼시스턴트볼륨클레임 또한 생성해야 한다. 이런 이유로 스테이트풀셋은 각 파드와 함께하는 퍼시스턴트볼륨클레임을 복제하는 하나 이상의 볼륨 클레임 템플릿을 가질 수 있따.
  • p446
    • 스테이트풀셋을 하나 스케일 업하면 두 개 이상의 API 오브젝트가 생성된다. 하지만 스케일 다운을 할 때 파드만 삭제하고 클레임은 남겨둔다.
      • 데이터가 날아가기 때문에. 다시 scale up하면 다시 붙는다 - 김준석
  • p448
    • 스테이트 풀셋은 교체 파드를 생성하기 전에 파드가 더 이상 실행 중이지 않는다는 점을 절대적으로 확신해야 한다는 뜻이다.
      • 아이덴티때문에 복잡할듯 - 김준석

10.3. 스테이트풀셋 사용하기

  • p450
    • 애플리케이션을 배포하려면 다른 유형의 오브젝트 두 가지를 생성해야 한다.
      • 데이터 파일을 저장하기 위한 퍼시스턴트볼륨
      • 스테이트풀셋에 필요한 거버닝 서비스
      • 스테이트풀셋 자체
  • p425
    • clusterIp 필드를 None으로 설정하면 헤드리스 서비스가 된다.

10.4. 스테이트풀셋의 피어 디스커버리

  • p462
    • 클러스터된 애플리케이션의 중요한 요구 사항은 피어 디스커버리이다.
  • p463
    • SRV 레코드는 특정 서비스를 제공하는 서버의 호스트 이름과 포트를 가리키는 데 사용된다.
      • DNS? kubedns한테 물어보면되나? - 김준석
        • 네, 일반적으로는 kubedns 가 응답하죠 - bluemir

10.5. 스테이트풀셋이 노드 실패를 처리하는 과정 이해하기

  • p467
    • 쿠버네티스 버전 1.7 부터 스테이트풀셋도 디플로이먼트나 데몬셋과 같은 방식으로 롤링 업데이트를 지원한다.
  • p469
    • 스테이트풀셋은 노드가 실패한 경우 동일한 아이덴티티와 스토리지를 가진 두 개의 파드가 절대 실행되지 않는 것을 보장하므로, 스테이트풀셋은 파드가 더 이상 실행되지 않는다는 것을 확신할 때까지 대체 파드를 생성할 수 없으며, 생성해서도 안 된다.
    • 오직 클러스터 관리자가 알려줘야만 알수 있다. 이를 위해 관리자는 파드를 삭제하거나 전체 노드를 삭제해야 한다.
      • liveness같은건 못쓰나? - 김준석
        • liveness 는 container 단위이므로 Pod 이 재성성 되거나 종료되는데는 관여할수 없습니다. - bluemir

11. 쿠버네티스 내부 이해

  • p475
    • 시스템의 기능을 잘 이해할 때까지 시스템의 동작 방식을 자세히 다루는 것이 합리적이지 않기 때문이다
      • 기술 서적을 읽을 땐 필요한 부분으로 건너뛰면서 읽는 방식이 더 효율적 인 것 같다 - 서지혜

11.1. 아키텍쳐 이해

  • p476
    • 컨트롤 플레인은 클러스터 기능을 제어하고 전체 클러스터가 동작하게 만드는 역할을 한다.

    • etcd 분산 저장 스토리지
      API 서버
      스케쥴러
      컨트롤 매니저
      
    • 컨테이너를 실행하는 작업은 각 워커 노드에서 실행되는 구성 요소가 담당한다.

    •  
      Kubelet
      Kube-proxy
      컨테이너 런타임(Docker, rkt 외 기타)
      
    • 애드온 구성 요소

    • 쿠버네티스 DNS 서버
      대시보드
      인그레스 컨트롤러
      힙스터
      컨테이너 네트워크 인터페이스 플러그인
      

11.1.1. 쿠버네티스 구성 요소의 분산 특성

  • p477
    • 구성 요소들은 모두 개별 프로세스로 실행된다.
  • p478
    • $ kubectl get componentstatuses
    • 쿠버네티스 시스템 구성 요소는 오직 API 서버하고만 통신한다. 서로 직접 통신하지 않는다.
      • 추상화가 잘 되어있군 - 서지혜
        • 볼떄마다 놀랍긴 합니다. - bluemir
    • API 서버는 etcs와 통신하는 유일한 구성 요소이다.
    • 워커노드의 구성 요소는 모두 동일한 노드에서 실행되야 하지만 컨트롤 플레인의 구성 요소는 여러 서버에 걸쳐 실행될 수 있다.
  • p479
    • kubelet은 항상 일반 시스템구성 요소로 실행되는 유일한 구성 요소이며, kubelet이 다른 구성 요소를 파드로 실행한다.

11.1.2. 쿠버네티스가 etcd를 사용하는 방법

  • p480
    • 생성한 모든 오브젝트는 API서버가 다시 시작되거나 실패하더라도 유지하기 위해 매니페스트가 영구적으로 저장될 필요가 있다. 이를 위해 쿠버네티스는 빠르고, 분산해서 저장되며, 일관된 키-값 저장소를 제공하는 etcd를 사용한다. 부산돼 있기 때문에 둘 이상의 etcd 인스턴스를 실행해 고가용성과 우수한 성능을 제공할 수 있다.
    • $ etcdctl ls /registry
  • p483
    • 쿠버네티스는 다른 모든 구성 요소가 API 서버를 통하도록 함으로써 이를 개선했다. API 서버 한곳에서 낙관전 잠금 매커니즘을 구현해서 클러스터의 상태를 업데이트하기 때문에, 오류가 발생할 가능성을 줄이고 항상 일관성을 가질 수 있다.
    • 고가용성을 보장하기 위해서는 두개 이상의 etcd 인스턴스를 실행하는 것이 일반적이다.여러 etcd 인스턴스는 일관성을 유지해야한다. 이러한 분산 시스템은 실제 상태가 무엇인지 합의에 도달해야 한다. etcd는 RAFT 합의 알고리즘을 사용해 어느 순간이든 각 노드 상태가 대다수의 노드가 동의하는 현재 상태이거나 이전에 동의된 상태 중에 하나임을 보장한다.
    • etcd 인스턴스를 일반적으로 홀수로 배포한다.

11.1.3. API 서버의 기능

  • p485
    • 클러스터 상태를 조회하고 변경하기 위해 RESTful API로 CRUD 인터페이스를 제공한다. 상태는 etcd 안에 저장한다.
    • 오브젝트 유효성 검사 작업도 수행하기 때문에 잘못 설정된 오브젝트를 저장할 수 없다. 유효성 검사와 함께 낙관적 잠금도 처리하기 때문에 동시에 업데이터가 발생하더라도 다른 클라이언트에 의해 오브젝트의 변경 사항이 재정의 되지 않는다.
  • p486
    • 먼저 API 서버는 요청을 보낸 클라이언트를 인증해야 한다. 이 작업은 API 서버에 구성된 하나 이상의 플러그인에 의해 수행된다.
    • API 서버는 인증 플러그인 외에도 하나 이상의 인가 플러그인을 사용하도록 설정돼 있다. 이 작업은 인증된 사용자가 요청한 작업이 요청한 리소스를 대상으로 수행할 수 있는지를 판별한다.
    • 리소스를 생성, 수정, 삭제하려는 요청인 경우에 해당 요청은 어드미션 컨트롤로 보내진다.
    • 해당 리소스는 모든 어드미션 컨트롤 플러그인을 통과한다.
    • https://kubernetes.io/docs/admin/admission-controllers/에서 찾아볼 수 있다.
    • 요청이 모든 어드미션 컨트롤 플러그인을 통과하면, API 서버는 오브젝트의 유효성을 검증하고 etcd에 저장한다. 그리고 클라이언트에 응답을 반환한다.

11.1.4. API 서버가 리소스 변경을 클라이언트에 통보하는 방법 이해

  • p487
    • API서버는 이런 커트롤러에 무엇을 해야 하는지 알려주지 않는다. 단지 컨트롤러와 다른 구성 요소가 배포된 리소스의 변경 사항을 관찰할 수 있도록 하면 된다.
    • 클라이언트는 API 서버에 http 연결을 맺고 변경 사항을 감지한다. 이 연결을 통해 클라이언트 감시 대상 오브젝트의 변경을 알 수 있는 스트림을 받는다. 오브젝트가 갱신될 때마다, 서버는 오브젝트를 감시하고 있는 연결된 모든 클라이언트에게 오브젝트의 새로운 버전을 보낸다.
      • 저는 GRPC 연결이라고 알고 있는데 과거에는 달랐을수도 있겠네요 - bluemir

11.1.5. 스케줄러 이해

  • p489
    • 스케줄러는 선택된 노드에 파드를 실행하도록 지시하지 않는다. 단지 스케줄러는 API 서버로 파드 정의를 갱신한다. API 서버는 kubelet에 파드가 스케줄링된 것을 통보한다.대상 노드의 kubelet은 파드가 해당 노드에 스케줄링된 것을 확인하자마자 파드의 컨테이너를 생성하고 실행한다.
  • p490
    • 노드의 선택은 그림 11.5에서 보는 것처럼 두 부분으로 나눌 수 있다.
      • 모든 노드 중에서 파드를 스케줄링할 수 있는 노드 목록을 필터링한다.
      • 수용 가능한 노드의 우선순위를 정하고 점수가 높은 노드를 선택한다. 만약 여러노드가 같은 최상위 점수를 가지고 있다면, 파드가 모든 노드에 고르게 배포되도록 라운드-로빈을 사용한다.
    • 스케줄러는 미리 설정된 조건 함수 목록에 각 노드를 전달한다. 이들 함수는 다음과 같은 다양한 조건을 확인한다.
      • 노드가 하드웨어 리소스에 대한 파드 요청을 충족시킬 수 있는가?
      • 노드에 리소스가 부족한가
      • 노드가 파드 정의 안에 있는 노드 셀렉터와 일치하는 레이블을 가지고 있는가?
      • 파드가 특정 호스트 포트에 할당되도록 요청한 경우 해당 포트가 이 노드에서 이미 사용 중인가?
      • 파드 요청이 특정한 유형의 볼륨을 요청하는 경우 이 노드에서 해당 볼륨을 파드에 마운트 할 수 있는가. 아니면 이 노드에 있는 다른 파드가 이미 같은 볼륨을 사용하고 있는가?
      • 파드가 노드의 테인트를 허용하는가?
      • 파드가 노드와 파드의 어피니티, 안티-어피니티 규칙을 지정했는가? 만약에 그렇다면 이 노드에 파드를 스케줄링하면 이런 규칙을 어기게 되는가?
  • p492
    • 클러스터에서 스케줄러를 하나만 실행하는 대신 여러 개의 스케줄러를 실행할 수 있다. 그런 다음에 파드 정의 안에 schedulerName 속성에 파드를 스케줄링할 때 사용할 스케줄러를 지정한다.

11.1.6. 컨트롤러 매니저에서 실행되는 컨트롤러 소개

  • p493
    • API 서버로 배포된 리소스에 지정된 대로 시스템을 원하는 상태로 수렴되도록 하는 다른 활성 구성 요소가 필요하다. 이는 컨트롤러 매니지 안에서 실행되는 컨트롤러에 의해 수행된다.
    • 컨트롤러의 목록은 다음과 같다.
      • 레플리케이션 매니저
      • 레플리카셋, 데몬셋, 잡 컨트롤러
      • 디플로이먼트 컨트롤러
      • 스테이트풀셋 컨트롤러
      • 노드 컨트롤러
      • 서비스 컨트롤러
      • 엔드포인트 컨트롤러
      • 네임스페이스 컨트롤러
      • 퍼시스턴트볼륨 컨트롤러
      • 그 밖의 컨트롤러
  • p494
    • 컨트롤러는 다양한 작업을 수행하지만 모두 API 서버에서 리소스가 변경되는 것을 감시하고 각 변경 작업을 수행한다.

11.1.7. Kubelet이 하는 일

  • p499
    • Kubelet은 워커 노드에서 실행하는 모든 것을 담당하는 구성 요소다. 첫번째 작업은 Kubelet이 실행중인 노드를 노드 리소스로 만들어서 API 서버에 등록하는 것이다. 그런 다음 API 서버를 지속적으로 모니터링해 해당 노드에 파드가 스케줄링 되면, 파드의 컨테이너를 시작한다.그런 다음 실행 중인 컨테이너를 계속 모니터링하면서 상태, 이벤트, 리소스 사용량을 API 서버에 보고한다.
    • Kubelet은 컨테이너 라이브니스 프로브를 실행하는 구성 요소이기도 하며, 프로브가 실패할 경우 컨테이너를 다시 시작한다. 마지막으로 API 서버에서 파드가 삭제되면 컨테이너를 정지하고 파드가 종료된 것을 서버에 통보한다.

11.1.8. 쿠버네티스 서비스 프록시의 역할

  • p501
    • kube-proxy는 서비스의 IP와 포인트로 들어온 접속을 서비스를 지원하는 파드 중 하나와 연결시켜준다. 서비스가 둘 이상의 파드에서 지원되는 경우 프록시는 파드 간에 로드 밸런싱을 수행한다.

11.1.9. 쿠버네티스 애드온 소개

  • p502
    • 쿠버네티스 서비스의 DNS 조회, 여러 HTTP 서비스를 단일 외부 IP 주소로 노출하는 기능, 쿠버네티스 웹 대시보드와 같은 것들이 있다.

11.1.10. 모든 것을 함께 가져오기

11.2. 컨트롤러가 협업하는 방법

  • p505
    • 전체 프로세스를 시작하기 전에도 컨트롤러와 스케줄러 그리고 kubelet은 API 서버에서 각 리소스 유형이 변경되는 것을 감시한다.
  • p506
    • 이벤트 체인
      1. 디플로이먼트 리소스 생성
      2. 감시를 통한 통보
      3. 레플리카셋 생성
      4. 통보
      5. 파드 생성
      6. 감시를 통한 통보
      7. 파드를 노드에 할당
      8. 감시를 통한 통보
      9. 도커에 컨테이너 실행 요청
      10. 컨테이너 실행
  • p509
    • $ kubectl get events --watch

11.3. 실행 중인 파드에 관한 이해

  • p511
    • 이 퍼즈 컨테이너는 파드의 모든 컨테이너를 함께 담고 있는 컨테이너다. 파드의 모든 컨테이너가 동일한 네트워크와 리눅스 네임스페이스를 공유하는 방법을 기억하는가? 퍼즈 컨테이너는 이러한 네임스페이스를 모두 보유하는 게 유일한 목적인 인프라스트럭처 컨테이너다. 파드의 다른 사용자 정의 컨테이너는 파드 인프라스트럭처 컨테이너의 네임스페이스를 사용한다.
    • 만약에 인프라스트럭처 컨테이너가 그 중간에 종료되면, kubelet이 인프라스트럭처와 파드의 모든 컨테이너를 다시 생성한다.

11.4. 파드 간 네트워킹

  • p512
    • 네트워크는 쿠버네티스 자ㅔ가 아닌, 시스템 관리자 또는 컨테이너 네트워크 인터페이스 플러그인에 의해 제공된다.
    • 파드 사이에 NAT가 없으면 내부에서 실행 중인 애플리케이션이 다른 파드에 자동으로 등록되도록 할 수 있따.
    • 파드가 인터넷에 있는 서비스와 통신할 때는 패킷의 출발지 IP를 변경하는 것이 필요하다. 파드의 IP는 사설이기 때문이다. 외부로 나가는 패킷의 출발지 IP는 호스트 워커 노드의 IP로 변경된다.
  • p514
    • 노드의 파드는 가상 이더넷 인터페이스 쌍을 통해 같은 브리지로 연결된다.
  • p516
    • SDN을 이용하면 하부 네트워크 토폴로지가 아무리 복잡해지더라도 노드들이 같은 네트워크에 연결된 것으로 볼 수 있다. 파드에서 전송한 패킷은 캡슐화 돼 네트워크로 다른 파드가 실행 중인 노드로 전달되고, 디캡슐화 단계를 거쳐 원래 패킷 형태로 대상 파드에 전달된다.

11.5. 서비스 구현 방식

  • p518
    • 성능이 더 우수한 iptables 프록시 모드가 이를 대체했다.
    • API 서버에서 서비스를 생성하면, 가상 IP 주소가 바로 할당된다.
    • 서비스의 IP/포트 쌍으로 향하는 패킷을 가로채서, 목적지 주소를 변경해 패킷이 서비스를 지원하는 여러 파드 중 하나로 리디렉션되도록 하는 몇 개의 iptables 규칙을 설정함으로써 이뤄진다.

11.6. 고가용성 클러스터 실행

  • p520
    • 애플리케이션의 가용성을 높이려면 디플로이먼트 리소스로 애플리케이션을 실행하고 적절한 수의 레플리카를 설정하기만 하면 되며, 나머지는 쿠버네티스가 처리한다.
    • 가동 중단 시간을 중리기 위해서는 애플리케이션을 수평으로 확장할 수 있어야 하지만 애플리케이션이 그런 경우에 속하지 않더라도 레클리카 수가 1로 지정된 디플로이먼트를 사용해야 한다.
    • 활성 복제본과 함께 비활성 복제본을 실행해두고 빠른 임대 혹은 리더 선출 매커니즘을 이용해 단 하나만 활성화 상태로 만들어야 한다.
  • p522
    • 쿠버네티스 가용성을 높이기 위해서는 다음 구성 요소의 여러 인스턴스를 여러 마스터 노드에서 실행해야 한다.
      • etcd
      • API 서버
      • 컨트롤러 매니저
      • 스케줄러
  • p523
    • 노드 한 대 이상으로 내결함성을 높이려면 5대 혹은 7대로 구성된 etcd 노드가 필요하다.
    • 여러 APi 서버 인스턴스 실행
      • API 서버의 가용성을 높이는 일은 훨씬 간단하다. API 서버는 상태를 저장하지 않기때문에 필요한 만큼 많은 API 서버를 실행할 수 있고 서로 인지할 필요도 없다.

12. 쿠버네티스 API 서버 보안

  • p527
    • 서비스어카운트가 무엇인지 알아보고 서비스어카운트뿐만 아니라 클러스터를 사용하는 다른 주체에 권한을 설정하는 방법을 학습한다.

12.1. 인증 이해

  • p528
    • API 서브를 하나 이상의 인증 플러그인으로 구성할 수 있다고 했다.
    • 인증 플러그인은 다음 방법을 사용해 클라이언트의 아이덴티티를 얻는다
      • 클라이언트의 인증서
      • HTTP 헤더로 전달된 인증 토큰
      • 기본 HTTP 인증
      • 기타
    • 쿠버네티스는 API 서버에 접속하는 두 종류의 클라이언트를 구분한다.
      • 실제 사람(사용자)
      • 파드
    • 사용자는 싱글 사인 온과 같은 외부 시스템에 의해 관리돼야 하지만 파드는 서비스 어카운트라는 매커니즘을 사용하며, 클러스터에 서비스어카운트 리소스로 생성되고 저장된다. 이와는 대조적으로 사용자 계정을 나타내는 자원은 없으며, 이는 API 서버를 통해 사용자를 생성, 업데이트 또는 삭제할 수 없다는 뜻이다.
    • 인증 플러그인은 사용자 이름 및 사용자 ID와 함께 그룹을 반환한다고 말했다. 그룹은 개별 사용자에게 권한을 부여하지 않고 한 번에 여러 사용자에게 권한을 부여하는 데 사용된다.
  • p530
    • $ kubectl get sa
    • 각 파드는 파드의 네임스페이스에 있는 하나의 서비스어카운트와 연계된다.
  • p531
    • 사용 가능한 인가 플러그인 중 하는 역할 기반 액세스 제어 플러그인이다.
  • p532
    • 리소스의 메타데이터를 검색해야 하는 파드는 해당 오브젝트의 메타데이터만 읽어야 한다. 리소스의 메타데이터를 검색해야 하는 파드는 해당 오브젝트의 메타데이터만 읽을 수 있는 서비스어카운트로 실행해야 하며, 오브젝트를 수정해야 하는 파드는 API 오브젝트를 수정할 수 있는 고유한 서비스 어카운트로 실행해야 한다.
  • p532
    • $ kubectl create serviceaccount foo
  • p534
    • 서비스어카운트는 이미지 풀 시크릿 목록도 포함 할 수 있다.

    imagepullSecrets:
     - name: my-dockerhub-secret 
  • p535

    •   spec :
          serviceAccountName: foo 

12.2. 역할 기반 액세스 제어로 클러스터 보안

  • p537
    • RBAC은 권한이 없는 사용자가 클러스터 상태를 보거나 수정하지 못하게 한다.
  • p538
    • 쿠버네티스 액션에 관한 몇가지 예가 있다.
      • 파드 가져오기
      • 서비스 생성하기
      • 시크릿 업데이트
      • 기타 등등
  • p539
    • RBAC 인가 플러그인은 사용자가 액션을 수행할 수 있는지 여부를 결정하는 핵심 요소로 사용자 롤을 사용한다. 주체는 하나 이상의 롤과 연계돼 있으며 각 롤은 특정 리소스에 특정 동사를 수행할 수 있다.
    • RBAC 인가 규칙은 네 개의 리소스로 구성되며 두 개의 그룹으로 분류할 수 있다.
      • 롤과 클러스터롤 : 리소스에 수행할 수 있는 동사를 지정한다.
      • 롤바인딩과 클러스터롤바인딩 : 위의 롤을 특정 사용자, 그룹, 또는 서비스어카운트에 바인딩한다.
      • 롤은 수행할 수 있는 작업을 정의하고, 바인딩은 누가 이를 수행할 수 있는지를 정의한다.
  • p540
    • 롤과 클러스터롤 또는 롤바인딩과 클러스터롤 바인딩의 차이점을 롤과 롤바인딩은 네임스페이스가 지정된 리소스이고 클러스터롤과 클러스터롤바인딩은 네임스페이스를 지정하지 않는 클러스터 수준의 리소스라는 것이다.
  • p552
    • 클러스터 수준 리소스에는 동일한 방식을 사용할 수 없다. 클러스터 수준 리소스에 액세스 권한을 부여하려면 항상 클러스터롤바인딩을 사용해야 한다.
  • p561
    • 특정 롤과 바인딩의 조합을 사용해야 하는 경우
      • 클러스터 수준 리소스 = 클러스터롤 + 클러스터롤바인딩
      • 리소스가 아닌 URL = 클러스터롤 + 클러스터롤바인딩
      • 모든 네임스페이스의 네임스페이스로 지정된 리소스 = 클러스터롤 + 클러스터롤바인딩
      • 특정 네임스페이스의 네임스페이스로 지정된 리소스 = 클러스터롤 + 롤바인딩
      • 특정 네임스페이스의 네임스페이스로 지정된 리소스 = 롤 + 롤바인딩
  • p562
    • 쿠버네티스는 API 서버가 시작될 때마다 업데이트되는 클러스터롤과 클러스터롤바인딩의 디폴트 세트를 제공한다.

13. 클러스터 노드와 네트워크 보안


13.1. 파드에서 호스트 노드의 네임스페이스 사용

  • p568
    • 각 파드는 고유한 PID 네임스페이스가 있기 때문에 고유한 프로세스 트리가 있으며 고유한 IPC 네임스페이스도 사용하므로 동일한 파드의 프로세스 간 통신 메커니즘 으로 서로 통신할 수 있다.
    • 특정 파드는 호스트의 기본 네임스페이스에서 작동해야 노드의 리소스와 장치를 읽고 조작할 수 있다. 예를 들어 파드는 가상 네트워크 어댑터 대신 노드의 실제 네트워크 어댑터를 사용해야 할수도 있다. 이는 파드 스펙에서 hostNetwork 속성을 true로 설정하면 된다.
    • 이는 파드 자체가 IP 주소를 갖는것이 아니라, 포트를 바인드하는 프로세스를 실행할 경우 해당 프로세스는 노드의 포트에 직접 바인드된다는 의미다.


 
  spec:
    hostNetwork: true
  • p570
    • 파드는 hostNetwork 옵션으로 노드의 기본 네임스페이스의 포트에 바인딩할 수 있지만 여전히 고유한 네트워크 네임스페이스를 갖는다. 이는 컨테이너의 포트를 정의하는 sepc.containers.ports 필드 안에 hostPort 속성을 사용해 할수 있다.
      • hostPort는 Nodeport로 노출된 파드와 다르다. - 김준석


spec:
  containers:
    ..
    ports:
    - containerPort: 8080
      hostPort: 9000
      protocol: TCP

  • p573
    • hostNetwork 옵션과 유사한 파드 스펙 속성으로 hostPID와 hostIPC가 있다. 이를 true로 설정하면 파드의 컨테이너는 노드의 PID와 IPC 네임스페이스를 사용해 컨테이너에서 실행중인 프로세스가 노드의 다른 프로세스를 보거나 IPC로 이들과 통신할 수 있도록 한다.

spec:
  hostPID: true
  hostIPC: true

13.2. 컨테이너의 보안 컨텍스트 구성

  • p574
    • 파드 컨텍스트 아래의 개별 컨테이너 스펙에서 직접 지정할 수 있는 securityContext 속성으로 다른 보안 관련 기능을 파드와 파드의 컨테이너에 구성할 수 있다.
    • 보안 컨텍스트를 설정하면 다음과 같은 다양한 작업을 수행할 수 있다.
      • 컨테이너의 프로세스를 실행할 사용자ID 지정하기
      • 컨테이너가 루트로 실행되는 것 방지하기
      • 컨테이너를 특권 모드에서 실행해 노드의 커널에 관한 모든 접근 권한을 가짐
      • 특권 모드에서 컨테이너를 실행해 컨테이너에 가능한 모든 권한을 부여하는 것과 달리 기능을 추가하거나 삭제해 세분화된 권한 구성하기
      • 컨테이너의 권한 확인을 강력하게 하기 위해 SELinux 옵션 설정하기
      • 프로세스가 컨테이너의 파일시스템에 쓰기 방지하기

  • p575


 $ kubectl exec pod-with-defaults id
uid=0(root) gid=0(root) ...
  • p576
    • 컨테이너 이미지에 설정한 것과 다른 사용자 ID로 파드를 실행하려면 파드의 securityContext.reunAsUser 속성을 설정해야한다.

    • spec :
       containers:
        ..
        securityContext:
          runAsUser: 405
      
  • p577
    • 대부분의 컨테이너는 호스트 시스템과 분리돼 있지만 프로세스를 루트로 실행하는 것은 여전히 나쁜 관행이다.

    •   securityContext:
          runAsNonRoot: true
      
  • p578

    •   securityContext:
          privileged: true
      
    • 노드의 커널의 모든 액세스 권한을 얻기 위해 파드의 컨테이너는 특권 모드로 실행된다.
  • p580
    • 권한 있는 컨테이너를 만들고 무제한 권한을 부여하는 대신 보안 관점에서 훨씬 안전한 방법은 실제로 필요한 커널 기능만 액세스하도록 하는것이다.

    •   securityContext:
          capabilities:
            add:
            - SYS_TIME
      
  • p582
    • 컨테이너가 이를 수행하지 못하게 하려면 컨테이너의 securityContext.capabilities.drop 속성 아래에 기능을 조회해 기능을 삭제해야 한다.

    •   securityContext:
          capabilities:
            drop:
            - CHown
      
  • p583
    • 컨테이너에서 실행 중인 프로세스가 컨테이너의 파일시스템에 쓰지 못하게 하고 마운트된 볼륨에만 쓰도록 할 수 있다.

    •   // 파일시스템은 못쓰지만 마운트 볼륨은 씀
        securityContext:
          readonlyRootFilesystem: true
        volumeMounts:
        - name: my-volume
          mountpath: /volume
          readOnly: false 
      
  • p585
    • 6장에서 파드의 컨테이너 간에 데이터를 공유하는 데 볼륨을 사용하는 방법을 설명했다.
    • 두 컨테이너가 모두 루트로 실행돼 볼륨의 모든 파일에 대한 전체 액세스 권한을 부여했기 때문이다.
    • 쿠버네티스를 사용하면 컨테이너에서 실행 중인 모든 파드의 supplementalGroups 속성을 지정해 실행 중인 사용자 ID에 상관없이 파일을 공유할 수 있따. 이는 다음 두가지 속성을 사용해 수행된다.
      • fsGroup
      • supplementalGroups

    •   securityContext:
          fsGroup: 555
          supplementalGroups: [666, 777]
      

13.3. 파드의 보안 관련 기능 사용 제한

  • p587
    • 클러스터 관리자는 하나 이상의 PodSecurityPolicy 리소스를 생성해 앞으로 설명한 보안 관련 기능의 사용을 제한할 수 있다.
  • p588
    • PodSecuirtyPolicy는 클러스터 수준 리소스로, 사용자가 파드에서 사용할 수 있거나 사용할 수 없는 보안 관련 기능을 정의한다.
    • PodSecurityPolicy 리소스에 구성된 정책을 유지하는 작업은 API 서버에서 실행되는 PodSecurityPolicy 어드미션 컨트롤 플러그인으로 수행된다.
  • p589
    • PodSecurityPolicy 리소스는 다음을 정의한다.
      • 파드가 호스트의 IPC, PID 또는 네트워크 네임스페이스를 사용할 수 있는지 여부
      • 파드가 바인딩할 수 있는 포트
      • 컨테이너가 실행할 수 있는 사용자 ID
      • 특권을 갖는 컨테이너가 있는 파드를 만들 수 있는지 여부
      • 어떤 커널 기능이 허용되는지, 어떤 기능이 기본으로 추가되거나 혹은 항상 삭제되는지 여부
      • 컨테이너가 사용할 수 있는 SELinuxs 레이블
      • 컨테이너가 쓰기 가능한 루트 파일시스템을 사용할 수 있는지 여부
      • 컨테이너가 실행할 수 있는 파일시스템 그룹
      • 파드가 사용할 수 있는 볼륨 유형
  • p591
    • 허용된 사용자 또는 그룹 ID 목록을 제한하려면 MustRunAs 규칙을 변경해 허용할 그룹 ID를 지정할 수 있다.
  • p593
    • runAsUser 필드의 경우 MustRunAsNonRoot라는 추가 규칙을 사용할 수 있다. 이름에서 알수 있듯이 사용자는 루트로 실행되는 컨테이너를 배포할 수 없다.
  • p594
    • 그동안 배운 대로 컨테이너는 특권 모드에서 실행될 수 있으며 각 컨테이너에 리눅스 커널 기능을 추가하거나 삭제해 좀 더 세분화된 권한 구성을 정의할 수 있다. 다음 필드 세 개는 컨테이너의 기능에 영향을 준다.
      • allowedCapabilities 컨테이너에 어떤 기능을 추가할지 지정
      • defaultAddCapabilities 모든 컨테이너에 기능 추가
      • requiredDropCapabilities 컨테이너에서 기능 제거
  • p596
    • PodSecurityPolicy 리소스가 할 수 있는 마지막 기능은 사용자가 파드에 추가할 수 있는 볼륨 유형을 정의하는 것이다. 최소한 PodSecurityPolicy는 적어도 emptyDir, 컨피그맵, 시크릿, 다운워드API, 퍼시스턴트볼륨클레임 볼륨을 사용을 허용해야 한다.
    • 다른 사용자에게 다른 정책을 할당하는 것은 12장에서 설명한 RBAC 매커니즘으로 수행된다. 클러스터롤 리소스를 만들고 이름으로 개별 정책을 지정해 필요한 만큼 많은 정책을 작성하고 개별 사용자 또는 그룹이 사용할 수 있도록 하는 것이다.
  • p598

    •  $ kubectl create clusterrole psp-default --verb=use --resource=podsecuritypolicies --resource-name=default
       $ kubectl create clusterrole psp-privileged --verb=use --resource=podsecuritypolicies --resource-name=previleged
      

    •  $ kubectl create clusterrolebinding psp-all-users --clusterrole=psp-defulat --group=system:authenticated
       $ kubectl create clusterrolebinding psp-bob --clusterrole=psp-privileged --user=bob
      


13.4. 파드 네트워크 격리

  • p601
    • NetworkPolicy는 해당 레이블 셀렉터와 일치하는 파드에 적용되며 일치하는 파드에 액세스할 수 있는 소스나 파드에서 액세스할 수 있는 대상을 지정한다. 이것은 각각 인그레스와 이그레스 규칙으로 구성된다. 두 유형의 규칙은 파드 셀렉터와 일치하는 파드나 레이블이 네임스페이스 셀렉터와 일치하는 네임스페이스의 모든 파드, 또는 CIDR표기법을 사용해 지정된 네트워크 IP 대역과 일치하는 파드에 대해 적용된다.
  • p602

    • kind: NetworkPolicy
      metadata:
        name: default-deny
      spec:
        podSelector: // 모두 매칭되어 모든 네트워크 deny
      

    • kind: NetworkPolicy
      metadata:
        name: postgres-netpolicy
      spec:
        podSelector: 
          matchLabels:
            app: database
        ingress:
        - from:
          - podSelector:
            matchLabels:
              app: webserver
          ports:
          - port: 5432
      

    •   ingress:
        - from:
          - namespaceSelector:
            matchLabels:
              tenant: manning
          ports:
          - port: 80
      
  • p606

    •   ingress:
        - from:
          - inBlock:
            cidr: 192.168.1.0/24
      

    •   egress:
        - to:
          - podSelector:
             matchLabels:
               app: database
      

14. 파드의 컴퓨팅 리소스 관리

  • p609
    • 이 두 세트의 파라메터를 설정하는 것은 파드가 쿠버네티스 클러스터가 제공하는 리소스를 공평하게 공유하게 하고, 클러스터 전체에서 파드가 스케쥴링 되는 방식에도 영향을 미친다.
      • CPU 리소스는 어떻게 할당하는건지 궁금하다 - 서지혜
        • 커널의 그것입니다. OS 시간에 배웠던것이요. Cgoup으로 각 group의 사용량을 모니터링 하고 기준시간내에 quota를 다 쓰면 더이상 CPU Time을 할당하지 않는 방법으로 동작합니다. - bluemir

14.1. 파드 컨테이너의 리소스 요청

  • p610
    • 파드의 리소스 요청과 제한은 모든 컨테이너의 리소스 요청과 제한의 합이다.
      • 파드 리소스를 컨테이너들이 나눠 쓰는 것 - 서지혜
      • 200 밀리코어는 1/5 CPU
    • Mi는 이진주 시반의 Mebibyte를 의미한다. MB(megabyte)는 십진수 기반으로 차이가 있다.
  • p611
    • CPU 요청을 지정하지 않으면 ... 최악의 경우 CPU 시간을 전혀 할당받지 못할 수 있다.
      • request 가 매우 낮을경우에도 발생합니다. 10m~50m 으로 설정했다가 1~5초 정도의 delay를 겪을수도 있습니다. - bluemir
    • 요청(request)는 컨테이너가 사용할 수 있는 CPU 양을 제한하지 않으므로 이는 예견된 일이다. 제한을 하려면 CPU 제한(limits)을 지정해야 한다.
      • request는 최소 할당 리소스, limits는 최대 할당 리소스 - 서지혜
    • $ kubectl exec -it requrests-pod top
  • p612
    • 스케줄러는 파드를 스케줄링 할 때 파드의 리소스 요청 사항을 만족하는 충분한 리소스를 가진 노드만을 고려한다.
    • 스케줄러는 스케줄링을 하는 시점에 각 개별 리소스가 얼마나 사용되는지 보지 않고, 노드에 배포된 파드들의 리소스 요청량의 전체 합만을 본다는 것이다.
      • 실제 파드가 그보다 적게 사용하고 있어도 요청(request)들의 총 합만 고려하므로 스케줄 계산 간단해 질 듯. 그래서 가끔 요청 값을 최적화 하는 것도 필요하다 - 서지혜
  • p613
    • 두 개의 우선순위 함수가 요청된 리소스 양에 기반해 노드의 순위를 정한다. 바로 LeastRequestedPriorityMostReqeustedPriority이다. 첫번째 함수는 요청된 리소스가 낮은(할당되지 않은 리소스의 양이 큰)노드를 선호하는 반면, 두 번째 함수는 그와 정반대로 요청된 리소스가 가장 많은 노드를 선호한다.
    • 파드를 일부 노드에 많이 스케줄링해 특정 노드를 비울 수 있고 제거할 수 있다. 각 노드별로 비용을 지불하므로 이렇게 비용을 절감할 수 있다.
  • p614
    • kubectl describe nodes의 출력 결과를 보면 노드의 사용 가능한 리소스가 두 세트로 표시된다. 노드의 capacity와 allocatable 리소스다. capacity는 노드의 총 리소스를 나타내고 파드에서 모두 사용 가능한 것은 아니다. 특정 리소스는 쿠버네티스와 시스템 구성 요소로 스케줄링된 것일 수 있다. 스케줄러는 오직 allocatable 리소스 양을 기준으로 결정한다.
  • p617
    • kube-system 네임스페이스의 세 파드가 명시적으로 CPU 리소스를 요청했다. 이 요청이 노드를 오버커밋 하게 만들기 때문에 스케줄러는 노드에 파드를 스케줄링 할 수 없다.
      • 노드 용량 초과를 overcommit이라고 하는군 - 서지혜
      • 또는 Overprovisioning 이라고도 합니다. - bluemir
  • p619
    • CPU 요청에 기반해 사용되지 않은 CPU시간이 컨테이너에 분배된다.
      • 제한을 두지 않은 파드들이 유휴상태가 아니라면 남는 CPU 시간은 파드들의 요청에 비례해 분배된다 - 서지혜
      • 이 분배 비율은 request에 영향을 받는것으로 알고 있습니다. cgroup의 동작이 그러한것으로 알아요 - bluemir
    • 결국 아무도 사용하지 않는다면 사용 가능한 모든 CPU를 사용하는 것이 상식이다.
    • 쿠버네티스를 사용하면 사용자 정의 리소스를 노드에 추가하고 파드의 리소스 요청으로 사용자 정의 리소스를 요청할 수 있다.
    • 리소스 이름은 kubernetes.io 도메인으로 시작하지 않는 이상 example.org/my-resource 와 같이 무엇이든 될수 있다. 수량은 반드시 정수여야 한다. 이값은 capacity 필드에서 allocatable 필드로 자동으로 복사된다.
    • 사용자 정의 리소스의 예로는 노드에 사용 가능한 GPU 단위 수가 있다.
      • local disk의 용량등으로 정해서 사용할수도 있습니다. - bleumir


14.2. 컨테이너에 사용 가능한 리소스 제한

  • p620
    • CPU는 압축 가능한 리소스다. 즉, 컨테이너에서 실행 중인 프로세스에 부정적인 영향을 주지 않고 컨테이너가 사용하는 CPU 양을 조절할 수 있다. 메모리는 분명 다르다. 프로세스에 메모리가 주어지면 프로세스가 메모리를 해제하지 않는 한 가져갈 수 없다.
      • 압축 가능한 리소스라는게 생소하군요 - 서지혜
  • p621
    • 오작동하거나 악의적인 파드 하나가 실제 전체 노드를 사용할 수 없게 만들 수 있다.
      • 리소스 모니터링이 필요한 이유 - 서지혜
    • 리소스 요청과는 달리 리소스 제한은 노드의 할당 가능한 리소스 양으로 제한되지 않는다. 모든 파드의 리소스 제한 합계는 노드 용량의 100%를 초과할 수 있다.
    • CPU 사용률은 조절되므로 컨테이너에 CPU 제한이 설정돼 있으면 프로세스는 설정된 제한보다 많은 CPU 시간을 할당받을 수 없다.
    • 메모리는 CPU와는 다르다. 프로세스가 제한보다 많은 메모리를 할당받으려 시도하면 프로세스는 종료된다(컨테이너가 OOMKilled 됐다고 한다. OOM은 Out Of Memory다) 파드의 재시작 정책이 Always 또는 OnFailure로 설정된 경우 프로세스는 즉시 다시 시작하므로 종료됐음을 알아차리지 못할 수 있다.
  • p625
    • top 명령은 컨테이너가 실행 중인 전체 노드의 메모리 양을 표시한다. 컨테이너에 사용 가능한 메모리의 제한을 설정하더라도 컨테이너는 이 제한을 인식하지 못한다.
  • p626
    • 메모리와 마찬가지로 컨테이너는 컨테이너에 설정된 CPU 제한과 상관없이 노드의 모든 CPU를 본다.
    • 여러분의 애플리케이션이 시스템에서 볼 수 있는 CPU 수에 의존하는 대신 Downward APi를 사용해 컨테이너의 CPU 제한을 전달하고 이를 사용할 수 있따. 또한 다음 파일을 읽어 cgroup 시스템에서 직접 설정된 CPU 제한을 얻을 수도 있다.

14.3. 파드 QoS 클래스 이해

  • p627
    • 어떤 파드가 우선순위를 가지는지 지정하는 방법이 필요하다. 쿠버네티스는 파드를 세가지 서비스 품질 클래스로 분류한다.
      • BestEffort (최하위)
      • Burstable
      • Guaranteed (최상위)
    • QoS 클래스는 파드 컨테이너의 리소스 요청과 제한의 조합에서 파생된다.
  • p628
    • 파드의 클래스가 Guaranteed이려면 다음 세 가지를 충족해야 한다.
      • CPU와 메모리에 리소스 요청과 제한이 모두 설정돼야 한다.
      • 각 컨테이너에 설정돼야 한다.
      • 리소스 요청과 제한이 동일해야 한다.
    • 컨테이너의 리소스 요청이 명시적으로 설정되지 않은 경우 기본적으로 리소스 제한과 동일하게 설정되므로 모든 리소스에 대한 제한을 지정하는 것으로 파드가 Guaranteed가 되기 충분하다.
    • 컨테이너의 리소스 제한이 리소스 요청과 일치하지 않은 단일 컨테이너 파드와 적어도 한 개의 컨테이너가 리소스 요청을 지정했지만 리소스 제한을 설정하지 않은 모든 파드가 여기에 속한다.
  • p629
    • 리소스 요청과 제한에 기반으로 한 컨테이너가 하나인 파드의 QoS 클래스
      • CPU 요청 대 제한 메모리 요청대 제한 컨테이너 QoS 리소스
        미설정 미설정 BestEffort
        미설정 요청 < 제한 Burstable
        미설정 요청 = 제한 Burstable
        요청 < 제한 미설정 Burstable
        요청 < 제한 요청 < 제한 Burstable
        요청 < 제한 요청 = 제한 Burstable
        요청 = 제한 요청 = 제한 Guaranteed
        • p630
          • 적어도 한 컨테이너가 다른 클래스를 가지면 컨테이너 클래스가 무엇이든 상관없이 파드의 QoS클래스는 Burstable이다.
        • p632
          • 실행 중인 각 프로세스는 OOM 점수를 갖는다. OOM점수는 두 가지 기준으로 계산된다. 프로세스가 소비하는 가용 메모리의 비율과 컨테이너의 요청된 메모리와 파드의 QoS 클래스를 기반으로 한 고정된 OOM 점수 조정이다. 컨테이너가 하나인 파드 두 개가 존재하고 둘 다 Burstable 클래스일 때 시스템은 요청된 메모리의 비율이 다른 것보다 높은 컨테이너를 종료한다.

14.4. 네임스페이스별 파드에 대한 기본 요청과 제한 설정

  • p633
    • LimitRange 리소스는 컨테이너의각 리소스에 최소/최대 제한을 지정할 뿐만 아니라 리소스 요청을 명시적으로 지정하지 않은 컨테이너의 기본 리소스 요청을 지정한다.
    • limitrange를 적용하면 파드의 처음 마주친 오류의 내용뿐만 아니라 파드가 거부된 모든 이유를 보여준다는 점이다.
    • 네임스페이스가 다른 팀을 분리하거나, 동일 쿠버네티스 클러스터에서 실행하는 개발, QA, 스테이징, 프로덕션 파트를 분리하는 경우 각 네임스페이스에 다른 LimitRange를 사용하면 큰 파드는 특정 네임스페이스만 생성되는 반면 나머지 네임스페이스는 더 작은 파드로 제한되도록 보장한다.

14.5. 네임스페이스의 사용 가능한 총 리소스 제한하기

  • p638
    • 앞서 본것처럼 LimitRange는 개별 파드에만 적용되지만 클러스터 관리자는 네임스페이스에서 사용 가능한 총 리소스 양을 제한할 수 있는 방법이 필요하다. 이것은 리소스쿼터 오브젝트를 생성해 달성할 수 있다.
    • 리소스쿼터는 네임스페이스에서 파드가 사용할 수 있는 컴퓨팅 리소스 양과 퍼시스턴트볼륨클레임이 사용할 수 있는 스토리지 양을 제한한다.
  • p640
    • 리소스쿼터를 생성할 때 주의할 점은 LimitRange 오브젝트도 함께 생성해야 한다는 것이다.
    • 특정 리소스에 대한 쿼터가 설정된 경우에, 파드에는 동일한 리소스에 대한 요청 또는 제한이 각각 설정돼야 한다. 그렇지 않으면 API 서버가 파드를 허용하지 않는다. 그렇기 때문에 이러한 리소스에 대한 기본값이 있는 LimitRange를 갖는 것이 파드를 만드는 것을 조금 더 쉽게 만든다.
  • p643
    • 오브젝트 수의 쿼터는 현재 다음 오브젝트에 설정할 수 있다.
      • 파드
      • 레플리케이션컨트롤러
      • 시크릿
      • 컨피그맵
      • 퍼시스턴트볼륨클레임
      • 서비스, 로드밸런서 서비스와 노드포트 서비스와 같은 두 가지 유형의 서비스
  • p644
    • 쿼터는 쿼터 범위로 제한될수 있다. 현재 BestEffort, NotBestEffort, Terminating, NotTerminating의 네 가지 범위를 사용할 수 있다.
    • BestEffortNotBestEffort 범위는 쿼터가 BestEffort QoS클래스 또는 다른 두 클래스 중 하나 가 있는 파드에 적용되는지 여부를 결정한다.
    • Terminating과 NotTerminating은 이름에서 알수 있듯이 종료 과정의 파드에는 적용되지 않는다. 각 파드가 종료되고 실패로 표시되기 전에 얼마나 오래 실행할 수 있는지 지정할 수 있다. 파드 스펙의 activeDeadlineSeconds필드를 설정하면 된다. 이 속성은 파드가 실패로 표시된 후 종료되기 전 시작 시간을 기준으로 노드에서 활성화되도록 허용하는 시간을 정의한다. Terminating 쿼터 범위는 activeDeadLineSeconds가 설정된 파드에 적용되는 반면 NotTerminating은 그렇지 않은 파드에 적용된다.

14.6. 파드 리소스 사용량 모니터링

  • p645
    • Kubelet 자체에는 이미 cAdvisor라는 에이전트가 포함돼 있는데 이 에이전트는 노드에서 실행되는 개별 컨테이너와 노드 전체의 리소스 사용 데이터를 수집한다. 전체 클러스터를 이러한 통계를 중앙세ㅓ 수집하려면 힙스터라는 추가 구성요소를 실행해야 한다.
    • 힙스터가 사라지고 cAdvisor가 대체된것으로 앎 - 김준석
      • 맞습니다 지금은 그냥 cAdvisor 를 쓰는게 defacto 같아요. - bluemir
    • $ kubectl top pod --all-namespaces

15. 파드와 클러스터 노드의 오토스케일링

  • p655
    • 파드에서 실행되는 애플리케이션은 레플리케이션컨트롤러, 레플리카셋, 디플로이먼트 또는 기타 확장 가능한 리소스 안에 있는 replicas 필드 값을 늘려 수동으로 확장할 수 있다.
    • 쿠버네티스는 파드를 모니터링하다가 CPU 사용량이나 다른 메타륵이 증가하는 것을 감지하는 즉시 자동으로 확장할 수 있다.

15.1. 수평적 파드 오토스케일링

  • p656
    • 수평적 파드 오토스케일링은 컨트롤러가 관리 파드의 레플리카 수를 자동으로 조정하는것을 말한다.
    • 이것은 Horizontal 컨트롤러에 의해 수행되며, HorizontalPodAutoscaler(HPA) 리소스를 작성해 활성화시키고 원하는 대로 설정한다.
    • 컨트롤러는 주기적으로 파드 메트릭을 확인해, HorizontalPodAutoscaler 리소스에 설정돼 있는 대상 메트릭 값을 만족하는 레플리카 수를 계산한다.
    • 그리고 대상 리소스 안에 있는 replicas 필드 값을 조절한다.
    • 오토스케일링 프로세스는 세 단계로 나눌 수 있다.
      • 확장 가능한 리소스 오브젝트에서 관리하는 모든 파드의 메트릭을 가져온다.
      • 메트릭을 지정한 목표 값과 같거나 가깝도록 하기 위해 필요한 파드 수를 계산한다.
      • 확장 가능한 리소스의 replicas 필드를 갱신한다.
    • 파드와 노드 메트릭은 모든 노드에서 실행되는 kubelet에서 실행되는 cAdvisor 에이전트에 의해 수집된다.
  • p658
    • 오토스케일러의 스케일링 대상이 되는 리소스에 속해 있는 파드의 모든 메트릭을 가지고 있으면, 이 메트릭을 사용해 필요한 레플리카 수를 파악할 수 있다. 모든 레플리카에서 메트릭의 평균 값을 이용해 지정한 목표값과 가능한 가깝게 하는 숫자를 찾아야 한다. 이 계산의 입력은 파드 메트릭 세트이고, 출력은 하나의 정수이다.
    • 오토스케일링이 여러 파드 메트릭(CPU 사용량, 초당 질의수(QPS))을 기반으로 하는 경우 계산이 그렇게 복잡하지는 않다. 오토스케일러는 각 메트릭의 레플리카 수를 개별적으로 계산한 뒤 가장 높은 값을 취한다.
  • p659
    • 오토스케일링 자겁의 마지막 단계는 스케일링된 리소스 오브젝트의 레플리카 개수 필드를 원하는 값으로 갱신해, 레플리카셋 컨트롤러가 추가 파드를 시작하거나 초과한 파드를 삭제하도록 하는 것이다.
    • API 서버가 스케일 서브 리소스를 노출하는 한, 오토스케일러는 모든 확장 가능한 리소스를 대상으로 동작할 수 있다. 현재 노출되는 리소스는 다음과 같다.
      • 디플로이먼트
      • 레플리카셋
      • 레플리케이션컨트롤러
      • 스테이트풀셋
  • p660
    • CPU 사용률 기반 스케일링
    • CPU 사용량이 100%에 도달하면 더 이상 요구에 대응할 수 없어 스케일 업(수직적 스케일링: 파드가 사용하는 CPU 양 증가)이나 스케일 아웃(수평적 스케일링: 파드 수 증가)이 필요하다. 여기서 우리는 수평적 파드 오토스케일러만 얘기하고 있기 때문에, 스케일 아웃에 관해서만 집중해보자. 스케일 아웃이 이루어지면 평균 CPU 사용량은 줄어들 것이다.
    • 오토스케일러는 파드의 실제 CPU 사용량과 CPU 요청을 비교하는데, 이는 오토스케일링이 필요한 파드는 오토스케일러가 CPU 사용률을 결정하기 위해서 오토스케일링이 필요한 파드는 직접 또는 간접적으로 LimitRange 오브젝트를 통해 CPU 요청을 설정해야 한다는 것을 의미한다.
  • p662

    •  $ kubectl autoscale deployment kubia --cpu-percent=30 --min=1 --max=5
       // cpu 사용률 30% 유지 최소 1 최대 5
      
  • p664

    •  $ kubectl get hpa
      
  • p668
    • 오토스케일러가 어떻게 네 개의 레플리카가 필요하다는 결론을 얻었는지 살펴보자. 처음에는 레플리카 한 개가 요청을 처리하면서 CPU 사용량이 108%로 급증했다. 108을 30으로 나누면 3.6을 얻게 되는ㄴ데, 오토스케일러는 이 값을 반올림해서 4로 만든다. 108을 4로 나누면 27%를 얻는다. 만약 오토스케일러가 네 개의 파드로 스케일 업하면, 파드들의 평균 CPU 사용률은 27% 근처일 것으로 예상되고, 이 값은 목표 값이 30%에 가깝고 관찰된 CPU 사용률과 거의 비슷하다.
    • 한 번의 확장 단계에서 추가할 수 있는 레플리카의 수는 제한돼 있기 때문이다. 오토스케일러는 두 개를 초과하는 레플리카가 존재할 경우 한 번의 수행에서 최대 두 배의 레플리카를 생성할 수 있다.
  • p669
    • 메모리 기반 오토스케일링은 CPU 기반 오토스케일링에 비해 훨씬 문제가 많다. 가장 큰 이유는 스케일 업 후에 오래된 파드는 어떻게든 메모리를 해제하는 것이 필요하기 때문이다.
  • p670
    • 쿠버네티스 오토스케일링 SIG 는 오토스케일러를 완전히 다시 설계했다.
  • p671
    • HPA 오브젝트에는 사용할 수 있는 세 가지 유형의 메트릭이 있다.
      • 리소스
      • 파드
      • 오브젝트
    • 메트릭의 예로는 이미 언급했던 초당 질의 수 또는 메시지 브로커의 큐 메시지 수 등이 있다.
  • p672
    • Object 메트릭 유형은 오토스케일러가 파드를 확장할 때 파드에 직접 관련되지 않는 메트릭을 기반으로 하도록 만든다. 예를 들어 파드를 확장할 때 인그레스 오브젝트 같은 클러스터 오브젝트 메트릭을 이용할 수 있다.
  • p673
    • 앞에서 언급한 것처럼 파드에 있는 컨테이너의 메모리 소비량은 오토스케일링에 적합한 메트릭이 아니다. 레플리카 수를 늘려도 관찰 중인 메트릭의 평균 값이 선형적으로 감소하지 않거나 최소한 선형에 가깝게 줄어들지 않는다면 오토스케일러가 제대로 동작하지 않는다.
    • 오토스케일러 애플리케이션 정의 메트릭을 오토스케일러의 기반 항목으로 하기 전에, 파드 수가 증가하고 감소할 때 메트릭 값이 어떻게 변화하는지 고려해야 한다.
    • 수평적 파드 오토스케일러는 현재 minReplicas 필드를 0으로 설정할 수 없기 때문에, 파드가 아무것도 하지 않더라고 오토스케일러는 파드 수를 0으로 감소시키지 않는다. 파드수를 0으로 축소할 수 있게 만들면 하드웨어 사용률이 크게 높아질 수 있따.

15.2. 수직적 파드 오토스케일링

  • 수평적 확장이 불가능한 애플리케이션의 경우 유일한 옵션은 수직적(더 많은 CPU와 메모리)으로 확장하는 것이다.
  • 안타깝게도 집필을 마친 지금도 수직적 파드 오토스케일링은 여전히 사용할 수 없다.


15.3. 수평적 클러스터 노드 확장

  • 모든 노드가 한계에 도달해 더 이상 파드를 추가할 수 없을 때는 어떻게 될까?
  • 쿠버네티스는 추가적인 노드가 필요한 것을 탐지하면 가능한 빠르게 추가 노드를 클라우드 제공자에게 요청하는 기능을 가지고 있다.
  • 새 파드가 생성된 후 스케줄러가 기존 노드에 스케줄링할 수 없는 경우, 새로운 노드가 공급된다. 클러스터 오토스케일러는 이런 파드를 찾고 클라우드 제공자에 추가 노드를 시작하도록 요청한다.
  • 클러스터 오토스케일러는 사용 가능한 노드 그룹을 검사해 최소한 하나의 노드 유형이 스케줄링되지 않은 파드를 수용할 수 있는지 확인한다.
  • 클러스터 오토스케일러가 기존 노드에 스케일링할 수 없는 파드를 찾았을 때 스케일 업을 수행한다
    1. 오토스케일러가 기존 노드에 스케줄할 수 없는 파드를 발견한다.
    2. 오토스케일러가 어떤 노드 유형이 파드에 맞을지 결정한다. 여러 유형이 가능하다면 그중 하나를 선택한다.
    3. 오토스케일러가 앞에서 선택한 노드 그룹을 스케일 업한다.
  • 오토스케일러는 모든 노드에 요청된 CPU와 메모리를 모니터링해 이를 수행한다. 특정 노드에서 실행 중인 모든 파드의 CPU와 메모리 요청이 50% 미만이면 해당 노드는 필요하지 않은 것으로 간주한다. 이것이 노드를 중단하는 데 사용하는 유일한 결정 요인은 아니다. 오토스케일러는 해당 노드에서만 실행 중인 시스템 파드가 있는지 검사한다.
  • 만약 시스템 파드가 노드에서 실행 중이라면 해당 노드는 종료될 수 없다. 관리되지 않는 파드나 로컬 저장소를 가진 파드가 실행되는 경우에도 마찬가지다. 만약 시스템 파드가 노드에서 실행 중이라면 해당 노드는 종료될 수 없다. 관리되지 않는 파드나 로컬 저장소를 가진 파드가 실행되는 경우에도 마찬가지다. 파드가 제공하는 서비스가 중단될 수 있기 때문이다.
  • 종료할 조드를 선택되면, 해당 노드는 먼저 스케줄링할 수 없다는 표시를 하고 노드에서 실행 중인 모든 파드를 제거한다. 제거하는 모든 노드는 레플리카셋이나 다른 컨트롤러에 속해 있기 때문에, 교체할 파드가 생성되고 남아 있는 나머지 노드에 스케줄링된다.

  •  $ kubectl cordon <node>  // 명령은 노드를 스케줄링할 수 없음으로 표시함
     $ kubectl drain <node>  // 명령은 노드를 스케줄링 할 수 없음으로 표시하고 노드에서 실행 중인 모든 파드를 종료한다.
    
    • 데몬셋은 이거 무시하고 실행하던데...? - 김준석
  • 클러스터 오토스케일러는 다음 클라우드 제공자에서 사용할 수 있다.
    • 구글 쿠버네티스 엔진
    • 구글 컴퓨트 엔진
    • 아마존 웹 서비스
    • 마이크로소프트 애저
  • p679
    • 특정 서비스에서는 최소 개수의 파드가 항상 실행돼야 한다. 이는 쿼럼 기반 클러스터 애플리케이션인 경우 특히 그렇다. 이런 이유로 쿠버네티스는 스케일 다운 드으이 작업을 수행할 경우에도 유지돼야 하는 최소 파드 개수를 지정하는 방법을 제공한다.

16. 고급 스케줄링


Extend Resource 이야기는 없네요.. 실무에서는 그게 유연하게 쓸수 있어서 많이쓰는데.. - bluemir

16.1. 테인트와 톨러레이션을 사용해 특정 노드에서 파드 실행 제한

  • p684
    • 노드 테인트와 이 테인트에 대한 파드 톨러레이션이다. 테인트와 톨러레이션은 어떤 파드가 특정 노드를 사용할 수 있는지를 제한하고자 사용된다. 노드의 테인트가 허영된 경우에만 파드가 노드세 스케줄링 될 수 있다.
    • 노드 셀렉터와 노드 어피니티를 사용하는 것과는 약간 다르다.
    • 노드에 테인트를 추가하는 것만으로도 파드가 특정 노드에 배포되지 않도록 한다. 테인트된 노드에 배포할 파드는 테인트된 노드를 사용하게 선택할 필요가 있는 반면, 노드 셀렉터를 사용하면 파드를 배포할 노드를 명시적으로 지정한다.
  • p685
    • 마스터 노드에는 테인트가 하나 있따. 테인트에는 키, 값, 효과 가 있고 <key>=<value>:<effect> 형태로 표시된다.

    • node-role.kubernetes.io/master <key> null <value> 효과는 NoSchedule
      
    • 시스템 파드는 톨러레이션과 노드의 테인트가 일치하기 때문에 마스터 노드에 스케줄링 된다.
  • p686
    • 테인트 효과 이해하기
    • kube-proxy 파드의 다른 두 가지 톨러레이션은 준비되지 않았거나 도달할 수 없는 노드에서 파드를 얼마나 오래 실행할 수 있는지를 정의한다.
      • NoSchedule: 파드가 테인트를 허용하지 않는 경우 파드가 노드에 스케줄링되지 않는다.
      • PreferNoSchedule: NoSchedule의 소프트한 버전이다. 즉, 스케줄러가 파드를 노드에 스케줄링하지 않으려 하지만 다른 곳에 스케줄링 할 수 없으면 해당 노드에 스케줄링 된다.
      • NoExecuete: 스케줄링에만 영향을 주는 NoSchedule이나 PreferNoSchedule과 달리, NoExecute는 노드에서 이미 실행 중인 파드에도 영향을 준다. NoExecute 테인트를 노드에 추가하면 해당 노드에서 이미 실행 중이지만 NoExecute 테인트를 허용하지 않는 파드는 노드에서 제거된다.
  • 노드에 사용자 정의 테인트 추가하기
$ kubectl taint node node1.k8s node-type=production:NoSchedule
  • 파드에 톨러레이션 추가

 spec:
   tolerations:
   - key: node-type
     Operator: Equal
     value: production
     effect: NoSchedule
  • p689
    • 테인트는 키와 효과만 갖고 있고, 값을 꼭 필요로 하지 않는다. 톨러레이션은 Equal 연산자를 지정해 특정한 값을 허용하거나, Exists 연산자를 사용해 특정 테인트 키에 여러값을 허용할 수 있다.

16.2. 노드 어피니티를 사용해 파드를 특정 노드로 유인하기

  • p691
    • 노드 셀렉터와 유사하게 각 파드는 고유한 노드 어피니티 규칙을 정의할 수 있다. 이를 통해 꼭 지켜야 하는 필수 요구 사항이나 선호도를 지정할 수 있다.
  • p693

    • apiVersion: v1
      kind: Pod
      metadata:
        name: kubia-gpu
      spec:
        affinity:
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
              nodeSelectorTerms:
              - matchExpressions:
                - key: gpu
                  operator: In
                  values:
                  - "true"
        containers:
        - image: luksa/kubia
          name: kubia
      
    • requireDuringScheduleing... 이 필드 아래에 정의된 규칙은 파드가 노드로 스케줄링되고자 가져야 하는 레이블을 지정한다.
    • ...IgnoredDuringExecution 이 필드 아래에 정의된 규칙은 노드에서 이미 실행중인 파드에는 영향을 미치지 않는다.
    • 현재 시점에는 어피니티가 파드 스케줄링에만 영향을 미치며, 파드가 노드에서 제거되지 않음을 알려주고싶다.
    • nodeSelectorTerms 필드와 matchExpressions 필드가 파드를 노드에 스케줄링하고자 노드의 레이블이 일치하도록 표현식을 정의하는데 사용된다는 것을 쉽게 이해할 수 있을 것이다.
  • p695
    • 새로 도입된 노드 어피니티 기능의 가장 큰 장점을 특정 파드를 스케줄링할 때 스케줄러가 선호할 노드를 지정할 수 있다는 것이다. 이는 prefereedDuringSchedulingIgnoredDuringExecution 필드를 통해 수행된다.
  • p697

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: pref
spec:
  replicas: 5
  template:
    metadata:
      labels:
        app: pref
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 80
            preference:
              matchExpressions:
              - key: availability-zone
                operator: In
                values:
                - zone1
          - weight: 20
            preference:
              matchExpressions:
              - key: share-type
                operator: In
                values:
                - dedicated
...
  • 이 파드는 어느 노드에나 스케줄링 될 수 있지만 파드의 레이블에 따라 특정 노드를 선호한다.
  • p699
    • 생성된 다섯 개의 파드 중 네 개는 node1에 배포됐으나 하나는 node2에 배포됐다. 왜 파드 중 하나가 node1 대신 node2에 배포돼쓸까? 그 이유는 스케줄러가 파드를 스케줄링 할 위치를 결정하는 데 노드의 어피니티 우선순위 지정 기능 외에도 다른 우선순위 지정기능을 사용하기 때문이다. 그중 하나다 Selector-spreadPriority 기능이다. 이 기능은 동일한 레플리카셋 또는 서비스에 속하는 파드를 여러 노드에 분산시켜 노드 장애로 인해 전체 서비스가 중단되지 않도록 한다. 이는 파드 중 하나가 node2에 스케줄링된 원인일 가능성이 높다.

16.3. 파드 어피니티와 안티-어피니티를 이용해 파드 함께 배치하기

  • p699
    • 쿠버네티스가 프론트엔드 파드와 백엔드 파드를 서로 가깝게 유지하면서 적절한 곳에 배포하도록 하는 게 낫다. 이는 파드 어피니티를 사용해 달성할 수 있다.

  • p700

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: frontend
spec:
  replicas: 5
  template:
    metadata:
      labels:
        app: frontend
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - topologyKey: kubernetes.io/hostname
            labelSelector:
              matchLabels:
                app: frontend
  • 예제는 이 디플로이먼트에서 app=backend 레이블이 있는 파드와 동일한 노드/topology에 배포되도록 하는 필수 요구 사항을 갖는 파드를 생성하는 것을 보여준다.
  • 백엔드 파드를 스케줄링 하는 과정에서 파드 간의 어피니티로 인해 node2가 node1보다 높은 점수를 받았다는 것을 알 수 있다.
  • p703
    • 노드 선호도를 지정해 스케줄러가 특정 노드에 파드를 스케줄링하도록 지시하되 해당 노드가 어떤 이유로든 파드에 맞지 않을 경우 다른 곳으로 스케줄링되게 할 수 있다.

    • apiVersion: extensions/v1beta1
      kind: Deployment
      metadata:
        name: frontend
      spec:
        replicas: 5
        template:
          metadata:
            labels:
              app: frontend
          spec:
            affinity:
              podAffinity:
                preferredDuringSchedulingIgnoredDuringExecution:
                - weight: 80
                  podAffinityTerm:
                    topologyKey: kubernetes.io/hostname
                    labelSelector:
                      matchLabels:
                        app: backend
      
  • p707
    • 파드를 서로 멀리 떨어뜨려 놓고 싶을 수 있다. 이것을 파드 안티어피니티 podAntiAffinity 라고 한다.
    • 두개의 파드 세트가 동일한 노드에서 실행되는 경우 서로의 성능을 방해하는 경우 이 기능을 사용한다.

    • piVersion: extensions/v1beta1
      kind: Deployment
      metadata:
        name: frontend
      spec:
        replicas: 5
        template:
          metadata:
            labels:
              app: frontend
          spec:
            affinity:
              podAntiAffinity:
                requiredDuringSchedulingIgnoredDuringExecution:
                - topologyKey: kubernetes.io/hostname
                  labelSelector:
                    matchLabels:
                      app: frontend
      ...
      

17. 애플리케이션 개발을 위한 모범 사례

18. 쿠버네티스의 확장

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2022-05-18 16:00:26
Processing time 0.3535 sec