GitLab OperatorはGitLab運用の自動化の夢を見るか
注意 : GitLab Operatorは10月9日現在まだv0.1.0のリリースがあったばかりです。本番環境への適用にはまーだ早いのでご注意してください🤔
–– さぁ、GitLab OperatorでGitLab運用の自動化をはじめよう!!
背景
GitLabはおそらく多くのエンジニア、組織で利用されているGitリポジトリ管理ツールです。しかし、GitLabには多様な機能が日々追加されており今やGitLabはただのGitリポジトリツールではなくっている……と個人的に思っています。
GitLabのIssue/Milestoneをはじめ、MavenやコンテナイメージのリポジトリやKubernetes Integrationなど多様なコミュニケーション機能や開発者向けの機能が追加されています。GitLabに求められる可用性は日々上がっている一方、ますます複雑になるGitLab運用は人間の手でやりたくないですよね。
そこで使えるのがGitlab Operator、Helmに次ぐ新しい"Cloud Native"なGitlabホスト方法です。
全体像
検証環境
AWSのEKS上で実施します。ただEKS専用の機能を使う部分は限定的なため、他のKubernetes環境でも同じように起動することができるはずです。
apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: ryusa-gitlab version: "1.21" # 後述のExternalDNSとcert-managerをRoute53で管理するためのIRSAを定義 iam: withOIDC: true serviceAccounts: - metadata: name: external-dns namespace: external-dns labels: {} wellKnownPolicies: externalDNS: true roleName: eksctl-ryusa-external-dns-role - metadata: name: cert-manager namespace: cert-manager labels: {} wellKnownPolicies: certManager: true roleName: eksctl-ryusa-cert-manager managedNodeGroups: - name: workers minSize: 1 maxSize: 6 desiredCapacity: 3 spot: true instanceTypes: - t3.medium - t3.large volumeSize: 60 volumeType: "gp3"
Getting Startedする
依存関係のセットアップ
GitLab Operatorは
を利用してGitLabを起動します。まずはこれらを適当にKubernetesにデプロイしておきましょう。
NGINX Ingress Controller
GitLabをKubernetesの外からアクセスできるようにするためのIngress ControllerとしてNGINX Ingress Controllerが推奨されています。実際にはIngress Controllerとして
の2点が必要な機能だと思います。
推奨に従ってNGINX Ingress ControllerをKubernetesにHelmでデプロイします。使うHelmチャートはingress-nginx/ingress-nginx
、Valueファイルは下記のYAMLで実装します。
# Helmチャート ingress-nginx/ingress-nginx controller: ingressClassResource: name: nginx enabled: true default: true # NGINX Ingress ControllerにSSH用のTCPプロキシーを作成する # 22: ${GITLAB_NAMESPACE}/${GITLAB_NAME}-gitlab-shell:22 tcp: 22: "gitlab-system/vulture-gitlab-shell:22"
cert-manager
GitLabのTLS証明書を発行するためにインストールが必須です、GitLabのシステム内部で利用する自己証明書の作成もcert-managerのIssuerを使って実装されています。
推奨に従ってcert-managerをKubernetesにHelmでデプロイします。使うHelmチャートはjetstack/cert-manager
、Valueファイルは下記のYAMLで実装します。一部項目にEKSからRoute53を変更するためのIRSAの設定が入ってますが、不要な方はスルーしてください。
# Helmチャート jetstack/cert-manager installCRDs: true # EKSのIRSAを利用するための設定 serviceAccount: create: false name: cert-manager annotations: eks.amazonaws.com/role-arn: arn:aws:iam::XXX:role/eksctl-ryusa-cert-manager securityContext: enabled: true fsGroup: 1001
今回はIssuerとしてLet's Encryptを利用するため、Let's EncryptのACMEを持つClusterIssuerを先に作成しておきます。
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt namespace: cert-manager spec: acme: email: YOUR_EMAIL privateKeySecretRef: name: letsencrypt-privatekey server: https://acme-v02.api.letsencrypt.org/directory solvers: - dns01: route53: region: YOUR_REGION hostedZoneID: HOST_ZONE_ID
External DNS
Ingressに割り振るドメイン名を自動的にDNSに設定するツールのインストールが推奨されています。GitLabをデプロイ後、デフォルトの状態で「GitLab」「MinIO」「Repository」の3つのIngressが作成され、それぞれ適切なドメイン名で名前解決できることが期待された状態でコンポーネントが起動してきます。
もちろん、Ingress作成後に手動でDNSを操作しても良いですが……素直にExternalDNSを利用した方が良いでしょう。今回はExternalDNSの公式リポジトリでホストされているマニフェストを利用してデプロイすることにします。
# 公式のRBACの定義は省略 --- apiVersion: apps/v1 kind: Deployment metadata: name: external-dns namespace: external-dns spec: strategy: type: Recreate selector: matchLabels: app: external-dns template: metadata: labels: app: external-dns annotations: # IRSAのための設定 iam.amazonaws.com/role: arn:aws:iam::XXX:role/eksctl-ryusa-external-dns-role spec: serviceAccountName: external-dns containers: - name: external-dns image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress - --domain-filter=ryusa.example.com - --provider=aws - --policy=upsert-only - --aws-zone-type=public - --registry=txt - --txt-owner-id=some-identifier securityContext: fsGroup: 65534
GitLab Operatorインストール
公式ドキュメントに沿ってインストールしていきます。
❯ GL_OPERATOR_VERSION=0.1.0 ❯ PLATFORM=kubernetes ❯ kubectl create namespace gitlab-system namespace/gitlab-system created ❯ kubectl apply -f https://gitlab.com/api/v4/projects/18899486/packages/generic/gitlab-operator/${GL_OPERATOR_VERSION}/gitlab-operator-${PLATFORM}-${GL_OPERATOR_VERSION}.yaml Warning: apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition customresourcedefinition.apiextensions.k8s.io/gitlabs.apps.gitlab.com created serviceaccount/gitlab-app created serviceaccount/gitlab-manager created serviceaccount/gitlab-nginx-ingress created role.rbac.authorization.k8s.io/gitlab-leader-election-role created role.rbac.authorization.k8s.io/gitlab-nginx-ingress created clusterrole.rbac.authorization.k8s.io/gitlab-app-role created clusterrole.rbac.authorization.k8s.io/gitlab-manager-role created clusterrole.rbac.authorization.k8s.io/gitlab-proxy-role created Warning: rbac.authorization.k8s.io/v1beta1 ClusterRole is deprecated in v1.17+, unavailable in v1.22+; use rbac.authorization.k8s.io/v1 ClusterRole clusterrole.rbac.authorization.k8s.io/gitlab-metrics-reader created rolebinding.rbac.authorization.k8s.io/gitlab-leader-election-rolebinding created rolebinding.rbac.authorization.k8s.io/gitlab-nginx-ingress created clusterrolebinding.rbac.authorization.k8s.io/gitlab-gitlab-app-rolebinding created clusterrolebinding.rbac.authorization.k8s.io/gitlab-gitlab-manager-rolebinding created clusterrolebinding.rbac.authorization.k8s.io/gitlab-gitlab-proxy-rolebinding created service/gitlab-controller-manager-metrics-service created service/gitlab-webhook-service created deployment.apps/gitlab-controller-manager created Warning: cert-manager.io/v1alpha2 Certificate is deprecated in v1.4+, unavailable in v1.6+; use cert-manager.io/v1 Certificate certificate.cert-manager.io/gitlab-serving-cert created Warning: cert-manager.io/v1alpha2 Issuer is deprecated in v1.4+, unavailable in v1.6+; use cert-manager.io/v1 Issuer issuer.cert-manager.io/gitlab-selfsigned-issuer created Warning: admissionregistration.k8s.io/v1beta1 ValidatingWebhookConfiguration is deprecated in v1.16+, unavailable in v1.22+; use admissionregistration.k8s.io/v1 ValidatingWebhookConfiguration validatingwebhookconfiguration.admissionregistration.k8s.io/gitlab-gitlab-validating-webhook-configuration created ❯ kubectl get all -n gitlab-system NAME READY STATUS RESTARTS AGE pod/gitlab-controller-manager-645466b464-jxn5l 2/2 Running 0 2m5s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/gitlab-controller-manager-metrics-service ClusterIP 10.100.68.88 <none> 8443/TCP 2m10s service/gitlab-webhook-service ClusterIP 10.100.163.107 <none> 443/TCP 2m9s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/gitlab-controller-manager 1/1 1 1 2m10s NAME DESIRED CURRENT READY AGE replicaset.apps/gitlab-controller-manager-645466b464 1 1 1 2m11s
いい感じに起動しますね、ヨシ!これからGitLab OperatorがWatchしているGitLabリソースをKubernetesにデプロイして、GitLab OperatorにGitLab本体をデプロイしてもらいましょう。
GitLabをデプロイする
GitLab Operatorをデプロイした際にGitLabリソースのCustom Resource Definition(CRD)もデプロイされています。
❯ kubectl api-resources --api-group apps.gitlab.com NAME SHORTNAMES APIVERSION NAMESPACED KIND gitlabs gl apps.gitlab.com/v1beta1 true GitLab
GitLab OperatorはOperator SDKのHelm Operatorで実装されています。つまりGitlabリソースのスキーマはHelmチャート(gitlab/gitlab)と同一になっています。
GitLabのHelmチャートを参考にしつつ、cert-managerとExternalDNS、NGINX Ingress Controllerと連携するGitLabリソースを作成していきます。
まずは*.ryusa.example.com
ワイルドカードの証明書のためCertificateリソースを作成しておきます。このリソースをあとでGitLabリソースに連携し、すべてのIngressがこのCertificateリソースを参照できるようにします。
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: gitlab-tls namespace: gitlab-system spec: dnsNames: - "*.ryusa.example.com" issuerRef: group: cert-manager.io kind: ClusterIssuer name: letsencrypt secretName: gitlab-tls
Certificateリソースが作成され、TLS証明書が発行されたらGitLabをデプロイしましょう。
apiVersion: apps.gitlab.com/v1beta1 kind: GitLab metadata: name: vulture namespace: gitlab-system spec: chart: version: "5.2.4" values: global: hosts: # `gitlab` `registory` `minio`のサブドメインが生えてくる domain: ryusa.example.com ingress: # NGINX Ingress Controllerを使うように指定 class: nginx configureCertmanager: false # *.ryusa.example.com ワイルドカード証明書を指定 tls: secretName: gitlab-tls nginx-ingress: enabled: false certmanager: install: false
これでGitLabをKubernetes上に展開できました。(長い……)
サクッと運用してみる
それではGitLabで運用作業をやってみましょう!とはいえGitLab OperatorはDay 2 Operationを効率化するためのツールなので、バックアップやバージョンアップなどは非常にシンプルに行うことができます。
実際にコマンドを叩いて動かしてみます。
バックアップ
GitLabリソースを作成するとデフォルトでハウスキーピング用のTask-Runnerが起動します。このTask-Runnerにバックアップ含め様々な作業をお願いすることができます(らしい)。Task-RunnerのPodにはデフォルトでMinIOへの接続情報が保存されているため、Podの内部でbackup-utility
コマンドをキックするだけでバックアップを保存することができます。
❯ kubectl exec -it \ -n gitlab-system task-runner-b854bfbd7-zrfgw -- backup-utility Defaulted container "task-runner" out of: task-runner, certificates (init), configure (init) Dumping database ... Dumping PostgreSQL database gitlabhq_production ... [DONE] done ... Dumping pages ... empty Packing up backup tar [DONE] Backup can be found at s3://gitlab-backups/XX_gitlab_backup.tar
すごく簡単、これでMinIOのオブジェクトストレージにバックアップが保存されました。
なお、GitLabリソースのTask-Runnerのサブチャートにバックアップのcron設定を追加することで定期的にバックアップを取ってくれるようになるらしいです。(未確認
apiVersion: apps.gitlab.com/v1beta1 kind: GitLab metadata: name: vulture namespace: gitlab-system spec: chart: version: "5.2.4" values: # 省略 gitlab: task-runner: enabled: true backups: cron: enabled: true # 毎日朝3時にバックアップを取得 schedule: '0 3 * * *'
リストア
リストア……を完全自動化することはあまりないと思いますが、手動バックアップと同じようにデータをリストアすることができます。バックアップと同じようにTask-Runner Podのコンテナ上でbackup-utility
コマンドをキックするだけです。
❯ kubectl exec -it -n gitlab-system vulture-task-runner-7dd4d9c4bd-dgs6l \ -- backup-utility --restore -f 'https://minio.ryusa.example.com/gitlab-backups/XXX_gitlab_backup.tar?...' ... [DONE] done
ただし上記コマンドでリストアできるのはデータのみであり、鍵などの秘密情報はリストアしてくれません。GitLabの再インストールなどする場合は、Secretリソースを自分でリストアする必要があります。(ドキュメントに記載あり)
GitLabアップグレード
Gitlabのバージョンをアップグレードするには、対応するHelmチャートのバージョンを変更してapplyすればOKです。あとの処理はOperatorが実施してくれます。
上記でインストールしたGitLabリソースのHelmチャートバージョンは5.2.4
ですので、これを5.3.0
にアップグレードにします。これによりインストールされるGitLabのバージョンが14.2.4
から14.3.0
に上がります。
apiVersion: apps.gitlab.com/v1beta1 kind: GitLab metadata: name: vulture namespace: gitlab-system spec: chart: # 5.2.4 -> 5.3.0 version: "5.3.0" # あとは省略
まとめ
GitLab Operatorを利用することでKubernetes上にGitLabを展開し、Kubernetesの言葉でGitLabを管理できるようになるところを確認しました。日時のバックアップや機能の拡張、アップデートなど日々の作業の多くをkubectl
コマンドだけで管理できるようになるのは、少なくとも個人的には嬉しいですね。
今回はcert-managerやNGINX Ingress ControllerをGitLab Operator内蔵のものではないExternalなものと連携しましたが、他にもいくつかのコンポーネントをExternalに変更できるみたいです。特にPostgreSQLやObject Storageなどの状態を持つものはマネージドサービスで使いたいところですね。
このGitLab Operatorはまだまだ開発中とのことで、Issueを見ている限り面白そうなIssueがいくつか上がってます。(ダウンタイムなしアップグレードとか、アツい……!)
現時点ではまだHelm版とOperator版のGitLabの間のクリティカルなギャップがあるわけではない(と思う)ですが、Operatorによる管理はHelmより柔軟な運用が可能になるのでこれからのロードマップに期待ですね。