Search

나를 성장하게 한 이직 준비 - 기술편 🇰🇷

면접 시 받았던 질문 중 기억에 남거나 대답을 잘 못했던 것에 대한 회고이다. 또는 JD 기반 예상 질문에 대해 준비한 답변이다.
제목이 질문 또는 키워드, 내용은 답변처럼 한번에 쭉 말하는 형식이다. 내용엔 작성하며 참고했거나 답변을 생각 하게끔 도움을 준 링크도 같이 있다.
객관적인 내용은 흰색, 주관적인 생각은 주황색으로 표기한다.

QoS

Quality of Service의 약자. 쿠버네티스에서 파드의 컨테이너가 요청하는 컴퓨팅 리소스(cpu, 메모리)를 확보하여 동작을 보장한다. 또 시스템 전체(클러스터)에서 리소스 관리를 효율적으로 하기 위한 방법이다. 요청(requests)과 한계(limits)에 따라 세 가지의 클래스가 있다.
Guaranteed: 각각 cpu와 메모리의 요청과 한계가 같아야 한다.
# .spec.containers[*] resources: limits: cpu: '1' memory: 2Gi requests: cpu: '1' memory: 2Gi
YAML
복사
세 클래스 중 스케쥴 우선순위가 가장 높고 방출(eviction) 우선순위가 가장 낮다. 말 그대로 실행을 ‘보장’한다
Burstable: 리소스 요청이나 제한이 하나라도 없는 경우에 해당한다.
# .spec.containers[*] resources: limits: memory: 2Gi requests: cpu: '1' memory: 4Gi # .resources.(requests|limits).(cpu|memory) 중 하나라도 없다면 해당한다.
YAML
복사
위에서 설명한 우선순위가 중간에 해당한다. 요청과 한계가 같지 않기 때문에, 스케쥴 된 노드에서 가능하다면 더 많은 리소스를 쓸 수 있다(burst). cpu와 메모리 오버커밋 시 시스템에서 동작과 처리가 다르기 때문에 주의가 필요하다(후술).
BestEffort: 리소스 요청과 제한이 없다.
# .spec.containers[*] resources: {}
YAML
복사
우선순위가 가장 낮아 시스템 리소스 부족 시(pressure) 먼저 방출된다.
나는 리소스 각각을 나눠서 클래스를 구분한다. 예를 들어 cpu는 요청만 주어서 burstable, 메모리는 요청과 한계를 같게 하여 gauranteed 라고. 물론 이러면 위에 설명한 스케쥴이나 eviction 우선순위에 들어 맞진 않는다. 하지만 각 리소스 오버커밋 시 다른 동작에 따라 정책을 가져갈 수 있다.
cpu는 오버커밋하면 시스템(노드의 OS, 리눅스 커널)에 의해 스로틀링 된다. 이게 지속되면 시스템 전체 부하(load)가 올라가고 작업 처리(=컨테이너 실행)가 지연 된다.
메모리는 오버커밋 시 시스템의 (물리 메모리와 swap까지) cap을 넘어서면 프로세스(=컨테이너)를 죽이는 식(SIGKILL)으로 관리한다(oom). 죽일 프로세스를 선택하는 과정은 사용하는 메모리량이나 실행 시간, 커널 구성 값에 따라 휴리스틱하게 선택한다.
따라서 나는 기본적으로 cpu는 burstable, 메모리는 gauranteed의 리소스 할당하여 각각 노드의 CFS와 OOM에게 관리를 위임한다. cpu는 오버커밋 되더라도 최악의 경우 다른 컨테이너를 죽이진 않기 때문에 한계를 두지 않는다. 메모리는 커널의 oom이 동작할 수 있도록 한계를 구성한다.
다만 워크로드 특성에 따라 다르게 적용해야 되는 경우가 있다.
cpu의 경우 컨텍스트 스위칭의 부하를 없애기 위해 정적으로 노드 코어를 할당할 수 있다. 이 경우 QoS 클래스는 gauranteed로 구성해야 하고, 노드에서 기능을 활성화하기 위한 몇가지 옵션이 있다:
또 cpu와 메모리 둘 다 초기 부팅 시에만 사용량이 피크치는 패턴이 많다. 이 경우, 특히 메모리는, 너무 높은 요청량 구성 시 사용률(utilization)이 낮아져 비용 효율적이지 않다. 적절한 burstable 구성을 하거나, 아직(v1.27) 알파 단계인, 파드 resizePolicy를 생각해볼 수도 있다:

IPSec VPN, AWS DX, BGP

IPSec VPN: IP 패킷 인증과 암호화VPN 구성할 수 있다. 인증은 접속하는 출처(source)가 신뢰할 수 있는지 확인한다. 인증이 안된 사용자는 데이터를 읽을 수 없게 암호화한다. 전송 중 데이터 변경을 확인하기 위해 무결성(integrity) 검사 및 전송 중 패킷을 가로챌 수 없도록 replay protection 기능이 있다. 보통 헤더와 페이로드 모두 암호화하는 터널 모드로 구성한다. 또는 페이로드만 암호화 하는 트랜스포트 모드로 구성할 수도 있다.
AWS Direct Connect(DX): 온프렘 사설 네트워크를 AWS에 연결하기 위한 dedicated 네트워크 연결이다. 인터넷을 통하지 않는 private 연결로 보안 강화대역폭 비용 절감, 일관된 네트워크 성능 등의 이점이 있다.
Broad Gateway Protocol(BGP): AS(Autonomous System; 관리 집합 내의 라우터 집합) 가장자리의 BG(Broad Gateway)를 연결하는 프로토콜. 같은 AS의 BG를 연결하는 iBGP와 다른 AS BG를 연결하는 eBGP가 있다. BGP의 목적은 라우터가 속한 AS를 주변 라우터에게 알림으로 패킷 전달 경로를 계산하게끔 한다. BGP는 Hot Potato Routing을 사용하여 경로를 선택한다. Hot Potato Routing은 알려진 경로 중 다음 hop의 비용이 낮은 곳을 선택하게 된다.

white box test vs. black box test

테스트 시 애플리케이션 내부를 볼 수 있느냐 없느냐로 구분한다. 따라서 방법과 목적도 그에 맞게 달라진다.
White(Clear, Glass) Box Testing: 테스트하는 사람이 애플리케이션 내부 구현, 구조, 설계에 대해 알고 있다. 그래서 테스트도 내부 동작에 중점을 둔다. 이는 애플리케이션 내부 코드 뿐만 아니라 특정 메트릭, 로그를 만드는 코드를 삽입해서 테스트할 수 있음도 의미한다. 테스트 대상은 내부 기능, 코드 구조, 알고리즘 구현등 애플리케이션 내부이다. 방법은 단위 테스트, 통합 테스트, 코드 커버리지 등이 있고 코드 정적 또는 동적 분석을 모두 포함한다. 목적은 애플리케이션 입출력의 흐름을 확인하고 보안등을 강화하기 위함이다.
Black Box Testing: 테스트하는 사람이 애플리케이션 내부에 대해 전혀 모른채로 한다. 볼 수 있는 메트릭, 로그가 애플리케이션의 것이나 코드 삽입을 통해 얻어낼 수 있는게 아닌, 일반적인 시스템 지표(e.g. cpu, 메모리, …)를 바탕으로 하는 테스트를 뜻하기도 한다. 따라서 테스트는 요구사항과 기능에 기반한다. 애플리케이션이 “무엇(what)”을 하는지에 중점을 둔다(”어떻게(how)”가 아니라). 방법은 기능 테스트, 시스템 테스트, 인수 테스트 또는 성능이나 사용성 테스트 같은 비기능 테스트를 사용한다. 목적은 비즈니스 프로세스 검증이나 사용자의 요구사항 충족 여부 그리고 오작동 또는 누락된 기능이 있는지 검증한다.

