0. 들어가며
[BASIC #2]에서는 도커를 설치하고 기본 명령어들을 실습해보았다. docker run nginx 같은 명령어를 실행하면 컨테이너가 실행된다는 것은 알겠는데, 도대체 이미지(Image) 와 컨테이너(Container) 는 정확히 무엇이고, 둘은 어떤 관계일까? 이번 포스팅에서는 도커의 가장 핵심 개념인 이미지와 컨테이너를 밀키트(Meal Kit) 비유를 통해 쉽고 완벽하게 이해해보겠다.
1. 밀키트 비유: 이미지와 컨테이너
1.1. 도커 이미지 = 밀키트
밀키트(Meal Kit) 란? 된장찌개 밀키트를 생각해보자.
- 밀키트 안에는 된장, 두부, 호박, 양파, 육수, 고춧가루 등 요리에 필요한 모든 재료가 정해진 양만큼 들어있다.
- 또한 조리법(레시피)도 함께 제공된다. "물 500ml를 넣고 끓이다가 두부를 넣으세요" 같은 설명이 적혀 있다.
- 하지만 밀키트 자체는 아직 요리된 상태가 아니다. 먹을 수 없고, 단지 요리를 만들기 위한 준비물일 뿐이다.
도커 이미지도 마찬가지다.
- 이미지 안에는 애플리케이션을 실행하는 데 필요한 모든 요소가 들어있다.
- 소스 코드
- 자바, 파이썬 같은 런타임
- 각종 라이브러리와 의존성
- 환경 변수, 설정 파일
- 실행 명령어
- 하지만 이미지 자체는 읽기 전용(read-only) 템플릿이다. 실행할 수 없고, 단지 컨테이너를 만들기 위한 설계도 역할을 한다.
1.2. 도커 컨테이너 = 완성된 요리
이제 밀키트를 실제로 냄비에 넣고 끓여보자.
- 밀키트의 재료들을 냄비에 넣고 레시피대로 조리하면, 비로소 먹을 수 있는 된장찌개가 완성된다.
- 이 완성된 된장찌개는 실행 중인 인스턴스다. 실제로 냄비에 담겨 있고, 국자를 떠서 먹을 수 있다.
- 냄비 안에서는 재료들이 섞이고, 국물이 끓는 등 동적인 상태가 유지된다.
도커 컨테이너도 마찬가지다.
- 이미지를 기반으로 생성되어, 실제로 실행 중인 인스턴스다.
- 컨테이너는 파일을 읽고 쓸 수 있고, 네트워크를 사용할 수 있으며, 프로세스가 동작하는 살아있는 환경이다.
- 하나의 이미지로 여러 개의 컨테이너를 만들 수 있다. (된장찌개 밀키트로 여러 냄비의 된장찌개를 끓일 수 있는 것과 같다)
1.3. 비유의 확장: 중요한 포인트들
① 하나의 이미지로 여러 컨테이너 생성 가능
된장찌개 밀키트 한 박스로 3개의 냄비에 된장찌개를 끓일 수 있다. 각 냄비의 된장찌개는 서로 독립적이다. 한 냄비가 눌어붙어도 다른 냄비는 영향을 받지 않는다. 도커도 마찬가지다. 하나의 nginx 이미지로 10개의 nginx 컨테이너를 실행할 수 있다. 각 컨테이너는 완전히 독립적이며, 포트만 다르게 설정하면 동시에 실행해도 문제없다.
② 컨테이너는 읽기/쓰기 레이어를 가진다
밀키트로 요리할 때, 재료들은 그대로지만 냄비 안에서 물이 끓고 재료가 익는 변화가 일어난다. 도커 컨테이너는 이미지의 읽기 전용 레이어 위에 읽기/쓰기 레이어를 추가한다. 컨테이너 내부에서 파일을 생성하거나 수정하는 모든 변경 사항은 이 읽기/쓰기 레이어에 저장된다.
③ 컨테이너 삭제 = 요리를 먹어치움
된장찌개를 다 먹고 냄비를 비우면, 그 냄비의 된장찌개는 사라진다. 새로운 된장찌개를 먹고 싶다면 밀키트로 다시 끓여야 한다. 도커 컨테이너를 삭제하면, 그 컨테이너의 읽기/쓰기 레이어에 저장된 모든 데이터도 함께 사라진다. 하지만 원본 이미지는 그대로 남아 있으므로, 언제든지 새 컨테이너를 다시 생성할 수 있다.
2. 이미지와 컨테이너의 관계
2.1. 이미지와 컨테이너의 생명주기
[이미지] --(docker run)--> [컨테이너(실행중)] --(docker stop)--> [컨테이너(중지)] --(docker start)--> [컨테이너(실행중)]
^ |
| |
+--------------------------------(docker commit)---------------------------------------------+
- 이미지: 정적인 템플릿. Docker Hub에서 pull 받거나, Dockerfile로 빌드하여 생성한다.
- 컨테이너: 이미지를 실행한 상태. docker run으로 생성하고, docker stop으로 중지하고, docker start로 다시 시작할 수 있다.
- 새 이미지 생성: 실행 중인 컨테이너를 변경한 후, docker commit으로 그 상태를 새로운 이미지로 만들 수 있다.
2.2. 레이어(Layer) 개념 이해하기
도커 이미지는 여러 개의 레이어(Layer) 로 구성된다.
+-------------------+
| Container Layer (읽기/쓰기) | <- 컨테이너 생성 시 추가됨
+-------------------+
| Image Layer 3 | <- 설정 파일
+-------------------+
| Image Layer 2 | <- 애플리케이션 코드
+-------------------+
| Image Layer 1 | <- 베이스 이미지 (Ubuntu)
+-------------------+
- 각 레이어는 읽기 전용이다.
- Dockerfile의 명령어 한 줄이 하나의 레이어가 된다.
- 레이어는 캐시되므로, 이미지 빌드 속도가 빠르고 디스크 공간을 절약할 수 있다.
레이어 확인하기:
# nginx 이미지의 레이어 확인
docker history nginx
실행하면 각 레이어의 크기와 생성 명령어를 볼 수 있다.
3. 이미지 관련 상세 명령어
3.1. 이미지 검색 및 다운로드
# Docker Hub에서 이미지 검색
docker search nginx
# 이미지 다운로드
docker pull nginx:latest
docker pull ubuntu:20.04
docker pull mysql:8.0
3.2. 이미지 목록 및 상세 정보
# 로컬 이미지 목록
docker images
# 특정 이미지의 상세 정보
docker inspect nginx
# 이미지의 레이어 히스토리
docker history nginx
3.3. 이미지 태그 관리
# 이미지에 태그 추가
docker tag nginx:latest my-nginx:v1
# 태그 확인
docker images | grep nginx
3.4. 이미지 삭제
# 특정 이미지 삭제
docker rmi nginx
# 사용하지 않는 이미지 모두 삭제
docker image prune
# 모든 이미지 강제 삭제
docker rmi -f $(docker images -q)
4. 컨테이너 관련 상세 명령어
4.1. 컨테이너 실행 심화
# 기본 실행
docker run nginx
# 백그라운드 실행 + 이름 지정
docker run -d --name web-server nginx
# 포트 매핑
docker run -d -p 8080:80 --name web nginx
# 환경 변수 전달
docker run -d -e MYSQL_ROOT_PASSWORD=root --name mysql mysql:8.0
# 볼륨 마운트
docker run -d -v /host/data:/container/data --name app myapp
# 컨테이너 종료 시 자동 삭제
docker run --rm -it ubuntu bash
4.2. 컨테이너 생명주기 관리
# 실행 중인 컨테이너 목록
docker ps
# 모든 컨테이너 목록 (종료 포함)
docker ps -a
# 컨테이너 중지
docker stop web-server
# 컨테이너 시작
docker start web-server
# 컨테이너 재시작
docker restart web-server
# 컨테이너 일시 중지/재개
docker pause web-server
docker unpause web-server
# 컨테이너 삭제
docker rm web-server
# 실행 중인 컨테이너 강제 삭제
docker rm -f web-server
4.3. 컨테이너 내부 접속 및 명령 실행
# 실행 중인 컨테이너에 접속
docker exec -it web-server bash
# 컨테이너 내부에서 단일 명령 실행
docker exec web-server ls -la
# 컨테이너 로그 확인
docker logs web-server
docker logs -f web-server # 실시간 로그 확인
4.4. 컨테이너와 파일 주고받기
# 호스트 → 컨테이너 파일 복사
docker cp ./index.html web-server:/usr/share/nginx/html/
# 컨테이너 → 호스트 파일 복사
docker cp web-server:/etc/nginx/nginx.conf ./
5. 실습: nginx 이미지와 컨테이너 다루기
5.1. nginx 이미지로 여러 컨테이너 실행하기
# nginx 이미지 pull
docker pull nginx
# 첫 번째 nginx 컨테이너 (포트 8081)
docker run -d -p 8081:80 --name nginx1 nginx
# 두 번째 nginx 컨테이너 (포트 8082)
docker run -d -p 8082:80 --name nginx2 nginx
# 실행 중인 컨테이너 확인
docker ps
두 개의 nginx 컨테이너가 각각 8081, 8082 포트로 실행된다. 브라우저에서 localhost:8081과 localhost:8082에 접속해보면 둘 다 nginx 환영 페이지가 보인다. 완전히 독립적인 인스턴스임을 확인할 수 있다.
5.2. 컨테이너 내부 파일 수정하기
# nginx1 컨테이너에 접속
docker exec -it nginx1 bash
# 웹 루트 디렉토리로 이동
cd /usr/share/nginx/html
# index.html 내용 확인
cat index.html
# index.html 수정
echo "<h1>Hello from nginx1</h1>" > index.html
# 컨테이너 종료
exit
이제 localhost:8081에 접속하면 "Hello from nginx1"이 보이고, localhost:8082는 여전히 기본 페이지가 보인다. 각 컨테이너의 파일 시스템이 독립적임을 확인할 수 있다.
5.3. 컨테이너 삭제와 이미지의 영속성
# nginx1 컨테이너 삭제
docker rm -f nginx1
# 이미지 확인 (여전히 존재)
docker images | grep nginx
# nginx1과 동일한 이미지로 새 컨테이너 실행
docker run -d -p 8083:80 --name nginx3 nginx
컨테이너는 삭제되었지만, 이미지는 그대로 남아 있다. 이미지로 새로운 컨테이너를 언제든지 다시 생성할 수 있다.
6. 이미지와 컨테이너의 핵심 차이점 정리
| 구분 | 도커 이미지 | 도커 컨테이너 |
| 비유 | 밀키트 (재료 + 레시피) | 완성된 요리 |
| 상태 | 정적 (읽기 전용) | 동적 (실행 중) |
| 생성 | docker build 또는 docker pull | docker run (이미지 필요) |
| 목록 확인 | docker images | docker ps |
| 삭제 | docker rmi | docker rm |
| 데이터 | 레이어로 저장 (변경 불가) | 읽기/쓰기 레이어에 저장 (변경 가능) |
| 수명 | 영구적 (삭제할 때까지) | 일시적 (삭제하면 데이터 소멸) |
7. 마치며
이번 포스팅에서는 도커의 가장 핵심 개념인 이미지와 컨테이너를 밀키트 비유를 통해 이해해보았다.
- 이미지는 실행하기 위한 설계도(템플릿) 다.
- 컨테이너는 그 설계도로 실제로 실행한 인스턴스다.
- 하나의 이미지로 여러 컨테이너를 만들 수 있으며, 각 컨테이너는 독립적이다.
- 컨테이너는 삭제되면 내부 데이터도 사라지지만, 이미지는 남아 있어 다시 컨테이너를 생성할 수 있다.
이 개념만 확실히 이해하면 도커의 절반은 이해한 것이다. 다음 포스팅에서는 이 이미지를 직접 만드는 방법, 즉 Dockerfile 작성법에 대해 알아보겠다.
'Docker' 카테고리의 다른 글
| [BASIC #6] 컨테이너 간 통신: Docker Network 이해하기 (0) | 2025.06.01 |
|---|---|
| [BASIC #5] 데이터를 영구적으로 저장하는 법: Docker Volume (0) | 2025.05.31 |
| [BASIC #4] 나만의 이미지 만들기: Dockerfile 완전 정복 (0) | 2025.05.31 |
| [BASIC #2] 도커 설치부터 첫 컨테이너 실행까지 (Hello World 실습) (0) | 2025.05.31 |
| [BASIC #1] VM과 비교하며 이해하는 도커(Docker)의 개념과 등장 배경 (0) | 2025.05.31 |
