2023年11月30日木曜日

Gitlab の alertmanager でテンプレートファイルを使用する方法

Gitlab の alertmanager でテンプレートファイルを使用する方法

概要

前回メール本文のテンプレートをカスタマイズする方法を紹介しました
今回は直接テンプレートを docker-compose に記載せずテンプレートファイルを使ってカスタムしてみたいと思います

環境

  • Gitlab 16.3.6
  • Alertmanager 0.25.0

my_email_html.tmpl

まずは html メールのカスタマイズからしていきます
html テンプレートのベースはこれを使います
リンクの部分を削除するのとテンプレート名を「my.email.html」という名前に変更しています

  • vim my_email_html.tmpl
{{ define "email.default.subject" }}{{ template "__subject" . }}{{ end }}
{{ define "my.email.html" }}
<!--
Style and HTML derived from https://github.com/mailgun/transactional-email-templates


The MIT License (MIT)

Copyright (c) 2014 Mailgun

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
<head>
<meta name="viewport" content="width=device-width">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>{{ template "__subject" . }}</title>
<style>
@media only screen and (max-width: 640px) {
  body {
    padding: 0 !important;
  }

  h1,
h2,
h3,
h4 {
    font-weight: 800 !important;
    margin: 20px 0 5px !important;
  }

  h1 {
    font-size: 22px !important;
  }

  h2 {
    font-size: 18px !important;
  }

  h3 {
    font-size: 16px !important;
  }

  .container {
    padding: 0 !important;
    width: 100% !important;
  }

  .content {
    padding: 0 !important;
  }

  .content-wrap {
    padding: 10px !important;
  }

  .invoice {
    width: 100% !important;
  }
}
</style>
</head>

<body itemscope itemtype="https://schema.org/EmailMessage" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 1.6em; background-color: #f6f6f6; width: 100%;">

<table class="body-wrap" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; background-color: #f6f6f6; width: 100%;" width="100%" bgcolor="#f6f6f6">
  <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
    <td style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top;" valign="top"></td>
    <td class="container" width="600" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; display: block; max-width: 600px; margin: 0 auto; clear: both;" valign="top">
      <div class="content" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; max-width: 600px; margin: 0 auto; display: block; padding: 20px;">
        <table class="main" width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; background-color: #fff; border: 1px solid #e9e9e9; border-radius: 3px;" bgcolor="#fff">
          <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
            {{ if gt (len .Alerts.Firing) 0 }}
            <td class="alert alert-warning" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; vertical-align: top; font-size: 16px; color: #fff; font-weight: 500; padding: 20px; text-align: center; border-radius: 3px 3px 0 0; background-color: #E6522C;" valign="top" align="center" bgcolor="#E6522C">
              {{ .Alerts | len }} alert{{ if gt (len .Alerts) 1 }}s{{ end }} for {{ range .GroupLabels.SortedPairs }}
                {{ .Name }}={{ .Value }}
              {{ end }}
            </td>
            {{ else }}
            <td class="alert alert-good" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; vertical-align: top; font-size: 16px; color: #fff; font-weight: 500; padding: 20px; text-align: center; border-radius: 3px 3px 0 0; background-color: #68B90F;" valign="top" align="center" bgcolor="#68B90F">
              {{ .Alerts | len }} alert{{ if gt (len .Alerts) 1 }}s{{ end }} for {{ range .GroupLabels.SortedPairs }}
                {{ .Name }}={{ .Value }} 
              {{ end }}
            </td>
            {{ end }}
          </tr>
          <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
            <td class="content-wrap" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; padding: 30px;" valign="top">
              <table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
                <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
                  <td class="content-block" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; padding: 0 0 20px;" valign="top">
                  </td>
                </tr>
                {{ if gt (len .Alerts.Firing) 0 }}
                <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
                  <td class="content-block" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; padding: 0 0 20px;" valign="top">
                    <strong style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">[{{ .Alerts.Firing | len }}] Firing</strong>
                  </td>
                </tr>
                {{ end }}
                {{ range .Alerts.Firing }}
                <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
                  <td class="content-block" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; padding: 0 0 20px;" valign="top">
                    <strong style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">Labels</strong><br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
                    {{ range .Labels.SortedPairs }}{{ .Name }} = {{ .Value }}<br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">{{ end }}
                    {{ if gt (len .Annotations) 0 }}<strong style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">Annotations</strong><br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">{{ end }}
                    {{ range .Annotations.SortedPairs }}{{ .Name }} = {{ .Value }}<br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">{{ end }}
                  </td>
                </tr>
                {{ end }}

                {{ if gt (len .Alerts.Resolved) 0 }}
                  {{ if gt (len .Alerts.Firing) 0 }}
                <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
                  <td class="content-block" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; padding: 0 0 20px;" valign="top">
                    <br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
                    <hr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
                    <br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
                  </td>
                </tr>
                  {{ end }}
                <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
                  <td class="content-block" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; padding: 0 0 20px;" valign="top">
                    <strong style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">[{{ .Alerts.Resolved | len }}] Resolved</strong>
                  </td>
                </tr>
                {{ end }}
                {{ range .Alerts.Resolved }}
                <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
                  <td class="content-block" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; padding: 0 0 20px;" valign="top">
                    <strong style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">Labels</strong><br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
                    {{ range .Labels.SortedPairs }}{{ .Name }} = {{ .Value }}<br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">{{ end }}
                    {{ if gt (len .Annotations) 0 }}<strong style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">Annotations</strong><br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">{{ end }}
                    {{ range .Annotations.SortedPairs }}{{ .Name }} = {{ .Value }}<br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">{{ end }}
                  </td>
                </tr>
                {{ end }}
              </table>
            </td>
          </tr>
        </table>

        <div class="footer" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; padding: 20px;">
          <table width="100%" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
            <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
            </tr>
          </table>
        </div></div>
    </td>
    <td style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top;" valign="top"></td>
  </tr>
