パッケージの利用、ローカルテスト、ビルド、Visual Studioからのデプロイまで来たのでローカル開発は問題なくできそうですね。ただCIがないままではチーム開発がしにくいです。
そこで今回は、.NET Core on Lambda をいい感じで CIで回す方法についてみていきます。
目次
先人の知恵
先人の知恵があります。Circle CI での例ですが、今回のベースになっています。
今回は、Circle CI と Visual Studio Team Service (VSTS) を試してみましょう。
デプロイ方法
Cloud Formation や Terraform はちょっと重厚すぎる、Serverless Framework ほどではない。ぐらいの温度感で行きたいので、dotnet lambda
を用いましょう。
dotnet lambda に関しては、コードをみるのもいいでしょう。
default-settings.json について
dotnet lambbda コマンドで渡す内容を事前に default-settings.json
に定義しておけばずいぶんとシンプルになります。
今回はデフォルトのものにfunction-name
と function-role
の 2パラメータを追加しています。この2つを足すことで、function名、roleが指定可能になりCIが捗ります。*1
"function-name": "GithubWebhook", "function-role": "arn:aws:iam::ACCOUNTID:role/service-role/lambda_exec_role"
.Net Core 1.0 の構築
CircleCI は Ubuntu 環境です。.NET Core は入っていないので入れましょう。
CI環境 | .NET Core有無 (インストールが必要) |
---|---|
CircleCI | なし (Ubuntu12 or 14) |
VSTS Hosted Windows | あり |
VSTS Hosted Linux | あり |
VSTS Agent | なし (環境に依存します) |
Ubuntu それぞれの環境構築コマンドは以下にまとまっています。
ただし、ここのバージョンは .NET Core 1.1 です。現状の AWS Lambda が .NET Core 1.0 なので、対象パッケージを変えます。ちなみにこのままやると以下のようなエラーに会います。
.NET Core 1.0 の最新パッケージバージョンは以下のURLで確認できます。
Circle CI
Circle CI のアカウントを持っていない場合は作ってしまいます。リポジトリ側と Circle CI でそれぞれ設定しておくことがあるので見てみましょう。
(リポジトリ側作業) circle.yml の作成
CircleCI のビルドタスクは、circle.yml
で記述できます。これをリポジトリの直下においておけば、CircleCI でビルドが走った時に自動的に利用されてるので記述しましょう。
今回は、circle.yml
に以下のタスクを記述します。
.net core 1.0
環境の構築dotnet restore
のビルド前実行dotnet build
によるコンパイルテストdotnet test
による実行テストdotnet lambda deploy-function
による AWS Lambda へのデプロイ
ざくっと書きました。
CircleCI は、Ubuntu 14 で行きます。
(CircleCI作業) 環境変数
AWS Lambda で、環境変数にリポジトリへ入れたくない情報を入れました。CircleCI でテストするにあたり、同様にこれらの情報を環境変数に入れます。
(CircleCI作業) AWS Lambda への デプロイIAM User Access/Secret
AWS に、dotnet lambda deploy-function
でデプロイするにあたり、Circle CIのAWS Permissions に 適切な Permission が付与された IAM User の Access Key/Secret Key を取得、設定します。ACCOUNT_ID にはご自分のIDをどうぞ。
今回は、Lambda Function の新規作成、更新を踏まえて以下の Permission にしました。
ビルド実行
あとは、git push でトリガーされます。
dotnet lambda deploy-function
をみてもいい感じですね。
Executing publish command ... invoking 'dotnet publish', working folder '/home/ubuntu/AWSLambdaCSharpIntroduction/AWSLambdaCSharpIntroduction/SlackSlashCommandWebhook/SlackSlashCommandWebhook/bin/Release/netcoreapp1.0/publish' ... publish: Publishing SlackSlashCommandWebhook for .NETCoreApp,Version=v1.0 ... publish: Project LambdaShared (.NETStandard,Version=v1.6) was previously compiled. Skipping compilation. ... publish: Project SlackSlashCommandWebhook (.NETCoreApp,Version=v1.0) will be compiled because expected outputs are missing ... publish: Compiling SlackSlashCommandWebhook for .NETCoreApp,Version=v1.0 ... publish: /home/ubuntu/AWSLambdaCSharpIntroduction/AWSLambdaCSharpIntroduction/SlackSlashCommandWebhook/SlackSlashCommandWebhook/Function.cs(25,35): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. ... publish: Compilation succeeded. ... publish: 1 Warning(s) ... publish: 0 Error(s) ... publish: Time elapsed 00:00:01.6428709 ... publish: ... publish: publish: Published to /home/ubuntu/AWSLambdaCSharpIntroduction/AWSLambdaCSharpIntroduction/SlackSlashCommandWebhook/SlackSlashCommandWebhook/bin/Release/netcoreapp1.0/publish ... publish: Published 1/1 projects successfully Changed permissions on published dll (chmod +r SlackSlashCommandWebhook.dll). Changed permissions on published dll (chmod +r Amazon.Lambda.Core.dll). Changed permissions on published dll (chmod +r Amazon.Lambda.Serialization.Json.dll). Changed permissions on published dll (chmod +r Amazon.Lambda.TestUtilities.dll). Changed permissions on published dll (chmod +r Newtonsoft.Json.dll). Changed permissions on published dll (chmod +r System.Runtime.Serialization.Primitives.dll). Changed permissions on published dll (chmod +r LambdaShared.dll). Zipping publish folder /home/ubuntu/AWSLambdaCSharpIntroduction/AWSLambdaCSharpIntroduction/SlackSlashCommandWebhook/SlackSlashCommandWebhook/bin/Release/netcoreapp1.0/publish to /home/ubuntu/AWSLambdaCSharpIntroduction/AWSLambdaCSharpIntroduction/SlackSlashCommandWebhook/SlackSlashCommandWebhook/bin/Release/netcoreapp1.0/SlackSlashCommandWebhook.zip ... publish: adding: SlackSlashCommandWebhook.dll (deflated 59%) ... publish: adding: SlackSlashCommandWebhook.pdb (deflated 46%) ... publish: adding: Amazon.Lambda.Core.dll (deflated 57%) ... publish: adding: Amazon.Lambda.Serialization.Json.dll (deflated 56%) ... publish: adding: Amazon.Lambda.TestUtilities.dll (deflated 61%) ... publish: adding: Newtonsoft.Json.dll (deflated 60%) ... publish: adding: System.Runtime.Serialization.Primitives.dll (deflated 48%) ... publish: adding: LambdaShared.dll (deflated 60%) ... publish: adding: LambdaShared.pdb (deflated 43%) ... publish: adding: SlackSlashCommandWebhook.deps.json (deflated 72%) ... publish: adding: SlackSlashCommandWebhook.runtimeconfig.json (deflated 22%) Created publish archive (/home/ubuntu/AWSLambdaCSharpIntroduction/AWSLambdaCSharpIntroduction/SlackSlashCommandWebhook/SlackSlashCommandWebhook/bin/Release/netcoreapp1.0/SlackSlashCommandWebhook.zip). Updating code for existing function
VSTS
Windows / Linux ともに、Hosted Agent では2つが障壁となってデプロイできません。これらは自前環境に Agent を入れることで回避ができます。
問題 | Agent の場合の解決方法 |
---|---|
~/.aws/config が作成できない | 作成してください。こんなことができないようになっているのは仕方ないとはいえ、見るところ間違えてますかねぇ。 |
VSTS UI 上の Environment Variables がコードに渡らない | OS の環境変数に入れてください。こんなことができな(略 |
ということで、VSTS で AWS Lambda をCI する場合は、hosted agent ではなく、自前エージェントでどうぞ。
~/.aws/config が作成できない
単純にこれをやるだけなんですが、厳しい...です。
結果、default
profile が見つからず dotnet lambda
が実行できない、と。
****************************************************************************** Starting: Run echo ****************************************************************************** ============================================================================== Task : Command Line Description : Run a command line with arguments Version : 1.1.1 Author : Microsoft Corporation Help : [More Information](https://go.microsoft.com/fwlink/?LinkID=613735) ============================================================================== /bin/echo '[default]' > ~/.aws/config '[default]' > ~/.aws/config ****************************************************************************** Finishing: Run echo ****************************************************************************** ****************************************************************************** Starting: Run ls ****************************************************************************** ============================================================================== Task : Command Line Description : Run a command line with arguments Version : 1.1.1 Author : Microsoft Corporation Help : [More Information](https://go.microsoft.com/fwlink/?LinkID=613735) ============================================================================== /bin/ls ~/.aws/config /bin/ls: cannot access '~/.aws/config': No such file or directory /bin/ls failed with return code: 2 /bin/ls failed with error: /bin/ls failed with return code: 2 ****************************************************************************** Finishing: Run ls ******************************************************************************```
Error retrieving configuration for function GithubWebhook: Profile default cannot be found /usr/bin/dotnet failed with return code: 255 /usr/bin/dotnet failed with error: /usr/bin/dotnet failed with return code: 255
VSTS UI 上の Environment Variables がコードに渡らない
単純にC#コードから、Environemnt.GetVariable()
で取得できると思ったんですが... CircleCI でできてVSTS Hosted Agent でできないのは何かやり方おかしいんですかねぇ。
Hosted agent では、環境依存を環境変数に逃がしている場合に、.Tests でコードを通せなくなっています。
============================================================================== Task : .NET Core (PREVIEW) Description : Build, test and publish using dotnet core command-line. Version : 0.1.0 Author : Microsoft Corporation Help : [More Information](https://go.microsoft.com/fwlink/?linkid=832194) ============================================================================== /usr/bin/dotnet test /opt/vsts/work/1/s/AWSLambdaCSharpIntroduction/GithubWebhook/GithubWebhook.Tests/project.json --configuration release GithubWebhook.Tests.FunctionTest.TestValidSnsGithubWebhookMessage [FAIL] SUMMARY: Total: 1 targets, Passed: 0, Failed: 1. Project LambdaShared (.NETStandard,Version=v1.6) was previously compiled. Skipping compilation. Project GithubWebhook (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation. Project GithubWebhook.Tests (.NETCoreApp,Version=v1.0) will be compiled because inputs were modified Compiling GithubWebhook.Tests for .NETCoreApp,Version=v1.0 Compilation succeeded. 0 Warning(s) 0 Error(s) Time elapsed 00:00:01.1756032 xUnit.net .NET CLI test runner (64-bit .NET Core ubuntu.16.04-x64) Discovering: GithubWebhook.Tests Discovered: GithubWebhook.Tests Starting: GithubWebhook.Tests GitHub WebHook triggered System.AggregateException : One or more errors occurred. (An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.) ---- System.InvalidOperationException : An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set. Stack Trace: at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions) at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) /opt/vsts/work/1/s/AWSLambdaCSharpIntroduction/GithubWebhook/GithubWebhook.Tests/FunctionTest.cs(21,0): at GithubWebhook.Tests.FunctionTest.TestValidSnsGithubWebhookMessage() ----- Inner Stack Trace ----- at System.Net.Http.HttpClient.PrepareRequestMessage(HttpRequestMessage request) at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken) at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.HttpClient.PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken) /opt/vsts/work/1/s/AWSLambdaCSharpIntroduction/GithubWebhook/GithubWebhook/Function.cs(81,0): at GithubWebhook.Function.<FunctionHandlerAsync>d__1.MoveNext() Finished: GithubWebhook.Tests === TEST EXECUTION SUMMARY === GithubWebhook.Tests Total: 1, Errors: 0, Failed: 1, Skipped: 0, Time: 0.545s Dotnet command failed with non-zero exit code: 1.
まとめ
CircleCI は流石、圧倒的な構築の容易さがあります。VSTS は、まぁシカタナイ(? 見るところがおかしいような気がするのですが...)
.NET Core on AWS Lambda は、.NET Core なだけあっていい感じに Linux 上でビルドできるので、CircleCI便利です。オススメ。
今回の内容もリポジトリに置いておきます 。
*1:省くと初めて作成するときに対話プロンプトで聞かれて困ったります