さくらのVPSでサーバーを壊しちゃったのでDockerSwarmを導入してWordPressを再構築してみた

きっかけは、さくらのVPSをスケールアップしたときストレージが増えたはずなのに、サーバーではそれが反映されてない(容量が少ないまま)って記事を見つけたのが始まりです。

「あれ?1Gプランにして、ストレージが50GBに増えたはずなのに、内部的には25GBしか使えてないな」

「それじゃ、さくらのVPSのスケールアップの反映について公式マニュアルがあるから、これを参考にやってみるか」

中略

「・・・再起動しても、OSが立ち上がってこない🥺」

何をやってしまったか

あまりも馬鹿としか言いようがないミスなんですが、以下の文章を読んで、自分はこう考えてしまったんです。

最後にOSを再起動してもマウントできるように、 /etc/fstab に設定を追加します。

# id=$(blkid -o value -s UUID /dev/vda5)
# echo “UUID=${id} /data ext4 defaults 0 2” >> /etc/fstab

https://vps-news.sakura.ad.jp/scaleup/disk-expansion_centos7

脳死状態の私「えーっと、fstabに追加ね」「コピペして・・・vi /etc/fstabっと」

冷静に見れば直ぐに気付きます。

これが「設定内容ではなく」「コマンドを入力すること」だということに・・・

憐れ脳死状態の私は、コマンド出力からのファイル書き込みを、fstabにコマンドを直接書き込んで再起動してしまったのです。・・・馬鹿としか言いようがない。

再起動してどうなったか

「Booting from Hard Disk…」

さくらのVPS、VNCコンソールに表示される最後の一文がピクリともしない。

待てども待てどもOSが立ち上がってこない。

05分後の私「ファイルシステムの更新って時間がかかるんだな」

10分後の私「うーん、VPSだから時間がかかるのかなぁ・・・」

30分後の私「・・・やべぇ明らかにおかしい」

復旧させようと試みるが

何度再起動したり、シャットダウン→起動しても変化が無いことに焦った私は、ついにサポートに聞いてみることにした。

コロナの影響で、電話窓口は閉じており、チャット相談もさくらのVPSは対象外ということで、メールでの問い合わせになった。

パニック状態の私「公式マニュアル通りにやったのに再起動しません。どうすればいいでしょうか?」

改めて振り返ると、いわゆる「何もしてないのに壊れた」ですねこれ。恥ずかしい。

メールの返信は「カスタムOSにてインストールされたOSは対象外になります。」という門前払い的な内容が営業時間終了後(メールを送信したのは13時)に届いた。

私は「酷いじゃないか」と頭にきて、「ほら、OSインストール画面だと標準OSってなってる(ただの勘違い)」「カスタムOSってどこで確認したんですか?」と怒りの返信。

メールを送信してから次の日の返信を待っている間、私は冷静になり始め、そこで初めてfstabの誤記入に気付いて事態の深刻さを思い知る。やっちまったと。

怒りのメール返信を「もういいです。やっぱり自分で解決します。」って取り下げて(サポートが受けれない事実はショックだったので、メール文面がひねくれています)、自分の力で何とかしようと悪戦苦闘を始める。

その時に参考になったサイト様です。

さくらのVPSでやらかしてから復旧させたはなし

https://qiita.com/qyen/items/948aafee25e5c314dc21

しかし現実は非情である

あれやこれやと試してみるが、結局進展はせず、ただ時間だけを浪費していく。

そこで私は復旧を諦め、最初からサーバーを建て直すことをようやく決心する。

幸いにも、サーバーはまだWordpressしか使っておらず、またWordpressのバックアップはUpdraftPlusにて全て保存済みであったので、理論的には元に戻すのはそう難しい話ではなかった。

UpdraftPlus WordPress Backup Plugin

https://ja.wordpress.org/plugins/updraftplus/

・・・しかし、ここで欲張りモードが発動する。

「せっかく再構築するんだから、Docker Swarmを使ってみよう」

そもそも、事の発端になったスケールアップのトラブルが発生したきっかけは、Wordpress内の警告に「PHP7.0と古いので更新してください」という文言を発見してしまったことだ。

