24/08 기준 최신 버전인 8.15 로 진행한다.
해당 포스팅은 elastic 에 대한 전반적인 개념은 다루고 있지 않다.
다만 single-node 로 구성된 것과, multi-node 로 구성된 것의 차이 정도는 아래 간략하게 설명한다.
Elasticsearch는 분산 검색 및 분석 엔진으로, 다음과 같은 주요 구성 요소로 이루어져 있다.
Elasticsearch에서는 여러 유형의 노드가 있지만, 주로 Master 노드와 Data(Cluster) 노드로 구분된다.
역할:
특징:
설정:
node.roles: [ master ]로 설정하여 마스터 전용 노드로 구성할 수 있음역할:
특징:
설정:
node.roles: [ data ]로 설정하여 데이터 전용 노드로 구성할 수 있음데이터 저장:
리소스 사용:
확장성:
작업 유형:
장애 영향:
Elasticsearch의 특정 구성 및 요구사항에 따라 마스터 노드와 데이터 노드의 역할을 분리하거나 결합할 수 있다.
대규모 클러스터에서는 역할을 분리하는 것이 일반적이지만, 소규모 클러스터에서는 모든 노드가 마스터와 데이터 역할을 동시에 수행할 수 있다.
우선 single-node 는 별도의 docker-compose 없이 진행해보자.
docker-compose 로 바로 설치할 사람은 multi node 구성 (docker-compose) 에서 진행하자.
docker 가 설치된 환경에서 cli 명령어로 진행한다.
# Elastic stack 의 구성 요소들이 원할하게 통신하기 위한 네트워크 구성
$ docker network create elastic
# 24/08 기준 최신 = 8.15.0 가급적 latest 말고 버전을 명시하자.
$ docker pull docker.elastic.co/elasticsearch/elasticsearch:8.15.0
# image 생성 확인
$ docker images
# image 를 기반으로 es01 이라는 컨테이너 띄우기
$ docker run --name es01 --net elastic -p 9200:9200 -it docker.elastic.co/elasticsearch/elasticsearch:8.15.0

# 기동중인 컨테이너 확인
$ docker ps -a
# es01 컨테이너의 에러 로그 json 형태로 출력
$ docker logs es01 | grep 'ERROR' | jq .
# jq 가 설치되지 않았다면 아래 명령어로 설치한다. (ubuntu 기준)
$ sudo apt udpate
$ sudo apt install jq
{
"@timestamp": "2024-08-12T10:01:15.462Z",
"log.level": "ERROR",
"message": "node validation exception\n[1] bootstrap checks failed. You must address the points described in the following [1] lines before starting Elasticsearch. For more information see [https://www.elastic.co/guide/en/elasticsearch/reference/8.15/bootstrap-checks.html]\nbootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]; for more information see [https://www.elastic.co/guide/en/elasticsearch/reference/8.15/_maximum_map_count_check.html]",
"ecs.version": "1.2.0",
"service.name": "ES_ECS",
"event.dataset": "elasticsearch.server",
"process.thread.name": "main",
"log.logger": "org.elasticsearch.bootstrap.Elasticsearch",
"elasticsearch.node.name": "b8fc11aacbdd",
"elasticsearch.cluster.name": "docker-cluster"
}
위를 보면
max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
라는 로그가 보인다. 이는 아래와 같이 메모리 영역을 더 넓힐 수 있다.
# 시스템 설정 파일 열기
$ sudo vi /etc/sysctl.conf
# 마지막 줄에 아래 내용을 추가한다.
vm.max_map_count=262144
# 즉시 적용
$ sudo sysctl -p
다시 컨테이너를 기동해보자.
$ docker start es01
$ docker ps -a

