VSCodeでJSONを編集する時にJSON schemaを指定して補完を効かせる

JSON editing in Visual Studio Code

tsconfig.jsonなどはデフォルトで補完が効くが、これはsettings.jsonで追加できる。

たとえばrenovate.jsonを編集する時はこういう設定を入れておくと便利。

  "json.schemas": [
    {
      "fileMatch": ["renovate.json"],
      "url": "https://raw.githubusercontent.com/renovatebot/renovate/master/renovate-schema.json"
    }
  ]

SlackとGitHub Deployments APIで疎結合なChatOpsを実現する


下記で紹介している /github deploy というコマンドは2021年4月9日の更新で現行のSlack連携からは削除された。

Removed deploy command and notification support: Today, the functionality provided by deploy command is very limited and doesn't address all the scenarios. We are removing deploy command and notifications support as part of this version. We want to relook at the scenarios and build a more holistic experience that customers need.

integrations/slack: Bring your code to the conversations you care about with the GitHub and Slack integration

this.aereal.org

Deployments APIが出た頃に上記記事を書いてもう5年が経とうしている中、最近いろいろなグッズが進化してタイトルにあるような良い塩梅のChatOpsが実現できそうなのでそれのメモ。

登場人物

Deployments APIGitHub Actions

このAPIだけではなんらかの仕事は行われず、ただWebhookのイベントが通知されるだけのAPIになっている。
この説明だけ聞くと「ふーん」というかんじだけれども、各種Webhookイベントに応じてなんらかのタスクが実行でき、しかもCI用に払い出されたAPIキーが振ってくるというGitHub Actionsの存在でできることの幅や手軽さが変わってくる。

実際のWorkflow YAMLを見るのが早いと思う: https://github.com/aereal/actions-playground/blob/master/.github/workflows/deploy.yml
on: deployment を書いておけば、Deploymentが作られた時にこのYAMLの内容が実行される。

内容の詳細は:

……となっている。

この例では活用していないが、Deployment APIのパラメータにはtaskやenvironmentがあるのでステージング環境か、アプリケーションのデプロイの他にDBのスキーマ更新などの付随するタスクも表現できたりなど、いろいろ使い出はありそうに見える。

Slackからデプロイ

では肝心のDeploymentはどうやって作るの、ということだけど、これまでは丁寧にcurlするしかなかったのが最近SlackのGitHub連携から作れるようになった。

/github deploy OWNER/REPOを実行するとこういう画面が出てきて:

n

リビジョンなどを埋めるとAPIが呼ばれる。

上記GitHub Actionsが設定されていれば、ピタゴラスイッチが動き出すという寸法。

Slackにはこういう通知が出る:

f:id:aereal:20191029121824p:plain

Deployment viewに期待

最近ひっそりとdeployment viewというものがベータリリースされている。これまで紹介してきたactions-playgroundの画面だとこういうかんじ: https://github.com/aereal/actions-playground/deployments

f:id:aereal:20191029121952p:plain

今は本当にログしか出てきていなくて味気が無いけれども、GitHub公式でこういうビューを作ろうとしているのはちょっと期待。

まあ仮にお蔵入りになってしまうとしてもDeployments APIを使ってちょっとしたビューを作るのはわりと楽だろう。

なぜDeployments APIなのか

こういうChatOpsの類はずっと前からいくらでもあるし、Deployments APIの何が良いの? という向きもあるかもしれませんが、以下の点でとても魅力的だと思っています:

  • チャット (Slack) 側の仕事内容が少ない = 移植性が高くコントローラブルな要素が多い
  • チャットを介さない実行が容易
  • Commit Statusなど既存のGitHubエコシステムと深く統合されて、今までの暮らしがスポイルされず、むしろ進化させられる

チャット側の仕事が少ないというのは、これまで見てきたように単にHTTP APIを呼び出しているだけなので、なにかうまく動かないということがそもそも起きにくい・起きたとしてもトレースがしやすい・実装の移植がしやすい、という点が嬉しい。
なんでもChatOpsにしたはいいがいざSlackが落ちると何もできないという事態に陥ることなく、いざとなればcurlを叩けば良いというのもポイントが高い。

