椅子と机が最終形態になった

椅子と机が最終形態となりました。

もう、壊れない限りは「他のものが欲しい」とならないと思います。

Mirra 2 Chairs

椅子です。

www.hermanmiller.com

2020年にリモートワークが増えることになったことをきっかけに購入しました。

会社ではとても良い椅子を提供してもらっていたので、それがなくなると身体的に大変なことになるかも?と思っていろいろ調べていた記憶があります。

当時、各所で椅子購入ブームだったので、得られる情報も多くとても迷いました。

決め手はハーマンミラーというブランドへの信頼と、調節要素の多さでした。

というのも椅子は奥さんと共有して使用する予定だったので*1、それぞれの体型や姿勢にあった調整ができたほうが良いだろうと考えました。

さらに、コロナ禍で店舗もあまり空いておらず、椅子ブームで在庫もなく、結局「座って確認」ができませんでした。そう言った意味でもブランドへの信頼や調節要素によるバッファが重要になりました。

結構な賭けでしたが購入を決断し、結果としてはとても満足して座れています。

PREDUCTS DESK - METRO / FlexiSpot E7

机です。

DESK - METRO / FlexiSpot E7preducts.jp

どの経路で知ったのかは覚えていないのですが、「PREDUCTSという会社ができてモジュール式のデスクを販売するよ」というのを知ってから、ずっとウォッチしていました。

note.com

「この机が欲しい」なんてことは今までの人生で思ったことがなかったのですが、これは欲しいと思ってしまい時々眺める日々。

実はそれまでのリモートワークでは奥さんが持ち込んだ机を共用させてもらっていました。

そろそろ「机もちゃんと別にあったほうがいいよね」と思いはじめたとても良いタイミングで昇降デスク版が出てしまい(?)、とても高い買い物なのでものすごく悩んだのですが、購入ボタンを押しました。

TwitterのTLを見ていると若干FORESTのほうが人気みたいなのですが、私はMETROを選択しました。

天板は艶消しブラックのメラミン化粧板らしいのですが、手触りもよく大満足です。

また、PREDUCTS代表のGo Andoさんの真似をしてキャスターをつけています。

私の部屋は広くないので「机の左右に人が立って机を持ち上げる」ということができないため、掃除や模様替えで苦労するかもしれないので念のためというのが理由です。

キャスターは重い昇降デスクを支えることになるので、何も考えずFlexiSpotが推奨しているものにしました。

flexispot.jp

「机にキャスターをつける」これが大成功で「気分によって机の位置を変える」こともできそうなくらい簡単に移動できるようになりました*2

そして今は「何でもかんでも机の下にぶら下げたい病」にかかっています。

電源やスマホ以外にもウェットティッシュボックスとハンディワイパーボックスは成功しました。山崎実業のマグネット付きのボックスがいい感じです。

残念ながらレールには直接マグネットでつけることはできませんでしたが、トレイやデスクの脚にはつけれるので貼り付けています。

ベーススライダーに適当な鉄製の小さめのボードをつけてもいけそうです。

今はゴミ箱をどうにかしていい感じにぶら下げられないかなあと思っています(今はフックスライダーにゴミ袋をかけているだけ)。

これからもDIYなしに拡張ができそうで楽しみです。

本当に良いものをずっと使うということ

私は「良いものをずっと使う」という考えを持っていなくて「リーズナブルで良さそうなものを使う」という感覚でした。

一方で奥さんは「良いものを大切にずっと使う」を地で行く人です。

彼女は時々(私にとっては)高い買い物をしていてびっくりするのですが、その一方で使っているものが実は10年以上(下手したら20年以上)使い続けているものだったりしてもっとびっくりします(そうは見えないくらい綺麗に使っているのですが事実そうなのです)。そういった長寿なものがたくさんあります。というかそういったものばかりな気がするな。。。

大切に長く使えるのであれば本当に良い物にお金を払うのはトータルで満足度が高いんだなあと思いました。

私はなかなか「大切に使う」が下手なのですが、「良いものを大切にずっと使う」を実践している彼女を見ると実践してみたい、見習いたいと思います*3

今回、椅子と机が本当に良い物(そしてお気に入り)になったので、大切に使っていこうと思います。

そういえば

他に最終形態になったものとして、バックパックがあるのですがこちらもずっと満足して使えています。こちらも良い物だった。

