公開:2025年2月19日

1分で読めます

継続的デリバリーにおける信頼できる情報源としてOCIイメージを活用する方法

GitOpsワークフローの一環としてOpen Container Initiative(OCI)イメージを活用する利点、およびKubernetesへのデプロイを簡素化するためにGitLabが提供する多くの機能について詳しくご紹介します。

gitリポジトリをデプロイメントアーティファクトとして使用しない場合でも、それをGitOpsと呼ぶのは適切なのでしょうか?gitは依然としてGitOpsワークフローの中心的な要素ですが、近年では、インフラ定義をOpen Container Initiative(OCI)アーティファクトとしてコンテナレジストリに保存し、それをGitOpsデプロイのソース(情報源)とする手法が広まりつつあります。この記事では、この傾向の背後にある考え方、およびGitLabの機能がどのようにGitOpsワークフローの進化を支えているのかについて詳しくご説明します。

GitOpsとは?

OpenGitOpsプロジェクトでは、GitOpsの実践に関する以下の4つの原則を定義しています。

GitOpsの一例として、マイクロサービスのKubernetesマニフェストをGitLabプロジェクトに保存することが挙げられます。これらのKubernetesリソースは、マイクロサービスがデプロイされたKubernetesクラスター上で実行されているコントローラーによって継続的に調整されます。これにより、エンジニアは通常のコード作業と同じワークフローを使用してインフラを管理できます。たとえば、マージリクエストを作成し、変更を加えてレビューしたり、変更にバージョン管理を適用することができます。GitOpsは、構成ドリフトを防ぐといった運用上の利点もあり、エンジニアが特定の展開結果に至った変更を監査するのにも役立ちます。

GitOpsワークフローにおけるgitの利点と制限

gitはGitOpsワークフローにおいて不可欠な要素ではありますが、もともとgitリポジトリはGitOpsコントローラによってデプロイされることを前提に設計されたものではありません。gitによってエンジニア同士が連携しながらインフラに変更を加えたり、その後変更を監査したりすることはできます。しかし、コントローラーが正常にデプロイを実行するために、gitリポジトリ全体をダウンロードする必要はありません。GitOpsコントローラーが必要とするのは、特定の環境のインフラ定義だけです。

さらに、デプロイプロセスにおいて重要なのは、デプロイの変更が信頼できるソースから行われたものであることを確認するために、デプロイに署名して検証することです。Gitのコミットは、GitOpsコントローラーによって署名・検証することが可能ですが、コミットはデプロイに関連しない他の詳細(ドキュメントの変更、他の環境の更新、Gitリポジトリの再構成など)を含むこともあります。また、1回のデプロイが複数のコミットにまたがる場合があるため、デプロイ全体が十分に反映しきれないこともあります。これもまた、このgit機能が設計されていないケースのように感じます。

GitOpsワークフローにおけるgitのもう一つの課題は、想定以上に自動化が進んでしまう可能性があることです。監視しているブランチに変更をマージすると、すぐにデプロイされてしまいます。これは、gitの外側にプロセスを制御する仕組みがないためです。たとえば、金曜日の午後遅くにデプロイが行われないようにするにはどうすればよいでしょうか?あるいは、デプロイ担当のチームが特定のGitLabプロジェクトで変更をマージする権限を持っていない場合、どう対処すればよいのでしょうか?OCIイメージを使用することで、プロセスにパイプラインが追加され、承認やデプロイの停止といったデリバリー制御の機能を活用できるようになります。

OCIイメージ

Open Container Initiativeは、コンテナ形式に関する標準を定義するために貢献してきました。多くのエンジニアは、Dockerfileを使用してコンテナイメージを作成することに慣れていますが、Kubernetesマニフェストをコンテナレジストリに保存することにはあまり馴染みがないかもしれません。GitLabのコンテナレジストリはOCI準拠であるため、特定の環境向けのKubernetesマニフェストをコンテナレジストリにプッシュすることができます。これにより、Flux CDのようなGitOpsコントローラーは、gitリポジトリ全体をクローンすることなく、このOCIアーティファクトに保存されたマニフェストを利用してデプロイを実行できます。

