ClearDBから、Azure Database for MySQL(Preview) への移行

このブログを作ったときから、ClearDBを使い続けていましたが、今年になって、Azure としてMySQLのマネージドサービスが出た(Preview)ということで、マイグレーションしてみました。

参考にしたのはこの記事
(ほぼそのまま)

https://azure.microsoft.com/ja-jp/blog/cleardb-migration-to-azure-database-for-mysql/

やったこと

  1. リンクの「https://dev.mysql.com/downloads/workbench/」からworkbenchをダウンロードしてインストール
  2. Azureポータル上から、ClearDBの接続文字列を拾い集める。ホスト名、ユーザー名、パスワード。
  3. workbenchを起動して、接続先を登録しておく。テスト接続成功でOK
  4. Azureで作っておいた Azure Database for MySQL の接続文字列を取得。ホスト名、ユーザー名、パスワード。
  5. 同様にworkbenchで接続する。このときポータル上から作業している端末のIPアドレスを許可するように設定する。「+自分の IP を追加」を選ぶと早い。
    保存。
  6. あとは、最初の記事のようにマイグレーションウィザードと!
  7. しかし、途中クエリのタイムアウトエラーが起きたので、サーバーパラメーターの「long_query_time」を10から30に変更して何度かRetryして成功。
  8. WordPress側は、ルートにある「wp-config.php」を書き換えた
  9. しかし、SSL接続を強制しているため、接続エラーとなる。(一度Debugを有効にして確認した)
  10. そこで、「wp-config.php」に
    define('MYSQL_CLIENT_FLAGS', MYSQL_CLIENT_SSL);

を追加して無事に完了

レスポンスは気持ち早くなったような気がしている。

何よりこの記事の画像にしているように、パフォーマンスをメトリックで確認できるので、使っていく中で適切なスケールとかも見えてきそうなところ。

 

Paas上のDevOps というものを受講してみて

とあるきっかけからチャレンジ

Welcome to Microsoft’s Azure Paas上のDevOps!

結果からいうと、合格点70%に対して70%!
で、問題の翻訳の質があんまりよくないのもあったけど、
何を聞かれているのか全くわからないのもあった。。。(多分私のスキル不足)

ほかに受講できるもの「azure-skills」

とはいえ、コースの内容は面白いものでした。

5つのモジュールで構成されており、
最初のモジュールは、DevOpsとは、なぜ?といったような考え方から入り、
自動化するアプローチ、どうしていったらいいかとか。

そして中盤からツールの使い方へフォーカスして、
コードを用いた、ハンズオンまで用意されていました。
このとき、Azureのサブスクリプションや、Visual Studio 2015 が必要になりました。
コースや個人差があるとは思いますが、
全体で12時間以上かかっていたような気がします。補足資料もじっくり読むともっともっとかかりそう。

かかるということはそれだけ多くの内容を知ることができるので、
これはVirtual Academyとは比にならないくらい。

おすすめしたい!と思いますー

ハンズオン

一部内容が古いものがあって、今のAzureに当てはめたときに・・・という補完が必要でした。またビルドエラーになるものもあるので、そこを問題ないようにもっていくというのも一つの醍醐味かなぁと。コードはVS2015のASP.NET Coreであるために、xprojが採用されてます。これは既に古い存在なので、もしかしたら時間とともに動かなくなっていくかも…

Bad Request

何日にも分けてやってたりすると、途中Bad Requestが出るので、
プライベートモードにしたブラウザを使うか、クッキーや履歴を消してログインしなおすと大丈夫でした。
(ヘッダーサイズが大きすぎるぞと怒られるらしい)

認定書?

受講した人に聞くところ、私は最終試験70%だったために、特に何もなく終わったのですが、70%以上の成績をおさめると認定書?みたいなものがもらえるようです。
知識・経験不足…がんばろう

Azure Container Instances というサービスが・・・~blackjumbodog-dotnet-core

出てきたので、試してみました。

Fast and Easy Containers: Azure Container Instances

リンクは、公式のBlogです。

 

既に試しており、ざっくりまとめている方(しばやん)のを一読してみてください。

 

というわけで、OSC2017Hokkaidoでは、App Service on Linux でしたが、こちらはどうやら、Hyper-Vレベルで分離したcontainerのゲストインスタンスを利用可能になるサービスのようです。スケーリング等の機能はなく、IaaSに近いようなシンプルなコンテナといったところでしょうか。

