Elasticsearch 입문 4편 — Quickstart (Docker Compose·curl 첫 명령·Kibana Dev Tools)

2026-05-19Elasticsearch 입문에서 운영까지

Elasticsearch 입문 4편 Quickstart. Docker Compose 로 ES + Kibana 한 번에 띄우고 _cat/health·문서 색인·Dev Tools 까지 hands-on.

📚 Elasticsearch 입문에서 운영까지 · 4편 — Quickstart (Docker Compose·curl 첫 명령·Kibana Dev Tools)

이 글은 Elasticsearch 입문에서 운영까지 시리즈 38편 중 4편이에요. 1편에서 "검색·로그·AI 통합 플랫폼" 으로 정체를 잡았고, 2편에서 Index·Document·Shard·Replica·Mapping 다섯 단어를, 3편에서 Lucene 의 Segment·Inverted Index·Posting List 까지 따라갔어요. 이쯤 오면 머리는 어느 정도 만들어졌는데, 손이 비어 있어요. 이번 글은 손을 채우는 hands-on 입니다.

📚 학습 노트

이 글은 Elasticsearch 8.x 공식 docs 와 Docker 공식 image (elastic/elasticsearch:8.x) 를 따라 풀어쓴 자료예요. 화면 앞에 노트북 한 대만 있으면 30분 안에 첫 검색 응답까지 갑니다.

막히는 자리는 8번째 섹션 *자주 만나는 사고* 에 거의 다 들어 있어요. 막히면 그 표부터 펴 보세요.

도입 — hands-on 이 가장 빠른 학습

검색 엔진은 글로만 읽으면 Inverted Index 가 머리에 안 박힌다 는 게 정설이에요. 문서를 한 번 직접 색인하고, 그 문서가 검색되는 응답을 두 눈으로 본다 — 이 한 사이클을 한 번이라도 돌리면 그다음 글들이 다 잘 읽혀요. 그래서 이 시리즈는 1~3편으로 머리를 잡자마자 4편에서 손을 묶도록 짰어요.

이번 글이 다루는 범위는 좁아요. Elasticsearch + Kibana 를 Docker Compose 로 띄우고, curl 로 첫 명령을 쳐 보고, Kibana Dev Tools 에서 같은 명령을 GUI 로 다시 쳐 보는 것 까지. 색인된 문서 한 건을 검색해서 hits 응답을 본다, 거기서 멈춰요. 인덱스 관리·매핑 설계·운영 튜닝은 5편부터 차례대로 들어가요.

처음 ES 를 만져 보는 사람이 가장 자주 막히는 자리가 환경 셋업 이에요. security 활성화·메모리 한도·포트 충돌 같은 자리에서 30분, 한 시간씩 빠지는데, 이 글은 최소 마찰 로 single-node + security 비활성 조합을 일부러 골랐어요. 운영에서 절대 따라 하면 안 되는 조합이라 9번째 섹션 운영 권장 패턴 에 별도로 정리해 뒀습니다.

사전 준비 — Docker Desktop·메모리 4GB+

이 글을 따라가려면 로컬에 세 가지가 갖춰져 있어야 해요. Docker Desktop (또는 OrbStack·colima 같은 대체) 이 깔려 있고, 메모리 4GB 이상 이 Docker 엔진에 할당돼 있어야 합니다. 운영 환경은 8GB+ 가 표준이지만 hands-on 한 사이클은 4GB 로도 충분해요. 마지막으로 curl — 맥/리눅스는 기본 설치, 윈도우는 WSL 또는 git bash 에 들어 있어요.

Docker Desktop 의 리소스 한도는 Settings → Resources → Memory 에서 확인합니다. 기본값이 2GB 인 환경이 종종 있어서 Elasticsearch 컨테이너가 OOMKilled 로 죽는 사고가 잦아요. 4GB 이상으로 올려 두는 게 안전해요.

