knqyf263's blog

自分のためのメモとして残しておくためのブログ。

Trivyのアップデート(2019/10 - 2020/04)

噂によると日本でもGWが終わったらしいです。自分は去年のGWにTrivyを開発したので気づけばもう一年経ちました。いい機会なので直近のアップデートをまとめようと思います。

あと会社の評価の時期の前に自分の成果まとめておくかーと思ったのですが(多分もう評価終わってしまったけど)、仕事の80%近くをOSSであるTrivyに費やしているので、Trivyに関して近頃のアップデートや周辺のニュースをまとめけば大体OKということに気づいたというのも理由の一つです。ということで書いておきますが、気まぐれなので次以降も書くかは不明です。近況が追えてなかったという人もちらほらいたので、基本は自分で見返すために書いてますが誰かの役に立てば幸いです。

なぜそういう仕事をすることになったのかについては過去にやたらと長いやつを書いてあるので興味あれば。

knqyf263.hatenablog.com

そしてこの記事もかなりかいつまんで書いたつもりだったのですが、やたらと長くなりました。アップデートだけ知りたい人は見出しだけ流し読みすれば良さそうです。

概要

そもそもどういうツールなの?という人はそもそもこの記事を開かずにスキップするとは思うのですが、一応貼っておきます。コンテナの脆弱性をスキャンするツールです。

qiita.com

どうでも良いですが自分のQiitaの記事を探そうと"trivy qiita"とかでググったら全然ヒットしなくて記事の書き方の下手さを改めて実感しました。

新機能

この半年でちまちまと新機能が増えました。バグの修正も多かったですが... 同僚や外部の方々等、色々な人に助けてもらっているもののメインはやはり自分一人なので若干もどかしい部分はあります。まだまだ足したい機能があるのでもう少しリソースを割きたい気持ちはありつつ、弊社はまだベンチャーGAFAのように金が無限にある状態ではないので、会社としては今ぐらいが丁度よいバランスなんじゃないかと思っています。小さい会社でOSSチームがあるだけ凄いなと思っています。

あとはやはりOSSをビジネスに繋げていこうというのが会社方針としてあります。どう繋げていくかについては内部でも非常に議論されていて面白いなと思っているのですが、それについて話すと長くなるので気分が高まった時に書きます。ということでビジネス要件で足した機能もあったりします。自分もヘルプでSaaS開発に入ったりするので、たまにそっちにリソースを割いたりもしています。

全部書くときりがないので、大きい機能だけ紹介します。Aqua Securityに譲渡したのが去年の9月ぐらいなので、それ以降のやつを書いていきます。

v0.1.7

Amazon Linuxのサポート

Amazon Linux 1/2をサポートしました。要望の声が多かったので優先度高めでやりました。Clair という競合ツールがあるのですが、そちらでは Amazon Linux 2018.03 以前のイメージはスキャンできません。スキャンできていそうに動きますが検知はされません。そんなに古いイメージ使わないからいいでしょ、という声もあるとは思いますが意外と闇のイメージがあったりします。

$ trivy amazonlinux:2

Google Distrolessのサポート

単純にDistrolessと言うとscratchやbusyboxとかと勘違いされやすい事が分かったのでGoogle Distrolessと呼んでいます。こちらは基本的にDebianがベースになっているのですが、パッケージがほとんど入っていません。distroless/baseだと確か6つぐらいです。そのため脆弱性も見つかりにくく近年利用が増えています。こちらは 天地さん の尽力もありサポートすることができました。

$ trivy gcr.io/distroless/base-debian10

Kanikoのサポート

Kanikoというビルドツールでビルドされたイメージは内部構造が若干違う関係で以前はスキャンが失敗していました。こちらもユーザからの声が増えてきたので対応しました。

templateファイルへの出力に対応

以前は結果をテーブルやJSONでしか出力できなかったのですが、template出力に対応しました。Golangのtext/templateのフォーマットで渡してあげれば結果がそのテンプレートを基に出力されます。自分としてはJSON出力しておけばあとはユーザ側でやってほしいという気持ちだったのですが、template対応したことでユーザがtemplateを書いてPRくれたりするようになったので(後述)対応して良かったです。

$ trivy --format template --template "{{ range . }} {{ .Target }} {{ end }}" golang:1.12-alpine

v0.2.0

スキャンの高速化

色々工夫した結果、スキャンの実行時間が劇的に短縮されました。実行時間のほとんどが脆弱性情報の更新だったのですが、そこが高速化されました。詳細は長いので割愛しますが、GitHub Releases上に脆弱性DBファイルを置いてあるので実行時にダウンロードするだけになっています。以前は初回スキャンだと数分かかってしまっていたのですが、現在はデフォルトオプションだと10秒前後で、--light オプションを使うと数秒です。CIサービスによっては1秒を切ることもありました。

ちなみに高速化前でも他の多くのスキャナーよりは速かったです。ただ何となく自分で許せないところまで来たのでカッとなってやりました。他のスキャナーと比べて遅いわけじゃないならやらなくて良いと会社は言っていたのですが、熱意を伝えて工数を勝ち取りました。

そしてハマコーさんがブログにしてくださいました。正直特に評価もされないのにかなり頑張ったのでブログにしてもらえて嬉しかったです。

dev.classmethod.jp

こういう声も嬉しいです。サポートOSが増えた関係でDBサイズも大きくなっちゃったのですが、まだ許容範囲のはずです。

lightオプションの追加

上に書いたように−−lightオプションを追加しました。以前は脆弱性詳細や関連URL一覧も取得していたのですが、人によってはCIで回したいだけなので詳細は不要で深刻度ぐらい分かれば良いという人も多いことがわかりました。CVE-IDさえ分かればあとは検索すれば詳細は出てくるのでそちらを参照というスタイルですね。こちらであればDBサイズがさらに小さいのでより速くスキャン可能です。

$ trivy --light alpine:3.11

環境変数によるオプション指定に対応

trivy --exit-code 1 alpine:3.11 のようなものが TRIVY_EXIT_CODE=1 trivy alpine:3.11 のように指定できるようになりました。今の御時世だとコンテナオーケストレーションツール経由で渡す場合など、何でも環境変数で指定できる方が便利ということですね。

v0.2.1

GITHUB_TOKENの指定

GitHub ReleasesからDBファイルをダウンロードするため、大量のイメージがある人はGitHub APIのRate Limitingに引っかかる事が分かりました。GITHUB_TOKENでtokenを指定するとRate Limitingの上限が上がり回避可能です。

$ GITHUB_TOKEN=xxx trivy alpine:3.11

v0.3.0

Client/Serverに対応

以前はスタンドアローンでしか動かせなかったのですが、10ホストあると10回脆弱性DBをダウンロードする必要があります。CIサービスとだとキャッシュも使えますし、そもそも上述したように数秒なのであまり問題ないのですが、オンプレミスでCI環境を構築していたり各マシンでcronでやっていたりすると一度ダウンロードしたDBを使いまわしたいというニーズがありました。そこでserver modeを用意し、serverで脆弱性DBさえ更新すればclient側は不要で済むようにclient/serverを実装しました。

サーバ側を以下のように起動して、

$ trivy server --listen localhost:8080
2019-12-12T15:17:06.551+0200    INFO    Need to update DB
2019-12-12T15:17:56.706+0200    INFO    Reopening DB...
2019-12-12T15:17:56.707+0200    INFO    Listening localhost:8080...

クライアントでスキャンするだけです。

$ trivy client --remote http://localhost:8080 alpine:3.11

サーバは定期的に勝手にDBを更新するので放っておけば良いです。

Oracle Linuxのサポート

これは @masahiro331 がメインでやってくれました。

$ trivy oraclelinux:8.2

v0.4.0

Photon OSの対応

これも@masahiro331 がメインでやってくれました。実はこれがHarborのデフォルトスキャナーとなるために重要な機能の一つでした。HarborはVMwareがメンテナンスしているOSSですが、Photon OSもVMwareが提供しているOSになります。Harborのイメージは全てPhoton OSで構築されているため、Photon OSのスキャンは重要でした。Harborは以前から脆弱性スキャナーとしてClairを採用していましたが、Issueを出しても一向にPhoton OSの対応をしてくれないということでメンテナーの方々も色々な思いを吐露していました。公の場で言うのはアレなのでここまでにしておきますが、既にデフォルトとなっているものをわざわざ置き換えるというのは非常に労力も大きいですし相当アレがアレしてました。

ちなみに他のOSと比べてPhoton OSはセキュリティアドバイザリがとても親切です。新たなOSに対応するのは簡単ではないのですが、実はその大部分がセキュリティアドバイザリの難しさから来ていたりします。その点Photon OSは開発者フレンドリーで最高です。まずJSONなどという生ぬるいフォーマットで完全な情報が提供されているのがPhoton OSぐらいです。Harborのメンテナーはとても喜んで感謝してくれていましたが、感謝を述べたいのは正直こっちでした。

そしてRed Hatのセキュリティアドバイザリの難しさは群を抜いています。対応しているOSは現時点で12個ぐらいあるのですが全体の工数の7割ぐらいをRed Hatに持っていかれています。

SUSE Enterprise Linux / openSUSEの対応

これも@masahiro331 と協力し進めました。セキュリティアドバイザリが異常な難しさで、Clair含め既存の脆弱性スキャナーは正しく動作しません。@masahiro331はSUSE脆弱性スキャンに世界一詳しいと言ってました。

使い方はいつも通り。

$ trivy opensuse/leap:15.0

v0.4.3

templateをファイルとして指定

text/template が使えるということを上述しましたが、@を最初につければファイルとして渡せるようになりました。

$ trivy --format template --template "@/path/to/template" golang:1.12-alpine

そしてこちらの機能を使ってGitLabのContainer ScanningのフォーマットのJSONを出力できるようになりました。こちらは @mrueg さんによるContributiionです。本当にありがたいです。

github.com

GitLab CIの連携

上でも触れましたが、@tnir さんがさらにGItLab CIとの連携を改良してくださって、簡単に使えるようになりダッシュボードでいい感じに表示できるようになりました。ありがとうございます。

https://github.com/aquasecurity/trivy/blob/master/contrib/Trivy.gitlab-ci.yml

実はGitLab CIをちゃんと使ったことなかったのですが便利すぎて感動しました。

v0.5.0

キャッシュの改良

以前はスキャンしたイメージのレイヤーをまるごとtarファイルとして保存していました。理由としてはCIで回すなら揮発するしローカルでそんなに大量にスキャンしないじゃろ、ぐらいのノリでした。あとはDockerのレイヤーを自前で組み立てるためにはopqファイルとか諸々処理しないとダメで、まるごと残っている方が都合が良いというのもありました。GW中に開発終えたかったのであまり余裕がなかったというただの言い訳も挟んでおきます。

