Skip to content

Latest commit

 

History

History
201 lines (140 loc) · 12.9 KB

File metadata and controls

201 lines (140 loc) · 12.9 KB

Docker Compose Repository

English | 한국어

Docker Compose Elasticsearch PostgreSQL ChromaDB OpenTelemetry Terraform License

개발 머신에서 상시로 띄워 쓰는 백엔드 서비스들의 Docker Compose 파일 모음입니다. 검색 엔진, 관계형 데이터베이스, 벡터 스토어, 분산 트레이싱, 정적 사이트 개발 서버, 컨테이너화된 Terraform CLI로 구성되어 있습니다.

애플리케이션 코드는 없습니다. 각 파일은 단독으로 실행 가능한 독립 스택이며, 모든 스택이 하나의 공용 Docker 브리지 네트워크에 붙기 때문에 서로 다른 스택의 컨테이너끼리도 서비스 이름으로 통신할 수 있습니다.


구성

스택 Compose 파일 서비스 공개 포트
Elasticsearch 8 elasticsearch/elkstack-v1.2.yml Elasticsearch 8.17.2(Nori 분석기 포함, 로컬 빌드), 초기 설정용 일회성 컨테이너, Kibana 8.17.2 10041, 10042
Elasticsearch 7 elasticsearch/elasticsearch-7-14-1/elkstack-v1.2.yml 동일한 구성의 7.14.1 버전 10060, 10061
Kibana → 원격 elasticsearch/kibana-ifns.yml Kibana 8.17.2 단독, 네트워크의 다른 곳에 있는 클러스터에 연결 10040
ChromaDB chromadb/chromadb-v10.yml ChromaDB, OpenTelemetry Collector, Zipkin 10050, 10051
PostgreSQL postgresql/postgresql-v11.yml PostgreSQL 17, 최초 실행 시 init.sql로 스키마 생성 10010
PostgreSQL + pgAdmin postgresql/postgresql-pgadmin-v10.yml PostgreSQL 17, pgAdmin 4 10010, 10011
Jekyll jekyll/jekyll.yml --watch로 실행되는 Jekyll 개발 서버 10020
Terraform terraform/terraform.yml Terraform 1.9 CLI, 일회성 명령으로 실행

PostgreSQL 파일 두 개는 함께 쓰는 것이 아니라 서로 대체하는 관계입니다. 둘 다 10010 포트를 사용하므로 한 번에 하나만 실행됩니다.


요구 사항

  • Compose v2가 포함된 Docker Engine (docker-compose가 아니라 docker compose)

  • 머신당 한 번만 만들어 두는 공용 네트워크:

    docker network create avocado-network

    모든 스택이 이 네트워크를 external: true로 선언하므로, 네트워크가 없으면 실행이 실패합니다.

  • Elasticsearch 스택을 돌릴 만한 메모리. 노드당 ES_HEAP_SIZE 기본값이 3g이고, 여기에 컨테이너 오버헤드가 더해집니다.


빠른 시작

각 스택 디렉터리에는 자체 .env.example이 있습니다. 복사해서 값을 채우고, 해당 디렉터리 안에서 스택을 실행합니다.

# Elasticsearch 8 + Kibana (최초 실행 시 로컬 이미지 빌드)
cd elasticsearch
cp .env.example .env
docker compose -f elkstack-v1.2.yml up -d --build
# Elasticsearch → http://localhost:10041   (계정: elastic)
# Kibana        → http://localhost:10042
# PostgreSQL
cd postgresql
cp .env.example .env
docker compose -f postgresql-v11.yml up -d
# ChromaDB + 트레이싱
cd chromadb
cp .env.example .env
docker compose -f chromadb-v10.yml up -d
# ChromaDB → http://localhost:10050
# Zipkin   → http://localhost:10051
# Terraform (상시 실행 컨테이너가 아님)
cd terraform
cp .env.example .env          # TF_PROJECT는 반드시 호스트의 절대 경로
docker compose -f terraform.yml run --rm terraform init
docker compose -f terraform.yml run --rm terraform plan

정리할 때는 docker compose -f <파일> down, 네임드 볼륨까지 삭제하려면 down -v를 사용합니다.


규칙

포트. 어떤 서비스도 기본 포트를 그대로 쓰지 않기 때문에, 호스트에 이미 설치된 PostgreSQL이나 Elasticsearch와 충돌하지 않습니다. 영역별로 대역을 나눠 씁니다.

대역 영역
1001x 관계형 데이터베이스와 관리 UI
1002x 웹 / 정적 사이트
1004x Elastic 8.x, 원격 클러스터용 Kibana
1005x 벡터 스토어와 트레이싱
1006x Elastic 7.x

