マイクロサービス CI/CD 実践 - GitOps の完全な設計と実装

マイクロサービス CI/CD 実践 - GitOps の完全な設計と実装

[[422238]]

単一のアプリケーションと環境

複数のアプリケーションと環境

CI 継続的インテグレーション

まず、コードベースを準備します。

https://github.com/DevOpsCICDCourse/microservicescicd/blob/main/microservice-demo-service-master.zip

CI パイプラインのステップを整理してみましょう。

  • 今回実装したコードリポジトリタイプは単一リポジトリ、つまり 1 つのリポジトリに複数のサービスモジュールコードが格納され、各サブディレクトリがサービスモジュールとなります。
  • まず、継続的インテグレーション パイプラインは、現在のコミットがどのサービス コードであるかを正しく取得できる必要があります。
  • サービスを決定し、サービス コードをダウンロードして、コンパイルとパッケージ化、単体テスト、コード スキャン、イメージの構築などの手順を実行します。

コミットサービス情報を取得するにはどうすればよいですか?ここでは、GitLab WebHook 関数と Jenkins ジョブ ビルド トリガーを使用してこれを実現します。

ワークフローは次のとおりです。Gitlab でコードを送信すると、GitLab Webhook を通じて Jenkins Scheduler ジョブがトリガーされ、送信されたコードによって生成されたフック データが POST モードで Jenkins ジョブに渡されます。この時点で、Generic Hook プラグインを使用してこの POST リクエストによって送信されたリクエスト本文情報を取得するように Jenkins ジョブを記述できます。これは JSON データです。ジョブの実行後、変更されたサービス モジュール情報を取得するために JSON でデータを解析するパイプラインを記述します。最後に、対応するサービスの CI ジョブが構築のためにトリガーされます。

CI スケジューラ ジョブ

このジョブでは、Webhook を有効にしてトリガー トークン (一意性) を構成することだけが必要です。 hookurl を生成します: http://jenkins.idevops.site/generic-webhook-trigger/invoke?token=microservicecicd-scheduler-CI

ジェンキンスファイル

  1. パイプライン
  2. エージェント  
  3.  
  4. ステージ{
  5.  
  6. ステージ( "GetData" ){
  7. ステップ{
  8. スクリプト {
  9. echo "${webHookData}"  
  10.  
  11. データ = readJSON テキスト: "${webHookData}"  
  12.  
  13. println(データ)
  14.  
  15. env.branchName = data.ref - "refs/heads/"  
  16. env.commitId = data.checkout_sha
  17. env.projectId = データ.プロジェクトID
  18. commits = data[ "コミット" ]
  19.  
  20. println( "${env.branchName}" )
  21. println( "${env.commitID}" )
  22. println( "${env.projectId}" )
  23.  
  24. //env.moduleName = "service01"  
  25. 変更サービス = []
  26. コミット コミット){
  27. println(コミット.id)
  28.  
  29. //追加した
  30. 追加  コミット.added) {
  31. s =リストとして.split( "/" )を追加
  32. s.size ()> 1)の場合{
  33. (changeServices.indexOf(s[0]) == -1)の場合{
  34. サービスを変更します。追加(s[0])
  35. }
  36. }
  37. }
  38.  
  39. //変更済み
  40.  コミット.modified) {
  41. s = m.split( "/" )リストとして
  42. // println s
  43. // println s.size ()
  44. // s[0]を印刷する
  45. s.size ()> 1)の場合{
  46. // println changeServices.indexOf(s[0])
  47. (changeServices.indexOf(s[0]) == -1)の場合{
  48. サービスを変更します。追加(s[0])
  49. }
  50. }
  51. }
  52.  
  53. //削除されました
  54. (r場合 コミット.removed) {
  55. s = r.split( "/" )リストとして
  56. 印刷する
  57. s.size ()> 1)の場合{
  58. (changeServices.indexOf(s[0]) == -1)の場合{
  59. サービスを変更します。追加(s[0])
  60. }
  61. }
  62. }
  63. }
  64.  
  65. println(サービスの変更)
  66. //currentBuild.description = "トリガー  ${eventType} ${changeServices}による
  67. }
  68. }
  69. }
  70.  
  71. ステージ( 'DefineService' ){
  72. 手順 {
  73. スクリプト{
  74. println(サービスの変更)
  75. //サービス構築順序制御
  76. サービス = [ 'service02' , 'service01' ]
  77. (サービス内のサービス){
  78. (changeServices.indexOf(サービス) != -1)の場合{
  79. ジョブ名 = 'microservicecicd-' +サービス+ '-service-CI'  
  80. ビルドジョブ: jobName、待機: false 、パラメータ: [string( name : 'branchName' 、値: "${env.branchName}" )、
  81. 文字列(名前: 'commitId' 、値: "${env.commitId}" )、
  82. 文字列(名前: 'projectId' 、値: "${env.projectId}" )]
  83. }
  84. }
  85. }
  86. }
  87. }
  88. }
  89. }

