07 Oct 2016, 17:00

SlackとAzure FunctionsでChatOpsする

Azure Functionsでやってみよう

Azure上でChatOpsしたい、と相談をいただきました。

AzureでChatOpsと言えば、Auth0のSandrino Di Mattia氏が作った素敵なサンプルがあります。

Azure Runスラッシュ

素晴らしい。これで十分、という気もしますが、実装のバリエーションがあったほうが後々参考になる人も多いかなと思い、Web App/Web JobをAzure Functionsで置き換えてみました。

SlackからRunbookを実行できて、何がうれしいか

  • 誰がいつ、どんな文脈でRunbookを実行したかを可視化する
  • CLIやAPIをRunbookで隠蔽し、おぼえることを減らす
  • CLIやAPIをRunbookで隠蔽し、できることを制限する

ブツ

Githubに上げておきました。

AZChatOpsSample

おおまかな流れ

手順書つらいのでポイントだけ。

  • SlackのSlash CommandとIncoming Webhookを作る

  • ARM TemplateでFunction Appをデプロイ

    • Github上のDeployボタンからでもいいですが、パラメータファイルを作っておけばCLIで楽に繰り返せます

    • パラメータファイルのサンプルはsample.azuredeploy.parameters.jsonです。GUIでデプロイするにしても、パラメータの意味を理解するためにざっと読むと幸せになれると思います

    • Function AppのデプロイはGithubからのCIです。クローンしたリポジトリとブランチを指定してください

    • GithubからのCIは、はじめてのケースを考慮しARM Templateのリソースプロパティ”IsManualIntegration”をtrueにしています

    • Azure Automationのジョブ実行権限を持つサービスプリンシパルが必要です (パラメータ SUBSCRIPTION_ID、TENANT_ID、CLIENT_ID、CLIENT_SECRET で指定)

    • Azure Automationについて詳しく説明しませんが、Slackから呼び出すRunbookを準備しておいてください。そのAutomationアカウントと所属するリソースグループを指定します

    • 作成済みのSlack関連パラメータを指定します

  • ARM Templateデプロイ後にkuduのデプロイメントスクリプトが走るので、しばし待つ(Function Appの設定->継続的インテグレーションの構成から進捗が見えます)

  • デプロイ後、Slash Commandで呼び出すhttptrigger function(postJob)のtokenを変更

    • kuduでdata/Functions/secrets/postJob.jsonの値を、Slackが生成したSlash Commandのtokenに書き換え
  • Slack上で、Slash Commandのリクエスト先URLを変更 (例: https://yourchatops.azurewebsites.net/api/postJob?code=TokenTokenToken)

  • ファンクションが動いたら、Slackの指定チャンネルでSlash Commandが打てるようになる

    • /runbook [runbook名] [parm1] [parm2] [parm…]

    • パラメータはrunbook次第

  • Runbookの進捗はIncoming Webhookでslackに通知される

    • Runbookのステータスが変わったときに通知

よもやま話

  • SlackのSlash Commandは、3秒以内に返事を返さないとタイムアウトします。なのでいくつか工夫しています。

    • ファンクションはトリガーされるまで寝ています。また、5分間動きがないとこれまた寝ます(cold状態になる)。寝た子を起こすのには時間がかかるので、Slackの3秒ルールに間に合わない可能性があります。

    • Azure FunctionsのWebコンソールログが無活動だと30分で停止するので、coldに入る条件も30分と誤解していたのですが、正しくは5分。ソースはここ

    • そこで、4分周期でTimer Triggerし、postJobにダミーPOSTするpingFuncを作りました。

    • ファンクションのコードに更新があった場合、リロード処理が走ります。リロード後、またしてもトリガーを待って寝てしまうので、コード変更直後にSlash Commandを打つとタイムアウトする可能性大です。あせらずpingまで待ちましょう。

    • でもAzure AutomationのAPI応答待ちなど、外部要因で3秒超えちゃう可能性はあります。非同期にしてひとまずSlackに応答返す作りに変えたほうがいいですね。これはSlackのSlash Commandに限らず、呼び出し元に待ってもらえないケース全てに言える考慮点です。

    • Azure Functionsはまだプレビューなので、議論されているとおり改善の余地が多くあります。期待しましょう。

13 Sep 2016, 17:30

Azure Functionsで運用管理サーバレス生活(使用量データ取得編)

背景と動機

Azure Functions使ってますか。「サーバレス」という、ネーミングに突っ込みたい衝動を抑えられないカテゴリに属するため損をしている気もしますが、システムのつくり方を変える可能性がある、潜在能力高めなヤツです。キャッチアップして損はないです。

さて、Azure Functionsを使ってAzureの使用量データを取得、蓄積したいというリクエストを最近いくつかいただきました。いい機会なのでまとめておきます。以下、その背景。

  • 運用管理業務がビジネスの差別化要素であるユーザは少ない。可能な限り省力化したい。運用管理ソフトの導入維持はもちろん、その土台になるサーバの導入、維持は真っ先に無くしたいオーバヘッド。もうパッチ当てとか監視システムの監視とか、やりたくない。
  • Azure自身が持つ運用管理の機能が充実し、また、運用管理SaaS(MS OMS、New Relic、Datadogなど)が魅力的になっており、使い始めている。いつかは運用管理サーバを無くしたい。
  • でも、それら標準的なサービスでカバーされていない、ちょっとした機能が欲しいことがある。
  • Azureリソースの使用量データ取得が一例。Azureでは使用量データをポータルからダウンロードしたり、Power BIで分析できたりするが、元データは自分でコントロールできるようためておきたい。もちろん手作業なし、自動で。
  • ちょっとしたコードを気軽に動かせる仕組みがあるなら、使いたい。インフラエンジニアがさくっと書くレベルで。
  • それAzure Functionsで出来るよ。

方針

  • Azure FunctionsのTimer Triggerを使って、日次で実行
  • Azure Resource Usage APIを使って使用量を取得し、ファイルに書き込み
  • Nodeで書く (C#のサンプルはたくさんあるので)
  • 業務、チームでの運用を考慮して、ブラウザでコード書かずにソース管理ツールと繋げる (Githubを使う)

Quick Start

準備

  • ところでAzure Funtionsって何よ、って人はまずいい資料1いい資料2でざっと把握を
  • AzureのAPIにプログラムからアクセスするため、サービスプリンシパルを作成 (こことかここを参考に)
    • 後ほど環境変数に設定するので、Domain(Tenant ID)、Client ID(App ID)、Client Secret(Password)、Subscription IDを控えておいてください
    • 権限はsubscriptionに対するreaderが妥当でしょう
  • Githubのリポジトリを作成 (VSTSやBitbucketも使えます)
  • 使用量データを貯めるストレージアカウントを作成
    • 後ほど環境変数に設定するので、接続文字列を控えておいてください

デプロイ

  • Function Appを作成
    • ポータル左上”+新規” -> Web + モバイル -> Function App
    • アプリ名は.azurewebsites.net空間でユニークになるように
    • App Seriviceプランは、占有型の”クラシック”か、共有で実行したぶん課金の”動的”かを選べます。今回の使い方だと動的がお得でしょう
    • メモリは128MBあれば十分です
    • 他のパラメータはお好みで
  • 環境変数の設定
    • Function Appへポータルからアクセス -> Function Appの設定 -> アプリケーション設定の構成 -> アプリ設定
    • 先ほど控えた環境変数を設定します(CLIENT_ID、DOMAIN、APPLICATION_SECRET、AZURE_SUBSCRIPTION_ID、azfuncpoc_STORAGE)
  • サンプルコードを取得
  • 準備済みのGithubリポジトリにpush
  • リポジトリとFunction Appを同期
    • Function Appへポータルからアクセス -> Function Appの設定 -> 継続的インテグレーションの構成 -> セットアップ
    • Githubリポジトリとブランチを設定し、同期を待ちます
  • Nodeのモジュールをインストール
    • Function Appへポータルからアクセス -> Function Appの設定 -> kuduに移動 -> site/wwwroot/getUsageData へ移動
    • このディレクトリが、実行する関数、functionの単位です
    • “npm install” を実行 (package.jsonの定義に従ってNodeのモジュールが”node_modules”へインストールされます)
    • deploy.cmd で自動的にインストールするよう変えました

これで、指定ストレージアカウントの”usagedata”コンテナに日次で使用量データファイルができます。

コード解説

3つのファイルをデプロイしました。簡単な順に、ざっと解説します。コードを眺めながら読み進めてください。

package.json

主となるコードファイルは後述の”index.js”ですが、その動作に必要な環境を定義します。依存モジュールのバージョンの違いでトラブらないよう、dependenciesで指定するところがクライマックスです。

function.json

Azure Functionsの特徴である、TriggerとBindingsを定義します。サンプルはTimer Triggerなので、実行タイミングをここに書きます。”schedule”属性に、cron形式({秒}{分}{時}{日}{月}{曜日})で。

“0 0 0 * * *” と指定しているので、毎日0時0分0秒に起動します。UTCです。

index.js

メインロジックです。

  • 先ほど設定した環境変数は、”process.env.HOGE”を通じ実行時に読み込まれます。認証関連情報はハードコードせず、このやり口で。
  • 日付関連処理はUTCの明示を徹底しています。Azure Functions実行環境はUTCですが、ローカルでのテストなど他環境を考えると、指定できるところはしておくのがおすすめです。これはクラウドでグローバル展開する可能性があるコードすべてに言えます。
  • 0時に起動しますが、使用量データ作成遅延の可能性があるので、処理対象は2日前です。お好みで調整してください。詳細仕様はこちら
  • module.export からが主フローです。asyncを使って、Blobコンテナの作成、使用量データ取得&ファイル書き込みを、順次処理しています。後ほど豆知識で補足します。
  • 最後にcontext.done()でFunctionsに対してアプリの終了を伝えます。黙って終わるような行儀の悪い子は嫌いです。
  • ヘルパー関数たちは最後にまとめてあります。ポイントはcontinuationTokenを使ったループ処理です。
    • Resource Usage API は、レスポンスで返すデータが多い場合に、途中で切って「次はこのトークンで続きからアクセスしてちょ」という動きをします。
    • ループが2周目に入った場合は、データを書きだすファイルが分かれます。フォーマットは”YYYY-MM-DD_n.json”です。

豆知識 (Node on Azure Functions)

  • 通信やI/Oの関数など、非同期処理の拾い忘れ、突き抜けに注意してください
    • NodeはJavascript、シングルスレッドなので時間のかかる処理でブロックしないのが基本です
    • Azure FunctionsはNode v6.4.0が使えるのでES6のpromiseが書けるのですが、SDKがまだpromiseをサポートしていないので、サポートされるまではcallbackで堅く書きましょう
  • Nodeに限った話ではないですが、Azure Functions Timer TriggerはInput/Output Bindingと組み合わせられません
    • サポートマトリックスを確認しましょう
    • なのでサンプルではOutput Binding使わずに書きました
    • Input/Outputを使える他のTriggerでは、楽なのでぜひ活用してください

豆知識 (Azure Usage API)

  • Resource Usage APIは使用量のためのAPIなので、料金に紐づけたい場合は、Ratecard APIを組み合わせてください

それでは、幸せな運用管理サーバレス生活を。

25 Aug 2016, 16:00

OMSでLinuxコンテナのログを分析する

OMS Container Solution for Linux プレビュー開始

OMS Container Solution for Linuxのプレビューがはじまりました。OMSのログ分析機能は500MB/日のログ転送まで無料で使えるので、利用者も多いのではないでしょうか。

さて、このたびプレビュー開始したLinuxコンテナのログ分析機能、サクッと使えるので紹介します。まだプレビューなので、仕様が変わったらごめんなさい。

何ができるか、とその特徴

  • Dockerコンテナに関わるログの収集と分析、ダッシュボード表示
  • 導入が楽ちん
    1. OMSエージェントコンテナを導入し、コンテナホスト上のすべてのコンテナのログ分析ができる
    2. コンテナホストに直接OMS Agentを導入することもできる

1がコンテナ的でいいですよね。実現イメージはこんな感じです。

OMS Agent Installation Type

これであれば、CoreOSのような「コンテナホストはあれこれいじらない」というポリシーのディストリビューションにも対応できます。

では試しに、1のやり口でUbuntuへ導入してみましょう。

手順

  • OMSのログ分析機能を有効化しワークスペースを作成、IDとKeyを入手 (参考)
  • OMSポータルのソリューションギャラリーから、”Containers”を追加
  • UbuntuにDockerを導入
    • 参考
    • 現在、OMSエージェントが対応するDockerバージョンは 1.11.2までなので、たとえばUbuntu 16.04の場合は sudo apt-get install docker-engine=1.11.2-0~xenial とするなど、バージョン指定してください
  • OMSエージェントコンテナを導入
    • 先ほど入手したOMSのワークスペースIDとKeyを入れてください
sudo docker run --privileged -d -v /var/run/docker.sock:/var/run/docker.sock -e WSID="your workspace id" -e KEY="your key" -h=`hostname` -p 127.0.0.1:25224:25224/udp -p 127.0.0.1:25225:25225 --name="omsagent" --log-driver=none --restart=always microsoft/oms

以上。これでOMSポータルからログ分析ができます。こんな感じで。

Dashboard1

Dashboard2

なんと簡単じゃありませんか。詳細が気になるかたは、こちらから。

なお、フィードバック熱烈歓迎だそうです。

22 Jun 2016, 15:00

Docker for WindowsでインストールレスAzure CLI環境を作る

舌の根の乾かぬ内に

最近、VagrantとVirualBoxで似たようなやり口を紹介しましたが、気にしないでください。テクノロジーの進化は早い。

動機

  • Docker for Windows(on Client Hyper-V)のベータが一般開放された
  • Dockerもそうだが、Hyper-V前提のツールが今後増えそう、となると、それとぶつかるVirtualBoxをぼちぼちやめたい
  • 月一ペースでアップデートされるAzure CLIをいちいちインストールしたくない、コンテナ引っ張って以上、にしたい
  • 開発端末の環境を汚したくない、いつでもきれいに作り直せるようにしたい
  • ○○レスって言ってみたかった

やり口

  • もちろんDocker for Windows (on Client Hyper-V) を使う
  • いちいちdocker run…と打たなくていいよう、エイリアス的にPowerShellのfunction “azure_cli” を作る
  • “azure_cli”入力にてAzure CLIコンテナを起動
  • コンテナとホスト(Windows)間でファイル共有、ホスト側のIDEなりエディタを使えるようにする

作業の中身

  • Docker for Windowsをインストール
    • 64bit Windows 10 Pro/Enterprise/Education 1511以降に対応
    • Hyper-Vの有効化を忘れずに
    • Hyper-VとぶつかるVirtualBoxとはお別れです
    • Docker for Windowsの起動時にIPをとれないケースがありますが、その場合はsettings -> Network から、設定変えずにApplyしてみてください。いまのところこれで対処できています。この辺はベータなので今後の調整を期待しましょう。
    • 共有ドライブも共有が外れていることが。settings -> Shared Drives で共有しなおしてください。
  • PowerShell functionを作成
    • のちほど詳しく

PowerShellのfunctionを作る

ここが作業のハイライト。

PowerShellのプロファイルを編集します。ところでエディタはなんでもいいのですが、AzureやDockerをがっつり触る人にはVS Codeがおすすめです。Azure Resource Manager TemplateDockerむけextensionがあります。

PS C:\Workspace\dockereval\arm> code $profile

こんなfunctionを作ります。

function azure_cli {
   C:\PROGRA~1\Docker\Docker\Resources\bin\docker.exe run -it --rm -v ${HOME}/.azure:/root/.azure -v ${PWD}:/data -w /data microsoft/azure-cli:latest
}
  • エイリアスでなくfunctionにした理由は、引数です。エイリアスだと引数を渡せないので
  • コンテナが溜まるのがいやなので、–rmで都度消します
  • 毎度 azure login しなくていいよう、トークンが保管されるコンテナの/root/azureディレクトリをホストの${HOME}/.azureと-v オプションで共有します
  • ARM TemplateのJSONファイルなど、ホストからファイルを渡したいため、カレントディレクトリ ${PWD} をコンテナと -v オプションで共有します
  • コンテナはdocker hubのMicrosoft公式イメージ、latestを引っ張ります。latestで不具合あればバージョン指定してください

ではテスト。まずはホスト側のファイルを確認。

PS C:\Workspace\dockereval\arm> ls


    ディレクトリ: C:\Workspace\dockereval\arm


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       2016/06/22     11:21                subd
-a----       2016/06/22     10:26           8783 azuredeploy.json
-a----       2016/06/22     11:28            690 azuredeploy.parameters.json

いくつかのファイルとサブディレクトリがあります。

コンテナを起動してみましょう。azure_cli functionを呼びます。

PS C:\Workspace\dockereval\arm> azure_cli
root@be41d3389a21:/data#

コンテナを起動し、入出力をつなぎました。ここからは頭と手をLinuxに切り替えてください。公式Azure CLIコンテナはdebianベースです。

ファイル共有できているか確認。

root@be41d3389a21:/data# ls
azuredeploy.json  azuredeploy.parameters.json  subd

できてますね。

azureコマンドが打てるか確認。

root@be41d3389a21:/data# azure -v
0.10.1

しあわせ。

21 May 2016, 11:00

Azure X-Plat CLIでResource Policyを設定する

Azure X-Plat CLIのリリースサイクル

OSS/Mac/Linux派なAzurerの懐刀、Azure X-Plat CLIのリリースサイクルは、おおよそ月次です。改善と機能追加を定期的にまわしていくことには意味があるのですが、いっぽう、Azureの機能追加へタイムリーに追随できないことがあります。短期間とはいえ、次のリリースまで空白期間ができてしまうのです。

たとえば、今回のテーマであるResource Policy。GA直後に公開されたドキュメントに、X-Plat CLIでの使い方が2016/5/21現在書かれていません。おやCLIではできないのかい、と思ってしまいますね。でもその後のアップデートで、できるようになりました。

機能リリース時点ではCLIでできなかった、でもCLIの月次アップデートで追加された、いまはできる、ドキュメントの更新待ち。こんなパターンは多いので、あきらめずに探ってみてください。

ポリシーによるアクセス管理

さて本題。リソースの特性に合わせて、きめ細かいアクセス管理をしたいことがあります。

  • VMやストレージのリソースタグに組織コードを入れること強制し、費用負担の計算に使いたい
  • 日本国外リージョンのデータセンタを使えないようにしたい
  • Linuxのディストリビューションを標準化し、その他のディストリビューションは使えなくしたい
  • 開発環境リソースグループでは、大きなサイズのインスタンスを使えないようにしたい

などなど。こういう課題にポリシーが効きます。

従来からあるRBACは「役割と人」目線です。「この役割を持つ人は、このリソースを読み取り/書き込み/アクションできる」という表現をします。組み込みロールの一覧を眺めると、理解しやすいでしょう。

ですが、RBACは役割と人を切り口にしているので、各リソースの多様な特性にあわせた統一表現が難しいです。たとえばストレージにはディストリビューションという属性はありません。無理してカスタム属性なんかで表現すると破綻しそうです。

リソース目線でのアクセス管理もあったほうがいい、ということで、ポリシーの出番です。もちろんRBACと、組み合わせできます。

X-Plat CLIでの定義方法

2016/4リリースのv0.9.20から、X-Plat CLIでもResource Policyを定義できます。

ポリシーの定義、構文はPowerShellと同じなので、公式ドキュメントに任せます。ご一読を。

ポリシーを使用したリソース管理とアクセス制御

X-Plat CLI固有部分に絞って紹介します。

ポリシー定義ファイルを作る

CLIでインラインに書けるようですが、人類には早すぎる気がします。ここではファイルに。

例として、作成できるVMのサイズを限定してみましょう。開発環境などでよくあるパターンと思います。VM作成時、Standard_D1~5_v2に当てはまらないVMサイズが指定されると、拒否します。

{
  "if": {
    "allOf": [
      {
        "field": "type",
        "equals": "Microsoft.Compute/virtualMachines"
      },
      {
        "not": {
          "field": "Microsoft.Compute/virtualMachines/sku.name",
          "in": [ "Standard_D1_v2", "Standard_D2_v2","Standard_D3_v2", "Standard_D4_v2", "Standard_D5_v2" ]
        }
      }
    ]
  },
  "then": {
    "effect": "deny"
  }
}

policy_deny_vmsize.json というファイル名にしました。では投入。ポリシー名は deny_vmsize とします。

$ azure policy definition create -n deny_vmsize -p ./policy_deny_vmsize.json
info:    Executing command policy definition create
+ Creating policy definition deny_vmsize
data:    PolicyName:             deny_vmsize
data:    PolicyDefinitionId:     /subscriptions/mysubscription/providers/Microsoft.Authorization/policyDefinitions/deny_vmsize
data:    PolicyType:             Custom
data:    DisplayName:
data:    Description:
data:    PolicyRule:             allOf=[field=type, equals=Microsoft.Compute/virtualMachines, field=Microsoft.Compute/virtualMachines/sku.name, in=[Standard_D1_v2, Standard_D2_v2, Standard_D3_v2, Standard_D4_v2, Standard_D5_v2]], effect=deny
info:    policy definition create command OK

できたみたいです。

ポリシーをアサインする

では、このポリシーを割り当てます。割り当ての範囲(スコープ)はサブスクリプションとします。リソースグループなど、より細かいスコープも指定可能です。

$ azure policy assignment create -n deny_vmsize_assignment -p /subscriptions/mysubscription/providers/Microsoft.Authorization/policyDefinitions/deny_vmsize -s /subscriptions/mysubscription
info:    Executing command policy assignment create
+ Creating policy assignment deny_vmsize_assignment
data:    PolicyAssignmentName:     deny_vmsize_assignment
data:    Type:                     Microsoft.Authorization/policyAssignments
data:    DisplayName:
data:    PolicyDefinitionId:       /subscriptions/mysubscription/providers/Microsoft.Authorization/policyDefinitions/deny_vmsize
data:    Scope:                    /subscriptions/mysubscription
info:    policy assignment create command OK

割り当て完了。では試しに、このサブスクリプションに属するユーザで、Gシリーズのゴジラ級インスタンスを所望してみます。

$ azure vm quick-create -g RPPoC -n rppocvm westus -y Linux -Q "canonical:ubuntuserver:14.04.4-LTS:latest" -u "adminname" -p "adminpass" -z Standard_G5
info:    Executing command vm quick-create
[...snip]
+ Creating VM "rppocvm"
error:   The resource action 'Microsoft.Compute/virtualMachines/write' is disallowed by one or more policies. Policy identifier(s): '/subscriptions/mysubscription/providers/Microsoft.Authorization/policyDefinitions/deny_vmsize'.
info:    Error information has been recorded to /root/.azure/azure.err
error:   vm quick-create command failed

拒否られました。

許可されているVMサイズだと。

$ azure vm quick-create -g RPPoC -n rppocvm westus -y Linux -Q "canonical:ubuntuserver:14.04.4-LTS:latest" -u "adminname" -p "adminpass" -z Standard_D1_v2
info:    Executing command vm quick-create
[...snip]
info:    vm quick-create command OK

成功。