Azure Web Apps 内のとあるファイルを WebJobs を使ってバックアップする
(7/10 WebJobs SDK で書く方法を修正しました。)
Azure Web Apps としてホストしている Web アプリのとあるファイルを、定期的に Azure Storage にバックアップしたく、WebJobs を使って実装しました。
WebJobs SDK で楽にしたかったがちょっと無理だった
実装は難しくなく、コンソールアプリケーションを作成して、とあるファイルを Azure Storage SDK を使って Storage の Blob にアップロードすればいい話なのですが、
Azure Storage SDK でその処理を書くのが面倒だなと思いつつ、以前見た WebJobs SDK の記事を思い出して↓
blog.shibayan.jp
ここにあるように [BlobOutput("backup/{name}")] という風に属性で楽に書けたらいいなと WebJobs SDK でも試してみました。(が今回のケースでは属性は使えず)
目次
ということで、以下のように手順を書いておきたいと思います。
- Azure で Web Apps と Stroage アカウントを用意する
- WebJobs 用のコンソールアプリケーションを作成する
- Azure Stroage SDK でファイルを Blob にアップする
- (別案)Azure WebJobs SDK でファイルを Blob にアップする
注意:
※Web Apps にはデフォルトでバックアップ機能があります。今回は1つのファイルだけバックアップしたかった。
※そもそもバックアップしたいようなファイルを Web Apps ではなく元から Blob に配置するべき、というのもあります。
環境
- Visual Studio 2013 Update 4
- Azure SDK for .NET 2.6 インストールはここから
Azure で Web Apps と Storage アカウントを用意する
Azure Portal サイト で Web Apps と Storage を作成します。詳細は省きます。
例として、Web Apps 内の Contents フォルダ内にある sample1.jpg を、1日に1回、Storage に「20150707_sample1.jpg」といった名前で保存する WebJobs を定義します。
ここでは、下のように ASP.NET プロジェクトを用意し、Web Apps にデプロイしておきました。
WebJobs 用ののコンソールアプリケーションを作成する
Azure SDK for .NET の機能を利用し、WebJobs 用のコンソールアプリケーションを作成します。
(WebJobs は、.cmd、.bat、.exe、.ps1 等でもOK。既存のコンソールアプリケーションから作成も可。)
Visual Studio で、ファイル→新規作成→プロジェクトを選択し、↓のように WebJobs のテンプレートを選択します。
ここではソリューションの下に作成しました。
(発行の際は、コンソールアプリ単体で発行可能、また Web アプリを発行する際に一緒に発行することも可能。)
作成すると、次のようなファイルが用意されています。
Program.cs :
using Microsoft.Azure.WebJobs; namespace WebJob1 { // To learn more about Microsoft Azure WebJobs SDK, please see http://go.microsoft.com/fwlink/?LinkID=320976 class Program { // Please set the following connection strings in app.config for this WebJob to run: // AzureWebJobsDashboard and AzureWebJobsStorage static void Main() { var host = new JobHost(); // The following code ensures that the WebJob will be running continuously host.RunAndBlock(); } } }
Functions.cs :
using System.IO; using Microsoft.Azure.WebJobs; namespace WebJob1 { public class Functions { // This function will get triggered/executed when a new message is written // on an Azure Queue called queue. public static void ProcessQueueMessage([QueueTrigger("queue")] string message, TextWriter log) { log.WriteLine(message); } } }
package.config
<?xml version="1.0" encoding="utf-8"?> <packages> <package id="Microsoft.Azure.WebJobs" version="1.0.0" targetFramework="net452" /> <package id="Microsoft.Azure.WebJobs.Core" version="1.0.0" targetFramework="net452" /> <package id="Microsoft.Data.Edm" version="5.6.0" targetFramework="net452" /> <package id="Microsoft.Data.OData" version="5.6.0" targetFramework="net452" /> <package id="Microsoft.Data.Services.Client" version="5.6.0" targetFramework="net452" /> <package id="Microsoft.Web.WebJobs.Publish" version="1.0.3" targetFramework="net452" /> <package id="Microsoft.WindowsAzure.ConfigurationManager" version="2.0.3" targetFramework="net452" /> <package id="Newtonsoft.Json" version="6.0.4" targetFramework="net452" /> <package id="System.Spatial" version="5.6.0" targetFramework="net452" /> <package id="WindowsAzure.Storage" version="4.2.1" targetFramework="net452" /> </packages>
App.config に、2つの Storage アカウントの接続文字列を定義する場所が用意されているので、Azure Portal サイトから接続文字列を参照し入力します。
App.config :
<?xml version="1.0" encoding="utf-8"?> <configuration> <connectionStrings> <!-- The format of the connection string is "DefaultEndpointsProtocol=https;AccountName=NAME;AccountKey=KEY" --> <!-- For local execution, the value can be set either in this config file or through environment variables --> <add name="AzureWebJobsDashboard" connectionString="****" /> <add name="AzureWebJobsStorage" connectionString="****" /> </connectionStrings> ...
AzureWebJobsDashboard と AzureWebJobsStorage のところです。
Azure Portal サイトの該当 Storage の↓の場所にある、プライマリ接続文字列の値を connectionString="" のところに入力します。
Functions.cs のコードは今回使用しないので、削除しておきます。
Azure Stroage SDK でファイルを Blob にアップする
コンソールアプリケーション右クリック→追加→参照で、「System.Configuration」の参照を追加します。
Program.cs を↓のように編集します。
using Microsoft.Azure.WebJobs; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; using System; using System.Configuration; using System.IO; namespace WebJob1 { // To learn more about Microsoft Azure WebJobs SDK, please see http://go.microsoft.com/fwlink/?LinkID=320976 class Program { // Please set the following connection strings in app.config for this WebJob to run: // AzureWebJobsDashboard and AzureWebJobsStorage static void Main() { string path = @"D:\home\site\wwwroot\Contents\sample1.jpg"; CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AzureWebJobsStorage"].ConnectionString); CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); CloudBlobContainer container = blobClient.GetContainerReference("mybackup"); container.CreateIfNotExists(); CloudBlockBlob blockBlob = container.GetBlockBlobReference( String.Format("{0:yyyyMMdd}_{1}", DateTime.UtcNow, Path.GetFileName(path))); using (var fileStream = System.IO.File.OpenRead(path)) { blockBlob.UploadFromStream(fileStream); } } } }
(Web Apps 上のファイルを @"D:\home\site\wwwroot\Contents\sample1.jpg" と指定していいものかどうか不明)
コードでは、Blob の mybackup コンテナー配下にファイルをアップロードしています。
コンソールアプリのプロジェクトを右クリックし、「Azure WebJob として発行」を選択します。
ダイアログが出るので、WebJobs を実行したいタイミングを設定します。
次に発行先のダイアログがでるので、Web Apps の発行先を選択し、デプロイを行います。
実行のタイミングは、webjob-publish-settings.json で定義されています。
ダイアログで選択した後、もう一度ダイアログでタイミングを選択したい場合は、この json ファイルを削除してもう一度「Azure WebJob として発行」を選択するとダイアログが出ます。
WebJobs が実行されると、Storage にファイルが生成されたことが確認できると思います。
(画像は、Azure Stroage Explorer で Storage を確認したもの)
また、Azure Portal サイトの Web Apps の方から、作成した WebJobs が表示されることを確認できます。
「ログ」のところをクリックすれば、Azure WebJobs Dashboard のページへ飛びます。
以上で、WebJobs を使った単体ファイルのバックアップが可能になります。
(別案)Azure WebJobs SDK でファイルを Blob にアップする
ここからは、WebJobs SDK を使った方法。
先ほどは削除した Functions.cs を追加し、Program.cs と合わせて次のように編集します。
Program.cs :
using Microsoft.Azure.WebJobs; namespace JobTry.WebJob { // To learn more about Microsoft Azure WebJobs SDK, please see http://go.microsoft.com/fwlink/?LinkID=320976 class Program { // Please set the following connection strings in app.config for this WebJob to run: // AzureWebJobsDashboard and AzureWebJobsStorage static void Main() { var host = new JobHost(); // Functions.cs の OutputBlob メソッドで定義した関数を呼び出す host.Call( typeof(Functions).GetMethod("OutputBlob"), new { path = @"D:\home\site\wwwroot\Contents\sample1.jpg" }); } } }
Functions.cs :
using System; using System.IO; using Microsoft.Azure.WebJobs; using Microsoft.WindowsAzure.Storage.Blob; namespace JobTry.WebJob { public class Functions { [NoAutomaticTrigger] //手動でトリガーする(Program.cs側から呼び出す) public static void OutputBlob(string path, IBinder binder) { var attribute = new BlobAttribute( String.Format("mybackup/{0:yyyyMMdd}_{1}", DateTime.UtcNow, Path.GetFileName(path)), FileAccess.ReadWrite); CloudBlockBlob blob = binder.Bind<CloudBlockBlob>(attribute); using (FileStream fileStream = new FileStream(path, FileMode.Open)) { blob.UploadFromStream(fileStream); } } } }
これで同じように WebJobs として発行を行い、実行します。
どちらの方法もコードが似たようなものですが、そもそも WebJobs SDK は Storage にあるデータをごにょごにょするためのライブラリなので、今回のケースではそれを発揮できていません。
Azure Web ジョブ SDK とは に、
Web ジョブ SDK の目的は、Web ジョブとして実行され、
Azure Storage のキュー、BLOB、テーブルや、Service Bus キューと組み合わせて動作するコードを記述するタスクを簡素化することです。
と書いてあります。