Azure DevOps Pipelines で Go の Docker コンテナを Heroku に継続的デプロイする

kheiakiyama.hateblo.jp

フロント部分は Nuxt.js で作っているアプリですが、バックエンドのAPIは Heroku にデプロイすることにしました。
どうせなら Firebase にデプロイしたかったのですが Firebase Function はまだ Go や Docker に対応していません。残念です。

実装方法

Heroku

Rails アプリを動かす PaaS と思ってましたがいつの間にか Docker コンテナを動かせるようになってました。

コンテナを動かすための手順はこのあたりにあります。
Container Registry & Runtime (Docker Deploys) | Heroku Dev Center

Dockerfile を書く上での制約がいくつかあるので気をつけたいところです。
引っかかりそうな部分は下記2点あたりです。

The web process must listen for HTTP traffic on $PORT, which is set by Heroku. EXPOSE in Dockerfile is not respected, but can be used for local testing. Only HTTP requests are supported.

(意訳)EXPOSE は無視します。$PORTトラフィックを流すのでよろしくね。

CMD is required. If CMD is missing, the registry will return an error CMD will always be executed by a shell so that config vars are made available to your process; to execute single binaries or use images without a shell please use ENTRYPOINT

(意訳)CMD は必ず指定してね。

Azure DevOps Pipelines

kheiakiyama.hateblo.jp

上の昨日の記事にも書きましたが DevOps Pipelines ではYAMLファイルで設定できます。
Agent-pool は Hosted Ubuntu 1604 を使います。

azure-pipelines.yml

pool:
  vmImage: 'Ubuntu 16.04'
  
variables:
  HEROKU_API_KEY: YOUR_API_KEY
  HEROKU_APP: YOUR_APP_NAME

steps:
- script: |
   #!/bin/bash
   heroku container:login
   heroku container:push web --app $HEROKU_APP
   heroku container:release web --app $HEROKU_APP
    
  displayName: 'deploy to heroku'

Heroku CLIHosted Ubuntu 1604 にインストールされているのでスクリプト一つで済みます。
Heroku CLI の認証は環境変数HEROKU_API_KEY があればそれで行えるので、 heroku auth:token とかで取得、適宜作成します。
おそらく Secret 用の指定方法はあるのですが、まだ調べてないのでそれはまた今度。

heroku container:pushdocker build && docker push が走るようで、若干気持ち悪さがあります。
タグを意識させないためでしょうか。

感想

ということで無料の範囲で DevOps パイプラインまで作成することができました。
サクッと Docker コンテナの PaaS が使える Heroku はやはりよいですね。

久しぶりに使ったので変なところにハマってしまいましたが無事動きました。

これで Nuxt.js のバックエンドAPIが動かせそうです。

Nuxt.jsビギナーズガイド―Vue.js ベースのフレームワークによるシングルページアプリケーション開発

Nuxt.jsビギナーズガイド―Vue.js ベースのフレームワークによるシングルページアプリケーション開発

Azure DevOps Pipelines で Nuxt.js アプリを Firebase に継続的にデプロイする

kheiakiyama.hateblo.jp

Nuxt.js で書いたアプリですが、デプロイが煩わしい状態でしたので、最近話題の Azure DevOps を使って継続的デプロイを設定しました。

Azure DevOps Pipelines について

まずは公式リンク。

azure.microsoft.com

なぜ Azure DevOps(Pipelines) を使うかというと、プライベートリポジトリを使う場合の CI/CD サービスで Travis CI や CircleCI を使うとそこそこの費用が発生するためです。
(私は GitHub はプライベートリポジトリを使っています)
ギョーム開発であれば有償サービスを使うべきかとは思いますが、Azure DevOps Pipelines は月1,800分の無償枠があります。(2018/9/14 現在)
個人開発で何かを作るにはこの枠を有効に使えるのではないでしょうか。

実装方法

Azure DevOps Pipelines

DevOps Pipelines では GUI で設定する方法とYAMLファイルで設定する方法がある。
GUI で作ったものは後からYAMLを確認できるので、まずは GUI から入るとよい。
ここでは結果のみ書く。

