Dockerfile은 Docker 이미지를 빌드하는 데 사용되는 텍스트 파일입니다. 이 파일에는 컨테이너에 포함될 소프트웨어, 라이브러리, 의존성 등을 설치하고 설정하는 데 필요한 명령어들이 포함되어 있습니다.
버전 관리와 재사용성: Dockerfile을 사용하면 이미지 생성 과정을 코드로 관리할 수 있습니다. 이를 통해 이미지 생성 과정을 버전 관리 시스템에 저장하고, 필요에 따라 이전 버전으로 롤백하거나 다른 사람과 공유할 수 있습니다.
일관성: Dockerfile을 사용하면 동일한 Dockerfile에서 항상 동일한 이미지를 생성할 수 있습니다. 이는 애플리케이션의 일관성을 보장합니다.
자동화: Dockerfile을하면 이미지 생성 과정을동화할 수 있습니다. 이는 수동으로 명령어를 실행하는 것보다 빠르고 안정적이며, 실수를 줄일 수 있습니다.
문서화: Dockerfile은 애플리케이션의 빌드와 배포 과정을 문서화하는 역할도 합니다. Dockerfile을 읽으면 어떤 단계를 거쳐서 이미지가 생성되는지 이해할 수 있습니다.
FROM: 이미지를 생성하기 위한 베이스 이미지를 지정합니다. 예: FROM ubuntu:18.04
RUN: 이미지를 빌드하는 동안 실행할 쉘 명령어를 지정합니다. 예: RUN apt-get update
CMD: 컨테이너가 시작될 때 실행할 기본 명령어를 지정합니다. Dockerfile에는 하나의 CMD 지시자만 있어야 하며, 여러 개가 있는 경우 마지막 CMD만 사용됩니다.
ENTRYPOINT: 컨테이너가 시작될 때 실행할 명령어를 지정합니다. CMD와 달리, docker run 명령어의 인수에 의해 오버라이드되지 않습니다.
COPY: 파일이나 디렉토리를 이미지에 복사합니다. 예: COPY ./app /app
ADD: COPY와 유사하지만, URL을 지원하고 압축 파일을 자동으로 압축 해제합니다.
EXPOSE: 컨테이너가 리스닝할 포트를 지정합니다. 예: EXPOSE 8080
WORKDIR: RUN, CMD, ENTRYPOINT, COPY 및 ADD 명령어의 작업 디렉토리를 설정합니다.
ENV: 환경 변수를 설정합니다. 예: ENV MY_NAME="John Doe"
VOLUME: 호스트와 공유할 볼륨을 설정합니다. 예: VOLUME /data
자세한 내용은 Docker 레퍼런스를 확인
https://docs.docker.com/engine/reference/builder/
ENTRYPOINT와 CMD는 모두 Docker 컨테이너가 시작될 때 실행할 명령을 지정하는 Dockerfile의 지시자입니다.
ENTRYPOINT와 CMD는 모두 Docker 컨테이너가 시작할 때 실행할 명령을 지정합니다. ENTRYPOINT는 컨테이너가 시작될 때 항상 실행되는 명령을 지정하는 반면, CMD는 기본 명령을 지정하되, docker run에서 명령 라인 인수를 통해 오버라이드될 수 있습니다. 두 지시자를 함께 사용하면, CMD는 ENTRYPOINT의 인수를 제공하는 역할을 합니다. 이에 따라, 항상 실행되어야 하는 명령이 있다면 ENTRYPOINT를, 변경 가능한 기본 명령이 필요하다면 CMD를 사용합니다.
우선 요청이 왔을 때 hello docker를 리턴하는 간단한 spring boot 프로젝트를 만듭니다.
@RestController
public class sample {
@GetMapping("/")
public String home() {
return "hello docker";
}
}
#vim을 통해 Dockerfile을 생성
vim Dockerfile
이후 만들어진 Dockerfile에 아래 내용을 작성합니다.
# 베이스 이미지 설정
FROM openjdk:17-jdk-slim
# 복사할 파일 위치 설정
ARG JAR_FILE=target/*.jar
# 파일 복사
COPY ${JAR_FILE} app.jar
# 포트 설정
EXPOSE 8080
# 커맨드 실행
ENTRYPOINT ["java","-jar","/app.jar"]
경로와 명령어가 일정하지 않을 때
# 베이스 이미지 설정
FROM openjdk:17-jdk-slim
# 작업 디렉토리를 설정
WORKDIR /app
# 파일 복사
COPY build/libs/ProjectName-0.0.1-SNAPSHOT.jar ProjectName.jar
# 커맨드 실행
CMD ["java", "-jar", "ProjectName.jar"]
경로와 명령어가 일정할 때
베이스 이미지 설정 : 프로젝트에서 사용하는 Java의 버전에 따라 베이스 이미지를 선택해야 합니다.
작업 디렉토리를 설정 : WORKDIR /app 명령어들이 실행될 작업 디렉토리를 설정하는 역할을 합니다.
/app 디렉토리에서 실행cd 명령어와 유사한 역할파일 복사 : Dockerfile 애플리케이션의 jar 파일을 이미지 안에 복사합니다.
ARG를 사용하여 동적으로 경로를 지정포트 설정 : 정보 제공 목적으로 사용되며, 실제로 포트를 열지는 않습니다. 실제로 포트를 열기 위해서는 docker run 명령어를 사용할 때 -p 플래그를 사용해야 합니다.
커맨드 실행 : 컨테이너가 시작될 때 실행할 명령어를 지정하고 있습니다.
ENTRYPOINT를 사용run 명령어와 함께 전달된 인수에 따라 실행할 명령어가 변할 수 있다면 CMD를 사용여기까지가 기본적인 Spring Boot 애플리케이션을 Docker에 배포하는 방법입니다. 이제 여기에 추가적인 내용을 덧붙이고자 합니다.
Docker 컨테이너는 호스트 운영체제와 독립적으로 동작합니다. 이는 Ubuntu 베이스 이미지를 사용하는 Docker 컨테이너를 Windows나 Linux 등 어떤 호스트 운영체제에서든 실행할 수 있다는 것을 의미합니다.
Docker는 애플리케이션을 실행하기 위한 독립적이고 격리된 환경, 즉 컨테이너를 제공합니다. 이 컨테이너는 호스트 운영체제와 상호작용하긴 하지만, 그 자체는 완전히 독립적인 환경이므로, 컨테이너 내부에서 Ubuntu를 실행하더라도 호스트 운영체제에는 아무런 영향을 주지 않습니다.
이런 Docker의 특성 덕분에, Dockerfile 작성시에는 운영체제의 제약을 받지 않고 필요한 환경을 자유롭게 구성할 수 있습니다. 예를 들어, 호스트 운영체제에 Java 17이 설치되어 있지 않아도, Dockerfile에 Java 설치 명령을 포함시키면 해당 Docker 이미지를 기반으로 한 컨테이너에서는 Java 17을 정상적으로 사용할 수 있게 됩니다.
다음은 Ubuntu를 베이스 이미지로 사용하고, 그 위에 Java 17을 설치하는 Dockerfile 예제입니다.(여기서 'ProjectName'은 원하는 프로젝트 이름으로 변경해 주세요.)
# 베이스 이미지로 ubuntu를 사용합니다.
FROM ubuntu:20.04
# 불필요한 경고 메시지를 방지하기 위해 환경변수를 설정합니다.
ENV DEBIAN_FRONTEND=noninteractive
# 필요한 패키지를 설치하고 OpenJDK 17을 설치합니다.
RUN apt-get update && \
apt-get install -y software-properties-common && \
add-apt-repository ppa:openjdk-r/ppa && \
apt-get update && \
apt-get install -y openjdk-17-jdk
# Java의 환경변수를 설정합니다.
ENV JAVA_HOME /usr/lib/jvm/java-17-openjdk-amd64
ENV PATH $JAVA_HOME/bin:$PATH
# 작업 디렉토리를 설정
WORKDIR /app
# 파일 복사
COPY ProjectName-0.0.1-SNAPSHOT.jar ProjectName.jar
# 커맨드 실행
CMD ["java", "-jar", "ProjectName.jar"]
이 Dockerfile을 사용하면, Docker 컨테이너 내에서 Java 17을 사용하여 Spring Boot 애플리케이션을 실행할 수 있습니다.
mvn clean package
Gradle을 사용하는 경우에는 다음 명령어를 실행합니다.
gradle bootJar
$ docker build -it myapp:0.0.1 .
docker build -it myapp . : 현재 디렉토리(.)에서 Dockerfile이라는 이름의 파일을 찾아 Docker 이미지를 빌드하고, 그 이미지에 'myapp'이라는 태그를 부여합니다. -t 옵션은 생성될 이미지에 태그를 지정하는 것입니다. -i 옵션은 터미널에서 직접 컨테이너에 입력을 제공할 수 있습니다.
docker build -f Dockerfile -t myapp : -f 옵션을 사용해서 Dockerfile의 경로와 이름을 직접 지정합니다.
#images 명령어로 docker이미지가 제대로 만들어 졌는지 확인
$ docker images
# 아래와 같은 이미지 생성확인
REPOSITORY TAG IMAGE ID CREATED SIZE
myapp 0.0.1 57529e52a879 3 min ago 43MB
Docker 사용 중 "권한 거부" 문제 해결하기
1. Docker 명령을 sudo를 통해 실행하기
2. 사용자를 Docker 그룹에 추가하기
$ sudo usermod -aG docker $USER
위 명령을 실행한 후에는 로그아웃하고 다시 로그인하거나, 시스템을 재부팅해야 변경사항이 적용됩니다.
docker run -d -p 8080:8080 myapp:0.0.1
docker run: Docker 이미지를 기반으로 새로운 컨테이너를 생성하고 실행하는 명령어입니다.
-d: 이 옵션은 "detached mode" 또는 "background mode"를 의미합니다. 이 옵션을 사용하면, Docker 컨테이너가 백그라운드에서 실행되며, 터미널은 즉시 반환됩니다.
-p 8080:8080: -p 옵션은 호스트와 컨테이너 사이에 네트워크 포트를 매핑합니다. 8000:8080은 호스트 시스템의 8080 포트를 Docker 컨테이너의 8080 포트에 연결하겠다는 의미입니다. 이렇게 하면 호스트 시스템을 통해 컨테이너의 애플리케이션에 접근할 수 있습니다.
myapp:0.0.1: Docker 컨테이너를 생성할 이미지의 이름과 태그를 지정합니다. 여기서는 myapp라는 이름의 0.0.1 버전 이미지를 사용하도록 지정하였습니다.
다음과 같이 컨테이너를 생성하고 실행하면, Docker 컨테이너가 백그라운드에서 spring boot 프로젝트가 실행되고 터미널은 즉시 반환됩니다.
$ curl localhost:8080/ 루트 경로로 요청하면, hello docker 바디 값을 리턴하여 프로젝트가 정상적으로 작동함을 알 수 있습니다.