- 2013년 첫 출시 이후 개발자들의 애플리케이션 빌드·배포·실행 방식을 근본적으로 바꿔온 Docker의 기술적 진화 과정을 조명하는 ACM 논문으로, 단순한 CLI 뒤에 숨겨진 수십 년간의 시스템 연구를 정리
- Linux 네임스페이스를 활용해 가상머신 없이도 프로세스 격리를 달성하는 방식이 Docker의 핵심 기술적 기반이며, 2001년부터 점진적으로 추가된 7가지 네임스페이스 유형을 조합해 경량 컨테이너 구현
- macOS와 Windows 지원을 위해 라이브러리 가상머신 모니터(HyperKit) 를 데스크톱 앱 내부에 내장하는 역발상 아키텍처를 채택, 기존 하이퍼바이저 방식 대신 사용자 프로세스 안에서 Linux를 실행
- 현재는 ARM·RISC-V 등 이기종 하드웨어와 AI 워크로드를 지원하며, 클라우드·데스크톱·엣지 전반에서 표준 개발 인프라로 자리 잡음
- AI 워크로드의 부상으로 GPU 의존성 관리가 새로운 과제로 부상했으며, CDI(Container Device Interface)를 통한 GPU 지원과 TEE(신뢰 실행 환경) 통합 등 Docker의 진화가 계속 진행 중
기술적 기원
- 2000년대 초반에는 Linux 배포판에 수많은 의존성을 수동 설치하고 소프트웨어를 직접 컴파일·설정하는 것이 일반적이었으며, 2010년 클라우드 컴퓨팅 부상으로 이 과정이 더욱 복잡해짐
- Docker는 개발자가 애플리케이션과 모든 의존성을 파일시스템 이미지("컨테이너") 로 패키징하여 Docker만 설치된 어떤 머신에서든 실행할 수 있도록 단순화
- 가상머신과 달리 전체 운영체제 설치 없이 몇 개의 명령어만으로 실행 가능
일반적인 워크플로
- 개발자가 Dockerfile을 작성하면 셸 문법 기반의 단계별 빌드 과정을 정의
- Python 웹사이트 예시:
FROM python:3으로 시작해 의존성 설치, 코드 복사, 포트 노출, 실행 명령까지 한 파일로 기술
- Python 웹사이트 예시:
-
docker build로 컨테이너 이미지를 생성하고docker push로 Docker Hub에 푸시 -
docker run -v data:/app/data -p 80:80처럼 데이터 볼륨 마운트와 네트워크 포트 노출을 지정해 실행 - 2013년 이후 CLI는 크게 확장되고 백엔드는 전면 재설계되었지만, Dockerfile 작성 →
docker build→docker run의 기본 워크플로는 일관되게 유지 - GitHub에서 공개 저장소 루트에 위치한 Dockerfile이 340만 개 이상 발견됨
내부 동작 원리: Linux 네임스페이스
- OS 커널은 프로세스 메모리를 격리하지만 파일시스템, 설정 파일, 동적 라이브러리 등 여러 시스템 리소스는 공유 상태
- 동일 머신에서 상충하는 동적 라이브러리 요구사항을 가진 여러 앱 설치가 매우 어려움
- 네트워크 포트 충돌 등 프로세스 간 원치 않는 간섭 발생 가능
- 각 앱을 개별 가상머신(VM) 에서 실행하면 해결되지만, 중복 커널·파일시스템·캐시·브릿지 네트워크 등으로 매우 무거움
- 각 게스트 OS가 독립적으로 동작하기 때문에 스토리지·메모리 중복 제거도 어려움
- 1978년 Unix v7의
chroot()가 별도 루트 파일시스템을 허용했지만, 다중 앱 파일시스템 합성은 미지원 - Nix와 Guix는 앱별 디렉토리 재패키징 + 동적 링킹으로 해결하나, 독점 소프트웨어에는 적용 어렵고 네트워크 포트 충돌 문제는 해결 불가
- Docker는 Linux 네임스페이스를 선택: 각 프로세스가 파일·디렉토리 등 공유 리소스 접근 방식을 개별 제어 가능
- 예: 서로 다른 네임스페이스의 두 프로세스가
/etc/passwd를 각각/alice/etc/passwd와/bob/etc/passwd로 다르게 해석 - 리소스를 열 때만 네임스페이스가 적용되고, 이후 파일 디스크립터는 추가 오버헤드 없이 일반 커널 리소스로 동작
- 예: 서로 다른 네임스페이스의 두 프로세스가
- 네임스페이스 도입 연혁
- 2001년 Linux 2.5.2: 마운트 네임스페이스
- 2006년 Linux 2.6.19: IPC 네임스페이스
- 2007년 Linux 2.6.24: 네트워크 스택 네임스페이스
- 총 7가지 네임스페이스 유형 지원
- Plan 9과 달리 네임스페이스가 처음부터 설계된 것이 아니라 점진적으로 추가되어 저수준이고 사용이 어려웠음
- FreeBSD, Solaris의 유사 기능도 대중적 사용에 이르지 못함
- 2013년 Docker의 핵심 기여: VM의 무거운 격리와 OS 기본 요소의 사용 편의성 사이에서 실용적 균형점 발견
Docker의 Linux 컨테이너 실행 구조
- Docker는 클라이언트-서버 구조로, 호스트에서 실행되는 서버 데몬(
dockerd)과 RESTful API를 통해 요청을 보내는 CLI 클라이언트로 구성 - 2015년경 모놀리식 데몬을 분리하여 전문화된 컴포넌트로 재구성
- BuildKit: 파일시스템 이미지 조립
- containerd: 이미지를 실행 중인 컨테이너로 인스턴스화하고 네트워크·스토리지 리소스 관리
컨테이너 이미지
-
docker build호출 시 Dockerfile의 실행 파일과 데이터를 나타내는 레이어드 파일시스템 이미지 생성- 최하위 레이어: Debian 또는 Alpine Linux 등 OS 배포판(또는 tar 아카이브로 수동 조립)
- 이후 레이어: Dockerfile의 개별 명령 실행 결과로 생긴 파일시스템 차이
-
콘텐츠 주소 지정 스토리지 시스템에 저장: 파일시스템 이미지의 해시를 키로 관리
- 효율적 중복 제거, 불변성 보장, 해시를 통한 변조 검증
- 2016년 Open Container Initiative(OCI) 에서 이미지 포맷 표준화, 다수의 독립 구현체 존재
- Linux 파일시스템 overlayfs, btrfs, ZFS를 활용해 copy-on-write 레이어를 효율적으로 스냅샷·클론
-
stargz스토리지 스냅샷터를 통한 이미지 지연 풀링(lazy-pulling) 지원
컨테이너 인스턴스
-
docker run호출 시 OCI 이미지에서 네임스페이스로 격리된 프로세스("컨테이너")를 생성하기 위해 시스템 리소스 할당 -
containerd가 각 컨테이너에 필요한 네임스페이스를 동적으로 설정하며 수행하는 작업:- 리소스 격리와 I/O 속도 제한을 위한 프로세스 cgroups(제어 그룹) 정의
- 컨테이너 내부 로컬 네트워크 포트를 호스트 인터페이스의 외부 노출 포트로 재매핑
- 영구적 앱 상태를 위해 호스트 파일시스템의 뮤터블 스토리지 볼륨 연결
- PID 네임스페이스로 컨테이너의 프로세스 트리 격리
- 사용자 네임스페이스로 컨테이너 내 로컬 UID를 호스트의 다른 UID로 매핑 (예: 컨테이너 내 UID 1000 → 호스트에서 UID 12345 또는 23456)
- 네임스페이스 구성에 약간의 오버헤드가 있으나 전체 Linux VM 스폰보다 훨씬 낮으며, 대부분 1초 미만
- Linux 커널이 종료된 컨테이너를 일반 프로세스처럼 가비지 컬렉션
Linux을 넘어서: macOS와 Windows 지원
- 클라이언트-서버 아키텍처 덕분에 CLI가 보안 네트워크 연결을 통해 원격 Docker 인스턴스에 명령 전송 가능
- 2015년, Docker가 Linux 개발에서 널리 채택되었으나 macOS/Windows 개발자들이 Linux 컨테이너를 실행할 수 없는 사용성 장벽 직면
- 대다수 개발자는 macOS/Windows를 기본 개발 환경으로 사용하지만, Docker 파일시스템 이미지는 Linux 커널에서만 실행 가능
- 퍼블릭 클라우드의 부상으로 배포 환경은 Linux가 선호됨
Docker for Mac 애플리케이션 구축
- 핵심 제약: Linux 버전 Docker에 익숙한 개발자에게 추가 설정 없이 동작하고, 동일한 Docker 이미지 실행 가능해야 함
- 기존 방식(Linux을 데스크톱 OS 옆에 별도로 실행)을 뒤집어, 하이퍼바이저를 macOS/Windows 사용자 공간 앱 내부에 내장하고 그 안에서 Linux 실행
- 유니커널(unikernel) 연구에서 영감: OS 컴포넌트를 더 큰 애플리케이션 내에 유연하게 내장 가능함을 입증
-
HyperKit: Intel CPU의 하드웨어 가상화 확장을 사용해 일반 사용자 프로세스에서 Linux 커널을 실행하는 라이브러리 VMM
- 내장 Linux 커널이 Docker 데몬을 실행하고, 이것이 컨테이너를 관리하며 일반 Docker 서버 엔드포인트 역할
- 모든 Linux 관리 세부 사항은 데스크톱 앱 내부에 숨김 → 데스크톱의
docker build와docker run이 내장 Linux 인스턴스로 전달되어 "그냥 동작"
- 이 접근법은 Podman 등 다른 컨테이너 시스템에도 채택되어 macOS/Windows에서 컨테이너 실행의 표준 방식으로 자리 잡음
LinuxKit: 내장형 커스텀 Linux 배포판
- 독립 실행형이 아닌 다른 앱의 컴포넌트로 내장되도록 설계된 커스텀 Linux 배포판
- 앱 시작 시간을 최소화하기 위해 Docker 컨테이너 실행에 필요한 최소 컴포넌트만 포함한 커스텀 사용자 공간 구축
- 모든 단일 컴포넌트를 컨테이너 내부에서 실행하여 부팅 시 사용되는 루트 네임스페이스에는 아무것도 실행하지 않음
- Docker 컨테이너가 사용하는 것과 동일한 copy-on-write 파일시스템과 네트워크 네임스페이스를 활용
- LinuxKit + HyperKit 조합으로 네이티브 macOS 프로세스와 거의 동일한 속도로 Linux 프로세스 부팅 가능
- 2016년 Docker for Mac 및 Windows 앱으로 출시
네트워킹 문제와 SLIRP 해결책
- 내장 Linux 컨테이너에서 macOS/Windows로의 네트워킹 연결이 예상외로 까다로운 문제
- 기존의 이더넷 브릿징 방식은 복잡한 네트워크 관리가 필요하고, 기업 데스크톱의 방화벽·바이러스 체커가 잠재적 악성 트래픽으로 탐지하여 베타 사용자로부터 수천 건의 버그 리포트 발생
-
SLIRP 해결책: 1990년대 중반 Palm Pilot PDA를 인터넷에 연결하는 데 처음 사용된 도구
- 컨테이너의 TCP 핸드셰이크 시 이더넷 프레임이 공유 메모리를 통해 virtio 프로토콜로 호스트에 전송
- MirageOS의 유니커널 라이브러리를 활용해 Linux 네트워킹 요청을 macOS/Windows 네이티브 소켓 콜로 변환
- OCaml로 작성된 사용자 공간 TCP/IP 스택 vpnkit이 호스트 OS에서 수신하여 macOS
connect()시스콜 호출 - VPN 정책 관점에서 나가는 트래픽이 별도 머신이 아닌 Docker 앱에서 발생한 것으로 인식
- 2016년 베타 테스트에서 vpnkit 배포 후 기업 사용자의 버그 리포트가 99% 이상 감소
- SLIRP 접근법은 이후 서버리스 클라우드 분야에서도 채택, 오래된 다이얼업 네트워킹 기법이 새로운 컨테이너 관리 문제 해결에 활용
인바운드 네트워크 트래픽 처리
- Linux 컨테이너가 포트를 리슨할 때 CLI에서 명시적으로 요청하지 않으면 자동으로 인터넷에 노출되지 않음 (예:
docker run -p 80:80 nginx) - 이상적인 사용자 경험: 컨테이너 포트가 데스크톱 IP에 직접 나타나
http://localhost:8080으로 브라우저에서 접근 가능- VMware Fusion 같은 기존 데스크톱 가상화는
localhost대신 임시 중간 IP를 노출
- VMware Fusion 같은 기존 데스크톱 가상화는
- LinuxKit 커널에 커스텀 eBPF 프로그램 설치 → 데스크톱 호스트에 대응하는 리스닝 소켓 생성 트리거 → 포트 포워더 활성화
- 결과: Mac에서 Linux 컨테이너 실행 시 즉시
localhost로 접근 가능, 네이티브 Linux 머신과 동일한 개발자 경험
스토리지
- 개발자는 코드를 로컬에서 편집하면서 컨테이너에서 코드와 테스트를 실행해야 함
- Linux에서는
docker run -v /host:/container로 바인드 마운트를 통해 라이브 파일 접근 - macOS와 Windows는 다른 커널이므로 바인드 마운트가 동작하지 않음
- Docker가 KVM 하이퍼바이저에서 유래한 virtio-fs 공유 메모리 프로토콜을 사용해 파일시스템 연산을 호스트로 전송(FUSE 요청 형식)
- 호스트가 이 요청을 수신하여 대응하는
open,read,write시스콜 호출
- 개발자의 코드와 데이터가 호스트 파일시스템에 유지되어 Apple Time Capsule이나 Spotlight 같은 백업·검색 도구에서 접근 가능
Windows Services for Linux (WSL)
- 2017년 Microsoft가 WSL 출시: Windows에서 직접 Linux 앱 실행
- 첫 번째 버전은 가상화 대신 Linux 바이너리의 시스템 콜을 Windows 시스템 콜로 동적 변환하는 라이브러리 OS 방식
- 많은 앱에서 성공적이었으나, Docker 컨테이너 실행에는 지원하는 시스템 콜이 부족
- 2018년 WSL2 출시: Docker for Mac과 유사하게 백그라운드에서 전체 Linux VM 실행 방식으로 재설계
- WSL2 Docker는 LinuxKit WSL 배포판 내에서 데몬과 사용자 컨테이너를 실행
- Windows 자체와 다른 Linux 배포판에서 Docker API와 네트워크 포트 포워딩 처리
- Docker 컨테이너의 크로스 플랫폼 진화를 가능하게 한 핵심 아키텍처: 전통적으로 "커널 전용 코드"를 사용자 공간 라이브러리로 재활용하여 다른 앱에 내장하는 라이브러리 OS 접근법
- 이 아키텍처의 성공은 보이지 않으면서 편재한다는 점에서 입증: 수백만 개발자가 매일 어떤 OS에서 실행 중인지 걱정 없이 Docker 사용
새로운 개발자 워크플로: 다중 CPU 아키텍처
- Docker 초기에는 클라우드 워크로드 대부분이 Intel 아키텍처 기반
- 2018년 Amazon Graviton ARM 프로세서, 2020년 Apple M1 ARM CPU 출시로 상황 변화
- ARM에서 워크로드 실행 시 비용 절감과 성능 향상 가능
- 동일 Docker 이미지 내에서 Intel, ARM, POWER, RISC-V 등 다중 CPU 아키텍처 지원 필요
- 서버 측에서는 OCI 이미지 포맷을 멀티아키텍처 매니페스트(multiarch manifests) 로 확장
- 단일 호스트에서 다중 CPU 아키텍처용 이미지 빌드를 위해 Linux의
binfmt_misc기능 활용- QEMU를 통해 ARM과 Intel 바이너리 간 투명 변환
- 주로 빌드 단계에서만 오버헤드 발생, 결과 멀티아키텍처 이미지는 어떤 호스트에서든 네이티브 실행
- Apple이 Rosetta를 통해 CPU 명령어 세트 변환의 하드웨어·소프트웨어 지원 도입 → Docker 아키텍처에 쉽게 통합
- 현재 Intel과 ARM 컨테이너를 나란히 실행하는 것이 일반적인 개발자 워크플로
신뢰 실행 환경(TEE)을 통한 비밀 관리
- 컨테이너 환경에서 비밀번호나 API 키 같은 비밀(secrets) 관리는 항상 도전 과제
- 파일시스템 이미지에 베이킹하지 않고 동적으로 주입해야 함
- Docker는 소켓 포워딩을 지원해 로컬 도메인 소켓을 컨테이너에 마운트 가능
- Docker for Mac/Windows의 경우 Linux VM까지 소켓 포워딩
-
ssh-agent같은 키 관리 시스템을 키를 직접 노출하지 않고 컨테이너 내에서 사용 가능
- 소켓 포워딩은 기본 보호 수준을 제공하지만, 커지는 소프트웨어 공급망 내 멀웨어에 대해 더 많은 방어 계층 필요
- 하이퍼바이저 보호를 컨테이너 런타임 내에 직접 적용하여 크로스 컨테이너 보호 수준 향상
-
신뢰 실행 환경(TEE): 현대 CPU의 하드웨어 기능으로 호스트 OS에서도 비밀 데이터를 보호할 수 있는 "기밀 VM(confidential VMs)" 생성
- 앱, 커널, 하이퍼바이저 경계를 넘어 데이터 접근 제한 적용 가능
- 그러나 TEE 구성·사용은 OS 가상화와 유사한 관리 복잡성 존재
-
Confidential Containers 워킹 그룹이 TEE 내에서 실행되고 Docker로 관리되는 앱 개발 중
- Docker CLI가 데스크톱 로컬 TEE에서 호스트를 거쳐 원격 클라우드 TEE 환경까지 암호화된 메시지 포워딩
- 개발자가 현장에 가지 않고도 민감한 클라우드 환경에 인증 가능, 자격 증명은 데스크톱 엔클레이브에 안전하게 저장
AI 워크로드를 위한 GPGPU 지원
- AI 워크로드의 부상으로 완전히 새로운 도전 과제 등장: 머신러닝 워크로드는 대부분 GPU에서 실행
- 핵심 문제: GPU 워크로드는 정확히 일치하는 커널 GPU 드라이버와 사용자 공간 라이브러리 필요, 다수의 컨테이너가 단일 공유 커널에서 실행
- 두 앱이 동일 커널 GPU 드라이버의 다른 버전을 요구하면 Docker가 원래 해결하려던 것과 동일한 근본 충돌 발생
- 2023년 3월부터 Docker가 CDI(Container Device Interface) 지원
- 컨테이너 시작 시점에 파일시스템 이미지를 커스터마이징
- GPU 장치 파일과 GPU 전용 동적 라이브러리를 바인드 마운트하고
ld.so캐시 재생성
- CDI는 특정 GPU 클래스·벤더 간 이미지 이식성을 보장하지만, 다른 OS·하드웨어 브랜드 간에는 완전히 매끄럽지 않음
- CDI가 추가하는 동적 라이브러리가 서로 다른 API를 정의하므로, 컨테이너의 전통적 인터페이스인 안정적 Linux 시스템 콜 ABI에 비견할 만한 것이 없음
- Nvidia GPU용 앱이 Apple M시리즈 CPU에서 실행되기 어려운 이유: GPU 가상화 지원이 다양한 하드웨어 간 벡터 명령어를 변환할 만큼 성숙하지 않음
- 컨테이너 커뮤니티 및 GPU 제조사와 협력해 GPU 관련 의존성 관리의 더 유연하고 안전한 방법 개발 중
- 이식 가능한 인터페이스 이니셔티브가 합의에 수렴하기를 기대
결론
- Docker는 2013년 개발자가 더 쉽게 앱을 빌드·공유·실행하도록 돕겠다는 목표로 시작
- 현재 표준 클라우드 및 데스크톱 개발 워크플로에 깊이 통합되어 전 세계 수백만 개발자가 매일 사용, 월간 수십억 건의 요청 처리
- 상호운용을 위한 표준을 구축하는 활발하고 다양한 오픈소스 커뮤니티 유지가 일관된 목표
- CNCF(Cloud Native Computing Foundation) 가 여러 핵심 컴포넌트의 관리자 역할
- Open Container Initiative(Linux Foundation 소속) 가 이미지 포맷의 관리자
- 오늘날 이들 요소의 다수 구현체가 활발하며, 클라우드·데스크톱·자동차·모바일·우주선 등 에지 환경에서 배포 증가
- 2025년 기준 일반적인 개발자 워크플로는 지속적 테스트·배포, IDE 언어 서버, 에이전틱 코딩을 통한 AI 지원을 통합
- Docker 관점에서 핵심 "빌드 앤 런" 워크플로는 10년 전과 매우 유사하지만, 다양한 환경에서의 마찰을 줄이는 시스템 지원이 대폭 강화
- Docker를 개발자가 더 빠르게 코드를 배포하도록 돕는 보이지 않는 동반자로 만드는 것이 목표이며, 현대 AI 코딩 워크플로에 맞게 확장 가능하도록 설계