たんぶろぐ

すぐ忘れる

Datadog を Kubernetes 上で運用するときのカーディナリティ設定

先月あたりからこんな事象に悩まされていた。

f:id:ZuiUrs:20200707192926p:plain
before

この画像は、Kubernetes 上の Deployment に対して一定の負荷 (50 req/s) をかけながら、レプリカ数を変化させたときのグラフである。

Deployment がどのくらいの負荷を受けているのかを見たかったのだが、グラフ化したときに意図した通りにならずモヤモヤしていた。この実験は一定負荷なのでレプリカ数を変えても Deployment 全体で受けている負荷は変わらないはず。それなのにレプリカ数を増やすとなぜか負荷が減っているように表示されてしまう。どうして。

TL;DR

Datadog Agent の環境変数 DD_CHECKS_TAG_CARDINALITYorchestrator を設定すれば解決する。

続き

これを最初見たとき、Aggregator 設定をミスっているのかと疑ったが、ちゃんと sum を指定していた。グラフを作るときはタグでメトリクスを絞ると思うが、これによってヒットしたメトリクスの合計値が表示されるようになる。ちなみに avg を指定していると平均値となってしまうため、レプリカ数が増えるに従って値は減少していく。

次に Rollup 設定を疑った。結局これは関係なかったのだが一応自分のために書いておくと、Rollup はデータポイントを減らす目的で適用されるメトリクスのまとめ方式の仕組みなので関係ない (デフォルトの avg で問題ない)。Datadog が送ってくれるデータポイントは最大 350 個なので、実際は大量にあるデータポイントがこの設定によって 350 個以下に圧縮される。そのときの計算方式の設定である。これにより長期間のメトリクスを Datadog Dashboard や Query API で取得した際にデータ量が爆発することを防いでいる。わかりやすくいうと Rollup は時間 (ヨコ方向) のまとめ方式であり、Aggregator は各ホストのメトリクス (タテ方向) のまとめ方式である。

ここらへんでサポートに聞いてみることにした。このときはまだ今ほど理解がクリアになっていなかったので話が何度か食い違ったが、どうやらカーディナリティの設定を上げる必要があるらしい。

カーディナリティを上げるとメトリクスのタグ情報が増える。これは Datadog Agent の環境変数 DD_CHECKS_TAG_CARDINALITY を介して設定することができ、低い方から low, orchestrator, high が値としてある。デフォルトは low であり、この場合はホストのタグ情報と Kubernetes Integration のタグしか付与されない。これを orchestrator にすることで pod_name というタグが付くようになる。high にするとさらに下層の Docker コンテナの名前や ID なども付与されるが、そこまで必要になることはあまりないだろう。ちなみにこれは公式の Kubernetes Installation マニュアルに載っていないので注意が必要である。

では最後になぜカーディナリティの設定が必要なのかについてまとめる。これはメトリクスの扱いの仕様が関係している。Datadog だとタグでメトリクスの一意性を判断しているため、同一のタグを持つメトリクスは同じものと認識される。例えばノード数 3 のクラスタ上にレプリカ数 6 の Deployment があったとする。このときカーディナリティが low だと、メトリクスはホストレベルでしか一意識別性を持たないため 3 種類として認識される (6 つのメトリクスは送られているが、おそらく同一ホスト上のコンテナは同じメトリクスと判断されて 1 つを残して他は無視される)。つまり sum Aggregator を使っても 3 つのメトリクスしか合計されない。これにより、レプリカ数が増えると本来一定のはずの合計値メトリクスが減っているように見えてしまう。

その後、カーディナリティの設定をして同一の実験を試してみた。意図したとおりに表示されている。良かった。

f:id:ZuiUrs:20200707193014p:plain
after

おまけ

Kubernetes クラスタの一意識別性について。

自分の職場は毎日数個の Kubernetes クラスタが作られは消されるような環境なので、Datadog に登録されているクラスタもなかなか多い。そこでメトリクスを絞り込む際に、他のクラスタの情報が混ざらないように一意識別するためのタグを探していた。

調べてみると Kubernetes 自体はクラスタの ID 情報は持たないが、その代わりとして kube-system Namespace の UID が使えるらしいということがわかった。とりあえず今はこれで満足している。

CloudNative Days Tokyo 2019 2 日目参加レポート

CloudNative Days Tokyo 2019 2 日目に参加してきたのでそのレポートです。仕事の都合で午後からの参加となったので、そこだけ書いています。

ちなみに 1 日目のレポートはこちら。

zuiurs.hatenablog.com

Session

セッションまとめ。

SODA - The Open Autonomous Data Platform For Cloud Native (OpenSDS)

OpenSDS の中の人の合同セッション。SODA プロジェクトと呼ばれる、ストレージサイドとそのストレージを利用するコンテナ・VM サイドの間がごちゃごちゃしてきてるから統一的に開発しようぜという取り組みの話。

オンプレ・パブリッククラウドに関わらずストレージが実際に提供されるまでには、ストレージドライバからデータの圧縮、暗号化、利用サイドのプラグインなど多くの開発が必要でその工数を軽減するために SODA が生まれたと言っていました。もともと OpenSDS はコントロールプレーン (エコシステム) の管理だけをしていたようなのですが、このような経緯でデータプレーン (ストレージ) も管理してくれるようになったそうです。こうしたインターフェースが定義されることによって抽象化されるので、ベンダーロックインも無くなるし開発も楽になるし良さそうですね。あと移行が楽そうですね。昨日の Airbnb の話に通じるものがある気がします。

デモでは OpenSDS のダッシュボードの紹介と、実際に osdsctl を叩いて Ceph からボリュームを作成したりなどしていました。そしてここで作ったボリュームを OpenStack の Cinder や Kubernetes の PVC から利用する例がありました。当然どちらも Plugin が必要ですが良さげでした。

Cluster API で簡単 Kubernetes on OpenStack

NEC の方のセッション。レベル感は Cluster API の入門 +α くらいでしたが、個人的な認識では「クラスタ作ってくれるやつ」程度だったので丁度良かったです。

Cluster APIsig-cluster-lifecycle で進められているもので、Kubernetes から宣言的に Kubernetesクラスタを作ろうという取り組みです。クラスタ (ノード) を作るというからには当然 CloudProvider がいるわけで、今回は OpenStack を使った話でした。CloudProvider 実装は結構多くのクラウドをサポートしているようでしたが、特に VMware が頑張っているらしく vSphereAWS の開発がとても活発だそうです。次点で RedHatBaremetal だそうですがこちらは Kubernetes SIG 傘下にはまだ入っていないようですね。その次に OpenStack あたりが来るらしいです。vSphere, AWS の開発が活発すぎてそれらの動向も追わないといけないので大変そうでした。

