くりにっき

フルスタックキュアエンジニアです

IntelliJ IDEAなどのTerminalでvimを使うと壊れる件の回避策

前置き

IntelliJ IDEAなどでgit操作をする時はIDE内のTerminalを使っているのですが、1〜2週間前からcommitメッセージの入力とかでvimの挙動が急におかしくなったので調べた。

期待した挙動(Macのitem2)

実際の挙動(IntelliJ IDEA内のTerminal)

確認した環境

OS

macOS 14.5(Sonoma)

vimのバージョン

Homebrewでインストールしたvimが使われてそう

$ vim --version
VIM - Vi IMproved 9.0 (2022 Jun 28, compiled Oct 19 2023 08:52:34)
macOS 版 - arm64
適用済パッチ: 1-2049
Compiled by Homebrew

IDE

IntelliJ IDEA、RubyMine、Golandの下記バージョンで再現

  • 2023.2.4
  • 2024.1.1

分かったこと

手元の ~/.vimrc を消したらなおったので自分の ~/.vimrc *1に原因がありそうだった。

回避策

~/.vimrc の下記を消したらなおったが *2、これがないと今度はIDEAのTerminal以外でのvimで色が出なくなるので悩ましい、、、

syntax on
colorscheme desert

地域.rbカレンダーでconnpass APIの個人利用申請をした

tl;dr;

connpass APIの仕様変更で 地域.rbカレンダー を閉じるつもりでしたが、個人利用申請を行ったので2024年5月23日(木)以降もカレンダーが更新されます

時系列

今年の2月にconnpass APIの無償提供終了が発表

3月頃にプランが発表されて、料金体系が個人向けじゃなさそうなので地域.rbカレンダーを閉じる(connpassの有料APIに対応しない)ことを決意

この時点では固定IPアドレスも費用かかりそうできっついなあということで閉じる方針は継続。

