かまたま日記3

プログラミングメイン、たまに日常

ETLとELTの違い

https://www.xplenty.com/jp/blog/etl-vs-elt-ja/

を読んでのETLとELTの違いのざっくりしたまとめ

ETL

  • Extract Transform Loadの順番で行う. ソースシステムからステージ環境にExtractして変換したものをData warehouseにLoadする流れ
  • OLAPデータウェアハウスを使う際は、構造化したデータにする必要があるので、DWHにロードする前に変換する必要がある
  • 構造をDWHに入れる前に決定する必要があるので、設計変更などがあった場合、データエンジニアの作業が発生する。SaaSも増えてきてそこのコストは低減してきている
  • 事前に処理したデータを使って分析するのでデータの信頼性、処理の高速性などに利点がある
  • DWHに入れる前にデータ処理を行っているので、GDPR個人情報保護法などコンプライアンスに関する規制に対応しやすい

ELT

  • ELTはExtract Load Transformの順番で処理を行う.
    • データレイクにためた非構造化データ *1 を含んだ雑多なデータを要件に応じて変換して使う形
  • 高性能なクラウドコンピューティング環境の登場によって生まれた概念
  • 必要なデータのみを処理するため、大量のデータがある場合でも比較的高速に処理できる *2
  • 事前に構造を定義しないといけないETLにくらべて柔軟性が高い
  • データの信頼性は低い
  • Load処理は生データをデータレイクに入れるだけなので、メンテナンス性と高速性が高い

*1:JSONファイル、画像データなど

*2:ETLは入ってくるデータ全てに処理を行わないと行けない

cgroupのDevice Whitelist Controllerについて

https://www.kernel.org/doc/Documentation/cgroup-v1/devices.txt

cgroupはmknod (特殊ファイルの作成) を制限できる。

echo 'c 1:3 mr' > /sys/fs/cgroup/1/devices.allow

これは 「cgroup 1 に/dev/nullのread and mknod の権限を追加する」という意味になる

  • 最初のcはtypeでa (all), c (char), or b (block) の3つがある
  • 1:3 はMajor, minorデバイス番号。詳細は ここ 参照
  • 最後のmrは権限でr (read), w (write), m (mknod)

参考: https://linuxcommand.net/mknod

Dockerで設定する場合 --device-cgroup-rule を使う

docker run --rm --device-cgroup-rule 'c 1:3 mr' myapp

Terraformのlockfileを更新するGitHub Actionを作った

Terraform 0.14からDependency Lock File が導入されました。 そのためTerraformのproviderを更新する際にこちらのlock file (.terraform.lock.hcl) も更新する必要があります。

SEQSENSEでは Renovate を使ってライブラリアップデートを行っていますが*1、Terraformのproviderのバージョンアップは対応しているものの、lock fileの更新は2021/6/6時点でまだ未対応です。

github.com

そのため、RenovateのPRが作成された後にlock fileを更新してpushするGitHub Actionを作成しました。

github.com

以下の設定をすると、RenovateのPRが作成された際に、.terraform.lock.hcl を検知して更新したものをpushしてくれます。