使い方的には clusterctl コマンドを使用して Create するだけです。背後の処理の流れとしては、対象のクラスタを作成する前に、まず Cluster API 用の Custom Controller がデプロイされた Bootstrap クラスタが立ち上がります (kind を使うのが良さそうでした)。次にそのクラスタが CloudProvider に対してリクエストを送って仮想マシンなり何なりを払い出してもらい、対象のクラスタkubeadm で構築します。構築が終わると Bootstrap クラスタコンポーネント群は対象のクラスタに移行され、kubeconfig だけを残して消滅するという流れでした。OpenStack CloudProvider は仮想ネットワークや Security Group などの作成処理は行わないので別途作っておく必要があるようでそこは面倒そうでした。ここも自動化しよう、といった趣旨の議論は生まれるらしいのですが大抵放って置かれて自然消滅しているそうです (笑)。

デモでは実際にクラスタを作成してスケールイン・アウトする例を見せてくれました。クラスタKubernetes の Resource として管理されるので、MachineSet (ReplicaSet 的なもの) のノード数を増減させることによってそれを実現できていました。スケールインするのを見た感じ OpenStack のノードが消えてから Kubernetes の方も消えるという感じだったので、上で動いてる Pod とかはちゃんと Drain されるのかな?という疑問が残っています (メモってたのに質問し忘れた...)。ちなみに MachineDeployment を利用したイメージのローリングアップデートはスピーカーの方もうまくいったことがないようです (笑)。

Cluster API 自体は個人的にとても好きになりましたが、成熟度はそこまで高くなさそうなので本番導入されるのはかなり先になりそうだなーと感じました。

Kubernetes に audit ログを求めるのは間違っているだろうか

CyberAgent の方のセッション。ログは Pod とかコンポーネントのログだけじゃないんだぜ、audit ログもあるんだぜという話。

kube-apiserver は audit の機能を持っているようでオプションから設定できるようでした。話は大きく 2 つに分かれていて、ログの出力ポリシーと出力媒体の話をしていました。まず audit ログは、どのリソースに対して (WHAT)、いつ (WHEN)、誰が (WHO)、どこから (WHERE)、何が (WHAT) 行われたのかという情報が出力されます。こういったログは全部出すとキリがないのでポリシーを決めて出力を絞ろうというわけです。ローテートの機能もあるようなので良さそうですね。また、audit ログの出力媒体はファイルにしたり Webhook にしたりすることができます。Webhook の方は Dynamic に送信先を変える仕組みもあるそうなので柔軟性はそっちの方がありそうですね。あとこっちの方が CloudNative 感があって良いなと思いました。ここらへんの話は資料が公開されているのでそちらを見たほうが正確で早いです。

ポリシーは出力するタイミング (Audit Stage) を決められるらしく、リクエストを受け付けたときや、レスポンスを返すときなどを指定できるようです。リクエスト受付時に Header だけ返して、本当の処理が終わったタイミングで初めて Body を返すような API もあるようなので、そこはちゃんと認識して出力タイミングを指定しないといけなさそうですね。(関係ないですが Netfilter のログデバッグで苦しんでいたときのことを思い出しました。)

RBAC を audit ログから自動で生成するものもあるようで便利だなと思いました。

資料上がってますね。

speakerdeck.com

How cgroup-v2 and PSI impacts CloudNative?

GMO ペパボの方のセッション。最終セッションでした。PSI という新しめの仕組みが Linux Kernel 4.20 に導入されているようで、それと cgroup のお話です。

序盤は cgroup v1 の基礎で、cgroupfs の操作や各 Subsystem に関する説明がありました。ここらへんは学生の頃 cgroup v1/v2 の調査をしてたり、v1 の memory/cpuset subsystem の拡張を行っていたことがあったので馴染み深い話でした。といっても他の Subsystem はそんなに触っていないので、pids subsystem で Fork 爆弾の対策ができるという話など、そういう使い方ができるのかといった面白い気づきもありました。また、/proc/self/cgroup でプログラムがどの環境で動いているのか判定できるという話も面白かったです。Chef の ohai はこの中に Docker 系の cgroup が入っているか確認して環境を判定しているそうです (コード)。他にも歴史の話や cgroup v2 の基礎の説明がありました。

その後 PSI のデモがありました。PSI は前述の通り Linux Kernel 4.20 で導入された機能であり、それを cgroup v2 の中から利用するという内容でした。ちなみに意外にも PSI は Facebook が開発したようです。PSI 自体は Subsystem ではなく、cgroup のツリー内に xxx.pressure というファイルが追加されて、そのファイルから所属する task (プロセス) の負荷状況を知ることができるというものでした。

最後に cgroup v2 の対応状況の話がありましたが、runc はまだ対応してないようですね。

まとめ

この 2 日間で新しいものを触りたい欲がとても高まりました。今はとりあえず Knative をやりたいですね。

運営の方々、ありがとうございました。

CloudNative Days Tokyo 2019 1 日目参加レポート

CloudNative Days Tokyo 2019 1 日目に参加してきたのでそのレポートです。メモを文章化してリンクを貼るだけですがお許しください。資料が公開前で内容を照らし合わせていないので間違った記述があるかもしれません。

Keynote

朝は Keynote から始まりました。

Opening

オープニングは CloudNative とは何なのかという話から始まりました。定義の話から、こういうことをすれば CloudNative な開発といえるぞ、的な指標である Cloud Native Trail Map の紹介がありました。もう 1 年近く CloudNative 界隈にいるのですが、この Map は CloudNative を段階的に導入するのに参考にすると良さそうだなと思いました。

参加者アンケートにも触れていて、一番印象的だったのは (話でも出ていましたが) Kubernetes を本番導入している人が半数を超えていることでした。回答者の所属会社の内訳とかも知りたかったですね。本番導入していると答えた人の多くは Web 系企業かと思っていますがどうなんでしょう。参加者は 1,600 人 (回答者は 1,300 って書いてあったかな?記憶が曖昧) なので結構な人数ですね。

また、Stackalytics の統計にも触れていて、最近は OpenStack に対する 中国企業のコミットの勢いがすごいという話をしていました。先月 KubeCon China に参加したのですが、OpenStack に限らず中国だけで全部できちゃうんじゃないか、的な空気感がありました。CNCF 関連のコミットに関してはやはり Google がトップで 1/3 を占めておりましたが、個人的に驚いたのは同じように 1/3 が野良のコミットであるということでした。野良といっても企業の Organization に参加していないとかそういう分類だと思いますが数の暴力ってすごいなーと感じました。

