ラベル MySQL の投稿を表示しています。 すべての投稿を表示
ラベル MySQL の投稿を表示しています。 すべての投稿を表示

2026年1月20日火曜日

Ubuntu24.04 に MySQL8.4 をインストールする方法

Ubuntu24.04 に MySQL8.4 をインストールする方法

概要

apt でインストールできます
ついでに unattended-upgrade にも対応しておきます

環境

  • Ubuntu 24.04
  • MySQL 8.4.7

インストール方法

curl -LO https://dev.mysql.com/get/mysql-apt-config_0.8.36-1_all.deb
sudo dpkg -i mysql-apt-config_0.8.36-1_all.deb
sudo apt -y update
sudo apt -y install mysql-server

確認項目

  • root パスワードの設定
  • 既存の設定ファイル (my.cnf など) がある場合は上書きするか

動作確認

  • dpkg -l | grep 'mysql'
ii  default-libmysqlclient-dev:amd64       1.1.0build1                             amd64        MySQL database development files (metapackage)
ii  libmysqlclient-dev                     8.4.7-1ubuntu24.04                      amd64        MySQL development headers
ii  libmysqlclient24:amd64                 8.4.7-1ubuntu24.04                      amd64        MySQL shared client libraries
ii  mysql-apt-config                       0.8.36-1                                all          Auto configuration for MySQL APT Repo.
ii  mysql-client                           8.4.7-1ubuntu24.04                      amd64        MySQL Client meta package depending on latest version
ii  mysql-common                           8.4.7-1ubuntu24.04                      amd64        Common files shared between packages
ii  mysql-community-client                 8.4.7-1ubuntu24.04                      amd64        MySQL Client
ii  mysql-community-client-core            8.4.7-1ubuntu24.04                      amd64        MySQL Client Core Binaries
ii  mysql-community-client-plugins         8.4.7-1ubuntu24.04                      amd64        MySQL Client plugin
ii  mysql-community-server                 8.4.7-1ubuntu24.04                      amd64        MySQL Server
ii  mysql-community-server-core            8.4.7-1ubuntu24.04                      amd64        MySQL Server Core Binaries
ii  mysql-server                           8.4.7-1ubuntu24.04                      amd64        MySQL Server meta package depending on latest version

unattended-upgrade

  • grep -e 'Origin:' -e 'Suite:' /var/lib/apt/lists/repo.mysql.com_apt_ubuntu_dists_noble_*
/var/lib/apt/lists/repo.mysql.com_apt_ubuntu_dists_noble_InRelease:Origin: MySQL
  • sudo vim /etc/apt/apt.conf.d/58unattended-upgrades-mysql-packages
Unattended-Upgrade::Allowed-Origins {
        "MySQL:noble";
};

最後に

8.0 は 2026/04 で EOL なのでアップグレードしましょう

参考サイト

2025年7月5日土曜日

MySQL8.4.5でInnoDBClusterにMySQLRouterを適用し自動でPRIMARYにアクセスできるようにしてみた

MySQL8.4.5でInnoDBClusterにMySQLRouterを適用し自動でPRIMARYにアクセスできるようにしてみた

概要

前回 MySQL8.4.5 で InnoDBCluster を構築し FailOver 可能な MySQL 環境を構築してみました
今回は FailOver 後に PRIMARY が変わってしまうのに自動で対応するために MySQL Router を導入しバランシングしてみました

なお MySQL Router は Arm 環境には対応していないので注意しましょう

環境

  • macOS 15.5
    M1 mac 上の docker では動きません

環境

  • Ubuntu 24.04
  • docker 28.2.2
  • MySQL 8.4.5

compose.yaml

過去のやつに mysqlrouter のサービスを追加しています
次回起動時に bootstrap の設定を使うようにボリュームを使っています

