かまたま日記3

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

退職しました4

TwitterFacebookでフォローされてる方は知っているかと思いますが、3月末で前職を退職していました。短い間ですがお世話になった皆さんありがとうございました。1年弱という社会人生活で一番短い在職期間になりました。

これまで

Hosted Embulk for TDである、DataConnector/ResultOutputという2つのサービスをメンテナンスするチームに所属していました。そこで新規/既存のEmbulkプラグインの開発、Embulk本体のメンテナンス、サービスを提供するためのアプリケーション開発、実行環境や開発環境の改善など主にバックエンド周りのことをやっていました。また、夏ごろにアメリカ出張に行ったことは人生初のアメリカということもあって、とても良い経験になりました。

現在

SEQSENSEという警備ロボットを開発しているベンチャー企業に4月から所属しています。コアとなる強みは自律移動ロボットの開発能力でロボット界隈では結構有名な会社のようです。自分が担当しているのはバックエンド周り全般で、具体的には以下のようなものがあります。メインとなる言語はGoなので勉強中です。

  • ロボットをWebから管理するためのアプリケーション開発
  • ロボットとのコネクティビティ周り
    • AWS IoTを使ったMQTTでのやりとり
    • ロボットと動画、音声をやり取りする*1ためのサーバ開発
  • 外部システム *2 との連携
  • 全体のインフラ*3、開発環境構築、改善

恥ずかしながらインタビューもしてもらったので、会社についてや転職の理由など詳しいところはこちらを見て頂ければと思います。

興味を持たれた方はぜひDMなりでご連絡いただくか、Wantedlyで応募してください、お待ちしております m(_ _)m

*1:via WebRTC

*2:ビル内の設備

*3:AWS

Goで複数バージョンを管理する

まあここに書いてることそのままなのですが、日本語のメモとして。

go get でダウンロード用のバイナリを取ってきて、downloadコマンドを打つ

$ go get golang.org/dl/go1.12.5
$ go1.12.5 download
Downloaded   0.0% (    15175 / 127612395 bytes) ...
Downloaded   5.0% (  6438912 / 127612395 bytes) ...
Downloaded  14.0% ( 17874944 / 127612395 bytes) ...
Downloaded  23.0% ( 29310976 / 127612395 bytes) ...
Downloaded  32.0% ( 40812544 / 127612395 bytes) ...
Downloaded  41.0% ( 52281344 / 127612395 bytes) ...
Downloaded  49.6% ( 63262720 / 127612395 bytes) ...
Downloaded  56.7% ( 72312832 / 127612395 bytes) ...
Downloaded  65.7% ( 83846144 / 127612395 bytes) ...
Downloaded  74.8% ( 95437556 / 127612395 bytes) ...
Downloaded  81.9% (104570610 / 127612395 bytes) ...
Downloaded  90.8% (115831263 / 127612395 bytes) ...
Downloaded  97.1% (123951181 / 127612395 bytes) ...
Downloaded 100.0% (127612395 / 127612395 bytes)
Unpacking /Users/kamatama41/sdk/go1.12.5/go1.12.5.darwin-amd64.tar.gz ...
Success. You may now run 'go1.12.5'

GOROOTgo env GOROOTで分かるので、GoLandとかIntelliJとかで使いたい場合はそこをSDKとして指定する。アンインストールする場合はGOROOTディレクトリを消す。

$ go1.12.5 env GOROOT
/Users/kamatama41/sdk/go1.12.5

embulk-executor-remoteserver 0.4.0 リリース

github.com

このバージョンより、Embulk clientとserver間でTLSでの接続ができるようになりました。

設定方法 (クライアント)

まず、use_tls オプションをtrueに設定してください。サーバ側が(クライアントにとって)既知のCA証明書でサインされた証明書を使っていれば、これだけでOKです*1

exec:
  type: remoteserver
  hosts: ...
  use_tls: true

そうでない場合は、CA証明書をca_cert_pathに追加してください

exec:
  type: remoteserver
  hosts: ...
  use_tls: true
  ca_cert_path: path/to/ca.cert.pem

クライアント認証が必要な場合、クライアント証明書と秘密鍵がセットになったPKCS12ファイルのパスとパスワードをcert_p12_fileで指定してください。

exec:
  type: remoteserver
  hosts: ...
  use_tls: true
  cert_p12_file:
    path: path/to/cert/client.p12
    password: xxxxx

設定方法 (サーバ)

EmbulkサーバをTLSの終端にする場合*2、以下の環境変数を設定してサーバを起動してください

  • USE_TLS=true: TLS接続を有効にする
  • REQUIRE_TLS_CLIENT_AUTH=true: クライアント認証を有効にする
  • CERT_P12_PATH, CERT_P12_PASSWORD: サーバ証明書秘密鍵のペアのPKCS12ファイルパスとパスワード
  • CA_CERT_PATH: CA証明書のパス。クライアント証明書が(サーバにとって)未知のCA証明書でサインされてる場合に必要

