`container:` でUbuntuのBionic以下のDockerイメージを指定してactions/checkout@v2を利用する場合は注意が必要

GitHub Actionsを使っているとき、あまり container: を指定することはないかもしれませんが、例えば以下のように ubuntu:bionic を指定して事前にGitをインストールした上で actions/checkout@v2 を実行したとき

name: CI

on:
  push:

jobs:
  build:
    runs-on: ubuntu-latest
    container: ubuntu:bionic
    steps:
      - run: |
          apt-get update -qqy
          apt-get install -qqy git
      - uses: actions/checkout@v2
      - run: git status

最後の git status が失敗します。

f:id:k1LoW:20210317230131p:plain

actions/checkout@v2 は Git 2.18 以上を要求している。しかし...

これの答えは actions/checkout@v2 のログに書かれています。

f:id:k1LoW:20210317230346p:plain

The repository will be downloaded using the GitHub REST API To create a local Git repository instead, add Git 2.18 or higher to the PATH

Git 2.18 以上がインストールされていないと git clone ではなくGitHub REST APIを使ってダウンロードしてくるのですね。

しかし、Ubuntu BionicにインストールされるGitのバージョンは

f:id:k1LoW:20210317230707p:plain

残念ながら1ポイント及ばす 2.17 なのです(2021年3月17日)

actions/checkout@v2 on Ubuntu Bionicでgit cloneしてもらうにはGitのバージョンをあげるしかない

ということで、私は以下のようにしています。

name: CI

on:
  push:

jobs:
  build:
    runs-on: ubuntu-latest
    container: ubuntu:bionic
    steps:
      - name: Update Git
        run: |
          apt-get update -qqy
          apt-get -qqy install software-properties-common
          add-apt-repository -y ppa:git-core/ppa
          apt-get update -qqy
          apt-get -qqy install git
      - uses: actions/checkout@v2
      - run: git status
  1. add-apt-repository を使いたいので software-properties-common をインストール
  2. “Ubuntu Git Maintainers” teamのPPAをリポジトリとして追加
  3. Gitをインストール

f:id:k1LoW:20210317232218p:plain

無事 git clone されました。

以上、メモでした。

GitHub Container RegistoryのDockerイメージをリポジトリに紐づける方法

GitHub Container Registoryは、GitHub Package Registryとは異なりPublicなDockerイメージのpullにGitHub認証の必要がないなど、利用者にとって便利です。

また、リポジトリとの紐付けが強制されていないので自由に様々なイメージを管理できます。

イメージはProfileページのPackagesタブにリストアップされます。

f:id:k1LoW:20210306193712p:plain

ただ、私の主な用途としてはリポジトリで公開しているライブラリのDockerイメージの提供なのでリポジトリと紐付けたい。

具体的にはリポジトリの Packages の欄に表示させたい。

f:id:k1LoW:20210306193956p:plain

どう紐づければいいのかわからなかったのですが、やっとわかりました。

DockerfileにLABELとして org.opencontainers.image.source を設定すればいいようです。

LABEL org.opencontainers.image.source=https://github.com/k1LoW/tbls

もしくはdocker build時にビルドフラグとして --label=org.opencontainers.image.source=https://github.com/k1LoW/tbls を渡せばいいみたいです。

私はGoReleaserを利用しているので以下のような設定を追加しています。

dockers:
  -
    goos: linux
    goarch: amd64
    image_templates:
      - 'ghcr.io/k1low/tbls:v{{ .Version }}'
      - 'ghcr.io/k1low/tbls:latest'
    dockerfile: docker/Dockerfile.ghcr.io
    build_flag_templates:
      - "--pull"
      - "--label=org.opencontainers.image.created={{.Date}}"
      - "--label=org.opencontainers.image.name={{.ProjectName}}"
      - "--label=org.opencontainers.image.revision={{.FullCommit}}"
      - "--label=org.opencontainers.image.version={{.Version}}"
      - "--label=org.opencontainers.image.source=https://github.com/k1LoW/tbls"

これで、無事リポジトリにDockerイメージを紐づけることができました。Dockerイメージの設定画面でも青の認証バッジがつきます。

f:id:k1LoW:20210306194539p:plain

そして、最後にDockerイメージをPublicにするのを忘れないでください。

どうやらGitHub Container RegistoryにpushしたイメージはデフォルトはPrivateなようです。

これを忘れると誰にも使ってもらえません。

というわけでメモでした。

