大約在2021.05.26的時候,我架在Linode上的站做了一次升級從Ubuntu 17.10=>20.04,我本來打的如意算盤是,我既然每個月都有額外交五塊錢給linode做備份,那升級後要是有什麼問題,理論上從備份回復就沒事了吧!

我先直接講結論,他的確是有備份,但是…. mount不回去,乾,那我要你這備份幹嘛!

慎選vm image的初始版本

其實一開始我幾年前做這台VM的時候,就沒考慮得很周全,選了Ubuntu 17.10(Zesty Zapus)這個並非LTS的版本。這個版本在我當時2017裝機的時候是最新的,但是事實上他僅支援到2018.01.23,這造成很多東西其實後來都沒辦法正確update。

如果當年選的是Ubuntu 16.04 LTS,那他支援會到2021.04.01,問題會少很多。所有開發者應該都知道,停止支援的時間越久,之後upgrade風險就會越大。

所以我這次的如意算盤是:

  • 我有備份,所以我要是升級有問題的話,我恢復linode幫我做的備份即可。
  • 我這次要選擇一個LTS作為升級目標,離最近的LTS是Ubuntu 20.04(Focal Fossa)

聽起來風險很低,都有了備份,還有什麼好怕的呢?上吧。

理所當然的,升級後系統出了點問題(嚴格說起來是Docker效能變得很差,這後來查詢知道是很多人從18.04前升級到18.04後的known issue),雖然其他問題都不大,不過決定還是回復備份,然後看看怎麼解決這問題後再升級。

Linode的備份是真的,但是….

從backup資料裡面可以看到他的確有按他說的,他備份了一個近期的(每天一個)跟一個遠期的(一個禮拜內)的資料。正常的做法就是從選單的backup裡面選擇備份後按下restore,等恢復就可以了。

但是,他是成功回復資料了,node卻開不了機:說掛不上硬碟 =口=?grub2抓不到guid…..這是怎樣,這個備份沒把硬碟的guid複製一份嗎?而且連grub2的console都進不去這哪招 XD

後來才知道grub2 console要從configurations tab去改,不過那是後話了…

先找個方法把資料掛出來

首先最明顯的問題就是,機器沒辦法啟動,所以只好先從recuse mode把資料想辦法先救回來。

Recuse藏得滿深的,看看右下角

Recuse mode藏在一個滿深的地方,而這個mode主要任務就是幫你用另外一個映像檔案(/dev/sdh下面的Finnix Media)開機,再讓你手動(對,不是自動,你要知道怎麼掛)把/dev/sda掛上去。當然,熟門熟路的人應該都知道就…mkdir -p /mnt/sda; mount /dev/sda /mnt/sda;就掛上去了。

接下來我們就可以把重建系統需要的檔案拷貝出來了。如果你對Linode還有信心的話(不過大概叫我在花錢用他們家backup是不可能了),我是建立了另外一個Linode開private ip,這樣這台rescue就可以把需要的檔案直接scp過去,或者,也可以花個兩塊錢買個volumn(額外磁碟空間),利用這個來在兩個linode間轉檔案。

如果你對Linode失去信心,那只剩下scp一途,幸運的是,這其實也沒有想像中困難。

恢復database

注意,不是每一個資料庫都能從磁碟檔案重建,很幸運的是,我使用的MariaDB是可以的:

  • 在新的node上安裝MariaDB
  • sudo service stop mysql
  • 把整個/var/lib/mysql備份
  • 把整個舊的/var/lib/mysql拷貝過來
  • sudo service start mysql

具體來講可以參考 https://serverfault.com/questions/250559/how-to-restore-mysql-database-from-the-physical-files

恢復Wordpress網頁

恢復網頁(就是你們現在看到的這個)具體來講需要恢復四件事情

  • database
  • nginx
  • letsencrypt
  • php

database已經恢復,包含wordpress使用的帳號密碼等等都已經回復。首先nginx,直接先安裝一個新的:sudo apt install nginx。然而,預設值來講nginx會讀取/var/www目錄,我們必須要全部把他們從舊的拷貝回來。幸運的是,整個wordpress的config是藏在database裡面,圖片等等東西都在/var/www,所以基本上只要database恢復,/var/www回來,整個wordpress是可以完全復原的。

