新着記事

Viewing posts for the category linux

そうだ、mysql8.0サーバーを構築してみよう

ども、お久しぶりです。

オンプレのインフラ構築を担当することが多い四斗邊です。

今回は社内の要望でmysql8.0サーバーを社内ネットワーク上に構築する!というのが目標です。

結構ありふれたネタだと思いますが、社内に向けた手順書のような形で残しておきたかったので今回記事しました。

PC構成


  • CPU intel i5-12400 6コア12スレッド 2.5GHz

  • メモリー CT2K32G4SFD832A メモリー32GB 1枚(レイテンシーは特に考えていない)

  • ベアボーンキット DeskMini B660

  • SSD WDS100T3X0E 1TB

これで10万円を切った構成になっています。
安くてそれなりに社内サーバーとしてはそこそこパワーがある構成にしてみました。
一番の特徴はなによりもベアボーンキットなのでコンパクトなのがいい。
個人的にはCPUはAMD派ですが、2022年8月上旬ではintelが安くてちょうどいいかんじでした。
家庭用なので消耗とか気になりますが、4年ぐらいは耐えてくれてると信じたい。

OSソフトウェア構成


OS ubuntu 22.04
DB mysql8.0.30

ubuntu以外も候補はありますが、構築経験があるのでこちらかなと。

mysqlインストール手順


*注意事項
手順の前にsshとかOS周りの設定は一通りしております。今回の手順はmysqlインストールに特化したものとご了承ください。

mysql-serverのインストール

$sudo apt install mysql-server

mysqlにログインする。

$sudo mysql
#ユーザー確認
mysql >select user,host from mysql.user;

インストールしているときに、すでにrootユーザーは作られているので、以下のコマンドでパスワードを改変する。hogeの部分は任意なパスワードに変える。

mysql > USE mysql; 
mysql >ALTER USER 'root'@'localhost' identified BY 'hoge';
一応権限の確認は以下で確認できる
mysql > show grants for 'root'@'localhost';

後々構築した後に気づいた点で、localhostになっているので、リモート時にはrootユーザーに入れないことがあった。

やっぱりここはrootユーザーのhost=%を作るに限る。(セキュアな面ではもうちょっとhost部分は制限したほうがいいかも)

mysql > CREATE USER 'root'@'%' IDENTIFIED BY 'hoge';
mysql > GRANT ALL ON *.* TO 'root'@'%';

これでリモート上でもrootで入れる。

文字のエンコードはutf-8に設定したかったので、my.cnfを以下のようにいじる。参考にしたURL↓

https://qiita.com/is0me/items/12629e3602ebb27c26a4

まずはmy.cnfの場所の特定。どうやら/etc/my.cnfが先で、次に/etc/mysql/my.cnfの順番で読み込まれるようだ。

mysql --help | grep my.cnf 
#以下結果 
order of preference,my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf

/etc/mysql/my.cnfの中身を見ると以下のような記載がありました。

!includedir /etc/mysql/conf.d/ 
!includedir /etc/mysql/mysql.conf.d/

/etc/mysql/conf.d/のディレクトリに入れると反映されるのでは?ということで、ここにmy.cnfを設置してみる。

保存するその前に、一旦、サーバー上でmysqlが止まっているか確認する。

mysqlが止まっているか以下でわかる。(すでに稼働している場合は周りに影響しないか注意してください。)

$sudo service mysql stop
#以下の内容を入れて/etc/mysql/conf.d/my.cnfに保存する。 
[mysqld]
character-set-server=utf8mb4
[mysql]
default-character-set=utf8mb4
[client]
default-character-set=utf8mb4
#更新したら以下でリスタートする。
service mysql restart

あとは、リモート上でも接続できるようにサーバー上でリッスンを設定する。今回は、mysqlのポート3306をリッスンさせる。

mysqlインストール時にすでにポートはリッスンしているので、bind-addressとmysqlx-bind-addressのアドレスを変更するようです。

/etc/mysql/mysql.conf.d/mysqld.cnf
#bind-address = 127.0.0.1
#mysqlx-bind-address = 127.0.0.1

更新したら以下でリスタートする。

service mysql restart

そうすると、自動的に全てのアドレスから全てのアドレス:3306でリッスンできる。

sudo ss -talpn 
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 151 *:3306 *:* users:(("mysqld",pid=3822,fd=23))
ただ、この設定は少し強引すぎる。

社内サーバー用とかで事前に外部からのアクセスを制限できているなど限定した場面で活用するのが望ましい。というか一応ufwも確認する。

sudo ufw allow 22 #ssh 
sudo ufw allow 3306 #mysql
sudo ufw enable
sudo ufw status numbered
To Action From -- ------ ----
[ 1] 22 ALLOW IN Anywhere
[ 2] 3306 ALLOW IN Anywhere
[ 3] 22 (v6) ALLOW IN Anywhere (v6)
[ 4] 3306 (v6) ALLOW IN Anywhere (v6)

