모든 주제와 태그

운영체제·런타임

28개의 글

[쿠버네티스 아래의 리눅스 1] 커널 경계: 쿠버네티스 컴포넌트는 프로세스이고 일은 시스템 콜이 한다

kubelet부터 runc까지 쿠버네티스 노드의 구성 요소는 모두 유저 공간 프로세스이고 격리, 제한, 네트워킹은 시스템 콜을 받은 커널이 처리합니다. x86_64 시스템 콜 테이블, procfs와 sysfs, 노드 준비용 커널 설정, seccomp와 LSM, 노드 장애 시간표, EEVDF까지 시리즈 전체의 지도를 공식 문서와 커널 소스 기준으로 정리합니다.

[쿠버네티스 아래의 리눅스 2] 네임스페이스와 pause: 파드 안에서 무엇을 나눠 쓰고 무엇을 따로 두는지

커널에는 컨테이너라는 객체가 없고 프로세스와 네임스페이스만 있습니다. 네임스페이스 8종을 unshare로 하나씩 재현해 보고 runc가 실제로 네임스페이스를 만드는 순서, 파드가 net·ipc·uts를 공유하고 pid·mnt·cgroup을 컨테이너별로 두는 방식, pause 컨테이너와 RunPodSandbox의 역할을 커널·runc·containerd·쿠버네티스 소스 기준으로 정리합니다.

[쿠버네티스 아래의 리눅스 3] cgroup v2와 QoS: requests와 limits가 커널 파일이 되기까지

파드의 requests와 limits가 cgroup v2의 cpu.max, cpu.weight, memory.max로 바뀌고 커널이 그 값을 집행하는 과정을 따라갑니다. OOMKilled와 CPU 스로틀링이 각각 어디서 생기는지, QoS 클래스와 oom_score_adj가 누구를 먼저 죽이는지 커널 문서와 kubelet 소스로 확인하고 JVM 서비스의 OOMKilled 포스트모템을 함께 읽습니다.

[쿠버네티스 아래의 리눅스 4] OverlayFS: 이미지 레이어가 하나의 루트가 되기까지와 Netflix의 마운트 병목

컨테이너 이미지 레이어가 OverlayFS의 lowerdir, upperdir, workdir, merged로 쌓여 컨테이너 루트가 되는 과정을 커널 문서와 containerd 소스로 따라갑니다. copy-up, whiteout, 마운트 옵션 한 페이지 제한을 정리하고 레이어마다 만든 마운트가 노드 전체를 멈춘 Netflix 사례를 원문 기준으로 읽습니다.

[쿠버네티스 아래의 리눅스 5] Service의 실체는 커널 규칙: iptables DNAT와 conntrack, 그리고 조용히 끊긴 DNS

ClusterIP로 보낸 패킷이 netfilter 훅과 kube-proxy의 KUBE-SERVICES, KUBE-SVC, KUBE-SEP 체인을 지나 파드 IP로 DNAT되는 과정을 따라갑니다. conntrack이 첫 패킷의 결정을 기억하는 방식과, 낡은 UDP conntrack 항목 때문에 DNS가 계속 타임아웃 난 ThousandEyes 장애(SREcon26 Americas 발표)를 함께 정리합니다.

자바에서 시간을 스마트하게 다루는 방법이란?

알리바바 클라우드 개발자 커뮤니티의 Java 시간 글 "如何才能在Java中优雅的操纵时间?"를 절 순서 그대로 따라가며 예제를 서울 시간대와 한국어 로캘로 바꿔 JDK 17, 21, 25에서 실행했습니다. 원문이 실행 결과나 문서와 다른 곳은 고쳐 적었고 서머타임, 월말 더하기, 시계 눈금, 포맷 문자, MySQL과 PostgreSQL의 저장 결과를 실행해 절마다 보탰습니다. 마지막 절에는 원문의 메서드 40개짜리 도구 클래스를 한국 기준으로 다시 실었습니다.

멀티스레드와 동기화를 한 줄기로: 스레드, 락, 락프리, 메모리 순서, 거짓 공유