리눅스 호스트는 한 가지가 더 있어요. 커널 파라미터 vm.max_map_count262144 이상 이어야 ES 가 뜹니다. 기본값이 65530 인 배포판이 많아서 — sudo sysctl -w vm.max_map_count=262144 한 줄을 호스트에 박아 두세요. 맥/윈도우는 Docker Desktop 내부 VM 이 알아서 잡아 줘서 따로 안 해도 됩니다. 이 자리에서 막히는 사고가 가장 흔해서 8번째 섹션 사고 1 로 따로 떼서 다뤘어요.

작성 시점(2026-05-19) 기준 안정 메이저는 Elasticsearch 8.x · Kibana 8.x. 이 글은 elastic/elasticsearch:8.15.0 · docker.elastic.co/kibana/kibana:8.15.0 두 이미지를 사용합니다. 8.15 가 아니어도 8.x 안에서는 거의 그대로 동작해요.

Docker Compose 로 ES + Kibana 한 줄에

작업 폴더 하나를 만들어 둡니다. mkdir es-quickstart && cd es-quickstart 정도면 충분해요. 그 안에 docker-compose.yml 한 파일만 두면 끝입니다.

# docker-compose.yml
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.15.0
    container_name: es-quickstart
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - xpack.security.http.ssl.enabled=false
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
      - bootstrap.memory_lock=true
    ulimits:
      memlock:
        soft: -1
        hard: -1
    ports:
      - "9200:9200"
      - "9300:9300"
    volumes:
      - es-data:/usr/share/elasticsearch/data
    healthcheck:
      test: ["CMD-SHELL", "curl -fs http://localhost:9200/_cluster/health || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 10

  kibana:
    image: docker.elastic.co/kibana/kibana:8.15.0
    container_name: kibana-quickstart
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    ports:
      - "5601:5601"
    depends_on:
      elasticsearch:
        condition: service_healthy

volumes:
  es-data:
    driver: local

읽어 둘 자리가 네 군데 있어요. discovery.type=single-node마스터 선출 없이 노드 한 대로 클러스터를 구성 하는 옵션이에요. 운영에서는 master-eligible 노드 3대 이상이 표준이지만, 학습용은 한 대로 충분합니다.

xpack.security.enabled=false 는 ES 8.x 의 기본 활성 보안 (HTTPS·자체 서명 인증서·자동 비밀번호 생성) 을 끄는 옵션이에요. 이 한 줄 때문에 입문이 훨씬 매끈해져요. 운영에서는 절대 끄면 안 되고, 31편(Security) 에서 다시 다룹니다.

ES_JAVA_OPTS=-Xms1g -Xmx1gJVM (Java Virtual Machine) heap 을 1GB 로 고정해요. ES 는 JVM heap = 컨테이너 메모리의 50%·최대 31GB 가 표준 가이드인데, 학습용은 1GB 면 충분합니다.

memlock + ulimitsswap 으로 밀려나는 사고 를 막는 옵션이에요. Elasticsearch 의 mmap 기반 검색 이 swap 으로 밀리면 응답이 ms → 초 단위로 폭증해서 — 운영은 거의 항상 켜요.

띄우기는 한 줄. docker compose up -d (또는 docker-compose up -d) 를 치면 두 컨테이너가 백그라운드로 뜹니다. 처음 한 번은 이미지를 받느라 몇 분 걸려요. 두 번째부터는 10초 안 에 헬스체크까지 떨어집니다.

상태 확인은 docker compose ps. StateUp (healthy) 이고, kibana-quickstartUp 이면 끝. 안 떨어지면 docker compose logs elasticsearch | tail -50 로 로그를 까서 vm.max_map_count · memory · JVM 셋 중 어느 자리인지 보면 80% 진단 됩니다.

첫 curl 명령 — _cat 한 묶음

가장 먼저 칠 명령 세 개를 묶어서 클러스터가 살아 있는지 한 호흡에 확인해요. ES 의 _cat API사람이 읽기 좋은 텍스트 응답 을 주는 진단용 엔드포인트 모음입니다.

# 클러스터 헬스
curl -s "http://localhost:9200/_cat/health?v"

# 노드 목록
curl -s "http://localhost:9200/_cat/nodes?v"

# 인덱스 목록
curl -s "http://localhost:9200/_cat/indices?v"

?vverbose — 헤더를 같이 찍어 주는 플래그예요. 첫 명령 응답이 이런 모양이면 정상.

epoch      timestamp cluster        status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_active_shards_percent
1747623890 12:24:50  docker-cluster green           1         1      0   0    0    0        0             0                  -                100.0%

statusgreen 이면 모든 primary + replica shard 가 할당됨. yellowprimary 는 OK 인데 replica 미할당. redprimary 중 일부가 미할당 — 데이터 일부 읽기·쓰기 X. single-node 환경은 replica = 1 인 인덱스가 있으면 자연스레 yellow 가 떠요. 학습에서는 무시해도 됩니다.

두 번째 명령은 노드 한 대가 떠 있는지, 세 번째 명령은 지금 인덱스 목록 을 보여 줘요. 처음 띄운 상태라면 시스템 인덱스 (.security-*·.kibana_*) 몇 개 만 보여요. 사용자 인덱스는 다음 절에서 만듭니다.

기본 응답이 JSON 인 일반 API 와 달리 _cat텍스트 표셸 파이프라인 에 그대로 꽂아 쓰기 좋아요. 운영에서 현재 상태 한눈에 보기 용도로 가장 많이 손이 가는 자리예요.

첫 문서 색인·검색

이제 진짜 ES 다운 작업. 문서 한 건 색인 → 한 건 조회 → 검색 쿼리 한 사이클을 돌립니다.

# 1) 문서 색인 — my-index 의 _doc 타입에 id=1
curl -s -X PUT "http://localhost:9200/my-index/_doc/1" \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "Elasticsearch 입문",
    "author": "smartlifen4n",
    "tags": ["search", "lucene", "study"],
    "published_at": "2026-05-19"
  }'

