GA

2025/07/02

最新のMySQL ShellだけでMySQLのPITR可能なバックアップを設定する(フルバックアップ編)

MySQL Shellには util.dumpInstance = フルバックアップと、9.2くらいから util.dumpBinlogs = 増分バックアップがあるので、ひょっとしたらMySQL ShellだけでPITR可能なバックアップをシンプルに設定できるのではないかと思った。

TL;DR

  • util.dumpBinlogs は「前回吸い上げたバイナリログから増えたぶんだけをMySQLプロトコルで吸い上げてローカルFSに保管」することができる。初回のみ最初のバイナリログファイル名の指定が必要
    • mysqlbinlog --stop-never --raw -R ではプロセスが再起動する時に常に自分でコピーを開始するバイナリログファイル名を指定しなければならなかった
  • util.dumpBinlogsgtid_mode=ON でしか使えない
    • リストア用である util.loadBinlogs は終端を示す stopAfter または stopBefore にGTIDしか使えない
      • mysqlbinlog --stop-datetime=.. が使えないのでPITRと考えると時間とGTIDのマップを自分でやらないといけない
      • じゃあ時間とGTIDを定期的に記録すればいけるんじゃないかなと思った

長くなったので今回はフルバックアップのみ。


大前提としてMySQL側は gtid_mode=ON でないといけない。あと、 util.dumpBinlogs はMySQL Shell 9.2だかそこいらからの機能なので今現在で 最新のMySQL Shell 9.3にしておく。

sudo dnf install -y https://dev.mysql.com/get/Downloads/MySQL-Shell/mysql-shell-9.3.0-1.el8.x86_64.rpm

リストアターゲットにするMySQLはdockerコンテナで済ます。
--restart=on-failureRESTART ステートメントに必要だから(今回使わないけどクセにしている)。
-e のいくつかはパスワードレスでネットワークがつながっている限りどこからでもrootでログインできるようにするもの。
URLが指定してあるのは MySQL公式のDockerリポジトリがcontainer-registry.oracle.comに引っ越していた から。
イメージの指定のあとに続いているのはそのまま mysqld に渡されるオプションになる。ここで --gtid-mode=ON --enforce-gtid-consistency=ON にしてGTIDを有効にしている。