ちなみに、Session と同時に OpenStack Upstream Training と Kubernetes Upstream Training も開催されるようでした。私は申込みをしていなかったので外からチラ見しましたが超良さそうな議論をしてました。次回あれば参加したいですね。こちらは後日資料が共有されるそうです。

? (Linux Foundation)

このパートは急遽話してもらったとのことだったのでタイムテーブルにタイトルが見当たりませんでした。

こちらは CNCF プロジェクトの話が主でした。個人的に Landscape に載っているやつは全部 CNCF プロジェクト のものだと勘違いしていたのでこの話が聞けてよかったです (笑)。プロジェクト配下のやつは枠で囲われてる 40 個くらいだけですね。 また、Apple が 6 月に CNCF のメンバー入りをしたそうでこの話も出ていました。Apple にそういうイメージはあまりなかったので意外ですね。

CNCF の Certification の話もしていました。現在 CKA の申し込みが 8,300、CKAD の申込みが 2,800 もあるそうです。申し込みの合計数なので全員がパスしているというわけではないです。CKAD は 2 月に取得したのが CKAD-1900-0443-0100 だったのですが、今はどのくらいの合格者になっているんですかね?

KubeCon + CNCon も参加者がめっちゃ増えているということも話してました。チケットすぐ売り切れるんだよなあ。あとホテルつらそう。

Collaboration Without Boundaries (OpenStack Foundation)

OpenStack Foundation の歴史を話してくれました。最初のグローバルカンファレンスが 2011, 2012 年あたりで、その時から NTT 来ててすげぇと話していた印象が強いです。

OpenStack を利用してる会社紹介では GMO が Ironic 使ってることとか話してましたね。どのサービスだろう。全部かな?

Performing Infrastructure Migrations at Scale (Airbnb)

Tech Debt (技術的負債) をどう解消して新システムへ移行していくかという話です。Tech Debt が溜まっていくと Efficiency が落ちていくので、それを解消 (回復) させるために新システムへ移行をします。移行するといっても全てを一気に移行することは当然できないので、依存関係を確認しながら粒度を細かくしていきます。そして簡単なものから徐々に移行していくわけですが、その際多くの場合は新旧システムが両方とも稼働することになります。そういう Mix System はまた Tech Debt を生むので同様につらみが生まれます。わかる。

そんなこんなで移行にあたって、Validation フェーズ (インフラコンポーネントの独立性の検証など)、Stress フェーズ (名称メモり忘れた。Low Latency/High Throughput でシステムに負荷をかけて変なこと起きないか見たりなど) を経てきたらしいです。現段階は、移行に時間がかからないようにサービスの設定を抽象化するようなレイヤを用意して、簡単に切り替えられるようにするフェーズにいる、まだできてないけどな、と話してました。その後も移行プロジェクト (?) のリーダーとの同意を取ったりする最終フェーズがあるらしいです。スライドの最後にめっちゃ良さそうなまとめが載っていたので、公開されたら見直したいですね。

ちなみに私は Airbnb を「エアーブンブ」と読んでました。正しくは「エアビーアンドビー」なんですね。

The 10 new rules of open source infrastructure (Canonical)

ここから Airbnb で集中力を持っていかれてちゃんと聞いてなかった気がします。「Upgrade をして Backport はするな」という言葉は心に残っています。新機能を使用したいなら Backport なんかせずにちゃんと Upgrade してね、そうしないと他の会社とは外れた手作りのインフラになってしまって負債になっちゃうからね、みたいな話だったと思います。確かにそういったミドルウェアに手を加えるのは極力やりたくないですね。(まあ Upgrade も大変ですけどね...)

また、インフラの Transition は必ず来るから Kubernetes で満足しないで次のやつにも身構えとけよ、というお話でした。

あと、途中で一瞬出てきた DeNA が Livepatch を使っているという話は結構気になりましたね。瞬断があるとは聞いたことがありますが、どのくらいのワークロードのマシンまでなら Livepatch できるのか知りたいです。

Demand Less Choices! (IBM)

Knative の話です。1 コマンドで Autoscale するアプリケーションがデプロイされるのを見て Knative をやりたい気持ちが高まりました。前に触ったときにアプリケーションを放置してると Pod が 0 になって久しぶりのリクエストに時間がかかるみたいなことがあったのですが、あれって結局設定とかで制御できるんですかね?次は時間を使ってじっくり触ってみたいですね。

Session

セッションのメモです。

Kubernetes クラスタのポータビリティを保つための 8 原則

Wantedly の方のセッション。ランチセッションだったのでマイセンのカツサンドを食べながら聞きました。内容はタイトル通り。Wantedly は古くから Kubernetes を使っているようで、古いクラスタの etcd のメジャーバージョンアップデートをしようとしたらしいのですが、リスクが大きいと判断してクラスタを作り直すことにしたそうです。そのときの運用で直面した問題からこの原則が生み出されたようです。

8 原則のうち 5 つは The Twelve-Factor App のいくつかをベースにしており、新しい原則として非名前管理、バックアップ、重複欠損管理の 3 つを挙げていました。「非名前管理」は Kubernetes クラスタが用意してくれる DNS レコードに意味を持たせず、label に依存したり、CNAME で抽象化させたりする、というものです。それを強制させるためにわざとクラスタ名に日付など依存できないような文字列を入れているのは賢いなと思いました。「バックアップ」は移行後のアプリケーションのデプロイを簡単にさせるために heptio/velero (Heptio Ark から名前変わったんですね) でリソースのバックアップを取る、というものです。これはデプロイを実際に行うアプリケーションエンジニアへの配慮ですね。「重複欠損管理」は移行時のアプリケーションの扱いについて、重複して起動して良いものなのか・ダメなもの (つまり欠損を許容しないといけない) なのかどちらを守るかのポリシーを決める、というものです。これについては Multi-Cluster Strategy というものを定義して at-least-one ならそのリソースを Create してから Delete する (重複タイミングが存在する) ようにして、at-most-one ならその逆で Delete してから Create する (欠損タイミングが存在する) ようにして、このように移行時の扱いを決めているようです。このパラメータは label とか annotation で定義してるのかな?とにかくこういう移行ポリシーを決めてるのは良いなと思いました。

The Twelve-Factor App をベースにしている部分もインフラにフォーカスして説明されていたのでとても飲み込みやすく、共感する部分も多かったです。アプリケーションエンジニア側とインフラエンジニア側の責任の区別 (?) みたいなのがしっかりされていて動きやすそうだなと感じました。こちらはもう資料が上がっていますね。

Kubernetes クラスタの自動管理システムのつくりかた