そして、Dockerコンテナで運用されているこのホームページを、どうやって新しいPHPでホットデプロイ(Wordpressがメンテ状態にならないままアップデート)するかを調べていた。

本来の目的はWordpressコンテナをPHP7.3に更新することであった。

「Dockerコンテナをホットデプロイするにはどうしたら?」

「Wordpressコンテナを2個(replica 2)たてて、片方を起動しながら、もう片方を更新する」

「Docker Swarmを使えば簡単に構築できるらしい」

となれば、やってみたくなるのが心情(技術向上への強迫観念)である。

サーバーを破壊したくなければ、/etc/fstabは脳死状態で扱うな!

Docker Swarm と Kubernetes (k8s) どっち?

「Docker Swarm について調べて見よう」

「何か Docker Swarm はもうオワコンらしい」「今は Kubernetes が流行り」

「それじゃ Kubernetes を勉強しよう」

「k8s ってホットデプロイできない?」「k8s の拡張ツールとかならできるらしい」

「なんか k8s 自体はそうでもないけど、ホットデプロイとなると複雑で面倒そう」

「Docker Swarm なら簡単そうやな」

「やっぱ今回は Docker Swarm を使うのさ、たとえオワコンでも!」

技術向上への強迫観念はどこへ行ったのか、面倒そうと思ってしまったが最後、簡単に楽な道へと進んでしまうのだ。

これは後から分かったことなのだが、Swarm も k8s も、コンテナ構築の手順や複雑さは、そう差は無い。どちらもDockerコンテナを使う以上、 docker-compose でコンテナの構築を行うのだが、composeを使った時点で9割やることは終わったようなもの。

Swarm と k8s の違いを感じたところは、用語と、初期設定と、環境構築ぐらいである。どちらも、そこに拡張ツールなどを付け加えて「やれること」を増やしていく感じなのだ。

Q
じゃあ何で Docker Swarm にしたの?
A

書いてあったサンプルがそのまま使えそうなサイトが見つかったから

それじゃ Docker Swarm をやっていきますか

OSをクリーンインストールし、DockerがCentOS8にまだ対応してないので、また同じCentOS7にしました。そこから、ssh、firewall、user、wheelなど面倒だけどやらないといけない設定をあれやこれやと済まし。

sudo yum install -y docker-ce

Docker の最新版をインストール。最新のは、これだけで他にも必要な、docker-ce-cli、containerd-ioも一緒にインストールされていた。

sudo curl -L “https://github.com/docker/compose/releases/download/1.26.1/docker-compose-$(uname -s)-$(uname -m)” -o /usr/local/bin/docker-compose

Docker Compose もインストール。自分は上記の通り1.26.1だったが、今は1.26.2が最新版ということで、ここのバージョン番号は時間と共に変動するのだ。

Swarm に関しては、Docker をインストールすれば使えるようになる。

sudo docker swarm init

Swarm の初期設定はこれで終わりである。オプションとして、listen-addでネットワークの制限があるサーバーに対しての設定が必要だったりするが、サーバー1台しか持っとらんし、ネットワークの制限なんぞも無い。これで完了。

これを実行すると、「To add a worker to this swarm, run the following command: docker swarm join –token ・・・」みたいな文章が表示される。

Swarmは、簡単に言えば、サーバー全体を管理するManagerサーバー、その他管理される側のWorkerサーバーで構成されていて、これを使ってネットワーク的に離れた場所のサーバー同士を1台のサーバーのように構成することができる。

「swarm init」したサーバーがManagerになるので、先ほどの文言は、他のサーバーをWorkerとして構成に追加(join)したければ、このコマンドを使ってねという感じである。

だが、サーバーが1台しかない自分の環境では全く関係のない話。

あれ?Docker Swarmってこれで出番終わり?

Swarm の主目的は、ネットワークを介して離れたサーバー同士をつなぐために使うものなのだが、私はサーバー1台の中に、ManagerとWorkerを混在できると勘違いしていた。

「This node is already part of a swarm. Use “docker swarm leave” to leave this swarm and join another one.って出るな」

「MangerとWorkerは同じサーバーに設定できないか」

「あれ?Swarmの機能を使ってなくない?」

