실행중인 터미널 위치에서 Dockerfile을 실행한다면 굉장히 쉽게 명령어를 통해 이미지를 build할 수 있다.
docker build -t my-java-app .
하지만 실제 Docker 프로젝트를 진행하다보면 다른 경로에 DockerFile들을 보관해야 하는 경우가 생긴다.
java application에서 build후 프로젝트 root에 build/libs/app.jar 생성된 jar 파일을 Docker image로 빌드하는 작업을 수행한다고 하자. 이 때 해당 경로에 있는 app.jar를 COPY하며 실행 가능한 EntryPoint를 만든 이미지이다.
해당 Dockerfile의 예시이다.
# root/docker/java/Dockerfile-java
FROM openjdk:11-jdk-slim
WORKDIR /app
COPY build/libs/app.jar app.jar
ENV SERVER_MODE default
ENV PORT 8000
ENV LOCATION "/"
ENTRYPOINT ["java","-Dserver.port=${PORT}","-Dspring.profiles.active=${SERVER_MODE}", "-jar", "app.jar", "--spring.config.location=${LOCATION}"]
해당 Dockerfile은 root/docker/java/Dockerfile-java에 위치한다.
COPY는 build/libs/app.jar 를 요청하고 있다. COPY의 현재 경로는 root일 것이다. 만약 우리가 build 명령어를 사용하려면 어떻게 요청해야 할까?
만약 root 경로에 있다면
docker build -t myapp -f /docker/java/Dockerfile-java .
마지막 .은 docker-compose의 context라 보면 된다. 현재 경로 기준으로 실행되어야 하므로 .을 적는다
만약 root/docker/java 경로에서 실행한다면 어떻게 될까?
docker build -t myapp -f Dockerfile-java .
이렇게 설정하고 Dockerfile의 COPY 경로 앞에 ../../ 를 추가하면 이론상 될 것같다. 하지만 COPY를 실패한다. 그 이유는 마지막에 context가 .이면 root의 폴더는 캐치하지 못하고 root/docker/java 경로의 파일만 캐치한다. 그렇기 때문에 전혀 root/build를 인식할 수 없다. 가장 좋은 방법은 다음과 같다.
docker build -t myapp -f Dockerfile-java ../../
실행 경로 context을 root로 인식하게 되면 root 하위 디렉토리와 파일을 캐칭하기 때문에 동작하게 된다. 이것은 docker-compose.yml에서도 동일하게 적용된다.
version: "3"
services:
java-api-server:
build:
context: ./docker/java
dockerfile: Dockerfile-java
ports:
- "8080:8080"
environment:
PORT: 8080
해당 코드는 실패한다. ./build를 인식하지 못하기 때문이다. 이를 다음과 같이 바꾸면 동작한다.
version: "3"
services:
java-api-server:
build:
context: ./
dockerfile: ./docker/java/Dockerfile-java
ports:
- "8080:8080"
environment:
PORT: 8080