k1low.hatenablog.com

追記

「写真がない」というコメントをいただいたので貼っておきます*4

*1:今は別々になりました

*2:まだその機会は訪れていません

*3:PREDUCTS DESKの購入に悩んでいる時も「ずっと使うんでしょ?だったら月1万円で15ヶ月と考えたら余裕じゃないの?」と言われて購入に踏み切った気がします。よく考えたら5年も10年もずっと使う物だった。

*4:写真下手で椅子と机に申し訳ない...

PHPerKaigi 2022でGitHub Actionsについて発表した #phperkaigi

参加してきましたPHPerKaigi 2022

phperkaigi.jp

感想

一言で言うと「オフライン参加の人たちが羨ましい!!!」でした。

オンライン開催でも本当に参加してよかったと思えたのですが、時折垣間見えるオフライン参加の人たちのワイワイ感が楽しそうでした。

オンライン参加しなかったのは完全に自分の選択であって誰のせいでもないのです。ただ、「オンラインでも楽しいけど、やっぱりオフライン楽しいんだな」という感じです( ep 67 @fortkle @o0h_と、私の尊敬する若手スペシャル by Yokohama North AM でも楽しそうに語っていて羨ましかったです)。

逆にオンラインの場を設けてもらって、地方勢や家庭イベント勢には本当にありがたいと思いました*1

GitHub Actions Deep Dive using PHP

今回はGitHub Actionsについてちょっとだけ濃い話を発表してきました。

私は、自分のOSSのCI/CD環境だけでなく所属会社であるGMOペパボでもGitHub Actionsにどっぷりなので「多分普通よりもGitHub Actionsを使っているだろう」ということで発表題材にしました。

Upload Artifact

発表の中では余談として話した「Upload ArtifactはAPIドキュメントにない」というお話ですが、なぜこんなマニアックな挙動を調べたかというと、「Artifactを使った実装を自作Actionで完結させて提供したかったから」です。

具体的には何に使っているかと言うと octocov のコードメトリクスレポートの保存先です。Artifactを使うことでリポジトリ内で完結した状態で、外部サーバやストレージなどに頼らずにPRごとにカバレッジの差分表示などを出すことができるので便利なのです。

言語はGoですが、Upload Artifactの実装はパッケージに切り出していますので、「Artifactを使った実装を自作Actionで完結させて提供したい」という奇特な方はご利用ください。

github.com

New Action

発表のインパクトになればいいなーと、今回の発表のためだけに2つActionを作成しました。

github.com

github.com

とはいえサンプルなどではなく、一応ちゃんと作ったつもりですので使うタイミングがあったらぜひ使ってみてください(マーケットプレイスにちゃんと登録しないとだ)。

私がGitHub Actionsに抱いているイメージ

これは賛同する人は少ないかもなのですが、私がGitHub Actionsに抱いているイメージは「CI/CD」というよりも「Serverless」です。

なんというかそれ自体の使い勝手が良いのと、コンピューティングリソースの運用をしなくていいので*2、なんでもかんでもGitHub Actionsで完結させたくなります。

「ハンマーを持つと全てが釘に見える」というアレですね。

これからも「いち実行環境」として便利に使っていくんだろうなと思います。

PHPerKaigi 2022 お疲れさまでした!!

運営の皆さん、発表者の皆さん、参加者の皆さん、お疲れさまでしたー!

楽しかったです!

*1:ただ、ただ、モジュラモノリス発表x2の合同アフタートークがあったりしたらしく、それは聞きたかったなーと

*2:正確には他の誰かに丸投げしている

PHPerKaigiが好きな理由 #phperkaigi

PHPの名を冠していて、それでいていろいろな技術に対して門戸を開いているところが好きです。

(ほぼ)元PHPerであるからなのですが、なんとなくPHPに関われている気がして嬉しいのです。

他のコミュニティや勉強会やカンファレンスも好きなところはたくさんありますし、他にも幅広い技術の話題を取り上げてくれるカンファレンスはあるので(PHPカンファレンス福岡とか)、「PHPerKaigiだけ」というわけではないのですが、少なくとも私がPHPerKaigiの好きなところの1つです。

あと、程よい距離感も好きです。

forteeの充実した機能も好きです。

運営の人の動きや頑張りが(たまたまですが)私のTwitter TLで見ることができるのも好きです。