当然ユーザが増えて大規模にスキャンする人が出てきてキャッシュサイズが問題になりました。Harborなどのレジストリに統合する場合は特に問題です。ということでレイヤーから必要な情報のみ抽出してJSONに変換して保存するようになりました。これにより劇的にキャッシュサイズが減ったので問題になるユーザはほとんど現れないと思われます。

また、Client/Serverで起動したときにキャッシュをサーバ側で共有するように変更し、不足しているレイヤーだけRegistryから取得するようにしました。そのため、ホストAでalpine:3.11をスキャンし、ホストBでalpine:3.11にレイヤー一つ足したイメージをスキャンした場合はalpine:3.11の部分は既にレイヤーのキャッシュがサーバに存在するためホストBではダウンロードせず、不足しているレイヤーだけ取得します。ローカルのDocker Engineにあるような場合はそもそもダウンロードが発生しませんが、その場合でも解析がスキップされるのでキャッシュの効果があります。

これは結構大変だったので、この改善により後述する各種レジストリーとの統合の話が進んで良かったです。

v0.5.3

レイヤーIDの表示

脆弱性が発見されたけどレイヤーが多くてどこでそのパッケージのバージョンが入ったか分からない、という問題もありました。いやパッケージ名でDockerfileをgrepすれば良いんじゃないの...みたいな気持ちもありましたが依存で入ったりするケースもあり、やはり対応してもらえたほうが嬉しいということだったので対応しました。