설정. 자격 증명과 호스트 경로는 디렉터리별 .env에서 읽어오며, 이 파일은 gitignore 대상입니다. 필수 변수는 ${VAR:?메시지} 형태로 참조하므로, 값이 비어 있으면 기본값으로 조용히 넘어가지 않고 시작 시점에 명시적인 오류로 멈춥니다. .env.example은 커밋되어 있으며 각 스택이 필요한 값을 문서화합니다.

이미지 버전. 대부분의 이미지는 latest 대신 명시적인 태그로 고정합니다. 예외는 dpage/pgadmin4:latest, jekyll/jekyll:latest, 그리고 태그를 지정하지 않아 latest가 되는 openzipkin/zipkin 세 개인데, 모두 재현할 데이터를 갖지 않는 UI·도구 컨테이너입니다. ChromaDB 태그(1.5.8.dev23)는 정식 릴리스 전 빌드입니다.

로컬 빌드 이미지. Nori가 포함된 Elasticsearch 이미지는 elasticsearch-nori:<버전>으로 태그합니다. 업스트림 태그를 의도적으로 피한 것으로, 그렇지 않으면 Docker가 플러그인이 없는 공식 이미지를 대신 가져올 수 있습니다. 이 스택들은 최초 실행 시 --build가 필요합니다.

시작 순서. 순서가 중요한 곳에서는 대기 시간이 아니라 헬스체크로 순서를 표현합니다. Kibana 서비스는 초기 설정 컨테이너의 service_completed_successfully를 기다리고, 그 컨테이너는 Elasticsearch의 service_healthy를 기다립니다. pgAdmin 서비스는 PostgreSQL의 pg_isready 헬스체크를 기다립니다.

상태 저장. PostgreSQL, pgAdmin, Elasticsearch는 네임드 Docker 볼륨에 저장합니다. ChromaDB와 Jekyll은 CHROMA_DATA_DIR, JEKYLL_SITE_DIR로 지정하는 바인드 마운트를 쓰며, 기본값은 compose 파일 기준 상대 경로입니다.

줄바꿈. .gitattributes가 텍스트 파일을 LF로 정규화하고 인증서·이미지 파일을 바이너리로 표시합니다. Windows에서 체크아웃해도 전체 트리가 수정된 것으로 표시되지 않습니다.


스택별 참고 사항

Elasticsearch + Kibana

Dockerfile.es-nori는 공식 이미지에 한국어 형태소 분석기 analysis-nori를 빌드 시점에 설치하며, 이미 설치되어 있으면 건너뜁니다.

두 Elastic 스택 모두 discovery.type=single-node로 동작하고, 보안은 켜 두되 HTTP·transport 계층의 TLS는 끈 상태입니다. 헬스체크는 Elasticsearch의 missing authentication credentials 응답을 성공 신호로 취급합니다. 인증 없는 요청이 거부된다는 것 자체가 노드가 응답하면서 보안을 적용하고 있다는 증거이기 때문입니다.

일회성 elasticsearch_settings 컨테이너가 보안 API로 kibana_system 비밀번호를 설정한 뒤 종료하고, Kibana는 이 컨테이너가 정상 종료된 뒤에야 시작합니다.

8.17.2와 7.14.1 스택은 포트, 컨테이너 이름, 볼륨이 모두 달라 동시에 실행할 수 있습니다. 7.x 디렉터리에는 자체 .env.example이 없으므로 상위 디렉터리의 것을 복사합니다.

cd elasticsearch/elasticsearch-7-14-1
cp ../.env.example .env
docker compose -f elkstack-v1.2.yml up -d --build

kibana-ifns.yml은 이 저장소가 관리하지 않는 클러스터를 들여다보기 위해, REMOTE_ES_HOST를 향한 Kibana만 단독으로 띄웁니다.

elasticsearch/ 안의 다음 두 파일은 참고용이며 여기의 어떤 스택도 사용하지 않습니다.

  • config/elasticsearch.yml — TLS를 켠 노드 설정. 이를 만드는 데 필요한 elasticsearch-certutil과 keystore 명령이 함께 적혀 있습니다. 인증서 자료는 certs/에 두며, 이 디렉터리는 gitignore 대상이고 로컬에서 생성합니다.
  • logstash/config/logstash.yml — 이전 Logstash 구성의 파이프라인 설정. Logstash를 띄우는 compose 파일은 없습니다.

ChromaDB