またWebhookなどイベントベースのピタゴラスイッチはどこがホットスポットなのかわかりづらく全容を把握しづらくなってしまうことも多いけれど、Deployments APIとActionsの組み合わせだとGitHubが中央にあるので、とりあえずリポジトリを見れば概形がわかるというのも差別化ポイントになりうると思う。

さらにCommit Statusなど既に広く使われている機能などと統合されているというのも魅力。たとえばDeploymentにrequired_contextsを指定できるので、prchecklistのチェックが完了しなければデプロイが進められない、という制約も簡単に実現・移行できる。

そもそもなぜDeployments APIの話をしているのか

git の develop ブランチは必要なのか、またはリリースtagについて - Togetter

ここらへんでGit FlowなのかGitHub Flowなのかみたいな話が盛り上がり、そういえば最近Deployments APIが盛り上がっとるなということを思い出したのがきっかけ。

id:Songmuさんにこういうリプライもした:

実際、いま新しくやっているプロジェクトでもGitHub Flowに近いワークフローになっている。
コンテナワークロードになると同じリビジョンから作られる成果物を複数環境にデプロイが容易になるはずなので、アプリケーションの内容は同じなのに複数リビジョンが付くGit Flowは困ることが増えるなあ、という印象を抱いていた。

とはいえ上記Togetterまとめにあるとおりgit-pr-releaseは様々な点で便利なのは間違いない。が、本質は差分の可視化といったところなどにあるはずでPull RequestやGit Flow的なブランチ運用が根幹にあるものではないと思っていた。

そんなモヤモヤを抱く中でDeployments APIが進化してきたので注目しているというかんじ。

1PasswordのChrome拡張どれ使えばいいのか問題

結論から言うとtouch IDを使いたいなら「Xじゃないほう」

相対パス、絶対パス、相対URL、絶対URL

どう違うのか微妙にわかりづらいので表にした。

URL 相対パス 絶対パス 相対URL 絶対URL
/hoge n Y Y n
hoge Y n Y n
file:/// n n *1 n Y
https://example.com/ n n *2 n Y

便宜上、path-rootlessあたりを「相対パス」、absolute URIでないものを「相対URL」としています。

schemeが付いている場合のみ絶対URLで他の表現は相対URL、パスの絶対相対とURIの絶対相対は独立している、ということを覚えておくとよさそう。

参考: RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax

*1:is aではないがcontainsではある

*2:is aではないがcontainsではある

『入門 監視』を読んでMackerelの良さを改めて実感した

読んだ。新サービスローンチ前に読んでおいてよかった。

  • 目新しい話題はあまりなかった
    • なんとなくこうだよね、と思っていることが確認できた
    • 自信がなかったり理解が曖昧だったところを確認できた
      • メッセージングキュー (はてなでいうワーカー) の監視メトリックはキューの長さと消費率 (仕事率) を見るのが良い
  • 印象的だったところ
    • 監視自体は何も 修復 してくれません。何かが壊れたら、あなたがそれを直す必要があります。

    • オンコールシフト中、場当たり的対応をしていない時間は、システムの回復力や安定性に対して取り組むのをオンコール担当の役割にする - 3.2.2 場当たり的対応を減らす

    • 自動車メーカーのフォ–ドが、燃料タンクにガソリンがどのくらい入っているか計測する方法がない車を作ったとしたらどうでしょうか。(略) これらは、車が完成してから単に取り付ければよいというものではありません。ごく最初の段階から車にデザインされているものです。 - 5.4 自分のアプリケーションにそんなメトリクスはないという時は

Mackerelネイティブに育った人間なので「監視はこうあるべきだよね」という意識がキャリアが始まった時からインストールされていたことに気がつき、最初から一番良いやつを選べたのは高速道路だなーと思った。

このブログはMackerelを開発・提供している株式会社はてなでの勤務時間中に書きましたが、意見は私個人のものです。

ところで:

はてなで一緒に働きませんか?

typescript-eslint: monorepoでVS Codeからtsconfig.jsonのパスを正しく認識させる

typescript-eslintは型情報が必要なルールのためにプロジェクトの場所をparserOptions.projectで指定できる。