これでmysqlとsshのみ通るようにポートは開けることが確認できた。

ここまでで一通りのmysqlサーバの完成となる。実際に自身のPC上で確認してみてください。

以下のコマンドで入れたら成功です。

(もちろんローカル上にもmysqlは入れてるよね?)

mysql -h XXXX.example.co.jp -u root -p
パスワードを入力:hoge

できましたかね?これであなたもmysqlサーバー構築者だ、おめでとう!

できない人は個別のトラブルシューティングに従って解決してください。

結構最低構成でできたはずなので、時間はかからないのかなと思っています。

みなさん試してみてください。

DB(MySQL)をネットワーク越しに簡単にコピーする。mysqldump + パイプで。python subprocess の例も

本番環境のデータベース(MySQL)をネットワーク越しに開発環境にコピーしたい時のプラクティスです。

シェル + パイプ

よくやるのが、bash等 でパイプを使って流し込む方法です。

$ ssh user@production.example.com mysqldump \
--skip-lock-tables \
--host=xxxx.rds.amazonaws.com \
--user=xxxx \
--password=xxxx \
database_name table_name | \
ssh user@dev.example.com mysql \
--host=127.0.0.1 \
--user=xxxx \
--password=xxxx \
--database=xxxx

ssh で本番サーバ user@production.example.com に接続し、mysqldump を実行。その標準出力を SSH 接続を通して手元まで持ってきます。

ssh でもう一つ、開発環境サーバ user@dev.example.com に SSH接続し、mysql を起動。先ほどの本番環境の mysqldump 結果をパイプでそのまま流し込みます。

速度が充分に早く、通信経路も ssh で暗号化されるため安全に、効率良くコピーできます。mysql に余計な穴を空ける必要もありません。

mysqldump のオプションで --where を付けて読み込むデータを絞り込んだりもできます。

Python subprocess を使う

subprocess shell=True で実行

(あまり面白くない。読みにくい。)

import subprocess
subprocess.check_call("上記のコマンド", shell=True)

subprocess で、Popen や check_call などの引数に shell=True を与えることで、シェルコマンドをそのまま実行できます。

subprocess のパイプを使う (おすすめ)

subprocess でシェルのパイプと同様の処理が行えます。

dump_command = [
"ssh",
"user@production.example.com",
"mysqldump",
"--skip-lock-tables",
"--host=xxxx.rds.amazonaws.com",
"--user=xxxx",
"--password=xxxx",
"database_name",
"table_name",
]
dump_process = subprocess.Popen(
dump_command, stdout=subprocess.PIPE)

import_command = [
"ssh",
"user@dev.example.com",
"mysql",
"--host=127.0.0.1",
"--user=xxxx",
"--password=xxxx",
"--database=xxxx",
]
import_process = subprocess.Popen(
import_command, stdout=subprocess.PIPE, stdin=dump_process.stdout)

stdout, stderr = import_process.communicate()

ダンププロセスの stdout を インポートプロセスの stdin に接続して 2 つのプロセスを実行します。

Python のコードにしておけば、再利用性・メンテナンス性を高くでき、使い回しに優れます。

Django のデータベースコネクションを使う場合

from django.db.transaction import get_connection

dump_command = [
"ssh",
"user@production.example.com",
"mysqldump",
"--skip-lock-tables",
"--host=xxxx.rds.amazonaws.com",
"--user=xxxx",
"--password=xxxx",
"database_name",
"table_name",
]
dump_process = subprocess.Popen(
dump_command, stdout=subprocess.PIPE)

connection = get_connection(using='db_alias_name')
cursor = connection.cursor()

cursor.execute(dump_process.stdout.read())

ダンプコマンドの結果を read() して、そのまま Django データベース接続の cursor で流し込むこともできます。

※ダンプ結果を一旦メモリにためるため、データ量が多い場合ちゃんと動くかは不安です。そして他の例より効率は悪そうです。

サーバでSSHの通信断してもバッチを動かし続けるため、tmux を使うと便利。nohup より

tmux という、CUI (TUI) 用仮想スクリーンアプリケーションがあり、SSH 越しに Linux を操作する際大変便利です。似たようなものに byobu とか screen がありますが、私は tmux が好きで、よく使います。

tmux

便利に使うスクリプト

Linux でのシェル起動時、 (.bashrc 等) 下記のスクリプトを起動しています。

