PEANUT 프로젝트를 진행하면서, 프론트엔드와 연결하여 테스트할 목적으로 배포를 계획했습니다. 단순히 테스트용 배포였기에 AWS EC2 서버에 Docker를 활용해 배포를 진행하려 했지만, 추후 수정 사항이 자주 발생할 것으로 예상되어 배포 과정이 번거로워질 수 있었습니다. 이를 해결하기 위해, CI/CD 파이프라인을 구축하여 자동화된 배포 환경을 마련하고자 GitHub Actions를 선택했습니다.
com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line X column Y path $ ...
처음에는 그냥 scret파일에 Fcm설정 JSON의 내용들을 저장하고, 다음과 같이 워크플로우 스크립트를 작성했습니다.
- name: Prepare Firebase JSON
run: |
mkdir src/main/resources/firebase/
echo -e "${{ secrets.PEANUT_FIREBASE_CREDENTIALS }}" > src/main/resources/firebase/peanut-bc734-firebase-adminsdk-bsc10-1d0f1c01e4.json
그런데 위와 같은 에러가 나왔습니다. ${{ secrets.PEANUT_FIREBASE_CREDENTIALS }}에 저장된 내용을 그대로 출력하여 파일에 저장하지만, 만약 PEANUT_FIREBASE_CREDENTIALS에 저장된 값이 잘못된 형식의 JSON이라면, 생성된 파일 역시 잘못된 JSON 형식이 됩니다. 이로 인해 이후 Firebase 설정에서 JSON 파일을 읽을 때 오류가 발생합니다. 즉, 잘못된 JSON 파일이 생성되었고, 다양한 방법으로 수정을 해보아도 동일한 문제가 발생했습니다.
- name: Create Firebase JSON directory
run: |
mkdir -p src/main/resources/firebase/
- name: create-json
id: create-json
uses: jsdaniell/create-json@v1.2.2
with:
name: "emptyAdminSDK.json"
json: ${{ secrets.FIREBASE_JSON }}
dir: 'src/main/resources/firebase/'
jsdaniell/create-json Action은 내부적으로 JSON 문자열을 검증하고, 이를 파일로 저장합니다.따라서, $ { { secrets.FIREBASE_JSON } }에 잘 형식화된 JSON이 저장되어 있다면, 이 Action이 JSON 형식에 맞게 파일을 생성하게 됩니다.
이 Action은 JSON 형식이 잘못된 경우 오류를 발생시키고, 올바르지 않은 JSON을 처리할 수 있는 내부 로직을 갖추고 있습니다.
즉, 이전에 사용한 echo 명령어는 단순히 문자열을 파일로 저장하는 것이기 때문에, 형식 검증이 없었습니다. 반면, create-json Action은 JSON을 생성하는 과정에서 형식 문제를 자동으로 처리합니다.
지정된 dir 경로에 JSON 파일을 생성하여, 프로젝트의 파일 구조에 맞춰 파일이 저장됩니다. 이는 나중에 Firebase 설정에서 해당 파일을 쉽게 찾을 수 있도록 합니다.
# 1. Java 11을 베이스 이미지로 사용
FROM openjdk:11-jre-slim
# 2. 애플리케이션 디렉토리 설정
WORKDIR /app
# 3. 빌드된 JAR 파일을 컨테이너로 복사
COPY target/Peanut-0.0.1-SNAPSHOT.jar app.jar
# 4. 설정 파일 복사
COPY config/application.properties /app/config/application.properties
COPY src/main/resources/firebase/peanut-bc734-firebase-adminsdk-bsc10-1d0f1c01e4.json /app/src/main/resources/firebase/peanut-bc734-firebase-adminsdk-bsc10-1d0f1c01e4.json
# 5. 포트 설정 (Spring Boot의 기본 포트)
EXPOSE 8080
# 6. JAR 파일 실행
ENTRYPOINT ["java", "-jar", "app.jar", "--spring.config.location=/app/config/application.properties"]
에서 Docker 컨테이너 내의 작업 디렉토리를 /app으로 설정하여 /app/firebase/파일이름.json 파일이 잘 저장이 되는 것을 확인했습니다.
그러나 아래와 같은 오류가 발생했습니다.
[void]: Factory method 'initializeFirebaseApp' threw exception; nested exception is java.lang.IllegalArgumentException:
Firebase JSON file is empty
오류를 확인하면 Firebase JSON 파일이 비어있다는 것입니다. 시크릿파일에 JSON을 넣었지만 왜 JSON파일이 비어있다는 것인가?에 대한 의문을 가지고, 처음부터 작성한 파일을 보았습니다.
제가 시크릿 파일을 저장할 땐 아래와 같은 이름으로 저장하지만,

