InterSystems Technologiesの継続的デリバリープロジェクト用GitLab

この記事では、InterSystemsプラットフォームでのアプリケーションのアセンブリ、テスト、および配信を自動化する継続的統合 /継続的配信プロセスの構成についてお話したいと思います。


次のようなトピックを検討してください。



Git 101


メイントピックはCD、 Gitであるという事実にもかかわらず、それを支える多くの基本原則がソフトウェア開発プロセスに大きな影響を与えているので、Gitの基本用語の簡単な説明から始めましょう。


Gitは、次のようなアイデアに基づいたバージョン管理および管理システムです。



Gitはこれらのアイデアが実装された最初のバージョン管理システムではありませんでしたが、Gitはこれらのアイデアを普及させ、実用化を大幅に簡素化しました。


リポジトリ


データが保存および維持される場所。



ローカルリポジトリ-ローカルコンピューターにあるリポジトリ
リモートリポジトリ-リモートサーバーにあるリポジトリ


コミットする


リポジトリのコミットされた状態。
親と呼ばれる他のコミットとの差(Diff)を保存します。


親は:



支店


コミットへのポインター。
最初のコミットの前にいつでも彼の話を見ることができます。 たとえば、 masterブランチ:


支店


コミットツリー


ツリーのコミット-リポジトリのグラフィカルな表現。 上の画像から2つの既存のコミットにさらに3つのコミットが追加された場合、最も単純な線形オプションを検討してください。


枝


現在、ツリーの例はより複雑です。2人の開発者が同時に作業し、互いに干渉しないように、それぞれが自分のブランチで動作します。 次のようになります。


枝


しばらくして、変更をマージする必要があります。これにはマージ要求があります。これは、2つのリポジトリ状態を1つの新しい状態に結合する要求です。 私たちの場合、 developブランチをmasterブランチにマージするリクエスト。 リクエストがレビューおよび承認され、マージが行われた後、リポジトリは次のようになります。


枝


その後、開発が続行されます。


枝


結論-Git 101



開発方法(Gitフロー)


Gitベースの開発方法論は、Gitを開発の基盤として使用する一連のソフトウェア開発アプローチです。 多くの開発方法論がありますが、そのうちの2つを検討してください。



Githubフロー


GitHubフローは、おそらくGitに基づいた最も単純な開発方法の1つです。 ここにあります:



さらに、いくつかのルールがあります。



環境は、アプリケーションコードが実行される構成済みのリソースです。 サーバー、仮想マシン、またはコンテナです。


これは次のようなものです。


Github


HabréでのGitHubフローの詳細については、すでに複数 書いて ます。


Gitlabフロー


産業環境でコードを自動的に更新する準備ができていない場合、GitLabフローはGitHubフローと複数の環境の統一を提供します。 仕組みは次のとおりです。開発はGitHubフローと同様に実行されます。別々のブランチでmasterにマージされますが、 masterブランチのコンテンツはテストサーバーにデプロイされます。 さらに、環境のコンテンツに対応するコンテンツを持つ環境ブランチがあります。 通常、3つの環境がありますが、要件に応じてこれよりも多い場合も少ない場合もあります。



開発プロセスは次のようになります。



HabréでのGitLabフローについての詳細も書いています。


結論-開発方法(Gitフロー)


単純なものから複雑なものまで、多数のGitベースの開発方法論があります。 一方では複雑ではない方法論を選択し、他方ではプロジェクトのステータスを適切に制御できます。


Gitlabのワークフロー


GitLab Workflowは、開発の段階だけでなく、アイデアからユーザーフィードバックまでの製品ライフサイクル全体に影響するソフトウェア開発方法論です。 これは次のようなものです。




各ステージの詳細については、GitLabのWebサイトで説明します。いくつかのステージの説明に限定します。


タスクと計画


GitLabワークフローの初期段階は、タスク、つまり新機能、バグ、またはその他の個別のワークロードに焦点を合わせています。 このタスクには、次のようないくつかの目標があります。



計画段階では、優先度、段階、ステータスに従ってタスクをグループ化できます。



上記の開発について議論し、git開発方法論に従います。 新しい機能を開発し、それをmasterブランチにマージした後、次は何をしますか?


継続的デリバリー


継続的デリバリは、チームが短いスプリントでソフトウェアを開発するソフトウェア開発アプローチであり、アプリケーションの新しいバージョンがいつでもリリースできるようにします。 このアプローチは、ソフトウェアの組み立て、テスト、および配信を自動化します。 このアプローチは、変更を行うコストとリスクを軽減するのに役立ち、産業用アプリケーションの高速増分更新を取得できます。 継続的な配信では、シンプルで繰り返し可能な配信プロセスを設定することが重要です。


GitLabでの継続的デリバリー


