Azure で一番好きなサービスはダントツで Web App です。以前は Azure WebSite と呼ばれていました。やりすぎず、でも必要なことはできる。このバランス感が今でも崩れていないのはすごいです。
さて、Azure は各種SCM からのデプロイをサポートしており、そのデプロイ動作も制御できます。
今回は、カスタムデプロイを使って特定の GitHub ディレクトリと Web App のディレクトリを同期する方法を見てみましょう。
目次
- 目次
- 何をするの
- Web App を起動しよう
- GitHub から継続的デプロイ連携を組む
- Kudu による状態確認
- push した変更の継続的デプロイ確認
- 一度連携を外して、別ブランチと連携し特定のディレクトリのみ同期する
- まとめ
何をするの
先日紹介した、OneGetのプライベートソースがありました。これを使ってデプロイの制御を行います。
次の流れでやってみましょう。
- Web App を起動しよう
- GitHub から継続的デプロイ連携*1を組む
- Kudu による状態確認
- push した変更の継続的デプロイ確認
- 一度連携を外して、別ブランチと連携し特定のディレクトリのみ同期する
継続的デプロイと合わせて、Kudu を使ってどう変化するか見てみましょう。
Web App を起動しよう
新ポータルで行います。旧ポータルでも余り操作は変わらないのでさくっと行きましょう。
新ポータルへ
https://portal.azure.com にアクセスして、
マイクロソフトアカウント、あるいは組織アカウントでログインします。ユーザー名のドメインに応じてそれぞれの画面にリダイレクトされます。
以前は旧ポータルがデフォルトでしたが、今ならログインすると新ポータルが見えると思います。
もし旧ポータルの場合は、右上のアカウントから Switch to Azure Preview Portal を選べばいいでしょう。
ログインでいつもはまるアレ
https://portal.azure.com は、ユーザー名のドメインに応じたリダイレクトをするのです。
が、Chromeだとちょくちょくリダイレクトに失敗してこけてそのまま身動きとれなくなるのはんぱなくストレスなのでいい加減直してほしいですね。*2
あと、Edge だとちょくちょく #
のみになったり、突然 Office365 にリダイレクトしようとして組織アカウントじゃないので起こられたりするのも。
Chromeの場合は、プライベートセッションにするとだいたいいけます。Edge は、もう一度アドレスに https://portal.azure.com/?l=en&r=1
を入れると今度は入れるのでほげー。
Web App を新規作成
今回はリソースマネージャーも使わず簡単にいきます。
New > Web + Mobile > Web App
おしまい。Virtual Machine や AWS EC2 よりここは圧倒的に楽です。
今回は、AppName (つまりアクセス時のアドレスのためのサブドメイン)にguitarrapc-OneGet をつけました。これにより Web App の公開アドレスは https://guitarrapc-OneGet.azurewebsites.net
となります。
作成直後から、
30秒程度で利用可能になりました。いい素早さですね。
GitHub から継続的デプロイ連携を組む
旧ポータルでの Web App作成だと、SCM*3デプロイの設定も作成時にでましたが完全ポータルでは今回出ませんでした。そこで、起動してある Web Appsに途中からデプロイを組んでみましょう。とはいえ、Jenkins や Circle CI も組む必要はなく、Visual Studio からの発行を行う必要もありません。
さっそく、Web App の下にスクロールします。
Set up continuous deployment というのがあり、ここが SCM からの継続的デプロイ設定箇所です。開いてみましょう。
Microsoft Azure > guitarrapc-oneget > Continuous Deployment > Choose source といくと、連携可能なSCM一覧がでてきました。
Azure Web Appは、Visual Studio Online 以外にも、git, GitHub, BitBucket, DropBpx, その他外部リポジトリ など各種SCMからの継続的デプロイが構成可能です。
今回は GitHub との継続的デプロイを選択します。するとリポジトリのWebHook を受け取るため GitHub アカウントとの連携を求められるので、Authorize から連携するユーザーで認証してください。*4
認証が終わったら、Choose Project からデプロイするリポジトリを選択します。
今回は MyOneGetServer ですね。
最後に、ブランチを master にして完了です。
連携直後に最新コミットが自動デプロイされる
設定が完了すると、10秒ほど読み込みして
現在の状態が表示されます。リポジトリにまだ push していないので、継続的デプロイは実行されていません。と思いきや??
継続的デプロイを設定すると直後に最新コミットがデプロイされます。
結果、先ほどの Web App のアドレスにアクセスすると、見事に表示されます。簡単素敵。
デプロイのログ
デプロイの結果を選択すると、デプロイ履歴が表示されます。履歴を選択すると、そのログが表示されます。さらにビルドログを選択することで詳細が表示されます。
これをみることで、nuget restore の状態、MSBuild がいつ、どう動いたのかなどはログで簡単に追うことができます。
Kudu による状態確認
Azure Web App が、PaaS として強力なのはもちろんですが、なにより Kudu の存在が大きいでしょう。
Kudu は Azure Web App の git デプロイの裏のエンジンです。が、それだけでなく、Kudu を使うことで、Azure Web App の中身や裏で何が起こっているのか。今どんな状態なのかまで、あたかも IaaS を扱うごとく容易に把握できます。
Kudu Services にアクセス
早速Kudu のポータルにアクセスします。Wiki にかかれている通り、公開されている Web App アドレスのドメインに .scm
を差し込むだけです。
例えば、https://guitarrapc-oneget.azurewebsites.net/
なら、 https://guitarrapc-oneget.scm.azurewebsites.net/
となります。
見えましたね?
PowerShell でのデバッグコンソール
Kudu を使うことで、cmd か PowerShell をデバッグコンソールで扱えます。もちろんファイル操作もある程度可能です。
早速 PowerShell のデバッグコンソールを開きましょう。Debug Console > PowerShell と進みます。
PowerShell コンソールが ブラウザ上に表示されました。
表示されているパスが、基点となります。
Azure Web App の構成
ざっくり環境変数を見れば概要はつかめます。
通常良く見る C:\ がシステムドライブな構成 とは異なり、D:\ が基本です。あとは、もろもろ見えますが、それほど大きな差異はなくふつうに扱えますね。
Name Value ---- ----- ALLUSERSPROFILE D:\local\ProgramData APP_POOL_CONFIG C:\DWASFiles\Sites\#1guitarrapc-OneGet\Config... APP_POOL_ID ~1guitarrapc-OneGet APPDATA D:\local\AppData APPSETTING_ScmType GitHub APPSETTING_WEBSITE_AUTH_ENA... False APPSETTING_WEBSITE_NODE_DEF... 0.10.32 APPSETTING_WEBSITE_SITE_NAME guitarrapc-OneGet aspnet:DisableFcnDaclRead true aspnet:PortableCompilationO... true aspnet:PortableCompilationO... Microsoft.Web.Compilation.Snapshots.SnapshotH... AZURE_JETTY9_CMDLINE -Djava.net.preferIPv4Stack=true -Djetty.port=... AZURE_JETTY9_HOME D:\Program Files (x86)\jetty-distribution-9.1... AZURE_TOMCAT7_CMDLINE -Dport.http=%HTTP_PLATFORM_PORT% -Djava.util.... AZURE_TOMCAT7_HOME D:\Program Files (x86)\apache-tomcat-7.0.50 AZURE_TOMCAT8_CMDLINE -Dport.http=%HTTP_PLATFORM_PORT% -Djava.util.... AZURE_TOMCAT8_HOME D:\Program Files (x86)\apache-tomcat-8.0.23 branch master CommonProgramFiles D:\Program Files (x86)\Common Files CommonProgramFiles(x86) D:\Program Files (x86)\Common Files CommonProgramW6432 D:\Program Files\Common Files COMPUTERNAME RD00155E002C72 ComSpec D:\Windows\system32\cmd.exe deployment_branch master DEPLOYMENT_SOURCE D:\home DEPLOYMENT_TARGET D:\home\site\wwwroot DIRCMD /OG /ON EnableNuGetPackageRestore true FP_NO_HOST_CHECK NO GO_WEB_CONFIG_TEMPLATE C:\Program Files (x86)\SiteExtensions\Kudu\47... HOME D:\home HOME_EXPANDED C:\DWASFiles\Sites\#1guitarrapc-OneGet\Virtua... HOMEDRIVE D: HOMEPATH \home JAVA_HOME D:\Program Files\Java\jdk1.7.0_51 KUDU_SELECT_NODE_VERSION_CMD node "C:\Program Files (x86)\SiteExtensions\K... KUDU_SELECT_PYTHON_VERSION_CMD python "C:\Program Files (x86)\SiteExtensions... KUDU_SYNC_CMD kudusync LOCAL_EXPANDED C:\DWASFiles\Sites\#1guitarrapc-OneGet LOCALAPPDATA D:\local\LocalAppData MSBUILD_PATH D:\Windows\Microsoft.NET\Framework\v4.0.30319... NPM_JS_PATH D:\Program Files (x86)\npm\1.4.28\node_module... NUGET_EXE C:\Program Files (x86)\SiteExtensions\Kudu\47... NUMBER_OF_PROCESSORS 8 OS Windows_NT Path C:\Program Files (x86)\SiteExtensions\Kudu\47... PATHEXT .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.... POST_DEPLOYMENT_ACTION postdeployment POST_DEPLOYMENT_ACTIONS_DIR D:\home\site\deployments\tools\PostDeployment... PROCESSOR_ARCHITECTURE x86 PROCESSOR_ARCHITEW6432 AMD64 PROCESSOR_IDENTIFIER AMD64 Family 16 Model 8 Stepping 1, AuthenticAMD PROCESSOR_LEVEL 16 PROCESSOR_REVISION 0801 ProgramData D:\local\ProgramData ProgramFiles D:\Program Files (x86) ProgramFiles(x86) D:\Program Files (x86) ProgramW6432 D:\Program Files PROMPT $P$G PSModulePath WindowsPowerShell\Modules;D:\Program Files (x... PUBLIC D:\Users\Public REGION_NAME Japan West REMOTEDEBUGGINGBITVERSION vx86 REMOTEDEBUGGINGPORT REWRITETABLE SCM_BUILD_ARGS SCM_COMMAND_IDLE_TIMEOUT 60 SCM_DNVM_PS_PATH C:\Program Files (x86)\SiteExtensions\Kudu\47... SCM_GIT_EMAIL windowsazure SCM_GIT_USERNAME windowsazure SCM_LOGSTREAM_TIMEOUT 1800 SCM_TRACE_LEVEL 1 ScmType GitHub SITE_BITNESS x86 SystemDrive D: SystemRoot D:\Windows TEMP D:\local\Temp TMP D:\local\Temp USERDOMAIN WORKGROUP USERNAME RD00155E002C72$ USERPROFILE D:\local\UserProfile WEBJOBS_DEPLOY_CMD deploy_webjobs.cmd webpages:Enabled true webpages:Version 3.0.0.0 WEBROOT_PATH D:\home\site\wwwroot WEBSITE_AUTH_ENABLED False WEBSITE_COMPUTE_MODE Shared WEBSITE_HOSTNAME guitarrapc-oneget.azurewebsites.net WEBSITE_HTTPLOGGING_ENABLED 0 WEBSITE_IIS_SITE_NAME ~1guitarrapc-OneGet WEBSITE_INSTANCE_ID 24db6f195ef296845321623d224468be044afda818348... WEBSITE_NODE_DEFAULT_VERSION 0.10.32 WEBSITE_OWNER_NAME f6f639a1-58f5-4277-ac58-ee8bd698878d+japanwes... WEBSITE_SCM_ALWAYS_ON_ENABLED 0 WEBSITE_SCM_SEPARATE_STATUS 1 WEBSITE_SITE_MODE Limited WEBSITE_SITE_NAME guitarrapc-OneGet WEBSITE_SKU Free WEBSOCKET_CONCURRENT_REQUES... 5 windir D:\Windows windows_tracing_flags windows_tracing_logfile
継続的デプロイによるクローン先パス
リポジトリがクローンされるパスを知っておくのは、デプロイを弄るうえで大事です。
起点になるのは、$env:Home\Site\repository
となります。
PS D:\home> ls site Directory: D:\home\site Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 9/8/2015 4:24 PM deployments d---- 9/8/2015 4:57 PM locks d---- 9/8/2015 4:24 PM repository d---- 9/8/2015 4:24 PM wwwroot
この辺の環境変数と合致しないのが腑に落ちないので、詳しい人の解説が欲しいですね。Kudu で監視する限り、Repository パスにClone しているようにみえるのですが...。
deployment_branch master DEPLOYMENT_SOURCE D:\home DEPLOYMENT_TARGET D:\home\site\wwwroot
アプリケーションが稼動するサイトパス
こちらもデプロイをいじるうえで必須です。
$env:\WEBROOT_PATH
となります。
デプロイによるリポジトリの変化をみる
パスがわかればこっちのものです。デプロイによって、クローンされたパスにファイルがあるか確認できますね。
先ほどのデプロイの時間と
クローンされたパスの時間、ビルド生成物をみれば一致していることがわかります。
PS D:\home> ls site/repository/MyOneGetServer Directory: D:\home\site\repository\MyOneGetServer Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 9/8/2015 4:24 PM App_Readme d---- 9/8/2015 4:24 PM bin d---- 9/8/2015 4:24 PM DataServices d---- 9/8/2015 4:24 PM obj d---- 9/8/2015 4:24 PM Properties -a--- 9/8/2015 4:24 PM 1952 Default.aspx -a--- 9/8/2015 4:24 PM 35561 favicon.ico -a--- 9/8/2015 4:24 PM 9588 MyOneGetServer.csproj -a--- 9/8/2015 4:24 PM 973 packages.config -a--- 9/8/2015 4:24 PM 5582 Web.config -a--- 9/8/2015 4:24 PM 1299 Web.Debug.config -a--- 9/8/2015 4:24 PM 1360 Web.Release.config PS D:\home> ls site/repository/MyOneGetServer\bin Directory: D:\home\site\repository\MyOneGetServer\bin Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 9/8/2015 4:24 PM roslyn -a--- 9/8/2015 4:24 PM 176128 Elmah.dll -a--- 9/8/2015 4:24 PM 29344 Microsoft.CodeDom.Providers.DotNet CompilerPlatform.dll -a--- 9/8/2015 4:24 PM 1805 Microsoft.CodeDom.Providers.DotNet CompilerPlatform.xml -a--- 9/8/2015 4:24 PM 45416 Microsoft.Web.Infrastructure.dll -a--- 9/8/2015 4:24 PM 81600 Microsoft.Web.XmlTransform.dll -a--- 9/8/2015 4:24 PM 5120 MyOneGetServer.dll -a--- 9/8/2015 4:24 PM 5582 MyOneGetServer.dll.config -a--- 9/8/2015 4:24 PM 11776 MyOneGetServer.pdb -a--- 9/8/2015 4:24 PM 126976 Ninject.dll -a--- 9/8/2015 4:24 PM 384512 Ninject.pdb -a--- 9/8/2015 4:24 PM 325908 Ninject.xml -a--- 9/8/2015 4:24 PM 532656 NuGet.Core.dll -a--- 9/8/2015 4:24 PM 49840 NuGet.Server.dll -a--- 9/8/2015 4:24 PM 26624 RouteMagic.dll -a--- 9/8/2015 4:24 PM 10752 WebActivatorEx.dll
デプロイによるサイトの変化をみる
同様にサイトもわかりますね。リポジトリの生成物と一致しているはずです。
PS D:\home> ls site/wwwroot Directory: D:\home\site\wwwroot Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 9/8/2015 4:24 PM App_Readme d---- 9/8/2015 4:24 PM bin d---- 9/8/2015 4:24 PM DataServices -a--- 9/8/2015 4:24 PM 1952 Default.aspx -a--- 9/8/2015 4:24 PM 35561 favicon.ico -a--- 9/8/2015 4:24 PM 973 packages.config -a--- 9/8/2015 4:24 PM 5569 Web.config PS D:\home> ls site/wwwroot/bin Directory: D:\home\site\wwwroot\bin Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 9/8/2015 4:24 PM roslyn -a--- 9/8/2015 4:24 PM 176128 Elmah.dll -a--- 9/8/2015 4:24 PM 29344 Microsoft.CodeDom.Providers.DotNet CompilerPlatform.dll -a--- 9/8/2015 4:24 PM 45416 Microsoft.Web.Infrastructure.dll -a--- 9/8/2015 4:24 PM 81600 Microsoft.Web.XmlTransform.dll -a--- 9/8/2015 4:24 PM 5120 MyOneGetServer.dll -a--- 9/8/2015 4:24 PM 126976 Ninject.dll -a--- 9/8/2015 4:24 PM 532656 NuGet.Core.dll -a--- 9/8/2015 4:24 PM 49840 NuGet.Server.dll -a--- 9/8/2015 4:24 PM 26624 RouteMagic.dll -a--- 9/8/2015 4:24 PM 10752 WebActivatorEx.dll
意図通りにデプロイされていますね。
push した変更の継続的デプロイ確認
さて、継続デプロイということは、SCMと連携して変更が自動的に Web App にデプロイされるはずです。
GitHub の場合は、Webhook を使っており、push のイベントを受けると自動デプロイされます。早速、master にテストコミットをします。*5
これを push すると?
即座に Github から Webhook が飛び、Web App でデプロイが開始されました。
デプロイが完了して、Active なバージョンが更新されていますね。
Kudu での確認
kudu で変更が反映されたか見てみましょう。
意図した通り、変更した Readme.md のみが更新されています。
PS D:\home> ls site/repository Directory: D:\home\site\repository Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 9/8/2015 4:24 PM MyOneGetServer d---- 9/8/2015 4:24 PM MyOneGetServer.Script d---- 9/8/2015 4:24 PM packages -a--- 9/8/2015 4:24 PM 2581 .gitattributes -a--- 9/8/2015 4:24 PM 3412 .gitignore -a--- 9/8/2015 4:24 PM 224 .gitmodules -a--- 9/8/2015 4:24 PM 1526 MyOneGetServer.sln -a--- 9/8/2015 5:16 PM 393 README.md
一度連携を外して、別ブランチと連携し特定のディレクトリのみ同期する
さてようやく本題です。
このGitHub での継続デプロイは、このままだと Web Siteのコンテンツが Github のビルド結果と同一になってしまいます。
しかし現実にはこれでは困るシーンがいくつかあります。
- WordPress をホスティングしており、一部のWordPress管理外の静的ファイルのみ Github と連動させたい場合は、丸ごとGitHubと同期されては困ります
- デプロイのフローに特殊な処理をはさみ込みたい場合も、デプロイを調整したくなるでしょう。
- プライベートNuGet サーバーからライブラリを取得してきたい
そこで出てくるのが、カスタムデプロイです。
参考
参考にするのは、Kudu の Wiki と Channel 9 です。
Custom Deploy の概要
どこのサイトをみてもざっくりと誰も書いていないのですが、単純です。*6
- リポジトリ直下に
.deployment
ファイルがあると、そこの[config]
属性に書かれたcommand=
のコマンドを実行します .deployment
から、別のcmdや.ps1を呼び出すことも可能でより複雑な処理を書くこともできます
たったこれだけです。早速 MyOneGetServer のリポジトリで、試してみましょう。
カスタムデプロイ構成
やることは単純です。
MyOneGetServer.Scriptフォルダ
を、wwwroot 直下に同期する
これを行うために以下の構成にします。
.deployment
ファイルを作成するBuildScript\deploy.ps1
で同期処理を記述する- 一度継続的デプロイ連携を切る
- 変更を push する
- 再度継続デプロイを連携してカスタムデプロイの確認
この .deployment
に記述された内容だけ実施されるのはとても大事です。何しろ 継続的デプロイ連携をした瞬間にデプロイされるので、事前に .deployment
の内容だけ実施されるとわかっていれば、運用中のアプリを壊す心配がなくなります。
.deploy ファイルの作成
とりあえず、さくっと作ります。
できましたね。
続いて、BuildScript\deploy.ps1
を実行するようにします。
今回のように、PowerShell スクリプトを実行する場合は、-ExecutionPolicy RemoteSigned
を指定しましょう。でないと、デフォルトがRestricted
になっており、.ps1 が実行できません。
BuildScript\deploy.ps1 の記述
続いて、BuildScript\deploy.ps1
を作成します。
同期内容を記述します。
同期処理には注意です。Azure Web Apps のデプロイ過程では、Web Deployment を呼び出してもエラーが出ます。
kudu でも実行できないことが確認できます。
そのため、PowerShell で頑張らずとも、ここは RoboCopy を使って同期処理を書きましょう。
ポイントは、try{}catch{}
での exit
処理です。PowerShell は、cmd などからの外部呼び出しでふつーにエラーをだしても終了コードは1のままです。
そこで、明示的にエラーを外部に通知するためには、終了コードとともに終了させる必要があります。*7今回は、エラーを起こす可能性のある、RoboCopy の処理でのエラーを捉えるようにしています。
これで準備は完了しました。
一度継続的デプロイ連携を切る
それでは、すでに存在するアプリケーションでの SCM連携を模擬するため、一度連携を切ります。
連携は、Disconnect
を選択することで切れます。
実行すると無事に切れましたね。
連携を切っても、連携してたアプリが消えるわけではないので安心してください。
変更を push する
それでは、先ほどの .deployment
と BuildScript\deploy.ps1
を push します。
再度継続デプロイを連携してカスタムデプロイの確認
連携したときのデプロイが、「カスタムデプロイがない時のビルド結果のデプロイ」ではなく「deploy.ps1 で記述したカスタムデプロイ処理のみ実施」されればokです。
さくっと連携します。
デプロイがキックされます。
ログを見ると、うまくいってそうですね。
kudu でみると、連携前のフォルダ構成に、
意図した通りMyOneGetServer.Script
が増えていますね。
まとめ
いかがでしたでしょうか? Azure Web App 最高ですね。継続的デプロイが CIいらずでここまで簡単にできるのは、.NET ではなかなか難しいものです。AppVeyor とかもふつーにCIでつらいですしね。
カスタムデプロイやkudu での確認も簡単です。
ぜひぜひ使ってみてください。