CI / CDパイプラインを通じてアプリケーションを実行し,すべてのテストにパスしたのに,アプリケーションをターゲット環境にデプロイすると期待どおりに動作しない,という問題にぶつかったことはありませんか。本番環境でのアプリケーションの挙動を正確に予測できないという事態は,実際に多々発生しており,チームの悩みの種となっています。スモークテストは、このようなエラーを早期に発見するために、アプリケーションの重要なコンポーネントや機能だけを大まかに検証するテストです。デプロイ後にアプリケーションが期待どおりに機能することも確認できます。通常、スモークテストはすべてのアプリケーション ビルドで実行されます。より時間のかかる広範なテストに踏み切る前に、必要不可欠な基本機能に問題がないことを検証するわけです。スモークテストを実装すれば、高速なフィードバック ループの構築が促進されるため、ソフトウェア開発ライフ サイクルにおいて大きなメリットが期待できます。

この记事では,CI / CDパイプラインのデプロイステージにスモークテストを追加して,デプロイ后のアプリケーションの基本机能をテストする方法について绍介します。

使用するテクノロジー

この记事では次のテクノロジーについて言及します。

前提条件

今回は,以前の记事「基础设施代码を使用したパイプラインからのリリースの自動化」で使用した构成とコードを取り扱います。ソースコードの全文はこちらのリポジトリでご確認ください。

スモークテスト

スモークテストは,予期せぬビルドエラーや接続エラーを検出し,新しいリリースをターゲット環境にデプロイした後にサーバーから期待どおりのレスポンスがあるかどうかを検証するのに効果的です。シンプルなスモークテストでは,たとえばアプリケーションがアクセス可能で,特定の応答コード(好200年300301404など)を返すかどうかをチェックできます。この記事で紹介するスモークテストでは,デプロイ後のアプリがサーバーコード好200年を返すこと,デフォルトのページコンテンツとして期待どおりのテキストが表示されることを確認します。

スモークテストが追加されていないCI / CDパイプライン

まず,サンプルのパイプライン构成を见てみましょう。単体テストの実行と,多克尔イメージのビルドおよび泊坞枢纽へのプッシュを行うパイプライン构成です。基础设施代码(Pulumi)を使用して,新しい谷歌Kubernetes引擎(GKE)クラスタをプロビジョニングし,このリリースをクラスタにデプロイします。このサンプルパイプライン構成は,スモークテストを実装していません。このサンプルパイプラインを実行すると,新しいGKEクラスタが作成され,手動でpulumi摧毁コマンド(作成されたすべてのインフラストラクチャを終了)を実行するまで有効になります。

注意:インフラストラクチャを终了しないと,予想外のコストがかかることがあります。

版本:2.1球体:pulumi: pulumi / pulumi@1.0.1工作:build_test:码头工人:——形象:circleci / python: 3.7.2章环境:PIPENV_VENV_IN_PROJECT:“真正的”步骤:——付款——运行:名称:安装python依赖命令:| pipenv安装——skip-lock运行:名称:运行测试命令:| pipenv运行pytest build_push_image:码头工人:——形象:circleci / python: 3.7.2章步骤:-付款- setup_remote_docker: docker_layer_caching:假-运行:名称:构建和推进码头工人形象命令:运行pyinstaller -F hello_world.py echo 'export TAG=${CIRCLE_SHA1}' ' >> $BASH_ENV echo 'export IMAGE_NAME=orb- pul米-gcp' >> $BASH_ENV source $BASH_ENV docker build -t $DOCKER_LOGIN/$IMAGE_NAME -t $DOCKER_LOGIN/$IMAGE_NAME:$TAG。echo $ DOCKER_PWD |码头工人登录- u DOCKER_LOGIN美元——password-stdin码头工人推DOCKER_LOGIN /美元IMAGE_NAME deploy_to_gcp:码头工人:——形象:circleci / python: 3.7.2章环境:CLOUDSDK_PYTHON:“/ usr / bin / python2.7”GOOGLE_SDK_PATH:‘~ / google-cloud-sdk /步骤:-结帐pulumi /登录:访问令牌:$ {PULUMI_ACCESS_TOKEN} -运行:名称:安装依赖命令:| cd ~ / sudo pip安装升级pip = = 18.0 & & pip安装,用户- r项目/ reqs.txt curl - o gcp-cli.tar.gz https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz焦油-xzvf gcp-cli.tar.gz echo $ {GOOGLE_CLOUD_KEYS} | base64解码——ignore-garbage > ${回家}/项目/ pulumi /质量/ gke / cicd_demo_gcp_creds。json ./google-cloud-sdk/install.sh—quiet echo’导出路径=$PATH:~/google-cloud-sdk/bin’>> $BASH_ENV source $BASH_ENV gcloud auth激活-service-account—key-file ${HOME}/project/pulumi/gcp/gke/cicd_demo_gcp_credsjson - pulumi/更新:栈:k8s working_directory: ${HOME}/项目/pulumi/gcp/gke/工作流:build_test_deploy: jobs: - build_test - build_push_image: requires: - build_test - deploy_to_gcp: requires: - build_push_image

