1. Elasticsearch Docker 구축 (docker-compose)
개발 및 테스트 편의를 위해 보안 설정(HTTPS, 인증)을 끄고 단일 노드(Single Node)로 구성하겠습니다.
폴더 구조:
es-crud-project/
├── docker-compose.yml
└── main.py
docker-compose.yml 작성:
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
container_name: es-container
environment:
- discovery.type=single-node
- xpack.security.enabled=false # 개발용: 보안 비활성화 (HTTPS/ID/PW 없이 접속)
- "ES_JAVA_OPTS=-Xms512m -Xmx512m" # 메모리 제한 (로컬 환경 부담 줄임)
ports:
- "9200:9200"
networks:
- es-net
# (선택사항) 데이터 시각화를 위한 Kibana
kibana:
image: docker.elastic.co/kibana/kibana:8.12.0
container_name: kibana-container
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- "5601:5601"
depends_on:
- elasticsearch
networks:
- es-net
networks:
es-net:
driver: bridge
실행 명령어:
터미널에서 해당 폴더로 이동 후 아래 명령어를 실행합니다.
docker-compose up -d
확인: 브라우저에서 http://localhost:9200에 접속했을 때 JSON 응답이 오면 성공입니다.
2. Python API 프로그램 작성 (FastAPI)
빠르고 현대적인 웹 프레임워크인 FastAPI와 공식 Elasticsearch Python 클라이언트를 사용합니다.
라이브러리 설치:
pip install fastapi uvicorn elasticsearch
main.py 작성:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from elasticsearch import Elasticsearch, NotFoundError
app = FastAPI()
# 1. Elasticsearch 연결 설정
# Docker에서 보안을 껐으므로 http://localhost:9200으로 접속합니다.
es = Elasticsearch("http://localhost:9200")
# 인덱스 이름 (RDBMS의 Table과 유사)
INDEX_NAME = "my_products"
# 데이터 모델 정의 (Request Body 검증용)
class Product(BaseModel):
name: str
price: int
category: str = None
# --- CRUD API 구현 ---
# 1. CREATE (데이터 생성)
@app.post("/products/")
def create_product(product: Product):
# document를 인덱스에 저장
resp = es.index(index=INDEX_NAME, document=product.dict())
return {"status": "success", "id": resp["_id"], "data": product}
# 2. READ (데이터 조회 - ID로 조회)
@app.get("/products/{item_id}")
def read_product(item_id: str):
try:
resp = es.get(index=INDEX_NAME, id=item_id)
return {"id": resp["_id"], "data": resp["_source"]}
except NotFoundError:
raise HTTPException(status_code=404, detail="Item not found")
# 2-1. READ ALL (검색 - 모든 데이터 조회)
@app.get("/products/")
def search_products(keyword: str = None):
if keyword:
# 키워드가 있으면 이름에서 검색
query = {
"match": {
"name": keyword
}
}
else:
# 키워드가 없으면 전체 조회 (match_all)
query = {"match_all": {}}
resp = es.search(index=INDEX_NAME, query=query)
# 검색 결과 가공
results = []
for hit in resp['hits']['hits']:
results.append({"id": hit["_id"], "data": hit["_source"]})
return {"count": len(results), "results": results}
# 3. UPDATE (데이터 수정)
@app.put("/products/{item_id}")
def update_product(item_id: str, product: Product):
try:
# doc: 부분 업데이트할 내용
es.update(index=INDEX_NAME, id=item_id, doc=product.dict())
return {"status": "updated", "id": item_id, "data": product}
except NotFoundError:
raise HTTPException(status_code=404, detail="Item not found")
# 4. DELETE (데이터 삭제)
@app.delete("/products/{item_id}")
def delete_product(item_id: str):
try:
es.delete(index=INDEX_NAME, id=item_id)
return {"status": "deleted", "id": item_id}
except NotFoundError:
raise HTTPException(status_code=404, detail="Item not found")
3. API 실행 및 테스트 방법

API 서버 실행:
터미널에서 다음 명령어를 입력합니다.
uvicorn main:app --reload
테스트 방법 (Swagger UI 사용):
FastAPI는 자동으로 문서 페이지를 생성해줍니다. 브라우저를 열고 아래 주소로 접속하세요.
여기서 버튼을 클릭하여 바로 테스트할 수 있습니다.
수동 테스트 예시 (CRUD 흐름)
-
Create (생성):
-
POST /products/
-
Body: {“name”: “MacBook Pro”, “price”: 3000000, “category”: “Electronics”}
-
결과: 생성된 id를 복사해 둡니다 (예: AbC123…).
-
-
Read (ID 조회):
-
GET /products/{item_id}
-
item_id에 위에서 복사한 ID 입력.
-
-
Search (검색):
-
GET /products/?keyword=MacBook
-
Elasticsearch의 검색 엔진 기능을 통해 “MacBook”이 포함된 데이터를 찾습니다.
-
-
Update (수정):
-
PUT /products/{item_id}
-
Body: {“name”: “MacBook Pro M3”, “price”: 3500000, “category”: “Electronics”}
-
-
Delete (삭제):
-
DELETE /products/{item_id}
-
요약
-
Docker Compose를 이용해 보안 설정을 끈 ES 8.x 버전을 실행했습니다.
-
Python Elasticsearch Client를 이용해 localhost:9200에 연결했습니다.
-
FastAPI로 RESTful API를 만들어 index(생성), get/search(조회), update(수정), delete(삭제) 기능을 구현했습니다.