GitLab WebHookの設定

Webhook を有効にし、hookurl を設定します: http://jenkins.idevops.site/generic-webhook-trigger/invoke?token=microservicecicd-scheduler-CI

CIパイプライン-CI操作

各マイクロサービスは、ブランチ名、コミット ID、プロジェクト ID の 3 つの文字列パラメータを持つ CI ジョブを作成します。

ジェンキンスファイル

  1. 文字列 branchName = "${env.branchName}"  
  2. 文字列 moduleName = "${JOB_NAME}" .split( "/" )[1].split( "-" )[1]
  3. 文字列 srcUrl = "http://gitlab.idevops.site/microservicecicd/microservicecicd-demo-service.git"  
  4. 文字列 commitId = "${env.commitId}"  
  5. 文字列 projectId = "${env.projectId}"  
  6.  
  7. パイプライン
  8. エージェント { ノード { ラベル"build" } }
  9.  
  10. ステージ {
  11. ステージ( 'GetCode' ){
  12. 手順 {
  13. スクリプト {
  14. チェックアウト([$class: 'GitSCM' ,
  15. ブランチ: [[名前: "${branchName}" ]],
  16. doGenerateSubmoduleConfigurations: false
  17. 拡張機能: [[$class: 'SparseCheckoutPaths' ,
  18. sparseCheckoutPaths: [[パス: "${moduleName}" ],[パス: 'Dockerfile' ]]]],
  19. サブモジュール構成: [],
  20. userRemoteConfigs: [[credentialsId: 'gitlab-admin-user' ,
  21. URL: "${srcUrl}" ]]])
  22. }
  23.                  
  24. }
  25. }
  26.  
  27. ステージ( "ビルド&テスト" ){
  28. ステップ{
  29. スクリプト{
  30. echo "ビルド..........."  
  31.  
  32. sh "" "
  33. cd ${モジュール名}
  34. mvn クリーンパッケージ
  35.  
  36. 「」 「
  37. }
  38. }
  39. 役職 {
  40. いつも {
  41. junit "${moduleName}/target/surefire-reports/*.xml"  
  42. }
  43. }
  44. }
  45.  
  46. ステージ( "SonarScan" ){
  47. ステップ{
  48. スクリプト{
  49.  
  50. def sonarDate = sh returnStdout: true 、スクリプト: 'date +%Y%m%d%H%M%S'  
  51. sonarDate = sonarDate - "\n"  
  52.  
  53. withCredentials([文字列(credentialsId: 'sonar-admin-user' 、変数: 'sonartoken' )、
  54. 文字列(資格情報ID: 'gitlab-user-token' 、変数: 'gitlabtoken' )]) {
  55. //ブロック
  56. sh "" "
  57. cd ${モジュール名}
  58. ソナースキャナー \
  59. -Dsonar.projectKey=${ジョブ名} \
  60. -Dsonar.projectName=${ジョブ名} \
  61. -Dsonar.projectVersion=${sonarDate} \
  62. -Dsonar.ws.タイムアウト=30 \
  63. -Dsonar.projectDescription= "xxxxxxx" \
  64. -Dsonar.links.homepage=http://www.baidu.com \
  65. -Dsonar.sources=src \
  66. -Dsonar.sourceEncoding=UTF-8 \
  67. -Dsonar.java.binaries=ターゲット/クラス\
  68. -Dsonar.java.test.binaries=ターゲット/テストクラス\
  69. -Dsonar.java.surefire.report=ターゲット/surefire-reports \
  70. -Dsonar.host.url= "http://sonar.idevops.site" \
  71. -Dsonar.login=${sonartoken} \
  72. -Dsonar.gitlab.commit_sha=${コミットID} \
  73. -Dsonar.gitlab.ref_name=${ブランチ名} \
  74. -Dsonar.gitlab.project_id=${プロジェクトID} \
  75. -Dsonar.dynamicAnalysis=レポートの再利用\
  76. -Dsonar.gitlab.failure_notification_mode=コミット-ステータス \
  77. -Dsonar.gitlab.url=http://gitlab.idevops.site \
  78. -Dsonar.gitlab.user_token=${gitlabtoken} \
  79. -Dsonar.gitlab.api_version=v4
  80.  
  81. 「」 「
  82.  
  83. }
  84.   
  85. }
  86. }
  87. }
  88.  
  89. ステージ( "BuildImage" ){
  90. ステップ{
  91. スクリプト{
  92.  
  93. withCredentials([usernamePassword(credentialsId: 'aliyun-registry-admin' 、passwordVariable: 'password' 、usernameVariable: 'username' )]) {
  94.                  
  95. env.nowDate = sh returnStdout: true 、スクリプト: 'date +%Y%m%d%H%M%S'  
  96. env.nowDate = env.nowDate - "\n"  
  97.  
  98. env.releaseVersion = "${env.branchName}"  
  99. env.imageTag = "${releaseVersion}-${nowDate}-${commitId}"  
  100. env.dockerImage = "registry.cn-beijing.aliyuncs.com/microservicecicd/microservicecicd-${moduleName}-service:${env.imageTag}"  
  101. env.jarName = "${モジュール名}-${ブランチ名}-${コミットID}"  
  102. sh "" "
  103. docker login -u ${ユーザー名} -p ${パスワード} registry.cn-beijing.aliyuncs.com
  104. cd ${moduleName} && docker build -t ${dockerImage} -f ../Dockerfile --build-arg SERVICE_NAME=${jarName} .  
  105. 睡眠1
  106. docker プッシュ ${dockerImage}
  107. 睡眠1
  108. docker rmi ${dockerImage}
  109. 「」 「
  110. }
  111.  
  112.  
  113. }
  114. }
  115. }
  116.  
  117.          
  118. }
  119. }

