Docker는 "내 맥에서는 되는데 서버에서는 안 돼요"라는 말을 줄이려고 만든 도구다. 실행 환경을 이미지로 묶어두면 노트북과 서버가 같은 컨테이너를 띄운다. 이 글은 Docker를 처음 켜는 사람이 설치하고, 컨테이너 하나 띄우고, Dockerfile과 Compose까지 가는 순서를 다룬다.
30초 요약
| 궁금한 것 | 답 |
|---|---|
| 설치 | Docker Desktop for Mac을 받아 /Applications로 옮기고 실행하면 끝이다. 최소 RAM 4GB가 필요하다 (설치 문서) |
| 무료 범위 | 직원 250명 미만이고 연매출 1,000만 달러 미만인 사업장, 개인·교육·비영리 오픈소스는 무료다 (요금 안내) |
| 이미지와 컨테이너 | 이미지는 실행 파일과 환경을 담은 템플릿, 컨테이너는 그 이미지를 실제로 띄운 프로세스다 |
| 첫 명령 | docker run hello-world — 이미지를 당겨서 컨테이너로 실행하고 로그를 찍고 끝난다 (docker run) |
| 포트 | -p 8080:80은 내 맥의 8080을 컨테이너의 80에 연결한다. 앞이 호스트, 뒤가 컨테이너다 |
| 데이터 | 컨테이너를 지우면 안에 쓴 파일도 같이 사라진다. 남길 것은 볼륨에 둔다 (볼륨 문서) |
| 여러 개 실행 | compose.yaml 하나에 서비스를 적고 docker compose up -d로 한 번에 띄운다 (Compose) |
| 현재 버전 | Docker Desktop 4.99.0(2026-11-09), Engine 29.9.3, Compose v5.7.0 (릴리스 노트) |

