マイクロサービス 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がサービスディスカバリを実装する方法について話す

推薦する

hostsolutions: 新しい KVM シリーズ VPS、10Gbps 帯域幅、SSD raid10、著作権/苦情なし

Hostsolutions は、10Gbps 帯域幅を備えた KVM シリーズ VPS の新製品シリ...

ブラック 5 プロモーション: HawkHost - 80% オフ/仮想ホスティング/VPS/ドメイン登録

Eagle Hosting は、ブラック フライデーの期間中も間違いなく見逃せません。ドメイン名登録...

クラウドとジェネレーティブ AI の今後の動向

絶えず変化するビジネス環境において、データは驚くべき速度で増加しています。データの急増により、あらゆ...

データ収集ウェブサイトを取り締まる百度の決意は恐ろしい

【はじめに】インターネット上にはどれくらいの重複コンテンツがあるのでしょうか?インターネット上で重複...

ウェブサイトの基盤をしっかり構築する方法

本日お伝えしたいのは、Web サイトの初期段階で強固な基盤を築く方法です。良いスタートは必ずしも戦い...

Linodeの10ドル割引コードの説明

過去 2 日間、Linode はホスティング業界で最もホットな話題となりました。11 年の歴史を持つ...

Webmaster.comからの毎日のレポート:山東ウェブマスター会議が開催、Xiaomi Boxの8日間の夢は打ち砕かれる

1. 2012年山東インターネットウェブマスター会議が済南で成功裏に開催されました11月26日のAd...

検索エンジンとユーザーはSEOウェブマスターにとって同等に重要です

私たち SEO ウェブマスターは皆、サービスの最終的なターゲットはユーザーであり、私たちの仕事の価値...

ビッグデータとクラウドコンピューティングの特別な関係

ビッグデータとは、現在のビジネス分野に存在するあらゆる種類のデータを指す総称です。医療機関のデジタル...

同じウェブサイトを構築してもなぜ収益が上がらないのでしょうか?

現時点では、イチゴの卸売価格は1斤4元で、農産物直売所では1斤8元で販売できる。ジュースにすると、1...

今日の話題: Alibaba のオンライン バンキングは登場するのか?伝統的な銀行にとって挑戦となるのでしょうか?

中国ビジネスニュース(ブログ、微博)の9月9日の報道によると、アリファイナンスは最近、金融規制当局に...

高品質なサイト最適化により、優れたユーザーエクスペリエンスを実現

2012 年を迎え、ウェブマスター界に新たな改革の波が到来しました。 Google が開始した Pl...

Webmaster.com からの毎日のレポート: 江蘇省ウェブマスター会議が開催、Sina Weibo が QR コードを宣伝

1. 2012年江蘇省インターネットウェブマスター会議が徐州で成功裏に開催されましたAdmin5 W...

毛宏亮: 企業ネットワークマーケティングのウェブサイト最適化に関する私の意見

筆者は、ある企業のインターネットプロモーターです。本日は、その企業のインターネットプロモーションの現...