본문 바로가기
트러블 슈팅

github actions 배포 스크립트 no such file or directory 에러

by CodingMasterLSW 2025. 7. 13.

오류상황

CI/CD 중 자동 배포 스크립트를 작성하던 중, no such file or directory라는 에러를 만남.

 

name: Java CI with Gradle

on:
  pull_request:
    branches: [ "dev" ]
  push:
    branches: [ "dev" ]

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read

    services:
      h2:
        image: oscarfonts/h2:latest
        ports:
          - 1521:1521
          - 8082:8082

    steps:
    - uses: actions/checkout@v4
    - name: JDK 21 설정
      uses: actions/setup-java@v4
      with:
        java-version: '21'
        distribution: 'temurin'

    - name: Gradle 설정
      uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582

    - name: Gradle Wrapper로 빌드 및 테스트 실행
      run: ./gradlew build

  deploy:
    name: Deploy to ECR Public
    needs: build
    if: github.ref == 'refs/heads/dev' && github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - name: AWS CLI 구성
        run: |
          aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws configure set region ${{ secrets.AWS_REGION }}

      - name: Docker ECR Public 로그인
        run: |
          aws ecr-public get-login-password --region ${{ secrets.AWS_REGION }} \
          | docker login --username AWS --password-stdin ${{ secrets.ECR_REPOSITORY_URI }}

      - name: Docker 이미지 빌드
        run: |
          docker build -t ${{ secrets.ECR_REPOSITORY }} .

      - name: Docker 태깅
        run: |
          docker tag ${{ secrets.ECR_REPOSITORY }}:latest ${{ secrets.ECR_REPOSITORY_URI }}/${{ secrets.ECR_REPOSITORY }}:latest

      - name: Docker 이미지 푸시
        run: |
          docker push ${{ secrets.ECR_REPOSITORY_URI }}/${{ secrets.ECR_REPOSITORY }}:latest

 

오류가 발생하는 부분은 아래 부분이다.

 - name: Docker 이미지 빌드
        run: |
          docker build -t ${{ secrets.ECR_REPOSITORY }} .

 

 

해당 코드에서 no such file or directory 에러가 발생하는데 이유가 뭘까?

 

