koudenpaのブログ

趣味のブログです。株式会社はてなでWebアプリケーションエンジニアをやっています。職業柄IT関連の記事が多いと思います。

Datadog の見込み客獲得施策を凄いなぁと思った

先日のAWS Summit Tokyo 2018後のDatadogの営業が印象的だったので、忘れないうちにメモしておく。

イベントの展示ブースで大量の名刺をばらまいてからしばらく後に、以下の様なキャンペーンの案内メールが着た。 (展示している企業は来場者の情報を収集できる)

クラウドサービスに登録して、チュートリアルを突破したら抽選で賞品をプレゼント、というものだ。 それだけならよくあるが、内容がなかなか印象的だった。

  • 1人のチュートリアル突破に対して1万円程度相当の賞品金額
    • 結構いい金額なのでは?
  • 10名中1名という見せ方
    • 10%で当たる、というのはなかなか高確率に感じられる
    • 当選確率は、例えば抽選で5名にで対象が50名だった場合と同じなのだけれど、10名中1名の方が確率高そうに感じる
      • 何なら、対象者が少なく抽選で何名に~の方が実際には高確率な可能性すらある
      • ユーザーには対象の人数が分からない
  • 費用の上限が明確な施策である
    • 対象メールアドレス把握できており、無限に対象者が増えることがない
    • AWS Summitに登録したメールアドレスで登録してください案内があった)

せっかくイベント出展というコストを払って得たメールアドレスに対して、特筆すべき事が書かれていない営業メールを送るだけの企業が多い中、これは相当印象に残った。

クラウドサービスは何はなくとも体感してもらわなくては始まらない。 実際問題効果的でありそうだ。

オチ

それだけ印象に残っている餌でも引っかからなかった獲物がここにいる。

だって面倒くさいのだもの。

自分の場合は一度Datadogを試したことがあったからという理由もあるけれど、ユーザー獲得は大変だろうなあ、と思った。

VSTS BuildのYaml定義

VSTSVisual Studio Team Services)のビルド機能はYAMLでの定義でも使用できると教えてもらったので試してみた。

なかなか良い感じなので、GAされたらコードベースでのビルド管理の選択肢の一つとして浮上してくるのではなかろうか。

GUIでやりたいこと(タスク)をサクサク探しつつざっくり定義して、そのYAMLを表示してビルドのコード管理を始める。のようなことができる。作業スタイルが広がるのがとても良さそう。

tech.guitarrapc.com

上記の記事は2018年1月のものだが、この記事を書いている時点でまだGAされていない。

なので、参照記事と変わらない手順で機能を有効化してから使うことになる。

有効化して先の記事で試したビルドYAMLを表示してみた。

f:id:koudenpa:20180611233814p:plain

続きを読む

VSTSのビルド機能で静的サイトをデプロイする

やりたくてやったこと。

  1. 静的サイトのリソースをビルドする
    • npm install
    • npm run build
  2. リソースを Azure Blob Storage にコピーする
  3. Azure CDN のエンドポイントをパージする

しばらくそれぞれ手動でやっていたのだけれど、何回もやるのは辛くなってきたので自動化した。

世の中には非常に強力なDevOps基盤としてVSTSVisual Studio Team Services)が存在する。

azure.microsoft.com

今回はそのビルド機能を使ってみた。リリース先がAzureなので楽だろう、という目論見だ。

実際楽だった。

f:id:koudenpa:20180611033219p:plain

ウィザードに従ってビルドのタスクを追加していくだけで、やりたかったことを実現できた。

続きを読む

Azure Function App 『だけ』でWebサービスをホスティングする

事を試していて、少々無理筋だな、と思った話。

最近2つのテーマを持ってWebサービスの実装を試していた。

  1. SPAっぽく、クライアントコードとサーバコードを完全に切り離す実装を体験する
  2. Azure Functionの従量課金だけで安価にAzureでWebサービスホスティングする

この記事のテーマは後者である。