例えばdocker-composeで設定する場合以下のようになるかと思います

version: '3'
services:
  server:
    image: kamatama41/embulk-executor-remoteserver
    ports:
      - "30001:30001"
    volumes:
      - ./certs:/root/certs
    environment:
      USE_TLS: "true"
      REQUIRE_TLS_CLIENT_AUTH: "true"
      CERT_P12_PATH: /root/certs/embulk-server.local.p12
      CERT_P12_PASSWORD: xxxxx
      CA_CERT_PATH: /root/certs/ca.cert.pem

*1:たぶん、未確認

*2:前段にAWS NLBやNGINXを置いてそこを終端にするなども多分できると思います

Gradleで動的にプラグインを適用する

モチベーション

とあるプロジェクトでgradle-release pluginを使っているのですが、DockerでJarをビルドするときにこのプラグインを設定していると .git ディレクトリをコピーしないと(プロジェクトがGitリポジトリじゃないと)最初のbuild.gradleの検証で失敗してしまうのですが、無駄なレイヤーが増えるのでDockerコンテナ上に.gitはあまりコピーしたくない。なので、releaseタスクを実行するときのみ上記のプラグインを有効にしたい。

方法

こちらの記事 を参考にさせてもらいました。プラグインを指定するときにapply falseをつけてallprojects ブロックの中で指定したプロパティがあるかをを使って遅延applyします。

before

plugins {
    id "net.researchgate.release" version "2.8.0"
}

release {
    git { requireBranch = 'master' }
}

after

plugins {
    id "net.researchgate.release" version "2.8.0" apply false
}

allprojects {
    if (properties.get("enableReleasePlugin") == "true") {
        apply plugin: "net.researchgate.release"
        release {
            git { requireBranch = 'master' }
        }
    }
}

これで、実行時に -PenableReleasePlugin=true をつけたときのみプラグインが適用されます。

$ ./gradlew release -PenableReleasePlugin=true

CicleCIでDockerイメージを再利用する in 2019

CicleCIでDockerイメージを再利用する - かまたま日記3

こちらの記事の最新版です。 現在CircleCIはバージョン2で、Docker Layer Cachingという機能がありますが、残念ながら追加のフィーが必要です。というわけで、会社とかで使っててフィーを払える方はそちらを使うとして、個人のOSS活動などで払うのが厳しい方用に普通にCircleCI 2.0のファイルのキャッシュ機能を使った方法を解説します*1

前回に比べて以下の点が変わっています

  • GoのようにMulti stage buildを使って多段ビルドを行う前提 (最初のビルドのステージはas buider でbuilderという名前がついてます)
  • Docker image を完全に再利用はしないで中間イメージを再利用する (docker build は毎回やる)
  • docker save 後のtarファイルを更にgzに圧縮してリストアの時間短縮を図る

注意として、自分の環境では、数百メガのキャッシュをload cacheとsave cacheするので2~3分かかるのでキャッシュを使うことによって、それ以上短縮出来なければ、総時間は変わらないか悪くなる可能性もあります。

1. キャッシュ用のディレクトリとキャッシュキーを決める

ここではディレクトリは /home/circleci/docker-cache、キャッシュキーは毎回変えたいので {{ .Branch }}-{{ .Revision }} を使います

- restore_cache:
    keys:
      - v1-docker-{{ .Branch }}-{{ .Revision }}
      - v1-docker-{{ .Branch }}-
      - v1-docker-

- save_cache:
    paths:
      - "/home/circleci/docker-cache"
    key: v1-docker-{{ .Branch }}-{{ .Revision }}

2. イメージをビルドする

今回は builder のイメージを取っておきたいので、builderの部分は別にビルドしてbuilerタグを付けています。

IMAGE_NAME=my_app
CACHE_FROM="--cache-from ${IMAGE_NAME}:builder --cache-from ${IMAGE_NAME}"
docker build --pull ${CACHE_FROM} --target builder -t ${IMAGE_NAME}:builder .
docker build --pull ${CACHE_FROM} -t ${IMAGE_NAME} .

3. イメージを保存する

docker save で保存するイメージを docker history コマンドで取得します。 builder を取ってるのがミソです。

mkdir -p /home/circleci/docker-cache
image_ids=$(docker history -q my_app:builder | grep -v '<missing>')
docker save ${image_ids} | gzip > ${DOCKER_CACHE_FILE}

4. イメージを展開する

Gzip化しているのでgunzipコマンドで解答して docker load に渡します

if [ -f /home/circleci/docker-cache/image.tar.gz ]; then
  gunzip -c /home/circleci/docker-cache/image.tar.gz | docker load
fi

全体

