かまたま日記3

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

RenovateでGoのプロジェクトの依存性を更新する

弊社でRenovateを使ってるので、知見のメモです

Privateリポジトリを含む場合

Renovateを適用したいGoのリポジトリのgo.modに同じorganizationの別のprivate repositoryを含む場合*1、その参照されているリポジトリにもRenovateを適用すれば、Renovateが持つGitHubトークンでそのprivate repositoryもgo mod download出来ます。

Support private go modules on github.com · Issue #3202 · renovatebot/renovate · GitHub

you don't need to check in a github token - Renovate will reuse the existing token for github.com. If you are running via the app, that means it uses the same token as Renovate uses to access the current repository, so you need to make sure Renovate is installed into the source repo too (Renovate can be disabled, but it must be installed in order to have permissions to read the contents).

一部のライブラリ更新頻度高すぎ問題

弊社の場合、主に golang.org/x/aws-sdk-goなんですが、頻繁に更新が来すぎて鬱陶しいです。他にも適宜更新にしていると結構業務時間取られるので、弊社では以下のようなポリシーにしています

  • 外部パッケージは週末にアップデート (して週明けにまとめてマージ)
  • 内部モジュールは更新され次第

renovate.json的にはこんな感じです (抜粋)

{
    "extends": [
        "config:base",
        "schedule:weekends",
    ],
    "postUpdateOptions": [
        "gomodTidy"
    ],
    "packageRules": [
        {
            "packagePatterns": [
                "^github.com/seqsense/"
            ],
            "schedule": [
                "at any time"
            ]
        }
    ],
    "timezone": "Asia/Tokyo"
}

go.sumのpackage sumが抜ける問題

RenovateでpostUpdateOptionsgomodTidy を指定している場合 *2 go mod tidy するときにリソースの都合で依存パッケージを全てはダウンロードしていないために、 go.sum からパッケージのsumが抜けることがあります。

これはかなり困る問題なんですが、Renovate側では今の所対策する予定は無いそうです。ということで、同僚がgo.sumを修正する用のGitHub Actionを作ってくれました。

github.com

このActionを以下のような感じで仕込めば、RenovateのPRに対して、go mod tidyを行って変更があったらコミットしてpushしてくれます.

name: go-mod-fix
on:
  push:
    branches:
      - renovate/*

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

patchバージョンのみをAutomergeしたい場合

デフォルトではminorとpatchは同じブランチで管理されるので、patchのみをアップデートする場合 separateMinorPatch: true が必要。 ということでaws-sdk-goのpatch versionのみをautomergeしたい場合は以下のように書きます。

{
  "packageRules": [
    {
      "packagePatterns": [
        "^github.com/aws/aws-sdk-go"
      ],
      "separateMinorPatch": true,
      "patch": {
        "automerge": true
      }
    }
  ]
}

最後に

色々問題もありましたが、Renovateのおかげで弊社のGoプロジェクトはかなり健全な状態にできてるかと思います。もしRenovateを使おうと検討している場合、参考になれば幸いです。

*1:よくあるのは複数のプロジェクトから参照される共通コアライブラリ的なの

*2:というかこれをしたくない場合ってあるのかな?

Herokuで特定のGoのバージョンを使う

デフォルトはGo buildpackのデフォルトバージョンが使われます (2020/05/31現在1.12.17)

これを変えたい場合以下の方法があります

  • go.mod// +heroku goVersion go1.14 というディレクティブを追加する
  • アプリケーションの環境変数GOVERSION を追加する (例: GOVERSION=go1.14)

go.modgo ディレクティブのバージョンを使うという提案もあるようで、もう少ししたら go.mod のバージョンを使うようになるかもしれません

参考

elements.heroku.com

GitHub Actionsでテストを分割する

やりたいこと

GitHub Actionsでテストケースを分割して、複数ノードで実行する

CircleCIだとプラットフォーム側で対応してくれていますがGH Actionsだと見当たらなかったので同等のことをやるための設定のメモです。

設定例

  rspec:
    runs-on: ubuntu-latest
    strategy:
      max-parallel: 2
      matrix:
        ci_node_total: [2]
        ci_node_index: [0, 1]
    steps:
      - uses: actions/checkout@v2
      - uses: ruby/setup-ruby@v1
      - name: Bundle install
        run: bundle install
      - name: DB setup
        run: bundle exec rake db:setup
      - name: Rspec
        run: |
          ruby -e 'Dir.glob("spec/**/*_spec.rb").each{|f| puts f}' | awk "NR%${CI_NODE_TOTAL}==${CI_NODE_INDEX} {print}" > /tmp/tests-to-run
          cat /tmp/tests-to-run
          bundle exec rspec $(cat /tmp/tests-to-run)
        env:
          CI_NODE_TOTAL: ${{ matrix.ci_node_total }}
          CI_NODE_INDEX: ${{ matrix.ci_node_index }}

