Search

Github Action Ubuntu runner 디스크 공간 확보하기

No space left on device

Github Action 워크플로 스크립트에서 runner: ubuntu-latest 를 사용하여 컨테이너 이미지를 빌드하다가 만난 오류이다.
github action의 기본 ubuntu runner의 디스크 크기가 그리 넉넉하진 않다(14GB):
더 큰 runnner가 있다:
Processor (CPU)
Memory (RAM)
Storage (SSD)
Operating system (OS)
4
16 GB
150 GB
Ubuntu
8
32 GB
300 GB
Ubuntu, Windows
16
64 GB
600 GB
Ubuntu, Windows
32
128 GB
1200 GB
Ubuntu, Windows
64
256 GB
2040 GB
Ubuntu, Windows
(스토리지 엄청 넉넉하네; 역시 기본 runner만 빡빡한건가) 하지만 github action의 과금 체계는 vCPU 수에 비례하기 때문에 비용이 늘어난다:

검색

github action runner no space left on device 로 검색해보면 역시나 똑같은 고통을 받았던 사람들이 있다:
여기서 몇 가지 힌트를 얻었다.
runner의 디스크 사용량을 들여다 볼 필요가 있다는 것(df -h)
채택된 답변처럼 사용하지 않는 불필요한 것을 삭제하면 되겠다는 것
그리고 이것과 관련한 좋은 사례를 찾았다:

구현