스레드가 무엇인지부터 락, 조건 변수, 락프리, 메모리 순서, 거짓 공유까지를 한 줄기로 잇고 Java로 직접 쟀습니다. 같은 64바이트 안의 두 카운터는 떨어뜨렸을 때의 7.5배가 걸렸고 일반 필드에서는 3,600만 회 중 787만 회에서 두 스레드가 둘 다 상대의 옛 값을 읽었습니다. 깊은 내용은 시리즈의 다른 글로 이었습니다.

유저 스레드: 커널 없이 갈아타기

스레드는 꼭 커널이 만들어줘야 할까. 한 프로세스 안에서, 커널의 도움 없이 유저 공간만으로 실행 흐름을 갈아타는 협조적 유저 스레드를 만든다. 이건 이 시리즈에서 한 번 실패했다 되돌렸던 주제다. 진짜 원인인 단일 페이지 모델의 전역 변수 제약, 그리고 힙 스택 위에 트랩 프레임을 저장하다 나는 커널 페이지 폴트를 찾아내고, 커널을 전혀 바꾸지 않고 두 가지 우회로 해결한다.

TCP: 신뢰성은 번호 매기기에서 온다

UDP는 패킷을 던지고 잊는다. TCP는 "내가 어디까지 보냈고 어디까지 받았나"를 시퀀스 번호로 추적해, 순서와 도착을 보장한다. net 스택 위에 TCP 세그먼트와 3-way 핸드셰이크를 올려, 수동 개방 서버를 만든다. 호스트가 접속해 보낸 데이터를 게스트 커널이 받아 에코하고, 그 왕복으로 핸드셰이크부터 종료까지를 검증한다. 그리고 우리가 일부러 빼놓은 재전송, 혼잡 제어, 윈도우의 트레이드오프까지 다룬다.

저널링 파일시스템: 절반만 쓰이지 않게

쓰기 도중 전원이 나가면 파일시스템은 어떻게 될까. 데이터는 썼는데 디렉터리는 못 썼다면 디스크가 깨진다. 저널링(write-ahead log)은 이걸 막는다. 변경을 제자리에 바로 쓰지 않고 먼저 로그에 모은 뒤, 커밋 표시를 찍고, 그제서야 설치한다. 크래시가 나도 "전부 반영" 또는 "전혀 반영 안 됨" 둘 중 하나라 디스크는 항상 일관적이다. 여기에 삭제(rm)와 빈 블록 재사용까지 더해 읽기 전용이던 FS를 진짜 읽기-쓰기로 키운다.

Copy-on-Write fork: 복사를 미루는 기술

fork는 주소공간을 통째로 복사한다. 하지만 대부분의 자식은 곧장 exec해 그 복사본을 버린다. Copy-on-Write는 이 낭비를 없앤다. fork 때는 페이지를 복사하지 않고 부모와 읽기 전용으로 공유하다가, 누군가 쓰는 "그 순간"에만 복제한다. 물리 페이지 참조 카운트와 쓰기 페이지 폴트로 이걸 구현하고, 우리 커널만의 설계 제약(스택은 공유 못 한다)과 그 트레이드오프까지 짚는다.

멀티코어로 가다: SMP와 락

단일 코어 커널을 여러 코어가 함께 도는 SMP 커널로 키운다. SBI HSM으로 보조 코어를 깨워 부팅하고, 스핀락으로 공유 자료구조를 보호하고, 컨텍스트 스위치를 가로지르며 락을 넘기는 baton 방식으로 멀티코어 스케줄러를 만든다. 그 과정에서 만난 가장 고약한 버그, 곧 유저가 tp 레지스터를 덮어 코어 번호가 틀어지던 문제와 그 해결까지 다룬다.

demand paging, mmap, 그리고 쓰기 가능 파일시스템

작은 유닉스 위에 메모리 관리를 깊이 올린다. 예외 핸들러를 "출력만 하던 것"에서 "실제로 페이지를 만드는 것"으로 키워, sbrk 기반 지연 할당(demand paging)과 파일을 메모리처럼 읽는 mmap을 구현한다. 그리고 읽기 전용이던 파일시스템을 블록 할당과 디스크 쓰기로 쓰기 가능하게 만들어, 파일이 재부팅에도 살아남게 한다. 페이지 폴트가 RISC-V에서 어떻게 S-mode로 전달되는지(medeleg)부터 차근히.