実際に作ってみよう

Create your first container in Azure Container Instances

 

公式ではポータルのCLIを使ってとなってましたが、それっぽいテンプレートがポータルにあるのでそっちで試してみました。

イメージは、BlackJumboDog!
darkcrash/blackjumbodog-dotnet-core
ポートは3080をHTTPにしてるのでこれを!
こちら、Linuxベースのイメージになります。

しかしながら、色々試してて、リージョンは選択できるけどデプロイできないみたいな状態なので、今日現在ではおとなしくAzコマンドを使ったほうがいいのだろうと思いました。

加えて、ポータルで出来上がったものは、こんな感じで
あまり、というか情報がありませんでした。

そこで、コマンド

az container list -g [グループ名]
{
 "nextLink": null,
 "value": [
 {
 "containers": [
 {
 "command": null,
 "environmentVariables": [],
 "image": "darkcrash/blackjumbodog-dotnet-core",
 "instanceView": null,
 "name": "bjd-container4-XXXXXXX",
 "ports": [
 {
 "port": 3080
 }
 ],
 "resources": {
 "limits": null,
 "requests": {
 "cpu": 4.0,
 "memoryInGb": 4.0
 }
 },
 "volumeMounts": null
 }
 ],
 "id": "/subscriptions/XXXX/resourceGroups/bjd-container4/providers/Microsoft.ContainerInstance/containerGroups/bjd-container4-j6bvkbkaxarxy1",
 "imageRegistryCredentials": null,
 "ipAddress": {
 "ip": "13.93.166.22",
 "ports": [
 {
 "port": 3080,
 "protocol": "TCP"
 }
 ]
 },
 "location": "westus",
 "name": "bjd-container4-XXXXXXX",
 "osType": "Linux",
 "provisioningState": "Succeeded",
 "resourceGroup": "bjd-container4",
 "restartPolicy": null,
 "state": null,
 "tags": null,
 "type": "Microsoft.ContainerInstance/containerGroups",
 "volumes": null
 }
 ]
}

http://13.93.166.22:3080/

開いたー!ひゃっほー!
ただ、BlackJumboDogのコンソールログは見えないので、ちょっと実感は薄かったw

とはいえ、今までIaaS上にVMを上げてDockerHostを作り、そこにコンテナをのっけるのではなく、Hyper-Vに直接乗っかっているような状態なので、非常にシンプルでわかりやすくリソースの調整もポータル上からできるようになるというのであれば、VMっぽい感覚で、素早くコンテナ作れるってのはちょっとしたものを作る上ではいいんじゃないかと思いました。スケーリングはApp Service On LinuxがPaaSとして存在しているので、そんなすみわけがあるのかなぁと妄想したところでした。

これ、オーケストレーションももちろんだけど。
VNET接続とか、DNSまたはホスト名、LBとかいろいろできるようになったらまた違う可能性ありそうな気がしないでもない。ARMテンプレートとイメージだけでDevOpsとか。
ちょっと、●●ほしいなぁ、おしデプロイするかー!みたいなのも。

 

Azure Functions Runtime

Build 2017
の中でひそかに更新されたBlogがあった。

Introducing Azure Functions Runtime preview

なんというか、Runtime?ってどういうことだろうと思って開いてみたところ。

Azure Functionをオンプレミスでも動かせるようにできるものらしい。

 

最低要件とか

細かいドキュメントは、「Azure Functions Runtime Overview」あたりから

Windows Server 2016 or Windows 10 Creators Update with access to a SQL Server instance.

Windows Server 2016 または、Windows 10 Creators Updateとなっている。
このあたり、Windows Containerに依存している部分があるためと考えられそうだ。また、SQL Serverへの接続も必要と。

機能

このRuntimeが持つ機能は大きく二つ

「Azure Functions Management Role」
ポータルのような管理する機能を提供する

「Azure Functions Worker Role」
FunctionをWindows Containerに展開して実行する

ドキュメントでは、VisualStudio 2017からの直接デプロイもできるとはなっている。

ダウンロードは、Blog記事より下部にある

How do I get started?

Please download the Azure Functions Runtime installer.

からできた。

