Fedora CoreOS + Podman + Prometheus + Blackbox Exporter + GrafanaでWebサーバ(IPv6)を監視してみた。(その1)

Web Server(IPv6)を監視するために、Fedora CoreOSにPodmanで監視コンテナ(Prometheus+Blackbox Exporter+Grafana)を作成してみました。

自宅サーバとNetlifyに構築したWeb Serverを外形監視したいと思います。外形監視はPrometheus+Blackbox Exporterで行います。Web Serverに対してIPv6でHTTPS通信してその応答時間を監視していきます。環境は自宅サーバのFedora CoreOSにPodmanでコンテナを構築していきます。

prometheus!

監視コンテナの環境

コンテナは自宅サーバのFedora CoreOS上にPodmanで構築していきます。またデプロイはgitLab.com(CI/CD)から自宅サーバでリモートシェルを使って行います。こちらの環境については別途備忘録を残していきたいと思います。監視コンテナは、backendポッドに作成していきたいと思います。

自宅サーバの環境!

PodmanはFedora CoreOSをセットアップすると標準で入っていますので新たにインストールする必要はありません。残念ながらPodman 3.0ではまだないよです。

追記 2021.03.13 Testing Streamは、Mar 03, 2021にpodman3.0.1にアップデートされているようです。まもなくStable Streamもアップデートされると思います。

Release Date: Mar 03, 2021:ignition2.9.0 kernel5.10.19 moby-engine19.03.13 podman3.0.1 rpm-ostree2021.2 systemd246.7

version
$ cat /etc/os-release
NAME=Fedora
VERSION="33.20210201.3.0 (CoreOS)"
ID=fedora
VERSION_ID=33
:
$ podman --version
podman version 2.2.1

今回は、以下のコンテナを構築していきます。

No ID 用途 Dockerイメージ ポート番号
[外部:内部]
備考
1 backend Pod - 52100-52110:52100-52110 後で利用するかもしれないので取り敢えず11Port外部と開けてます。
2 pr2 proxy alpine + (nginx) 52100:52100 nginxのDockeイメージではなくAlpineに個別インストール
2 prothemeus イベント監視 prom/prometheus 52101:52101
3 balckbox-exporter 外形監視 prom/blackbox-exporter 9115 ポート番号9115はDefault値でPod内のみの通信、外形監視はhttps
4 grafana 監視結果のグラフ grafana/grafana 52102:52102

backendポッドの作成

ポッドは、以下のコマンドで作成します。

podman pod create --name backend --net=slirp4netns:enable_ipv6=true -p 52100-52110:52100-52110

rootlessコンテナとしたいのでコンテナから外部のサーバとIPv6で通信するためにnetオプションでslirp4netns:enable_ipv6=trueを指定しています。ポッド内のコンテナ間通信はこの設定をしなくてもIPv6通信ができると思いますが、外との通信にはこの指定をすると良さそうです。なお外からコンテナとIPv6通信するためにはこの指定ではなく、rootfullでIPv6のアドレス指定するやり方でやるしかないと思います。おそらく。こちらの方法はコンテナ用サーバをFedora Core OSで構築してみました。のTip podmanでIPv6コンテナ通信(ULA)を参照してください。

この指定をしないでGrafanaでみるとStatusがDOWNとなっていました。試しにgoogle.comをデバッグモードでみてみるとip_protocol=ip6となっていましたがProbe failedとエラーを吐いていました。ip_protocol=ip4にしてIPv4で外形監視する方法もあるようですが私はコンテナをIPv6に対応して回避しました。

