GAミント至上主義

Web Monomaniacal Developer.

JavaScript (TypeScript) のMapをObjectに変換する

TypeScriptで素のObjectよりMapの方がTypeScriptと相性がよく使う機会が増えてきたけど、レスポンスに変換するときなどはObjectに変換する必要があったのでメモ。

ぐぐったらreduceとか使う古いのが検索上位に出てきてしまうが、
Map.prototype.entries()Object.fromEntries()に渡すというシンプルな組合わせでできる。

Map - JavaScript | MDN

Object.fromEntries() - JavaScript | MDN

以下はChromeのconsoleなのでJavaScriptで試したけどTypeScriptでも同じようにできる。

const map = new Map()
>undefined
map.set(1, 'one')
>Map(1) {1 => 'one'}
map.set(2, 'two')
>Map(2) {1 => 'one', 2 => 'two'}
map.set(3, 'three')
>Map(3) {1 => 'one', 2 => 'two', 3 => 'three'}
map.entries()
>MapIterator {1 => 'one', 2 => 'two', 3 => 'three'}
Object.fromEntries(map.entries())
>{1: 'one', 2: 'two', 3: 'three'}

reduced使うやつ
https://qiita.com/mktoho-n/items/6b96674c9c7ba542d2be

CircleCIからCloud Runにデプロイするときにハマった3つのエラー

CircleCIを使っていてCloud Runが必要になったので設定したけど、いくつかハマったのでメモ

前提

この公式Orbsを使用する。

CircleCI Developer Hub - circleci/gcp-cloud-run

.circleci/config.ymlはこんな感じ。本番でなくステージング環境を作ってるので環境変数は変えてある。

version: 2.1
orbs:
  gcp-cloud-run: circleci/gcp-cloud-run@1.0.2

jobs:
// 省略
  deploy-cloud-run-staging:
    docker:
      - image: 'cimg/base:stable'
    steps:
      - checkout
      - gcp-cloud-run/init:
          gcloud-service-key: GCLOUD_SERVICE_KEY_STAGING
          google-project-id: GOOGLE_PROJECT_ID_STAGING
      - gcp-cloud-run/build:
          config: ./cloudbuild.yml

GCPのプロジェクトでサービスアカウントを作り、キーやプロジェクトIDなどはCircleCIの環境変数に設定済み。

今回モノレポなプロジェクトでDockerfileの場所とコンテキストの場所が異なるけど、Orbの設定ではできなさそうだったので、cloudbuild.ymlが必要になった。

シンプルにビルド、プッシュ、デプロイの3アクション。

cloudbuild.yml

steps:
  - id: "build the container image"
    name: "gcr.io/cloud-builders/docker"
    args: ["build", "-t", "gcr.io/${PROJECT_ID}/api-staging:${BUILD_ID}", "-f", "./Dockerfiles/api/Dockerfile", "."]

  - id: "push container image"
    name: "gcr.io/cloud-builders/docker"
    args: ["push", "gcr.io/${PROJECT_ID}/api-staging:${BUILD_ID}"]

  - id: "deploy to Cloud Run"
    name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: gcloud
    args: ['run', 'deploy', 'api-staging', '--image', 'gcr.io/${PROJECT_ID}/api-staging:${BUILD_ID}', '--region', 'asia-northeast1']

Cloud Buildは成功しているのにCircleCIでエラー

ログを表示しようとしてるのにサービスアカウントに権限がなくてエラーになってる模様。

