Summary
- Docker 이미지는 실행에 필요한 코드와 라이브러리를 담은 템플릿이고, 컨테이너는 이미지를 실행한 인스턴스다.
- Dockerfile로 이미지의 구성과 실행 명령어를 정의하고
docker build로 이미지를 만든다.docker pull,docker run,docker ps로 이미지를 받고 컨테이너를 실행·관리한다.- 볼륨으로 컨테이너의 생명주기와 데이터를 분리할 수 있다.
들어가며
Docker는 애플리케이션을 실행하는 데 필요한 환경을 이미지로 묶고, 그 이미지를 컨테이너로 실행하는 도구다. 이 글에서는 하나의 흐름을 따라 이미지와 컨테이너의 관계를 이해한 뒤, Dockerfile로 이미지를 만들고 볼륨으로 데이터를 보존하는 방법까지 살펴본다.
Docker 기본 흐름
이미지와 컨테이너
Docker의 구조와 이미지·컨테이너의 개념은 Docker의 기본 개념에서 먼저 설명했다. 이 글에서는 그 개념을 실제 명령어로 다룬다.
핵심 관계만 다시 정리하면 아래와 같고, 이 흐름을 Dockerfile과 명령어로 구현해보자.
- 이미지(Image) : 애플리케이션 실행에 필요한 코드·라이브러리·설정을 담은 템플릿
- 컨테이너(Container) : 그 이미지를 실행한 인스턴스
이미지 이름과 태그
이미지는 이름:태그 형식으로 구분한다. my-app:1.0에서 my-app은 이미지 이름이고 1.0은 버전 태그다. -t(--tag) 옵션으로 이 값을 지정한다.
이미지 이름과 태그 지정 예시
docker build -t my-app:1.0 .현재 디렉터리의 Dockerfile로 이미지를 빌드해 my-app:1.0이라는 이름을 붙이는 명령어다. .은 현재 디렉터리를 빌드 컨텍스트로 사용한다는 뜻이다. 태그를 생략하면 일반적으로 latest가 사용된다.
컨테이너와 데이터
컨테이너 내부에 저장한 데이터는 컨테이너를 삭제할 때 함께 사라질 수 있다. 컨테이너의 생명주기와 데이터를 분리하려면 호스트의 특정 디렉터리와 컨테이너 내부 경로를 연결한다.
호스트의 특정 경로를 직접 지정해 연결하는 방식은 정확히는 bind mount다. Docker가 직접 관리하는 named volume(docker volume create로 생성)도 있지만, 이 글의 실습은 bind mount 방식이다.
Dockerfile로 이미지 정의하기
직접 만든 애플리케이션을 이미지로 만들 때는 Dockerfile에 이미지의 구성과 실행 방법을 적는다. Dockerfile은 이미지의 설계도에 해당한다.
Python 애플리케이션용 Dockerfile 예시
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]Docker는 위 파일을 위에서부터 읽으며 이미지를 구성한다.
| 명령어 | 의미 |
|---|---|
FROM | 어떤 이미지를 기반으로 시작할지 지정한다. |
WORKDIR | 이후 명령어가 실행될 기준 디렉터리를 지정한다. |
COPY | 호스트의 파일을 이미지 내부로 복사한다. |
RUN | 이미지를 빌드하는 시점에 명령어를 실행한다. |
CMD | 컨테이너가 실행될 때 기본으로 실행할 명령어를 지정한다. |
requirements.txt를 먼저 복사하는 이유
- 소스 코드보다 먼저 복사해야 의존성 설치 레이어 재사용이 가능
- 소스 코드만 변경된 경우
RUN pip install단계까지 다시 실행하지 않아 빌드가 빨라짐
Docker 명령어 실습
이 챕터에서는 다음 순서로 Docker 이미지를 받고 컨테이너를 실행·관리한 뒤, 직접 이미지를 빌드하고 데이터를 연결한다.
이미지 받아오기
컨테이너를 실행하려면 먼저 실행할 이미지가 로컬에 있어야 한다. 앞에서 설명한 이미지 이름과 태그를 docker pull에 지정하면 Registry에서 해당 이미지를 받을 수 있다.
Docker 이미지 받기
docker pull nginx:1.27nginx는 이미지 이름이고 1.27은 태그다. 태그를 생략하면 latest를 받지만, 배포 환경마다 다른 버전을 받을 수 있으므로 운영 환경에서는 태그를 명시하는 편이 안전하다.
컨테이너 실행하기
이미지를 받았다면 docker run으로 컨테이너를 실행한다.
컨테이너 실행 명령어
docker run -d -p 8080:80 --name my-nginx nginx:1.27명령어의 주요 옵션은 다음과 같다.
| 옵션 | 의미 |
|---|---|
-d | 백그라운드(detached)로 실행한다. 터미널을 닫아도 컨테이너가 계속 실행된다. |
-p 8080:80 | 호스트의 8080번 포트를 컨테이너의 80번 포트에 연결한다. 호스트 포트:컨테이너 포트 순서다. |
--name my-nginx | 컨테이너에 이름을 지정한다. 생략하면 Docker가 임의의 이름을 붙인다. |
-it | 컨테이너 내부 터미널에 직접 접속할 때 사용한다. |
여기서 nginx:1.27은 실행할 이미지의 이름과 태그이고, my-nginx는 실행된 컨테이너의 이름이다. 이미지와 컨테이너는 서로 다른 대상이므로 이름도 별도로 지정한다.
이 글의 docker build와 docker run 실습은 하나의 이미지를 하나의 컨테이너로 실행하는 기본 단위다. 웹 서버·애플리케이션·데이터베이스처럼 여러 서비스의 컨테이너를 함께 정의하고 실행·관리할 때는 Docker Compose를 사용한다.
컨테이너 상태 관리하기
컨테이너는 생성·실행·중지·삭제의 생명주기를 가진다. 다음 명령어로 실행 상태와 로그를 확인하고 컨테이너를 제어할 수 있다.
컨테이너 상태 확인과 제어 명령어
docker ps # 실행 중인 컨테이너 목록
docker ps -a # 중지된 컨테이너를 포함한 전체 목록
docker logs my-nginx # 컨테이너 로그 확인
docker stop my-nginx # 중지
docker rm my-nginx # 삭제(중지된 컨테이너만 삭제 가능)
stop과rm은 다르다
stop은 프로세스만 멈추는 명령이다. 컨테이너 자체의 설정과 기록은 남아 있다. 완전히 없애려면rm까지 실행해야 한다.
Dockerfile로 이미지 빌드하기
앞에서 본 Dockerfile이 있는 디렉터리에서 다음 명령어를 실행한다.
Docker 이미지 빌드 명령어
docker build -t my-app:1.0 .-t my-app:1.0은 결과 이미지에 my-app이라는 이름과 1.0이라는 태그를 지정한다. 마지막의 .은 Dockerfile과 requirements.txt, 애플리케이션 코드가 있는 현재 디렉터리를 빌드 컨텍스트로 전달한다는 뜻이다.
빌드가 끝나면 my-app:1.0이라는 이미지가 만들어진다. 이후에는 이 이미지를 사용해 컨테이너를 실행할 수 있다.
볼륨 연결하기
컨테이너 내부 경로와 호스트 경로를 -v 옵션으로 연결한다.
호스트 디렉터리 연결 명령어
docker run -d -v /host/data:/app/data --name my-app my-app:1.0/host/data:/app/data는 호스트 경로:컨테이너 경로 형식이다. 컨테이너의 /app/data에 저장되는 파일은 실제로 호스트의 /host/data에 저장되므로 컨테이너를 지워도 데이터가 남는다.
Airflow에 적용하기
Airflow 컨테이너 설정에서도 DAG 디렉터리를 볼륨으로 연결한다.
Airflow DAG 디렉터리 연결 설정
volumes:
- ./dags:/opt/airflow/dags이 설정은 로컬 프로젝트 폴더의 ./dags와 컨테이너 내부의 /opt/airflow/dags를 연결한다. 따라서 로컬에서 DAG 파일을 수정하면 컨테이너를 새로 만들지 않아도 변경사항이 반영된다.
정리
Docker에서는 Dockerfile로 이미지의 구성을 정의하고, docker build로 이미지에 이름과 태그를 붙여 만든다. 이후 docker run으로 하나의 이미지를 하나의 컨테이너로 실행하고, docker ps와 docker logs로 상태를 확인한다. 컨테이너 외부에 데이터를 남겨야 할 때는 볼륨을 사용한다. 여러 서비스의 컨테이너를 함께 관리해야 한다면 Docker Compose를 사용한다.
Reference

