pokutuna.com

pokutuna

Web Developer / Software Engineer
Hyogo, Japan

Links

Publications

  • Podcast - Backyard Hatena

    #8 id:pokutuna に聞くココピーの現在と未来

    はてなのエンジニア組織である技術グループでやっているポッドキャストで、ビジネスプラットフォームチームの活動や Chrome 拡張「ココピー」について話しました。

  • TechTalk - Google Cloud Born Digital Summit

    はてな広告配信システムのクラウドネイティブ化への道のり

    広告配信システムを Google Cloud へ移転しました。Elasticsearch で行っていた配信ログの集計を BigQuery へ置き換える過程を中心に GCP の各種プロダクトの活用事例を紹介しました。

Products

Blog Entries

  • ぽ靴な缶

    2022-10 の Cloud Storage 料金改定に伴い GCR から Artifact Registry へ移行する

    Google Cloud で運用しているサービスの Cloud Storage 費用が10月の料金改定から爆増していた。 Cloud Storage 費用(オレンジ部分)が増加 料金改定のタイミングで Cloud Storage のマルチリージョンからマルチリージョン内のリージョンへの転送費用が無料じゃなくなっていた。 Docker イメージの転送費用によるものであれば、Container Registry から Artifact Registry へ移行することでこの費用は無にできる。 cloud.google.com 無料条件がなくなった Google Cloud 内の下り(外向き)ネットワーク費用を見る。 Internet Archive に残っている過去の料金表(2022-05-01)には以下の記述があった。 マルチリージョンにある Cloud Storage バケットからある 1 つのリージョンにある別の Google Cloud サービスへのデータの移動で、両方のロケーションが同じ大陸にある。 無料 現行は、この無料条件がなくなっているうえに、 $0.08/GB とまずまず高めの値段設定になった。 同じ大陸内の異なるロケーション間でデータを移動する場合、転送元バケットは ASIA マルチリージョンに配置され、上記の無料ケースのいずれも適用されない。 $0.08/GB cloud.google.com Container Registry (GCR) のコンテナイメージは Cloud Storage のマルチリージョンバケットに保存され、イメージを利用する実行環境は何らかのリージョンにあるので、この条件にあたってしまう。 今まではイメージと実行環境のロケーションを合わせていれば無料で使えたが1、一通りマルチリージョンバケットからの転送に費用がかかるようになってしまった現在はもう無料で使うことはできない!! asia ほどの費用にはならないが、gcr.io から us 内への転送も $0.02/GB と、無料ではなくなっている。 Artifact Registry を使う Container Registry (GCR) より後に公開された Artifact Registry。 Maven や npm モジュールなどもホストできる。 cloud.google.com 移行するモチベーションは特になかったけど、今回の費用改定で明らかにメリットが生まれてしまった。 Artifact Registry はアーティファクトを保存するリポジトリのロケーションを選ぶことができる。実行環境と同じロケーションにイメージを置くことで、Cloud Storage のネットワーク費用を無料にすることができる!! 移行する作業は特に難しくなく、ドキュメントで移行について案内されている。 cloud.google.com アクセス権限周りに大きな変更があったが、困るようなことはなかった。 GCR 時代のアクセスコントロールは Cloud Storage の IAM ロールでやる感じで、おおざっぱだし分かりづらかったけど、Artifact Registry ではそれ用のロールが設けられプロジェクト単位でも個別のリポジトリに対しても権限を設定できる。 実際の作業としては、API を有効にし、Artifact Registry にリポジトリを作って、GCR に置いてあるイメージを Artifact Registry Registry に上げなおして、k8s manifest やデプロイコマンドなど各所の image 指定を更新する程度でした。 これでグラフの右端のように、また Cloud Storage 費用を無にできたわけです。 今回の値上げといい、ドキュメントの記述といい、かなり Artifact Registry への移行を促してる感ありますね。 Container Registry の進化形である Artifact Registry は、 https://cloud.google.com/artifact-registry?hl=ja Container Registry は引き続き使用可能で、Google Enterprise API としてサポートされていますが、新機能は Artifact Registry でのみ利用可能です。Container Registry には、重要なセキュリティ修正のみ与えられます。 https://cloud.google.com/artifact-registry/docs/transition/transition-from-gcr Google Cloud のドキュメント中の "大陸" (continent に対する訳) って独特の概念だよね、ASIA マルチリージョンの各所は海で隔てられている(台湾, 香港, 東京, ムンバイ, ...)2ものの、同じ文脈で大陸として出てくる "US" や "EU" と同じ扱いであったりもするわけで。でもある日 ASIA は大陸じゃありませーんと言われてもしょうがない気もするし。 https://blog.pokutuna.com/entry/gke-autopilot-storage-egress↩ https://cloud.google.com/storage/docs/locations#available-locations↩

  • ぽ靴な缶

    gcloud の configurations を切り替える

    前回の記事では --project を毎回渡せという主張を展開していたけど切り替える話。 blog.pokutuna.com gcloud コマンドには構成を管理するサブコマンド gcloud config configurations がある。管理するプロジェクトが多くない場合は、カレントプロジェクトを設定しつつ切り替える運用でもよいのではないでしょうか。 また、複数の Google アカウントを切り替える場合も configuration を作って切り替えるのがいい。カレントプロジェクトは設定しない派だけど、個人の @gmail.com と勤務先の Google Workspace のログイン状態を切り替えるのに使ってる。 ちなみに configurations を切り替えても ADC はそのままで、最後に gcloud auth application-default login した時点の認証情報から変わらないのが注意ポイント。 gcloud config configurations Cloud SDK 構成の管理 | Cloud SDK のドキュメント | Google Cloud 触ってみないと微妙に分かりづらいけど、Google アカウントやカレントプロジェクトなど一連の設定を 1 つのエントリとしてまるっと切り替えることができる。 "プロジェクトを切り替えることができる" と説明されていたりするけど、Google アカウントを含む一連の構成を切り替えると思っておかないと、 gcloud config set project でプロジェクトを切り替えたり、ログインし直したりしているとよく分からなくなる。 プロジェクトを切り替えるには、同じ Google アカウントでログインした複数の構成を作って、別々のカレントプロジェクトを設定しておいて、それらを切り替えるという感じ。 # configuration の一覧 $ gcloud config configurations list # configuration を作る & 同時にその設定名がアクティブになる $ gcloud config configurations create NAME # configuration に設定する $ gcloud init # 最初から $ gcloud auth login --project=PROJECT_ID # ログインしてプロジェクト ID 設定する $ gcloud config set project PROJECT_ID # プロジェクト ID だけ設定する $ gcloud config set compute/region REGION # region $ gcloud config set comute/zone ZONE # zone # NAME の設定に切り替える $ gcloud config configurations activate NAME 例のように、region や zone も保存しておけるので、Compute Engine などこれらの引数を要求するコマンドをよく使うなら、設定してあるとちょっと楽になる。 gcloud config に設定できるもの 先に挙げたものが config に設定できるものとしてメジャーだけど、他にもいろんな設定を保存できるし、configuration で切り替えられる。 例えば以下のように設定しておくと、Cloud Functions に新しい関数をデプロイする際に region を省略しても asia-northeast1 になる。 $ gcloud config set functions/region asia-northeast1 設定可能な項目はドキュメントにちゃんとまとまってある。 gcloud config | Google Cloud CLI Documentation あるいは json や yaml で出力してみると雰囲気が分かっておもしろい。 $ gcloud config configurations list --format=json accessibility/screen_reader を true に設定すると gcloud の出力がスクリーンリーダーフレンドリーになったり、core/log_http すると gcloud の API リクエストとレスポンスが出力されたりして面白いですね。 fzf や peco で切り替える よくあるやつ。fzf でも peco でも動くので読み替える。 gcloud-switch() { local selected=$( gcloud config configurations list --format='table[no-heading](is_active.yesno(yes="[x]",no="[_]"), name, properties.core.account, properties.core.project.yesno(no="(unset)"))' \ | fzf --select-1 --query="$1" \ | awk '{print $2}' ) if [ -n "$selected" ]; then gcloud config configurations activate $selected fi } gcloud にはグローバルな `--format=NAME[ATTRIBUTES](PROJECTION) オプションがあって、単体で出力をかなり加工できる。他のツールと組み合わせるときに使うとかわいいですね。 gcloud topic formats | Google Cloud CLI Documentation gcloud topic projections | Google Cloud CLI Documentation あるいは direnv を使っている場合は CLOUDSDK_ACTIVE_CONFIG_NAME 環境変数で切り替えることもできる。チームで configuration 名をプロジェクト名にしてリポジトリに入れたりするのもよいかもしれません。 Cloud SDK 構成の管理 | Cloud SDK のドキュメント | Google Cloud

  • ぽ靴な缶

    gcloud にカレントプロジェクトを設定しない派

    gcloud CLI にカレントプロジェクトをなるべく持たせないようにして暮らしている。 gcloud はデフォルトでカレントプロジェクトのリソースを操作する。操作するプロジェクトが 1 つなら良いけど、仕事でも遊びでもいくつもの GCP プロジェクトを扱っているので、うっかり異なるプロジェクトのリソースを操作してしまったり、意図しないプロジェクトに費用が計上されてしまうのが嫌だから。 カレントプロジェクトは設定しないようにして、gcloud を使う時は都度 --project=PROJECT_ID で渡すようにしている。 # カレントプロジェクトを確認するには以下のコマンドなど $ gcloud config get-value project $ gcloud config list # カレントプロジェクトの設定を消す $ gcloud config unset project ローカルの ADC の quota project 忘れられがちだけど、ローカルの Application Default Credentials にもカレントプロジェクトに相当する "quota project" がある。 ADC についてはこちら blog.pokutuna.com ADC の quota project は、gcloud auth application-default login した時点のカレントプロジェクトが設定される。 ~/.config/gcloud/application_default_credentials.json を見ると分かるし、ログイン時のメッセージにも出てくる。 Credentials saved to file: [/Users/pokutuna/.config/gcloud/application_default_credentials.json] These credentials will be used by any library that requests Application Default Credentials (ADC). Quota project "pokutuna-playground" was added to ADC which can be used by Google client libraries for billing and quota. Note that some services may still bill the project owning the resource. 普段からカレントプロジェクトを設定しないようにしていると気にしなくて良いが、unset したり切り替えたりしていると gcloud のカレントプロジェクトと ADC の quota project が異なる状態になるのがややこしい。 なのでこれも設定しないようにしている。 カレントプロジェクトを ADC に伝播させたくない場合は ADC ログイン時に --disable-quota-project オプションを使う。 $ gcloud auth application-default login --disable-quota-project ADC に quota project を設定しない場合、以下のような警告を見ることになるけど、アプリケーションコードからプロジェクト ID を与えればよいので気にしない。 WARNING: Cannot find a quota project to add to ADC. You might receive a "quota exceeded" or "API not enabled" error. Run $ gcloud auth application-default set-quota-project to add a quota project. ADC にプロジェクト ID を持たせない暮らし ADC に quota project を設定しない場合、アプリケーションコード中にプロジェクトIDが登場することになるけど、意図しないプロジェクトを操作してしまう危険を避けることを優先している。 認証情報はメンドイので ADC に解決してほしいが、プロジェクト ID まで暗黙に解決したいことはほぼないし、複数のプロジェクトで同じコードを実行する場合でも、設定や環境変数などでアプリケーションに伝えればいいという考え。 GCP 上の実行環境でも、実行環境とプロジェクト ID が異なってないなら問題はない。 Node Google Cloud の各種プロダクトに用意されたクライアントライブラリはコンストラクタに渡せばいい。 // Imports the Google Cloud client library const {BigQuery} = require('@google-cloud/bigquery'); const client = new BigQuery({ projectId: "<PROJECT_ID>" }); Spreadsheet など、Google Cloud 感ないものは GoogleAuth に渡す。Spreadsheet や Calendar なども API を有効にしたり使用量を管理するために Google Cloud プロジェクトが必要。 googleapis/google-api-nodejs-client import { google } from "googleapis"; const auth = new google.auth.GoogleAuth({ projectId: "<PROJECT_ID>", scopes: [ "https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/spreadsheets.readonly", ], }); const sheets = google.sheets({ version: "v4", auth }); Node の場合、明に指定しない場合は google-auth-library がプロジェクト ID を解決しようとする。その過程で GCLOUD_PROJECT や GOOGLE_CLOUD_PROJECT 環境変数を参照したり、gcloud のカレントプロジェクトを参照したりする(歴史的経緯だろうけど、この挙動が嫌だなあ)。 Go Go でも Google Cloud 系のクライアントライブラリでは素直に渡せばいい。 googleapis/google-cloud-go import ( "context" "cloud.google.com/go/bigquery" ) func main() { ctx := context.Background() client, err := bigquery.NewClient(ctx, "<PROJECT_ID>") ... } Google Cloud 感のないものは google.golang.org/api を使うことになるが、こちらは option.WithQuotaProject() を使う。google.golang.org/api 以下でほぼすべての Google の API を叩けるので、Cloud API もこちらの方法で叩ける。 googleapis/google-api-go-client import ( "context" "google.golang.org/api/option" "google.golang.org/api/sheets/v4" ) func main() { ctx := context.Background() client, err := sheets.NewService(ctx, option.WithQuotaProject("<PROJECT_ID>")) ... } まとめ いろんなプロジェクトを触る場合は gcloud にカレントプロジェクトを設定しないのをおすすめしている ローカルの ADC も quota project があり、ログイン時のカレントプロジェクトが引き継がれる、これも設定しないのがいい アプリケーションコードでプロジェクト ID を明に指定すればいい blog.pokutuna.com

  • ぽ靴な缶

    GCP IAM ロールの持つ権限を比較するテク

    メンバーやサービスアカウントの権限を考える際に、ロールの持つ権限を比較したいことがしばしばある。そういう時は gcloud と diff を使うことで比較できるという素朴なテク。 ロールと権限 ロール(role)は roles/{roleName}, roles/{service}.{roleName} などで表され、許可されている操作を表す権限(permission)の集合である。 例えば BigQuery データ閲覧者 (roles/bigquery.dataViewer) は、以下の permission を持つ。 bigquery.datasets.get bigquery.datasets.getIamPolicy bigquery.models.export bigquery.models.getData bigquery.models.getMetadata bigquery.models.list bigquery.routines.get bigquery.routines.list bigquery.tables.createSnapshot bigquery.tables.export bigquery.tables.get bigquery.tables.getData bigquery.tables.getIamPolicy bigquery.tables.list resourcemanager.projects.get resourcemanager.projects.list cloud.google.com ロールの比較 個別のロールと権限について確認したいときは以下のドキュメントを見る、GCP 屈指の縦に長いページ role から permission Understanding roles | IAM Documentation | Google Cloud permission からそれを持つ role IAM permissions reference | IAM Documentation | Google Cloud role をいじっていると以下のような疑問が湧いてくることがある。 roles/bigquery.dataViewer と roles/bigquery.metadataViewer ってテーブルのデータ読める以外に何が違うんだっけ? roles/browser と roles/resourcemanager.folderViewer ってどう違うんだっけ? roles/editor は強い権限だけど、意外と SecretManager で出来ない操作あった気がする 上のドキュメントを行ったり来たりしてもいいけど、* でサービス内の個別の permission が省略されていたりするのでいまいち分からないし大変。 diff で比較する そういう時は gcloud コマンドで role の permission を得つつ、diff で比較するとよい $ gcloud iam roles describe ROLE で権限のリストが得られるので、これを diff -y で左右に並べる。 roles/bigquery.dataViewer と roles/bigquery.metadataViewer の違いは、 $ diff -y -W80 <(gcloud iam roles describe roles/bigquery.dataViewer) <(gcloud iam roles describe roles/bigquery.metadataViewer) description: Access to view datasets | description: Access to view table and etag: AA== etag: AA== includedPermissions: includedPermissions: - bigquery.datasets.get - bigquery.datasets.get - bigquery.datasets.getIamPolicy - bigquery.datasets.getIamPolicy - bigquery.models.export < - bigquery.models.getData < - bigquery.models.getMetadata - bigquery.models.getMetadata - bigquery.models.list - bigquery.models.list - bigquery.routines.get - bigquery.routines.get - bigquery.routines.list - bigquery.routines.list - bigquery.tables.createSnapshot < - bigquery.tables.export < - bigquery.tables.get - bigquery.tables.get - bigquery.tables.getData < - bigquery.tables.getIamPolicy - bigquery.tables.getIamPolicy - bigquery.tables.list - bigquery.tables.list - resourcemanager.projects.get - resourcemanager.projects.get - resourcemanager.projects.list - resourcemanager.projects.list name: roles/bigquery.dataViewer | name: roles/bigquery.metadataViewer stage: GA stage: GA title: BigQuery Data Viewer | title: BigQuery Metadata Viewer ほうほう、roles/bigquery.dataViewer はテーブルやモデルのスナップショットやエクスポートも取れるんですね。 includedPermissions 以下だけ欲しいなら --format オプションで中身だけ取ることもできる。 --format='value[delimiter="\\n"](includedPermissions)' gcloud の format オプションについてはこちら。 roles/browser と roles/resourcemanager.folderViewer の違いは、 $ diff -y \ <(gcloud iam roles describe roles/browser --format='value[delimiter="\\n"](includedPermissions)') \ <(gcloud iam roles describe roles/resourcemanager.folderViewer --format='value[delimiter="\\n"](includedPermissions)') > orgpolicy.constraints.list > orgpolicy.policies.list > orgpolicy.policy.get resourcemanager.folders.get resourcemanager.folders.get resourcemanager.folders.list resourcemanager.folders.list resourcemanager.organizations.get < resourcemanager.projects.get resourcemanager.projects.get resourcemanager.projects.getIamPolicy < resourcemanager.projects.list resourcemanager.projects.list フムフム。 多くの permission を持つ権限なら比較したい部分で grep すればいいですね。 roles/editor のうち、SecretManager で、roles/secretmanager.admin より弱いのは、 $ diff -y <(gcloud iam roles describe roles/editor | grep secretmanager) <(gcloud iam roles describe roles/secretmanager.admin | grep secretmanager) - secretmanager.locations.get - secretmanager.locations.get - secretmanager.locations.list - secretmanager.locations.list - secretmanager.secrets.create - secretmanager.secrets.create - secretmanager.secrets.delete - secretmanager.secrets.delete - secretmanager.secrets.get - secretmanager.secrets.get - secretmanager.secrets.getIamPolicy - secretmanager.secrets.getIamPolicy - secretmanager.secrets.list - secretmanager.secrets.list > - secretmanager.secrets.setIamPolicy - secretmanager.secrets.update - secretmanager.secrets.update > - secretmanager.versions.access - secretmanager.versions.add - secretmanager.versions.add - secretmanager.versions.destroy - secretmanager.versions.destroy - secretmanager.versions.disable - secretmanager.versions.disable - secretmanager.versions.enable - secretmanager.versions.enable - secretmanager.versions.get - secretmanager.versions.get - secretmanager.versions.list - secretmanager.versions.list > name: roles/secretmanager.admin roles/editor でも、secret に IAM Policy を設定することと、実際の version の読み取りができないのだな〜ということが分かる。 gcloud と diff を使うとこういう感じで比較できます。 適切なロールを選ぶとともに、IAM の推奨事項を見て絞ったりできるとよりよいですね。 cloud.google.com