name: terraform-lock-fix
on:
  push:
    branches:
      - renovate/*

jobs:
  terraform-lock-fix:
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: 2
      - name: fix
        uses: seqsense/terraform-lock-fix-action@v0
        with:
          git_user: @@MAINTAINER_NAME@@
          git_email: @@MAINTAINER_EMAIL_ADDRESS@@
          github_token: ${{ secrets.GITHUB_TOKEN }}
          commit_style: squash
          push: force

余談

Terraformのproviderのバージョン指定は範囲指定など柔軟にできるようになってますが (参考)、Renovateを使う場合、次のバージョンの検知はRenovateが勝手にやってくれるので、Renovate外での不要な更新を避けるために固定バージョンでやるのが良いと思います。

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "3.44.0"
      //      version = "~> 3.0"
    }
  }
}

Pull requestでPostされたBotのコメントを消すGitHub Actionを作った

皆さんCIで実行したテストやLint, カバレッジレポートの結果をbotがPull requestにpostするというのはやったことがあるのではないかと思います。 ただ、何回もPushしているとそのコメントが溜まってきて見づらくなったりすることは無いでしょうか?

たとえば弊社ではTerraformの設定ファイルが置いてあるレポジトリではCIで terraform plan をした結果をこんな感じでコメントとして貼り付けてます。

f:id:kamatama_41:20201118072616p:plain

(アプリケーションの環境ごとにポストしているので1 pushにつき4つのコメントが投稿されます)

これが毎pushごとに追加されるので、コミットが増えてくるとかなり見づらいです。今までは手動で消したり隠したりしてたのですが、自動で隠せるようにGitHub Actionを作りました。

github.com

使い方

こんな感じでActionを呼び出すだけです。絞り込み条件は2つあって、指定しない場合は過去に投稿されたコメント 全部を隠します ので、注意してください。

  • author: コメントしたアカウントのusername, たとえばbotのusername.
  • message_regex: 隠したいコメントの内容を正規表現でマッチさせる
on: pull_request

jobs:
  hide-pr-comments-action:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Hide PR comments
      uses: kamatama41/hide-pr-comments-action@v0
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        author: my-system-bot                 # OPTIONAL
        message_regex: "Test result: (OK|NG)" # OPTIONAL

実行するとこんな感じで過去のコメントが隠れます

f:id:kamatama_41:20201118073431p:plain

もし同じようなことで困っていたら、使ってみてください〜

Goでtesting.T#Helperを使う

Goのテストでヘルパーメソッドを作って共通のアサーションを定義することがあるかと思います。

package test

import "testing"

func Add(x, y int) int {
    return x + y
}

func TestAdd(t *testing.T) {
    AssertEquals(t, 2, Add(1, 1))
    AssertEquals(t, 3, Add(1, 2))
    AssertEquals(t, 4, Add(1, 3))
}

func AssertEquals(t *testing.T, expected, actual int) {
    if expected != actual {
        t.Errorf("Unexpected int\nexpected:%d, actual:%d", expected, actual)
    }
}

ここで言う AssertEquals が共通のアサーションですね。 これをこんな感じで、わざと失敗させてると以下のような出力になります。

func TestAdd(t *testing.T) {
    AssertEquals(t, 1, Add(1, 1))
    AssertEquals(t, 2, Add(1, 2))
    AssertEquals(t, 3, Add(1, 3))
}
=== RUN   TestAdd
    TestAdd: add_test.go:17: Unexpected int
        expected:1, actual:2
    TestAdd: add_test.go:17: Unexpected int
        expected:2, actual:3
    TestAdd: add_test.go:17: Unexpected int
        expected:3, actual:4
--- FAIL: TestAdd (0.00s)
FAIL

出力される行番号が全部ヘルパーメソッドの位置になってて実際のテストのどこで失敗したかが分かりづらいですね。 *1

こういうときは t.Helper() を呼ぶとそのヘルパーメソッドがcallerのスタックから除外されます。

AssertEquals関数を以下のように変更して実行します

func AssertEquals(t *testing.T, expected, actual int) {
    t.Helper()
    if expected != actual {
        t.Errorf("Unexpected int\nexpected:%d, actual:%d", expected, actual)
    }
}
=== RUN   TestAdd
    TestAdd: add_test.go:10: Unexpected int
        expected:1, actual:2
    TestAdd: add_test.go:11: Unexpected int
        expected:2, actual:3
    TestAdd: add_test.go:12: Unexpected int
        expected:3, actual:4
--- FAIL: TestAdd (0.00s)
FAIL

実際のアサーションを実行しているテストケースの行番号になりました。

まとめ

テストのヘルパーメソッドでは t.Helper() を呼び出すべし

*1:本来はこういうテストは一つのケースにまとめないでケースを分けるなどをした方が良いと思います

SEQSENSEの会社・仕事の紹介

2021/06/11 更新

はじめに

このエントリーは SEQSENSE株式会社 への採用 (主にクラウドチームのエンジニア) を目的としたエントリーです。もし興味を持った方は Findy or Wantedly から、もしくは @kamatama_41 まで直接連絡ください。

転職ドラフトにも参加しているので、よければラブコールをお願いします。

SEQSENSEについて

2016年10月に創業したロボットのスタートアップです。惑星探査機はやぶさに搭載されたローバーのミネルバの開発にも携わった明治大学黒田洋司教授の持つ自律移動ロボットの技術を広く一般に使える形で商用化したいという思いから、CEOの中村と組んで創業しました。

そういった経緯もあり、コアとなる技術は高度な自律移動性能を持ったロボットの製作技術なります。現在は深刻な人手不足に悩む警備業界にフォーカスを当てて、ロボット警備のサービスを提供しています。

2019年8月に商用化を開始して、2021年6月時点で都心のオフィスビルを中心に10の施設で警備ロボットが稼働しています。*1

2021年2月には東京都庁で実証実験も行い、SEQSENSEのロボット (SQ-2) が警備業務を1ヶ月間東京都庁で行いました。

www.metro.tokyo.lg.jp

  • 『世界を変えない』
  • 『ヒト型も、ネコ型も、目指さない。』

というちょっと変わったミッション・開発理念を持っていますが、これは「本当に実用性のあるロボットを世に送りだして、人口減少に向かう社会を、テクノロジーの力で悪い方向に変えない様にしよう」という意味を持っています。詳しくは以下のインタビューが参考になるかと思います。

xtech.mec.co.jp

弊社のYouTubeチャンネル *2

www.youtube.com

チームについて

人数はSlackの#randomにいる人が40人で、数えてみるとエンジニアとそれ以外の人が2:1くらいの割合でした。

エンジニアリングチームは大きく4つに分かれていて

  • ハードウェア (ロボットのハードウェアの設計・製造)
  • ロボソフト (ロボ上で動く自律移動ソフトウェアの開発)
  • クラウド (ロボットを管理するWebアプリなどの開発)
  • AI (画像認識モジュールの開発)

というチームで仕事を行っています。全然使っている技術が違うので、普段はそれぞれのチームで開発を行っていますが、当然チームをまたいだ機能開発なんかもあるので、その場合は連携して仕事を行います。

クラウドチームの仕事

ここからは私の所属しているクラウドチームの仕事の紹介になります。

クラウドチームが担当しているのは主にクラウド上で動くアプリケーションの開発・運用です。具体的には以下のようなモジュールがあります *3

  • 顧客 (警備員) が利用するWebアプリケーション
  • 管理者 (我々) が利用するWebアプリケーション
  • ロボットから上がってくる情報を処理するWorker
  • ロボット上で動くクラウドと情報のやり取りを行うagentプログラム
  • ロボットからの動画・音声を配信するサーバ

技術スタックとしては、顧客用のWebアプリケーションがRuby (on Rails)で書かれている以外は、バックエンドの処理はほぼGo言語で書かれています。フロントエンドはReact (Next.js)、内部サービス間の通信ではgRPC, GraphQLなんかが使われています。あとロボットから送られてくる動画をWebで配信する際にWebRTC (pion) を使っていたりもします。クラウドAWSを使っていて、前述のアプリケーションすべてがECS上のDockerコンテナとして動いています。

その他監視はDatadog, CIはGitHub Actions, インフラ管理はTerraformを使っています。

仕事の進め方としては、すべてのチケットはGitHubのissueとして上げるようにしていて、2週間に1回のスプリント計画MTGで各人がissue一覧から何をやるかを決めて進めていきます。細かい見積もりとかスプリントバックログを作ったりといった厳密さはないゆるいスクラム*4でやっています。今の所は人数が多くないのとそれぞれのメンバーの自律性が高いので大きな問題は出ずにやれています。

システム的な詳細は2020年6月にAWS IoT Loftで発表したときの資料がパブリックに上がってるものでは一番詳しいです

kamatama41.hatenablog.com

クラウドチームの技術的課題

割と大きめなのを上げるとこんなのがあります。当然この他にもサービスの機能追加・改修などは随時発生しています。

管理アプリケーションのリプレース

社内用の管理アプリケーションは歴史的経緯から、現在Django + jQueryで構築されているのですが、メンテナンス性に課題があるため *5 現在React (Next.js) + GraphQLの構成の新アプリケーションに移行中です。

OTA (over-the-air) アップデートの仕組み構築

ロボットのソフトウェアをクラウド経由で自動でアップデートする仕組みを構築する。

  • Docker imageの更新
  • systemdサービスの更新
  • その他細かいプロビジョニング
  • など

現在はメンテナンス時間を取って手動で作業を行ってるのですが、稼働するロボットが100台を超えるスケールになると回らなくなるので、この仕組の構築は急務で、現在はAWS IoT Jobsとスケジューラ (今の所Rundeckを検討中) で行う予定です。

データ分析の基盤構築

商用化を開始して2年ほど経ち、ユーザーやロボットのデータも蓄積してきたので、データ分析をして素早い意思決定やサービス改善に活かしていきたいと考えています。サービス上にある各種統計情報・ユーザーのアクセス情報などデータを集めるところからBIダッシュボードツールを入れてレポーティングするところまで、やること盛りだくさんです。

エレベーター連携

現在は三菱電機さんとクラウド側で連携してロボットをエレベーターに乗せているのですが *6 オフィスビルには他にもたくさんのベンダーのエレベーターがあり、それらも使えるようにすることが喫緊の課題になっています。こちらは様々な方向性を検討中です。

SEQSENSEのクラウドチームで働いて面白いところ

いわゆる普通のWebサービスと一番違うところは、ロボットという実際のモノの開発に携われるところになります。自分の開発した機能でロボットが動いたりするところは非常にユニークな体験かなと思います。

技術的な観点でいうと、Webサービス以外でも、IoT的なロボットとクラウドの双方向のデータのやり取りだったり、動画配信、エレベーター連携など様々なモジュールがあり、それらを非同期で組み合わせて一つのサービスを実現しているところが、難しいながらもやりがいのあるポイントです。

また、SEQSENSEはハードウェアの設計からクラウドサービスの提供まですべて社内で内製しているので、多種多様なバックグラウンドの人と関われるところだったり、まだ未開拓の ロボット警備 という市場を1から作っていけるというのも、大変ですが面白いところだと思います。

*1:詳しくは https://www.seqsense.com/product/ を参照

*2:動画1つしか無いですが

*3:この他にも色々あります

*4:といって良いかも微妙なレベル

*5:DjangojQueryが悪いと言うよりは社内の技術スタック的な問題で

*6:https://www.risktaisaku.com/articles/-/22215

AWS IoT@Loft #11 で登壇してきた

iot-loft.connpass.com

スマートビルディングにおけるIoT活用の取り組み
というお題でスマートビルディングを警備するSEQSENSEのロボットのサービスについてお話してきました。

初めてのオンライン登壇、自分が話するときは200人近くの接続者がいたようで結構緊張しましたが、無難にこなせて(?) 良かったです。

スライドを見て興味を持っていただいたら是非ともお話しましょう!

www.wantedly.com

(追記) AWSさんの記事も投稿されました aws.amazon.com