Uploading tarball of [.] to [gs://********************_cloudbuild/source/*****************.tgz]
Created [https://cloudbuild.googleapis.com/v1/projects/********************/locations/global/builds/*****************.].
Logs are available at [https://console.cloud.google.com/cloud-build/builds/*****************?project=************].
ERROR: (gcloud.builds.submit) 
The build is running, and logs are being written to the default logs bucket.
This tool can only stream logs if you are Viewer/Owner of the project and, if applicable, allowed by your VPC-SC security policy.

The default logs bucket is always outside any VPC-SC security perimeter.
If you want your logs saved inside your VPC-SC perimeter, use your own bucket.
See https://cloud.google.com/build/docs/securing-builds/store-manage-build-logs.


Exited with code exit status 1
CircleCI received exit code 1

よく読むと答えが書いてあり

This tool can only stream logs if you are Viewer/Owner of the project

プロジェクトのオーナーか参照の権限をサービスアカウントに追加が必要。もちろん参照でいいので追加して解決。

Cloud Buildのログを出すだけなのに、プロジェクト全体が必要とはちょっと大げさな権限だなぁ。

Cloud Runにデプロイ時に権限かサービスがなくてエラー1

Step #2 - "deploy to Cloud Run": gcr.io/google.com/cloudsdktool/cloud-sdk:latest
Step #2 - "deploy to Cloud Run": ERROR: (gcloud.run.deploy) PERMISSION_DENIED: Permission 'run.services.get' denied on resource 'namespaces/********************/services/api-staging' (or resource may not exist).
Finished Step #2 - "deploy to Cloud Run"
ERROR
ERROR: build step 2 "gcr.io/google.com/cloudsdktool/cloud-sdk" failed: step exited with non-zero status: 1


BUILD FAILURE: Build step failure: build step 2 "gcr.io/google.com/cloudsdktool/cloud-sdk" failed: step exited with non-zero status: 1
ERROR: (gcloud.builds.submit) build bc02f3af-d341-4af1-98cb-0e2d396078a4 completed with status "FAILURE"

単純に最初なのでCloud Runのサービスが存在しない。

最初は手作業でサービス作って解決、と思ったらだめだった。

こちらを参考にCloud BuildのサービスアカウントにCloud RunのAdminをつけて解決するはず、と思ったらだめだった。 stackoverflow.com

Cloud Runにデプロイ時に権限かサービスがなくてエラー2

1をやったらエラーが変わった。

Step #2 - "deploy to Cloud Run": ERROR: (gcloud.run.deploy) PERMISSION_DENIED: Permission 'iam.serviceaccounts.actAs' denied on service account *****-compute@developer.gserviceaccount.com (or it may not exist).

ググると解決策が出てくるけどiam.serviceaccounts.actAsが見つからない。 stackoverflow.com

ロール作成画面でフィルタするも出てこないのでiamだけでフィルタし、ページ送りしまくったらやっとみつかったので、カスタムロールを作成。 f:id:uyamazak:20220107111632p:plain

Cloud Buildでイメージのタグにコミットハッシュが使えなくてエラー

昔作った設定を参考に、イメージのバージョンに$COMMIT_SHAなどを使っていたけど、今回はGitレポジトリのフックではなくコマンド経由なせいか存在せず、空白になってしまいエラー。

Already have image (with digest): gcr.io/cloud-builders/docker
invalid argument "gcr.io/*****api-staging:" for "-t, --tag" flag: invalid reference format
See 'docker build --help'.

Substituting variable values  |  Cloud Build Documentation  |  Google Cloud

にある通り、絶対に使えるのは下記3つだけで、ビルドごとに異なるのはBuild IDだけなので必然的にそれを使うことにして解決。

$PROJECT_ID: Cloud プロジェクトの ID

$BUILD_ID: ビルドの ID

$PROJECT_NUMBER: プロジェクトの番号

2021年振り返り

GitHub統計

シニアジョブのレポジトリには3,028回コミットしてた

f:id:uyamazak:20211229162740p:plain

出社回数

健康診断と新規採用の顔合わせで2回?

ざっくり時系列

会社のメインのレポジトリは通年ちょこちょこやってたのでそれ以外

1−3月

会社が歌舞伎町に引っ越しで、NuxtJS + Google App Engine + Googleスプレッドシートで受付システム作ってた。

Google Apps ScriptとNuxtJSで簡易来客受付システムをつくったら実質サーバーコスト無料だった - GAミント至上主義

業務に必要なデータを集めるためにWEBサイトのスクレイピングをPuppeteerとTypeScriptでやってた。

Puppeteer + TypeScriptでWEBサイトをスクレイピングしたメモ - GAミント至上主義

スタンディングデスク導入

2月からスタンディングデスクに移行した。2021年12月でも使用中で腰の痛みから開放された。 1年過ぎたら別記事にしたい

4−7月

AWSAWS Elastic Beanstalkで動いているメインのシステムをFargate化しようと格闘してた。 それは完了できず、他の人に引き継いでいるけど、下記のサテライトサイトはFargateで動いてる。 AWSはTerraform必須なのを実感。

サテライトサイト作成

uyamazak.hatenablog.com

主力の業種である会計に特化した求人検索サイトをNuxtJS 2とComposition APIで作ってた。

サーバーサイドは既存のLaravelに追加する形だったけどPHPとTypeScriptの往復はつらかった記憶。

あと長男生まれた

とりさん地図アプリ

Viteを試すのと自身の埼玉力を上げるために作り始めた。

地図部分はできたけど、肝心のテキストコンテンツを作っていくところで、長男誕生とNestJSの新プロジェクトがはじまってリソース不足で止まってしまっている。

8−12月

新しい求人サービスのプロジェクトを開始。

NestJS + NuxtJSの両方TypeScriptの構成。NestJSに関しては完全に未経験で、情報も少ないため、最初は依存解決とかで難航したけど 慣れてくるとフロントとサーバーの型共有や、GraphQLも使って非常に快適な開発ができた。

NestJS自体はまさにフレームワークという言葉どおり、いろんなNode.jsの有名ライブラリを必要に応じて組み合わせていくための枠組みといった感じで、

細かい実装自体には、RoRみたいにこうすればよい、っていうのがほとんど無く、技術力が求められるものだと感じた。

雑につぶやいたら、日本語なのにCore Teamの人がメンションくれたの驚いた。

ドキュメントが本当によくできてる。

また、Firebaseの利用(Auth、Storage)、初めてのElasticsearchの新規構築、E2Eテスト環境構築(DB、Elasticsearch、Firebaseエミュレータ等、モックではなく全部動く)、 CIの活用(E2Eテストやlintはもちろんマイグレ差分検知など)等、やりたいと思ってた理想を全部実現できてる感じがする。いい職場だなぁ。

既存のシニアジョブに続いて、2つ目の大きなサービスとなる予定だけど、求人ドメインに関する6年?以上の知見がある分 最初の要求が非常に大きなものになってしまい、データ設計、選択項目などのマスターデータ等が最初から巨大になってしまうという問題を実感した。

DBのテーブル設計に時間をかけてしまったけど、もっと早く部分的にでもフロントからDBまで、通しで動く状態にするべきだったなぁという教訓。

社内向け管理画面は現時点でベータ版のNuxt3を使って作っているけど、ViteやNitroをはじめ快適すぎてもう昔には戻れないので、ユーザー側もNuxt3で行きたいなぁという気持ち。

仕事着探し

新生児+3歳児+リモートワークで服に限界を感じていたので、至高の日本製ジャージや、リモートワーク用作業着などを探求してた。

コスパはもちろん、耐久性、汚れ耐性、動きやすさ等引き続き探求したい。

芸人も愛用のカネマスの2本線ジャージと、バートルの作業着7051シリーズはいいぞ。

Macbook Pro 16インチ M1 Pro

キーボードもバッテリーも限界がきてた2017年のMacbookPro 15インチ(ESCキーがタッチバー)から買い替えてもらって、ESCキーが物理キーになった。

ARM系のM1になったので心配してたけど、開発環境はMySQLのDockerが動かなかったのをMariaDBにしたぐらいで思ったより何事もなかった。

あとESCキーが物理キーになって、各ビルドやDocker系の動作など待ち時間が短縮されたのと、ESCキーが物理キーになった。

ARM普及していくとラズパイもいろいろ便利になったりクラウドもARM化が進行しそう。

2022年

社長がAdobe XD始めたり、デザインに力を入れてきたので、そっちも力をつけていきたい。

デザイン強めのフロントエンジニアの方にいろいろ教えてもらいたい。

NestJSにだいぶお世話になってるので何かコミュニティ活動したいなぁ。

あと年明けから経験浅めの新しい人入るので、能力発揮できるよう手伝っていきたい。フルリモートでどうやろう