Posts for: #2022/07

github actions の push イベントワークフロー改善

23時に寝て6時に起きた。今週はサービスインで凸凹していて疲れた。

ストレッチ

今日の開脚幅は開始前161cmで、ストレッチ後164cmだった。ちょっと数値がよくなった。一昨日の日本酒イベントで4時間ほど立ち呑みをしていた疲労で腰に張りが少しあった。それ以外はとくに問題はなくて調子がよかった。右股関節の詰まりも2-3週間前よりもよくなっている気がする。これはトレーナーさんも注意を払って詰まりを取り除くようにストレッチのメニューを組んでくれているのでその成果が徐々に出始めている気がする。以前よりも可動領域が広がってきている気がして安心感を得た。

github actions の push イベントワークフロー改善

午後からビルド・デプロイの最適化のために github actions のワークフローを改善作業をしていた。

今週はサービスインにより、本番環境への緊急リリースを何回もやっているのを傍からみていて、ビルド・デプロイが速くなればなるほど、その回数を増やせるし、修正後の検証に時間を多く割ける。あるリポジトリが7つのモジュールをまとめてビルド・デプロイしている。これはあるモジュールの微修正の反映には向かないので改善することにした。結果として最大で50%ぐらいのビルド時間の削減、モジュールに依っては、具体的には10分かかっていたものを4分台でビルドできるようにした。

ワークフロー改善のためのデバッグしている間はビルド・デプロイが出来なくなることから開発者が使っていない時間帯が望ましい。必然的にサービス休日出勤して github actions のワークフローを改善していた。デバッグと動作の検証も兼ねて午後から半日以上やっていたので休日にやったのは正解だと言えるだろう。

push イベントの github コンテキストの github.event.commits にコミット情報が入っていて、そこにコミットのリビジョンがある。例えば、次のようなオブジェクトで id がコミットのリビジョンに相当する。

[
  {
    "author": {
      "email": "...",
      "name": "...",
      "username": "t2y"
    },
    "committer": {
      "email": "...",
      "name": "...",
      "username": "t2y"
    },
    "distinct": true,
    "id": "f8df1f77ffec9ef234e7321b2e237b663256b01c",
    "message": "コミットログのメッセージ",
    "timestamp": "2022-07-08T12:32:33+09:00",
    "tree_id": "37b066734e58779c5d2c687d40b4cc43af177cb2",
    "url": "https://github.com/OWNER/REPO/commit/f8df1f77ffec9ef234e7321b2e237b663256b01c"
  },
  ...
]

このリビジョンを使って github rest api からファイル情報を取得できる。

$ gh api -H "Accept: application/vnd.github+json" /repos/OWNER/REPO/commits/f8df1f77ffec9ef234e7321b2e237b663256b01c

いろんなデータが返ってくるけど、ここでは変更したファイルのパスを知りたい。

{
  "sha": "...",
  "node_id": "...",
  "commit": {
    ...
  },
  ...
  "files": [
    {
      "sha": "...",
      "filename": "module1/path/to/src",
      ...
    },
    {
      "sha": "...",
      "filename": "module2/path/to/src",
      ...
    }
  ]
}

この filename のトップディレクトリがモジュール名と同じなのでここだけ取り出して、管理対象のモジュールかどうかを比較する。bash でも =~ をサブ文字列のマッチングができる。

$ targets=(mymodule1 mymodule2)
$ echo " ${targets[@]} "
 mymodule1 mymodule2 
$ [[ " ${targets[@]} " =~ " mymodule1 " ]] && echo "match"
match
$ [[ " ${targets[@]} " =~ " mymodule2 " ]] && echo "match"
match

さらにマッチしたモジュールを github actions の expressions で制御しやすいように json の array に変換する。

$ jq --compact-output --null-input '$ARGS.positional' --args -- ${targets[@]}
["mymodule1","mymodule2"]

これを step の outputs として格納する。

echo "::set-output name=modules::${json_array}"

例えば、後続の job で実行条件としてモジュールの有無を調べたいときは expressions を使って次のように記述できる。if 文は ${{ ... }} のブラケットを省略できるようだけど、ここだけ省略すると返って混乱するかなと思って私は記述するようにしている。その方が統合性があってコードが読みやすいように私は考えている。

  mymodule1-job:
    if: ${{ contains(fromJSON(needs.build.outputs.mymodule_target.modules), 'mymodule1') }}
    needs:
      - build

