注意: このブログは私のプラクティスを記述したもので、 OpenTelemetry 公式の方法を紹介したものではありません。
OpenTelemetry Collector をプロダクションにデプロイする時、自分がつかうコンポーネントのみを含めた Collector をカスタムビルドすることが推奨されています。 カスタムビルドは ocb (OpenTelemetry Collector Builder) を使っておこないます。このブログでは ocb のバージョンを固定する方法を紹介します。 ocb を使った Collector の作り方自体は他のブログに譲ります。
結論を先に言うと tools.go を用いた方法です。 Go に詳しい方ならすぐわかると思います。次のページが詳しいです。
簡単に言うと Go のモジュールマネージャに ocb のバージョンを固定させます。 Go のモジュールマネージャは次のチュートリアルが詳しいです。このブログでは実行するコマンドを書くだけに留め、詳しい説明は次のブログを参照してください。
また(このブログを書いたときの最新バージョンは Go 1.23)将来のバージョン Go 1.24 からは tools.go ではなく、もっと簡潔な方法できるようになりそうです。
前提
Git などのバージョン管理ツールを使って OpenTelemetry Collector builder の設定ファイルやバージョンを管理しようとしている。
以下の説明は Git で管理しているディレクトリ mycustomcollector/ の中で実行しているとする。 また mycustomcollector/ には OpenTelemetry Collector Builder の設定ファイルがあるとする。
$ pwd /path/to/mycustomcollector $ ls builder-config.yaml # OpenTelemetry Collector Builder の設定ファイル
go mod init
Go のモジュールを初期化しましょう。次のコマンドを実行します。
go mod init {このディレクトリをおくリポジトリのURL}{/ディレクトリ...}
{} 内は適宜値を入れてください。お試しで作る場合、つまりリポジトリにおかない場合、{} 内は何でもいいです。Go のモジュールを定義するファイル go.mod を生成します。 go.mod にはモジュールが依存するサードパーティモジュールも記述します。後々の説明で依存モジュールに ocb を含めます。これによって Go に ocb のバージョンを管理させるのです。
この説明では以下、
go mod init example.com/mycustomcollector
を実行したとします。
tools.go を書く
次のようなファイルを作ります。tools.go という名前にします。
//go:build tools package tools import _ "go.opentelemetry.io/collector/cmd/builder"
tools.go は普通の Go プログラムのファイルです。tools.go というファイルを Go が特別扱いすると言うわけではありません。名前も tools.go でなくても良いですが、習慣的に tools.go となっています。
先頭の行の //go:build は Build Constraints と呼ばれるもので、コードをビルドするときにこのファイルを含めるかの条件を書くものです。例えば Unix-like な環境だけビルドに含めたいファイルは //go:build unix と書きます。Go は今回の条件である tools を (unix や windows などと違って) 知りません。この場合、常にビルドに含まれないファイルとなります。
"go.opentelemetry.io/collector/cmd/builder" をインポートするだけのファイルです。go.opentelemetry.io/collector/cmd/builder は ocbのパスですね。通常の Go のコードではライブラリをインポートしますが、ここではコマンド (ocb) をインポートします。これによって go.mod に記述された依存モジュールに ocb を追加させるのです。
import と "go.opentelemetry.io/..." の間にある _ を忘れないようにしてください。ブランクインポートと言うものです。詳しい説明は省きます。
go mod tidy を実行する
go mod tidy はgo.mod を整頓するコマンドです。モジュール以下にある Go のコードファイルを探し、go.mod に記述していない依存サードパーティパッケージを go.mod に追加したり、 go.mod にあるのに誰も依存していないサードパーティパッケージを消したりします。今回は tools.go が依存しているパッケージである ocb を go.mod に追加します。
go mod tidy
すると go.mod は次のようになります。
module example.com/mycustomcollector
go 1.23.3
require go.opentelemetry.io/collector/cmd/builder v0.116.0
require (
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/knadh/koanf/maps v0.1.1 // indirect
github.com/knadh/koanf/parsers/yaml v0.1.0 // indirect
github.com/knadh/koanf/providers/env v1.0.0 // indirect
github.com/knadh/koanf/providers/file v1.1.2 // indirect
github.com/knadh/koanf/providers/fs v0.1.0 // indirect
github.com/knadh/koanf/v2 v2.1.2 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sys v0.21.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
またパッケージのハッシュが記録された go.sum も生成されます。
generate.go ファイルを作る
この準備が終わると、 go.mod があるディレクトリ以下で
go run go.opentelemetry.io/collector/cmd/builder
と実行すると、常にバージョンが固定された ocb が実行されます。上の go.mod ならば常に v0.116.0 の ocb が実行されることになります。
毎回 go run go.opentelemetry.io/collector/cmd/builder を実行してもよいですが、長いし、めんどくさいので go generate コマンドで実行できるようにしましょう。
次のような Go のプログラムのファイルを作ります。名前は何でもいいですが、generate.go にしました。たった2行です。
package mycustomcollector //go:generate go run go.opentelemetry.io/collector/cmd/builder --config {builder の設定ファイル} --skip-compilation
{builder の設定ファイル} は今回の場合 builder-config.yaml になります。
go generate はモジュール以下にある go のソースコードから //go:generate {cmd ...} と書かれた行を探して cmd ... を実行するコマンドです。Go ではソースコードを自動生成することが多々あり、その用途に使われることが多いです。 ocb はカスタムコレクターのソースコードを生成するもので、この用途にぴったりですね。
--skip-compilation はカスタムコレクターのソースコードを生成するだけで、コレクターのバイナリを作らないように ocb に指定するものです。私の場合、バイナリ自体は Docker でビルドするのでバイナリのビルドが不要です。
コレクターを生成する
ここまで準備をしたらあとは go generate を実行するだけ ocb が実行され、カスタムのコレクターのコードが生成されます。
go generate
ここまで実行するとカレントディレクトリは次のようになっているはずです。
collector/ は ocb が自動生成したコレクターのソースコードが入っているディレクトリです。 ocb の設定ファイル builder-config.yaml で ./collector に出力するように指定しました。
$ ls -F -1 collector/ builder-config.yaml generate.go go.mod go.sum tools.go
今後 builder-config.yaml を変更したとき
ocb の設定ファイル builder-config.yamlを変更したら、毎回 go generate をしましょう。バージョンが固定された ocb でコレクターをビルドしてくれます。
自動生成された collector/ 以下を git で管理するか?
Go では自動生成したファイルも git add するのが習慣になっています。その延長で私は ocb が自動生成した collector/ 以下も git で管理しています。ただこれは私がそうしているだけで OpenTelemetry 公式がそのように書いた文章があったわけではないです。