Prometheus の Config ファイルの構文チェックを GitHub Actions で行う

# Prometheus の Config ファイルの構文チェックを GitHub Actions で行う

# 目次

[1.前提](#前提)  
[2.Promtool とは](#promtool-とは)  
[3.Amtool とは](#amtool-とは)  
[4.prometheus.yml の構文チェックの Workflow](#prometheusyml-の構文チェックの-workflow)  
[5.ルールファイルの構文チェックの Workflow](#ルールファイルの構文チェックの-workflow)  
[6.alertmanager.yml の構文チェックの Workflow](#alertmanageryml-の構文チェックの-workflow)

# 前提

Prometheus の監視対象などを変更する際、これまではローカルで検証を行っていたが、  
PR を出した時点で検証したく、 GitHub Actions × Promtool を使って構文チェックを行うことにした。

# Promtool とは

https://prometheus.io/docs/prometheus/latest/command-line/promtool/

**Promtool**は、Prometheus プロジェクトに付属する公式のコマンドラインツールです。  
Prometheus の設定ファイルやルールファイルの検証、テスト、診断など、運用に関わるさまざまなサポート機能を提供します。

## 使い方

1. **Prometheus 設定ファイルの検証**  
   Prometheus の設定ファイル（`prometheus.yml`）に構文エラーや設定ミスがないか確認します

   ```bash
   promtool check config /path/to/prometheus.yml
   ```

   エラーがある場合、具体的なエラーメッセージと問題の箇所が表示されます。  
   こんな感じ

   ```bash
    $ promtool check config prometheus.yml
    Checking prometheus.yml
    FAILED: parsing YAML file prometheus.yml: yaml: unmarshal errors:
    line 7: field target not found in type struct { Targets []string "yaml:\"targets\""; Labels model.LabelSet "yaml:\"labels\"" }
   ```

2. **ルールファイルの検証**  
   ルールファイルの構文と内容を検証します

   ```bash
   promtool check rules /path/to/rules.yml
   ```

   検証例

   ```bash
     $ promtool check rules rules.yml
    Checking rules.yml
    FAILED:
    rules.yml: 5:13: group "instance", rule 1, "InstanceDown": could not parse expression: 1:4: parse error: unexpected "="
   ```

# Amtool とは

**Amtool**は、Prometheus エコシステムの一部である**Alertmanager**を操作・検証するためのコマンドラインツールです。  
Promtool と同様に Alertmanager の設定ファイルの検証や、アラートの管理、シルエンス（一時的なアラート抑制）の設定など、Alertmanager の運用を支援します。

## 使い方

1. **Alertmanager 設定ファイルの検証**  
   Alertmanager の設定ファイル（`alertmanager.yml`）に構文エラーや設定ミスがないか確認します

   ```bash
   amtool check-config /path/to/alertmanager.yml
   ```

   使用例

   ```bash
   $ amtool check-config alertmanager.yml
    ger check-config alertmanager.yml
    Checking 'alertmanager.yml'amtool: error: failed to validate 1 file(s)

    FAILED: yaml: unmarshal errors:
    line 42: field receiver not found in type config.plain
   ```

# prometheus.yml の構文チェックの Workflow


<details><summary><b>prometheus.yml の構文チェック</b></summary>

```yaml
name: Prd Config Check

on:
  pull_request:
    paths:
      - "roles/prometheus/files/*.yml"
      - "!roles/prometheus/files/rules/*"

env:
  CONTAINER_NAME: prometheus-container

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker container
        run: docker create --name ${{env.CONTAINER_NAME}} prom/prometheus

      - name: Start Docker container
        run: docker start ${{env.CONTAINER_NAME}}

      - name: Copy Prometheus config to container
        run: |
          for file in ${{ github.workspace }}/roles/prometheus/files/prd-*; do
            filename=$(basename "$file")
            echo $filename
            docker cp "$file" "${{env.CONTAINER_NAME}}:/etc/prometheus/$filename"
          done

      - name: Check Prometheus Config
        run: docker exec ${{env.CONTAINER_NAME}} promtool check config /etc/prometheus/prometheus.yml

      - name: Check Warning exists
        run: |
          output=$(docker exec ${{env.CONTAINER_NAME}} promtool check config /etc/prometheus/prometheus.yml)
          echo "$output"
          if echo "$output" | grep -q "WARNING"; then
            echo "Prometheus config check failed due to warnings."
            exit 1
          fi

      - name: Clean up Docker container
        run: docker rm -f ${{env.CONTAINER_NAME}}
```

</details>

## ステップの説明

1. リポジトリのチェックアウト  
   actions/checkout@v4 を使用してリポジトリをチェックアウトします
2. Docker コンテナのセットアップ  
   prom/prometheus イメージを使用してコンテナを作成し、起動します
3. Prometheus 設定ファイルのコピー  
   roles/prometheus/files/ ディレクトリ内の prd- で始まるファイルをコンテナ内の /etc/prometheus/ にコピーします
4. Prometheus 設定ファイルのチェック  
   promtool を使用して、コンテナ内の /etc/prometheus/prometheus.yml の設定をチェックします
5. 警告のチェック  
   promtool の出力に WARNING が含まれているかを確認し、含まれている場合はエラーとして処理します
6. Docker コンテナのクリーンアップ  
   使用した Docker コンテナを削除します

## 設計のポイント

1. ワークフローのトリガー  
   pull_request が出されたときに実行されます。  
   対象ファイルは `roles/prometheus/files/*.yml` で、`roles/prometheus/files/rules/*` は除外されます。  
   著者の環境ですと、`roles/prometheus/files/prd-*` に prd-prometheus.yml という名前で設定ファイルが格納されているため、このような設定になっています。
   またルールファイルが`roles/prometheus/files/rules/*` に格納されているため、除外しています

2. 環境変数の設定  
   `CONTAINER_NAME` として `prometheus-container` を設定しています
3. Prometheus 設定ファイルのコピー  
   これまた環境的にファイル名に prd がついているため、ファイル名を`Prometheus.yml` に変更しています
4. 警告のチェック  
   `file_sd_configs`で指定しているファイルが存在しない場合などは WARNING が出ますが、終了コードが 1 ではないため、Actions がエラーとして判定しませんでした。  
   そのため、出力に WARNING が含まれているかを確認し、含まれている場合はエラーとして処理するようにしています。  
   関連するような Issue はありました。  
   
https://github.com/prometheus/prometheus/issues/12499

# ルールファイルの構文チェックの Workflow



<details><summary><b>rules.yml の構文チェック</b></summary>

```yaml
name: Rules File Check

on:
  pull_request:
    paths:
      - "roles/prometheus/files/rules/*"

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.base.sha }}

      - uses: actions/checkout@v4

      - name: Get changed files
        id: changed-files
        run: |
          git diff --diff-filter=AM --name-only ${{ github.event.pull_request.base.sha }}.. | grep 'roles/prometheus/files/rules/.*\.rules$' > changed_files.txt

      - name: Pre-pull Prometheus Docker image
        run: docker pull prom/prometheus

      - name: Lint and Check Prometheus Rule
        run: |
          while IFS= read -r file; do
            full_path="${{ github.workspace }}/$file"
            docker container run --rm -v="$full_path:/prometheus-config/$(basename $file)" --entrypoint="promtool" prom/prometheus check rules --lint-fatal /prometheus-config/$(basename $file)
          done < changed_files.txt
```

</details>

## ステップの説明

1. リポジトリのチェックアウト  
   actions/checkout@v4 を使用して、プルリクエストのベースブランチの SHA を指定してリポジトリをチェックアウトします
2. リポジトリの再チェックアウト  
   再度 actions/checkout@v4 を使用してリポジトリをチェックアウトします
3. 変更されたファイルの取得  
   git diff コマンドを使用して、プルリクエストで追加または変更されたファイルを取得し、  
   `roles/prometheus/files/rules/` ディレクトリ内の` .rules` ファイルのみを `changed_files.txt` に保存します
4. Prometheus Docker イメージの事前プル  
   docker pull prom/prometheus コマンドを使用して、Prometheus の Docker イメージを事前にプルします
5. Prometheus ルールの Lint とチェック  
   changed_files.txt にリストされた各ファイルについて、  
   promtool を使用してルールファイルの Lint とチェックを行います。  
   具体的には、各ファイルを Docker コンテナ内にマウントし、promtool check rules --lint-fatal コマンドを実行します

## 設計のポイント

1. 差分ファイルの取得
   ルールファイルの中でも、差分があったファイルのみを検証にかけるよう、下記記事を参考に差分ファイルの取得を行いテキストファイルに追記し、後のステップで扱うようにしています  
   
https://qiita.com/osakiy/items/0e18eee444446307b970
   
https://qiita.com/nade/items/3a5fbd77e2bc7df8a48a


2. lint-Fatal オプション  
   lint エラーを終了コード 3 で終了させます。  

https://prometheus.io/docs/prometheus/latest/command-line/promtool/#promtool-check

# alertmanager.yml の構文チェックの Workflow

<details><summary><b>alertmanager.yml の構文チェック</b></summary>

```yaml
name: AlertManager Check Config

on:
  pull_request:
    paths:
      - "roles/alertmanager/files/*"

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.base.sha }}

      - uses: actions/checkout@v4

      - name: Get changed files
        id: changed-files
        run: |
          git diff --diff-filter=AM --name-only ${{ github.event.pull_request.base.sha }}.. | grep 'roles/alertmanager/files/.*\.yml$' > changed_files.txt

      - name: Pre-pull AlertManager Docker image
        run: docker pull prom/alertmanager

      - name: Lint and Check AlertManager Config
        run: |
          while IFS= read -r file; do
            full_path="${{ github.workspace }}/$file"
            docker container run --rm -v="$full_path:/prometheus-config/$(basename $file)" --entrypoint="amtool" prom/alertmanager check-config  /prometheus-config/$(basename $file)
          done < changed_files.txt
```

</details>

## ステップの説明

1. リポジトリのチェックアウト  
   actions/checkout@v4 を使用して、プルリクエストのベースブランチの SHA を指定してリポジトリをチェックアウトします。

2. リポジトリの再チェックアウト  
   再度 actions/checkout@v4 を使用してリポジトリをチェックアウトします。

3. 変更されたファイルの取得  
   git diff コマンドを使用して、プルリクエストで追加または変更されたファイルを取得し、roles/alertmanager/files/ ディレクトリ内の .yml ファイルのみを changed_files.txt に保存します。

4. AlertManager Docker イメージの事前プル  
   docker pull prom/alertmanager コマンドを使用して、AlertManager の Docker イメージを事前にプルします。

5. AlertManager 設定ファイルの Lint とチェック  
   changed_files.txt にリストされた各ファイルについて、amtool を使用して設定ファイルの Lint とチェックを行います。  
   具体的には、各ファイルを Docker コンテナ内にマウントし、amtool check-config コマンドを実行します。

# まとめ

良い感じになった

# 参考

https://blog.uzimihsr.com/post/2021-01-28-promtool-amtool-check-config/