Cybozu の方のセッション。Neco プロジェクトにおける CKE (Cybozu Container Engine)アーキテクチャの話です。もともと Rancher を使おうとしていたらしいのですが、コンテナランタイムに containerd がどうしても使いたくて CKE を自作するに至ったようです。

アーキテクチャ的には中央集権となる CKE Manager 的なクラスタが 1 台いて、そいつが Kubernetes Master/Node をプロビジョニングするというものでした。Manager となるクラスタが設定を Declarative に管理しているので Auto Repair 機能や Node の入れ替えとかがとてもしやすそうだと感じました。またそのクラスタで Vault を動かしており、そこで証明書の発行や Secret の暗号化を行っているようでした。以前 Kubernetes クラスタ (Master HA 構成) で Secret の暗号化を oracle/kubernetes-vault-kms-plugin でやったことがあるのですが、同クラスタ上で Vault や Consul のクラスタを組んだりと面倒だったので、中央集権 Vault がいるとかなりやりやすそうですね。

あと、Master HA 構成時の kube-apiserver の前段 LB が信頼性担保などの面で用意できなかったようで、そこは rivers という自作のリバースプロキシ (川かな?と思ったけどダジャレで笑った) を用意したとのことでした。それを Kubernetes Node に展開して kubelet のリクエストをハンドリングすることで対処しているようです。記憶があいまいですが、kubelet が etcd へのリクエストに失敗したときに他の etcd ノードに聞きに行ってくれない問題の workaround としても機能しているそうです。

CKE のソースは公開されている ので時間あるときに読んでみたいですね。OS のインストールどうしてるのかとか、外部向けの type Loadbalancer 作りたいときにどうするのかとか色々気になります。

Kubernetes 拡張を利用した自作 Autoscaler で実現するストレスフリーな運用の世界/adtech studio における CRD 〜抽象化した GPUaaS による段階移行計画 & AKE Ingress v2〜

CyberAgent の方のセッション。20 分 / 20 分の 2 人のセッションでした。

自作 Autoscaler の方は、運用しているアプリケーションが Cloud Pub/Sub の Subscriber (Kubernetes Pod) とそれからのリクエストを処理する Bigtable の 2 箇所にボトルネックがあってそれをいい感じにオートスケールさせようというものでした。Bigtable の負荷状況は Stackdriver Monitoring から取得しており、スパイク判定はめっちゃいい感じに調整された (ウィンドウサイズなど) 移動平均を用いているようでした。オートスケールの管理は CRD + Custom Controller でやっているとのことでしたが、その Custom Controller に kubebuilder とかを使わないでフルスクラッチで実装したというのが驚きでした。。。

GPUaaS の方は、ML 系のエンジニアのために GPU リソースを管理できる CRD + Custom Controller を作ったという話でした。普通に Deployment とかでも実装できるようですが、キャッシュ機能などをつけるとなると Custom Controller じゃないと実現できないとのことでした。nvidia-docker を用いて GPU のリソースを分割して提供しているそうです。Datadog のダッシュボードも映してくれたのですが、ちゃんと誰がどのくらい使ったかが表示されていて良さそうでした。現段階では ChatOps のレベルまで落とし込んでいてこれから更に使いやすく調整をするようでした。ML 側のエンジニアの温度感はあまりわかりませんが、Kubernetes があまり流行っていない領域だと思うので頑張って布教してほしいですね。

こんな感じでこのセッションは CRD がメインのセッションでした。ちなみにセッションの最後にブースで Kubernetes キーキャップを配っているというアナウンスがあってブースの通路が通れないくらい激混みになっていました (笑)。

GPUaaS の方は資料上がってます。

Operator でどう変わる?これからのデータベース運用

こちらも CyberAgent の方のセッション。Operator 入門者向けの内容だったので、Operator って何?CRD とか Custom Controller って何?という人は資料に目を通しておくと良いです。説明はかなり丁寧でわかりやすかったです。

OperatorHub.io という Operator まとめサイト的なものがあるというのを知ることができたのは良かったです。Awesome Operators のちゃんとした版って感じですね (失礼)。

資料上がってますね。

OCIv2?!軽量高速なイケてる次世代イメージ仕様の最新動向を抑えよう!

NTT の方のセッション。OCIv2 (正式な名称ではないらしい) が策定中のようで、そこで議論されている今後策定されるかもしれない内容についての話。

OCI はコンテナに関する標準化をしている団体ですが、今 3 つの標準化プロジェクト、image-specruntime-specdistribution-spec (これは OCI 公式にリンクがなかったんだけどただの見落としだろうか?) があります。distribution-spec だけイメージが湧きづらいと思いますが、これはコンテナレジストリなどが対象になったプロジェクトです。

メインテーマは image-spec ということで最初にコンテナイメージの tarball 内の構造について説明があり、その後デモがありました。構造は Markle Tree (つまりハッシュツリー) になっており、内部のメタデータ/index.json で管理されています。その json ファイルに manifest というイメージの構造を表す Key/Value があり、そこからベースイメージやその各レイヤーイメージを追うことができます。デモではその情報をもとに Container Registry の APIcurl で叩いていました。Container Registry は主に 3 つのデータを必要としていて、そのコンテナイメージが持つレイヤーイメージの tarball (中に root file system が入ってる) と、Container を実行する際に適用する実行時情報 (これの実体は確認してないので暇な時に見たい) と、その 2 つを紐付けるための manifest (どのファイルを指してたっけな...) を渡すことによって初めて docker push と同様のことが実現できます。逆にその送り先の URL から manifest を GET することによって、どのイメージがどの実行時情報に紐付いているのかという情報が得られます。このようにして docker pull 相当のことができます。その後は runc run コマンドを直接たたいてコンテナを実行するところまでやってもらいました。とても面白そうだったのでこれ書き終えたら手元で試そうと思います。

...と書きましたがデモは前座で、本題はコンテナイメージのレイヤーの重複排除が効きづらいから新しい OCIv2 を策定中だぞという話でした。実際に有名なイメージのレイヤーがどのくらい共通して使われているかという統計を示されていたのですが、レイヤーの 8 割くらいはユニークなレイヤーでした。つらそう。重複排除は当然 1-bit でも異なれば別のものとみなします。ですがそれはレイヤーレベルの話なので、もっとファイルレベル、ブロックレベルなどに落とし込んで重複排除が効くようにしようという話が進んでいるそうです。また、tar 自体にも問題があり、実装依存で index がずれたりするので重複排除が効かなくなるケースや、仕組み上うえから順に取り出す (シークができない) ので並列処理ができないことなどがあり、もしかしたら将来的に違うツールを使うことになるのかもしれませんね。

