在傻傻的人工備份資料一陣子之後,我才發現可以使用 K8s 的 CronJob 來定期備份資料庫的資料。使用 CronJob 備份的效果讓我相當的滿意,終於擺脫了人工作業!但這次我有了另外一個問題。如何在 K8s 一建立好資料庫資源後,立刻匯入我之前備份的資料呢?
找了一下資料,發現 K8s 並沒有提供像是 Docker Compose 的 depends_on
功能,因為 K8s 是宣告式的,只要寫好我們要的目標資源狀態,K8s 會自動幫我們處理每個資源的建立順序。
雖然 K8s 沒有 depends_on
功能,但好加在 Argo CD 有提供一種叫做 Resource Hooks 的功能,讓你可以在資源建立的不同階段觸發設定好的任務。
使用 Resource Hooks 在不同的階段觸發任務
Argo CD 提供多種 hooks,讓你可以在資源建立的各個階段觸發指定的操作:
PreSync
: 在資源建立之前執行。Sync
:在所有PreSync
操作與所有資源建立之後執行。Skip
:請 Argo CD 忽略這個資源PostSync
:在所有Sync
操作與所有資源建立之後執行SyncFail
:當 sync 相關操作失敗時執行
Hooks 常常使用在 K8s 的 Job
資源,例如在部署應用程式前,用 PreSync
操作 Job
先執行資料庫 Schema 的建立。
Helm 也有提供 Hooks 的功能,Argo CD 的
PreSync
正好對應 Helm 的pre-install
。
使用 Deletion Policies 刪除 Hooks 建立的資源
為了避免 hooks 建立的資源在完成任務後持續佔用系統資源,Argo CD 提供三種 Deletion Policies 來刪除 hook 資源:
BeforeHookCreation
:在其他 hook 資源建立之前刪除。HookSucceeded
:在 hook 資源執行成功之後刪除。HookFailed
:在 hook 資源執行失敗之後刪除。
使用 Hooks 來匯入資料
我想在 MySQL 的 Pod 建立後,立刻執行一個 Job
,從 S3 上面下載資料備份,然後將資料匯入 MySQL 中。
apiVersion: batch/v1
kind: Job
metadata:
name: mysql-migration-job
namespace: docfunc
annotations:
# 在所有資源建立後執行
argocd.argoproj.io/hook: PostSync
# 成功之後,將該資源刪除
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: mysql-backup-cronjob
# 這裡我預先包好一個安裝好 mysql-client 與 aws-cli 的容器
image: nella0128/aws-mysql-client:0.1.0
imagePullPolicy: "Always"
command:
- "/bin/bash"
- "-c"
- |
# 暫停 30 秒,等待 MySQL 準備好
sleep 30s
# 取得 S3 上面最新的資料備份
OBJECT_KEY=$(aws s3 ls s3://$S3_BUCKET_NAME --recursive | sort | tail -n 1 | awk '{print $4}')
aws s3 cp s3://$S3_BUCKET_NAME/$OBJECT_KEY /tmp/migration.sql
# 將資料匯入 MySQL
cat /tmp/migration.sql | mysql -h $DATABASE_HOST -P $DATABASE_PORT -u $DATABASE_USER --password=$DATABASE_PASSWORD $DATABASE_NAME
env:
# ... 設定各種環境變數,例如資料庫連線與 AWS Token 等相關資訊
restartPolicy: Never
重新部署資源到 K8s 之後,就會發現有一個 Job
會在資源都部署好之後才執行,並且在執行後立刻被刪除,此時資料庫中也會有之前備份的資料囉。
結果 Argo CD 的 Resource Hooks 用了沒多久就換成 Helm 的 Hooks 了 😂。