これからはじめるThanos

この記事は [Kubernetes2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/kubernetes2) 10日目の記事です。
## はじめに
この記事では[Thanos](https://thanos.io/)というCNCFのSandboxプロジェクト(2019/12/10時点)のOSSについて書いてみたいと思います。
[Thanos](https://thanos.io/)の概要から[Kubernetes](https://kubernetes.io/)クラスタ上での動かし方までを書いていきます。

**※Thanos自体はKubernetesに依存していないため、Kubernetes環境以外でも利用可能です**


## Thanosとは
[Thanos](https://thanos.io/)はデータの長期保存と可用性の高い[Prometheus](https://prometheus.io/)を提供するためのOSSです。
複数の[Prometheus](https://prometheus.io/)に対して[PrompQL](https://prometheus.io/docs/prometheus/latest/querying/basics/)を実行することができるため、複数の[Kubernetes](https://kubernetes.io/)クラスタでそれぞれ稼働している[Prometheus](https://prometheus.io/)を統合的に管理することができます。
また、[Thanos](https://thanos.io/)はデータ保存用のバックエンドとしてオブジェクトストレージを利用する構成となっており、各[Prometheus](https://prometheus.io/)のメトリクスデータをオブジェクトストレージに保存することによりメトリクスの長期保存を実現することができます。

### Thanosのアーキテクチャ
[Thanos](https://thanos.io/)の全体構成は下記のようになっています。それぞれのコンポーネントについてもう少し細かく見ていきたいと思います。
![arch.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80181/2eca4158-fb92-2e8b-70ea-012ee634b3a9.jpeg)
参考：https://thanos.io/quick-tutorial.md/

#### Sidecar
まずはじめに[Prometheus](https://prometheus.io/)のSidecarとして動作しているThanos Sidecarについて見ていきます。
Thanos Sidecarは[StoreAPI](https://github.com/thanos-io/thanos/blob/229f978dffca4fda136d455e1553cf8cf08a3c9e/pkg/store/storepb/rpc.proto#L19)という[gRPC](https://grpc.io/)のAPIを介して[Prometheus](https://prometheus.io/)のデータをQuerierに提供するプロキシとして動作します。

![Thanos_Sidecar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80181/706b4258-f9db-0486-95a0-7b530eb0f7ae.png)

Sidecarのもう一つの役割はディスクに書き込まれた[Prometheus](https://prometheus.io/)のデータをオブジェクトストレージにアップロードして永続化することです。
Thanos Sidecarは[Prometheus](https://prometheus.io/)のDiskへの書き込みを検知してオブジェクトストレージにデータをアップロードするように動作します。
![Thanos_backup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80181/e56f3124-aa87-8ffc-a16b-63512394e54a.png)

#### Store Gateway
Sidecarが[Prometheus](https://prometheus.io/)のデータをObjectStorageにアップロードすることによってデータの永続化と[Prometheus](https://prometheus.io/)がのっているノードのストレージのデータサイズを抑えることが可能になります。
しかし、オブジェクトストレージにアップロードされたデータを取得する方法がなければ永続化したデータを活用することができません。オブジェクトストレージに保存されたデータをQuerierが取得できるようにするのがStore Gatewayの役割です。
Store GatewayはSidecarと同様にStoreAPIをQuerierに対して提供します。QuerierはStore GatewayのStoreAPIを利用してオブジェクトストレージのbucketに保存されたデータを取得することができます。
![Thanos_Gateway.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80181/ae752282-9e3f-e713-686f-1f4875d3c583.png)

#### Compactor
オブジェクトストレージをスキャンして古いデータの圧縮やコンパクション、ダウンサイジングしたデータのコピーを作成してクエリの実行を高速化します。

#### Ruler
[Thanos](https://thanos.io/)ではQuerierに対してAlertルールを設定することで複数の[Prometheus](https://prometheus.io/)にまたがった監視や、[Prometheus](https://prometheus.io/)単体の保存期間を超えたルールを設定した監視を行うことができます。
![Thanos_Ruler.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80181/b6210b9e-a544-bce2-3563-f889bcca9734.png)


## 環境構築
[Thanos](https://thanos.io/)の概要をおさえたところで実際に環境構築をしていきましょう。
今回はローカルのPCに[Kubernetes](https://kubernetes.io/)を構築してそこに[Prometheus](https://prometheus.io/)と[Thanos](https://thanos.io/)をデプロイしていきます。
筆者のPCのOSはmacOS catalinaです。[Kubernetes](https://kubernetes.io/)クラスタの構築には[kind](https://kind.sigs.k8s.io/)を利用しました。

[Thanos](https://thanos.io/)の[Kubernetes](https://kubernetes.io/)クラスタへのデプロイは[Thanosのドキュメント](https://thanos.io/getting-started.md/#community-thanos-kubernetes-applications)でCommunity Helm chartsとして紹介されていた[Thanos Helm chart](https://hub.helm.sh/charts/banzaicloud-stable/thanos)を使いました。

オブジェクトストレージはGoogleCloudStorageを利用します。
オブジェクトストレージの選択肢としてはAmazon S3やOpenStack Swift等他にも選択肢があるので、他のオブジェクトストレージを利用する場合は下記ドキュメント参考に設定してください。
https://thanos.io/storage.md/ 

## Kubernetesクラスタの構築
最初にHomebrewで[kind](https://kind.sigs.k8s.io/)をインストールします。

```
$ brew install kind
```

インストールが完了したらクラスタを作成します。
下記のように[kind](https://kind.sigs.k8s.io/)のconfigファイルを記述してcontrol-plane1台、worker1台の構成とします。

```yaml:kind-config.yaml
kind: Cluster
apiVersion: kind.sigs.k8s.io/v1alpha3
nodes:
- role: control-plane
- role: worker
```

では実際にクラスタを作成してみましょう。

```
$ kind create cluster --config kind-config.yaml
```

しばらく待つと[Kubernetes](https://kubernetes.io/)クラスタが作成されるので、contextを切り替えます。

```
$ kubectl config use-context kind-kind
$ kubectl config current-context
kind-kind
```

## Thanosのdeploy
デプロイに[Helm](https://helm.sh/)を使うのでまず最初に[Helm](https://helm.sh/)のインストールを行います。

```
$ brew install helm
```

次に[Prometheus](https://prometheus.io/)のデータをオブジェクトストレージに保存するためのservice accountを作成します。
service accountのポリシーは下記を参考にストレージのオブジェクト作成者とストレージオブジェクト閲覧者を割り当てます。
https://thanos.io/storage.md/#gcs-policies

service accountを作成したら鍵を作成して下記の形式でオブジェクトストレージのconfigファイルに設定します。

```yaml:object-store.yaml
type: GCS
config:
  bucket: "thanos"
  service_account: |-
    {
      "type": "service_account",
      "project_id": "project",
      "private_key_id": "abcdefghijklmnopqrstuvwxyz12345678906666",
      "private_key": "-----BEGIN PRIVATE KEY-----\...\n-----END PRIVATE KEY-----\n",
      "client_email": "project@thanos.iam.gserviceaccount.com",
      "client_id": "123456789012345678901",
      "auth_uri": "https://accounts.google.com/o/oauth2/auth",
      "token_uri": "https://oauth2.googleapis.com/token",
      "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
      "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/thanos%40gitpods.iam.gserviceaccount.com"
    }
```
参考：https://thanos.io/storage.md/#using-inline-a-service-account

[Thanos](https://thanos.io/)をデプロイするためのNamespaceを作成してデプロイを行います。

```
$ git clone https://github.com/banzaicloud/banzai-charts.git
$ cd banzaicloud/banzai-charts/thanos

$ helm repo add banzaicloud-stable https://kubernetes-charts.banzaicloud.com
$ helm install thanos banzaicloud-stable/thanos --namespace thanos -f values.yaml --set-file objstoreFile=object-store.yaml
```

[Thanos](https://thanos.io/)のデプロイが完了しました。
次に[Prometheus](https://prometheus.io/)をデプロイします。[Prometheus](https://prometheus.io/)のデプロイには[prometheus-operator](https://github.com/coreos/prometheus-operator)を使います。
[prometheus-operator](https://github.com/coreos/prometheus-operator)は[Helm Chart](https://github.com/helm/charts/tree/master/stable/prometheus-operator)が存在するのでこちらを使ってデプロイを行います。

[Thanos](https://thanos.io/)を利用するには[Prometheus](https://prometheus.io/)にSidecarをデプロイする必要がありますが、こちらは[prometheus-operator](https://github.com/coreos/prometheus-operator)に下記の通り設定を追加することで[Prometheus](https://prometheus.io/)のSidecarとしてThanos Sidecarをデプロイすることができます。

```yaml:thanos-sidecar.yaml
prometheus:
  prometheusSpec:
    thanos:
      image: quay.io/thanos/thanos:v0.8.1
      version: v0.8.1
      objectStorageConfig:
        name: thanos
        key: object-store.yaml
```

上記の内容をthanos-sidecar.yamlというファイル名で保存したら、[Helm](https://helm.sh/)を使って[Prometheus](https://prometheus.io/)をデプロイします。

```
$ helm install prometheus stable/prometheus-operator --namespace thanos -f thanos-sidecar.yaml
```

Podの一覧を確認してすべてRunningになっていることを確認します。

```
$ kubectl get pods -n thanos
NAME                                                     READY   STATUS    RESTARTS   AGE
alertmanager-prometheus-prometheus-oper-alertmanager-0   2/2     Running   0          19h
prometheus-grafana-6bd876879f-hf8sb                      2/2     Running   0          19h
prometheus-kube-state-metrics-766476f899-5kshh           1/1     Running   0          19h
prometheus-prometheus-node-exporter-vkfg8                1/1     Running   0          19h
prometheus-prometheus-oper-operator-5bd8d4db69-62j8m     2/2     Running   0          19h
prometheus-prometheus-prometheus-oper-prometheus-0       4/4     Running   1          19h
thanos-bucket-574dcc6585-mb8jl                           1/1     Running   0          19h
thanos-compact-7fbf995746-rgp9t                          1/1     Running   0          19h
thanos-query-f754c67c9-5n6fm                             1/1     Running   0          19h
thanos-store-0-6d967bc966-m22fk                          1/1     Running   0          19h
```

kubectl port-forwardを利用してPrometheusのUIを確認します。

```
$ kubectl port-forward svc/prometheus-prometheus-oper-prometheus 9090
Forwarding from 127.0.0.1:9090 -> 9090
Forwarding from [::1]:9090 -> 9090
```

別ターミナルで下記を実行してブラウザでUIを確認します。

```
$ open http://localhost:9090
```

<img width="1672" alt="スクリーンショット 2019-12-08 16.12.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80181/897d160a-66b4-27b6-21c3-8b7a1be4dfd1.png">

次にThanos Queryを見てみます。

```
$ kubectl port-forward svc/thanos-query-http 10902
Forwarding from 127.0.0.1:10902 -> 10902
Forwarding from [::1]:10902 -> 10902

$ open http://localhost:10902
```

<img width="1667" alt="スクリーンショット 2019-12-08 16.15.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80181/cee83058-bc02-47ca-800d-145cef75984a.png">

Thanos Bucket Viewerでオブジェクトストレージのbucketにアップロードされているデータを確認できます。

```
$ kubectl port-forward svc/thanos-bucket 8080 
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

$ open http://localhost:8080
```

2時間毎に[Prometheus](https://prometheus.io/)がTSDB Blockを生成し、Thanos SidecarがそれをオブジェクトストレージにアップロードするのでThanos Bucket Viewerにデータが表示されるには時間がかかります。

<img width="1673" alt="スクリーンショット 2019-12-08 19.56.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80181/3bf4c3d5-5346-a2bf-ad44-23962a553edb.png">

## まとめ
[Thanos](https://thanos.io/)の概要について調べてみました。
[Prometheus](https://prometheus.io/)を複数にスケールして統合的に管理したいかつデータを永続化したいという要件がある場合に利用を検討しても良いのではないかと感じました。

一方で[Prometheus](https://prometheus.io/)単体で運用するよりもコンポーネントが結構増えてしまうので、本番環境等で運用する際にどの程度手間がかかるのかは気になりました。