Azureのプログラムホスティング用のPaaSは概ねApp Serviceという共通の基盤の上で提供されており、Azure Functionsも例外ではない。

そのため、App ServiceがWebサービスホスティング用に備えている強力な機能をFunctionsでも使用することができる。 加えて、Functions固有の機能も使用できる。

これらを組み合わせると、Azure Functions(+そのためのStorageアカウント)のみでWebサービスホスティングできるのではないか? と思え、この2週間ほど試していた。

結論から言うと、出来なくもないが固執するのは良くない、といったところだった。

確かにやってできないことはないのだが、より向いているマネージドサービスと組み合わせたり、無理に組み込み機能を使わない方が平易だったりする感じを受けた。 適材適所である。

続きを読む

ConoHaのオブジェクトストレージからAmazon S3に移行した

やったこと

  • サービスをメンテナンスイン
  • ConoHaのオブジェクトストレージから全オブジェクトをダウンロード
  • ダウンロードしたオブジェクトをS3にSync
    • AWS CLIaws s3 sync コマンドを使用
  • オブジェクトストレージへのアクセスをS3に変更したアプリケーションをデプロイ
    • オブジェクトのGet/Putのみを行っていたため最小限の変更で済んだ
  • オブジェクトへのプロキシー(Nginx)のオリジンをS3に変更
  • サービスをメンテナンスアウト

規模はオブジェクト数万、容量数GB程度。 この程度なら力業でオブジェクトをコピーできる。

今すぐに移行先を(自分が多少触ったことがあるという理由で)AzureのBlob Storageにする、としてもそれほどのインパクトはさそうだ。

一般的なサービスであれば、S3が落ちたら巻き込まれで停止してもいいだろうと考えているが、それが許されなかったりするような場合に複数のオブジェクトストレージサービスにオブジェクトをミラーリングしておき、場合によって接続先を切り替えるようなことは、他の分野のフェールバックよりは平易に行えそうだと感じた。

変更点と留意点

f:id:koudenpa:20180504005541p:plain

サービスのアプリケーションへの変更と移行作業は非常にシンプルで上の図程度だった。

変更を平易に済ますためには以下のような点に留意しておきたい。

  • オブジェクトのI/Oの処理は1か所に集約する
  • オブジェクトに関する情報は オブジェクトキー の形で保持する
  • 移行に使うソフトウェアは移行規模に向いたものにする

オブジェクトのI/Oの処理は1か所に集約する

当たり前だが、ある同種のリソースへのアクセスの実装は1か所に集約、汎用的なインタフェースとしておきたい。

正直なところ『リポジトリパターン』とかがどの程度テスト以外の実際の便利に寄与するかは分からない部分があるのだけれど、 いざ「永続化先を変更したい」となった時にリソースへのアクセスの実装が散っていたら詰む。

基本は大事にしたい。

オブジェクトに関する情報は オブジェクトキー の形で保持する

オブジェクトのI/Oの処理 に通じるものがあるが、アプリケーションがオブジェクトに関して持つ情報はオブジェクトキーにしておきたい。

今回はそうだったので、オブジェクトのI/Oの処理を変更するだけで永続化先の変更に対応できた。

全然別のアプリケーションでURIでオブジェクトの情報を持たせているものがあって「失敗したなぁ」と思っている。

そのアプリケーションのオブジェクトを別のサービスに変更したいとしたら、それらの情報のマイグレーションも行わなくてはならない。

ロックインされているということだ。

移行に使うソフトウェアは移行規模に向いたものにする

移行に当たって、今回はローカルマシンに Cyberduck でダウンロード、そこから AWS CLI でアップロードしたが、Cyberduckでのダウンロードはよりオブジェクト数が多いと厳しそうだった。

数万オブジェクト程度だったが、不安感のある動作だった。

多数のファイル操作には向いていないのかもしれない。

f:id:koudenpa:20180504010213p:plain