GitOps-CI 拡張機能

元の CI ジョブの手順に基づいて、環境を更新する手順が追加されます。 GitOps プラクティスでは、現在の基本環境デプロイメント ファイルを Git リポジトリに保存します。 CI ジョブがイメージのアップロードを完了すると、環境デプロイメント ファイル内のイメージ タグ情報も更新されます。 (そのため、まず環境ファイルを取得して更新する必要があります)

  1. ステージ( "PushFile" ){
  2. //いつ{
  3. // 式 { "${env.branchName}" . ( "RELEASE-" )を含む}
  4. // }
  5. ステップ{
  6. スクリプト{
  7. if ( "${env.branchName}" . contains ( "RELEASE-" )){
  8. println( "ブランチ名 = ブランチ名" )
  9. env.branchName = "マスター"  
  10.  
  11. }それ以外{
  12. env.branchName = "機能"  
  13. }
  14.  
  15. (i = 0; i < 3; i++)の場合{
  16. //バージョンライブラリファイルをダウンロードする
  17. 応答 = GetRepoFile(40, "${moduleName}%2fvalues.yaml" , "${env.branchName}" )
  18. //println(応答)
  19.                      
  20. //ファイル内の内容を置き換える
  21. yamlData = readYaml テキスト: "" "${response}" ""  
  22.  
  23. println(yamlData.image.version)
  24. println( yamlData.image.commit )
  25. yamlData.image.version = "${releaseVersion}-${env.nowDate}"  
  26. yamlData.image.commit = "${commitId}"  
  27.  
  28. yamlData.toString() を println します。
  29.  
  30. sh "rm -fr test.yaml"  
  31. writeYaml 文字セット: 'UTF-8' 、データ: yamlData、ファイル: 'test.yaml'  
  32. newYaml = sh returnStdout: true 、スクリプト: 'cat test.yaml'  
  33.                      
  34. println(新しいYaml)
  35. //gitlabファイルの内容を更新
  36. base64Content = newYaml.bytes.encodeBase64().toString()
  37.  
  38. // 並行して問題が発生し、更新によって同時にエラーが報告されます
  39. 試す {
  40. リポジトリファイルを更新します(40、 "${moduleName}%2fvalues.yaml" 、base64Content、 "${env.branchName}" )
  41. 壊す;
  42. } キャッチ(e){
  43. sh 「睡眠2」  
  44. 続く;
  45. }
  46. }
  47. }
  48. }
  49. }
  50.          
  51. //HTTPリクエストをカプセル化する
  52. def HttpReq(reqType,reqUrl,reqBody){
  53. gitServer を"http://gitlab.idevops.site/api/v4"に設定します 
  54. withCredentials([string(credentialsId: 'gitlab-token' , 変数: 'gitlabToken' )]) {
  55. 結果 = httpRequest customHeaders: [[maskValue: true 名前: 'PRIVATE-TOKEN' 、値: "${gitlabToken}" ]],
  56. httpMode: 要求タイプ、
  57. コンテンツタイプ: "APPLICATION_JSON"
  58. コンソールログレスポンスボディ: true
  59. SSLエラーを無視: true
  60. リクエストボディ: reqBody、
  61. url: "${gitServer}/${reqUrl}"  
  62. // 静か: 
  63. }
  64. 結果を返す
  65. }
  66.  
  67.  
  68. //ファイルの内容を取得する
  69. def GetRepoFile(プロジェクトID,ファイルパス,ブランチ名){
  70. apiUrl = "projects/${projectId}/repository/files/${filePath}/raw?ref=${branchName}"  
  71. レスポンス = HttpReq( 'GET' ,apiUrl, '' )
  72. レスポンスを返す。
  73. }
  74.  
  75. //ファイルの内容を更新する
  76. def UpdateRepoFile(プロジェクトID、ファイルパス、ファイルコンテンツ、ブランチ名){
  77. apiUrl = "プロジェクト/${プロジェクトID}/リポジトリ/ファイル/${ファイルパス}"  
  78. reqBody = "" "{" branch ": " ${branchName} "," encoding ":" base64 ", " content ": " ${fileContent} ", " commit_message ": "新しいファイルを更新"}" ""  
  79. レスポンス = HttpReq( 'PUT' ,apiUrl,reqBody)
  80. println(応答)
  81.  
  82. }

