docker composeで作っていたzabbixをバージョンアップして再構築しようとしたら色々はまったときのメモ

mysqlのlatestイメージとzabbix-server-mysql:alpine-7.0-latestの組み合わせだとDBの権限が足りなくて初期構築のsqlが実行されない

docker compose を初回起動するとおおよそ以下のようなエラーが出た

ERROR 1419 (HY000): You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)

zabbixサーバー(zabbix-server-mysql)からdbに初期構築のsqlを実行しようとするが、バイナリログを使用しているときには特別に権限が必要らしい。意図的にはバイナリログを有効にしていないしDockerのmysqlだと通常無効と調べている途中で見たが実際にできたDBを覗くとバイナリログが有効になっている。

mysql> SHOW VARIABLES LIKE 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+

my.cnfカスタマイズしている影響の可能性もあるけど、下のコマンドで素の引っ張りたてイメージでもバイナリログ有効になっていた。

 docker run -it --name test-wolrd-mysql -e MYSQL_ROOT_PASSWORD=mysql -d mysql

このへんから呼ばれるcreate.sql.gzの中身で呼ばれているっぽい。qz自体はzabbixのものでたぶんここらへんでつくられている模様。(ちゃんと見ていない)zabbix-serverの/usr/share/doc/zabbix-server-mysql/create.sql.gzを見ようとしたけど長いので見るのやめた。何か制約にかかるトリガーとかを作っているのだと思う。

対処法

my.confに以下を追加

[mysqld]
log_bin_trust_function_creators = 1

制約回避の設定。他にも回避策の指定は色々あるらしい。

zabbix-agentとのバージョン違い?

zabbix-server-1 | 197:20240929:102940.592 unknown request received from “192.168.xxx.yyy“: [active check heartbeat]

みたいなメッセージがzabbix-serverのログに出ていて、zabbixのGUIのエージェント死活監視の色が緑にならず灰色のままだった。データ自体は取れている模様。

対処法

エージェントとサーバのバージョンを合わせた。(他にもいろいろやっていた中だったのでたまたまの可能性もなくはない)

zabbiz-agentでサーバ側のipを指定する必要があるがdocker composeの素の状態だと変わってしまう

zabbix agent(/etc/zabbix/zabbix_agentd.conf)でServer,ServerActiveにzabbixサーバのIPを指定する必要があるがcompose内で明確に指定しないとipが変わってしまうので接続できなくなる時がある。

対処法

ipを固定すればよい。

まずはdocker-compose.ymlで、下みたいにカスタムネットワーク作ってIP指定する。

services->zabbix-server->networks->zabbix2hostでの利用指定とnetworks->zabbix2hostでのネットワーク作成。

services:
  zabbix-server:
    build: ./server
    cap_add:
      - NET_ADMIN
    restart: always
    depends_on:
      - db
    volumes:
      - "./data/zabbix:/var/lib/zabbix"
    environment:
      DB_SERVER_HOST: db
      MYSQL_USER: ほげ
      MYSQL_PASSWORD: ふが
    ports:
      - "10051:10051"
    networks:
      zabbix2host:
        ipv4_address: 192.168.100.2
      default: {}

networks:
  zabbix2host:
    driver: bridge
    ipam:
      config:
        - subnet: 192.168.100.0/24

zabbix2hostとdefaultの二つのネットワークに所属しているのでルーティング設定も必要。(zabbix-serverで使うネットワークが一つならおそらく不要)

dockerイメージでip route を使うがdocker-compose.ymlでcap_add:NET_ADMINの権限を付与していないと使えないはず。(もしくはprivileged指定)

docker起動時にルーティングをするようにentrypointとなるシェルを作成。

#!/bin/sh
# route2はdocker fileにてインストール済み
#向き先 host gwはcomposeで作成したネットワークのもの 
sudo ip route add 192.168.1.2 via 192.168.100.1

exec docker-entrypoint.sh "$@"

192.168.1.2(zabbix-agentが実際に動いているdockerのホストIP)は192.168.1.2(zabbix-agentが実際に動いているdockerのホストIP)は192.168.1.2(zabbix-agentが実際に動いているdockerのホストIP)は作ったネットワーク(192.168.100.1)を使う設定。