$ podman exec -it pr1 sh
curl 'localhost:9115/probe?target=google.com&debug=true' ← pr1(proxyコンテナ)からcurlでprobeしてみる。
Logs for the probe:
ts=2021-02-24T12:22:39.035707468Z caller=main.go:304 module=http_2xx target=google.com level=info msg="Beginning probe" probe=http timeout_seconds=119.5
ts=2021-02-24T12:22:39.03586488Z caller=http.go:342 module=http_2xx target=google.com level=info msg="Resolving target address" ip_protocol=ip6
ts=2021-02-24T12:22:39.037457859Z caller=http.go:342 module=http_2xx target=google.com level=info msg="Resolved target address" ip=2404:6800:4004:81b::200e
ts=2021-02-24T12:22:39.037551564Z caller=client.go:252 module=http_2xx target=google.com level=info msg="Making HTTP request" url=http://[2404:6800:4004:81b::200e] host=google.com
ts=2021-02-24T12:22:39.037716724Z caller=main.go:119 module=http_2xx target=google.com level=error msg="Error for HTTP request" err="Get \"http://[2404:6800:4004:81b::200e]\": dial tcp [2404:6800:4004:81b::200e]:80: connect: network is unreachable"
ts=2021-02-24T12:22:39.037760284Z caller=main.go:119 module=http_2xx target=google.com level=info msg="Response timings for roundtrip" roundtrip=0 start=2021-02-24T12:22:39.037636095Z dnsDone=2021-02-24T12:22:39.037636095Z connectDone=2021-02-24T12:22:39.037684075Z gotConn=0001-01-01T00:00:00Z responseStart=0001-01-01T00:00:00Z end=0001-01-01T00:00:00Z
ts=2021-02-24T12:22:39.037797644Z caller=main.go:304 module=http_2xx target=google.com level=error msg="Probe failed" duration_seconds=0.002054087
Tip 【Blackbox ExporterでHTTPS IPv6通信】
コンテナを外との通信にIPv6通信を許可する。
podman pod create --nameポット名--net=slirp4netns:enable_ipv6=true・・・

ポッドは、gitLab.com(CI/CD)からリモートシェルを使って自宅サーバでコンテナをデプロイします。自宅サーバにgitLab-runnerのコンテナをたて自宅サーバ側で実行するようにしています。

自宅Mac(VSC)-git→gitLab.com(CI/CD)-rshell→自宅サーバ(dev-pod:gitLab-runner)-rshell→自宅サーバ(ホストPodman:deploy)のような流れです。

用途別に.gitlab-ci-ymlを作成したいので、メインの.gitlab-ci-ymlは以下のように記述しました。

.gitlab-ci-yml
## v2.1 akibo.I
include:
  - 'backend/.gitlab-ci.yml'

variables:
  GIT_SSL_NO_VERIFY: '1'

stages:
  - buildPod
  - buildContainer

before_script:
  - set -x
  - pwd

after_script:

こちらが実際のポッド構築のスクリプトとなります。podmanを使ってshellでデプロイしています。

backend/.gitlab-ci.yml
## v2.1 akibo.I
## backend
variables:

backend-pod:
  stage: buildPod
  only:
    changes:
      - backend/pod
  script:
    - HOST="xxxx@yyyy"
    - POD="backend"
    - ssh $HOST podman pod stop -i $POD
    - ssh $HOST podman pod rm -i $POD
    - ssh $HOST podman pod create --name $POD --net=slirp4netns:enable_ipv6=true -p 52100-52110:52100-52110

proxyコンテナの作成

自宅サーバは、別サーバでfrontEnd Serverが動作していますので、そちらから転送されたものを各コンテナに転送するproxyコンテナを作成します。

fronend-Pod(pr1)→backend-Pod(pr2,balckbox-exporter,prometheus,grafana)

フォルダ構成

backend
├──.gitlab-ci.yml
├──pr2
│  ├──Dockerfile
│  ├──build
│     ├──conf.d
│     │  ├──default.conf
│     │  ├──header.conf
│     │  └──log.conf
│     ├──nginx.conf
│     └──vhost.d
│         ├──01_ap-Server.conf
│         └──99_default.conf

Dockerfile

nginxの設定ファイルを作成しそのままコピーするようにしています。

backend/pr1/Dockerfile
FROM alpine

LABEL version="1.0" "akiboi.net"="akiboI"
RUN apk add --update --no-cache nginx
COPY build/ /etc/nginx/CMD ["/usr/sbin/nginx", "-g", "daemon off;"]

nginxの起動は-gオプションでdaemon offとしています。

podmanのデプロイ

ホスト側でDockefileを元にビルドしますが、gitLab-runnerのコンテナ内にあるbuildsディレクトは動的に変わるのでこの対応をします。

gitlab-runnerコンテナのボリューム