GitHub ActionsにはBuild Matrix という機能があって、本来はOSのバージョンと言語のバージョンの複数のマトリクステストを実施するための機能なのですが、これを使って ci_node_totalci_node_index という2つのパラメタを登録します。

  • ci_node_total: ノードの合計, max-parallel と同じ数にする必要がある
  • ci_node_index: ノードのインデックス, 0始まりで ci_node_total-1 で終わる配列

これで、 rspec のJobは (2, 0) と (2, 1) という2つの設定で実施されることになります

f:id:kamatama_41:20200518161853p:plain

あとはindex毎にspec配下のファイルを分割してrspecコマンドに渡すだけです。CircleCIだとsizeの大きさとか各exampleのかかった時間とかでいい感じに平準化してくれますが、GitHub Actionsにはそういう機能は無いので、単にspecファイルを2分割して渡すのみです。

ちなみに、Go言語の場合はこんな感じでテストを分割実行できます

$ go test $(go list ./... | awk "NR%${CI_NODE_TOTAL}==${CI_NODE_INDEX} {print}")

2019年振り返り、2020年の抱負

2019年は書かなかったので、2年ぶりの振り返り記事になります。

転職

退職しました4 - かまたま日記3

一番のトピックはこれでしょうか。前職では色々心残りもありましたが、春にSEQSENSEという警備ロボットを作っているベンチャー企業に転職しました。

現職では主にバックエンド全般を担当していて、GoとかRailsとかTerraformとかを使って仕事しています。ここ数ヶ月は特にロボットのカメラからの動画をWebRTCで配信する機能をメインで見ていて、RTPとかMatroskaとかVP8とかの仕様に詳しくなりました。

去年の8月にロボットの商用化が始まったばかりでまだまだ改善点がたくさんあるので、興味のあるかたはぜひともお声掛けください。

www.wantedly.com

OSS活動

Embulkの内部構造に詳しくなるために、Embulkのプラグインを2つ作ったり

kamatama41.hatenablog.com

kamatama41.hatenablog.com

現職でTravis CIの設定をコード化するためにTerraformのプラグインを作ったりしていました

kamatama41.hatenablog.com

オーナー移管してしまいましたが、tfenvみたいなヒット作をいつかまた作りたいです。

子育て

子供も2歳になり、喋ったり走り回ったりできるようになりました。 週末は行けるときは色んな所に行くようにしているのですが、東京あそびマーレという八王子のアミューズメント施設にはとてもお世話になりました。オススメです。

asobimare.jp

最近は物や動物の名前を覚えたり、数を数えたりできるようになってきたので、動物園や博物館みたいなモノと触れ合う的なところに行く機会を増やしているところです。

麻雀

2018年後半くらいから競技麻雀に猛烈にハマっており、AbemaTVで麻雀の動画を見たり麻雀の本を読み漁ったり都内の某雀荘に足繁く通ったり家でも天鳳やったりと、最近は趣味の時間をほぼ麻雀にベットしている状態です。大会にもいくつか出ているのですが、一番結果が出たのは麻雀最強戦2019で東東京最強位決定戦まで行けたことでしょうか。東東京の試合では準決勝で敗れたのですが、負けた相手が後に最強戦ファイナルまで進出した方だったので、まあ仕方ないかなと。今年は何かしらの結果を出したいです。

2020年の抱負

  • 何かしらの勉強会・カンファレンスで登壇をする
    • 自分の知識向上と会社のプレゼンスアップのため
  • ダイエット (5kg以上減量する)
    • 直近の健康診断で、メタボリック診断されてしまったため。。
  • 天鳳鳳凰卓に行く *1
  • マチュア最強位決定戦に進出する

過去の振り返り

*1:7段になる

Nginxで同じポートでUDPとTCPをリッスンして別のバックエンドにプロキシする

たとえばNLBを使ってUDPをロードバランシングする場合、ヘルスチェックのために、UDPをリッスンするのと同じポートでTCPをリッスンする必要があります *1

そういう場合、バックエンドがNginxの場合は以下のような map$protocol を使った方法で振り分けることが出来ます。ここでは5001番がヘルスチェック用のポートです

stream {
  map $server_port:$protocol $backend {
    5000:UDP "example.com:5000";
    5000:TCP "127.0.0.1:5001";
  }

  server {
    listen 5000 udp;
    listen 5000;
    proxy_pass $backend;
  }

  # Health check
  server {
    listen 5001;
    return "OK";
  }
}

余談

