CLOVER🍀

That was when it all began.

Incusのデフォルトイメージサーバーで提供されているイメージの出典を確認する

これは、なにをしたくて書いたもの?

Incusのデフォルトイメージサーバーを参照すると、仮想マシンやコンテナー以外にもVariantというものがあります。

例えばUbuntu Linux 24.04 LTSでもubuntu/nobleubuntu/noble/cloudなどがあります。

$ incus image list images: ubuntu/noble
+-------------------------------------+--------------+--------+---------------------------------------+--------------+-----------------+------------+----------------------+
|                ALIAS                | FINGERPRINT  | PUBLIC |              DESCRIPTION              | ARCHITECTURE |      TYPE       |    SIZE    |     UPLOAD DATE      |
+-------------------------------------+--------------+--------+---------------------------------------+--------------+-----------------+------------+----------------------+
| ubuntu/noble (7 more)               | 2c6a397c32a7 | yes    | Ubuntu noble amd64 (20260920_07:42)   | x86_64       | CONTAINER       | 133.79MiB  | 2026/09/20 09:00 JST |
+-------------------------------------+--------------+--------+---------------------------------------+--------------+-----------------+------------+----------------------+
| ubuntu/noble (7 more)               | 9cd1a1d16c20 | yes    | Ubuntu noble amd64 (20260920_07:42)   | x86_64       | VIRTUAL-MACHINE | 290.79MiB  | 2026/09/20 09:00 JST |
+-------------------------------------+--------------+--------+---------------------------------------+--------------+-----------------+------------+----------------------+
| ubuntu/noble/arm64 (3 more)         | 67abc56655ca | yes    | Ubuntu noble arm64 (20260920_07:42)   | aarch64      | CONTAINER       | 130.95MiB  | 2026/09/20 09:00 JST |
+-------------------------------------+--------------+--------+---------------------------------------+--------------+-----------------+------------+----------------------+
| ubuntu/noble/arm64 (3 more)         | 094efc093e47 | yes    | Ubuntu noble arm64 (20260920_07:42)   | aarch64      | VIRTUAL-MACHINE | 301.85MiB  | 2026/09/20 09:00 JST |
+-------------------------------------+--------------+--------+---------------------------------------+--------------+-----------------+------------+----------------------+
| ubuntu/noble/armhf (3 more)         | 419ca8d5ae51 | yes    | Ubuntu noble armhf (20260920_07:42)   | armv7l       | CONTAINER       | 122.07MiB  | 2026/09/20 09:00 JST |
+-------------------------------------+--------------+--------+---------------------------------------+--------------+-----------------+------------+----------------------+
| ubuntu/noble/cloud (3 more)         | 0e5e51af9bf3 | yes    | Ubuntu noble amd64 (20260920_07:42)   | x86_64       | CONTAINER       | 161.25MiB  | 2026/09/20 09:00 JST |
+-------------------------------------+--------------+--------+---------------------------------------+--------------+-----------------+------------+----------------------+
| ubuntu/noble/cloud (3 more)         | bbeff1b571a7 | yes    | Ubuntu noble amd64 (20260920_07:42)   | x86_64       | VIRTUAL-MACHINE | 326.10MiB  | 2026/09/20 09:00 JST |
+-------------------------------------+--------------+--------+---------------------------------------+--------------+-----------------+------------+----------------------+

〜省略〜

こういったものの差はなんだろう?というのを確認するのが今回の目的です。

デフォルトイメージサーバーと提供イメージ

Incusのincusコマンドは、デフォルトイメージサーバーを使うように設定されています。

Default image server - Incus documentation

デフォルトイメージサーバーというのはこちらのことで、登録されているイメージが確認でいます。

Linux Containers - Image server

こちらのコマンドでも確認できますね。

$ incus image list images:

コマンドの結果だとこのようにまとめられているのでちょっとわかりにくいのですが、

+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------------+-----------+----------------------+
| almalinux/10 (3 more)       | 47b55666cac2 | yes    | Almalinux 10 amd64 (20260920_23:08) | x86_64       | VIRTUAL-MACHINE | 679.56MiB | 2026/09/20 09:00 JST |
+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------------+-----------+----------------------+