余談で Lazypull と呼ばれる、ファイルにアクセスがあった時点でネットワーク越しにイメージレイヤを取ってくるドラフトの話や、distribution-spec の領域で OCI Artifact Registry と呼ばれる Docker、Kubernetes、Helm などのリポジトリを統合して使えるようにしようという動きも進められているそうです。これに関してはすでに oras といった実装があるそうな。

とても Deep で面白いセッションでした。

失敗しない! Kubernetes 向けストレージ選び 5 つのポイント

Z Lab の方のセッション。Kubernetes でストレージを使うときにどういうことを考慮して選択しないといけないのかという話。序盤に話してた MySQL Operator 的なものを自作していた話が強烈でしたが、それについての詳細は著書のKubernetes 実践入門に載ってるそうなので買いましょう (私も読みました)。あと、ここも CybozuCyberAgent と同じように Kubernetese as a Service を作っており、タイプとしては Cybozu の CKE と同じ中央集権タイプでした。管理側の Kubernetes が OpenStack を叩いてデプロイしている感じです。Kubernetes クラスタを CRD で管理しているのが先進的だなと思いました。

本題のストレージの考慮ポイントは下記にまとめます。

  • Rolling Update
    • Rolling Update に限らずストレージを要求する Pod がたくさん立つ状況が Kubernetes では存在するので、そのボリュームの Attach/Detach リクエストが大量に飛んできても耐えられるものを選択する。Kubernetes は RESTful API でストレージをリクエストするのでボリューム払い出す側がそのリクエストをさばけるようでないといけない。複数 Node でマルチパスが張れるならなお良い。
  • Locking
    • ブロックストレージへのアクセスには SCSi を使うのでデータの破壊に注意する。SCSi はロックの機構を持たないので ReadWriteMany は基本的に使わないようにする。ストレージにアクセスするアプリケーションがロックの機構を積んでない限り使わないようにしたほうが良さそう。
  • Security
    • 複数クラスタで同一ストレージにアクセスするときの制御は、クラスタ単体だとどうにもならないのでストレージ側でマルチテナント機能を使って Isolation してあげる。
  • Quota
    • Kubernetes の Quota は Napespace 単位の管理しかしないので、複数クラスタのときはストレージ側の機能も使って合わせ技でいい感じにする。
  • Value
    • データの価値を考える。Storage Class に Gold (アプライアンス製品) / Silver (Ceph とかの SDS) / Bronze (ROOK とかの Container-Native Storage) みたいなランク付けをして、価値に応じて置き場所を決定する。保険と同じだから消えたらやばいやつはちゃんと金払って良いところに置いてやれ、という話をしていてなるほどとなった。この 3 つの比較をする表が良かったので公開されたら見てください。あと Ceph って壊れたら多分直せないよね...という話を聞いてゾッとした。

最後に、「VM が出た頃はステートフルな物を置くのをめっちゃ嫌ってたのに、今は普通にステートフル乗せてるし、コンテナもいずれそうなるかもね。」という感じの話をされていてとても心に滲みました。

1 日目全体の所感

セッションは面白いものが多く、どれもハズレがないなあという印象でした。会場全体としてはちょっと小さくてセッション待ちや、スポンサーブースを回るのがちょっとキツかったですが、セッション会場内は適切な大きさでそんなにストレスはなかったです。お昼はランチセッションを考慮した食べやすいマイセンのカツサンドだったのでとても満足でした。運営の方々ありがとうございました!

ブースでは Oisix さんから Vegeel という 2 日分の野菜が摂れるという神飲料をいただきました。家で冷やして飲みましたがめちゃくちゃおいしかったです。濃い野菜ジュースみたいな感じでした。私は最低週 2 回サラダを食べるようにしているので、これで今週分は達成したということになります。ありがとうございます。

f:id:ZuiUrs:20190723041538j:plain:w500
Vegeel

Wi-Fi については提供スポンサーがいるわけではなくて虎ノ門ヒルズのものなので仕方ないと思うのですが、朝あまりにも繋がらなくて以降キャリアの回線を使っていました (その後繋がりやすくなったかもしれませんね)。あそこの Wi-Fi は 2.4Ghz っぽかったのでテザリングは控えて、スマホでぽちぽちメモを取っていました。

とりあえず、明日の夜は手を動かす系のやつの検証をしたいです (私のメモがミスっている可能性があるので)。

2 日目は疲れてなかったら書きます。

AWS SAA の re:Invent 現地受験

AWS re:Invent 2018 で AWS Solution Architect - Associate の現地受験をしたのでその雰囲気レポートです。

随分前の話ですが re:Invent 2019 が始まる前なのでセーフです。完全に記憶から消えるまでに書き残しておきます。向こうで受験する人の参考になれば幸いです。

経緯

私の会社には海外カンファレンス参加制度があって推薦 (自薦他薦問わず) と上の人達の承認が得られれば参加することができます。re:Invent に関しては (とてもありがたいことに) 同僚からの他薦だったのですが、個人的に AWS の知識がほとんどなかったため折角行くなら最大限吸収できるように勉強しよう、と思い受験することにしました。(あと Certification を取得しておくと当日に Certification 保持者向けのグッズが貰えるというのも大きな理由ですねw)

当然日本で受けられるならそっちにしたのですが、受けると決めたのがカンファレンス当日 1 週間前で時間もなかったので余裕をもたせて現地受験にしました。

現地受験

現地受験のフローを簡単に説明します。

申し込み

公式の Certification 申し込みページから申し込みます。手順は他の試験と同じだと思います。会場に re:Invent 専用会場を選択するところだけ注意してください。日程は選択式なので都合のいいところを選びます。

f:id:ZuiUrs:20190716022751p:plain:w800
試験申し込み画面

会場入り

試験時間が近づいてきたら会場入りしましょう。カンファレンス会場であるホテル (2018 は Venetian) がかなり広いので、空いてる時間に下見をしておくと良いです。私のときは試験会場が Keynote 会場出た広いホールの 1 階通路の暗がりにありました。毎年ここなんですかね。

旗とスタッフの方が入り口に立っているので目に入ればわかると思います。あと「静かにしろ!!!!!」の看板とともに、かなり大きい黄色のパトランプが置いてあってわかりやすかったです。

写真は撮り忘れました。

受付・待機

入って受付に行くと身分証明書の提示を要求されます。試験の注意事項に 2 種類持参するように書いてあるのですが、私はパスポートだけを出した記憶があります。おそらく re:Invent の写真入り ID を首からぶら下げているので、それでもう 1 つは満たされたのだと思います (とはいえ念の為 2 種類持っていったほうが安全です)。

受付を済ませると席の番号札と、こんな感じの受験上の注意が配られます。あとはこれを読みながら円卓で待機します。みんなめっちゃ静かでした。