services:
  mysqlrouter:
    image: container-registry.oracle.com/mysql/community-router:8.4
    depends_on:
      - mysql1
      - mysql2
      - mysql3
    environment:
      - MYSQL_HOST=mysql1
      - MYSQL_PORT=3306
      - MYSQL_USER=root
      - MYSQL_PASSWORD=rootpass
      - MYSQL_INNODB_CLUSTER_MEMBERS=3
      - MYSQL_ROUTER_BOOTSTRAP_EXTRA_OPTIONS=--conf-use-sockets --conf-use-gr-notifications
    ports:
      - "6446:6446"  # Read-write port (Primary)
      - "6447:6447"  # Read-only port (all members)
    networks:
      - mysqlnet
    restart: always

  mysql1:
    image: mysql:8.4.5
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
    ports:
      - "33061:3306"
    command: >
      --mysql-native-password=ON
      --server-id=1
      --gtid-mode=ON
      --enforce-gtid-consistency=ON
      --binlog-format=ROW
      --log-bin=mysql-bin
      --relay-log=relay-bin
      --log-replica-updates=ON
      --read-only=OFF
    volumes:
      - mysql1_data:/var/lib/mysql
    restart: always
    networks:
      - mysqlnet

  mysql2:
    image: mysql:8.4.5
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
    ports:
      - "33062:3306"
    command: >
      --mysql-native-password=ON
      --server-id=2
      --gtid-mode=ON
      --enforce-gtid-consistency=ON
      --binlog-format=ROW
      --log-bin=mysql-bin
      --relay-log=relay-bin
      --log-replica-updates=ON
      --read-only=OFF
    volumes:
      - mysql2_data:/var/lib/mysql
    restart: always
    networks:
      - mysqlnet

  mysql3:
    image: mysql:8.4.5
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
    ports:
      - "33063:3306"
    command: >
      --mysql-native-password=ON
      --server-id=3
      --gtid-mode=ON
      --enforce-gtid-consistency=ON
      --binlog-format=ROW
      --log-bin=mysql-bin
      --relay-log=relay-bin
      --log-replica-updates=ON
      --read-only=OFF
    volumes:
      - mysql3_data:/var/lib/mysql
    restart: always
    networks:
      - mysqlnet

  mysqlshell:
    image: mysql:8.4.5
    depends_on:
      - mysql1
      - mysql2
      - mysql3
    networks:
      - mysqlnet
    volumes:
      - ./scripts:/scripts
    command: >
      bash -c "
      echo 'Waiting for MySQL to be ready...' &&
      sleep 15 &&
      mysqlsh --host=mysql1 --port=3306 --user=root --password=rootpass --py < /scripts/setup_cluster.py
      "

networks:
  mysqlnet:

volumes:
  mysql1_data:
  mysql2_data:
  mysql3_data:

MYSQL_ROUTER_BOOTSTRAP_EXTRA_OPTIONS--conf-use-sockets は最後に s が付くのが正しいようです (参考)

--conf-use-gr-notifications も同様に s が付くのが正しいです

動作確認

まずは起動します

  • docker compose up -d

そして router に対して mysql コマンドが使えるか確認します

書き込みができるポートと読み込みのみのポートがあるのでそれぞれで挙動を確認しましょう
今回であれば 6446 が書き込み可能なポートで 6447 が読み込み専用ポートです

  • mysql -u root -h 192.168.1.100 --port 6446 -p

ちなみに InnoDBCluster では PRIMARY_KEY がないテーブルに対する書き込みはエラーになるので必ず PRIMARY_KEY を各テーブルに設定するようにしましょう

mysql> create database test;
Query OK, 1 row affected (0.01 sec)

mysql> use test;
Database changed
mysql> create table test (`id` int, `name` varchar(50));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test values (1, "hoge");
ERROR 3098 (HY000): The table does not comply with the requirements by an external plugin.
mysql> drop table test;
Query OK, 0 rows affected (0.01 sec)

mysql> create table test (`id` int primary key, `name` varchar(50));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test values (1, "hoge");
Query OK, 1 row affected (0.00 sec)

読み込み専用では上記のテーブルに書き込みできないことが確認できます

  • mysql -u root -h 192.168.1.100 --port 6447 -p
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | hoge |
+----+------+
1 row in set (0.00 sec)

mysql> insert into test values (2, "fuga");
ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement

耐障害テスト

PRIMARY なノードを停止し他に移動した上で書き込みが継続できるか試してみます

  • docker compose stop mysql1
  • docker compose start mysql1
  • docker compose exec -it mysql1 mysqlsh --py
dba.get_cluster().status()

クラスタの状態を確認し PRIMARY なノードが移動していることを確認します
このあとで 6446 ポートに接続し問題なくデータが登録できることを確認しましょう

mysql -u root -h 10.104.37.79 --port 6446 -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 0
Server version: 8.4.5-router MySQL Community Server - GPL

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | hoge |
+----+------+
1 row in set (0.00 sec)

mysql> insert into test values (2,"fuga");
Query OK, 1 row affected (0.01 sec)

最後に

MySQL8.4.5 で InnoDB Cluster に MySQL Router を設定し自動的に PRIMARY にバランシングしてくれる仕組みを試しました
確かに便利ですが PRIMARY_KEY の制約などは注意が必要かもしれません

参考サイト

2025年7月4日金曜日

MySQL8.4.5でInnoDBClusterを構築してみた

MySQL8.4.5でInnoDBClusterを構築してみた

概要

前回 MySQL8.4.5 で簡単なレプリケーション構成を組んでみました
今回は少し複雑にして Group Replication を使った InnoDB Cluster を構築してみます

なお検証なので docker compose で一発で InnoDB Cluster が構築できるようしています

環境

  • macOS 15.5
  • docker 28.2.2
  • MySQL 8.4.5

compose.yaml

まずは3台の MySQL を Group Replication に必要なオプションを付与して起動します
InnoDB Cluster を構築するには mysqlshell コンテナがクラスタを構築するための Python スクリプトを実行することで構築されます

MySQL の起動オプションのみで InnoDB Cluster を構築できるわけではないので注意しましょう

