nasa9084
· 3 min read

confd + initContainerでAlertmanagerの設定をSecretに逃がす

confd + initContainerでAlertmanagerの設定をSecretに逃がす

TL;DR

  • Alertmanagerの設定には一部Secretが含まれる
    • バージョン管理システムに入れたくない
  • initContainerでconfdを使って設定ファイルを生成する
    • Alertmanagerの設定の一部をSecretに格納できる

confd

kelseyhightower/confdは非常に軽量な設定ファイル管理ツールです。基本的にはテンプレートエンジンですが、多くのバックエンドデータストアからデータを持ってきて、設定ファイルに書き出すことが出来ます。
また、事前処理や事後処理を行うことが出来るので、例えば設定ファイルを書き換えたあと、リロードする、というところまでconfdで行うことが出来ます。

Install

Go言語で書かれているため、インストールは非常に簡単で、バイナリをダウンロードしてきて実行権限を与え、パスの通ったところに置くだけです。バイナリはリリースページからダウンロードすることが出来ます。

使用方法

confdを使用するためには、三つのものを用意する必要があります。

  • テンプレートリソース
  • テンプレート
  • データストア

テンプレートリソース

テンプレートリソースには、どのテンプレートを使用して、どんなキーでデータストアからデータを取り出し、完成した設定ファイルをどこに置くのか、事前処理・事後処理はどんなものかを記述します。書式はTOMLで、慣れ親しんだ(慣れ親しんでない?)iniファイルの様に気軽に書くことが出来ます。/etc/confd/conf.d以下に配置します。

テンプレート

テンプレートはその名の通り、設定ファイルのテンプレートです。ここに、データストアから取り出したデータを合わせて設定ファイルを作成します。書式はGo言語のtext/templateに準じます。/etc/confd/templates以下に配置します。

データストア

そして、データストアにデータを入れる必要があります。

confdは、データストアとして、次のものをサポートしています(2018/08/20現在)

Alertmanager

AlertmanagerPrometheusからのアラートを受け取り、適切にハンドルするためのアプリケーションです。Alertmanagerの設定はYAMLで記述するのですが、SMTPのパスワードやSlackIncoming Webhook URL等、平文でバージョン管理システムに入れるのは躊躇われるデータを含みます。しかし、環境変数などから設定をすることも出来ないため、平文で記述するか、何らかの方法で設定ファイルを編集してから使う必要があります。
特に、Prometheus/AlertmanagerはKubernetesと併せて使用されることが多いため、出来ればKubernetesのSecret機能を使用したいところです。
そこでconfdをinitContainerで使用して、設定ファイルを生成します。

まず、テンプレートを作成します。Alertmanagerの設定ファイルを用意し、後から挿入したい部分をテンプレート文字列で置換しておきます。

global:
  slack_api_url: {{getenv "ALERTMANAGER_SLACK_URL"}}

route:
  receiver: slack

receivers:
  - name: slack
    slack_configs:
      - channel: "#alert"

今回は例なので、細かい設定の一切を省いた形にしました。上記の内容で、alertmanager.yml.tmplとして保存しました。

次に、テンプレートリソースを作成します。

[template]
src = "alertmanager.yml.tmpl"

dest = "/etc/alertmanager/alertmanager.yml"

keys = [
    "ALERTMANAGER_SLACK_URL",
]

こちらも、上記内容でconfd.tomlとして保存しました。

最後に、データストアにデータを投入します。今回の想定はKubernetesでSecretを使用する、ということなので、KubernetesのSecretを作成します。

$ echo 'https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX' > alertmanager_slack_url
$ kubectl create secret general alertmanager-slack-url --from-file ./alertmanager_slack_url

Alertmanagerの起動前に設定ファイルを生成するため、initContainerを使用します。initContainerはPod内のアプリケーションコンテナが起動する前に、初期化処理を行うことが出来るコンテナです。今回は、nasa9084/confdを使用して設定ファイルを生成します。

nasa9084/confdのDockerfileは次の様になっています(ラベル省略)。

FROM busybox:latest

RUN wget https://github.com/kelseyhightower/confd/releases/download/v0.16.0/confd-0.16.0-linux-amd64 -O confd &&\
    chmod +x confd &&\
    mv confd /bin/confd

ENTRYPOINT ["confd"]

これをinitContainerで起動します。Kubernetesのマニフェストは次の様に記述します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: alertmanager
spec:
  selector:
    matchLabels:
      app: alertmanager
  template:
    metadata:
      labels:
        app: alertmanager
    spec:
      containers:
        - name: alertmanager
          image: prom/alertmanager:v0.15.2
          ports:
            - containerPort: 9093
          args: ["--config.file=/etc/alertmanager/alertmanager.yml"]
          volumeMounts:
            - name: alertmanager-config
              mountPath: /etc/alertmanager
      initContainers:
        - name: init-alertmanager-config
          image: nasa9084/confd:v0.16.0
          args: ["-onetime", "-backend", "env"]
          volumeMounts:
            - name: alertmanager-config
              mountPath: /etc/alertmanager
            - name: alertmanager-config-template
              mountPath: /etc/confd/templates
            - name: alertmanager-confd-toml
              mountPath: /etc/confd/conf.d
          env:
            - name: ALERTMANAGER_SLACK_URL
              valueFrom:
                secretKeyRef:
                  name: alertmanager-slack-url
                  key: alertmanager_slack_url
      volumes:
        - name: alertmanager-config-template
          configMap:
            name: alertmanager-config-template
        - name: alertmanager-confd-toml
          configMap:
            name: alertmanager-confd-toml
        - name: alertmanager-config
          emptyDir: {}

.template.spec.initContainersで設定ファイル生成用のコンテナを定義しています。テンプレートリソース、テンプレートをそれぞれconfigMapに格納し、適切なディレクトリにマウントしています。alertmanager-configが設定ファイル格納用のボリュームです。Podの起動時に設定ファイルが生成されるため、永続化する必要はありませんが、initContainerとAlertmanagerのコンテナ間でデータを受け渡す必要があるため、emptyDirとして作成しました。また、先ほど作成したSlack Incoming webhook URLのSecretを環境変数としてマウントしています。
confdは通常、デーモンとして動作します。今回は一度設定ファイルを生成すれば十分なため、-onetimeオプションをつけています。
最後に、生成した設定ファイルをボリュームとしてAlertmanagerのコンテナにマウントしてあります。

confdをinitContainerで起動する方法はAlertmanager以外にも応用が利きそうです。