脆弱性が発見された場合に以下のようにLayerが表示されます。ざっくり言うとDiffIDはレイヤーを解凍したあとのIDで、Digestというのは圧縮時のIDです。Docker Registryにある場合はDigestの方をLayerIDとして見ることが多く、ローカルにあるイメージはDiffIDの方がLayerIDというような扱いになっています。もちろん細かい条件でどちらが使われるか違うのですが、大枠そんなイメージです。

    "Vulnerabilities": [
      {
        "VulnerabilityID": "CVE-2011-3374",
        "PkgName": "apt",
        "InstalledVersion": "1.8.2",
        "Layer": {
          "DiffID": "sha256:78c1b9419976227e05be9d243b7fa583bea44a5258e52018b2af4cdfe23d148d"
          "Digest": "sha256: 9740df1ac227d21600b22524f869c9bec2d8c13446d1c8579a6195b6d855ae2b"
        },
        "SeveritySource": "debian",
        "Description": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.",
        "Severity": "LOW",
        "References": [
          "https://snyk.io/vuln/SNYK-LINUX-APT-116518"
        ]
      },
  ...

v0.6.0

内部のライブラリを変えてソースコードの変更が莫大だったんですが、今見るとユーザに価値を提供するようなやつなかったのでスキップ。

v0.7.0

OCI Image Formatのサポート

OCI Image Formatをサポートしました。個人的にはskopeoとかでDockerイメージフォーマットに変更してもらえれば良いのでは...と思っていたのですが何やかんやで要望も多く対応しました。

Buildah:

$ buildah push docker.io/library/alpine:3.11 oci:/path/to/alpine
$ trivy --input /path/to/alpine

Skopeo:

$ skopeo copy docker-daemon:alpine:3.11 oci:/path/to/alpine
$ trivy --input /path/to/alpine

tarで固められている場合には対応していません。ディレクトリである必要があります。

ニュース

新機能のv0.2.0あたりで既に疲れて後半かなり適当になってきているので、ここからは完全に雑です。Trvyを取り巻くニュース的なやつをまとめておきます。見返したら結構多かったので大きいやつだけ。

Harborのデフォルトスキャナーに採用

まずはこれがとても大きいです。HarborというのはOSSのコンテナレジストリーです。ただ2.0からはOCIレジストリーとして進化を遂げてコンテナイメージだけに限らなくなっています。

Harborのブログを見ると、Trivyをデフォルトスキャナーとして採用したという件が非常に大きく書いてあります。感無量のあまりまだ実は読んでないです。

goharbor.io

元々はClairというスキャナーがデフォルトでした。自分にはClairを使うのが難しすぎて、これ使える人プロだけなのでは?みたいな気持ちが膨れ上がり爆発した結果Trivyを作り始めたという背景もあるため、デフォルトを置き換えられたのはとても嬉しいです。ただ実際にはClairもまだデフォルトスキャナーの位置づけではあります。Trivyの方が優先してインストールされるという感じで、一応両方デフォルトという名目になっています。これ実はHarborのメンテナー達と我々現場のメンバーではもう撤廃しようぜwwというノリで盛り上がってたんですが、うちのチームのボスとあちらのマネージャーが大人なミーティングをした結果、廃止は角が立つので一応残そうということになったという背景があります。ですがそのぐらい評価していただいている状態です。

これはうちのチームメンバーであるDanielがHarborにコミットし続けた結果、コミッターになったというのも大きいです。Harborの脆弱性スキャン周りは完全に裁量を持っています。ただ上述したようにPhoton OSの対応だったりバグがあったときの迅速な対応だったり、そもそも機能的に優れていたりという諸々が積み重なった結果、こういう成果を得たという感じです。スキャナーとしてどのぐらい違うのか、というのは自分が精度や機能面で比較してブログ書いたのですが大人の事情でまだリリースされていません。お蔵入りになる可能性も高そうです。

大きなニュースと思ってもらえたのか、InfoQでも記事にしてもらっています。普通はツール名しか載らないものですが、InfoQでは自分の個人名を載せてくれています。これはとてもありがたいのでInfoQのファンになりました。

www.infoq.com

Docker Enterpriseでの採用

Docker EnterpriseはMirantisが2019年11月に買収したのですが、そのMiranatisからDocker EnterpriseにTrivyを統合したいというお声がけをもらいました。

www.itmedia.co.jp

これは弊社の営業が強いとかでも何でもなく、自分個人宛にメールを頂いています。Docker Enterpriseでは既に自分達のスキャナーを持っているのですが、それがいまいちなので置き換えを検討していたらしくClairなども含め色々検討した結果、Trivyが良かったということで連絡をもらいました。

以下の記事に貰っているコメントが載っていますが、全て最高に嬉しいです。

www.prnewswire.com

containerjournal.com

Docker Enterpriseへの統合は発表したもののいくつか不足している機能があるためMirantis社のSlackに入って一緒に開発しています。Windowsイメージの対応もやってくれるということでお願いしています。

CNCF Cloud Native Interactive Landscapeへの掲載

以下のLandscapeに載せてもらったので、一応クラウドネイティブなツールと言っていけそうです。

landscape.cncf.io

これはCNCFプロジェクト(Kubernetesみたいなやつ)ではないものでもクラウドネイティブ関連ツールであれば掲載されます。ただうちのチームのボスはCNCFのTOCでチェアーをやっています。このTOCは投票でCNCFのプロジェクトとして採択するかどうかを決める立場であり、恐らく弊社OSSもCNCFプロジェクトして寄贈することは可能です。

なのになぜプロジェクト寄贈しないの?というのは前に質問して裏話が聞けて結構面白かったので、いつかオフラインの場で話せせたらなと思っています。

ThoughtWorks Technology Radarへの掲載

Trialという区分で載せてもらいました。

www.thoughtworks.com

どうやら凄いことみたいなのですが、見つけた当時は全く知らなかったので和田さんに教えていただきました。

無知すぎてめちゃめちゃ恥ずかしいことを言っていました。

AWSブログ掲載

AWSのブログに載せてもらいました。ECRの裏側ではClair使われてるのでTrivyダメなのかというとそういうわけではなく、単純にECR連携のプロジェクトが開始したときはまだTrivyなかったとかそういう背景もあったりします。

aws.amazon.com

これはうちのボスがAWS Container Hero的なやつなので、その力も大きそうです。イギリスでTrvyについて発表したらAWSの人がブログ書いてほしいと声かけてきて寄贈したという流れみたいです。発表するだけで次々と面白い話が転がってきていてすげーな...と他人事みたいに眺めてました。

Grafanaでも利用

あんまりどこで使われているかとか把握してないのですが、自分がミスって最新版が一部の環境で動かなくなったときにGrafanaで動かないんだけど、と言われて知りました。個人で始めたので最初の頃はまだどこか気楽に考えていたのですが、有名OSSのJobを失敗させてしまって怒られるとなるともう気軽にミスできるようなプロダクトではなくなってきたのかなと思うようになりました。

github.com

Clairが自分のライブラリを使用

これはかなり驚いたんですが、Clairが自分のバージョン比較のライブラリを使い始めました。Clairを倒すために作り始めたものなのに気づいたらClairに使われるという。

github.com

自分はバージョン比較王を名乗るぐらいバージョン比較を厳密にやることにこだわっていて、有名なOSSの実装を見に行ってバージョン比較のバグを直してあげたりしています。Clairも過去にPR送って直したりしてます。その結果、自分たちで開発するよりライブラリを使おうとなったのかなと思います。そして選ばれたのが自分のライブラリというのは何とも奇妙な話です。

TrivyをベースにしたSaaSをリリース

Aquaには元々脆弱性スキャナーがあったのですが、Trivyをベースにした全く新しいSaaSを0から開発しました。このSaaSでは動的解析やランタイムセキュリティなど脆弱性スキャン以外の豊富な機能を提供しています。この辺りの詳細もいずれ書けたら良いと思っています。 containerjournal.com

ブログ

かなり多くの方にブログにしてもらったので全ては挙げきれないのですが、印象に残ったものをリストアップしておきます。漏れてたらすみません。

IBMのブログ

公式ブログっぽい?

developer.ibm.com

Use Trivy and Azure DevOps to scan container images for Vulnerabilities

Microsoft Azure MVPの方がAzure DevOpsとの連携を書いてくださったみたいです。

pixelrobots.co.uk

Understanding Kubernetes: part 21 – Useful tools - part 4 - security

dev.to

Google Dev Expertの方が書いてくださったみたいです。

January Virtual Meetup Recap: Improve Image Builds Using the Features in BuildKit

Docker Captainの方がDocker Blogに寄稿したようです。BuildKitとかがメインの話でTrvyはほんの少し出てくるだけです。

www.docker.com

gitrivy

スキャン結果をIssueに登録してくれるGitHub Actionsです qiita.com

kube-trivy-exporter

Prometheus Exporterを実装してkube-trivy-exporterとして公開して下さったという内容がLIFULLのブログで触れられていました。周辺ツールを作ってもらえるのは本当に大歓迎です。

www.lifull.blog

helm-trivy

フランス語的なやつですが、helm-trivyを作ったという話っぽい。 www.objectif-libre.com

Docker Image Security: Static Analysis Tool Comparison – Anchore Engine vs Clair vs Trivy

コンテナスキャナーを比較した記事。最終的にTrivyがオススメと言ってくれていたので安心しました(記事を開く前は緊張する)。ただ比較が若干正確ではないので(例えばTrivyはCVE-IDベースだけどClairはRHSA-ID使ってたりするとかするのでどちらかに変換して比較する必要がある)、自分の方で比較したやつを公開したいのですが色々あって実現に至っておらずです。

www.a10o.net

20 ways to become a better Node.js developer in 2020

なぜかNode.jsの記事に突然脆弱性スキャンの話が出てきたのが面白かったのでここに入れました。

medium.com

KitPloit

www.kitploit.com

2019年にOSS界隈で話題になったニュース10選~日立社内SNSより~

日立のような大企業で認知されるのはやはり嬉しいです。

qiita.com

その他

medium.com

devopschat.co

scrapbox.io

発表とか

自分はまだ一回もまともにカンファレンスで話してないのですが、カンファレンスやmeetup等で誰かが話してくれていたようで自分で頑張らなくても広がるのは便利だなと思います。

GitHubの人の発表かな?

これは確かKubernetes Forum Seoul

インド

などなど

雑多な話

それ以外にも雑多なやつを少し書いておきます。

ステッカー

ステッカーをAquaが作ってくれました。KubeCon North Americaで配ったらしくみんな持ってるのに自分だけ持ってないという状態だったんですが、帰国してきたあとにちゃんと自分ももらいました。

ボスの手腕はやはり大きいですね。シンプルに凄いなーと思っています。でも上に書いたようなニュースは営業とかして得たわけではないしプロダクトが結局良くないとダメかなと思っているので、そこはある程度頑張った結果かなと思っていたりもします。

今後について

まだまだ機能追加する予定です。本音を言うと自分はsimpleに保ちたいので別プロジェクトとして立ち上げたいのですが、話し合いに負けたのでTrivyに足していくことになりました。ここらへんの大変さはまた別途書けたら良いなと思っています。

具体的には今はGitHubリポジトリスキャン対応をしています。もちろんGitHubが既にプログラミング言語のライブラリに対して脆弱性スキャンを提供しているのですが、意外と検知できない脆弱性も多かったりします。そもそもGitHub使ってないという人も多いのでこの対応をします。

プログラミング言語に関してもJavaC#の対応をしたいと考えています。パッケージマネージャのlockfileをベースでやってるためMavenとNugetになります。Mavenの仕様が色々と難しく難航という感じですがいずれそう遠くない将来対応できると考えています。

先ほど上でも述べたようにWindowsイメージのスキャンも実装されると思います。実はAqua社としてはプライオリティが低いのですがMirantisの方がやる気十分なのでいい感じに実装してくださると思います。こちらも既に話は進んでいるので一緒にやっていくことになると思います。

あとはDockerfileに組み込んで使いたいという声もあるため、そちらの対応も現在進めています。元々Aquaが提供していたフリーのスキャナーでMicroScannerというものがあり、そちらはDockerfileへの組み込み機能がありそちらが好評だったようです。Trivyの加入によってMicroScannerは廃止予定なので機能を引き継ぐ予定です。

github.com

また、現在は脆弱性の結果に対して簡単なフィルターしか行えないのですがOPAと統合することで複雑なルールを適用可能にします。さらにKubernetesへOPAと共に組み込み、脆弱なイメージはデプロイできないような設定を可能にします。このあたりはKubeCon Europe 2020で発表予定だったのですが延期になったのでまだ発表していません。

そして現在のようなパッケージベースの脆弱性だけでなく脆弱な設定のスキャンも行う予定です。例えばNginxの設定がこうなっていると危険、などといったようなものです。conftestに近いです。ですがもう少しセキュリティに特化し、具体的な攻撃や脆弱性の検知を行っていきたいです。

脆弱性を検知するだけではなく、その後の対応にも踏み込みたいと思います。以前は可視化されていなかった脆弱性が可視化されたのは良いが、結局その後の対応が楽になっていないと思っており、そこを何とかしたいと考えています。具体的には動的解析との連携を予定しています。AquaではtraceeというeBPFベースのコンテナ動的解析ツールをOSSとして提供しており、これを使って内部ではコンテナのサンドボックス環境を構築しています。コンテナを実際に動かしイベントを観察し、起動後に実際に影響の大きい脆弱性を検知したいと考えています。例えばbashで致命的な脆弱性が発見されたけど実際コンテナ起動後には一切使われない場合は極端な話対応しなくてもあまり問題ないわけです。似たアプローチしてDockerSlimのようにそもそも不要なものをイメージから削除するアプローチもあるのですが、意外とアプリケーションが動かなくなったりして大変です。一部のファイルだけ除外設定を渡してあげたりとなかなかチューニングが求められます。そもそも消したくないという話もあるかもしれませんし、あくまで削除はせずに検知できたら良いなと考えています。

github.com

他にもまだ温めている新しいアイディアがあるのですが、それらはそこそこ新規性があると思っているので実際に開発してから発表したいと思います。これは今年のGWで作るぞ〜〜と気合い入れていたのですがイスラエルはGWなくて作れませんでした。有給めっちゃ余ってるので取得できれば作るかもしれません。それが無理だと来年ぐらいになる可能性もあります...

そして何よりまだまだ知名度が低いので宣伝を頑張らないといけないなと思っています。自分は宣伝が苦手なので特に何もしていないのですが、やはり使われるためにはまず知ってもらわないといけないなと思っています。比較した上で他のツールを、というならもっと開発頑張ろうとなりますが、知らなかったので選びませんでした、となるのはもったいないなと感じています。比較してもらえれば良さが分かってもらえたかもしれないのにそのチャンスを失っています。

まとめ

途中で疲れてしまって書ききれなかったけど色々あった半年でした。

Goの1.14以前かつChrome 80以上を使っているとgo tool traceが動かない問題

問題

Goにはtrace機能がありgoroutineの実行状況などを可視化出来ます。具体的にはCPUやメモリを計測するときと同じようにpprofを差し込めば使えます。

defer profile.Start(profile.TraceProfile, profile.ProfilePath(".")).Stop()

あとは実行したらtrace.outが出力されるので $ go tool trace trace.out で利用可能です。ですが、自分の環境ではうまく表示されずエラーが出て困っていました。

f:id:knqyf263:20200326010443p:plain

解決策

自分の環境の問題だろうと思っていたのですが、 @orisano 先生に聞いたら同様のエラーが表示されるとのことでした。どうやらChromeがWebComponents V0を廃止したのが原因のようだと@orisano先生が発見しました。

github.com

ということでGo 1.14.1以降を使えば動くようですが、Go 1.14以前かつChrome 80以上だと動かないようです。

Goのpprofがruntime関連の情報しか表示してくれない時の解決方法

問題

Goでpprofを使っていたら以下のようにruntimeの情報しか表示してくれなくなりました。これだとどこがボトルネックなのか分かりません。runtimeのpthread_cond_signalが大きいけどどこから呼ばれているのか分からないし何も分からんという感じです。

f:id:knqyf263:20200326005037p:plain

解決策

GOMAXPROCS=1 を指定すれば良いと @orisano 先生から教わりました。CPUのコア数が多い時に発生しそうな雰囲気ですが詳細は深追いしてないので不明です。これで必ず解決するとは限りませんが自分の環境では改善されました。

イスラエルの良いところ・大変なところ

対象読者

イスラエルに引っ越す可能性があるような人やイスラエル生活に興味がある人向けに少しでも情報提供できればという思いで詳しく書いた記事になります。あくまで住む人対象で観光地とかはあまり触れてないです。それ以外の人はやたら長いだけで読んでも特に得るものないです。

背景

イスラエルに来て半年が経ちました。1年ぐらい経ったら引っ越してみての感想を書こうと思っていたのですが、既に慣れてきて自分の中で新鮮さが失われつつあり、日本もこんな感じじゃなかったっけ?みたいな気持ちになってきたので今のうちに書くことにしました。それでも面倒で放置していたのですが、CEOやCTOからも日本に向けて書いてよって言われたのでついに重い腰を上げました。

最初に断っておくと日本と比べてどっちが良いというわけではなく、一長一短だなと感じています。単にインターネット上に情報が多いほうが良いということで良い点・大変な点を書いてます。実際、自分がこっちに来る前に調べてみたもののアメリカやヨーロッパのようにたくさん日本人が住んでいる国とは違いあまり情報は得られず、良く分からないけど行ってみるか、とノリで来た部分はあります。もし来る前にもう少し情報があれば不安は少し和らいだかもと思うので、未来の誰かの役に立てばということで覚えている限りで全部書きます。何か思い出したらちょくちょく追記していこうかなと思っています。

あと、多分ここに出てくる多くの話はテルアビブの話になります。テルアビブはイスラエルで一番の都市で、自分もそこに住んでいるので必然的にテルアビブで体験したことが多くなります。とはいえイスラエル初心者がいきなりテルアビブというキーワードで検索するかと言うとそうじゃない気がするので(自分がそうじゃなかった)、あえてタイトルは大きめにしています。1つの都市にしか住んだことない人が日本を語ることもありますし、あまり大きく捉えずにそういうこともあるんだなーと思ってもらえれば幸いです。

あくまで主観の話なので、ヨーロッパではそれは常識だ!とか日本でもこの地域ではこうだ!というよりはボケーっと見てもらえればと思います。

気づいたことは大体Twitterに書いてるのでツイートをペタペタ貼ってます。

良いところ

良いところはとても多くて挙げきれないのですが、一応可能な限り説明してみます。

天気が良い

まず、基本ずっと晴れてます。9月に来て12月末まで一回もまともに雨見たことなかったです。今は雨季みたいなやつに入ったので雨が降ってますが、こっちの人に聞くと乾季の9ヶ月ぐらい雨の日が0という年も普通にあるみたいです。

もしかしたら天気がなんぼのもんじゃいと思う人もいるかも知れません。実際こちらに来る前に現地の人に天気良いと言われた時に自分も思ってました。ですが、こちらに来て気づきました。天気は本当に重要です。精神に与える影響が絶大です。こっちに陽気な人が多いのも間違いなく天気のおかげです(適当)。一番好きなところを挙げろと言われたら天気かもしれません。

自分はスクーターで会社に来てますが、雨が降って帰れないかも...とか心配する必要がありません。天気予報をチェックするのが苦手だった自分としては人生のストレスが1割ぐらい減りました。もう天気予報を見るのは諦めて濡れるという紳士的解決策を取っていた自分としてはとても助かっています。犬の散歩も行き放題です。

あと冬も短いので大体暖かいです。とはいえ冬は10度ちょっとぐらいまでは下がるみたいなので、あまり油断しないほうが良いです。

ヨーロッパの町並み

雰囲気はヨーロッパに似ていると思います。オフィスの近くは以下みたいな感じです。

週末には蚤の市のようなものも開かれ歩いてるだけで楽しいです。

そしてTel Avivは普通に都会ですし綺麗です。日本のニュースの印象や中東のイメージとはかけ離れてます。自分も来てからただの都会じゃん...と驚きました。もちろん事前に調べてはいましたが想像以上でした。

ちなみに1人当たり名目国内総生産GDP)では日本は2014年にイスラエルに抜かれています。あまりイメージがないかもしれませんが完全に先進国です。その後もめざましく発展を続けています。

