← --library
이과 · 19이과

운영체제 및 시스템 아키텍처

단계1단계2단계3단계4단계5

3단계: 격리, 관측, 그리고 이기종 컴퓨팅의 세계


들어가며 — 여기까지 온 여정을 복기하며

2단계에서 너는 커널이 어떻게 다수의 프로세스에게 CPU 시간을 나눠주는지(멀티코어 스케줄링), 그리고 각 프로세스가 마치 자신만의 메모리 공간을 가진 것처럼 착각하게 만드는 가상 메모리(virtual memory) 의 마법을 배웠다. 한번 생각해보자. 가상 메모리는 프로세스들이 서로의 메모리를 건드리지 못하도록 막아준다. 그런데 "메모리만" 격리하면 충분할까? 만약 어떤 프로세스가 파일 시스템 전체를 뒤지거나, 네트워크 포트를 마음대로 열거나, 다른 프로세스를 들여다본다면? 2단계의 가상 메모리가 "각자의 RAM 영토" 를 만들어준 것이라면, 3단계에서 다룰 컨테이너와 하이퍼바이저는 그보다 훨씬 넓은 의미의 "각자의 세계" 를 만드는 기술이다. 그리고 그 세계를 "바깥에서 들여다보는 망원경" 이 바로 eBPF 이며, 이 모든 격리된 세계들에 다양한 종류의 연산 엔진(CPU, GPU, FPGA)을 묶어 하나의 작업 흐름으로 만드는 것이 이기종 컴퓨팅 오케스트레이션 이다. 세 개의 개념은 독립적으로 보이지만, 실제 현대 클라우드 인프라에서는 이 셋이 항상 함께 작동한다.


Part 1: 이론적 기초 — "격리"라는 철학과 가상화의 역사

격리는 왜 필요한가?

컴퓨터가 처음 등장했을 때는 한 번에 하나의 프로그램만 실행했다. 문제가 없었다. 그런데 여러 사람이 동시에 같은 컴퓨터를 쓰기 시작하면서 문제가 생겼다. 철수가 실수로 영희의 파일을 덮어쓴다. 영희의 프로그램이 무한 루프를 돌면서 CPU를 혼자 독점한다. 1단계에서 배운 동기화(synchronization) 문제가 떠오를 것이다. 락(lock)으로 해결하려 했지만, 락은 공유 자원에 대한 접근 순서를 제어할 뿐이지 애초에 접근 자체를 차단하지는 않는다. 이때 등장한 근본적 해법이 격리(isolation) 다. "공유하되 서로 보이지 않게" 만드는 것. 이 원칙은 운영체제 역사 전반을 관통하는 핵심 철학이며, 나중에 나올 Saltzer & Schroeder의 1975년 논문 "The Protection of Information in Computer Systems" 에서 최소 권한 원칙(Principle of Least Privilege) 으로 정식화된다.

[노트 기록] 격리의 두 가지 차원: (1) 공간적 격리 — 각 주체가 볼 수 있는 자원의 범위를 제한한다, (2) 자원 격리 — 각 주체가 소비할 수 있는 자원의 양을 제한한다. 이 두 축이 이번 단계 전체의 뼈대다.

가상화의 역사: IBM에서 Docker까지

가상화의 기원은 놀랍게도 1960년대 IBM의 메인프레임으로 거슬러 올라간다. IBM의 CP-40(1967)은 하나의 물리적 기계 위에 여러 개의 가상 기계(VM)를 실행했다. 이유는 단순했다. 메인프레임은 엄청나게 비쌌고, 유휴 시간이 생기면 돈 낭비였다. "한 대를 여러 대처럼 쓰자"는 발상이다. 이것이 하이퍼바이저(hypervisor) 의 기원이다. 2000년대에는 x86 아키텍처에서 VMware가 이 기술을 부활시켰고, 이후 Linux 커널 자체에 가상화 기능이 내장되면서 KVM(Kernel-based Virtual Machine) 이 탄생했다. 그런데 가상 기계는 무겁다. 각 VM이 완전한 운영체제 커널을 따로 실행해야 하기 때문이다. 이 무게를 극단적으로 줄인 것이 컨테이너(container) 다. 컨테이너는 커널을 공유하되, Linux가 원래 가지고 있던 격리 도구들(namespace와 cgroup)을 조합해 격리된 환경을 만든다. 2013년 Docker가 이 복잡한 과정을 사용자 친화적인 CLI로 포장하면서 컨테이너가 폭발적으로 확산되었다.