</table>

</body>
</html>

{{ end }}

テンプレートファイルの配置

コンテナで動作する Gitlab が参照できるようにします
今回はホストマシンの一部のパスをマウントしてコンテナが参照できるようにしています

  • mkdir /path/to/opt/alertmanager/template
  • cp my_email_html.tmpl /path/to/opt/alertmanager/template

gitlab.rb

あとはテンプレートを参照するように alertmanager の設定を書き換えます

html の部分を定義した template を使うように変更します
また配置したテンプレートファイルを読み込むように alertmanager['templates'] を定義します

  • vim .gitlab.rb
alertmanager['listen_address'] = '0.0.0.0:9093'
alertmanager['receivers'] = [
  {
    name: 'email',
    email_configs: [
      to: 'your_to@mail',
      from: 'your_from@mail',
      smarthost: 'smtp.ess.nifcloud.com:465',
      auth_username: 'your_access_key',
      auth_password: 'your_secret_key',
      require_tls: false,
      headers: {
        subject: '[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] ({{ $$alerts := "" }}{{ $$instance_id := (index .Alerts 0).Labels.instance_id }}{{ range .Alerts }}{{ $$alerts = (printf "%v %v" $$alerts .Labels.alertname) }}{{ end }}{{ $$instance_id }} ->{{ $$alerts }})'
      },
      html: '{{ template "my.email.html" . }}',
      send_resolved: true
    ]
  }
]
alertmanager['routes'] = [
  {
    receiver: 'email',
    group_wait: '30s',
    group_interval: '5m',
    repeat_interval: '4h',
    matchers: [ 'instance_id = hoge' ]
  }
]
alertmanager['templates'] = ['/var/opt/gitlab/alertmanager/template/*.tmpl']
# alertmanager['default_receiver'] = 'email'

動作確認

あとは redis などを停止すればアラートがきます

  • docker-compose exec gitlab gitlab-ctl stop redis

