[Docker] 개발자를 위한 필수 컨테이너 기술 Part 3: 이미지부터 컨테이너까지
이전 Part 2에서 Docker를 성공적으로 설치하고 hello-world 컨테이너를 실행해봤습니다. 이제 본격적으로 Docker의 핵심 개념들을 실습을 통해 익혀보겠습니다.
Docker 이미지(Image)란?

Docker 이미지는 컨테이너를 만들기 위한 '설계도' 또는 '템플릿'입니다. 건축으로 비유하면 건물의 설계도면과 같습니다.
- 애플리케이션 실행에 필요한 모든 것을 포함 (코드, 라이브러리, 환경변수, 설정 파일 등)
- 읽기 전용(Read-only) 파일
- 한 번 만들어지면 변경되지 않음
- 여러 개의 컨테이너를 만드는 기준이 됨
컨테이너(Container)란?

컨테이너는 이미지를 기반으로 실제 실행되는 '인스턴스'입니다. 설계도를 바탕으로 실제 지어진 건물과 같습니다.
- 이미지에서 생성된 실행 가능한 환경
- 읽기/쓰기(Read-Write) 가능
- 실행 중에 데이터 변경 가능
- 하나의 이미지로 여러 개의 컨테이너 생성 가능
관계 이해하기

실생활 비유:
- 이미지 = 붕어빵 틀
- 컨테이너 = 틀에서 구워낸 실제 붕어빵들
Docker 기본 명령어 실습
1. 이미지 관련 명령어
이미지 검색하기
# Docker Hub에서 nginx 이미지 검색
docker search nginx

이미지 다운로드하기
# 최신 nginx 이미지 다운로드
docker pull nginx

Docker Hub에서 이미지를 pull 합니다.
로컬 이미지 목록 확인
# Docker 이미지 확인
docker images


도커 데스크탑 GUI에서도 확인 가능합니다.
2. Docker 명령어
기본 실행
# 기본 실행
docker run nginx

- 이 명령어는 nginx 컨테이너를 포그라운드(foreground) 모드로 실행합니다.
- 즉, 현재 터미널 세션과 컨테이너가 연결되어 있어서, 터미널에서는 해당 컨테이너 로그가 출력되고, 터미널을 통해 입력을 받거나 종료할 때까지 다른 작업을 할 수 없습니다.
- 터미널을 닫거나 Ctrl+C로 컨테이너를 멈추면 컨테이너도 종료됩니다.
백그라운드에서 실행
# 백그라운드 실행 (Detached 모드)
docker run -d nginx

- -d 옵션을 사용하면 컨테이너가 백그라운드에서 실행됩니다.
- 컨테이너가 백그라운드에서 실행되기 때문에 터미널에서는 즉시 다른 명령어를 사용할 수 있습니다.
- 실행 중인 컨테이너 로그를 보고 싶을 때는 docker logs <컨테이너 이름 또는 ID>를 사용할 수 있습니다.
포트 매핑과 컨테이너 이름 지정하여 실행하기
# 포트 매핑 옵션과 백그라운드 실행
docker run -d -p 8080:80 nginx

- -p 옵션은 호스트(내 컴퓨터)의 포트와 컨테이너 내부의 포트를 연결해주는 역할을 합니다.
- 위 예시에서는 호스트의 8080 포트가 컨테이너의 80 포트와 연결되어서, 브라우저에서 http://localhost:8080 으로 접속하면 nginx 웹서버에 접속할 수 있습니다.


포트 매핑(-p)을 사용할 때 반드시 호스트와 컨테이너 포트를 명확히 지정해야 외부에서 접속할 수 있습니다.
포그라운드 모드는 주로 디버깅이나 로그 실시간 확인용으로 사용되고, 실제 서비스는 백그라운드 모드로 운영하는 것이 일반적입니다.
컨테이너에 이름 지정
# 컨테이너에 이름 지정하며 실행
docker run -d -p 8080:80 --name my-nginx nginx
- --name 옵션으로 컨테이너에 사람이 기억하기 쉬운 이름을 지정할 수 있습니다.
- 이렇게 이름을 지정하면 my-nginx라는 이름으로 컨테이너를 관리할 수 있어, 중지/삭제 등의 명령어를 작성할 때 편리합니다.
주의사항!

