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

推薦する

百度検索が大きく変化、インデックス減少の詳細な分析

2012 年は激動の年でした。Baidu のアルゴリズムは絶えず調整され、変更されてきました。含まれ...

ダウンロードサイトのタイトル表記方法の比較実験結果

ダウンロード Web サイトのページで TITLE を記述する方法は主に 3 つあります。 XXXX...

ウェブサイト開設から20日以上経過しても、Baiduがホームページではなく内部ページのみをインデックスした理由

ウェブサイトが開設されてから20日以上経ちましたが、ホームページはまだ掲載されていません。一方、ウェ...

OpenStack ネットワークデプロイメントの実装方法

この OpenStack in Action からの抜粋では、OpenStack を展開する方法が説...

重いテーマ - SEOがどのように発展し、変化するか

数日前、私は 2 人の友人に SEO の仕事を紹介しました。明らかに、より規模が大きく、給与も高いプ...

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

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

ftechはどうですか? ftech ベトナム VPS サーバーの簡単なレビュー。IP で Netflix/spotify\steam\chatgpt などをブロック解除できます。

2011 年に設立されたベトナムのサーバー プロバイダーである ftech.vn は、ベトナムで仮想...

デジタル変革を背景とした銀行におけるプライベートクラウドの構築に関する簡単な議論

01. 銀行におけるクラウドコンピューティングの発展の背景クラウド コンピューティングは、金融業界の...

微博の大手アカウントが死滅。微博の急成長期の極端な代表

彼らはWeiboの急成長期の極端な代表であり、そのため他のものよりも早く目新しさの喪失と過剰商業化の...

hosteons: ハロウィーン、すべての VPS が 50% オフ、無制限のトラフィック、無料のセキュリティ、Windows 付き

Hosteons のハロウィン プロモーションが始まりました。今から 11 月 1 日まで、Host...

サーバーレスが本当にわかりません!

アレン・ヘルトン企画 |趙雲サーバーレスの定義は変化しており、それが実際に何を意味するのか誰も同意で...

SEO最適化とウェブサイトの立ち上げを統合する方法

現在、多くの SEO 担当者は、注文を受けた後にタスクを完了するのが難しい、または合意した時期になっ...

外部リンク構築戦略の5つの側面

外部リンク構築の戦略原則は比較的マクロです。いわゆる戦略的方向性とは、外部リンク構築のプロセスにおい...

カザフスタンの VPS: pqhosting、月額 3.77 ユーロから、1G メモリ/1 コア/15g SSD/G ポート無制限トラフィック

中央アジアのカザフスタン VPS は市場では珍しいようですね。現在、pq.hosting はカザフス...

社内ブランドマーケティングは数え切れないほど多くの人々に無視されています。

この記事を読み始める前に、ちょっとしたテストをしてみましょう。画像ソース: The Paperなぜこ...