Docker를 만든 사람인데 우연히 이 글을 발견함. 다른 엔지니어들이 내가 설계한 시스템을 어떻게 이해하는지 보는 건 늘 재미있음. Docker 개발에서 손을 뗀 지는 오래됐지만, 옛날을 돌아보는 즐거운 시간이 됨. 궁금한 게 있다면 기꺼이 답하겠음.
처음에 Docker의 발상을 어떻게 떠올렸는지 궁금함. Linux의 기본 기능들을 보고, 애플리케이션을 패키징해 배포하는 플랫폼을 만들고 내 컴퓨터에서는 되는데라는 문제까지 해결할 수 있겠다고 생각한 과정은 무엇이었나요? 이미 답한 곳이 있다면 검색어나 링크를 알려줘도 좋겠음.
2015년 파나마 Bocas del Toro의 해변 카페 와이파이로 처음 컨테이너를 써봤는데, 결과는 짐작할 만했음. 잠시 쉬었다가 다시 사용하기 시작했고, 이후 여러 로컬 개발 환경과 Compose 기반 운영 환경의 핵심으로 자리 잡았음.
특히 소스 디렉터리를 마운트하면 로컬 개발 도구는 그대로 쓰면서 런타임과 의존성 조합 등 나머지를 전부 격리할 수 있다는 걸 깨달았을 때 놀라웠음. 환경 차이와 신규 참여자의 프로젝트 설정 문제를 해결해 주니, 소프트웨어 개발은 원래 이렇게 해야 한다는 느낌이 들었고 돌아가기 어려워짐.
만든 사람으로서 지금도 Docker를 쓰고 있나요? 아니면 이미 다음의 실험적인 도구로 넘어갔나요? 그렇다면 무엇인지 궁금함.
Docker는 웹을 넘어 애플리케이션을 패키징하고 배포하는 주요 수단이 됐음. 처음 만들 때 상상한 용도는 무엇이었나요? 지금 업계의 활용 방식이 예상과 일치하나요? 업계가 놓쳤지만 활용했다면 더 좋았을 용도도 있나요?
Docker를 특별하게 만든 건 컨테이너 기술 자체가 아니라고 봄. 20년 전에도 chroot를 잘 썼고, 네트워크나 프로세스 네임스페이스가 없었지만 그것들이 그렇게 중요하다고 생각하지는 않음.
차별점은 세 가지였음. 첫째는 Dockerfile과 계층별 빌드·캐시로, 하나의 파일 안에서 이미지를 빠르게 개선하고 CI 빌드를 효율적으로 수행할 수 있게 함. 둘째는 범용 이미지를 서버에 올려 전 세계와 공유하는 이미지 레지스트리 개념임.
셋째는 확산의 기세였음. 배포하기 까다롭던 소프트웨어가 속속 Docker 이미지로 등장했고, 짧은 docker-compose 설정만으로 WordPress 사이트를 띄울 수 있다는 게 놀라웠음. 호스트에서 흔적까지 모두 지울 수 있을 만큼 격리되어 있어, 이것저것 직접 설치할 때 느끼던 불안도 해소됨.
평소에는 Podman을 더 선호하지만, Docker는 이른바 ‘코트 하나 걸친 Linux 커널 기능 다섯 개’ 위에 훌륭한 개발자 경험을 얹은 도구임. 매우 가벼우면서도, 이미 존재하거나 개발 중이었지만 쓰기 불편하고 전문 지식이 많이 필요했던 운영체제 기능을 제대로 활용한다는 게 핵심 매력임.
Podman은 Docker의 이런 이상한 점들을 모두 피해 가나요? 아니면 일부만 해결하나요?
이건 빙산의 일각에 불과함. Linux에는 컨테이너라는 개념 자체가 없다는 사실을 알면 놀라는 사람이 많음.
VM이 아니라 전부 네임스페이스로 이루어짐. mnt, pid, net, ipc, uts, user, cgroup, time 네임스페이스 중 하나 이상을 분리하면 그것이 곧 ‘컨테이너’임.
Reddit에서 Docker를 맹목적으로 권하는 모습을 보고 싫어지기 시작함. Linux에 앱을 배포하는 방법을 물으면 항상 적어도 하나는 “그냥 Docker 쓰세요”라는 답변임. 결국 우리는 Docker를 전혀 쓰지 않고 전체 기술 스택을 배포하는 자체 자동화 도구를 만들었음.
복잡한 기술을 구성 요소부터 배워 이해하는 과정은 언제 봐도 좋음. 내부 구조를 알고 나면 루트 권한 없는 Podman의 fork-exec 방식이 더 합리적으로 느껴질 수 있고, 나도 그렇게 봄. 루트 권한도, 데몬도, 소켓도 필요 없음.
컨테이너를 구성하는 Linux 커널 네임스페이스를 더 알아보고 싶다면 이 LWN 연재가 아주 좋음. https://lwn.net/Articles/531114/.
글의 모든 항목을 읽을 때마다 “이게 왜 이상하지?”라는 생각이 듦. 오랜 시간에 걸친 발전 과정을 알면 전부 자연스럽게 느껴짐. 그저 내가 나이 들고 호기심이 줄어든 것일 수도 있음.
대부분은 이상하게 느껴지지 않지만 Go를 선택한 것은 예외임. 네임스페이스와 컨테이너 구현에 가장 중요한 시스템 호출 중 하나인 clone을 네이티브로 호출할 수 없는 언어를 고른 건 확실히 이상해 보임.
정작 진짜 이상한 결정인 클라이언트·서버 모델은 한 번도 다루지 않음. 이 구조 때문에 권한 관리가 적어도 100배는 복잡해짐.
많은 사람이 Docker를 내부를 모르는 채 쓰기 시작하고 VM처럼 이해함. 그러다 내부를 파고들면 온갖 ‘이상한 점’이 드러나기 시작함.
“재미로 컨테이너 런타임을 직접 만들었다”, “VM과 달리 컨테이너는 그저 프로세스다”라고 했는데, 다음에는 VM 런타임도 직접 만들어 보면 놀랄 수 있겠음!
초기에는 고루틴의 스레드 이동이 큰 골칫거리였음. 고루틴은 스레드를 옮겨 다닐 수 있는데, fork할 때 상속되는 것은 해당 스레드의 네임스페이스와 cgroup 설정이기 때문임.
특히 까다로웠던 오류는 네트워크 네임스페이스가 간헐적으로 제대로 정리되지 않는 현상이었음. 특정 부하에서 더 자주 나타났지만 겉보기에는 무작위로, 재사용된 스레드의 네트워크가 꼬여 Docker가 더 이상 이미지를 내려받지 못하게 됨.
사용자 공간 스레딩 라이브러리를 직접 만드는 일은 절대로 하지 말아야 함. 안타깝게도 널리 쓰이는 언어 대부분이 이 원칙을 어기고 있음.