このパイプラインは新しいGKEクラスタに新しいアプリリリースをデプロイしますが,この自动化が完了した后,アプリケーションが実际に稼働しているかどうかを知る术はありません。アプリケーションのデプロイが完了し,新しいGKEクラスタ内で正しく机能しているかどうかをすばやく确认するにはどうしたらよいでしょうか。ここでCI / CDパイプラインにスモークテストを実装すると,デプロイ后のアプリケーションのステータスをすばやく简単に确认することができます。

スモークテストの作成方法

スモークテストを作成するにはまず,アプリケーションの机能の検证に必要なステップを定义するテストケースを开発します。テストケースの开発は,検证したい机能を特定し,そのテストシナリオを作成するプロセスの一部になっています。今回のチュートリアルでは,意図的にテスト范囲を非常に狭くしました。この场合,デプロイ后のアプリケーションにアクセスできるかどうか,デフォルトのページに期待どおりの静的テキストが表示されるかどうかの検证が最重要事项です。

以下では,このスモークテスト用のテストケースをどのようにして开発したかについて说明します。个人的には,自分の开発スタイルに沿って,テスト対象のアイテムの概要をまとめ,一覧を作成するようにしています。概要には,そのアプリ向けにスモークテストを开発したときに考虑した要素を记载します。

  • 言语/テストのフレームワーク
    • Bash
    • smoke.sh
  • テストの実行タイミング
    • GKEクラスタの作成後
  • テスト対象
    • テスト:デプロイ後のアプリケーションにアクセスできるか
      • 期待される结果:サーバーがコード200を返す
    • テスト:デフォルトページに“欢迎来到CI / CD”と表示されるか
      • 期待される結果:真正
    • テスト:デフォルトページに「版本号:」というテキストが表示されるか
      • 期待される結果:真正
  • テスト後のアクション(テストにパスしたかどうかにかかわらず実行)
    • 標準出力にテスト結果を出力
    • GKEクラスタと関連インフラストラクチャを破棄
      • pulumi摧毁を実行

このチュートリアルのテストケースの概要は完全で,テストしたい項目に関する情報が明白に記載されています。これは“テストスクリプト”とも呼ばれます。今回は,bashベースのオープンソースのスモークテストフレームワークsmoke.sh(asm89作成)を使用してスモークテストを作成しますが,お好みの言语またはフレームワークで作成してかまいません。ここでsmoke.shを选択したのは,実装しやすく,オープンソースのフレームワークだからですで。は,smoke.shフレームワークを使用して,このテストスクリプトを作成する方法について見ていきましょう。

smoke.shを使用してスモークテストを作成する

smoke.shフレームワークのドキュメントに,フレームワークの使い方が記載されています。以下には,サンプルコードのリポジトリ测试/ディレクトリにあるsmoke_testファイルを使用する場合のコード例を示します。

