오늘은 aws ecs fargat에 spring boot microservice를 code pipeline을 사용하여 배포하던 중 발생한 에러에 대해서 말해보려고 합니다.
발생 이슈
docker 이미지를 build 하던 중, 계속 COPY failed: no source files were specified
라는 에러를 발생시키고 있었습니다.
해결 과정
1. build 파일의 경로를 찾지 못하는 경우
보통 해당 문제에 대해 구글 검색으로 찾아보면, docker image를 build하기 전 프로젝트를 build하지 않아 build 파일 경로를 찾지 못하는 것이 대부분이었습니다. 저의 경우는 gradlew clean build
를 통해 build와 jar 파일의 경로를 확인하였기에 해당되지가 않았습니다.
2. docker build 시, context 문제
일반적인 검색으로는 위의 경우가 거의 대부분이어서 도움을 받지 못했습니다. 그래서 docker 공식 문서 중, docker build와 COPY에 대해 살펴보았습니다 (역시 공식문서를 먼저 볼껄 그랬습니다.😥)
docker build
문서의 첫문장을 보면 다음과 같이 나와 있습니다.
즉, docker의 image를 build하려면 Dockerfile과 context가 필요하다고 합니다. 그리고 COPY
지시자는 context 내부의 파일을 참조할 수 있습니다. 한마디로 context 위치가 잘못 정해진다면 COPY를 못하는 상황이 올 수 있다는 것입니다.
그렇다면 context 위치는 어디가 될까요?
Context의 위치
context는 특정한 PATH
나 git 등의 URL
에 위치한 폴더를 이야기 합니다. 간단히 말해 docker build
를 실행한 시점의 현재 디렉토리가 됩니다.
예를들어, 아래와 같은 폴더 구조와 Dockerfile이 있다고 가정해 보겠습니다.
microservice
ㄴ game
ㄴ Dockerfile
ㄴ ...
FROM openjdk:8-jre-alpine
WORKDIR app
EXPOSE 8080
COPY ./build/libs/*.jar app.jar
CMD ["java","-jar","app.jar"]
현재 microservice라는 디렉토리에서 game이라는 디렉토리로 옮겨서 빌드를 해보면 다음과 같습니다.
// 현재 microservice 디렉토리
cd game
docker build -f Dockerfile .
이때 build라는 명령어를 game 디렉토리에서 실행했기 때문에 .
가 가르키는 context
는 game 디렉토리 내부가 됩니다.
(docker build -f Dockerfile .
는 docker build .
과 같습니다.)
만약에 microservice라는 디렉토리에서 game 디렉토리의 Dockerfile을 빌드하면 다음과 같습니다.
// 현재 microservice 디렉토리
docker build -f game/Dockerfile .
이때 build라는 명령어를 microservice이라는 디렉토리에서 실행했기 때문에 .
가 가르키는 context
는 microservice 디렉토리 내부가 됩니다. 즉, docker build
명령어를 실행한 시점의 현재 디렉토리가 context가 되게 됩니다. docker build
문서에서도 아래와 같이 COPY <src> <dest>
를 사용할 때 src는 반드시 build의 context 내부에 있어야 한다고 합니다.
이제 저의 문제를 살펴보겠습니다.
해결법
아래는 첫번째 game 디렉토리에서 build를 한 경우입니다.
docker build
라는 명령어를 game
에서 실행하였으므로 context는 game
디렉토리가 됩니다. 절차를 보면 다음과 같습니다.
docker build .
실행- Dockerfile 읽음
- Dockerfile 내부의 COPY 명령어로 현재 context(game 디렉토리)에서
./build/libs/*.jar
를 찾음 - game 디렉토리 내부에는
./build/libs/*.jar
파일이 있으므로 컨테이너로 복사
이렇게 잘 실행됨을 알 수 있습니다.
이제 두번째 microservice 디렉토리에서 game을 build한 경우입니다.
docker build
라는 명령어를 microservice
에서 실행하였으므로 context는 microservice
디렉토리가 됩니다. 절차를 보면 다음과 같습니다.
docker build -f game/Dockerfile .
실행- Dockerfile 읽음
- Dockerfile 내부의 COPY 명령어로 현재 context(microserivce 디렉토리)에서
./build/libs/*.jar
를 찾음 - 하지만 microservice 폴더 내부에는 game 디렉토리만 있으므로 Dockerfile은 존재하지 않는다
이때 COPY failed: no source files were specified
가 발생하게 됩니다. 이처럼 COPY
시점에서 docker build
명령어를 실행한 디렉토리(context)에서 파일을 찾지 못해서 발생하는 에러가 됩니다.
저는 아래와 같이 Dockerfile
내부의 COPY build/libs/*.jar app.jar
를 COPY game/build/libs/*.jar app.jar
로 바꾸어서 docker가 호스트의 파일을 찾을 수 있도록 하였습니다.
아래와 같이 빌드 되는 것을 볼 수 있습니다.
후기
docker의 context에 대해 알아 보았습니다. 저는 지금까지 docker context
명령어의 context를 이야기 하는 줄 알았는데 지금까지 잘 못 알고 있었던 것 같습니다. docker context
와 어떤 연관관계가 있는건지 다음에 알아봐야 될 것 같습니다 (알고 계신 분이 계시면 알려주시면 감사하겠습니다😄).