今年はオンライン/オフラインのハイブリッド開催です。私はオンラインでの参加になりますが、今回も楽しみです。

phperkaigi.jp

今回もタイムテーブルを見る限り、多少のPHPの軸足がありつつも発表内容の幅は広そうです。

forteeの機能によってプロポーザルに星をつけたセッションには、そのままタイムテーブルに☆マークがついているので便利です。

あと、オンラインの人たちの野良懇親会とかもあれば参加したいなあと思っています。

まだ若干チケットはあるみたいなので、参加してみんなで楽しみましょう。

データベースにクエリを投げて結果をプリントするライブラリqpを作った

データベースを伴うテストを書いていて、何故かテスト結果が安定しない事象に出くわして「なんでだ?????」と混乱した結果、データベースの状況をprintデバッグをしたくなって作りました*1

github.com

使い方は

package main

import (
    "database/sql"
    "log"

    "github.com/k1LoW/qp"
    _ "github.com/mattn/go-sqlite3"
)

func main() {
    db, err := sql.Open("sqlite3", "path/to/db")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    qp.Print(db, "SELECT * FROM users WHERE username = 'alice'")
}

みたいにqp.Print()*sql.DB と実行したいクエリを渡すと、

$ go run main.go
+----+----------+----------+-------------------+---------------------+---------+
| id | username | password |       email       |       created       | updated |
+----+----------+----------+-------------------+---------------------+---------+
|  1 | alice    | passw0rd | alice@example.com | 2017-12-05 00:00:00 | <nil>   |
+----+----------+----------+-------------------+---------------------+---------+
(1 row)

のように結果がでるシンプルなものです。SELECT だけ結果をだしますが、他のクエリでもデータベースに投げるようにしています。

私のように混乱しないとなかなか必要になることはないと思いますが、「Goのコードからデータベースにクエリをカジュアルに投げてデバッグしたい」というときがあれば使ってみてください。

*1:原因は、単純にgo test ./... がパッケージ単位で並列に実行されるのに対して別のパッケージで同じテストデータベースにクエリを投げていたからでした...

ファイルの一部の文字列を差し替えするためのコマンド/パッケージ repin を作った

継続的ドキュメンテーション関連です。

README.mdなどのドキュメントを運用していると、そのドキュメントの一部を(CIなどで)自動で差し替えたいことがあります。

例えば xxx help コマンドの出力をもって機能一覧にしているようなREADMEだと、機能が追加されるたびに xxx help の実行結果でREADMEを差し替える必要があります。

ちょっと前に作った dirmap も出力結果をREADMEに貼っておきたい系のツールです。

k1low.hatenablog.com

そういう「文字列の差し替え」というのはsedでもある程度可能ですが、エスケープが難しかったり複数行の置換もなかなか覚えられないので専用ツールを書きました。

github.com

repin

例えば

# Hello

```console
```

みたいなMarkdownファイルがあったとして、$ echo hello world! という文字列を入れたいとき、GNU sedだと

$ cat README.md | sed -z 's/```console.*```/```console\n$ echo hello world!\n```/'

と書けば

# Hello

```console
$ echo hello world!
```

と出力されます。

これを repin で書くと

$ repin README.md -k '```console' -k '```' -r '$ echo hello world!'

となります。多少直感的になります。

また、置換文字列を標準入力で受け取れるので、

$ repin --help | repin README.md -k '```console' -k '```'

とすれば

# Hello

```console
repin is a tool to replace strings between keyword pair.

Usage:
  repin [FILE] [flags]

Flags:
  -h, --help              help for repin
  -i, --in-place          edit file in place
  -k, --keyword strings   keywords to use as a delimiter. If 1 keyword is specified, it will be used as the start and end delimiters; if 2 keywords are specified, they will be used as th\
e start and end delimiters, respectively.
  -N, --no-newline        disable appending newlines
      --raw-keywords      do not convert \n or \t of the entered keywords
  -r, --replace string    replace file path or string
  -v, --version           version for repin

```

と、複数行の help コマンドの出力を差し込んだMarkdownが得られます(これをGNU sedですることが私には難しかった)。

パッケージとしての利用

repinはパッケージとしての利用もできるようにしています*1

pkg.go.dev

というわけで

小さいコマンド/パッケージの紹介でした