# ! / bin / bash测试/ smoke.shTIME_OUT=300TIME_OUT_COUNT=0PULUMI_STACK=“美丽”PULUMI_CWD=“pulumi /质量/ gke /”SMOKE_IP=$(pulumi堆栈--stackPULUMI_STACK美元慢性消耗病——PULUMI_CWD美元输出app_endpoint_ip)SMOKE_URL=“http://SMOKE_IP美元真正状态=$(卷曲-s-o的/ dev / null的-w“% {http_code}”SMOKE_URL美元)如果(美元的地位当量200];然后smoke_url_okSMOKE_URL美元smoke_assert_body“欢迎到CI / CD”smoke_assert_body版本号:“smoke_report回声\ n \ n回声“烟雾测试成功完成。”回声“300第二终接的Kubernetes集群......”睡眠300年pulumi摧毁--stackPULUMI_STACK美元慢性消耗病——PULUMI_CWD美元——是的打破elif[[TIME_OUT_COUNT美元-gt$ TIME_OUT]];然后回声"进程已超时! "运行超时统计. .TIME_OUT_COUNT美元pulumi摧毁--stackPULUMI_STACK美元慢性消耗病——PULUMI_CWD美元——是的退出1其他回声“检查主机状态$ SMOKETIME_OUT_COUNT美元秒运行”TIME_OUT_COUNT=$ ((TIME_OUT_COUNT + 10))科幻睡眠10完成

次に,smoke_testファイルで何が行われているかを説明します。

smoke_testファイルの解説

ファイルの先頭から見ていきましょう。

# ! / bin / bash测试/ smoke.sh

上のスニペットでは,猛砸バイナリを使用するよう指定しています。また,smoke_testスクリプトにインポートまたは追加する,コアのsmoke.shフレームワークのファイルパスを指定しています。

TIME_OUT = 300 TIME_OUT_COUNT = 0 PULUMI_STACK = “K8S” PULUMI_CWD = “pulumi / GCP / GKE /” SMOKE_IP = $(pulumi堆--stack $ PULUMI_STACK --cwd $ PULUMI_CWD输出app_endpoint_ip)SMOKE_URL = “HTTP:// $ SMOKE_IP”

上のスニペットは,smoke_testスクリプトで使用する环境変数を定义しています。以下に,环境変数の说明を一覧します。

  • PULUMI_STACK = “K8S”——pulumiがpulumiアプリスタックを指定するために使用します。
  • PULUMI_CWD = " pulumi /质量/ gke /”- pulumiインフラストラクチャコードのパス。
  • SMOKE_IP=$(pulumi stack—stack $PULUMI_STACK—cwd $PULUMI_CWD output app_endpoint_ip)——GKEクラスタ上のアプリケーションのパブリックIPアドレスを取得するPulumiコマンド。この変数はスクリプト全体で使用します。
  • SMOKE_IP美元SMOKE_URL = " http:// "——GKEクラスタ上のアプリケーションのurlエンドポイントを指定します。
而真正做STATUS = $(卷曲-s -o的/ dev / null的-w '%{HTTP_CODE}' $ SMOKE_URL)如果[$ STATUS当量200];然后smoke_url_ok $ SMOKE_URL smoke_assert_body “欢迎CI / CD” smoke_assert_body “版本号:” smoke_report回声 “\ n \ n” 回声 '冒烟测试顺利完成。'回声 '终止的Kubernetes集群300,其次...' 睡300个pulumi破坏--stack $ PULUMI_STACK --cwd $ PULUMI_CWD --yes打破的elif [$ TIME_OUT_COUNT -gt $ TIME_OUT];然后回声“过程已超时!经过的超时计数.. $ TIME_OUT_COUNT” pulumi破坏--stack $ PULUMI_STACK --cwd $ PULUMI_CWD --yes出口1个别的回声“在主机上$ SMOKE检查状态... $ TIME_OUT_COUNT秒过去了”TIME_OUT_COUNT = $((TIME_OUT_COUNT + 10))Fi休眠10完成