services:
  mysql1:
    image: mysql:8.4.5
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
    ports:
      - "33061:3306"
    command: >
      --mysql-native-password=ON
      --server-id=1
      --gtid-mode=ON
      --enforce-gtid-consistency=ON
      --binlog-format=ROW
      --log-bin=mysql-bin
      --relay-log=relay-bin
      --log-replica-updates=ON
      --read-only=OFF
    volumes:
      - mysql1_data:/var/lib/mysql
    restart: always
    networks:
      - mysqlnet

  mysql2:
    image: mysql:8.4.5
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
    ports:
      - "33062:3306"
    command: >
      --mysql-native-password=ON
      --server-id=2
      --gtid-mode=ON
      --enforce-gtid-consistency=ON
      --binlog-format=ROW
      --log-bin=mysql-bin
      --relay-log=relay-bin
      --log-replica-updates=ON
      --read-only=OFF
    volumes:
      - mysql2_data:/var/lib/mysql
    restart: always
    networks:
      - mysqlnet

  mysql3:
    image: mysql:8.4.5
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
    ports:
      - "33063:3306"
    command: >
      --mysql-native-password=ON
      --server-id=3
      --gtid-mode=ON
      --enforce-gtid-consistency=ON
      --binlog-format=ROW
      --log-bin=mysql-bin
      --relay-log=relay-bin
      --log-replica-updates=ON
      --read-only=OFF
    volumes:
      - mysql3_data:/var/lib/mysql
    restart: always
    networks:
      - mysqlnet

  mysqlshell:
    image: mysql:8.4.5
    depends_on:
      - mysql1
      - mysql2
      - mysql3
    networks:
      - mysqlnet
    volumes:
      - ./scripts:/scripts
    command: >
      bash -c "
      echo 'Waiting for MySQL to be ready...' &&
      sleep 15 &&
      mysqlsh --host=mysql1 --port=3306 --user=root --password=rootpass --py < /scripts/setup_cluster.py
      "

networks:
  mysqlnet:

volumes:
  mysql1_data:
  mysql2_data:
  mysql3_data:

./scripts/setup_cluster.py

mysqlsh という機能を使って Python スクリプトを実行します
Python の他に JavaScript でも InnoDB Cluster を操作できます

# setup_cluster.py

import time


# 簡単なリトライ(実際はもっと robust に作ったほうがよい)
# dba は import しなくても使えるようになっている
def wait_and_configure(uri):
    for i in range(10):
        try:
            # cluster管理用のユーザを各ノードに作成する
            dba.configure_instance(
                uri, {"clusterAdmin": "admin", "clusterAdminPassword": "adminpass"}
            )
            return
        except Exception as e:
            print(f"Retry configuring {uri} in 5 sec: {e}")
            time.sleep(5)
    raise RuntimeError(f"Failed to configure instance: {uri}")


wait_and_configure("root:rootpass@mysql1:3306")
wait_and_configure("root:rootpass@mysql2:3306")
wait_and_configure("root:rootpass@mysql3:3306")

# Cluster 作成
cluster = dba.create_cluster("testCluster")
cluster.add_instance("root:rootpass@mysql2:3306", {"recoveryMethod": "clone"})
cluster.add_instance("root:rootpass@mysql3:3306", {"recoveryMethod": "clone"})

print("Cluster status:")
print(cluster.status())

流れとしては

  1. 各ノードにクラスタ構築用のユーザを設定 (configure_instance)
  2. 各ノードの追加 (add_instance)
  3. クラスタの状態を確認 (status)

という感じになっています
今回は一発で構築するためスクリプトにしましたが各 MySQL を起動したあとに手動で mysqlsh を実行し InnoDB Cluster を構築しても OK です

動作確認

  • docker compose up -d

でまずは各種コンテンを起動します
今回は上記一発で InnoDB Cluster が構築できるのであとは構築できたかを mysqlsh を使って確認します

  • docker compose exec -it mysql1 mysqlsh --py

でますは mysqlsh を起動しましょう root ユーザのパスワードが必要になります
そして Python を使ってクラスタの状況を確認します

dba.get_cluster().status() 

以下のようにクラスタが ONLINE で構築されていれば OK です

{
  "clusterName": "testCluster",
  "defaultReplicaSet": {
    "name": "default",
    "primary": "65d9833167a3:3306",
    "ssl": "REQUIRED",
    "status": "OK",
    "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
    "topology": {
      "65d9833167a3:3306": {
        "address": "65d9833167a3:3306",
        "memberRole": "PRIMARY",
        "mode": "R/W",
        "readReplicas": {},
        "replicationLag": "applier_queue_applied",
        "role": "HA",
        "status": "ONLINE",
        "version": "8.4.5"
      },
      "6892d7a7d916:3306": {
        "address": "6892d7a7d916:3306",
        "memberRole": "SECONDARY",
        "mode": "R/O",
        "readReplicas": {},
        "replicationLag": "applier_queue_applied",
        "role": "HA",
        "status": "ONLINE",
        "version": "8.4.5"
      },
      "bcbe386a9df7:3306": {
        "address": "bcbe386a9df7:3306",
        "memberRole": "SECONDARY",
        "mode": "R/O",
        "readReplicas": {},
        "replicationLag": "applier_queue_applied",
        "role": "HA",
        "status": "ONLINE",
        "version": "8.4.5"
      }
    },
    "topologyMode": "Single-Primary"
  },
  "groupInformationSourceMember": "65d9833167a3:3306"
}