www.nikkei.com

宗教の聖地がある

特に詳しくない自分が語るべきことではないので割愛しますが、エルサレムがあり3つの宗教の聖地になっています。無宗教の自分ですら嘆きの壁は感じるものがあったので歴史に造詣が深い方は感動するのではないかと思います。

ちなみに無宗教と言うよりは"仏教"と答えるほうが良いみたいですが、今のところ無宗教と答えて何か問題になったことはありません。

1kara.tulip-k.jp

Tel Avivは移民も多く割とその辺りゆるい都市なので、会社の人も親は敬虔な信者だけど自分たちの世代はそこまで教えを厳格に守っている人は少ないと言っていました。エルサレムに住んでる人たちはかなりその辺り厳格で、ユダヤ教の制服のようなものも着ています。黒いスーツに黒いハットで全身黒い感じです。ただ一部のユダヤ教の人はあんなの暑くて無理でしょ、と言ってましたし個人差がありそうです。

イスラエルは今選挙のやり直し続きで非常に揉めていますが、より宗教色を強くしてユダヤ教以外の人間を締め出したいという派閥ともっと海外の人を呼び込んでオープンな国にしたいという派閥で争っているみたいです。Tel Avivの人はグローバルな人が多いので後者の考えの人が多いみたいですが、エルサレム周辺の人は前者の考えみたいなので票が真っ二つとのことです。

人が優しい

イスラエルは英語話せる人がかなり多くて、その点では困ることは少ないのですが駅の仕組みとか諸々日常で困ることがあります。そんな時、どうやるんだろう...みたいな顔をしていると大体誰か近づいてきて助けてくれます。駅のチケット売り場で困っていたらやり方を教えてくれましたし(普段は難しくないのですがその日は選挙でちょっと特殊だった)、スーパーで肉の注文とか分からなくて困っていた時も助けてもらいました(日本みたいにパックで売られていなくて、店内にでかい肉が置いてあって量を伝えて切ってもらう)。

また、妻が体調悪くなってベンチで休んでいたら色々な人が声かけてくれたり水買ってきてくれたりしました。全部イスラエルに着いてから2週間ぐらい以内に起きたことで驚きました。

日本で海外から来た人が困っていても自分が積極的に声かけられるかと言うと難しいと思うので、この辺りガンガン行けるのは良いなーと思いました。1回や2回なら良い人もいるんだなーという感じですが、しょっちゅう起きるのでもうこれは国民性と言っても良いんじゃないかと思っています。

上の例は見知らぬ人の例でしたが、社内でも助けられまくっています。銀行口座作ったりとか家の契約したりとか、自分のような外人には簡単ではなくて毎日困難の連続でしたが、その度に会社の人が付き添ってくれたり代理でやってくれたりして何とかなってきました。あまりにも何もできないですし、自分が一人で単独乗り込んでいたら今頃死んでたと思います。アメリカからイスラエルに移住した人とかは割と多いのでもう少しスムーズに行くのですが、日本人はとにかく少ないので銀行でも「日本人は初めてだからなー」とか言われますし難易度高めです。

Wikipediaによると2015年時点でイスラエルにいる日本人は1011名らしいです。自分の大学の学部入学者は毎年1100人ぐらいいたと思うので、それよりも少ないです。

2015年10月時点で在留邦人数は1011名

日本とイスラエルの関係 - Wikipedia

レストランは大体英語メニューが付いていますが、大衆向けのところは回転が早いのでレジの前に行ってからゆっくり見る余裕はありません。なので遠くからメニューを見て予め頼むものを決めておく必要がありますが、大きく書いてあるのは大体ヘブライ語です。そんな時も同僚は常に英訳してくれます。とても助かっているのですが、英語も別に得意じゃないのでちょくちょく理解できてなくて本当にすまぬと思っています。

妻の誕生日が近いと言ったらみんなオススメとかを次々と教えてくれたり代わりに電話でスパ予約してくれたり、マジで優しいです。インターネット開通手続きも代わりにやってもらいましたし、注文した洗濯機が大きすぎて部屋に入らなかった時の交換の交渉とかも全部やってもらいました。これだけ良い人が多いのも天気が影響してるのではないかと疑っています。他にも挙げるとキリがないのでこの辺りにしておきます。

人が陽気

やたらと話しかけてきます。店員とかも気さくな人が多いです。この写真は家の近くのカフェの店員です。

今何時?とか火貸してとかすぐ言われます。近所付き合いも活発なので外出ると最近どう?みたいに話しかけられます。東京で住んでたマンションでは隣に誰が住んでたのかすら知らなかったので大きな変化でした。その辺りは日本の田舎も同じかもしれませんが。

陽気なところ良いなと自分では思っていたのですが、近所の人はスーパーで多めに買ってたら知らないおばさんから「あんた何をそんなにたくさん買うの!」とか言われたりするので陽気すぎてちょっとうざいと言ってました。

シェアスクーターが便利

電動スクーターが至るところに置いてあって、好きなところで乗って好きなところに乗り捨てられます。

電動スクーターがこれだけ普及しているのはサイクルレーンのおかげだと思います。もし車道で車と一緒に走らないとダメだとしたらかなり怖いと思います。

www.bcnretail.com

日本ではサイクルレーンも少ないですし、こういう新しい取り組みに対して障壁が多いので使えるようになるとしても当分先かなと思います。

jp.techcrunch.com

リゾート

テルアビブはビーチがすぐそこにあり、地中海リゾートと呼ばれています。この辺りは既に解説しているブログが多いので割愛します。ビーチ綺麗だし人の密度もハワイとかに比べれば全然少ないので快適です。

sekaishinbun.net

オフィス街とビーチが近い

リゾートなのは良いとして、もしそのリゾートが遠ければ気軽に行けないし実質意味ありません。ですが、テルアビブの凄いところはビーチとオフィスが融合されているところだと思います。ちょうどよい写真を持っていないのですが、若干雰囲気伝わる写真を貼っておきます。

これを見るとビーチと高いビルが近いことがわかります。オフィス街からスクーターで飛ばせば12, 13分でビーチまで着きます。自分の家からであればビーチまで8分です。オフィスまでも8分なので移動が楽です。今日疲れたからビーチ行こうとかも気軽にできます。実際、休日は気分転換ビーチに行ったりすることもちょくちょくあります。そもそもテルアビブは51.79平方kmで小さい都市なのでスクーターでどこでも行けます。

治安が良い

イスラエル行くというと治安大丈夫なの?とか聞かれたりすることがありますが、正直かなり安全です。大枠は以下のブログに書いてある通りです。

https://getnews.jp/archives/2212356getnews.jp

上のブログに書いてないようなことを補足しておきます。まずガザ地区からの攻撃ですが、基本的にTel Avivに届くようなことはほとんどありません。万が一危険性があるような場合はアラームが街中に鳴り響くのでアパートに付いているシェルターに入れば普通に間に合います。

そしてこれは同僚から聞いた話なのですが、そもそもガザはイスラエルに大きなダメージを与えることを望んでいないとのことです。もしそうなれば戦争になり、軍事力で劣るガザは深刻なダメージを受けることになります。なので、適度に緊張感を保つようにしているとのことです。また、ロケット弾を打つとイスラエル市民はシェルターに入ることになり学校等も休校になり会社も休みになります。そうすることで経済的にダメージを与えることが可能です。このように直接的に死者を出すようなダメージを与えるというよりは経済的な狙いのほうが大きいということみたいです。ロケット弾に関してもガザは経済的な余裕がないため威力の大きい高精度なロケット弾は打つことが出来ないようです。さらにイスラエルにはアイアンドームという迎撃ミサイルがあるためほとんどが撃墜されます。ですが、ガザの打つ安いロケット弾よりもアイアンドームのミサイルのほうが高額です。そのためロケット弾を打てば打つほど経済的にはイスラエルにダメージを与えられます。こちらも先程同様の狙いがあるということです。

ということでガザの脅威はあまりありません。もちろん最初にアラームを聞いてシェルター入ったときは驚きましたが、日本の地震の方がやばいだろうという指摘を受けてその通りだと思いました。ロケット弾に慣れているイスラエル人にとっては地震のほうが遥かに怖いと。東日本大震災では死者1万5897人、不明2533人ですが、ここ10年でのガザのロケット弾による死者はそれより遥かに少ないと思われます。

イスラエルパレスチナ紛争として第四次中東戦争以来最大の死傷者と言われているガザ侵攻でも民間人犠牲者は7人です。東日本大震災での死者はほとんど民間人と考えるとロケット弾より断然恐ろしい国に住んでいたのではないかという気がしました。東京に首都直下地震とか来たらどうなるのか考えると恐ろしいです。それに比べたらロケット弾はアイアンドームで頑張れば防げる、とこっちの人に言われてなるほど...と考えさせられました。

ガザ侵攻 (2014年) - Wikipedia

ということで長くなりましたが街中の治安の話に戻します。上のブログにもあるように、こっちの人はレストランとかで平気で財布等の貴重品を置きっぱなしにして離れます。財布も普通にズボンの後ろポケットに入れて剥き出しになっています。フランスとかイタリアでそんなことをしたら一瞬で盗まれると思いますが、こっちはそういう危険な雰囲気も全く無いです。

あとは夜間に女性が1人で出歩いていたりします。子供も夜遅くに外で遊んでいたりします。治安の悪い国ではまず不可能なので安全な国だなと感じています。

そしてつい先日のことですが、自分はショッピングモールで鞄をなくしました。3/11で日本では防災意識を高めようという雰囲気だったと思いますが、危機意識のかけらもない自分は普通に鞄を置きっぱなしにして手ぶらで帰宅しました。何か体が軽いな?とは思いましたが全く気づきませんでした。

鞄にはiPadAirPods Proなどなどそこそこの金額のものが何点か入っていました。これは絶対見つからないなと思って諦めていたのですが、翌日探しに行ったら発見されました。中身も全部無事でした。親切な人が届けていてくれたみたいです。

高価なものが一切盗まれず落とし物が見つかるというのは治安の良さとして伝わりやすいのではないかと思います。

ヨーロッパに観光行ったときは結構怖い地域も多かったのですがイスラエルは怖いと感じることがほとんどないです。こっちに8年住んでいる日本人の方と話したら東京よりもテルアビブの方が治安良いと感じていると言っていました。そう言うのも納得なぐらいです。ただもちろんテルアビブ以外では少し怖いと感じる地域もあります。どこに行っても安全というわけではないので、その点は気をつけてください。

食事が美味しい

個人差あると思いますが、料理は普通に美味しいです。以下はフムスやファラフェル、シャクシューカの写真です。そのあたりのワードでググれば美味しそうな写真出てきます。

