ECK(Elastic Cloud on Kubernetes) オンプレ動作確認

## はじめに
ElasticStack の Kubernetes Operator である Elastic Cloud on Kubernetes (ECK) が [1.0 でリリースされた。(2020.01.16)](https://www.elastic.co/jp/blog/elastic-cloud-on-kubernetes-ECK-is-now-generally-available?blade=tw&hulk=social)

これまでは オンプレサーバで、docker/docker-compose で ElasticStack を利用してきたが、
Kubernetes での利用を視野にオンプレ環境で ECK の動作確認を実施した。


## Elastic Cloud on Kubernetes

ElasticStack を Kuberetes 上で Operator を使用して構築・運用が可能。

### ECK Support Version
[ECK 1.0 でのサポートバージョン](https://www.elastic.co/guide/en/cloud-on-k8s/1.0/k8s-overview.html)(2020.02.01時点)

 - kubectl 1.11+
 - Kubernetes 1.12+ or OpenShift 3.11+
 - Elastic Stack: 6.8+, 7.1+

### Operator
Operatorで対応している項目は下記の通り (2020.02.07時点.[Operator.io記載引用](https://operatorhub.io/operator/elastic-cloud-eck))

[要約]

 - 構築は、**Elasticsearch, Kinaba, APMserver に対応**している。(**Beats には未対応**)
 - TLS認証を管理してくれる。
 - クラスタの変更に Elasticsearch クラスタを安全に変更してくれる。
 - ボリュームに関しては、PVを使用するので、PVC等に対応できるPVを用意しないといけない。
 - セキュリティ設定 (色々な secret の準備) は Operator で実施してくれる。

TLS とかパスワードとか設定を管理・構築してくれ、
DB 部分 (Elasticsearch クラスタ) も安全に処理してくれて便利な感じ。
ただ、クラスタ自体のオブザーバビリティ取得のため beats を入れるなどは operator ではそこまでしてくれないようです。

## 環境・Version
### kubernetes
kubespray で構築した k8s上で構築する。(intel nuc + ESXi + CentOS7 + kubespray)
Version : **v1.16.3**
詳細構成は下記記事の環境。
https://qiita.com/suzuyui/items/e7531fe5e1e84c061b23

### Storage
PersistentVolume (PV) としては QNAP で構築した iSCSI を使用している。
途中で記載するが、これを最初に用意せずに PV 無しでテストして途中で失敗する。(当たり前だが…)
詳細構成は下記記事の環境。
https://qiita.com/suzuyui/items/0efa505f3db03390f181

### ElasticStack
Version: **7.5.2** and **7.6.0**
本確認中に 7.6.0 がリリースされたため、最初は 7.5.2 で実施し、7.6.0 に Upgrade も実施した。

### ECK
Version: **1.0.0**

## 今回の実施内容 
公式ページ記載の[QuickStart](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-quickstart.html)の 1.~4. なぞって実施してみる。
次に、Elasticsearch の Version Upgrade も実施する。(5.)
最後に Elasticsearch の delete を実施すると PVC も消える動作が確認できたのでそれも記載する。(6.)
ステップは下記の通り。

1. ECK Operator 導入 (Deploy ECK in your Kubernetes cluster)
2. Elasticsearch の構築 (Deploy an Elasticsearch cluster)
3. Kibana の構築 (Deploy a Kibana instance)
4. Elasticsearch 構築数の変更テスト(Upgrade your deployment)
5. Elasticsearch の Version Upgrade 
6. Elasticsearch の delete 動作確認

https://www.elastic.co/jp/downloads/elastic-cloud-kubernetes

## 1. ECK Operator 導入 (Deploy ECK in your Kubernetes cluster)

ECK の yaml をダウンロードして apply する

```
curl -OL https://download.elastic.co/downloads/eck/1.0.0/all-in-one.yaml
kubectl apply -f all-in-one.yaml
```

※ 一行でも可能 (yaml 保存が不要な場合)
``` kubectl apply -f https://download.elastic.co/downloads/eck/1.0.0/all-in-one.yaml ```

実施すると下記のように構築される

```
$ kubectl apply -f all-in-one.yaml 
customresourcedefinition.apiextensions.k8s.io/apmservers.apm.k8s.elastic.co created
customresourcedefinition.apiextensions.k8s.io/elasticsearches.elasticsearch.k8s.elastic.co created
customresourcedefinition.apiextensions.k8s.io/kibanas.kibana.k8s.elastic.co created
clusterrole.rbac.authorization.k8s.io/elastic-operator created
clusterrolebinding.rbac.authorization.k8s.io/elastic-operator created
namespace/elastic-system created
statefulset.apps/elastic-operator created
serviceaccount/elastic-operator created
validatingwebhookconfiguration.admissionregistration.k8s.io/elastic-webhook.k8s.elastic.co created
service/elastic-webhook-server created
secret/elastic-webhook-server-cert created
```

構築状況の確認

```
$ kubectl get all -n elastic-system
NAME                     READY   STATUS    RESTARTS   AGE
pod/elastic-operator-0   1/1     Running   0          2m22s

NAME                             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/elastic-webhook-server   ClusterIP   10.233.46.231   <none>        443/TCP   2m23s

NAME                                READY   AGE
statefulset.apps/elastic-operator   1/1     2m23s
```

Operatorのログの確認方法 (たくさんのログが出ます)

```
$ kubectl -n elastic-system logs -f statefulset.apps/elastic-operator
{"level":"info","@timestamp":"2020-02-01T06:01:05.514Z","logger":"manager","message":"Setting up client for manager","ver":"1.
0.0-6881438d"}
{"level":"info","@timestamp":"2020-02-01T06:01:05.515Z","logger":"manager","message":"Setting up scheme","ver":"1.0.0-6881438d
"}
{"level":"info","@timestamp":"2020-02-01T06:01:05.516Z","logger":"manager","message":"Setting up manager","ver":"1.0.0-6881438
d"}
```
## 2. Elasticsearch の構築 (Deploy an Elasticsearch cluster)
まずは quickstart 記載のママの下記 yaml を apply する。

``` elasticsearch-quickstart.yaml
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: quickstart
spec:
  version: 7.5.2
  nodeSets:
  - name: default
    count: 1
    config:
      node.master: true
      node.data: true
      node.ingest: true
      node.store.allow_mmap: false
```

```
$ kubectl apply -f elasticsearch-eck-test.yaml
elasticsearch.elasticsearch.k8s.elastic.co/quickstart created
```

すると**今回の実行環境では**、次項目のように**失敗した**。

### PVアサインでの失敗

状態を確認するとずっとHEALTHが unknown 。。。

```
$ kubectl get elasticsearch
NAME         HEALTH    NODES   VERSION   PHASE             AGE
quickstart   unknown           7.5.2     ApplyingChanges   109s
```

※ elasticsearch は es で短縮可能 (`kubectl get es` が上記と同様)

#### 切り分け
起動podを確認して、そのdescribe情報での Events をみている。

```
$ kubectl get pod
NAME                              READY   STATUS    RESTARTS   AGE
quickstart-es-default-0           0/1     Pending   0          2m13s

$ kubectl describe pod quickstart-es-default-0
Name:           quickstart-es-default-0
Namespace:      default
Priority:       0
〜〜〜
Events:
  Type     Reason            Age        From               Message
  ----     ------            ----       ----               -------
  Warning  FailedScheduling  <unknown>  default-scheduler  pod has unbound immediate PersistentVolumeClaims (repeated 4 times)
  Warning  FailedScheduling  <unknown>  default-scheduler  pod has unbound immediate PersistentVolumeClaims (repeated 4 times)
```

#### 公式トラブルシュート
Elasticサイトに記載あり

https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-troubleshooting.html#k8s-describe-failing-resources

以下抜粋。
If you see an error with unbound persistent volume claims (PVCs), it means there is not currently a persistent volume that can satisfy the claim. 

ECK Operator が作成する PVC に適応する PV がないとだめらしい。(当たり前ですね。。)


#### 今回の問題点と対処
 - PVを用意してなかった。 **→ 「環境」項目に記載してある [QNAPで作成した](https://qiita.com/suzuyui/items/0efa505f3db03390f181
)**
 - PVC がうまくいかない **→ 次の項目「volumeClaimTemplate の追記」で対処する**

### volumeClaimTemplate の追記

マニフェスト (yaml) に追加で volumeClaimTemplate を記載してあげる。
書き方は公式サイトを参照：https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-volume-claim-templates.html

事象改善できるパターンは2つ。
 A. 環境のPVにあった volumeClaimTemplate を書いてあげる
 B. emptyDir にしてしまう

#### A. 環境のPVにあった volumeClaimTemplate を書いてあげる

公式サイトを参考に自身にあった書き方で追記する。
下記は自環境での例。

 - volumeClaimTemplates[]
    - metadata.name: elasticsearch-data であることが ECK での Must 条件
    - spec
        - storage
        - storageClassName: PVに合った記載。PVにも**同じstorageClassName**で準備する。
    - PV yaml例
        - https://qiita.com/suzuyui/items/0efa505f3db03390f181#5-pv-%E3%81%AE%E4%BD%9C%E6%88%90
        - spec.capacity.storage を 10Gi -> 50Gi に変えただけでそれ以外は同じで準備した

```elasticsearch-quickstart-pv.yaml
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: quickstart
spec:
  version: 7.5.2
  nodeSets:
  - name: default
    count: 1
    config:
      node.master: true
      node.data: true
      node.ingest: true
      node.store.allow_mmap: false
    volumeClaimTemplates:
    - metadata:
        name: elasticsearch-data
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 50Gi
        storageClassName: standard
```

**以降は上記の yaml で実施していく(次のB. emptyDir は参考)**

#### B. emptyDir にしてしまう
vloume 自体を永続化しないのであれば、emptyDirで対処することも可能。
(こちらはデータ消失の可能性もあるので非推奨。テスト環境で動き見るだけならばOK)

```elasticsearch-quickstart-emptydir.yaml
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: quickstart
spec:
  version: 7.5.2
  nodeSets:
  - name: default
    count: 1
    config:
      node.master: true
      node.data: true
      node.ingest: true
      node.store.allow_mmap: false
    podTemplate:
        spec:
          volumes:
          - name: elasticsearch-data
          emptyDir: {}
```

### PV/PVC 準備後の再 Apply
PV/PVC 対応を実施し、再度 kubectl apply を実行

```
$ kubectl apply -f elasticsearch-quickstart-pv.yaml
elasticsearch.elasticsearch.k8s.elastic.co/quickstart created
```

下記の通り、今回はデプロイが成功したことが確認できる。
(pod は **Running**, PVC は **Bound**, elasticsearch は **Ready**)

```
$ kubectl get po -o wide
NAME                      READY   STATUS     RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
quickstart-es-default-0   0/1     Init:0/1   0          21s   10.233.65.103   k8sworker01   <none>           <none>
$ kubectl get po -o wide
NAME                      READY   STATUS            RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS 
GATES
quickstart-es-default-0   0/1     PodInitializing   0          22s   10.233.65.103   k8sworker01   <none>           <none>
$ kubectl get po -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
quickstart-es-default-0   0/1     Running   0          30s   10.233.65.103   k8sworker01   <none>           <none>
$ kubectl get po -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
quickstart-es-default-0   1/1     Running   0          37s   10.233.65.103   k8sworker01   <none>           <none>
$ kubectl get elasticsearch
NAME         HEALTH   NODES   VERSION   PHASE   AGE
quickstart   green    1       7.5.2     Ready   55s
$ kubectl get es
NAME         HEALTH   NODES   VERSION   PHASE   AGE
quickstart   green    1       7.5.2     Ready   2m6s
$ kubectl get pvc
NAME                                         STATUS   VOLUME           CAPACITY   ACCESS MODES   STORAGECLASS   AGE
elasticsearch-data-quickstart-es-default-0   Bound    iscsi-50g-pv05   50Gi       RWO            standard       3m18s
$ kubectl get pv iscsi-50g-pv05
NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                                STORAGECLASS   REASON   AGE
iscsi-50g-pv05   50Gi       RWO            Retain           Bound    default/elasticsearch-data-quickstart-es-default-0   standard                4m4s
```

## 3. Kibana の構築 (Deploy a Kibana instance)
### 3.1. Deploy
quickstart 記載通りの下記 yaml にて kibana を構築する。

```kibana-quickstart.yaml
apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
  name: quickstart
spec:
  version: 7.5.2
  count: 1
  elasticsearchRef:
    name: quickstart
```

applyする。

```
$ kubectl apply -f kibana.yaml 
kibana.kibana.k8s.elastic.co/quickstart created
```

時間が経つと HEALTH が **green** となる。
(最初は Readiness probe が failed になるが時間が経つと greenになるので待つ)

```
$ kubectl get kibana
NAME         HEALTH   NODES   VERSION   AGE
quickstart   red              7.5.2     37s
$ kubectl get kibana
NAME         HEALTH   NODES   VERSION   AGE
quickstart   green    1       7.5.2     93s
```

### 3.2 Web Access
Kibana へ Web ブラウザでアクセス・ログインできることを確認する。

#### Service
ClusterIPが自動で作成されていることが確認できる。

```
$ kubectl get service quickstart-kb-http
NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
quickstart-kb-http   ClusterIP   10.233.21.197   <none>        5601/TCP   7m30s
```

#### PortForward
自動作成された SVC へ `kubectl port-forward` を使用して、手元環境へポートフォワードする。

```
$ kubectl port-forward service/quickstart-kb-http 5601
Forwarding from 127.0.0.1:5601 -> 5601
Forwarding from [::1]:5601 -> 5601
```

#### Password
ログインに必要なパスワードは、Operator が自動で elastic ユーザで secret が作成されているので、
下記で base64 でデコードして取得できる。

```
$ kubectl get secret quickstart-es-elastic-user -o=jsonpath='{.data.elastic}' | base64 --decode; echo
pd7fxj899v8lsgh2ks4rkfjr
```
上記だと `pd7fxj899v8lsgh2ks4rkfjr` がパスワード(これは **環境により異なるので注意**)

#### アクセス画面
Webブラウザを開いて、下記のようにアクセスする。
1. URL は「https://127.0.0.1:5601」
2. Username は「elastic」
3. Password は一つ前で secret から取得したパスワード (本記載では `pd7fxj899v8lsgh2ks4rkfjr` これは **環境により異なるので注意**)
4. 「Log in」をクリック

<img width="1043" alt="スクリーンショット 2020-02-14 14.50.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/ce82a03e-6b0a-ac88-7a8f-5770820237c3.png">

#### ログイン認証後
認証が上手くいけば、下記のようなページに遷移する。

<img width="1033" alt="スクリーンショット 2020-02-14 14.55.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326183/f5105bcf-8fd9-2482-9bb7-a1c7d0ed9bff.png">

**KibanaをデプロイしWebアクセス・認証まで確認できた**

## 4. Elasticsearch 構築数の変更テスト(Upgrade your deployment)
Elasticsearch 数を 1 -> 3 に変更してElasticsearch の数をスケールさせる動作を確認する。

 - 変更箇所
    - **spec.nodeSets[].count: 1 -> 3 に変更**するのみ

```elasticsearch-quickstart-pv.yaml
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: quickstart
spec:
  version: 7.5.2
  nodeSets:
  - name: default
    count: 3
    config:
      node.master: true
      node.data: true
      node.ingest: true
      node.store.allow_mmap: false
    volumeClaimTemplates:
    - metadata:
        name: elasticsearch-data
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 50Gi
        storageClassName: standard
```

上記通り、nodeSets を 3 に書き換えた後、 apply を実行する。
※ -w オプションで徐々に増えていっていることも見ている

```
$ kubectl apply -f elasticsearch-quickstart-pv.yaml
elasticsearch.elasticsearch.k8s.elastic.co/quickstart configured
$ kubectl get po -o wide -w
NAME                             READY   STATUS    RESTARTS   AGE     IP              NODE          NOMINATED NODE   READINESS GATES
quickstart-es-default-0          1/1     Running   0          6m43s   10.233.65.103   k8sworker01   <none>           <none>
quickstart-es-default-1          0/1     Running   0          15s     10.233.92.171   k8sworker02   <none>           <none>
quickstart-kb-6c88bdd64c-87w9l   1/1     Running   0          2m7s    10.233.65.104   k8sworker01   <none>           <none>
quickstart-es-default-1          1/1     Running   0          28s     10.233.92.171   k8sworker02   <none>           <none>
quickstart-es-default-2          0/1     Pending   0          0s      <none>          <none>        <none>           <none>
quickstart-es-default-2          0/1     Pending   0          0s      <none>          <none>        <none>           <none>
quickstart-es-default-2          0/1     Pending   0          1s      <none>          k8sworker03   <none>           <none>
quickstart-es-default-2          0/1     Init:0/1   0          1s      <none>          k8sworker03   <none>           <none>
quickstart-es-default-2          0/1     Init:0/1   0          7s      10.233.110.31   k8sworker03   <none>           <none>
quickstart-es-default-0          1/1     Running    0          7m4s    10.233.65.103   k8sworker01   <none>           <none>
quickstart-es-default-1          1/1     Running    0          36s     10.233.92.171   k8sworker02   <none>           <none>
quickstart-es-default-2          0/1     Init:0/1   0          7s      10.233.110.31   k8sworker03   <none>           <none>
quickstart-es-default-0          1/1     Running    0          7m4s    10.233.65.103   k8sworker01   <none>           <none>
quickstart-es-default-1          1/1     Running    0          36s     10.233.92.171   k8sworker02   <none>           <none>
quickstart-es-default-2          0/1     Init:0/1   0          7s      10.233.110.31   k8sworker03   <none>           <none>
quickstart-es-default-2          0/1     PodInitializing   0          9s      10.233.110.31   k8sworker03   <none>           <none>
quickstart-es-default-2          0/1     Running           0          10s     10.233.110.31   k8sworker03   <none>           <none>
quickstart-es-default-2          1/1     Running           0          21s     10.233.110.31   k8sworker03   <none>           <none>
$ kubectl get es
NAME         HEALTH   NODES   VERSION   PHASE   AGE
quickstart   green    3       7.5.2     Ready   7m27s 
$ kubectl get pvc
NAME                                         STATUS   VOLUME           CAPACITY   ACCESS MODES   STORAGECLASS   AGE
elasticsearch-data-quickstart-es-default-0   Bound    iscsi-50g-pv05   50Gi       RWO            standard       18m
elasticsearch-data-quickstart-es-default-1   Bound    iscsi-50g-pv06   50Gi       RWO            standard       12m
elasticsearch-data-quickstart-es-default-2   Bound    iscsi-50g-pv04   50Gi       RWO            standard       11m
```

最終的には **NODES が 3** となっていることまで確認できた。
下記で 3 つの elasticsearch の quickstart の Pod が Running 1/1 となっていることも確認できる。

```
$ kubectl get po -o wide
NAME                             READY   STATUS    RESTARTS   AGE     IP              NODE          NOMINATED NODE   READINESS GATES
quickstart-es-default-0          1/1     Running   0          11m     10.233.65.103   k8sworker01   <none>           <none>
quickstart-es-default-1          1/1     Running   0          4m57s   10.233.92.171   k8sworker02   <none>           <none>
quickstart-es-default-2          1/1     Running   0          4m28s   10.233.110.31   k8sworker03   <none>           <none>
```

## 5. Elasticsearch の Version Upgrade
試している期間に 7.6.0 が新しくリリースされたので [VersionUp](https://www.elastic.co/guide/en/cloud-on-k8s/1.0/k8s-upgrading-stack.html) についても動作を確認する。

 - 変更箇所
    - spec.version: **7.5.2 -> 7.6.0 に変更**するのみ

```elasticsearch-quickstart-pv.yaml
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: quickstart
spec:
  version: 7.6.0
  nodeSets:
  - name: default
    count: 3
    config:
      node.master: true
      node.data: true
      node.ingest: true
      node.store.allow_mmap: false
    volumeClaimTemplates:
    - metadata:
        name: elasticsearch-data
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 50Gi
        storageClassName: standard
```

上記 yaml を apply すると下記の動作を確認できた。

 - 動作
    - Apply 前の VERSION は 7.5.2 であり、Apply 完了後の VERSION は 7.6.0 になっている ($kubectl get es)
    - Upgrade 順番 ($ kubectl get po -o wide -w)
        - Pod が処理される順番： quickstart-es-default-2 -> quickstart-es-default-1 -> quickstart-es-default-0
        - Pod の状態遷移： Running(1/1) -> Terminating -> Pending -> Init:0/1 -> PodInitializing -> Running(0/1) -> Running(1/1)

```
$ kubectl get es
NAME         HEALTH   NODES   VERSION   PHASE   AGE
quickstart   green    3       7.5.2     Ready   25m
$ kubectl apply -f elasticsearch-quickstart-pv.yaml
elasticsearch.elasticsearch.k8s.elastic.co/quickstart configured
$ kubectl get po -o wide -w
NAME                             READY   STATUS        RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINE
SS GATES
quickstart-es-default-0          1/1     Running       0          25m   10.233.65.103   k8sworker01   <none>           <none>
quickstart-es-default-1          1/1     Running       0          18m   10.233.92.171   k8sworker02   <none>           <none>
quickstart-es-default-2          1/1     Terminating   0          18m   10.233.110.31   k8sworker03   <none>           <none>
quickstart-kb-6c88bdd64c-87w9l   1/1     Running       0          20m   10.233.65.104   k8sworker01   <none>           <none>
quickstart-es-default-2          0/1     Terminating   0          18m   10.233.110.31   k8sworker03   <none>           <none>
quickstart-es-default-2          0/1     Terminating   0          18m   10.233.110.31   k8sworker03   <none>           <none>
quickstart-es-default-2          0/1     Terminating   0          18m   10.233.110.31   k8sworker03   <none>           <none>
quickstart-es-default-2          0/1     Pending       0          0s    <none>          <none>        <none>           <none>
quickstart-es-default-2          0/1     Pending       0          0s    <none>          k8sworker03   <none>           <none>
quickstart-es-default-1          1/1     Running       0          19m   10.233.92.171   k8sworker02   <none>           <none>
quickstart-es-default-2          0/1     Pending       0          1s    <none>          k8sworker03   <none>           <none>
quickstart-es-default-0          1/1     Running       0          25m   10.233.65.103   k8sworker01   <none>           <none>
quickstart-es-default-2          0/1     Init:0/1      0          1s    <none>          k8sworker03   <none>           <none>
quickstart-es-default-2          0/1     PodInitializing   0          20s   10.233.110.32   k8sworker03   <none>           <none>
quickstart-es-default-2          0/1     PodInitializing   0          20s   10.233.110.32   k8sworker03   <none>           <none>
quickstart-es-default-0          1/1     Running           0          26m   10.233.65.103   k8sworker01   <none>           <none>
quickstart-es-default-1          1/1     Running           0          19m   10.233.92.171   k8sworker02   <none>           <none>
quickstart-es-default-1          1/1     Running           0          19m   10.233.92.171   k8sworker02   <none>           <none>
quickstart-es-default-2          0/1     PodInitializing   0          20s   10.233.110.32   k8sworker03   <none>           <none>
quickstart-es-default-0          1/1     Running           0          26m   10.233.65.103   k8sworker01   <none>           <none>
quickstart-es-default-2          0/1     Running           0          21s   10.233.110.32   k8sworker03   <none>           <none>
quickstart-es-default-2          1/1     Running           0          33s   10.233.110.32   k8sworker03   <none>           <none>
quickstart-es-default-1          1/1     Terminating       0          20m   10.233.92.171   k8sworker02   <none>           <none>
quickstart-es-default-1          0/1     Terminating       0          20m   10.233.92.171   k8sworker02   <none>           <none>
quickstart-es-default-1          0/1     Terminating       0          20m   10.233.92.171   k8sworker02   <none>           <none>
quickstart-es-default-1          0/1     Terminating       0          20m   10.233.92.171   k8sworker02   <none>           <none>
quickstart-es-default-1          0/1     Pending           0          0s    <none>          <none>        <none>           <none>
quickstart-es-default-1          0/1     Pending           0          0s    <none>          k8sworker02   <none>           <none>
quickstart-es-default-0          1/1     Running           0          27m   10.233.65.103   k8sworker01   <none>           <none>
quickstart-es-default-1          0/1     Pending           0          1s    <none>          k8sworker02   <none>           <none>
quickstart-es-default-2          1/1     Running           0          71s   10.233.110.32   k8sworker03   <none>           <none>
quickstart-es-default-1          0/1     Init:0/1          0          1s    <none>          k8sworker02   <none>           <none>
quickstart-es-default-1          0/1     Init:0/1          0          11s   10.233.92.172   k8sworker02   <none>           <none>
quickstart-es-default-1          0/1     Init:0/1          0          11s   10.233.92.172   k8sworker02   <none>           <none>
quickstart-es-default-2          1/1     Running           0          81s   10.233.110.32   k8sworker03   <none>           <none>
quickstart-es-default-0          1/1     Running           0          27m   10.233.65.103   k8sworker01   <none>           <none>
quickstart-es-default-1          0/1     Init:0/1          0          12s   10.233.92.172   k8sworker02   <none>           <none>
quickstart-es-default-2          1/1     Running           0          82s   10.233.110.32   k8sworker03   <none>           <none>
quickstart-es-default-0          1/1     Running           0          27m   10.233.65.103   k8sworker01   <none>           <none>
quickstart-es-default-1          0/1     PodInitializing   0          12s   10.233.92.172   k8sworker02   <none>           <none>
quickstart-es-default-1          0/1     Running           0          13s   10.233.92.172   k8sworker02   <none>           <none>
quickstart-es-default-1          1/1     Running           0          27s   10.233.92.172   k8sworker02   <none>           <none>
quickstart-es-default-0          1/1     Terminating       0          27m   10.233.65.103   k8sworker01   <none>           <none>
quickstart-es-default-0          0/1     Terminating       0          28m   <none>          k8sworker01   <none>           <none>
quickstart-es-default-1          1/1     Running           0          61s   10.233.92.172   k8sworker02   <none>           <none>
quickstart-es-default-2          1/1     Running           0          2m11s   10.233.110.32   k8sworker03   <none>           <none>
quickstart-es-default-0          0/1     Terminating       0          28m     <none>          k8sworker01   <none>           <none>
quickstart-es-default-0          0/1     Terminating       0          28m     <none>          k8sworker01   <none>           <none>
quickstart-es-default-0          0/1     Terminating       0          28m     <none>          k8sworker01   <none>           <none>
quickstart-es-default-0          0/1     Terminating       0          28m     <none>          k8sworker01   <none>           <none>
quickstart-es-default-0          0/1     Terminating       0          28m     <none>          k8sworker01   <none>           <none>
quickstart-es-default-0          0/1     Pending           0          0s      <none>          <none>        <none>           <none>
quickstart-es-default-0          0/1     Pending           0          0s      <none>          k8sworker01   <none>           <none>
quickstart-es-default-0          0/1     Init:0/1          0          1s      <none>          k8sworker01   <none>           <none>
quickstart-es-default-0          0/1     PodInitializing   0          6s      10.233.65.105   k8sworker01   <none>           <none>
quickstart-es-default-0          0/1     PodInitializing   0          6s      10.233.65.105   k8sworker01   <none>           <none>
quickstart-es-default-1          1/1     Running           0          74s     10.233.92.172   k8sworker02   <none>           <none>
quickstart-es-default-2          1/1     Running           0          2m24s   10.233.110.32   k8sworker03   <none>           <none>
quickstart-es-default-0          0/1     PodInitializing   0          6s      10.233.65.105   k8sworker01   <none>           <none>
quickstart-es-default-1          1/1     Running           0          74s     10.233.92.172   k8sworker02   <none>           <none>
quickstart-es-default-2          1/1     Running           0          2m24s   10.233.110.32   k8sworker03   <none>           <none>
quickstart-es-default-0          0/1     Running           0          7s      10.233.65.105   k8sworker01   <none>           <none>
quickstart-es-default-0          1/1     Running           0          21s     10.233.65.105   k8sworker01   <none>           <none>
$ kubectl get es
NAME         HEALTH   NODES   VERSION   PHASE   AGE
quickstart   green    3       7.6.0     Ready   28m
$ kubectl get po -o wide
NAME                             READY   STATUS    RESTARTS   AGE     IP              NODE          NOMINATED NODE   READINESS GATES
quickstart-es-default-0          1/1     Running   0          40s     10.233.65.105   k8sworker01   <none>           <none>
quickstart-es-default-1          1/1     Running   0          108s    10.233.92.172   k8sworker02   <none>           <none>
quickstart-es-default-2          1/1     Running   0          2m58s   10.233.110.32   k8sworker03   <none>           <none>
quickstart-kb-6c88bdd64c-87w9l   1/1     Running   0          24m     10.233.65.104   k8sworker01   <none>           <none>
```

この動作は ECK Operator の [Node Orchestration](https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-orchestration.html#k8s-upgrading)によって、下記のように安全に Upgrade している。

 - ECK Operator での Upgrade 動作
    - ノードが削除される前に、関連データは他のノードに移行
    - クラスタ・トポロジが変化したとき、Elasticsearch オーケストレーション設定は下記に応じて調整
        - `discovery.seed_hosts`
        - `cluster.initial_master_nodes`
        - `discovery.zen.minimum_master_nodes`
        - `_cluster/voting_config_exclusions`
    - ローリングアップグレードは安全に実行され、アップグレードされた Elasticsearch ノードは PersistentVolumes を再利用

## delete 時の PVC 動作の StatefulSet との違い
### 内容
今回使用した Elasticesearch を Delete した際に、
**自動生成されていた PVC も削除**された。([StatefulSet では PVC は削除されない](https://kubernetes.io/ja/docs/tasks/run-application/delete-stateful-set/#%E6%B0%B8%E7%B6%9A%E3%83%9C%E3%83%AA%E3%83%A5%E3%83%BC%E3%83%A0))
これは StatefulSet は異なるため、下記の注意が必要だと思われる。

 - 削除して再 Create した場合、StatefulSet とは異なり、PVCが再生成され、別PVがアサインされる可能性がある
 - Retain ポリシーの場合、使用していた PV は Released 状態となり再利用するには対応が必要 (PersistentVolume で provisioner 未対応だと Recycle/Deleteが環境によって対応できず、削除・解放などの工夫が必要になると思われる) 

そもそも Elasticsearch を削除しているので、紐づく PVC も一緒に削除してくれるので問題ではなく、動作の違いとして認識すればいい感じかと思う。
### 動作

下記に使用していた yaml で delete を実施すると下記の動作が確認できる。

 - delete 時動作
    - PVC が削除されている ($ kubectl get pvc)
    - PV がリリースされている ($ kubectl get pv)

```
$ kubectl get po
NAME                      READY   STATUS    RESTARTS   AGE
quickstart-es-default-0   1/1     Running   0          51m
quickstart-es-default-1   1/1     Running   0          52m
quickstart-es-default-2   1/1     Running   0          54m
$ kubectl get pvc
NAME                                         STATUS   VOLUME           CAPACITY   ACCESS MODES   STORAGECLASS   AGE
elasticsearch-data-quickstart-es-default-0   Bound    iscsi-50g-pv05   50Gi       RWO            standard       80m
elasticsearch-data-quickstart-es-default-1   Bound    iscsi-50g-pv06   50Gi       RWO            standard       73m
elasticsearch-data-quickstart-es-default-2   Bound    iscsi-50g-pv04   50Gi       RWO            standard       73m
$ kubectl delete -f elasticsearch-eck-pvc.yaml 
elasticsearch.elasticsearch.k8s.elastic.co "quickstart" deleted
$ kubectl get po
NAME                      READY   STATUS        RESTARTS   AGE
quickstart-es-default-0   1/1     Terminating   0          52m
quickstart-es-default-1   1/1     Terminating   0          53m
quickstart-es-default-2   1/1     Terminating   0          54m
$ kubectl get po
NAME                      READY   STATUS        RESTARTS   AGE
quickstart-es-default-0   0/1     Terminating   0          52m
[suzuyu@k8smaster01 elastic]$ k get po
NAME                      READY   STATUS        RESTARTS   AGE
quickstart-es-default-0   0/1     Terminating   0          52m
$ kubectl get po
NAME                      READY   STATUS        RESTARTS   AGE
quickstart-es-default-0   0/1     Terminating   0          52m
$ kubectl get po
No resources found in default namespace.
$ kubectl get pvc
No resources found in default namespace.
$ kubectl get pv
NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                                                STORAGECLASS   REASON   AGE
iscsi-50g-pv04   50Gi       RWO            Retain           Released    default/elasticsearch-data-quickstart-es-default-2   standard                81m
iscsi-50g-pv05   50Gi       RWO            Retain           Released    default/elasticsearch-data-quickstart-es-default-0   standard                81m
iscsi-50g-pv06   50Gi       RWO            Retain           Released    default/elasticsearch-data-quickstart-es-default-1   standard                81m
```

## 確認できたこと

 - Scale / Upgrade は 1箇所記載を変更して Apply するだけで Operator がよしなに安全に実施してくれた
 - ストレージ
    - ストレージ(PV)を ECK に合った形で準備する必要がある(環境によると思うが)
    - StatefulSet のように volumeClaimTemplate で PVC 作成可能だが、削除時に PVC も消える
 - Secret をデフォルトで準備してくれるので TLS 対応がデフォルトでされている

## おわりに
ECK の QuickStart と VersionUp などを通して、ECK による Elasticsearch/Kibana の構築・動作の確認を実施できた。
今後は、ECK / ElasticStack でオブザーバビリティ(ログ・メトリクス・トレーシング)環境を、オンプレ Kubernetes 上で構築をしたかったので、次にそちらを実施していく予定。