電脳世界のケーキ屋さん

考えの甘い甘党エンジニアがいろいろ書くブログ

rsyslogとtelegraf

何となく syslog をイケイケに監視してオレカッケーをしたかった.
構成としては, 以下の通り.

  1. rsyslog でインフラのログを受信
  2. ローカルのtelegrafにTCPでぶん投げる
  3. telegraf が InfluxDBに保存
  4. Chronograf で眺める

rsyslogの設定

Fedora では /etc/rsyslog.d/ 配下の設定を読み込む形になっていたので, そこに telegraf.conf を作成して以下の内容を記述する.

$ModLoad imudp
$UDPServerRun 514

*.notice action(type="omfwd"
  Target="127.0.0.1" Port="6514"
  Protocol="tcp"
  TCP_Framing="octet-counted"
  template="RSYSLOG_SyslogProtocol23Format"
  queue.type="LinkedList"
  queue.filename="telegraf_fwd"
  queue.saveonshutdown="on"
  action.resumeRetryCount="-1"
  KeepAlive="on"
  KeepAlive.Probes="5"
  KeepAlive.Interval="10"
  KeepAlive.Time="10"
  ResendLastMSGOnReconnect="off")

TCP_Framing がデフォルトだと traditional なのだが, Telegraf 側が octet-counted なので, これに合わせる.
合わせないと上手く Telegraf側で受信しない.

KeepAliveの設定はなくても良いかもしれない.

Telegraf の設定

/etc/telegraf/telegraf.coninputs.syslog セクションを編集する.

[[inputs.syslog]]
  server="tcp://127.0.0.1:6514"
  keep_alive_period = "10s"
  read_timeout = "0"

read_timeout がデフォルトで5秒となっているのだが, これが有効だと, 1つのTCPコネクションで5秒が経過すると問答無用で対向にFIN ACK を送ってクローズしてしまう.
rsyslog 側では destruct TCP Connection なんてログが大量に出力されて気付いた.
Telegraf がセッションをクローズした後に送られたメッセージはロストするため, 注意が必要.