ルーティングだけ追加したら、元々のエントリーのdocker-entrypoint.shを呼び出し元のパラメータ付きでコール

で、Dockerファイルも作成

FROM zabbix/zabbix-server-mysql:alpine-7.0-latest

# 元イメージでユーザーがzabbix(1997になっているので一旦切り替え)
USER 0
COPY add-route-entrypoint.sh /usr/local/bin/add-route-entrypoint.sh
RUN chmod +x /usr/local/bin/add-route-entrypoint.sh && apk add --no-cache iproute2 && apk add --no-cache sudo && echo "zabbix ALL=(ALL) NOPASSWD: /sbin/ip" >> /etc/sudoers
USER 1997

ENTRYPOINT ["add-route-entrypoint.sh"]
CMD ["/usr/sbin/zabbix_server", "--foreground", "-c", "/etc/zabbix/zabbix_server.conf"]

alpineだとiproute2もないのでapk(alpineのapt相当)でインストール。sudoも使うのでインストール、シェル実行時にパスワードがいいらないように/etc/sudoersも編集。

あとは作ったadd-route-entrypoint.shをエントリーポイントにして、zabbix/zabbix-server-mysql:alpine-7.0-latestと同じCMDをつけて呼び出し。(ENTRYPOINT付けたらベースイメージのCMDがクリアされていた。引き継がれる気がしていたけどどこか間違っている?)

netplanのgateway4がdeprecatedになっていた

sudo vi /etc/netplan/50-cloud-init.yaml
network:
    ethernets:
        enp2s0:
            dhcp4: false
            addresses:
              - 192.168.1.5/24
            gateway4: 192.168.1.1
            nameservers:
              addresses:
                - 8.8.8.8
                - 8.8.4.4
    version: 2

からの

sudo netplan try

** (process:991): WARNING **: 08:38:09.630: gateway4 has been deprecated, use default routes instead.
See the 'Default routes' section of the documentation for more details.

と怒られた。

gateway4がdeprecated(非推奨)になってrouteを使えとのこと

network:
  version: 2
  ethernets:
    enp0s3:
      dhcp4: false
      addresses:
        - 192.168.1.100/24
      routes:
        - to: 0.0.0.0/0
          via: 192.168.1.1
      nameservers:
        addresses:
          - 8.8.8.8
          - 8.8.4.4

Dockerがhostのネットワークを使っている場合routingがこのto設定の影響を受けるので要注意

Ubuntuを24にメジャーアップグレードしたらZabbix-agentがなくなったので再インストール

以前インストールしていた(こちら)zabbix-agentがUbuntuのメジャーアップグレードのタイミングでなくなっていた。再度インストールしなおしたときの手順。

zabbixのレポジトリ再インストール

wget https://repo.zabbix.com/zabbix/6.4/ubuntu/pool/main/z/zabbix-release/zabbix-release_6.4-1%2Bubuntu24.04_all.deb
sudo dpkg -i zabbix-release_6.4-1+ubuntu24.04_all.deb

からのaptインストール

sudo apt update
sudo apt install zabbix-agent

/etc/zabbix/zabbix_agentd.confのServer,ServerActive,Hostnameを監視サーバのドメインに書き換え

Server=kanshi.epea.co.jp
ServerActive=kanshi.epea.co.jp
Hostname=kanshi.epea.co.jp

サービス登録

sudo systemctl start zabbix-agent
sudo systemctl enable zabbix-agent

上記で動いたっぽい

C++勉強メモ

やりそうなエラー

stringリテラルの設定もれ

string型のリテラルはincludeとnamespace設定がいる

忘れた場合のエラーメッセージは

vscode

ユーザー定義のリテラル演算子が見つかりませんC/C++(2486)

gcc

chap3.cpp:4:18: error: unable to find string literal operator ‘operator""s’ with ‘const char [6]’, ‘long unsigned int’ arguments
4 | std::cout << "hoge\n"s;
| ^~~~~~~~~
make: *** [Makefile:6: chap3.o] Error 1

補足

C++11でリテラル演算子をユーザー定義できるようになったとのこと。自分で定義するなら