#=====================================================
# colors
#-----------------------------------------------------
C_RESET=$'\e[0m'
C_RED=$'\e[31m'
C_GREEN=$'\e[32m'
C_YELLOW=$'\e[33m'
C_BLUE=$'\e[34m'
C_MAGENTA=$'\e[35m'
C_CYAN=$'\e[36m'
C_IRED=$'\e[1;37;41m'
C_IGREEN=$'\e[1;30;42m'
C_IYELLOW=$'\e[1;30;43m'
C_IBLUE=$'\e[1;37;44m'
C_IMAGENTA=$'\e[1;37;45m'
C_ICYAN=$'\e[1;30;46m'
C_IWHITE=$'\e[1;30;47m'

#=====================================================
# tmux
#-----------------------------------------------------
alias TL="tmux ls"

function T() {
if [ "$1" ]; then
tmux a -t $1 || tmux -u new -s $1
else
TMUX_COUNT=`tmux ls 2>/dev/null |wc -l`
if [ ${TMUX_COUNT} -ge 2 ]; then
tmux ls
else
tmux a || tmux -u
fi
fi
}

TMUX_PS=`pgrep tmux`
if [ "${TMUX_PS}" ]; then
if [ ! "${TMUX}" ]; then
echo "? ${C_GREEN}tmux is running. type ${C_RESET}${C_IGREEN} T ${C_RESET}${C_GREEN} to attach.${C_RESET}"
tmux ls
# else already in tmux
fi
# else
# echo "tmux is not running."
fi

説明は下に書きます。

tmux が役立つケース

SSH セッションが切れた時に処理しているプロセスを終了させない、というのが最大の魅力です。

Linuxを触りたての頃は、SSHセッションが切れてもバッチプロセスを継続させるため

$ nohup ... >/tmp/log 2>&1 &

みたいなスクリプトをよく書いてました。が、正直長ったらしいですし、何かあった時シグナル送るのも面倒ですね。

SSH ログインしたサーバ上で tumx を起動し、その中でバッチプロセスを動かせば、回線断などでセッションが切れた場合も処理は継続しますし、事務所行っていた処理を一時中断して回線を切り、PCを会議室に持ってって新たに SSH ログインして tmux に再アタッチし、処理を続ける…なんてこともできます。

ちなみに、複数のユーザー(端末) で1つの tmux セッションにログインし、同じシェルセッションを見るってこともできます。

インストール方法

当社ではサーバ Linux は Ubuntu / Debian が多いので、インストールは

$ sudo apt-get install tmux

です。

基本的な tmux の使い方

起動オプション

$ tmux -u

UTF-8 サポートをONで起動します。日本語を使う場合入れとくと無難です。

( LANG=en_US.UTF-8 などの環境下では関係無いと思いますが、入れても問題無さそうです)

$ tmux a

起動している tmux セッションにアタッチ(再接続)します。回線を接続しなおした後、続きの作業をしたい時に使います。

$ tmux ls

起動しているセッションを一覧表示します

$ tmux a -t <セッション名>

セッション名を指定してアタッチします。

tmux起動後 (tmux内)での操作

Control + B が、tmux用のキーバインド(tmuxプレフィックス)です。これを押した後に別キーを押すことで tmux を操作します。

Control + B → D  … tmux セッションからデタッチ(退出)します。tmux は動き続けます。作業を中断したい場合に使います。tmux からデタッチした後は、Control + D で SSH セッションを終了させて問題ありません。tmux は動き続けます。再接続したい場合は、tmux a です。

Control + B → C  … 新しいウインドウを作成します。ウインドウというか、「タブ」と呼んだほうがイメージしやすいです。

Control + B → N … 次のウインドウ(タブ)

Control + B → P … 前のウインドウ(タブ)

Control + B → [ … コピーモード。スクロールバッファが見えるようになります。上にスクロールすることができるようになります。

文頭のスクリプトの使い方

この記事の上部にスクリプトを書きましたが、これをログインシェルの Bash 起動時に動作するよう、.bashrcなどに書いておくと

1. SSHログイン時、tmux のセッションがあると知らせます

Last login: Tue Mar 13 11:39:53 2018 from
? tmux is running. type T to attach.

このように表示されます。

複数セッションが起動している場合は、セッションのリストを表示します。

2. tmux に簡単にアタッチできます

T ファンクションを作ってます。

$ T

とすると、

  • tmux セッションが無ければ新規セッションを開始
  • tmux セッションがあればアタッチ

という動作をします。

また、引数でセッション名を指定できるので

$ T hello

とすると、セッション hello が無ければ作成、あればアタッチします。

3. その他

TLコマンド

tmux ls のエイリアスなので、実行するとセッションリストを表示します。

ターミナルの色付け

シェル変数 C_なんとか を定義してecho での色付けをしやすくしています。tmux とは直接関係無いですが、外してスクリプトを書き直すのも面倒だったのでついでに掲載しました。

Search