docker run -d -P \
  --restart=on-failure \
  -e MYSQL_ALLOW_EMPTY_PASSWORD=1 \
  -e MYSQL_ROOT_PASSWORD="""" \
  -e MYSQL_ROOT_HOST=""%"" \
  container-registry.oracle.com/mysql/community-server:8.4.5 \
    --gtid-mode=ON --enforce-gtid-consistency=ON --lower-case-table-names

mysql> CREATE USER mysqlsh_backup IDENTIFIED BY 'secret_password';
Query OK, 0 rows affected (0.02 sec)

mysql> GRANT SELECT, RELOAD, REPLICATION SLAVE, REPLICATION CLIENT, EVENT, TRIGGER, BACKUP_ADMIN ON *.* TO mysqlsh_backup;
Query OK, 0 rows affected (0.01 sec)

mysql> SHOW GRANTS FOR mysqlsh_backup;
+------------------------------------------------------------------------------------------------------------+
| Grants for mysqlsh_backup@%                                                                                |
+------------------------------------------------------------------------------------------------------------+
| GRANT SELECT, RELOAD, REPLICATION SLAVE, REPLICATION CLIENT, EVENT, TRIGGER ON *.* TO `mysqlsh_backup`@`%` |
| GRANT BACKUP_ADMIN ON *.* TO `mysqlsh_backup`@`%`                                                          |
+------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

MySQL Shellは mysql_config_editor で作ったクレデンシャルを食えるので、先に設定しておく。

$ mysql_config_editor set --login-path=backup --user=mysqlsh_backup --password
Enter password:     ### 対話的に入れるしかない

$ mysqlsh --login-path=backup -h 172.17.0.2 -e "SHOW GRANTS"
Grants for mysqlsh_backup@%
GRANT SELECT, RELOAD, REPLICATION CLIENT, EVENT, TRIGGER ON *.* TO `mysqlsh_backup`@`%`
GRANT BACKUP_ADMIN ON *.* TO `mysqlsh_backup`@`%`

GTIDとPITRの時刻を紐づけるためにハートビートテーブルを作って定期的に実行する。

#!/usr/bin/perl

use strict;
use warnings;
use utf8;

use Time::Piece;
use DBI;

my $dsn = "dbi:mysql:;host=172.17.0.2";
my $user= "root";
my $pass= "";
my $opt = { RaiseError => 1, PrintError => 1, use_mysql_utf8 => 1, mysql_connect_timeout => 1 };

my $conn= DBI->connect($dsn, $user, $pass, $opt) or die;

$conn->do("CREATE DATABASE IF NOT EXISTS sakura");
$conn->do("CREATE TABLE IF NOT EXISTS sakura.hb (seq SERIAL, hostname VARCHAR(255) NOT NULL, recorded DATETIME NOT NULL, gtid_executed TEXT NOT NULL)");

while ()
{
  my $now= Time::Piece::localtime;
  $conn->do(q|INSERT INTO sakura.hb (hostname, recorded, gtid_executed) VALUES (@@hostname, ?, @@global.gtid_executed)|, undef, $now->strftime("%Y-%m-%d %H:%M:%S"));
  printf("%s\n", $now->strftime("%Y-%m-%d %H:%M:%S"));
  sleep 1;
}

まずフルバックアップ。MySQL Shellはいくつからだったかデフォルトモードが --js から --sql に変わっているので util.* 系を呼び出す時には --js が必要。

$ mysqlsh --login-path=backup -h 172.17.0.2 --js -- util dumpInstance /path/to/full_backup

-e "util.dumpInstance('/path/to/full_backup')" でも取れると思うけど俺は -- 記法の方が好き(単に先にそっちでおぼえたから)

$ ll /path/to/full_backup/
total 86260
-rw-r-----. 1 yoku0825 yoku0825      599 Jul  2 02:26 @.done.json
-rw-r-----. 1 yoku0825 yoku0825    31733 Jul  2 02:26 @.json
-rw-r-----. 1 yoku0825 yoku0825      238 Jul  2 02:26 @.post.sql
-rw-r-----. 1 yoku0825 yoku0825      238 Jul  2 02:26 @.sql
-rw-r-----. 1 yoku0825 yoku0825     4708 Jul  2 02:26 @.users.sql
-rw-r-----. 1 yoku0825 yoku0825      386 Jul  2 02:26 sakura.json
-rw-r-----. 1 yoku0825 yoku0825      807 Jul  2 02:26 sakura.sql
-rw-r-----. 1 yoku0825 yoku0825      639 Jul  2 02:26 sakura@hb.json
-rw-r-----. 1 yoku0825 yoku0825      830 Jul  2 02:26 sakura@hb.sql
-rw-r-----. 1 yoku0825 yoku0825      318 Jul  2 02:26 sakura@hb@@0.tsv.zst
-rw-r-----. 1 yoku0825 yoku0825        8 Jul  2 02:26 sakura@hb@@0.tsv.zst.idx
-rw-r-----. 1 yoku0825 yoku0825      401 Jul  2 02:26 sbtest.json
-rw-r-----. 1 yoku0825 yoku0825      807 Jul  2 02:26 sbtest.sql
-rw-r-----. 1 yoku0825 yoku0825      637 Jul  2 02:26 sbtest@sbtest1.json
-rw-r-----. 1 yoku0825 yoku0825      856 Jul  2 02:26 sbtest@sbtest1.sql
-rw-r-----. 1 yoku0825 yoku0825 29377820 Jul  2 02:26 sbtest@sbtest1@0.tsv.zst
-rw-r-----. 1 yoku0825 yoku0825      496 Jul  2 02:26 sbtest@sbtest1@0.tsv.zst.idx
-rw-r-----. 1 yoku0825 yoku0825 29415751 Jul  2 02:26 sbtest@sbtest1@1.tsv.zst
-rw-r-----. 1 yoku0825 yoku0825      496 Jul  2 02:26 sbtest@sbtest1@1.tsv.zst.idx
-rw-r-----. 1 yoku0825 yoku0825 29415671 Jul  2 02:26 sbtest@sbtest1@2.tsv.zst
-rw-r-----. 1 yoku0825 yoku0825      496 Jul  2 02:26 sbtest@sbtest1@2.tsv.zst.idx
-rw-r-----. 1 yoku0825 yoku0825      117 Jul  2 02:26 sbtest@sbtest1@@3.tsv.zst
-rw-r-----. 1 yoku0825 yoku0825        8 Jul  2 02:26 sbtest@sbtest1@@3.tsv.zst.idx

$ jq . /path/to/full_backup/@.json
{
    "dumper": "mysqlsh Ver 9.3.0 for Linux on x86_64 - for MySQL 9.3.0 (MySQL Community Server (GPL))",
    "version": "2.0.1",
    "origin": "dumpInstance",
    "schemas": [
        "sakura",
        "sbtest"
    ],
    "basenames": {
        "sakura": "sakura",
        "sbtest": "sbtest"
    },
    "users": [
        "'healthchecker'@'localhost'",
        "'mysqlsh_backup'@'%'",
        "'root'@'%'",
        "'root'@'localhost'"
    ],
    "defaultCharacterSet": "utf8mb4",
    "tzUtc": true,
    "bytesPerChunk": 64000000,
    "user": "mysqlsh_backup",
    "hostname": "yoku0825-oci",
    "gtidExecutedInconsistent": false,
    "consistent": true,
    "targetVersion": "9.3.0",
    "hasLibraryDdl": false,
    "source": {
        "binlog": {
            "file": "binlog.000002",
            "position": 190942962,
            "gtidExecuted": "3b5d02fb-56e7-11f0-8f01-0242ac110002:1-455"
        },
        "sysvars": {
..
        },
        "topology": {
            "canonicalAddress": "a7786309934c:3306"
        }
    },
    "server": "a7786309934c",
    "serverVersion": "8.4.5",
    "binlogFile": "binlog.000002",
    "binlogPosition": 190942962,
    "gtidExecuted": "3b5d02fb-56e7-11f0-8f01-0242ac110002:1-455",
    "partialRevokes": false,
    "compatibilityOptions": [],
    "capabilities": [],
    "checksum": false,
    "begin": "2025-07-02 02:26:38"
}


$ jq -r .begin /path/to/full_backup/@.json
2025-07-02 02:26:38

バックアッププロセス自体の情報は @.json@.post.json に含まれている。論理バックアップである util.dumpInstance のデータの切断面は開始時刻になると期待するので、 @.json に含まれる begin を確認しておく。

リストア用にもう1つコンテナを立ち上げて、 util.loadDump に必要な local_infile をONにして実行。

docker run -d -P \
  --restart=on-failure \
  -e MYSQL_ALLOW_EMPTY_PASSWORD=1 \
  -e MYSQL_ROOT_PASSWORD="""" \
  -e MYSQL_ROOT_HOST=""%"" \
  container-registry.oracle.com/mysql/community-server:8.4.5 \
    --gtid-mode=ON --enforce-gtid-consistency=ON --lower-case-table-names