목차
- Docker가 뭔가요 — 가상머신과 다른 점
- Docker Desktop 설치 — macOS에서 세 단계
- 첫 컨테이너 실행 — hello-world가 하는 일
- 자주 쓰는 명령 — 이미지와 컨테이너 구분
- 포트와 볼륨 — 컨테이너를 지워도 남는 것
- Dockerfile로 내 이미지 만들기
- Docker Compose로 두 개 같이 띄우기
- 내가 막혔던 곳
- 참고 자료
Docker가 뭔가요 — 가상머신과 다른 점
Docker는 애플리케이션을 컨테이너라는 격리된 환경에 담아 실행하는 플랫폼이다. 공식 문서는 컨테이너가 가볍고 실행에 필요한 것을 안에 다 담기 때문에, 호스트에 무엇이 설치돼 있는지에 기대지 않아도 된다고 설명한다 (Docker 개요).
구조는 클라이언트와 데몬으로 나뉜다. 내가 터미널에서 docker를 칠 때 그 명령은 Docker 데몬에 REST API로 전달되고, 데몬이 이미지를 당기고 컨테이너를 만든다. 맥에서는 Docker Desktop이 리눅스 VM을 띄우고 그 안에서 데몬을 돌리는 식이다.
가상머신과 자주 비교되는데, 차이는 부팅 단위에 있다.
| 구분 | 가상머신 | 컨테이너 |
|---|---|---|
| 부팅 | 게스트 OS 전체를 부팅한다 | 호스트 커널을 공유하고 프로세스만 격리한다 |
| 무게 | OS 이미지와 드라이버가 통째로 들어간다 | 앱과 라이브러리만 담는다 |
| 용도 | 다른 OS가 필요할 때 | 같은 OS 위에서 앱 환경을 고정할 때 |
그래서 맥에서 리눅스 바이너리를 돌리는 용도로는 컨테이너가 맞고, 윈도우 데스크톱 앱을 띄우려면 가상머신이 맞다. 이 구분이 잡히면 뒤에 나오는 명령이 훨씬 덜 헷갈린다.
Docker Desktop 설치 — macOS에서 세 단계
설치 파일은 칩에 따라 다르다. 애플 실리콘은 arm64, 인텔 맥은 amd64 빌드를 받는다 (설치 문서).
- dmg를 열고 Docker 아이콘을
Applications폴더로 끌어다 놓는다. Docker.app을 실행하고 구독 약관 화면에서 Accept를 누른다.- 트레이 아이콘에 고래가 뜨고
docker version이 응답하면 준비 끝이다.
요구 사항은 macOS 현재 버전과 그 이전 두 개 메이저 버전, RAM 4GB 이상이다. 애플 실리콘에서 인텔 바이너리를 돌리는 선택 도구를 쓰려면 Rosetta 2를 설치한다. 최근 버전은 CLI를 $HOME/.docker/bin에 넣고 PATH에 추가하며, 기본 도커 소켓은 만들지 않는다. 이 부분은 Settings > Advanced에서 바꿀 수 있다.
라이선스는 회사 규모를 확인하고 쓰는 게 좋다. 직원 250명 이상이거나 연매출 1,000만 달러 이상인 기업의 상업적 사용은 유료 구독이 필요하다. 정부 기관도 유료다. 개인 학습과 소규모 사업장은 무료 범위에 들어간다 (Docker Desktop 약관).
첫 컨테이너 실행 — hello-world가 하는 일
설치 확인은 보통 이 한 줄로 한다.
docker run hello-world
이 명령은 로컬에 이미지가 없으면 Docker Hub에서 당겨오고, 컨테이너를 만들어 실행한 뒤 로그를 출력하고 종료한다. docker run 문서에도 이미지가 필요하면 pull하고 컨테이너를 시작한다고 적혀 있다 (docker run).
조금 더 만져보고 싶으면 우분투를 대화형으로 띄운다.
docker run -it --rm ubuntu:24.04 bash
# 컨테이너 안에서
cat /etc/os-release
exit
-it는 키보드 입력을 연결하고, --rm은 끝날 때 컨테이너를 지우라는 뜻이다. 여기서 exit를 하면 컨테이너가 사라진다. docker ps -a로 확인하면 --rm을 안 붙인 컨테이너만 목록에 남아 있다.
자주 쓰는 명령 — 이미지와 컨테이너 구분
처음에 가장 많이 헷갈리는 건 이미지와 컨테이너를 같은 것으로 보는 것이다. 이미지는 변하지 않는 템플릿이고, 컨테이너는 그 템플릿에서 만들어진 실행 인스턴스다. 같은 이미지로 컨테이너를 세 개 띄우면 서로 다른 프로세스 세 개가 생긴다.
| 하고 싶은 일 | 명령 |
|---|---|
| 받은 이미지 목록 | docker images |
| 이미지 받기 | docker pull nginx:latest |
| 컨테이너 실행 | docker run -d --name web nginx |
| 실행 중 목록 | docker ps |
| 종료된 것까지 목록 | docker ps -a |
| 로그 보기 | docker logs -f web |
| 안으로 들어가기 | docker exec -it web bash |
| 멈추기 | docker stop web |
| 컨테이너 삭제 | docker rm web |
| 이미지 삭제 | docker rmi nginx:latest |
docker exec는 이미 실행 중인 컨테이너에 셸을 하나 더 붙이는 명령이다. docker run으로 bash를 띄우는 것과 다르다. 실행 중인 서비스 설정을 확인할 때는 exec를 쓴다.
이미지 태그를 생략하면 latest가 붙는다. 운영에 쓸 이미지는 nginx:1.29처럼 버전을 명시하는 편이 안전하다. 태그가 바뀌면 같은 이름으로 다른 이미지가 받아질 수 있기 때문이다.
포트와 볼륨 — 컨테이너를 지워도 남는 것
컨테이너 안의 포트는 기본적으로 밖에서 보이지 않는다. -p로 연결해야 한다.
docker run -d --name web -p 8080:80 nginx
curl -I http://localhost:8080
8080:80은 호스트 8080을 컨테이너 80에 매핑한다는 뜻이다. 순서를 반대로 넣으면 접속이 안 되는데, 이건 뒤에서 다시 얘기한다.
데이터는 더 조심해야 한다. 컨테이너의 쓰기 레이어는 컨테이너와 함께 사라진다. 공식 문서는 볼륨을 컨테이너가 만든 데이터를 보존하는 기본 수단으로 설명하고, 볼륨의 내용은 컨테이너 수명과 별개로 존재한다고 적는다 (볼륨).
docker volume create pgdata
docker run -d --name db -e POSTGRES_PASSWORD=devpass \
-v pgdata:/var/lib/postgresql/data postgres:17
docker volume ls
개발 중에는 바인드 마운트를 더 자주 쓴다. 내 폴더를 컨테이너 안에 그대로 붙여서, 코드를 고치면 컨테이너 안 파일도 같이 바뀐다.
docker run --rm -it -v "$(pwd)":/app -w /app python:3.12-slim bash