ちょっとだけ

以下、Windows Server 2016 へのインストールと、インストール後の画面
SQL Serverへの接続を構成しない限り動作しないようだ。
インストール後は再起動が必要となった。

スライドショーには JavaScript が必要です。

Azure Managed Disks – stripe 32 disks

びっくりなことに、仮想マシン上で扱えるディスクに
Managed Disksというものが追加された。
それまで、Azureの仮想マシンでは、StorageアカウントにBlobとしてVHDが追加される形で、少しややこしい部分もあり、物理的なVHDファイルを置いておきながら、仮想マシン独自の形で関連付けられていた。
Managed Disksは一つのリソースで一つのディスクと扱えるようになっており、現実世界のディスク1枚または、VHD1つのように考えることができて、サイズの指定もできて料金もわかりやすくなった。

価格

Managed Disks の価格

種類

大きく2種類。

<Premium>

SSDベースな、IOPS、スループット重視な
P10、P20、P30

 

<Standard>

HDDベースな
S4、S6、S10、S20、S30

 

仮想マシン

SSDベースなものは、接続できる仮想マシンのサイズが決まっているようです。DSシリーズ、DS_V2シリーズ、FSシリーズ、GSシリーズ。とSがついているやつ。

AzureのVMには、サイズによって最大IOPS、スループットが制限されるという仕様があるので、サイズの小さいインスタンスでは、思ったほどでないかもしれないですね。最大接続可能なManaged Disksの数も同様にサイズの制限を受けるようです。

Managed Disks 接続

ポータル上からぽちぽちクリック。旧来のようなストレージアカウントがあって、VHDファイルがあるというような実体はない様子。

1.Managed Disksのインスタンスを作成する

2.仮想マシンのディスクに接続する

だけ。

うん。このままだと面白くないので、少し試してみよう!

 

複数束ねてStripe

ディスク-ストライピング

というわけで試してみたこと。
D、DSでデプロイ。
接続するディスクはすべてホストキャッシュの読み取り書き込みを有効にしている。
仮想マシン内で、Stripeしている。

Standard Disk16 Disk32
(per 64GB)

Premium Disk10 Disk20 Disk32
(per 1TB)

おまけ、Temp(D:ドライブ)

わかったこと

Standardを32束ねても、Premiumには追い付かない!
コンシューマのSSDとベンチマークの結果だけで判断してはいけない。
(このディスクが物理ディスク一つではなく、冗長化された存在であることを忘れない)
また、揮発性の用途でよければ、Tempを使う選択肢がある。
大量にPremiumを接続する場合では、最大スループットは、ディスク側ではなく仮想マシン側の制約を受けているためか、20と32に差はほとんどなかった。
なお画像では、32のほうが低いようにみえるが、ホストキャッシュの影響か、非常に安定しない結果となった。ホストキャッシュの無効化によってまた異なる結果が出ると思われる。加えてStripeはファイル・アクセスごとに都合よく負荷分散をするためのものではないことも影響する一つと思われる。

また、この結果は個人的なもので、何かを保証するものではありません。

アプリ

CrystalDiskMark

 

 

 

Microsoft TranslatorのAPIを使うに当たって・・

Azureの認証が必要となるために、単純な呼び出しでは利用できない様子。

https://github.com/MicrosoftTranslator/GetAzureToken

ここのソースが参考になった。

Functionsで利用する場合は

https://github.com/MicrosoftTranslator/GetAzureToken/blob/master/AzureAuthToken.cs

Tokenの取得が必要となるため、上記を参考にするとよさそうだ。
リクエストがTokenの取得と、取得したTokenを渡すAPI呼び出しになっていることに注意が必要。

 

 

Visual Studio Tools for Azure Functions の修正版

Azure Functions 向けの拡張機能を入れたところで、.NET Coreのプロジェクトがだめになるっていうものに対する修正版が出てたようです。

https://blogs.msdn.microsoft.com/webdev/2016/12/01/visual-studio-tools-for-azure-functions/

Update 12-6-16 @5:00 PM: Updated version of the tools are available that fix the ability to open .NET Core projects with Azure Functions tools installed. Install the updated version over your old version to fix the issue, there is no need to uninstall the previous copy.

というわけで、入れてみたところ・・・

2016-12-10