以下の yamlリポジトリ直下に置き、Agent-pool は Hosted Ubuntu 1604 を使う。

azure-pipelines.yml

pool:
  vmImage: 'Ubuntu 16.04'
  
variables:
  firebaseToken: '********'

steps:
- script: |
   #!/bin/bash
   npm install firebase-tools firebase-functions firebase-admin
  displayName: 'Install firebase-cli'

- task: Npm@1
  displayName: 'npm install'
  inputs:
    verbose: false

- script: |
   #!/bin/bash
   npm run build
   npm run copyassets
   node_modules/.bin/firebase deploy --token $(firebaseToken)
  displayName: 'Run npm deploy'

パイプライン内では npm のグローバル環境下に Firebase CLI をインストールする権限がないため、firebase はローカルにインストールしています。
そのため firebase deploy はパス指定して動かす苦肉の策で実行しています。

このYAML についてのドキュメントはまだまだ充実してません。
サンプルコードが以下に紹介されており、GitHub を漁ると iOSAndroid のサンプルも見つかるので参考になれば。

Create your first pipeline | Microsoft Docs

Node 部分

package.json

  "scripts": {
    "dev": "nuxt",
    "build": "npm run clean && nuxt build",
    "clean": "rm -rf dist && rm -rf functions/nuxt",
    "deploy": "npm run build && npm run copyassets && firebase deploy", // for local only
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "precommit": "npm run lint",
    "copyassets": "mkdir -p dist/assets && npm run copydist && npm run copystatic",
    "copydist": "cp -R functions/nuxt/dist/ dist/assets",
    "copystatic": "cp -R static/ dist"
  },

Nuxt.js 部分

nuxt.config.js