どのノードがどのホスト名なのかわかない場合は add_instance 時に label というオプションが指定できるのでそれを使ってホスト名などを指定するといいかなと思います

FailOver の確認

PRIMARY なノードを停止して他のノードが PRIMARY になることを確認しましょう

  • docker compose stop mysql1

しばらくしたら再度起動します

  • docker compose start mysql1

これで再度クラスタの状態を確認すると PRIMARY が変わっていることが確認できると思います

{
    "clusterName": "testCluster", 
    "defaultReplicaSet": {
        "name": "default", 
        "primary": "bcbe386a9df7:3306", 
        "ssl": "REQUIRED", 
        "status": "OK", 
        "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.", 
        "topology": {
            "65d9833167a3:3306": {
                "address": "65d9833167a3:3306", 
                "memberRole": "SECONDARY", 
                "mode": "R/O", 
                "readReplicas": {}, 
                "replicationLag": "applier_queue_applied", 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.4.5"
            }, 
            "6892d7a7d916:3306": {
                "address": "6892d7a7d916:3306", 
                "memberRole": "SECONDARY", 
                "mode": "R/O", 
                "readReplicas": {}, 
                "replicationLag": "applier_queue_applied", 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.4.5"
            }, 
            "bcbe386a9df7:3306": {
                "address": "bcbe386a9df7:3306", 
                "memberRole": "PRIMARY", 
                "mode": "R/W", 
                "readReplicas": {}, 
                "replicationLag": "applier_queue_applied", 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.4.5"
            }
        }, 
        "topologyMode": "Single-Primary"
    }, 
    "groupInformationSourceMember": "bcbe386a9df7:3306"
}

mysql クライアントを使うときには

基本は普通に使えば OK ですが必ず PRIMARY に接続するようにしましょう

  • mysql -u root -h 192.168.1.100 -p --port=33063

InnoDB Cluster の場合マルチマスター構成なのでどのノードもマスタなので書き込みが出来そうなのですが実際はできずにエラーになります

mysql> create database test;
ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement

なので Failover 時にはアプリ側で書き込み先を変更しなければいけないのですがそれを自動で行う MySQL Router という機能があるので次回はそれを組み合わせてみます

最後に

MySQL8.4.5 で InnoDB Cluster を構築してみました
構築自体は非常に簡単で MySQL を3台用意して mysqlsh でクラスタを構築するための API をコールするだけでした
これで MySQL の冗長構成 + 自動 FailOver な環境は構築できました
次回は MySQL Router を組み合わせてみます

参考サイト

2025年7月3日木曜日

MySQL8.4でレプリケーション構成を試してみた

MySQL8.4でレプリケーション構成を試してみた

概要

検証なので docker 上で構築しています
パラメータなどはそのまま使えると思います

8.4 から Master/Slave は Source/Replica となりコマンドを完全に変わっているので注意しましょう

環境

  • Ubuntu 24.04
  • docker 28.2.2
  • MySQL 8.4.5

compose.yaml

基本的には Source/Replica に必要な設定を指定して起動するだけです
mysql-native-password に関しては後述しますが指定不要にもできます

healthcheck はいらないかもです

services:
  mysql-master:
    image: mysql:8.4.5
    container_name: mysql-master
    environment:
      - MYSQL_ROOT_PASSWORD=rootpassword
    command:
      - --mysql-native-password=ON
      - --server-id=1
      - --log-bin=mysql-bin
      - --gtid-mode=ON
      - --enforce-gtid-consistency=ON
    ports:
      - "3306:3306"
    volumes:
      - master_data:/var/lib/mysql
      - ./master-init/:/docker-entrypoint-initdb.d/
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: always

  mysql-slave:
    image: mysql:8.4.5
    container_name: mysql-slave
    depends_on:
      - mysql-master
    environment:
      - MYSQL_ROOT_PASSWORD=rootpassword
    command:
      - --mysql-native-password=ON
      - --server-id=2
      - --log-bin=mysql-bin
      - --gtid-mode=ON
      - --enforce-gtid-consistency=ON
      - --relay-log=relay-log
      - --read-only=ON
    ports:
      - "3307:3306"
    volumes:
      - slave_data:/var/lib/mysql
      - ./slave-init/:/docker-entrypoint-initdb.d/
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: always

volumes:
  master_data:
  slave_data:

./master-init/init-master.sql