こんな感じで alertmanager へのリンクが削除されているのが確認できると思います

テキストメールのテンプレート化

次にテキストメールでもテンプレート化してみます
テンプレート化する内容は前回の本文とタイトルの内容をテンプレート化してみます

今回は1つのテンプレートファイルに2つの define を使って本文とタイトル用のテンプレートを定義します

  • vim my_email_text.tmpl
{{ define "my.email.text.body" }}
{{ range .Alerts.Firing }}
{{ range .Annotations.SortedPairs }}
- {{ .Name }} = {{ .Value }}
{{ end }}
{{ end }}
{{ end }}

{{ define "my.email.text.subject" }}
{{ $alerts := "" }}
{{ $instance_id := (index .Alerts 0).Labels.instance_id }}
{{ range .Alerts }}
{{ $alerts = (printf "%v %v" $alerts .Labels.alertname) }}
{{ end }}
[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] ({{ $instance_id }} ->{{ $alerts }})
{{ end }}

コンテナが参照できるパスにコピーします

  • cp my_email_text.tmpl /path/to/opt/alertmanager/template

gitlab.rb でテキストメールの本文とタイトルにテンプレートを使うように変更します
html メールは無効化するのでブランクを設定します

  • vim gitlab.rb
alertmanager['listen_address'] = '0.0.0.0:9093'
alertmanager['receivers'] = [
  {
    name: 'email',
    email_configs: [
      to: 'your_to@mail',
      from: 'your_from@mail',
      smarthost: 'smtp.ess.nifcloud.com:465',
      auth_username: 'your_access_key',
      auth_password: 'your_secret_key',
      require_tls: false,
      headers: {
        subject: '{{ template "my.email.text.subject" . }}'
      html: '',
      text: '{{ template "my.email.text.body" . }}',
      send_resolved: true
    ]
  }
]
alertmanager['routes'] = [
  {
    receiver: 'email',
    group_wait: '30s',
    group_interval: '5m',
    repeat_interval: '4h',
    matchers: [ 'instance_id = hoge' ]
  }
]
alertmanager['templates'] = ['/var/opt/gitlab/alertmanager/template/*.tmpl']
# alertmanager['default_receiver'] = 'email'

あとは再起動して再度 redis を停止すればテンプレートファイル化された内容でテキストメールのアラートが届くことが確認できると思います

最後に

docker-compose に直接テンプレート構文を使うこともできますがテンプレートの内容が長くなり一行では管理しづらい場合などはテンプレートファイル化してあげるといいのかなと思います

参考サイト

2023年11月29日水曜日

Gitlab の alertmanager でメール本文をカスタマイズする方法

Gitlab の alertmanager でメール本文をカスタマイズする方法

概要

前回 routes を設定する方法を紹介しました
今回はメールの本文やタイトルをカスタムする方法を紹介します

環境

  • Gitlab 16.3.6
  • Alertmanager 0.25.0

gitlab.rb

alertmanager['receivers'] の email_configs 内にある headers.subject, text を編集します
デフォルトの html メールは無効にするためブランクを設定しておきます

メールの内容には golang のテンプレート構文が使えます
注意するのは変数の定義で golang ではダラー1つで定義しますが今回は docker-compose 内でテンプレートを定義するためダラーを2つにする必要があります

使用できるテンプレート文字列やテンプレート構文に関しては各種公式を参考にしてください

alertmanager['listen_address'] = '0.0.0.0:9093'
alertmanager['receivers'] = [
  {
    name: 'email',
    email_configs: [
      to: 'your_to@mail',
      from: 'your_from@mail',
      smarthost: 'smtp.ess.nifcloud.com:465',
      auth_username: 'your_access_key',
      auth_password: 'your_secret_key',
      require_tls: false,
      headers: {
        subject: '[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] ({{ $$alerts := "" }}{{ $$instance_id := (index .Alerts 0).Labels.instance_id }}{{ range .Alerts }}{{ $$alerts = (printf "%v %v" $$alerts .Labels.alertname) }}{{ end }}{{ $$instance_id }} ->{{ $$alerts }})'
      },
      html: '',
      text: '{{ range .Alerts.Firing }}{{ range .Annotations.SortedPairs }}  - {{ .Name }} = {{ .Value }}{{ "\n" }}{{ end }}{{ end }}',

      send_resolved: true
    ]
  }
]
alertmanager['routes'] = [
  {
    receiver: 'email',
    group_wait: '30s',
    group_interval: '5m',
    repeat_interval: '4h',
    matchers: [ 'instance_id = hoge' ]
  }
]

custom.rules

groups:
- name: Custom
  rules:
  - alert: RedisDown
    expr: avg_over_time(redis_up[5m]) * 100 < 50
    labels:
      severity: critical
      instance_id: hoge
    annotations:
      description: The Redis service is not responding for more than 50% of the time for 5 minutes.
      summary: The Redis service is not responding

動作確認

実際に redis をダウンさせるとカスタムした本文とタイトルでテキストメールが届くと思います

最後に

Gitlab 内の alertmanager のメール本文をカスタムする方法を紹介しました
golang の知識が必要になると alertmanager に送信させる json の内容も把握する必要があります

alertmanager に送信される json 情報はどこかで確認することができるのだろうか

参考サイト

2023年11月28日火曜日

amtool を使って alertmanager のテンプレートの確認をする方法

amtool を使って alertmanager のテンプレートの確認をする方法

概要

メールなどを送信する際に事前にテンプレートの内容がちゃんと展開できるか確認することができます

環境

  • Ubuntu 22.04
  • amtool 0.26.0

インストール

  • go install github.com/prometheus/alertmanager/cmd/amtool@latest

data.json

{
  "Status": "firing",
  "Alerts": [
    {
      "Status": "firing",
      "Labels": {
        "alertname": "alert1",
        "instance_id": "hoge"
      },
      "Annotations": {
        "runbook": "https://1.example.com/",
        "description": "desc1"
      }
    },
    {
      "Status": "firing",
      "Labels": {
        "alertname": "alert2",
        "instance_id": "hoge"
      },
      "Annotations": {
        "runbook": "https://2.example.com/",
        "description": "desc2"
      }
    }
  ],
  "GroupLabels": {
    "cluster": "cluster-A"
  }
}

試す

template.text に好きなテンプレート文字列を渡してテストできます
テスト用のデータは template.data で渡します

  • ~/go/bin/amtool template render --template.glob=/dev/null --template.text='{{ $alerts := "" }}{{ $instance_id := (index .Alerts 1).Labels.instance_id }}{{ range .Alerts }}{{ $alerts = (printf "%v %v" $alerts .Labels.alertname) }}{{ end }}{{ $instance_id }} ->{{ $alerts }}' --template.data=data.json

結果は以下のようになります

hoge -> alert1 alert2

最後に

サンプルは golang のテンプレートの記述に慣れていればもっと簡潔に書けるかなと思います

書いているときに一行だと大変なので複数行で記載してから一行にするといいかなと思います

参考サイト

2023年11月27日月曜日

Mac でファイルを共有する方法

Mac でファイルを共有する方法

概要

ざっくりメモ

環境

  • M2Mac mini (共有する側
  • Mac Book Air (共有される側

共有フォルダの指定

M2Mac mini 上での作業

  • 環境設定からファイル共有
  • 共有フォルダの指定
  • 共有するユーザの追加と権限の確認

共有フォルダにアクセス

Mac Book Air 上での作業

  • Finder
  • ネットワーク
  • M2Mac mini があることを確認
  • ダブルクリックし接続
  • 共有したフォルダにアクセスできることを確認

トラブルシューティング

  • 同一ネットワーク上にいるか
  • 共有したいユーザの設定があっているか、権限はあっているか

2023年11月24日金曜日

Gitlab の Promethues に独自のルールを設定する方法

Gitlab の Promethues に独自のルールを設定する方法

概要

rules ファイルを作成してコンテナ側にマウントすれば OK です
今回は簡単な独自ルールを作成して設定してみました

環境

  • Gitlab 16.3.6

custom.rules

groups:
- name: MyCustomRule
  rules:
  - alert: CpuHighUsage
    expr: instance:node_cpu_utilization:ratio > 0.5
    for: 30m
    annotations:
      description: Current cpu usage is {{ $value }}.
      summary: CPU usage exceeded 50%.

instance:node_cpu_utilization:ratio は Gitlab のルールでデフォルトで提供されている Recoding rule の一つで CPU の使用率を取得することができる値です

コンテナ内の /var/opt/gitlab/prometheus/rules/ に配置

  • cp custom.rules /mnt/opt/gitlab/prometheus/rules

ローカル領域のマウントでもボリュームのマウントでも OK です

Omnibus Gitlab のデフォルトでは /var/opt/gitlab/prometheus/rules/ 配下のルールを見るのでそこに配置しましょう

gitlab.rb

もし別の場所に rules ファイルを配置する場合は配列に追加しましょう

prometheus['rules_files'] = ['/var/opt/gitlab/prometheus/rules/*.rules']

動作確認

  • docker-compose down
  • docker-compose up -d

であとは Promethues の rules の設定を確認して追加されていることを確認しましょう

参考サイト

2023年11月23日木曜日

Gitlab の Alertmanager で特定のアラートだけメールで送信する方法

Gitlab の Alertmanager で特定のアラートだけメールで送信する方法

概要

前回はとりあえず出たアラートをすべてメールで送信しました
今回は route 機能を使って特定のアラートだけをメールで飛ばすようにしてみます

環境

  • Gitlab 16.3.6
  • Alertmanager 0.25.0

gitlab.rb

alertmanager['listen_address'] = '0.0.0.0:9093'
alertmanager['receivers'] = [
  {
    name: 'email',
    email_configs: [
      to: 'your_to@mail',
      from: 'your_from@mail',
      smarthost: 'smtp.ess.nifcloud.com:465',
      auth_username: 'your_access_key',
      auth_password: 'your_secret_key',
      require_tls: false,
      send_resolved: true
    ]
  }
]
alertmanager['routes'] = [
  {
    receiver: 'email',
    group_wait: '30s',
    group_interval: '5m',
    repeat_interval: '4h',
    matchers: [ 'alertname = RedisDown' ]
  }
]
# alertmanager['default_receiver'] = 'email'

ポイント

  • alertname は必ず付与されるのでこれを使ってアラートを特定します
    • マッチには正規表現が使える match_re などもあります
    • ルールをカスタムすれば severity などのラベルも付与できますが面倒なので alertname を使います
    • デフォルトの Gitlab のルールだと他に instance, job あたりがマッチルールに使えます
  • default_receiver を設定してしまうと route にマッチしない場合に defualt_receiver の設定を使ってしまうのでコメントする

参考サイト

2023年11月22日水曜日

BeautifulSoup を使った画像URL取得のサンプルコード

BeautifulSoup を使った画像URL取得のサンプルコード

概要

img タグを取得してその src 属性を取得するだけです

環境

  • macOS 14.0
  • Python 3.11.6

サンプルコード

import requests
from bs4 import BeautifulSoup


class Downloader:
    def __init__(self, url: str = "https://picsum.photos/"):
        super().__init__()
        self.url = url

    def get_img_urls(self) -> list:
        response = None
        try:
            with requests.Session() as session:
                response = session.get(self.url, timeout=60)
                if response.status_code == 200:
                    soup = BeautifulSoup(response.text, "html.parser")
                    img_urls = [element.get("src") for element in soup.find_all("img")]
                    return img_urls
        except Exception as e:
            print(e)
            if response:
                response.close()
        return []


if __name__ == "__main__":
    dl = Downloader()
    for img_url in dl.get_img_urls():
        print(img_url)