大約在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 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)都可以,就盡可能地把這些跟系統分開,這樣出問題的時候直接把後者掛回一個全新的系統,可以節省很多重建的時間。
如果你要備份系統,那你也只需要備份這四個目錄即可(大多數的情況下)。