公式の MySQL8.4.5 のイメージでは MYSQL_REPLICATION_USERMYSQL_REPLICATION_PASSWORD の環境変数は使えないので初期化スクリプトでレプリケーション用のユーザを作成します

CREATE USER 'replicator'@'%' IDENTIFIED BY 'replicatorpassword';
GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;

./slave-init/init-replica.sql

スレーブ側ではマスターに接続する設定を初期化スクリプトで行います
MASTER_HOST などは使えず SOURCE_HOST になっているので注意しましょう

CHANGE REPLICATION SOURCE TO
  SOURCE_HOST='mysql-master',
  SOURCE_USER='replicator',
  SOURCE_PASSWORD='replicatorpassword',
  SOURCE_AUTO_POSITION=1;
START REPLICA;

動作確認

  • docker compose up -d

であとは Source/Replica の状態を確認します

Source (マスター)

mysql -h 127.0.0.1 -P 3306 -u root -p

mysql>  SHOW BINARY LOG STATUS\G
*************************** 1. row ***************************
             File: mysql-bin.000003
         Position: 198
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set: 705ee183-57b5-11f0-b5ae-2a2407db9148:1-8
1 row in set (0.00 sec)

Replica (スレーブ)

mysql> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: mysql-master
                  Source_User: replicator
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: mysql-bin.000003
          Read_Source_Log_Pos: 198
               Relay_Log_File: relay-log.000004
                Relay_Log_Pos: 415
        Relay_Source_Log_File: mysql-bin.000003
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 198
              Relay_Log_Space: 2985967
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Source_SSL_Allowed: No
           Source_SSL_CA_File:
           Source_SSL_CA_Path:
              Source_SSL_Cert:
            Source_SSL_Cipher:
               Source_SSL_Key:
        Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Source_Server_Id: 1
                  Source_UUID: 705ee183-57b5-11f0-b5ae-2a2407db9148
             Source_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
    Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Source_Retry_Count: 10
                  Source_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Source_SSL_Crl:
           Source_SSL_Crlpath:
           Retrieved_Gtid_Set: 705ee183-57b5-11f0-b5ae-2a2407db9148:1-8
            Executed_Gtid_Set: 705ee183-57b5-11f0-b5ae-2a2407db9148:1-8,
708f9d45-57b5-11f0-b04a-d263a8c2e257:1-5
                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Source_TLS_Version:
       Source_public_key_path:
        Get_Source_public_key: 0
            Network_Namespace:
1 row in set (0.00 sec)

あとはデータベースやテーブルを作成して Replica 側でデータがあることを確認しましょう

mysql_native_password を使わないほうがいい

sha256_password も deprecated なので caching_sha2_password を使いましょう

基本的には起動オプションを変更してレプリケーション用のユーザのパスワードを設定する際に caching_sha2_password を使えば OK です

  • vim compose.yaml
services:
  mysql-master:
    image: mysql:8.4.5
    container_name: mysql-master
    environment:
      - MYSQL_ROOT_PASSWORD=rootpassword
    command:
      - --server-id=1
      - --log-bin=mysql-bin
      - --gtid-mode=ON
      - --enforce-gtid-consistency=ON
    ports:
      - "3306:3306"
    volumes:
      - master_data:/var/lib/mysql
      - ./master-init/:/docker-entrypoint-initdb.d/
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: always

  mysql-slave:
    image: mysql:8.4.5
    container_name: mysql-slave
    depends_on:
      - mysql-master
    environment:
      - MYSQL_ROOT_PASSWORD=rootpassword
    command:
      - --server-id=2
      - --log-bin=mysql-bin
      - --gtid-mode=ON
      - --enforce-gtid-consistency=ON
      - --relay-log=relay-log
      - --read-only=ON
    ports:
      - "3307:3306"
    volumes:
      - slave_data:/var/lib/mysql
      - ./slave-init/:/docker-entrypoint-initdb.d/
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: always

volumes:
  master_data:
  slave_data:
  • vim ./master-init/init-master.sql
CREATE USER 'replicator'@'%'
IDENTIFIED WITH caching_sha2_password BY 'replicatorpassword';
GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;

最後に

MySQL8.4.5 で Source/Replica 構成を構築してみました
構築自体は非常に簡単にできます
MySQL8.4.5で非推奨になっていたり使えないコマンドが増えているのでそこは注意しましょう

参考サイト

2025年5月11日日曜日

OpenWebUI で mcp-server-mysql を使って自然言語で MySQL を操作してみる

OpenWebUI で mcp-server-mysql を使って自然言語で MySQL を操作してみる

概要

前回 open-webui から mcp サーバに接続する方法法を紹介しました
今回は localhost にある mysql サーバに接続しいろいろな操作を試してみます
なお INSERT,UPDATE,DELETE も行える設定なのでテスト用のテーブルなどに対して行いましょう

環境

  • Ubuntu 24.04
  • OpenWebUI 0.6.7
  • LiteLLM Proxy 1.68.1
  • Python 3.12.9
    • mcpo 0.0.13
    • mcp 1.8.0
  • @benborla29/mcp-server-mysql - v0.1.18