| 방식 | 예 | 쓰는 곳 |
|---|---|---|
| 볼륨 | -v pgdata:/var/lib/postgresql/data | DB 데이터처럼 지우면 안 되는 것 |
| 바인드 마운트 | -v "$(pwd)":/app | 소스 코드를 실시간으로 반영할 때 |
| tmpfs | --tmpfs /tmp | 컨테이너가 죽으면 같이 없어져도 되는 임시 파일 |
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"]
빌드는 태그를 붙여서 실행한다.
docker build -t myapp:0.1 .
docker run --rm -p 8000:8000 myapp:0.1
여기서 순서가 중요하다. requirements.txt를 먼저 복사하고 설치한 다음에 나머지 코드를 복사했다. 코드만 바뀌면 마지막 COPY . . 레이어부터 다시 만들면 되고, 의존성 설치 레이어는 캐시로 남는다. 이 순서를 반대로 쓰면 코드 한 줄 고칠 때마다 pip 설치를 다시 한다.
.dockerignore도 같이 두는 게 좋다. .git, __pycache__, .venv를 넣어두면 빌드 문맥이 가벼워진다. 파이썬 가상환경을 컨테이너 안에 또 넣을 이유는 없으니 venv 글에서 만든 .venv는 꼭 제외한다.
이미지 크기를 줄이고 싶으면 베이스 이미지를 -slim이나 -alpine으로 바꾼다. 다만 alpine은 glibc 대신 musl을 쓰기 때문에, 미리 컴파일된 휠이 없는 패키지는 빌드가 깨질 수 있다. 처음에는 slim으로 시작하고 필요할 때 바꾸는 편이 낫다.
Docker Compose로 두 개 같이 띄우기
서비스가 두 개를 넘어가면 docker run을 길게 치는 대신 Compose를 쓴다. 공식 문서는 Compose를 여러 컨테이너 앱을 YAML 하나로 정의하고 한 명령으로 띄우는 도구로 설명한다 (Docker Compose).
services:
web:
build: .
ports:
- "8000:8000"
environment:
- REDIS_HOST=redis
depends_on:
- redis
redis:
image: redis:7
docker compose up -d
docker compose ps
docker compose logs -f web
docker compose down
Compose 안에서는 서비스 이름이 그대로 호스트 이름이 된다. 그래서 코드에서 localhost:6379 대신 redis:6379로 접속한다. 이 한 줄 때문에 로컬과 배포 환경의 설정 차이가 줄어든다.
docker compose down은 컨테이너와 네트워크를 지우지만 볼륨은 남긴다. 볼륨까지 지우려면 docker compose down -v를 쓴다. 이 차이를 모르면 "DB를 새로 시작했는데 예전 데이터가 그대로" 같은 상황이 생긴다.
내가 막혔던 곳
첫 번째는 포트 순서였다. -p 80:8080으로 띄워놓고 브라우저에서 8080을 열어놓고 왜 안 되냐고 한참을 봤다. 앞이 내 맥, 뒤가 컨테이너라는 걸 외우고 나서야 정리가 됐다. 지금은 -p 호스트:컨테이너를 소리 내어 읽으면서 친다.
두 번째는 데이터였다. --rm으로 컨테이너를 정리하는 습관을 들인 뒤, 볼륨 없이 띄운 PostgreSQL에 테스트 데이터를 넣고 다음 날 전부 날렸다. 컨테이너를 지우면 쓰기 레이어가 같이 사라진다는 걸 문서로만 알고 실제로 겪지 않아서 생긴 일이다. 그 뒤로는 DB는 무조건 볼륨을 먼저 만든다.
세 번째는 맥을 재부팅한 뒤였다. Cannot connect to the Docker daemon at unix:///var/run/docker.sock이 뜨면 Docker Desktop이 꺼져 있는 경우가 대부분이다. 트레이에서 Docker.app을 실행하고 docker info가 응답하는지 먼저 확인한다. 이 오류를 보고 이미지나 컨테이너 문제부터 의심하면 시간이 더 걸린다.
마지막으로 애플 실리콘에서 인텔 이미지를 받을 때 나오는 platform 경고다. 급할 때는 --platform linux/amd64로 맞춰서 띄우면 되지만, 빌드까지 필요하면 멀티 아키텍처 이미지를 만드는 쪽이 오래 간다. 나는 로컬 테스트에서만 platform 옵션을 쓰고 있다.
참고 자료
- Docker Desktop for Mac 설치 — 다운로드 링크, macOS·RAM 요구 사항, 설치 절차
- Docker 개요 — 컨테이너 개념과 클라이언트·데몬 구조
- docker run 레퍼런스 — 옵션 전체와 이미지 pull 동작
- 볼륨 — 볼륨과 바인드 마운트의 차이, 데이터 수명
- Docker Compose — 다중 컨테이너 정의와 실행
- Docker Desktop 릴리스 노트 — 4.99.0(2026-11-09), Engine 29.9.3, Compose v5.7.0
- Mac 개발환경 세팅 — Homebrew와 zsh를 먼저 잡아두면 설치가 편하다
- Python 가상환경 venv 만들기 — 컨테이너와 비교해서 보면 이해가 빠르다
- git 기초 사용법 — Dockerfile과 compose.yaml도 결국 버전 관리 대상이다
'IT' 카테고리의 다른 글
| Opus 5.5 effort 추천 — claude.dev가 밝힌 기본값 medium 총정리 (2026) (0) | 2026.11.14 |
|---|---|
| VSCode 단축키·설정 정리 — macOS에서 손을 키보드에 붙여두는 법 (0) | 2026.11.14 |
| 파이썬 한글 깨짐 해결 — UnicodeDecodeError 원인과 encoding 지정 순서 (0) | 2026.11.10 |
| OpenAI dots란? — 컴퓨터 여러 대에 붙는 AI 에이전트 총정리 (0) | 2026.11.10 |
| 부이(vooy) vs 피클 비교 — 말로 시키는 한국 AI 에이전트, 뭘 골라야 하나 (2026) (2) | 2026.11.09 |


