インストール完了。
プロジェクトの新規作成で、ASP.NET Coreのプロジェクトテンプレートから作成したみところ、無事にできました。

2016-12-10-2

良かった良かったー

風邪っぽい・・・?VS2015の拡張機能

Microsoft Azure2 Advent Calendar 2016 の6日目の記事です。
.NET Core Advent Calendarの6日目の記事です。


2016-12-10追記
Visual Studio Tools for Azure Functions の修正版が出たようで、解消しました。

両方空いていたのと、両方を好きな人はこれから私と悲しい気持ちを味わう前に楽しくなってもらえればという願いを込めて書きました。
相変わらず、しょうもないネタなのですが・・・お時間あればお付き合いください。
Visual Studio 2015の話になります。

季節の変わり目で、咳が止まらず目が覚めて何気なく.NET Coreプロジェクトを作ろうとしたら・・・

2016-12-05-1

2016-12-05-2

あ、、、あれれ?コンソールだめなら、Webは・・・?

2016-12-05-3

2016-12-05-4

 

うーむ、VS2017 RCと共存してるからかなぁ・・・とか思いつつ、既存の.NET Coreアプリを開いてみたところ・・・

=====================
2016/12/04 5:47:00
Recoverable
System.Exception: ディスク上のプロジェクトファイルの検出中に次のエラーが発生しました。Could not load file or assembly 'Microsoft.VisualStudio.ProjectSystem.DotNet, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. 指定されたファイルが見つかりません。。
   at Microsoft.VisualStudio.ProjectSystem.DotNet.Common.FileMirroring.SourceItemsInMemoryProject.<InitializeFromDiskAsync>d__54.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.VisualStudio.ProjectSystem.DotNet.Common.FileMirroring.SourceItemsInMemoryProject.<Creator>d__52.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.VisualStudio.ProjectSystem.UnconfiguredProjectImpl.AutoLoadMethodStateMachine.<<StartExecution>b__6_0>d.MoveNext()
===================

どうやら風邪がうつったようです

いやいやそんなわけはなく・・・いろいろ調べてみたところ・・・
どうやら、Visual Studio Tools for Azure Funtionsの問題として認識されてるよというところまでは見つけました。

https://blogs.msdn.microsoft.com/webdev/2016/12/01/visual-studio-tools-for-azure-functions/

Warning: We have discovered that installing this Preview breaks the ability to create or open .NET Core projects in Visual Studio 2015.  We are currently investigating, and will make a fix available as soon as it is ready.  In the meantime, do not install this on any machines where you plan to work with .NET Core projects.

.NET Coreプロジェクトを扱うことができなくなってしまうということで、対策をがんばってるそうです。

そう・・・思えばFunctionsへの浮気心が、.NET Coreとの距離を近づけたのかもしれない・・・

そうか、浮気といえば・・・電話番号は二つ・・・つまり、マシンをもう一つAzureで作ればいいじゃない!
この発想には賛否両論あると思いますが…

というわけで、デプロイ!!
で、さりげなく機能紹介。

2016-12-05-5