キャッシュファイルのパスを変数に入れて、以下のような感じになります。関係ない部分*2は略してます。

version: 2
jobs:
  build:
    environment:
      DOCKER_CACHE_FILE: /home/circleci/docker-cache/image.tar.gz
    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-docker-{{ .Branch }}-{{ .Revision }}
            - v1-docker-{{ .Branch }}-
            - v1-docker-
      - run: |
          name: Load Docker cache
          command: |
            if [ -f ${DOCKER_CACHE_FILE} ]; then
              gunzip -c ${DOCKER_CACHE_FILE} | docker load
            fi
      - run: |
          name: Docker build
          command: |
            IMAGE_NAME=my_app
            CACHE_FROM="--cache-from ${IMAGE_NAME}:builder --cache-from ${IMAGE_NAME}"
            docker build --pull ${CACHE_FROM} --target builder -t ${IMAGE_NAME}:builder .
            docker build --pull ${CACHE_FROM} -t ${IMAGE_NAME} .
      - run:
          name: Save Docker cache
          command: |
            mkdir -p $(dirname ${DOCKER_CACHE_FILE})
            image_ids=$(docker history -q my_app:${t} | grep -v '<missing>')
            docker save ${image_ids} | gzip > ${DOCKER_CACHE_FILE}
      - save_cache:
          paths:
            - ${DOCKER_CACHE_FILE}
          key: v1-docker-{{ .Branch }}-{{ .Revision }}

*1:基本となる考え方は別に他のCIでも使えると思います

*2:たとえばdockerのインストールとかsetup_remote_dockerやテストの実行、デプロイなど

embulk-executor-remoteserverを作った #Embulk

Embulkのexecutor pluginの仕組みとネットワークプログラミングを学びたかったので、勉強がてらこのようなプラグインを作ってみました。

github.com

できること

  • Embulkのタスクの実行を別に立てた専用のサーバ(以下Embulkサーバと呼びます)上で実行できる
  • 複数サーバにタスクの処理を分散させる
  • サーバとの接続が切れたときに再接続する

できないこと (TODOs)

使い方

2019/04/06時点の最新は 0.2.1 です

Embulkサーバを起動する

基本的にはDockerコンテナ上で動かすことを想定していて、DockerHubにイメージをホストしているので、それをrunすれば起動できます。クライアント(plugin)と同じバージョンのイメージを使うことをおすすめしますが、多少違ってもたぶん動きます。コンテナ側は 30001 番のポートを開くので*2それを公開します。

$ docker run -p 30001:30001 -it --rm kamatama41/embulk-executor-remoteserver     
14:55:48.805 [main] INFO  c.g.kamatama41.nsocket.SocketServer - Starting server..

Embulkを起動する

exectype: remoteserver を指定して hosts に起動中のEmbulkサーバのホストを登録します。

exec:
  type: remoteserver
  hosts:
    - localhost:30001

この状態でEmbulk runをすると、サーバに接続に行き、タスクの実行を依頼します。 もっと詳しいチュートリアルは、こちらのexample を参照してください。

中身の話

このプラグインは、指定されたEmbulkサーバとTCPコネクションを張り、そのコネクションを通じてクライアントとサーバが相互にデータのやり取りを行います。例えばクライアントからはEmbulkEmbedを構築するのに必要なタスクの情報やシステムコンフィグ、OSSプラグインを実行に必要なgemをZIPファイルにまとめて送ったりしています。逆にサーバからはクライアントに各タスクの進捗状況を送っており、クライアント側は終了の通知が来るまで待受をします。

いわゆるWebSocket的な双方向通信をしているのですが、この仕組みを自作しました。

github.com

まあnettyとか使ってWebSocketにしても良かったのですが、あんまり依存ライブラリを増やしたくなかったのとネットワークプログラミングの勉強も兼ねてスクラッチで作ってみたかったという次第です。nsocketNIOで作ったノンブロッキングsocketサーバとクライアント の略です。大変だったけど結構いい勉強になりました。

実用性があるかは微妙なところですが、よかったら使ってみて感想をいただけると喜びます。

*1:現状Maven pluginは(たぶん)無いので、あんまり実害はないかもしれません

*2:変えることもできます

gradle-embulk-plugin v0.5.0 リリース

Release 0.5.0 · kamatama41/gradle-embulk-plugin · GitHub

embulk_* のタスクを実行時の config.yml output.yml のオーバーライドを build.gradle 内ではなくプロパティを渡すようにしました。

以前

embulk {
  configYaml = "myconfig.yml"
  outputYaml = "myoutput.yml"
}

今回以降

$ ./gradlew embulk_guess -PconfigYaml=myconfig.yml -PoutputYaml=myoutput.yml

プラグインの詳しい使い方は以下の記事を参照ください。

kamatama41.hatenablog.com