ElasticSearch 8.x 버전부터는 클라이언트에서 접속하기 위해서는 비밀번호와 SSL 인증서 정보가 필요하다.
로그로도 확인할 수 있다.
$ docker logs es01
✅ Elasticsearch security features have been automatically configured!
✅ Authentication is enabled and cluster connections are encrypted.
ℹ️ Password for the elastic user (reset with `bin/elasticsearch-reset-password -u elastic`):
byH4ZsCd+XIX_uSsZxxM
ℹ️ HTTP CA certificate SHA-256 fingerprint:
63b953f73c22500915986cecea40f5575ff47074c08a6a445c77bcac06a85143
ℹ️ Configure Kibana to use this cluster:
• Run Kibana and click the configuration link in the terminal when Kibana starts.
• Copy the following enrollment token and paste it into Kibana in your browser (valid for the next 30 minutes):
eyJ2ZXIiOiI4LjE0LjAiLCJhZHIiOlsiMTcyLjE4LjAuMjo5MjAwIl0sImZnciI6IjYzYjk1M2Y3M2MyMjUwMDkxNTk4NmNlY2VhNDBmNTU3NWZmNDcwNzRjMDhhNmE0NDVjNzdiY2FjMDZhODUxNDMiLCJrZXkiOiJkWUliUnBFQjQyWExSUVdwcVNCZjpPWU1SeWdnblJNLWVVbmRpUmJLRUVBIn0=
ℹ️ Configure other nodes to join this cluster:
• Copy the following enrollment token and start new Elasticsearch nodes with `bin/elasticsearch --enrollment-token <token>` (valid for the next 30 minutes):
eyJ2ZXIiOiI4LjE0LjAiLCJhZHIiOlsiMTcyLjE4LjAuMjo5MjAwIl0sImZnciI6IjYzYjk1M2Y3M2MyMjUwMDkxNTk4NmNlY2VhNDBmNTU3NWZmNDcwNzRjMDhhNmE0NDVjNzdiY2FjMDZhODUxNDMiLCJrZXkiOiJkb0liUnBFQjQyWExSUVdwcVNCZjpXZFpmVXNubFQ2R3BBalpjNjdBd2p3In0=
If you're running in Docker, copy the enrollment token and run:
`docker run -e "ENROLLMENT_TOKEN=<token>" docker.elastic.co/elasticsearch/elasticsearch:8.15.0`
$ docker cp es01:/usr/share/elasticsearch/config/certs/http_ca.crt .
$ ls

인증서까지 준비가 되었으니, curl 로 접속해보자.
비밀번호는 위 docker log es01 에서 보았던 본인만의 비밀번호를 입력하면 된다.
$ curl --cacert http_ca.crt -u elastic https://localhost:9200

만약 비밀번호를 초기화하고 싶다면, 아래 명령어로 해결할 수 있다.
$ docker exec -it es01 /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic
# iamge pull
$ docker pull docker.elastic.co/kibana/kibana:8.15.0
# kib01 이라는 컨테이너명으로 띄우기
$ docker run --name kib01 --net elastic -p 5601:5601 docker.elastic.co/kibana/kibana:8.15.0
이후 웹에서 localhost:5601 에 접속해보자. (localhost -> 서버 IP)

토큰을 입력하라는 modal 이 뜨면, 아래 명령어로 token 을 가져오자.
es01 컨테이너 내부에서 관리하는 token 을 출력하는 명령어이다.
docker exec -it es01 /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibana

그러면 또 귀찮게 6자리 인증번호를 입력하라고 한다..

아래는 kib01 컨테이너 내부에서 관리하는 인증코드를 출력하는 명령어이다.
$ docker exec -it kib01 ./bin/kibana-verification-code

그러면 여기까지 성공적으로 왔다. 이제 로그인만 남았다.
Username : elastic
Password : 아까 es01 컨테이너에서 발급받은 비밀번호 입력

까먹었어도 괜찮다. 또 발급받으면 된다.
$ docker exec -it es01 /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic
그러면 ElasticSearch + Kibana 설치 및 환경 구성이 끝났다. 축하한다.