응답에 "result": "created""_version": 1 이 박혀 있으면 색인 성공. 이 순간 ES 가 자동으로 동적 매핑(Dynamic Mapping) 으로 title=text·keyword·author=text·keyword·tags=text·keyword·published_at=date 매핑을 잡아 둬요. 매핑 확인은 curl -s "http://localhost:9200/my-index/_mapping?pretty" 한 줄.

조회는 GET 한 번이면 끝.

curl -s "http://localhost:9200/my-index/_doc/1?pretty"

응답의 _source 자리에 색인한 JSON 이 그대로 박혀 있어요. ES 가 원본 JSON 을 _source 필드에 저장하고, 별도로 Inverted Index 를 만들어 검색에 쓰는 구조 (3편에서 다뤘던 자리) 가 바로 이 응답에서 확인됩니다.

진짜 검색은 _search 엔드포인트.

curl -s -X POST "http://localhost:9200/my-index/_search?pretty" \
  -H 'Content-Type: application/json' \
  -d '{
    "query": {
      "match": {
        "title": "입문"
      }
    }
  }'

응답의 hits.total.value = 1hits.hits[0]._score0.x 양수풀텍스트 검색 + BM25 점수 가 정상 동작하는 자리예요. BM25 (Best Matching 25, Lucene 기본 랭킹 함수) 는 문서 안 단어 빈도와 전체 문서 빈도를 함께 계산 해서 점수를 매기는데, 14편(Full-text 검색) 에서 깊이.

여기까지 가면 Quickstart 의 핵심 사이클 은 한 바퀴 다 돈 거예요. 30분 안에 여기까지 도착했으면 환경 셋업·기본 API 가 손에 잡힌 셈이고, 5편부터 인덱스 설계·매핑·검색 DSL 로 넘어가도 따라가는 데 큰 무리가 없어요.

Kibana Dev Tools — Console UI