Contributions

  • prebid/Prebid.js

    Adagio Adapter: set back to the original style after getSlotPosition

    Type of change Bugfix Description of change The Adagio adapter revert to the previous style of the element itself, rather than computed style. Details is the issue #9035. Resolves #9035 Other information

    pokutuna opened on 2022-09-25
  • prebid/Prebid.js

    Adagio Adapter: getSlotPosition breaks ad slot styles

    Type of issue Bug Description Since adding the Adagio adapter, I have found that some ad slots remain hidden. Adagio adapter sends adunit_position which means slot position from window.top with bid request. Adagio adapter temporarily set display: block to the slot element to compute its position, and then reverts to the previous computed style. Prebid.js/modules/adagioBidAdapter.js Lines 791 to 800 in 0acda04 const elComputedStyle = wt.getComputedStyle(domElement, null); const elComputedDisplay = elComputedStyle.display || 'block'; const mustDisplayElement = elComputedDisplay === 'none'; if (mustDisplayElement) { domElement.style = domElement.style || {}; domElement.style.display = 'block'; box = domElement.getBoundingClientRect(); domElement.style.display = elComputedDisplay; } This moves the style from the stylesheet to the elements and away from the control of the website to switch classes. This causes problems when ad slots have placed that switch between display states. For example, when a ad slot is placed in a collapsible sidebar or when content and an ad slot are switched by some condition. In this situation, the ad slot itself or the page part containing the ad slot may have display: none at bidding time and continue to retain the style by Adagio adapter. To avoid this problem, the adapter should revert to the previous style of the element itself, rather than computed style. Steps to reproduce Occurs when SafeFrame is not used and window.top is accessible. Prebid.js/modules/adagioBidAdapter.js Line 763 in 0acda04 } else if (canAccessTopWindow()) { 1. Starts with hidden ad slots <style> .is-hidden { display: none; } </style> <div id="slot1" class="is-hidden"></div> <div id="container" class="is-hidden"> <div id="slot2"></div> </div> 2. Adapter calculates slot positions <style> .is-hidden { display: none; } </style> <div id="slot1" class="is-hidden" style="display: block;"></div> <div id="container" class="is-hidden"> <div id="slot2" style="display: block;"></div> </div> 3. Adapter reverts styles to computed <style> .is-hidden { display: none; } </style> <div id="slot1" class="is-hidden" style="display: none;"></div> <div id="container" class="is-hidden"> <div id="slot2" style="display: none;"></div> </div> 4. Publisher site attempts to display by removing class <style> .is-hidden { display: none; } </style> <div id="slot1" class="" style="display: none;"></div> <div id="container" class=""> <div id="slot2" style="display: none;"></div> </div> Test page Expected results Actual results Platform details Other information When working with Google Ad Manager, gpt.js (pubads_impl_*.js) may eventually work correctly by updating the styles of elements (removing display: none for ad slot). However, problems occur when using other ad servers. It is better not to depend on the gpt.js behavior. And the fix is easy.

    pokutuna opened on 2022-09-25
  • genkiroid/cert

    Update install command

    Fixed installation commands in README. Installation executables by go get is deprecated in 1.17. https://go.dev/doc/go1.17#go-get no longer works in 1.18 https://go.dev/doc/go1.18#go-get Installation by go install is available from 1.16 (released 2021-02-16). It seems recent, but 1.16 is no longer supported.

    pokutuna opened on 2022-04-25
  • techtouch-inc/Go-SCP-jaJP

    fix: fix typo 切り捨てい → 切り捨て

    原文: https://github.com/OWASP/Go-SCP/blob/248f41d62b7cd17c0ea4f140546fe8888472ece1/src/input-validation/validation.md?plain=1#L138L139

    pokutuna opened on 2022-08-27