Github Container Registry(GCR)에 업로드된 새로운 이미지를 docker compose 환경으로 자동으로 배포하기 위해서는 docker compose를 구성하는 요소가 새로운 이미지의 존재를 확인할 수 있어야 합니다. 대표적으로는 webhook 기반 방법, polling 기반 방법이 있습니다.
Webhook을 사용하는 도구들, 또는 이와 비슷한 모종의 방식들(HTTP 요청 등)은 실시간 배포가 가능하고 리소스 효율적이지만 약간의 설정 복잡성이 있을 수 있습니다. GCR에 새 이미지가 푸시되면 즉시 홈 서버의 webhook 엔드포인트로 알림을 전송하는 방식입니다.
우아한 Webhook 기반 방법들에 비해 Polling 기반 방법들은 전반적으로 GitHub API의 시간당 5,000회 요청 제한(ref2)과 업데이트 지연이라는 문제들이 있음에도 불구하고 구현이 단순하고 방화벽과 같은 걱정에서 자유로울 수 있어 홈 서버에 배포하는 토이 프로젝트, 작은 서비스에서는 더 안정적인 선택이 될 수 있습니다.
물론 보안상 권장되지 않는 방법이지만, github action에서 빌드가 완료되었을 때 SSH를 이용해 서버에 접근해 image pull을 해 버리는 방법도 있습니다. 이 글에서는 어떤 방법과 도구들이 있는지를 살펴보고, 제가 Watchover을 선택한 이유도 간단히 풀어봅니다.
우선 정말 간단한 애플리케이션에 있어서는 CD 대신 간단히 알림을 보내주는 접근방식이 더 합리적인 경우가 많습니다. Diun는 지속적 배포가 아니라 알림을 보내는 일에 집중하는 도구입니다. 프로젝트 페이지를 보면 활발히 개발되고 있는 것을 확인할 수 있습니다. 메모리 사용량이 8MB도 되지 않아 가볍고, 15개 이상의 알림 채널을 지원합니다. 앞으로 소개할 Watchtower과 같이 사용하는 사람들도 있습니다.
# Diun 설정 예시
services:
diun:
image: crazymax/diun:latest
volumes:
- "./data:/data"
- "/var/run/docker.sock:/var/run/docker.sock"
environment:
- "DIUN_WATCH_WORKERS=20"
- "DIUN_NOTIF_TELEGRAM_TOKEN=YOUR_TOKEN"
restart: always
하지만 저는 개발 사정상 완전 자동 CD를 고민하고 있으므로 요구사항에 맞지 않아 이정도만 하고 넘어갑니다.
두 번째로 살펴볼 것은 SSH 기반의 배포입니다. 하지만 이 방법도 가볍게만 살피고 넘어가야 할 것 같습니다. 아무리 비밀번호가 걸려 있다고 한들 내 컴퓨터의 특정 포트를 외부로 노출시키는 것은 정말 생각보다 위험한 일이기 때문입니다. 예전에 킥보드를 개발할 때 Jetson 컴퓨터에 특히 중국 IP로부터 브루트 포스 공격을 쉴 새 없이 받았고, 그 결과 로그 파일이 잔뜩 쌓이다 못해 컴퓨터가 용량 부족을 호소하거나 네트워크 대역폭에 영향을 받아 쓰지 못할 지경에 이르렀던 경험을 실제로 해 버렸거든요. 해커가 내 컴퓨터 문턱까지 와서 포트를 더듬거리고 있는 것도 기분나쁜 일인데, 그 더듬음이 도를 지나쳐서 컴퓨터가 고장이 날 정도라면 보안 불감증인 저조차도 생각만 해도 끔찍합니다.
그렇다고 안전하게 SSH 연결을 만들 방법을 알아보자니, https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/use-cases/ssh/ssh-infrastructure-access/ 이렇게 길고 복잡한 매뉴얼을 읽어야 합니다. 그래서 이 방법도 고려하지 않게 되었습니다. 어쨌든 이런 방법도 존재함을 짚고 넘어가려고 합니다.
- name: Deploy via SSH
uses: appleboy/[email protected]
with:
script: |
cd /app
echo "DOCKER_TAG=${{ github.sha }}" > .env
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
약간의 상용 도구를 찾는다면 Portainer도 살펴볼만 합니다. Portainer는 Docker 환경을 시각적으로 관리해주는 UI 도구입니다. Webhook 기반의 자동 배포 기능이 상용 라이선스에 한해(뒤늦게 알았지만-.-) 내장되어 있습니다. Portainer에서 생성한 webhook URL을 Docker Hub, GitHub Actions, GitLab CI/CD 등의 플랫폼에서 호출하여 사용하는 방식입니다. 새로운 이미지가 푸시되는 등의 이벤트가 발생하면, 해당 플랫폼이 이 webhook URL로 알림(HTTP 요청)을 보냅니다. Portainer는 알림을 받는 즉시 연결된 컨테이너를 최신 이미지로 자동으로 재시작합니다. 직접 docker pull 명령을 실행할 필요 없이, webhook 알림 하나로 CD(Continuous Delivery)를 구축할 수 있습니다.
이 가이드를 응용하여 docker compose를 구성할 수 있습니다. 더불어 저는 개인 도메인을 사용하므로, 이 이슈에 따라 TRUSTED_ORIGINS 환경 변수를 설정하여 로그인할 수 있었습니다.
services:
...
portainer:
image: portainer/portainer-ce:lts
container_name: portainer
environment:
- TRUSTED_ORIGINS=portainer.mydomain.com,mydomain.com
ports:
- "9000:8000"
- "9443:9443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
restart: always
volumes:
portainer_data:

