株式会社クリアコード > ククログ

ククログ


FluentdとそのプラグインのWindowsでの開発環境

はじめに

クリアコードはFluentdの開発に参加しています。

また、Fluentdにはプラグインというしくみがあり、たくさんのプラグインが開発されています。
FluentdはWindowsでも動くようになっています。FluentdやそのプラグインはmacOSやLinux上で開発するのが一般的であり、Windowsでプラグインを開発するときの開発環境についての記事を見かけないため、筆者畑ケの環境をまとめてみます。

Fluentdやそのプラグインの開発環境

筆者はFluentdやそのプラグインの開発をするときにWindows環境を使う時があります。
Windows 10 Pro 1909環境で、少しRubyのバージョンが古めですが、2.5.7を使用しています。
このRubyはRubyInstaller2のプロジェクトが公開しているインストーラーです。

シェル環境は非Windows環境と統一していません
ターミナルエミュレータにはWindows Terminal (Preview)を使用しています。
Windows Terminal (Preview)はv0.4.2382.0辺りのころから使用しています。
そこで動かすシェルはPowerShellを使用しています。執筆時点ではPowerShell 6.2.4を動かしています。
PowerShellを使っている理由は筆者畑ケが.NET環境の言語やライブラリに馴染みがあるからです。
RubyInstaller2からはMSYS2というWindows環境でgccを用いた開発環境を作成できるツールチェインがあるため、これをRubyの拡張ライブラリのビルドに使用しています。

GitはWindows用のインストーラーをGit for Windowsが用意しているのでこれを使用します。

PowerShellにはposh-gitを入れてgitのbranchの様子などを表示させています。

また、Docker Desktop for Windowsを使用し、Dockerコンテナを動かす必要があるときはこのパッケージ由来のdockerコマンドを使っています。

Docker Desktop for WindowsのdockerコマンドはWindows環境ではコマンドプロンプトやPowerShellでの動作が想定されており、それ以外のシェルでの動作が想定されていないようです。

エディタはGNU EmacsまたはVisual Studio Codeを使用しています。
エディタに関しては普段使っている環境との乖離を少なくするため、非Windows環境と共通のGNU Emacsを使っていることが多いです。

まとめ

FluentdやそのプラグインのWindows開発環境を解説してみました。
WindowsではPowerShell環境が.NETと親和性が高く、スクリプトとしても痒いところに手が届くようになっています。
そのため、筆者はMSYS2付属のbashやコマンドプロンプトを使わずにPowerShellをWindowsでは普段使いのシェル環境としています。

タグ: Fluentd
2020-02-14

ノータブルコード3 - 危険なバグを仕組みで予防する

第三回目のノータブルコードで取り上げるのは、分散バージョン管理システムGitのヘッダファイル「banned.h」です。

banned.h とは何か?

これは何かと言うと、その名前の通り「危ない関数の利用を禁止する」ためのヘッダです。実際にコードを見てみましょう。

#ifndef BANNED_H
#define BANNED_H

/*
 * This header lists functions that have been banned from our code base,
 * because they're too easy to misuse (and even if used correctly,
 * complicate audits). Including this header turns them into compile-time
 * errors.
 */

#define BANNED(func) sorry_##func##_is_a_banned_function

#undef strcpy
#define strcpy(x,y) BANNED(strcpy)
#undef strcat
#define strcat(x,y) BANNED(strcat)
...

https://git.kernel.org/pub/scm/git/git.git/tree/banned.h

ここで注目したいのは、冒頭に定義されている BANNED というマクロです。そもそも、この banned.h がどうやって関数の使用を禁止しているかというと、「禁止したい関数の呼び出しを、まったく別の関数の呼び出しに書き換える」という方法でこれを実現しています。この書き換えを担当しているのが BANNED マクロで、例えば最初の strcpy を例にとると、これを sorry_strcpy_is_a_banned_function に強制的に書き換えてしまいます。

禁止された関数を使うとすると何が起きるのか?

実際にこのヘッダをインクルードして、禁止された関数を使ってみましょう。今回はこんなコードを用意しました。

#include <string.h>
#include "banned.h"

int main(int argc, char *argv[])
{
    char buf[16];
    strcpy(buf, "aiueo");
    return 0;
}

このコードをコンパイルすると何が起きるかというと、未定義の識別子エラーが発生してコンパイラがコケます。コンパイルが失敗する原因は sorry_strcpy_is_a_banned_function() という関数が(当然のことながら)存在しないためです。実際のエラーメッセージを以下に示します。

$ cc test.c
In file included from test.c:2:
test.c: In function ‘main’:
banned.h:11:22: error: ‘sorry_strcpy_is_a_banned_function’ undeclared (first use in this function)

ここで非常に面白いのは、BANNED マクロが書き換えた後の関数名が、そのままエラーメッセージになっていることです ("Sorry strcpy is a banned function") 。つまり、ここで BANNED マクロは (1) コンパイル処理を失敗させ (2) さらに失敗した理由を開発者に伝える、という一人二役を担っているのです。

ビルドシステムに組み込まれた安全

ヒューマンエラーを低減する為の最も効果的な設計技法の1つは、エラーが物理的に不可能であるか、あるいはエラーが明白なように設計することである。例えば、連結部分のサイズが異なるように設計すれば弁を取り違えることはできなくなる。あるいは、非対称、すなわちオス/メスの連結にすることで1つの方法でしか組み立てられないようにすることは可能である。カラーコーディングで接続の誤りを明示することができる。同等の技法を、オペレータとコンピュータのインターフェイス設計に利用することができる。

ナンシー・G・レブソン 『セーフウェア - 安全・安心なシステムとソフトウェアを目指して』(2009年, 翔泳社)p447

「システムの安全性をどのように実現するか?」という問題は、システム工学の中心的な課題の一つですが、その一つの知見に「ヒューマンエラーの大部分は、実は設計の欠陥である」というものがあります。単純に「人間のミス」として片付けてしまわず、ヒューマンエラーを引き起こした設計を分析して、システム面から対策を講じない限り、次の事故を防ぐことは困難なのです。

今回紹介した BANNED マクロは、システムに組み込まれた安全の一例です。strcpy()strcat() が深刻な不具合を生みやすい機能であることについては、長い議論の積み重ねがあります。ヒューマンエラー防止の観点から見ると、この BANNED マクロは次の3つの特長を持っています。

  1. コーディング規約のような約束ではなく、マクロによる書き換えという仕組みにより、危険な実装を防いでいる。
  2. 単に警告メッセージを出すだけではなく、規約に反するコードはコンパイルが失敗するようにしている。
  3. すべてのコンパイラでも動作する汎用的な制限ロジックを、独自に実装している。

このうち(3)は、手法面で興味深い部分です。例えば、特定のプラットフォーム(例えばGCC)を前提にしてよいなら、#pragma GCC poisonといったコンパイラ独自の機能を使うことで、同じ目的を達成することができます。これにはコンパイラの支援を受けられる(より詳細なエラーメッセージが出せるなど)というメリットがありますが、その一方で他のプラットフォームではうまく機能しなくなるという別の問題を抱えることになります。

今回の BANNED マクロは、コンパイラの支援を受けずに、原因を明解に示すエラーメッセージを出力しているという非常に面白い試みです。

まとめ

皆さんも、コーディング規約を一歩進めて、仕組みによってコードの健全性を担保するようにしてみませんか? 皆さんが使っている、効果的な工夫やアイデアがあれば、ぜひとも教えてください。

2020-02-12

第一回クリアコード・万葉・レトリバ合同ボウリング大会

私の「ボウリング」のイントネーションが他の人と違う気がしている須藤です。青森訛りなのかな。。。

1年半ほど前から「クリアコードをいい感じにする人」の採用を開始していましたが、これまでに何人かの方に手伝ってもらえています。今はたなべさんに手伝ってもらっています。手伝ってもらっているという表現にしているのは、たなべさんには副業として「クリアコードをいい感じにする人」をやってもらっているからです。

クリアコードをいい感じにする中で「チーム間でもっと情報交換できるともっといい感じになるのではないか」という仮説がでてきました。それを実現するための1つの手段としてボウリングをして親睦を深めようという案がでました。なぜボウリング案がでたかというとたまたま第7回ITSボウリング大会実施要領 | [ITS]関東ITソフトウェア健康保険組合があったからです。クリアコードをいい感じにする活動はなにをするのが正解かわからない類の活動なので、試しにやってみてその結果を観察してその次の進め方を調整することが多いです。そのため、ボウリングも試しにやってみることにしました。

クリアコードメンバーだけでやってもよかったのですが、前に大場さんと「ボウリングやろうよー」と話していたので万葉さんも誘って合同でやることにしました。その流れでレトリバさんも一緒にやることになりました。大場さんはレトリバの取締役でもあるのでそのつながりです。ちなみに、クリアコードは万葉さんともレトリバさんとも一緒に仕事をしたことはありません。私の昔なじみの人たちが何人か万葉さんにもレトリバさんにもいるんですけどねぇ。

結果は、万葉チームが1位、少し離れてレトリバチームが2位、かなり離れてクリアコードチームが3位でした。万葉さんはチームで成果をだすことをがんばっていると私は思っているんですが、仕事だけでなくボウリングでもチームで成果をだしていてすごいですね!

ボウリングの後は近くの飲食店に移動して3社合同で懇親会をしました。楽しかったからまた3社でやろうと確認し、解散しました。次もあるはずなのでこの記事のタイトルに「第一回」と入れているのです!

この話を読んでクリアコードとボウリングをしたくなった人は@ktouに連絡してください。万葉さんとボウリングをしたくなった人は@nay3に連絡してください。また別の合同ボウリング大会が実現することでしょう。

さて、今回のボウリングが「チーム間でもっと情報交換できるともっといい感じになるのではないか」仮説にどれだけアプローチできたかはどうやって確認するといいのだろうか。。。

タグ: 会社
2020-02-05

第28回 中国地方DB勉強会 in 岡山:Amazon RDS + Amazon EC2 + ロジカルレプリケーションを使った低コスト高速全文検索 #ChugokuDB

2020年1月25日(土)に第28回 中国地方DB勉強会 in 岡山が開催されました。
私は、昨年の2019年11月に行われた PostgreSQL Conference Japan 2019 の内容(「Amazon RDS + Amazon EC2 + ロジカルレプリケーションを使った低コスト高速全文検索」)を再演させていただきました。

これは、既存の技術を組み合わせて、なるべく楽に高速、高機能な全文検索ができる仕組みを紹介したものです。

当日使用した資料は、以下に公開しています。
PostgreSQL Conference Japan 2019 の資料とほぼ同じですが、 PostgreSQL Conference Japan 2019 で頂いた質問を元に一部加筆しています。

関連リンク:

内容

内容については、PostgreSQL Conference Japan 2019 の再演となりますので、PostgreSQL Conference Japan 2019:Amazon RDS + Amazon EC2 + ロジカルレプリケーションを使った低コスト高速全文検索 #pgcon19jの内容とほぼ同じです。

ただ、PostgreSQL Conference Japan 2019 にて、この構成は同期レプリケーションと非同期レプリケーションのどちらを使っているのか?という質問をいただいていたので、この質問についての回答を追記しています。(スライドの85 - 90ページが追記した内容です。)

以下に追記した内容について記載します。

同期、非同期どちらのレプリケーションでもAmazon RDS + Amazon EC2 + ロジカルレプリケーション + PGroongaを使った低コスト高速全文検索の構成を使うことができます。

ただ、同期、非同期のレプリケーションを使った構成にはそれぞれ以下の特徴があるので、これらの特徴を踏まえた上でユースケースに合わせて選択することをおすすめします。

  • 同期レプリケーション
    • 同期レプリケーションでは、Subscriberの更新を待ってから応答を返すため、非同期レプリケーションに比べて更新性能は落ちてしまう。
    • Subscriberの更新を待つので、PublisherとSubscriberのデータは同一であることが保証される。
  • 非同期レプリケーション
    • 非同期レプリケーションでは、Subscriberの更新を待たずに応答を返すため、同期レプリケーションに比べて更新性能は高い。
    • Subscriberの更新を待たないので、PublisherとSubscriberのデータが同一でないことがある。(タイミングによっては、更新前のデータが見えてしまう。)

同期レプリケーションでは、PublisherとSubscriberのデータが同一であることが保証されるので、更新したデータを即時検索できることがとても重要な場合は、同期レプリケーションを選択することをおすすめします。

そうではない場合は、非同期レプリケーションを選択して更新性能を落とさず検索できるようにすることをおすすめします。

まとめ

今回の発表にあたって、追記した内容を中心に紹介いたしました。
中国地方DB勉強会の皆様、中国地方のコミュニティでの発表という貴重な機会をいただきありがとうございました。

最後に、PGroongaを使った全文検索について、興味、疑問などございましたら、是非、お問い合わせください。

タグ: Groonga
2020-01-28

2020-03-12開催のRubyセミナー松江で講演予定:「Rubyと仕事と自由なソフトウェア」

株式会社クリアコード代表取締役の須藤です。

2020-03-12開催のRubyセミナー松江で「Rubyと仕事と自由なソフトウェア」というタイトルの話をします。松江に住んでいる人も松江に住んでいない人も私のファンの人は来てね。

Rubyアソシエーションの前田さんに声をかけてもらえたので快諾しました。前田さんに声をかけてもらえてうれしかったです。

主な参加者は「業務でRubyを使っているプログラマ」で内容はまかせてくれるということだったので「Rubyと仕事と自由なソフトウェア」にしました。業務でRubyを使っているプログラマには自由なソフトウェアのことを考えて欲しいなと思ったからです。

前に似たような話をしたことはあったかな?と思い返してみると関西Ruby会議2017での「株式会社クリアコード」が少し近いかも。が、なんか、こういう感じじゃなくて、プログラマが活用できるような話にできるといいな。なぜ、オープンソースは自由ソフトウェアの的を外すのかのような内容を少しでも伝えたいな。

松江でみなさんに会えることを楽しみにしています!

2020-01-24

GitHub Actionsを使ったパッケージ作成の自動化

2019年の11月にGitHub Actionsが正式にリリースされました。
GitHub ActionsはGitHubに組み込まれたCI/CD機能でpush等のGitHub上のイベントをトリガーに任意のアクションを実行できるものです。
GitHub ActionsではDockerが使用できるので、様々な環境上でテストの実行やビルドなどができます。

CIサービスは、他にもAppVeyorやTravis CIがありますが、AppVeyorは無料のプランだと、ワーカーがプロジェクトにつき1つなので、Groongaのように複数のパッケージを作成するためにジョブが多くなるプロジェクトだと、ビルドとテストの完了に時間がかかってしまい効率的ではありませんでした。
GitHub Actionsでは、リポジトリーにつき20まで並列で実行できます。

また、Travis CIでは、ビルドした成果物を保存する場所がデフォルトで用意されていないため、正常にビルドできるかの確認やテスト実行はできますが、リリース用のパッケージを作成して置いておくということがやりにくいです。
GitHub Actionsではアクションを実行した結果、生成されたファイルを置いておく場所がデフォルトで用意されているため、GitHub Actions上でパッケージを作成し、作成したパッケージを取得してリリース用のパッケージとしてアップロードするということがやりやすいです。

上記のようなメリットがあったため、Groongaプロジェクトでは、CI/CDをTravis CIやAppveyorからGitHub Actionsへ移行しています。

いままで、GroongaやMroonga、PGroongaのパッケージは開発者の手元でビルド、署名、アップロードを実施していました。
GroongaとMroongaは毎月末にリリースがあるため、毎月末に開発者はパッケージを作る作業を実施しなければなりません。
また、この際にパッケージの作成に失敗するような問題が発覚すると、問題の修正作業にも追われることになります。

GitHub Actionsはpushトリガーでアクションを実行できるので、変更がリポジトリにpushされた段階でパッケージ作成することで、問題の早期発見に繋がり、問題を発生させた変更もすぐに特定できます。
また、GitHub Actionsでパッケージを作成すると開発者はパッケージを署名、アップロードするだけでよくなるので、毎月発生したパッケージ作成時間をなくし、その時間を別の作業に充てることができます。

GitHub Actionsを活用すると、上記のような様々なメリットが発生するので、GroongaとMroonga、PGroongaのパッケージの作成をGitHub Actionsで行うようにしました。この記事は、その過程で得た知見を共有するために記載しています。

まずは、GitHub Actionsの使い方について記載します。

使い方

GitHub ActionsのアクションはYAML形式で記述します。
YAML形式なので、GitHub上でコードとして管理できます。

ここからは、Groongaのパッケージ作成のアクションを例に説明していきます。
Groongaのパッケージ作成のアクションは、以下の場所にあります。

https://github.com/groonga/groonga/blob/master/.github/workflows/package.yml

トリガー

何のイベントをトリガーにしてアクションを実行するかを決めるには、on:を使います。
Groongaのアクションではpush毎にアクションが実行されてほしいので、on:にはpushを指定します。

on:
  push:

GitHub Actionsでは、イベントが起こった対象を指定することができます。
上記のように定義すると、リポジトリーのどのブランチ、タグにpushされてもアクションが実行されます。

全てのブランチやタグが対象ではなく、特定のブランチ、タグにpushされたときだけアクションを実行したい場合は以下のようにします。

on:
  push:
    branches:
      - branch
    tags:
      - tag

push等のイベントトリガーではなく、定期的に実行したいアクションがあるケースもあります。
その場合には、schedule:を使用します。

schedule:の書式はcronの書式で指定できます。ここで指定した時刻はUTCなので、UTCと時差がある日本の場合は時差を考慮に入れて設定する必要があることに注意してください。

Groongaでは以下のように設定し、毎朝9時にアクションが実行されるようにしています。

  schedule:
    - cron: |
        0 0 * * *

onに指定できるイベントは他にもあり、以下のページにまとまっているので、必要に応じて参考にしてください。
https://help.github.com/en/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows

アクションの定義

実行するアクションはjobs:という単位で定義できます。
複数のジョブを作成してそれぞれ並列に実行することもできますし、あるジョブの完了を待ってから実行するというようにジョブ同士の依存関係を定義することもできます。

Groongaでは、現状、パッケージを作成するというアクションのみを行っていますので、以下のようにbuildというジョブを1つだけ定義しています。

jobs:
  build:

ジョブの中ではいくつかのステップに分けてアクションを定義します。
GitHub Actionsのジョブはステップごとに成功、失敗を表示するので、ジョブをステップに分割しておくと、ジョブが失敗したときの原因特定が容易になります。

Groongaでは、パッケージ作成を以下のステップに分割して実行しています。

  • 依存パッケージの配置
    • aptを用いたインストール
    • pip3を用いたインストール(ドキュメントビルド用に使うSphinxをインストールしています)
    • パッケージのビルドに必要なソースコードをClone
  • configureの生成
  • ソースアーカイブ作成用にconfigure実行
  • ソースアーカイブをビルド
  • debian/changelogの更新
  • Docker上でパッケージをビルド
  • ビルドされた成果物をGitHubへアップロード

具体的には以下のように定義しています。
name:で分割したステップに名前をつけます。
run:で実行するアクションを定義します。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - name: Install dependencies
        run: |
          sudo apt update
          sudo apt -V install \
            autoconf-archive \
            bison \
            devscripts \
            python3-pip \
            ruby
      - name: Install Sphinx
        run: |
          sudo pip3 install -v sphinx
      - name: Clone dependencies
        run: |
          cd ..
          git clone --depth 1 https://github.com/groonga/groonga.org.git
          git clone --depth 1 https://github.com/clear-code/cutter.git
      - name: Generate configure
        run: |
          ./autogen.sh
      - name: Configure for archive
        run: |
          ./configure \
            --enable-document \
            --enable-mruby \
            --with-cutter-source-path=../cutter \
            --with-groonga-org-path=../groonga.org \
            --with-ruby
      - name: Build archive
        run: |
          make dist
      - name: Update version
        run: |
          OLD_RELEASE=$(grep -E -o '[0-9.]+' packages/debian/changelog | \
                          head -n1)
          OLD_RELEASE_DATE_FULL="$(grep '^ -- ' packages/debian/changelog | \
                                     head -n1 | \
                                     sed -E -e 's/ -- .+<[^>]+>  //')"
          OLD_RELEASE_DATE=$(date --date="${OLD_RELEASE_DATE_FULL}" +%Y-%m-%d)
          make update-latest-release \
            OLD_RELEASE=${OLD_RELEASE} \
            OLD_RELEASE_DATE=${OLD_RELEASE_DATE} \
            NEW_RELEASE_DATE=$(date +%Y-%m-%d)
      - name: Build with docker
        run: |
          cd packages
          rake ${{ matrix.rake_arguments }}
        env:
          APACHE_ARROW_REPOSITORY: ../../arrow
      - uses: actions/upload-artifact@master
        with:
          name: packages-${{ matrix.id }}
          path: ${{ matrix.repositories_path }}

どのOSでアクションを実行するかはruns-on:で指定します。Groongaではruns-on:ubuntu-latestと定義して、Ubuntuの最新版でアクションが実行されるようにしています。これ以外にも、windows-latest(Windows Serverの最新版)やmacos-latestなどがサポートされています。

実行するコマンドはruns-on:で定義したOSに応じて定義する必要があります。Ubuntuでアクションを実行する場合は、デフォルトでBashが使われるので、Bashで実行できるコマンドを使って定義しています

windows-latestを指定した場合は、デフォルトでアクションがPowerShellで実行されるので、アクションはPowerShellで実行できるコマンドで定義する必要があります。(コマンドプロンプトを使うように指定することもできます。)

アクションを実行するシェルの指定については、以下のページにも説明があるので、必要に応じて参照してください。
https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#using-a-specific-shell

GitHub Actionsでは、よくある処理をまとめて公開共有することが可能で、それらの処理はsteps:の中で呼び出せます。
Groongaでは、リポジトリからソースコードをチェックアウトするのにactions/checkoutを、ビルドしたパッケージをアップロードするのにactions/upload-artifactを使用しています。

actions/checkout@以下にチェックアウトしたいタグやブランチを指定することができます。Groongaでは、masterのソースコードを使いたいので- uses: actions/checkout@masterと指定しています。

actions/checkoutactions/upload-artifact以外にも様々な処理がactionとして以下のURLで公開されています。
https://github.com/marketplace?type=actions

複数の環境でアクションを実行する

複数の環境(複数のOSであったり、ソフトウェアの複数のバージョン)に対して同じアクションを実行したいケースがあります。
もちろん、それぞれの環境用にワークフローを定義しても良いのですが、同じアクションが複数のワークフローにあると、修正漏れが発生しやすくなってしまい、メンテナンスが煩雑になります。

同じアクションを複数の環境で実行したい場合は、matrix:という定義が使えます。

Groongaも各OS毎にパッケージを作成するため、このmatrix:を使ってDebianの各バージョン(stretchの32bit, 64bit、busterの32bit, 64bit)、CentOSの各バージョン(CentOS 6,7,8)に対して同じアクションを実行しています。

具体的には以下のように定義しています。

    strategy:
      matrix:
        label:
          - Debian GNU/Linux stretch amd64
          - Debian GNU/Linux stretch i386
          - Debian GNU/Linux buster amd64
          - Debian GNU/Linux buster i386
          - CentOS 6
          - CentOS 7
          - CentOS 8
        include:
          - label: Debian GNU/Linux stretch amd64
            id: debian-stretch-amd64
            rake_arguments: apt:build APT_TARGETS=debian-stretch
            repositories_path: packages/apt/repositories/
          - label: Debian GNU/Linux stretch i386
            id: debian-stretch-i386
            rake_arguments: apt:build APT_TARGETS=debian-stretch-i386
            repositories_path: packages/apt/repositories/
          - label: Debian GNU/Linux buster amd64
            id: debian-buster-amd64
            rake_arguments: apt:build APT_TARGETS=debian-buster
            repositories_path: packages/apt/repositories/
          - label: Debian GNU/Linux buster i386
            id: debian-buster-i386
            rake_arguments: apt:build APT_TARGETS=debian-buster-i386
            repositories_path: packages/apt/repositories/
          - label: CentOS 6
            id: centos-6
            rake_arguments: yum:build YUM_TARGETS=centos-6
            repositories_path: packages/yum/repositories/
          - label: CentOS 7
            id: centos-7
            rake_arguments: yum:build YUM_TARGETS=centos-7
            repositories_path: packages/yum/repositories/
          - label: CentOS 8
            id: centos-8
            rake_arguments: yum:build YUM_TARGETS=centos-8
            repositories_path: packages/yum/repositories/

strategy:の中にmatrix:を定義します。matrix:の中に変数を定義してそれをsteps:の中で${{matrix.xx.xx}}の形で参照できます。

例えば、Groongaの場合各OS向けのパッケージでビルドしたパッケージの格納場所が異なるため、${{ matrix.repositories_path }}を参照して各OSごとのパッケージをアップロードできるようにしています。

${{ matrix.repositories_path }}とすると、matrix:の定義の中にあるrepositories_path:を参照するので、

      - uses: actions/upload-artifact@master
        with:
          name: packages-${{ matrix.id }}
          path: ${{ matrix.repositories_path }}

は、packages/apt/repositories/packages/yum/repositories/配下のファイルをアップロードしていることになります。

まとめ

Groongaのパッケージ作成に使っている内容を中心にGituHub Actionsを使ったパッケージ作成の自動化の方法について記載しました。
GitHub Actionsに興味はあるが、使っていないという方は、この記事に記載されている内容を参考にして自身のプロジェクトで使用してみてはいかがでしょうか。

タグ: Groonga
2020-01-23

Prometheus Meetup Tokyo #3でLTをしました

はじめに

Prometheus Meetup Tokyo #3でLTをしてきた畑ケです。
Prometheusは近年注目されるメトリクスモニタリングツールです。特徴としては非常にスケーラビリティが高く、Pull型でメトリクスを収集するため、Prometheusのインスタンス1つで1万インスタンスのサーバー群を監視できます。このPrometheus Meetup Tokyo #3ではPrometheus本体というよりもそれを取り巻くエコシステムを対象としたミートアップでした。

筆者は最近Prometheusのエコシステムの一つでGrafana Labが出しているLokiというログ基盤を触ったことがあり、触った時の成果の一つがLTのネタになるのではないかとのことでLTに応募してみたところ、LTに採択されました。

イベントの内容

まず他の方のされた発表をご紹介します。

Remote Write API と Thanos を活用したメトリクス永続化
  • Moto Ishizawa 氏(@summerwind), Z Lab Corporation

コンテナを基盤とする環境でPrometheusを運用していると、例えば、k8sのクラスターを作り直したときにPrometheusで収集したメトリクスが消失してしまう問題があるそうです。
このメトリクスがk8sクラスターに紐づいてしまっている問題を解消するのに永続化ストレージを採用し、永続化を試みていました。ThanosというPrometheusを高可用性にし、長期間のログ保存を可能にするソフトウェアを用いて方法をPrometheusで収集したメトリクスを永続化する方法を丹念に調査していた発表でした。

Victoria Metricsで作りあげる大規模・超負荷システムモニタリング基盤
  • 入江 順也 (GitHub: inletorder)氏, 株式会社コロプラ

Victoria MetricsというこちらもPrometheusで収集したメトリクスを長期間永続化するソフトウェアを使って、Prometheusを高負荷環境にも耐えられえるようにした試行錯誤を発表されていました。このソフトウェアにたどり着くまでにいくつかのPrometheus関連のメトリクス永続化ストレージを試されたそうです。Victoria Metricsはいくつかのコンポーネント(VMStorage, VMSelect, VMInsert)に分かれており、そのうちVMStorageは持つデータによって状態を持つのでk8sではStatefulSetとしてデプロイする必要があるそうです。k8sのマルチテナント構成では合計1万Pod以上の監視を安定的に行えるようになったそうです。

次世代のログ基盤 Grafana Lokiを始めよう!
  • 仲亀 拓馬氏(@kameneko1004, さくらインターネット 株式会社), 上村 真也氏(@uesyn, Z Lab Corporation)

本ククログで何回か筆者が開発者視点で取り上げているGrafana Lokiについての発表です。Lokiについてのデモを通じてどのようなソフトウェアなのかを解説するのが前半の発表でした。後半はpromtail特集でした。promtailはpromtail.yamlにてPrometheusの設定と同様の設定を流し込むことで設定できるそうです。Prometheusと同様にGrafana Lokiも時系列データを保持するのにTSDBを使用しており、これに入れたデータをクエリするのにラベルが必要になるのですが、このラベル設計がうまくないと後に目的の時系列データをクエリするのに苦労するようです。