module.exports = {
  buildDir: "functions/nuxt",
  build: {
    publicPath: "/assets/",
  }

感想

Microsoft-Hosted Agent の Docker Image に Firebase CLI を入れる PullRequest 書いたら通るのでしょうか。
後で気が向いたら試してみようと思います。
GitHub - Microsoft/vsts-agent-docker: Visual Studio Team Services (VSTS) Agent Docker Images

Self-Hosted Agent を作るのは結構敷居が高い印象あるので、Travis CI のように Agent に使う Docker Image を指定できると 一番理想的です。

Nuxt.jsビギナーズガイド―Vue.js ベースのフレームワークによるシングルページアプリケーション開発

Nuxt.jsビギナーズガイド―Vue.js ベースのフレームワークによるシングルページアプリケーション開発

Azure Blob Storage の Static website を使い始めた

はじめに

azure.microsoft.com

GA のニュースが入ってきたので、以下自分のレジュメサイトで早速導入した。

kheiakiyama's CV

きっかけ

というのも、先日以下記事でホスティングしたサイトが毎日3時間くらい稼働すると落ちる現象が出ていたため。

kheiakiyama.hateblo.jp

Consumption Plan を使っていたのに App Service の Shared Plan みたいな挙動をしていて、原因を調べていたが、Function Proxy のドキュメントが見当たらなかったので、これを機会に利用をやめたかった。

使い始め方

使い方は冒頭のドキュメントに書いてあり、補足はなし。

Static website の手前には Azure CDN を置いており、先日発表された MicrosoftCDN network を利用している。

Announcing Microsoft's own Content Delivery Network | ブログ | Microsoft Azure

最新の Azure Storage Explorer(Version 1.2.0) では Blob Storage Container の $web を開けない疑惑があるが、先日フィードバックしたときに開けるバージョンをもらっていたのでなんとかなった。

フィードバックでもらったバージョンは Version 1.1.0 なので、間違って更新してしまいそうになる。
早く機能が組み込まれてほしいです。

よくわからない

CDN endpoint でカスタムドメインを設定したとき、whois の連絡先に確認メールが届く仕様だと思っていたが、お名前.com で whois 情報代行していた。
しばらく時間が経つと認証が完了していて、何が起きたか全くわからなかった。
お名前.com 側でよきにはからってくれることなのか?(だとしても本人によるリクエストかを お名前.com 側が知るすべはないはず)

願望


travis-ci などの CD サービスで自動更新できるようにしたい。

Build 2018 振り返りと気になったニュースや感想と考察

Build2018 が終わりました。
日本では de:code2018 が始まります。

昨年は Build 2017 ではありがたいことにギョーム扱いで現地参加していましたが、今年の Build は国内組でした。
リアルタイムは初日のキーノート程度で、あとはニュースや Channel9 でキャッチアップしてました。
ニュースのまとめやピックアップ記事をこのタイミングで書いても仕方ないので、気になったことだけを頭の整理を兼ねてまとめておきます。

気になったニュース

Alexa Cortana 連携

Microsoft、「Cortana」とAmazonの「Alexa」の連携をデモ - ITmedia NEWS

Alexa から Cortana を、Cortana から Alexa を呼び出せる機能がクローズドベータになりました。

最近 Alexa Skill をいじっているので気になるところです。
BotBot を呼び出すことに何のメリットが?と思うかもしれませんが、やはり Office 365 など Microsoft 製品との連携で分がある Cortana を、 Alexa が載っている製品から呼び出せるのは大きいのではないでしょうか。
逆にオフィスに大量にある Windows PC から Alexa Skill を呼び出せるということは、Amazon Echo がなくとも大量にデバイスが存在することになります。

クラウドで競合している Amazon と協調する動きができるのは面白いですね。

メモ帳が LF 対応

Windows 10 RS5で“メモ帳”が改行コードLFとCRをサポート - PC Watch

表題のとおり。 Microsoft loves OSS ですね。
それ以上言うことはないです。

Microsoft Storeアプリの開発者収益割合が 85% から 95% に変更

「Microsoft Store」アプリの開発者収益配分を95%に - ITmedia NEWS

全然追ってませんでしたが収益比率相当いいですね。
スマホアプリの寺銭と比べると良心的に見えます。
何か作ってみたい気持ちになりました。
とはいえゲーム以外ですか。

Microsoft Azure

Cloud Platform Release Announcements for May 7, 2018 | Cloud Platform News Bytes Blog
上記記事 Google 翻訳版 | Bing 翻訳版

ニュースとしては上の記事を見ればすべてよしです。
Bing 翻訳を普段あまり使ってませんが、文脈理解して Azure を認識できるといいですね。
Azure については気になったもの、すぐに使いそうなものだけピックアップしておくことにします。

App Center - GitHub Marketplace

App Center はそこまで使えてませんでしたが、これで使う理由が高まりました。

Web App for Container - Authentication 機能追加

Blob Storage - Static Websites support

ちょうど3ヶ月ほど前に Azure 静的サイトをホスティングしようと思った時はわりと面倒な手順を踏んでいました。 kheiakiyama.hateblo.jp

Leverage Azure Blob Storage to build storage intensive cloud native applications | Microsoft Build 2018 | Channel 9
Storage だけで完結するのはいいですね。
Custom Domain + SSL の場合は CDN 必要なようです。
まだ使っていませんが、AWS の S3 に追いついたと思ってよさそうです。

Function でホストしたサイトを近日載せ換えてみようかと思います。
(de:code 終わってからかな・・・)

Blob Storage - Tiers and Lifecycle Management

Blob Storage は 料金表 を見るとわかりますが、ホット・クール・アーカイブの Tier に応じて容量課金・アクセス課金のテーブルが変わります。
この機能は n 日経過したオブジェクトの Tier を切り替えたり、削除する設定が可能になるというものです。

Leverage Azure Blob Storage to build storage intensive cloud native applications - YouTube
大量のデータを預かっているサービスでは効果がありそうです。
もっとも v2 を使わないといけないので、v1 を使っている古いサービスではマイグレーションを頑張る必要がありそうです。

AKS - DevOps, CI/CD

Getting started with CI/CD & Azure Container Service (AKS) powered by VSTS | Microsoft Build 2018 | Channel 9

AKS 自体はプレビューかつ日本リージョンが来ていない状況ですが、デプロイ周りや監視ツールの整備が急速に進んでいるようです。
あまり k8s に詳しくなくても使えてしまいそうに見えるのが Microsoft らしい気がしています。

Azure 以外

Microsoft Teams

Microsoft Teams をあちこちで推し始めてるのが気になりました。
正直 Windows クライアントがもっさりしていて、現時点では Slack には及ばないイメージですが、競争自体は善なのでがんばってほしいです。
優位性としては Office 365 を使っている企業はかなり多いので、追加費用なしに利用できるのは大きいです。
Slack 、SSO やメッセージの有効期限を欲しいとそれなりにお金かかりますからね。。

Microsoft Graph

最近 Office 365 API を調べていたのでちょうと気になった話。

Office365 の API を扱うソリューション、と思っていたらそうではなく、Windows や Azure Active Directory など他も含めての API 群のような位置づけになるようです。
channel9.msdn.com

Office 製品の優位は当分揺るがないと思うので、このあたりは今後周辺サービスを提供するサードパーティー企業からすると注目されそうに思います。
特に Cortana や Alexa などスマートスピーカー製品のように、今後発展していく分野で使っていきたい気持ちがあります。

Blazor

C# で Single Page Web Application が書ける Blazor が凄かった件 - Qiita

Qiita の記事がバズっていたときは流してましたが、動画のデモを見たらよさそうだと感じました。

.NET Overview & Roadmap - YouTube

多少アセットのダウンロードが遅くても許容できるエンタープライズ系のWebサービスなら使えるのではという印象。
今回 Microsoft が独自の CDN を始めることが発表された のと合わせて、Blazor が使うアセットのうち標準ライブラリは Azure でホストしていれば標準で Microsoft CDN が配信するとか、今後の発展があるのではないかという妄想をして面白がっています。

最後に

全体的にこれはいらないのでは?というようなものが見当たらず、誰かが欲しいと思っているものが順当に出てきている印象です。

また、今回の Build 2018 では Channel9 のセッション動画は Youtube にアップロードされており、このあたりでも Microsoft が変革しているのを感じ取れて面白かったです。
やはり CEO が変わったことは大きいですね。

Hit Refresh(ヒット リフレッシュ)

Hit Refresh(ヒット リフレッシュ)

帰省ついでに Azure IoT Hub を試してた

はじめに

2年くらい前から温度湿度をラズパイで取得することをやってた。
kheiakiyama.hateblo.jp

GrowthForecast で可視化していたものの、ラズパイ自体にはグローバルからアクセスできるようにはしていないため、帰省しないと見えないという不満があった。
それをいい具合にしたいと思って IoT Hub を試す決意をしていた。

Azure IoT Hub は Free プランが1日8000メッセージ受信できる ということで、毎分メッセージ送っても使えるのがよさそうだった。

やったこと

試したのはこのあたり。

ラズパイからセンサーデータを IoT Hub に送り、Web App でリアルタイムを見れるのができた。

知見

ラズパイ と Python Azure IoT Hub SDK つらみ

ラズパイ(デバイス)側はいろんな言語が選べる。
はじめに Python 使ったところ Azure IoT Hub の SDK の導入で苦しんだので Node にスイッチした。

Web App の Node version 問題

Free プランだったからかもしれない。
しかし Free プランで Socket I/O 使えたり Azure AD のシングルサインオン連携したりいろいろできて Web App は素晴らしいと思う。

可視化できてない件

リアルタイム可視化はできたけどデータ蓄積するところ作ってなくて全然やりたいことできてない。

そもそもセンサー壊れてた問題

ラズパイの死活監視は個人 Slack に流してるので問題ないのだが、温度湿度センサーが壊れていたことに気づかなかった。
今思うと Mackerel に流してた(こちらも Free プランなのでログは1日まで)ので、そこからアラートしていればもっと早く気付いたのに。
帰省で気付いて次の帰省までに買って持っていく、というの時間がかかってよくない。

ステージング環境というか別環境を都内に作るか。 せっかく ansible で管理していることだし。

あとがき

あまり問題は解決してないけど限られた時間で手を動かすのはよい。

Azure Logic App と Travis CI を使って翻訳サイトを静的ホスティングする

kheiakiyama.hateblo.jp

先月静的サイトホスティングについて試した。

延長線上で、サイトのコンテンツを自動生成するサンプルを作った。

github.com

デモサイトはこちら

仕組みについて

trans-feed では jekyll を使って静的サイトとして生成している。

翻訳記事の生成

Logic App はかなり安価で、翻訳(Cognitive Service) は現時点で無料で使える。
図で表すと以下のような形だ。
f:id:khei-fuji:20180321170353p:plain

ここでは翻訳したファイルを Markdown で保存する。

ホスティング

f:id:khei-fuji:20180321170403p:plain

ホスティングについては特に 前回の記事 から違いはない。

デプロイ

f:id:khei-fuji:20180321170407p:plain

翻訳したファイルとリポジトリTravis CI でまとめる。
jekyll build した結果を Azure Blob Storage にアップロードする。

Azure Function Proxy の proxies.jsonTravis CI で生成するようにしている。
Let's Encrypt の証明書を利用したい場合に、jekyll のファイル配信用プロキシと Let's Encrypt の Extension 用のプロキシが共存できるように書くのが困難で、jekyll 部分の設定は自力で書くようにしたため。
いい書き方があるのかもしれないが、ドキュメントが少なくたどり着けなかった。

Azure Functions でのプロキシの操作 | Microsoft Docs

おわりに

Azure の公式ブログ読むときに概要読んでパッと取捨選択したいと思い、今回のサンプルに至る。

書いてて気付いたが、サイト作らなくても RSS を翻訳してそのまま Slack などに流せば要求満たせる気がしてきた。
まあ jekyll を少し試したかったのでよし。

しかし、ぶっちゃけ翻訳の精度は・・・

Azureテクノロジ入門 2018

Azureテクノロジ入門 2018

Azure Function Proxy を使って静的サイトをカスタムドメインかつHTTPSのホスティングする

キーワードを詰め込んだら長いタイトルになりました。

静的サイトのホスティング方法

Azure で静的サイトをホスティングするにはいくつか方法があります。

  • Azure Web App
  • Azure CDN + Blob Storage
  • Azure Function Proxy + Blob Storage

大まかに3つあります。

Azure Web App

オーソドックスな方法です。
カスタムドメインを適用するには Shared プラン以上が必要なので、日本リージョンで運用するには大体月1000円以上かかります。(公式:App Service 料金)
このパターンについてはギョームで使っているのでそのうち別媒体で書きます。

Azure CDN + Blob Storage

費用はアクセスが少なければ月数十円で済むでしょう。

なぜ Blob Storage の手前に CDN を挟む必要があるかというと、以下の記事が大変よくまとまっています。

Azure BlobでのWebサイト公開がつらい

Blob Storage のツラみを CDN でどうにかしてやろうということです。
CDNSSL 証明書の面倒を見てくれるということで大変ありがたいです。
スケーラビリティも言うことなしでしょう。

しかし CDN で URL Rewrite するルールの適用が4時間以上かかるということで、待つのがかったるいです。
この記事を書いている間は絶賛待機中なのですが、待っている間に Function で試したところ動いたのでもういいかというところが今ココです。

Azure Function Proxy + Blob Storage

こちらも費用はアクセス次第ですが数十円から運用可能です。

Blob Storage で管理しやすいように管理するコンテンツの URL を Function Proxy でいい感じに整えるという役割分担です。
カスタムドメインSSL 終端は Azure Function が担当します。
なお、今回の例では SSL証明書 は Let's Encrypt を使っているので無料です。

実現方法

ということで本題。

完成品

まずは成果物です。

kheiakiyama's CV

(2018/7/8 追記: こちらの記事で Blob の Static Website によるホスティングに変更済み)

コンテンツは何でもいいですが、Jekyll で作成したレジュメっぽいものを置いています。

GitHub - kheiakiyama/kheiakiyama.github.com at 12dc107f19cdea04a73fd72ec877c2e1f57acf13

余談ですが Octopress はどこに行ったんでしょうね。

GitHub から Blob Storage へのデプロイ

Web App には GitHub からの継続的デプロイ方法が提供されていますが、Blob ではもちろんありません。
そこで Travis CI を使っています。

kheiakiyama.github.com/.travis.yml at 12dc107f19cdea04a73fd72ec877c2e1f57acf13 · kheiakiyama/kheiakiyama.github.com · GitHub

デバッグ用コード多めです。
(上のリンクを開いた前提で)やっていることをざっくり書くと以下のとおりです。

  • Jekyll のビルド
  • .NET Core のインストール
  • AzCopy のインストール
  • AzCopy で Jekyll の成果物を Blob にコピー

Travis CI の権限周りがよくわからなかったので .NET Core のインストールはコピーしてきて手元で動かすだけという雑な作りになっています。

また、AzCopy で set-content-type しないと Blob 側の配信がすべて application/octet-stream になるという悲しい現象が起きるため、拡張子ごとにコピーするというイケてないコードになっています。
Function でヘッダーを上書きするのもありますが、Blob の時点で動作確認できる方が原因切り分けの面で有利なので Blob で実現しています。
コンテンツの一部ファイルが削除された場合など考慮することが他にもありますが、まずはこれで。

Azure Function の実装

proxies.json は以下のとおりです。

{
    "$schema": "http://json.schemastore.org/proxies",
    "proxies": {
        "blob-route": {
            "matchCondition": {
                "route": "/"
            },
            "backendUri": "http://{your_storage}.blob.core.windows.net/{container}/index.html"
        },
        "blob-index": {
            "matchCondition": {
                "route": "/index.html"
            },
            "backendUri": "http://{your_storage}.blob.core.windows.net/{container}/index.html"
        },
        "blob-asserts": {
            "matchCondition": {
                "route": "/assets/{*file}"
            },
            "backendUri": "https://{your_storage}.blob.core.windows.net/{container}/assets/{file}"
        },
        "letsencrypt": {
            "matchCondition": {
                "route": "/.well-known/acme-challenge/{*rest}"
            },
            "backendUri": "https://%WEBSITE_HOSTNAME%/api/letsencrypt/{rest}"
        }
    }
}

Blob Storage から取得したいファイルを Proxy する以外では Let's Encrypt の承認プロセスのための API を Proxy しています。
このあたりは 公式の Wiki に書いてある通りに書いただけです。

Proxy 以外にも api/letsencrypt/{rest} の部分を実装する必要があります。
上述の公式の Wiki を参考に C# か NodeJS の内容をコピペしましょう。

余談ですが Azure ポータルと App Service Editor を両方開きながら相互に読み書きしたところ proxies.json が消えるハプニングが起きました。ローカルに適宜バックアップしながら作業を進めるのが無難です。

Azure Function でカスタムドメインSSL の設定

カスタムドメイン公式 でも見てください。

Let's Encrypt の導入については Azure Function でも Web App でも上記の Proxy 部分以外に差はありません。
How to install · sjkp/letsencrypt-siteextension Wiki · GitHub

公式の手順を参考に粛々と作業を進めましょう。
英語がニガテな方は以下サイトを参考にするとよさそうです。

Azure Web Apps に Let's Encrypt を使って簡単に SSL を導入する - えむにわリソース

無事完了すると SSL 証明書が割り当てられ、カスタムドメインSSL バインディングされた状態になります。

f:id:khei-fuji:20180212164429p:plain

https://{your_site}.scm.azurewebsites.net/.well-known/acme-challenge/{*rest} のリダイレクトでエラーになった場合は Function Proxy の実装が上手くいっていないと思われます。
一つずつ見直しましょう。

参考にした記事

最後に

Proxy は書き換え直後にすぐ動くので使っていて気持ちいいです。
最初に上げた通り、実現方法のパターンはいくつかありますが、要件に合わせて適切に使っていきたいものです。

Azureテクノロジ入門 2018

Azureテクノロジ入門 2018