というわけで、デプロイできた仮想マシンのブレードを開くと、
Automation スクリプトというのがあるのでそこを選択すると出てくるものです。
これは、ご存知の方多いとは思いますが、ARMというテンプレートで、この仮想マシンと同じものを再現するために使える逆起しの設計書みたいな状態です。
ただ、エラーが出てる通り、この仮想マシンに設定した自動シャットダウンと、仮想マシン拡張の診断機能は含まれていません。なので100%ではないですが、このJSONを1から作るよりも、一度作ってみたものをもとにJSON取得して、修正。
ARMとしてテンプレートデプロイをするというシナリオが近道のような気がします。

 

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "virtualMachines_vm20161206_adminPassword": {
            "defaultValue": null,
            "type": "SecureString"
        },
        "virtualMachines_vm20161206_name": {
            "defaultValue": "vm20161206",
            "type": "String"
        },
        "networkInterfaces_vm20161206128_name": {
            "defaultValue": "vm20161206128",
            "type": "String"
        },
        "networkSecurityGroups_vm20161206_nsg_name": {
            "defaultValue": "vm20161206-nsg",
            "type": "String"
        },
        "publicIPAddresses_vm20161206_ip_name": {
            "defaultValue": "vm20161206-ip",
            "type": "String"
        },
        "virtualNetworks_vm20161206_vnet_name": {
            "defaultValue": "vm20161206-vnet",
            "type": "String"
        },
        "storageAccounts_vm20161206diag122_name": {
            "defaultValue": "vm20161206diag122",
            "type": "String"
        },
        "storageAccounts_vm20161206disks246_name": {
            "defaultValue": "vm20161206disks246",
            "type": "String"
        }
    },
    "variables": {},
    "resources": [
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Compute/virtualMachines/vm20161206' から一般化されました。",
            "type": "Microsoft.Compute/virtualMachines",
            "name": "[parameters('virtualMachines_vm20161206_name')]",
            "apiVersion": "2015-06-15",
            "location": "japaneast",
            "properties": {
                "hardwareProfile": {
                    "vmSize": "Standard_F8s"
                },
                "storageProfile": {
                    "imageReference": {
                        "publisher": "MicrosoftVisualStudio",
                        "offer": "VisualStudio",
                        "sku": "VS-2015-Ent-VSU3-AzureSDK-29-Win10-N",
                        "version": "latest"
                    },
                    "osDisk": {
                        "name": "[parameters('virtualMachines_vm20161206_name')]",
                        "createOption": "FromImage",
                        "vhd": {
                            "uri": "[concat('https', '://', parameters('storageAccounts_vm20161206disks246_name'), '.blob.core.windows.net', concat('/vhds/', parameters('virtualMachines_vm20161206_name'),'20161204060340.vhd'))]"
                        },
                        "caching": "ReadWrite"
                    },
                    "dataDisks": []
                },
                "osProfile": {
                    "computerName": "[parameters('virtualMachines_vm20161206_name')]",
                    "adminUsername": "watashi.kanrisha",
                    "windowsConfiguration": {
                        "provisionVMAgent": true,
                        "enableAutomaticUpdates": true
                    },
                    "secrets": [],
                    "adminPassword": "[parameters('virtualMachines_vm20161206_adminPassword')]"
                },
                "networkProfile": {
                    "networkInterfaces": [
                        {
                            "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaces_vm20161206128_name'))]"
                        }
                    ]
                }
            },
            "resources": [],
            "dependsOn": [
                "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_vm20161206disks246_name'))]",
                "[resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaces_vm20161206128_name'))]"
            ]
        },
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Network/networkInterfaces/vm20161206128' から一般化されました。",
            "type": "Microsoft.Network/networkInterfaces",
            "name": "[parameters('networkInterfaces_vm20161206128_name')]",
            "apiVersion": "2016-03-30",
            "location": "japaneast",
            "properties": {
                "ipConfigurations": [
                    {
                        "name": "ipconfig1",
                        "properties": {
                            "privateIPAddress": "10.0.0.4",
                            "privateIPAllocationMethod": "Dynamic",
                            "publicIPAddress": {
                                "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddresses_vm20161206_ip_name'))]"
                            },
                            "subnet": {
                                "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vm20161206_vnet_name')), '/subnets/default')]"
                            }
                        }
                    }
                ],
                "dnsSettings": {
                    "dnsServers": []
                },
                "enableIPForwarding": false,
                "networkSecurityGroup": {
                    "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_vm20161206_nsg_name'))]"
                }
            },
            "resources": [],
            "dependsOn": [
                "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddresses_vm20161206_ip_name'))]",
                "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vm20161206_vnet_name'))]",
                "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_vm20161206_nsg_name'))]"
            ]
        },
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Network/networkSecurityGroups/vm20161206-nsg' から一般化されました。",
            "type": "Microsoft.Network/networkSecurityGroups",
            "name": "[parameters('networkSecurityGroups_vm20161206_nsg_name')]",
            "apiVersion": "2016-03-30",
            "location": "japaneast",
            "properties": {
                "securityRules": [
                    {
                        "name": "default-allow-rdp",
                        "properties": {
                            "protocol": "TCP",
                            "sourcePortRange": "*",
                            "destinationPortRange": "3389",
                            "sourceAddressPrefix": "*",
                            "destinationAddressPrefix": "*",
                            "access": "Allow",
                            "priority": 1000,
                            "direction": "Inbound"
                        }
                    }
                ]
            },
            "resources": [],
            "dependsOn": []
        },
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Network/publicIPAddresses/vm20161206-ip' から一般化されました。",
            "type": "Microsoft.Network/publicIPAddresses",
            "name": "[parameters('publicIPAddresses_vm20161206_ip_name')]",
            "apiVersion": "2016-03-30",
            "location": "japaneast",
            "properties": {
                "publicIPAllocationMethod": "Dynamic",
                "idleTimeoutInMinutes": 4
            },
            "resources": [],
            "dependsOn": []
        },
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Network/virtualNetworks/vm20161206-vnet' から一般化されました。",
            "type": "Microsoft.Network/virtualNetworks",
            "name": "[parameters('virtualNetworks_vm20161206_vnet_name')]",
            "apiVersion": "2016-03-30",
            "location": "japaneast",
            "properties": {
                "addressSpace": {
                    "addressPrefixes": [
                        "10.0.0.0/24"
                    ]
                },
                "subnets": [
                    {
                        "name": "default",
                        "properties": {
                            "addressPrefix": "10.0.0.0/24"
                        }
                    }
                ]
            },
            "resources": [],
            "dependsOn": []
        },
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Storage/storageAccounts/vm20161206diag122' から一般化されました。",
            "type": "Microsoft.Storage/storageAccounts",
            "sku": {
                "name": "Standard_LRS",
                "tier": "Standard"
            },
            "kind": "Storage",
            "name": "[parameters('storageAccounts_vm20161206diag122_name')]",
            "apiVersion": "2016-01-01",
            "location": "japaneast",
            "tags": {},
            "properties": {},
            "resources": [],
            "dependsOn": []
        },
        {
            "comments": "リソース '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/vm20161206/providers/Microsoft.Storage/storageAccounts/vm20161206disks246' から一般化されました。",
            "type": "Microsoft.Storage/storageAccounts",
            "sku": {
                "name": "Premium_LRS",
                "tier": "Premium"
            },
            "kind": "Storage",
            "name": "[parameters('storageAccounts_vm20161206disks246_name')]",
            "apiVersion": "2016-01-01",
            "location": "japaneast",
            "tags": {},
            "properties": {},
            "resources": [],
            "dependsOn": []
        }
    ]
}