mysql> SET GLOBAL local_infile = 1;
Query OK, 0 rows affected (0.00 sec)

$ mysqlsh root@172.17.0.3 --js -- util loadDump /path/to/full_backup/ { --loadUsers=true --ignoreExistingObjects=true --updateGtidSet=replace }   ### デフォルトではユーザーまでは生成されないのと、既存のアカウントは無視してくれればいい、gtid_executedは上書きする

狙った通りにリストアできてるか、ハートビートテーブルから確認できる。
綺麗にぴったり  @.json の begin と一致してよかった。

mysql> SELECT * FROM sakura.hb ORDER BY seq DESC LIMIT 1;
+-----+--------------+---------------------+--------------------------------------------+
| seq | hostname     | recorded            | gtid_executed                              |
+-----+--------------+---------------------+--------------------------------------------+
|  65 | a7786309934c | 2025-07-02 02:26:38 | 3b5d02fb-56e7-11f0-8f01-0242ac110002:1-454 |
+-----+--------------+---------------------+--------------------------------------------+
1 row in set (0.00 sec)

特に仕組みを作っている最中はこのハートビートテーブルが役に立つというのが一番の知見かもしれない。

増分バックアップ編に続く。

2025/06/20

バイナリログのバックアップについて考える in 2025

rsync