Webサイトを見ると同じイメージに対していくつか種類があることがわかります。

CPUアーキテクチャー、Variantなどで差があります。

特にVariantの差を確認したいのが今回の主旨です。

デフォルトイメージサーバーの定義元

デフォルトイメージサーバーの定義元は、デフォルトイメージサーバーに記載があります。

ざっくり言うと、こちらのGitHubリポジトリーで定義された内容を

GitHub - lxc/lxc-ci: LXC continuous integration and build scripts · GitHub

distrobuilderでビルドしたもの、と言えばよさそうです。

GitHub - lxc/distrobuilder: System container image builder for LXC and Incus · GitHub

各種イメージの定義についてはこちらのディレクトリーを参照します。

https://github.com/lxc/lxc-ci/tree/main/images

Ubuntu Linuxの場合はubuntu.yamlを参照します。

https://github.com/lxc/lxc-ci/blob/main/images/ubuntu.yaml

このあたりを見ると、Variantはイメージに含める内容と見ればよさそうですね。

たとえばUbuntu Linuxだとdefault、cloud、desktopの3つのVariantがあります。

cloudだとこういうパッケージが追加されそうです。

  - packages:
    - cloud-init
    - python3-debian
    action: install
    variants:
    - cloud

タイプが仮想マシンで、Variantがdesktopだとこういう設定が入ったりします。

- path: /etc/sudoers.d/90-incus
  generator: dump
  mode: 0440
  content: |-
    # User rules for ubuntu
    ubuntu ALL=(ALL) NOPASSWD:ALL
  variants:
  - desktop
  types:
  - vm

リリースバージョンでインストールするパッケージが分かれたりもしそうです。

  - packages:
    - systemd-timesyncd
    action: install
    releases:
    - resolute

ところで、どのようなリリースバージョンがあるかはこれらのYAMLから読み取ることはできません。

それはJenkins側の設定を見ればよさそうです。

https://github.com/lxc/lxc-ci/tree/main/jenkins

たとえばUbuntu Linuxだとこちらです。

https://github.com/lxc/lxc-ci/blob/main/jenkins/jobs/image-ubuntu.yaml

これでなんとなく雰囲気がわかった気がします。またどれを見ると各Variantなどの違いがわかりそうかというのも掴めたと
思います。

Telemetry generator for OpenTelemetry(telemetrygen)でテスト用にトレース、メトリクス、ログシグナルを生成する

これは、なにをしたくて書いたもの?

Telemetry generator for OpenTelemetry(telemetrygen)を使うと、OpenTelemetryの各種シグナルをテストなどの用途向けに
生成できるようです。

軽く使い方は見ておいた方がいいのかなと思ったので、試してみます。

Telemetry generator for OpenTelemetry(telemetrygen)

Telemetry generator for OpenTelemetry(telemetrygen)は、OpenTelemetry Collector ContribのGitHubリポジトリーの
一部に含まれています。

https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/cmd/telemetrygen

用途としてはテストやデモ用のシミュレーターです。

This utility simulates a client generating traces, metrics, and logs. It is useful for testing and demonstration purposes.

telemetrygenを使うと、トレース、メトリクス、ログの各種シグナルを生成してOpenTelemetry Collectorのテストができます。

実際に、OpenTelemetryのドキュメント内でtelemetrygenが出てくるのは、OpenTelemetry CollectorのQuick startですからね。

Quick start | OpenTelemetry

では、少し試してみましょう。

環境

今回の環境はこちら。Ubuntu Linux 24.04 LTSです。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 24.04.5 LTS
Release:        24.04
Codename:       noble


$ uname -srvmpio
Linux 6.8.0-139-generic #139-Ubuntu SMP PREEMPT_DYNAMIC Sat Aug  1 03:52:05 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux

またGoも必要になります。

$ go version
go version go1.26.8 linux/amd64

テレメトリーデータの受信確認には、Grafana LGTMを使うことにします。

