
도커 이미지는 Docker Hub에서 가져와서 사용할 수도 있지만, 직접 생성할 수도 있다. Dockerfile을 먼저 작성하면 클라이언트를 통해 서버에 전달되고, 최종적으로 이미지가 생성된다. Dockerfile은 도커 이미지를 생성하기 위한 설정 파일인데, 컨테이너, 즉 프로그램을 실행하기 위한 설정들을 정의해준다.
- 베이스 이미지를 명시해준다. 이는 파일 스냅숏에 해당한다.
- 추가적으로 필요한 파일, 패키지를 다운받기 위한 명령어를 명시해준다.
- 컨테이너 시작 시 실행될 명령어를 명시해준다. 예를 들어 애플리케이션 소스 코드를 복사하는 명령어를 명시해준다.

베이스 이미지는 보통 Docker Hub에서 가져오며, 베이스 이미지 크기는 최대한 작게 하는 것이 좋다.

도커 이미지는 여러개의 레이어로 구성되어 있다. 베이스 이미지는 운영체제 개념처럼 생각하면 된다.
간단하게 스프링부트 프로젝트, 플라스크 프로젝트를 위한 도커 파일을 작성해 보았다.
Spring Boot 도커파일
# 빌드 단계: 빌드에 필요한 Java 17 JDK가 포함된 경량 이미지 사용
FROM openjdk:17-jdk-slim as build
# 작업 디렉토리 설정
WORKDIR /app
# 모든 소스 파일을 컨테이너의 작업 디렉토리로 복사
COPY . .
# Gradle 빌드 명령 실행
RUN ./gradlew clean build
# 타임존을 서울로 설정하기 위한 환경 변수 추가
ENV TZ=Asia/Seoul
# 타임존 설정을 위해 필요한 tzdata 패키지 설치
RUN apt-get update && apt-get install -y tzdata && \
# 타임존을 /etc/localtime에 심볼릭 링크로 설정
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
# 설치 완료 후 불필요한 캐시 삭제하여 이미지 크기 최소화
apt-get clean
# JAR 파일 복사
COPY --from=build /app/build/libs/*jar app.jar
# Spring Boot 기본 포트를 설정
EXPOSE 8080
# 실행 명령: Java 옵션으로 타임존을 설정하고, JAR 파일을 실행
ENTRYPOINT ["java", "-Duser.timezone=Asia/Seoul", "-jar", "app.jar"]
Flask 도커파일
FROM python:3.12-slim
# 작업 디렉토리 설정
WORKDIR /app
# 필요한 파일 복사
COPY requirements.txt .
COPY app.py .
# 필요한 패키지 설치
RUN pip install —no-cache-dir -r requirements.txt
# 포트 노출
EXPOSE 8000
# 애플리케이션 실행
CMD ["python", "app.py"]
FROM : 베이스 이미지를 설정해주는 부분으로, <이미지명>:<태그> 형식으로 작성한다. 태그는 이미지의 버전이며, 태그 생략 시 latest로 자동으로 설정되며 최신 버전을 가져온다.
WORKDIR : 이미지 안에서, 복사해올 프로젝트의 소스 코드를 가지고 있을 디렉토리를 생성하는 부분이다. WORKDIR을 지정하지 않고 COPY를 해올 경우 문제가 생길 수 있다.
- COPY해 온 파일 중, 이미지에 있던 파일과 파일명이 겹칠 경우 원래 있던 폴더가 덮어씌어져 버린다.
- 이미지의 루트 디렉토리에 있는 파일들과 섞이기 때문에 정리 정돈이 안되어있는 상태가 된다.
RUN : 도커 이미지가 생성되기 전에 실행할 명령어를 명시해준다.
COPY : 스프링부트는 ./gradlew clean build 명령어를 통해 빌드하고, 생성된 jar 파일이 있어야 애플리케이션을 실행할 수 있으므로 jar 파일을 복사해준다.
EXPOSE : 포트 번호를 8080으로 설정해줬다.
ENTRYPOINT: CMD와 마찬가지로 생성된 이미지가 컨테이너로 실행될 때 사용되는 명령어 및 인자를 설정한다. ENTRYPOINT는 도커 컨테이너 실행 시 항상 수행해야 하는 명령어를 지정할 때 사용하고, CMD는 도커 컨테이너 실행 시에 다양한 명령어를 지정하는 경우에 사용한다.
CMD : 컨테이너를 실행할 때 실행하는 명령어로 도커파일에서는 컨테이너 시작 시 한 번만 실행된다. 즉 여러개의 CMD를 작성하더라도, 마지막 하나만 처리된다.
ENV : 이미지 내에서 환경변수를 지정할 때 사용한다.
스프링부트 도커 파일에서는 스프링부트 로그를 표시할 때, 시간을 현재 시간으로 맞춰서 로그를 더 효율적으로 확인하기 위해 서울 시간으로 맞춰 주는 데에 필요한 패키지를 설치하도록 해줬다.
flask는 requriements에 명시된 패키지들을 다운로드 해줘야 하기 때문에 COPY를 통해 파일을 복사하도록 해줬다. RUN을 통해 requriements에 있는 파일을 설치해준다.
도커 파일에 입력된 내용들을 도커 서버가 인식할 수 있도록 해야 하는데, docker build 명령을 수행하면 된다.
docker build [옵션] ./
docker build [옵션] .
경로의 경우, "." 을 사용하면 현재 경로에 반드시 Dockerfile이 있어야 한다. 없다면 절대경로를 반드시 작성해줘야 한다.
따로 옵션을 지정할 수도 있다.

베이스 이미지에서 다른 종속성이나 새로운 커맨드를 추가할 경우, 임시 컨테이너를 만든 후에, 그 컨테이너를 기반으로 새로운 이미지를 생성하고 임시 컨테이너를 삭제한다.
docker run -p [로컬에서 접속하는 포트]:[애플리케이션의 포트] [이미지명]
-p 옵션을 통해 포트 매핑을 설정해줄 수 있다. 스프링부트 애플리케이션은 8080으로 설정하고, 로컬에서 애플리케이션에 접속하고 싶을 수 있다. 로컬에서 접속하는 포트와 컨테이너의 포트를 따로 명시해주면서 컨테이너를 실행하면, 로컬에서 컨테이너가 실행할 때 실행되는 애플리케이션에 접속해 볼 수가 있다.