omfwd: TCPSendBuf error -2027, destruct TCP Connection to 127.0.0.1:6514 [v8.1907.0 try https://www.rsyslog.com/e/2027 ]

最初はTCPキープアライブの設定を疑ったが, パケットキャプチャを眺めた感じ変わりがなかった.
今回は localhost でやり取りをする設定になっているので, これでよしとする.

PacemakerでPrometheusを冗長化する(Pacemaker編)

はじめに

せっかくLPIC304を取ったのに何もそれらしいことに活用できていないので, 監視ソフトのPrometheusの冗長化とかやってみようと思った次第である.

前提条件

  • 2台のLinuxマシンがIP疎通可能な状態で準備できていること
    今回は以下の2台を利用する.
    • [node-1(Active)] KVM上に準備した Fedora30
      • Prometheus: 2.10
      • Pacemaker: 2.0.1-2
      • corosync: 3.0.1-2
      • pcs: 0.10.1-4
    • [node-2(Standby)] 家のLANで適当にSSHアクセスできた Debian9.9(ARMv7)
      • Prometheus: 2.10
      • Pacemaker: 2.0.1-5
      • corosync: 3.0.1-2
      • pcs: 0.10.1-2

Prometheus の簡易インストール

ダウンロードするバイナリのプロセッサタイプを間違えないよう注意.

# curl -O https://github.com/prometheus/prometheus/releases/download/v2.10.0/prometheus-2.10.0.linux-amd64.tar.gz -L
# mkdir /opt/prometheus
# tar xvf prometheus-2.10.0.linux-amd64.tar.gz -C /opt/prometheus/ 

それぞれのホストで, systemd 用のサービスファイルを以下の具合に作成

# /etc/systemd/system/prometheus.service #
[Unit]
Description=Prometheus server daemon
After=network.target

[Service]
ExecStart=/opt/prometheus/prometheus-2.10.0.linux-amd64/prometheus --config.file=/opt/prometheus/prometheus-2.10.0.linux-amd64/prometheus.yml

[Install]
WantedBy=multi-user.target
# systemctl daemon-reload
# systemctl start prometheus
# systemctl status prometheus

http://<ノードアドレス>:9090 にアクセスしてそれっぽい画面が出力されたらインストールは完了である.
これを2台分実施する. クラスタに外れてる状態で勝手に起動すると困るので, enable にはしない方が良い.

Pacemaker によるクラスタの構築

基本は Linux-HA プロジェクトのクイックスタートガイド通りに実行する.
clusterlabs.org

パッケージのインストール

# apt-get install pacemaker pcs
または
# yum install pacemakr pcs

クラスタサービスの有効化

本環境では pacemaker, corosync, pcsdクラスタの動作に必要なデーモンであるので, これらの enable と start を実施する.
/etc/corosync/corosync.conf が存在しない場合は空ファイルを touch しておく.
(ファイルが無いと pcs デーモンの起動の際に怒られて失敗する(場合がある))

# touch /etc/corosync/corosync.conf
# systemctl start pcsd
# systemctl enable pcsd
# systemctl enable corosync
# systemctl enable pacemaker

pcsd用ユーザの設定

pcs がクラスタ管理に利用するユーザ hacluster について, ログインパスワードを設定する. 必ず両ノードで実施すること.

# passwd hacluster

設定後, どちらかのノード以下のコマンドを実行し, pcs にノード認証を行わせる.
Authorized と出力されれば問題なく認証が行なわれている.

# pcs host auth node1 addr=<ノード#1のアドレス> node2 addr=<ノード#2のアドレス> -u hacluster -p "<ユーザパスワード>"
node1: Authorized
node2: Authorized

クラスタ初期化

pcs cluster setup で指定ノードでクラスタを構築する.
ここで動作している各デーモンのバージョンに差分があると死ぬ.
Error: node2: Old version of pcsd is running on the node, therefore it is unable to perform the action なんて親切に出力してくれる.
ちなみに, マイナーバージョンまで合ってれば誤魔化せた.

# pcs cluster setup Prometheus-Cluster node1 node2 --force
...
Cluster has been successfully set up.

空ファイルだった /etc/corosync/corosync.conf に色々書き込まれていることが確認できる.
クラスタの初期セットアップが完了したので, クラスタを開始させる.

# pcs cluster start --all
# pcs cluster status

クラスタ開始後にクラスタに関するプロパティの変更が行えるようになる.

  • STONITH の無効化
# pcs property set stonith-enabled=false
  • 2ノードで自動フェイルオーバが実行されるようにする(クォーラムを無視する)
# pcs property set no-quorum-policy=ignore

クラスタへのリソース登録

VIP

クライアントが Prometheus にアクセスする際のIPアドレスを登録する.

# pcs resource create VIP ocf:heartbeat:IPaddr2 \
 > ip=192.168.16.35 cidr_netmask=24 \
 > op monitor interval=15s

Prometheus

Prometheus もデフォルトで RA の定義があるので, これをクラスタに登録する.

# pcs resource create Prometheus service:prometheus

リソースのコロケーション制約の設定

VIPが設定されているノードでPrometheusが動作するように colocation 制約を設定する.

# pcs constraint colocation add Prometheus with VIP

この辺りまで実施すれば, 他問題がなければクラスタが稼動を初める.
他の問題とは, prometheus を片ノードでサービス登録していなかったり, ルート領域が pacemaker のログで溢れていたりである.

正常に動作していればどちらのノードから pcs status を発行しても以下のような出力が得られる.

# pcs status 抜粋
Online: [ node1 node2 ]

Full list of resources:

 VIP    (ocf::heartbeat:IPaddr2):       Started node1
 Prometheus     (service:prometheus):   Started node1

おまけ

確認系コマンド

# pcs cluster status
Cluster Status:
 Stack: corosync
 Current DC: NONE
 Last updated: Sun Jun 30 15:03:11 2019
 Last change: Sun Jun 30 15:02:04 2019 by root via cibadmin on node1
 2 nodes configured
 2 resources configured

PCSD Status:
  node1: Online
  node2: Online
# pcs status
Cluster name: Prometheus-Cluster
Stack: corosync
Current DC: NONE
Last updated: Sun Jun 30 15:03:43 2019
Last change: Sun Jun 30 15:02:04 2019 by root via cibadmin on node1

2 nodes configured
2 resources configured

OFFLINE: [ node1 node2 ]

Full list of resources:

 VIP    (ocf::heartbeat:IPaddr2):       Stopped
 Prometheus     (service:prometheus):   Stopped

Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled
# pcs property
Cluster Properties:
 cluster-infrastructure: corosync
 cluster-name: Prometheus-Cluster
 dc-version: 2.0.1-9e909a5bdd
 have-watchdog: false
 no-quorum-policy: ignore
 stonith-enabled: false
  • 利用可能なリソースエージェントの一覧
    出力に時間がかかる
# pcs resource list
ocf:heartbeat:aliyun-vpc-move-ip - Move IP within a VPC of the Aliyun ECS
ocf:heartbeat:anything - Manages an arbitrary service
ocf:heartbeat:AoEtarget - Manages ATA-over-Ethernet (AoE) target exports
ocf:heartbeat:apache - Manages an Apache Web server instance
ocf:heartbeat:asterisk - Manages an Asterisk PBX
ocf:heartbeat:AudibleAlarm - Emits audible beeps at a configurable interval
...

トラブル

Debian側のpcsコマンドが pycurl 云々のエラーで動作しない

libcurl 系がエラー出力に記載のバージョンと合うように調整する(libcurl3-gnutlsかな).

crm_mon コマンドがないって言われる

yum なら pacemaker-cli , apt なら pacemaker-cli-util がパッケージとして入っている必要がある.
crm_mon コマンドがインストールされていない場合 pcs status コマンドなどを打った際に以下のエラーが出る.

Error: unable to run command crm_mon --one-shot --inactive: No such file or directory: 'crm_mon'

ノード再起動後に既存クラスタに再認識されない.

pacemaker サービスを再起動させようとするとハングする

CIBがノード間で正常に同期されない

上の3つの事象は結論として CIB の設定がノード間で異なっていたことに起因するものであった.

pcs cluster stop を行おうとすると以下のようなログを出力し続けて pacemaker の停止が終わらない.
これのせいでログが膨れ上がってルート領域が溢れた.
こうなるとシステムの再起動も正常に実施できない状態になって大惨事である.

  • ノード1
pacemaker-based     [732] (cib_file_backup)         info: Archived previous version as /var/lib/pacemaker/cib/cib-71.raw
pacemaker-controld  [737] (election_count_vote)     info: election-DC round 170944 (owner node ID 2) lost: vote from node2 (Uptime)
pacemaker-controld  [737] (update_dc)       info: Unset DC. Was node2
pacemaker-controld  [737] (do_log)  info: Input I_PENDING received in state S_PENDING from do_election_count_vote
pacemaker-controld  [737] (update_dc)       info: Set DC to node2 (3.1.0)
pacemaker-based     [732] (cib_process_replace)     info: Digest matched on replace from node1: ac2adcc396bcf584915ad51e4ef426ad
pacemaker-based     [732] (cib_process_replace)     info: Replaced 0.34.4 with 0.34.4 from node1
pacemaker-based     [732] (cib_file_write_with_digest)      info: Wrote version 0.34.0 of the CIB to disk (digest: 621d39f18d6f54be5f4c900d543c5c00)
pacemaker-based     [732] (cib_process_request)     info: Completed cib_replace operation for section 'all': OK (rc=0, origin=node1/crmd/341932, version=0.34.4)
  • ノード2
pacemaker-based[14088]:  error: Completed cib_replace operation for section 'all': Update does not conform to the configured schema ...
pacemaker-controld[14093]:  error: Sync from node1 failed: Update does not conform to the configured schema

pcs cluster cib で両ノードの CIB を diff ってみると, 1行目にそれらしい差分があることが分かる.
どう見ても validate-with プロパティのpacemakerのバージョンに差異が発生している.
恐らく pacemaker のバージョンが違う状態でクラスタを組もうとしたのが原因と考えられる.

# node1 CIB
<cib crm_feature_set="3.1.0" 
  validate-with="pacemaker-3.2" epoch="46"  //*
  num_updates="2" admin_epoch="0"
  cib-last-written="Sat Jul  6 20:24:51 2019"
  update-origin="node2"
  update-client="crmd"
  update-user="hacluster"
  have-quorum="1" dc-uuid="1">   
# node2 CIB
<cib crm_feature_set="3.1.0"
  validate-with="pacemaker-2.6" epoch="19"  //*
  num_updates="29" admin_epoch="0"
  have-quorum="1"
  cib-last-written="Tue Jul  2 14:30:52 2019"
  update-origin="node1"
  update-client="cibadmin"
  update-user="root" dc-uuid="2">

一旦この値をノード間で合わせて, クラスタが正常化するかを試してみる.

# cibadmin --modify --xml-text '<cib validate-with="pacemaker-2.0"/>' 

直すと, クラスタが正常化したのでこれでヨシとする.
pacemaker を再起動したり, pcs cluster stop --all も正常に動作するようになった.

さいごに

見れば分かるが, Prometheus のデータ共有などは全く行っていないため, クラスタとしては不完全な状態である.
Pacemaker でどはまりして体力を使ったので, Prometheusについては別記事を書くこととする.

KVM ゲストとして Container-Linux を導入する



はじめに

以前の記事で構築した KVM on Gentoo で色々遊ぼうと思う.
今回は手始めに Container-Linux をゲストとして導入する.

なんで Container Linux のインストールをしようと思ったのかは分からない.
でもKVMで構築する上でハマる落とし穴1つずつにハマっていた感じだったので勉強になった.

Container-Linux の管理や, KVMホストの管理については別記事を用意する.

手順

1.OSイメージのダウンロード

この辺りのリリースノート を確認して,
この辺り から stable image をダウンロードする.
ダウンロードしたらチェックサムを確認して bzcat で展開して適当な場所に置いておく.

2.ファイルシステム作成

以下のコマンドでファイルシステムを作成する.
qcow2形式でベースイメージに CoreOS のイメージを利用したファイルシステムを作成したことになる.
いわゆる差分イメージとして作成され, ベースイメージに対する差分が記録されるイメージとなる.

> sudo qemu-img create -f qcow2 -b /osimage/coreos_production_qemu_image.img container-linux00.qcow2

この時作成するイメージの場所は libvirt のプールに登録されている場所が望ましい.
ちなみに差分を破棄したい場合は同じコマンドを打てば良い(再フォーマットされる).

3.ドメイン設定ファイルの作成

virt-install コマンドによってドメインの設定ファイルを作成する.
普段は virt-install と OS のインストールイメージを用いて, ファイルシステムにOSをインストールする必要がある.

Container OS のイメージはインストールイメージではないため, インストール操作を実施する必要はない.
--import オプションを利用することでインストールプロセスをスキップし, 指定したファイルシステムから起動するような設定をすることが可能となっている.

Container OS では後の手順でドメイン設定ファイルを編集する必要があるため, libvirt に直接登録せずに, XML設定ファイルを出力する動作を指定している(print-xml).
ちなみに, 完全なシミュレーション動作ではないため, ストレージの作成などは行われる点に注意.
必要に応じて --dry-run オプションを付与すると良いと考えられる.

sudo virt-install --connect qemu:///system --virt-type kvm --import \
  --name container-linux00 \
  --ram 2048 --vcpus 2 \
  --os-type linux \
  --disk path=/var/lib/libvirt/images/container-linux00.qcow2,format=qcow2 \
  --nographics --network bridge=privbr \
  --accelerate \
  --print-xml | sudo tee /var/lib/libvirt/container-linux/container-linux00/domain.xml

4.ignitionファイルの作成

公式ドキュメント を参考に Ignition config を作成する.
ネットワークの設定とユーザ設定をしておかないと救い用のないホストとなってしまうため注意.

ネットワーク設定

公式ドキュメント通りに設定しておくのが無難. 静的IPを設定する場合は下記のように記述しておく.

"networkd": {
 "units" : [
 {
  "contents" : "[Match]\nMACAddress=XX:XX:XX:XX:XX:XX\n\n[Network]\nAddress=192.168.101.2/25\nGateway=192.168.101.126\n",
   "name": "10-ens3.network"
 }
 ]
},

[Match] 項で何らかの条件を設定しておかないとループバックインターフェイスにアドレスが付与されて酷い目に会う(経験済み).
前の手順で domain.xml を作成した時点でインターフェイス物理アドレスは分かるので, それを条件に設定しておくと良い.

ユーザパスワードを設定しておきたい

Container OSはデフォルトではユーザに対してのログインを一切許容していない鬼畜仕様である.
公開鍵を登録してSSHログインする方法は幾つか紹介されているのを見かけるが, コンソールログインする設定はなかなか見かけない.
KVMでゲストに対してコンソール接続はできるけどネットワーク疎通が取れないというケースがある.
こういった時にコンソールログインできると便利なので設定しておきたい場合の手順を示す.

passwordHash 項を passwd.users 内のオブジェクトに挿入すれば良い.

抜粋すると以下のような設定となる.

"passwd": {
 "users": [
 {
  "name": "core",
   "passwordHash": "$6$rXw/hoge$60wal<省略>ZAr1",
   "sshAuthorizedKeys": [
    "ssh-ed25519 AAAA<省略>PI6fS alice@Lab_A"
   ]
 }
 ]
},

問題は passwordHash に渡す文字列の作成の仕方である.
これは /etc/shadow 内の暗号化パスワードの表記と全く同じもので, 平文パスワードにソルト値を追加したものをハッシュ化して得られる文字列である.

これを自前で作るのは Perl を使えばワンライナーで作成できる.

# perl -e 'print crypt("password", "\$6\$hogehoge");'

以下の文献を参考にしている.
http://www.unknownengineer.net/entry/2017/08/16/184537
上記のコマンドで得た値をそのまま貼り付ければ, コンソールで接続した際に設定したパスワードで core ユーザにログインできるようになる.

SSHの認証鍵の設定は ssh-keygen によって得られた公開鍵をそのまま貼り付ければ問題ない.
今回は ssh-keygen -t ed25519 の出力を利用した.

5.ドメイン設定ファイルの編集

Container-OS は初回起動自に先の手順で作成した Ignition Config を利用して設定のプロビジョニングを行う.
そのために, 作成した Ignition Config を起動時にゲストのファイルシステムへ転送する必要がある.
qemu はゲスト起動時にファイルを転送する -fwd_cfg オプションがあり, libvirt もこれを利用することができる.

公式ドキュメント通りに下記のコマンドを実行すれば良い.

domain=/var/lib/libvirt/container-linux/container-linux1/domain.xml
ignition_file=/var/lib/libvirt/container-linux/container-linux1/provision.ign

sed -i 's|type="kvm"|type="kvm" xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"|' "${domain}"
sed -i "/<\/devices>/a <qemu:commandline>\n  <qemu:arg value='-fw_cfg'/>\n  <qemu:arg value='name=opt/com.coreos/config,file=${ignition_file}'/>\n</qemu:commandline>" "${domain}"

1回目の sed によって, ドメインファイルで qemu のオプションを利用できるように設定する.
これを省くと後の libvirt へのドメイン登録時に怒られる.

2回目の sed によって具体的に qemu 実行の際のオプションを設定する.
これにより Ignition Config がゲストの /sys/firmware/qemu_fw_cfg/by_name/opt/com.coreos/config に転送される設定で起動処理が行われる.

-fwd_cfg オプションについての詳しい説明はこの辺りが参考になる.

6.ドメインの登録とゲストの起動及び動作確認

virsh define domain.xml を実行すると libvirt の管理下に置かれる.
virsh start <ドメイン名> で起動可能となる.
ドメイン名は virsh list --allP で確認できる.

起動確認として, 以下を確認すると良いだろう.

  • 設定したアドレスに対して ping が通るか
  • virsh console <ドメイン名> で接続した際にレスポンスがあるか
  • 登録したSSH設定でログイン可能か

いずれかが失敗した場合は Ignition ファイルか ドメイン設定ファイルを再確認する.

ignitionファイルを変更した時

マシンをリセットするだけだと変更は適用されない.
ファイルシステムを作り直すと適用されたのを確認したが, めんどくさい...

既に差分イメージが存在する場合でも下記を実行することでフォーマットされる.

> sudo qemu-img create -f qcow2 -b /osimage/coreos_production_qemu_image.img container-linux00.qcow2

参考文献