같은 명령을 GUI 에서 쳐 볼 차례. 브라우저로 http://localhost:5601 을 열면 Kibana 가 떠요. 보안을 껐기 때문에 로그인 화면 없이 바로 홈으로 진입합니다.

좌측 햄버거 메뉴 → Management → Dev Tools 로 들어가면 화면이 왼쪽 에디터 / 오른쪽 응답 두 칸으로 갈려요. 이 화면이 Console 이고, 일상에서 ES 를 만질 때 가장 손이 많이 가는 자리예요.

쳐 보기는 curl 그대로 가 아니라 축약된 DSL. 예를 들어 위에서 친 문서 색인 을 Dev Tools 에서는 이렇게 씁니다.

PUT /my-index/_doc/2
{
  "title": "Quickstart hands-on",
  "author": "smartlifen4n",
  "tags": ["docker", "kibana", "study"],
  "published_at": "2026-05-19"
}

HTTP 메서드 + 경로 + 본문 만 쓰면 호스트·헤더·인증 은 Kibana 가 알아서 붙여 줘요. curl 대비 한 줄이 짧다 는 게 가장 큰 장점이에요.

세 가지 단축키를 같이 익혀 두면 작업이 빨라집니다. Ctrl+Enter (맥은 Cmd+Enter) 가 현재 커서가 놓인 명령을 실행해요. Ctrl+/ 가 줄 주석. Ctrl+I (맥은 Cmd+I) 가 JSON 본문을 자동 정렬해 줘요. 한 화면에 명령 10개를 쌓아 두고 Ctrl+Enter 로 하나씩 돌리는 게 일상 워크플로예요.

오른쪽 위 시계 아이콘이 Request History 예요. 직전에 친 명령들을 보존해 줘서, 어제 친 검색 쿼리를 다시 꺼내 쓸 수 있어요. 50개까지 자동 보존됩니다.

curl 과 Dev Tools 중 어느 쪽을 쓰느냐는 상황 에 따라요. 셸 스크립트·CI·자동화 는 curl, 탐색·디버깅·시연 은 Dev Tools 가 답이에요. 두 표기 사이의 변환은 Kibana 가 도와줘요 — 명령 옆 ⚙ → Copy as cURL 버튼이 curl 한 줄 로 자동 변환해 줍니다.

다음 단계 — 5편으로 연결

여기까지 따라왔으면 환경 + 첫 사이클 이 끝났고, 다음 자리는 인덱스를 의도적으로 설계해서 만드는 것 이에요. 5편(Index 관리) 에서 create index API · settings · alias · reindex 를 묶어서 다룹니다. 동적 매핑에 의존하지 않고 매핑을 미리 박는 법, 운영에서 alias 로 노출하는 법 두 가지가 핵심.

그 사이에 손에 안 익은 자리는 Dev Tools 에서 같은 명령을 다섯 번 더 쳐 보는 것 으로 메우는 게 좋아요. 색인하는 문서를 상품·블로그 글·로그 한 줄 처럼 형태를 바꿔 가며 넣고, _searchquery.match · query.term · query.range 를 한 번씩 만져 보면 12~16편의 검색 DSL 들이 머리에 훨씬 잘 박혀요.

자주 만나는 사고

사고 1 — vm.max_map_count 미설정으로 ES 미기동

원인 — 리눅스 호스트의 vm.max_map_count 기본값이 65530 인 배포판이 흔해요. ES 가 mmap 으로 segment 파일을 매핑 하면서 최소 262144 를 요구해서, 컨테이너가 bootstrap check failure 로그를 남기고 죽어요.

해결 — 호스트에서 sudo sysctl -w vm.max_map_count=262144 를 즉시 적용하고, /etc/sysctl.confvm.max_map_count=262144 줄을 박아 재부팅에도 살아 남게 합니다. 맥/윈도우는 Docker Desktop 의 내부 VM 이 알아서 잡아 줘서 따로 안 해도 됩니다.