Part 2: 컨테이너와 하이퍼바이저 — 내부 해부

2-1. Linux의 격리 원시체: Namespace와 Cgroup

컨테이너를 이해하려면 먼저 Linux 커널이 제공하는 두 가지 핵심 메커니즘을 알아야 한다. 이것들은 Docker가 발명한 것이 아니라, 이미 Linux 커널에 있던 것들을 Docker가 영리하게 조합한 것이다.

Namespace(네임스페이스) 는 커널 자원에 대한 "시야각"을 제한하는 메커니즘이다. 비유하자면, 넓은 사무실에서 각 팀이 자기 팀의 화이트보드만 볼 수 있는 파티션을 치는 것과 같다. 현재 Linux에는 7가지 namespace가 있다. PID namespace는 프로세스 ID의 독립적인 번호 체계를 만든다. 컨테이너 안에서 실행된 첫 번째 프로세스는 자신이 PID 1(일반적으로 init 역할)이라고 생각하지만, 호스트 입장에서는 PID 4927일 수 있다. Mount namespace는 파일 시스템의 마운트 포인트를 격리한다. 컨테이너는 자신만의 파일 시스템 트리를 가진다. Network namespace는 네트워크 인터페이스, 라우팅 테이블, 방화벽 규칙을 격리한다. 컨테이너가 자신만의 eth0을 가지는 이유다. UTS namespace는 hostname과 domain name을, IPC namespace는 프로세스 간 통신 자원(공유 메모리, 세마포어)을, User namespace는 UID/GID 매핑을 격리한다.

[노트 기록] Namespace는 "무엇을 볼 수 있는가(what you can see)"를 제어한다. 각 namespace 종류와 격리 대상을 한 줄씩 정리할 것: PID→프로세스 ID, Mount→파일시스템, Network→네트워크 스택, UTS→호스트명, IPC→프로세스간통신, User→사용자ID.

이제 시야를 제한했다면, 자원 소비량도 제한해야 한다. 바로 cgroup(control group) 이 담당한다. cgroup은 "얼마나 쓸 수 있는가(how much you can use)"를 제어한다. CPU 사용률을 최대 50%로, 메모리를 512MB로, 디스크 I/O 대역폭을 10MB/s로 제한하는 식이다. cgroup은 계층 구조(tree structure)를 이루며, 1단계에서 배운 프로세스 트리와 겹쳐서 생각하면 이해가 쉽다. cgroup v1과 v2의 차이도 흥미로운데, v2는 계층 구조를 단일화해서 이전의 혼란스러운 다중 계층 구조 문제를 해결했다.

Namespace와 cgroup을 조합하면 이미 컨테이너의 핵심이 완성된다. 스스로 생각해보자: 만약 cgroup 없이 namespace만 있다면 어떤 문제가 생길까? 반대로 namespace 없이 cgroup만 있다면?

2-2. 컨테이너 런타임의 내부 구조

Docker를 실행하면 내부에서 어떤 일이 일어날까? OCI(Open Container Initiative) 가 정의한 표준에 따르면, 컨테이너 실행은 크게 세 계층으로 나뉜다. 맨 위에 Docker CLI가 있고, 그 아래에 containerd(컨테이너 생명주기를 관리하는 데몬), 그리고 맨 아래에 runc(실제로 namespace와 cgroup을 설정하고 컨테이너 프로세스를 fork/exec하는 저수준 런타임)가 있다. runc의 소스코드를 보면 clone() 시스템 콜에 CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWNS 같은 플래그를 전달해 새 namespace를 만드는 것을 확인할 수 있다. 이것이 바로 1단계에서 배운 프로세스 생성(fork)의 고급 변형이다. 컨테이너 이미지는 Union File System(OverlayFS) 을 이용해 레이어를 쌓는다. 기반 이미지(ubuntu:22.04) 위에 애플리케이션 레이어를 덮어씌우는 방식으로, 변경된 레이어만 추가하면 되므로 저장 공간을 크게 절약한다. 2단계에서 배운 Copy-on-Write(CoW) 메커니즘이 여기서도 사용된다는 점이 보이는가?