画像

GitOps-CD セクション

CD スケジューラ ジョブ

このジョブは、CI スケジューラ ジョブと同様に、実際に GitLab の webhook リクエストを受信します。違いは、この CD スケジューラ ジョブが環境リポジトリ内のコード変更を受信するために使用されることです。 Webhook を有効にし、トリガー トークンを構成します。 hookurl を生成します: http://jenkins.idevops.site/generic-webhook-trigger/invoke?token=microservicecicd-scheduler-CD

ジェンキンスファイル

  1. パイプライン
  2. エージェント 
  3.  
  4. ステージ {
  5. ステージ( 'GetCommitService' ){
  6. 手順 {
  7. スクリプト{
  8. 「こんにちは世界」をエコーし​​ます 
  9. echo "${WebHookData}"  
  10.                      
  11. // Git 情報
  12. webhookdata = readJSON テキスト: "" "${WebHookData}" ""  
  13. イベントタイプ = webhookdata[ "オブジェクトの種類" ]
  14. commits = webhookdata[ "commits" ]
  15. branchName = webhookdata[ "ref" ] - "refs/heads/"  
  16. projectID = webhookdata[ "プロジェクトID" ]
  17. コミットID = webhookdata[ "checkout_sha" ]
  18.  
  19.  
  20. 変更サービス = []
  21. コミット コミット){
  22. println(コミット.id)
  23.  
  24. //追加した
  25. 追加  コミット.added) {
  26. s =リストとして.split( "/" )を追加
  27. s.size ()> 1)の場合{
  28. (changeServices.indexOf(s[0]) == -1)の場合{
  29. サービスを変更します。追加(s[0])
  30. }
  31. }
  32. }
  33.  
  34. //変更済み
  35.  コミット.modified) {
  36. s = m.split( "/" )リストとして
  37. // println s
  38. // println s.size ()
  39. // s[0]を印刷する
  40. s.size ()> 1)の場合{
  41. // println changeServices.indexOf(s[0])
  42. (changeServices.indexOf(s[0]) == -1)の場合{
  43. サービスを変更します。追加(s[0])
  44. }
  45. }
  46. }
  47.  
  48. //削除されました
  49. (r場合 コミット.removed) {
  50. s = r.split( "/" )リストとして
  51. 印刷する
  52. s.size ()> 1)の場合{
  53. (changeServices.indexOf(s[0]) == -1)の場合{
  54. サービスを変更します。追加(s[0])
  55. }
  56. }
  57. }
  58. }
  59.  
  60. println(サービスの変更)
  61. currentBuild.description = " ${eventType} ${changeServices} によってトリガー "  
  62. }
  63. }
  64. }
  65.  
  66. ステージ( 'DefineService' ){
  67. 手順 {
  68. スクリプト{
  69. println(サービスの変更)
  70. //サービス構築順序制御
  71. サービス = [ 'service02' , 'service01' ]
  72. (サービス内のサービス){
  73. (changeServices.indexOf(サービス) != -1)の場合{
  74. ジョブ名 = 'microservicecicd-' +サービス+ '-service-CD'  
  75. ビルドジョブ: jobName、待機: false 、パラメーター: [string( name : 'branchName' 、値: "${branchName}" )]
  76. }
  77. }
  78. }
  79. }
  80. }
  81. }
  82. }

