Prometheus 2.0 の変更点と移行

[Prometheus 2.0](https://prometheus.io/blog/2017/11/08/announcing-prometheus-2-0/) の主な変更点と移行するときのメモをまとめました。

## 主な変更点
- ストレージ部分がリライトされて[パフォーマンスが大きく向上](https://prometheus.io/blog/2017/11/08/announcing-prometheus-2-0/#storage) :tada:
  - CPU、ディスク使用量、I/O のすべてが改善された
  - オプションがシンプルになり `-storage.local.target-heap-size` のチューニングが不要に(後述)
  - :warning: v1.x からデータファイルの移行はできないので注意
  - コードは [prometheus/tsdb](http://github.com/prometheus/tsdb) という独立したレポジトリで管理されている
- staleness の取扱が変わった
  - staleness とはターゲットが消えたりして有効でなくなった time series を無視するための仕組み
  - 1.x では直近 5 分間データがなければ time series が無効になったと判定していた
  - 2.0 ではstaleness のマーカーが実装され timeseries が終了したことが明示的にわかるようになった
- オプション、設定ファイルにいくつか変更あり
  - v1.x から起動オプション、設定ファイルを修正する必要あり

## 1.x から 2.0 への移行
移行については [PROMETHEUS 2.0 MIGRATION GUIDE](https://prometheus.io/docs/prometheus/2.0/migration/) というドキュメントにまとまっています。設定ファイルは v1.x から大きくは変わっていないので一部の修正で移行することができました。移行の注意点は主に以下になります。

- 1.x とのデータの互換性はないのでデータ移行はできない
  - 1.8 移行であれば scrape を止めた旧バージョンを並行して動かしておき新バージョンから remote_read で参照することは可能
- アラートルール、レコーディングルールの記述が yaml 形式に変わった
  - [promtool](https://github.com/prometheus/prometheus/tree/master/cmd/promtool) で自動変換可能 (後述)
  - https://prometheus.io/docs/prometheus/2.0/migration/#recording-rules-and-alerts
- コマンドライン引数のダッシュが一つから二つに変更
  - 例: `-config.file` が `--config.file` に
  - フラグライブラリが go 標準の `flag` から [alecthomas/kingpin](https://godoc.org/github.com/alecthomas/kingpin)に変わったことに起因
- 下記のコマンドライン引数が削除された
  - `-alertmanager.url`: [設定ファイルで指定する](https://prometheus.io/docs/prometheus/2.0/migration/#alertmanager-service-discovery)
  - `-log.format`: stderr への出力だけになった。
  - `-query.staleness-delta`: ` --query.lookback-delta` にリネームされた。
  - `-storage.local.*`: ストレージエンジンが変わったことでなくなった。`--storage.tsdb.*` で新しいストレージエンジンの設定を行う(後述)
  - `-storage.remote.*`: もともと deprecated だったフラグが削除された。
- PromQL から下記の関数が削除された
  - `drop_common_labels`: 代わりに `without` を使う
  - `keep_common`: 代わりに `by` を使う
  - `count_scalar`: time series の存在をチェックしたい場合は `absent` を利用する
- 設定ファイルのリロード用エンドポイント `/-/reload` はセキュリティ上の理由でデフォルト無効になった
  - `--web.enable-lifecycle` で有効にできる
- prometheus の Docker イメージが non-root で実行されるようになった
  - 80 番のような特権ポートを使いたい場合は[指定が必要](https://prometheus.io/docs/prometheus/2.0/migration/#prometheus-non-root-user)

### ストレージのオプション

`-storage.local.*` のオプションがなくなった代わりに `--storage.tsdb.*` というオプションが追加されています。データの保持期間(retention)は v1 と同様存在しますが、メモリの使用量を指定する `-storage.local.target-heap-size` に相当するものはなくなりオプションは非常にシンプルになりました。

#### `-storage.local.target-heap-size` が不要になった理由
`-storage.local.target-heap-size` による明示的なメモリの指定がいらなくなったのは [Go のレイヤで行っていたチャンクデータのキャッシュ](https://github.com/prometheus/prometheus/blob/5211b96d4d1291c3dd1a569f711d3b301b635ecb/storage/local/storage.go#L1130)の処理を、2.0 では[mmap を使い](https://github.com/prometheus/tsdb/blob/1bacdf8e33ff7506916cca62471459525aab3456/block.go#L396)カーネル側に任せることで自前での退避(evict)処理が必要なくなったからだそうです。参考: [Unable to deploy v2.0.0-beta.0 #480 のコメント](https://github.com/coreos/prometheus-operator/issues/480#issuecomment-315750449)

#### オプション
```
$ docker run prom/prometheus:v2.0.0 -h
      --storage.tsdb.path="data/"
                                 Base path for metrics storage.
      --storage.tsdb.min-block-duration=2h
                                 Minimum duration of a data block before being
                                 persisted.
      --storage.tsdb.max-block-duration=<duration>
                                 Maximum duration compacted blocks may span.
                                 (Defaults to 10% of the retention period)
      --storage.tsdb.retention=15d
                                 How long to retain samples in the storage.
      --storage.tsdb.no-lockfile
                                 Do not create lockfile in data directory.
```

### promtool でのアラートルールの変換

promtool で下記のようにアラートルールを変換が可能です。

```
$ docker run -v $PWD:/current --entrypoint /bin/promtool prom/prometheus:v2.0.0 update rules /current/general.rule
Updating /current/general.rule
```

変換元のルール `.yml` という prefix が付いたファイル名で変換されたものが保存されます

```text:general.rule
# 変換前
ALERT InstanceDown
  IF up == 0
  FOR 5m
  LABELS { severity = "page" }
  ANNOTATIONS {summary = "Instance {{ $labels.instance }} down"}
```

```yaml:general.rule.yml
# 変換後
groups:
- name: /current/general.rule
  rules:
  - alert: InstanceDown
    expr: up == 0
    for: 5m
    labels:
      severity: page
    annotations:
      summary: Instance {{ $labels.instance }} down
```

## 参考
- https://prometheus.io/blog/2017/11/08/announcing-prometheus-2-0/
- https://prometheus.io/docs/prometheus/2.0/migration/