포트 매핑 시 지정한 호스트 포트(8080)가 이미 다른 프로그램에서 사용 중이라면 충돌이 발생할 수 있으니 주의하세요. 이 경우 다른 번호로 바꾸거나 해당 포트를 사용 중인 프로그램을 종료해야 합니다.
컨테이너 이름은 고유해야 하며, 동일한 이름을 가진 컨테이너가 이미 존재하면 실행이 실패합니다.
포트와 이름을 바꿔서 다시 진행해보겠습니다.
# 컨테이너에 이름 지정하며 실행(포트와 이름을 바꿔서 실행)
docker run -d -p 8090:80 --name my-nginx2 nginx

실행 중인 컨테이너 확인
# 실행중인 컨테이너 확인
docker ps

모든 컨테이너 확인 (중지된 것 포함)
# 모든 컨테이너 확인
docker ps -a

컨테이너 중지
# 컨테이너 이름으로 중지
docker stop my-nginx2
# 컨테이너 ID로 중지
docker stop [컨테이너 ID]

컨테이너 시작
# 컨테이너 시작
docker start my-nginx2
컨테이너 삭제
# 컨테이너 삭제
docker rm my-nginx2

- 실행중인 컨테이너를 삭제하려 하면 위와 같이 컨테이너를 중지한 후 삭제하라는 에러 메시지가 뜹니다.
- 컨테이너를 중지 후 삭제를 하거나 또는 아래의 명령어를 사용하여 실행중인 컨테이너를 강제로 삭제 가능합니다.
# 실행 중인 컨테이너 강제 삭제
docker rm -f my-nginx2
# 이미지 이름으로 삭제
$ docker rmi nginx
# 이미지 ID로 삭제
$ docker rmi 87a94228f133
# 태그를 포함한 이미지 삭제
$ docker rmi nginx:latest
$ docker rmi nginx:1.21
여러 이미지 한 번에 삭제
# 여러 이미지를 공백으로 구분하여 삭제
$ docker rmi nginx mysql redis
# 이미지 ID 여러 개 삭제
$ docker rmi 87a94228f133 abc123def456 xyz789uvw012
강제 삭제 옵션
- -f (force) 옵션 사용
# 컨테이너가 실행 중이어도 강제로 이미지 삭제
$ docker rmi -f nginx
# 여러 이미지 강제 삭제
$ docker rmi -f nginx mysql redis
- 강제 삭제 시 해당 이미지를 사용 중인 컨테이너도 함께 삭제될 수 있습니다
- 데이터 손실 가능성이 있으므로 신중하게 사용하세요
일괄 삭제 명령어
사용하지 않는 이미지 삭제
# 컨테이너에서 사용되지 않는 이미지 삭제
$ docker image prune
# 태그가 없는 이미지(dangling images) 삭제
$ docker image prune
# 모든 사용하지 않는 이미지 삭제 (주의!)
$ docker image prune -a
모든 이미지 삭제
# 모든 이미지를 나열하고 삭제
$ docker rmi $(docker images -q)
# 강제로 모든 이미지 삭제
$ docker rmi -f $(docker images -q)
안전한 이미지 정리 워크플로우
# 1단계: 중지된 컨테이너 삭제
$ docker container prune
# 2단계: 사용하지 않는 이미지 삭제
$ docker image prune
# 3단계: 사용하지 않는 볼륨 삭제
$ docker volume prune
# 4단계: 사용하지 않는 네트워크 삭제
$ docker network prune
# 5단계: 전체 시스템 정리 (신중하게!)
$ docker system prune -a
디스크 사용량 확인
# Docker가 사용 중인 디스크 공간 확인
$ docker system df
# 상세한 사용량 정보
$ docker system df -v
마무리
지금까지 Docker의 핵심 개념과 명령어를 익히고, 직접 이미지를 다운로드하고 컨테이너를 실행하는 과정을 실습했습니다. 간단한 명령어 한 줄로 서비스 환경을 빠르게 구축할 수 있다는 점에서 Docker가 가진 강력한 효율성을 체감했을 것입니다.
Docker와 함께라면 복잡한 환경 설정에 시간 낭비하지 않고, 본연의 개발에 더욱 집중할 수 있습니다.
다음 Part 4에서는 Dockerfile을 직접 작성해보며 나만의 Docker 이미지를 만들어보겠습니다. 간단한 Node.js 웹 애플리케이션을 예제로 하여 코드 작성부터 Dockerfile 생성, 이미지 빌드, 컨테이너 실행까지의 전체 과정을 단계별로 실습해보겠습니다.
또한 Docker Hub에 내가 만든 이미지를 업로드하는 방법과 이미지 최적화 팁도 함께 다뤄보겠습니다.