第10回 Microservices Patterns 読書会
参加してきました。
今回のトピックは「8.3 API ゲートウェイパターンの実装」と、「9. マイクロサービスのテストその1」でした。
こちらは休憩時間にいただいた甘いものたち。(各自がいろいろなお菓子を持ち寄るので参加者が増えると大量になる)
8.3 API ゲートウェイパターンの実装
APIゲートウェイの役割にAPIコンポジションを含めているのはどうなの、とか、マイクロフロントエンドとの関係はどうなの、とか、普段は BFF でやりますね、とかそういう会話をしてました。(実際に仕事で扱っている人の意見は参考になるなぁ)
マイクロフロントエンドについてはEJB時代のポートレットと同じじゃね?といった感想もあり、技術要素のトレンドを感じました。
書籍化するまでの期間よりサービスのアップデートの方が早くて、ALB のデメリットとして挙げられていたエッジ機能(認証)がないことは過去の話になってしまっているのは残念ポイント。
Spring Cloud Gateway によるゲートウェイの実装では、Reactor の抽象の Mono と CompletableFuture の違いはなんだろう、とかそういう会話をしてました。
私は、Mono はリアクティブプログラミングのための抽象で、並行プログラミングの要素も含んでいるのに対して、CompletableFuture は並行プログラミングのためのAPIでより低レベルの抽象と考えています。
GraphQL によるゲートウェイの実装では、どの辺がグラフ構造なんだろう、とか、クライアントが自由すぎてサーバー側は負荷対策できないんじゃないか、とかそういう会話をしてました。
Facebook では友達の友達や友達の友達が所属するグループといった情報へのアクセスを効率化する必要があったため、クエリドキュメントの type のフィールドに並べた type を再帰的に問い合わせるような仕様のことをグラフと見立てているのではないか、という話をしました。
クライアントがクエリを少し変更しただけで、サーバーサイドで発生する問い合わせ数が大きく変化する場合がありそうで、そんな構成で負荷対策は不可能だ、とか、経験的にクライアント側でそんなやばいことをすることはなかった、とか、クライアント側ではサーバーサイドのSLAを気にするくらいがせいぜい、とか、そういう話をしてました。(参加者それぞれが経験的な話をしてくれてるので、とても参考になる)
9. マイクロサービスのテストその1
その1ではテストの考え方、ユニットテストを紹介し、その2でインテグレーションテスト以降を紹介することになっています。
早くデリバリーするには効率よくテストする必要があり、それはテスト自動化によって実現する、という考え方でした。
テスト自動化の導入状況の市場調査が紹介されていたけど、著者の見解は悲観的すぎるんじゃないかと思いました。
2018年のSauce Labs Testing Trendsレポートは、テスト自動化の状態のかなり暗い絵を描いている(https://saucelabs.com/resources/white-papers/testing-trends-for-2018) 組織の26%はほとんど自動化されておらず、わずか3%だけが完全に自動化されていることを説明している。
自動テストの説明では xUnit Test Patterns の考え方を踏襲していました。嬉しい。
ただ、わざわざ Exercise を Execute と置き換えているのが気になりました。何か嫌なことでもあったんだろうか。
ユニットテストやインテグレーションテストなどの分類基準はわりとふわっと説明されています。
ここで参加者の中から「コマンドとイベントを対象にテストするべきだ。サービスのロジックや内部のデータモデルは不安定なため、そのテストも無駄になりがちだからだ。」というイベントソーシング界隈の考え方を紹介されました。
特定の局面を氾化しすぎるパラノイアの考えだ(私)とか、銀の弾丸が無いことを知っているエンジニアにとって説得力のかけらもない意見だ(私)とか、自分たちでちゃんとテスティングフレームワークを開発して完全性を保証する手段を用意してから出直しして欲しい(私)とか、そういう意見が出ました。
テストを分類するツールとして、テストの4象限、テストピラミッドが紹介されています。
テストの4象限はブライアン・マリックさんのブログから引用されていました。
テストの4象限と言えば実践アジャイルテストだと思い込んでいたのですが、投稿日からするとおそらくこちらが初出の考え方だったようです。知らなかった。
テストピラミッドはマーティン・ファウラーのblikiからの引用でした。
次回予定
11月になりました。それまでは自習して過ごします。
eksctl で 既存の VPC にプライベートなワーカーノードが作れない
こんな感じでずっと待ち状態になってしまう原因が知りたかった。
eksctl create nodegroup \ --region ap-northeast-1 \ --cluster ekstest \ --name ng0 \ --node-type t3.medium \ --nodes 1 --nodes-min 1 --nodes-max 1 --node-ami auto --node-volume-size 10 \ --node-private-networking \ --node-security-groups sg-0d021a3fc762eed89 \ --node-labels "usage=client" \ --ssh-access \ --ssh-public-key .ssh/mymachine.pub [ℹ] using region ap-northeast-1 [ℹ] will use version 1.14 for new nodegroup(s) based on control plane version [ℹ] nodegroup "ng0" will use "ami-055d09694b6e5591a" [AmazonLinux2/1.14] [ℹ] using SSH public key ".ssh/mymachine.pem.pub" as "eksctl-ekstest-nodegroup-ng0-86:8d:7f:00:97:c2:c8:19:af:94:61:03:72:c8:31:51" [ℹ] 1 nodegroup (ng0) was included [ℹ] will create a CloudFormation stack for each of 1 nodegroups in cluster "ekstest" [ℹ] 1 task: { create nodegroup "ng0" } [ℹ] building nodegroup stack "eksctl-ekstest-nodegroup-ng0" [ℹ] deploying stack "eksctl-ekstest-nodegroup-ng0" [ℹ] adding role "arn:aws:iam::1234567890:role/eksctl-ekstest-nodegroup-ng0-NodeInstanceRole-1F01MBBM84FH5" to auth ConfigMap [ℹ] nodegroup "ng0" has 0 node(s) [ℹ] waiting for at least 1 node(s) to become ready in "ng0"
待ち状態になってから作成したノードに ssh
でログインしていろいろ確認したら理由がわかった。
まず、kubelet.service
がクラッシュループを繰り返していることを確認。
どうやら aws クラウドプロバイダーの初期化に失敗しているようだ。
journalctl -u kubelet.service Sep 24 00:41:30 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: Starting Kubernetes Kubelet... Sep 24 00:41:30 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: Started Kubernetes Kubelet. Sep 24 00:41:30 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3619]: Flag --max-pods has been deprecated, This parameter should be set via the config file specified by the Kubelet's --config flag. See https://ku Sep 24 00:41:30 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3619]: Flag --allow-privileged has been deprecated, will be removed in a future version Sep 24 00:41:30 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3619]: Flag --max-pods has been deprecated, This parameter should be set via the config file specified by the Kubelet's --config flag. See https://ku Sep 24 00:41:30 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3619]: Flag --allow-privileged has been deprecated, will be removed in a future version Sep 24 00:41:30 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3619]: I0924 00:41:30.498199 3619 server.go:418] Version: v1.14.6-eks-5047ed Sep 24 00:41:30 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3619]: W0924 00:41:30.499460 3619 plugins.go:118] WARNING: aws built-in cloud provider is now deprecated. The AWS provider is deprecated and will Sep 24 00:41:30 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3619]: I0924 00:41:30.501778 3619 aws.go:1137] Zone not specified in configuration file; querying AWS metadata service Sep 24 00:41:30 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3619]: I0924 00:41:30.507431 3619 aws.go:1171] Building AWS cloudprovider Sep 24 00:43:30 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3619]: F0924 00:43:30.852164 3619 server.go:266] failed to run Kubelet: could not init cloud provider "aws": error finding instance i-01c729a3a7fe Sep 24 00:43:30 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: kubelet.service: main process exited, code=exited, status=255/n/a Sep 24 00:43:30 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: Unit kubelet.service entered failed state. Sep 24 00:43:30 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: kubelet.service failed. Sep 24 00:43:36 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: kubelet.service holdoff time over, scheduling restart. Sep 24 00:43:36 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: Starting Kubernetes Kubelet... Sep 24 00:43:36 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: Started Kubernetes Kubelet. Sep 24 00:43:36 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3836]: Flag --max-pods has been deprecated, This parameter should be set via the config file specified by the Kubelet's --config flag. See https://ku Sep 24 00:43:36 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3836]: Flag --allow-privileged has been deprecated, will be removed in a future version Sep 24 00:43:36 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3836]: Flag --max-pods has been deprecated, This parameter should be set via the config file specified by the Kubelet's --config flag. See https://ku Sep 24 00:43:36 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3836]: Flag --allow-privileged has been deprecated, will be removed in a future version Sep 24 00:43:36 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3836]: I0924 00:43:36.082885 3836 server.go:418] Version: v1.14.6-eks-5047ed Sep 24 00:43:36 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3836]: W0924 00:43:36.083072 3836 plugins.go:118] WARNING: aws built-in cloud provider is now deprecated. The AWS provider is deprecated and will Sep 24 00:43:36 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3836]: I0924 00:43:36.083155 3836 aws.go:1137] Zone not specified in configuration file; querying AWS metadata service Sep 24 00:43:36 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3836]: I0924 00:43:36.084224 3836 aws.go:1171] Building AWS cloudprovider Sep 24 00:45:36 ip-192-168-10-221.ap-northeast-1.compute.internal kubelet[3836]: F0924 00:45:36.401506 3836 server.go:266] failed to run Kubelet: could not init cloud provider "aws": error finding instance i-01c729a3a7fe Sep 24 00:45:36 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: kubelet.service: main process exited, code=exited, status=255/n/a Sep 24 00:45:36 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: Unit kubelet.service entered failed state. Sep 24 00:45:36 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: kubelet.service failed. Sep 24 00:45:41 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: kubelet.service holdoff time over, scheduling restart.
そして cloud-init.service
が失敗していることも確認。
yum リポジトリのアクセスに失敗している。
原因は NAT ゲートウェイも NAT インスタンスも作ってなかったから。
なるほど :thinking_face: すぐに課金始まるから作ってなかったんだよね・・・
systemctl list-units | grep cloud-config ● cloud-config.service loaded failed failed Apply the settings specified in cloud-config journalctl -u cloud-config.service Sep 24 00:40:52 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: Starting Apply the settings specified in cloud-config... Sep 24 00:40:52 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: Cloud-init v. 18.2-72.amzn2.0.7 running 'modules:config' at Tue, 24 Sep 2019 00:40:52 +0000. Up 12.19 seconds. Sep 24 00:40:52 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: Loaded plugins: priorities, update-motd Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: One of the configured repositories failed (Unknown), Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: and yum doesn't have enough cached data to continue. At this point the only Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: safe thing yum can do is fail. There are a few ways to work "fix" this: Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: 1. Contact the upstream for the repository and get them to fix the problem. Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: 2. Reconfigure the baseurl/etc. for the repository, to point to a working Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: upstream. This is most often useful if you are using a newer Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: distribution release than is supported by the repository (and the Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: packages for the previous distribution release still work). Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: 3. Run the command with the repository temporarily disabled Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: yum --disablerepo=<repoid> ... Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: 4. Disable the repository permanently, so yum won't use it by default. Yum Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: will then just ignore the repository until you permanently enable it Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: again or use --enablerepo for temporary usage: Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: yum-config-manager --disable <repoid> Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: or Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: subscription-manager repos --disable=<repoid> Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: 5. Configure the failing repository to be skipped, if it is unavailable. Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: Note that yum will try to contact the repo. when it runs most commands, Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: so will have to try and fail each time (and thus. yum will be be much Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: slower). If it is a very temporary problem though, this is often a nice Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: compromise: Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: yum-config-manager --save --setopt=<repoid>.skip_if_unavailable=true Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: Cannot find a valid baseurl for repo: amzn2-core/2/x86_64 Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: cloud-config.service: main process exited, code=exited, status=1/FAILURE Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: Could not retrieve mirrorlist http://amazonlinux.ap-northeast-1.amazonaws.com/2/core/latest/x86_64/mirror.list error was Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: 12: Timeout on http://amazonlinux.ap-northeast-1.amazonaws.com/2/core/latest/x86_64/mirror.list: (28, 'Connection timed out after 5000 mill Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: Sep 24 00:41:29 cloud-init[3052]: util.py[WARNING]: Package upgrade failed Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: Sep 24 00:41:29 cloud-init[3052]: cc_package_update_upgrade_install.py[WARNING]: 1 failed with exceptions, re-raising the last one Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal cloud-init[3052]: Sep 24 00:41:29 cloud-init[3052]: util.py[WARNING]: Running module package-update-upgrade-install (<module 'cloudinit.config.cc_package_upd Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: Failed to start Apply the settings specified in cloud-config. Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: Unit cloud-config.service entered failed state. Sep 24 00:41:29 ip-192-168-10-221.ap-northeast-1.compute.internal systemd[1]: cloud-config.service failed.
ぼっちを越えるための第一歩
AWS Cloud9 の共有環境では bash プロンプトを共有できない
Google Docs や Dropbox Paper のように、同じファイルを複数人で編集できました。他の人のカーソルが見える状態。
ただし、次のような仕様になっています。
- 操作主体は独立しているため、どのファイルを編集してるのか分からないと同時編集はできない
- 一番残念なのは bash プロンプトを共有できない
残念だなぁ。後者は本当に残念だ。
screen や tmux 使えばいいんだけど。
XP祭り2019に参加した
参加した感想です。
今後参加するとしたら役に立ちそうなこと
- 懇親会はカウンターがキャパシティーオーバーになるため、回転率が上がらない(逆に話を切り上げるきっかけにすることもできる)
- 喫煙者はもう少し自重したほうがいい(とても反省してる)
参加したセッションや思ったこと
基調講演
熱量高い。
XP の20年を振り返りつつ、闇落ちした経験や今に至るまでの道のりを紹介されてました。
インフレーションにより誕生したアジャイルユニバースでは、スクラム宇宙やリーン宇宙が誕生し、急速に成長しながら距離を広めている。それぞれの宇宙にはXPのかけらがあるんだよ、という背景。
FF6 のクリスタルのかけらみたいだ。
本題は、ソーシャルチェンジという言葉の解釈。
「全てのギークがこの世界で人として生きていく手助けをしたい」というケント・ベックさんの意志は当時から一貫していたことの再発見がありました。
ケント・ベック、聖人か。
本題はだいぶ的外れだった。意図をくみ取るの難しい。
https://twitter.com/kakutani/status/1175599455908712450?s=20
https://twitter.com/kakutani/status/1175599455908712450?s=20
文化をつくる~エンジニアを超えた真のDevOpsへの旅~(蜂須賀 大貴さん)
みんな、仲良くしようぜ!以上。
思ったことはこちらにまとめた。
(申し訳ないけど同じ時間帯の咳さんの話を聞きたかったなぁ)
学ぶ力を高めるメタ認知のご紹介(小笠原 晋也さん)
なんなんだろうね、メタ認知。
自我と超自我みたいな?西洋哲学なの?
人間の認知モデルをリバースエンジニアリングする話なら、リファクタリングウェットウェアで学んだ気がする。
アジャイルソフトウェア開発への統計的品質管理の応用(坂田 晶紀さん)
「シャッター音OK。フェスみたいでいいよね」
めっちゃロックな姿勢、見習いたい。
チケットシステムを工夫した、的な話だった。
前に読んだソフトウェア開発メトリクスの方が、考え方や具体的な手法としても納得感があると思った。
ビブリオバトル
印象的だった2冊は次のとおり。「岩田さん」は川口さんにディスられた印象が残ったのでなんか違うなと思った。
- 「ナイチンゲール○○な本」。プレゼン上手だったし、読むきっかけがセールで見かけたとか神がかってたのでよかった。投票しました。
- 「ゲームモデルな本」。役に立つ雰囲気をすごい発散してた。
懇親会
- 「DevOpsに代表される集中的な協業の流行は、これまでソフトウェア開発が問題を分割して役割を分けてきたことに対するアンチテーゼなのか、それとも周期的な傾向なのか」というテーマで数人の知人に意見を聞いて回った
- およべさん、きょんさんの教えを受けたという方とちょっと会話した
- さいとーさんやせとさんから、相変わらずやべー話を聞いた(やりそうだなーとは思った)
- メイド服にWACATE関係者を紹介されたら弊社社員だったので(本当に知らない人だった)、テストエンジニアリングの啓蒙活動をやっていく相談をした
- 原田騎朗さんのセッションでは「XPは文章書いてないから停滞して見える」といった諸事情の話がきけたらしいので、ちょっと掘り起こしたい
- 対象範囲があやふやでお悩みのJasst実行委員の方に、「コストかけるならE2Eテストですよ、デイブ・トーマスもそう書いてるし」という話をした
消耗しない場作りの取り組み
他の人が用意してくれる場に入っていくのは簡単。
しかし、自分で場を用意してみると驚くほど難しいことがわかる。
コアメンバーを集めるとか、そういうノウハウを活用したほうがいいんだろうなぁとは思う。文脈が全然違うので活用できないんだけど…
「場作り」が目的ではないので、あまり思い入れを持たないよう淡々とアプローチすることを心がけている。期待し過ぎると反動でとても落ち込む性格なので。