keepalive, HTTP 1.0 ~ 3.0

파드 내 컨테이너는 어떻게 서로 통신하는가(네트워크)?

루프백을 통해 서로 통신한다.
한 파드의 여러 컨테이너가 같은 네트워크 네임스페이스에 위치하여 같은 IP(veth0)를 갖게(보게) 함
veth0을 만드는 pause 컨테이너가 생성된다(어느 버전?)
 파드 간 통신(까지 다루면 CNI 전부)
파드 가상 이더넷의 IP가 겹치지 않도록 노드 단위로 서브네팅한다(node wide, 오버레이 네트워크)

프로메테우스가 인스턴스를 찾는 법(*_sd_)

Istio의 control plane

istiod(단일 프로세스)
pilot
플랫폼 특정 라우팅 규칙(CRD) 서비스 디스커버리를 envoy config로 합성
라우팅 규칙 → envoy config, 사이드카(envoy proxy)에 전파;
citadel
보안 모듈, mTLS(CA, certs 발급, …)
gallery
CR(virtualservice, destinationrule, …) 관리, pilot에게 handover

GIL?

무중단 업그레이드 방법

TLS는 L4? L7?

파드 삭제(delete) 시 과정

delete → prestop hook → (SIGTERM) → graceful shutdown → (SIGKILL)
graceful shutdown에 되어야 하는 일(=할 수 있을만큼 충분히 길어야 한다)
persistent connections 끊기; DB, queue, ws, …
활성 요청 drain

요청은 어떻게 클러스터까지 들어와요?

STUN/TURN

ICE(interactive connectivity establishment): peer의 최적 경로를 찾는 프레임워크
STUN(session traversal utilities for nat): peer의 public ip를 보내준다
TURN(traversal using relays around): nat (보안) 정책으로 바인딩이 어려울 경우 릴레이서버를 경유할 수 있게 한다. peer local address 뿐만 아니라 server reflex, relay를 보내준다.
NAT: 주소 변환, private → public 망이 바뀔 때 게이트웨이의 public ip로 변환하여 요청을 보낸다.
SNAT/DNAT: source vs. destination

간헐적인 타임아웃 디버깅

일단 질문 상황의 한가지 경우로, MSA에서 특정 서비스의, 가장 짧은 타임아웃 구성이 전파되는 상황으로 가정했다(간헐적인 것은 특정 요청이 그 타임아웃을 유발할만큼 오래 걸리는 것으로 가정함).
위에서 설명한거처럼, 여러 서비스 요청 흐름 중 가장 짧은 타임아웃이 응답 타임아웃으로 정해져 올바르게 처리되지 않을 수 있다. 우선 재현하기 위해선 간헐적인 상황의 요청을 특정해야 한다(e.g. 페이로드가 몇 크기 이상의 요청, …). 그리고 요청이 흐르는 각 서비스의 타임아웃 구성을 추적해야 한다.
MSA 복잡도가 증가할 수록 추적과 관리가 어렵다. 따라서 istio와 같은 서비스 메시를 구성하여 가시성을 높여 디버깅을 쉽게 한다.
특히 이 경우 가장 짧은 타임아웃만큼의 fault injection을 해봄으로써 테스트 또는 재현하고 실제 문제를 예방할 수 있다.

메트릭 유형: count vs. gauge

Count: 시간 경과에 따른 발생 횟수(count)의 누적(cumulative) 단조(monotonically increasing) 메트릭. 누적이란 특징 때문에, 특정 기간(time frame, vector)내의 비율로 변환하여 사용하기도 한다(irate).
Gauge: 특정 시점의 특정 값 즉, 스냅샷이다. 누적되지 않기 때문에 count와 달리 감소할 수도 있다. 현재 상태를 측정하는데 쓰인다(e.g. cpu 로드, 온도, …)
 histogram, summary