動かざることバグの如し

近づきたいよ 君の理想に

UbuntuでMariaDBを複数起動させる方法(systemd編)

環境

やりたいこと

1つのサーバーで複数のMariaDBを起動させたい。とはいえ全部のポートが3306だとコンフリクトしてしまうので

  • ポート番号
  • データ格納場所
  • プロセスファイル、ソケットファイル
  • ログパス

は別々にしたい

調べてみると色々記事は出てくるが、systemdを使用していない古い記事、mysqld_multiに依存している記事、CentOSとかArchLinuxとか仕様が違う記事等あって

Ubuntuかつモダンなsystemd版の記事がなかったのでメモ

MariaDBのインストール

ここではMariaDB公式のレポジトリを追加してインストールする

apt-get install apt-transport-https curl
curl -o /etc/apt/trusted.gpg.d/mariadb_release_signing_key.asc 'https://mariadb.org/mariadb_release_signing_key.asc'

cat > /etc/apt/sources.list.d/mariadb.list <<EOF
deb https://ftp.yz.yamagata-u.ac.jp/pub/dbms/mariadb/repo/10.8/ubuntu focal main
EOF
apt install -y mariadb-server

複数起動させる方法

実は複数起動させる方法は公式ドキュメントに記載されている。

Running Multiple MariaDB Server Processes - MariaDB Knowledge Base

が、残念なことにこの記事だけだとsystemdの説明が足りなさすぎて何もできない。実際に細かく書かれているのはsystemdの記事だったりする。下記

systemd - MariaDB Knowledge Base

Ubuntuの場合、 /lib/systemd/system/mariadb@.service に必要な設定ファイルが記載されている

こんな感じで%Iが変数化されており動的に入れることが出来る。

[Unit]
Description=MariaDB 10.8.3 database server (multi-instance %I)
Documentation=man:mariadbd(8)
Documentation=https://mariadb.com/kb/en/library/systemd/
After=network.target

Environment の設定で書かれているが、環境変数 MYSQLD_MULTI_INSTANCE--defaults-group-suffix= パラメータを追加するのが大事

これは別に自分が設定しなくてもsystemd側で動的に設定してくれる。 %I ってのがミソ

# Controlling how multiple instances are separated. See top of this file.
# Note: This service isn't User=mysql by default so we need to be explicit.
# It is as an option here as a user may want to use the MYSQLD_MULTI_INSTANCE
# to run multiple versions.
Environment='MYSQLD_MULTI_INSTANCE=--defaults-group-suffix=.%I'

後ポイントの設定は ConditionPathExists

## See Environment=MYSQLD_MULTI_INSTANCE below for current recommended options.
ConditionPathExists=!/etc/mysql/mariadb.conf.d/my%I.cnf

これ、自分も最初ミスリードしてしまったがsystemdのドキュメントいわく

ConditionPathExists
If the absolute path name passed to ConditionPathExists= is prefixed with an exclamation mark ("!"), the test is negated, and the unit is only started if the path does not exist.

とあり、今回みたいに!があると /etc/mysql/mariadb.conf.d/my%I.cnf の設定があると起動しない コメント見る感じ下位互換性のための設定らしい

手順

10000、20000ポート2つのサーバーを起動しようとする例

データ格納用のディレクトリを作成する

mkdir /var/lib/mysql_{10000,20000}
chown mysql: /var/lib/mysql_{10000,20000}
mysql_install_db --datadir=/var/lib/mysql_10000 --user=mysql
mysql_install_db --datadir=/var/lib/mysql_20000 --user=mysql

MariaDBだとデフォルトだと /etc/mysql/mariadb.conf.d/50-server.cnf がサーバーの設定ファイル

以下のように追記する。 defaults-group-suffix=.%I%Iがmysqld.10000の「10000」に該当するのを注意

何故か公式で「.」がついているので mysqld10000 で動かないので注意

[mysqld.10000]
port       = 10000
datadir    = /var/lib/mysql_10000
socket     = /run/mysqld/mysqld1.sock
pid-file   = /run/mysqld/mysqld1.pid
log-error  = /var/log/mysql/error1.log