*1:これは、 https://github.com/k1LoW/ndiag に組み込んでドキュメンテーション生成の仕組みをもう少しシンプルにしたいという思惑があるのですがまだ取りかかれていません

Colima on ARM Macでaarch64とx86_64のDocker環境を切り替えて使う

Colimaにはプロファイル( profile )という概念があり、--profile によってVM環境を切り替えることができます。

また --arch オプションでVMのイメージを切り替えることも可能です。

上記を利用してaarch64とx86_64のDocker環境を両方準備してみます。

方針

ARM Macなので基本的には aarch64(ARM)をデフォルトにします

profile ISA
default aarch64
x64 x86_64

各環境を作成

まずaarch64の環境を作成します。

$ colima start --cpu 8 --memory 8 --disk 128 --mount '~/src/:w' --mount '~/tmp:w' --dns 8.8.8.8

次にx86_64の環境を x64 というプロファイル名をつけて作成します。

$ colima start --profile x64 --arch x86_64 --cpu 8 --memory 8 --disk 128 --mount '~/src/:w' --mount '~/tmp:w' --dns 8.8.8.8

この時点で以下のようになっています

$ colima list
PROFILE    STATUS     ARCH       CPUS    MEMORY    DISK
default    Running    aarch64    8       8GiB      128GiB
x64        Running    x86_64     8       8GiB      128GiB

ColimaはLimaのラッパーなので limactl でも確認してみます。

$ limactl list
NAME          STATUS     SSH                ARCH       CPUS    MEMORY    DISK      DIR
colima        Running    127.0.0.1:52650    aarch64    8       8GiB      128GiB    /Users/k1low/.lima/colima
colima-x64    Running    127.0.0.1:58188    x86_64     8       8GiB      128GiB    /Users/k1low/.lima/colima-x64

docker context list をみるとホストのdockerがどのDockerのエンドポイントを向いているのかがわかります。

$ docker context list
NAME            DESCRIPTION                               DOCKER ENDPOINT                               KUBERNETES ENDPOINT   ORCHESTRATOR
colima          colima                                    unix:///Users/k1low/.colima/docker.sock
colima-x64 *    colima [profile=x64]                      unix:///Users/k1low/.colima-x64/docker.sock
default         Current DOCKER_HOST based configuration   unix:///var/run/docker.sock                                         swarm
desktop-linux                                             unix:///Users/k1low/.docker/run/docker.sock

colima-x64* がついているので、今は x86_64 環境を向いています。

contextの切り替えは docker context use [NAME] で切り替え可能です。

これで、Colima on ARM Macでaarch64とx86_64のDocker環境を切り替えて使えるようになりました。

--profile=x64 の環境ではx86_64のDockerイメージしかない mysql:5.7 なども動きます。

ベンチマーク

せっかくなのでベンチマークも取ってみます。

aarch64 環境

$ docker context use colima
colima
Current context is now "colima"
$ docker container run -it --rm --name debian-bullseye debian:bullseye /bin/bash
Unable to find image 'debian:bullseye' locally
bullseye: Pulling from library/debian
c7869242ae9a: Pull complete
Digest: sha256:10b622c6cf6daa0a295be74c0e412ed20e10f91ae4c6f3ce6ff0c9c04f77cbf6
Status: Downloaded newer image for debian:bullseye
root@faabf0fd5dcf:/# apt -y update && apt -y install sysbench
[...]
root@faabf0fd5dcf:/# uname -a
Linux faabf0fd5dcf 5.10.93-0-virt #1-Alpine SMP Thu, 27 Jan 2022 09:34:38 +0000 aarch64 GNU/Linux
root@faabf0fd5dcf:/# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
root@faabf0fd5dcf:/# sysbench cpu --cpu-max-prime=10000 --threads=8 --time=30 run
sysbench 1.0.20 (using system LuaJIT 2.1.0-beta3)

Running the test with following options:
Number of threads: 8
Initializing random number generator from current time


Prime numbers limit: 10000

Initializing worker threads...

Threads started!

CPU speed:
    events per second: 64490.28

General statistics:
    total time:                          30.0003s
    total number of events:              1934753

Latency (ms):
         min:                                    0.09
         avg:                                    0.12
         max:                                   21.01
         95th percentile:                        0.46
         sum:                               239149.80

Threads fairness:
    events (avg/stddev):           241844.1250/1938.40
    execution time (avg/stddev):   29.8937/0.01