ChromaDB는 /data에 데이터를 유지하고 OTLP 트레이스를 OpenTelemetry Collector로 보냅니다. Collector는 메모리 제한 아래에서 트레이스를 배치 처리해 http://zipkin:9411/api/v2/spans의 Zipkin으로 내보냅니다. Collector는 compose 파일 기준 상대 경로로 읽기 전용 마운트된 otel-collector-config.yaml을 읽습니다. ANONYMIZED_TELEMETRY는 켜진 상태로 두었습니다.

PostgreSQL

두 파일 모두 사용자, 비밀번호, 데이터베이스 이름을 .env에서 받습니다. init.sql을 마운트하는 것은 postgresql-v11.yml뿐이고, Postgres는 데이터 디렉터리가 비어 있을 때만 이 스크립트를 실행합니다. 즉 최초 실행 시, 또는 down -v 이후에만 적용됩니다.

init.sqlrag_chatbot 스키마와 config 키/값 테이블을 만들고, 설정을 데이터베이스에서 읽어가는 애플리케이션용 검색 파라미터, 인덱스 이름, 모델 경로를 넣습니다. 비밀값처럼 보이는 항목은 모두 자리표시자(__SET_AT_DEPLOY__)이며, 실제 자격 증명은 애플리케이션 시작 시점에 주입합니다.

Jekyll

JEKYLL_SITE_DIR이 가리키는 디렉터리(기본값 ./jekyll-site, 최소 구성의 샘플 사이트)를 jekyll serve --watch --drafts로 서비스합니다. Windows와 WSL의 바인드 마운트에서는 inotify 이벤트가 항상 전달되지 않으므로, 수정 사항이 반영되지 않으면 명령에 --force_polling을 추가합니다.

Terraform

CLI를 호스트에 설치하지 않고 버전이 고정된 컨테이너로 실행하며, TF_PROJECT/workspace에 마운트합니다. Docker는 바인드 마운트의 상대 경로를 해석하지 못하므로 TF_PROJECT는 절대 경로여야 합니다. AWS 자격 증명은 설정되어 있으면 전달되고 기본값은 빈 값인데, 로컬 전용 프로바이더를 쓸 때는 이대로도 문제없습니다. AWS_REGION 기본값은 ap-northeast-2입니다.


저장소 구조

.
├── chromadb/
│   ├── chromadb-v10.yml            # Chroma + OTel Collector + Zipkin
│   └── otel-collector-config.yaml  # OTLP 수신 → 배치 → Zipkin 전송
├── elasticsearch/
│   ├── elkstack-v1.2.yml           # ES 8.17.2 + Nori + Kibana
│   ├── Dockerfile.es-nori          # 이미지 빌드 시점에 Nori 설치
│   ├── kibana-ifns.yml             # Kibana → 원격 클러스터
│   ├── config/elasticsearch.yml    # TLS 참고 설정 (스택에서 미사용)
│   ├── logstash/config/            # Logstash 설정 (스택에서 미사용)
│   └── elasticsearch-7-14-1/       # 병행 실행용 7.14.1 스택
├── postgresql/
│   ├── postgresql-v11.yml          # Postgres 17 + init.sql
│   ├── postgresql-pgadmin-v10.yml  # Postgres 17 + pgAdmin
│   └── init.sql                    # 스키마와 설정 초기값, 최초 실행 시에만
├── jekyll/
│   ├── jekyll.yml                  # Jekyll 개발 서버
│   └── jekyll-site/                # 서비스할 샘플 사이트
├── terraform/terraform.yml         # 컨테이너화된 Terraform CLI
├── .gitattributes                  # LF 정규화, linguist 설정
└── prompt-documentation.md         # 이 저장소 변경 작업 기록

유의 사항

  • 로컬 개발용 구성입니다. 운영 환경 기준으로 강화되어 있지 않습니다. compose 스택에서 HTTP 계층 TLS는 꺼져 있고, 컨테이너는 이미지 기본 사용자로 실행되며, CPU·메모리 제한이 없고, 비밀값은 시크릿 매니저가 아니라 .env에 있습니다.
  • Windows의 Docker Desktop에서 작성하고 사용했습니다. compose 파일에 OS에 종속된 경로는 없으므로 Linux와 macOS에서도 그대로 동작합니다.
  • bootstrap.memory_lock=true는 Elastic 스택에 이미 선언된 memlock ulimit에 의존합니다. 이 설정을 지우면 노드가 시작에 실패합니다.
  • 두 Elasticsearch 스택은 서로 다른 .env 파일에서 같은 이름의 변수를 읽습니다. 포트, 컨테이너 이름, 볼륨이 다르므로 동시 실행에는 문제가 없지만, 비밀번호는 각 .env에 적힌 값을 따릅니다.

라이선스

MIT