GitOpsワークフローでは、gitリポジトリにマイクロサービスがデプロイされるすべての環境のインフラ定義が含まれていることがよくあります。特定の環境向けのKubernetesマニフェストをパッケージ化することで、Flux CDはデプロイに必要な最小限のファイルだけをダウンロードして、特定の環境へのデプロイを実行できます。

OCIアーティファクトのセキュリティ上の利点

前述のとおり、環境にデプロイされるアーティファクトに署名し、検証することで、ソフトウェアプロジェクトのセキュリティが一層強化されます。Kubernetesマニフェストがコンテナレジストリにプッシュされた後、Sigstore Cosignのようなツールを使用してOCIイメージに秘密鍵で署名できます。この秘密鍵は、GitLabプロジェクト内のCI/CD変数として安全に保存できます。その後、Flux CDはKubernetesクラスターに保存された公開鍵を使用して、デプロイが信頼できるソースから来ていることを確認できます。

GitLabを使ってOCIイメージをプッシュして署名する方法

GitLabは、OCIイメージのパッケージ化、署名、デプロイのプロセスを簡素化する多くの機能を提供しています。GitOpsワークフローにおけるGitLabプロジェクト構成の一般的な方法は、各マイクロサービスのコード用に個別のGitLabプロジェクトを用意し、すべてのマイクロサービスに共通する単一のインフラリポジトリを持つというものです。アプリケーションがn個のマイクロサービスで構成されている場合、アプリケーションにはn + 1個のGitLabプロジェクトが必要になります。

コードプロジェクトで作成されるアーティファクトは、通常、アプリケーションをパッケージ化するために使用されるコンテナイメージです。インフラプロジェクトまたはデリバリープロジェクトには、各マイクロサービスをスケールさせ、トラフィックを提供するために必要なリソースを定義したKubernetesマニフェストが含まれます。このプロジェクトで作成されるアーティファクトは通常、アプリケーションと他のマニフェストをKubernetesにデプロイするために使用されるOCIイメージです。

この構成では、環境の分離はKubernetesマニフェストを別々のフォルダに定義することで行われます。これらのフォルダは、アプリケーションをホストする環境(開発、ステージング、本番など)を表します。コードプロジェクトに変更が加えられ、新しいコンテナイメージがプッシュされた場合、その変更をGitLabのFlux CDとのインテグレーションを使ってデプロイするために必要なのは、環境フォルダ内のマニフェストを編集して新しいイメージ参照を追加し、マージリクエストを作成することだけです。マージリクエストのレビュー、承認、マージが実行されると、デリバリープロジェクトのCI/CDジョブが新しいOCIイメージをプッシュし、Flux CDがそれを受け取って新しい環境にデプロイします。

OCIイメージ - フローチャート

OCIイメージへの署名は、CosignをプロジェクトのCI/CDジョブに組み込むだけで簡単に行えます。以下のコマンドをローカルで実行することで、Cosignを使って新しい公開鍵と秘密鍵を生成できます。その際は、glab CLIを使ってGitLabインスタンスにログインし、Cosignコマンド内の[PROJECT_ID]をデリバリープロジェクトのIDに置き換えてください。

glab auth login
cosign generate-key-pair gitlab://[PROJECT_ID]

cosignコマンドが正常に実行されると、COSIGN_PUBLIC_KEYCOSIGN_PRIVATE_KEYという名前で、プロジェクトのCI/CD変数セクションにCosignキーが追加されていることが確認できます。

CI/CDジョブの例

OCIイメージをプッシュするためのGitLab CI/CDジョブは、以下のような形になります。

frontend-deploy:
  rules:
  - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    changes:
      paths: 
      - manifests/dev/frontend-dev.yaml
  trigger:
    include:
      - component: gitlab.com/components/fluxcd/[email protected]
        inputs:
          version: 0.3.1
          kubernetes_agent_reference: gitlab-da/projects/tanuki-bank/flux-config:dev
          registry_image_url: "oci://$CI_REGISTRY_IMAGE/frontend"
          image_tag: dev
          manifest_path: ./manifests/dev/frontend-dev.yaml
          flux_oci_repo_name: frontend
          flux_oci_namespace_name: frontend-dev
          signing_private_key: "$COSIGN_PRIVATE_KEY" 

