その4 - Azure Artifacts に格納された NuGet パッケージを Azure Pipeline から取得する

掲載内容は個人の見解であり、所属する企業を代表するものではありません.


CICDパイプラインからパッケージを利用する

それでは最後にパッケージを利用するアプリケーションの CI/CD を実現してみましょう。

ソースコードリポジトリの作成

まずは Azure Repos を作成します。 ライブラリ開発側とは開発ライフサイクルも異なりますし要件も独立しますので別の Azure Repos を作成します。

ソースコードリポジトリの作成

次にリポジトリを利用するアプリケーションを作成します。 その2 で作成したプロジェクトはコンソールアプリケーションであるため、 自動リリースといってもどこかのフォルダに実行可能ファイルを配置するだけで面白くありません。 ここでは Azure Functions を作成し、そこにその3で発行したライブラリを利用する関数を配置してみましょう。

利用側アプリケーションの作成

Visual Studio 等を使用して Azure Functions のアプリケーションを作成します。 次に その2 で紹介したように NuGet パッケージマネージャでフィードを参照すると、 その1その3 で発行した各バージョンのパッケージが参照できます。

フィードの参照

ここで設定したパッケージとバージョン番号はプロジェクトファイルに記載され、ビルド時に適切なバージョンのインストールを行います。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <AzureFunctionsVersion>v2</AzureFunctionsVersion>
    <RootNamespace>hello_function</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Ayuina.Samples.Utility" Version="1.1.0-CI-20190522-041524" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.28" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

このパッケージを利用した関数のコードは以下のようになります。

       [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest  req, 
            ILogger log)
        {
            string name = req.Query["name"];
            if(name == null)
            {
                return new BadRequestObjectResult("Please pass a name on the query string or in the request body");
            }

            var message = $"{Ayuina.Samples.Utility.Class1.Hello(name)}";
            return (ActionResult)new OkObjectResult(message);
        }
    }

この Functions アプリをソースコード レポジトリに Push しておきます。

PS > git add .
PS > git commit -m "コメント"
PS > git push

継続的インテグレーションとデプロイの実装

次に格納したソースコードをビルドして、成果物を自動生成します。 ここでは 共有ライブラリを利用する Azure Function アプリ が成果物として得られることがゴールになります。

ビルドパイプライン

ビルドパイプラインの定義方法は その3 をご参照いただければと思いますが、Azure Functions の場合は専用のビルドテンプレートが用意されていますのでそちらを利用します。

Azure Functionのビルドテンプレート

残念ながらこのテンプレートではカスタムフィードを設定する箇所がないので、このまま実行してもエラーになってしまいます。 このためプロジェクトファイル csproj に記載された独自の共有ライブラリを含んだパッケージを、パブリックの NuGet.org に探しに行ってしまいます。 当然 NuGet.org にはパッケージを発行してませんので、見つからずにビルドエラーになってしまうわけです。

さてどうしましょう。

dotnet タスクの restore コマンドであればフィードが指定できます。 このタスクを実行してプロジェクトファイルに記載されたパッケージをビルドエージェント環境に取得し、 その後で build コマンドを実行すると、既にパッケージのキャッシュがある状態ですのでビルドを実行することができます。

パッケージリストアの追加

「」ドを実行して正常に完了したら、成果物として出力されている ZIP ファイルを解凍して中身を確認します。 この中身が Azure Functions に配置できるレイアウトになっていればリリース処理に進むことができます。

ビルドの実行結果

.NET Core ベースの Azure Functions アプリではアセンブリが bin フォルダ配下に配置されています。 この中には利用側 Functions アプリ hello-function.dll と一緒に共有ライブラリ Ayuina.Samples.Utility.dll が含まれていることが確認できます。

なお Azure Functions アプリの ZIP 形式での展開する方法についての詳細は こちら をご参照ください。

リリースパイプライン

ビルド成果物ができたらそれを Azure Function にデプロイします。 リリースパイプラインの定義方法も その3 をご参照いただければと思いますが、 Azure Functions の場合は専用のデプロイタスクが用意されていますのでそちらを利用します。

Funcsionアプリのデプロイ

まずは その3 と同様にリリースエージェントの実行環境にビルド成果物をダウンロードしておき、 Functions デプロイ用のタスクでデプロイ先と対象となるアプリ(zip)を指定します。 リリース定義が完成したら保存し、実行してみましょう。

リリースも正常に完了したら Function アプリを実行してみましょう。 前述のサンプルコードでは HTTP トリガーになっていますので、URL のクエリ文字列に名前を入力すると、 共有ライブラリ内に実装されたメッセージが返ってくるはずです。

テスト実行

なお Azure Portal でデプロイセンターを確認すると、現在 Azure Function で動作しているアプリケーションのバージョンや過去の履歴を確認することができます。

デプロイセンター

この情報を元に Azure DevOps のビルド番号や Commit を確認すれば、実際に動作している共有ライブラリのバージョン(プロジェクトファイルに記載されているはず)を特定することができます。

ここまでのまとめ

以上でカスタムフィードを使用したビルドおよびリリースパイプラインが実装できました。

まとめ