このmapでbackendを切り替える方法は。Nginxが動的にホスト名の名前解決をしてくれない問題の対策にもなります。 (httpの方でよく使う set $backend example.com と同じ効果を得られる)

*1:デフォルトの場合。設定でヘルスチェックを別ポートにすることも可能

Travis CIの設定用のTerraform providerを作った話

この記事はTerraform Advent Calendar 2019 の9日目の記事です。

私の所属しているSEQSENSEではTravis CIを主に利用しています。 CIサービスを使うにあたって、ビルドで使う環境変数SSH鍵などの管理は課題の一つです。

一つ一つ手動で設定していってもいいのですが、リポジトリ数が多くなると

  • リポジトリを横断して一括で設定を変更するのが大変
  • どのリポジトリに何のクレデンシャルが使われているのかがわからないので、うかつにRevokeすると変なところでビルドが落ちる

などの問題が発生したりします。 それを解決するためにTravis CIの設定をコードナイズして一括管理するためのTerraform providerを作成しました。

github.com

よかったら、使ってみてください! *1

使い方

これはオレオレprovider (正式名称はThird-party plugin) のため、バイナリをGitHubのReleasesから落として来る必要があります。

curlなんかを使ってCLIでインストールする場合はこんな感じでしょうか。

$ latest=$(curl -s https://api.github.com/repos/kamatama41/terraform-provider-unofficial-travis/releases/latest | jq -r ".name")
$ os=$(uname | tr '[:upper:]' '[:lower:]')
$ curl -LO https://github.com/kamatama41/terraform-provider-unofficial-travis/releases/download/${latest}/terraform-provider-utravis_${latest}_${os}_amd64.zip
$ unzip terraform-provider-utravis_${latest}_${os}_amd64.zip && rm terraform-provider-utravis_${latest}_${os}_amd64.zip

インストール後、実際のTFファイルの書き方はこんな感じになっています。

# Configure the unofficial Travis Provider (utravis)
provider "utravis" {
  base_url = "https://api.travis-ci.com/"
  token = "${var.travis_api_token}"
}

# Add an environment variable to the repository
resource "utravis_env_var" "my-repo" {
  slug = "myuser/my-repository"
  name = "FOO"
  value = "bar"
  public = true
}

# Add a private key to the repository
resource "utravis_key_pair" "my-repo" {
  slug = "myuser/my-repository"
  value = "${file("~/.ssh/id_travis_rsa")}"
}
  • プロバイダ名は utravis
    • base_url でアクセスするAPIを指定する (travis-ci.com or travis-ci.org)
    • tokenTravis CIのコンソールで取得する
  • utravis_env_var環境変数を設定するためのリソースです
    • public フラグでTravisのコンソール上で表示するかどうかを指定できます (デフォルトはfalse)
  • utravis_key_pairSSH Keyを登録するためのリソースです。 value秘密鍵の中身を指定します

注意

  • 両リソースのValueはSHA-256でハッシュ化された値をstateファイルに保存して生のデータではどこにも保存しませんが、valueを渡すまでののクレデンシャルの管理には十分注意してください *2
  • Travis CIにはブランチごとに環境変数を出し分けるEnvironment variables per branch という機能が少し前に追加されましたが未対応です

*1:そもそもTravisを会社で使ってるというのを(ry

*2:無いとは思いますが、直接tfファイルに書くなどは当然NG

AWS Savings Plans メモ

AWSのSavings Plansのセミナーに参加してきたのでそのメモ。

Fargateに対しても割引が効いたりするし、インスタンスタイプの垣根が無いので*1、そろそろM6が出そうなので、M5のRI買うのやめとこうみたいなのが発生しないのがイイですね。

Savings Plansとは?

  • AWSの計算リソース割引プラン、リザーブインスタンス(RI)より柔軟性が高い
  • 1時間あたりのコミットメント金額 に対して適用される
  • Compute Savings Plans と EC2 Instance Savings Plansがある
    • Compute Savings Plans: より柔軟なプラン。インスタンスファミリー、リージョン、OSに関わらず割引が適用。Fargateの割引もされる
    • EC2 Instance Savings Plans: 割引率が高いもの、インスタンスファミリー、リージョン、OSの指定が必要、Fargateは対応外 (今のRIと同じ)
      • 違いとしてはインスタンス単位ではなく コミットメント金額 単位で購入するという違いがある
  • 割引率は、インスタンスファミリー、Fargateによって違う(https://aws.amazon.com/jp/savingsplans/pricing/) ので、自分で計算するのは面倒。
    • Recommendationsで直近 7 or 30 or 60 日の使用量をベースに推奨値を出してくれるので、それに従うのが良い
  • 割引は一番安くなるように (割引率が高いものから順番に) 適用される
  • RDSは対象外

*1:Compute Savings Plansの場合