朝食は小皿みたいなのがいくつか出てくるのが主流で美味しいです。

ユダヤ教徒が多いのでもっと質素な食事を想像していたのですが、昼にハンバーガー夜にピザとか平気で食べます。正直日本のほうが質素な食事してました。

唯一注意したいのはKosherです。これはユダヤ教徒が守る食事に関する教えなのですが、これがかなり厳しいです。豚はNGですし、エビや貝のように鱗がない魚もNGです。

コーシャジャパン株式会社 | 日本初のKJマーク(コーシャ認定)取得機関

肉と魚を同時に食べることも許されていませんし、肉と乳製品を同時に食べることも出来ません。つまりチーズバーガーは食べられません。そして肉も血抜きが必要なのでジューシーさがあまりありません。そこまで詳しくないので細かいルールは間違っているかもしれません。

基本的にユダヤ教徒ではない人には関係ないのですが、Kosherレストランが街には結構多いです。うっかり知らずに入ってしまうと口に合わない可能性が高いです。Kosherマクドナルドも存在しているのですが、我々の知っているマクドナルドの味だと思って食べると衝撃を受けると思います。観光の記念として挑戦して見る分には良いと思います。

安息日がある

毎週安息日というユダヤ教の休日があります。こちらは金土休みなのですが、金曜の日没から土曜の日没まで労働が許されていません。つまりショッピングモールやレストランは閉まります。さらにバスや電車等の交通機関も全て止まります。そのためどこにも出かけられませんし、出かけても何もすることがないです。

business.nikkei.com

厳格なユダヤ教徒は電化製品も使えないのでテレビやパソコンも利用不可です。料理もできないので前日までに作っておく必要があります。さらに労働の解釈は広く、エレベーターのボタンを押したりするのすら労働に当たります。そのためホテルではどうしているかというと各階に停止するエレベーターが動きます。ボタンを押さずに乗ることが出来ます。Apple Storeだと思えばオシャレさを感じることが可能です。

基本的には何も出来ないしデメリットだなと思っていたのですが、逆に言うと何も出来ないのでひたすらリラックスする時間になります。自分はこっちで犬を飼い始めたので週末は犬と散歩に行ってます。

日本だと何かしなくては、という強迫観念にかられていましたが毎週強制的に休ませられるというのは実はとても良いことかもしれないと思うようになりました。

公園で犬とダラダラ過ごすのも悪くないです。

多様性に寛容

LGBTフレンドリーな国です。

locotabi.jp

また、ビーガンメニューなど多くのレストランにありますし、デカフェコーヒーも多くのカフェにあります。日本に観光行ったビーガンの人は日本では食べられるものを探すのが大変だったと言っていて、自分がビーガンじゃないので意識していませんでしたが確かにビーガン対応レストランとか少ないなと気づきました。

電車が綺麗

電車が新幹線みたいなスタイルで綺麗ですし広いです。さらに自分が乗った限りでは100%座れてます。もちろん路線にも依るとは思います。東京の電車とかに慣れていると、電車ってこんなに快適な乗り物だったのか、と気付かされます。

子供に優しい

合計特殊出生率は3.1で、日本の1.4と比べて倍以上あります。街中にとにかく子供が多いです。そしてみんな子供に優しいです。子供が泣いて嫌な顔をする人とか基本いませんし、ベビーカー押してるお母さんとかがいると知らない人が当たり前のように手伝っています。バスの中で旦那さんがベビーカー持ってるのかな、と思ったらお母さんがベビーカーと降りる時に手を振ってお別れしてて、全く知らない人がただ手伝っていただけみたいなことも多いです。

dot.asahi.com

あと公園の数が多いです。さらに一つ一つの公園に遊具がとても多いです。ブランコも長い。

週末は子供がとても多くて家族で溢れています。

犬に優しい

Tel Avivは信じられないぐらい数の犬がいます。犬の散歩に行くとどの時間帯でもまず間違いなく数匹の犬と会います。ドッグランが家の近くだけで徒歩10分以内に3つもあるので週末はそこに連れて行って他の犬達と遊ばせてやれます。レストランも基本的に大体犬OKです。それどころかレストランに犬用の水や餌入れとかも用意してあることが多いです。

さらに驚いたのは犬専用ビーチがあります。はっきりと犬向けと書いてあるのでみんな犬を連れてきてビーチで遊ばせています。

あとオフィスに犬を連れてくる人も普通にいます。大きい企業だとドッグシッターを雇っていて仕事中は預けておけば散歩なども行ってくれるみたいです。バスや電車など乗せるのも何も問題ありません。犬に関しては間違いなく日本に住むよりこっちに住むほうが幸せだろうなと思います。

ベンチが多い

街中の至るところにベンチがあります。みんな日中ベンチに座ってコーヒー飲んだりしながらゆったり過ごしていて良いなーと思います(この写真では誰も座っていませんが)。

ゴミ箱が多い

ゴミ箱が5m置きぐらいに設置されていたりします。すぐに物を捨てられるの便利。

美男・美女が多い

こっちの人はヨーロッパ系の顔立ちで、女性は金髪の人が多く美人が多いです。あと男女ともに太っている人が少なくてシュッとしてます。理由を聞いてみたら兵役でトレーニングさせられるので土台として身体が鍛えられているし運動する習慣が付くので兵役後も運動している人が多いのとかはあるかも、と言っていました。

街中には軍服来た兵役中の女性も多いので本当にこんな感じです。

matome.naver.jp

ナタリー・ポートマンイスラエル出身です。

www.mine-3m.com

携帯料金が安い

後述しているように基本的には物価がめちゃめちゃ高いので焼け石に水的なところはありますが、携帯料金はなぜか安いです。月20GBで電話かけ放題のプランで1500~2000円です。同僚に言ったら「それでも高い。1000円以内で契約できる。」と言ってました。

タクシーが安い

タクシーはGettというUberのようなアプリがあってとても便利です。そしてなぜかやたら安いです。結構乗ったし3000, 4000円はするだろうなーと思ってメーター見ても2000円行ってないこととかも普通にあります。

10bisが便利

10bisというサービスがあるのですがこれが便利です。

www.10bis.co.il

会社からカードが配られて、そのカードで支払うと会社支払になります。会社は月にある程度の金額をそのカードにチャージしてくれるので、そのカードで支払えば無料で食べられます。このカードはほとんどの店が対応しているため、休日とかでもそのカードで払えばタダです。月の上限を超えれば自分のクレジットカードから引落されます。社食とか作るよりもみんな好きなものを店で食べられるからこっちのほうが良い、と言っていてなるほどなと思いました。

あとデリバリーも可能です。賢いなと思ったのはオフィスにいる場合、別フロアの人が同じ店で頼んでいれば注文がまとめられて送料が無料になります。うちのビルは40F以上あって会社が多く入っているので送料がほぼ間違いなく無料になります。これ日本でもやったら流行るんじゃないかと思ってます。

そして送料払えば家からでも注文可能です。中にはデリバリーが無料の店もあります。他にもWoltというUber Eatsみたいなやつもありますしフードデリバリーは日本よりも盛んです。

医療制度が整っている

以下の記事に書いているのですが、大きな病院のグループが4つぐらいあってそのグループ内ではカルテ等が全て共有されているので違う病院に行っても続きから受けられます。さらにその先生でわからないことがあっても別の病院の先生にすぐ連携できるので専門家の話が聞きやすいというメリットもあります。日本では何で毎回問診票書くんだ...と常々思っていたので便利で驚きました。過去の病気とかうっかり書き忘れたら命に関わることもありそうだし改善されて欲しいなと思います。

www.itmedia.co.jp

Tel Avivは狭いのでmeetupとか行くの楽

日本では基本的に移動が面倒であまり勉強会とか行かない人間だったのですが、こっちでは大体徒歩で行ける距離で開催されるのでそれなら仕事終わりに少し顔出してみるかという気分になります。それでも2ヶ月に1回ぐらいしか行ってませんが。

ソフトウェアエンジニアの待遇が良い

これはまた別途書こうと思いますがイスラエル企業はアメリカのソフトウェアエンジニアとかを雇うための給料設定がされているので給料はかなり高いです。これは若者にとってソフトウェアエンジニアが憧れの職業であることが大きいみたいです。逆に医者や弁護士は人気がなくて給料が低いらしいです。こちらで働いている日本人弁護士の方は日本の時よりも給料が下がったとのことです。

どちらでもない点

アジア人が少ない

チャイナタウンは世界中にどこでもあるからな〜とか言ってイスラエルに来たのですがありませんでした。聞いたら中国人や韓国人はビザを取るのがとても難しいみたいです。日本人も簡単なわけではないので先述したとおり1000人程度しかいません。実際に街中を歩いていてアジア人を見かけることはほとんど0です。観光客っぽい人をたまに見かけるぐらいです。日本人は半年で1, 2回しか見たことないです。こっちでアジア人と交流したいと思っても厳しいです。

自分は別に交流しなくても平気だなと思ってたのですが、中華料理や韓国料理が食べられないのはかなりストレスであることに気づきました。中華料理店自体はたまーにあるのですが、恐らく知っている料理とは大きく異なります。韓国料理がないので焼肉屋も一切ありません。というかアジアの区別がそもそもあまり付いてません。

ですが日本料理はこちらで大人気で寿司はどこでも食べられます。人口あたりの寿司屋の数は世界3位と言われているみたいです。ただ周りを揚げてあったりスパイシーマヨネーズを付けて食べたり、我々の求めている寿司とはかなり異なります。お金を出せば日本っぽい寿司が食べられたりもしますが高すぎて頻繁には食べられないのと、それでも回転寿司のクオリティにも満たないのでおとなしくフムス食べておいたほうが良いな、となって久しく食べてないです。

アジア人が本当にいないので日本語とかを使う機会が0です。こないだ2ヶ月ぶりに妻以外の日本人の人と会いました。さすがに少しテンション上がりました。基本生活の全てが英語かヘブライ語で話さないといけないので勉強になるという点では良い点かなと思います。

ただ一方でとても目立ちます。すぐ「Chinese?」とか話しかけられます。別に普段は気にしていなかったのですがコロナウイルスの影響でアジア人に対しての風当たりが強い状況だと少しマイナスかなと感じています。

www3.nhk.or.jp

とはいえこういうのは一部の話で自分は全く被害を受けていません。会社の人も近所の人もひたすら優しいです。一部におかしなやつもいるから気をつけてね、と忠告はしてもらいました。

大変な点

どちらかと言うと日本が異常、みたいな話が多い気もしますが一応比較として。

物価が高い

これは今となっては日本の物価が安すぎるという話だとは思いますが、日本と比べると物価が圧倒的に高いです。すべての物が2倍はします。マクドナルドに行ってセット頼むと1500円はします。ランチで2000円ぐらい出しても大したものが食べられないということも多いです。