こんなエラーコードははじめて見た。


余談

以前ConoHaのオブジェクトストレージのサービスレベルが低い旨を記事にしているが、その状況が改善しないので仕方なく移行対応した形になる。

koudenpa.hatenablog.com

ConoHaのVPSは非常に良いものなのだけれど、周辺のマネージドサービスはコアな用途に使うには少々頼りない。

オブジェクトストレージに関しては、ConoHaのVPSからでもインターネット経由でのアクセスとなるため、使用することに特にこれといったメリットはない。 (他のマネージドサービスではインターネットに出ないアクセスができるものもある)

先の記事にも書いたが、どこであろうとコアサービス以外は開発・運用のリソース投入が限られているはずなので、大事な用途には安定の実績があるサービスを使用するようにしたい。

Mackerelエージェントから他のサービスに投稿したい Vol.2

前回のあらすじ。

あるオープンソースCLIアプリケーションソフトウェアでやりたいことがある場合には、大体以下ようなことを上から順に試すと思う。

  1. Readmeを読む
  2. help コマンドを叩く
  3. ソースコードを読み込む
  4. とりあえずガチャガチャ実装を直す

下からやってしまいました。 Goのプログラムをビルドしてみるという他の目的があったとはいえ、あんまりな段取りだったと反省しました。

さて、Mackerelエージェントをビルドできるようになったので、次は以下のようなことを試していきたい。

  • 設定項目を追加する
  • 追加した設定項目を動作に反映する

設定項目を追加する

設定ファイルの形式はTOMLだということは知っていて、何かしらのライブラリで読み込んでいるのだろうと思っていた。

実際その通りで、設定用の構造体にメンバを追加したらいい感じに読み込まれた。

設定項目を追加する · 7474/mackerel-agent@88623e4 · GitHub

f:id:koudenpa:20180425221935p:plain

大昔は設定ファイルの読み込み処理を独自に書いたりしたものだけれど、今どきは簡単で良い。

追加した設定項目を動作に反映する

追加した設定を動作に反映していく。

元々は、大きな設定差分毎にAPI呼び出し用のインタフェースを実装していこうと思っていたのだけれど、MackerelエージェントはAPIクライアントをインタフェースではなく構造体で取り廻しているようなので無理筋だった。 (多分。Goは入門本を斜め読みした程度なので、実体を取り廻していてもいい感じに多様性を持たせられるのかもしれない)

APIクライアント構造体と、そこに生えているメソッドをゴリゴリ修正して行く形で追加変更していくことにした。

追加した設定項目を動作に反映する · 7474/mackerel-agent@1ed3258 · GitHub

apikey = "xxx"
apibase = "https://mackerel-dash-stub.azurewebsites.net"
verbose = true

# Custom Config
APIClientType = "custom-http"
CustomHTTPHeaders = { x-functions-key = "b64==", foo = "bar" }

上記のような設定をして実行。