$ docker container run -it --rm --name lgtm \
    -p 3000:3000 -p 4040:4040 -p 4317:4317 -p 4318:4318 -p 9090:9090 \
    -e GF_PATHS_DATA=/data/grafana \
    grafana/otel-lgtm:0.33.1

telemetrygenを使ってみる

では、telemetrygenを使ってみましょう。

インストール。

$ go install github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen@latest

今回は0.161.0がインストールされました。

go: downloading github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen v0.161.0

ちなみに、Dockerイメージでも提供されているようです。

Package opentelemetry-collector-contrib/telemetrygen · GitHub

ヘルプを見てみます。

$ telemetrygen --help
Telemetrygen simulates a client generating traces, metrics, and logs

Usage:
  telemetrygen [command]

Examples:
telemetrygen metrics --otlp-insecure --metrics 1
telemetrygen traces --otlp-insecure --traces 1
telemetrygen logs --otlp-insecure --logs 1

Available Commands:
  help        Help about any command
  logs        Simulates a client generating logs. (Stability level: alpha)
  metrics     Simulates a client generating metrics. (Stability level: alpha)
  traces      Simulates a client generating traces. (Stability level: alpha)

Flags:
  -h, --help   help for telemetrygen

Use "telemetrygen [command] --help" for more information about a command.

各種シグナルを送信するにはサブコマンドを利用するようですが、それぞれにもヘルプがあるようです。

使い方のイメージはこんな感じみたいです。それぞれ、各種シグナルを1回送信するコマンドです。

## トレースを1回送信する
$ telemetrygen traces --otlp-insecure --traces 1


## メトリクスを1回送信する
$ telemetrygen metrics --otlp-insecure --metrics 1


## ログを1回送信する
$ telemetrygen logs --otlp-insecure --logs 1
トレースを送信する

トレースから見ていくことにします。こちらのコマンドを実行してみましょう。

$ telemetrygen traces --otlp-insecure --traces 1

こんな感じに標準出力に書き出されるのですが

