---
# System prepended metadata

title: ELK 部屬 & 設定
tags: [deploy, elasticsearch]

---

# ELK 部屬 & 設定

[TOC]

## 部屬

### 部屬順序

> 依目前使用需求

:::info
需確認版本互相支援，[官方資料](https://www.elastic.co/support/matrix#matrix_jvm)
:::

1. Elasticsearch
2. Kibana
3. Beats (filebeat)

### 初始流程總覽（不含設定細節）

#### 1. 啟用核心服務

- 啟用 Elasticsearch
- 使用 CLI 修改 `kibana_system` 密碼（Kibana 與 ES 連線用）
- 啟用 Kibana，指定 `kibana_system` 為連線帳號
- 使用 `elastic` 登入 Kibana UI

#### 2. 權限角色與使用者建立

##### ➤ 建立角色（Roles）

1. 建立接近 `superuser` 的角色（如有特殊需求）
2. 建立 `filebeat_setup` 角色
3. 建立 `filebeat_writer` 角色

##### ➤ 建立使用者並分配角色

1. `admin_user`：給予接近 `superuser` 的角色 （如有特殊需求）
2. `filebeat_setup`：給予 `filebeat_setup` + `kibana_admin` + `ingest_admin`
3. `filebeat_writer`：給予 `filebeat_writer`

> 💡 `kibana_admin` 與 `ingest_admin` 是為了 setup 時能導入 template、dashboard、pipeline

##### ➤ 其他使用者管理

- 視情況修改 `beats_system` 密碼（Stack Monitoring 使用，通常是 Metricbeat/Filebeat）

#### 3. 建立基礎資源（如果使用自訂 index）

- 建立自定 `index template`（若非使用 `filebeat-*` 為前綴）
- 建立對應的 ILM Policy 並在 template 中引用

#### 4. 部署 Filebeat

- 啟用需要的 module（例如 elasticsearch, kibana, nginx, system 等）
- 使用 `filebeat_setup` 帳號，執行 `filebeat setup -e`
  - ✅ 匯入 dashboard 至 Kibana
  - ✅ 建立 `filebeat-8.x` 的 index template
  - ✅ 建立 `filebeat-8.x` 的 datastream（若使用 ILM + datastream）
  - ✅ 建立 `filebeat` 專用 ILM Policy（預設只包含 hot phase，後續調整policy）

#### 5. 啟用 Filebeat 傳送資料

- 使用 `filebeat_writer` 帳號執行 filebeat 主服務，開始發送 logs 到 Elasticsearch

---

### 基本需求

#### ports

| 預設Port | 元件          |                               用途                               | 可設定參數 |
|:-------- |:------------- |:----------------------------------------------------------------:| ---------- |
| 9200     | Elasticsearch |     給外部服務（Kibana、Logstash、curl）使用的 REST API 介面     |  http.port          |
| 9300     | Elasticsearch | 節點之間通訊的 Transport API（intra-cluster / Java client 使用） | transport.port           |
| 5601     | Kibana        |                Kibana 的 HTTP 存取介面（Web UI）                 | server.port           |

#### Bootstrap checks

Elasticsearch 啟用會有一系列的啟用檢查，會根據 [Developemtn / Production mode](##Development-Mode-vs-Production-Mode) 有差異

這些檢查是要確保可以最佳使用 Elasticsearch

:::warning
如果設定single-node，會被認為是開發模式，
在正式環境使用single-node，需透過設定JVM.options，啟用bootstrap checks

```bash
# config/jvm.options
-Des.enforce.bootstrap.checks=true
```

```yaml
# docker compose
environment:
  - discovery.type=single-node
  - ES_JAVA_OPTS=-Des.enforce.bootstrap.checks=true
```

:::

:::spoiler Heap size check

- :information_source:  -Xms & -Xmx 需設定一樣
- JVM 啟動時，如果 初始（-Xms）與最大 heap 大小（-Xmx）不同，JVM 執行期間可能會 resize heap → 導致停頓。
- 如果有啟用 bootstrap.memory_lock: true，resize heap 還會導致 heap 區塊鎖定錯誤。
:::

:::spoiler File descriptor check

- :information_source: Elasticsearch 一個節點可能同時打開非常多檔案（shard segments、網路 socket、log、index file...）
- :information_source: Linux 預設限制每個 process 能開的檔案數量（通常太低）
- :warning: 至少需要 `65535`

```yaml
elasticsearch:
  ulimits:
    nofile:
      soft: 65535
      hard: 65535
```

:::

:::spoiler Memory lock check
> 當 JVM 執行 major GC 時，會觸碰到整個 heap 的記憶體區塊。
> 如果某些 heap pages 被 swap 到 disk，會造成 GC 期間大量 I/O，導致性能下降。
> 如果不是透過docker設定，須設定 systemd（避免被限制 memlock )

```yaml
# 防止 elasticsearch 使用 swap
elasticsearch:
  environment:
    - bootstrap.memory_lock=true # 避免 JVM heap 被 swap 掉
  ulimits:
    memlock:
      soft: -1 # 對應 Linux mlock，需要 -1（無上限）
      hard: -1 # 對應 Linux mlock，需要 -1（無上限）
```

:::

:::spoiler Maximum number of threads check
> Elasticsearch 的請求會被拆分成多個階段、送進不同的 thread pool executors（像是 search、write、management...）。
> 因此它需要建立大量 thread，來應付並行操作。
> 如果系統限制 thread 數過低（例如 nproc 限制），就會造成啟動失敗或服務異常。

- elasticsearch 建議至少 4096

```yaml
elasticsearch:
  ulimits:
   nproc: 65535 # 建議設成更高一點，例如 65535 與 nofile 設定一致
```

:::

::: spoiler Max file size check
Elasticsearch 的 shard segment files 和 translog 可能會非常大（數 GB 以上），如果作業系統限制了每個檔案的大小，會導致：

- 寫入失敗
- 索引建立異常
- 資料遺失風險

將最大檔案大小（fsize）設定為 unlimited，讓 Elasticsearch 能自由寫入大型 segment。

```bash
# /etc/security/limits.conf：
elasticsearch soft fsize unlimited
elasticsearch hard fsize unlimited

```

```yaml
elasticsearch:
  ulimits:
    fsize:
      soft: -1
      hard: -1
```

:::

:::spoiler Max virtual memory check

- Elasticsearch 與 Lucene 使用 mmap 加速資料查詢（memory-mapped IO），需要足夠的虛擬地址空間。
- 若虛擬記憶體限制太小，將導致查詢失敗或 mapping 錯誤。
- 建議設定為 unlimited：

```yaml
ulimits:
  as:
    soft: -1
    hard: -1

```

:::

:::spoiler Max map count check

- Elasticsearch 使用 mmap 將 index segment 映射到記憶體中，每個映射需要一個記憶體區塊（memory-mapped area）。
- 若 Linux 設定的 vm.max_map_count 過小，將導致映射失敗與錯誤。
- 建議設定

```bash
sudo sysctl -w vm.max_map_count=262144
# 永久設定
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
```

:warning: 此設定無法透過 docker-compose 設定，必須在主機執行。
:::

:::spoiler Client JVM check

- Elasticsearch 僅支援運行於 Server JVM。
- :information_source: 現代作業系統預設會使用 Server JVM，不需額外設定。
:::

:::spoiler Use serial collector check

- Java 有多種 Garbage Collector（GC），而 Serial GC 是最輕量、單執行緒的版本，若 Elasticsearch 使用 Serial GC，會嚴重降低效能，因此預設會進行檢查並阻止啟動。
- :information_source:  若使用 Elastic 官方映像或官方建議的 OpenJDK 版本，預設就會是 G1GC，不需額外設定。
:::

:::spoiler System call filter check

- Elasticsearch 在啟動時會安裝系統層級的 system call filter
- 確保 ES 成功啟用了 syscall 過濾器
- 如果因為系統設定或權限限制，這些過濾器無法安裝，Elasticsearch 會啟動失敗
:::

:::spoiler OnError and OnOutOfMemoryError checks

- Elasticsearch 禁止使用 OnError 或 OnOutOfMemoryError，因其依賴執行外部指令（fork/exec），與系統呼叫過濾機制（seccomp）衝突。
- :information_source: 只要不設定相關參數就沒問題
:::

:::spoiler Early-access check

- Elasticsearch 不允許在 early-access（EA）版本的 JDK 上運行，這些版本尚未正式發佈，穩定性與安全性無法保證。
- :information_source: 官方安裝或官方docker image 就沒問題
:::

:::spoiler  All permission check

- 若在 JVM 啟動時指定的 policy file 中包含 java.security.AllPermission，Elasticsearch 將拒絕啟動。
- 預設情況下（包含 Elastic 官方映像）並未授予 AllPermission，因此這項檢查通常不會觸發。

:::

:::spoiler Discovery Configuration Check

- 當 Elasticsearch 啟動時，會試圖與其他節點建立叢集。如果沒有正確設定 discovery 會有問題
- 如果是單節點啟用加上 discovery.type: single-node
:::

:::spoiler Encrypt sensitive data check

- :information_source: 未使用 Watcher，可跳過此檢查。

:::

:::spoiler Role mappings check

- :information_source: elasticsearch 預設有 native realms & file realms
- :information_source: 沒有使用其他的realms不會觸發此檢查

> [!Note]
> Realm 是 Elasticsearch 處理使用者認證的模組。

:::

::: spoiler PKI realm check

- :information_source: 未啟用 xpack.security.authc.realms.pki，此檢查不會觸發。
:::

:::spoiler SSL/TLS check

- 當你啟用 Elasticsearch 的安全功能（xpack.security.enabled: true）時，Elasticsearch 預設會要求節點之間的通訊必須使用加密 (TLS)
- 要通過check，需要針對 `transport` 加上TLS

```yaml
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.key: certs/node.key
xpack.security.transport.ssl.certificate: certs/node.crt
xpack.security.transport.ssl.certificate_authorities: [ "certs/ca.crt" ]
```

> [!Warning]
> 這是針對「節點間通訊」（9300 port）的加密，不是 HTTP API（9200）那邊。
:::

::: spoiler Token SSL check

- 若啟用內建 token 認證服務（access token、Kibana 登入等），則 必須 同時啟用 HTTP 層的 HTTPS：

```yaml
xpack.security.authc.token.enabled: true
xpack.security.http.ssl.enabled: true
```

- :warning: 若未啟用 HTTPS 則無法使用 token 功能，Elasticsearch 將拒絕啟動。
- :information_source: 不使用 token 的話，可關閉該功能以略過此檢查：

```yaml
xpack.security.authc.token.enabled: false
```

:::

#### 啟用後檢查 log

```bash
# 啟動後可以透過 log 搜尋以下關鍵字
docker logs -f elasticsearch | grep -i "bootstrap"

# 或透過 API 檢查是否成功啟動
curl -u user:pass http://localhost:9200/_cluster/health?pretty
```

### Elasticsearch & Kibana Docker compose 配置啟用

:::danger

1. 如果elasticsearch.yml 相關設定是透過掛載檔案的，必須設定 network.host: 0.0.0.0 或其他ip，否則其他 container 都會連不到
2. 官方建議 log4j2.properties 使用預設即可，不需要調整或掛載檔案
    - 如果是本機安裝，會寫檔到 $ES_HOME/logs
    - 如果是 docker 安裝預設是 stdout，透過 docker logs 查看
    - docker 如果要跟本機安裝一樣寫擋，帶入變數ES_LOG_STYLE=file
:::

#### 單節點測試(快速啟用)

```yaml
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.11.1
    container_name: es-dev
    environment:
      # 關閉安全機制，不需要帳號密碼
      - xpack.security.enabled=false
      # 單節點啟用
      - discovery.type=single-node
      # 依需求調整記憶體需求，container的一半
      - ES_JAVA_OPTS=-Xms2g -Xmx2g
    ports:
      - "9200:9200"
      - "9300:9300"
    mem_limit: 4g
    volumes:
      - es-data:/usr/share/elasticsearch/data
      
 kibana:
    image: docker.elastic.co/kibana/kibana:8.11.1
    container_name: kibana-dev
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch

volumes:
  es-data:
```

#### 單節點正式環境

```yaml
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.11.1
    container_name: es-prod
    environment:
      # 單節點啟用
      - discovery.type=single-node
      # 啟用安全設定
      - xpack.security.enabled=true
      # docker 啟用預設 log 是 stdout，如果要改為寫檔需加入此變數
      - ES_LOG_STYLE=file
      # 如果啟用bootstrp check，transport 需要加上 SSL 使用 elasticsearch cli 自簽
      - xpack.security.transport.ssl.enabled=true
      - xpack.security.transport.ssl.verification_mode=certificate
      - xpack.security.transport.ssl.keystore.path=elastic-certificates.p12
      - xpack.security.transport.ssl.truststore.path=elastic-certificates.p12
      # 1. 依需求調整記憶體需求，container的一半，2. 啟用bootstrp check
      - ES_JAVA_OPTS=-Xms4g -Xmx4g -Des.enforce.bootstrap.checks=true
      # 確保ES不使用SWAP
      - bootstrap.memory_lock=true
      # 如果沒有預先給定一個密碼，elastic 會有一個隨機密碼，需要後續處理
      - ELASTIC_PASSWORD=changeme
      # 啟用監控 Elasticsearch 狀態，多節點建議使用MetricBeat處理
      - xpack.monitoring.collection.enabled=true
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65535
        hard: 65535
      nproc: 65535
      fsize:
        soft: -1
        hard: -1
      as:
        soft: -1
        hard: -1
    ports:
      - "9200:9200"
      - "9300:9300"
    mem_limit: 8g
    volumes:
      - es-data:/usr/share/elasticsearch/data
      # - es-logs:/usr/share/elasticsearch/logs # 如果有調整為寫檔，將logs接出來持久化
      - ./certs/elastic-certificates.p12:/usr/share/elasticsearch/config/elastic-certificates.p12:ro # TLS 憑證
      # - ./ealsticsearch/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml # 有需要才掛載

  kibana:
    image: docker.elastic.co/kibana/kibana:8.11.1
    container_name: kibana-prod
    environment:
      - SERVER_NAME=kibana
      - ELASTICSEARCH_HOSTS=https://elasticsearch:9200
      # 官方建議使用 kibana_system，建立 kibana 與 elasticsearch 的連線
      - ELASTICSEARCH_USERNAME=kibana_system
      # ⚠️手動建立 kibana_system 密碼
      - ELASTICSEARCH_PASSWORD=set_kibana_password
      # 如果使用container 並且啟用 monitor
      - monitoring.ui.container.elasticsearch.enabled= true
      # - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=/usr/share/kibana/config/ca.crt # 內網使用
    ports:
      - "5601:5601"
    volumes:
      - kibana-data:/usr/share/kibana/data
      # - ./kibana/kibana.yml:/usr/share/kibana/config/kibana.yml:ro 有需要才掛載
      # - kibana-logs:/usr/share/kibana/logs          # 開啟 log 檔輸出再加
      # - ./certs/ca.crt:/usr/share/kibana/config/ca.crt:ro # elasticsearch 有啟用http.ssl 才需要
    depends_on:
      - elasticsearch
      
volumes:
  es-data:
  es-logs:
  kibana-data:
  # kibana-plugins:
  # kibana-logs:
```

:::warning
主機上設定：

```bash
sudo sysctl -w vm.max_map_count=262144
```

:::

##### 產生憑證

- 本地搭建

```bash
# 1. 產生 CA（自己就是憑證授權中心），預設名稱 elastic-stack-ca.p12，會在$ES_HOME/elasticsearch資料夾
./bin/elasticsearch-certutil ca

# 2. 產生節點使用憑證，預設名稱 elastic-certificates.p12 ，
# 如果產生在$ES_HOME/elasticsearch資料夾，要移去$ES_HOME/elasticsearch/config
./bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12
```

- docker 啟用，在elasticsearch啟用前，先使用docker啟用elasticsearch指令產生憑證

```bash
#1. 在當前路徑建立本機放憑證的資料夾
mkdir -p ./certs

#2. 使用 Docker 執行 certutil 產生 CA
docker run --rm -v ${PWD}/certs:/usr/share/elasticsearch/config \
  docker.elastic.co/elasticsearch/elasticsearch:8.11.1 \
  bin/elasticsearch-certutil ca --silent --out config/elastic-stack-ca.p12 --pass ""

#3. 利用剛剛產生的CA，使用 Docker 再產生節點用憑證
docker run --rm -v ${PWD}/certs:/usr/share/elasticsearch/config \
  docker.elastic.co/elasticsearch/elasticsearch:8.11.1 \
  bin/elasticsearch-certutil cert --ca config/elastic-stack-ca.p12 \
  --ca-pass "" --silent --out config/elastic-certificates.p12 --pass ""
```

##### 手動建立 kibana_system 密碼

> [!Warning]
> kibana_system 是連線使用，登入 kibana UI 使用 elastic 或另外建立帳號

> [!Tip] 
> 加上 -i 代表要自行輸入密碼，沒有 -i 會隨機給一組密碼

```bash
# Docker 容器內執行
docker exec -it es-prod bin/elasticsearch-reset-password -u kibana_system -i
```

```bash
# 也可以透過api更新
curl -X POST http://localhost:9200/_security/user/kibana_system/_password \ 
  -u elastic:your_password \
  -H "Content-Type: application/json" \
  -d '{"password" : "new_password"}'
```

## 確認elasticsearch(ES)是否執行中

```bash
# 沒有使用TLS
curl -u [user]:[password] http://localhost:9200
# 有使用 TLS + 驗證 CA 憑證
curl -cacert $ES_HOME/config/certs/http_ca.crt -u [user]:[password] https://localhost:9200
# 確認叢集是否健康
curl http://localhost:9200/_cluster/health
```

正常 Response:

```json
{
  "name": "faa534e37683",
  "cluster_name": "docker-cluster",
  "cluster_uuid": "9UBFxQXhSiiyJwzX1kCuzg",
  "version": {
    "number": "8.11.1",
    "build_flavor": "default",
    "build_type": "docker",
    "build_hash": "6f9ff581fbcde658e6f69d6ce03050f060d1fd0c",
    "build_date": "2023-11-11T10:05:59.421038163Z",
    "build_snapshot": false,
    "lucene_version": "9.8.0",
    "minimum_wire_compatibility_version": "7.17.0",
    "minimum_index_compatibility_version": "7.0.0"
  },
  "tagline": "You Know, for Search"
}
```

## elasticsearch 預設會將所有相關的設定&資料都放在同一個目錄下面

```bash
$ES_HOME/
├── bin/
├── config/
├── data/
├── logs/
├── plugins/
```

| 資料夾       | 用途                                                                                          | 可設定參數              |
|:------------ |:--------------------------------------------------------------------------------------------- |:----------------------- |
| home         | Elasticsearch 的主目錄（$ES_HOME），解壓縮後的資料夾路徑                                      |                         |
| bin          | elasticsearch執行檔與工具，例如 elasticsearch（啟動 ES）、elasticsearch-plugin（安裝 plugin） |                         |
| config       | 設定檔放這裡                                                                                  | ES_PATH_CONF 環境變數   |
| data         | 存放所有索引資料（如 shards、segments），相當重要不要進去改資料                               | path.data               |
| logs         | Elasticsearch 的 log 檔儲存路徑                                                               | path.logs               |
| plugins      | 所有已安裝的 Plugin 都會存放在這個資料夾，每個 plugin 是一個子資料夾                          |                         |
| repo         | Snapshot 快照備份的位置，可設多個資料夾做為 repository，通常是 NFS 或掛載的磁碟目錄           | path.repo               |

如果使用 docker 正式環境務必依照預設路徑或設定參數將 data, logs 接出來持久化，其他依照使用需求

設定檔主要有3種

| 設定檔            | 功能                                      |
|:----------------- |:----------------------------------------- |
| elasticsearch.yml | 主要設定（叢集、節點、network、xpack 等） |
| jvm.options       | JVM 相關設定（記憶體大小、GC、Java 參數） |
| log4j2.properties | Log 設定（log 等級、格式、輸出路徑等）    |

## 設定方式

Elasticsearch 設定分為2種
> elasticsearch.yml → 適合 靜態、開機時就要生效的設定
> /_cluster/settings → 適合 動態、可即時修改的設定（不重啟）

部分只能靜態設定，部分只能動態
部分可以靜態設定後，透過動態API覆蓋

### 動態設定

> 可以在 Elasticsearch 執行中（不重啟）即時修改。

設定方式透過API設定:

```bash
# 範例
PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.enable": "all"
  },
  "transient": {
    "logger._root": "DEBUG"
  }
}

```

### 整理表格

| 設定方式          | 用途     | 是否可在執行中改變  | 是否需重啟 | 實例                         |
|:----------------- |:-------- |:------------------- |:---------- |:---------------------------- |
|`elasticsearch.yml` | 靜態設定 | 不可                | 需重啟     | cluster.name, network.host   |
| `_cluster/settings` | 動態設定 | 可立即生效          | 不需重啟   | cluster.routing.*, indices.* |
| `API Transient`     | 暫時有效 | （重啟即失效）      | 不需重啟   | 開發/測試時用                |
| `API Persistent`    | 長期有效 | （會儲存在 config） | 不需重啟   | 正式部署使用                 |

### 靜態設定

> 只能在未啟動的節點上（或需重啟）生效的設定。

設定方式透過 elasticsearch.yml 設定

## 官方列舉重要設定及注意事項

Elasticsearch 只需要很少的配置就可以開始使用，但是在生產中使用叢集之前必須考慮許多事項：

### Path settings（路徑設定）

```yaml
path:
  data: /var/data/elasticsearch
  logs: /var/log/elasticsearch
```

:::warning
不要在 elasticsearch 啟用後修改任何路徑。
絕對不要動 /data 內的資料，需要備份請使用ES的 Snapshot and restore 相關機制
:::

### Cluster name setting (叢集名稱)

- 一個節點要加入叢集，必須和其他節點使用相同的 cluster.name
- 更改叢集名稱需要重啟所有節點（full cluster restart），建議一開始就設好，不要輕易變更
- 預設值是 `elasticsearch`，但建議修改為能夠代表用途的名稱，例如：

  ```yaml
  cluster.name: logging-prod
  ```
  
### Node name setting (節點名稱)

- node.name 是這台節點的唯一標識符（對人類與 API 都可辨識）
- 預設是主機名稱，但可以自己指定更清楚的名稱

  ```yaml
  node.name: prod-data-2
  ```
  
### Network host setting

- 預設是 127.0.0.1 or [::1]
- 只要調整成其他IP，elasticsearch 就會進入 production mode

  ```yaml
  network.host: 192.168.1.10
  ```
  
### Development Mode vs Production Mode

#### Development Mode

- 是 elasticsearch 啟用預設狀態（當沒設定 network.host 時）
- 錯誤設定只會顯示警告（warning）
- 可以啟動但不保證穩定性
- 適合本機測試、單節點快速試用
:::warning
Development Mode (沒有調整ip)，除了本機服務其他機器是沒有辦法連到的，就算是同一個內網也不行
:::

#### Production Mode

- 當你設定了 network.host 為非 loopback（如 0.0.0.0、內網 IP），會`自動切換`為生產模式
- 所有警告（如 bootstrap checks）會升級為例外（exception） 拋錯
- 有錯會阻止 Elasticsearch 啟動，這是為了避免部署錯誤造成資料損毀

### Discovery and cluster formation settings

> 在正式部署多節點叢集時，為了讓節點之間彼此發現並進行第一次 master 選舉，需要設定以下參數：

:::success
如果你是單節點部署的 Elasticsearch：
> 你可以完全不需要設定 discovery.seed_hosts 和 cluster.initial_master_nodes
> 會自動加自己選為 master 節點
> 只要加一行：

```yaml
discovery.type: single-node
```

:::

#### discovery.seed_hosts

> 定義哪些節點可以被當作「入口節點」來發現其他節點

- 可以寫 IP、FQDN（完整網域）、或 IPv6（需用 [] 包起來）
- 須為 可能成為 master 的節點
- 支援多筆 DNS IP 對應（例如用於雲端自動發現）

#### cluster.initial_master_nodes

> 用於「第一次叢集啟動」時，指定參與第一次 master 選舉的節點（必填！）

- :warning: 這個參數只需要在第一次建立新叢集時設定
- :white_check_mark: 設定值必須與每個節點的 node.name 完全相符（區分大小寫）
- :x: 成功建立後必須刪除此參數，否則未來重啟或擴充會出錯
- :x: 不可設定在非 master-eligible 節點上（如 ingest-only 節點）

| 節點數         | cluster.initial_master_nodes 要填多少？      | 說明                                                 |
| -------------- |:-------------------------------------------- |:---------------------------------------------------- |
| 1 台（單節點） | 不需要設定，改用 discovery.type: single-node | 單機免選舉                                           |
| 2 台           | 填 2 台節點的 node.name (不要設定偶數)       | 雙節點也需要明確選舉(設定奇數個節點，選舉才會正常) |
| 3 台           | 填 3 台節點的 node.name                      | 所有要參與第一次投票的節點都要列出                   |
| 5 台           | 填 5 台節點的 node.name                      | 所有要參與第一次投票的節點都要列出                   |

#### 範例

```yaml
node.name: master-node-a
discovery.seed_hosts:
   - 192.168.1.11  # port 預設為 9300，可省略
   - [0:0:0:0:0:ffff:c0a8:10c]:9301
   
cluster.initial_master_nodes: 
   - master-node-a
   - master-node-b
   - master-node-c
```

:::info

- `discovery.seed_hosts` 負責「找到其他節點」
- `cluster.initial_master_nodes` 負責「誰可以投票選 master（僅第一次）」
  - 依照上面的範例，啟用後就可以comment或移除掉，只有第一次啟用需要

  ```yaml
  # cluster.initial_master_nodes: 
  #  - master-node-a
  #  - master-node-b
  #  - master-node-c
  ```

:::
:::warning
新節點加入時要填`cluster.initial_master_nodes`嗎？
*不用也不能填!!!*
:::

#### 如何確認選舉結果

1. 用 API 查詢 master 節點

  ```bash
  curl -u [user]:[password] http://[任一節點IP]:9200/_cat/master?v
  ```
  
2. 查詢叢集狀態

  ```bash
  curl -u [user]:[password] http://[IP]:9200/_cluster/health?pretty
  ```
  
3. 透過 Kibana Dev Tools

進入 Kibana → Dev Tools 輸入：

```bash
GET /_cat/master?v
```

![image](https://hackmd.io/_uploads/HyR0QqoAkx.png)

### JVM Heap size settings

> 如果都沒有設定，預設是主機記憶體的一半，官方建議，其他留給OS

- 如果ES node有特定設定不同的 roles，可以依據 roles 調整，沒有特別設定，一半就是安全牌
- :warning: 若 ES_JAVA_OPTS 設定高於 mem_limit，會導致容器啟動失敗（OutOfMemoryError）
- 若要覆寫預設堆大小，請設定最小和最大堆大小設定 Xms 和 Xmx。最小值和最大值必須相同。

:::spoiler :information_source: 如果使用docker，依照 container mem_limit 為主，預設為 mem_limit 的一半

假設container mem_limit設定 6G，可以手動設定 3~4G
範例:

```yaml
elasticsearch:
  image: docker.elastic.co/elasticsearch/elasticsearch:8.11.1
  environment:
    - discovery.type=single-node
    - ES_JAVA_OPTS=-Xms4g -Xmx4g
  mem_limit: 6g
```

::: 

### Temporary Directory 設定說明

- Elasticsearch 啟動時會在系統暫存目錄（例如 /tmp）下建立一個私有暫存目錄
- 某些 Linux 發行版會定期清理 /tmp 內未使用的檔案／目錄
- 這可能導致 Elasticsearch 還在執行中，但暫存目錄被清掉，而導致某些功能（如 snapshot、ML）失敗

#### 解決方式

1. 如果是用 .deb 或 .rpm 安裝（搭配 systemd 啟動）沒問題，系統會自動幫你排除這個目錄的清除機制

2. 用 .tar.gz 安裝 或 自己手動執行

建議你自己設定一個 專屬 temp 目錄，並透過 $ES_TMPDIR 指定給 Elasticsearch：

```bash
mkdir -p /var/tmp/elasticsearch-tmp
chown elasticsearch:elasticsearch /var/tmp/elasticsearch-tmp
chmod 700 /var/tmp/elasticsearch-tmp

export ES_TMPDIR=/var/tmp/elasticsearch-tmp
```

3. 如果是docker啟用

- Docker 容器中的 temp 目錄會是容器內部的 /tmp
**問題是：**容器重啟時 /tmp 裡的檔案會被清空，等於這個目錄不是「持久化」的

- 可能導致：
snapshot、reindex、plugin 等操作失敗
報錯訊息像是 No such file or directory, permission denied

- 掛 volume + 設定 $ES_TMPDIR

  ```yaml
  services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.11.1
    container_name: elasticsearch
    environment:
      - ES_TMPDIR=/usr/share/elasticsearch/tmp
    volumes:
      - ./elasticsearch/data:/usr/share/elasticsearch/data
      - ./elasticsearch/tmp:/usr/share/elasticsearch/tmp
    ports:
      - "9200:9200"

  ```
  
## 其他目前常使用到設定

### Security

透過xpack.security做相關設定

- 付費功能(都沒有用到)
  - xpack.security.audit.*
  - xpack.security.authc.realms.ldap.*
  - xpack.security.authz.store.roles.index.*
  - xpack.security.dls_fls.*（document/field level security）

- General security settings (一般安全設定)
  - `xpack.security.enabled`
    - Type: `Static`, Boolean
    - Default: `true`
    - 授權需求: Basic（免費）
    - 說明: 啟用整體安全功能（帳號、認證、TLS 等），==不開啟將無任何安全保護!!!==。