このテンプレートを見て、何をデプロイしたか分かった人はすごい!

で、話は戻りまして・・・こうしてどちらかの環境用のマシンを分けておくと、何かと便利なので、あまり使ってないサブスクリプションを持ってる人とかはどうでしょうか?

まとめ

こんな状態でもツールをリリースして、たたかれる覚悟でも一歩でも進もうとしていることに私はすごいことなんじゃないかと思っています。

enjoy azure !
enjoy .NET Core !

Visual Studio 2015 のAzure FunctionsでStartしたときのUAC

Microsoft Azure2 Advent Calendar 2016 の3日目の隙間に向けて・・・隙間なネタを・・・!

開始するたびにダイアログがぽこぽこ上がってくるこれ・・・

UACを切ってしまえば・・・でもいいのだけど。それはそれで不安があるしとか思いつつ、もう一ついけそうだと思ってたのが、Visual Studioを管理者モードで起動する

2016-12-04-1

こうすると、親プロセスであるVisual Studioが管理者状態で動いていているので、そこから開始されるFunctionsのローカル実行のプロセスも自動的に管理者権限で動いてくれるということで、UACのダイアログは出てこなくなる。

ただ、Visual Studioに特権が与えられるので、それはそれで不安になることもあるかもしれない。

クリスマス近いんだねー

(メモ)Visual Studio 2015 の Azure Functions プロジェクトに 参照サービスを追加する

Functions単体では、ただコードを書いて、日付を返すとかはできますが、それだけでは、日付を返すとか文字列を変換するとかのことはできても、それは普通にローカルで動くプログラムでも得られるわけで、あまり意味がありません。
Functionsのプロジェクトを他のサービスに接続してみます。

 

プロジェクトのコンテキストメニュー(失敗)

ソリューションエクスプローラー>Functionsプロジェクト>コンテキストメニュー>追加>Connected Service

2016-12-03-1

追加用の画面が表示される
2016-12-03

Azure Storageを選ぶ
2016-12-03-2

既存を選ぶか、Create a New Storage Accountで新規に追加

