이 문서는 서버나 배포 환경을 처음 다루는 분들도 어렵지 않게 따라올 수 있도록, Docker라는 도구의 개념부터 실제 사용법까지 하나하나 풀어서 설명합니다. 명령어를 단순히 나열하는 대신, 왜 그런 명령어가 필요한지, 각 명령어가 실제로 무슨 일을 하는지 이야기하듯 정리했습니다.
- Docker란 무엇인가요?
- 꼭 알아야 할 세 가지 개념: 이미지, 컨테이너, 레지스트리
- 설치하기
- 첫 컨테이너 실행해 보기
- 이미지 다루기
- 컨테이너 다루기
- 컨테이너 안을 들여다보고 조작하기
- 데이터를 안전하게 보관하기 (볼륨)
- 바깥세상과 연결하기 (포트와 네트워크)
- 나만의 이미지 만들기 (Dockerfile)
- 여러 컨테이너를 한 번에 (Docker Compose)
- Docker의 대안, Podman 사용하기
- 정리와 청소
- 자주 마주치는 문제와 해결법
- 자주 쓰는 명령 한눈에 보기
- 용어집
- 관련 도구와 링크
프로그램을 만들어 다른 컴퓨터에서 돌려 본 경험이 있다면 한 번쯤 이런 말을 들어 봤을 것입니다. "제 컴퓨터에서는 잘 되는데요?" 내 컴퓨터에서는 멀쩡히 돌아가던 프로그램이 동료의 컴퓨터나 실제 서버에서는 갑자기 말썽을 부리는 일이 흔합니다. 운영체제가 다르고, 설치된 라이브러리 버전이 다르고, 설정이 미묘하게 어긋나기 때문입니다.
Docker는 바로 이 문제를 해결하기 위해 태어난 도구입니다. 프로그램과 그 프로그램이 돌아가는 데 필요한 모든 것 — 운영체제의 일부, 라이브러리, 설정까지 — 을 하나의 상자에 통째로 담아 둡니다. 이 상자를 "컨테이너(container)"라고 부릅니다. 이렇게 담아 두면 내 노트북에서든, 동료의 PC에서든, 클라우드 서버에서든 똑같은 환경에서 똑같이 동작합니다. "제 컴퓨터에서는 잘 되는데요?"라는 말이 사라지는 셈입니다.
그렇다면 이 컨테이너는 흔히 아는 "가상 머신"과 무엇이 다를까요? 가상 머신은 컴퓨터 한 대를 통째로 흉내 내기 때문에 무겁고 느리게 켜집니다. 반면 컨테이너는 운영체제의 핵심(커널)은 호스트 컴퓨터의 것을 함께 빌려 쓰고, 프로그램에 꼭 필요한 부분만 담습니다. 그래서 훨씬 가볍고, 몇 초 만에 켜지며, 한 컴퓨터에서 수십 개를 동시에 돌릴 수도 있습니다. 이 가벼움이 Docker가 사랑받는 가장 큰 이유입니다.
Docker를 쓰기 전에 세 가지 용어만 확실히 잡고 가면 나머지는 훨씬 수월합니다. 아래 그림이 전체 흐름을 한눈에 보여 줍니다. 이어서 하나씩 요리에 빗대어 설명해 보겠습니다.
**이미지(image)**는 "레시피"이자 "냉동식품"에 해당합니다. 프로그램과 그 실행에 필요한 모든 것을 한 덩어리로 굳혀 놓은, 읽기 전용의 설계도입니다. 이미지 자체는 가만히 있는 파일 묶음일 뿐, 스스로 움직이지 않습니다.
**컨테이너(container)**는 그 레시피로 실제로 만들어 낸 "요리"입니다. 이미지를 실행하면 컨테이너가 됩니다. 같은 이미지 하나로 컨테이너를 여러 개 만들 수도 있는데, 이는 같은 레시피로 같은 요리를 여러 접시 만드는 것과 같습니다. 컨테이너는 실제로 돌아가는, 살아 있는 존재입니다.
**레지스트리(registry)**는 이미지들을 모아 두고 나눠 주는 "창고"이자 "앱 마켓"입니다. 가장 유명한 곳이 Docker Hub인데, 여기에는 이미 잘 만들어진 이미지가 수없이 올라와 있습니다. 예를 들어 데이터베이스 프로그램인 MySQL이나 웹 서버인 Nginx를 직접 설치할 필요 없이, 레지스트리에서 이미지를 내려받아 곧바로 실행할 수 있습니다.
정리하면, 레지스트리에서 이미지를 내려받아 실행하면 컨테이너가 되는 것입니다. 이 흐름만 기억하면 됩니다.
macOS에서 Docker를 쓰는 방법은 크게 두 가지입니다. 요즘은 가볍고 빠른 OrbStack을 많이 씁니다.
OrbStack (권장)
OrbStack은 macOS 전용으로 만들어진 도구로, Docker 컨테이너를 아주 가볍고 빠르게 실행해 줍니다. 명령어 자체는 Docker와 똑같아서(똑같이 docker 명령을 씁니다) 이 문서의 내용을 그대로 따라 하면 되지만, 켜지는 속도가 빠르고 메모리와 배터리를 훨씬 덜 먹는다는 점이 큰 장점입니다. 그래서 노트북에서 개발하는 분들에게 특히 잘 어울립니다.
Homebrew로 간단히 설치할 수 있습니다.
brew install orbstack또는 OrbStack 공식 사이트에서 설치 파일을 받아 실행해도 됩니다. 설치 후 OrbStack 앱을 한 번 실행해 두면, 이후로는 터미널에서 docker 명령을 바로 쓸 수 있습니다.
Docker Desktop (대안)
가장 널리 알려진 공식 도구입니다. 회사나 팀에서 표준으로 정해 두었다면 이쪽을 쓰면 됩니다. Docker 공식 사이트에서 설치 파일을 받거나, Homebrew로 설치할 수 있습니다.
brew install --cask docker설치 후에는 응용 프로그램 목록에서 Docker를 한 번 실행해, 상단 막대에 고래 모양 아이콘이 나타나는지 확인하세요. 이 아이콘이 있어야 Docker가 켜진 상태입니다.
OrbStack과 Docker Desktop을 동시에 켜 두면 서로 충돌할 수 있으니, 둘 중 하나만 실행하는 것이 좋습니다.
Windows에서는 Docker Desktop을 씁니다. (OrbStack은 macOS 전용이라 Windows에서는 쓸 수 없습니다.) Docker 공식 사이트에서 설치 파일을 받아 실행하면 됩니다.
Windows의 Docker Desktop은 WSL2라는 리눅스 호환 환경을 기반으로 동작합니다. 설치 과정에서 WSL2를 함께 켜도록 안내가 나오면 그대로 따르면 되고, 특별한 사정이 없다면 WSL2 방식을 쓰는 것이 성능 면에서 유리합니다. 설치가 끝나면 Docker Desktop을 실행해, 작업 표시줄에 고래 모양 아이콘이 나타나는지 확인하세요.
리눅스에서는 공식에서 제공하는 편의 스크립트로 간단히 설치할 수 있습니다.
curl -fsSL https://get.docker.com | sh설치가 끝나면, 매번 sudo를 붙이지 않고도 Docker를 쓸 수 있도록 현재 사용자를 docker 그룹에 넣어 두면 편리합니다. 이 설정은 로그아웃 후 다시 로그인해야 적용됩니다.
sudo usermod -aG docker $USER리눅스에서 Docker는 조금 특별한 구조로 동작합니다. 실제로 컨테이너를 만들고 관리하는 것은 "Docker 데몬(dockerd)"이라는 백그라운드 프로그램인데, 이 데몬은 기본적으로 root(최고 관리자) 권한으로 실행됩니다. 우리가 입력하는 docker 명령은 이 root 데몬에게 "이렇게 해 달라"고 요청을 전달하는 심부름꾼일 뿐입니다. 그래서 일반 사용자가 그냥 docker 명령을 쓰면 데몬에 접근할 권한이 없어 오류가 나고, 그때마다 sudo를 붙이거나 앞서처럼 사용자를 docker 그룹에 넣어 주어야 합니다.
여기서 꼭 짚고 넘어갈 점이 있습니다. 사용자를 docker 그룹에 넣는 것은 편하지만, 사실상 그 사용자에게 root와 맞먹는 권한을 주는 것과 같습니다. docker 그룹에 속하면 root로 도는 데몬을 통해 시스템 어디든 건드릴 수 있기 때문입니다. 개인 개발용 PC에서는 흔히 감수하는 부분이지만, 여러 사람이 함께 쓰는 서버라면 보안상 주의가 필요합니다.
이런 이유로, 데몬 자체를 root가 아닌 일반 사용자 권한으로 돌리는 방법들이 마련되어 있습니다. 여기서 오해하기 쉬운 점 하나를 바로잡자면, root 없이 특정 사용자로 Docker를 돌리기 위해 반드시 Rancher 같은 별도 도구가 필요한 것은 아닙니다. 대표적인 선택지는 다음과 같습니다.
Rootless Docker (Docker에 기본 포함)
사실 Docker에는 데몬을 일반 사용자 권한으로 실행하는 "rootless 모드"가 기본으로 들어 있습니다. 즉, 다른 도구를 새로 깔지 않고도 root 없이 쓸 수 있습니다. 아래 스크립트로 현재 사용자 전용 데몬을 설치할 수 있습니다.
dockerd-rootless-setuptool.sh install이렇게 하면 Docker가 그 사용자 권한으로만 동작하므로, 혹시 컨테이너가 뚫리더라도 피해 범위가 그 사용자 선으로 제한되어 훨씬 안전합니다. 다만 1024 미만의 낮은 포트를 여는 등 일부 기능에는 추가 설정이 필요할 수 있습니다.
Podman
Podman은 아예 데몬 없이(daemonless), 그리고 기본적으로 rootless로 동작하도록 설계된 도구입니다. 명령어가 Docker와 거의 똑같아서 docker를 podman으로 바꿔 podman run ...처럼 쓰면 됩니다. alias docker=podman으로 이름을 맞춰 두고 그대로 쓰는 경우도 많습니다. 보안을 중시하는 서버 환경에서 특히 인기가 높습니다.
Rancher Desktop
Rancher Desktop은 앞서 소개한 Docker Desktop을 대신하는 데스크톱 앱으로, 화면(GUI)으로 컨테이너와 쿠버네티스 환경을 관리할 수 있게 해 줍니다. 내부적으로 rootless 방식으로 동작할 수 있어, root 없이 편하게 쓰고 싶은 데스크톱 사용자에게 좋은 선택입니다.
정리하면, 가볍게는 Docker의 rootless 모드로 충분하고, 데몬 없는 방식을 원하면 Podman, 화면으로 편하게 관리하고 싶으면 Rancher Desktop을 고르는 식으로 상황에 맞게 선택하면 됩니다.
제대로 설치되었는지 확인하려면 아래 명령을 실행해 봅니다. 버전 정보가 출력되면 성공입니다.
docker --version한 걸음 더 나아가, 아래 명령은 Docker가 실제로 이미지를 내려받아 컨테이너로 실행하는 전 과정을 시험해 봅니다. 환영 메시지가 나오면 모든 준비가 끝난 것입니다.
docker run hello-world가장 기본이 되는 명령은 docker run입니다. 이미지를 지정하면 Docker가 그 이미지를 (없으면 레지스트리에서 내려받아) 컨테이너로 실행합니다. 가벼운 리눅스인 우분투를 예로 들어 보겠습니다.
docker run ubuntu echo"안녕하세요"이 한 줄이 하는 일은 이렇습니다. 우분투 이미지를 준비하고, 그 안에서 echo "안녕하세요" 명령을 실행한 뒤, 할 일이 끝났으니 컨테이너가 멈춥니다.
컨테이너 안에 직접 들어가서 이것저것 해 보고 싶다면, 아래처럼 옵션을 붙여 대화형으로 실행합니다.
docker run -it ubuntu bash여기서 -it는 두 옵션을 합친 것으로, 컨테이너 안의 명령창(bash)과 여러분의 터미널을 이어 주어 마치 그 안에 들어간 것처럼 명령을 주고받게 해 줍니다. 안에서 exit를 입력하면 다시 밖으로 나옵니다.
실제 서비스에서 자주 쓰는 방식은 컨테이너를 백그라운드에서 조용히 돌리는 것입니다. 웹 서버 Nginx를 예로 들면 이렇습니다.
docker run -d -p 8080:80 --name my-web nginx각 옵션의 뜻을 풀어 보면, -d는 백그라운드에서 실행하라는 뜻이고, -p 8080:80은 내 컴퓨터의 8080번 포트를 컨테이너의 80번 포트에 연결하라는 뜻이며(포트는 뒤에서 자세히 다룹니다), --name my-web은 이 컨테이너에 알아보기 쉬운 이름을 붙이는 것입니다. 실행한 뒤 웹 브라우저에서 http://localhost:8080에 접속하면 Nginx의 기본 화면이 보일 것입니다.
레지스트리에서 이미지를 미리 내려받아 두고 싶다면 pull을 씁니다. docker run은 이미지가 없으면 알아서 내려받지만, 명시적으로 받아 둘 수도 있습니다.
docker pull nginx이미지 이름 뒤에 콜론을 붙여 특정 버전(이를 "태그"라고 합니다)을 지정할 수 있습니다. 아무것도 붙이지 않으면 최신을 뜻하는 latest가 기본으로 쓰입니다.
docker pull nginx:1.27지금 내 컴퓨터에 어떤 이미지들이 있는지 확인하려면 아래 명령을 씁니다.
docker images더 이상 쓰지 않는 이미지는 지워서 공간을 정리할 수 있습니다.
docker rmi nginx지금 돌아가고 있는 컨테이너들을 확인하려면 아래 명령을 씁니다.
docker ps멈춰 있는 것까지 포함해 모든 컨테이너를 보고 싶다면 -a 옵션을 붙입니다.
docker ps -a돌아가는 컨테이너를 멈추거나 다시 시작할 때는 컨테이너의 이름(또는 ID)을 지정합니다.
docker stop my-web
docker start my-web
docker restart my-web멈춘 컨테이너를 지울 때는 rm을 씁니다.
docker rm my-web돌아가는 컨테이너를 멈추지 않고 곧바로 강제로 지우고 싶다면 -f 옵션을 붙입니다.
docker rm -f my-web한 가지 알아 두면 좋은 팁이 있습니다. docker run에 --rm 옵션을 붙이면, 컨테이너가 할 일을 마치고 멈추는 순간 자동으로 삭제됩니다. 잠깐 쓰고 버릴 컨테이너라면 이 옵션이 뒷정리를 덜어 줍니다.
docker run --rm ubuntu echo"쓰고 나면 자동으로 사라집니다"백그라운드에서 돌아가는 컨테이너가 무슨 일을 하고 있는지 궁금할 때는 로그를 봅니다.
docker logs my-web로그를 실시간으로 계속 지켜보고 싶다면 -f 옵션을 붙입니다. 마치 폭포처럼 새 로그가 아래로 이어져 나옵니다. 그만 보려면 Ctrl + C를 누르면 됩니다.
docker logs -f my-web이미 돌아가고 있는 컨테이너 안에 들어가 상태를 살펴보거나 명령을 실행하고 싶을 때는 exec를 씁니다.
docker exec -it my-web bash앞서 docker run -it가 새 컨테이너를 만들어 들어가는 것이었다면, docker exec -it는 이미 돌아가는 컨테이너에 들어간다는 점이 다릅니다. 안에서 exit를 치면 컨테이너는 계속 돌아가는 채로 여러분만 빠져나옵니다.
컨테이너의 세부 설정과 상태를 자세히 들여다보려면 아래 명령을 씁니다. 네트워크 주소, 마운트된 볼륨 등 많은 정보가 나옵니다.
docker inspect my-webDocker를 쓰다 보면 곧 중요한 사실 하나를 마주하게 됩니다. 컨테이너를 삭제하면 그 안에 저장했던 데이터도 함께 사라진다는 점입니다. 컨테이너는 기본적으로 "잠깐 쓰고 버리는" 존재로 설계되어 있기 때문입니다. 그런데 데이터베이스처럼 데이터를 오래 보관해야 하는 경우에는 이 성질이 곤란합니다.
이를 해결하는 것이 "볼륨(volume)"입니다. 볼륨은 컨테이너 바깥에 데이터를 따로 보관하는 저장 공간입니다. 컨테이너가 사라져도 볼륨에 담긴 데이터는 그대로 남아, 새 컨테이너에 다시 연결해 이어서 쓸 수 있습니다.
볼륨을 만들고 목록을 확인하는 명령은 다음과 같습니다.
docker volume create my-data
docker volume ls컨테이너를 실행할 때 -v 옵션으로 볼륨을 연결합니다. 아래는 my-data 볼륨을 컨테이너 안의 특정 경로에 이어 주는 예입니다.
docker run -d -v my-data:/var/lib/mysql --name my-db mysql볼륨 대신, 내 컴퓨터의 실제 폴더를 컨테이너에 직접 연결할 수도 있습니다. 이를 "바인드 마운트"라고 하며, 개발 중에 내 코드를 컨테이너에 바로 반영해 볼 때 특히 유용합니다. 콜론 앞에 내 컴퓨터의 경로를 적어 주면 됩니다.
docker run -d -v $(pwd)/html:/usr/share/nginx/html --name my-web nginx여기서 $(pwd)는 지금 있는 폴더의 경로를 뜻합니다. 즉 현재 폴더의 html 디렉터리를 Nginx가 웹 페이지를 읽어 가는 위치에 연결한 것입니다.
컨테이너는 기본적으로 바깥세상과 격리되어 있습니다. 그래서 컨테이너 안에서 웹 서버가 돌아가고 있어도, 아무 설정 없이는 브라우저로 접속할 수 없습니다. 이때 컨테이너의 문을 바깥으로 열어 주는 것이 앞서 잠깐 나왔던 -p 옵션입니다.
docker run -d -p 8080:80 nginx-p 8080:80은 "내 컴퓨터의 8080번 문으로 들어온 손님을 컨테이너의 80번 문으로 안내하라"는 뜻입니다. 콜론 앞이 내 컴퓨터 쪽 포트, 뒤가 컨테이너 쪽 포트입니다. 그래서 브라우저에서 localhost:8080에 접속하면 컨테이너 안 80번 포트의 웹 서버에 닿게 됩니다.
여러 컨테이너가 서로 통신해야 할 때 — 예를 들어 웹 애플리케이션 컨테이너가 데이터베이스 컨테이너에 접속해야 할 때 — 는 같은 네트워크에 묶어 주면 됩니다. 사용자 정의 네트워크를 만들어 컨테이너들을 그 안에 넣으면, 컨테이너들이 서로의 이름만으로 통신할 수 있습니다.
docker network create my-net
docker run -d --name my-db --network my-net mysql
docker run -d --name my-app --network my-net my-app-image이렇게 하면 my-app 컨테이너 안에서 데이터베이스에 접속할 때, 복잡한 IP 주소 대신 그냥 my-db라는 이름을 주소처럼 쓸 수 있습니다.
지금까지는 남이 만들어 둔 이미지를 가져다 썼습니다. 이제 내가 만든 프로그램을 담은 나만의 이미지를 만들어 보겠습니다. 이때 필요한 것이 "Dockerfile"이라는 설계도 파일입니다. Dockerfile은 "이 이미지를 어떻게 만들지"를 위에서 아래로 한 줄씩 적어 둔 조리법입니다. Docker는 이 파일을 첫 줄부터 순서대로 읽으며 이미지를 한 겹씩 쌓아 올립니다.
파일 이름은 확장자 없이 그냥 Dockerfile로 하여 프로젝트 폴더에 둡니다. 간단한 파이썬 웹 애플리케이션을 예로 든 Dockerfile은 다음과 같은 모습입니다.
# 어떤 기반 이미지에서 시작할지 정합니다FROM python:3.12-slim
# 컨테이너 안에서 작업할 폴더를 정합니다WORKDIR /app
# 먼저 의존성 목록만 복사해 설치합니다 (이렇게 하면 빌드가 빨라집니다)COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 나머지 소스 코드를 전부 복사합니다COPY . .
# 컨테이너가 사용할 포트를 알립니다EXPOSE 8000
# 컨테이너가 시작될 때 실행할 명령을 정합니다CMD ["python", "app.py"]우선 큰 흐름만 보면, 파이썬이 미리 설치된 기반 이미지에서 출발해 → 작업 폴더를 정하고 → 필요한 라이브러리를 설치한 뒤 → 내 코드를 복사하고 → 실행 방법을 지정하는 순서입니다. 이제 각 명령어를 하나씩 자세히 살펴보겠습니다.
FROM — 출발점이 될 기반 이미지
모든 Dockerfile은 FROM으로 시작합니다. 맨바닥부터 운영체제를 만드는 대신, 이미 잘 준비된 이미지 위에 얹어 시작하는 것입니다. 예를 들어 python:3.12-slim은 파이썬 3.12가 깔린 가벼운 리눅스입니다. 이름 뒤 태그로 버전을 고정해 두는 것이 좋은데, latest처럼 뭉뚱그리면 나중에 기반이 바뀌어 예기치 않게 동작이 달라질 수 있기 때문입니다. 이름에 slim이나 alpine이 붙은 이미지는 용량을 줄인 경량 버전이라 최종 이미지를 가볍게 만드는 데 도움이 됩니다.
WORKDIR — 작업 폴더 지정
이후의 명령들이 실행될 기본 폴더를 정합니다. 폴더가 없으면 알아서 만들어 줍니다. WORKDIR /app을 써 두면 그다음 COPY나 RUN이 모두 /app 안에서 이루어집니다. 매번 경로를 길게 적지 않아도 되어 깔끔합니다.
COPY — 내 파일을 이미지 안으로 복사
내 컴퓨터(정확히는 빌드하는 폴더)의 파일을 이미지 안으로 가져옵니다. COPY requirements.txt .은 "현재 폴더의 requirements.txt를 작업 폴더로 복사하라"는 뜻이고, COPY . .은 "현재 폴더의 모든 것을 복사하라"는 뜻입니다. 비슷한 명령으로 ADD가 있는데, 압축 파일을 자동으로 풀거나 인터넷 주소에서 내려받는 부가 기능이 있습니다. 하지만 그런 기능이 필요 없다면 동작이 예측 가능한 COPY를 쓰는 것이 권장됩니다.
RUN — 이미지를 만드는 도중에 명령 실행
이미지를 빌드하는 과정에서 실행할 명령입니다. 주로 라이브러리 설치나 폴더 준비 같은 일에 씁니다. 여러 명령을 &&로 이어 한 줄에 묶으면 이미지 층(레이어)이 줄어 이미지가 조금 더 가벼워집니다.
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*ENV와 ARG — 값을 미리 정해 두기ENV는 컨테이너가 실행될 때도 계속 살아 있는 환경 변수를 정합니다. ARG는 빌드하는 동안에만 쓰이고 사라지는 값입니다. 둘의 차이를 기억해 두면 유용합니다.
ARG APP_VERSION=1.0 # 빌드할 때만 쓰는 값
ENV TZ=Asia/Seoul # 컨테이너 안에서도 유지되는 값EXPOSE — 사용할 포트 알리기
이 컨테이너가 어떤 포트를 쓰는지 문서처럼 알려 주는 표시입니다. 다만 이것만으로 포트가 바깥에 열리는 것은 아니고, 실제 연결은 실행할 때 -p 옵션으로 해야 한다는 점을 헷갈리지 마세요.
CMD와 ENTRYPOINT — 컨테이너가 시작될 때 실행할 명령
이 둘은 완성된 컨테이너가 켜질 때 무엇을 실행할지 정합니다. 가장 헷갈리는 부분이라 짚고 넘어가겠습니다.
CMD는 "기본 실행 명령"입니다. 컨테이너를 실행할 때 사용자가 다른 명령을 덧붙이면 통째로 대체됩니다.ENTRYPOINT는 "항상 실행되는 고정 명령"입니다. 사용자가 덧붙인 값은 이 명령의 인자로 전달됩니다.
둘을 함께 쓰면 "실행 프로그램은 고정하되, 옵션만 바꿔 받는" 형태를 만들 수 있어 자주 활용됩니다.
ENTRYPOINT ["python", "app.py"]
CMD ["--port", "8000"]이렇게 하면 기본적으로 python app.py --port 8000이 실행되고, 사용자가 실행 시 --port 9000만 주면 포트만 바뀝니다. 참고로 CMD ["python", "app.py"]처럼 대괄호로 감싸는 형태(exec 형식)를 권장합니다. 종료 신호가 프로그램에 제대로 전달되어 컨테이너가 깔끔하게 멈추기 때문입니다.
USER — 실행 사용자 지정
컨테이너는 기본적으로 최고 권한인 root로 실행됩니다. 보안을 위해 권한이 낮은 사용자를 만들어 그 사용자로 실행하도록 바꿔 두는 것이 좋습니다.
RUN useradd -m appuser
USER appuserCOPY . .으로 폴더 전체를 복사하면, 굳이 이미지에 넣을 필요 없는 파일까지 딸려 들어갈 수 있습니다. 용량만 큰 로그, 개발용 임시 파일, 비밀 정보가 담긴 파일, 무거운 .git 폴더 등이 그렇습니다. 이럴 때 프로젝트 폴더에 .dockerignore 파일을 만들어 두면, 여기에 적은 것들은 빌드에서 제외됩니다. 문법은 .gitignore와 같습니다.
.git
__pycache__/
*.log
.env
node_modules/
이렇게 해 두면 이미지가 가벼워지고 빌드도 빨라지며, 실수로 비밀 정보가 이미지에 담기는 사고도 막을 수 있습니다.
Docker는 Dockerfile의 명령 한 줄 한 줄을 "레이어(layer)"라는 얇은 층으로 쌓아 이미지를 만듭니다. 그리고 다시 빌드할 때, 바뀌지 않은 층은 이전에 만들어 둔 것을 그대로 재사용합니다. 이것을 "캐시"라고 하며, 덕분에 두 번째 빌드부터는 훨씬 빨라집니다.
여기서 핵심은 한 층이 바뀌면 그 아래(뒤에 오는) 층은 캐시를 못 쓰고 전부 다시 만든다는 점입니다. 그래서 앞의 예제에서 소스 코드(COPY . .)보다 라이브러리 설치(COPY requirements.txt + RUN pip install)를 먼저 둔 것입니다. 소스 코드는 자주 바뀌지만 라이브러리 목록은 그렇지 않으므로, 이 순서로 두면 코드만 고쳤을 때 무거운 라이브러리 설치 단계는 캐시로 건너뛰게 됩니다. 만약 순서를 반대로 두었다면 코드를 한 줄만 고쳐도 매번 라이브러리를 처음부터 다시 설치하게 됩니다. 자주 바뀌지 않는 것을 위에, 자주 바뀌는 것을 아래에 — 이 원칙만 기억하면 빌드 속도가 크게 달라집니다.
프로그램을 빌드할 때는 컴파일러나 각종 개발 도구가 필요하지만, 완성된 프로그램을 실제로 실행할 때는 그런 도구들이 필요 없습니다. 그런데 이것들이 최종 이미지에 그대로 남으면 이미지가 불필요하게 무거워집니다. "멀티 스테이지 빌드"는 빌드용 공간과 실행용 공간을 나누어, 빌드 결과물만 쏙 뽑아 가벼운 최종 이미지를 만드는 기법입니다.
# 1단계: 빌드 전용 공간 (개발 도구 포함)FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o myapp
# 2단계: 실행 전용 공간 (결과물만 복사)FROM alpine:3.20
WORKDIR /app
COPY --from=builder /src/myapp .
CMD ["./myapp"]첫 단계에 AS builder라고 이름을 붙여 두고, 두 번째 단계에서 COPY --from=builder로 그 단계의 결과물만 가져옵니다. 최종 이미지에는 무거운 빌드 도구가 빠지고 실행 파일만 남아, 크기가 극적으로 줄어듭니다.
Dockerfile이 준비되면 build 명령으로 이미지를 만듭니다. -t로 이미지에 이름(태그)을 붙이고, 맨 끝의 점(.)은 "현재 폴더를 빌드 재료로 삼고, 여기 있는 Dockerfile을 쓰라"는 뜻입니다.
docker build -t my-app:1.0 .자주 쓰는 빌드 옵션 몇 가지를 정리하면 다음과 같습니다.
docker build -t my-app:1.0 -f Dockerfile.prod .# 다른 이름의 Dockerfile 지정
docker build --build-arg APP_VERSION=2.0 -t my-app:2.0 .# ARG 값 전달
docker build --no-cache -t my-app:1.0 .# 캐시 무시하고 처음부터 다시만들어진 이미지는 여느 이미지와 똑같이 실행할 수 있습니다.
docker run -d -p 8000:8000 my-app:1.0내가 만든 이미지를 다른 사람과 나누거나 서버에 배포하고 싶다면, 레지스트리에 올릴 수 있습니다. 먼저 로그인한 뒤, 이미지 이름을 계정이름/이미지이름:태그 형태로 붙여 push합니다.
docker login
docker tag my-app:1.0 myusername/my-app:1.0
docker push myusername/my-app:1.0실제 서비스는 대개 하나의 컨테이너로 끝나지 않습니다. 웹 애플리케이션 컨테이너, 데이터베이스 컨테이너, 캐시 컨테이너처럼 여러 개가 함께 맞물려 돌아갑니다. 이들을 매번 docker run 명령을 여러 번 입력해 띄우고, 네트워크로 잇고, 순서를 맞추는 일은 번거롭고 실수하기도 쉽습니다.
Docker Compose는 이 여러 컨테이너의 구성을 docker-compose.yml이라는 파일 하나에 적어 두고, 명령 한 줄로 전부 띄우고 내리게 해 주는 도구입니다. 말하자면 여러 개의 긴 docker run 명령을 파일 하나로 정리해 둔 것입니다. Docker Desktop에는 Compose가 기본으로 포함되어 있습니다.
웹 애플리케이션, 데이터베이스, 캐시 서버를 함께 띄우는 좀 더 실전에 가까운 docker-compose.yml을 예로 들어 보겠습니다. 이 파일은 YAML이라는 형식으로 쓰는데, 들여쓰기(칸 맞춤)로 계층을 표현하므로 들여쓰기를 정확히 맞추는 것이 중요합니다. 들여쓰기는 반드시 스페이스(공백)로 하며, 탭 문자는 쓰지 않습니다.
services:
web:
build: . # 현재 폴더의 Dockerfile로 이미지를 빌드ports:
- "8000:8000"# 내 컴퓨터 8000번 ↔ 컨테이너 8000번environment:
- DB_HOST=db # 데이터베이스 주소로 서비스 이름을 그대로 사용depends_on:
- db
- cacherestart: unless-stoppeddb:
image: mysql:8 # 레지스트리의 기존 이미지 사용environment:
MYSQL_ROOT_PASSWORD: exampleMYSQL_DATABASE: myappvolumes:
- db-data:/var/lib/mysql # 데이터를 볼륨에 보관해 삭제돼도 유지healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]interval: 10stimeout: 5sretries: 5cache:
image: redis:7volumes:
db-data: # 위에서 쓴 볼륨을 여기서 선언이 파일을 위에서부터 읽어 보면 이렇습니다. services 아래에 컨테이너 하나하나가 서비스로 나열됩니다. 여기서는 web, db, cache 세 개입니다. 눈여겨볼 점은, 이 서비스들은 Compose가 자동으로 만들어 주는 공용 네트워크에 함께 묶이므로, 서로를 서비스 이름 그대로 주소처럼 부를 수 있다는 것입니다. 그래서 web에서 데이터베이스에 접속할 때 복잡한 IP 대신 db라고만 쓰면 됩니다(위 예에서 DB_HOST=db가 그것입니다). 앞서 하나하나 명령어로 지정하던 것들이 이 파일 한 곳에 정리되어 있는 셈입니다.
위 예제에 쓰인 주요 항목들을 하나씩 살펴보겠습니다.
build vs image — 이미지를 어디서 가져올까build: .은 "현재 폴더의 Dockerfile로 이미지를 직접 만들어 쓰라"는 뜻이고, image: mysql:8은 "레지스트리에 있는 기존 이미지를 가져다 쓰라"는 뜻입니다. 내가 만든 애플리케이션은 build로, 데이터베이스나 캐시처럼 남이 만든 것은 image로 지정하는 경우가 많습니다.
ports — 포트 연결docker run -p와 같은 역할입니다. "8000:8000"은 내 컴퓨터의 포트와 컨테이너의 포트를 잇습니다. 앞이 내 컴퓨터, 뒤가 컨테이너 쪽입니다. 참고로 db나 cache처럼 ports를 적지 않으면, 그 서비스는 바깥에는 열리지 않고 Compose 내부의 다른 서비스끼리만 접근할 수 있습니다. 데이터베이스는 굳이 바깥에 열지 않는 편이 안전합니다.
environment와 env_file — 환경 변수 전달
컨테이너 안에서 쓸 환경 변수를 정합니다. 위 예처럼 파일에 직접 적을 수도 있지만, 비밀번호 같은 민감한 값은 별도의 .env 파일에 담아 두고 env_file로 불러오는 것이 안전합니다.
env_file:
- .envvolumes — 데이터 보관과 폴더 연결
데이터를 오래 보관할 볼륨을 연결합니다. db-data:/var/lib/mysql처럼 볼륨 이름을 쓰면 이름 있는 볼륨이 연결되고, 이때 사용한 볼륨 이름은 파일 맨 아래 volumes: 항목에 한 번 선언해 주어야 합니다. ./html:/usr/share/nginx/html처럼 내 컴퓨터의 폴더 경로를 쓰면 바인드 마운트가 되어, 개발 중 코드를 바로 반영해 볼 때 유용합니다.
depends_on — 실행 순서 정하기web이 db, cache보다 나중에 시작되도록 순서를 잡아 줍니다. 다만 여기에는 한 가지 함정이 있습니다. depends_on은 "컨테이너가 켜지는 순서"만 보장할 뿐, 그 안의 데이터베이스가 "실제로 접속 받을 준비가 됐는지"까지 기다려 주지는 않습니다. 그래서 데이터베이스가 완전히 준비된 뒤에 웹을 띄우고 싶다면, 아래 healthcheck와 함께 조건을 걸어 줍니다.
depends_on:
db:
condition: service_healthyhealthcheck — 서비스가 정말 준비됐는지 확인
컨테이너가 켜진 것을 넘어 "제대로 응답할 수 있는 상태인지"를 주기적으로 점검합니다. 위 예의 db는 mysqladmin ping으로 데이터베이스가 살아 있는지 10초마다 확인합니다. 이 상태 점검이 통과해야 앞의 service_healthy 조건이 만족됩니다.
restart — 자동 재시작 정책
컨테이너가 뜻하지 않게 멈췄을 때 어떻게 할지 정합니다. unless-stopped는 "내가 직접 멈추기 전에는 문제가 생겨도 알아서 다시 켜라"는 뜻으로, 실제 서비스에서 자주 씁니다. 이 밖에 항상 재시작하는 always, 오류로 멈췄을 때만 재시작하는 on-failure 등이 있습니다.
개발할 때와 실제 서비스로 배포할 때는 설정이 조금씩 달라야 합니다. 예를 들어 개발 중에는 코드 폴더를 바인드 마운트해 바로바로 반영하고 싶지만, 실제 서비스에서는 그럴 필요가 없습니다. Compose는 기본 파일인 docker-compose.yml에 더해, docker-compose.override.yml이라는 파일이 있으면 자동으로 두 파일을 합쳐서 적용합니다. 공통 설정은 기본 파일에 두고, 개발용으로만 덧붙일 내용을 override 파일에 적어 두는 식입니다.
특정 상황용 파일을 직접 골라 쓰고 싶다면 -f 옵션으로 여러 파일을 순서대로 지정할 수 있습니다. 뒤에 오는 파일의 설정이 앞의 것을 덮어씁니다.
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d파일이 준비되면, 그 파일이 있는 폴더에서 아래 한 줄로 모든 컨테이너가 함께 뜹니다. -d는 백그라운드 실행을 뜻합니다.
docker compose up -dDockerfile을 고쳐서 이미지를 다시 빌드하며 띄우고 싶다면 --build를 붙입니다.
docker compose up -d --build돌아가는 상태를 보거나, 로그를 확인하거나, 특정 서비스 안에 들어가는 명령은 다음과 같습니다. 서비스 이름(web, db 등)을 뒤에 붙이면 그 서비스만 대상으로 삼습니다.
docker compose ps # 서비스 상태 목록
docker compose logs -f # 전체 로그 실시간 보기
docker compose logs -f web # web 서비스 로그만 보기
docker compose exec web bash # web 서비스 컨테이너 안으로 들어가기
docker compose restart web # web 서비스만 재시작전부 내릴 때는 down을 씁니다. 이 명령은 관련 컨테이너와 네트워크를 한 번에 정리해 줍니다. 볼륨에 담긴 데이터는 기본적으로 남으므로, 다시 up 하면 데이터를 이어서 쓸 수 있습니다.
docker compose down볼륨에 담긴 데이터까지 완전히 지우고 처음 상태로 되돌리고 싶다면 -v를 붙입니다. 데이터가 사라지므로 신중하게 사용하세요.
docker compose down -v앞의 설치 항목에서 rootless 실행을 이야기하며 Podman을 잠깐 언급했습니다. Podman도 결국 컨테이너를 다루는 도구라 Docker와 짝을 이루므로, 여기서 조금 더 자세히 살펴보겠습니다. 반가운 소식은, 지금까지 배운 Docker 사용법을 거의 그대로 Podman에서도 쓸 수 있다는 점입니다. 그래서 새로 배울 것이 생각보다 적습니다.
Podman은 Docker를 대신할 수 있는 컨테이너 도구입니다. 겉으로 쓰는 방법은 거의 같지만, 속을 들여다보면 몇 가지 중요한 차이가 있습니다.
첫째, 데몬이 없습니다(daemonless). Docker는 항상 백그라운드에서 돌아가는 데몬(dockerd)에게 요청을 전달하는 방식이었지요. 반면 Podman은 그런 상시 대기 프로그램 없이, 명령을 내리면 그 자리에서 곧바로 컨테이너를 실행합니다. 중앙에서 모든 것을 관장하는 데몬이 없으니, 그 데몬이 멈춰서 전체가 마비되는 일도 없습니다.
둘째, 기본적으로 root 없이 동작합니다(rootless). Docker에서는 rootless 모드를 따로 설정해야 했지만, Podman은 처음부터 일반 사용자 권한으로 도는 것을 기본으로 삼습니다. 그래서 여러 사람이 함께 쓰는 서버에서 보안상 유리합니다.
셋째, 명령어가 Docker와 거의 똑같습니다.docker를 podman으로 바꾸기만 하면 대부분 그대로 동작합니다. 사용하는 이미지도 Docker와 완전히 같은 표준(OCI)을 따르므로, Docker Hub 등에 올라온 이미지를 그대로 내려받아 쓸 수 있습니다. Dockerfile 역시 수정 없이 그대로 빌드됩니다.
넷째, 완전한 오픈소스라서 Docker Desktop과 같은 상업용 라이선스 조건을 신경 쓸 필요가 없습니다. 회사 규모에 따라 유료 조건이 걸리는 Docker Desktop 대신 Podman을 택하는 경우도 많습니다.
Linux
리눅스에서는 배포판의 패키지 관리자로 간단히 설치할 수 있습니다.
# 우분투 / 데비안 계열
sudo apt install -y podman
# 페도라 / RHEL 계열
sudo dnf install -y podmanmacOS
Podman은 리눅스 컨테이너를 실행하는 도구라, macOS에서는 내부적으로 가벼운 리눅스 가상 머신이 필요합니다. Homebrew로 Podman을 설치한 뒤, 이 가상 머신을 한 번 만들어 시작해 주면 됩니다.
brew install podman
podman machine init # 가상 머신을 처음 한 번 만들기
podman machine start # 가상 머신 시작하기화면(GUI)으로 관리하고 싶다면 Podman Desktop이라는 앱을 설치해도 됩니다. Windows에서도 이 Podman Desktop을 통해 손쉽게 설치하고 쓸 수 있습니다.
설치 확인
podman --version
podman run docker.io/library/hello-world환영 메시지가 나오면 준비가 끝난 것입니다. Podman은 이미지 주소를 명확히 적는 것을 권장하기 때문에, 위 예처럼 docker.io/library/를 앞에 붙여 주면 헷갈릴 일이 없습니다.
앞에서 익힌 Docker 명령들은 docker를 podman으로 바꾸면 그대로 통합니다. 몇 가지만 예로 들어 보겠습니다.
podman pull nginx
podman run -d -p 8080:80 --name my-web nginx
podman ps
podman logs -f my-web
podman exec -it my-web bash
podman stop my-web
podman build -t my-app:1.0 .docker라는 명령을 손에 익힌 그대로 쓰고 싶다면, Podman을 docker라는 이름으로 부르도록 별칭을 걸어 둘 수 있습니다.
alias docker=podman리눅스에서는 podman-docker라는 패키지를 설치하면 docker 명령이 자동으로 Podman으로 연결되도록 해 주기도 합니다. 이렇게 해 두면 기존 스크립트나 문서를 거의 고치지 않고도 Podman으로 옮겨 갈 수 있습니다.
Podman의 이름은 "파드(pod)"라는 개념에서 왔습니다. 파드는 여러 컨테이너를 하나로 묶는 상자라고 생각하면 됩니다. 같은 파드에 담긴 컨테이너들은 네트워크와 포트를 함께 나눠 쓰기 때문에, 서로 아주 가깝게 붙어서 협력하는 컨테이너들을 묶어 관리하기에 좋습니다. 이 개념은 컨테이너 오케스트레이션 도구인 쿠버네티스(Kubernetes)의 파드와 같아서, 나중에 쿠버네티스로 넘어갈 때도 자연스럽게 이어집니다.
파드를 만들고 그 안에 컨테이너를 넣는 흐름은 다음과 같습니다.
podman pod create --name my-pod -p 8080:80 # 포트를 파드 단위로 연다
podman run -d --pod my-pod nginx # 파드 안에 컨테이너를 넣는다
podman pod ps # 파드 목록 보기
podman pod stop my-pod # 파드 통째로 멈추기
podman pod rm my-pod # 파드 통째로 삭제포트를 개별 컨테이너가 아니라 파드에 여는 점, 그리고 파드를 단위로 한 번에 멈추고 지울 수 있는 점이 특징입니다.
여러 컨테이너를 한 번에 띄우는 Docker Compose도 Podman에서 쓸 수 있습니다. 최신 Podman에는 podman compose 명령이 포함되어 있어, 앞서 배운 docker-compose.yml 파일을 거의 그대로 활용할 수 있습니다. (내부적으로 podman-compose나 Docker Compose 도구를 이용합니다.)
podman compose up -d
podman compose down한 가지 Podman이 특히 강점을 보이는 부분은 서버에서의 자동 실행입니다. 리눅스 서버에서는 컨테이너를 systemd라는 서비스 관리자에 등록해, 서버가 켜질 때 컨테이너가 자동으로 함께 시작되도록 만들 수 있습니다. 데몬이 없는 Podman은 이 방식과 잘 어울립니다. 요즘은 "Quadlet"이라는 방법으로 간단한 설정 파일을 두어 컨테이너를 systemd 서비스처럼 다루는 것이 권장됩니다. 서버 운영 단계에서 필요해지면 Podman 공식 문서의 systemd/Quadlet 항목을 참고하면 됩니다.
정리하면, Podman은 "데몬 없이, root 없이 동작하는 Docker"에 가깝습니다. 이미 Docker를 익혔다면 대부분의 명령을 그대로 쓰면서, 보안과 서버 운영 면에서 이점을 더 얻고 싶을 때 좋은 선택입니다.
Docker를 쓰다 보면 쓰지 않는 이미지, 멈춘 컨테이너, 버려진 볼륨이 쌓여 디스크 공간을 야금야금 잡아먹습니다. 이럴 때 한 번에 정리해 주는 편리한 명령이 있습니다.
docker system prune이 명령은 멈춰 있는 컨테이너, 어디에도 연결되지 않은 네트워크, 태그 없는 이미지 등을 정리합니다. 쓰지 않는 이미지와 볼륨까지 더 과감하게 지우고 싶다면 옵션을 붙입니다. 다만 볼륨까지 지우면 그 안의 데이터가 사라지므로 신중해야 합니다.
docker system prune -a --volumesCannot connect to the Docker daemon 같은 오류가 납니다.
Docker의 실제 엔진이 켜져 있지 않을 때 나는 오류입니다. macOS라면 OrbStack 또는 Docker Desktop 앱이, Windows라면 Docker Desktop 앱이 실행 중인지(고래 아이콘이 떠 있는지) 확인하세요. 리눅스라면 sudo systemctl start docker로 서비스를 켤 수 있습니다.
리눅스에서 명령마다 permission denied가 나옵니다.
현재 사용자가 docker 그룹에 속해 있지 않아서일 수 있습니다. 앞의 설치 항목에서 소개한 sudo usermod -aG docker $USER를 실행한 뒤, 로그아웃했다가 다시 로그인해 보세요.
port is already allocated, 즉 포트가 이미 사용 중이라고 나옵니다.
연결하려는 포트를 다른 프로그램이나 다른 컨테이너가 이미 쓰고 있는 경우입니다. -p 8081:80처럼 내 컴퓨터 쪽 포트 번호를 비어 있는 다른 번호로 바꿔 실행하면 해결됩니다.
컨테이너를 지웠더니 데이터가 전부 사라졌습니다. 컨테이너는 원래 삭제하면 내부 데이터도 함께 사라집니다. 오래 보관해야 하는 데이터는 반드시 볼륨에 담아 두어야 합니다. 앞의 "데이터를 안전하게 보관하기" 항목을 참고하세요.
| 하고 싶은 일 | 명령어 |
|---|---|
| 이미지 내려받기 | docker pull nginx |
| 컨테이너 실행 (백그라운드) | docker run -d -p 8080:80 --name my-web nginx |
| 대화형으로 실행 | docker run -it ubuntu bash |
| 실행 중인 컨테이너 목록 | docker ps |
| 모든 컨테이너 목록 | docker ps -a |
| 이미지 목록 | docker images |
| 컨테이너 멈추기 / 시작 | docker stop my-web / docker start my-web |
| 컨테이너 삭제 | docker rm my-web |
| 이미지 삭제 | docker rmi nginx |
| 로그 실시간 보기 | docker logs -f my-web |
| 돌아가는 컨테이너 안 들어가기 | docker exec -it my-web bash |
| 볼륨 연결해 실행 | docker run -v my-data:/data ... |
| 이미지 만들기 | docker build -t my-app:1.0 . |
| Compose로 전체 띄우기 / 내리기 | docker compose up -d / docker compose down |
| 안 쓰는 자원 청소 | docker system prune |
이 정도만 익혀 두어도 일상적인 개발과 배포에서 Docker로 곤란할 일은 거의 없을 것입니다. 처음에는 run, ps, stop, logs 네 가지로 컨테이너를 다루는 감을 잡고, 익숙해지면 Dockerfile로 나만의 이미지를 만들고, 마지막으로 Docker Compose로 여러 컨테이너를 엮는 순서로 넓혀 가기를 권합니다.
이 문서에 등장한 용어들을 한자리에 모아 간단히 정리했습니다. 읽다가 헷갈리는 단어가 나오면 여기서 빠르게 찾아보세요.
| 용어 | 뜻 |
|---|---|
| 컨테이너 (Container) | 프로그램과 그 실행에 필요한 모든 것을 담아 격리된 채로 실제 돌아가는 실행 단위. "이미지로 만들어 낸 요리"에 해당합니다. |
| 이미지 (Image) | 컨테이너를 만들기 위한 읽기 전용 설계도이자 재료 묶음. "레시피"에 해당하며, 실행하면 컨테이너가 됩니다. |
| 레지스트리 (Registry) | 이미지를 모아 두고 나눠 주는 저장소. 대표적인 곳이 Docker Hub입니다. |
| Docker Hub | 가장 널리 쓰이는 공개 레지스트리. 잘 만들어진 이미지를 내려받아 바로 쓸 수 있습니다. |
| 태그 (Tag) | 이미지의 버전 이름표. nginx:1.27에서 1.27 부분이며, 생략하면 latest가 기본입니다. |
| 데몬 (Docker daemon, dockerd) | 실제로 컨테이너를 만들고 관리하는 백그라운드 프로그램. docker 명령은 이 데몬에 요청을 전달합니다. |
| 볼륨 (Volume) | 컨테이너 바깥에 데이터를 따로 보관하는 저장 공간. 컨테이너를 지워도 데이터가 남습니다. |
| 바인드 마운트 (Bind mount) | 내 컴퓨터의 실제 폴더를 컨테이너 안에 직접 연결하는 방식. 개발 중 코드 반영에 유용합니다. |
| 포트 (Port) | 컨테이너와 바깥세상을 잇는 통로. -p 8080:80으로 내 컴퓨터 포트와 컨테이너 포트를 연결합니다. |
| Dockerfile | 이미지를 어떻게 만들지 한 줄씩 적어 둔 설계도 파일. |
| 레이어 (Layer) | Dockerfile의 명령 하나하나가 쌓이는 얇은 층. 바뀌지 않은 층은 캐시로 재사용됩니다. |
| 멀티 스테이지 빌드 | 빌드용 공간과 실행용 공간을 나누어 최종 이미지를 가볍게 만드는 기법. |
| Docker Compose | 여러 컨테이너 구성을 docker-compose.yml 파일 하나로 정의해 한 번에 띄우고 내리는 도구. |
| 헬스체크 (Healthcheck) | 컨테이너가 켜진 것을 넘어 실제로 응답할 준비가 됐는지 주기적으로 점검하는 기능. |
| WSL2 | 윈도우에서 리눅스를 돌릴 수 있게 해 주는 호환 환경. 윈도우용 Docker Desktop의 기반입니다. |
| rootless | 컨테이너 엔진을 root가 아닌 일반 사용자 권한으로 실행하는 방식. 보안에 유리합니다. |
| 파드 (Pod) | 여러 컨테이너를 하나로 묶어 네트워크를 공유하게 하는 단위. Podman과 쿠버네티스의 핵심 개념입니다. |
| OCI | 컨테이너 이미지와 실행 방식에 대한 공개 표준. 덕분에 Docker와 Podman이 같은 이미지를 씁니다. |
| 오케스트레이션 (Orchestration) | 많은 컨테이너를 자동으로 배치·확장·관리하는 일. 대표 도구가 쿠버네티스입니다. |
이 문서에서 다룬 도구와 개념들의 공식 자료를 모았습니다. 더 깊이 알아보고 싶을 때 참고하세요.
컨테이너 실행 도구
- Docker Desktop — Windows·macOS용 공식 Docker 앱
- OrbStack — 가볍고 빠른 macOS 전용 Docker 실행 도구
- Rancher Desktop — Docker Desktop 대안 데스크톱 앱(쿠버네티스 포함)
- Podman — 데몬 없이 rootless로 동작하는 Docker 대안
- Podman Desktop — Podman을 화면(GUI)으로 관리하는 앱
공식 문서 · 레퍼런스
- Docker 공식 문서 — Docker 전반의 공식 안내서
- Docker Hub — 공개 이미지 레지스트리
- Dockerfile 레퍼런스 — Dockerfile 명령어 전체 설명
- Docker Compose 문서 — Compose 사용법과 파일 문법
- Rootless 모드 문서 — root 없이 Docker 실행하기
- Podman 공식 문서 — Podman 사용법과 systemd/Quadlet 연동
관련 기술
- WSL2 (Windows Subsystem for Linux) — 윈도우용 Docker Desktop의 기반
- Kubernetes — 컨테이너 오케스트레이션의 대표 도구