ちなみに workflow レベルの env は job の if 文には使えない。outputs を使って動的な値を扱うようにしている。どうも workflow レベルの env はいろいろ問題があるみたいでなかなか issue がクローズされないのをみると取り扱い注意なのかもしれない。

最終的なモジュールを判別するための step は次のようなものになった。

  build:
    outputs:
      mymodule_target: ${{ steps.mymodule-target.outputs.modules }}
    steps:
    - name: コミットログからビルド対象のモジュールを設定
      id: mymodule-target
      run: |
        declare -A modules
        target_modules=${{ env.TARGET_MODULES }}
        revisions=$(jq --raw-output '.[].id' <<< '${{ env.COMMITS }}')
        for revision in ${revisions}
        do
          names=$(gh api -H "${{ env.ACCEPT_HEADER }}" ${{ env.COMMITS_PATH }}/${revision} | jq --raw-output '.files[].filename' | cut -d"/" -f1 | sort -u)
          for name in $names
          do
            if [[ " ${target_modules[@]} " =~ " ${name} " ]]; then
              modules[${name}]=true
            fi
          done
        done
        targets=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${!modules[@]}")
        echo "::set-output name=modules::${targets}"        
      env:
        TARGET_MODULES: |
          (
            'mymodule1'
            'mymodule2'
          )          
        ACCEPT_HEADER: "Accept: application/vnd.github+json"
        COMMITS_PATH: /repos/${{ github.repository }}/commits
        COMMITS: ${{ toJSON(github.event.commits) }}

処理も理屈も簡単なんだけど、実際の運用コードはもう少しだけ複雑なものの、デバッグは github actions を実行しないといけない。ちょっとした typo のために実は2時間ほどはまっていたのは内緒。シェルの配列や連想配列を使うと、記号が多くてわかりにくい。配列の閉じブラケットを忘れていたがために EOF のエラーが発生していた。閉じブラケットのミスだけにエラーが発生しているところと実際のコードがズレていて、それに気付くのに少しずつコードを足したり消したりしてデバッグするみたいな原始的なやり方で些細な typo を気付くのに時間がかかった。