LTの内容

以下は筆者が行ったLTの内容です。

Grafana Lokiの開発元にFluent BitのGo製のLokiプラグインをフィードバックしてみた話をしました。
このFluent BitのGo製LokiプラグインはFluent BitからGrafana Lokiに転送する方法をまとめたときに紹介しました。
Grafana Lokiは開発が活発なソフトウェアということもあり、ドキュメントがあまり見当たりませんでした。
そのため、promtailがやっていることをソースコードを見つつFluent BitのGo製Lokiプラグインとして仕上げました。

LTではフリーソフトウェアにフィードバックする作法を軽く触れました。
Grafana Lokiもフリーソフトウェアです。フリーソフトウェアの開発は通常開発者同士が同時に同じ場所に集まっているのではなく、住んでいる国や文化、ひいては暮らしているタイムゾーンも異なる場合があります。
フィードバックするには言葉で説明しなければいけません。

まずは、動機や今困っていることを説明します。

  • なぜこの機能が必要か?なぜこの問題を報告したのか?
  • このIssueチケットやプルリクエストでは何を問題にするのか?

プルリクエストは小粒なtypo修正ではない限り、Issueチケットに関連付けられるものとして出す方が良いと筆者は考えています。しかし、この方針はプロジェクトによって異なります。プルリクエストを出す時はプロジェクトの方針を確認してみてください。

  • プルリクエストでは方針を議論するよりも提出したパッチが前もって議論した方針に合っているか、このプロジェクトに受け入れられる品質となっているか?を議論する場だからです。

プルリクエストやIssueチケットにチェックリストが付いているのであれば一通り確認すべきです。

  • 問題が発生している報告者の環境を開発者が再現するには十分な情報が書き込まれている必要があります。
  • よいIssueチケットは開発者が見た時にどのようにすればこの問題が再現できるか?がチケットを見ただけで理解できるチケットです。
  • レビュアーが見るべき箇所が発散しておらず、実現したい機能が実現できているか、パッチの変更は妥当かのレビューに集中できるものがよいプルリクエストです。

Grafana LokiにFluent BitのGo製プラグインをフィードバックしてみたところ、ユーザーもそこそこ出てきたようです。

Grafana Loki自体は一個のバイナリですし、promtailもバイナリ一個で済みます。そのため、Dockerコンテナに載せやすいです。
これらの特徴に加え、Grafana LokiはPrometheusファミリーということもありk8sと非常に親和性がよいです。

k8sに載せるにはまずDockerコンテナ化しないといけないということで、Dockerコンテナ化の要望が新たにIssueチケットとして切られました。
このFluent BitのGo製のLokiプラグインDockerイメージもGrafana Lokiの公式イメージとして提供されることになりました。

k8sでは複数のサービスを連携して動作させる必要がありますが、手動で連携させるには面倒な場合があります。
この煩雑さを解決するソフトウェアはいくつか出ています。Grafana Lokiの開発元からはこの煩雑さを解決するソフトウェアのhelmを用いたFluent BitのGo製Lokiプラグインのレシピが提供されることになりました。

筆者はこのhelmのレシピがきっかけでk8sをより深く理解することになりました。自身の成果をフリーソフトウェアにフィードバックするだけで終わりではなく、フィードバックすることにより学びのきっかけを頂けました。

まとめ

日本ではあまり事例の少ないFluent BitとGrafana Lokiを題材にしてフリーソフトウェアの開発元にフィードバックする作法をLTしました。
フリーソフトウェアの問題を手元で回避するのではなく、開発元にフィードバックするのはクリアコードが普段実践している開発スタイルです。

フリーソフトウェアを普段使っている方でもフリーソフトウェアの開発元にフィードバックする方法が分からず、手元で問題を回避していたり、手元でパッチを持ったままになっている方もいると思います。
その時には本記事のフリーソフトウェアであるGrafana Lokiの開発元へフィードバックした事例をヒントにしてフィードバックに挑戦してみてはいかがでしょうか?

また、フリーソフトウェアの開発にまだ参加したことがない人を対象にしてOSS Gateワークショップを開催しています。こちらも併せて検討してみてください。

タグ: Fluentd
2020-01-17

ノータブルコード2 - 斬新なコメントでコードの可読性を高める

この新しいコーナー「ノータブルコード」では、私たちが開発の折々に目にした興味深いコードをご紹介しています。世の中の実際のプロジェクトから、興味深い素材を肩の凝らない形でご紹介していきたいと思いますので、楽しみにしていてください。

Brubeck - 創造的なコメントで見通しを良くする

第2回目に紹介するのは、GitHubが開発したStatsD互換サーバー Brubeck からの一コマです。