> mackerel-agent.exe
2018/04/25 22:24:02 main.go:171: INFO <main> Starting mackerel-agent version:0.54.1, rev:, apibase:https://mackerel-dash-stub.azurewebsites.net
2018/04/25 22:24:02 main.go:172: INFO <main> APIClientType:custom-http
2018/04/25 22:24:02 command.go:649: DEBUG <command> NewCustomHttpClient
2018/04/25 22:24:02 command.go:659: DEBUG <command> headers x-functions-key: b64==
2018/04/25 22:24:02 command.go:659: DEBUG <command> headers foo: bar
2018/04/25 22:24:09 command.go:739: INFO <command> Start: apibase = https://mackerel-dash-stub.azurewebsites.net, hostName = , hostID = xxx
2018/04/25 22:24:09 command.go:199: DEBUG <command> wait 4 seconds before initial posting.
2018/04/25 22:24:09 command.go:597: DEBUG <command> Updating host specs...
2018/04/25 22:24:09 memory.go:43: DEBUG <metrics.memory> memory : map[~~]
2018/04/25 22:24:09 filesystem.go:45: DEBUG <metrics.filesystem> map[~~]
2018/04/25 22:24:09 processor_queue_length.go:61: DEBUG <metrics.processor_queue_length> processor_queue_length: map["processor_queue_length":%!q(float64=0)]
2018/04/25 22:24:09 cpuusage.go:76: DEBUG <cpu.user.percentage> cpuusage: map["cpu.user.percentage":%!q(float64=0) "cpu.system.percentage":%!q(float64=0) "cpu.idle.percentage":%!q(float64=0)]
2018/04/25 22:24:15 api.go:306: DEBUG <api> PUT /api/v0/hosts/xxx {"name":"DESKTOP-xxx","meta":{~~}
2018/04/25 22:24:15 api.go:319: DEBUG <api> PUT /api/v0/hosts/xxx status="200 OK"

どうやら、想定通りにヘッダが設定されたリクエストが行われているようだ。

MackerelサービスAPIスタブ

前回雑に作成したMackerelのAPIスタブをローカルマシン上で実行していたが、本命はAzure Functions上での実行である。

Functionsは様々なトリガーで実行できるが、HTTPリクエストをトリガーとする場合の認証は特定のクエリパラメータないしHTTPヘッダにキーを送出することで行う。

Azure Functions における HTTP と Webhook のバインド | Microsoft Docs

キーは、上記のように code という名前のクエリ文字列変数に含めることも、x-functions-key HTTP ヘッダーに含めることもできます。 キーの値には、関数のために定義されている任意の関数キーまたは任意のホスト キーを指定できます。

先にHTTPヘッダを設定できるようにしたのはそのためだ。

これでHTTPでリクエストを受け付け、HTTPヘッダ内容を見てクライアント認証する形のサービスへの投稿は過不足なく設定できるようになった。

遊び

改造エージェントは想定通りに動作していることを確認するために、投稿されたメトリックをチャート表示した。

f:id:koudenpa:20180426011835p:plain

Teat Chart ← Blobストレージに適当なHTMLを置いて、Functionsの方のCORS設定をした。

はっきり言ってエージェントの改造よりこの『遊び』やAPIのスタブ作りの方が何倍も時間がかかっている。

が、まぁ、そういうもん。

Mackerelというサービスの価値の過半はそちらの方にあるわけだし、一朝一夕でクローン出来たらそれで商売するわ。


次は何をするか、HTTPクライアントを拡張して証明書認証できるようにするか、さっさとMQTTクライアントに手を出すか、少し迷っている。

どちらもAWS IoTをターゲットとしているので、最終的にはどちらも試そうかなぁ、と思っている。

Mackerelエージェントから他のサービスに投稿したい Vol.1

前回の記事には書いていないことも含まれているあらすじ。

Goのディレクトリ構成の『い』の字すら無視したGit Cloneからのビルドの結果、Mackerelエージェントは全くビルドされる気配がなかった。

go get コマンドを叩いた後も、インストールしていないGCCが求められ、環境面の面倒くささを目の当たりにしてテンションがすでに下がっている。

果たしてARMクロスビルドしてRaspberry Pi向けのカスタムMackerelエージェントを構成することはできるのだろうか?

  • ローカルマシンでエージェントをビルド
  • 呼び出すAPIベースを変更(バイナリ埋め込み)

の2本でお届けします。


ローカルマシンでエージェントをビルド

というわけで、Windows向けのGCCをインストール、パスを通してからビルド、実行した。

PS C:\Users\koudenpa\go\src\github.com\7474\mackerel-agent> .\build-sandbox.bat
C:\Users\koudenpa\go\src\github.com\7474\mackerel-agent>echo on
C:\Users\koudenpa\go\src\github.com\7474\mackerel-agent>go build -o build/mackerel-agent.exe
PS C:\Users\koudenpa\go\src\github.com\7474\mackerel-agent> cd .\build\
PS C:\Users\koudenpa\go\src\github.com\7474\mackerel-agent\build> .\mackerel-agent.exe init -apikey xxx
PS C:\Users\koudenpa\go\src\github.com\7474\mackerel-agent\build> .\mackerel-agent.exe2018/04/24 19:10:04 INFO <main> Starting mackerel-agent version:0.54.1, rev:, apibase:https://api.mackerelio.com
2018/04/24 19:10:11 INFO <command> Start: apibase = https://api.mackerelio.com, hostName = DESKTOP-xxx, hostID = xxx

メトリック届いている。

f:id:koudenpa:20180424191620p:plain

これでVol.1のノルマは達成だ。


呼び出すAPIベースを変更(バイナリ埋め込み)

コードを眺めていると、さしあたって呼び出し先を変更するだけならビルドオプションでAPIベースURIを指定すればよい様子だったので試した。

サンドボックスビルド用のビルドファイルを追加。 · 7474/mackerel-agent@36b2eaf · GitHub

呼び出し先のAPIスタブはなんとなくAzure Function AppをVisualStudioで雑にスキャフォルドしてローカルで実行した。

GitHub - 7474/MackerelDashFunctionApp: Mackerelエージェントの変更を試す際に使用しているアプリケーションです。

エージェントの実行ログ。

PS C:\Users\koudenpa\go\src\github.com\7474\mackerel-agent> .\build\mackerel-agent.exe
# 変更したAPIベースになっている
2018/04/24 21:15:53 INFO <main> Starting mackerel-agent version:0.54.1, rev:, apibase:http://localhost:7071
2018/04/24 21:16:00 INFO <command> Start: apibase = http://localhost:7071, hostName = , hostID = xxx
# APIスタブで 201 を返したら期待と違うと失敗
2018/04/24 21:17:01 WARNING <command> Failed to post metrics value (will retry): API error. status: 201, msg: api request failed
# リトライでキー重複エラーしてAPIスタブも失敗
2018/04/24 21:18:01 WARNING <command> Failed to post metrics value (will retry): API error. status: 500, msg: api request failed

APIスタブに呼び出しログが出ている。

f:id:koudenpa:20180424211736p:plain

ローカルストレージにそれっぽいメトリックが保存されている。

f:id:koudenpa:20180424213205p:plain

単に投稿先を変えたいだけで、認証もAPIキーで行うようなら、これだけの修正で実現できてしまうようだ。

そりゃぁ、開発の便宜上呼び出し先のURIは平易に変更できるようになっているよなぁ。という感じである。

ビルドすらできなかった前回からしたら格段の進歩だが、Goのコードは全く触っていない。 次はこうもいくまい。

設定項目を増やす、認証やプロトコルの変更を睨んでAPI呼び出しを変更できるようにする(Go的には何ていうのか知らん)、など順次試していきたい。


余談。

f:id:koudenpa:20180424213815p:plain

フォーク数がちょうど 74 で縁起が良い。


追記。

そりゃぁ、開発の便宜上呼び出し先のURIは平易に変更できるようになっているよなぁ。という感じである。

ビルドオプションを変えるという行為が平易だと思ってるようならお前はアホだ。

もう少しコードを読んでいたら、普通に設定ファイル内容を読み込んでいた。 つまり、ビルドオプションでデフォルトのAPIベースをローカルホストにしているバイナリでも、以下の様な設定ファイルを食べさせることで元のMackerelにメトリックを投稿できる。

apikey = "xxx"
apibase = "https://api.mackerelio.com"

こうやって、印象的な出来事が起きるたびに要素技術や実装が身に刻まれていくのだ。

消して道化ではないぞ! 心を強く持つんだ!!

さらについき。

> mackerel-agent.exe -h
Usage: mackerel-agent [options]

main process of mackerel-agent

Options:
  -apibase string
        API base (default "http://localhost:7071")
...

まぁ、そういうこともあるさ。基本は大事。