これを見てRubyKaigi後に機運が高まった。*1(実質KaigiEffect*2

申請した2日後くらいに許諾された!!!

詳しいログ

github.com

具体的にやったこと

2024年5月23日(木)以降もConnpass APIを使うには固定IPアドレスが必要なので、その対応を行いました。

地域.rbカレンダーのカレンダー生成のエンドポイントはCloud Functionsで動いているため*3Serverless VPC Access Connectorを利用してCloud Functionからインターネットに出る時にCloud NATを経由して送信元のIPアドレスを固定化しました。

変更前後の構成は下記のような感じです。

Before

After

この図だと端折っていますが、送信元のIPアドレスが本当に固定化されているかの動作確認としてVPC内にVMを立てたりもしています。(Cloud NATはVPCからインターネットに出る時の送信元を全て固定IPアドレスにするので、VPC内にVMを立てても当然同じIPアドレスになる)

Terraform

具体的な方針は下記が参考になりました。

dev.classmethod.jp

これを参考に実装したのが下記のTerraformになります。

# VPC
locals {
  subnet_cidr = "10.128.0.0/20" # 10.128.0.0 - 10.128.15.255

  # Requires /28 for Serverless VPC Access Connector
  # c.f. https://cloud.google.com/vpc/docs/serverless-vpc-access
  vpc_access_connector_cidr = "10.128.16.0/28" # 10.128.16.0 - 10.128.16.15
}

resource "google_compute_network" "main" {
  name                    = "main"
  auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "main" {
  name          = google_compute_network.main.name
  network       = google_compute_network.main.self_link
  ip_cidr_range = local.subnet_cidr
  region        = "asia-northeast1"
}

resource "google_compute_router" "main" {
  name    = google_compute_network.main.name
  region  = google_compute_subnetwork.main.region
  network = google_compute_network.main.self_link
}

resource "google_vpc_access_connector" "main" {
  name          = "main"
  machine_type  = "f1-micro"
  ip_cidr_range = local.vpc_access_connector_cidr
  network       = google_compute_network.main.id

  # NOTE: requires 2+ instances
  min_instances = 2
  max_instances = 3
}

# Cloud NAT
resource "google_compute_router_nat" "main" {
  name   = google_compute_network.main.name
  router = google_compute_router.main.name
  region = google_compute_router.main.region

  nat_ip_allocate_option = "MANUAL_ONLY"
  nat_ips                = [google_compute_address.nat.self_link]

  source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
}

resource "google_compute_address" "nat" {
  name        = "nat"
  region      = google_compute_subnetwork.main.region
  description = "Static Address for Cloud NAT"
}

アプリケーション側(デプロイ時にFunctionをVPC Connectorに紐づける設定)は下記

github.com

ハマったポイント:Terraformでapplyする時だけなぜかエラーになる

具体的には下記のようなエラーです

│ Error: Error waiting to create Connector: Error waiting for Creating Connector: Error code 13, message: An internal error occurred: VPC Access connector failed to get healthy. Please check GCE quotas, logs and org policies and recreate.
│ 
│   with google_vpc_access_connector.main,
│   on vpc.tf line 27, in resource "google_vpc_access_connector" "main":
│   27: resource "google_vpc_access_connector" "main" {

設定自体は問題なさそうだし、なんなら全く同じ設定をコンソールから設定できたので本当に謎でした。( terraform apply でのみエラーになる)

Terraformで利用しているサービスアカウントに対して service-PROJECT_NUMBER@gcp-sa-vpcaccess.iam.gserviceaccount.com の「サービスアカウントユーザー( roles/iam.serviceAccountUser )」*4 のIAMロールが必要なのが原因でした。 *5

最後に

作った後で気づいたけど自分の用途だとオーバーテクノロジーだったかもしれないです。

似たようなことをやりたい人は参考にして下さい。

*1:このポストはRubyKaigi直前のものなんだけど機運が高まったのはRubyKaigi後

*2:https://togetter.com/li/162817

*3:icsを返すエンドポイントを自分のGoogle Calendarに登録してからGitHub Pagesで公開している

*4:https://cloud.google.com/iam/docs/understanding-roles#iam.serviceAccountUser

*5:https://cloud.google.com/vpc/docs/configure-serverless-vpc-access?hl=ja#service_account_permissions

kagaribiを作った

kagaribiって?

Cloud Firestoreを手軽に使うためのgemです。

https://github.com/petergoldstein/dallihttps://github.com/redis-rb/redis-client のようなシンプルなインターフェースでFirestoreにアクセスしたくて作りました。

github.com

元々は個人アプリで3〜4年くらいずっと使ってたやつでそのうちgem化しようとは思ってたんですが、いい感じのgem名が思いつかずに今に至ってました。

この度いい感じのgem名を思いついたのでgem化しました。

gem名の由来は「Firestore -> Fire -> 火 -> 篝火🔥*1」です。

使い方とかはREADMEを参照

頑張りポイント

Firestoreって普通に使ってるとたまに「Could not load the default credentials.」みたいなエラーが出てリトライするとなおるんですが、今まで運用してきて遭遇したそれ系のエラーはだいたい網羅してます。

https://github.com/sue445/kagaribi/blob/v0.1.0/lib/kagaribi/collection.rb#L111-L149

Switch用ファミリーコンピュータ コントローラーを本体以外でも充電したい

前置き

www.nintendo.com

このコントローラはSwitchの両サイドに1コンと2コンを挿して充電する方式です。

参考画像: https://news.denfaminicogamer.jp/news/240509l/attachment/img-main-02

本体以外でも充電したいことがたまにあるのでジョイコン充電器を探したんですが、ファミコンのコントローラーが普通のジョイコンよりもサイズが大きいため実際に充電できるやつを見つけるのに苦労しました。

比較した写真

元々はNintendo Switch Online加入者限定商品なんですが、今度一般発売されるらしい *1のでこの手の需要がありそうな気がしてメモ。

実際に充電できたやつ

実際にファミコンコントローラーを充電できた充電器はこちらになります。

探せば他にも色々ありそうだけど、確実に充電できるものが欲しい人はこれを買うといいと思います。

実際に買って試したけどダメだったやつ

最初に買ったやつがこれ。

ケーブルタイプなのでいけるかと思ったんですが、ファミコンコントローラーの充電端子の溝にうまく入らなくて充電できなかったです。

2024/07/18 11:00追記

ファミコンコントローラー対応の充電器が公式から発売されるようなのでこれでよさそう。

www.nintendo.com

RubyKaigi 2024 Mapを作った #rubykaigi

RubyKaigi 2024 関係のPartyが多すぎて把握しきれなくなったので自分用にGoogleマイマップにまとめた。

ブラウザで3rd party cookieが無効化されていると地図が見れないので、その場合は下記を見てください

www.google.com

備考

  • アイコンは各日付ごとに色分けしつつ、イベントの種類ごとにそれっぽい絵柄にしています(例:Drinkupは🍺など)
  • 日付ごとにレイヤーを分けているので、特定の日付のみ見たい場合は見たい日付以外のレイヤーを非表示にしてください

新しいPCを買った

コンテキスト

今まで使ってた私物のデスクトップPCは7〜8年前くらいに買ったやつなんだけど、数日前からHDDかCPU辺りから異音を発生するようになって(夜寝れないくらいうるさい)、いよいよ寿命が近いかなと悟って新しいデスクトップPCを買った。

これまでもPC起動後20分くらい経たないとまともに使えなかったり、どっかのタイミングでWindows Updateに失敗するようになってだましだまし使ってたんですが、異音がトドメになった。

誕生月なので実質自分への誕プレ

OLD

  • CPU: Intel Core i7
  • Memory: 8GB -> 16GB(購入後に増設)
  • Storage: 1TB (HDD)

NEW

僕は基本的に購入時にスペックガン積みする金の弾丸戦略をとってるんだけど、今売ってるメーカーPCは基本的にメモリ最大16GBが多くて最初から32GBのやつを探すのに苦労しました。

後から増設できるのは結構あったんだけど、どうせ増やすのは分かりきってるし自分でバラすとメーカー保証が効かなくなって嫌なので購入時に増やしたいんですよね...

スペックマシマシで購入できるのは調べた範囲だとNECしかなかったと思います。

https://www.nec-lavie.jp/products/desktop/lavie/dt/

Cloud Functionsのデプロイ時に使われるArtifact Registryで古いタグを削除する

前提

Google Cloudの Cloud Functions の第2世代ではデプロイする時には自動的に Artifact Registry にDockerイメージが作られます。

cloud.google.com

デプロイ時に自動的にDockerイメージを作ってくれるので利用者側では全然気にすることはないのですが、作られたイメージは消えないので頻繁にデプロイしているとDockerイメージが増えてArtifact Registryのストレージの費用が増えて気になっていました。

具体的にどれくらい費用かかっていたのかというと、週1回デプロイを1年間続けたらArtifact Registryだけで月1ドル前後かかるようになっていました。(Cloud Functions部分は無料枠におさまっているので0円)

業務だと全然無視していい費用感なんだけど個人プロダクトだと削りたかったので自動的に消す方法を仕込みました。

基本的にはTerraformでやる前提なので他の方法でやる場合には適宜読み替えてください。

手順1. Cloud Functionsが作ったArtifact RegistryのリポジトリをTerraformにimportする

TerraformでArtifact Registryの設定変更をするためには最初にimportする必要があります。

まずは適当なtfファイルに下記を書きます。

import {
  id = "asia-northeast1/gcf-artifacts" # TODO: 東京リージョン以外を使ってる場合は要修正
  to = google_artifact_registry_repository.gcf-artifacts
}

その後 terraform plan -generate-config-out=_generated.tf のようにコマンドを実行すればimport結果が _generated.tf に出力されます。

_generated.tf の中身はこんな感じ。

# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.

# __generated__ by Terraform from "asia-northeast1/gcf-artifacts"
resource "google_artifact_registry_repository" "gcf-artifacts" {
  cleanup_policy_dry_run = true
  description            = "This repository is created and used by Cloud Functions for storing function docker images."
  format                 = "DOCKER"
  kms_key_name           = null
  labels                 = {}
  location               = "asia-northeast1"
  mode                   = "STANDARD_REPOSITORY"
  project                = "XXXXXXXXXXXXXXX"
  repository_id          = "gcf-artifacts"
}

生成されたリソースを別のtfファイルに移動させれば_generated.tf は削除していいです。

手順2. Artifact RegistryにCleanup Policyを適用する

Cloud FunctionsでしばらくデプロイしているとArtifact Registryのリポジトリ

  • latestタグ
  • UUID形式のタグ
  • タグ無し

のような構成になります。

そのためlatestタグだけ残して他は全部消すような Cleanup Policy のルールを適用します。

Terraformだと下記のようになります。

locals {
  # "0" 〜 "f" の文字列を生成する
  hex_chars = [for i in range(0, 16) : format("%x", i)]
}

resource "google_artifact_registry_repository" "gcf-artifacts" {
  location      = "asia-northeast1"
  repository_id = "gcf-artifacts"
  description   = "This repository is created and used by Cloud Functions for storing function docker images."
  format        = "DOCKER"
  mode          = "STANDARD_REPOSITORY"

  cleanup_policy_dry_run = false

  # latest tagは常に残す
  cleanup_policies {
    id     = "keep-latest"
    action = "KEEP"

    condition {
      tag_state    = "TAGGED"
      tag_prefixes = ["latest"]
    }
  }

  # tag無しは全て削除する
  cleanup_policies {
    id     = "delete-all-untagged"
    action = "DELETE"

    condition {
      tag_state = "UNTAGGED"
    }
  }

  # UUID形式のタグを全て削除する
  cleanup_policies {
    id     = "delete-hex-prefix-tags"
    action = "DELETE"

    # FIXME: Cleanup Policyでは正規表現が指定できないので0〜fで始まるものは全てUUIDとみなす(残したいlatestはマッチしないので一応問題ない)
    condition {
      tag_state    = "TAGGED"
      tag_prefixes = local.hex_chars
    }
  }
}

コメントにも書いてるけどCleanup Policyでは正規表現が使えないのでUUID形式のタグを消す部分はかなりの力技です...(UUIDで取りうるアルファベットはa〜fなのでlatestが消えずに済んでいる)

Terraform読めない人向けに一応 gcloud artifacts repositories list-cleanup-policies コマンドの結果も載せておきます。

$ gcloud artifacts repositories list-cleanup-policies gcf-artifacts --location asia-northeast1
Listing items under project XXXXXXXXXXXXX, location asia-northeast1, repository gcf-artifacts.

Dry run is disabled.
[
  {
    "action": {
      "type": "DELETE"
    },
    "condition": {
      "tagState": "UNTAGGED"
    },
    "name": "delete-all-untagged"
  },
  {
    "action": {
      "type": "DELETE"
    },
    "condition": {
      "tagPrefixes": [
        "0",
        "1",
        "2",
        "3",
        "4",
        "5",
        "6",
        "7",
        "8",
        "9",
        "a",
        "b",
        "c",
        "d",
        "e",
        "f"
      ],
      "tagState": "TAGGED"
    },
    "name": "delete-hex-prefix-tags"
  },
  {
    "action": {
      "type": "KEEP"
    },
    "condition": {
      "tagPrefixes": [
        "latest"
      ],
      "tagState": "TAGGED"
    },
    "name": "keep-latest"
  }
]

他のソリューション

Artifact RegistryにCleanup Policyが導入されるまでは https://github.com/GoogleCloudPlatform/gcr-cleaner を使っていましたが、こっちはもうメンテされていないので基本的にはCleanup Policyを使うのがいいと思います。

とはいえgcr-cleanerは正規表現でタグ指定ができるのが便利なのでどうしても正規表現を使いたい場合にはこっちを使うことになりそう。(早くCleanup Policyでも正規表現対応されてほしい...)