monorepo構成の場合かつ相対パスで指定している時、 yarn workspace front eslint ... のように実行する場合は期待通りtsconfig.jsonを見つけてくれるのだけれど、VS Codeのeslint extensionが実行する時にはtsconfig.jsonを見つけられない。

これは既知のissueでこの記事を書いている現在でもopenのまま:
Make `tsconfigRootDir` relative to the `.eslintrc` file · Issue #251 · typescript-eslint/typescript-eslint · GitHub

workaroundはあって tsconfigRootDir という相対パスを解決する基準となるパスを指定できるので、これに __dirname を指定するとVS Codeからも正しく見つけられる。

    project: "./tsconfig.json",

    // tsconfigRootDir: __dirnameを指定しないとVS Codeでmonorepoのtsconfig.jsonを正しく解決できないので.eslintrc.jsにしている
    // refs. https://github.com/typescript-eslint/typescript-eslint/issues/251
    tsconfigRootDir: __dirname,

__dirname が必要なので .eslintrc.js に書く必要がある。package.jsonや.eslintrc.jsonではだめ。

制限されたIAMロールをAssumeRoleして安全に削除操作を実行する

三行

  • 怖い操作をする時は許可するAPIコールを制限したIAMロールをAssumeRoleすれば安心
  • IAMユーザーにアクセス許可を委任するロールは同じAWSアカウントを指定することもできる

怖い操作をする時は許可するAPIコールを制限したIAMロールをAssumeRoleすれば安心

大量のリソースを削除するような操作はコンソールでぽちぽちやるとミスりそうで怖いのでスクリプトを書いて適宜レビューしやすいようにしたい。
けれども、普段使うIAMユーザーの権限だと広すぎると間違ったリソースを削除するなどの事故が怖い。普段からやや広めの権限で生活しているといきなり狭めるのも難しい。

今回はversioningが有効なS3バケットを削除したいが、削除するためにはすべてのオブジェクトのすべてのバージョンが削除されてバケットが完全に空じゃないといけない、という問題に遭遇した。

そこで実行したいAPIコールとリソースを限定したポリシーをアタッチしたIAMロールを作る。そしてaws-cliを実行する際にrole_arnを指定してAssumeRoleすることで、リスクを抑えられる。
refs. AWS CLI での IAM ロールの使用 - AWS Command Line Interface

IAMユーザーにアクセス許可を委任するロールは同じAWSアカウントを指定することもできる

IAMロールは使用する主体に応じて作り方・コンソールの画面が違う。

ドキュメントには以下の3つが挙げられている:

  • IAM ユーザーにアクセス許可を委任するロールの作成
  • AWS サービスにアクセス許可を委任するロールの作成
  • サードパーティーの ID プロバイダー (フェデレーション) 用のロールの作成
IAM ロールの作成 - AWS Identity and Access Management

今回はこのうち「IAM ユーザーにアクセス許可を委任するロールの作成」を選ぶ。

IAM ユーザーにアクセス許可を委任するロールの作成 - AWS Identity and Access Managementを読むとあたかもAWSアカウントをまたいだ操作を許可するためだけに使うようにも読めるがそんなことはなくて、IAMロールを発行するAWSアカウントと使用するAWSアカウントが同一であっても構わない。