ただし、自作する場合はアンスコ(_)で始めろと。

試しに自作したら

上でも動いた

Found orphan containers

docker-composeを新たに作成して実行したところ以下のワーニングが出た。

WARNING: Found orphan containers (proxy_letsencrypt-nginx-proxy-companion_1, nginx-proxy) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.

こちらにあるように他のdocker-composeとの名前重複が原因。

]新しいdocker-composeだとドキュメントによると以下のようにname要素(top level element)が存在し名前重複を避けられるそう。ただ、一時期バグがあって使えない時期もある模様。

対応していないと思われる私の環境では以下のエラー

ERROR: The Compose file './docker-compose.yml' is invalid because:
Invalid top-level property "name". Valid top-level sections for this Compose file are: version, services, networks, volumes, secrets, configs, and extensions starting with "x-".

現在の環境は長く使わない予定なので他の暫定対処を選択する。

環境変数にCOMPOSE_PROJECT_NAMEを指定しても同じ効果があるそうなので。docker-compose.ymlと同じディレクトリに.envを以下内容で作成。

COMPOSE_PROJECT_NAME=momoyama_shop

そしてdocker-compose buildをすると以下のように指定したcompose_project_nameを持つイメージが作成された。

Building front
Step 1/2 : FROM nginx
---> 92b11f67642b
Step 2/2 : RUN echo 'server_tokens off;\n' > /etc/nginx/conf.d/my_default.conf
---> Using cache
---> 597e7dfaab23

Successfully built 597e7dfaab23
Successfully tagged momoyama_shop_front:latest

自宅用通知マシン作成(5)

前回の続き

スタックチャンがしゃべれるようになったので、次は外部からしゃべる指令を出す端末のバージョンアップ。呼び出しは予約確認のための自宅用通知マシンと兼用。

エッジ検出処理&疑似的な並列処理はこちらに大体まとめた感じ。

メインのループ(Arduinoのloop関数)は並行処理するループ(yoyakuCheckLoop,yobidashiCheckLoop)をそれぞれ呼び出しyobidashiCheckLoopの中でボタンが押されている判定をして押されていたらネットワーク越しにスタックチャンがしゃべるURLをたたいてしゃべらせる。

最初はPOSTで叩こうとしたけどPOSTの引数違うぞみたいなエラーメッセージが出たのでとりいそぎGETメソッド(5秒も調べていない)

メインのループの中でyobidashiCheckLoopを呼び出し。下に張った中のyobidashiCheckLoopでやっていることはこちらに大体まとめた感じ。で、execYobidashi(開発環境ならexecDevYobidashi)で、httpsのリクエストを投げているだけ。セキュリティ的なものはつけていないのでそのまま叩ける。

一応全体

続けてネットワーク回り

ESP8266でエッジ検出処理

やりたいこと

ボタンを押したときにそれを検出して処理をしたい。ループの中とかで検出処理をごにょごにょやるのはつらいのでボタン検知の割り込み処理を試す。LOWからHIGHになったとき(立ち上がりエッジ:RISING)や逆にHIGHからLOW(立ち下がりエッジ:FALLING)になった時を検出するやつ。

概要

void ICACHE_RAM_ATTR shopYobidashiCallback() {
  Serial.println("working");
}
void setup() {
  pinMode(INPUT_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(INPUT_PIN), shopYobidashiCallback, FALLING);
}

割り込みが効くGPIOでattachInterruptを呼び出し。GPIOがどれかはちゃんと確認していない。(データシート参照)とりあえず、12は効いて1-15が効くと思う。

呼び出し元

attachInterrupt(割り込み番号,コールバック関数名,検出エッジ)の引数。

割り込み番号はdigitalPinToInterrupt(ピン番号)で取得できる。

コールバック関数名はそのまま関数名

検出エッジはLOW/CHANGING/RISING/FALLINGが選べる模様。LOWはLOWの時常に。実際に試したのはFALLINGのみ。(参照 ESPでなくArduinoのドキュメントなので少し違うかもしれない)

コールバック

ドキュメントはこちら