GitLab CI/CDカタログには、GitLabが管理するCI/CDコンポーネント(OCIアーティファクトおよびFlux CD向け)が用意されています。このコンポーネントにより、開発チームはKubernetesマニフェストをOCIイメージとしてGitLabのコンテナレジストリや外部コンテナレジストリにプッシュし、Cosignを使用してOCIイメージに署名を行い、Flux CDを通じて新しくプッシュされたイメージをすぐに環境に同期することができます。

上記の例では、Flux CD componentがGitLabプロジェクトの.gitlab-ci.ymlファイル内に含まれています。コンポーネントの入力パラメータを使って、ユーザーはイメージのプッシュ先レジストリ(すなわちregistry_image_urlimage tag)、プッシュ対象となるKubernetesマニフェストのファイルパス(すなわちmanifest_path)、イメージの署名に使用するCosignの秘密鍵(すなわちsigning_private_key)、そして環境への更新同期に必要なKubernetes名前空間とFlux CDの OCIRepository名(すなわちflux_oci_namespace_nameflux_oci_repo_name)を定義できます。

kubernetes_agent_referenceを使用することで、各GitLabプロジェクトにkubeconfig CI/CD変数を個別に保存することなく、GitLab CI/CDジョブがKubernetesクラスターへアクセスするために必要なkubeconfigの権限を継承できるようになります。Kubernetes向けGitLabエージェントをセットアップすることで、同じGitLabグループ内のすべてのプロジェクトのCI/CDジョブに、Kubernetesクラスターへのデプロイ権限を継承させるように設定できます。

Kubernetesエージェントのコンテキストは、通常、GitLabグループ内でKubernetes向けGitLabエージェントを設定している場所で構成されます。この設定は、通常、Flux CDを管理しているプロジェクトで行うことが推奨されています。CI/CDアクセス向けのエージェント設定について詳しくは、CI/CDワークフローのドキュメントをご覧ください。

$COSIGN_PRIVATE_KEY$FLUX_OCI_REPO_NAME$FRONTEND_DEV_NAMESPACEといった変数は、機密性の高い情報をCI/CDログ上でマスキングしつつ、簡単にアクセスできるようにするためにCI/CD変数として保存されています。$CI_REGISTRY_IMAGEは、GitLabジョブでデフォルトで利用可能な変数で、対象のGitLabプロジェクトのコンテナレジストリを示します。

OCIイメージのデプロイ

Flux CDをGitLabプロジェクトと組み合わせて使用することで、マイクロサービスの各環境へのデプロイと署名の検証を自動化できます。Flux CDをGitLabプロジェクトと連携するように設定したら、プッシュしたOCIイメージを同期するために、以下のKubernetesカスタムリソース定義 CRDをプロジェクトに追加できます。

apiVersion: v1
kind: Namespace
metadata:
  name: frontend-dev
  labels:
    name: frontend-dev
---
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: cosign-public-key
  namespace: frontend-dev
spec:
  encryptedData:
    cosign.pub: AgAKgLf4VbVzJOmr6++k81LlFayx88AELaUQFNOaXmBF4G+fBfBYeABl0skNvMAa1UrPVNSfMIHgFoYHoO96g576a+epk6V6glOI+++XvYbfsygof3GGxe0nL5Qh2b3ge0fNpyd0kTPSjTj0YUhRhKtMGMRSRw1jrwhNcGxCHK+Byibs52v8Np49KsIkeZKbzLdgYABkrv+k0j7hQM+jR180NpG+2UiRvaXpPuogxkbj61FEqWGrJHk8IVyfl3eh+YhoXxOHGDqko6SUC+bUZPDBlU6yKegO0/8Zq3hwulrSEsEjzRZNK+RFVMOLWWuC6h+WGpYhAMcsZPwjjJ/y29KLNa/YeqkN/cdk488QyEFc6ehCxzhH67HxIn2PDa+KkEOTv2TuycGF+Q00jKIizXF+IwLx/oRb3pTCF0AoAY8D8N3Ey+KfkOjsBON7gGID8GbQiJqX2IgIZxFMk0JRzxbRKOEqn+guLd5Shj7CD1a1Mkk0DxBdbqrGv2XNYUaFPI7xd3rZXUJZlnv+fsmwswsiGWRuXwim45HScWzQnfgLAe7tv3spVEGeaO5apl6d89uN21PBQnfE/zyugB//7ZW9tSp6+CSMyc5HynxI8diafqiwKPgvzLmVWRnkvxJijoXicRr3sCo5RudZPSlnjfd7CKdhwEVvLl7dRR4e/XBMdxCzk1p52Pl+3/kJR+LJii5+iwOpYrpVltSZdzc/3qRd19yMpc9PWpXYi7HxTb24EOQ25i21eDJY1ceplDN6bRtop2quzkjlwVeE2i4cEsX/YG8QBtQbop/3fjiAjKaED3QH3Ul0PECS9ARTScSkcOL3I00Xpp8DyD+xH0/i9wCBRDmH3yKX18C8VrMq02ALSnlP7WCVVjCPzubqKx2LPZRxK9EG0fylwv/vWQzTUUwfbPQZsd4c75bSTsTvxqp/UcFaXA==
  template:
    metadata:
      name: cosign-public-key
      namespace: frontend-dev