우선 빌드 스크립트가 제대로 동작하는지부터 점검을 해보자.

    - name: Gradle Wrapper로 빌드 및 테스트 실행
      run: ./gradlew build

    - name: 빌드된 JAR 파일 확인 및 로그
      run: |
        echo "빌드 디렉토리 내용 확인 (build/libs):"
        ls -l build/libs/
        if [ -f build/libs/*SNAPSHOT.jar ]; then
          echo "✅ JAR 파일이 build/libs 경로에 성공적으로 생성되었습니다."
        else
          echo "❌ JAR 파일이 build/libs 경로에서 발견되지 않았습니다. 빌드 실패 가능성."
          exit 1
        fi

 

 

.jar 파일이 예상한 경로에 잘 생성이 되었는지 검증을 해보자.

 

 

build 과정에서는 특별한 문제를 발견하지 못했다... jar 파일이 정상적으로 잘 생성이 된다. 그렇다면 왜 docker build가 되지 않는 걸까?? deploy 작업의 시작점에도 해당 디버깅을 해보자.

deploy:
    name: Deploy to ECR Public
    needs: build
    if: github.ref == 'refs/heads/dev' && github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - name: 빌드된 JAR 파일 확인 및 로그
        run: |
          echo "빌드 디렉토리 내용 확인 (build/libs):"
          ls -l build/libs/
          if [ -f build/libs/*SNAPSHOT.jar ]; then
            echo "✅ JAR 파일이 build/libs 경로에 성공적으로 생성되었습니다."
          else
            echo "❌ JAR 파일이 build/libs 경로에서 발견되지 않았습니다. 빌드 실패 가능성."
            exit 1
          fi

 

놀랍게도 .jar 파일을 못 찾는다는 결과가 나온다.

 

왜 이런 오류가 발생했을까?

 

열심히 이유를 찾아본 결과,  각 Job은 별도의 독립된 가상머신에서 실행된다고 나와있다...

Each Github-hosted runner is a new virtual machine (VM) hosted by Github with the runner application and other tools ~~~...

 

정리하자면, build job 시점에서는 .jar 파일이 존재하지만, deploy job으로 넘어오는 순간 다른 VM이기 때문에 파일을 찾지 못하는 것!

 

해결방안 1) 아티펙트 기능 사용

Github Actions에서는 아티팩트(Artifacts) 기능을 제공해 준다.한 Job에서 생성된 파일을 GitHub Actions의 내부 저장소에 업로드하고, 다른 Job에서 필요한 파일을 다운로드하여 사용할 수 있게 해주는 좋은 기능이다.

    - name: Gradle Wrapper로 빌드 및 테스트 실행
      run: ./gradlew build

    - name: 빌드 아티팩트(JAR) 업로드
      uses: actions/upload-artifact@v4 # 아티팩트 업로드 액션 사용
      with:
        name: application-jar # 이 아티팩트의 이름. deploy Job에서 이 이름으로 다운로드합니다.
        path: build/libs/feed-zupzup-cicd-0.0.1-SNAPSHOT.jar
  deploy:
    name: Deploy to ECR Public
    needs: build
    if: github.ref == 'refs/heads/dev' && github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: 빌드 아티팩트(JAR) 다운로드
        uses: actions/download-artifact@v4 # 아티팩트 다운로드 액션 사용
        with:
          name: application-jar # build Job에서 업로드한 아티팩트 이름과 동일해야 합니다.
          path: .

 

 

해결방안 2) job 을 효율적으로 나누기

애초에 job 분배가 잘못되지 않았나? 싶다. 

 

서버 배포는 아직 AWS 계정을 받지 않아 나중에 하려고 했는데, 생각해 보니까 지금 Deploy에 있는 ECR에 이미지 올리는 작업이 CI에 적합하다는 생각을 했다.

 

 

내가 선택한 방법 : 해결방안 2

 

애초에 잘못된 테스트 분리였다...! test / CICD workflow 파일을 분리하는 게 좋은 전략인 것 같다. 

 

gradle-test.yml

name: Java CI with Gradle

on:
  pull_request:
    branches: [ "dev" ]

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read

    services:
      h2:
        image: oscarfonts/h2:latest
        ports:
          - 1521:1521
          - 8082:8082

    steps:
      - uses: actions/checkout@v4
      - name: JDK 21 설정
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'

      - name: Gradle 설정
        uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582

      - name: Gradle Wrapper로 빌드 및 테스트 실행
        run: ./gradlew clean test

 

gradle-ci.yml

name: Java CI with Gradle

on:
  push:
    branches: [ "dev" ]

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read

    services:
      h2:
        image: oscarfonts/h2:latest
        ports:
          - 1521:1521
          - 8082:8082

    steps:
    - uses: actions/checkout@v4
    - name: JDK 21 설정
      uses: actions/setup-java@v4
      with:
        java-version: '21'
        distribution: 'temurin'

    - name: Gradle 설정
      uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582

    - name: Gradle Wrapper로 빌드 및 테스트 실행
      run: ./gradlew build -x test      
        

    - name: AWS CLI 구성
      run: |
        aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws configure set region ${{ secrets.AWS_REGION }}
        
    - name: Docker ECR Public 로그인
      run: |
        aws ecr-public get-login-password --region ${{ secrets.AWS_REGION }} \
        | docker login --username AWS --password-stdin ${{ secrets.ECR_REPOSITORY_URI }}

    - name: Docker 이미지 빌드
      run: |
        docker build -t ${{ secrets.ECR_REPOSITORY }} .

    - name: Docker 태깅
      run: |
        docker tag ${{ secrets.ECR_REPOSITORY }}:latest ${{ secrets.ECR_REPOSITORY_URI }}/${{ secrets.ECR_REPOSITORY }}:latest

    - name: Docker 이미지 푸시
      run: |
        docker push ${{ secrets.ECR_REPOSITORY_URI }}/${{ secrets.ECR_REPOSITORY }}:latest

 

gradle 파일 분리하고, job 합치니까 잘 돌아간다!

 

+ 추가

하나의 Repository에서 backend / frontend 파일을 함께 관리하는 경우가 있다. (우테코 레포..)

그럴 경우, working-directory를 따로 명시해줘야 잘 돌아간다.

 

예시코드

      - name: Gradle Wrapper로 빌드 및 테스트 실행
        run: ./gradlew clean test
        working-directory: ./backend