Docker 이미지와 컨테이너의 차이점, Dockerfile의 기본 구조를 설명해주세요.
답변 포인트
이미지는 실행 템플릿, 컨테이너는 이미지가 실행된 인스턴스입니다.
정답 및 해설
빠른 요약
Docker 이미지는 애플리케이션 실행에 필요한 파일, 라이브러리, 설정, 실행 명령을 담은 읽기 전용 템플릿입니다. 컨테이너는 이미지를 실행한 인스턴스입니다.
Docker는 애플리케이션과 실행 환경을 함께 패키징해 어디서나 일관되게 실행할 수 있게 해주는 컨테이너 기술입니다. 핵심 개념은 이미지와 컨테이너입니다.
이미지(Image)
이미지는 애플리케이션 실행에 필요한 파일, 라이브러리, 설정, 실행 명령을 포함한 읽기 전용 템플릿입니다.
예:
node:20-alpine
postgres:16
nginx:alpine이미지는 여러 레이어로 구성되며, 같은 레이어는 캐시되어 빌드와 배포 효율을 높입니다.
컨테이너(Container)
컨테이너는 이미지를 실행한 인스턴스입니다. 하나의 이미지로 여러 컨테이너를 띄울 수 있습니다.
docker run -p 3000:3000 my-app이미지는 클래스, 컨테이너는 객체 인스턴스에 비유할 수 있습니다.
Dockerfile 기본 구조
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]각 명령의 의미:
| 명령 | 설명 |
|---|---|
| FROM | 베이스 이미지 지정 |
| WORKDIR | 작업 디렉터리 설정 |
| COPY | 파일 복사 |
| RUN | 이미지 빌드 중 명령 실행 |
| EXPOSE | 컨테이너가 사용할 포트 문서화 |
| CMD | 컨테이너 시작 시 기본 명령 |
COPY 순서가 중요한 이유
COPY package*.json ./
RUN npm ci
COPY . .의존성 파일을 먼저 복사하고 설치하면, 소스 코드만 바뀐 경우 npm ci 레이어를 재사용할 수 있어 빌드가 빨라집니다.
반대로 처음부터 전체 소스를 복사하면 작은 코드 변경에도 의존성 설치 레이어가 무효화될 수 있습니다.
.dockerignore
이미지 빌드 컨텍스트에 불필요한 파일이 들어가지 않도록 .dockerignore를 사용합니다.
node_modules
.next
.git
*.log빌드 속도와 이미지 크기를 줄이고, 민감한 파일이 이미지에 들어가는 것을 방지합니다.
컨테이너 데이터와 볼륨
컨테이너 파일 시스템은 컨테이너 삭제 시 함께 사라질 수 있습니다. 데이터베이스처럼 유지가 필요한 데이터는 볼륨을 사용합니다.
docker run -v postgres-data:/var/lib/postgresql/data postgres:16정리
이미지는 실행 환경을 담은 불변 템플릿이고, 컨테이너는 그 이미지를 실행한 프로세스입니다. 좋은 Dockerfile은 작은 이미지, 캐시 효율, 명확한 실행 명령, 불필요한 파일 제외를 고려해 작성해야 합니다.
이미지와 컨테이너를 비유로 이해하기
Docker 이미지는 실행에 필요한 파일 시스템과 설정을 담은 읽기 전용 템플릿이고, 컨테이너는 그 이미지를 실제로 실행한 프로세스입니다. 클래스와 인스턴스의 관계에 비유할 수 있습니다.
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]Dockerfile 작성 팁
- 변경이 적은 파일(
package.json)을 먼저 복사해 레이어 캐시를 활용합니다. - 빌드 도구와 런타임 이미지를 분리하려면 multi-stage build를 사용합니다.
- secret을 이미지에 COPY하거나 ENV로 박아 넣지 않습니다.
- 컨테이너는 stateless하게 만들고 영속 데이터는 volume/외부 DB에 둡니다.
흔한 오해
컨테이너는 가상머신보다 가볍지만 완전한 보안 경계는 아닙니다. 호스트 커널을 공유하므로 권한, 네트워크, 이미지 취약점 스캔을 함께 관리해야 합니다.