コールバックには関数をRAM上に配置する指定のIRAM_ATTRまたはICACHE_RAM_ATTR(多分こっちはDupricated)がいる。

つけ忘れると下みたいなメッセージが出て再起動するはず。

ISR not in IRAM!

User exception (panic/abort/assert)
--------------- CUT HERE FOR EXCEPTION DECODER ---------------

Abort called

>>>stack>>>

ctx: cont

RAMにない=Flashにあるとそっちの書き込みとかぶってだめよという事らしい。

その他制限として

  • delay() or yield()を読んだり内部で使うものを使用できない
  • 1ms以上かかる処理をすると不安定orクラッシュ引き起こす。よって、時間かかる処理は他でして極力そのためのフラグ操作など推奨。フラグはvolatileつける(参照
  • ヒープ操作は不具合起こしえる。malloc最小限にしてreallocとfreeは使うなと。stringやvectorも要注意。詳細はドキュメント。
  • C++のnewやdeleteも

あとは、ドキュメントに書いてないけどコールバックの宣言は使う前に。

チャタリング対策

立ち上がり、立ち上がりを検出したいが変化した時に押しているのか押していないのか中間の状態を経由するのでその際に何度もコールバック関数が呼ばれてしまう。(参照

今ブレッドボードでやっているけどイメージは下。

0件だよ
0
working
working
working
working
working
working
working
working

呼ばれたときの処理で出力される”working”が一回であってほしいが何度も出力される。

参照先に色々な対策があるが、ソフトウェアで対策できれば楽。今回の使用用途としては押されたときにあるURLをたたければよい。また、即時に何度も呼ばれなくてもよい。なので、エッジ検出後一定期間その状態が続いていれば処理を実行するとすればよい。

  1. ボタン押す
  2. 最初の立ち上がり/立下りを検出後最初数100msはチャタリングしているかもしれないので読み飛ばす
  3. その後、100ms間隔で数回状態が継続していたら押されていると判断する

みたいな感じで今回は大丈夫。

ソフトウェア的にやらないなら積分回路組んだり、ラッチ回路組んだり、いいスイッチ使ったりとあるが要件厳しくなければソフトで切り抜けた方が大体良い気がする。(というかそういう要件に収めたい)

で、ループからボタン検知と状況確認の並行処理しようとしたらESP8266はスレッドなかった。並行処理するためにFreeRTOSいれる。FreeRTOSを使おうと思ったら「ESP8266などいまさら開発する暇ないんじゃ!」とのお言葉。ESP32-C3なら使えるらしい。

ループ切り替えながらやる。2つの処理があるけど、時間はざっくりでよい。

下のイメージになった。

コールバック(shopYobidashiCallback)はフラグの設定のみ

メインのループ(Arduinoのloop関数)は並行処理するループ(yoyakuCheckLoop,yobidashiCheckLoop)をそれぞれ呼び出しのみ。

yobidashiCheckInterval 経過していなかったらスキップする処理を入れつつチェックをいれる。yobidashiCheckLoopが走っている間はもう一個の処理(yoyakuCheckLoop)は順番回ってこない。

ESP8266には基本INPUT_PULLDOWNなかった。

ESP8266(ESP-WROOM-02)で内部プルダウン使おうと思ったら怒られた。

C:\Users\kitam\git\yobidashi\client\home_yobidashi\home_yobidashi.ino:109:22: error: 'INPUT_PULLDOWN' was not declared in this scope; did you mean 'INPUT_PULLDOWN_16'?
109 | pinMode(INPUT_PIN, INPUT_PULLDOWN);
| ^~~~~~~~~~~~~~
| INPUT_PULLDOWN_16

ESP8266のGPIO1から15にはPULL_DOWN抵抗はない。INPUT/OUTPUT/INPUT_PULLUPのいずれか指定。

GPIO16だけプルダウン抵抗がある。GPIO16はディープスリープ用の特別なやつ。指定する場合はINPUT_PULLDOWN_16。

https://links2004.github.io/Arduino/dc/d6f/md_esp8266_doc_reference.html

ブレッドボードの配線的にPULL_DOWNの方が指しやすかっただけなのでおとなしくPULL_UP使う。

自宅用通知マシン作成(4)

音声関連クラス化

見通しが悪くなりそうなので音声周りは別クラスに。多分まだ予想してない改造をしそなのでパラメーター渡すとか考えずに単純な別ファイル化だけ。(StackSpeaker.h)

呼び出しは

しておいて使いたいところで

通信

次に外部から呼び出せるようにserver機能を持たせる。店の外から呼び出す計画のでまずはhttpでそのまま外からつなげられるようする。そのうちリバースプロキシの後ろに隠すかもしれないけどとりあえずルーターにNAPTでさばかせておく。

wifi周り

スマートコンフィグ使おうかと考えたけど、ip指定で起動するときにデフォゲとサブネット与えないといけなかった。そいつらをしっかりと渡すとなると外から与えてスマートコンフィグの意味なくなるか、一回目の接続で取れた値を使用と面倒になりそう。というわけでおとなしく明示的に指定することにした。

と、サンプルにありそうなやつそのまま

server周り

これもよくありそうなやつ。

WebServer.hつかって、呼び出し処理があったら音声を流す処理を行う。

handleYobidashiの中で、speaker#stopVoice/speaker#startVoiceを直接呼んでいるので同期処理になっている。音声が流れ終わってから呼び出し側にはレスポンス返る。使うケース次第では非同期呼び出しにするためにさらにスレッドを呼ぶ形にする方が良い場合は多そう。

続き 呼び出し側の自宅端末バージョンアップ

M5Unified_StackChanを参考にした際のメモ

MP3_with_ESP8266Audio.inoを参考に音声出力をしていたが音がとんだり画面にノイズ?が入ったりとしていた。ツイッターで呟いたらタカヲさん(@mongonta555)から参考情報を教えてもらった。

こちらで音が出るようになった。リンク先レポジトリのメモ書きを残す。なお、M5Unified_StackChanにはあるが試していないものもある。

対象音声フォーマット

readmeにはwavとなっているけどmp3用

バッファ処理

MP3_with_ESP8266Audioにはなかったbuffer処理が入っている。下のあたり

音声ファイルのサンプリングレート

readmeには”wavファイルのサンプリング周波数は16khzか24khzにしてください。”とある。ffmpegで16khzか24khzに変換したかったが、26khzが生成されて直し方がわからなかったので26khzを受け入れて試験。サンプリングレートじゃなくてビットレートが26kbpsだった。

スピーカーのコンフィグ指定

下のようにいくつか指定が入っている。

sample_rate は出来上がったファイルに合わせてみた。

task_priorityは同じコアでの処理優先順位。数時大きい数が優先順位高くたしか23が最大値。m5avaterの中で2が使われているはずなので使っているライブラリの範囲では3にしとけば最優先のはず。

dma_buf_count /dma_buf_len はよくわかっていない。

task_pinned_core は処理をさせるCPUコアの指定(PRO_APP_NUMデフォルトで、もう一個がPRO_APP_NUM)。M5Unified_StackChanではPRO_CPU_NUMを使っていたがデフォルトでも音質違いが分からなかったのでデフォルトに戻してある。

  auto spk_cfg = M5.Speaker.config();
  spk_cfg.sample_rate = 26000;
  spk_cfg.task_priority = 23;
  spk_cfg.dma_buf_count = 20;
  spk_cfg.dma_buf_len = 128;
  //spk_cfg.task_pinned_core = PRO_CPU_NUM;
  M5.Speaker.config(spk_cfg);

ファイルクローズ処理

mp3.stop()の中でもoutやfileのクローズが呼ばれているのでソフトウェア的にはfileやoutのクローズ処理はいらないはず。ただし、どこかのサイト(メモってなかったら出典探せなくなった)で下みたいな書き方の方がスピーカーの最初の音が小さくなるみたいなことが書かれていたのでそちらに合わせた。ちなみに、スピーカーの最初の音とはスピーカーに電源が入る時のボッみたいな音。その違いが分からなかったが、こだわるところでもないので合わせておく。

補足

比較をしていないけどもともと使っていたのが160kbpsの3分というファイルだったのでそいつの影響が大きい気がしなくもない。