2016-12-03-3

  1. Azure サブスクリプション を関連付けられているアカウントを選択
  2. サブスクリプションを選択
  3. Storage Account のURLになるものを入力
  4. お好みで料金体系・サービス体系を選択
  5. リソースグループを選択(ここで新規で作ることもできる)
  6. Locationを選択

Azure Storageの画面でAddとしてみると・・・

2016-12-03-4

NuGetのパッケージを追加できずにエラー。
というわけで、この方法ではだめな様子。
ひとまずフィードバックを送信。

functions の場合、プロジェクトの参照というよりは、bindingの定義があってという感じなのもあるかもしれないのでひとまずこの方法ではなさそう。

Functionsの追加から

試しにFunctionの追加から、
テンプレートは、FaceLocatorという、Blobストレージにある画像から顔がある四角形領域を返してくれるもの。

2016-12-03-5

ストレージアカウントの接続文字列を入力する欄が赤くなってますので、ポータルから引っ張ってくる。

2016-12-03-6

この接続文字列は絶対に公開しないように・・・
このように公開してしまった場合は、アカウントを消すか、接続文字列を再生成する必要が出てくる。その場合既存の接続文字列は使えなくなるので、いろいろ面倒。

追加した「FaceLocatorCSharp」の
function.json

{
  "bindings": [
    {
      "type": "blobTrigger",
      "name": "image",
      "path": "images/{name}.jpg",
      "connection": "DefaultEndpointsProtocol=https;AccountName=functionapp;AccountKey=xxxxxx;",
      "direction": "in"
    },
    {
      "type": "table",
      "name": "outTable",
      "tableName": "faceRectangle",
      "connection": "DefaultEndpointsProtocol=https;AccountName=functionapp;AccountKey=xxxxxx;",
      "direction": "out"
    }
  ],
  "disabled": false
}

このファイルにあるbindingsが、作ったfunctionsの入出力の定義そのものになっている。nameにある文字列がfunctionsのメソッドにある引数として以下のように

public static async Task Run(Stream image, string name, IAsyncCollector<FaceRectangle> outTable, TraceWriter log)
{
    ....
}

しかし・・・

F5デバッグ開始をしてみるもののエラーが発生してしまう。
かなり手詰まりではあるが、実際に動いているものがあるということはそこから得られるヒントがある・・・と信じて

ポータルから・・・

ポータルから生成したもののソースコードを見てみると

  {
  "bindings": [
    {
      "type": "blobTrigger",
      "name": "image",
      "path": "images/{name}.jpg",
      "connection": "functionappXXXX",
      "direction": "in"
    },
    {
      "type": "table",
      "name": "outTable",
      "tableName": "faceRectangle",
      "connection": "functionappXXXX",
      "direction": "out"
    }
  ],
  "disabled": false
}

といった形で、appSettings.jsonに設定されたものを指定しているようだ。
なので置き換えた。

それでもエラーはまだ残るため次に、テンプレート作成時には空となっていた
AzureWebJobsStorageおよびAzureWebJobsDashboardにも接続文字列を追加した

これは、ポータルで生成した場合は自動的に追加されているものだった。

FaceLocatorのキー

さらにわかったことがあって、テンプレート「FaceLocatorCSharp」では、VisionAPIを使うことになっているが、このための接続情報をappSettingsに追加してやる必要があった。

それがわかるコードはここで

        client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", Environment.GetEnvironmentVariable("Vision_API_Subscription_Key"));

「Vision_API_Subscription_Key」という設定値を必要としていたので、appSettings.jsonに追加した。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=functionapp;AccountKey=xxxx",
    "AzureWebJobsDashboard": "DefaultEndpointsProtocol=https;AccountName=functionapp;AccountKey=xxxx",
    "Vision_API_Subscription_Key": "xxxxxxxxxxxxxxxxx",
    "functionapp": "DefaultEndpointsProtocol=https;AccountName=functionapp;AccountKey=xxxx"
  }
}

もちろんこれは使えるものではなく、
https://www.microsoft.com/cognitive-services/en-us/subscriptions
より取得する必要がある

 

 

Visual Studio の拡張機能として

まだ、このFunctionsの拡張機能はPreviewであり今後変わる可能性があると思うが、
現状動くポータルを正解としていけば動かす道は掴んでいけそうであることがわかった。