同僚がビッグマックの値段で比較すると良いと教えてくれたのですがイスラエルは6位です。アメリカが3位なのでアメリカの物価に迫るぐらいの高さだということが分かります。日本は27位です。

https://www.statista.com/statistics/274326/big-mac-index-global-prices-for-a-big-mac/www.statista.com

たまにまだ東京が高い物価の都市だと思ってくれる人もいるのですが、毎回半分ぐらいの物価だと伝えて切ない気持ちになっています。既にそれを知っている人は日本は物価が安いので旅行や買い物に便利という認識になっていますし、後進国になっていってる感があって悲しいです。

家賃高い

家賃もTel Avivだと平気で30~40万円とかかかります。こちらに住んでる日本人弁護士の方も家賃は40万円以上だと言っていました。自分たちはたまたま日本好きのオーナーの人と出会えたおかげで22~23万円ぐらいのところに住むことが出来ましたが、他の物件は高かったですし運が良かったケースかなと思っています。

ウォシュレットがない

イスラエルに限らずアメリカとかアジアとか日本人が多数住んでいる国全てそうだと思いますがウォシュレットがないです。これは本当に致命的で、ずっとウォシュレットのない国には住めないと言い続けていたのですが主張は正しかったです。もう限界が来ています。

二郎がない

自分はジロリアンですが二郎食べられないのが本当にストレスです。これだけで日本に住む価値があります。ただボストンにもあるという噂を聞いたのでアメリカは住めるかもしれません。というかこっちは二郎どころかラーメンすら殆ど無いです。2000円払って出てきたラーメンは不味すぎて食べきれずに残しました。こっちでマルちゃん正麺を2000円で売ればエグいほど儲けが出るんじゃないかと思ってます。

時間にルーズ

基本待ち合わせも遅刻しますし、バスや電車の時間は守られません。日本では電車が1分遅れるだけで謝罪することもあると言うと大体狂ってると言われますし、日本が異常なだけという気もしてます。

運送業が終わっている

時間指定とかいうのはまず機能しません。時間外に来るならまだマシですが、その日にすら来ないことがしょっちゅうです。そして来なくても連絡の一つもありません。仕方ないのでこちらから電話するのですが、道に迷って帰ったとか言われたりします。しかもこっちの住所はとてもシンプルで、〜丁目までしかありません。つまり"品川1丁目"とかがもう家の位置を指します。このシンプルさで道分からないならドライバーもうやっていけないでしょ...と思ってます。さらに言うと休日は安息日の関係で働かないので平日の日中に待機し続ける必要があるのも大変です。

つまり、

  1. 時間指定する
  2. 平日に家で待機する
  3. 時間内に来ない
  4. その日にすら来ない
  5. こちらから電話する
  6. 1に戻る

というのを3回ぐらい繰り返す必要があります。死ぬほどストレスが溜まるのですが、3回ぐらいやるとさすがに受け取れます。そして受け取ると大体以下のような状況になっています。

ツイートにも書きましたが、3回目ですら時間内に来ずiMacの入ったボロボロの段ボールを家の前に放置して帰っていました。一番信頼性が高いと言われているEMSで送ったのですが、現地の人からするとイスラエルに物を送るときには絶対にEMSは使ってはいけないというのは常識みたいです。自分の場合は関税で何ヶ月もストップされた挙げ句、新品のPCに見えるとかイチャモンを付けられて何万円も取られて3ヶ月越しにようやく受け取れる...!!と胸を膨らませて上の状況だったので、さすがにドライバーを10発ぐらい本気で殴ろうかと思いました。税関では新品に見えるとイチャモンつけられていたので壊したのはほぼ間違いなく運送業者だと思われます。

中もボロボロです。

補償を求めてダメージレポートを出したのですが、実はドアの前に放置されていたのは逆に良かったみたいです。もし受け取ってしまっていたらこの状態の荷物を了承したとみなされて厳しかったみたいです。ダメージレポートも自分では出せなかったのでこっちの人に代理でやってもらいました。本当にありがたいです。

ちなみにPCが壊れた話を会社の人にしたらみんな似たようなことを言っていて国民性を感じました。

EMSは一番速いと歌っているため一番値段が高いのですが、実際には数ヶ月かかる上に関税に間違いなく目をつけられるので一つもいいことがありません。その上粉々に壊されます。ですが実験を重ねた結果、小型包装物が神であることが分かりました。

www.post.japanpost.jp

2kgまでしか送れませんが1週間で届きますし5000円以下と書いておけば関税にも捕まりません。2kg超えるものは帰国時に気合で持ってくるか諦めましょう。

買い物が不便

大型量販店みたいなのがないので、それぞれ買いに行く必要があります。日本みたいにイオンで何でも揃うぜ!みたいなことがないです。肉欲しければ肉屋に行って野菜が欲しければ八百屋に行きます。家電が欲しくてもビッグカメラみたいなのがないので、在庫調べて小さい店に行ったりしないといけないです。ただこれはヨーロッパとかも割と同じだと思います。

接客が雑

これも日本が異常シリーズだと思いますし他の国に行ったときにもよく感じていたことなのですが、接客が雑です。普通に話しかけてもスマホゲームしてて無視とかされます。レストランで声かけて明らかに目があったのに無視されることもあります。

特に酷いのはバスです。バス停で待っていても平気で無視します。上に書いたように遅延も酷いので30分待たされた挙げ句に無視されたこともあります。手を挙げて全力で乗りたいアピールしないと止まってくれません。外人に対する嫌がらせか?!と思いましたがイスラエル人も辛いらしいのでバス運転手が単に酷いみたいです。以前バス乗ってたらおじいちゃんが走ってきてドア叩いて開けてくれ!と叫んでいたのにガン無視する運転手も見ました。

色々と雑

接客だけに限らず基本大体全てが雑です。銀行でカード発行されたから支店に取りに来いと言われたから行ったらないと言われて、「でもあるって言われて来たんだけど?」「いやないもんはない」ってやり取りをして帰らされたことがあります。コールセンターにかけたらやっぱり支店にあるって言われて、仕方なくもう一度行ったら「だからないって言ってるでしょ」と言われて「は?!?!」ってなりました。最終的に支店の人がカード紛失していただけらしくめっちゃ探したら見つかったと後日連絡が来ました。銀行でカードなくすことある?!と衝撃を受けました。

他にも携帯の契約を自動更新することが出来ず(理由はIDのところで後述)3ヶ月単位で契約していたんですが、突然2ヶ月で使えなくなりました。連絡したら「2と3間違えてたわーガハハ」ってなって、いやネットから申し込んだのに手動で打ち込んでんの...?と衝撃を受けたりもしました。

他にも当初言われていた日程からビザの手続きが遅れに遅れまくって、家解約したのにビザが間に合わずホームレスになったりもしました。

仕方なく1ヶ月遅らせたのですがそれでもギリギリで、出国まで24時間を切ってもビザが手に入らずひたすら祈り続けたりもしました。

この手の衝撃エピソードは挙げるとキリがないです。

順番守らない

順番待っていても普通に割り込まれます。そのぐらいはまだいいのですが、番号を発行して待っていても割り込まれることがあります。郵便局では待っている人に対して番号が発行されます。モニターに番号が表示されたらカウンターに行く仕組みですが、自分の番だと思って行ったらサッと自分の前に他の人が入りました。さすがにいやいや自分の番だからって言ったのですがガン無視されました。驚いて譲ってしまったのですが、こういう時に強く言えるようにならないと生きていけないなと思います。

物言いがストレート

回りくどいのが嫌いみたいなのでかなりビシッと言います。お前のアイディアはダメだ、とか平気で言います。喧嘩してるのか...?みたいなミーティングもありますがネチネチ言うよりはストレートに言う方がスムーズで良いなと言う気もするので最近は特に気になってないです。

サウナがない

サウナがないです。もしかしたら現地の人に探してもらえば見つかるのかもしれませんが、自分で見つけられたサウナはゲイのやつでした。

年末年始休みがない

ユダヤ教の新年は9月末から10月頭(年によって違うとのこと)なので、12月末は平日です。時期が異なるだけで年末年始がないわけではないのですが、日本の年末年始の感じは好きだったので少し残念に感じます。そして同じチームで別の国の同僚達が12月中旬あたりから長期休暇を取る中働いていると切ない気持ちになります。

祝日が固まっている

こっちに来てから気づいたのですが日本は祝日天国でした。ほぼ毎月祝日があるという。イスラエルでは10月に大量の休みがあり、有給も繋げれば1ヶ月ほとんど休みみたいな感じになります。ただし、10月が終わるとそれ以降4月まで祝日が0です。トータルでの祝日も日本に比べたら少ないです。日本とやり取りしていると今週も3連休!みたいなことを凄く頻繁に言われているように感じて辛くなります。 www.arukikata.co.jp

何するにもIDが必要

これはイスラエルが悪いわけではないのですが、イスラエルに住む外人には関係ある話なので書いておきます。当たり前ですがイスラエル市民じゃないと国民番号がもらえません。そしてオンラインショッピングなどをしようとすると98%ぐらいの確率でIDを求められます。そのためネット上で買い物ができません。他にも税金や光熱費などの支払いでもIDが求められるせいでネット手続きができません。なので仕方なく近くの郵便局に2ヶ月に1回行って支払っています。これは結構ストレスなので気をつけたほうが良いです。

ラクション鳴らしがち

始めて中国や韓国に行った時にも驚いたことなので特に気にしてないのですが、自分がスクーター載ってる時に後ろの車からクラクション鳴らされると結構ビビるので辞めてほしいと思うことがあります。

まとめ

日本にもイスラエルにもどちらにも良いところ・大変なところがあります。

KubeCon + CloudNativeConにプロポーザル出すときに気をつけたこと

サイボウズさんの記事を読んで、自分も今回プロポーザル出したときに会社の人から貰ったアドバイスをまとめておこうと思いました。というのも、自分の席の隣の人が実際に今回のKubeCon Europe 2020でレビュワーだった人ですし、チームのボスはKubeConのChair経験者だったりするので、割と貴重な情報なのではないかと思っています。とはいえ何か特別なテクニックがあるわけではないです。

KubeConって何?とかは以下の記事を読んでもらえればと思います。 blog.cybozu.io

恐らくKubeConに限った話ではないですし指摘内容も普通の内容が多いと思いますが、一応次以降に自分で見返すこともありそうなので全部書いておきます。

プロポーザルに関するアドバイス

全部教えてもらったやつです。ただ自分なりに解釈した内容を書いてるので伝言ゲームで若干齟齬あるかもです。

タイトルは短く

あまりに説明的すぎるタイトルは避けたほうが良いようです。長すぎると敬遠されがちなので、Wordに書いて1行以内には納めたほうが良さそうです。恐らく50~80文字ぐらい。しかし一方で短すぎても何のセッションか分からないので、参加者が興味を持つぐらいの内容を1行でまとめる必要があり難しいです。

