FRONT-END.AI Blog

FRONT-END.AIやAI/機械学習に関する最新情報を発信しています

cert-manager (v1.0.0以前)を最新版へ入れ替える方法

CTOのshirailyです。cert-managerの更新でいくつかハマりポイントがあったので紹介します。

はじめに

cert-managerはKubernetesのアドオンで、証明書の取得・更新・利用をシンプルにしてくれます。

Tsunagu.AIではフロントエンド開発を自動化する FRONT-END.AI アプリケーションのSSL証明書ソースとして一部Let's Encryptを利用しており、 その取得・更新・利用のプロセスをGKE上のcert-managerで自動化しています。

弊社ではv1.0.0以前 (0.12.0) というかなり古いバージョンを削除したうえで最新版を新規作成しました。 本記事では、最終的にうまく行った手順や検証時のハマりポイントを紹介します。

前提

  • アップデート前: 0.12.0
  • アップデート後: 1.7.1 (アップデート作業時点での最新版)
  • cert-managerはhelmでインストール
用語

簡易的に↓と記載します。

  • カスタムリソースまたは単にAPI: DeploymentやPodsのように、独自に定義したリソース。
  • CRDオブジェクト: カスタムリソースのエンティティ(つまり実体)。

たとえばカスタムリソースIssuer

# Source: cert-manager/templates/templates.out
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
spec:
  group: cert-manager.io
  names:
    kind: Issuer
    listKind: IssuerList
...

と宣言し(v1.7.1のファイルはこちら)、kubectl applyしてクラスタで利用できます。

一方CRDオブジェクトは実体で

apiVersion: cert-manager.io/v1
kind: Issuer
spec:
  ...

などとなりますが、内容はユーザー自身が定義します。Deploymentなどと同様です。

手順

最終的な手順はこのようになります*1。ですので正確には「更新」ではなく「削除」+「新規作成」です。

まず、事前に関連するCRDオブジェクト( CertificateIssuer )の宣言を削除、Ingressのマニフェストを更新します。

# 事前準備を適用
helm upgrade
# cert-manager自体のアンインストール
helm delete --purge cert-manager
# namespaceの削除
kubectl delete namespace cert-manager
# 古いカスタムリソースの削除
kubectl delete -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.12/deploy/manifests/00-crds.yaml
# カスタムリソースの作成
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.7.1/cert-manager.crds.yaml
# cert-managerのインストール
helm install -n cert-manager jetstack/cert-manager --namespace cert-manager --version v1.7.1
# 関連するCRDオブジェクト( `Certificate`と`Issuer` )のAPIバージョンなどを適切に書き換えてから
helm upgrade

手順自体は公式のreinstall手順を修正したもので、解説は省きます。

ポイント

CRDオブジェクトの書き換え

v0.12.0とv1.7.1では書き方が大きく異なりますが、 cmctl convertという便利コマンドで書き換えられます。

cmctl convert -f your-certificate.yaml

helmを利用している場合はテンプレート文字列部分を一時的にダミー文字列で置き換えてから実行します。

v1.0.0以前からv1.8など最新版への直接更新は複雑

直接更新する方法はありますが、 リスクを考慮すると削除+新規作成のほうが断然楽です。

CRDオブジェクトより先にカスタムリソースAPIを削除するとリカバリが困難

helm upgradeは直前のリリースとの差分をもとにクラスタへ更新をかけます(新たなリリースを作成します)。 そのため、「直前のリリースを解釈」できる必要があります。

よって、CRDオブジェクトが古いAPI versionを利用している状態でAPIを先に削除すると、 helm upgradeがCRDオブジェクトのマニフェストを解釈できず失敗します。

その場合次のようなログが出力されます。

Error: current release manifest contains removed kubernetes api(s) for this kubernetes version
  and it is therefore unable to build the kubernetes objects for performing the diff.
  error from kubernetes: [
    unable to recognize "": no matches for kind "Certificate" in version "cert-manager.io/v1alpha2",
    unable to recognize "": no matches for kind "Issuer" in version "cert-manager.io/v1alpha2"
  ]

この状態になるとhelmではリカバリできず、手動での煩雑なリカバリが必要です*2

... when Kubernetes removes an API version, the Kubernetes Go client library can no longer parse the deprecated objects and Helm therefore fails when calling the library. Helm unfortunately is unable to recover from this situation and is no longer able to manage such a release.

私は開発環境で起こしてしまったので諦めてhelm installし直しました。。

コマンドが正常に通らないことがあった

kubectl delete namespace cert-manager がスタックするとき、 webhook APIの削除 またはfinalizersを手で空にして適用が参考になります。 finalizersを空にする方法は

# これはうろ覚えです
kubectl describe namespace cert-manager -o json > cert-manager.json
# 適用
kubectl replace --raw "/api/v1/namespaces/cert-manager/finalize" -f ./cert-manager.json 

最後に

セキュリティ面もそうですが大量のリリースノートを一気に精査するのがつらかったので、今後は早め早めに移行しようと思います。

本記事は副業メンバーの @hide04241990 さんにも協力いただきました。ありがとうございました!!

なお、FRONT-END.AIを運営するTsunagu.AIでは正社員・副業・フリーランスエンジニアを積極的に募集しています。 本記事はインフラについてでしたが、Vue.js / TypeScript / Python / 自動化あたりに関心がある方だとより楽しめるかと思います。

※もちろんインフラまわりも希望に応じて担当したり一緒に進められます! 応募は↓

www.wantedly.com

*1:念のため。環境により手順は異なると思いますので開発環境等で検証してから実施すべきです

*2:以前試したことがあるのですが、ステップが煩雑で…失敗しました