「でもホットデプロイのサイトでSwarm使ってるのにな」

「docker service createとかupdateとかってSwarmが必要なのかな?」

This command works with the Swarm orchestrator. って書いてあるから関係あるっぽい?」

「なんだかよく分からんがSwarm使う意味はあるっぽいのでヨシ!」

よし、あとはhttps-portalとか使って・・・ん?

以前までは、通信のHTTPS化にhttps-portalコンテナ、あとWordpressコンテナ、MySQLコンテナをlinkで繋いで、はいお終い!だった。

しかし、今回はホットデプロイのために、Wordpressコンテナを2個用意して、それをdocker service update でローリングアップデートさせる野望があった。

コンテナが2個に増えたので、通信はSwarmのロードバランサーによって振り分けられる。そこで問題になるのが、セッションである。

Swarmがコンテナの状態を見て通信を振り分けるのだが、これは1回の通信ごとであるようだ。そのときにセッションは維持されない(ようだった)。

例えば、Wordpressのダッシュボードを開くためにログインするが、ログイン状態はセッションが使われている。つまりセッションが維持されないと、何かダッシュボード内のリンクをクリックするたびにセッションが途切れ、またログイン画面に戻されてしまうのだ!

https-portalを調べたところ、セッションについて言及されていないので、このコンテナはセッションが維持される(普通はそう)前提なのだ。このままでは不味い。

Swarm でセッションを維持するような追加設定はないらしい(なんじゃそりゃ)。

そういうときは「traefikを使うといいよ」という記事が多かった。

ここから大苦戦のはじまり

Swarm なんじゃこいつ役に立たんやんけ、ってことで、どうやってセッションを維持させつつhttps化をすればいいんじゃ・・・って悩んでいたところ、traefikというSwarmを拡張するコンテナを見つけた。

・・・だが、このtraefik、かなりの曲者だったのだ。

ちなみに k8s も同じようにセッション問題があり、ingress というネットワークコントローラ(その正体はnginx?)をかぶせることで解決しているようです。

Swarmもk8sも本体は役立たずなんじゃないか?・・・あんまりdisってると、まさかりが飛んでくるかな。

・・・さて、traefikとは何者なのか。

traefikは、Dockerコンテナで、Swarmのロードバランシングを無視して通信を振り分けるロードバランサです。ようはSwarmが使えねぇんでネットワークを乗っ取ってしまうコンテナらしい。

実はこの事実に気付くのは、かなり苦戦した後になります。

traefikの設定記事、みんなバラバラやん・・・

traefikは、様々なネットワーク構成ができるようになっているので、調べれば山のように設定情報が見つかりますが、自分の欲しい情報(Swarmでセッション維持)が簡単には見つかりません。

しばらくして、英語圏ではセッション維持のことを「sticky session」と呼称するのが分かりました。

ようやく突破口を見つけましたが、同時に奇妙なことに気付き始めます。

同じsticky sessionの設定が書かれているはずなのに、みんな書いている設定がバラバラなんです。これには理由がありました。

traefik.tomlとdocker-composeどっちでもいい

traefikの設定値は、外部ファイルから読み込む形(tomlファイル)と、docker-compose(ymlファイル)でtraefikコンテナを作るときにcommandで指定する形の2通りがあります。

この2通りの方法について、各利用者サイトが両方使っている場合が大半だったのが問題でした。

さらには、同じ設定値をtomlとymlで、重複しているのに気づいていない人が大半だったのです。つまり、みんな他所からコピペしてなんか知らんが動いたからヨシ!状態。

例えば、tomlで

[docker]
watch = true

とdockerに対する設定を書くのと、ymlで

serivces:
traefik:
image: traefik:latest
・・・中略・・・
command:
– “–dokcer”
– “–dokcer.watch”

これは同じ意味になるんですが、ほとんどのサイトで重複して書かれていたりします。

この2通りで書ける狙いとしては、tomlで設定の共通化を図りつつ、環境によって差がでる部分を各ymlで吸収させること。

しかし、その自由さ故に、各個人での設定がバラバラになり、さらには煩雑なコピペが進むことで、重複した設定情報が世にあふれることになってしまっています。

これが大いに私を苦しめる原因のひとつになりました。

ですが、さらに大きな問題が・・・

traefik v1とv2が混在している・・・?!

traefikは現在v2.2なんですが、ネットに設定情報として書かれている7割ぐらいがv1時代のものでした。

参考サイトのすべてがv1時代の情報だったら良かったんですが、v1とv2の情報がネット上に混在していました。

以下は、v1からv2への変更点がまとめられた公式マニュアルです。

Migration Guide: From v1 to v2

https://docs.traefik.io/migration/v1-to-v2/

見てもらえば分かると思いますが、機能追加だけでなく、書式の大幅な変更が入ったところや、もう別物やんけみたいな所、無くなった設定や、追加された必須設定など、様々な修正が入っています。

各利用者サイトが、これに正しく対応していれば何も問題なかったんですが・・・

なんと混在していたんです。v1と、v2の設定が。

つまり動作確認されてない情報もたくさんありました。

「書いてある通りに設定しても、うまく行かないなぁ」

「FAQサイトによると・・・なになに?traefik:v1.7にしろって?」

「え?なにこれ?v1とv2って完全に別物やんけ!」

「え?でも公式マニュアル、これv1の設定じゃ?公式が古いじゃん🤪」

「えーと、今まで見てきたサイトは・・・」

「こっちはv2で書かれてるっぽい?あれ?でもこれv1じゃないとダメでは?」

「・・・正しい設定情報はどこなんだぁ~」

正しいのは何処だと、調べて行けばいくほど沼にはまっている感じがしました。

みんな「何となく」「何だから知らんけど」って設定値を書いてる感じなんだよね。

↓心が折れそうになった私

結局、公式マニュアルなどで各設定値の意味や情報を洗い直すことになり、かなりの手間になりました。また、v2の動作確認された情報が少なすぎたので、v1.7で進めることにしました。

悪戦苦闘したおかげで、何とかtraefikが起動しましたが(ダッシュボードが見れるようになる)、wordpressにアクセスしようとしてもタイムアウトしてしまいます。

「traefikの設定をコメントアウトしたりしながら確認してみよう」

「・・・どうやら、swarm = trueにすると何かおかしくなるなこれ」

「swarmオプションを全部コメントアウトするとwordpressが見れるか」

「いろいろ調べたが、traefik.backend.loadbalancer.swarm=true・・・これが追加で必要っぽい?」

「traefikはロードバランシングを行わず、swarmに委譲します、と小さく書いてあるな」

「これを追加すると、swarm=trueでもwordpressコンテナに通信できるようなる。・・・swarm=trueの効果を無効にしているような気もするけど・・・これでいっか!」

「えっと、次は、つながるようになったが、何でwordpressは404なんだ・・・」

WordPressの初期化に失敗する・・原因は?

今度はWordpressにアクセスしようとすると、404エラーしか出ない問題にぶち当たります。本来ならば、言語選択画面が表示されて、Wordpressのインストール画面になります。

traefikの設定が間違っているのかと、あーでもない、こーでもないとネット情報が当てにならないので自力で手探りで色々試していました(すでに疲労困憊)。

しかし、夜も更け、朝になっても解決せず・・・も~ダメだと寝ました。

起きてからリセットされた頭で考えた結果、原因の切り分けを行うことにしました。

まず大前提として「traefik無しでwordpressが起動するか」

・・・すると、なんと起動しなかったのです🤣

何故これに気付かなかったのかというと、Dockerコンテナというものは起動することが基本的に証明されたものが公式によって配布されています(traefikみたいに設定が別に必要なのはともかく)。

PCで言えば、PC業者が組み立ててくれたものを買ってきたので、電源ボタンを押せば起動するのが当たり前みたいな話です。

「wordpressコンテナが起動しないだと?!」

「原因は?初期化に失敗している・・・なぜ?」

「えーと、MySQLコンテナが起動する前に、wordpressコンテナが起動するとダメ?」

「wordpress.ymlのdepens_on: mysqlってやってるけどなぁ・・・」

「え?depens_onって起動の順番までは制御してない?なん・・だと・・!」

「みんなどうやってこの問題を解決しているんだ?・・・シェルスクリプト?!」

「え?docker-composeに知らない設定があるとかではなく、自作だと・・?!」

「・・・な、何か他にやりようは無いのか?」

何だか知らんが動いたからヨシ!

今回docker-composeで、Swarmを利用した新しい概念としてserviceを使っていました。以下のような感じで、deploy属性のreplicasを指定することで配置するコンテナの数などを設定できます。

wordpress:
depends_on:
– db
image: wordpress:latest
deploy:
mode: replicated
replicas: 2
update_config:
parallelism: 1
delay: 2s
restart_policy:
condition: on-failure
placement:
constraints: [node.role == manager]

前回と違うところは、このdeploy属性です。特にコンテナの数が2個になったので、それが影響しているのではないかと考えました。

ログを見ると、最初の1個が起動に失敗し、その次に2個目が起動し(その間にmysqlが起動したから?)、最後に最初に失敗したのが起動するという感じになっていました。

その最初の失敗の影響でwordpressの初期化に失敗し、起動はしているがwordpressにアクセスできない状態を作り出しているのではないか。

いろいろ試していると、初期化に成功することもありました。たまたまmysqlが先に起動したこともあったのでしょう。たまに成功するのが問題を複雑にしていました。

・・・正直なところ、この問題を解決できたのは偶然です。

コンテナ内で発生するデータ変更を永続化するために、volumes属性があります。

このvolumes属性は、Dockerが決めた場所(/var/lib/docker以下)か、自分で指定したディレクトリにすることができます。

いろいろ試しているときに、自分で指定した場所(./www:/var/www/html)にしてみたところ、何故かずっと成功するようになりました。

完全に推測ですが、最初に永続化されたDocker配下のvolumesが何かしら壊れた状態になったが、完全に壊れたわけではなかったので、コンテナは起動するが、wordpressの初期化に成功したり失敗したりするようになったのではないかなと思います。

そこで、新しくvolumesの場所を変え、新品のvolumesを使ったことで成功するようになったのではないかと。

・・・詳しく原因を調べるのはもう面倒なのでやめました。

何だか知らないけど動いたのでヨシ!!

やっとここまで俺は戻ってきた

ついにWordpressも使えるようになり、当初の目的だったhttps化や、sticky sessionも問題なく働いています。2個あるwordpressコンテナの片方をstopしても、Wordpressを変わらず操作し続けることも出来るようになりました。長かった、ここまで本当に長かった。

あとはブログを復元するだけ・・・

実は今回フルバックアップからのフル復元は初めてでした。

↓(頼む・・・成功してくれ・・・!)

正直こんなに簡単に復元できるとは思っていませんでした。

ここまでの苦労が報われた感じがしました。

いろいろあったプラグイン、その設定まで元通りになっていました。

ただ一つだけ問題がありました。

バックグラウンド更新が想定通りに・・・

最新のWordpresにはサイトヘルス機能という、Wordpressの様々な問題を発見して警告を表示するものがあります。事の始まりであった「PHPが古い」という警告もサイトヘルス機能で表示されていたものです。

復元したWordpressのサイトヘルスに見慣れない致命的エラーがありました。

「バックグランド更新が想定通りに動作していません」

これは調べたところ、新しくvolumesを作ったのが原因でした。

wwwというディレクトリをvolumesに設定しましたが、このwwwディレクトリの権限設定を変更すると解決しました。

「wordpressコンテナ内の/var/www/htmlの権限は、www-data:www-dataか」

「www-dataは33に設定されているな、それじゃ、wwwをchown 33:33にしてみよう」

「あれ?33:tapeってなるけど・・・CentOS7だと33はtapeグループなのか」

「サイトヘルスの警告文が消えてる・・・これでいいみたい!」

これにてWordpressの再構築は完了であります!

最後にGithubに設定ファイルを公開して終わります。

注意点として、traefikのSwarmに関する設定は、自分から見てもかなり怪しいです。また、v1.7での設定方法になるので、将来的に公式サポート外になるかも。使うならば自己責任でお願いします。

細かい設定などについては、Githubの方に書いておきますね。

コメントを残す