環境ライブラリ構成ウェブフック

Webhook を有効にし、hookurl を設定します: http://jenkins.idevops.site/generic-webhook-trigger/invoke?token=microservicecicd-scheduler-CD

CD製造ライン-CD操作

ジェンキンスファイル

  1. 文字列 serviceName = "${JOB_NAME}" .split( "-" )[1]
  2. 文字列 nameSpace = "${JOB_NAME}" .split( "-" )[0].split( "/" )[-1]
  3.  
  4.  
  5. //パイプライン
  6. パイプライン{
  7. エージェント { ノード { ラベル"k8s" }}
  8.      
  9. ステージ{
  10.  
  11. ステージ( "GetCode" ){
  12. ステップ{
  13. スクリプト{
  14. println( "${branchName}" )
  15. println( "${env.branchName}" . ( "RELEASE-" )が含まれています)
  16. println "コードを取得"  
  17. チェックアウト([$class: 'GitSCM' , ブランチ: [[ name : "${env.branchName}" ]],
  18. doGenerateSubmoduleConfigurations: false
  19. 拡張機能: [[$class: 'SparseCheckoutPaths' ,
  20. sparseCheckoutPaths: [[パス: "${serviceName}" ]]]],
  21. サブモジュール構成: [],
  22. userRemoteConfigs: [[credentialsId: 'gitlab-admin-user' 、url: "http://gitlab.idevops.site/microservicecicd/microservicecicd-env.git" ]]])
  23. }
  24. }
  25. }
  26.  
  27. ステージ( "HelmDeploy" ){
  28. ステップ{
  29. スクリプト{
  30. sh "" "
  31. kubectl はns "${nameSpace}-uat"を作成します||エコー 
  32.  
  33. helm インストール"${serviceName}"   --namespace "${nameSpace}-uat" ./"${serviceName}" || helm アップグレード "${serviceName}" --namespace "${nameSpace}-uat" ./"${serviceName}"  
  34.  
  35. helm list --namespace "${nameSpace}-uat"  
  36. helm 履歴"${serviceName}"   --namespace "${nameSpace}-uat"  
  37.  
  38. 「」 「
  39. }
  40. }
  41. }
  42. }
  43. }