f:id:ZuiUrs:20190716022846j:plain:w800
注意事項のプリント

入場

時間になるとスタッフの人がみんなを試験用の部屋に案内してくれます。上述の紙を読んでる前提なので部屋に入ったら何の説明もなく放置されます。落ち着いて荷物を棚に入れて自分の番号の席に向かいましょう。

席はめちゃくちゃ座りにくいです。足のスネくらいまでのテーブルクロスが引いてある長机と、玉座みたいな椅子があるのでそれに腰を下ろします。椅子を引くと隣のテーブルクロスが突っ張って座ってる人を押し出す感じになるんですよね。ちなみに機材は 24-inch くらいのモニターとマウスとキーボードです。

試験開始

自分の力を頼りに解きます。

完全入れ替え制ではないのか 30 分くらい経ったあと数人の集団が入ってきたので気が散りました。あと、位置の関係で斜め前に座った人の顔がガッツリ見えてしまって集中できなかったので、モニターに顔を近づけて無理やり見えないようにしていました。

開始直後、全員の画面が 3 分程フリーズするという事態に遭遇しましたが、カウントは減っていなかった (気がする) ので問題なかったと思います。

お疲れ様でした

解き終わったら手を上げてスタッフを呼んで退室します。

採点結果がその場で出るという話を耳にしたことがあったので、結果について聞いたところ「後日連絡するわ」とだけ言われて期間中に来るかどうか内心ビクビクしていました (期間中に結果が来ないと Certification ラウンジに入れない == グッズがもらえない)。結局、結果はその日の夜に届きました。

f:id:ZuiUrs:20190716022938p:plain:w800
テスト結果

おめでとうございます

合格したら Certification ラウンジに行ってグッズをもらいます。ちょっとボロいデザインの帽子がおしゃれで気に入っています。バイナリ T シャツも好きです。

f:id:ZuiUrs:20190716023007j:plain:w800
Certification ラウンジでもらったグッズたち

ID にもシールを貼ってもらえます。

f:id:ZuiUrs:20190716023056j:plain:w600
自分の ID

試験勉強

一応試験対策についても書いておきます。

  • まず本を読む
    • AWS の知識が少ないので本から収集
    • 合格対策 AWS認定ソリューションアーキテクト -アソシエイト
    • 読んだポイントを書いてまとめる
      • (iPad Pro を直前に買ったので文字を書きたかっただけ)
    • 大体業後 2 日くらいで終わる量

f:id:ZuiUrs:20190716023116j:plain:w800
iPad Pro 最高 (本の切り貼りは黒塗りしてる)

  • 模擬試験を受ける

    • テストに近い問題を見るのが一番いい
      • 2018/02 に改定されたので、それに対応した模擬試験が役に立った
      • 理解してないところが洗い出される
    • 2,160 JPY
    • 本読んだあと受験
  • Black Belt 読む

これをやっていれば大体合格できると思います (多分他のサイトでも同じようなことが書かれてます)。加えてナウいサービスをいくつか Black Belt で目を通しておけばもっと確率は上がるでしょう。

まとめ

現地受験は緊張しましたが、なんとか受けてくることができました。

とはいえ日本の方がリラックスして受けられると思うので、スケジュールが空いている人は日本で受けるのが良いと思います。

Go で Twitter のリスト管理を始める (入門編)

Twitter のリスト管理に Go の ChimeraCoder/anaconda というライブラリを使用したので利用例を紹介します。

ながい前置き

最近 Twitter のフォロー数がある程度増えてきて重要な情報を見逃すことが増えてきたので、相互の人・公式アカウント・特定の界隈の人、のようにリスト管理をしたくなってきました。僕の場合、同じ人が複数のリストにまたがって入ることは少ないので「未整理リスト」としてフォローしている全員が入ったリストを作り、そこから別のリストに移動することにしました。

ですが、いざやってみると Twitter のリスト管理って面倒なんですよね。Twitter 公式はユーザーをひとりひとり追加していく必要があるし、icotile3 (サードパーティ製 Web アプリ) は全選択機能があるのですが少し使いにくかったりします。*1

コツコツとリスト整理してきた人はちょっといじるだけなので楽なのですが、新しく作るってなると結構負荷高いんですよね。

そんな経緯でプログラムにやらせようということになりました。

Twitter Developer Account

以下の開発には TwitterDeveloper Account が必要になります。まだ持っていない人は下記のページから申請を行ってください。

去年から少し申請が厳しくなりましたが (UseCase の詳細な記述など)、聞かれたことに答えていれば特に問題はありません。運営の返答は早いので翌日には返信が来て、Approve の通知、または更に詳細な情報を求められます。私の場合は一度詳細情報を求められたあとに Approve されました。申請から Approve までは 1 日くらいでした。

ChimeraCoder/anaconda

ChimeraCoder/anaconda は Go の Twitter API ラッパーライブラリです。シンプルで余計な機能がないところがとても気に入っています。

開発はここらへんを見ながら進めます。Godoc には各関数に対する説明がほとんどありませんが、これは Twitter API に準拠しているためなので、そういう部分は Twitter API Docs の対応するエンドポイントの説明を参照します。

TwitterApi 構造体の取得

全ての API リクエストはここを介して行われます。予め Twitter Developer Portal で取得しておいた API キー (Twitter アプリケーションを区別する認証情報) と自身のアクセストークン (Bearer Token) を渡します。

api = anaconda.NewTwitterApiWithCredentials(
    AccessToken,
    AccessTokenSecret,
    APIKey,
    APISecretKey,
)

今回は自分自身なので直接アクセストークンを取得していますが、他のユーザーを操作する場合は func (*TwitterApi) AuthorizationURL あたりからトークンを取得する必要があります。

Cursor

早速フォロー情報の取得に入りたいところですが、その前に Cursor と anaconda での扱いについて少し話しましょう。CursorTwitter API が持つページネーションの仕組みです。フォロー数の取得など大量のレスポンスが想定される API にはこれが適用されています。

Cursor は実データと前後の Cursor ID を持っている双方向連結リストです。リクエスト時にそのインデックスを渡すことにより対応したページのデータが得られます。-1 は最初のページを示しており、多くの場合これを初期値としてリクエストを開始します。0 はその先がないことを示しており、クライアントはこれにより最後のページだと判断します。簡単な例を下記に示します。

//-> Request to http://example.com&cursor=-1
//<- Response
{
  "ids": [
    "aaa",
    "bbb",
    "ccc"
  ],
  "previous_cursor": 0,
  "next_cursor": 200
}

//-> Request to http://example.com&cursor=200
//<- Response
{
  "ids": [
    "ddd",
    "eee",
    "fff"
  ],
  "previous_cursor": 100,
  "next_cursor": 300
}

