Oracle Cloud Free Tier 서버 디스크가 76% 차서 21GB 회수한 과정 — Docker 빌드 캐시가 범인이었다

서버에 SSH 로 들어갔다가 무심코 친 df -h 한 줄에 가슴이 철렁했다.

/dev/sda1   45G   34G used   12G avail   76%

Oracle Cloud Always Free 의 컴퓨트 인스턴스는 디스크가 45GB 가 전부다. 76% 면 임계점인 80% 까지 4GB 남짓. 다음 주에 docker 이미지 한두 개만 더 받아도 가용 공간이 모자라 컨테이너가 죽을 수 있는 구간이었다.

급한 마음에 du -sh /home/ubuntu/* 부터 돌렸는데 가장 큰 디렉토리가 273MB. 홈 디렉토리는 무죄였다. 그렇다면 누가 30GB 가 넘는 공간을 차지하고 있는 걸까.

이번 글은 그 범인을 찾아내고, 재부팅 없이 21GB 를 회수해서 디스크 사용량을 76% → 27% 로 떨어뜨린 과정을 그대로 기록한 것이다.

1. 진짜 범인 찾기 — docker system df

서버에서 n8n / mariadb / 작은 사이드카 컨테이너 몇 개가 24시간 돌고 있다. Docker 가 의심됐다.

$ docker system df
  TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
  Images          7         3         20.71GB   15.84GB (76%)
  Containers      3         3         57.26MB   0B (0%)
  Local Volumes   1         1         218.3MB   0B (0%)
  Build Cache     86        0         18.06GB   17.69GB

답이 나왔다.

  • Build Cache 가 18GB, 그것도 98% 가 회수 가능한 상태
  • Image 가 20.7GB, 그 중 15.8GB 는 사용 안 하는 dangling/old 이미지

Docker 만으로 약 33GB. 디스크 전체 사용량의 거의 전부였다. 코드도, 로그도, 백업도 아닌, 빌드 캐시와 옛 이미지가 범인이었던 것이다.

2. 가장 안전한 한 줄 — docker builder prune

빌드 캐시는 다음 docker build 때 다시 만들어진다. 즉, 지워도 동작 중인 컨테이너에 0의 영향을 준다. 가장 먼저 정리해야 할 1순위다.

$ docker builder prune -af
  ...
  Total: 18.06GB

명령 한 줄에 18GB 가 사라졌다. df -h 를 다시 쳐 보니 디스크는 76% → 43%.

여기서 끝내도 사실 당장의 위기는 끝났지만, 이미지 prune 까지 가면 추가로 더 회수할 수 있다.

3. 옛 이미지 정리 — docker image prune -a

-a 플래그는 dangling 뿐 아니라 현재 컨테이너가 쓰지 않는 모든 이미지를 제거한다. 단 실행 중인 컨테이너의 이미지는 자동 보존이므로 안전하지만, 옛 버전을 롤백 용도로 남겨뒀다면 잃을 수 있다. 한 번 확인하고 진행.

$ docker image prune -af
  Deleted Images:
    - ghcr.io/openclaw/openclaw:latest   (안 쓰는 옛 버전)
    - my_youtube/youtube-helper:0.1.0    (현재 0.2.0 사용 중)
    - alpine:latest, hello-world:latest  (베이스/테스트용)
  Total reclaimed space: 1.137GB

1.1GB 추가 회수. 남은 이미지는 실제 운영 중인 3개 뿐. 디스크는 43% → 33%.

4. 시스템 캐시도 차곡차곡 — journal / npm / apt

Docker 만큼은 아니지만 시스템 캐시도 야금야금 자란다. 27일 무중단 운영의 결과로 systemd journal 이 1.4GB 까지 쌓여 있었다.

$ sudo journalctl --vacuum-size=200M
  Vacuuming done, freed 1.1G of archived journals.

  $ npm cache clean --force
  $ du -sh ~/.npm
  66M    # 직전 1.1GB → 66MB

  $ sudo apt clean
  $ du -sh /var/cache/apt/archives
  32K    # 직전 14MB → 32KB

합계 약 2.1GB 추가 회수. 디스크는 33% → 28%.

5. “_old” 라는 이름의 디렉토리는 거의 항상 정리 대상이다

마지막으로 홈 디렉토리에 openclaw_old/ 라는 273MB 짜리 폴더가 있었다. 이름이 _old 면 거의 99% 백업이다. 다만 확인 없이 삭제하면 안 된다.

$ ls /home/ubuntu/openclaw_old/.env
  -rw-------  1 ubuntu ubuntu 471 Feb 21 .env  # 자격증명 들어있음

.env 파일에 자격증명이 있어서 한 번 더 의심. 운영 중인 서비스가 이 자격증명을 쓰는지 비교해 봤더니, 토큰이 옛 값이었다. 운영본은 npm global 로 다른 경로에서 돌고 있었고 이 디렉토리와 무관했다.

$ rm -rf /home/ubuntu/openclaw_old
  $ df -h /
  /dev/sda1  45G  12G  33G  27%

27%. 처음의 12GB 가용에서 33GB 가용으로 바뀌었다.

6. 다음 정비 큐 — 재부팅 일정에 묶어둘 것

이번에 손대지 않고 남겨둔 항목들.

  • 옛 커널 linux-image-6.8.0-1047-oracle — 현재 이 커널로 가동 중이라 못 지움. 신규
    커널 -1050 이 설치만 돼 있고 부팅을 안 한 상태. 재부팅 일정이 잡힐 때 sudo apt autoremove 로 1047 제거하면 약 300MB 회수.
  • snap 옛 revisionsudo snap set system refresh.retain=2 로 기본 3 → 2 로 줄이면
    점진적으로 자동 정리.
단계명령회수
Docker 빌드 캐시docker builder prune -af18 GB
Docker 옛 이미지docker image prune -af1.1 GB
systemd journaljournalctl --vacuum-size=200M1.1 GB
npm 캐시npm cache clean --force1 GB
apt 캐시apt clean14 MB
openclaw_old/rm -rf273 MB
합계~22 GB

디스크는 76% → 27%, 가용 공간은 12GB 에서 33GB 로 늘었다. 재부팅도, 컨테이너 재기동도 없이 운영 중에 끝낸 작업이다.

교훈 한 줄

디스크가 차오를 때 가장 먼저 의심할 곳은 /home/var/log 도 아닌 Docker 다. docker system df 한 번이면 5초 안에 범인이 보인다. 그리고 docker builder prune -af 는 운영 중 시스템에 언제 돌려도 안전한 한 줄짜리 청소 도구다. 이번처럼 빌드 캐시 하나로만 18GB 가 나오는 경우가 흔하다.

다른 자동화 노트들 — n8n 도메인 연결, Telegram 봇 충돌, YouTube 자막 차단 진단 — 도 시리즈로 차례로 정리 중이다.

참고 자료

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