GitHub Actionsを使用してバージョンを指定してパッチを当てたバイナリをビルドするというフローを自動化する

リポジトリはこちらです。

github.com

何をやっているかというと過去にも実施したWazuh agentにパッチを1行当ててビルドするだけです。

k1low.hatenablog.com

ただ、GitHub Actionsの利用方法としてはなかなか面白い使い方かなと思ったのでエントリにしました。

実現しているのは

欲しい「パッチ済みWazuh agentのバージョン」をタグとして git push すると、それをトリガーにGitHub Actionsのワークフローが起動して

  1. 指定のバージョンの wazuh/wazuh のソースをgit clone
  2. パッチを適用
  3. ディストリビューションごとにビルド
  4. ビルドしたバイナリをtarでまとめてReleasesにアップロード

を並列に実行するというものです。

以下YAML全文

name: build

on:
  push:
    tags:
      - v*

jobs:
  debug-build:
    name: Build agent with patch
    strategy:
      matrix:
        platform: [ubuntu-xenial, ubuntu-bionic, centos-6, centos-7]
    runs-on: ubuntu-latest
    steps:
      - name: Install packages
        run: |
          sudo apt-get -qq update
          sudo apt-get install -qq git tar
          curl -sL https://github.com/tcnksm/ghr/releases/download/v0.13.0/ghr_v0.13.0_linux_amd64.tar.gz -o ghr.tar.gz
          sudo sh -c "tar xf ghr.tar.gz -O ghr_v0.13.0_linux_amd64/ghr > /usr/local/bin/ghr"
          sudo chmod +x /usr/local/bin/ghr
      - name: Check out source code
        uses: actions/checkout@v2

      - name: Make directory
        run: |
          mkdir dist
          mkdir pkg
      - name: Build agent with patch
        run: |
          docker build . -f Dockerfile.${{ matrix.platform }} -t wazuh-debug
          docker run --rm -v $(pwd)/dist:/dist --env WAZUH_VERSION=${GITHUB_REF##*/} wazuh-debug
      - name: Release
        run: |
          tar cfz pkg/wazuh-debug-${GITHUB_REF##*/}-${{ matrix.platform }}.tar.gz dist/
          ghr -replace ${GITHUB_REF##*/} pkg/
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

指定のバージョンでビルドする

前提として

  • wazuh/wazuh がバージョンでタグを切っている

というのがあるのですが、それを利用して各DockerfileのCMDに設定している build.sh 内で

git clone https://github.com/wazuh/wazuh.git -b ${WAZUH_VERSION} --depth 1

を実行し、必要なソースコードをgit cloneしてきています。

${WAZUH_VERSION} はどう取得してきているかというと、環境変数 GITHUB_REF${GITHUB_REF##*/} で文字列置換して取得しています。

GITHUB_REFGitHub Actionsにおいてブランチやタグのrefなのですが、on.push.tags: でタグpushのみでジョブが実行されるようにしているので必然的に「タグ=Wazuh agentのバージョン」を取得できる仕組みになっています。

並列実行する

これは strategy.matrix: を利用しています。

よく strategy.matrix: は言語のバージョンや実行環境の種類などが例にあげられますが、別にそれらに限らず並列実行するのに使えるので便利です。

今回はディストリビューション名を与えて、それを使用してDockerfileのファイル名やリリースするアーカイブ名に使っています。

作成したバイナリは ghr でアップロードしています。

ディストリビューションごとにバイナリファイル名をうまく分けて、かつ -replace オプションを使うことで

  • 並列で
  • 何度でも同じタグのReleaseに

アップロードできるので便利です。


以上です。

今年はさらにGitHub Actionsを使い倒すことになりそうです。

2020年の振り返りと2021年の抱負

年が変わるタイミングは寝ていました。起きたら明けてました。

2020年の振り返り

内に籠もった年だったのかなと思います。これには様々な要因があるとは思いますが、あまりアクティブな活動はなかったかなと思います。

(子育てが自分のライフサイクルに深く組み込まれたのは前からですが)在宅勤務になったことと、外でのイベントごとが皆無になったことで発散する場が無くなってしまった感じです(「発散」というと何か鬱憤が溜まっているように聞こえるかもしれませんが、そうではなくて「うまくリズムが取れない」というか)。

自分は生活環境の変化に弱い自覚があるのですが、2020年1年かけてもまだ慣れていないのかも?という感覚です。

2020年の抱負は「視座を上げる」でした。

エンジニアとしては、完全に外的要因なのですが社内の評価制度や周辺の目標(?)設定スキームがさらに洗練されたことがキッカケで中長期的な視点で考える機会が増えました。本当にありがたい。

その結果自分に足りないモノがよく見えるようになってしまい凹むこともありますが、気づかないままでいるより断然マシです。気づきから改善に繋げていきたいです。

ヒトとしての視座は、、、、イマイチ上がらず。です。

OSS活動

いろいろ作りました。

2020年はtblsをより良くすることができた年だったかなと思います。

tbls自体の設計方針と目の前のtblsで解決したい課題にズレがある状態から、tblsの設計を曲げるのではなくtblsにプラグイン機能を追加することで課題解決をする機能を外出しすることにしたのですが、結果としてtblsの可能性を広げることにつながりました。

自分のOSS活動はやっぱり「課題があってこそ」なんだなと実感できました。

そういえば作るOSSも構想や設計に時間がかかるものや機能がポツポツ出てきた気がします(これ、単純にエンジニアとしての能力が衰えたから時間がかかるとかじゃなければいいんですけど。。。)。

2020年に作成したけれどもまだもう少し洗練させたいと思っているツールが1、2個あるので、何か良いアイデアが降ってくるのを待ちつつドッグフーディングをして、良いタイミングで紹介したいと思います。

発表

2020年はほとんど発表していません。ただ、発表しているものは(自分の中では)一貫していて、その点に関しては良かったかなと思っています。

2021年の抱負

今年は「インプットができるようにする」です。読んで字の如くです。

私は解決したい課題ドリブンで技術をインプットする(調査したり習得したりする)ことが多いです。逆に作りたいモノがない状態で何かを1から学ぶというのが苦手です。

このいわゆる「遅延勉強法」はモチベーションがないと何もできない私にはしっくりきているのですが、実は私の場合は大きな欠点があります。

課題を解決してしまうとその技術の習得サイクルが終わってしまい、結果として体系的な知識を獲得できないという点です。「雰囲気でやっている」というやつです。

最近この欠点がじわじわと自分を苦しめているような気がしてならないのです。やっと気づいた。

いきなり遅延勉強法をやめるというのは難しいので、まずはあえて今まで避けてきた「コンフォートゾーンから大きく外れている技術」が必要な課題を解決することを目指したいと思っています。解決までに時間がかかる分、そこまでに得られるインプットも大きいと思っています。

さっそく解決したい課題からかなり遠いチュートリアルからはじめていて新年早々イライラしているのですが、あせらずやっていこうと思います。

あ、あと分割キーボードを手に入れたい。MacBook Proとほぼ同じキー配置で。

今年もよろしくお願いいたします。

フォント周りで作成したGoパッケージの紹介

Goでフォントを扱うことって(おそらく、たぶん、きっと)ほとんどないと思うのですが、私はなぜか文字が入っているpngファイルの生成とかER図とかを出すようなOSSを開発していることから、フォント周りのGoパッケージを作る機会がありました。

どれもパッケージというには小さいコード片で紹介することもないだろうと思っていたのですが、せっかくなので紹介したいと思います*1

fontdir

github.com

フォントを指定するためには大抵フォントファイルのパスを指定しなければいけません。

fontdirは各環境でフォントファイルが格納されているディレクトリを取得できるだけのパッケージです。

これはパッケージを作ったと言うより https://github.com/flopp/go-findfont のフォントディレクトリ取得関数がprivateだったのでその関数だけポーティングしました。

ffff

github.com

何かのOSSとかでフォントを指定してもらうような設定を作った時、「自分でフォントファイルを指定する」ならまだしも「ユーザにフォント名を寸分違わず指定してもらう」って厳しいUXだろうなと思って作りました。

ffffはフォントをFuzzy FindしてくれるGoパッケージです。

今のところTrueTypeとOpenTypeに対応していて、検索するときに 検索結果のフォントがどのTypeかはわからないので両方のOptionを指定しておく というアプローチをとっています。

package main

import (
    "fmt"

    "github.com/beta/freetype/truetype"
    "github.com/k1LoW/ffff"
    "golang.org/x/image/font"
    "golang.org/x/image/font/opentype"
)

func main() {
    fontSize := 12.0
    dpi := 72.0
    to := &truetype.Options{
        Size:              fontSize,
        DPI:               dpi,
        Hinting:           font.HintingNone,
        GlyphCacheEntries: 0,
        SubPixelsX:        0,
        SubPixelsY:        0,
    }
    oo := &opentype.FaceOptions{
        Size:    fontSize,
        DPI:     dpi,
        Hinting: font.HintingNone,
    }

    face, err := ffff.FuzzyFindFace("Arial", to, oo)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%v", face)
}

mplus-fonts

github.com

golang.org/x/image/font/gofont のフォントの組み込みの仕組み面白いですよね。中身は単純にTTFファイルを []byte にして突っ込んでいるだけという。

面白いと思ったのでgofontの []byte 化の仕組みを使って、M+FONTSのTTFファイルをGoパッケージにしてみました。

本当は他のOSSで使おうと思って作ったのですが、他のアプローチでいろいろ解決したのでまだ使っていません。

ちなみに、デザイナーの人からしたら :thinking: な感じかもしれませんが「好きなフォントは何ですか?」と聞かれたら私は「Century GothicかM+FONTS」と答えるくらいにはM+FONTSの印象が強いです。


紹介は以上です。

他にもGoでSVGの扱うときの細かいTipsとかあったりするのですが、GoでSVGを扱うってほとんd(ry

*1:本エントリはGo 5 Advent Calendar 2020 20日目の代理投稿です

Trivy DBを他のデータベースにマイグレーションするツール trivy-db-toを作った

Trivyは言わずと知れた脆弱性スキャナです。

私は最近までコンテナ専用のスキャナだと思っていましたがそんなことはなく、様々な環境に対してOSパッケージやアプリケーションの依存ライブラリの脆弱性を高速に検知してくれる汎用的なスキャナです。

k1low.hatenablog.com

CI環境だろうがサーバ内だろうが脆弱性検知をしてくれるTrivyですが、「その脆弱性データベースはどこにあるんだ?」となると思います。

実は毎回最新の脆弱性データベースを確認し(手元のデータベースより新しいものがあれば)ダウンロードしています。Trivy DBと呼ばれているようです。

Trivy DB

github.com

Trivy DBは通常版とlight版があるのですが、通常版でもダウンロードサイズはわずか19.4MBです *1

(実は、このTrivy DBを作成するまでの仕組みがよくできていたり、Trivy DBの中身についてTrivyの作者である@knqyf263さんに解説いただいたりしたので、それはまた別のエントリとか別のどこかで紹介したいです。)

Trivy DBを利用することでTrivyと同一の脆弱性データベースを得ることができるわけです。

同一のデータベースを得ることで、Trivyで検知した脆弱性情報を確認するWebUIを作ったり、別のツールでTrivyと同一の情報を利用することで情報の信頼性を担保したり、Trivyを中心としたシステムを作りやすくなります。

Trivy DBはbboltというファイルベースのいわゆる組み込み向けKey-Valueデータベースを採用しており、Trivyが効率的に使う想定になっています(それは当然そう)。

bboltのままだと他のシステムからの情報取得がしづらいので*2、Trivy DBを他のデータベースにマイグレーションするツールを作りました。

github.com

trivy-db-to

trivy-db-toはTrivy DBを他のデータベースにマイグレーションをするツールです。

CIやk8sのCronJobなど、データベースに接続できる環境で定期的に実行して脆弱性情報を更新する想定で作成しています。

使い方は以下のようにマイグレーション先のデータベースを指定して実行するだけです。

$ trivy-db-to mysql://root:mypass@127.0.0.1:3306/mydb

内部のフローとしては、

  1. (なければ)最新のTrivy DBを取得
  2. (なければ)マイグレーション先のデータベースに必要なテーブルを作成
  3. Trivy DBから脆弱性情報を吸い出してテーブルに登録
    • INSERT前にTRUNCATEが走ります

となります。更新が必要なデータだけUPDATEすれば良いとは思ったのですが、処理がある程度実時間で完了するので

v0.2.0ではMySQLPostgreSQLに対応しており、要望があれば他のデータベースにも対応したいと思っています。

私もまだプロダクション環境では利用していないのですが、使っていきたいところがあるので近いうちに適用できるように狙っていきます。

ニッチですがぜひどうぞ。

*1:2020/12/7時点のサイズ

*2:Goのツールであれば良いのですが

サーバが抱えているCVEとパッケージアップグレードによって解決するCVEを確認する方法

trivy fs /

これだけ。

Trivy便利!コンテナにしか使ってなかったけど何にでも使っていけそう。

こちらからは以上です。

github.com