//-> Request to http://example.com&cursor=300
//<- Response
{
  "ids": [
    "ggg",
    "hhh",
    "iii"
  ],
  "previous_cursor": 200,
  "next_cursor": 0
}

このように一度のリクエストで完結しないため、anaconda では Channel を用いてユーザーにレスポンスを提供しています。具体的なコードは次のセクションを見てください。

フォロー情報の取得

まず自分がフォローしているユーザー (Friends) と フォロワー (Followers) の ID を取得します。

Cursor を使用した API なのでコードは下記のようになります。

friends := make([]int64, 0, 1000)
friendsChan := api.GetFriendsIdsAll(nil)

friendsLoop:
for {
    select {
    case p, ok := <-friendsChan:
        if ok {
            for _, id := range p.Ids {
                friends = append(friends, id)
            }
        } else {
            break friendsLoop
        }
    }
}


followers := make([]int64, 0, 1000)
followersChan := api.GetFollowersIdsAll(nil)

followersLoop:
for {
    select {
    case p, ok := <-followersChan:
        if ok {
            for _, id := range p.Ids {
                followers = append(followers, id)
            }
        } else {
            break followersLoop
        }
    }
}

ちなみに似たような関数に func (TwitterApi) GetFriendsListAllfunc (TwitterApi) GetFollowersListAll がありますが、リスト追加には ID だけで十分なのと、こちらは Rate Limit の関係で 300 人までしか取得できない (1 Cursor 20 人までで 15 分間に 15 回しかリクエストできない) ため使用しませんでした。

次に相互フォローのユーザーとそれ以外に分割します。Twitter API に相互フォローのユーザーを取得する API は提供されていないため、Friends と Followers の And を取ります。関係性は下記のようになります。

  • 相互フォローの Friends
    • n(Friends) ∩ n(Followers)
  • 相互フォローでない Friends
    • n(Friends) - n(Followers)

ここらへんのスニペットを置いておきました。必要でしたらコピペしてください。

リストの作成

分類をするリストを作成します。

mutual, err := api.CreateList("Mutual", "mutual friends", nil)
if err != nil {
    return err
}

unsorted, err := api.CreateList("Unsorted", "other friends", nil)
if err != nil {
    return err
}

すでにあるリストに追加したい場合は、そのリストの ID を取得して指定する or Slug でリストを指定する必要があります。Slug については次のセクションで少し触れます。

自身のリストを取得するには、自身のユーザー ID が必要なので下記のようにします。

me, err := api.GetSelf(nil)
if err != nil {
    return err
}

lists, err := api.GetListsOwnedBy(me.Id, nil)
if err != nil {
    return err
}

var mutual, unsorted anaconda.List
for _, l := range lists {
    switch l.Name {
    case "mutual":
        mutual = l
    case "unsorted":
        unsorted = l
    default:
    }
}

ユーザーの追加

最後に用意したユーザーをリストに突っ込みましょう。

リストへの追加は Twitter API の仕様により、一度に 100 人までしか追加できないようになっています。そのため、追加するユーザーの配列を 100 人ずつに分割する必要があります。下記に 100 人単位で 2 次元配列に変換するスニペットを置いておきました。必要でしたらコピペしてください。

分割したら API を叩きます。ここのポイントは func (TwitterApi) AddMultipleUsersToList に対して第 1 引数のスクリーンネーム (Twitter のユーザー名) の配列を渡しているのではなく、第 3 引数の url.Value 経由で ID (Twitter 内部の ID) 配列を渡しているところです。これまでに取得したフォロー情報には ID しか含まれていないためこうしています。仮にスクリーンネームでやる場合は各ユーザーの情報を引っ張ってくる必要があります。

// chunk はユーザー配列 (100 人以内)
// e.g.) chunk = []strings{"123", "456", ...}

v := url.Values{}
v.Set("user_id", strings.Join(chunk, ","))

_, err := api.AddMultipleUsersToList(nil, mutual.Id, v)
if err != nil {
    return err
}

このように anaconda ではメインとなるパラメータ以外は url.Value で渡す設計になっています。前セクションで触れた Slug によるリスト指定は下記のように行います。ここでの Slug は ID を指定する代わりに、リスト名とリストを保持するユーザー ID から対象リストを特定するものです。その他パラメータは Twitter API Docs を見ることで知ることができます。

v := url.Values{}
v.Set("user_id", strings.Join(chunk, ","))
v.Set("slug", "Mutual")
v.Set("owner_screen_name", "zuiurs")

_, err := api.AddMultipleUsersToList(nil, 0, v)
if err != nil {
    return err
}

おわりに

anaconda とても使いやすくていい感じでした。

今回は関数を利用して操作するだけでしたが、気が向いたら宣言的にリストを管理するものでも書きたいですね。とはいえほとんどアイコンでユーザーを判断しているので、文字だけで管理するのもなんかなーと思ってます。フロントと組み合わせられたら良いですね。

*1:icotile3 は全選択ができる一方で、一度に追加できるユーザー数に制限 (100 人まで) があり、結局自分の手で 100 人クリックする必要があって使用を断念しました。他に方法があったらごめんなさい。ちなみに 100 人制限は Twitter API の仕様です。

Go の備忘録 (range とポインタ編)

Go の range は変数を宣言するので、その値をポインタで渡したかったら対象スライスをインデックス参照して渡してねという話です。

今見ると、それはそう、となるのですがアウトプットするくせがないので、こういった小さいところから書いていこうと思います。

本編

こういうコードがありますよね。Goroutine である processor にチャネルを介して値を渡し、処理してもらおうという寸法です。構造体は大きい (予定) のでポインタで渡すことにします。

package main

import (
    "fmt"
    "sync"
)

type A struct {
    n int
}

func main() {
    as := []A{
        {n: 0},
        {n: 1},
        {n: 2},
        {n: 3},
        {n: 4},
    }

    q := make(chan *A)
    wg := &sync.WaitGroup{}
    wg.Add(1)

    go processor(q, wg)

    for _, a := range as {
        q <- &a
    }

    wg.Wait()
}

func processor(q <-chan *A, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 5; i++ {
        a := <-q
        fmt.Println(a.n)
    }
}

さあ、実行してみましょう。感覚で読むと 0, 1, 2, 3, 4 と出力されるような気がします。

0
2
2
4
4

あれっ、あれっ。なにかおかしい。とりあえず同じ構造体を何度か見ているようなのでポインタを合わせて出力させてみます。