xxx.sh: line 47: unexpected EOF while looking for matching `"'

ゾンビスクラムを教えてもらった

2時に寝て7時に起きた。今週はバテた。金曜日は非稼働日だけど、バタバタしているから普通に働いていた。

隔週の雑談

顧問のはらさんと隔週の打ち合わせ。今週はお手伝い先がサービスインでバタバタしていて議題の準備がほとんどできなかった。少し前に参加したアトラシアンさんのウェブセミナーのスライド資料が公開されたのでそれを眺めながら雑談していた。

jira の有料プランのサービスに jsm chat という halp の技術を活かした新機能が追加されたらしい。既存プランの延長上で使えるらしい。質疑応答のときに halp とは別プロダクトだと明確に回答していたので halp が今後どうなっていくのかの将来にはかなり懸念がある。チャットと課題管理システムの双方向連携という、slack や teams といったチャットサービスがよく使われるようになった昨今のビジネス事情にあわせたサービスと言えるだろう。

私も以前からその領域に課題意識をもっていたし、ベンチャーでは workstreams.ai も同様のサービスを提供している。満を持してというのか、(私にとっての) 課題管理システムのベースラインとなる jira にその機能が入ったことで競合製品も同様に機能拡張を提供していく気がする。1-2年後にはチャットと課題管理システムが双方向連携しているのが当たり前の開発スタイルになるのかもしれない。非開発者にとってはチケットを扱うよりも敷居が下がるのでそれは適切な世の中の変化だと私は考えている。

ゾンビスクラム

jsm chat と課題管理の話しをしているうちにスクラムの話題になった。Zombie Scrum Survival Guide という書籍があって形骸化したスクラムの特徴をまとめているらしい。ある記事で2021年から翻訳していると書いてあったので翻訳版が出版されたら読んでみようと思う。

ブログ記事の所感を読んだ感じだと、私がいま関わっているスクラムにも一部通じるところがあるなと思って関心がある。

うちのチームは1週間スプリントをもう1年近く続けているのだけど、これは検査が早い段階でできるというメリットがあるものの、開発のメリハリがないなぁとずっと思ってた。それはただ与えられたタスクを無理なくこなすだけというルーチンになってしまっているのと、昨今の労務管理を徹底する働き方改革?のせいか、残業・休出を一切やらない開発スタイルが開発者の自律性や意欲を削いでしまっているのではないかとも思う。もちろん「余白」があれば、業務時間内に好きなことをやったらよいと思うけれど、うちの場合は半分ぐらいのスプリントゴールが未達で、スプリントに達成できないタスクを盛り込むからスプリントゴール未達の状態で他のことをやるのが憚られる空気がある。もっとも好き勝手やっている私がそれを感じるのだから、若い開発者には相応のプレッシャーになっていると思う。結果として、指示されたタスク (プランニングで決めたこと) 以外のことはやらない雰囲気になってしまっている。試しに直近3ヶ月のスプリントバックログアイテムの種別のみで開発者のチケット登録した数をカウントすると次のようになった。

  • 私: 66件
  • 開発リーダー: 17件
  • 開発者1: 14件
  • 開発者2: 12件
  • 開発者3: 1件
  • 開発者4: 6件

これは課題管理システムに慣れていて、業務をタスク分解しながら作業していくというワークフローに私が最も習熟しているから、適度な粒度のチケットをいくつも作りながら作業をやっているという背景もある。しかし、いまやらなくてもいずれ必要なタスクも、業務をやりながら気付いたときに私は随時登録している。憚られる空気を感じている私が週4日労働で控えめにやっても3ヶ月でもこれだけの数が開く。要はゾンビスクラムだと開発者の自律性は期待できないという話し。

七夕と日本酒

1時に寝て7時に起きた。

障害対応の手伝い

昨日の続きで定期処理を k8s の cronjob へすべて移行した。その後、チケット整理したり、他メンバーの手がまわっていない作業を手伝ったりしてた。バッチ処理の在庫チェックの数字があわなくて「俺たちは雰囲気で在庫チェックをやっている」みたいな状況に陥っていた。とはいえ、サービスイン3日目でも致命的な運用の問題は発生していないということでこのリリースはもう完了したと断言してしまってもよいだろう。今後、数ヶ月かけてさらに他施設へのサービスインが続いていくわけだけど、見通しはみえてきた感じはする。まぁ大丈夫そう。

灘五郷酒所イベント

なにかのきっかけで クラウドファンディングの灘五郷酒所 をみつけた。地元の応援をしとくかと思って5,000円を支援した。いまみたら271人の支援者から1,472,900円の支援金が集まったみたい。その支援金のお礼イベントがあって、せっかくの機会なので行ってきた。5,000円ってちょっとよい居酒屋さんで使うぐらいの金額だけど、その場で飲める2,000円分の金券とお腹いっぱい食べられたビッフェ形式で十分に飲み食いできた。写真にある料理をもう1皿もらってきてお腹いっぱいになった。料理はなくなっても補充されていたので十分に用意されていた。支払った支援金を考慮すると十分に良心的なイベントだった。小耳に聞いた話だと80人ほど参加者がいたらしい。

飲んだお酒はこれら。あと竹酒と呼ばれる竹の筒に入れて主催者がついでまわっていたのを2杯ほど飲んだ。

  • 福寿 純米酒「御影郷」 (神戸酒心館)
  • 琥泉 純米吟醸おりがらみ無濾過生酒原酒 (泉酒造)
  • 黒松剣菱 (剣菱酒造)
  • 浜福鶴 生酛純米辛口 (小山本家酒造 灘浜福鶴蔵)

1人で行ったのでぼっちだったらどうしよう?みたいな不安もあったんだけど、たまたま隣り合わせた人が プライズ日本酒会 というコミュニティのメンバーで4人組で参加していた。その人たちと雑談してた。ご近所さんでとてもよい人たちだった。三ノ宮でお酒イベントをやっているそうで、また機会があればそちらにも参加してみようと思う。私は地元の人たちとのコネがほとんどない。今後会社のマーケティングをやっていく上でも地元の人たちともなにかしら繋がりをもてるとよいなとは考えている。お仕事がバタバタしてたから朝の時点では行くのをやめようかと考えていたけど、午後から落ち着いていたのもあって行ってよかった。

lambda から cronjob へ

0時に6時に起きた。今日は晴れたので自転車通勤。

優雅にドキュメントを書きながら障害対応

昨日は凸凹しながら乗り切ってサービスイン2日目。今日から外部システムとの連携なども絡んでくる。昨日の今日なんで何か起こるだろうと思いつつ、暇だったらドキュメント書くタスクがいくつも溜まっているのでそれを片付けるかと業務を始めた。私ぐらいの人間になると、いつ凸凹が発生してもよいように、この日のために取っておいたようなドキュメントタスクがいくつも溜まっている。午前中に私の出番はなく、優雅にドキュメントの1つを完成させた。

以前から定期実行やバッチ処理は lambda 関数をトリガーに作られていた。それらを serverless framework から cdk へ移行した んだけど、その後にバッチ処理を k8s の cronjob で実装した 。この cronjob が思いの外、うまくいって、私がフルスクラッチで cli を作っているのだから、私からみてさいきょうのばっちしょりの土台を実装している。定期実行もすべて cronjob でやればいいやんと気付いて、過去に lambda 関数 (cdk/python) で実装したものをすべて移行することに決めた。昨日の流れからわかるように過去に作成済みの一連の lambda 関数はまだ本番環境にデプロイされていない。m1 chip macbook 問題 で同僚のマシンからデプロイできないという不運もあったんだけど、もうデプロイしなくていいよ、すべて cronjob で置き換えるからと伝えて2つ移行した。あと半日もあれば完了できそうな見通し。

lambda 関数から cronjob への移行作業をしていると、本番環境でのバッチ処理の一部のロジックが誤っているとわかってそれを修正したり、当然のようにテスト環境のデータも誤っているので正しいかどうかは本番環境にデプロイするしかないみたいな凸凹した状況を横切りながら本日の作業を終えた。いくつか残課題は残っているものの、明日中には平常業務に戻れるぐらいの状況にはなりつつあるのかもしれない。サービスイン2日目を終えて致命的な問題は起こっていないようにみえる。ひとまずはよかったという感じ。

サービスインは突然に

1時に寝て6時に起きた。暑くてあまり眠れない。今朝も雨降りで徒歩通勤。

cdk の ECS サービスに紐づくセキュリティグループの設定

明日がサービスイン初日だと思っていたら、私の勘違いで今日だった。私が直近でやっている作業はアプリケーションの直接的な機能ではなく、インフラやバッチ処理などの間接的な機能を作っているわけだけど、それでも1日調整を間違えていて、あれーって感じでサービスインが始まった。とはいえ、私は本番環境にアクセスできなければ、ログすらもみれないので同僚ががんばっているのを傍から応援しつつ、平常通りタスクをこなしていくだけのはずであった。

のほほんと通常通りのタスクをやっていたら、本番環境の ecs サービスと通信できないという連絡がくる。私が前任者から引き継いで構築したインフラなので何だろう?と調査していて、本番環境でセキュリティグループの設定が漏れていることがわかった。これはわかりにくい問題で cdk の FargateService で ecs サービスを構築している。このプロパティは securityGroups のパラメーターをもっている。このパラメーターを指定しない場合、新規にセキュリティグループそのものは作成してくれるけれど、その ecs サービスへ通信するポートへのインバウンドルールは作ってくれない。

securityGroups?

Type: ISecurityGroup[] (optional, default: A new security group is created.)

The security groups to associate with the service. If you do not specify a security group, a new security group is created.

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs.FargateService.html#securitygroups

テスト環境はセキュリティグループに対して、インバウンドルールを管理画面から手動で追加していたために疎通できていた。セキュリティグループは ecs サービスに紐付いているものだから、ecs サービスを再作成しない限りはインバウンドルールが消えることもなくてこの作業漏れに気付けなかったという落ちだった。さらに、そのセキュリティグループのインバウンドルールを設定したのは私ではない。その説明欄に次のコメントが書かれていた。

atode-kesu

今すぐ消してやろうかという気持ちを抑えつつ、cdk でインバウンドルールを設定したセキュリティグループを紐付けるようにして解決した。疎通ができないと、ロードバランサーのヘルスチェックが通らず、ecs のタスクが延々と再起動を繰り返すというわかりにくい障害となっていた。1時間ぐらい唸っていた。

未検証の本番環境

前節で障害の原因自体はわかりにくいものだが、なぜサービスインの初日にこんなことが起こるのだろうか?という当然の疑問。そう。これまでこのインフラの本番環境は一切検証されていなかった。4月から5月にかけて構築されたインフラだった。この後にデータを格納するための s3 bucket がない、一部の設定はテスト環境の設定しかない、アプリケーションのコード中にテスト環境の設定がハードコードされているとか。追加であちこち直してデプロイしていた。私は本番環境に一切アクセスできないので過去にこれらの検証をすることはできなかったわけではあるけど、いろいろ思うところはあるなぁと感慨に浸っていた。

m1 chip macbook と cdk の追加調査

0時に寝て7時に起きた。昨日はずっと寝てて、今朝は雨降りで徒歩通勤。週始めからしんどい。

デバッグ調査を断念

以前 m1 chip macbook で aws-lambda-python-alpha のデプロイができない ことについて書いた。同僚がそのためにデプロイできないと運用上の不都合があるので調査してみることにした。ワークアラウンドの1つとして、ビルドに使う Docker イメージを任意のものに置き換える仕組みを使えば、arm64 アーキテクチャでビルド処理のプロセス自体は通ることを確認していた。しかし、その後の python distribution が生成されていなかった。同僚にデバッグを手伝ってもらってログをみていると、python distribution をバンドルする処理のログが出ていない。

おそらく docker イメージのビルド処理ではなく、aws-cdk の core 側の bundling のところに原因がありそうに思える。core のライブラリをみると、たしかにいくつか条件次第で bundling をスキップする実装はあったし、ログが出力されていないことからも意図したステップが実行されていないことだけはわかった。その周辺から当たりをつけて aws-cdk の issues なども検索してみたけど、それっぽい issue をみつけることはできなかった。何よりも私がもっていないマシン環境の、様々な環境設定を調べることもできず、aws-cdk の core をデバッグするのも大変かなと午前中いっぱい調べて断念することに決めた。もしかしたら同僚のホスト環境に特化した問題が発生している可能性もある。

アプリケーションレベルで再現できた問題を解決できないというのは情けないけど、自分でデバッグできないものは仕方ないかと諦めることにした。本当に悔しいけれど。

夏休み

0時に寝て7時に起きたけど、昨日から体調よくなくてしんどくて寝てた。

開発やら決算の事務手続きやらのタスクが一段落して余裕時間ができたことでぼーっとしてた。まぁたまにはそういう日もあるか。何も作業せず休んだ日は day off というタグを付ける。あとで何日ぐらい休んだか、どのぐらいの期間で休んだかの確認にもなるかもしれない。

夏バテ

0時に寝て7時に起きた。途中で吐き気がして何度も起きた。夜うまく眠れない。

ストレッチ

今日の開脚幅は開始前160cmで、ストレッチ後163cmだった。先週とほぼ同じでよい状態を維持できている。外が暑くなってその比較から dr.stretch さんの事務所はエアコンがよくきいていて涼しい。うちのオフィスはエアコンの設定温度を上げる人がいて気付くと26.5℃とかに設定されていて私にとっては暑い。とくにどこか張りの強い部位や痛いところはなかった。夜にあまり眠れないわりには身体的には負荷がかかっているところはなさそう。

ストレッチを終えてからオフィスに戻って軽く調べものして、眠くなって仮眠して、そのまま家に帰って寝てた。とくに急ぎでやるタスクがなかったせいか、なんか一気にバテた。

法人決算の会計処理を終えた

0時に寝て6時に起きた。夜あまり眠れない。

算定基礎届

e-gov電子申請 を使って初めて電子申請してみた。昨年もやろうと挑戦したけど、macos からだと不具合があってエラーになるから断念してた。今年は windows マシンがあるので windows アプリケーションをインストールして問題なく申請できた。うちは社員1人なので csv 取り込みを使わず、手入力で申請した。申請した書類は pdf 出力できるし、申請後に送信したデータは xml で控えとして保持できる。本当に紙でやっていたものを文書データと数値データに置き換えたようなアプリケーションになっている。紙の書類と比べて、アプリケーションがよいところは申請の進捗状況がわかるところ。算定基礎届で問題が発生することは過去にないけど、審査開始、審査終了、手続終了のステータスをアプリケーションから確認できる。それはそれで申請者にとって状況の追跡ができて安心感になる。

振替伝票の使い方

前期は赤字決算だったので中間申告で支払った税金が還付される。中間申告というのは、前年度の納税金額から翌年の税金の半分を納めるという仕組み。前年度の法人税額が20万円を超えると中間申告が必要となる。前年度と同じ法人税が今年度もあるという前提で半分納めるけれど、その納めた金額よりも確定申告のタイミングで実際の納税金額が少ない場合は還付金という形で返ってくる。今回は赤字決算となったものの、それも初めてだったので税務署からの還付金をどう会計処理するのかも初めての機会でよくわからなくて調べながら作業した。

会計システムとして普通に行う処理ではないので freee のドキュメントも断片的にしか説明されていない。基本的な操作の考え方を理解した上で自分がやりたい会計処理に変更しないといけない。

まず中間申告のタイミングで振込した納付金額は「仮払金」として登録される。本来は確定申告のタイミングで確定した納付額に対して「仮払金」を相殺するような会計処理を行う必要がある。freee では取引データの決済欄に「+更新」というボタンがあってそこから仮払金から引き落とすようなデータ登録が可能となる。今回は赤字決算ですでに支払った「仮払金」が還付金として戻ってくるときの会計処理をしなければいけない。その手続きのために使うのが「振替伝票」になる。例として金額を10万円とすると次のような振替伝票を作成する。

  • 借方
    • 勘定科目: 未収入金
    • 税区分: 対象外
    • 金額: 10万円
  • 貸方
    • 勘定科目: 仮払金
    • 税区分: 対象外
    • 金額: 10万円

「仮払金」を相殺するための勘定科目は「未収入金」になる。この「未収入金」を還付金の取引 (税務署から銀行口座に振り込まれた金額) で消し込むことで会計システム上の辻褄があう。一般的に還付金の勘定科目は「雑収入」として扱うらしい。還付金は消費税がかからない取引であるので不課税取引となる。ややこしいのは還付金が振り込まれる際に還付加算金というお金も一緒に振り込みされる場合がある。還付加算金というのは、納め過ぎた税金に対する金利のようなものになる。試しに計算してみると金利が 0.46% になった。ある銀行の定期が 0.002% だったので税務署に税金を納め過ぎるとめちゃくちゃ金利のよい貯金みたいな扱いになる。話しを元に戻すと、還付加算金は課税対象になるので「雑収入」の課税売上として会計処理する。

うちの会社では、振替伝票は決算のタイミングでしか使わない。振替伝票の使い方を忘れていてたまに使うときに右往左往する。

はんなりDAO

はんなりDAOをはじめてみます に参加した。イベントで話した内容は notion で公開されている。

まだ全然、計画段階で段取りの計画も目処もたっていない。dao が良いものかどうか、私はまだよくわかっていないが、実際に自分で試してみることには肯定的である。そして組織の取り組みは実際に複数人いないとあまり実用的ではないことからコミュニティのような、一定以上の信頼のある実際の人間が関わってくれるならそれはそれで実証実験の場としてはおもしろい取り組みになるかもしれない。初回だったので dao とは何かとか、dao や web3 を取り巻く世の中の状況はどうかとか、はんなり dao の目的をどうするかとか、計画段階の雑談が主だった。最初はそんなもんかもしれない。私もスマートコントラクトとか、何が嬉しいのかよくわかってないので dao を運営する中で実際に実装してみる機会があれば、それはそれで学びの機会としてよいかもしれないと考えている。

aragon という dao を作るためのプラットフォームがあって、これを使うと dao そのものはすぐに準備できるらしい。あとは組織運営のルールやスマートコントラクトを実装していくだけみたいな話し。ethereum で動かすと手数料がかかる。しばらくは testnet であーでもないこーでもないみたいなやり取りをしながら dao の運営を学んでいこうみたいな話しをしていた。