クラウドに再現する従来型ストレージ【GCP構築編】
はじめに
以下の記事の構築編です。クラウド (GCP) に従来型ストレージを構築していきます。
GCP固有機能は使用していませんのでGCP以外でも複数マシン間のディスク共有が設定できる環境 (AWS、VirtualBoxなど) で同様に構築可能です。
AWS編、VirtualBox編の記事は以下にあります。
クラウドに再現する従来型ストレージ【AWS構築編】
デスクトップに再現する従来型ストレージ
クラウド利用にあたっては料金がかかります。 未使用時にはVMインスタンスを停止する、不要になった際には速やかにリソースを削除することで料金を抑えられます。
構成概要
以下のような構成で「star0001」というストレージを構築していきます。
GCPのプロジェクトを新規に割り当てることを勧めます (不要時にプロジェクトごと削除できる)。
スター?
中身が見えるストレージを目標に
see‐through array (シースルー アレイ)
という名前をつけました。
中心的な役割を果たすinitスクリプト名はSTARorbit (star orbit、星の軌道) です。
GCPに作るストレージのイメージ
ソフトウェアはdnf (yumの後継パッケージ管理コマンド) で入手できる一般的なLinuxソフトウェアと100行未満の自前スクリプト (STARorbit) 1個から構成されます。
ストレージの構築
GCPが既に使える状態からの手順です。
コマンド操作はコピー&ペーストができますので実際の手数はそれほど多くありません。
1. コントローラ作成 (新規VMインスタンス2台)
以下オプションを指定して新規VMインスタンスを2台作成します。
項目 | 設定値 | 備考 |
---|---|---|
ゾーン | us-central1-a | リージョン、ゾーンに制約あり |
名前[1] | star0001-ctl1 | 2台目の名前はstar0001-ctl2とする |
マシンタイプ | n2-standard-2 | 共有ディスク設定にはN2の必要あり |
ブートディスク - OS | Rocky Linux | Rocky Linux 8 optimized for GCP |
その他 | デフォルト指定 | 外部IPが必要 (dnfで利用) |
リージョン、ゾーン、その他の制約は以下に情報があります。
2. 共有ディスク割り当て (永続ディスクのマルチライターモード)
Cloud Shellをアクティブにします。
Cloud Shell上で共有ディスクを作成し、VM (コントローラ) にアタッチします。
## 変数設定
ARRAY_NAME="star0001"
ZONE="us-central1-a"
DISK_SIZE=10 # gigabytes
NUM_DISKS=2
## 共有ディスク作成・コントローラにアタッチ
for N in `seq $NUM_DISKS`
do
gcloud beta compute disks create ${ARRAY_NAME}-disk-${N} \
--size $DISK_SIZE --type pd-ssd --multi-writer --zone $ZONE
for NODE_NAME in \
`gcloud compute instances list | grep $ARRAY_NAME | awk -F: '{ print $2 }'`
do
gcloud compute instances attach-disk $NODE_NAME \
--disk ${ARRAY_NAME}-disk-${N} --zone $ZONE
done
done
echo '(「・ω・)「がおぉー!'
3. コントローラ共通設定 (両コントローラに実施)
VMインスタンスの一覧画面からコントローラにSSHでログインします。
sudo su -
コマンドでrootユーザになります。
コントローラ1,2で以下のコマンドを実行し、ソフトウェアインストール・設定を行います。
## タイムゾーン設定
timedatectl set-timezone Asia/Tokyo ; timedatectl
## パッケージインストール、アップデート
dnf -y install pcs pacemaker targetcli iscsi-initiator-utils \
sysstat vsftpd lvm2 jq --enablerepo=ha
dnf update -y
## selinux無効
grubby --update-kernel ALL --args selinux=0
## サービス起動設定
systemctl start vsftpd # ftpはSSH設定まで利用、enableしない
systemctl enable --now pcsd iscsid
systemctl disable --now target iscsi-onboot iscsi
systemctl --no-pager status pcsd iscsid target iscsi-onboot iscsi vsftpd
## firewall設定
firewall-cmd --permanent --add-service=high-availability
firewall-cmd --reload
firewall-cmd --add-service=ftp # ftpはSSH設定まで利用、--permanentしない
## ユーザ、パスワード設定
echo hacluster | passwd --stdin hacluster
useradd -u 1979 alien && echo alien | passwd --stdin alien
## SSHサーバ設定 (rootログインを許可、rootのパスワードログインは不要)
sed -i 's/^PermitRootLogin no/PermitRootLogin yes/g' /etc/ssh/sshd_config
systemctl restart sshd
## LVM環境設定
FILTER='a|google-.*|'
grep -qF "$FILTER" /etc/lvm/lvm.conf || {
sed -Ei -e 's/# system_id_source = "none"/system_id_source = "uname"/' \
-e "/# Run vgscan aft.+cache/a \ filter = [ \"$FILTER\", \"r|.*|\" ]" \
/etc/lvm/lvm.conf ; }
# STANDBYに見えるiSCSIデバイス拒否、failoverにてSTANDBY->ACTIVE昇格後に
# 不通のiSCSIデバイスを走査してSTARpool活性T.O.から切替失敗するのを防ぐ
echo '(=・ω・)ノ ぃょぅ'
コントローラ1,2で以下のコマンドを実行し、iSCSI target起動スクリプトの設定を行います。
## ファイル配置
cat << "__EOF__" > /etc/init.d/STARorbit
#!/bin/bash
# chkconfig: 345 99 1
# description: STAR iSCSI target control script
NODE_BASENAME="$(uname -n | sed 's/\(.\+\).$/\1/g')"
NODE_NUM="$(uname -n | sed 's/.\+\(.\)$/\1/g')"
PARTNER_NODE="${NODE_BASENAME}$(( 3 - $NODE_NUM ))"
test -f /etc/star/config && . /etc/star/config
is_active_node() { pcs resource status STARpool | egrep -q "Started +$(uname -n)"; }
start_as_active() {
iscsiadm -m node --logout
cp /etc/target/{saveconfig.json.active,saveconfig.json}
sed -i -e "s/node._tg_pt_gp/node${NODE_NUM}_tg_pt_gp/g" \
-e "s/\"tg_pt_gp_id\": [12]/\"tg_pt_gp_id\": ${NODE_NUM}/g" \
/etc/target/saveconfig.json
systemctl restart target
ssh -n -o ConnectTimeout=10 $PARTNER_NODE "/etc/init.d/STARorbit start" &
}
start_as_standby() {
for I in $(seq 120); do
is_active_node && break
# This function may run for up to 10 minutes, with the possibility of
# parallel switching to ACTIVE. If it detects ACTIVE, it exits.
pcs resource status STARorbit | egrep -q "Started +${PARTNER_NODE}" || \
{ sleep 5 ; continue ; }
iscsiadm -m discovery -t sendtargets -p $PARTNER_NODE
iscsiadm -m node --login
for ISCSI_HOST in $(ls -1 /sys/class/iscsi_host) ; do
echo '- - -' > /sys/class/scsi_host/$ISCSI_HOST/scan ; done
sleep 5 ; lsscsi | fgrep -q -e STAR-LUN -e STAR-HD140283 || continue
cp /etc/target/{saveconfig.json.standby,saveconfig.json}
sed -i -e "s/node._tg_pt_gp/node${NODE_NUM}_tg_pt_gp/g" \
-e "s/\"tg_pt_gp_id\": [12]/\"tg_pt_gp_id\": ${NODE_NUM}/g" \
/etc/target/saveconfig.json
if type jq >/dev/null 2>&1; then
jq '(.storage_objects[].alua_tpgs[] | select(.name | test("node._tg_pt_gp"))
| .alua_access_type) |=1' /etc/target/saveconfig.json \
| jq "(.storage_objects[].alua_tpgs[]
| select(.name | test(\"node._tg_pt_gp\")) | .alua_access_state) \
|=${STANDBY_NON_OPTIMIZED:-0}" > /etc/target/saveconfig.json.$$ \
&& mv /etc/target/{saveconfig.json.$$,saveconfig.json}; fi
systemctl start target
break
done
}
stop_as_active() {
ssh -n -o ConnectTimeout=10 $PARTNER_NODE "/etc/init.d/STARorbit stop"
systemctl stop target
}
stop_as_standby() { systemctl stop target ; }
start() {
echo -n "Starting STAR iSCSI target:"
is_active_node && start_as_active
is_active_node || start_as_standby
return 0
}
stop() {
echo -n "Stopping STAR iSCSI target:"
systemctl is-active target || return 0
is_active_node && stop_as_active
is_active_node || stop_as_standby
return 0
}
status() {
is_active_node || return 3
# STANDBY returns 'stopped' to avoid 2-nodes-active detection by Pacemaker.
systemctl status target
}
case $1 in
start) start ;;
stop) stop ;;
status) status ;;
esac
__EOF__
## パーミッション設定
chmod 755 /etc/init.d/STARorbit
## rc.local有効化と追記
echo "/etc/init.d/STARorbit start" >> /etc/rc.d/rc.local
chmod 755 /etc/rc.d/rc.local
echo 'ヽ(^O^)ノ いらっしゃいませー'
4. SSH公開鍵認証設定
コントローラ1,2の順に以下のコマンドを実行し、SSHの公開鍵認証設定を実施します。
NODE_BASENAME="$(uname -n | sed 's/\(.\+\).$/\1/g')"
NODE_NUM="$(uname -n | sed 's/.\+\(.\)$/\1/g')"
PARTNER_NODE="${NODE_BASENAME}$(( 3 - $NODE_NUM ))"
test -f /root/.ssh/id_rsa || {
if [ $NODE_NUM -eq 1 ]; then
ssh-keygen -t rsa -N "" -f /root/.ssh/id_rsa # 公開鍵作成 (両ノード共通)
## 鍵転送 (コントローラ2に向けて)
curl -T "/root/.ssh/{id_rsa.pub,id_rsa}" -u alien:alien ftp://${PARTNER_NODE}/
# コントローラ2を再起動した場合にはvsftpdが起動していません
# 先に`systemctl start vsftpd ; firewall-cmd --add-service=ftp`が必要です
else
## 鍵配置 (コントローラ1から転送されたもの)
test -d /root/.ssh || { mkdir /root/.ssh ; chmod 700 /root/.ssh ; }
mv /home/alien/{id_rsa.pub,id_rsa} /root/.ssh
chown root:root /root/.ssh/{id_rsa.pub,id_rsa}
chmod 600 /root/.ssh/id_rsa
fi
cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys # ログイン許可
echo '( ´ー`)フゥー...'
}
コントローラ1,2で以下のコマンドを実行し、SSH動作確認をします。
ssh -n -o StrictHostKeyChecking=no $PARTNER_NODE "date ; uname -n"
# 表示例 (初回は`Warning: Permanently added ...`が出ます):
# Sun Oct 15 12:37:27 JST 2023
# star0001-ctl2
echo '∩( ・ω・)∩'
5. ストレージプール、LUN作成
コントローラ1 (star0001-ctl1) にログイン、sudo su -
コマンドでrootユーザになります。
コントローラ1で以下のコマンドを実行し、ストレージプール、LUN作成を実施します。
POOL_NAME="STARpool"
DIR="/etc/star" ; mkdir -p $DIR
LUN_SIZE="3072M"
NODE_NUM="$(uname -n | sed 's/.\+\(.\)$/\1/g')"
if [ $NODE_NUM -eq 1 ]; then
vgs -q "$POOL_NAME" || {
## ストレージプール (Volume Group) 作成
for disk in $(pvs --all | grep -v '\-part[1-9]' | awk '/dev/{ print $1 }'); do
pvcreate $disk ; done
vgcreate --setautoactivation n $POOL_NAME $(pvs | awk '/dev/{ print $1 }')
vgs -o+systemid ; pvs --all
lvcreate -n HD140283 -l 1 $POOL_NAME
# Pacemakerで制御するにあたりLogical Volumeが0個になる状況を避けるため
## LUN (Logical Volume) 作成
for I in $(seq 0 5); do
LUN_NAME="LUN${I}" ; LUN_WWN="$(uuidgen)"
lvcreate -n $LUN_NAME -L $LUN_SIZE $POOL_NAME
echo "$LUN_NAME $LUN_WWN $LUN_SIZE" >> $DIR/lunlist
done
}
echo '>゜)))彡 サカナ'
else
echo '(#゚Д゚) ゴルァ!!' # 誤ってコントローラ2で実行した場合
fi
6. iSCSIターゲット設定
コントローラ1 (star0001-ctl1) にログイン、sudo su -
コマンドでrootユーザになります。
コントローラ1で以下のコマンドを実行し、iSCSIターゲット設定を実施します。
## 変数設定
ARRAY_NAME="star0001" # 任意の筐体名を指定可
DIR="/etc/star"
ARRAY_VERSION="0.5"
STANDBY_NON_OPTIMIZED=0
NUM_HOSTS=2
NODE_BASENAME="$(uname -n | sed 's/\(.\+\).$/\1/g')"
NODE_NUM="$(uname -n | sed 's/.\+\(.\)$/\1/g')"
PARTNER_NODE="${NODE_BASENAME}$(( 3 - $NODE_NUM ))"
if [ $NODE_NUM -eq 1 ]; then
test -f /etc/target/saveconfig.json.active || {
## 筐体情報作成
echo $ARRAY_NAME > $DIR/starname
echo $ARRAY_VERSION > $DIR/version
echo "STANDBY_NON_OPTIMIZED=${STANDBY_NON_OPTIMIZED}" > $DIR/config
## iSCSIターゲット設定 (ACTIVEコントローラ用)
ARRAY_IQN=iqn.2023-09.test.use.only:${ARRAY_NAME}-target
targetcli /iscsi create $ARRAY_IQN
while read LUN_INFO ; do
LUN_NAME="$(echo $LUN_INFO | awk '{ print $1 }')"
LUN_WWN="$(echo $LUN_INFO | awk '{ print $2 }')"
targetcli /backstores/block create name=STAR-${LUN_NAME} \
dev=/dev/STARpool/$LUN_NAME wwn=${LUN_WWN}
targetcli /backstores/block/STAR-${LUN_NAME}/alua \
create node${NODE_NUM}_tg_pt_gp ${NODE_NUM}
targetcli /iscsi/$ARRAY_IQN/tpg1/luns create /backstores/block/STAR-${LUN_NAME}
done < $DIR/lunlist
for lunN in \
$(targetcli ls /iscsi/$ARRAY_IQN/tpg1/luns 1 | awk '/STAR/{ print $2 }') ; do
targetcli /iscsi/$ARRAY_IQN/tpg1/luns/$lunN \
set alua alua_tg_pt_gp_name=node${NODE_NUM}_tg_pt_gp ; done
for I in $(seq $NUM_HOSTS); do
HOST_NAME="Host_${I}"
HOST_IQN="iqn.2023-09.com.example:host${I}-initiator"
echo "$HOST_NAME $HOST_IQN LUN0,LUN1,LUN2,LUN3,LUN4,LUN5" >> $DIR/hostlist
targetcli /iscsi/$ARRAY_IQN/tpg1/acls create $HOST_IQN
done
targetcli /iscsi/$ARRAY_IQN/tpg1/acls \
create iqn.2023-09.test.use.only:${ARRAY_NAME}-initiator
targetcli saveconfig /etc/target/saveconfig.json.active
## コントローラ2に構成情報を転送
ssh -n $PARTNER_NODE "mkdir -p $DIR"
scp $DIR/* ${PARTNER_NODE}:${DIR}
scp /etc/target/saveconfig.json.active ${PARTNER_NODE}:/etc/target
## iSCSIイニシエータ設定 (コントローラ間iSCSIアクセス用)
echo InitiatorName=iqn.2023-09.test.use.only:${ARRAY_NAME}-initiator \
> /etc/iscsi/initiatorname.iscsi
systemctl restart iscsid
}
echo '▼・ェ・▼'
else
echo '(#゚Д゚) ゴルァ!!' # 誤ってコントローラ2で実行した場合
fi
コントローラ2 (star0001-ctl2) にログイン、sudo su -
コマンドでrootユーザになります。
コントローラ2で以下のコマンドを実行し、iSCSIターゲット設定を実施します。
DIR="/etc/star"
ARRAY_NAME=$(cat $DIR/starname)
NODE_BASENAME="$(uname -n | sed 's/\(.\+\).$/\1/g')"
NODE_NUM="$(uname -n | sed 's/.\+\(.\)$/\1/g')"
PARTNER_NODE="${NODE_BASENAME}$(( 3 - $NODE_NUM ))"
if [ $NODE_NUM -eq 2 ]; then
test -f /etc/target/saveconfig.json.standby || {
## iSCSIイニシエータ設定 (コントローラ間iSCSIアクセス用)
echo InitiatorName=iqn.2023-09.test.use.only:${ARRAY_NAME}-initiator \
> /etc/iscsi/initiatorname.iscsi
systemctl restart iscsid
## LUN認識
iscsiadm -m discovery -t sendtargets -p $PARTNER_NODE
iscsiadm -m node -o show ; iscsiadm -m node --login
iscsiadm -m session -o show
sleep 10 ; lsscsi
## iSCSIターゲット設定 (STANDBYコントローラ用)
ARRAY_IQN=iqn.2023-09.test.use.only:${ARRAY_NAME}-target
targetcli /iscsi create $ARRAY_IQN
while read LUN_INFO ; do
LUN_NAME="$(echo $LUN_INFO | awk '{ print $1 }')"
LUN_WWN="$(echo $LUN_INFO | awk '{ print $2 }')"
targetcli /backstores/block create name=STAR-${LUN_NAME} \
dev=/dev/disk/by-id/scsi-36001405$(echo ${LUN_WWN//-/} | cut -c 1-25) \
wwn=${LUN_WWN}
targetcli /backstores/block/STAR-${LUN_NAME}/alua \
create node${NODE_NUM}_tg_pt_gp ${NODE_NUM}
targetcli /iscsi/$ARRAY_IQN/tpg1/luns create /backstores/block/STAR-${LUN_NAME}
done < $DIR/lunlist
for lunN in \
$(targetcli ls /iscsi/$ARRAY_IQN/tpg1/luns 1 | awk '/STAR/{ print $2 }') ; do
targetcli /iscsi/$ARRAY_IQN/tpg1/luns/$lunN \
set alua alua_tg_pt_gp_name=node${NODE_NUM}_tg_pt_gp ; done
for HOST_IQN in $(cat $DIR/hostlist | awk '{ print $2 }'); do
targetcli /iscsi/$ARRAY_IQN/tpg1/acls create $HOST_IQN ; done
targetcli saveconfig /etc/target/saveconfig.json.standby
## コントローラ1に構成情報を転送
scp /etc/target/saveconfig.json.standby ${PARTNER_NODE}:/etc/target
}
echo '( ゚Д゚).。oO(もうひと息)'
else
echo '(#゚Д゚) ゴルァ!!' # 誤ってコントローラ1で実行した場合
fi
7. クラスタ構築
コントローラ1 (star0001-ctl1) にログイン、sudo su -
コマンドでrootユーザになります。
コントローラ1で以下のコマンドを実行し、クラスタ構築を実施します。
DIR="/etc/star"
ARRAY_NAME=$(cat $DIR/starname)
POOL_NAME="STARpool"
NODE_NAME=`uname -n`
NODE_BASENAME="$(uname -n | sed 's/\(.\+\).$/\1/g')"
NODE_NUM="$(uname -n | sed 's/.\+\(.\)$/\1/g')"
PARTNER_NODE="${NODE_BASENAME}$(( 3 - $NODE_NUM ))"
if [ $NODE_NUM -eq 1 ]; then
## クラスタ作成
NODE_ADDR=`getent ahostsv4 ${NODE_NAME} | head -1 | awk '{ print $1 }'`
PARTNER_ADDR=`getent ahostsv4 ${PARTNER_NODE} | head -1 | awk '{ print $1 }'`
pcs host auth ${NODE_NAME} addr=${NODE_ADDR} ${PARTNER_NODE} \
addr=${PARTNER_ADDR} -u hacluster -p hacluster
pcs cluster setup ${ARRAY_NAME} ${NODE_NAME} addr=${NODE_ADDR} \
${PARTNER_NODE} addr=${PARTNER_ADDR}
## クラスタ起動
pcs cluster start --all ; pcs cluster enable --all
pcs cluster status ; pcs status corosync
## STONITH無効化 (スプリットブレインでデータ破壊の可能性!!実験用のため)
pcs property set stonith-enabled=false no-quorum-policy=ignore
pcs property
## リソース作成
pcs resource create ${POOL_NAME} ocf:heartbeat:LVM-activate \
vgname=${POOL_NAME} vg_access_mode=system_id --group star_group
pcs resource create STARorbit lsb:STARorbit --group star_group \
op monitor enabled=false force-reload timeout=60 restart timeout=60 \
start timeout=60 stop timeout=60
sleep 60 ; pcs status
echo 'キタ━(゚∀゚)━!!'
else
echo '(#゚Д゚) ゴルァ!!' # 誤ってコントローラ2で実行した場合
fi
8. 1台ずつコントローラリブート (クラスタ動作確認)
コントローラ2→コントローラ1の順で1台ずつリブートします。
1台リブートしたらpcs status
コマンドの出力のNode Listが2台ともOnlineになるまで待ってから2台目をリブートします。
Node List:
* Online: [ star0001-ctl1 ]
* OFFLINE: [ star0001-ctl2 ]
Node List:
* Online: [ star0001-ctl1 star0001-ctl2 ]
サーバの構築
1. サーバ作成 (新規VMインスタンス1台)
以下オプションを指定して新規VMインスタンスを1台作成します。
項目 | 設定値 | 備考 |
---|---|---|
ゾーン | us-central1-a | ストレージと同じゾーン |
名前 | instance-1 | 任意の名前 |
マシンタイプ | n2-standard-2 | E2でも動作可 |
ブートディスク - OS | Rocky Linux | Rocky Linux 8 optimized for GCP |
ファイアウォール | HTTPトラフィックを許可する | 性能情報のWeb参照用 |
その他 | デフォルト指定 | 外部IPが必要 (dnf、apacheで利用) |
2. サーバ設定
VMインスタンスの一覧画面からサーバにSSHでログインします。
sudo su -
コマンドでrootユーザになります。
以下のコマンドを実行し、ソフトウェアインストール・設定を行います。
## 変数設定
ARRAY_NAME="star0001"
NODE1_NAME="${ARRAY_NAME}-ctl1" # ctl1ではない場合は書換え必要
NODE2_NAME="${ARRAY_NAME}-ctl2" # ctl2ではない場合は書換え必要
## タイムゾーン設定
timedatectl set-timezone Asia/Tokyo ; timedatectl
## パッケージインストール、アップデート
dnf -y install iscsi-initiator-utils device-mapper-multipath sysstat
yum update -y
## selinux無効
grubby --update-kernel ALL --args selinux=0
## iSCSIイニシエータ設定
echo InitiatorName=iqn.2023-09.com.example:host1-initiator \
> /etc/iscsi/initiatorname.iscsi
## multipath設定
mpathconf --enable --user_friendly_names y
cat << "__EOF__" >> /etc/multipath.conf
devices {
device {
vendor "LIO-ORG"
product "STAR-.+"
path_grouping_policy "group_by_prio"
path_selector "round-robin 0"
hardware_handler "1 alua"
prio "alua"
failback "immediate"
no_path_retry 10
detect_prio no
max_sectors_kb 256
}
}
__EOF__
systemctl restart multipathd
## ディスク認識
iscsiadm -m discovery -t sendtargets -p $NODE1_NAME
iscsiadm -m discovery -t sendtargets -p $NODE2_NAME
iscsiadm -m node -o show ; iscsiadm -m node --login
iscsiadm -m session -o show
sleep 10 ; lsscsi ; ll /dev/sd* /dev/disk/by-id
## マルチパス確認
multipath -ll
echo 'キタ━━(゚∀゚)━( ゚∀)━( ゚)━( )━( )━(・ )━(∀・ )━(・∀・)━イイ!!!!'
この段階で1度サーバリブートします。
ここまででサーバにストレージが見えましたので、ファイルシステムを作成する、読み書きをするなど試行することができます。
3. サーバ追加設定 (性能情報取得インターバル変更とWeb表示)
サーバにログイン、sudo su -
コマンドでrootユーザになります。
以下のコマンドを実行し、ブラウザからsarグラフが見えるように設定します。
## パッケージインストール
dnf -y install httpd expect
## digest認証設定
cat << "__EOF__" > /etc/httpd/conf.d/digest.conf
<Directory "/var/www/html/">
AuthType Digest
AuthName "milky way"
AUthUserFile "/etc/httpd/.htdigest"
Require valid-user
</Directory>
__EOF__
M=$(date '+%m') ; D=$(date '+%d')
X=$([ $((D % 2)) -eq 1 ] && echo "-" || echo "=") # 奇数日なら"-"、偶数日なら"="
expect -c "
spawn htdigest -c /etc/httpd/.htdigest \"milky way\" perfweb
expect \"New password:\"
send -- \"${M}Kinp@kU${D}${X}\n\"
expect \"Re-type new password:\"
send -- \"${M}Kinp@kU${D}${X}\n\"
wait"
systemctl enable --now httpd # apache起動
## sar記録インターバル変更 (30秒)
DIR="/etc/systemd/system/sysstat-collect.timer.d/"
mkdir -p $DIR
cat << "__EOF__" > $DIR/override.conf
[Timer]
OnCalendar=*:00/1
__EOF__
DIR="/etc/systemd/system/sysstat-collect.service.d/"
mkdir -p $DIR
cat << "__EOF__" > $DIR/override.conf
[Service]
Type=oneshot
User=root
ExecStart=/usr/lib64/sa/sa1 30 2
__EOF__
systemctl enable --now sysstat
systemctl daemon-reload
sleep 90 # データ生成待ち
## sarデータWeb化スクリプト配置・設定
cat << "__EOF__" > /usr/bin/perfweb
#!/bin/bash
DIR="/var/www/html"
METRIC=("disk" "cpu" "net")
OPTION=("-d -p" "-P ALL" "-n DEV")
INTERVAL=1
CMD="nice -n 10 sadf -Tg -O showinfo"
ENDTIME="$(date '+%H:%M')"
PREVDAY="$(date '+%d' -d '-1 day')"
sleep 3 ; cd $DIR || exit 1
draw_graph() {
STARTTIME="$(date -d "-${1} minutes" '+%H:%M')"
SADIR="/var/log/sa"
[ $2 -lt 30 ] && SADIR="/var/log/sa.short.5"
[ $2 -lt 5 ] && SADIR="/var/log/sa.short.1"
for I in $(seq 0 $(( ${#METRIC[@]} - 1 ))); do
if [ ${STARTTIME:0:2} -gt ${ENDTIME:0:2} ]; then
$CMD -s $STARTTIME -- ${OPTION[$I]} $2 $SADIR/sa$PREVDAY \
> ${METRIC[$I]}.${1}m.1.svg.$$
sleep $INTERVAL
$CMD -e $ENDTIME -- ${OPTION[$I]} $2 $SADIR > ${METRIC[$I]}.${1}m.2.svg.$$
rm -f ${METRIC[$I]}.${1}m.svg
else
$CMD -s $STARTTIME -e $ENDTIME -- ${OPTION[$I]} $2 $SADIR \
> ${METRIC[$I]}.${1}m.svg.$$
rm -f ${METRIC[$I]}.${1}m.{1,2}.svg
fi
rename .$$ '' *.svg.$$
sleep $INTERVAL
done
}
draw_graph 1 1 ; draw_graph 5 5 ; draw_graph 15 5 ; draw_graph 30 5
draw_graph 60 30 ; draw_graph 180 30 ; draw_graph 360 60
cat << _eof_ > index.html.$$
<html lang=en><title>$(uname -n) - perfweb</title><body>
<h2 style="background:#88ee88;padding:5px">$(uname -n)</h2>
<h2>Performance Statistics Graphs</h2>
<table border=1 cellpadding=3>
_eof_
for I in $(seq 0 $(( ${#METRIC[@]} - 1 ))); do
echo '<td>'
for SVG in $(ls -1 ${METRIC[$I]}.*.svg | sort -t . -k 1,1 -k 2n); do
echo "<a href=${SVG} target=_blank>${SVG}</a><br>" ; done
echo '</td>'
done >> index.html.$$
echo "</table><br>Last Updated on $(date)</body></html>" >> index.html.$$
mv index.html.$$ index.html
exit 0
__EOF__
chmod 700 /usr/bin/perfweb
mkdir /var/log/sa.short.{1,5} # 1秒、5秒間隔のsar取得ディレクトリ作成
## cronに1秒、5秒間隔のsar取得とsarデータWeb化スクリプト登録
cat << "__EOF__" > /var/spool/cron/root
MAILTO=""
S1=/var/log/sa.short.1
S5=/var/log/sa.short.5
* * * * * cd $S1 && sar -o sa$(date +\%d\%H\%M) 1 60 >/dev/null
* * * * * cd $S1 && ln -sf sa$(date +\%d\%H\%M -d '-1 min') sa$(date +\%d)
* * * * * cd $S5 && sar -o sa$(date +\%d\%H00) 5 12 >/dev/null
* * * * * cd $S5 && ln -s sa$(date +\%d\%H00) sa$(date +\%d) 2>/dev/null
* 1-23 * * * cd $S5 && sar -o sa$(date +\%d\%H30 -d '-30 min') 5 12 >/dev/null
0,30 1-23 * * * cd $S5 && ln -sf sa$(date +\%d\%H\%M -d '-30 min') sa$(date +\%d)
* * * * * find $S1 $S5 -xtype l -delete -o -type f -name 'sa*' -mmin +30 -delete
* * * * * /usr/bin/perfweb
__EOF__
chmod 600 /var/spool/cron/root
systemctl reload crond
sleep 90 # データ生成待ち
## firewalld起動・設定
systemctl enable --now firewalld
firewall-cmd --permanent --add-service=http
firewall-cmd --reload
echo -e "Username: perfweb\nPassword: ${M}Kinp@kU${D}${X}"
echo '(。・ω・)ノ゙ ありがとう'
VMインスタンスの一覧画面からサーバの外部IPをクリックしてWeb接続します。
認証ダイアログが出るのでユーザ名とパスワードを入力してログインします。
- ユーザ名は
perfweb
です - パスワードは
3. サーバ追加設定
を実施した日付によって変化します- パスワードは
2桁月
+Kinp@kU
+2桁日
+-
または=
です-
Kinp@kU
は「金箔」のローマ字を一部変更、末尾は奇数日が-
で偶数日が=
です - 例えば2月29日の場合には
02Kinp@kU29-
、2月28日の場合には02Kinp@kU28=
です
-
- パスワードは
ログインすると、sarをSVG形式にグラフ化したファイルへのリンクページが表示されます。
クリックするとグラフ化されたsarが表示されます[2]。
例えば以下のグラフ (disk.15m.svg) はI/O負荷を入れながらコントローラのVMインスタンスのリセット (ハードリセット) を実施しています (落ち込み部分がリセットの影響)。
サーバから見たI/O状況 (mpathf)
落ち込み部分を1分インターバルのグラフ (disk.1m.svg) で見ると20秒程度のI/O停止 (プログラムは待たされる) が発生しています。
サーバから見たI/O状況 (mpathf) - 23:03:23付近
上記グラフは以下コマンドでI/O負荷を入れた状況のものです。
while :
do
dd if=/dev/zero of=/dev/mapper/mpathf bs=8192 oflag=direct
done
あとがき
今回作成したストレージを初期構成から変更するツールの導入は別記事を参照下さい。通常ストレージ製品には固有のコマンドやWebツールが提供されており、それらを利用して変更をします。
また、このストレージはRAIDを構成していません[3]が、LVMでのRAIDやmdadm (ソフトウェアRAID) をPacemakerで管理することでこれも実現できると思います (未検証)。
Discussion