概要
「gitbackup」というGitリポジトリをバックアップするためのKubernetes Operatorを作りました。
https://github.com/ebiiim/gitbackup に公開したので遊んでください。
はじめに
イイ感じにGitリポジトリをバックアップしたい
インターネッツの住人なので大企業のサービスを含め任意の「ホームページ」を砂上の楼閣と認識しており、明らかに信頼性の低い自宅のHDDに人生のほぼすべてを保管しています1。Gitリポジトリも人生の一部なので同じようにしたいと考えました。
平たく言うと「書き散らしたク○コードをGitHubにあげて永遠の物にした気でいるようだけどお前垢バンされたらどうすんの?」です。
どうやって実現するの?
最近は自宅のITインフラをKubernetesに載せるのがマイブームなので、同じようにやりたいです。具体的には、冒頭の図を↓こんな感じのマニフェストでやれたら嬉しいなと思いました。
|
|
なぜ○○○を使わないの?
コードホスティングサービスのミラー機能は?(複数のサービスが同時に壊れることは無いでしょ?)
さきほどのポエムに書いた2。
インターネッツの住人なので大企業のサービスを含め任意の「ホームページ」を砂上の楼閣と認識しており、
GitLabを構築してRepository Mirroringを使うのは?(多くのGitHub Alternativesが似たような機能を備えているよね?)
仕事ならそれでやると思う。
それKubernetesでやる必要なくね?
それはそのとおりだが、前述したように自宅ITインフラをKubernetesで管理したい。VM飽きたを用途ごとに作って管理するのはめんどうくさいし。
普通にCronJobでやれば?
自宅クラスタに自作Operator載せるの楽しそうじゃん🥳🥳🥳
さっそく使ってみよう
インストールする
READMEに書いたとおりですが、コマンド2行でインストールできます。
Kubernetesクラスタを用意する
お好みのものをご準備ください。
cert-managerをインストールする(コマンド実行後30秒ほど待つ)
すでにインストールしてある場合は本ステップを省略します。
1
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.0/cert-manager.yaml
gitbackupをインストールする
1
kubectl apply -f https://github.com/ebiiim/gitbackup/releases/download/v0.2.0/gitbackup.yaml
Repositoryリソースを作成する
Repositoryリソースは、1つのGitリポジトリからもう1つのGitリポジトリへのコピーを周期的に実施します。
|
|
この例でいえば、0 6 * * *
(毎日6時, UTC)に https://github.com/ebiiim/repo1
を https://git.ebiiim.com/me/repo1
にコピーします。
実際には、RepositoryリソースはCronJobを1つ作成し、そのCronJob(によって作成されたJobのPod)がgit clone --mirror
と git push --mirror
を実行することでバックアップが行われます。
|
|
あとは、バックアップしたいリポジトリの数だけRepositoryリソースを作ればOKです。
認証を行う
読者のみなさまはすでにお気づきかもしれませんが、ここまでの手順では認証について触れていません。
普通(たとえばGitHub)は認証が必要ですよね。gitbackupではgit credential
のstore
モードを使います。つまり、次の状態を想定します。
~/.gitconfig
に次の記載がある[credential] helper = store
~/.git-credentials
に各サイトの認証情報が平文で記載されているhttps://12345678:[email protected] https://user:[email protected]
このうち1.はデフォルトで自動生成されますが、2.はユーザが用意する必要があります。
Secretを手動で作成するか、すでに~/.git-credentials
がある場合は次のコマンドで作成します。※この例ではSecret名をgitbackup-secret
とします。
|
|
続いて、このSecretを使うようにRepositoryリソースを変更します。
|
|
これで、指定した認証情報を使ってアクセスを行うようになりました。
Collectionリソースで複数のGitリポジトリをバックアップする
使ってみて気づいたのですが、1つのプロジェクトで複数のGitリポジトリがあったり、そもそも多くのGitリポジトリがあったりする場合があります。そうなると project1-repo1
project1-repo2
のような名前で似た設定のRepositoryリソースをたくさん作ることになり、すごくめんどうくさいです。なので、そういうユースケースを想定したCollectionリソースを用意しました。
|
|
見てのとおりですが、このCollectionリソースは、複数のGitリポジトリからそれぞれに対応したGitリポジトリへのコピーを周期的に実施します。
実際には、CollectionリソースはRepositoryリソースを複数作成し、作成されたRepositoryリソースがバックアップを行います。ReplicaSetとPodのような関係ですね。
|
|
Collectionリソースは、各Repositoryリソースに同じ内容を設定していきますが、schedule
は1分ずつずらします。この例でいえば、repo1
には 0 6 * * *
、repo2
には 1 6 * * *
、repo3
には 2 6 * * *
を指定します。同時に大量のアクセスが発生することを回避するためです。
|
|
実装を見てみよう
ここまでで使い方と動作を説明しました。続いては実装です。といっても簡単なカスタムコントローラなので特筆すべきことはないのですが……。
gitbackupの実装にはKubebuilderを利用しました。KubebuilderはOperator Patternを簡単にやるためのコードをテンプレートするツールです。カスタムコントローラやCRDを一から書くのではなく、穴埋めで作れるようにしてくれます。詳しい説明は公式ドキュメントやつくって学ぶKubebuilderがわかりやすいです。
Reconciler
RepositoryReconciler
とCollectionReconciler
がそれぞれRepositoryリソースとCollectionリソースを管理します。
RepositoryReconciler
はRepositoryリソースの内容に従ってCronJobやConfigMapを作成するので、必要な権限を割り当てています3。Secretに関しては、LocalObjectReferenceを使って名前を渡すだけなので、権限は必要ありません。どこの馬の骨とも知れないカスタムコントローラにSecretを見せたくないですし。
Admission Webhook
Mutating admission webhooksでリソースの各パラメータの初期値を設定し、Validating admission webhooksで検証します。
たとえば、Repositoryリソースでは(使い方の説明では省略しましたが)spec.gitImage
と spec.gitConfig
に適切な初期値を設定します。
テスト
EnvTestでリソースの作成を軽く確認しています。
Repositoryリソースを削除した際に、そのRepositoryリソースによって作成されたCronJobがガベージコレクションによって削除されます4が、これは実クラスタ上でテストする必要があります。EnvTestは実クラスタでのテストも可能なので、kindでクラスタを作ってその上でやればいいですが、いまのところテストコードとしては作成していません。
異なるバージョンのKubernetesでの動作確認はkindとシェルスクリプトで少しだけやっています。
議論
パスワードを平文で置いておくのは危なくないですか?
同感ですが、この問題はSecretを使う任意のアプリケーションに存在します。良いアイデアがありましたらご教示ください。
ご参考: GitOpsをやる場合はbitnami-labs/sealed-secretsが役に立つと思います
Collectionリソースのscheduleに 59 23 * * *
を設定するとどうなりますか?
- 1つ目のRepositoryは
59 23 * * *
に設定されます - 2つ目のRepositoryは
0 23 * * *
に設定されます - 3つ目のRepositoryは
1 23 * * *
に設定されます - Nつ目のRepositoryは
(58+N)%60 23 * * *
に設定されます
1時間の中でループします。cron expressionのインクリメントを(ちゃんと定義して)実装するのがめんどうくさいのと、実用的にはこれで十分な気がするため、このような実装にしました。良いアイデアがありましたらご教示ください。
cron expressionをインクリメントする代わりにランダム時間sleepするとかですかね……。そしたら @daily
なども使えますし。
おわりに
イイ感じにGitリポジトリをバックアップすることができました。
カスタムコントローラの習作として作り始めたものですが、思いのほか普通に使えそうなので書きました。
もちろんインターネット上にもバックアップしています ↩︎
そんなことを考えていても仕方ないのはわかります ↩︎
厳密にはこのカスタムコントローラ用のサービスアカウントに割り当てられます ↩︎
ownerReferenceの話。ご参考: Owners and Dependents ↩︎