シェルが必要(たとえば ~/.ssh/authorized_keys で mysqldの実効アカウントにログインできるとか)なので新規に採用は嫌な感じ。
それを飲めるなら候補の一つとしてアリな気はする。
帯域ネックなら -z で圧縮をかけるとCPUを使いつつ転送に圧縮をかけられるが、転送後のファイルは圧縮されていない状態で現れるので保管を考えると更に圧縮する必要があって手間は手間。 binlog_transaction_compression が有効なら最初から圧縮されているのでベター。
binlog暗号化をされている状態でも保管はできるが、暗号化されたバイナリログを読み出すためにはkeyringが必要で、mysqldを起動させないといけない。
mysqldを止めずに実行する前提なので、バイナリログの最後のイベント(今まさに書き込んでいるイベント)は壊れているかもしれない。ただmysqlbinlogでデコードする時にワーニングが出るだけなのでわかっていさえすれば大丈夫。デフォルトではファイルのタイムスタンプが一致すれば次回はスキップされる。その時アクティブだったバイナリログは大体先頭から転送し直しになる。
コマンドの実行間隔がRPOになるが、他にレプリカがあれば最新のデータはそいつから取り出せるのでPITRの文脈であれば数分~15分, 30分, 1時間くらいは許容範囲なのではないかしら。

$ rsync user@host:/var/lib/mysql/mysql-bin.* ./
$ ll
total 375940
-rw-r----- 1 yoku0825 yoku0825       381 Jun 20 09:37 bin.000009
-rw-r----- 1 yoku0825 yoku0825       569 Jun 20 09:37 bin.000010
-rw-r----- 1 yoku0825 yoku0825 269449054 Jun 20 09:38 bin.000011
-rw-r----- 1 yoku0825 yoku0825 115493747 Jun 20 09:38 bin.000012
-rw-r----- 1 yoku0825 yoku0825        52 Jun 20 09:38 bin.index

mysqlbinlog

俺の大好きなパターン。 REPLICATION SLAVE 権限が必要。 —read-from-remote-server—raw を組み合わせて使う。 --raw を使わない場合はデコード後のテキストファイルが手に入るが、この場合PITRの時の —stop-datetime などのオプションが使えなくなる = テキストエディタで編集しないといけないのでなるべくそのままのバイナリログの形が好み。

  • 日々の覚書: mysqlbinlogでバイナリログをバックアップするとか
  • yoku0825/binlog_stream_container: Docker image for streaming MySQL binlog backup.
    通信経路圧縮をするにはzlibを使った -C だったが、8.0.18とそれ以降では —compression-algorithms でzstdが指定可能。zstdの方が軽くて速い。これもbinlog圧縮がされているなら圧縮後の転送量&ファイルサイズで済む。
    rsyncのようなワイルドカード指定がないので1つずつバイナリログファイル名を指定するか、「このバイナリログ以降のすべてをストリームし続ける( = —stop-never )」の2択しかない。転送対象に指定したバイナリログは手元にあろうがなかろうが全部先頭から再転送になる。
    rsyncと違ってmysqldが落ちている間は使えない。基本的にファイルを全部読み切ってから終了(または、 --stop-never で次のバイナリログを待機)するので最後のイベントが無効ってことはない。mysqlbinlog側がプロセスダウンしない限りは。
    binlog暗号化されている場合、mysqlbinlogが保管したファイルは平文に戻っている。得られたバイナリログを別途暗号化するなりなんなりが必要。
    --stop-never を使っている場合はmysqlbinlogプロセスが常駐して ( レプリケーションのレプリカと同じように ) バイナリログを逐次受信するためRPOがすこぶる短いことが期待できる。プロセスダウンをちゃんと検知して必要なら再起動する必要はあるけれども。
    そのへん(プロセスが起動された時に手元の最後のバイナリログのみ先頭から取り直す、手元にバイナリログがないならサーバーにある最初のファイルから読み出す)をケアしたスクリプトがこんな感じ。
  • https://github.com/yoku0825/binlog_stream_container/blob/main/binlog_stream_wrapper.sh#L22-L53

