[Elasticsearch] Kibana ๊ตฌ์ฑ (with Docker)
Docker Compose ๊ธฐ๋ฐ์ผ๋ก Kibana + Elasticsearch ์คํ์ ๋ง์์ ์ฌ๋ฆฌ๋ ๋ฒ์ ๋๊ฐ ๋ค๋ค๋ณด๊ฒ ๋ค.
Kibana๋ Elasticsearch Stack์ ์์๋ ๋์๋ณด๋ ์ ์ฉ ํ๊ฒฝ์ด๋ค. ์ด๊ฒ ์์ฒด๋ก ๋ญ ์์ฒญ๋๊ฑธ ํ์ง ์๊ณ , ๋ณด์ฌ์ฃผ๋ ๋์๋ณด๋ ์ญํ ๋ง ํ๋ค. Grafana Dashboard์ ๋์๋๋ค๊ณ ๋ณด๋ฉด ๋๋ค.
Elasticsearch ๊ฐ๋ฐ์ ์ํ ๊ฐ๋ฐ/ํ ์คํธ ๋๊ตฌ, ๋ณด์ ๊ด๋ฆฌ, ์์คํ ๋ฆฌ์์ค ๋ชจ๋ํฐ๋ง, ๋ฉํธ๋ฆญ ๊ด๋ฆฌ ๋ฑ ๋ชจ๋ํฐ๋ง/๊ด๋ฆฌ์ ํ์ํ ๊ฑฐ์ ๋ชจ๋ ๊ฒ์ด ์ฌ์ธ์์ผ๋ก ๋ค์ด์๋๊ฒ ํน์ง์ด๋ค. ์ฌ์ฉ์ฑ๋ ๋์์ง ์๋ค.
Docker compose ๊ธฐ๋ฐ์ผ๋ก elasticsearch์ kibana๋ฅผ ๊ฐ๋จํ๊ฒ ๋์์ ์ฐ๊ฒฐํ๋ ๋ฒ์ ๋ค๋ค๋ณด๊ฒ ๋ค.
ํด๋ฌ์คํฐ ๊ตฌ์ฑ์ด๋ ๊ณ ๊ฐ์ฉ์ฑ ๋ฑ์ ๊ณ ๋ คํ์ง ์๋๋ค.
Elasticsearch ๊ตฌ์ฑ
์ผ๋จ elasticsearch๋ฅผ ๋จผ์ ๋์์ผ ํ๋ค.
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.18.0
container_name: elasticsearch
environment:
- node.name=elasticsearch
- cluster.name=elastic-cluster
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- xpack.security.enabled=true
- xpack.security.enrollment.enabled=true
- xpack.security.http.ssl.enabled=false
- xpack.security.transport.ssl.enabled=false
- xpack.security.authc.token.enabled=true
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- elasticsearch_data:/usr/share/elasticsearch/data
ports:
- "19200:9200"
- "19300:9300"
networks:
- elastic
healthcheck:
test: ["CMD-SHELL", "curl -s http://localhost:9200 > /dev/null || exit 1"]
interval: 10s
timeout: 5s
retries: 3
elasticsearch๊ฐ ๋ฌ ๋ค์์ kibana๊ฐ ๋ ์ผ ํ๊ธฐ ๋๋ฌธ์, ๋ด๋์ง๋ฅผ ํ์ธํ๋ ํฌ์ค์ฒดํฌ๋ฅผ ๊ตฌ์ฑํ๋ค.
๊ทธ ๋ค์์๋ ํจ์ค์๋์ ํ ํฐ ๋ฑ์ ๋ฐ๊ธํด์ค์ผ ํ๋ค.
์ด๊ฒ ์ข ์ง์ฆ๋๋๊ฒ, Docker ์ปจํ
์ด๋ ์์ค์์๋ ํ๊ฒฝ๋ณ์๋ก ํจ์ค์๋๋ ํ ํฐ ๋ฑ์ ๋ฐ๋ก ์์ฑํ๋๋ก ์ง์ ํ ์๊ฐ ์๋ค. ์์ ์๋ ๋๋๊ฑฐ ๊ฐ์๋ฐ ์ต์ elasticsearch ๊ธฐ์ค์ผ๋ก๋ ์๋๋ค.
FATAL Error: [config validation of [elasticsearch].username]: value of "elastic" is forbidden. This is a superuser account that cannot write to system indices that Kibana needs to function. Use a service account token instead. Learn more: https://www.elastic.co/guide/en/elasticsearch/reference/8.0/service-accounts.html
์ด์ ๋ฒ์ ์ธ 6์ด๋ 7 ๋ฑ์์๋ ๊ธฐ๋ณธ ๊ณ์ ์ด elastic:changeme์๋๋ฐ, username์ด elastic์ธ ๊ฒ์ ๋์ผํ์ง๋ง ํจ์ค์๋๊ฐ ๊ธฐ๋ณธ์ผ๋ก ์ค์ ๋์ง๋ ์์ ๋ฟ๋๋ฌ, ํ๊ฒฝ๋ณ์๋ก ์ง์ ํ์ง๋ ๋ชปํ๋ค. ์ ์ด๋ฐ์๋ก ๋ง๋ ๊ฑฐ์ง?
Elasticsearch ํจ์ค์๋ ์ค์
์๋ฌดํผ ๊ทธ๋์ ํจ์ค์๋๋ฅผ ์ด๊ธฐํํ๋ ค๋ฉด elasticsearch-reset-password ๊ฐ์ ๋๊ตฌ๋ฅผ ์จ์ผ ํ๋ค.
password-setter:
image: docker:latest
container_name: password-setter
command: >
/bin/sh -c "
if [ -f /config/elastic_password.env ]; then
echo 'Password has already been set. Skipping.';
exit 0;
fi;
echo 'Waiting for Elasticsearch to be ready before setting password...';
sleep 5;
echo 'Setting password for elastic user...';
PASSWORD=$(docker exec elasticsearch bin/elasticsearch-reset-password -u elastic -s -b -a);
echo \"ELASTIC_PASSWORD=$$PASSWORD\" > /config/elastic_password.env;
echo 'Password set successfully.';
"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./config:/config
depends_on:
elasticsearch:
condition: service_healthy
์๋ํ๋ฅผ ์ํด ๊ทธ๊ฑธ ๋์ ์ด์ฃผ๋ ์ผํ์ฑ ํ๋ก์ธ์ค๋ฅผ ๋ ๋ฐ๋ก ๋ง๋ค์๋ค.
์ด๋ฌ๋ฉด ํ์ฌ ๋๋ ํ ๋ฆฌ ๊ธฐ์ค์ผ๋ก config ํด๋์ ํจ์ค์๋ ํ์ผ์ด ์์ฑ๋๋ค.
ํค๋ฐ๋ ํ ํฐ ์์ฑ
์ด๊ฒ์ด ๋์ด ์๋๋ค.
ํค๋ฐ๋๋ ๋ ์ด์ํ ์์ฒด์ ์ธ ๋ณด์ ์ ์ฑ
์ ๊ฐ์ง๊ณ ์๋๋ฐ, ๊ธฐ๋ณธ๊ณ์ ์ธ elastic ๊ณ์ ์ผ๋ก๋ ๋ก๊ทธ์ธ์ ํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
์์ ๊ตฌ๋ฒ์ ์ ์ด๋ฐ๊ฑฐ ์๋๊ฑฐ๊ฐ์๋ฐ, ์ด๋์๊ฐ ์ด๋ฐ๊ฒ ์๊ฒผ๋ค.
๊ทธ๋์ ํ ํฐ์ ๋ ๋ฐ๊ธํด์ค์ผ ํ๋ค.
๋ฐฉ๊ธ ๋ง๋ ํจ์ค์๋๋ฅผ ์ฝ์ด์ ๋์ ์๊ณ ๋ฐ์์ค๋๋ก ๊ตฌ์ฑํ๋ค.
kibana-token-setter:
image: alpine:latest
container_name: kibana-token-setter
command: >
sh -c "
source /config/elastic_password.env
env
ELASTIC_PASSWORD=$${ELASTIC_PASSWORD}
echo $$ELASTIC_PASSWORD
if [ -f /config/kibana_token.env ]; then
echo 'Kibana service token already exists. Skipping creation.';
exit 0;
fi;
if [ -f /config/kibana_token.env ]; then
echo 'Kibana token file exists. Skipping creation.';
exit 0;
fi;
echo 'Creating Kibana service token...';
apk add --no-cache curl jq;
echo 'Creating Kibana service token...';
# ์๋น์ค ํ ํฐ ์์ฑ API ํธ์ถ (๋น๋ฐ๋ฒํธ ๋ณ์๋ฅผ ํฐ๋ฐ์ดํ๋ก ๊ฐ์ธ๊ณ $$๋ก ์ด์ค์ผ์ดํ)
TOKEN_RESPONSE=$(curl -s -X POST 'http://elasticsearch:9200/_security/service/elastic/kibana/credential/token/kibana?pretty' -u "elastic:$${ELASTIC_PASSWORD}" -H 'Content-Type: application/json');
echo \"Response: $$TOKEN_RESPONSE\";
# ์๋ต์์ ํ ํฐ ๊ฐ ์ถ์ถ
TOKEN=$(echo $${TOKEN_RESPONSE} | jq -r '.token.value');
if [ '$$TOKEN' = null ] || [ -z '$$TOKEN' ] || [ "$$TOKEN" = "" ]; then
echo 'Error: Failed to create or parse service token.';
echo \"Response: $$TOKEN_RESPONSE\";
exit 1;
fi;
# ํธ์คํธ์ ๊ณต์ ๋ ๋ณผ๋ฅจ์ .env ํ์ผ๋ก ์ ์ฅ
echo \"ELASTICSEARCH_SERVICEACCOUNTTOKEN=$$TOKEN\" > /config/kibana_token.env;
echo 'Kibana token has been saved to ./config/kibana_token.env';
"
volumes:
- ./config:/config
networks:
- elastic
depends_on:
password-setter:
condition: service_completed_successfullyํค๋ฐ๋ ๊ตฌ์ฑ
๊ทธ๋ฌ๋ฉด ์ด์ ํค๋ฐ๋๋ฅผ ๋ถ์ฌ๋ณผ ์ ์๋ค.
kibana:
image: docker.elastic.co/kibana/kibana:8.18.0
container_name: kibana
command: >
sh -c "
# ํ ํฐ ํ์ผ์ด ์กด์ฌํ๋ฉด ์ฝ์ด์ ํ๊ฒฝ ๋ณ์๋ก ๋ก๋
if [ -f /config/kibana_token.env ]; then
. /config/kibana_token.env;
echo 'Service account token loaded.';
else
echo 'WARNING: Service account token file not found.';
fi;
# Kibana ์๋ ์คํ ๋ช
๋ น์ด ์คํ
exec /usr/local/bin/kibana-docker;
"
environment:
- ELASTICSEARCH_SERVICEACCOUNTTOKEN=$${ELASTICSEARCH_SERVICEACCOUNTTOKEN}
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
- SERVER_NAME=kibana
- SERVER_SSL_ENABLED=false
- SERVER_HOST=0.0.0.0
- xpack.security.enabled=true
- xpack.encryptedSavedObjects.encryptionKey=min-32-byte-long-strong-encryption-key
ports:
- "15601:5601"
networks:
- elastic
depends_on:
elasticsearch:
condition: service_healthy
kibana-token-setter:
condition: service_completed_successfully
volumes:
- ./config:/config
healthcheck:
test: ["CMD-SHELL", "curl http://localhost:5601"]
interval: 10s
timeout: 5s
retries: 3
๋ฐฉ๊ธ ๋ง๋ ํ ํฐ์ ๊ธฐ๋ฐ์ผ๋ก Elasticsearch์ ์ฐ๊ฒฐํ๋ค.
๊ทธ๋์ ๋ฌ๋ค๋ฉด
elastic ๊ณ์ ์ ๋ณด๋ก ์ ๊ทผํด์ ์จ๋ณผ ์ ์๋ค.


์ ์ฒด docker compose ๊ตฌ์ฑ์ ๋ค์ ๋งํฌ์ ์๋ค.
https://github.com/myyrakle/docker-compose/tree/master/elastic-and-kibana