Sent: A{n: 0} 0x41402c
Got : A{n: 0} 0x41402c
Sent: A{n: 1} 0x41402c
Sent: A{n: 2} 0x41402c
Got : A{n: 2} 0x41402c
Got : A{n: 2} 0x41402c
Sent: A{n: 3} 0x41402c
Sent: A{n: 4} 0x41402c
Got : A{n: 4} 0x41402c
Got : A{n: 4} 0x41402c

んん?なんで同じポインタ?

僕は答えを知っているのでもう書いてしまいますが、犯人はここなんですね。分かってる方は「あたりめーだろ!」とツッコミを入れてる頃だと思いますが許してください。

for _, a := range as {
    q <- &a
}

range は a という変数を定義して、それを as の各要素を入れるのに使い回すため a は常に同一オブジェクトなわけです。そのため、同じポインタがチャネルに入れられており、range のループの進捗によって参照する値が書き換えられていただけなのです。上の出力を見るとその様子がよくわかりますね。

つまり意図した挙動は次のように書きます。range の Value を定義せずに、Index のみを定義してスライスをインデックス参照するようにします。

for i, _ := range as {
    q <- &as[i]
}

わかってしまったらもう間違えようがないのですが、こういうところは気をつけていきたいですね。

以上、ありがとうございました。

builderscon tokyo 2017 に行ってきた

はじめまして。22 歳の学生です。これがこのブログ初のエントリとなります。

突然ですが、builderscon tokyo 2017 に行ってきました。知識も得られて、意識も高まり、知り合いもできて素晴らしいカンファレンスでした。

事前に「家に帰ってブログを書くまでが builderscon」とスタッフの方々からの洗脳を受けていたのでブログ開始に踏み切ることが出来ました。

builderscon tokyo 2017

builderscon は「知らなかった、を聞く」というテーマで開催されているカンファレンスです。

様々な分野のセッションが各部屋で繰り広げられており、自分が興味あるなーと感じたトークを聞きに行くみたいな感じです。フロントからインフラ、コンパイラとか 3D プリンタで作ったアナログコンピュータみたいなめっちゃコンピュータサイエンスっぽい話まで色々ありました。

詳しくは公式をご覧ください。

本エントリでは、私が聞いた中でも特に興味深かったセッションについて 2 つほどメモ的にまとめます。

Go で実装する軽量マークアップ言語パーサー

はてな記法 (LML) のパーサーを作る話。

はてな記法とか Markdown とかの LML は大体 HTML を生成するためのものなんだけど、それ用のパーサーが直接 HTML 吐くと柔軟じゃない (この HTML タグは使っちゃダメだよーみたいな設定が面倒)。はてな記法Perl の実装が多いらしく、手を加えるとなると Perl正規表現を読み解く必要があってツラい。つまり、HTMLじゃなくて中間表現を出力してくれて、かつ正規表現をゴリゴリ使ってないシンプルな実装が欲しい。

じゃあどうやって構文解析するのかというと、yacc に頼る。yaccBNF ライクな構文規則を渡してあげることでパーサーを生成してくれる。Go 用の yaccgoyacc というのがあるらしいのでそれを使う。ちなみにレキサーtext/scanner を使う。Go は公式で色々用意されてて便利。

実装がこれ↓。最近、普段使ってる FSWiki のパーサー書きたいなーと思ってたところなのでこれを機に頑張って書いてみたい。

あと応用編の話の中で、URL のスキーム名以外にも : が出て来る可能性がある関係 (特殊文字では無いらしいので) で、はてな記法のリンクのパースに手こずったということを話していた。独自記法を考えるときはそこら辺色々考慮する点が多くて難しそう。

OSS で始めるセキュリティログ収集

osquery を利用してサーバーのセキュリティログを収集してサーバーを監視する話。会場にはやはりインフラの人が多かったような気がする。

運用をしていく上で分類されるセキュリティ対策として、抑止、予防、検知、復旧の 4 つに分類されており、この話では「検知」がメイン。セキュリティログを記録→視覚化→「検知」というアプローチ。

セキュリティログというものの定義がいまいち理解できてないのですが、とりあえずユーザーのログイン、実行したコマンド、修正されたファイルなどのログという認識をしてます。例としては /var/log/secure とかですかね。

そこで Audit を使うとそのあたりがかなり詳細にできるらしい。Audit はカーネルの機能とその他 Audit デーモンなどから成るシステムで、システムコール周りを監視して、このシステムコールが対象のファイルに実行されたー、とか、こんなコマンド実行されたー、とかをフィルタしてログとかに書き込んでくれるやつ(間違っていたらごめんなさい)。すごく便利そうだし、ログたくさん取ってビジュアライズしたらすごく面白そう。

ブログ書くついでに、手元でも「ユーザーが cd するたびにロギング」するどうでもいいルールを定義してみた。ちなみにシステムコールを指定するときはちゃんと -Fアーキテクチャを指定しないといけない。システムコール一覧は /usr/include/asm/unistd_64.h。(参照: https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/6/html/Security_Guide/sec-Defining_Audit_Rules_and_Controls.html)

# auditctl -a always,exit -F arch=b64 -S chdir

実際に /var/log/audit/audit.log に出力されるログは下記。読めなくもないけど読みたくない。

type=SYSCALL msg=audit(1502199111.467:94838): arch=c000003e syscall=80 success=yes exit=0 a0=563480012400 a1=7f71a67e5ae8 a2=5634800123d0 a3=563480012401 items=1 ppid=24901 pid=24902 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts8 ses=1 comm="bash" exe="/usr/bin/bash" key=(null)
type=CWD msg=audit(1502199111.467:94838): cwd="/home/users/zuiurs"
type=PATH msg=audit(1502199111.467:94838): item=0 name="/home/users/zuiurs/work" inode=486803 dev=fd:00 mode=040700 ouid=1000 ogid=1000 rdev=00:00 nametype=NORMAL
type=PROCTITLE msg=audit(1502199111.467:94838): proctitle=7375002D007572757368696461

このログをパースしてくれるのが osquery。吐き出す形式は JSON で、これを集約して Kibana で可視化したり、イベントを Slack に投げたりする。ちなみにスピーカーの方はこれで 200 台監視して、ログ多めの設定で 1 日 1200 万行くらい溜まるらしいので logrotate は必須。

おわりに

身になる知識はもちろん、勉強の取っ掛かりとなる入門的な知識もたくさん得られたので、これから数ヶ月はやりたいことでいっぱいだと思います。

あとインターンの仲間だったり、その知り合いだったりと人とのコミュニケーションとかもあったので良かったです。懇親会は参加しなかったのですが、行っておけば良かったような気がします。

次回もまた参加したいと思えるくらい楽しいカンファレンスでした。運営の方々、スピーカーの方々、その他関わってくださった皆さま、ありがとうございました。