はじめに
過去に 艦これ作戦行動記録の公開 ってタイトルで、艦これのイベント進捗状況を Redmine に記録してて何故かこれを公開するっていうのをやってたんですが、これを取りやめることにしました。
いや、ゲームに飽きたとかそういう話じゃなくて、むしろ単発任務とかも全部この Redmine で管理しているのでバリバリ使っているのですが、このブログと同じサーバーで動かしてるのでたまにどちらかで負荷が掛かってしまうとこのサイトが落ちちゃうんですよね。
いや、別にマネタイズしているわけではないから落ちても良いんですけど、なぜか1日200人くらいはアクセス来ているらしい(ありがとうございます)ので、せっかくいらしたのにがっかりさせるのもなぁと思い始めました。
で。Lightsail サーバーを分けちゃうのが最高に話が早いんですけど、当然サーバー代も満額2重で払わなければならなくなる。無理じゃないけどイヤ。だって別にマネタイズしているわけではないし。
それでは 100円単位級のスケールでお届けする、みみっちい個人 AWS の世界をお楽しみください。
必要な時だけ起動する EC2 という選択肢
前述を考えているときに、艦これ Redmine って期間限定イベントの攻略中か、単発任務の記録でしか使わないので「じゃあ使うときだけ起動すりゃ良いじゃん」という考えに至り、月額固定の Lightsail から、起動中だけ課金される EC2 に移行することにしました。
なんて一見合理的に見えて非合理的な判断なんだ。
多分誰も見てないので公開を止めて、私だけ使うようにしてしまえば転送量課金とかも気にしなくて良いし、ストレージを最小限の HDD にすれば更に課金を抑えられるぞ!
別解:Lightsail のスケールアップで両方動かす(不採用)
ケチって最安インスタンスで動かしてるので、1ランク上げて両方の挙動を安定させるというアプローチも考えましたが、以下の理由で不採用。
● bitnami のインストーラーが廃止(配布終了)している
bitnami の Redmine のアプリイメージをデプロイして、更にそこに追加で WordPress のアプリケーションスタックをインストールする手法で構築していましたが、配布元が面倒になったのかインストーラーの配布をやめてしまいました。
手動でインストールする手段もありますが、bitnami のアプリケーションスタックは独特でうまく行かない可能性が極めて高いので断念。
あと、そもそも複数インストールの難易度がめちゃめちゃ高い。
独自路線な Apache の使い方してて一筋縄ではいきません。
こうなると分けるほうに傾きます。
● 結局分けたほうがメンテしやすい
当たり前ですが相互に影響を及ぼすことがなくなるので、プラットフォームを簡単にアップデート(≒サーバ移行)することが出来るようになります。
この Web サイトの移設前の PHP バージョンは長い間 7.3 だったのですが、Redmine と統合している事によって中々アップデートできなかったのです。なので、インスタンスをスケールアップして使い続けてもゆくゆくは行き詰って、上記のインストーラー廃止問題が出てくると考えられました。
● ディスクサイズが無駄に大きくなる
Lightsail のディスクサイズはインスタンスとセットで大きくなりますので、使っていないにも関わらず20GB → 40GB に増えてしまいます。ディスクは料金に含まれるので良いじゃんって思いきや、別料金のスナップショットが倍増する罠があります。150円→300円/月くらいかな。
いや払えよそれくらい。ゆくゆくスケールアップしたら払うかも。
Bitnami による AWS への WordPress 構築
上記のサイトの『Launch in AWS Console』から立ち上げることができます。
(Azure 用や Google Cloud Platform 用もあるよ)
スペック
大阪リージョン ( ap-northeast-3 )を選択しました。大阪人なので。
ボリュームは マグネティック(標準)を選択。
大阪リージョンだと 0.08ドル/1GB 月 ですね。
10GB にしたので、月額 0.8 ドル。110円くらい?
I/O に対しても課金(0.08ドル/100万I/O)されるので認識だけしておきます。
ボリュームに関しては電源停止していても課金され続けるので、出来るだけケチります。
考えたら大阪リージョンじゃなくてアメリカで構築した方が 0.05ドルになって良かったかもしれない。
(約110円→約70円/月)
コンピュートは t3.nano ( 2vCPU / 0.5GB MEM)を選択。
大阪リージョンだと 0.0052 ドル/時間 ですね。
1か月 約 744時間 ずーっと起動すると、約540円くらい?
使っているときだけ課金なのでメモリをもう少し上げても良いのですが、一人用 Redmine は多重で編集とかしなければ 512MB でサクサク動いてくれるので今のところは t3.nano です。贅沢は敵。
したがって、現状に加えて 150円~300円/月額くらいの増加になる見込みです。
サーバ移行(Redmine)
以下でやっているのですが、結構簡単です。
・移行元サーバで、DB ダンプして、files ディレクトリを tar で固めて移行先サーバにコピー
・移行先サーバで コマンド発行、必要に応じてエラー対処する
bundle exec rake db:migrate RAILS_ENV=production
・移行先サーバで DB リストアして files ディレクトリを展開し、bitnami が実行される ID が編集できるように chmod -R する
・DNS を移行先に向けて SSL 証明書新規発行。
マジでこれだけです。
失敗:スポットインスタンスの利用
別に何時止まっても良いし、スポットインスタンスにしたら更に安くできるんじゃね??って思ったんですよ。(現在だと Savings Plan?)
で、仕様を知らないままスポットインスタンスを使った私が悪いんですけど、「永続的」にチェック入れないと自分の好きなタイミングで停止できないんですね。
停止テストするときにエラーが表示されて詰んでしまい、結局 終了 させました。
もう一回再構築できるドン!
Elastic IP 使わないから EC2 の名前解決できない問題
Elastic IP と Route 53 使えばいい話なんですよ、普通に。
でもほとんど使っていないから Elastic IP にも課金が掛かるんですよね。
その為だけに、だいたい 400円/月。ふざけんな。
で、Lightsail の廉価版 Route53 みたいな DNS サービス使っているので、結局この Elastic IP 使っても連携は出来ない。
じゃあ、Route53 に移行するかーっていっても、手間と維持費と DNS クエリ料金だけ新たに掛かって、結果得られるメリットが日ごろ使わない EC2 の持ってる Elastic IP との自動連携だけ。イラネ。
で、AWS EC2 が Azure VM にボロ負けしている数少ない点として、サービスでの DDNS 名前解決が出来ない、があるんですよね。
いや、厳密には 「 ec2-public-ipv4-address.compute-1.amazonaws.com 」みたいな名前解決できるんですけど、Public IP が FQDN に含まれるとかいう起動するたびに毎回変わる FQDN になんの存在価値があんねんって感じのトンデモ仕様なので使い物になりません。AWS 内部で使ってるんですかね。
Route 53 と、Elastic IP 使えって話と思いますけど、あまりにもスマートではない。
ということで、EC2 の DNS の思考回路よりもスマート な、
いにしえ の DDNS を根性で実装する必要がありました。
以下にスクリプト群を掲載しますが、私専用なので雑です。
従って、適切に権限設定や aws config が済まされているという前提です。
起動させる JOB のついでに更新させる案(採用)
Jenkins サーバを家で動かしていますので、そこから EC2 のインスタンスを起動するついでに、
起動後に パブリック IP アドレスを確認してその値で AWS CLI を使って Lightsail の DNS レコードを書き換えちゃう例です。これで運用することにしました。
INSTANCE_NAME="i-インスタンス名"
##############
# start
##############
echo "Start instance..."
/usr/local/aws/bin/aws ec2 start-instances --instance-ids ${INSTANCE_NAME} --region ap-northeast-3
##############
# check start
##############
i=0
while :
do
echo "Checking to start instance complete."
RESULT_STRING=`/usr/local/aws/bin/aws ec2 describe-instances --instance-ids ${INSTANCE_NAME} --region ap-northeast-3 --output text |grep "STATE`
RESULT=`echo ${RESULT_STRING} | grep -c "running"`
if [ ${RESULT} -ne 0 ] ; then
break
fi
echo "The instance has not been running. ( ${RESULT_STRING} )"
sleep 10
i=`expr $i+1`
if [ $i -ge 10 ] ;then
echo "The instance not running. ( ${RESULT_STRING} )"
exit 1
fi
done
echo "The instance has been running."
##############
# update DNS
##############
SUB_DOMAIN_NAME="yotei.twinfami.com"
DOMAIN_NAME="twinfami.com"
#public ip 確認
PUBLIC_IP=`/usr/local/aws/bin/aws ec2 describe-instances --instance-ids ${INSTANCE_NAME} --region ap-northeast-3 --output text | grep ASSOCIATION | head -1 | awk '{print $4}'`
#Entry ID 確認
ENTRY_ID="`/usr/local/aws/bin/aws lightsail get-domain --domain-name "${DOMAIN_NAME}" --region us-east-1 --output text | grep "${SUB_DOMAIN_NAME}" | awk '{print $2}'`"
# update
/usr/local/aws/bin/aws lightsail update-domain-entry --domain-name $DOMAIN_NAME --domain-entry "{\"id\":\"$ENTRY_ID\",\"name\":\"$SUB_DOMAIN_NAME\",\"target\":\"$PUBLIC_IP\",\"type\":\"A\",\"options\":{}}" --region us-east-1
Lightsail の DNS は更新するために、ゾーン、該当レコード名、Public IP の他に「EntryID」という独自の管理番号を要求してきますので、これを合わせて取得し、利用しています。
ちなみに面倒だったので原案は AI(ChatGPT-4)に書いてもらいました。すごいネ。
EC2 インスタンスから直接更新させる案(採用→不採用)
cron で5分ごとに自分のパブリック IP アドレスを確認して、前回と変わっていれば自動で更新するという仕掛けのシェルスクリプトにしました。
#!/bin/bash
export AWS_DEFAULT_REGION=us-east-1
EXEC_DIR="/usr/local/bin/UPDATE_DNS"
PREV_IP_FILE="${EXEC_DIR}/prev_ip.txt"
DOMAIN_NAME="twinfami.com"
DOMAIN_ENTRY_NAME="yotei.twinfami.com"
PUBLIC_IP=$(curl -s http://checkip.amazonaws.com/)
if [ ! -f ${PREV_IP_FILE} ] ; then
curl -s http://checkip.amazonaws.com/ > ${PREV_IP_FILE}
fi
PREV_IP=`cat ${PREV_IP_FILE}`
if [ "${PREV_IP}" = "${PUBLIC_IP}" ] ; then
exit 0
fi
DNS_ENTRIES=$(aws lightsail get-domain --domain-name $DOMAIN_NAME --region us-east-1 | jq ".domain.domainEntries[] | select(.name==\"${DOMAIN_ENTRY_NAME}\")")
ENTRY_ID=$(echo $DNS_ENTRIES | jq '.id' -r)
ENTRY_NAME=$(echo $DNS_ENTRIES | jq '.name' -r)
aws lightsail update-domain-entry --domain-name $DOMAIN_NAME --domain-entry "{\"id\":\"$ENTRY_ID\",\"name\":\"$ENTRY_NAME\",\"target\":\"$PUBLIC_IP\",\"type\":\"A\",\"options\":{}}" --region us-east-1
echo "Updated $DOMAIN_NAME A record. ${PREV_IP} to $PUBLIC_IP"
これも面倒だったので原案は AI(ChatGPT-4)に書いてもらいました。すごいネ。
当初はこれだったんですが、起動後の DNS レコード更新に最長5分掛かるので先述の案に変更しました。
AWS の マネージド サービスで行う案(不採用)
色々教えて頂いたりして、EventBridge で特定の EC2 が起動したときにイベントを起こして、それから Lambda を呼び出して DDNS 更新させれば良いのではと思いつき実装を試みました。一番クラウドっぽい。
{
"source": ["aws.ec2"],
"detail-type": ["EC2 Instance State-change Notification"],
"detail": {
"state": ["running"],
"instance-id": ["i-EC2のインスタンスID"]
}
}
上記の EventBridge フィルタルールでイベントを拾えて Lambda に発火させるところまではいけたんですけど、肝心の Lambda での更新がうまく行かず断念。プログラミングスキルのなさが露呈した訳です。まあ俺プログラマーじゃないし実際フィルタも ChatGPT に書いてもらったしな。ホントすげえな。
ついでにサーバ移行(WordPress)
このサーバ上から Redmine が要らなくなったのでキレイにするためにサーバを再構築しました。
Lightsail → Lightsail の WordPress 移行です。おかげでサポート切れの PHP 7.3 から PHP8 系へ。
WordPress の移行って「All-in-One WP Migration」みたいな移行ツール使わないといけないと思い込んでて大変だと思ってたんですが、
調べているうちに考えたら DB ダンプして、tar でディレクトリごと固めて持っていけば良いだけって気づかされました。そりゃそうか・・・Linux だしな・・・。
エラー1:mysqldump できない
上記のサイトを参考にしましたが、mysqldump が「Error: ‘Access denied; you need (at least one of) the PROCESS privilege(s) for this operation’ when trying to dump tablespaces」で失敗。
私の環境では「–no-tablespaces」指定が必要でした。以下を参考。
エラー2:データベース接続確立エラー
再起動したタイミングで「データベース接続確立エラー」が表示されて詰みそうになりました。
なんのことは無い、前のサーバの wp-config.php ごと移行してたというオチでした。
ID/PW を正しく修正して完了。
エラー3: .htaccess が効かない
そもそも bitnami 構成で .htaccess を使うのは非推奨なんですけどね。
結構ガチガチにアクセス制限をしているので、以下を参考に AllowOverride All にしました。
Lightsail|WordPress – bitnami|.htaccessを有効化する方法
https://qiita.com/tomokei5634/items/51ecd10fa0bd09c5cf60
Redmine のことを気にせずに移行バージョンアップが出来るようになったので、脆弱性が出ても追随出来るようになったわけです。やったぜ。
あれ、WordPress だけになったなら bitnami やめればコンポーネントごとにアップデートできるようになったのでは?
結論
マネージドな Lightsail のコンテナでやればよかったんでは?