gitlab-runnerコンテナのボリュームマップは -v /vol/gitlab-runner/data:/home/gitlab-runner:Zとしています。
Dockerファイルを例にするとコンテナ側は、/home/gitlab-runner/builds/動的フォルダ/0/・・・/backend/pr2/Dockerfileとなります。このファイルはホスト側では/vol/gitlab-runner/data/builds//動的フォルダ/0/・・・/backend/pr2/Dockerfileとなります。ホスト側のPodmanでビルドしていきますので、sedコマンドでコンテナ側のカレントディレクトを元に取得しています。以前はgitlab-runnerをホスト側で動かしていましたのでこのようなことをする必要はありませんでしたが、Fedora CoreOSに変更してからはgitlab-runner自身もコンテナに変更しましたのでこのような対応が必要でした。なおpr2コンテナのボリュームマップは、-v /vol/pr2/data:/usr/share/nginx:Zと -v /vol/pr2/log:/var/log/nginx:Zとしました。

backend/.gitlab-ci.yml
pr1:
  stage: buildContainer
  only:
    changes:
      - backend/pr2/**/*
  script:
    - HOST="xxxx@yyyy"
    - POD="backend"
    - BASEDIR="/vol"
    - HOMEDIR=`pwd`    - WORKDIR=`echo ${HOMEDIR} | sed -e "s/^\/home\/gitlab-runner/\/vol\/gitlab-runner\/data/g"`    - CONTAINER=pr2
    - VOLUME="-v $BASEDIR/$CONTAINER/data:/usr/share/nginx:Z -v $BASEDIR/$CONTAINER/log:/var/log/nginx:Z "
    - REGISTRY="registry.akiboi.net:5000"
    - ssh $HOST mkdir -p $BASEDIR/$CONTAINER/data $BASEDIR/$CONTAINER/log
    - ssh $HOST podman build -t $REGISTRY/$CONTAINER $WORKDIR/$POD/$CONTAINER    - ssh $HOST podman push $REGISTRY/$CONTAINER
    - ssh $HOST podman stop -i $CONTAINER
    - ssh $HOST podman rm -i $CONTAINER
    - ssh $HOST podman run -dt --pod $POD --restart=always --name $CONTAINER $VOLUME $REGISTRY/$CONTAINER

Balckbox ExporterとPrometheusコンテナの作成

Balckbox ExporterとPrometheusコンテナを作成していきます。

ビルド用フォルダ

backend
:
├──blackbox-exporter
│  └──Dockerfile
├──prometheus
│  ├──Dockerfile
│  └──build
│     └──prometheus.yml

Blackbox exporter Dockerfile

prom/blackbox-exporterイメージを利用します。設定ファイルはディフォルトのものをそのまま利用しますのでDockerfileのみでOKです。

backend/blackbox-exporter/Dockerfile
FROM prom/blackbox-exporter
LABEL version="1.0" "akiboi.net"="akiboI"

prometheu Dockerfile

prom/prometheusイメージを利用しています。configファイルやポート番号はCMDで指定しています。

backend/prometheus/Dockerfile
FROM prom/prometheus
LABEL version="1.0" "akiboi.net"="akiboI"

USER 0
COPY build/prometheus.yml /etc/prometheus
CMD [ "--config.file=/etc/prometheus/prometheus.yml","--web.listen-address=:52103","--web.console.libraries=/usr/share/prometheus/console_libraries","--web.console.templates=/usr/share/prometheus/consoles","--web.enable-admin-api"]

USER 0(root)を設定しています。この指定をしないとnobodyとなりホスト側のボリュームマッピングしたフォルダにアクセスできないためです。 rootユーザ名前空間にマッピングされていないUIDが所有するファイルオブジェクトは「nobody」(65534、kernel.overflowuid)が所有するものとして扱われます。

今回は、rootlessユーザID 1001で実行しています。この時の名前空間を見てみると以下のようになっています。グループIDも同様ですが、要はコンテナ側のユーザID 0(root)の場合は、ホスト側rootlessの実行ユーザーIDとマッピングされてます。このおかげで、ホスト側のrootlessユーザIDで作成したVoluemマッピングのフォルダにアクセスできるのだと思います。通常のDockerイメージはroot IDで作成されていることが多いので意識する必要ありませんが別IDで作成されている場合などは注意が必要と思います。