[mysqld.20000]
port       = 20000
datadir    = /var/lib/mysql_20000
socket     = /run/mysqld/mysqld2.sock
pid-file   = /run/mysqld/mysqld2.pid
log-error  = /var/log/mysql/error2.log

いざ起動

systemctl restart mariadb@10000
systemctl restart mariadb@20000

ps aux| grep mysql で確認

mysql       2544  0.0  5.0 1344868 102304 ?      Ssl  18:07   0:00 /usr/sbin/mariadbd
mysql       4636  0.8  4.8 1352680 98544 ?       Ssl  18:19   0:00 /usr/sbin/mariadbd --defaults-group-suffix=.10000
mysql       4681  1.6  4.8 1278948 98320 ?       Ssl  18:19   0:00 /usr/sbin/mariadbd --defaults-group-suffix=.20000

デフォルトだとソケットログインが出来る

root@vagrant:/etc/mysql/mariadb.conf.d# mysql -S /run/mysqld/mysqld1.sock
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 10.8.3-MariaDB-1:10.8.3+maria~focal mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

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

MariaDB [(none)]>

mysql_secure_installation でMySQLの初期設定が出来るが、デフォルトだとポート3306を参照してしまう。ポート番号を指定することが何故かできないのでソケットファイルを指定する。

export MYSQL_UNIX_PORT=/run/mysqld/mysqld1.sock

これで初期設定が出来る

mysql_secure_installation

参考リンク

KubernetesにMariaDBをマスタースレーブ構成でデプロイする

環境

やること

MySQLサーバーをKubernetesで構築しようと思ったとき、練習用なら自分でYAML書いてデプロイ出来るが、永続化とかレプリケーションまで考えるとちょっと面倒すぎる。

そもそもKubernetesMySQLのデプロイが向いているのかはさておき、とりあえずbitnami製のhelmレポを使うと簡単にMySQLをデプロイ出来るのでメモ

まあMySQLといいつつ今回はMariaDBだが

とりあえず立ててみる

まずはスレーブとか無しの単体運用のデプロイ

レポジトリの追加

helm repo add bitnami https://charts.bitnami.com/bitnami

以下のようなYAML作成 storageClassは適宜変更して

architecture: standalone
storageClass: nfs-test
auth:
  rootPassword: password
image:
  debug: true
primary:
  service:
    type: LoadBalancer
  extraEnvVars:
    - name: TZ
      value: "Asia/Tokyo"
  persistence:
    storageClass: nfs-test

いざインストール --create-namespaceつけると自動でNamespaceも作成してくれる「dev-mysql」は名前

helm install dev-mysql bitnami/mariadb --namespace mysql --create-namespace -f bitnami.yaml

設定したパスワードを再確認する方法

kubectl get secret --namespace mysql dev-mysql -o jsonpath="{.data.mysql-root-password}" | base64 -d

MySQLサーバーへログイン 一発

mysql -h dev-mysql.mysql.svc.cluster.local -uroot -p
Enter password:
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 840
Server version: 10.6.8-MariaDB-log Source distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

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

MariaDB [(none)]>

設定変更した場合

helm upgrade dev-mysql bitnami/mysql --namespace mysql -f bitnami.yaml

削除

helm delete dev-mysql --namespace mysql
kubectl delete ns mysql

マスタースレーブ構成を試す

architecture: replication にするとマスタースレーブ構成を作成できる

architecture: replication
storageClass: nfs-test
image:
  debug: true
primary:
  persistence:
    storageClass: nfs-test
secondary:
  replicaCount: 2
  persistence:
    storageClass: nfs-test

合計3台のMariaDBのサーバーが作成される。

$ kubectl get -n mysql pod -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP             NODE       NOMINATED NODE   READINESS GATES
oyakodon-mariadb-primary-0     1/1     Running   0          74m   10.189.79.21   ubuntu02   <none>           <none>
oyakodon-mariadb-secondary-0   1/1     Running   0          74m   10.189.79.22   ubuntu02   <none>           <none>
oyakodon-mariadb-secondary-1   1/1     Running   0          71m   10.189.3.203   ubuntu01   <none>           <none>

スレーブの設定も自動でやってくれる 神