int brubeck_statsd_msg_parse(struct brubeck_statsd_msg *msg, char *buffer, char *end)
{
    *end = '\0';

    /**
     * Message key: all the string until the first ':'
     *
     *      gaugor:333|g
     *      ^^^^^^
     */
    {
        msg->key = buffer;
        msg->key_len = 0;
        while (*buffer != ':' && *buffer != '\0') {
            /* Invalid metric, can't have a space */
            if (*buffer == ' ')
                return -1;
            ++buffer;
    ...

https://github.com/github/brubeck/blob/master/src/samplers/statsd.c#L140-L241

このコードが面白いのは、ずばりコメントの付け方です。

そもそもC言語でパーサを書くのは、非常に面倒な仕事です。RubyやPythonなどのより高級な言語と比べると、その手間のかかり具合は歴然としています。例えば、メッセージを単語に分割する処理ひとつ取っても、Pythonならmsg.split(" ")と書けば簡潔に記述できるのに対して、C言語だと「文字列の先頭から空白文字を探索し、見つかったらノードを初期化して連結リストに追加して次に進む。見つからなければ...」というように 『手続きの積み重ね』 として表現する必要があります。

これは書くのも面倒なら、読むのも大変なコードです。プログラムの作成者の意図は手続きの積み重ねの中に隠れてしまっているので、他の開発者はコードを地道に追うことでそれを読み取るしかないからです。

Brubeckのコードが斬新なのは、このC言語の技術的な制約をコメントの付け方によって回避している点です。冒頭にコードの一部を引用していますが、Brubeckの開発者はブロックごとに「いまここではプロトコルのこの部分を解析しています」というコメントを付与することで、書き手の意図を読み手に伝える戦略を選びました。

ポイントをはっきりさせるため、コードの一部を取り出して構成を以下に図示します。冒頭のコメントが後続する処理の宣言になっていることが明解に見て取れると思います。

Brubeckのコード解説

私たちは、このコードに感銘を受けたので、自分たちのStatsDパーサでも同じようなブロックコメントを付けることにしました

開発の現場では、時としてコメントは「おまけ」として扱われがちですが、創造的な使い方をすることで、コードの読みやすさを一変させることができるのだ、というのが今回の連載の要点です。

補足: 関連するテクニックについて

このBrubeckの手法に似ているものとして、コミットメッセージの中で記号を使って、変更内容を視覚的に示すというテクニックがあります。

こちらについては、過去記事「わかりやすいコミットメッセージの書き方」 の中で紹介しているので(記事中の「英語だけで表現することにこだわらない」の節を参照)、興味のある方はご一読ください。

2020-01-15

ノータブルコード1 - printfの縦揃え

リーダブルコードの解説の著者の須藤です。リーダブルコードの本編ではプログラマそれぞれがリーダブルなコードを書く方法を紹介しています。リーダブルコードの解説ではチームでリーダブルなコードを書く方法を紹介しています。

では、その次のステップはなんでしょう。それは「チーム外とリーダブルコードの知見を共有する」です。情報を提供するところに情報は集まります。自分たちがリーダブルコードの知見を発信することで知見が集まります。集まるのを待つだけではなく自分から知見を探しにいけばさらに知見を集められます。チーム内だけで知見を共有していると、限られたコンテキストでの知見しか得られなくなってしまいます。チーム外の知見も活用することでチームに新しい知見を導入できます。

たとえば、Ruby on Railsを使ってWebアプリケーションだけを書いている場合はそのコンテキストの知見ばかり集まります。しかし、その知見は、Pythonで機械学習するコードを書いたときに得られる知見とは違います。Pythonで機械学習するコードを書いたときに得られる知見のうちRuby on Railsを使ってWebアプリケーションを書いているときに活かせる知見もあるものです。違うコンテキストの知見を集められればもっとリーダブルなコードを書けるようになります。

実際に自分が違うコンテキストのコードを書かなくても、違うコンテキストで書かれたコードを読むだけでも知見を得られます。(もちろん、自分が書いた方が得られる知見は大きいです。)そのため、クリアコードのメンバーは他の人が書いたコードを読んで学んでいます。野生のリーダブルコードを見つけて学んでいるということです。クリアコードが大事にしているフリーソフトウェアには「プログラムがどのように動作しているか研究し、必要に応じて改造する自由 (第一の自由)」があるので野生のリーダブルコードを学び放題です。

前置きが長くなりましたが、クリアコードのメンバーが普段やっている「他の人が書いたコードから学んだこと」を「ノータブルコード(Notable Code)」としてこのブログで紹介することにしました。前から社内では紹介していたのですが、社内で閉じる必要はないので公開している場所で紹介することにしました。

「ノータブルコード」という名前にした理由は次の通りです。

  • 「リーダブルコード」っぽい!(語感が似ている)
  • 「よい悪い」というより「単に私はここに注目したよ!」というだけだから(「note」ってそういうニュアンスだよね?)
    • 「notable」には「重要な」という「よい」ニュアンスがあるみたいなので本当はアレなんですけど。。。

それでは最初のノータブルコードを紹介します。

Apache ArrowのRのLinux向けパッケージを改良するプルリクエストで見つけたものです。

sprintfを使って文字列をフォーマットしているRのコードです。Rのコードですが、sprintfはいろんな言語にある機能なので、Rを読み書きできない人でも読めるはずです。

https://github.com/apache/arrow/pull/6068/files#diff-3875fa5e75833c426b36487b25892bd8R153-R155

  env_vars <- sprintf(
    "SOURCE_DIR=%s BUILD_DIR=libarrow/build DEST_DIR=%s CMAKE=%s",
    src_dir,                                dst_dir,    cmake
  )

sprintfはフォーマット文字列に実際の値を埋め込んで最終的な文字列を生成しますが、どの値がどこに対応するかわかりにくくなりがちです。このコードでは縦に埋め込み場所と埋め込まれる値を揃えて対応をわかりやすくしています。

他のやり方として、文字列内に式を埋め込む方式(Rubyなら"SOURCE_DIR=#{src_dir}"と書く)や、埋め込み場所に名前を使う方式(Rubyなら"SOURCE_DIR=%{src_dir}" % {src_dir: src_dir}と書ける)がありますが、このスタイルは初めてみました。1行が長すぎると使えないとか、埋め込む値の式が長いと使えないとか使える機会は限定される気がしますがおもしろいなぁと思いました。

おもしろくて思わずコメントしてしまいました。このコードを書いた人によるとリーダブルなコードになるようにいろんな方法を実験していたとのことでした。やっぱり工夫して書いたものだったんですね。

2020年はみなさんも気になったコードを「ノータブルコード」として共有してみませんか?

2020-01-14

Apache Arrow東京ミートアップ2019 参加レポート

Apache Arrow 1.0.0の正式リリースを間近に控えた先週12月11日に、第二回目となるApache Arrow東京ミートアップが開催されました。
今回の会場は株式会社Speeeの六本木オフィスをご提供いただきました。O'Reilly本が並んだ書棚を背景に、シックな木目の家具で統一された会場で、とても素敵な会場でした。

Apache Arrow Tokyo Meetup 2019

ミートアップの内容としては、まずプログラムの冒頭で弊社の須藤から簡単なガイダンスがあった後、7人の講演者による発表がありました。
本記事の作者(藤本)の聴講メモより、各発表の要点をまとめます(箇条書き外は藤本の感想です)。

Apache Arrowの最新情報 (株式会社クリアコード/須藤)

スライド資料リンク (Rabbit)

  • Apache Arrowとは多言語に対応したオンメモリのデータ形式(とそれに関連する一連のデータ処理ライブラリ)である。
  • 列指向の考え方を採用していて、できるだけコンピューターがそのまま扱えるような形式で作られている。
  • 用途としては、プロセス・ホスト間のデータの受け渡しに使われている。シリアライズとパースの手間が減るので、相当効率化できる(具体的には、後の山室さんの発表を参照のこと)。
  • 技術提供できるので、使ってみたい企業の方はお問い合わせください。
Apache Arrow Datasets C++ (株式会社Speee/村田さん)

スライド資料リンク (Speaker Deck)

  • Datasetsとは、様々な場所にあるファイルデータ(ローカルディスクやAmazon S3など)を読み出して、Apache ArrowのTableオブジェクトに統合してくれるレイヤ。
  • パスによって階層的にデータを保存する設計になっている。これで一部のデータのみを読み出したいという要望にも応えられる。
  • 現時点でファイル形式はApache Parquetのみ対応しているが、今後CSVやJSONなどの各種形式の対応が計画されている。
  • これを基盤として、SQLライクなクエリを実行するクエリエンジンや、集計処理を実行するデータフレームが作られていく予定。

Apache Arrowプロジェクトが単なるデータ形式にとどまらず、ストレージや計算実行まで拡大しつつある状況がよく分かる報告でした。また「まだ全体的に議論が進んでいる段階で、実装の手が届いていないところも多いので、積極的に開発に関与すると喜ばれるかもしれない」とのことでした。

RとApache Arrow (湯谷さん)

スライド資料リンク (Speaker Deck)

  • RとApache Arrowの統合が格段に進みつつあるという報告。
  • 一つの進展として、Apache Sparkのライブラリ sparklyr にApache Arrow対応が入った。これでApache Sparkとの間でApache Arrowで直接やりとりできるようになった。
  • また、Apache Parquetの読み書きもできるようになった。Pythonなどの他の言語との連携が期待できる。
  • その他にも、CRANで手軽にインストールできるようになった等の進展がある。
PostgreSQLとApache Arrowの利用事例 (ヘテロDB株式会社/海外さん)

スライド資料リンク (SlideShare)

  • PostgreSQLのForeign Data WrapperでApache Arrow形式のデータを扱えるようにしたという報告。
  • 列指向なので、参照されているデータのみを読み出せるなどの良い特性がある。GPUメモリバスの特性から、演算実行も高速。
  • 自社製品のPG-Stormと組み合わせることで、シングルノードで10億レコード/秒程度の性能を出せることが実証できた。
Apache SparkとApache Arrowの連携 (NTT/山室さん)

スライド資料リンク (SlideShare)

  • Apache SparkでApache Arrowを活用できる箇所は大きく二つある。1つはプログラムからクラスタにデータを投入する箇所、もう1つはクラスタの内部でデータを受け渡している箇所。
  • 1つ目のユーザーとのやりとりは@pandas_udfというデコレータを使うだけでApache Arrow形式を使えるようになっている。ベンチマークの結果から、これでかなり高速化できることが分かっている。
  • 2つ目のクラスタ内部でのデータのやりとりは、設定で有効化できるようになっている。一部の型が未対応なのでデフォルトではオフになっている。
  • 未対応の型などの問題も、今後のバージョンで解消されていく予定。

なぜApache Arrowが開発されたのかとても納得がいく発表でした。要するに、並列計算のパラダイムのシステムでは、設計上、計算を実行するノード間で膨大なデータのコピーが発生する。このため、パースの手間を可能な限り省いたApache Arrowのようなデータ形式を採用することで、飛躍的な速度の向上が見込めるのです。

TensorFlowとApache Arrowの連携 (日本アイ・ビー・エム株式会社/石崎さん)
  • 同僚であるIBM Spark Technology Centerのブライアンさんの代理報告とのことでした。
  • Tensorflow I/Oというデータ入出力をサポートするライブラリがあり、この中でApache Arrowもサポートされている。
  • Apache Arrowの中に高速なCSVの読み出し実装もあるので、この点でも効率化をはかることができる。
  • 具体的なベンチマークはもう少しブラッシュアップしてから公表したい、とのことでした。
TensorFlowとBigQuery Storage APIとApache Arrowの連携評価事例 (SENSY株式会社/漆山さん)

スライド資料リンク (Google Docs)

  • 「感性を学習する」をテーマに、数百GBから数TBのデータの購買データを分析されているとのことでした。
  • データの保存にBigQueryを使っていたが、このStorage APIにApache Arrow対応が入ったので、これを利用されているとのこと。
  • ベンチマークをとってみると、Apache Arrowを使うことで、データ取得に要する時間はもちろん、その後の学習も高速化されたとのことでした。

まとめ

ここで講演は終了して、残りの時間ではSpeeeさんにご提供いただいた夕食を食べながらの懇親会がありました。立食形式で興味のある講演者の方と直接お話することができるようになっていて、それぞれのテーブルでは活発に議論が交わされていました。

以上でApache Arrow東京ミートアップ2019 は終了しました。3時間という枠で様々な側面からの発表が聞けた充実した会だったと思います。会場を提供頂いた株式会社Speeeさんをはじめとする関係者および講演者のみなさまには改めてお礼申し上げます。ありがとうございました。

2019-12-16

タグ:
年・日ごとに見る
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|