似た事例: [https://dev.classmethod.jp/cloud/aws/assume-role-deploy-iam-user-and-role/:title=[AssumeRole] アクセスキーが流出しても被害が最小限になるIAMユーザでCloudFormationにデプロイする方法 | DevelopersIO]

#builderscon tokyo 2019で「自動作曲入門」について話した

自分のトーク

speakerdeck.com

デモはこちらです: musik

社内勉強会でやったトーク (『Scalaで自動作曲の練習』を社内勉強会で話した - Sexually Knowing) をベースにしています。 自分は資料を使い回して登壇することに強い抵抗を感じるので心苦しくあったのですが、社内勉強会から飛び出して広いところでぜひ話したいという思いがある一方で、ここから進んだ話をスクラッチから立てるのは今は厳しいという評価もあったので、折衷案としてトークの内容はほぼそのままに、きちんと動くデモを作りなんなら登壇するその場でメロディをつけるくらいのライブ感を出すくらいはやれたら自分も納得できそうだということでproposalを出し、トークする場をいただきました。

当日はWeb Audioを使ったデモはうまくいったのですが、MIDIキーボードを挿してメロディをつけるところはうまくいかなかったのでそれだけ心残りです。 Oscillator nodeのゲイン調整をしておらず音が大きすぎたため、メロディが鳴っているはずだけどほとんど聞こえないということが起きていました。ちゃんとGain nodeを繋げたらよさそう。

正直、目新しくも高度でもない話なので失望されないかドキドキしていましたが「おもしろかった」「やってみようかと思った」といった感想をいただけて登壇冥利につきます。

トークを聞いた方・このブログを読んだ方はぜひaereal/musikをforkしておもしろコンポーザを作ってください!!!

聞いたトーク

当日朝までデモを作るなどした結果、時間も体力も尽きてあまり聞けなかったのが悔やまれます。

Open SKT: メルペイ開発の裏側 - builderscon tokyo 2019

メルペイのオンボーディング内容をベースに公開できる内容にしたということで、まずオンボーディングプロセスが充実していることに驚きました。

個人的には分散トランザクションを伴う決済システムを開発しているので、わかる〜〜〜と思いながら、やっぱりある程度泥臭くなるよね、と安心しました。

コンパイラをつくってみよう - builderscon tokyo 2019

DQNEOさんによるコンパイラを1から作るライブコーディング。

Goのscannerなども使わず、コアの部分はほぼスクラッチから書いていくかんじで他の言語でも実践できそうなつくりなのが真似しやすくて親切設計でした。

会場から「そこtypoしています」とかやりとりがあったり、ライブ感があってめちゃくちゃ楽しかった。

Ruby (off|with) the Rails - builderscon tokyo 2019

僕はこのトークを「Railsに乗る = 使わされるだけではなく、ツールとして使う対象にする」「守破離」という趣旨だと理解しました。

普段、Railsを使わない立場 (業務で書いた経験はある) なので「大変そうだなー ActiveRecordが向いていないところもけっこうあるよなー」とわりと対岸の火事気味に聞いていましたが、一方、ライブラリ・フレームワークを使う上で一般的な話だとも思います。

つまりライブラリの事情などを抜きにして、責任の分離など抽象度の高い設計の作業を行い、それを実装へ落とし込む際に設計で果たしたい分離や凝集を壊しそうなライブラリの機能 *1 はこれとこれがありますね、というような思考を辿っていくもので、Railsユーザー以外でも得るものが多い内容でした。

Building, and Upkeeping Super Kamiokande - builderscon tokyo 2019

事前から楽しみだったし実際にめちゃくちゃおもしろかったトーク

実はこのトークを聞くまでスーパーカミオカンデが何なのかよくわかっていなかったので、そういった点でもdiscover something newが果たされました。

基礎物理学の世界の遠大な観測対象であっても、個々は素朴な技術 (センサー) と素朴な役割のソフトウェアシステムでできあがるというのがおもしろい。ただそのスケールがめちゃくちゃに大きいというのが興奮します。

11月に一般公開があるみたいなので申し込みます。いやーよかった。

北千住

事前の公式ブログで北千住駅の案内で脅かされていたり、足立区はなかなかラディカル *2 な土地だよと聞いて、トラブルに巻き込まれずに済むのか内心ヒヤヒヤしていましたが、無事どころかずいぶん楽しいできごとが多くて好きになりました。かなりホーム感がありました。

駅の近くにクラフトビールのお店がいろいろあったり、雑なところからそこそこのところまで飲食に困らなかったり、なにより荒川が近いのが良い。

川で飲んだりすることはけっこう奇行じみていると思われがちだけど、実質立食パーティみたいなもので、席に囚われず歩きまわっていろんな人と話せるというとても合理的なかたちでかなり好き。 懇親会が終わったあと20人くらいで荒川に移動したけど、飛び込みで20人も入れるお店はなかなか無いと思うし、見つかっても近くの席以外の人と話すのはなかなか難しいと思う。 出入り自由で、飛び入り参加したければ任意でお酒や食べ物を持ち寄るだけでよく実質プリペイドなのも気軽。

他人との距離、たしかにという感じ。居酒屋だと近すぎて疲れるけど、川だと自由に歩いて離れられるから気が楽、とかある。あとは、クラブとか行くとうるさいから距離近くなるとかある気がする。 かくれた次元 - hitode909の日記

鴨川でビール飲んでた.15人くらい来てくれた.

コンビニでクリスマスケーキ買って川で立ってケーキ持ってたら雪降ってきて最高の誕生日みたいな感じだった.前回は寒すぎてすぐ店に入ってしまったけど今回は暗くなるまで川にいられて自由に歩きまわって会話できてよかったと思う. ■ - hitode909の日記

荒川はとても広く地元の石狩川を彷彿とさせるスケールで、懐しい顔ぶれと話しているシチュエーションも手伝ってやけに楽しくちょっと懐かしい感じがした。

*1:いわゆるハマりポイントと呼ばれがちなもの

*2:婉曲しています

Google App Engine Standard EnvironmentにScalaで書いたWebアプリケーションをデプロイ

してみた: GitHub - aereal/gae-scala

GAE SE (Google App Engine Standard Environment) のいわゆる2nd generationと呼ばれるgVisorで構築された世代でJava 8/11が使える。

GAE SE (Google App Engine Standard Environment) ではgVisor上で実行されるランタイムとして新たにJava 8/11が選べる。

※当初Java 8を含めて2nd gen.としていたが公式ドキュメントによるとJava 8はgVisorで仮想化されているが、世代としてはJava 11のみが2nd gen.だったので訂正します。

Second generation runtimes are: Python 3.7, Java 11, Node 8, Node 10 PHP 7.2, PHP 7.3, Ruby 2.5, Go 1.11, and Go 1.12.

The App Engine Standard Environment  |  App Engine Documentation  |  Google Cloud

かつ、Serveletに対応しているJVM言語なら基本なんでも動くっぽく、公式のサンプルではKotolinの例もあった
https://github.com/GoogleCloudPlatform/getting-started-java/tree/master/appengine-standard-java8

古いJava 7ランタイムとの詳しい違いは以下:

The App Engine Java 8 runtime, which is based on OpenJDK 8, supports all of the existing features available in the current Java 7 runtime, which is based on OpenJDK 7, but with the following upgrades and enhancements:

  • Doesn't impose a security manager as the Java 7 runtime does, which means your code won't be restricted by Java permissions issues.
  • Supports all the standard public Java libraries.
  • Uses Jetty 9
  • Supports the Java Servlet 3.1 and Java Servlet 2.5 specifications.
  • Supports all Google Cloud-based APIs accessible from the Google Cloud Client Library for Java.
Java 8 Runtime Environment  |  App Engine standard environment for Java 8  |  Google Cloud

で、Scalaも動きそうだったので試した。

やったことは:

  • Scalaなのでmvnではなくsbtを使いたいのでsbt-appengineを入れる
  • GAEと関係ないけどScala 2.13にしたかったのでScalatra 2.7 RC1にした
    • ドキュメントに書いてある依存ライブラリのバージョンだと古くて2.13に対応していなかったりするので適宜上げたりした
  • Homebrewで入れたApp Engine SDK for Javaのどこにパスを遠したらいいかわからなかったけど `libexec` が正解だった

元気に動いています: https://gae-scala-247510.appspot.com

Serveletに対応していないとだめなのでPlayは動かなさそう。
こういう時はScalaでもWSGI/Rack的なやつがはやく策定・普及するといいですね〜〜って思う。

#builderscon 2019で「自動作曲入門」というトークをします

8月29日の前夜祭から始まるbuilderscon tokyo 2019で「自動作曲入門」というトークをします。
以前、このブログで紹介したScalaで実装してみたものを発展させたものをベースにしながら「そもそも作曲という行為をソフトウェアエンジニアの視点で再解釈するとどうなるのか」といった話から始める予定なので「むずかしそう」と思っている方でも楽しめる・むしろそんな方にこそ楽しんでほしいトークになると思います!

あと、おそらく音がなります。

僕のトークは8月31日の11:30から1204 セミナー会議室です。

builderscon.io

そんなbuilderscon tokyo 2019のチケットは7月22日までの販売だそうなのでまだの方はいますぐカモンジョイナス

builderscon-tokyo-2019.eventbrite.com

SVGから複数のfaviconを出力したり開発環境用に色を変えたりする

  • faviconやらapple-touch-iconやらいろいろ必要なアイコンが多い問題
  • 開発環境と本番でfaviconを区別して事故を防ぎたい問題

……などの話題がアイコン界隈にはあります。

SVGを使ってどちらも解決してみよう! のコーナーです。

必要なアイコンを生成する

icon-genというnpmパッケージを使うとSVGからicoやらpngが生成できます。便利。

こういうかんじ:

      const results = await icongen(variant.src, destPath, {
        favicon: {
          sizes: [180, 192],
        },
      })

開発環境ごとにfaviconを変える

↑でSVGからico/pngを生成するグッズを手に入れたので、ソースのSVGを環境ごとに変えればよさそう。

こういうかんじ:

const generateVariantSource = (variant) => {
  const { fillColor, src: dest } = variant;
  if (fillColor === undefined) {
    throw new Error('fillColor is empty');
  }
  const buf = Buffer.from(readFileSync(variants.live.src)); // assumed buffer
  const content = buf.toString().replace(/fill="#000000"/, `fill="${fillColor}"`);
  writeFileSync(dest, content);
};

replace(/fill="#000000"/, `fill="${fillColor}"`) は色を変えるハイテクなコードです。

BuildKitによるレイヤキャッシュのtargetは変数 (ENV, ARG) を展開してくれない

feature request: allow variables in the `RUN --mount=type=bind` values · Issue #815 · moby/buildkit

RUN --mount=type=cache,target=${APP_DIR}/pkg/cache go get -v と書いても `${APP_DIR}` という名前のディレクトリが作られるだけです! びっくり!

✘╹◡╹✘ < docker run --rm api:builder ls
${APP_DIR}
Makefile
api
go.mod
go.sum

HTTP関連のRFCで現れる `N#token` はカンマ区切りのリストを表す

1#header-token みたいなのは「少なくとも1個以上のheader-tokenがカンマ区切りのリストとして現れる」と読める。

出典:

A #rule extension to the ABNF rules of [RFC5234] is used to improve
readability in the definitions of some header field values.

A construct "#" is defined, similar to "*", for defining
comma-delimited lists of elements. The full form is "#element"
indicating at least and at most elements, each separated by a
single comma (",") and optional whitespace (OWS).

RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing

aws-xray-sdk-nodeを使う時はexperimentalを入れよう、じゃないと最近のnpmパッケージとの組み合わせだと動かないぞ

タイトルがすべてです。

AWS X-RayをNodeアプリケーションに組み込むaws-xray-sdk-nodeというパッケージがありますが、これを使う時はlatest (何もバージョン指定しないとこれ) ではなくexperimentalを入れると良いです。
yarn add -D aws-xray-sdk@experimental こういうかんじ。

なぜかというとlatestだと使っているライブラリの問題で親segmentを見つけられず、Webアプリケーションのコントローラ内で発行されたHTTPリクエストがsubsegmentとして回収されないのでアプリケーショントレースとしてほとんど意味をなさないためです。

あらゆるケースで親segmentを見つけられないわけではなくautomatic modeでかつasync/awaitを使っている場合に限られます。
が、最近のアプリケーションおよびnpmパッケージはasync/awaitを使っていることが多いですし、明示的にsegmentを渡さずとも勝手にSDKが切ってくれるautomatic modeを無効にすることは現実的ではないので、多くのユースケースで問題になります。

特にREADMEに書かれていませんがissueでさらっと言及されています。

問題はautomatic modeで使っているcontinuation-local-storageというパッケージがasync/awaitに対応していないことです。experimentalではこれにパッチを当てたバージョンを使っているのでsubsegmentが回収される、ということのよう。
continuation-local-storageはいわゆるスレッドローカル変数にあたるものをNodeに提供するものですが、async/await関数のセマンティクスに対応できていないようです。