nodejs 環境準備

mcp-server-mysql は nodejs で動作するので nodejs が動作する環境を準備します
何でも OK ですが今回は nvm を使う方法を紹介します

  • nvm use --save 20.19.0

ここで保存された .nvmrc があるパスで MCPO を動かします

config.json

mcpServers に追記します
今回は INSERT,UPDATE,DELETE も試したいので ALLOW_INSERT_OPERATION などは true に設定しています

{
  "mcpServers": {
    "time": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "mcp/time"]
    },
    "mcp_server_mysql": {
      "command": "npx",
      "args": [
        "-y",
        "@benborla29/mcp-server-mysql"
      ],
      "env": {
        "MYSQL_HOST": "127.0.0.1",
        "MYSQL_PORT": "3306",
        "MYSQL_USER": "test",
        "MYSQL_PASS": "xxx",
        "MYSQL_DB": "devops",
        "ALLOW_INSERT_OPERATION": "true",
        "ALLOW_UPDATE_OPERATION": "true",
        "ALLOW_DELETE_OPERATION": "true"
      }
    }
  }
}

localhost で mysql -u test-p devops -h 127.0.0.1 でアクセスできれば上記でもアクセスできます

MCPO 起動

先ほど作成した .nvmrc と config.json があるパスで実行します

  • pipenv run mcpo --port 8000 --host 0.0.0.0 --config ./config.json --api-key "top-secret"

MCP サーバの接続

open-webui から行います
uri の部分は config.json に定義した MCP サーバのキー情報を入力します
Bearer は api_key で指定した情報をしていします   接続テストもしておきましょう

動作確認

チャット上のツールが増えていることを確認します
あとはテーブル情報などを含めて質問することでいろいろな操作をしてくれます

MCPO のログを見ると実際に投げている SQL の情報なども確認できます

最後に

open-webui + mcp-server-mysql を試してみました
自然言語でデータベースを操作できる時代が本格的に到来したなと実感しました
以下は試してみた感想です
本番ではまだ使わないほうが安全かなと思います

命令を詳細にすれば実用レベルになる気はします

  • 雑なSQLを投げたりするので本番では更新削除追加系はやらないほうがよさそう
    • WHERE 句 id などのユニークキーを使わずに更新や削除を行ったりする
    • 命令をしっかりすれば id を使ってやってはくれそうだが雑な質問だとやらない
  • コンテキストがおかしくなる場合があるのでSQLを投げたい場合は新規のチャットを作成したほうがいい
  • 外部キー制約などがある場合はそれも伝えるとやってくれる
    • 「先にAテーブルの外部キーを削除してからBテーブルのレコードも削除して」など
  • データをINSERTするときは各カラムの情報を正確に伝えないとやってくれない
    • テーブルの各カラムに制約がある場合などはちゃんと伝えなければダメそう
    • 適当な値でお願いしますと命令もできるがその場合はテーブルのスキーマ情報から適当な数値や文字列を入れようとはする

参考サイト

2024年9月4日水曜日

Windows11 に Wordpress をインストールする

Windows11 に Wordpress をインストールする

概要

Windows11 上に wsl なしで wordpress を構築する流れを紹介します

環境

  • Windows11
  • Wordpress 6.6.1

1. PHP のインストール

こちら

2. nginx のインストール

こちら

3. MySQL のインストール

これはインストーラがあるのでインストーラを使うと簡単です
ここでアーキテクチャなどを指定してインストーラをダウンロードします

基本は指示に従えば OK です
Workspace などは自由にインストールしてください
最低限コマンドラインインタフェースがあればいいかなと思います

3.1 wordpress 用データベースの作成

作成しましょう
名前は何でも OK です
専用のユーザを作ってもいいですがこの記事では localhost でしか使わないので root ユーザで進めます

なおデータベース名は「wordpress」として進めます

4 Wordpress のダウンロード

ここからダウンロードします
執筆時点では wordpress-6.6.1-ja.zip でした

ダウンロードした wordpress を展開し C:\nginx\html\wordpress に配置します

4.1 wp-config.php の編集

C:\nginx\html\wordpress\wp-config-sample.php があるのでこれを wp-config.php にリネームなりコピーして作成します

そして接続先データベースの設定を行います
以下はデータベースの設定部分のみ抜粋しているので設定ファイル内の該当部分を探して設定してください

  • vim wp-config.php
