miso_soup3 Blog

主に ASP.NET 関連について書いています。

Azure Web Apps 内のとあるファイルを WebJobs を使ってバックアップする

(7/10 WebJobs SDK で書く方法を修正しました。)

Azure Web Apps としてホストしている Web アプリのとあるファイルを、定期的に Azure Storage にバックアップしたく、WebJobs を使って実装しました。

f:id:miso_soup3:20150709020815p:plain

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 に配置するべき、というのもあります。

環境

Azure で Web Apps と Storage アカウントを用意する

Azure Portal サイト で Web Apps と Storage を作成します。詳細は省きます。

f:id:miso_soup3:20150709023218p:plain

f:id:miso_soup3:20150709023631p:plain

例として、Web Apps 内の Contents フォルダ内にある sample1.jpg を、1日に1回、Storage に「20150707_sample1.jpg」といった名前で保存する WebJobs を定義します。

ここでは、下のように ASP.NET プロジェクトを用意し、Web Apps にデプロイしておきました。

f:id:miso_soup3:20150709024022p:plain

WebJobs 用ののコンソールアプリケーションを作成する

Azure SDK for .NET の機能を利用し、WebJobs 用のコンソールアプリケーションを作成します。
(WebJobs は、.cmd、.bat、.exe、.ps1 等でもOK。既存のコンソールアプリケーションから作成も可。)

Visual Studio で、ファイル→新規作成→プロジェクトを選択し、↓のように WebJobs のテンプレートを選択します。

f:id:miso_soup3:20150709024551p:plain

ここではソリューションの下に作成しました。

f:id:miso_soup3:20150709024905p:plain

(発行の際は、コンソールアプリ単体で発行可能、また 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="" のところに入力します。

f:id:miso_soup3:20150709030221p:plain

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 として発行」を選択します。

f:id:miso_soup3:20150709030953p:plain

ダイアログが出るので、WebJobs を実行したいタイミングを設定します。

f:id:miso_soup3:20150709031130p:plain

次に発行先のダイアログがでるので、Web Apps の発行先を選択し、デプロイを行います。

実行のタイミングは、webjob-publish-settings.json で定義されています。

f:id:miso_soup3:20150709031549p:plain

ダイアログで選択した後、もう一度ダイアログでタイミングを選択したい場合は、この json ファイルを削除してもう一度「Azure WebJob として発行」を選択するとダイアログが出ます。

WebJobs が実行されると、Storage にファイルが生成されたことが確認できると思います。

f:id:miso_soup3:20150709031855p:plain

(画像は、Azure Stroage Explorer で Storage を確認したもの)

また、Azure Portal サイトの Web Apps の方から、作成した WebJobs が表示されることを確認できます。

f:id:miso_soup3:20150709032130p:plain

「ログ」のところをクリックすれば、Azure WebJobs Dashboard のページへ飛びます。

f:id:miso_soup3:20150709032340p:plain

以上で、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 キューと組み合わせて動作するコードを記述するタスクを簡素化することです。

と書いてあります。