사고 2 — JVM Heap 부족 OOM

원인ES_JAVA_OPTS=-Xms2g -Xmx2g 를 박았는데 Docker Desktop 의 Memory 한도가 2GB 라서, JVM heap + off-heap + Lucene mmap 합산이 컨테이너 한도를 넘어 OOMKilled 가 떨어져요. docker compose psRestarting 이 반복되는 패턴.

해결 — Docker Desktop Memory 를 JVM heap × 2 이상으로 올려요. 학습은 4GB 한도 + heap 1g, 운영은 8GB+ 한도 + heap 4~8g 가 거친 가이드.

사고 3 — 9200·5601 포트 충돌

원인 — 다른 ES 인스턴스·Spring Boot 가 9200·5601 을 이미 점유 중이라 bind: address already in use 에러가 떨어져요.

해결lsof -i :9200 (맥/리눅스) 또는 netstat -ano | findstr 9200 (윈도우) 로 점유 프로세스 확인. 죽이거나, compose 의 ports 매핑을 9201:9200·5602:5601 로 바꿔 외부 포트만 갈아 끼우면 끝.

사고 4 — Kibana 가 ES 를 못 찾음

원인ELASTICSEARCH_HOSTS=http://localhost:9200 처럼 localhost 로 박으면 Kibana 컨테이너 안에서는 자기 자신 을 가리켜서 연결 실패. 컨테이너 네트워크에서는 서비스 이름 으로 가리켜야 해요.

해결ELASTICSEARCH_HOSTS=http://elasticsearch:9200 으로, compose 의 service 이름 을 쓰세요. 이 글의 compose 가 이미 맞춰 둔 상태.

사고 5 — security 비활성 미설정으로 https 강제

원인 — ES 8.x 는 기본으로 security on + 자체 서명 HTTPS 인증서 자동 생성 이라, 옵션 없이 띄우면 curl http://localhost:9200 응답이 empty reply / 401 로 떨어져요.

해결 — 학습 환경은 이 글처럼 xpack.security.enabled=false · xpack.security.http.ssl.enabled=false 두 줄을 박아 plain HTTP 로 띄워요. 운영은 반드시 on — 31편(Security) 에서 자체 서명 → 정식 인증서 전환과 elastic 비밀번호 재설정 까지 다룹니다.

사고 6 — network.host=0.0.0.0 누락

원인single-node + Docker 안에서기본 bind 가 localhost (127.0.0.1) 라서 컨테이너 밖 호스트의 9200 으로는 응답이 안 와요. production mode 자동 전환 + bootstrap check 실패 패턴도 같이 나타나요.

해결network.host=0.0.0.0 또는 network.publish_host=_site_ 환경변수를 추가합니다. 이 글의 compose 는 discovery.type=single-nodedevelopment mode 를 켜 줘서 별도 설정 없이도 외부 접근이 가능해요.

사고 7 — mmapfs 한도 초과

원인Many indices · many segments 환경에서 open file 한도 (nofile) 가 부족하면 Too many open files 가 떨어져요.

해결 — compose 의 ulimitsnofile: 65536 을 추가하거나, 운영 호스트는 /etc/security/limits.confelasticsearch 사용자 한도를 박아 둡니다. 26편(Cluster Operations) 에서 깊이.

운영 권장 패턴

이 글의 compose 는 학습 최단 경로 라 운영에 그대로 쓰면 사고가 납니다. 운영 시작 전에 네 가지를 반드시 갈아 끼우세요.

첫째, security 활성. xpack.security.enabled=true 로 켜고 elastic / kibana_system 계정 비밀번호를 박은 뒤, 자체 서명 인증서 를 정식 CA 로 갈아 끼웁니다. 31편(Security) 의 메인 주제.

둘째, single-node → multi-node. master-eligible 3대 + data 노드 N대 구성이 표준이에요. single-nodesplit-brain 방지 quorum 이 X 라서 운영 데이터에 절대 X. 26편(Cluster Operations) 에서 깊이.