define( 'DB_NAME', 'wordpress' ); 
define( 'DB_USER', 'root' ); 
define( 'DB_PASSWORD', 'xxxxxxxx' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8mb4' );

動作確認

nginx と cgi サーバを起動します
コマンドプロンプトで以下を実行します

cd c:\nginx
start nginx
cd c:\php
start php-cgi -b 127.0.0.1:9000

これで localhost/wordpress/wp-admin にアクセスすると wordpress の初期設定画面にアクセスできるので設定を進めれば OK です

最後に

wordpress にインストーラはないので nginx 配下に配置することで動作します
最低限必要なコンポーネント (php, nginx, mysql) がいくつかあるのでそれらのインストールと設定もしっかりしましょう

今回の手順ではすべてのコンポーネントを Windows11 上にインストールしましたが面倒であれば WSL2 + docker で簡単に構築できるのでその方法でも OK です

2024年6月17日月曜日

Cloudbeaver を nginx で動作させる方法

Cloudbeaver を nginx で動作させる方法

概要

rootURI を編集します
設定ファイルを置くパスがポイントです

環境

  • Ubuntu 22.04
  • docker 26.1.1
  • dbeaver 24.1.0
  • MySQL 8.0.36

dbeaver 用 compose.yaml

/opt/cloudbeaver/conf/cloudbeaver.conf に設定ファイルを配置します
dbeaver は 192.168.0.100:8978 で動作します

services:
  dbeaver:
    image: dbeaver/cloudbeaver:24.1.0
    volumes:
      - type: volume
        source: dbeaver
        target: /opt/cloudbeaver/workspace
      - type: bind
        source: /home/user01/work/cloudbeaver.conf
        target: /opt/cloudbeaver/conf/cloudbeaver.conf
    ports:
      - 8978:8978
    restart: always

volumes:
  dbeaver:

cloudbeaver.conf

少し長いですがすべて掲載しています
変更するのは冒頭の rootURI の部分だけです
それ以外はすべてデフォルトの設定です

今回は /dbeaver で受けます

{
    server: {
        serverPort: 8978,

        workspaceLocation: "workspace",
        contentRoot: "web",
        driversLocation: "drivers",

        sslConfigurationPath:"${CLOUDBEAVER_SSL_CONF_PATH:workspace/.data/ssl-config.xml}",

        rootURI: "/dbeaver",
        serviceURI: "/api/",

        productSettings: {
            # Global properties
            core.theming.theme: 'light',
            core.localization.localization: 'en',
            plugin.sql-editor.autoSave: true,
            plugin.sql-editor.disabled: false,
            # max size of the file that can be uploaded to the editor (in kilobytes)
            plugin.sql-editor.maxFileSize: 10240,
            plugin.log-viewer.disabled: false,
            plugin.log-viewer.logBatchSize: 1000,
            plugin.log-viewer.maxFailedRequests: 3,
            plugin.log-viewer.maxLogRecords: 2000,
            plugin.log-viewer.refreshTimeout: 3000,
            sql.proposals.insert.table.alias: PLAIN
        },

        expireSessionAfterPeriod: 1800000,

        develMode: false,

        enableSecurityManager: false,

        sm: {
            enableBruteForceProtection: "${CLOUDBEAVER_BRUTE_FORCE_PROTECTION_ENABLED:true}",
            maxFailedLogin: "${CLOUDBEAVER_MAX_FAILED_LOGINS:10}",
            minimumLoginTimeout: "${CLOUDBEAVER_MINIMUM_LOGIN_TIMEOUT:1}",
            blockLoginPeriod: "${CLOUDBEAVER_BLOCK_PERIOD:300}",
            passwordPolicy: {
                minLength: "${CLOUDBEAVER_POLICY_MIN_LENGTH:8}",
                requireMixedCase: "${CLOUDBEAVER_POLICY_REQUIRE_MIXED_CASE:true}",
                minNumberCount: "${CLOUDBEAVER_POLICY_MIN_NUMBER_COUNT:1}",
                minSymbolCount: "${CLOUDBEAVER_POLICY_MIN_SYMBOL_COUNT:0}"
            }
        },

        database: {
            driver: "h2_embedded_v2",
            url: "jdbc:h2:${workspace}/.data/cb.h2v2.dat",
            initialDataConfiguration: "conf/initial-data.conf",
            pool: {
                minIdleConnections: 4,
                maxIdleConnections: 10,
                maxConnections: 100,
                validationQuery: "SELECT 1"
            },
            backupEnabled: "${CLOUDBEAVER_DB_BACKUP_ENABLED:true}"
        }

    },
    app: {
        anonymousAccessEnabled: true,
        anonymousUserRole: "user",
        defaultUserTeam: "user",
        grantConnectionsAccessToAnonymousTeam: false,
        supportsCustomConnections: false,
        showReadOnlyConnectionInfo: false,
        systemVariablesResolvingEnabled: "${CLOUDBEAVER_SYSTEM_VARIABLES_RESOLVING_ENABLED:false}",

        forwardProxy: false,

        publicCredentialsSaveEnabled: true,
        adminCredentialsSaveEnabled: true,

        resourceManagerEnabled: true,

        resourceQuotas: {
            dataExportFileSizeLimit: 10000000,
            resourceManagerFileSizeLimit: 500000,
            sqlMaxRunningQueries: 100,
            sqlResultSetRowsLimit: 100000,
            sqlResultSetMemoryLimit: 2000000,
            sqlTextPreviewMaxLength: 4096,
            sqlBinaryPreviewMaxLength: 261120
        },
        enabledAuthProviders: [
            "local"
        ],

        disabledDrivers: [
            "sqlite:sqlite_jdbc",
            "h2:h2_embedded",
            "h2:h2_embedded_v2",
            "clickhouse:yandex_clickhouse"
        ],
        disabledBetaFeatures: [

        ]

    }

}

nginx.conf

location /dbeaver/ を定義します
proxy_set_header 系はそのままコピペで OK です

location = /dbeaver はリダイレクト用でなぜか自動でブラウザがリダイレクトしてくれないケースがあるので明示しておきます
末尾のスラッシュがない場合にスラッシュのある URI に移動させます

upstream dbeaver {
    server 192.168.0.100:8978;
}


server {
    listen 80;
    server_name my_nginx;

    location = /dbeaver {
        return 302 /dbeaver/;
    }

    location /dbeaver/ {
        proxy_pass http://dbeaver;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

動作確認

これで nginx と dbeaver を起動させ nginxのアドレス/dbeaver にアクセスすると画面が表示されます

最後に

DBeaver を nginx 配下で動作させる方法を紹介しました
サブディレクトリを指定する場合は dbeaver 側の rootURI も変更する必要があります

参考サイト

2024年6月14日金曜日

DBeaver でセッションタイムアウトを設定する方法

DBeaver でセッションタイムアウトを設定する方法

概要

cbadmin のセッションが切れる時間を伸ばす方法を紹介します

環境

  • Ubuntu 22.04
  • docker 26.1.1
  • dbeaver 24.1.0
  • MySQL 8.0.36

設定方法

  • 右上歯車 -> Administration -> Server configuration -> Session lifetime

単位は分です

この設定が /opt/cloudbeaver/workspace/.data/.cloudbeaver.runtime.con あたりにないのでどこに保存されているのか不明です

2024年6月5日水曜日

Dbeaver を docker で動かして MySQL に接続してみる

Dbeaver を docker で動かして MySQL に接続してみる

概要

dbeaver はいろいろなデータベースに対応したクライアントツールでテーブルの一覧や好きな SQL を発行することができます
phpMyAdmin の代替として使えます

基本はマシン上で動作するクライアントアプリですが今回は docker 上で動かしてみました

環境

  • Ubuntu 22.04
  • docker 26.1.1
  • dbeaver 24.1.0
  • MySQL 8.0.36

起動

以下のコマンド一発です
起動すると 8080 ポートで起動します
エンタープライズエディションもありますがアクティベーションキーが必要になるのでコミュニティエディションを使います

  • docker run --name cloudbeaver-ee --rm -ti -p 8080:8978 -v $(pwd):/opt/cloudbeaver/workspace dbeaver/cloudbeaver:latest

cbadmin ユーザのパスワードを設定

起動するとまず初期設定をします
必ず設定しなければいけないのは管理者のパスワードです
パスワードにはポリシーがあるのでそれに沿ったパスワードにしましょう

MySQL のコネクタを作成する

管理者のパスワードを設定すると次にコネクションテンプレートというテンプレートを作成する画面になりますがそこはスルーして一度トップ画面に戻ります
そして上部のプラスボタンからコネクションを作成します

テンプレートを作成しない理由としては本当はテンプレートからコネクションを作成できるボタンがあるのですがコミュニティエディションだとそれがなかったのでテンプレートを作成する意味がないからです

いろいろなデータベースコネクタがあるので MySQL を選択します

データベースの情報を入力する

次に接続先のデータベースの情報を入力します
今回は docker 上で動作させているので localhost だとコンテナにアクセスしに行ってしまうので基本は IP や FQDN を入力することになります

IP で接続できない場合は

MySQL はデフォルトだと localhost からのみアクセスできるようになっています
今回は docker 上のコンテナの IP (ex 172.17.0.2) からのアクセスになるのでその IP からのアクセスを許可します

こちらを参考に特定の IP からでもアクセスできるユーザを作成します

Public Key Retrieval is not allowed

接続テストをした際に「Public Key Retrieval is not allowed」エラーが出る場合にはドライバの設定を変更します

DRIVER PROPERTIES タブを選択し「allowPublicKeyRetrieval」を TRUE に設定します

これで再度右上の「Test」をクリックして接続テストしてください

動作確認

コネクションが作成できたらデータベースやテーブルの一覧が表示できることを確認しましょう

よくわからないのですがコネクション作成時にデータベースを指定してもすべてのデータベース情報を取得するようです

最後に

Dbeaver を docker で動かしてみました
コミュニティエディションなので一部機能が使えなかったりするようです
閲覧するだけならこれで十分かなと思います
またダークモードや好きな SQL を発行する機能もあるので便利です

MySQL の Web クライアントで phpMyAdmin の代替になりそうなツールとして他にも ILLA Builder というツールを紹介しています

Dbeaver 自体は Java で書かれています

参考サイト