강의 정보
- 러닝스푼스에서 2023년 4월 ~ 6월 간 강의한 쿠버네티스 딥다이브 2기 를 듣고 정리한 내용입니다.
강의 필기록 원본이라 글이 좀 어수선할 수 있습니다.
4주차 회고 (및 썰들)
- (옛날 카카오) ingress nginx 를 커스텀해서 사용자 인증 쿠키를 ingress controller 에서 검사하도록 했었다
- 다만 버그가 있으면 500 에러가 뜨기 때문에 디버깅이 어려움
- (네이버) 네이버는 사내에 10개의 클러스터로 모든 서비스를 소화중이고, AWS 처럼 overlay network 를 사용하지 않고 Routing table 을 건든다
- 물론 버그가 많아 고생했다고 하네
- 원래 개발하던 KubeDNS 가 확률상으로 질의가 잘 되지 않는 문제가 있었는데, 별개의 프로젝트로 진행되던 CoreDNS 가 쿠버네티스에서 사용하기 편해보여 추가적으로 plugin 을 개발하여 쿠버네티스에서 사용하게 되었다
- (옛날 카카오) CoreDNS 가 버그가 있어 7000개가 넘는 클러스터가 사내 중앙 DNS 서버를 바라보게 했는데, 이것이 장애가 나서 클러스터가 전부 죽은적이 있었다고 한다.
OCI (Open Container Initiative)
- Linux Foundation 에 대한 썰들
- 리누스 토발즈를 내쫒았다
- 중국을 싫어한다: 중국 오픈소스 프로젝트를 배제하는 경향이 있다
Docker run nginx 를 실행하면 어떤일이 일어나는가
- 이미지가 레지스트리에 있는지 확인
- 이미지를 로컬에 다운로드 (tar)
- 이미지 압축해제
- 로컬 어딘가에 파일시스템을 생성
- 해당 파일시스템으로 프로세스 실행
- 프로세스 (PID?), 파일시스템 격리
실습
- 실습 코드) iwanhae/learningspoons-kubernetes
- 위의 실습에서는
- ubuntu 이미지의 root dir 을 tmp 라는 로컬 폴더로 다 옮긴다
- 그리고 로컬폴더의 tmp 를 chroot 를 사용해서 (
chroot tmp
) 루트를 속여준 후에 bash 를 실행시키면 - 실제로는 tmp 라는 파일에 데이터들이 담겨있지만 bash 에서 pwd 를 때리면 root 로 나온다 + 따라서 당연히 bash 로는 root 의 상위로 올라갈 수는 없다
- 즉, 파일시스템이 격리되게 되는 것
OCI Spec
- OCI 에서는 컨테이너를 어떻게 만들고 관리하고 삭제할건지
Runtime Spec
- Docker 가 만든 OCI-compatible runtime: runc
- 구글이 만든 OCI?
Image Spec
- image spec 은 변경점이 많아져서 옛날 docker spec 과 oci spec 이 호환되지 않을 수 있다
- 즉, 오래된 이미지면 호환성문제가 생길 수 있다
- Image 는 아래의 네개로 구성되어 있다
- index json
- manifest json 들의 shasum 저장?
- manifest json
- layer tar 들의 shasum 저장
- config json
- 이미지를 실행시키기 위한 방법이 기술
- layer tar
- rootfs 가 tar 파일로 묶여있는 것
- 이미지 tar 의 blobs 에 각 layer 들이 tar 로 들어있는데
- layer(N) 은 layer(N-1) 에서 변경된 것들만 저장한다 (뭐가 삭제되었고 뭐가 생성되었는지 등)
- index json
Distribution Spec
- HTTP API 로 이미지를 어떻게 배포하는지에 대해 기술
- auth 를 어떻게 구현하는지는 정의하지 않는다
- Docker hub 에서 Docker pull 을 했을 때 우선 token 이 없으니까 401을 주는데
- 여기에는
www-authenticate: Bearer realm=”$URL”
헤더가 포함되어 있음- 그럼 Docker 는
$URL
에서 token 을 받아와서 다시 요청을 날린다고 한다
- 그럼 Docker 는
- 여기에는
- Layer 를 다운로드할 때에는 registry 에서 직접 주는게 아니라 301 을 줘서 딴곳에서 받아오도록 한다
CNCF (Cloud Native Computing Foundation)
- CNCF 가 관여하고 있는 프로젝트 오버뷰
- CNCF 가 내린 Cloud Native 의 정의
- Linux Foundation 이 관리하는 클라우드 관련 단체
- OCI 도 좋지만 이것은 컨테이너에 대한 low level 의 정의만을 내림
- 따라서 실제 Production 에서 컨테이너를 사용하기 위해 필요한 추가적인 것들을 CNCF 에저 정의함
- Spec 보다는 Interface 를 정의
- 다양한 환경을 지원하기 위해 + K8s 의 책임범위를 명확하게 하기 위해 정의
CNI
- runc 처럼 커맨드로 작동하는 내용이 기술됨
- CNCF 의 CNI 설명: Deep Dive: CNI - Bryan Boreham, Weaveworks & Bruce Ma, Ant Financial
- CNI 에는 garbage collection 이 정의되어있지 않다
- 컨테이너가 정상종료되면 Container runtime 이 네트워크 세팅도 지운다
- exit 1 등으로 종료돼도 Container runtime 이 네트워크 세팅을 지운다
- 하지만 node OOM 등으로 비정상 종료되면 CNI 설정이 남아있을 수도 있다
- 종종 발생한다고 한다
- 이때는 노드 재부팅으로 말끔히 해결할 수 있다
- CNI Plugin
- Pod 의 net ns 에 ip 를 부여하고, 해당 net ns 끼리 통신이 잘 될 수 있도록 중간 네트워크 구성을 자동화하는 놈
- CNI 는 Container 가 아니라 VM 에서도 사용 가능하다
- id 만 잘 설정해주면 된다
Flannel deep dive
- hostpath
/run/flannel
: 노드 하나에서 여러개의 flannel container 가 뜨지 못하게 함/opt/cni/bin
: flannel binary 를 host 에 설치- CNI 스펙에서는 여기에 어떤 바이너리가 있어야 하고, 각 바이너리는 어떤 인자와 환경변수를 가져야 하는지 정의해놓았다
- 이 디렉토리에는 flannel 같은 cni plugin 의 binary 뿐 아니라 kubelet 이 복사 혹은 apt install 한 binary 들이 들어간다
/etc/cni/net.d
:/opt/cni/bin
속의 binary 를 실행시키기 위한 설정파일 저장
CRI
- Container runtime 과 UNIX Socket (UDS, UNIX Domain Socket) 로 gRPC 소통하는 서버의 성격이 강하다
- RunC -(래핑)-> ContainerD -(래핑)-> Docker
- CRI-O: ContainerD 는 다양한 요구사항을 맞추기 위한 다양한 기능을 제공하지만 Kubernetes 에만 집중한 기능들을 제공하는 더 가벼운 런타임을 제공하기 위해 redhat 에서 개발
- Pod 와 Container 의 차이
- pod 는 6 개의 LNS(Linux namespace) 중에 2개 (mnt, pid) 만 빼고 나머지 (net, ipc, uts, uid) 를 공유한다
- 즉, pod 에서 돌아가는 container 들은 저 둘 빼고 나머지는 공유한다는 소리
- Pod sandbox: pod 에서 공유하는 LNS 들을 생성해주기 위한 sandbox container
- 이놈이 장애날일을 별로 없다: 보통 kubelet 이 알아서 복구해줌
- Pod sandbox 를 생성해서 공유 ns 에 대한 자원들 (IP 등) 을 할당받고 pod 의 container 들이 이 ns 에서 작동할 수 있도록 함
- Protobuf
- gRPC
- cAdvisor
- CRI 에는 container 의 사용량을 모니터링하는 인터페이스가 없다
- 최근에 추가되었다고 하긴 함; 아직 alpha 단계
- 따라서 Kubelet 은 CRI 를 통해 container 를 생성 및 관리하지만
- Container 를 모니터링하는 것은 CRI 를 통하지 않고 cgroup 으로 메트릭을 수집하는 cAdvisor 프로세스를 fork 해서 모니터링하게 함
- CRI 에는 container 의 사용량을 모니터링하는 인터페이스가 없다
- CRI 에는 ImageService API 가 있어서 사용하지 않는 이미지를 자동으로 지운다
- K8s 에서 dind 파드 띄우기
- dind 파드에서의 docker process 는 moby namespace 로 ContinerD 에 접근하니까 k8s 에서는 보이지 않는다
- 추가적으로 CRI 는 image flush 를 제공하는데 docker 는 지원하지 않기 때문에 k8s 입장에서는 보이지 않는 이미지가 계속 쌓일 수도 있다
CSI
- Storage 쪽 interface
- CSI Controller 는 k8s 에서 pv 와 pvc 의 reconcile 을 담당: watch 하고 있다가 event 가 생기면 CSI Driver 에 gRPC 로 API 를 찌른다
CPI
- 나머지는 약간 cli 인자를 뭘 줘야 하고 이런 것들에 대해 정의되어있었다면
- 이건 진짜 인터페이스
- Provider 쪽에 강제되는 인터페이스쪽이다: AWS, GCP 모두 따르고 있다
- Availability Zone 간의 트래픽을 최소화하기 위한 Inner zone first 설정도 있다더라