( ´-`).oO( holded ってなんだ… held だろう…

$ export MYSQL_PWD=xx
$ for num in {9..12} ; do
> mysqlbinlog -h sandbox.oci.yoku0825.work -P 64080 --raw -ubinlog -R --compression-algorithms=zstd "$(printf "%06d" $num)"
> done

$ ll
total 375936
-rw-r----- 1 yoku0825 yoku0825       381 Jun 20 09:40 bin.000009
-rw-r----- 1 yoku0825 yoku0825       569 Jun 20 09:40 bin.000010
-rw-r----- 1 yoku0825 yoku0825 269449054 Jun 20 09:40 bin.000011
-rw-r----- 1 yoku0825 yoku0825 115493747 Jun 20 09:41 bin.000012

MySQL Shellのutil.dumpBinlogs

最近の新顔。MySQL Shell 9.2か何かの新機能で、 MySQL Shell 8.4には入っていない 。2025年6月現在ではInnovation ReleaseのMySQL Shellが必要。
対象になるバイナリログファイルを特定するために SHOW BINARY LOGS を実行するので REPLICATION CLIENT 権限、実際にバイナリログを吸い上げるために REPLICATION SLAVE 権限が必要。MySQLプロトコルを使うので mysqld がダウンしてるとダメ。
俺が詳しくないだけかも知れないけど通信経路の圧縮はなさそう? サーバー側のbinlog圧縮が効いてれば節約になるのは他のと同じ。コイツだけ、「転送してきたバイナリログを圧縮してファイルに落とす」ので別途の圧縮は不要( binlog_transaction_compression
初回のみ、「最初に取り始めるバイナリログファイル名」を指定する必要があるが、2回目以降は「初回のバックアップで読み切ったポジションをメタデータファイルに残す」ので勝手に差分取得が可能。

mysqlbinlog と違って常駐はできないのでrsyncと同じくRPOの制約がある。実行のたびに指定したディレクトリに日時を示したディレクトリができるっぽい。

$ mysqlsh -h sandbox.oci.yoku0825.work -P 64080 -ubinlog -- util dumpBinlogs ./ { --startFrom=bin.000009 }
$ ll
total 8
drwxr-x--- 2 yoku0825 yoku0825 4096 Jun 20 09:58 2025-06-20-00-56-58
-rw-r----- 1 yoku0825 yoku0825  457 Jun 20 09:56 @.binlog.info.json

$ ll
total 8
drwxr-x--- 2 yoku0825 yoku0825 4096 Jun 20 09:58 2025-06-20-00-56-58
-rw-r----- 1 yoku0825 yoku0825  457 Jun 20 09:56 @.binlog.info.json

$ ll 2025-06-20-00-56-58/
total 182440
-rw-r----- 1 yoku0825 yoku0825       251 Jun 20 09:58 @.binlog.done.json
-rw-r----- 1 yoku0825 yoku0825     31614 Jun 20 09:56 @.binlog.json
-rw-r----- 1 yoku0825 yoku0825       275 Jun 20 09:56 bin.000009.json
-rw-r----- 1 yoku0825 yoku0825       274 Jun 20 09:56 bin.000009.zst
-rw-r----- 1 yoku0825 yoku0825       278 Jun 20 09:56 bin.000010.json
-rw-r----- 1 yoku0825 yoku0825       342 Jun 20 09:56 bin.000010.zst
-rw-r----- 1 yoku0825 yoku0825       295 Jun 20 09:58 bin.000011.json
-rw-r----- 1 yoku0825 yoku0825 130723963 Jun 20 09:58 bin.000011.zst
-rw-r----- 1 yoku0825 yoku0825       324 Jun 20 09:57 bin.000012.json
-rw-r----- 1 yoku0825 yoku0825  56018567 Jun 20 09:57 bin.000012.zst

もう一度実行すると差分がまた日付のディレクトリに現れる。今度は startFrom の指定をする必要はない。バックアップ先ディレクトリで一度でもdumpBinlogsが実行されていれば勝手に途中から実行する。

$ mysqlsh -h sandbox.oci.yoku0825.work -P 64080 -ubinlog -- util dumpBinlogs ./
Starting from previous dump: /home/yoku0825/work/2025-06-20-00-56-58, created at: 2025-06-20 00:56:58 UTC
Starting from binary log file: bin.000012:115493970
Will finish at binary log file: bin.000012:121584248
Dumping 1 binlogs (6.09 MB of data) using 4 threads
100% (6.09 MB / 6.09 MB), 3.27 MB/s, 2.46 MB/s compressed, 1 / 1 binlogs done
Dump was written to: /home/yoku0825/work/2025-06-20-01-03-00
Total duration: 00:00:01s
Binlogs dumped: 1
GTID set dumped: 6f9ee6f0-1feb-11f0-a8f1-02001702f486:449-9081
Uncompressed data size: 6.09 MB
Compressed data size: 4.64 MB
Compression ratio: 1.3
Events written: 17267
Bytes written: 4.64 MB
Average uncompressed throughput: 3.35 MB/s
Average compressed throughput: 2.55 MB/s

$ ll
total 16
drwxr-x--- 2 yoku0825 yoku0825 4096 Jun 20 09:58 2025-06-20-00-56-58
drwxr-x--- 2 yoku0825 yoku0825 4096 Jun 20 10:03 2025-06-20-01-03-00
-rw-r----- 1 yoku0825 yoku0825  457 Jun 20 09:56 @.binlog.info.json

$ ll 2025-06-20-01-03-00/
total 4568
-rw-r----- 1 yoku0825 yoku0825      42 Jun 20 10:03 @.binlog.done.json
-rw-r----- 1 yoku0825 yoku0825   31480 Jun 20 10:03 @.binlog.json
-rw-r----- 1 yoku0825 yoku0825     355 Jun 20 10:03 bin.000012.json
-rw-r----- 1 yoku0825 yoku0825 4636447 Jun 20 10:03 bin.000012.zst

$ ll */bin.000012*.zst
-rw-r----- 1 yoku0825 yoku0825 56018567 Jun 20 09:57 2025-06-20-00-56-58/bin.000012.zst
-rw-r----- 1 yoku0825 yoku0825  4636447 Jun 20 10:03 2025-06-20-01-03-00/bin.000012.zst

ファイルも先頭から取り直しているわけではなかった。

各zstファイルを解凍するといつもの(デコード前の)バイナリログが出てくる。
util.dumpBinlogs で取ったバックアップは util.loadBinlogs でディレクトリを指定する形で一気に適用できる。一つ一つ解凍して mysqlbinlog | mysql とかする必要はない。

binlog暗号化に関する話は mysqlbinlog と一緒。binlog圧縮の解凍はクライアントの責務だけど、暗号化されたbinlogを適用可能に復号するのはMySQLサーバー側の責務なので、MySQLプロトコルを使うクライアントサーバー形式だとどうしてもこうなる ( なので gh-ost とかも一緒)

【2025/06/20 18:18】

ただし、


     MySQL  localhost:3306  JS > util.dumpBinlogs('/backup/binlog_mysqlsh')
    The 'gtid_mode' system variable on the source instance is set to 'OFF'. This utility requires GTID support to be enabled. (ArgumentError)で

でした。最近サンドボックスも全部gtid_mode=ON統一だから気が付かなかった…

意外と楽しかった。

2025/06/17

バックアップをネットワークまたいだファイルサーバに置きたいけど指定した以外のファイルは上書きもされたくないし読まれたくもない

TL;DR


普段から使っていたのはファイルサーバー側でポートを開いてリダイレクトしちゃう。実際にはもう少し「ランダムにポートを開いてその番号を教えてくれるスクリプトだけをssh越しに実行させる」とか「curlで叩くとトークン検証してランダムにポートを開いてその番号を教えてくれるAppにする」とかの工夫はできる。

nc -l 13306 > /path/to/myfile

バックアップはリモートから書き込む。bash使いなので /dev/tcp は好き。

xtrabackup -S /usr/mysql/8.4.5/data/mysql.sock -uroot --backup --stream=xbstream | pv >  /dev/tcp/file_server/13306

書き込みが終わる(異常終了を含む)とncプロセスは落ちるので再利用のためにはレシーバー側でncの再実行が必要。そのタイミングでリダイレクト先のファイル名を変更できるので上書きも回避できる(noclobberでエラーにするか、別のファイルとして受けるかの違いではある)

もし通信経路を通す前に圧縮したいなら送信元で圧縮すればいいし、

xtrabackup -S /usr/mysql/8.4.5/data/mysql.sock -uroot --backup --stream=xbstream | pzstd -c | pv  > /dev/tcp/file_server/13306

受信側でそのまま展開したいならncからパイプしてやればいい(xbstreamまではパイプで繋げるけどxtrabackup —prepareは別でやらないといけない)

nc -l 13306 | pzstd -dc | xbstream -x

受ける側でパスワードをかけたりもした(ランダムに推測不可能なものを作ってDBAにだけメールしてた気がする)

nc -l 13306 | openssl aes-256-cbc -pbkdf2 -e -pass pass:something > /tmp/myfile.enc

$ file /tmp/myfile.enc
/tmp/myfile.enc: openssl enc'd data with salted password

$ openssl aes-256-cbc -pbkdf2 -d -in /tmp/myfile.enc -out /tmp/myfile
enter AES-256-CBC decryption password:

$ pzstd -dc /tmp/myfile | xbstream -x
/tmp/myfile         : 75159378 bytes

デーモンにしたりすると面倒だけど後々が楽。。

2025/06/10

Oracle Linux 8でMySQL 5.7のrpmをビルドする

TL;DR


MySQL Product Archives で見たら、MySQL 5.7はOracle Linux(に限らずRHEL系の)8に対応したrpmはなかった。けど欲しい。

というわけで(el7用のrpmファイルでも動くような気はするけど一応) Oracle Linuxのコンテナイメージ の中でrpmbuildするメモ。

# wget http://repo.mysql.com/yum/mysql-5.7-community/el/7/SRPMS/mysql-community-5.7.44-1.el7.src.rpm
# rpm -i mysql-community-5.7.44-1.el7.src.rpm

# dnf install rpm-build

# rpmbuild -bb ~/rpmbuild/SPECS/mysql.spec
error: Failed build dependencies:
        cyrus-sasl-devel is needed by mysql-community-5.7.44-1.el8.x86_64
        libaio-devel is needed by mysql-community-5.7.44-1.el8.x86_64
        ncurses-devel is needed by mysql-community-5.7.44-1.el8.x86_64
        numactl-devel is needed by mysql-community-5.7.44-1.el8.x86_64
        openldap-devel is needed by mysql-community-5.7.44-1.el8.x86_64
        openssl-devel is needed by mysql-community-5.7.44-1.el8.x86_64
        perl is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Carp) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Config) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Cwd) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Data::Dumper) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(English) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Errno) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Exporter) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Fcntl) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Basename) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Copy) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Find) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Path) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Spec) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Spec::Functions) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Temp) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Getopt::Long) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(IO::File) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(IO::Handle) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(IO::Pipe) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(IO::Select) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(IO::Socket) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(IO::Socket::INET) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(JSON) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Memoize) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(POSIX) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Sys::Hostname) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Time::HiRes) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Time::localtime) is needed by mysql-community-5.7.44-1.el8.x86_64
        time is needed by mysql-community-5.7.44-1.el8.x86_64
        zlib-devel is needed by mysql-community-5.7.44-1.el8.x86_64

依存のものを入れる。

# dnf install -y cyrus-sasl-devel libaio-devel ncurses-devel numactl-devel openldap-devel openssl-devel perl time zlib-devel perl-JSON

# rpmbuild -bb ~/rpmbuild/SPECS/mysql.spec
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.5u4iqi
+ umask 022
+ cd /root/rpmbuild/BUILD
+ cd /root/rpmbuild/BUILD
+ rm -rf mysql-5.7.44
+ /usr/bin/mkdir -p mysql-5.7.44

..
+ cmake ../mysql-5.7.44 -DBUILD_CONFIG=mysql_release -DINSTALL_LAYOUT=RPM -DCMAKE_BUILD_TYPE=Debug -DWITH_BOOST=.. '-DCMAKE_C_FLAGS= -g -pipe -Wall -Werror=format-security   -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection' '-DCMAKE_CXX_FLAGS= -g -pipe -Wall -Werror=format-security   -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection' -DWITH_INNODB_MEMCACHED=1 -DINSTALL_LIBDIR=lib64/mysql -DINSTALL_PLUGINDIR=lib64/mysql/plugin/debug -DMYSQL_UNIX_ADDR=/var/lib/mysql/mysql.sock -DMYSQLX_UNIX_ADDR=/var/run/mysqld/mysqlx.sock -DFEATURE_SET=community -DWITH_EMBEDDED_SERVER=1 -DWITH_EMBEDDED_SHARED_LIBRARY=1 -DWITH_NUMA=ON '-DCOMPILATION_COMMENT=MySQL Community Server - Debug (GPL)' -DMYSQL_SERVER_SUFFIX=
/var/tmp/rpm-tmp.AHE541: line 47: cmake: command not found
error: Bad exit status from /var/tmp/rpm-tmp.AHE541 (%build)

RPM build errors:
    Bad exit status from /var/tmp/rpm-tmp.AHE541 (%build)

cmake忘れてた…というかBuildRequiresに書いておいてくれればいいのに。そのほか、ビルド中に転けたパッケージも入れた。

# dnf install -y cmake gcc gcc-c++ libtirpc-devel
# dnf install -y --enablerepo=ol8_codeready_builder rpcgen
# rpmbuild -bb ~/rpmbuild/SPECS/mysql.spec

これで完成。

# ll ~/rpmbuild/RPMS/x86_64/mysql-community-*
-rw-r--r--. 1 root root  22908224 Jun 10 03:31 /root/rpmbuild/RPMS/x86_64/mysql-community-client-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root    323348 Jun 10 03:31 /root/rpmbuild/RPMS/x86_64/mysql-community-common-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root   3790152 Jun 10 03:32 /root/rpmbuild/RPMS/x86_64/mysql-community-devel-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root  59816800 Jun 10 03:32 /root/rpmbuild/RPMS/x86_64/mysql-community-embedded-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root 172178112 Jun 10 03:33 /root/rpmbuild/RPMS/x86_64/mysql-community-embedded-devel-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root   1866328 Jun 10 03:32 /root/rpmbuild/RPMS/x86_64/mysql-community-libs-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root 166402044 Jun 10 03:31 /root/rpmbuild/RPMS/x86_64/mysql-community-server-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root 150149116 Jun 10 03:32 /root/rpmbuild/RPMS/x86_64/mysql-community-test-5.7.44-1.el8.x86_64.rpm