継続的デプロイ(CD)は、新しいコードを本番環境に自動的にデプロイする方法です。ほとんどの継続的デプロイシステムは、ユニットテストと機能テストを実行することにより、デプロイされるコードが実行可能であることを検証し、すべてが正常に見える場合は、デプロイメントがロールアウトされます。通常、ロールアウト自体は、コードが期待どおりに動作しない場合にロールバックできるようにするために段階的に行われます。
AWSスタック、Google Cloudスタック、Bitbucketパイプラインなどのさまざまなツールを使用して独自のCDパイプラインを実装する方法についてのブログ投稿は少なくありません。しかし、それらのほとんどは、優れたCDパイプラインについての私の考えに合わないことがわかりました。次のようになります。最初にビルドし、ビルドされた単一のファイルのみをテストしてデプロイします。
この記事では、イベント駆動型の継続的デプロイパイプラインを構築します。このパイプラインは、最初にビルドしてから、デプロイの最終アーティファクトでテストを実行します。これにより、テスト結果の信頼性が高まるだけでなく、CDパイプラインを簡単に拡張できるようになります。次のようになります。
この記事は、Kubernetesとコンテナテクノロジーに少なくともある程度精通していることを前提としていますが、慣れていない場合や復習を使用できる場合は、を参照してください。 Kubernetesとは何ですか?コンテナ化と展開のガイド 。
ほとんどのCDパイプラインに関する私の問題は次のとおりです。通常、ビルドファイル内のすべてを実行します。これについて私が読んだほとんどのブログ投稿には、ビルドファイルに次のシーケンスのバリエーションがあります(Google CloudBuildの場合はcloudbuild.yaml
、Bitbucketの場合はbitbucket-pipeline.yaml
)。
この順序で実行することにより、テストを実行します。それらが成功した場合は、イメージを構築し、パイプラインの残りの部分に進みます。ビルドプロセスによってイメージが変更され、テストに合格しなくなった場合はどうなりますか?私の意見では、アーティファクト(最終的なコンテナイメージ)を作成することから始めるべきであり、このアーティファクトはビルドと本番環境にデプロイされる時間の間で変更されるべきではありません。これにより、アーティファクトに関するデータ(テスト結果、サイズなど)が常に有効になります。
ビルド環境を使用してイメージを本番スタックにデプロイすることにより、本番環境を効果的に変更できるようになります。ソースリポジトリへの書き込みアクセス権を持っている人なら誰でも、本番環境に対してやりたいことができるようになったので、これは非常に悪いことだと思います。
最後のステップが失敗した場合(たとえば、資格情報の問題のため)、パイプライン全体を再実行する必要があり、他のことを行うために費やすことができる時間やその他のリソースを消費します。
これは私の最後のポイントに私を導きます:
より一般的な意味では、独立したステップを持つことで、パイプラインの柔軟性を高めることができます。パイプラインに機能テストを追加したいとします。 1つのビルドファイルにステップを含めることにより、ビルド環境で機能テスト環境を起動し、その中でテストを実行する必要があります(ほとんどの場合は順次)。ステップが独立している場合は、「イメージ構築」イベントによって単体テストと機能テストの両方を開始できます。その後、それらは独自の環境で並行して実行されます。
私の意見では、この問題に取り組むためのより良い方法は、一連の独立したステップをすべてイベントメカニズムによってリンクさせることです。
これには、以前の方法と比較していくつかの利点があります。
上記のように、新しいイメージのビルドが成功すると、「ビルドの成功」イベントが公開されます。次に、このイベントがトリガーされたときに、いくつかのことを実行できます。この場合、ユニットテストと機能テストを開始します。ビルド失敗イベントがトリガーされたときや、テストに合格しなかった場合に開発者に警告するなどのことも考えられます。
各ステップを独自の環境で実行することにより、単一の環境ですべての権限を取得する必要がなくなります。これで、ビルド環境はビルドのみ、テスト環境はテストのみ、デプロイメント環境はデプロイのみが可能になります。これにより、イメージが作成された後は変更されないことを確信できます。生成されたアーティファクトは、最終的にプロダクションスタックに含まれるアーティファクトです。また、1セットの資格情報を1つのステップにリンクできるため、パイプラインのどのステップが何を行っているかを簡単に監査できます。
ビルドが成功するたびに誰かにメールを送信したいですか?そのイベントに反応してメールを送信するものを追加するだけです。簡単です。ビルドコードを変更したり、ソースリポジトリに誰かのメールをハードコーディングしたりする必要はありません。
独立したステップがあるということは、1つのステップが失敗した場合にパイプライン全体を再起動する必要がないことも意味します。失敗状態が一時的なものであるか、手動で修正されている場合は、失敗したステップを再試行できます。これにより、より効率的なパイプラインが可能になります。ビルドステップに数分かかる場合は、デプロイ環境にクラスターへの書き込みアクセス権を付与し忘れたという理由だけで、イメージを再構築する必要がないのは良いことです。
Google Cloud Platformには、このようなシステムを短時間で、非常に少ないコードで構築するために必要なすべてのツールがあります。
私たちのテストアプリケーションは、静的テキストの一部を提供するだけの単純なFlaskアプリケーションです。このアプリケーションは、より広範なインターネットにサービスを提供するKubernetesクラスターにデプロイされます。
以前に紹介したパイプラインの簡略化されたバージョンを実装します。基本的にテスト手順を削除したので、次のようになります。
これがパイプラインのグラフィック表現です。
フローは次のとおりです。
私たちのソースコード は非常にシンプルなFlaskアプリで、静的なテキストを提供するだけです。プロジェクトの構造は次のとおりです。
├── docker │ ├── Dockerfile │ └── uwsgi.ini ├── k8s │ ├── deployment.yaml │ └── service.yaml ├── LICENSE ├── Pipfile ├── Pipfile.lock └── src └── main.py
Dockerディレクトリには、Dockerイメージの構築に必要なすべてのものが含まれています。画像はに基づいています uWSGIとNginxの画像 依存関係をインストールして、アプリを正しいパスにコピーするだけです。
k8sディレクトリにはKubernetes設定が含まれています。これは、1つのサービスと1つのデプロイメントで構成されます。デプロイメントは、から構築されたイメージに基づいて1つのコンテナーを開始します Dockerfile 。次に、サービスはパブリックIPアドレスを持つロードバランサーを開始し、アプリコンテナーにリダイレクトします。
クラウドビルドの構成自体は、クラウドコンソールまたはGoogleCloudコマンドラインから実行できます。クラウドコンソールを使用することにしました。
ここでは、任意のブランチで任意のコミット用のイメージを作成しますが、たとえば、開発用と本番用で異なるイメージを使用できます。
ビルドが成功すると、クラウドビルドは独自にイメージをコンテナレジストリに公開します。次に、cloud-builds pub / subトピックにメッセージを公開します。
クラウドビルドは、ビルドの進行中と失敗したときにもメッセージを公開するため、これらのメッセージに反応させることもできます。
クラウドビルドのpub / sub通知のドキュメントは ここに そしてメッセージのフォーマットは見つけることができます ここに
企業の社会的責任は利益を増やしますか
クラウドコンソールの[cloudpub / sub]タブを見ると、クラウドビルドによってクラウドビルドと呼ばれるトピックが作成されていることがわかります。これは、クラウドビルドがステータスの更新を公開する場所です。
ここで行うことは、cloud-buildsトピックに公開されたメッセージでトリガーされるクラウド関数を作成することです。ここでも、クラウドコンソールまたはGoogleCloudコマンドラインユーティリティのいずれかを使用できます。私の場合は、クラウドビルドを使用して、変更があるたびにクラウド機能をデプロイします。
クラウド機能のソースコードは ここに 。
まず、このクラウド関数をデプロイするコードを見てみましょう。
steps: - name: 'gcr.io/cloud-builders/gcloud' id: 'test' args: ['functions', 'deploy', 'new-image-trigger', '--runtime=python37', '--trigger-topic=cloud-builds', '--entry-point=onNewImage', '--region=us-east1', '--source=https://source.developers.google.com/projects/$PROJECT_ID/repos/$REPO_NAME']
ここでは、Google CloudDockerイメージを使用します。これにより、GCcloudコマンドを簡単に実行できます。実行しているのは、ターミナルから直接次のコマンドを実行するのと同じです。
gcloud functions deploy new-image-trigger --runtime=python37 --trigger-topic=cloud-builds --entry-point=onNewImage --region=us-east1 --source=https://source.developers.google.com/projects/$PROJECT_ID/repos/$REPO_NAME
Google Cloudに、Python 3.7ランタイムを使用し、cloud-buildsトピックの新しいメッセージによってトリガーされる新しいクラウド関数をデプロイするように依頼しています(または、そのリージョンにその名前の関数が既に存在する場合は置き換えます)。また、その関数のソースコードの場所をGoogleに通知します(ここで、PROJECT_IDとREPO_NAMEは、ビルドプロセスによって設定される環境変数です)。また、エントリポイントとして呼び出す関数も指定します。
ちなみに、これを機能させるには、クラウドビルドサービスアカウントに「クラウド機能開発者」と「サービスアカウントユーザー」の両方を与えて、クラウド機能をデプロイできるようにする必要があります。
クラウド関数コードのコメント付きスニペットを次に示します。
エントリポイントデータには、pub / subトピックで受信したメッセージが含まれます。
def onNewImage(data, context):
最初のステップは、その特定のデプロイメントの変数を環境から取得することです(クラウドコンソールでクラウド機能を変更することによって変数を定義しました。
project = os.environ.get('PROJECT') zone = os.environ.get('ZONE') cluster = os.environ.get('CLUSTER') deployment = os.environ.get('DEPLOYMENT') deploy_image = os.environ.get('IMAGE') target_container = os.environ.get('CONTAINER')
メッセージの構造が期待どおりであることを確認する部分はスキップし、ビルドが成功して1つのイメージアーティファクトが生成されたことを検証します。
次のステップは、ビルドされたイメージがデプロイするイメージであることを確認することです。
image = decoded_data['results']['images'][0]['name'] image_basename = image.split('/')[-1].split(':')[0] if image_basename != deploy_image: logging.error(f'{image_basename} is different from {deploy_image}') return
ここで、Kubernetesクライアントを取得し、変更するデプロイを取得します
v1 = get_kube_client(project, zone, cluster) dep = v1.read_namespaced_deployment(deployment, 'default') if dep is None: logging.error(f'There was no deployment named {deployment}') return
最後に、デプロイメントに新しいイメージをパッチします。 Kubernetesがロールアウトを担当します。
for i, container in enumerate(dep.spec.template.spec.containers): if container.name == target_container: dep.spec.template.spec.containers[i].image = image logging.info(f'Updating to {image}') v1.patch_namespaced_deployment(deployment, 'default', dep)
これは、CDパイプラインで物事を設計する方法の非常に基本的な例です。どのpub / subイベントが何をトリガーするかを変更するだけで、より多くのステップを実行できます。
たとえば、イメージ内でテストを実行し、成功時にイベントを公開し、失敗時に別のイベントを公開するコンテナーを実行し、結果に応じてデプロイメントを更新するかアラートを出すことでそれらに対応できます。
私たちが構築したパイプラインは非常に単純ですが、他の部分のために他のクラウド関数を書くことができます(たとえば、単体テストを壊したコードをコミットした開発者に電子メールを送信するクラウド関数)。
ご覧のとおり、ビルド環境ではKubernetesクラスター内の何も変更できず、デプロイコード(クラウド関数)ではビルドされたイメージを変更できません。特権の分離は見栄えがよく、不正な開発者が本番クラスターをダウンさせないことを知って、しっかりと眠ることができます。また、私たちは私たちのより多くを与えることができます ops指向の開発者 クラウド機能コードにアクセスして、修正または改善できるようにします。
ご質問、ご意見、改善点がございましたら、以下のコメントでお気軽にお問い合わせください。
継続的デリバリーは、いつでも安定したソフトウェアをデリバリーできるようにすることを目的とした手法です。継続的デプロイはこれをさらに一歩進め、前述のソフトウェアを自動的にデプロイします(通常はサービスとしてのソフトウェア環境で)。
デプロイメントパイプラインは、開発者がアプリケーションのソースコードから本番環境で実行されているアプリケーションに移動できるようにするソフトウェアのコレクションです。これには通常、アプリケーションをビルド、テスト、およびデプロイするためのソフトウェアが含まれます。
ほとんどの従来の継続的デプロイパイプラインは、新しいアーティファクトを本番環境にプッシュするための資格情報を含むすべての情報を同じ場所に置くことに依存しています。
理想的には、パイプラインのすべての異なる部分が独立している必要があり、前のステップが成功したときにステップを開始するために何らかのタイプのイベントメカニズムを使用する必要があります。