2-3. 하이퍼바이저 — 격리의 다른 차원

컨테이너가 커널을 공유하는 "얇은 격리"라면, 하이퍼바이저는 커널 자체를 분리하는 "두꺼운 격리"다. **Type 1 하이퍼바이저(bare-metal)**는 하드웨어 바로 위에서 실행된다. VMware ESXi, Xen, KVM이 여기에 속한다. **Type 2 하이퍼바이저(hosted)**는 기존 운영체제 위에서 실행된다. VirtualBox, VMware Workstation이 예시다. AWS EC2, Google Cloud, Azure 같은 실제 클라우드 서비스는 모두 Type 1을 사용한다.

KVM은 흥미로운 하이브리드다. Linux 커널 자체가 하이퍼바이저 역할을 하며, /dev/kvm 이라는 캐릭터 디바이스를 통해 vCPU(가상 CPU) 를 하드웨어 수준에서 실행한다. Intel의 VT-x (또는 AMD의 SVM)라는 하드웨어 가상화 지원 덕분에 Guest OS의 특권 명령어가 Host에서 직접 실행될 수 있다. 이것을 하드웨어 지원 가상화(hardware-assisted virtualization) 라 부른다. 이전에는 소프트웨어로 특권 명령어를 에뮬레이션해야 했는데(binary translation), 이 오버헤드가 엄청났다. VT-x 덕분에 VM 오버헤드가 1020%에서 15% 수준으로 급감했다.

메모리 가상화도 흥미롭다. Guest OS는 자신만의 가상 주소 공간을 가지지만, 이 "가상의 가상 주소"가 실제 물리 메모리로 변환되는 과정은 2단계에서 배운 TLB와 페이지 테이블이 두 번 거쳐지는 2단계 페이지 테이블(EPT/NPT: Extended Page Tables / Nested Page Tables) 로 처리된다. Guest Virtual Address → Guest Physical Address → Host Physical Address의 두 단계 변환이다. KVM + QEMU 조합에서 QEMU는 I/O 장치(디스크, 네트워크 카드)를 소프트웨어로 에뮬레이션하고, KVM은 CPU와 메모리를 하드웨어 수준에서 처리한다.

[노트 기록] 컨테이너 vs 하이퍼바이저 비교 표: 커널 공유 여부, 격리 수준, 기동 시간, 오버헤드, 보안 강도 — 각 항목을 직접 채워볼 것. (힌트: 컨테이너는 ms 단위로 시작하고, VM은 초~분 단위다.)


Part 3: eBPF — 커널 속의 현미경

3-1. 역사: 패킷 필터에서 범용 관측 도구로

1992년 Steve McCanne과 Van Jacobson이 "The BSD Packet Filter: A New Architecture for User-level Packet Capture" 를 발표했다. 원래 목적은 단순했다. tcpdump 같은 도구가 네트워크 패킷을 필터링할 때, 모든 패킷을 user space로 복사한 뒤 거기서 필터링하면 너무 느리다는 문제를 해결하는 것이었다. BPF(Berkeley Packet Filter) 는 간단한 가상 머신(레지스터 2개, 작은 명령어 셋)을 커널 내부에 두어 패킷 필터링 코드를 커널 안에서 직접 실행하게 했다. 불필요한 패킷은 user space로 올라오기 전에 커널 내에서 버려지므로 훨씬 빠르다.

