如何使用 Ansible 同步 GitHub 和 GitLab

2020-01-01 10:40:00

通過使用 Ansible 映象 Git 儲存庫,保護對重要專案的存取。

開源無處不在。它在家裡的計算機上、在工作場所的計算機上、在網際網路上,並且很多都由 Git 管理。由於 Git 是分散式的,因此許多人也將其視為一種眾包的備份解決方案。從理論上講,每當有人將 Git 儲存庫克隆到其本地計算機時,他們就建立了該專案原始碼的備份。如果有 100 個人這樣做,則儲存庫就有 100 個備份副本。

從理論上講,這可以緩解“災難”的影響,例如當專案維護者突然決定刪除儲存庫莫名其妙地阻止所有流量,導致開發人員們無頭蒼蠅般地尋找誰擁有主分支的最新版本。類似的,整個程式碼託管站點也會消失。沒有人會想到 Google Code、Microsoft CodePlex 或 Gitorious 會在鼎盛時期將被關閉。

簡而言之,如果在過去的幾十年中網際網路教給了我們一些東西,那就是依靠網際網路神奇地建立備份並不是冗餘的最可靠途徑。

此外,對於許多人來說,很多開源專案都託管在 GitHub 上是個問題 —— GitHub 並不是開放平台。許多開發人員和使用者都希望支援諸如 GitLab 之類的堆疊並與之互動,它具有開源社群版本。

使用 Ansible 管理 Git

Git 的去中心方式對於解決這個問題很有用。使用純 Git,你可以使用一個 push 命令輕鬆地將其推到兩個或多個儲存庫。但是,為了使其在發生意外故障時有用,你必須經常與 Git 儲存庫進行互動(特別是推播)。此外,即使你可能永遠不會自己推播或拉出程式碼,也可能有一些要備份的儲存庫。

但是,使用 Ansible,你可以自動執行專案主分支(或其他任何分支)的 Git 拉取,然後自動進行儲存庫到“異地”映象的 Git 推播。換句話說,你可以讓你的計算機定期從 GitHub 拉取並推播到 GitLab 或 Gitolite 或 Gitea(或你喜歡的任何 Git 託管主機)。

Ansible 模組

如果不是因其出色的模組集合,那麼 Ansible 就沒那麼出色。像 Python 的第三方庫或 Linux 的應用程式一樣,這個技術引擎的一個有用而令人驚訝的簡單技巧是,Ansible 以其他人貢獻的元件而聞名。因為本文正在研究如何有效和可靠地備份 Git 儲存庫,所以這裡使用的模組是 Git 模組ini_file 模組。

首先,建立一個名為 mirror.yaml 的檔案作為劇本playbook。你可以像通常使用 Ansible 一樣,從 nametask 條目開始。本範例將 localhost 新增到 hosts 列表中,以便在控制器計算機(你現在坐在前面的計算機)上執行動作play,但是在現實生活中,你可能會在特定的主機或一組網路上的主機上執行它。

---- name: "Mirror a Git repo with Ansible"  hosts: localhost  tasks:

Git 拉取和克隆

如果要進行備份,則需要最新程式碼的副本。明顯,在 Git 倉庫中實現這一目標的方法是執行 git pull。 但是,pull 會假定克隆已經存在,而寫得很好的 Ansible 動作(Ansible 指令碼)則盡可能少的假定。最好告訴 Ansible 先克隆儲存庫。

將你的第一個任務新增到劇本:

---- name: "Mirror a Git repo with Ansible"  hosts: localhost  vars:    git_dir: /tmp/soso.git  tasks:  - name: "Clone the git repo"    git:       repo: 'https://github.com/ozkl/soso.git'       dest: '{{ git_dir }}'       clone: yes       update: yes

這個例子使用了開源的、類似於 Unix 的作業系統 soso 作為我要映象的儲存庫。這是一個完全任意的選擇,絕不意味著我對該儲存庫的未來缺乏信心。它還使用變數來參照目標資料夾 /tmp/soso.git,這很方便,並且如果以後你希望將它擴充套件為一個通用的映象指令碼也會受益。在現實生活中,你的工作機上可能會比 /tmp 具有更永久的位置,例如 /home/gitmirrors/soso.git/opt/gitmirrors/soso.git

執行你的劇本:

$ ansible-playbook mirror.yaml

首次執行該劇本時,Ansible 會正確檢測到 Git 儲存庫在本地尚不存在,因此將其克隆。

PLAY [Ansible Git mirror] ********TASK [Gathering Facts] ***********ok: [localhost]TASK [Clone git repo] ************changed: [localhost]PLAY RECAP ***********************localhost: ok=2 changed=1 failed=0 [...]

如果你再次執行該劇本,Ansible 會正確檢測到自上次執行以來沒有任何更改,並且會報告未執行任何操作:

localhost: ok=2 changed=0 failed=0 [...]

接下來,必須指示 Ansible 將儲存庫推播到另一個 Git 伺服器。

Git 推播

Ansible 中的 Git 模組不提供 push 功能,因此該過程的一部分是手動的。但是,在將儲存庫推播到備用映象之前,你必須具有一個映象,並且必須將映象設定為備用遠端伺服器remote

首先,必須將備用的遠端伺服器新增到 Git 設定。因為 Git 組態檔是 INI 樣式的設定,所以你可以使用 ini_file Ansible 模組輕鬆地新增所需的資訊。將此新增到你的劇本:

 - name: "Add alternate remote"    ini_file: dest={{ git_dir }}/.git/config section='remote \"mirrored\"' option=url value='[email protected]:example/soso-mirror.git'    tags: configuration

為此,你必須在目標伺服器上有一個空的儲存庫(在本例中為 GitLab.com)。如果需要在劇本中建立目標儲存庫,可以按照 Steve Ovens 的出色文章《如何使用 Ansible 通過 SSH 設定 Git 伺服器》來完成。

最後,直接使用 Git 將 HEAD 推播到備用遠端伺服器:

 - name: "Push the repo to alternate remote"    shell: 'git --verbose --git-dir={{ git_dir }}/.git push mirrored HEAD'

像往常一樣執行該劇本,然後使該過程自動化,這樣你就不必再次直接執行它了。你可以使用變數和特定的 Git 命令來調整指令碼以適應你的需求,但是通過常規的拉取和推播操作,可以確保駐留在一台伺服器上的重要專案可以安全地映象到另一台伺服器上。

這是完整的劇本,供參考:

---- name: "Mirror a Git repository with Ansible"  hosts: localhost  vars:    git_dir: /tmp/soso.git  tasks:  - name: "Clone the Git repo"    git:       repo: 'https://github.com/ozkl/soso.git'       dest: '{{ git_dir }}'       clone: yes       update: yes  - name: "Add alternate remote"    ini_file: dest={{ git_dir }}/.git/config section='remote \"mirrored\"' option=url value='[email protected]:example/soso-mirror.git'    tags: configuration   - name: "Push the repo to alternate remote"    shell: 'git --verbose --git-dir={{ git_dir }}/.git push mirrored HEAD'