Feb 28, 2021

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

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

NoID用途Docker イメージポート番号[外部:内部]備考
1backendPod-52100-52110:52100-52110後で利用するかもしれないので取り敢えず 11Port 外部と開けてます。
2pr2proxyalpine + (nginx)52100:52100nginx の Docke イメージではなく Alpine に個別インストール
2prothemeusイベント監視prom/prometheus52101:52101
3balckbox-exporter外形監視prom/blackbox-exporter9115ポート番号 9115 は Default 値で Pod 内のみの通信、外形監視は https
4grafana監視結果のグラフgrafana/grafana52102: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 の設定ファイルを作成しそのままコピーするようにしています。

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 としました。

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 で指定しています。

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、自宅サーバとしてみました。

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

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 を使ってダッシュボードを作っていきたいと思います。