---
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
    name: frontend
    namespace: frontend-dev
spec:
    interval: 1m
    url: oci://registry.gitlab.com/gitlab-da/projects/tanuki-bank/tanuki-bank-delivery/frontend
    ref:
        tag: dev
    verify:
      provider: cosign
      secretRef:
        name: cosign-public-key
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
    name: frontend
    namespace: frontend-dev
spec:
    interval: 1m
    targetNamespace: frontend-dev
    path: "."
    sourceRef:
        kind: OCIRepository
        name: frontend
    prune: true

Kustomizationリソースを使用することで、Kubernetesマニフェストをさらにカスタマイズできるほか、リソースをデプロイする対象のネームスペースも指定することができます。Flux CDのOCIRepositoryリソースでは、定期的に同期する対象となるOCIイメージのリポジトリ参照およびタグを指定できます。また、verify.providerverify.secretRefというプロパティがあることに気づくでしょう。これらのフィールドを使うことで、クラスターにデプロイされるOCIイメージが、先ほどのCI/CDジョブで使用されたCosignの秘密鍵によって署名されたものであることを検証できます。

公開鍵は、OCIRepositoryリソースと同じネームスペース内に格納する必要がある、Kubernetesシークレットに保存しなければなりません。このシークレットをFlux CDによって管理し、平文で保存しないようにするには、値を暗号化してクラスター側のコントローラーで復号させるために、SealedSecretsの使用を検討しましょう。

SealedSecretsを使わないより簡単な方法としては、kubectl CLIを使用してGitLab CI/CDジョブでシークレットをデプロイする方法があります。SealedSecretを使用しない方法では、上記で使用していたSealedSecretを削除し、新しいOCIイメージをプッシュするジョブを実行する前に、公開鍵のシークレットをデプロイするジョブを実行するだけです。これにより、シークレットがGitLab上で安全に管理され、クラスター内でOCIRepositoryから正常にアクセスできるようになります。このアプローチは比較的シンプルですが、本番環境でのシークレット管理には適していないことにご留意ください。

OCI、GitLab、およびGitOpsの利点

OCIアーティファクトを活用することで、GitOpsチームはセキュリティ面での利点を得ながら、デプロイを最小限に抑えることができます。ユーザーは、インフラの信頼できる情報源としてgitを活用できる点や、プロジェクトでのコラボレーションが可能になる点など、gitがもたらすあらゆる利点を引き続き享受できます。OCIイメージは、GitOpsにおけるデプロイの側面を強化する新たなパッケージ化手法を提供します。

GitLab は、GitOpsワークフローをよりシンプルにするための利用体験を提供できるよう、ユーザーやクラウドネイティブコミュニティから継続的に学び続けています。このブログでご紹介した機能をお使いになるには、GitLab Ultimateの60日間無料トライアルにお申込みください。これらのツールに関する皆さまのご利用体験についても、ぜひお聞かせください。フィードバックはコミュニティフォーラムにて受け付けています。

ご意見をお寄せください

このブログ記事を楽しんでいただけましたか?ご質問やフィードバックがあればお知らせください。GitLabコミュニティフォーラムで新しいトピックを作成して、ご意見をお聞かせください。

フォーチュン100企業の50%以上がGitLabを信頼

より優れたソフトウェアをより速く提供

インテリジェントなDevSecOpsプラットフォームで

チームの可能性を広げましょう。