MariaDB [(none)]> show slave status\G;
*************************** 1. row ***************************
                Slave_IO_State: Waiting for master to send event
                   Master_Host: oyakodon-mariadb-primary
                   Master_User: replicator
                   Master_Port: 3306
                 Connect_Retry: 10
               Master_Log_File: mysql-bin.000002
           Read_Master_Log_Pos: 471
                Relay_Log_File: mysql-relay-bin.000004
                 Relay_Log_Pos: 770
         Relay_Master_Log_File: mysql-bin.000002
              Slave_IO_Running: Yes
             Slave_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_Master_Log_Pos: 471
               Relay_Log_Space: 2885
               Until_Condition: None
                Until_Log_File:
                 Until_Log_Pos: 0
            Master_SSL_Allowed: No
            Master_SSL_CA_File:
            Master_SSL_CA_Path:
               Master_SSL_Cert:
             Master_SSL_Cipher:
                Master_SSL_Key:
         Seconds_Behind_Master: 0
 Master_SSL_Verify_Server_Cert: No
                 Last_IO_Errno: 0
                 Last_IO_Error:
                Last_SQL_Errno: 0
                Last_SQL_Error:
   Replicate_Ignore_Server_Ids:
              Master_Server_Id: 848
                Master_SSL_Crl:
            Master_SSL_Crlpath:
                    Using_Gtid: No
                   Gtid_IO_Pos:
       Replicate_Do_Domain_Ids:
   Replicate_Ignore_Domain_Ids:
                 Parallel_Mode: optimistic
                     SQL_Delay: 0
           SQL_Remaining_Delay: NULL
       Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
              Slave_DDL_Groups: 8
Slave_Non_Transactional_Groups: 2
    Slave_Transactional_Groups: 0
1 row in set (0.000 sec)

細かいパラメータは 公式ドキュメント 参照

CalicoのIP範囲設定を変更する

環境

PodのIP範囲変えるの面倒くさい説

PodのIP範囲とはいわゆる --cluster-cidr を指す。PodのIPが足りなくなってきたので急遽既存のクラスタcluster-cidrを変更することにした。

変更自体はマスターノードの /etc/kubernetes/manifests/kube-controller-manager.yaml の起動オプションを変更すればOKだが、Calicoで運用している場合、それだけでは不十分。

Calico側にもIP範囲の設定があるので、それを変更しなければならない。

手順

例えば変更前が「192.168.100.0/24」で変更後が「10.189.0.0/16」だったとする。

既存の cluster-cidr の値は以下のコマンドで確認できる。

kubectl cluster-info dump | grep -m 1 cluster-cidr
                            "--cluster-cidr=10.189.0.0/16",

先にcalicoctlコマンドが使えるようにしておく。公式ドキュメントからインストールできる

確認 古CIDRのママである

$ calicoctl get ippool -o wide
NAME                  CIDR            NAT    IPIPMODE   VXLANMODE   DISABLED   DISABLEBGPEXPORT   SELECTOR   
default-ipv4-ippool   192.168.100.0/24   true   Always     Never       false      false              all()      

以下のようにYAMLを適用する。「new-pool」の名前は任意、「10.189.0.0/16」は変更後のCIDR

calicoctl create -f -<<EOF
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: new-pool
spec:
  cidr: 10.189.0.0/16
  ipipMode: Always
  natOutgoing: true
EOF

増えているのを確認

calicoctl get ippool -o wide

NAME                  CIDR             NAT    IPIPMODE   DISABLED   SELECTOR
default-ipv4-ippool   192.168.100.0/24   true   Always     false      all()
new-pool              10.189.0.0/16    true   Always     false      all()

だが、このままだと古いCIDRがそのままなので最終的には消したい。が、まだPodは古いCIDRを使っているので移行する必要がある。

まずは古いCIDRにこれ以上行かないように無効化する

YAMLを出力

calicoctl get ippool -o yaml > pool.yaml

古い方のCIDRに disabled: true を追記

apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: default-ipv4-ippool
spec:
  cidr: 192.168.100.0/24
  ipipMode: Always
  natOutgoing: true
+  disabled: true

適用

calicoctl apply -f pool.yaml

確認

calicoctl get ippool -o wide

NAME                  CIDR             NAT    IPIPMODE   DISABLED   SELECTOR
default-ipv4-ippool   192.168.100.0/24   true   Always     true      all()
new-pool              10.189.0.0/16    true   Always     false      all()