2014년 Linux 커널 3.18에서 Alexei Starovoitov가 이 BPF를 완전히 재설계했다. 레지스터를 11개로 늘리고(64-bit), 명령어 셋을 확장하고, JIT(Just-In-Time) 컴파일러 를 추가해 BPF 바이트코드를 네이티브 기계어로 변환하게 만들었다. 이것이 eBPF(extended BPF) 다. 이름에서 "e"는 extended의 약자지만, 이제는 그냥 "eBPF"가 공식 명칭이다. 이 확장된 BPF는 네트워크 패킷 필터링을 훨씬 넘어서, 시스템 콜 추적, 성능 프로파일링, 보안 정책 적용 등 거의 모든 커널 이벤트에 붙을 수 있게 되었다. Brendan Gregg의 "BPF Performance Tools" (2019, Addison-Wesley)는 이 분야의 바이블로 여겨진다.

3-2. eBPF의 작동 원리

eBPF 프로그램의 생애 주기를 따라가 보자. 개발자는 C의 서브셋으로 eBPF 프로그램을 작성한다. 이 코드는 clang/LLVM으로 컴파일되어 eBPF 바이트코드(일종의 중간 표현)가 된다. 이 바이트코드를 bpf() 시스템 콜을 통해 커널에 로드할 때, verifier(검증기) 가 이 코드를 정밀 검사한다. Verifier는 세 가지 핵심 조건을 확인한다: 무한 루프가 없을 것(bounded loops만 허용), 항상 종료될 것, 그리고 허가되지 않은 커널 메모리에 접근하지 않을 것. 이 검증 과정은 정적 분석(static analysis)으로 수행되며, verifier를 통과한 프로그램만 커널에서 실행될 수 있다. 검증을 통과하면 JIT 컴파일러가 바이트코드를 해당 CPU 아키텍처의 네이티브 기계어로 변환한다. x86-64, ARM64, RISC-V 각각의 JIT 구현이 별도로 존재한다.

실행된 eBPF 프로그램은 hook point에 붙어 이벤트를 가로챈다. 주요 hook 유형은 다음과 같다. kprobe/kretprobe는 커널의 어떤 함수 진입점(kprobe)과 반환 지점(kretprobe)에도 동적으로 붙을 수 있다. uprobe는 user-space 프로그램의 함수에 붙는다. tracepoint는 커널 개발자가 미리 정의해 둔 안정적인 관측 지점이다(예: sched:sched_switch, syscalls:sys_enter_execve). **XDP(eXpress Data Path)**는 네트워크 드라이버 수준에서 패킷을 처리해, 커널의 TCP/IP 스택을 거치기 전에 패킷을 처리할 수 있어 엄청난 성능을 발휘한다.

eBPF 프로그램이 수집한 데이터는 BPF map을 통해 user space와 공유된다. BPF map은 커널과 user space 모두에서 접근 가능한 키-값 저장소(key-value store)다. 해시 맵, 배열, LRU(Least Recently Used) 해시 맵 등 다양한 자료구조가 지원된다. 예를 들어, 시스템 콜 빈도를 측정하는 eBPF 프로그램이 있다면, 커널의 eBPF 프로그램이 시스템 콜 hook에서 카운터를 증가시키고, user space의 Python 스크립트가 주기적으로 이 map을 읽어 화면에 출력하는 식이다.

[노트 기록] eBPF 실행 흐름: C 코드 → clang/LLVM → BPF 바이트코드 → bpf() syscall → Verifier → JIT → hook point에 부착 → 이벤트 발생 시 실행 → BPF map으로 결과 저장 → user space에서 읽기. 이 흐름을 화살표로 직접 그려볼 것.

3-3. 보안 강화: Seccomp와 LSM hooks