root@faabf0fd5dcf:/#

x86_64 環境

$ docker context use colima-x64
colima-x64
Current context is now "colima-x64"
$ docker container run -it --rm --name debian-bullseye debian:bullseye /bin/bash
[...]
root@be6276f3da26:/# uname -a
Linux be6276f3da26 5.10.93-0-virt #1-Alpine SMP Thu, 27 Jan 2022 09:34:38 +0000 x86_64 GNU/Linux
root@be6276f3da26:/# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
root@be6276f3da26:/# sysbench cpu --cpu-max-prime=10000 --threads=8 --time=30 run
sysbench 1.0.20 (using system LuaJIT 2.1.0-beta3)

Running the test with following options:
Number of threads: 8
Initializing random number generator from current time


Prime numbers limit: 10000

Initializing worker threads...

Threads started!

CPU speed:
    events per second:  1077.72

General statistics:
    total time:                          30.0053s
    total number of events:              32340

Latency (ms):
         min:                                    3.38
         avg:                                    7.41
         max:                                   37.02
         95th percentile:                       13.22
         sum:                               239622.11

Threads fairness:
    events (avg/stddev):           4042.5000/46.19
    execution time (avg/stddev):   29.9528/0.01

root@be6276f3da26:/#

x86_64 on ARM はやはり遅いか......

参考

blog.amedama.jp

awsdoに ~/.aws/(config|credentials)の設定情報がなくてもAssumeRoleできるようにするためのオプションと、AssumeRoleしたロールでAWSコンソールにログインするオプションを追加した

1年以上前からの久しぶりのアップデートです。

k1low.hatenablog.com

--role-arn --source-profile

複数のAWSアカウントを横断して作業することがあり、AssumeRoleのための設定を~/.aws/(config|credentials)に書くのすら面倒になってきたので、設定なしでAssumeRoleができるようにするためのオプション --role-arn--source-profile を追加しました。

委任元のアカウントAのロール arn:aws:iam::AAAAAAAAAAAAAA:role/example-role を委任先のアカウントBに委任できるようにしている場合、

委任先のアカウントBの設定が ~/.aws/(config|credentials) にある場合は( profile-b )、

$ awsdo --role-arn=arn:aws:iam::AAAAAAAAAAAAAA:role/example-role --source-profile=profile-b -- aws ec2 describe-instance-status

と書けばいいし、アカウントBの設定がなくてもクレデンシャルがあれば

$ env AWS_ACCESS_KEY_ID=BBBBBbbbBBbBb AWS_SECRET_ACCESS_KEY=bbbbBBBbBBBBBBBB awsdo --role-arn=arn:aws:iam::AAAAAAAAAAAAAA:role/example-role -- aws ec2 describe-instance-status

と書けばAssumeRoleをした上でコマンドを実行できます。

設定を書かなくてもAssumeRoleできるということは、シェルスクリプトの一部だったりとかCIで実行したりなどがやりやすくなります。

例えばGitHub Actionsだと以下のようなワークフローでOIDC Connectして認証しながらさらにAssumeRoleしてコマンド実行ができたりします(未検証)。

name: AWS example workflow
on:
  push
permissions:
  id-token: write
  contents: read
jobs:
  assumeRole:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT }}:role/example-role
          aws-region: ${{ secrets.AWS_REGION }}
      - name: Run as ${{ secrets.AWS_ACCOUNT }}
        run: |
          aws sts get-caller-identity
      - name: Setup awsdo
        run: |
          export AWSDO_VERSION=X.X.X
          curl -L https://git.io/dpkg-i-from-url | bash -s -- https://github.com/k1LoW/awsdo/releases/download/v$AWSDO_VERSION/awsdo_$AWSDO_VERSION-1_amd64.deb
      - name: Run as ${{ secrets.AWS_ANOTHER_ACCOUNT }} using awsdo
        run: |
          awsdo --role-arn=arn:aws:iam::${{ secrets.AWS_ANOTHER_ACCOUNT }}:role/another-example-role -- aws sts get-caller-identity

--login

AssumeRoleしたロールでAWSマネジメントコンソール(Web)にログインできるオプションです。

$ AWS_PROFILE=myaws awsdo --login

もともと aws-vault にある機能で、便利だったので実装を参考にして awsdo にも追加しました。

というわけで

どんどんAssumeRoleしていきます。