$ podman unshare id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:system_r:container_runtime_t:s0-s0:c0.c1023
$ podman unshare cat /proc/self/uid_map
         0       1001          1
         1     165536      65536
$ podman unshare cat /proc/self/gid_map
         0       1001          1
         1     165536      65536

prometheus.ymlの設定

prometheus.ymlは、監視するwebサーバを指定してその他はディフォルトのままとしました。テストのために監視サーバは、google.comとNetlify、自宅サーバとしてみました。

backend/prometheus/build/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

alerting:
  alertmanagers:
    - static_configs:
        - targets:

rule_files:

scrape_configs:
  - job_name: 'blackbox_http'
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets:
          - https://google.com/          - https://www.akiboi.net/ ← 自宅サーバ          - https://www.akiboi.info/ ← Netlify    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: localhost:9115

Blackbox ExporterとPrometheusの.gitlab-ci.yml

proxyコンテナとほとんど同じで、ビルド判断するフォルダとコンテナ名、ボリュームマッピングが違うのみです。

backend/.gitlab-ci.yml

blackbox-exporter:
  stage: buildContainer
  only:
    changes:      - backend/blackbox-exporter/**/*
  script:
    - HOST="xxxx@yyyy"
    - POD="backend"
    - BASEDIR="/vol"
    - HOMEDIR=`pwd`
    - WORKDIR=`echo ${HOMEDIR} | sed -e "s/^\/home\/gitlab-runner/\/vol\/gitlab-runner\/data/g"`    - CONTAINER=blackbox-exporter    - VOLUME=""
    - REGISTRY="registry.akiboi.net:5000"
    - ssh $HOST mkdir -p $BASEDIR/$CONTAINER/data
    - ssh $HOST podman build -t $REGISTRY/$CONTAINER $WORKDIR/$POD/$CONTAINER
    - ssh $HOST podman push $REGISTRY/$CONTAINER
    - ssh $HOST podman stop -i $CONTAINER
    - ssh $HOST podman rm -i $CONTAINER
    - ssh $HOST podman run -dt --pod $POD --restart=always --name $CONTAINER $VOLUME $REGISTRY/$CONTAINER

prometheus:
  stage: buildContainer
  only:
    changes:      - backend/prometheus/**/*
  script:
    - HOST="xxxx@yyyy"
    - POD="backend"
    - BASEDIR="/vol"
    - HOMEDIR=`pwd`
    - WORKDIR=`echo ${HOMEDIR} | sed -e "s/^\/home\/gitlab-runner/\/vol\/gitlab-runner\/data/g"`    - CONTAINER=prometheus    - VOLUME="-v $BASEDIR/$CONTAINER/data:/prometheus/data:Z "
    - REGISTRY="registry.akiboi.net:5000"
    - ssh $HOST mkdir -p $BASEDIR/$CONTAINER/data
    - ssh $HOST podman build -t $REGISTRY/$CONTAINER $WORKDIR/$POD/$CONTAINER
    - ssh $HOST podman push $REGISTRY/$CONTAINER
    - ssh $HOST podman stop -i $CONTAINER
    - ssh $HOST podman rm -i $CONTAINER
    - ssh $HOST podman run -dt --pod $POD --restart=always --name $CONTAINER $VOLUME $REGISTRY/$CONTAINER

Black ExporterとPrometheusの動作確認

PrometheusでWebサーバを監視できているか確認してみます。標準であれば http://prometheusサーバ:9090/でアクセスするとPrometheusの初期画面が表示できると思います。私の環境はFrontEnd ServerのProxy1の設定も行いhttps://●●●●.akiboi.net/でアクセスしてみます。ヘッダーメニューからStatus-Targetsを選ぶとBlack Exporterと接続されていることが確認できました。

prometheus target

メトリックスも確認していきます。ヘッダーメニューからGraphを選択します。probe_http_duration_secondsと入力してExecuteボタンをクリックするとメトリックスが表示されます。Graphに切り替えてみましょう。

prometheus graph

自宅からNetlifyは流石に遠いのでDurationは400ms、Googleが200ms、自宅サーバは同じLAN上ですので20msといったぐらいでしょうか。次回はこれをGrafanaを使ってダッシュボードを作っていきたいと思います。



© 2021 akibo.I Blog v2.0.8