上のスニペットがすべての魔法の源となる部分です。ループは,条件が真正になるかスクリプトが終了するまで実行されます。この場合,ループは卷曲コマンドを使ってアプリケーションが好200年応答コードを返すかどうかをテストします。このパイプラインは新しいGKEクラスタをゼロから作成するので,谷歌云平台でトランザクションが発生します。スモークテストを始める前に,この处理が完了するのを待ちましょう。まずGKEクラスタとアプリケーションサービスを稼働させる必要があります。美元的地位変数には,旋度リクエストの結果が入ります。次に,値が200かどうかのテストが行​​われます。それ以外の场合,ループはTIME_OUT_COUNT美元変数を10秒インクリメントして,10秒待ってから卷曲リクエストをもう一度実行します。これはアプリケーションが応答するまで繰り返されます。クラスタとアプリケーションが稼働していて,応答を返す場合,状态変数が200応答コードを生成し,テストの残りの部分が実行されます。

smoke_assert_body “欢迎到CI / CD”およびsmoke_assert_body "版本号:"ステートメントで、Webページに欢迎と版本号のテキストが表示されるかどうかをテストします。結果が假なら,テストは失敗し,パイプラインのエラーになります。結果が真正なら,アプリケーションは200応答コードを返し,テキストテストの結果が真正になります。するとスモークテストがパスして,pulumi摧毁コマンドが実行され,このテストケースのために作成されたすべてのインフラストラクチャが終了します。このクラスタはもう必要ないので,テストで作成されたすべてのインフラストラクチャが終了します。

このループには,アプリケーションが$ TIME_OUT値を超过したかどうかを确认するelif(否则如果)ステートメントも含まれています。elifステートメントは,例外处理の一例で,予期しない結果が発生した場合の制御に使用します。TIME_OUT_COUNT美元値がTIME_OUT値を超過した場合,pulumi摧毁コマンドが実行され,新しく作成されたインフラストラクチャが终了します。さらに1号出口コマンドにより,パイプラインビルドプロセスが失敗します。テスト以外の目的にはこのインフラストラクチャは必要ないため、テスト結果にかかわらず、GKE クラスタは終了します。

パイプラインにスモークテストを追加する

ここまでの手順では,サンプルのスモークテストと,テストケースの開発プロセスについて説明してきました。ここでは,上記のCI / CDパイプライン構成にスモークテストを統合します。deploy_to_gcpジョブのpulumi /更新ステップの下に,新しい运行ステップを追加します。

...  - 运行:名称:对GKE命令运行冒烟测试:|回声“的GKE集群初始化冒烟测试” ./tests/smoke_test回声“GKE集群测试及销毁” ...

上のスニペットは,既存のCI / CDパイプラインにsmoke_testスクリプトを统合し,実行する方法を示しています。パイプラインに新しい运行ブロックを追加すると,各パイプラインビルドが実行中のGKEクラスタ上のアプリケーションをテストし,アプリケーションがすべてのテストケースをパスしたという検证结果を返すようになります。特定のリリースをテスト済みのターゲット环境(この例の场合は谷歌Kubernetesクラスタ)にデプロイすると,名目上実行されます。

まとめ

この记事では,CI / CDパイプラインでスモークテストと基础架构代码を利用して,ターゲットデプロイ环境でビルドをテストする利点について详しく绍介しました。ターゲット环境でアプリケーションをテストすると,同じターゲット环境にデプロイしたときのアプリケーションの挙动について贵重なインサイトが得られます.CI / CDパイプラインにスモークテストを実装することで,アプリケーションビルドの信頼性がいっそう高まります。

ご質問,ご意見,ご感想がございましたら,Twitterで@punkdata宛にメンションしてください。

最后までお読みいただき,ありがとうございました。