2026-09-21T12:51:30.684+0900    INFO    traces/traces.go:53     starting gRPC exporter
2026-09-21T12:51:30.684+0900    INFO    grpclog/component.go:69 [core] original dial target is: "localhost:4317"        {"grpc_log": true}
2026-09-21T12:51:30.684+0900    INFO    channelz/trace.go:200   [core] [Channel #1] Channel created for target "localhost:4317" {"grpc_log": true}
2026-09-21T12:51:30.684+0900    INFO    channelz/trace.go:200   [core] [Channel #1] parsed dial target is: resolver.Target{URL:url.URL{Scheme:"dns", Opaque:"", User:(*url.Userinfo)(nil), Host:"", Path:"/localhost:4317", Fragment:"", RawQuery:"", RawPath:"", RawFragment:"", ForceQuery:false, OmitHost:false}} {"grpc_log": true}
2026-09-21T12:51:30.684+0900    INFO    channelz/trace.go:200   [core] [Channel #1] Channel authority set to "localhost:4317"   {"grpc_log": true}
2026-09-21T12:51:30.684+0900    INFO    traces/traces.go:125    generation of traces is limited {"per-second": 1}
2026-09-21T12:51:31.685+0900    INFO    traces/worker.go:180    traces generated        {"worker": 0, "traces": 1}
2026-09-21T12:51:31.686+0900    INFO    traces/traces.go:75     stop the batch span processor
2026-09-21T12:51:31.686+0900    INFO    channelz/trace.go:200   [core] [Channel #1] Channel Connectivity change to CONNECTING   {"grpc_log": true}
2026-09-21T12:51:31.687+0900    INFO    channelz/trace.go:200   [core] [Channel #1] Channel exiting idle mode   {"grpc_log": true}
2026-09-21T12:51:31.688+0900    INFO    channelz/trace.go:200   [core] [Channel #1] Resolver state updated: {
  "Addresses": [
    {
      "Addr": "127.0.0.1:4317",
      "ServerName": "",
      "Attributes": null,
      "BalancerAttributes": null,
      "Metadata": null
    }
  ],
  "Endpoints": [
    {
      "Addresses": [
        {
          "Addr": "127.0.0.1:4317",
          "ServerName": "",
          "Attributes": null,
          "BalancerAttributes": null,
          "Metadata": null
        }
      ],
      "Attributes": null
    }
  ],
  "ServiceConfig": null,
  "Attributes": null
} (resolver returned new addresses)     {"grpc_log": true}
2026-09-21T12:51:31.688+0900    INFO    channelz/trace.go:200   [core] [Channel #1] Channel switches to new LB policy "pick_first"      {"grpc_log": true}
2026-09-21T12:51:31.688+0900    INFO    grpclog/prefix_logger.go:42     [pick-first-leaf-lb] [pick-first-leaf-lb 0xecf47ae8000] Received new config {
  "shuffleAddressList": false
}, resolver state {
  "Addresses": [
    {
      "Addr": "127.0.0.1:4317",
      "ServerName": "",
      "Attributes": null,
      "BalancerAttributes": null,
      "Metadata": null
    }
  ],
  "Endpoints": [
    {
      "Addresses": [
        {
          "Addr": "127.0.0.1:4317",
          "ServerName": "",
          "Attributes": null,
          "BalancerAttributes": null,
          "Metadata": null
        }
      ],
      "Attributes": null
    }
  ],
  "ServiceConfig": null,
  "Attributes": null
}       {"grpc_log": true}
2026-09-21T12:51:31.688+0900    INFO    channelz/trace.go:200   [core] [Channel #1 SubChannel #2] Subchannel created    {"grpc_log": true}
2026-09-21T12:51:31.688+0900    INFO    channelz/trace.go:200   [core] [Channel #1 SubChannel #2] Subchannel Connectivity change to CONNECTING  {"grpc_log": true}
2026-09-21T12:51:31.688+0900    INFO    channelz/trace.go:200   [core] [Channel #1 SubChannel #2] Subchannel picks a new address "127.0.0.1:4317" to connect    {"grpc_log": true}
2026-09-21T12:51:31.689+0900    INFO    channelz/trace.go:200   [core] [Channel #1 SubChannel #2] Subchannel Connectivity change to READY       {"grpc_log": true}
2026-09-21T12:51:31.689+0900    INFO    grpclog/prefix_logger.go:42     [pick-first-leaf-lb] [pick-first-leaf-lb 0xecf47ae8000] SubConn 0xecf47aa0190 reported connectivity state READY and the health listener is disabled. Transitioning SubConn to READY. {"grpc_log": true}
2026-09-21T12:51:31.689+0900    INFO    channelz/trace.go:200   [core] [Channel #1] Channel Connectivity change to READY        {"grpc_log": true}
2026-09-21T12:51:31.690+0900    INFO    channelz/trace.go:200   [core] [Channel #1] Channel Connectivity change to SHUTDOWN     {"grpc_log": true}
2026-09-21T12:51:31.690+0900    INFO    channelz/trace.go:200   [core] [Channel #1] Closing the name resolver   {"grpc_log": true}
2026-09-21T12:51:31.690+0900    INFO    channelz/trace.go:200   [core] [Channel #1] ccBalancerWrapper: closing  {"grpc_log": true}
2026-09-21T12:51:31.690+0900    INFO    channelz/trace.go:200   [core] [Channel #1 SubChannel #2] Subchannel Connectivity change to SHUTDOWN    {"grpc_log": true}
2026-09-21T12:51:31.690+0900    INFO    channelz/trace.go:200   [core] [Channel #1 SubChannel #2] Subchannel deleted    {"grpc_log": true}
2026-09-21T12:51:31.690+0900    INFO    grpclog/prefix_logger.go:42     [transport] [client-transport 0xecf47af8008] Closing: rpc error: code = Canceled desc = grpc: the client connection is closing       {"grpc_log": true}
2026-09-21T12:51:31.690+0900    INFO    grpclog/prefix_logger.go:42     [transport] [client-transport 0xecf47af8008] loopyWriter exiting with error: rpc error: code = Canceled desc = grpc: the client connection is closing        {"grpc_log": true}
2026-09-21T12:51:31.690+0900    INFO    channelz/trace.go:200   [core] [Channel #1] Channel deleted     {"grpc_log": true}
2026-09-21T12:51:31.690+0900    INFO    traces/traces.go:65     stopping the exporter

Grafana LGTMで見た方がわかりやすいですね。

実行には--tracesまたは--durationオプションが必須のようです。生成個数で指定するか実行時間で指定するかですね。

Error: either `traces` or `duration` must be greater than 0

オプションをいろいろ試してみましょう。

## トレースを10個生成
$ telemetrygen traces --otlp-insecure --traces 10


## トレースを5秒間生成
$ telemetrygen traces --otlp-insecure --duration 5s


## トレースを無限に生成
$ telemetrygen traces --otlp-insecure --duration inf


## トレースを10秒間、5秒おきに生成
$ telemetrygen traces --otlp-insecure --duration 10s --interval 5s


## サービス名を変更
$ telemetrygen traces --otlp-insecure --traces 1 --service myapp


## エンドポイントを指定
$ telemetrygen traces --otlp-insecure --otlp-endpoint localhost:4317 --traces 1


## 任意の属性を追加
$ telemetrygen traces --otlp-insecure --traces 1 --telemetry-attributes 'foo1="bar1"' --telemetry-attributes 'foo2=100'


## OpenTelemetryの属性を変更
$ telemetrygen traces --otlp-insecure --traces 1 --otlp-attributes 'service.name="myapp"'

このあたりの使い方は、オプション(フラグ)の説明を見るとなんとなくわかる気がします。

Flags:
      --allow-export-failures                 Whether to continue running when export operations fail (instead of terminating)
      --batch                                 Whether to batch telemetry records before sending (default true)
      --batch-size int                        Number of telemetry records to batch before sending (default 100)
      --ca-cert string                        Trusted Certificate Authority to verify server certificate
      --child-spans int                       Number of child spans to generate for each trace (default 1)
      --client-cert string                    Client certificate file
      --client-key string                     Client private key file
      --duration duration|inf                 For how long to run the test. Use 'inf' for infinite duration. (default 0s)
  -h, --help                                  help for traces
      --interval duration                     Reporting interval (default 1s)
      --marshal                               Whether to marshal trace context via HTTP headers
      --mtls                                  Whether to require client authentication for mTLS
      --otlp-attributes map[string]any        Custom resource attributes, describing the entity that produces the telemetry. They are set once on the OTLP resource and are shared by every span, metric data point and log record emitted by this run, e.g. --otlp-attributes service.name="my-service" overrides --service. The value is expected in one of the following formats: key="value", key=true, key=false, key=<integer>, or key=["value1", "value2", ...]. Note you may need to escape the quotes when using the tool from a cli. Flag may be repeated to set multiple attributes (e.g --otlp-attributes key1=\"value1\" --otlp-attributes key2=\"value2\" --otlp-attributes key3=true --otlp-attributes key4=123 --otlp-attributes key5=[1,2,3])
      --otlp-endpoint string                  Destination endpoint for exporting logs, metrics and traces
      --otlp-header map[string]any            Custom header to be passed along with each OTLP request. The value is expected in the format key="value". Note you may need to escape the quotes when using the tool from a cli. Flag may be repeated to set multiple headers (e.g --otlp-header key1=\"value1\" --otlp-header key2=\"value2\")
      --otlp-http                             Whether to use HTTP exporter rather than a gRPC one
      --otlp-http-url-path string             Which URL path to write to (default "/v1/traces")
      --otlp-insecure                         Whether to enable client transport security for the exporter's grpc or http connection
      --otlp-insecure-skip-verify             Whether a client verifies the server's certificate chain and host name
      --rate float                            Approximately how many metrics/spans/logs per second each worker should generate. Zero means no throttling. (default 1)
      --service string                        Service name to use (default "telemetrygen")
      --size int                              Desired minimum size in MB of string data for each generated telemetry record
      --span-duration duration                The duration of each generated span. (default 123µs)
      --span-links int                        Number of span links to generate for each span
      --status-code string                    Status code to use for the spans, one of (Unset, Error, Ok) or the equivalent integer (0,1,2) (default "0")
      --telemetry-attributes map[string]any   Custom attributes describing an individual telemetry item. They are set on every generated span, metric data point and log record rather than on the resource, e.g. --telemetry-attributes http.response.status_code=200. The value is expected in one of the following formats: key="value", key=true, key=false, or key=<integer>, or key=["value1", "value2", ...]. Note you may need to escape the quotes when using the tool from a cli. Flag may be repeated to set multiple attributes (e.g --telemetry-attributes key1=\"value1\" --telemetry-attributes key2=\"value2\" --telemetry-attributes key3=true --telemetry-attributes key4=123 --telemetry-attributes key5=[1,2,3])
      --timeout duration                      Maximum time to wait for the signals to reach destination. (default 10s)
      --traces int                            Number of traces to generate in each worker (ignored if duration is provided)
      --workers int                           Number of workers (goroutines) to run (default 1)

デフォルト値や例も書いていますし。

      --duration duration|inf                 For how long to run the test. Use 'inf' for infinite duration. (default 0s)
      --interval duration                     Reporting interval (default 1s)
      --service string                        Service name to use (default "telemetrygen")
      --telemetry-attributes map[string]any   Custom attributes describing an individual telemetry item. They are set on every generated span, metric data point and log record rather than on the resource, e.g. --telemetry-attributes http.response.status_code=200. The value is expected in one of the following formats: key="value", key=true, key=false, or key=<integer>, or key=["value1", "value2", ...]. Note you may need to escape the quotes when using the tool from a cli. Flag may be repeated to set multiple attributes (e.g --telemetry-attributes key1=\"value1\" --telemetry-attributes key2=\"value2\" --telemetry-attributes key3=true --telemetry-attributes key4=123 --telemetry-attributes key5=[1,2,3])
      --traces int                            Number of traces to generate in each worker (ignored if duration is provided)
メトリクスを送信する

次はメトリクスを見ていきましょう。

$ telemetrygen metrics --otlp-insecure --metrics 1

こんな感じのメトリクスが送信されています。

メトリクスのオプションで気になるところはこのあたりかなと。

      --aggregation-temporality temporality   aggregation-temporality for metrics. Must be one of 'delta' or 'cumulative' (default )
      --metric-type MetricType                Metric type enum. must be one of 'Gauge', 'Sum', 'Histogram', or 'ExponentialHistogram' (default Gauge)
      --otlp-metric-name string               Metric name of the exported metric (default "gen")
      --span-id string                        SpanID to use as exemplar
      --trace-id string                       TraceID to use as exemplar
      --unique-timeseries                     Enforce unique timeseries within unique-timeseries-timelimit, performance impacting
      --unique-timeseries-duration duration   Time limit for unique timeseries generation, timeseries generated within this time will be unique (default 1s)

他のオプションはトレースと似たようなものなので省略します。

ログを送信する

最後はログです。

$ telemetrygen logs --otlp-insecure --logs 1

オプションを試してみます。

## ログメッセージを変更
$ telemetrygen logs --otlp-insecure --logs 1 --body 'my log'


## ログの重要度を変更
$ telemetrygen logs --otlp-insecure --logs 1 --severity-number 17 --severity-text ERROR

Severity(重要度)でどのような値を指定すればよいのかは、こちらを参照するとよいでしょう。

Logs Data Model / Log and Event Record Definition / Severity Fields

ログのオプションで気になるものはこのあたりでしょうか。

      --body string                           Body of the log (default "the message")
      --severity-number int32                 Severity number of the log, range from 1 to 24 (inclusive) (default 9)
      --severity-text string                  Severity text of the log (default "Info")
      --span-id string                        SpanID of the log
      --trace-id string                       TraceID of the log

おわりに

テスト用にトレース、メトリクス、ログシグナルを生成できるTelemetry generator for OpenTelemetry(telemetrygen)を
試してみました。

ローカルにインストールしようと思うとGo言語が必要になりますが、インストールできれば意外と簡単に使えることが
わかりました。

どちらかというとCollectorなどの受信側の確認に使うものなので登場機会はあまり多くないかもしれませんが、ひとまず
テレメトリーデータを投入したいという時に覚えておくと便利なのかなと思います。