우선 node 등록에 필요한 token 을 발급받는다.
토큰의 유효기간은 30분이니 참고하자.
$ docker exec -it es01 /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s node
docker run -e ENROLLMENT_TOKEN="<token>" --name es02 --net elastic -it -m 1GB docker.elastic.co/elasticsearch/elasticsearch:8.15.0
아래와 같이 <token> 부분에 발급받은 토큰을 넣으면 된다.

이후 아래 cat nodex API 를 활용해 노드가 추가됐음을 인증한다.
$ curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD https://localhost:9200/_cat/nodes
위 설정들은 귀찮은 작업이 한 두개가 아니었다.
image pull 할 것도 없이 docker-compose.yml 에서 다 정의해보자.
# 설정을 모아놓을 디렉토리 생성
$ mkdir ~/elasticsearch
# .env 파일 생성, 확인, 편집
$ vi .env
.env 파일 내부는 아래와 같이 공식 문서에서 버전, 비밀번호만 조금 변경했다.
라이센스는 basic = 기본 기능을 무제한으로 제공하며,
trial = 유료 기능을 30일 제한으로 제공하니 참고하자.
ElasticSearch docker 설치 공식문서
# .env
# Password for the 'elastic' user (at least 6 characters)
ELASTIC_PASSWORD=elastic
# Password for the 'kibana_system' user (at least 6 characters)
KIBANA_PASSWORD=kibana_system
# Version of Elastic products
STACK_VERSION=8.15.0
# Set the cluster name
CLUSTER_NAME=docker-cluster
# Set to 'basic' or 'trial' to automatically start the 30-day trial
LICENSE=basic
#LICENSE=trial
# Port to expose Elasticsearch HTTP API to the host
ES_PORT=9200
#ES_PORT=127.0.0.1:9200
# Port to expose Kibana to the host
KIBANA_PORT=5601
#KIBANA_PORT=80
# Increase or decrease based on the available host memory (in bytes)
MEM_LIMIT=1073741824
# Project namespace (defaults to the current folder name if not set)
#COMPOSE_PROJECT_NAME=myproject
docker-compose.yml 을 작성하자.
docker-compose 로 build 및 실행할 때에는 docker-compose.yml 파일이 존재하는 위치에서 docker-compose 명령어를 실행해야 됨에 참고하자.
위 mkdir ~/elasticsearch 로 설정 파일을 모아놓은 디렉토리를 만든 이유이다.
# docker-compose.yml
version: "2.2"
services:
setup:
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
volumes:
- certs:/usr/share/elasticsearch/config/certs
user: "0"
command: >
bash -c '
if [ x${ELASTIC_PASSWORD} == x ]; then
echo "Set the ELASTIC_PASSWORD environment variable in the .env file";
exit 1;
elif [ x${KIBANA_PASSWORD} == x ]; then
echo "Set the KIBANA_PASSWORD environment variable in the .env file";
exit 1;
fi;
if [ ! -f config/certs/ca.zip ]; then
echo "Creating CA";
bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip;
unzip config/certs/ca.zip -d config/certs;
fi;
if [ ! -f config/certs/certs.zip ]; then
echo "Creating certs";
echo -ne \
"instances:\n"\
" - name: es01\n"\
" dns:\n"\
" - es01\n"\
" - localhost\n"\
" ip:\n"\
" - 127.0.0.1\n"\
" - name: es02\n"\
" dns:\n"\
" - es02\n"\
" - localhost\n"\
" ip:\n"\
" - 127.0.0.1\n"\
" - name: es03\n"\
" dns:\n"\
" - es03\n"\
" - localhost\n"\
" ip:\n"\
" - 127.0.0.1\n"\
> config/certs/instances.yml;
bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key;
unzip config/certs/certs.zip -d config/certs;
fi;
echo "Setting file permissions"
chown -R root:root config/certs;
find . -type d -exec chmod 750 \{\} \;;
find . -type f -exec chmod 640 \{\} \;;
echo "Waiting for Elasticsearch availability";
until curl -s --cacert config/certs/ca/ca.crt https://es01:9200 | grep -q "missing authentication credentials"; do sleep 30; done;
echo "Setting kibana_system password";
until curl -s -X POST --cacert config/certs/ca/ca.crt -u "elastic:${ELASTIC_PASSWORD}" -H "Content-Type: application/json" https://es01:9200/_security/user/kibana_system/_password -d "{\"password\":\"${KIBANA_PASSWORD}\"}" | grep -q "^{}"; do sleep 10; done;
echo "All done!";
'
healthcheck:
test: ["CMD-SHELL", "[ -f config/certs/es01/es01.crt ]"]
interval: 1s
timeout: 5s
retries: 120
es01:
depends_on:
setup:
condition: service_healthy
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
volumes:
- certs:/usr/share/elasticsearch/config/certs
- esdata01:/usr/share/elasticsearch/data
ports:
- ${ES_PORT}:9200
environment:
- node.name=es01
- cluster.name=${CLUSTER_NAME}
- cluster.initial_master_nodes=es01
- discovery.seed_hosts=es02,es03
- node.roles=master
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
- bootstrap.memory_lock=true
- xpack.security.enabled=true
- xpack.security.http.ssl.enabled=true
- xpack.security.http.ssl.key=certs/es01/es01.key
- xpack.security.http.ssl.certificate=certs/es01/es01.crt
- xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
- xpack.security.transport.ssl.enabled=true
- xpack.security.transport.ssl.key=certs/es01/es01.key
- xpack.security.transport.ssl.certificate=certs/es01/es01.crt
- xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
- xpack.security.transport.ssl.verification_mode=certificate
- xpack.license.self_generated.type=${LICENSE}
mem_limit: ${MEM_LIMIT}
ulimits:
memlock:
soft: -1
hard: -1
healthcheck:
test:
[
"CMD-SHELL",
"curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'",
]
interval: 10s
timeout: 10s
retries: 120
es02:
depends_on:
- es01
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
volumes:
- certs:/usr/share/elasticsearch/config/certs
- esdata02:/usr/share/elasticsearch/data
environment:
- node.name=es02
- cluster.name=${CLUSTER_NAME}
- cluster.initial_master_nodes=es01
- discovery.seed_hosts=es01,es03
- node.roles=data
- bootstrap.memory_lock=true
- xpack.security.enabled=true
- xpack.security.http.ssl.enabled=true
- xpack.security.http.ssl.key=certs/es02/es02.key
- xpack.security.http.ssl.certificate=certs/es02/es02.crt
- xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
- xpack.security.transport.ssl.enabled=true
- xpack.security.transport.ssl.key=certs/es02/es02.key
- xpack.security.transport.ssl.certificate=certs/es02/es02.crt
- xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
- xpack.security.transport.ssl.verification_mode=certificate
- xpack.license.self_generated.type=${LICENSE}
mem_limit: ${MEM_LIMIT}
ulimits:
memlock:
soft: -1
hard: -1
healthcheck:
test:
[
"CMD-SHELL",
"curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'",
]
interval: 10s
timeout: 10s
retries: 120
es03:
depends_on:
- es02
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
volumes:
- certs:/usr/share/elasticsearch/config/certs
- esdata03:/usr/share/elasticsearch/data
environment:
- node.name=es03
- cluster.name=${CLUSTER_NAME}
- cluster.initial_master_nodes=es01
- discovery.seed_hosts=es01,es02
- node.roles=data
- bootstrap.memory_lock=true
- xpack.security.enabled=true
- xpack.security.http.ssl.enabled=true
- xpack.security.http.ssl.key=certs/es03/es03.key
- xpack.security.http.ssl.certificate=certs/es03/es03.crt
- xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
- xpack.security.transport.ssl.enabled=true
- xpack.security.transport.ssl.key=certs/es03/es03.key
- xpack.security.transport.ssl.certificate=certs/es03/es03.crt
- xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
- xpack.security.transport.ssl.verification_mode=certificate
- xpack.license.self_generated.type=${LICENSE}
mem_limit: ${MEM_LIMIT}
ulimits:
memlock:
soft: -1
hard: -1
healthcheck:
test:
[
"CMD-SHELL",
"curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'",
]
interval: 10s
timeout: 10s
retries: 120
kibana:
depends_on:
es01:
condition: service_healthy
es02:
condition: service_healthy
es03:
condition: service_healthy
image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
volumes:
- certs:/usr/share/kibana/config/certs
- kibanadata:/usr/share/kibana/data
ports:
- ${KIBANA_PORT}:5601
environment:
- SERVERNAME=kibana
- ELASTICSEARCH_HOSTS=https://es01:9200
- ELASTICSEARCH_USERNAME=kibana_system
- ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
- ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt
mem_limit: ${MEM_LIMIT}
healthcheck:
test:
[
"CMD-SHELL",
"curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'",
]
interval: 10s
timeout: 10s
retries: 120
volumes:
certs:
driver: local
esdata01:
driver: local
esdata02:
driver: local
esdata03:
driver: local
kibanadata:
driver: local
위 내용을 간략히 요약하면, .env 에 있는 설정을 적용하고
SSL 인증을 넣어 node 를 3개 띄운다는 설정이다.
es01 컨테이너를 Master 노드로 잡고, es02, es03 컨테이너를 Data 노드로 잡아두었다.
일반적으로 마스터 노드는 데이터를 저장하지 않고 인덱싱 및 관리를 담당하니, 데이터를 저장시키는 역할이 아닌 master 로서의 역할만 가지고 있는 것이 좋다.
.env 파일을 docker-compose 에 적용시키고 기동해보자.
앞서 말했듯이, docker-compose 가 존재하는 디렉토리에서 실행해야 한다.
# env설정을 적용함.
docker-compose config
# 기동
docker-compose up -d
docker-compose.yml 에 적혀있던 echo 출력들이 잘 되어 아래와 같이 나온 모습이다.

