DevOps/Docker

[Docker] 로컬에서 성공했지만 도커로 배포 시 [No such file or directory] 오류

ysg 2023. 3. 24. 15:46

Firebase 클라우드 메시징(FCM)을 이용하는 서버를 개발하고, 로컬에서 실행 성공 후 도커를 이용하여 aws ec2에 배포하였습니다. 

 

빌드는 성공했지만 실행 시 로그에 자꾸 아래와 같은 에러가 떴습니다.

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.google.firebase.FirebaseApp]: Factory method 'firebaseApp' threw exception; nested exception is java.io.FileNotFoundException: src/main/resources/파일이름.json (No such file or directory)

 

FCM을 사용하기 위해 FirebaseAdminsdk.json 파일이 필요한데 이 파일을 계속 못가지고 온다는 에러였습니다.

여러가지 삽질 후에 도커와 관련된 문제임을 깨달았습니다.

 

도커 내부에서는 파일시스템이 독립적으로 구성되어 있기 때문에, 도커 내부에서 파일을 사용할 때는 호스트 머신에서의 파일 경로와는 다른 경로를 사용해야 합니다.

 

일반적으로는 Dockerfile 내부에 복사 명령어를 이용하여 호스트 머신에서의 파일을 도커 내부로 복사한 후에 사용합니다.

그리고 이때 복사한 파일은 도커 컨테이너 내부의 원하는 경로에 위치시켜야 합니다. 

 

ex)

COPY ./src/main/resources/파일이름.json ./src/main/resources/

하지만 이 방법은 파일의 크기가 크거나, 파일이 자주 변경되는 경우 유지보수에 어려움이 있을 수 있습니다.

이러한 문제를 해결하기 위해 도커에서는 '볼륨(Volume)' 기능을 제공합니다.

 

볼륨은 도커 호스트와 컨테이너 간의 데이터 공유를 가능하게 하는 도커 내장 기능입니다. 컨테이너가 종료되어도 데이터를 보존할 수 있으며, 호스트와 컨테이너 간의 파일 공유가 쉬워지는 등의 장점이 있습니다.

 

Docker Compose를 사용하여 여러 개의 컨테이너를 실행할 때, volumes 옵션을 사용하여 호스트와 컨테이너 간의 디렉토리를 공유할 수 있습니다.

 

ex)

docker-compose.yaml

version: "3.7"
services:
  pushalert:
      build:
        context: .
        dockerfile: Dockerfile
      ports:
        - "81:8080"
      volumes:
     	- ./app:/app
      command: [ "./gradlew", "bootrun" ]
      restart: always
      extra_hosts:
        - "host.docker.internal:host-gateway"

위 예시의 경우 호스트의 ./app 디렉토리와 컨테이너 내부의 /app 디렉토리를 공유합니다. 

따라서 호스트에서 ./app 디렉토리에 파일을 추가하거나 수정하면, 컨테이너 내부의 /app 디렉토리에서도 해당 파일을 사용할 수 있습니다.

 

이렇게 볼륨을 사용하면 컨테이너 간의 데이터 공유가 용이해지며, 호스트와 컨테이너 간의 파일 공유도 쉬워집니다.