Docker로 배포
Chorus는 공식 Docker 이미지 **chorusaidlc/chorus-app**을 제공합니다. 이 가이드는 두 가지 Compose 형태(스탠드얼론(내장 데이터베이스)과 프로덕션(외부 PostgreSQL + Redis)), 기존 데이터베이스에 연결하는 순수 docker run, 전체 환경 변수 참고, 그리고 컨테이너가 시작 시 무엇을 하는지 보여 줍니다.
먼저 이미지를 풀합니다.
docker pull chorusaidlc/chorus-app:latest스탠드얼론 형태와 프로덕션 형태 중 무엇을 고를지는 배포 개요를 참고하세요.
스탠드얼론(내장 데이터베이스)
섹션 제목: “스탠드얼론(내장 데이터베이스)”외부 데이터베이스가 필요 없습니다. 이미지는 PGlite(내장 PostgreSQL)를 함께 담고 있으며 모든 것을 자동으로 시작합니다. 데이터는 Docker 볼륨에 저장되어 컨테이너 재시작을 넘어 유지됩니다.
docker-compose.local.yml을 만듭니다.
# Standalone Chorus — embedded PGlite, no external PostgreSQL or Redisservices: app: image: chorusaidlc/chorus-app:latest ports: - "8637:8637" environment: # No DATABASE_URL — entrypoint auto-starts embedded PGlite - REDIS_URL= - NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-chorus-local-secret} - COOKIE_SECURE=false - DEFAULT_USER=${DEFAULT_USER:-admin@example.com} - DEFAULT_PASSWORD=${DEFAULT_PASSWORD:-changeme} volumes: - chorus-local-data:/app/data
volumes: chorus-local-data:그런 다음 실행합니다.
docker compose -f docker-compose.local.yml up -dhttp://localhost:8637을 열고 admin@example.com / changeme로 로그인합니다(또는 DEFAULT_USER / DEFAULT_PASSWORD 환경 변수로 재정의합니다).
스탠드얼론 모드에서 컨테이너는 다음을 수행합니다.
- PGlite를 내부 포트(
5433)에서 시작하며, 외부로 노출하지 않습니다. - 데이터를
chorus-local-dataDocker 볼륨에 저장하므로 재시작을 넘어 유지됩니다. - Redis를 비활성화합니다(메모리 내 EventBus로 폴백 — 단일 인스턴스만).
- 시작 시 Prisma 마이그레이션을 자동으로 실행합니다.
프로덕션(외부 PostgreSQL + Redis)
섹션 제목: “프로덕션(외부 PostgreSQL + Redis)”프로덕션 환경, 특히 다중 복제본을 둘 때는 앱을 외부 PostgreSQL과 Redis에 연결하세요. docker-compose.yml을 만듭니다.
services: app: image: chorusaidlc/chorus-app:latest ports: - "8637:8637" environment: - DATABASE_URL=postgresql://chorus:chorus@db:5432/chorus - REDIS_URL=redis://default:chorus-redis@redis:6379 - NEXTAUTH_SECRET=change-me-to-a-random-secret - DEFAULT_USER=admin@example.com - DEFAULT_PASSWORD=your-password depends_on: db: condition: service_healthy redis: condition: service_healthy
redis: image: redis:7-alpine command: redis-server --requirepass chorus-redis volumes: - redis-data:/data healthcheck: test: ["CMD", "redis-cli", "-a", "chorus-redis", "ping"] interval: 5s timeout: 3s retries: 5
db: image: postgres:16-alpine environment: POSTGRES_USER: chorus POSTGRES_PASSWORD: chorus POSTGRES_DB: chorus volumes: - chorus-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U chorus -d chorus"] interval: 5s timeout: 5s retries: 5
volumes: chorus-data: redis-data:그런 다음 실행합니다.
docker compose up -dhttp://localhost:8637을 열고 DEFAULT_USER / DEFAULT_PASSWORD에 설정한 자격 증명으로 로그인합니다.
기존 PostgreSQL에 연결해 실행하기
섹션 제목: “기존 PostgreSQL에 연결해 실행하기”이미 PostgreSQL과 Redis가 실행 중이라면 컨테이너를 직접 시작합니다.
docker run -d \ -p 8637:8637 \ -e DATABASE_URL=postgresql://user:pass@your-db-host:5432/chorus \ -e REDIS_URL=redis://default:password@your-redis-host:6379 \ -e NEXTAUTH_SECRET=change-me-to-a-random-secret \ -e COOKIE_SECURE=false \ -e DEFAULT_USER=admin@example.com \ -e DEFAULT_PASSWORD=your-password \ chorusaidlc/chorus-app:latest환경 변수
섹션 제목: “환경 변수”| 변수 | 설명 |
|---|---|
DATABASE_URL | PostgreSQL 연결 문자열. 형식: postgresql://user:password@host:port/dbname. 대신 개별 DB_* 변수를 설정할 수도 있습니다(아래 참고). 생략하면 엔트리포인트가 내장 PGlite 인스턴스를 자동으로 시작합니다. |
NEXTAUTH_SECRET | JWT 세션 토큰에 서명하기 위한 비밀 키. 무작위 문자열을 사용하세요(예: openssl rand -base64 32). |
데이터베이스(DATABASE_URL의 대안)
섹션 제목: “데이터베이스(DATABASE_URL의 대안)”DATABASE_URL이 설정되지 않은 경우, 엔트리포인트는 다음 개별 변수로 그것을 조립합니다.
| 변수 | 설명 |
|---|---|
DB_HOST | PostgreSQL 호스트 |
DB_PORT | PostgreSQL 포트(기본값: 5432) |
DB_USERNAME | PostgreSQL 사용자 이름 |
DB_PASSWORD | PostgreSQL 비밀번호 |
DB_NAME | 데이터베이스 이름 |
Redis
섹션 제목: “Redis”| 변수 | 설명 |
|---|---|
REDIS_URL | 전체 Redis 연결 문자열. 형식: redis://username:password@host:port. 개별 변수보다 우선합니다. |
REDIS_HOST | Redis 호스트(REDIS_URL이 설정되지 않은 경우 사용) |
REDIS_PORT | Redis 포트(기본값: 6379) |
REDIS_USERNAME | Redis 사용자 이름(기본값: default) |
REDIS_PASSWORD | Redis 비밀번호 |
| 변수 | 설명 |
|---|---|
DEFAULT_USER | 내장 로그인용 이메일 주소(OIDC를 우회합니다). 첫 로그인 시 사용자와 회사를 자동으로 프로비저닝합니다. |
DEFAULT_PASSWORD | 기본 사용자의 비밀번호(평문이며, 런타임에 bcrypt로 대조합니다). |
NEXTAUTH_URL | 앱의 외부 공개 기본 URL(기본값: http://localhost:8637). 리버스 프록시 뒤에서 실행할 때 설정합니다. |
COOKIE_SECURE | HTTP 전용 배포에서 보안 쿠키를 끄려면 "false"로 설정합니다(docker-compose에서는 기본값 "false"). 프로덕션에서 HTTPS로 배포할 때는 "true"로 설정합니다. |
| 변수 | 기본값 | 설명 |
|---|---|---|
LOG_LEVEL | info(프로덕션) / debug(개발) | 서버 최소 로그 레벨. 허용 값: trace, debug, info, warn, error, fatal, silent. Prisma 쿼리 로그를 억제하려면 info로 설정합니다. |
NEXT_PUBLIC_LOG_LEVEL | warn(프로덕션) / debug(개발) | 브라우저 최소 로그 레벨. 허용 값: debug, info, warn, error. |
프로덕션 Docker 이미지는 항상 JSON을 stdout으로 출력합니다(CloudWatch / ELK에 바로 연결 가능). 색상이 입혀진 보기 좋은 출력은 로컬 개발에서만 사용할 수 있습니다.
슈퍼 관리자
섹션 제목: “슈퍼 관리자”| 변수 | 설명 |
|---|---|
SUPER_ADMIN_EMAIL | 슈퍼 관리자 계정의 이메일(/admin 패널에 접근할 수 있습니다). |
SUPER_ADMIN_PASSWORD_HASH | 슈퍼 관리자 비밀번호의 bcrypt 해시. 생성 방법: node -e "console.log(require('bcryptjs').hashSync('your-password', 10))" |
시작 시 동작
섹션 제목: “시작 시 동작”컨테이너의 엔트리포인트는 시작할 때마다 같은 순서를 실행합니다.
DATABASE_URL이 설정되지 않고DB_*변수도 하나도 제공되지 않으면, 엔트리포인트는 내부 포트(5433)에서 내장 PGlite 인스턴스를 시작합니다. 외부 데이터베이스가 구성되어 있으면 PGlite는 시작하지 않습니다.prisma migrate deploy를 실행해 보류 중인 데이터베이스 마이그레이션을 적용합니다.- 데이터베이스가 아직 준비되지 않았으면 10초마다 재시도합니다(최대 30회, 약 5분).
- 마이그레이션이 성공하면 Next.js 서버가
8637포트에서 시작합니다.
이미지 세부 정보
섹션 제목: “이미지 세부 정보”- 기본 이미지:
node:22-alpine - 내부 포트:
8637 - 아키텍처:
linux/amd64,linux/arm64