컨테이너명들을 확인해보고, 인증서를 적용하자.
$ docker ps

elasticsearch-es-0?-? 으로 node (컨테이너) 들이 기동된 것이 확인된다.
elasticsearch-es01-1 컨테이너의 인증서를 밖으로 가져오자.
# elasticsearch-es01-1
$ docker cp elasticsearch-es01-1:/usr/share/elasticsearch/config/certs/ca .

인증서를 가져왔으니, 이제 curl 로 접속을 테스트해보자.
비밀번호는 위 .env 파일에서 적용한 elasticsearch 의 비밀번호를 입력하면 된다. (ELASTIC_PASSWORD)
$ curl --cacert ca.crt -u elastic https://localhost:9200alhost:9200

인증서는 잘 보관해두고, kibana 도 접속해보자.
웹에서 localhost:5601 에 접속하자. localhost -> ip
여기에서의 비밀번호 역시 .env 에서 적용한 비밀번호를 입력하면 된다.
KIBANA_PASSWORD=kibana_system 은 kibana 내부적으로 사용하는 비밀번호 이므로, ELASTIC_PASSWORD 를 사용한다.

설정은 끝났다.
만약 Data node 를 추가하고 싶다면,
docker-compose.yml 에서 es02 나 es03 설정을 그대로 복사해 es04 를 만들면 된다.
이 외로 MetricBeat, FileBeat, LogStash, APM, Fleet 등을 추가로 설치해 데이터 저장소 뿐 아니라 외부 로그 및 통합 관제로서의 역할도 할 수 있으나,
해당 기능들은 K8s 를 사용하는 상태라면 굳이 필요가 없다.
오픈소스가 잘 되어있기도 하고, 배포 / 모니터링 / 관리를 목적으로 사용하는 k8s 에서 담당하는 것이 맞다고 생각된다.
만약 위 기능들을 사용하고 싶다면
https://www.youtube.com/watch?v=q74_FfM7sn0&list=PLPatHYWw1RVsoX4jww-N4W6x-TscezmaC&index=4
에서 설정 방법들을 확인하자.