eBPF는 관측(observability)에만 쓰이지 않는다. 보안(security) 에도 강력하게 활용된다. Seccomp(Secure Computing Mode) 는 프로세스가 사용할 수 있는 시스템 콜을 화이트리스트(또는 블랙리스트) 방식으로 필터링한다. Docker 컨테이너는 기본적으로 44개의 위험한 시스템 콜을 seccomp 필터로 차단한다. Seccomp의 필터 규칙 자체가 BPF 프로그램으로 작성된다. LSM(Linux Security Modules) 은 접근 제어 결정 지점(예: 파일 열기, 네트워크 소켓 생성)에 hook을 제공하며, BPF-LSM 은 이 hook들에 eBPF 프로그램을 붙일 수 있게 해준다. 이를 활용한 Falco(런타임 보안 도구)나 Cilium(Kubernetes 네트워킹 + 보안)이 현재 클라우드 네이티브 보안의 핵심 도구다.


Part 4: 이기종 컴퓨팅 오케스트레이션

4-1. CPU, GPU, FPGA의 본질적 차이

2단계에서 GPU 아키텍처의 병렬 연산 특성을 배웠다. 이를 다시 환기하면서 FPGA까지 확장해보자. CPU는 몇 개의 강력한 코어(high-performance, low-latency)를 가지며, 분기 예측(branch prediction)과 비순차 실행(out-of-order execution) 같은 복잡한 메커니즘으로 직렬 코드의 성능을 극대화한다. GPU는 수천 개의 단순한 코어를 가지며, SIMD(Single Instruction Multiple Data) 방식으로 같은 연산을 수많은 데이터에 동시 적용한다. FPGA(Field-Programmable Gate Array) 는 완전히 다른 철학이다. CPU와 GPU는 "프로그래머블 소프트웨어를 실행하는 고정된 하드웨어"이지만, FPGA는 하드웨어 자체를 프로그래밍한다. LUT(Look-Up Table)flip-flop 으로 구성된 로직 블록들을 VHDL이나 Verilog 같은 HDL(Hardware Description Language) 로 원하는 회로 구조로 "재구성(reconfigure)"할 수 있다. 이 때문에 FPGA는 특정 알고리즘에 대해 극도로 낮은 지연시간(latency)과 높은 에너지 효율을 달성할 수 있다. 금융 거래의 초저지연 처리, 5G 기지국의 신호 처리, 암호화 가속 등에 쓰인다.

[노트 기록] 세 연산 유닛 비교: 코어 수, 특기, 메모리 모델, 사용 사례, 프로그래밍 언어를 표로 정리. CPU(수 개수십 개, 직렬 복잡 로직, DDR DRAM, C/C++), GPU(수천 개, 병렬 단순 연산, GDDR/HBM, CUDA/OpenCL), FPGA(수십만수백만 LUT, 하드웨어 재구성, on-chip BRAM, VHDL/Verilog/HLS).

4-2. 메모리 모델과 오케스트레이션의 어려움

이기종 컴퓨팅의 가장 큰 난제는 메모리 복사(memory copy) 오버헤드다. CPU와 GPU는 물리적으로 분리된 메모리(discrete memory)를 가지는 경우가 많다. GPU의 VRAM(예: 24GB GDDR6X)은 PCIe 버스를 통해 CPU의 DRAM과 연결된다. 큰 행렬을 GPU로 보내려면 CPU RAM → PCIe 버스 → GPU VRAM 방향으로 복사가 일어나야 하며, 이 PCIe 버스의 대역폭은 GPU 내부 메모리 대역폭의 1/50 수준이다. 이 병목이 이기종 컴퓨팅의 성능을 제한하는 주요 요인이다. 최근의 Unified Memory Architecture(UMA) — Apple Silicon M4의 "unified memory"가 대표적이다 — 는 CPU와 GPU가 같은 물리 메모리를 공유함으로써 이 복사 오버헤드를 없앤다. AMD의 APU, NVIDIA의 Grace Hopper 슈퍼칩도 비슷한 방향을 추구한다.