전사에 제공하는 build/push 용 composite 워크플로에 적용하자. 먼저 df -h 로 디스크 사용량을 확인한다:
name: Docker Image Build and Push description: ... inputs: ... debug: description: "Debug mode" required: false default: "" ... runs: using: "composite" steps: - name: Check disk if: ${{ inputs.debug == 'true' }} shell: bash run: df -h ...
YAML
복사
모든 run 마다 불필요한 로그를 남기지 않기 위해 debug 입력을 추가하고 활성화 되었을 때만 실행하도록 했다. 이렇게 출력한 현재 ubunu-latest(22.04) runner의 디스크는 다음과 같다:
> Run df -h Filesystem Size Used Avail Use% Mounted on /dev/root 84G 60G 25G 72% / tmpfs 3.4G 172K 3.4G 1% /dev/shm tmpfs 1.4G 1.1M 1.4G 1% /run tmpfs 5.0M 0 5.0M 0% /run/lock /dev/sdb15 105M 6.1M 99M 6% /boot/efi /dev/sda1 14G 4.1G 9.0G 31% /mnt tmpfs 693M 12K 693M 1% /run/user/1001
Bash
복사
여유 공간 25G. 문서의 14GB 보단 많다. 그리고 전체 디스크 크기는 80G 였다. 무엇에 이렇게 많이 쓰고 있을지 확인해본다:
steps: ... - name: List packages if: ${{ inputs.debug == 'true' }} shell: bash run: | echo "Listing 100 largest packages" dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -n | tail -n 100 - name: List largest directories under /usr if: ${{ inputs.debug == 'true' }} shell: bash run: | echo "Listing 100 largest directories under /usr" sudo du -ah /usr | sort -h | tail -n 100 ...
YAML
복사
위에서 링크한, flink에서 사용하는 free_disk_space.sh을 참고하여 크기가 큰 패키지와 디렉토리를 확인한다. 디렉토리를 /usr/ 아래를 검사하는 것은 다른 시스템 디렉토리는 괜히 건드리지 않기 위함 같다. 결과의 일부를 공유하면:
> Run echo "Listing 100 largest packages" Listing 100 largest packages ... 199815 temurin-8-jdk 208517 gcc-13 240557 firefox 251340 llvm-13-dev 270995 llvm-14-dev 293154 llvm-15-dev 317409 temurin-11-jdk 322796 temurin-17-jdk 326369 google-chrome-stable 337404 dotnet-sdk-6.0 351993 temurin-21-jdk 390274 dotnet-sdk-8.0 403092 dotnet-sdk-7.0 555711 microsoft-edge-stable 783977 azure-cli 785565 google-cloud-cli > Run echo "Listing 100 largest directories under /usr" Listing 100 largest directories under /usr ... 1.9G /usr/share/swift 1.9G /usr/share/swift/usr 2.0G /usr/local/.ghcup/ghc/9.6.3/lib 2.0G /usr/local/.ghcup/ghc/9.6.3/lib/ghc-9.6.3 2.0G /usr/local/.ghcup/ghc/9.8.1/lib 2.0G /usr/local/.ghcup/ghc/9.8.1/lib/ghc-9.8.1 2.0G /usr/local/lib/android/sdk/ndk/24.0.8215888/toolchains 2.0G /usr/local/lib/android/sdk/ndk/24.0.8215888/toolchains/llvm 2.0G /usr/local/lib/android/sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt 2.0G /usr/local/lib/android/sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux-x86_64 2.0G /usr/local/lib/android/sdk/ndk/26.1.10909125/toolchains 2.0G /usr/local/lib/android/sdk/ndk/26.1.10909125/toolchains/llvm 2.0G /usr/local/lib/android/sdk/ndk/26.1.10909125/toolchains/llvm/prebuilt 2.0G /usr/local/lib/android/sdk/ndk/26.1.10909125/toolchains/llvm/prebuilt/linux-x86_64 2.1G /usr/local/lib/android/sdk/ndk/26.1.10909125 2.2G /usr/local/lib/android/sdk/ndk/24.0.8215888 2.6G /usr/local/.ghcup/ghc/9.6.3 2.7G /usr/local/.ghcup/ghc/9.8.1 2.9G /usr/lib 2.9G /usr/local/lib/android/sdk/build-tools 4.8G /usr/share 5.3G /usr/local/.ghcup 5.3G /usr/local/.ghcup/ghc 5.8G /usr/local/lib/android/sdk/ndk 12G /usr/local/lib/android 12G /usr/local/lib/android/sdk 14G /usr/local/lib 23G /usr/local 33G /usr
Bash
복사
결과와 참고 스크립트를 대조하면 어떤 패키지가 그리고 어떤 디렉토리가 도커 이미지 빌드 시 필요치 않지만 크기가 큰지 파악할 수 있다. 따라서 현재 ubuntu-latest runner에선 다음과 같이 삭제하고 사용하기로 했다:
inputs: ... large-image: description: "Large image" required: false default: "" ... steps: ... # ref. https://github.com/apache/flink/blob/master/tools/azure-pipelines/free_disk_space.sh#L28-L53 - name: Free unused disk space if: ${{ inputs.large-image == 'true' }} shell: bash run: | # delete packages sudo apt-get remove -y '^dotnet-.*' sudo apt-get remove -y '^llvm-.*' sudo apt-get remove -y '^temurin-.*' sudo apt-get remove -y '^mysql-server-core-.*' sudo apt-get remove -y '^postgresql-.*' sudo apt-get remove -y azure-cli google-chrome-stable google-cloud-cli firefox powershell microsoft-edge-stable mono-devel sudo apt-get autoremove -y sudo apt-get clean # delete directories sudo rm -rf /usr/share/dotnet/ sudo rm -rf /usr/share/swift sudo rm -rf /usr/share/miniconda sudo rm -rf /usr/local/graalvm/ sudo rm -rf /usr/local/.ghcup/ sudo rm -rf /usr/local/share/powershell sudo rm -rf /usr/local/share/chromium sudo rm -rf /usr/local/lib/android sudo rm -rf /usr/local/lib/node_modules
YAML
복사
결과적으로 이 작업은 large-image 라는 입력 플래그로 실행 여부를 제어했다. 시간이 꽤 걸리기 때문. 검색 결과에서 타고타고 들어가다가 위 스크립트를 만났지만, github action ubuntu runner에 어떤 패키지를 설치하는지도 확인할 수 있었다:
Operating system
Package manager
Third-party repos and packages
Ubuntu
ansible-coreyamllint

결과

다시 한번 df -h 했을 때, 기존 대비 약 40%, 31G의 디스크 공간을 확보하게 됐다:
> Run df -h Filesystem Size Used Avail Use% Mounted on /dev/root 84G 28G 56G 34% / tmpfs 3.4G 172K 3.4G 1% /dev/shm tmpfs 1.4G 1.2M 1.4G 1% /run tmpfs 5.0M 0 5.0M 0% /run/lock /dev/sdb15 105M 6.1M 99M 6% /boot/efi /dev/sda1 14G 4.1G 9.0G 31% /mnt tmpfs 693M 12K 693M 1% /run/user/1001
Bash
복사
56G 정도의 여유 공간이면 도커 이미지 빌드하는데에 문제 없겠지…?

습득 교훈

지금은 large-image 라는 플래그 인자로 디스크 공간 확보(불필요한 패키지 및 디렉토리 삭제)를 한다. self-hosted runner로 더 최적화 할 수 있을지 고민해볼 수 있다(처음에 비교했을 땐 github hosted runner가 사용 + 관리 비용에서 더 이점이 있다고 판단했다).