gitlab 7.2.1 升級到 7.14.3 過程中遇到的坑
背景:
在此次升級之前,我們線上的 gitlab 7.2.1 版本已經跑了3年之久,其中也加了一些自定義的 patch,使用過程中也沒有遇到什麼問題。不過隨著微服務、docker、k8s、service mesh 等概念的興起,各個技術棧也都跟著不斷的革新, CI/CD 領域也不例外, 其中 Gitlab 內建了支援 k8s 的功能, Jenkins 也推出了基於 k8s 的全新 CI/CD 解決方案 Jenkins-X。
各個技術公司都在積極地瞭解並參與到這次技術革新,我們當然也一樣,為了更好的支援公司業務的發展和技術的更新,gitlab 的更新已經是勢在必行。我們的第一步計劃就是 gitlab 7.2.1 升級到 7.14.3 。
在這次 7.2.1 到 7.14.3 的升級過程中,我們獲得了不少經驗與教訓,尤其是在資料遷移方面。其中一個教訓就是一定要考慮到資料的完整性以及如何驗證資料的完整性。在這次升級操作前我們理所當然地認為使用 rsync 先做全量同步,升級時再做增量同步,資料遷移方面就沒有任何問題了。然而結果卻還是沒有逃過墨菲定律的暗示。
下面我們將簡單的描述整個升級方案和遇到的問題:
- 備份
所有升級操作都在全新的伺服器上進行,原有的 gitlab 伺服器和 db 用作備份。
選擇在全新的伺服器上進行升級,主要是基於以下幾個方面的考慮:
- 使用原有的服務資料做備份和恢復方案,恢復速度是最快的
- 因為 gitlab 很久沒有做過升級,再加上升級過程中要考慮自定義 patch 的相容性,這給整個升級增加了一定的複雜性和不確定性
- 如果選擇在原有伺服器上做升級,假如升級中意外失敗了並且無法恢復,這會影響上千個研發人員,這個結果是我們承擔不起的。 雖然我們在測試環境做了多次升級演練,但是也不敢確保線上升級一定不出問題,所以這種方案就沒有考慮
- 新伺服器上搭建和線上相同的 gitlab 7.2.1 環境
- 全量遷移 gitlab 7.2.1 資料 (repo, db)
考慮到從 gitlab server 主伺服器同步會對線上 gitlab 造成效能影響, repo 的全量同步是從 gitlab 備庫同步的 - 停 7.2.1 版本的 gitlab 服務
- 增量遷移資料 (repo, db)
使用 rsync 命令 從 gitlab 主伺服器增量同步 repo 到新伺服器上
db 從線上資料庫增量同步到新的 db - 啟動新伺服器上的 7.2.1 gitlab
- 升級新伺服器上的 7.2.1 到 7.14.3
- 功能驗證
按照上述的操作步驟,預計3個小時內就可以完成整體升級。然而真實情況卻是一波多折,中間發生了幾個意外情況。
意外 1:由於忽略了 gitlab 主伺服器上會有 git gc 操作,導致在 gitlab 主機上執行 rsync 增量同步的時間遠遠超過了預計的時間
現象:
按照計劃在 gitlab 主伺服器上做 repo 資料的增量同步時 ,發現 rsync 執行的時間非常長,在預計的時間內並沒有執行完
分析:
在測試環境中 rsync 的增量同步時間僅僅是 10幾分鐘,仔細觀察 rsync 同步 repo 過程日誌發現,同步的資料是按照 repo 名字的首字母的順序依次逐個同步的,然後我們對比了整個 repo 列表,按照當前的同步速度估計大概還需要4-5個小時完成增量同步任務,這結果太讓人崩潰了。
之後我們對比了線上gitlab 伺服器上的 repo 和 新伺服器上的 repo 各個檔案與它們的 sha1 值,發現它們的值確實不一樣。期間同事突然提醒線上的 gitlab 會有 gc 操作 (觸發 git gc 有關的兩個引數是 gc.auto default value is 6700, gc.autopacklimit default 50,超過這2個預設值就會觸發 gc),gc 後會有很多小檔案的合併。新伺服器上做完 repo 全量遷移後沒有再實時同步資料 ,然而主 gitlab 伺服器由於升級前運行了 24 小時,這期間開放人員的 fetch/merge 等操作會觸發 gc,這也是導致主 gitlab 伺服器上 repo 資料和 新伺服器上 repo 資料的差異的原因。
因此在執行 rsync 同步的時候,它已經不是簡單的增量了,而會做很多差異對比,這個世界甚至比全量同步的時間更長。
解決方法:
想清楚這個問題後,我們剩下的任務就是如何加快同步速度,於是我們把剩下的 repo 列表整理好並分批次的放到多個 rsync 程序來同步,通過 iftop 檢視,此時的千兆頻寬也已打滿,已經達到同步的最大速度。這大大加快了同步過程,沒過多久整個 repo 資料就同步完成了。
思考:
由於 gc 的差別導致遷移增量資料的速度受影響,可以考慮在主機上實時的同步 repo 資料到新伺服器 (注意限流)
可以考慮原地升級,不做資料遷移
意外 2:rsync 長時間的檔案同步會有檔案損壞的可能
現象:
資料同步完成後,登入 gitlab 首頁會提示 500 Internal error
分析:
檢視 gitlab 日誌發現下面的錯誤
根據這個錯誤的相關資訊找到了對應的 repo, 我們對比了 repo 下的各個檔案的 sha1 值,發現沒有任何差別。通過查詢網上資料,有人提示有可能是檔案損壞,可以通過使用 git fsck 做校驗,執行結果如下
從結果可以看出 objects 下的 pack 檔案缺失損壞了,而在 rsync 執行過程中卻沒有報任何錯誤資訊。
解決方法:
刪除了損壞的 repo 並重新同步有問題的 repo。
思考:
rsync 在長時間的資料同步過程中出現的這種通過對比 checksum 也發現不了的資料損壞該如何快速的發現?
意外 3: 升級後有的 ldap 賬戶登入提示使用者不存在
現象:
個別 ldap 賬號登入提示賬戶不存在
分析:
檢視當時的日誌,
然後我們對比了 ldap 中的賬號資訊和 gitlab 中的個人資訊,發現個人的 identity 中的 OU 變了,查看了多個有問題的使用者,發現他們的問題和現象都是一致的,經過了解才知道這些人都是同一批的實習生,實習期結束後被分配到各個業務線,所以 ldap 中的個人資訊也跟著變化了。
查看了 gitlab 關於 ldap 相關資訊,找到了 “Please bring LDAP group sync to CE” ( ofollow,noindex" target="_blank">https://gitlab.com/gitlab-org/ ... 43239 ),從這個 issue 裡瞭解到 LDAP 同步 group 資訊一直是企業版的功能,很多企業都期望 gitlab 把這個功能在社群版也 開發,不過很遺憾這個訴求還沒有實現。
解決方法:
我們實現了一個定時任務, 定期會呼叫 ldap 相關的介面查詢到所有人員的 identity 資訊,並與 gitlab 中的個人資訊做diff, 如果有變化則做更新 gitlab 中的個人資訊。
意外 4: 有個歷史 commit 的 timestamp 錯誤導致含有這個 commit 的 branch 釋出失敗
現象:
QA 人員反饋他們的專案釋出一直失敗,在 gitlab 頁面瀏覽他們專案分支的時候頁面會報 500 錯誤
分析:
檢視報 500 錯誤的日誌顯示如下:
提示 commit 的時間有問題,開發人員在本地檢視這個 commit 的資訊發現這個 commit 的提交時間是 2048/11/2, 這個錯誤的時間戳在 7.2.1 版本是沒有問題的。查詢 gitlab 的 issue 也發現有人提過相同的 issue ( https://github.com/libgit2/libgit2/issues/126 3),問題出在了底層的 libgit2 解析時間戳溢位,這個問題在高版本 8.4 以上已經解決了。
後來從 commit 的提交者那裡瞭解到,這個 commit 是他在家裡的虛擬機器中提交的,當時也沒有注意到時間的差別
解決方法:
拋棄所有的提交歷史,新建一個專案,並把老專案的 master 程式碼 copy 到新專案,並基於 master 重新拉分支。同時有問題的專案 禁止提交,只允許讀。
(我們也試過重寫 commit 的 timestamp 然後重新提交,不過並沒有生效,所以最後只能拋棄所有的提交歷史。)
通過這次 gitlab 7.2.1 到 7.14.3 升級的經驗積累,讓我們對下次升級更有把握,也希望這次升級的小經驗可以幫到其他正考慮升級 gitlab 的同學。
Qunar 工程效率團隊