拷貝回/var/www後還要再注意一件事,nginx其實並非以root去讀取/var/www,所以要讓/var/www有正確的owner

比較簡單的做法就

sudo chown www-data:www-data -R /var/www

不過你仍然需要回復nginx的config,所以把舊的/etc/nginx直接蓋到新的/etc/nginx應該就可以了。

然而,sudo service nginx start的時候你如果有像我一樣使用lets encrypt的話,會發現nginx因為缺乏必要的module無法啟動。其實,裝回let’s encrypt的certbot即可:https://certbot.eff.org/lets-encrypt/ubuntufocal-nginx 。然而,裝好後別急著啟動,certbot的configuration藏在/var/lib/letsencrypt,同樣的拷貝過來以後可以試試看certbot --renew-by-default 是否正常的把cert裝回來。

最後則是php了,首先先按照wordpress的建議裝上php:

sudo apt update
sudo apt install php-fpm php-curl php-gd php-intl php-mbstring php-soap php-xml php-xmlrpc php-zip

nginx理論上這樣就能動了。但是有些情況是,像我從舊版17.04換到20.04,php版本從7.2變成7.4,nginx啟動會失敗。其實,只要把所有/etc/nginx/sites-available/default裡面的fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; 把7.x換成現在的版本(7.4)就可以了。

這樣sudo service nginx restart 應該就能正常啟動了。還有其他問題以至於啟動不了的話,看看/var/log/nginx/*底下的log檔案怎麼說。

恢復服務

我大多數的服務都是以docker架起來,然後使用ubuntu systemd來啟動的。所以要恢復服務極簡單。裝好docker後,把舊的/etc/systemd/system/jenkins.service拷貝過來,然後sudo service jenkins start服務就恢復了。當然,也可以看一下這檔案怎麼mount volumn,去把他從舊的node拷貝過來到新機器即可。以jenkins為例子:

[Unit]
 Description=Jenkins service
 [Service]
 User=root
 The configuration file application.properties should be here:
 change this to your workspace
 WorkingDirectory=/tmp/
 path to executable.
 executable is a bash script which calls jar file
 ExecStart=/usr/bin/docker run --rm -p 10000:8080 -p 50000:50000 -v /var/jenkins:/var/jenkins_home --name jenkins-service jenkins/jenkins:alpine
 ExecStop=/usr/bin/docker stop jenkins-service
 SuccessExitStatus=143
 TimeoutStopSec=10
 Restart=on-failure
 RestartSec=5
 [Install]
 WantedBy=multi-user.target

所以我們看ExecStart就知道,舊的jenkins備份放在/var/jenkins,所以把他recover到新的node就好。當然,service script拷貝過來幾乎就是無痛在新機器上把jenkins復活了。

總結一下,我們應該要拷貝什麼檔案?

首先最重要的,/etc基本上應該都要留著。我們不需要把整個/etc覆蓋過去,但是全部tar起來留著其實很小,挑需要的放到新的機器會是個好主意。如果你像我一樣會自己寫服務描述檔(這很簡單的,試試看!),那恢復服務基本上只是拷貝個xxx.service就可以搞定的事情。

再來就是/var/lib,很多「實際上存放東西」的程式都是以/var/lib或者/opt當作存放的場所。進去挑你需要的把他拷貝過來吧。

最後就是/home,以server來講其實/home應該不會放太多東西,不過要是你忘記service怎麼啟動(如docker時要下哪些參數),記得留著.bash_history以及.zsh_history會有巨大的好處。

總結一下我這次搬過來的檔案

  • /etc
  • /var/lib/mysql
  • /var/lib/letsencrypt
  • /var/www
  • /home/rayer
  • /opt/jenkins (我的jenkins工作目錄在這)

以後我們應該要怎麼分割磁碟呢?

最好的做法就是「工作檔案跟系統檔案分開」,把工作檔案(尤其是我上面提到要拷貝那些)放到一個不同的分割區也許是個好主意。

所以以一個80G的空間規劃的話,30G給系統,50G看要分開還是把工作檔案掛一起(/var /opt /home /etc)都可以,就盡可能地把這些跟系統分開,這樣出問題的時候直接把後者掛回一個全新的系統,可以節省很多重建的時間。

如果你要備份系統,那你也只需要備份這四個目錄即可(大多數的情況下)。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *