Skip to content

Latest commit

 

History

History

README.md

single-host

일반 서버용 self-contained 배포 폴더.

이 디렉토리만 서버로 복사한 뒤 .env를 준비하면 docker compose로 배포할 수 있다.

SERVICE=app|linkpie|deskpie로 서비스 종류를 지정할 수 있다. 다만 APP_IMAGE는 선택한 SERVICE와 같은 이미지를 가리켜야 한다.

원칙

  • deploy/single-host만 일반 서버 배포의 SSOT로 사용한다.
  • 이 폴더는 바깥 deploy/shared/monitoring, deploy/compose/tencent/dev, deploy/compose/tencent/stage를 참조하지 않는다.
  • 배포에 필요한 설정, provisioning, template, helper script를 같은 폴더 안에 닫아 둔다.
  • KISS를 위해 앱 내부 포트는 8011로 고정하고, 외부에서 필요한 값만 .env로 노출한다.
  • 동적 처리가 필요한 부분은 monitoring service label 렌더링처럼 작은 shell script로만 제한한다.

파일

  • docker-compose.dev.yaml
  • docker-compose.prod.yaml
  • .env.example
  • .env.prod.example
  • caddy/Caddyfile
  • db/Dockerfile.postgres
  • monitoring/loki/config.yaml
  • monitoring/prometheus/config.tmpl.yaml
  • monitoring/prometheus/render-config.sh
  • monitoring/promtail/config.tmpl.yaml
  • monitoring/promtail/render-config.sh
  • monitoring/grafana/provisioning/

준비

  1. 서버 DNS가 APP_BASE_URL 호스트를 현재 서버 IP로 가리키도록 설정한다.
  2. 서버 80/tcp, 443/tcp 포트를 연다.
  3. 예시 env를 복사해 .env를 만든다.
cp .env.example .env

또는 환경별 예시를 그대로 시작점으로 쓸 수 있다.

cp .env.prod.example .env

필수 수정 값:

  • SERVICE
  • APP_IMAGE
  • DATABASE_URL
  • APP_BASE_URL
  • ACME_EMAIL
  • APP_CRYPTO_CURRENT_PROVIDER=ENV
  • APP_CRYPTO_PROVIDERS_ENV_KEK
  • APP_CRYPTO_PROVIDERS_ENV_KEK_KID (선택, 기본값 kek-v1)
  • GRAFANA_ADMIN_PASSWORD

bundled PostgreSQL 비밀번호를 기본값(deck)이 아닌 값으로 바꿀 경우에는 아래도 함께 맞춘다.

  • DB_PASSWORD
  • DATABASE_URL

DATABASE_URLuser, password&, =, %, ?, # 같은 reserved character가 들어가면 percent-encoding해서 넣는다.

시작 순서 제어는 별도 wait-for-pg.sh 없이 처리한다.

  • db healthcheck가 pg_isready로 준비 상태를 판단한다.
  • appdepends_on: condition: service_healthy로 DB 준비 후 시작한다.
  • 불필요한 wrapper script를 두지 않아 single-host 번들을 더 단순하게 유지한다.

기본 포트 노출 정책:

  • 외부 공개는 caddy80/443만 담당한다.
  • appdb127.0.0.1에만 bind 되므로 서버 외부에서 직접 접근되지 않는다.
  • 앱 내부 포트는 고정 8011이며, 외부에서 localhost로 붙을 때만 APP_PORT를 바꾼다.
  • DB_PORT는 bundled PostgreSQL의 localhost bind용이므로 운영 서버에서는 로컬 점검이나 SSH 터널 용도로만 본다.

앱 런타임 최소 계약은 아래 세 값이다.

  • DATABASE_URL
  • APP_BASE_URL
  • APP_CRYPTO_CURRENT_PROVIDER
  • APP_CRYPTO_PROVIDERS_ENV_KEK

현재 single-host 번들은 ENV 단일 KEK 운영만 문서화한다.

DB_PASSWORD는 bundled PostgreSQL 컨테이너 설정값이며, 앱은 split datasource env를 읽지 않는다.

실행

프로필:

  • db: PostgreSQL
  • app: 선택한 SERVICE 이미지
  • caddy: HTTPS reverse proxy
  • monitoring: loki, promtail, prometheus, grafana

주의:

  • 이 compose는 모든 서비스가 profile에 묶여 있다.
  • 그래서 profile 없이 docker compose up -d를 실행하면 no service selected가 나온다.
  • app만 서비스 이름으로 지정해도 db profile은 자동으로 켜지지 않는다.
  • app을 띄우려면 최소 --profile db --profile app을 같이 줘야 한다.

권장 조합:

  • 앱 개발 확인: db + app
  • HTTPS 포함 확인: db + app + caddy
  • 전체 운영 스택: db + app + caddy + monitoring

전체 스택:

docker compose -f docker-compose.dev.yaml --env-file .env \
  --profile db --profile app --profile caddy --profile monitoring up -d

프로덕션:

docker compose -f docker-compose.prod.yaml --env-file .env \
  --profile db --profile app --profile caddy --profile monitoring up -d

앱만:

docker compose -f docker-compose.dev.yaml --env-file .env \
  --profile db --profile app up -d

서비스 이름 직접 지정 예시:

docker compose -f docker-compose.dev.yaml --env-file .env \
  --profile db --profile app up -d app

앱 + HTTPS:

docker compose -f docker-compose.dev.yaml --env-file .env \
  --profile db --profile app --profile caddy up -d

모니터링 포함:

docker compose -f docker-compose.dev.yaml --env-file .env \
  --profile db --profile app --profile monitoring up -d

로컬 이미지 빌드 예시:

docker build --build-arg SERVICE=app -t deck-single-host-app:test ../..
docker build --build-arg SERVICE=linkpie -t deck-single-host-linkpie:test ../..

노출 경로

  • 앱: ${APP_BASE_URL}
  • Grafana: ${APP_BASE_URL}/grafana/

Grafana는 익명 접근을 허용하지 않으며 GRAFANA_ADMIN_PASSWORD가 반드시 필요하다. Grafana에는 Deck Overview 대시보드가 함께 프로비저닝된다.

CI/CD 주의사항

  • CI는 반드시 docker compose ... config 검증을 먼저 수행해 .env.example과 compose/template의 계약이 깨지지 않는지 확인해야 한다.
  • deploy/single-host 검증은 이 폴더만 복사한 임시 디렉토리에서 실행해야 한다. 바깥 경로를 참조한 채 통과하면 SSOT가 깨진다.
  • 운영 배포 job은 APP_IMAGE를 빌드/푸시한 뒤 compose 배포 단계로 넘겨야 한다. SERVICE와 다른 이미지를 넣으면 잘못된 서비스가 배포된다.
  • prod 배포에서는 DATABASE_URL, DB_PASSWORD, GRAFANA_ADMIN_PASSWORD, APP_CRYPTO_PROVIDERS_ENV_KEK, APP_BASE_URL, ACME_EMAIL 누락을 즉시 실패시켜야 한다.
  • Let's Encrypt 자동 발급은 공개 DNS와 80/443 개방이 전제다. CI 환경에서는 실제 발급을 검증하지 말고 compose/config와 local TLS wiring만 검증한다.
  • review automation이 제안하는 개선이라도 single-host 외부 의존을 다시 만드는 방식이면 받지 않는다. SSOT와 self-contained 특성이 우선이다.