箇条書き

発表内容について長々と文章で書くよりは、箇条書きで要点をレビュワーの方に伝えるほうが良いようです。その箇条書きも5~10個とかだと見にくいので色々書きたい気持ちは抑えて2, 3個にしましょう。

デモ

デモがある発表の方が人気みたいです。もちろんデモがなくても良いのですが、もし出来そうなら積極的にやるべきでプロポーザル内にもその旨を書くべき、とのこと。実際うちのボスはほぼすべての発表でデモしていて、それが評判良いみたいです。

対象者

これも重要で、誰に向けての発表なのかはしっかり盛り込むほうが良いです。もし事前知識が必要だったりする場合は正直に書きましょう。

エコシステムへの影響

確か応募フォームの中にBenefits to the Ecosystemという欄があります。CloudNativeConなので、クラウドネイティブのエコシステムにどう影響があるのかを書く必要があります。これも重要で関連性が強かったり分かりやすい方が通りやすいそうです。

実用的な解決策

既存のCNCFプロジェクトにどういう問題がありこの発表でそれをどう解決するのか、という内容や、デフォルトだとこういう問題があるのでこのCNCFプロジェクトの利用をおすすめします、とかいう内容も書くと良さそうです。聞いてふーんで終わりの内容ではなく、実際にすぐ聴講者が行動出来るような内容を持ち帰ってもらえる発表ですよ、というのがポイントみたいです。

プロポーザル例

上のをまとめると以下のような構成です。

# タイトル
短くて興味を引くタイトル(80文字以内ぐらい)

# 発表内容
概要1(1~2行ぐらい)

- 要点1
- 要点2

概要2(1~2行ぐらい)
デモの内容

この発表の対象者、必要な事前知識

# Benefits to the Ecosystem
この発表がCNCFにおいて重要な理由(1~2行ぐらい)
CNCFプロジェクトとの関連性(1~2行ぐらい)
聴講者に持ち帰ってもらえる内容(1~2行ぐらい)

これがベストかどうかは分かりませんが、今回自分はボスの過去のプロポーザルを丸パクリして上の構成で出しました。

その他

発表実績

実はこの部分が今回の記事で一番書きたかったところで、こいつは英語でうまく発表できるのか?というのを見られるみたいです。もちろん応募内容が圧倒的に良ければそんなの関係なく通るのですが、当落線上にいる場合は実績が重要になってきます。自分の場合は何も実績の動画とか送らなかったので判断つかなくて困っていたらしいのですが、レビュワーの同僚が英語発表問題ないと言ってくれたらしく(実際には問題ありまくるけど)、それなら良いかということで通ったみたいです。そういう意味では自分はラッキーだったと言えます。もし何か実績が少しでもあるなら送っておいたほうが良いです。

実際KubeSecというKubeConと一緒に開催されるイベントに知人が応募していたのですが、レビュワーから彼の英語発表大丈夫?と聞かれました。大丈夫です!!!と答えた結果、採択されることになりました。もちろん大前提として応募内容が良かったからなのですが、やはり発表スキルは気にされるみたいです。

つまり大きいカンファレンスに一発目から行くよりは少し小さめのところで発表して実績を作り(可能ならYouTubeとかで録画が配信されるぐらいの規模)、そのURLを一緒に送ると採択率が上がるということです。知人だから通りやすいとかいうわけではなくて、判断がつかないとカンファレンスを成功させたいレビュワーとしても困るということです。

メンタル

そもそもカンファレンスで話したいと思ってる時点で圧倒的に他の人より前にいますし、上のような点に気をつければ問題なく通ると思います。さらに言えば通ると良いなというよりは通って当然ぐらいの気持ちで応募すると良いかもしれません。

正直自分は登壇自体も苦手で敬遠してるので経験が少ないですし、英語力もヤムチャぐらいしかないので話したいとは全く思ってませんでした。自分程度の実力で大きなカンファレンス行くのは無謀だと思ってます。ヤムチャが街に人造人間探しに行くようなもんです。仲間呼ぶ前に殺されます。ただうちのチームはフルタイムが6人いて、前回と今回だけでスピーカーが4人もいます。実質CTO直轄チームなのでCTOも入れてしまえば7人中5人です(1人諸事情で辞退しましたが)。つまり話してない方のほうが少ないぐらいです。なので、あまり乗り気ではなかったのですが何で出さないの?みたいな空気感もあり結局出しました。ダメ元で、というよりは通さないとダメだよな...みたいな気持ちだったのが今となっては良かったのかもなと思っています。

そんな感じで自分の中で当たり前のレベルが上がると自然と自信を持って書けるようになって良い結果に繋がるのかなと感じました。

まとめ

お願いだから誰も聞きに来ないで欲しい。

コミット前後でベンチマークが悪化していたらテストを落とすGoのCI用ツール

本当にただこれがやりたかっただけです。今でも既存のものがあるだろうと思っているのですが、誰も教えてくれなかったのでシュッと作りました。落ち込まないので今からでも教えてくれて良いです!

概要

上のツイートにある通りなのですが、Goだとベンチマークを計測するツールがデフォルトでgo testに同梱されているので、GitHubとかにコミットされたらそのコミットと一つ前のコミットでベンチマークのスコアを比較して、悪くなっていたら教えて欲しかっただけです。シェルスクリプトで数行で出来るようなレベルですし、ちょっとオプションつけたり表示をリッチにしても200行ぐらいで済みそうだったのでGoでツールを作りました。ブログ執筆時点だと260行でした。

f:id:knqyf263:20200114005936p:plain:w300

github.com

実際、あまりにも簡易的なツール過ぎてGoのコードよりインストールスクリプトのほうが行数が長く、GitHub上でShellScriptのリポジトリとして認識されてしまいました。テストを足してかさ増ししたりもしたのですが、最終的には.gitattributesを足してちょろまかしました。

使い方

基本的にはCI上で使うことを想定しています。内部でgit reset相当のことをしているので、ローカルで実行する場合は注意して下さい。 もしコードが消えても責任は取れないです。というか自分が開発中に間違って自分のリポジトリ上で実行してコードが消え去りました。内部でgo-gitを使っているのですが、こいつのresetはuntrackedなやつも消されるみたいです。まだgit addすらしてないから大丈夫だろうと油断していて完全にやられました。シンプルにコードを失いました。そもそもgo-gitのこの挙動がアレだと思うので直したい気持ちもあります。

とりあえず実行するならベンチマークのあるプロジェクトのディレクトリに行って以下のように打つだけです。これで勝手にHEADとHEAD{@1}のベンチマークを比較します。

$ cob ./...

メモリとかも計測したい場合は-benchmemつければよいです。使い方はgo testと同じです。go testのうちベンチマークに関係ありそうで自分が欲しかったオプションだけ取り込んでいます。-bench-benchmem-benchtimeはそのままgo testに渡されます。

$ cob -benchmem ./...

結果は以下のようになります。上のテーブルは単純にHEADとHEAD{@1}の値が並んでいます。下のテーブルはそれがどのぐらい変化したかを表示しています。赤は悪化で青は改善を示します。

f:id:knqyf263:20200113043030p:plain

デフォルトではベンチマークが20%以上悪化するとプログラムがエラーを返します。つまりCI上で実行するとテストが落ちます。ただ元々の値が小さい場合は変化が大きく出てしまうので、同じベンチマークを実行しても20%を超える場合があります。そういう場合は-threshold を変えたり -benchtime 10s など大きくして値が安定するようにすると良いです。

$ cob -benchtime 10s -threshold 0.5 ./...

ベンチマークの関数ごとに閾値を決められると良いかもなとは思っているのですが、-benchの正規表現指定とパッケージ指定とか工夫でなんとか出来る気がしたのでやめました。上に書いたように簡易的なツールなので機能は殆ど無いです。

$ cob -bench BenchAppend -threshold ./foo

上のような感じですね。BenchAppendという文字列を含むfooパッケージ内のベンチマークだけ実行されます。-benchgo testに渡してるだけなので、正規表現も使えます。

あと、パッケージが違えば同じベンチマークの関数名が定義できますが、それも対応してないです。同じ名前がある場合はうまく結果が表示されないのでパッケージ名を指定して2回実行して下さい。

$ cob ./foo
$ cob ./bar

オプションもあまりないです。

NAME:
   cob - Continuous Benchmark for Go Project

USAGE:
   cob [global options] command [command options] [arguments...]

COMMANDS:
   help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --only-degression  Show only benchmarks with worse score (default: false)
   --threshold value  The program fails if the benchmark gets worse than the threshold (default: 0.1)
   --bench value      Run only those benchmarks matching a regular expression. (default: ".")
   --benchmem         Print memory allocation statistics for benchmarks. (default: false)
   --benchtime value  Run enough iterations of each benchmark to take t, specified as a time.Duration (for example, -benchtime 1h30s). (default: "1s")
   --help, -h         show help (default: false)

結果をコミットIDと保存しておいて比較すれば2回実行しなくても済むかなと思ったのですが、CI環境だと起動される度に微妙に環境が違ったりしてそっちの要因でベンチマークのスコアが変わったら嫌だなと思って今のところやっていません。その辺り、何か良い知見をお持ちの方がいらっしゃれば助けてほしいです。

CI

CIで使う場合のサンプルを置いておきます。ここではGitHub Actionsだけ置いておきますが、他の例や実際の出力を見たい場合はcob-exampleを見て下さい。

name: Bench
on: [push, pull_request]
jobs:
  test:
    name: Bench
    runs-on: ubuntu-latest
    steps:

    - name: Set up Go 1.13
      uses: actions/setup-go@v1
      with:
        go-version: 1.13
      id: go

    - name: Check out code into the Go module directory
      uses: actions/checkout@v1

    - name: Install GolangCI-Lint
      run: curl -sfL https://raw.githubusercontent.com/knqyf263/cob/master/install.sh | sudo sh -s -- -b /usr/local/bin

    - name: Run Benchmark
      run: cob -benchmem ./...

まとめ

みんな黙ってるだけでやっぱりこういうツールあるんじゃないかと疑っています。でも自分の要件はこれぐらいなので、必要最小限という意味では自作して良かったかもしれません。自分の環境以外でちゃんと動くかも分かりません。もしこういうの欲しくて困っていた人はフィードバック頂ければもう少し真面目にメンテナンスします。

stretchr/testify/mockでTable Driven Testしやすいようにmockeryを拡張した

アドベントカレンダー用に書こうと思っていたのですが乗り遅れました。あとあんまり大衆向けの話でもないのでひっそりと公開しておきます。

良いやり方を調べても見つからない時は自分の思いつく最良の方法を公開すると誰か凄い人がやってきてより良いやり方を教えてくれたりするので、今回もそれを期待しています。

課題

stretchr/testifyにはテストするために使える便利なパッケージが複数含まれていますが、その中にmockがあります。
https://github.com/stretchr/testify

これを使うと指定した引数に対する戻り値を簡単に定義できます。例えば会社名入れたら会社情報を返してくれるstructのmockに対する引数と戻り値は以下のように書けます。

mockCompany.On("Info", "FooCompany").Return("101-0001", "東京都千代田区", "03-3000-0000", "2000")

上の場合だとinterfaceは以下のような感じです

type Company interface {
    Info(string) (string, string, string, int)
}

思いつきで作ったので、このInterfaceなんなんみたいなのは置いておいて下さい。

ちなみにmockはこれ以外にもCallで関数呼び出したりとか、色々な機能があるので普段テストでそれらを使う機会の方が多い人はここで記事を閉じてもらったほうが良さそうです。自分もCallTimesたまに使うのですが、多くのケースでは上のシンプルな使い方で十分な場合が多いです。なので、今回は上のmock.On().Return()の形に絞った話になります。

テスト用のstructを用意する

これをTable Driven Testで使おうとすると、テストケース内で上の引数・戻り値を定義したくなります。そしてその時に専用のstructがあると便利です。MockCompanyは先に作っておく必要がありますが、それはググればたくさん使い方出るので省略します。MockCompanyは作成済みということで進めます。

// mockが受け取る引数
type InfoArgs struct {
    CompanyName string
}

// mockが返す戻り値
type InfoReturns struct {
    Zip      string
    Address  string
    Phone    string
    Employee int
}

// 上の2つをまとめたstruct
type InfoExpectation struct {
    Args    InfoArgs
    Returns InfoReturns
}

こんな感じでstructを定義しておけば、テストケースを定義する時に綺麗に書けます。補完も効くしサクサク書けて気持ち良いです。意味的にも分かりやすいです(個人的には)。

testCases = []struct {
    name string
    info InfoExpectation
}{
    {
        name: "happy path",
        info: InfoExpectation{
            Args: InfoArgs{
                CompanyName: "FooCompany",
            },
            Returns: InfoReturns{
                Zip:      "101-0001",
                Address:  "東京都千代田区",
                Phone:    "03-3000-0000",
                Employee: 2000,
            },
        },
    },
}

あとはこれをfor文の中でOnとReturnに渡せばよいです。

for _, tc := range testCases {
    t.Run(tc.name, func(t *testing.T) {
        mockCompany := new(MockCompany)
        mockCompany.On("Info", tc.info.Args.CompanyName).Return(tc.info.Returns.Zip,
            tc.info.Returns.Address, tc.info.Returns.Phone, tc.info.Returns.Employee)
        ...

これで複数のテストケースでも対応できて便利なのですが、問題は上のstruct達をいちいち作るのがだるすぎるということです。導入が若干長くなりましたがこれが自分の課題でした。

Sliceを使ってみる

Onはinterfaceを渡せるので、以下のような方法も考えたりしました。

type InfoExpectation struct {
    Args    []interface{}
    Returns []interface{}
}

func TestCompany_Info() {
    testCases = []struct {
        name string
        info InfoExpectation
    }{
        {
            name: "happy path",
            info: InfoExpectation{
                Args:    []interface{}{"FooCompany"},
                Returns: []interface{}{"101-0001", "東京都千代田区", "03-3000-0000", 2000},
            },
        },
    }
    for _, tc := range testCases {
        t.Run(tc.name, func(t *testing.T) {
            mockCompany := new(MockCompany)
            mockCompany.On("Info", tc.info.Args...).Return(tc.info.Returns...)
        })
    }
}

[]interface{}で全部受け取れるようにしてOnとReturnに渡す方法です。試した時のコード消しちゃったので上ので動くかわかりませんがイメージが伝わればよいです。これを試してみて思ったのは、何番目が何の値とか覚えてられないです。例えば住所と電話番号逆にしてもすぐには気づけないですし、型も分からないので郵便番号ってstringだったっけ...?みたいになって辛いです。あとintやstringなどのプリミティブ型だけでなく別のstructを渡したい時も不便です。

mapを使ってみる

せめて名前ぐらいは知りたいということでmapにしてみたりもしました。

func TestCompany_Info() {
    testCases = []struct {
        name string
        info InfoExpectation
    }{
        {
            name: "happy path",
            info: InfoExpectation{
                Args: map[string]interface{}{
                    "CompanyName": "FooCompany",
                },
                Returns: map[string]interface{}{
                    "Zip":      "101-0001",
                    "Address":  "東京都千代田区",
                    "Phone":    "03-3000-0000",
                    "Employee": 2000,
                },
            },
        },
    }
    ...
}

ですが、これも結局keyがただの文字列なのでtypoとかすると終了します。補完も効かないので自分で名前を調べて打つ必要があって人類がやるべきことではないなと感じました。

などと考えると一番最初のように専用のstructがある方が補完も出来るし名前付いてるから分かりやすいし一番良いなーとなりました。もし他に良い方法をご存じの方は可及的速やかに教えていただきたいです。

stretchr/testify は有名なツールだし他のOSSで既に同じことやってるだろうと思って調べたのですが、意外とみんなTable Driven Testしてませんでした。特にmockとか使うようなテストは割と手続き的に書いてました。自分が見つけられなかっただけで良い方法で解決してるOSSがあればどなたか教えて下さい。

Goの流儀に則るならやはりコード生成だろう、ということでstructを自動生成することにしました。

ツール

上のようなstructを作ってくれるツールを探したのですが見つけられませんでした。なので作りました。既存のvektra/mockeryというinterfaceを見つけてMockを作ってくれるツールがあったので、それをforkして作りました。
https://github.com/knqyf263/mockery

upstreamにパッチ送らないのかという話がありますが、残念ながらメンテナンスが止まっているようです。
https://github.com/vektra/mockery/issues/237

ソースコードを読んだのですが難しいことはしていなかったですし、自分で使う範囲なら十分メンテナンスしていけそうだったのでforkすることにしました。特に他の人に使ってもらおうと思って作っておらず、自分の使う範囲で動くように拡張しています。なのでオプション次第では動かないかもしれません。ただupstrean自体が既にバグあったりしてfork内で直したりもしました。

2時間ぐらいで作ったので全く動作保証はできないです。追加したかった機能とは別のupstreamのバグの調査に時間かかったのでもう満足してしまいました。

では実際に使ってみます。オプションの意味はヘルプを見てもらえればと思いますが、以下のように打つとサブディレクトリも含めinterfaceを探してきて同じパッケージ内にMockを作ります。

$ mockery -all -inpkg -case=snake

本家mockeryは以下のようなMockを生成します。

// MockCompany is an autogenerated mock type for the Company type
type MockCompany struct {
    mock.Mock
}

// Info provides a mock function with given fields: _a0
func (_m *MockCompany) Info(_a0 string) (string, string, string, int) {
    ret := _m.Called(_a0)
    ...
}

自分が拡張した方のmockeryを使うと、上のMockに加えてテストで使うときのためのstruct達が生成されます。また、interfaceの引数や戻り値に名前つけておかないと_a0とかになっちゃうので、付けておくのがおすすめです。じゃないと実質名前付きじゃなくなっちゃってこの拡張があんまり意味なくなると思います。

interfaceの引数と戻り値に名前つけると以下のようになります。

type Company interface {
    Info(name string) (zip, address, phone, string, employee int)
}

以下のようなstructになります。

type InfoArgs struct {
    Name         string
    NameAnything bool
}

type InfoReturns struct {
    Zip      string
    Address  string
    Phone    string
    Employee int
}

type InfoExpectation struct {
    Args    InfoArgs
    Returns InfoReturns
}

Name だけじゃなくて NameAnything があるのは、Mockしたいけど引数は何でも良い場合とかがあるので、その場合に NameAnything をtrueにしておくとMockには mock.Anything を渡してくれます。 mock.Anything がただのstringなので、 Employee: mock.Anything みたいに渡すことができず苦肉の策でこうしています。これに関しては何か他に良いやり方ありそう。

そして同時にApplyする側のメソッドも生成します。

func (_m *MockCompany) ApplyInfoExpectation(e InfoExpectation) {
    var args []interface{}
    if e.Args.NameAnything {
        args = append(args, mock.Anything)
    } else {
        args = append(args, e.Args.Name)
    }
    _m.On("Info", args...).Return(e.Returns.Zip, e.Returns.Address, e.Returns.Phone, e.Returns.Employee)
}

テストから呼び出す時は、これを単に呼び出せばよいです。OnとかReturnとかテストに書かなくても良いのですっきりします。

for _, tc := range testCases {
    t.Run(tc.name, func(t *testing.T) {
        mockCompany := new(MockCompany)
        mockCompany.ApplyInfoExpectation(tc.info)
        ...

簡単に引数・戻り値を定義できるしApplyも簡単だし最高ですね(個人の感想)。ちなみに自分は全然違う命名をしてたのですが、英語の得意な同僚が上のような命名をしているのを見てそっと変えました。

定義の部分で文字数が少し増えてしまうのが気にはなっているものの、補完されるし書く分にはあまり困らないです。どちらかと言うと読む時に文字が詰まって見えることがあるのでそれは何とかしたい気持ちがあります。ただきちんと説明されているという意味では初めて見る時には今のほうが良いかもしれないし悩みどころです。

余談

vektra/mockeryはメンテナンスが止まっているため、stretchr/testifyからgomockに移行するという人も結構いるみたいです。ただ個人的にはtestify/mockの方が使いやすくて好きなので現時点ではこっちで良いかなと思っています。数カ月後にどうなるかはわかりませんそもそも大体必要な機能は揃っているのでこれからどんどん破壊的変更が入るかと言うとそうではないような気がしますし、Kubernetesなども使っているのでとりあえずは大丈夫かなと楽観視しています。 https://github.com/kubernetes/kubernetes/blob/7f23a743e8c23ac6489340bbb34fa6f1d392db9d/pkg/kubelet/eviction/mock_threshold_notifier_test.go#L20

自分はあまりMock自体が好きじゃないので本当に必要になるまでは使わないのですが、最近は大人の事情で必要になってしまったので使っています。

まとめ

Mockに与える引数と戻り値を簡単に定義できるstructと適用するためのメソッドを自動生成できるように既存ツールを拡張しました。このツールを使ってほしいと言うよりは、みんなどうしてるんだろう、という議論の種になれば良いなという気持ちです。実は同じ問題を抱えてた人が多かったりしたら真面目にmockeryの拡張部分のテスト書いたりして整備しようと思います。

あと今回の件もそうなのですが、入門記事みたいなのは結構出てくるけどプロダクトで実際にどうやって使うのみたいなので困ることが結構多い気がします。GitHubを漁って実際の使われ方を探すものの意外と出てこなかったりするので、そういうのに使ってる時間が結構長くて辛いです。