あとは全podを再起動させる必要がある。

全部PodのIPを乗せ替え終わったら以下のコマンドで削除

calicoctl delete pool default-ipv4-ippool

参考リンク

DockerのPHPは結局どのphp.ini使えばいいんだ問題

環境

どのphp.ini使えばいいんだ問題

DockerのPHPでは/usr/local/etc/php/php.iniがルートのphp.iniになっている

root@e2459ffbe39f:/var/www/html# php -i|grep php.ini
Configuration File (php.ini) Path => /usr/local/etc/php

が、肝心の/usr/local/etc/php/php.iniはデフォルトではいない。その代わり、php.ini-developmentとphp.ini-productionが別途同じディレクトリにいる

root@e2459ffbe39f:/usr/local/etc/php# ls -l
total 148
drwxr-xr-x 1 root root  4096 Jul 12 09:22 conf.d
-rw-r--r-- 1 root root 72554 Jul 12 09:22 php.ini-development
-rw-r--r-- 1 root root 72584 Jul 12 09:22 php.ini-production

ってことは自分でイメージ作るときは適宜開発用と本番用でphp.iniをコピってくれってことなのか。

とりあえず違いをdiffコマンドで確認してみる

php.ini-developmentとphp.ini-productionの違い

root@a9133efa6266:/usr/local/etc/php# diff -u php.ini-development php.ini-production
 ;;;;;;;;;;;;;;;;;;;
 ; Quick Reference ;
@@ -365,7 +365,7 @@
 ; In production, it is recommended to turn this setting on to prohibit the output 
 ; of sensitive information in stack traces
 ; Default: Off
-zend.exception_ignore_args = Off
+zend.exception_ignore_args = On
 
 ;;;;;;;;;;;;;;;;;
 ; Miscellaneous ;
@@ -462,7 +462,7 @@
 ; Development Value: E_ALL
 ; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT
 ; http://php.net/error-reporting
-error_reporting = E_ALL
+error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
 
 ; This directive controls whether or not and where PHP will output errors,
 ; notices and warnings too. Error output is very useful during development, but
@@ -479,7 +479,7 @@
 ; Development Value: On
 ; Production Value: Off
 ; http://php.net/display-errors
-display_errors = On
+display_errors = Off
 
 ; The display of errors which occur during PHP's startup sequence are handled
 ; separately from display_errors. PHP's default behavior is to suppress those
@@ -490,7 +490,7 @@
 ; Development Value: On
 ; Production Value: Off
 ; http://php.net/display-startup-errors
-display_startup_errors = On
+display_startup_errors = Off
 
 ; Besides displaying errors, PHP can also log errors to locations such as a
 ; server-specific log, STDERR, or a location specified by the error_log
@@ -1190,7 +1190,7 @@
 
 ; Enable / Disable collection of memory usage statistics by mysqlnd which can be
 ; used to tune and monitor MySQL operations.
-mysqlnd.collect_memory_statistics = On
+mysqlnd.collect_memory_statistics = Off
 
 ; Records communication from all extensions using mysqlnd to the specified log
 ; file.
@@ -1563,7 +1563,7 @@
 ; Development Value: 1
 ; Production Value: -1
 ; http://php.net/zend.assertions
-zend.assertions = 1
+zend.assertions = -1
 
 ; Assert(expr); active by default.
 ; http://php.net/assert.active
@@ -1883,7 +1883,7 @@
 
 ; Enables or disables copying of PHP code (text segment) into HUGE PAGES.
 ; This should improve performance, but requires appropriate OS configuration.
-;opcache.huge_code_pages=0
+;opcache.huge_code_pages=1
 
 ; Validate cached file permissions.
 ;opcache.validate_permission=0

エラーを画面に出さないとか、メトリクス取らないとかの値が違っている。違いの表が以下

dev production
zend.exception_ignore_args off on
error_reporting E_ALL E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors On Off
display_startup_errors On Off
mysqlnd.collect_memory_statistics On Off
zend.assertions 1 -1
opcache.huge_code_pages 0 1

当然本番ではphp.ini-productionをphp.iniにコピーして使ったほうがいいのがわかった。

デフォルトとphp.ini-developmentと違い