오케스트레이션 수준에서는 Kubernetes의 Device Plugin 인터페이스가 중요하다. Kubernetes는 원래 CPU와 메모리만 자원으로 인식하도록 설계되었지만, Device Plugin API를 통해 GPU, FPGA, 커스텀 ASIC 같은 이기종 자원을 requests/limits로 선언할 수 있게 되었다. NVIDIA의 k8s-device-plugin, Intel의 intel-device-plugins-for-kubernetes가 이 역할을 한다. 작업 스케줄러 관점에서는 각 작업의 연산 특성(compute pattern) 을 파악해 최적의 실행 장치를 자동으로 선택하는 이기종 자원 스케줄러가 연구 프론티어다. NVIDIA의 RAPIDS 생태계는 CPU 기반 데이터 처리 파이프라인(pandas)을 GPU로 자동 전환(cuDF, cuML)하는 방향을 추구하며, Apache TVM은 딥러닝 모델을 CPU, GPU, FPGA에 맞게 자동으로 컴파일한다.

이제 3단계의 학습 목표 세 가지가 서로 어떻게 연결되는지 보이는가? 컨테이너/하이퍼바이저는 격리된 실행 환경을 만들고, eBPF는 그 격리된 환경 속에서 일어나는 일을 커널 수준에서 투명하게 관측하며, 이기종 컴퓨팅 오케스트레이션은 격리된 각 워크로드에 최적의 연산 유닛을 할당한다. 현대 클라우드 플랫폼(AWS EKS + GPU + Lambda)은 이 세 기술이 모두 조합된 결과물이다.


Part 5: 프로젝트 예제 — 스스로 풀어보는 문제

아래 세 개의 프로젝트 예제는 각각 약 12~15분의 사고 시간을 요구하도록 설계되었다. 코드를 짜는 것이 목적이 아니라, 앞에서 배운 개념들을 실제 시나리오에 적용해 설계를 논리적으로 추론하는 것이 목적이다. 각 문제에는 힌트 질문이 포함되어 있다. 힌트 질문에 스스로 답하면서 전체 설계를 채워나가라.


프로젝트 1: 미니 컨테이너 런타임 설계 (약 13분)

시나리오: 너는 nano-run이라는 초경량 컨테이너 런타임을 설계하고 있다. Docker나 runc 없이, Linux 시스템 콜만 이용해 격리된 프로세스를 실행하는 것이 목표다. 단, GPU 워크로드를 위해 컨테이너 내부에서 /dev/nvidia0 디바이스에 접근할 수 있어야 하고, 컨테이너 하나당 메모리 사용량을 512MB로 제한해야 한다.

풀어야 할 문제: nano-run bash를 실행했을 때 내부에서 일어나는 정확한 단계를 설계하라. 구체적으로 어떤 시스템 콜이 어떤 순서로 호출되어야 하는가? 격리된 파일 시스템은 어떻게 준비하는가? /dev/nvidia0를 컨테이너 안으로 "노출"하려면 어떤 설정이 필요한가? 메모리 512MB 제한은 어떤 인터페이스를 통해 설정하는가?

힌트 질문: clone() 시스템 콜의 플래그 조합을 어떻게 구성할 것인가? chroot()pivot_root()의 차이는 무엇이며 어떤 상황에서 각각 써야 하는가? cgroup v2에서 메모리 제한은 어떤 파일에 어떤 값을 쓰면 설정되는가? 디바이스 파일을 컨테이너 내부에 마운트할 때 bind mount를 사용한다면 보안 위험은 무엇인가?


프로젝트 2: eBPF 기반 이상 탐지 시스템 설계 (약 14분)

시나리오: 수백 개의 컨테이너가 실행 중인 Kubernetes 클러스터에서 보안 침해(supply-chain attack)가 발생했다고 가정하자. 공격자가 컨테이너 내부에 침투해 execve() 시스템 콜로 악성 바이너리를 실행하고, 외부 C2(Command and Control) 서버와 TCP 연결을 맺고 있다. 이를 실시간으로 탐지하는 eBPF 기반 시스템을 설계하라.