스크립트를 확인하면 ${{ secrets.FIREBASE_JSON }} 이렇게 저장이 되어있었습니다. 수정한다고 한 것을 놓친 실수 였습니다.
- name: Create Firebase JSON
id: create-json
uses: jsdaniell/create-json@v1.2.2
with:
name: "peanut-bc734-firebase-adminsdk-bsc10-1d0f1c01e4.json"
json: ${{ secrets.FIREBASE_CREDENTIALS }}
dir: '/src/main/resources/firebase/'
이렇게 수정 후 워크 플로우를 다시 실행하니 오류 없이 배포가 완료 되었습니다.

# 1. Java 11을 베이스 이미지로 사용
FROM openjdk:11-jre-slim
# 2. 애플리케이션 디렉토리 설정
WORKDIR /app
# 3. 빌드된 JAR 파일을 컨테이너로 복사
COPY target/Peanut-0.0.1-SNAPSHOT.jar app.jar
# 4. 설정 파일 복사
COPY config/application.properties /app/config/application.properties
COPY src/main/resources/firebase/peanut-bc734-firebase-adminsdk-bsc10-1d0f1c01e4.json /app/src/main/resources/firebase/peanut-bc734-firebase-adminsdk-bsc10-1d0f1c01e4.json
# 5. 포트 설정 (Spring Boot의 기본 포트)
EXPOSE 8080
# 6. JAR 파일 실행
ENTRYPOINT ["java", "-jar", "app.jar", "--spring.config.location=/app/config/application.properties"]
name: Build and Deploy to Ubuntu Server
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: "17"
distribution: "temurin"
- name: Prepare application.properties
run: |
mkdir config
echo "${{ secrets.PEANUT_APP_PROPERTIES }}" > config/application.properties
- name: Create Firebase JSON directory
run: |
mkdir -p src/main/resources/firebase/
- name: Create Firebase JSON
id: create-json
uses: jsdaniell/create-json@v1.2.2
with:
name: "peanut-bc734-firebase-adminsdk-bsc10-1d0f1c01e4.json"
json: ${{ secrets.PEANUT_FIREBASE_CREDENTIALS }}
dir: 'src/main/resources/firebase/'
- name: Build with Maven
run: mvn clean package -DskipTests
- name: Check if jar file exists
run: |
echo "Contents of target directory:"
ls -la target
if [ ! -f target/Peanut-0.0.1-SNAPSHOT.jar ]; then
echo "Error: Jar file not found!"
exit 1
fi
- name: Docker build and push
run: |
docker login -u ${{ secrets.PEANUT_DOCKER_REPO }} -p ${{ secrets.PEANUT_DOCKER_KEY }}
docker build -t ${{ secrets.PEANUT_DOCKER_REPO }}/peanut-backend:latest .
docker push ${{ secrets.PEANUT_DOCKER_REPO }}/peanut-backend
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to Ubuntu Server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.PEANUT_HOST }}
username: ${{ secrets.PEANUT_USERNAME }}
key: ${{ secrets.PEANUT_SSH_PRIVATE_KEY }}
script: |
sudo docker network create peanut || true
sudo docker stop peanut-backend || true
sudo docker rm peanut-backend || true
sudo docker pull ${{ secrets.PEANUT_DOCKER_REPO }}/peanut-backend:latest
sudo docker run -d -p 8080:8080 --net peanut --name peanut-backend ${{ secrets.PEANUT_DOCKER_REPO }}/peanut-backend:latest


이렇게 도커와 깃액션으로 배포 자동화를 진행하였습니다. 다음에는 스터디한 GItLab과 ECR,ECS를 활용한 배포로 다시 해볼 예정입니다.