GitLabでは、連続配信設定は各リポジトリに対して個別に定義され、リポジトリのルートにあるYAML設定ファイルに保存されます。



スクリプト


1つのアクションと、それを実行するために満たす必要がある条件を定義します。



環境は、スクリプトを実行できる構成済みのサーバーまたはコンテナです。


ランナー -特定の環境でスクリプトを実行するサービス。 GitLabに接続し、必要に応じてスクリプトを実行します。


ランナーは、サーバー、コンテナ、またはローカルの開発者のコ​​ンピューターに展開できます。


連続配信はどのように行われていますか?



実行例を次に示します。



順次実行される4つのステップで構成されます



ご覧のとおり、各スクリプトは正常に実行され、スクリプトの1つが失敗すると、次のスクリプトは実行されません。



スクリプトを開くと、エラーで終了した理由を確認できます。


スクリプト実行ログ
 Running with gitlab-runner 10.4.0 (857480b6) on test runner (ab34a8c5) Using Shell executor... Running on gitlab-test... Fetching changes... Removing diff.xml Removing full.xml Removing index.html Removing tests.html HEAD is now at a5bf3e8 Merge branch '4-versiya-1-0' into 'master' From http://gitlab.eduard.win/test/testProject * [new branch] 5-versiya-1-1 -> origin/5-versiya-1-1 a5bf3e8..442a4db master -> origin/master d28295a..42a10aa preprod -> origin/preprod 3ac4b21..7edf7f4 prod -> origin/prod Checking out 442a4db1 as master... Skipping Git submodules setup $ csession ensemble "##class(isc.git.GitLab).loadDiff()" [2018-03-06 13:58:19.188] Importing dir /home/gitlab-runner/builds/ab34a8c5/0/test/testProject/ [2018-03-06 13:58:19.188] Loading diff between a5bf3e8596d842c5cc3da7819409ed81e62c31e3 and 442a4db170aa58f2129e5889a4bb79261aa0cad0 [2018-03-06 13:58:19.192] Variable modified var=$lb("MyApp/Info.cls") Load started on 03/06/2018 13:58:19 Loading file /home/gitlab-runner/builds/ab34a8c5/0/test/testProject/MyApp/Info.cls as udl Load finished successfully. [2018-03-06 13:58:19.241] Variable items var="MyApp.Info.cls" var("MyApp.Info.cls")="" Compilation started on 03/06/2018 13:58:19 with qualifiers 'cuk /checkuptodate=expandedonly' Compiling class MyApp.Info Compiling routine MyApp.Info.1 ERROR: MyApp.Info.cls(version+2) #1003: Expected space : '}' : Offset:14 [zversion+1^MyApp.Info.1] TEXT: quit, "1.0" } Detected 1 errors during compilation in 0.010s. [2018-03-06 13:58:19.252] ERROR #5475: Error compiling routine: MyApp.Info.1. Errors: ERROR: MyApp.Info.cls(version+2) #1003: Expected space : '}' : Offset:14 [zversion+1^MyApp.Info.1] > ERROR #5030: An error occurred while compiling class 'MyApp.Info' ERROR: Job failed: exit status 1 

コンパイルエラーが原因でスクリプトが失敗しました。


理論から実践に移りましょう。


GitLabをインストールする


GitLabを独自のサーバーにインストールします。 ただし、GitLab.comを使用できます。 GitLabをインストールするには、ソースから、パッケージから、コンテナにさまざまな方法があります。 お好みの方法を選択し、インストール手順に従ってください


要件:



構成


まず、 メール通知を設定します


次に、Pagesをインストールすることをお勧めします。 前述のように、スクリプトアーティファクトはGitLabにアップロードできます。 ユーザーはそれらをダウンロードできますが、ブラウザで直接開くと便利な場合が多く、そのためにはページをインストールする必要があります。


ページが必要な理由:



ページをロードする際の自動リダイレクトをHTMLに追加できるため、単体テストの結果を含むページにユーザーを誘導できます。