풀어야 할 문제: 어떤 eBPF hook point들에 프로그램을 부착할 것인가? 각 hook에서 어떤 데이터를 수집할 것인가? "정상" 행동과 "비정상" 행동을 어떻게 구분할 것인가(특히 합법적인 curl 호출과 악성 C2 통신을 어떻게 분리하는가)? 수집된 이벤트 데이터를 어떤 BPF map 구조로 저장할 것인가? User space의 탐지 엔진은 어떤 로직으로 알람을 발생시켜야 하는가?

힌트 질문: tracepoint:syscalls:sys_enter_execve에서 어떤 인자를 캡처해야 하는가? 컨테이너를 식별하려면 어떤 커널 데이터 구조에서 namespace ID를 읽어야 하는가? 성능 오버헤드를 최소화하면서 고빈도 이벤트를 처리하려면 BPF ring buffer와 perf buffer 중 어느 것이 더 적합한가? Falco의 rule 기반 탐지 방식이 ML 기반 이상 탐지 방식에 비해 갖는 장단점은 무엇인가?


프로젝트 3: 서버리스 이기종 런타임 프로토타입 설계 (약 15분)

시나리오: 커리큘럼 최종 과제인 "서버리스 런타임 엔진"의 핵심 컴포넌트를 설계하라. 이 엔진은 사용자가 Python 함수를 업로드하면, 함수의 연산 특성을 자동 분석해 CPU, GPU, FPGA 중 최적의 실행 장치를 선택하고 실행한다. Cold Start(함수가 처음 호출될 때 컨테이너를 띄우는 데 걸리는 지연 시간) 를 최소화하는 것이 핵심 제약이다.

풀어야 할 문제: (A) 함수의 연산 특성을 어떻게 정적으로 혹은 동적으로 분류할 것인가? (행렬 연산이 많으면 GPU, 조건 분기가 복잡하면 CPU, 특정 프로토콜 파싱이면 FPGA 등) (B) Cold Start를 줄이기 위한 스냅샷 복원 기법을 설계하라. CRIU(Checkpoint/Restore In Userspace)가 어떤 원리로 프로세스 상태를 저장하고 복원하는지 설명하고, 이를 이 시스템에 어떻게 적용하는가? (C) 이기종 자원 스케줄러의 의사 결정 알고리즘을 의사 코드(pseudocode)로 작성하라. 자원이 부족할 때 대기열(queue) 전략을 어떻게 설계하는가?

힌트 질문: Python AST(Abstract Syntax Tree) 분석으로 어떤 라이브러리를 import하는지 감지하면 연산 특성을 추정할 수 있을까? CRIU가 저장해야 하는 프로세스 상태의 종류는 무엇인가(메모리 맵, 파일 디스크립터, 소켓 상태, 신호 마스크 등)? GPU 함수를 FPGA 대신 GPU에서 실행할 때 PCIe 메모리 복사 오버헤드를 Cold Start 계산에 포함해야 하는가? Kubernetes의 Device Plugin API로 이 스케줄러를 구현한다면 어떤 인터페이스를 구현해야 하는가?


이 세 프로젝트를 끝냈다면 스스로에게 물어보라. 프로젝트 1에서 설계한 컨테이너가 실행 중일 때, 프로젝트 2의 eBPF 탐지 시스템이 그 컨테이너의 동작을 어떻게 관측하는가? 그리고 프로젝트 3의 스케줄러가 프로젝트 1의 런타임 위에서 어떻게 작동하는가? 이 세 문제가 독립적이지 않고 서로 맞물리는 하나의 시스템임을 이해할 때, 3단계 학습 목표가 달성된 것이다.


참고 문헌 (더 깊이 파고들고 싶다면): Brendan Gregg, BPF Performance Tools (2019, Addison-Wesley) / Arpaci-Dusseau, Operating Systems: Three Easy Pieces (무료 온라인 공개) / Linux Kernel Documentation: Documentation/admin-guide/cgroup-v2.rst, Documentation/bpf/ / Patterson & Hennessy, Computer Organization and Design: ARM Edition (5th ed., Morgan Kaufmann) / Saltzer & Schroeder, "The Protection of Information in Computer Systems", Proc. IEEE, 1975.

← 단계 2단계 4