셋째, 데이터 볼륨 분리. 이 글은 named volume 한 개에 데이터를 박지만, 운영은 전용 디스크 (NVMe SSD)bind mount 로 잡아 줘요. iops · throughput · latency 셋이 ES 성능의 60% 를 결정해요. 30편(Performance) 에서 깊이.

넷째, 모니터링 표준 셋업. _cluster/health · _nodes/stats · slow log 세 가지를 Grafana 또는 Kibana 대시보드에 박아 두는 게 표준. 30편(Monitoring) 에서 깊이.

시험 직전 한 번 더 — 압축 노트

  • Docker Compose 한 파일 로 ES + Kibana 두 컨테이너를 한 번에 띄움. 이미지: elastic/elasticsearch:8.15.0 + kibana:8.15.0.
  • discovery.type=single-node = 마스터 선출 없이 한 대로 클러스터 구성. 학습용.
  • xpack.security.enabled=false = 8.x 의 기본 활성 보안을 꺼서 plain HTTP. 운영 X.
  • ES_JAVA_OPTS=-Xms1g -Xmx1g = JVM heap 고정. 학습 1GB, 운영은 컨테이너 메모리의 50%·최대 31GB.
  • 첫 사이클: _cat/health_cat/nodes_cat/indicesPUT /my-index/_doc/1GET /my-index/_doc/1POST /my-index/_search.
  • _cat API = 사람이 읽기 좋은 텍스트 응답. 진단용. ?v 로 헤더 같이.
  • health 상태 = green (정상) · yellow (replica 미할당, single-node 의 정상 모습) · red (primary 미할당, 데이터 손실 위험).
  • 동적 매핑(Dynamic Mapping) = 첫 색인 때 ES 가 자동으로 필드 타입 추론. 운영은 strict 권장.
  • BM25 = Lucene 기본 랭킹. hits.hits[].\_score 자리.
  • Kibana Dev Tools = Management → Dev Tools. HTTP 메서드 + 경로 + 본문 형태.
  • 단축키: Ctrl/Cmd+Enter 실행, Ctrl+/ 주석, Ctrl/Cmd+I JSON 정렬.
  • Request History 50개 자동 보존, ⚙ → Copy as cURL 변환 버튼.
  • 7대 사고: vm.max_map_count · JVM OOM · 포트 충돌 · Kibana 가 localhost 로 찾기 · security on/off · network.host · nofile 한도.
  • 운영 X 조합: single-node + security off + heap 1g + named volume. 운영은 multi-node + security on + 4~8g + NVMe bind mount.
  • 리눅스 호스트는 vm.max_map_count=262144 가 필수.
  • 학습 4GB · 운영 8GB+ 가 Docker Memory 한도 거친 가이드.

시리즈 다른 편

  • 이전 글 = 3편 Lucene 내부 — Segment·Inverted Index·Posting List
  • 다음 글 = 5편 Index 관리 — Create·Settings·Alias·Reindex
  • 6편 = ILM (Index Lifecycle Management) — Rollover·Hot·Warm·Cold·Delete
  • 8편 = Mapping Deep — Static·Dynamic·Multi-field·Runtime
  • 11편 = Korean Analyzer — Nori·mecab-ko·사용자 사전
  • 26편 = Cluster Operations — Node 역할·Quorum·Allocation
  • 30편 = Performance — Heap·GC·Slow Log·Profile API
  • 31편 = Security — RBAC·TLS·API Key·Audit
  • 32편 = Spring Data Elasticsearch — Repository·Template·POJO

한 줄 정리 — Docker Compose 한 파일 + _cat/health + PUT /my-index/_doc/1 + Dev Tools 단축키 (Ctrl+Enter) 까지, Elasticsearch 첫 사이클 30분 hands-on. 운영 X 조합 (single-node + security off) 으로 마찰을 줄이고, 5편부터 의도적 인덱스 설계로 넘어가는 디딤돌.

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!