デフォルトではphp.iniがないが、php.ini-developmentをphp.iniにリネームして使ったときと同じになるのかというと「ならない」検証方法はphp -iの結果をdiffで比較。

実は微妙に差があるので比較表が以下 display_startup_errorsの値とか結構重要なのも変わっている。

なし dev
display_startup_errors Off On
enable_dl On Off
error_reporting no Value 32767
log_errors Off On
request_order no Value GP
short_open_tag On Off
variables_order EGPCS GPCS
Collecting memory statistics No Yes
session.cookie_httponly 0 No value
session.gc_divisor 100 1000
session.sid_bits_per_character 4 5
session.sid_length 32 26

これを見る限り、デフォルトのままPHPのイメージを使用するのは微妙で、明示的にphp.ini-developmentをphp.iniにコピーして使ったほうがよさそう

生のdiffが以下

-display_startup_errors => Off => Off
+display_startup_errors => On => On

-enable_dl => On => On
+enable_dl => Off => Off

-error_reporting => no value => no value
+error_reporting => 32767 => 32767

-log_errors => Off => Off
+log_errors => On => On

-request_order => no value => no value
+request_order => GP => GP

-short_open_tag => On => On
+short_open_tag => Off => Off

-variables_order => EGPCS => EGPCS
+variables_order => GPCS => GPCS

-Collecting memory statistics => No
+Collecting memory statistics => Yes

-session.cookie_httponly => 0 => 0
+session.cookie_httponly => no value => no value

-session.gc_divisor => 100 => 100
+session.gc_divisor => 1000 => 1000


-session.sid_bits_per_character => 4 => 4
-session.sid_length => 32 => 32
+session.sid_bits_per_character => 5 => 5
+session.sid_length => 26 => 26

UbuntuからReadyNASのホームディレクトリをNFSマウントできない問題

環境

問題

自宅のNASではネットギアのReadyNASを使用している。特に不満はないんだが、気づいたらネットギア自体がコンシューマ向けNAS事業から撤退したので購入後しばらくしたら廃盤になってた(

まあそれはいいとして、NASLinuxでアクセスしたいので、NFSを有効化したい。以前はSambaプロトコルでお茶を濁したが、Kubernetes経由ともなればNFSが必須

thr3a.hatenablog.com

いざLinuxサーバーから試しにマウント NFSのバージョンはv4ではなくv3にした

mount -t nfs 192.168.16.xxx:/data/home/admin /mnt/nas -o vers=3

が、何回やってもホームディレクトリのマウントが「Access Denied」エラーでできない。

調査

NAS自体にSSH機能があるので有効化して ssh root@192.168.16.xxx でアクセス(パスワード認証しかできなかった。パスワードはadmin権限の初期ユーザーのパスワード)すると

Jul 24 11:57:03 mynas rpc.mountd[2775]: refused mount request from 192.168.16.xxx for /data/home/xxx (/): not exported

なるほど、アクセス拒否と。。。で/etc/exportsを見てみると

root@mynas:~# cat /etc/exports
"/home" *(insecure,insecure_locks,root_squash,anonuid=99,anongid=99,no_subtree_check,rw,sync)

一見/homeが書かれているので問題なさそうだが マウント元は /dataから始まっている。

これはReadyNASでX-RAIDが有効になっている場合は/dataがスタート地点になっているためである。

mount -t nfs (NASIPアドレス):/(NASのボリューム名)/(NASの共有名) (Linux側のマウント用ディレクトリ名)
X-RAID を使用されている場合、ボリューム名は "data" となります。
mount␣–t␣nfs␣192.168.10.1:/data/share1␣/mnt

引用元: ReadyNAS(OS6)の共有をLinuxにてnfsマウントするコマンドが判りません。 | ネットギア【NETGEAR】

つまり、/data自体が許可されていないからマウントできないと。これバグやんけ

解決方法

/etc/exportsに /dataから始まるユーザーのディレクトリパスを追加した

"/home" *(insecure,insecure_locks,root_squash,anonuid=99,anongid=99,no_subtree_check,rw,sync)
+"/data/home/xxx" *(insecure,insecure_locks,root_squash,anonuid=99,anongid=99,no_subtree_check,rw,sync)

反映 これでマウントできるようになった

exportfs -ra