この記事はWeChatのパブリックアカウント「DevOps Cloud Academy」から転載したものです。

<<:  業界で人気のエッジコンピューティングとは一体何でしょうか?

>>:  Kubernetesがサービスディスカバリを実装する方法について話す

推薦する

テンセントクラウドのプログラマブルネットワーク技術の強みが「2022年未来ネットワーク先導革新科学技術成果」に選出され、再び権威に認められた

8月25日、テンセントクラウドプログラマブルネットワークプロジェクトは、クラウドネットワークの転送性...

Baidu を使ってトラフィックを集める方法 (ケーススタディ)

今日ここでお話しするのは、Baidu Knows がいかに重要で、いかに便利であるかをお伝えすること...

企業ウェブサイト向けのオリジナル記事リソースをより適切に見つける方法

最近、ウェブサイトの構築と最適化に忙しく、ブログの更新が遅くなってしまいました。この間、多くの企業サ...

tmhhost: VPS 夏季 20% 割引、香港 BGP (200M 帯域幅) + 米国 3 ネットワーク cn2 gia + 米国 cn2 gia 200G 高防御

tmhhost は、四半期ごとの支払いで 20% オフとなる新しい夏の VPS プロモーションを実施...

サーバーレスから始まるエッジコンピューティングの未来についてお話ししましょう

エンタープライズレベルのストレージ、エンタープライズレベルのコンテナプラットフォームなどのアーキテク...

共同購入サイトの存続率はわずか18.6%で、残っているのは1,000未満です。

本紙(薛松記者)は、業界全体の規模が拡大を続ける一方で、今年の春節以降、中小共同購入サイトが多数閉鎖...

ウェブサイトの包含率を向上させる方法

Baiduが最近アルゴリズムを更新した後、含まれるウェブサイトの数が急減しました。著者のウェブサイト...

GoDaddyドメイン名の移管方法

現在、中国には多くのドメイン名登録業者が存在します。ドメイン名を移転しようとすると、さまざまな障害に...

register.com ドメイン名を8.99ドルで登録

Register からドメイン名のプロモーションがあるというメールが届きました。確認してみると、全体...

losangelesvps: アップグレードされたVPSの別のレビュー。この1Gbps無制限帯域幅VPSのパフォーマンスを確認します。

以前(3月9日)、losangelesvpsの宣伝記事を投稿しましたが、その中で公式がサーバー構成を...

Interserver VPS シンプルレビュー (初月 0.1 USD)

週末は何もすることがなかったので、以前書いた特別オファーのいくつかを整理し、それらがまだ購入する価値...

SaaS ガバナンス計画が必要な理由と、その計画に何を含めるべきか

現在、SaaS の採用は IaaS をはるかに上回っています。それにもかかわらず、多くの企業はインフ...