집에 안쓰는 구형 맥북이 있다.
MacBook Pro 2017
CPU : i5 어쩌구 인가? 기억 안남
RAM : 8GB
GPU : 모름 아무튼 내장 그래픽
SSD : 256GB 인가 아무튼 그쯤
이 정도 스펙인데 집에서 뒹굴거리길래 홈서버를 구축해서 요긴하게 써먹고 있다.
홈서버를 구축하면서
물론 CI/CD 구축할땐 그냥 AI로 짰다.
그냥 아하 이렇게 하는 거구나? 하는 느낌
그런데..
그런데 어느 순간부터 배포하려고 PR 날리면 Actions가 너무 오래 돌다가 timeout 나기 시작했다.

이것 저것 찔러보면서 해결하려고 애쓴 모습
AI로 코드를 짰으므로, 클로드 열심히 돌려가면서 원인을 찾으려고 애썼지만 문제는 지속됐다.
그래서 찾은 문제의 원인은 바로 ...
💡 OOM Out Of Memory
메모리가 터진 것이였다.
8GB RAM 사용 현황:
macOS: ~3GB
Colima VM: ~1GB
기존 컨테이너들: ~1GB
Maven 빌드: ~2GB+
─────────────────────
합계: 7GB+ → OOM → Colima VM 강제 종료 → docker ps 블로킹
내 맥북은 구형이기 때문에 Docker가 해당 os버전까지 지원해주지 않는다. (건방지게)
그래서 Colima라는 Linux 가상 머신을 띄워서 도커를 띄우고 있었다.
그게 리소스를 꽤 먹는데다가 컨테이너도 왕창 띄워놨었다.
그리고 결정적으로 빌드 자체를 홈서버에서 하고 있었다
그 커다란 maven 의존성 덩어리를 배포할때마다 빌드하고 있었으니 간당간당했던 내 맥북이 뻗어버린 것이다.
정리하자면
그래서 이 참에 그냥 CI/CD 과정을 배워보기로 했다.
📝
CI (Continuous Integration) — 코드를 push할 때마다 자동으로 빌드·테스트
CD (Continuous Deployment) — CI 통과 후 자동으로 서버에 배포git push 하나로 → 빌드 → 테스트 → 배포 전부 자동화
결국 푸시만 하면 알잘딱 빌드와 테스트, 배포까지 해주는 아주 똘똘한 방식이다.

steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
- name: Build JAR
run: mvn package -DskipTests -q && cp target/*.jar app.jar
- name: SCP JAR to server # JAR를 홈서버로 전송
uses: appleboy/scp-action@v0.1.7
with:
source: "app.jar"
target: ${{ secrets.DEPLOY_PATH }}
- name: Deploy via SSH # ssh로 홈서버 접속
uses: appleboy/ssh-action@v1.0.3
with:
script: |
cd ${{ secrets.DEPLOY_PATH }}
git pull origin main
docker compose up -d --build # 💥 홈서버에서 Docker 빌드 → OOM
이 방식에 문제점이 있다면
1. 서버에서 빌드하기 때문에 서버에 부하가 크다 (얼마나 부하가 큰지는 측정을 못해봤음 ㅠ)
어쨌든 PR 날릴 때마다 서버가 통으로 멈추는건 아주 크나큰 문제였다.
name: Deploy to Home Server
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SSH_HOST }}
port: ${{ secrets.SSH_PORT }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
set -e
cd ${{ secrets.DEPLOY_PATH }}
git pull origin main
./mvnw package -DskipTests # 홈서버에서 Maven 빌드
docker compose up -d --build # 홈서버에서 Docker 빌드
echo "✅ 배포 완료"
Github Container Registry (ghcr.io)를 도입하기로 했다.
ghcr.io란? github에서 운영하는 Docker 이미지 저장소

Github Container Registry를 이용해서 도커 이미지를 pull받아 이미지만 실행시키는 방식을 사용하도록 했다.
1. Actions VM 실행!
2. github Repo에서 코드 checkout
3. maven 빌드
4. 생성된 jar를 토대로 docker 빌드
5. 생성된 이미지를 ghcr.io에 업로드
6. SSH로 홈서버 접속
7. git pull로 최신 코드(docker-compose.yml) 땡겨옴
8. docker compose pull로 이미지 pull 받아오기
9. 그 상태에서 Docker Run
10. 배포
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
- name: Build JAR # maven 빌드
run: mvn package -DskipTests -q && cp target/*.jar app.jar
- name: Set up Docker Buildx # docker build 도구
uses: docker/setup-buildx-action@v3
- name: Log in to ghcr.io # ghcr.io 로그인
uses: docker/login-action@v3
- name: Build and push Docker image # VM에서 이미지 빌드 + ghcr.io push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/0xdf0101/mock_invest:latest
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.3
with:
script: |
git pull origin main
docker compose pull # ghcr.io에서 이미지 pull
docker compose up -d # 실행만 (빌드 없음) ✅
✅
ghcr.io를 도입함으로써 서버의 부하를 줄이고, OOM을 예방할 수 있었다.
(두 방식에 대한 메모리 변화량도 기록하고 싶었으나 Grafana를 띄우니까 또 뻗었다.)