HTML生成コード
 ClassMethod writeTestHTML() { set text = ##class(%Dictionary.XDataDefinition).IDKEYOpen($classname(), "html").Data.Read() set text = $replace(text, "!!!", ..getURL()) set file = ##class(%Stream.FileCharacter).%New() set name = "tests.html" do file.LinkToFile(name) do file.Write(text) quit file.%Save() } ClassMethod getURL() { set url = "http://host:57772" set url = url _ $system.CSP.GetDefaultApp("%SYS") set url = url_"/%25UnitTest.Portal.Indices.cls?Index="_ $g(^UnitTest.Result, 1) _ "&$NAMESPACE=" _ $zconvert($namespace,"O","URL") quit url } XData html { <html lang="en-US"> <head> <meta charset="UTF-8"/> <meta http-equiv="refresh" content="0; url=!!!"/> <script type="text/javascript">window.location.href = "!!!"</script> </head> <body> If you are not redirected automatically, follow this <a href='!!!'>link to tests</a>. </body> </html> } 

ちなみに、ページを使用するとバグが発生しました(アーティファクトを表示するとエラー502)-これが解決策です。


環境をGitLabに接続する


CDスクリプトを実行するには、環境が必要です-アプリケーションを実行するように構成されたサーバー。 まず、InterSystemsプラットフォーム(たとえば、InterSystems IRISですが、すべてがCachéまたはEnsembleで動作します)と共にインストールされたLinuxサーバーがあるとします。 環境をGitLabに接続するには、次のものが必要です。


  1. GitLabランナーをインストールします
  2. GitLabランナーをGitLabに登録します。
  3. gitlab-runnerがInterSystems IRIS gitlab-runner起動できるgitlab-runnerます。

GitLabランナーのインストールに関する重要な注意-GitLabランナーのインストール後にサーバーのクローンを作成しないでください。 結果は予測不能で望ましくありません。
手順2と3について詳しく説明します。


GitLabランナーをGitLabに登録します。


コマンドの実行後: sudo gitlab-runner register


いくつかのオプションから選択でき、ほとんどの手順は非常に簡単ですが、そのうちのいくつかはコメントする価値があります。



いくつかのトークンが利用可能です:システム全体(管理設定で利用可能)または1つのプロジェクト(プロジェクト設定で利用可能)。
特定のプロジェクトのCDのランナーを接続するとき、この特定のプロジェクトのトークンを指定する必要があります。



構成CDで、特定のタグを持つ環境で実行されるスクリプトをフィルタリングできます。 したがって、最も単純なケースでは、環境の名前となる1つのタグを指定します。



Dockerを使用するかどうかに関係なく、スクリプトを実行するシェルを選択します。


gitlab-runnerがInterSystems IRIS gitlab-runner起動できるgitlab-runnerます。


GitLabに接続したら、 gitlab-runnerユーザーがInterSystems IRISを呼び出すことを許可する必要があります。 これを行うには:


  1. gitlab-runnerユーザーには、 irissessionまたはcsessionを呼び出すirissession必要csession 。 これを行うには、 irisusrグループまたはcacheusrコマンドに追加します: usermod -a -G cacheusr gitlab-runner
  2. InterSystems IRISで gitlab-runner ユーザー作成し、 CDスクリプトを実行する権限(データベースへの書き込みなど)を付与します。
  3. OS認証を有効にします

ポイント2と3の代わりに、たとえばユーザー/パスワードの転送など、他のアプローチを使用することもできますが、OS認証のオプションの方がより望ましいようです。


CD構成


それでは、連続配信設定の作成を始めましょう。 まず、環境と計画について説明します。


環境


いくつかの環境とそれに対応するブランチがあります。


環境支店配送誰がコミットできますか誰がマージできるか
テストマスター自動開発者、所有者開発者、所有者
経験者preprod自動誰も所有者
産業用製品ボタンに触れるだけで誰も所有者

作業計画


  1. 問題の記述、開発、および自動テスト
    • 所有者がタスクを設定します
    • 開発者は機能ブランチを作成し、そこで問題を解決するコードをコミットします
    • 開発者は機能ブランチをマスターにマージします
    • 新しいコードは自動的にテスト環境に配信され、テストされます。
  2. 経験豊富な環境での配達
    • 開発者がpreprodのマスターコードをマージする要求を作成します
    • 所有者がマスターからプリプロッドへのコードのマージを承認
    • 新しいコードは実験環境に自動的に配信されます。
  3. 産業環境での配送
    • 開発者(または所有者)は、コードをpreprodからprodにマージする要求を作成します
    • 所有者がpreprodコードをprodにマージすることを承認します
    • 所有者が「展開」ボタンをクリックします
    • アプリケーションの新しいバージョンは自動環境に展開されます

グラフィカル形式でも同じ:



アプリ


テストアプリケーションは2つの部分で構成されています。



ステージ


上記の計画から、連続配信構成で決定する必要がある手順を特定できます。



.gitlab-ci.yml設定を開始しましょう:


 stages: - load - test - package - deploy 

スクリプト


構成の次の部分はスクリプトです。 ドキュメンテーション


負荷


サーバーコードをロードするload serverスクリプトから始めましょう。


 load server: environment: name: test url: http://test.hostname.com only: - master tags: - test stage: load 

ここで何が起こっていますか?



次に、 isc.git.GitLabクラスを作成する必要があります。 すべてのエントリポイントは次のようになります。


 ClassMethod method() { try { // code halt } catch ex { write !,$System.Status.GetErrorText(ex.AsStatus()),! do $system.Process.Terminate(, 1) } } 

この方法は、2つの方法でのみ完了できます。



ダウンロードコードは次のとおりです。


 /// Do a full load /// do ##class(isc.git.GitLab).load() ClassMethod load() { try { set dir = ..getDir() do ..log("Importing dir " _ dir) do $system.OBJ.ImportDir(dir, ..getExtWildcard(), "c", .errors, 1) throw:$get(errors,0)'=0 ##class(%Exception.General).%New("Load error") halt } catch ex { write !,$System.Status.GetErrorText(ex.AsStatus()),! do $system.Process.Terminate(, 1) } } 

このメソッドは、他の2つのメソッドを呼び出します。



しかし、リポジトリのあるディレクトリをどのように取得できますか?


GitLabがスクリプトを実行すると、多くの環境変数が定義されます 。 それらの1つはCI_PROJECT_DIRリポジトリーのルートへのCI_PROJECT_DIRパスです。 そのため、 getDirメソッドで取得できます。


 ClassMethod getDir() [ CodeMode = expression ] { ##class(%File).NormalizeDirectory($system.Util.GetEnviron("CI_PROJECT_DIR")) } 

テスト


テスト実行スクリプトは次のとおりです。


 tests: environment: name: test url: http://test.hostname.com only: - master tags: - test stage: test script: csession IRIS "##class(isc.git.GitLab).test()" artifacts: paths: - tests.html 

何が変わった? もちろん、スクリプトの名前とコードですが、 artifactsも追加されています。 アーティファクトとは、スクリプトが正常に完了した後にスクリプトに添付される一連のファイルとフォルダーです。 この場合、テストが完了した後、ユーザーをテスト結果にリダイレクトするHTMLページを生成できます。


テストスクリプトとダウンロードスクリプトの類似性に注意してください。 すべてのスクリプトで同じ環境などのスクリプトの部分は、個別のブロックに分割できます。 テスト環境を定義します。


 .env_test: &env_test environment: name: test url: http://test.hostname.com only: - master tags: - test 

これで、 testsスクリプトは次のようになります。


 tests: <<: *env_test script: csession IRIS "##class(isc.git.GitLab).test()" artifacts: paths: - tests.html 

次に、 単体テストを呼び出す対応するサーバーコードを記述します( Habrの記事 )。


 /// do ##class(isc.git.GitLab).test() ClassMethod test() { try { set tests = ##class(isc.git.Settings).getSetting("tests") if (tests'="") { set dir = ..getDir() set ^UnitTestRoot = dir $$$TOE(sc, ##class(%UnitTest.Manager).RunTest(tests, "/nodelete")) $$$TOE(sc, ..writeTestHTML()) throw:'..isLastTestOk() ##class(%Exception.General).%New("Tests error") } halt } catch ex { do ..logException(ex) do $system.Process.Terminate(, 1) } } 

tests — . , .


writeTestHTML ( ) - -.


Package


-, REST API:


 <html> <head> <script type="text/javascript"> function initializePage() { var xhr = new XMLHttpRequest(); var url = "${CI_ENVIRONMENT_URL}:57772/MyApp/version"; xhr.open("GET", url, true); xhr.send(); xhr.onloadend = function (data) { document.getElementById("version").innerHTML = "Version: " + this.response; }; var xhr = new XMLHttpRequest(); var url = "${CI_ENVIRONMENT_URL}:57772/MyApp/author"; xhr.open("GET", url, true); xhr.send(); xhr.onloadend = function (data) { document.getElementById("author").innerHTML = "Author: " + this.response; }; } </script> </head> <body onload="initializePage()"> <div id = "version"></div> <div id = "author"></div> </body> </html> 

"", ${CI_ENVIRONMENT_URL} . (npm), . :


 package client: <<: *env_test stage: package script: envsubst < client/index.html > index.html artifacts: paths: - index.html 

Deploy


, index.html -.


 deploy client: <<: *env_test stage: deploy script: cp -f index.html /var/www/html/index.html 

以上です!



? , . :


 stages: - load - test .env_test: &env_test environment: name: test url: http://test.hostname.com only: - master tags: - test .env_preprod: &env_preprod environment: name: preprod url: http://preprod.hostname.com only: - preprod tags: - preprod .script_load: &script_load stage: load script: csession IRIS "##class(isc.git.GitLab).loadDiff()" load test: <<: *env_test <<: *script_load load preprod: <<: *env_preprod <<: *script_load 

.


CD , .


結論


— , , , . , . , .


InterSytems, InterSystems IRIS Data Platform ( Caché Ensemble), , , , .


参照資料




Source: https://habr.com/ru/post/J354158/


All Articles