OpenObserve を使ってみよう

ストレージ

OpenObserveはデータをインデックせず、圧縮してローカルだけではなくS3などオブジェクトストレージに保存することができる。 S3に保存することで、大容量のEBSを用意する場合と比べてコストが下げられるということのようで、HA構成にした場合でもあがらないと言いたいらしい。

アーキテクチャ

https://openobserve.ai/docs/architecture/

単一ノード

1台のノードで、2TB/day までのデータ量であれば扱うことができる。 全データをローカルディスクストレージに保存することもできるし、メタデータをetcd、データをS3に保存するということもできる。 拡張性を考えると単一ノードでもオブジェクトストレージを使ったほうがよさそう。

HA構成

HAモードではローカルディスクは使用できないので、必ずS3などが保存先になる。 以下複数の役割のノードで構成される。

  • Ingester: 投入されたデータをparquetフォーマットに変換して、オブジェクトストレージに保存する。受け取ったデータを即オブジェクトストレージに転送するのではなく、ある程度ローカルに貯めてから転送するようだ。
  • Querier: クエリを実行する。
  • Compactor: 複数の小さいファイルを一つの大きいファイルにマージして、検索の効率を上げる
  • Router: リクエストをingesterやquerierに分配する、proxyの役割。
  • AlertManager: 定期実行やアラート通知

デプロイは https://openobserve.ai/docs/ha_deployment/ を参照。 今のところ Kubernetes にhelmでデプロイする手順のみが用意されている。 EC2やECSでもやれなくはない が公式手順はないので、自分でkubernetesのマニフェスト見ながら頑張るしかなさそう。

データ摂取(ingestion)

https://openobserve.ai/docs/ingestion/logs/python/#python

ログやメトリクスはFluent-bitやKinesis Firehose、curlなどさまざまなソースからHTTP APIで投入できる。 すでに構築済みのデータ投入機構があれば、投入先をOpenObserveにすればよさそう

セットアップ(セルフホスト)

https://openobserve.ai/docs/quickstart/

Dockerで簡単に起動できる

mkdir data
docker run -v $PWD/data:/data -e ZO_DATA_DIR="/data" -p 5080:5080 -e ZO_ROOT_USER_EMAIL="root@example.com" -e ZO_ROOT_USER_PASSWORD="Complexpass#123" public.ecr.aws/zinclabs/openobserve:latest

localhost:5080 で開く

サンプルデータも用意してくれているのでそれを投入すれば閲覧できる

curl -L https://zinc-public-data.s3.us-west-2.amazonaws.com/zinc-enl/sample-k8s-logs/k8slog_json.json.zip -o k8slog_json.json.zip
unzip k8slog_json.json.zip
curl http://localhost:5080/api/default/default/_json -i -u "root@example.com:Complexpass#123"  -d "@k8slog_json.json"

サンプルデータを作成する

本題ではないが、今後役立ちそうなのでfakeデータをつくってみる。 fakeの作成には https://github.com/brianvoe/gofakeit を使った。

package main
 
import (
	"encoding/json"
	"fmt"
	"log"
	"math/rand"
	"time"
 
	"github.com/brianvoe/gofakeit/v6"
)
 
type accessLog struct {
	Timestamp    time.Time `fake:"{daterange:2023-06-30T16:00:00,2023-06-30T16:59:59,yyyy-MM-ddTHH:mm:ss}" format:"2006-01-02T15:04:05"`
	Path         string    `fake:"{urlpath}"`
	Method       string    `fake:"{httpmethod}"`
	InstanceId   string    `fake:"{regex:i-[a-f]{1}}"`
	ResponseTime int       `fake:"{number:1500,3000}"`
	Status       int       `fake:"{httpstatuscodesimple}"`
}
 
func main() {
	faker := gofakeit.NewUnlocked(0)
 
	gofakeit.AddFuncLookup("urlpath", gofakeit.Info{
		Category:    "custom",
		Description: "Path only",
		Example:     "/image",
		Output:      "string",
		Generate: func(r *rand.Rand, m *gofakeit.MapParams, info *gofakeit.Info) (interface{}, error) {
			return gofakeit.RandomString([]string{"/example", "/image", "/hello", "/health", "/ping", "/login", "/account", "/route", "/spot"}), nil
		},
	})
 
	logs := make([]accessLog, 0)
	for i := 0; i < 5000; i++ {
		var l accessLog
		err := faker.Struct(&l)
		if err != nil {
			log.Fatalln(err)
		}
		logs = append(logs, l)
	}
 
	b, err := json.Marshal(logs)
	if err != nil {
		log.Fatalln(err)
	}
 
	fmt.Println(string(b))
}
 

大量に作ってぶっこんでパフォーマンス検証

while true; do JSON=fake_$(date +%s).json; ./faker -count 10000 > $JSON; curl http://localhost:5080/api/default/fake/_json -i -u "root@example.com:Complexpass#123"  -d "@${JSON}"; rm "${JSON}"; sleep 1; done

HA構成をKubernetesで動かす

Rancher DesktopKubernetes にデプロイして、HA構成を試してみる。

HA構成の場合はオブジェクトストレージが必須なので、事前に MinIOをローカルのkubernetesで動かす OpenObserveのhelm内にminioが内包されていたので不要だった。。気づくの遅かった

そうしたらhelm chartが用意されているのでデプロイする

GitHub - openobserve/openobserve-helm-chart: Helm charts for OpenObserve favicon GitHub
GitHub - openobserve/openobserve-helm-chart: Helm charts for OpenObserve
Helm charts for OpenObserve. Contribute to openobserve/openobserve-helm-chart development by creating an account on GitHub.
GitHub - openobserve/openobserve-helm-chart: Helm charts for OpenObserve

values.yaml

serviceAccount:
  # Annotations to add to the service account
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::12345353456:role/zo-s3-eks
 
replicaCount:
  ingester: 1
  querier: 1
  router: 1
  alertmanager: 1
  compactor: 1
 
minio:
  enabled: true # if true then minio will be deployed as part of openobserve

デプロイ

helm --namespace openobserve -f values.yaml install --create-namespace o1 openobserve/openobserve
 

localhost:5080 で開く

kubectl --namespace openobserve port-forward svc/o1-openobserve-router 5080:5080

minioの中身確認

kubectl run awscli -it --rm --image amazon/aws-cli --env=AWS_ACCESS_KEY_ID=rootuser --env=AWS_SECRET_ACCESS_KEY=rootpass123 --command -- sh
 
sh-4.2$ aws --endpoint-url http://o1-minio-svc.openobserve.svc.cluster.local:9000 --no-verify-ssl s3 ls
1-01-01 00:00:00    mysuperduperbucket

HA構成をDocker composeで動かす

helmでデプロイされたリソースから、ある程度動くようにDocker composeに落とし込む。

services:
  querier:
    image: public.ecr.aws/zinclabs/openobserve:latest
    expose:
      - 5080
      - 5081
    restart: on-failure
    depends_on:
      - etcd-1
      - etcd-2
      - minio
    environment:
      - ZO_NODE_ROLE=querier
      - OTEL_OTLP_HTTP_ENDPOINT=http://127.0.0.1:5080/api/nexus/traces
      - RUST_BACKTRACE=1
      - RUST_LOG=info
      - ZO_BASE_URI=
      - ZO_COLS_PER_RECORD_LIMIT=200
      - ZO_COMPACT_BLOCKED_ORGS=
      - ZO_COMPACT_DATA_RETENTION_DAYS=0
      - ZO_COMPACT_ENABLED=true
      - ZO_COMPACT_FAKE_MODE=false
      - ZO_COMPACT_INTERVAL=60
      - ZO_COMPACT_MAX_FILE_SIZE=2
      - ZO_DATA_DIR=./data/
      - ZO_DATA_STREAM_DIR=
      - ZO_DATA_WAL_DIR=
      - ZO_ETCD_ADDR=etcd-1:2379
      - ZO_ETCD_CERT_FILE=
      - ZO_ETCD_CLIENT_CERT_AUTH=false
      - ZO_ETCD_COMMAND_TIMEOUT=5
      - ZO_ETCD_CONNECT_TIMEOUT=2
      - ZO_ETCD_DOMAIN_NAME=
      - ZO_ETCD_KEY_FILE=
      - ZO_ETCD_LOAD_PAGE_SIZE=10000
      - ZO_ETCD_LOCK_WAIT_TIMEOUT=600
      - ZO_ETCD_PASSWORD=
      - ZO_ETCD_PREFIX=/zinc/observe/
      - ZO_ETCD_TRUSTED_CA_FILE=
      - ZO_ETCD_USER=
      - ZO_FEATURE_FULLTEXT_ON_ALL_FIELDS=false
      - ZO_FEATURE_PER_THREAD_LOCK=false
      - ZO_FILE_EXT_JSON=.json
      - ZO_FILE_EXT_PARQUET=.parquet
      - ZO_FILE_MOVE_THREAD_NUM=0
      - ZO_FILE_PUSH_INTERVAL=10
      - ZO_GRPC_ORG_HEADER_KEY=zinc-org-id
      - ZO_GRPC_PORT=5081
      - ZO_GRPC_TIMEOUT=600
      - ZO_HEARTBEAT_INTERVAL=30
      - ZO_HTTP_IPV6_ENABLED=false
      - ZO_HTTP_PORT=5080
      - ZO_INSTANCE_NAME=
      - ZO_JSON_LIMIT=209715200
      - ZO_LOCAL_MODE=false
      - ZO_LOCAL_MODE_STORAGE=disk
      - ZO_LUA_FN_ENABLED=false
      - ZO_MAX_FILE_RETENTION_TIME=10
      - ZO_MAX_FILE_SIZE_ON_DISK=1
      - ZO_MEMORY_CACHE_CACHE_LATEST_FILES=false
      - ZO_MEMORY_CACHE_ENABLED=true
      - ZO_MEMORY_CACHE_MAX_SIZE=0
      - ZO_MEMORY_CACHE_RELEASE_SIZE=0
      - ZO_METRICS_DEDUP_ENABLED=true
      - ZO_METRICS_LEADER_ELECTION_INTERVAL=30
      - ZO_METRICS_LEADER_PUSH_INTERVAL=15
      - ZO_PARQUET_COMPRESSION=zstd
      - ZO_PAYLOAD_LIMIT=209715200
      - ZO_PROMETHEUS_HA_CLUSTER=cluster
      - ZO_PROMETHEUS_HA_REPLICA=__replica__
      - ZO_QUERY_THREAD_NUM=0
      - ZO_ROUTE_TIMEOUT=600
      - ZO_S3_BUCKET_NAME=mysuperduperbucket
      - ZO_S3_BUCKET_PREFIX=mysuperduperbucket
      - ZO_S3_PROVIDER=minio
      - ZO_S3_REGION_NAME=us-east-1
      - ZO_S3_SERVER_URL=http://minio:9000
      - ZO_SKIP_SCHEMA_VALIDATION=false
      - ZO_SLED_DATA_DIR=
      - ZO_SLED_PREFIX=/zinc/observe/
      - ZO_TELEMETRY=true
      - ZO_TELEMETRY_URL=https://e1.zinclabs.dev
      - ZO_TIME_STAMP_COL=_timestamp
      - ZO_TRACING_ENABLED=false
      - ZO_TRACING_HEADER_KEY=Authorization
      - ZO_TRACING_HEADER_VALUE=Basic YWRtaW46Q29tcGxleHBhc3MjMTIz
      - ZO_TS_ALLOWED_UPTO=5
      - ZO_UI_ENABLED=true
      - ZO_WAL_LINE_MODE_ENABLED=true
      - ZO_WAL_MEMORY_MODE_ENABLED=false
      - ZO_WIDENING_SCHEMA_EVOLUTION=false
      - ZO_ROOT_USER_EMAIL=root@example.com
      - ZO_ROOT_USER_PASSWORD=Complexpass#123
      - ZO_S3_ACCESS_KEY=rootuser
      - ZO_S3_SECRET_KEY=rootpass123
 
  ingester:
    image: public.ecr.aws/zinclabs/openobserve:latest
    expose:
      - 5080
      - 5081
    restart: on-failure
    depends_on:
      - etcd-1
      - etcd-2
      - minio
    volumes:
      - ./data:/data
    environment:
      - ZO_NODE_ROLE=ingester
      - OTEL_OTLP_HTTP_ENDPOINT=http://127.0.0.1:5080/api/nexus/traces
      - RUST_BACKTRACE=1
      - RUST_LOG=info
      - ZO_BASE_URI=
      - ZO_COLS_PER_RECORD_LIMIT=200
      - ZO_COMPACT_BLOCKED_ORGS=
      - ZO_COMPACT_DATA_RETENTION_DAYS=0
      - ZO_COMPACT_ENABLED=true
      - ZO_COMPACT_FAKE_MODE=false
      - ZO_COMPACT_INTERVAL=60
      - ZO_COMPACT_MAX_FILE_SIZE=2
      - ZO_DATA_DIR=./data/
      - ZO_DATA_STREAM_DIR=
      - ZO_DATA_WAL_DIR=
      - ZO_ETCD_ADDR=etcd-1:2379
      - ZO_ETCD_CERT_FILE=
      - ZO_ETCD_CLIENT_CERT_AUTH=false
      - ZO_ETCD_COMMAND_TIMEOUT=5
      - ZO_ETCD_CONNECT_TIMEOUT=2
      - ZO_ETCD_DOMAIN_NAME=
      - ZO_ETCD_KEY_FILE=
      - ZO_ETCD_LOAD_PAGE_SIZE=10000
      - ZO_ETCD_LOCK_WAIT_TIMEOUT=600
      - ZO_ETCD_PASSWORD=
      - ZO_ETCD_PREFIX=/zinc/observe/
      - ZO_ETCD_TRUSTED_CA_FILE=
      - ZO_ETCD_USER=
      - ZO_FEATURE_FULLTEXT_ON_ALL_FIELDS=false
      - ZO_FEATURE_PER_THREAD_LOCK=false
      - ZO_FILE_EXT_JSON=.json
      - ZO_FILE_EXT_PARQUET=.parquet
      - ZO_FILE_MOVE_THREAD_NUM=0
      - ZO_FILE_PUSH_INTERVAL=10
      - ZO_GRPC_ORG_HEADER_KEY=zinc-org-id
      - ZO_GRPC_PORT=5081
      - ZO_GRPC_TIMEOUT=600
      - ZO_HEARTBEAT_INTERVAL=30
      - ZO_HTTP_IPV6_ENABLED=false
      - ZO_HTTP_PORT=5080
      - ZO_INSTANCE_NAME=
      - ZO_JSON_LIMIT=209715200
      - ZO_LOCAL_MODE=false
      - ZO_LOCAL_MODE_STORAGE=disk
      - ZO_LUA_FN_ENABLED=false
      - ZO_MAX_FILE_RETENTION_TIME=10
      - ZO_MAX_FILE_SIZE_ON_DISK=1
      - ZO_MEMORY_CACHE_CACHE_LATEST_FILES=false
      - ZO_MEMORY_CACHE_ENABLED=true
      - ZO_MEMORY_CACHE_MAX_SIZE=0
      - ZO_MEMORY_CACHE_RELEASE_SIZE=0
      - ZO_METRICS_DEDUP_ENABLED=true
      - ZO_METRICS_LEADER_ELECTION_INTERVAL=30
      - ZO_METRICS_LEADER_PUSH_INTERVAL=15
      - ZO_PARQUET_COMPRESSION=zstd
      - ZO_PAYLOAD_LIMIT=209715200
      - ZO_PROMETHEUS_HA_CLUSTER=cluster
      - ZO_PROMETHEUS_HA_REPLICA=__replica__
      - ZO_QUERY_THREAD_NUM=0
      - ZO_ROUTE_TIMEOUT=600
      - ZO_S3_BUCKET_NAME=mysuperduperbucket
      - ZO_S3_BUCKET_PREFIX=mysuperduperbucket
      - ZO_S3_PROVIDER=minio
      - ZO_S3_REGION_NAME=us-east-1
      - ZO_S3_SERVER_URL=http://minio:9000
      - ZO_SKIP_SCHEMA_VALIDATION=false
      - ZO_SLED_DATA_DIR=
      - ZO_SLED_PREFIX=/zinc/observe/
      - ZO_TELEMETRY=true
      - ZO_TELEMETRY_URL=https://e1.zinclabs.dev
      - ZO_TIME_STAMP_COL=_timestamp
      - ZO_TRACING_ENABLED=false
      - ZO_TRACING_HEADER_KEY=Authorization
      - ZO_TRACING_HEADER_VALUE=Basic YWRtaW46Q29tcGxleHBhc3MjMTIz
      - ZO_TS_ALLOWED_UPTO=5
      - ZO_UI_ENABLED=true
      - ZO_WAL_LINE_MODE_ENABLED=true
      - ZO_WAL_MEMORY_MODE_ENABLED=false
      - ZO_WIDENING_SCHEMA_EVOLUTION=false
      - ZO_ROOT_USER_EMAIL=root@example.com
      - ZO_ROOT_USER_PASSWORD=Complexpass#123
      - ZO_S3_ACCESS_KEY=rootuser
      - ZO_S3_SECRET_KEY=rootpass123
 
  router:
    image: public.ecr.aws/zinclabs/openobserve:latest
    ports:
      - 5080:5080
    restart: on-failure
    depends_on:
      - etcd-1
      - etcd-2
      - minio
    expose:
      - 5080
      - 5081
    environment:
      - ZO_NODE_ROLE=router
      - OTEL_OTLP_HTTP_ENDPOINT=http://127.0.0.1:5080/api/nexus/traces
      - RUST_BACKTRACE=1
      - RUST_LOG=info
      - ZO_BASE_URI=
      - ZO_COLS_PER_RECORD_LIMIT=200
      - ZO_COMPACT_BLOCKED_ORGS=
      - ZO_COMPACT_DATA_RETENTION_DAYS=0
      - ZO_COMPACT_ENABLED=true
      - ZO_COMPACT_FAKE_MODE=false
      - ZO_COMPACT_INTERVAL=60
      - ZO_COMPACT_MAX_FILE_SIZE=2
      - ZO_DATA_DIR=./data/
      - ZO_DATA_STREAM_DIR=
      - ZO_DATA_WAL_DIR=
      - ZO_ETCD_ADDR=etcd-1:2379
      - ZO_ETCD_CERT_FILE=
      - ZO_ETCD_CLIENT_CERT_AUTH=false
      - ZO_ETCD_COMMAND_TIMEOUT=5
      - ZO_ETCD_CONNECT_TIMEOUT=2
      - ZO_ETCD_DOMAIN_NAME=
      - ZO_ETCD_KEY_FILE=
      - ZO_ETCD_LOAD_PAGE_SIZE=10000
      - ZO_ETCD_LOCK_WAIT_TIMEOUT=600
      - ZO_ETCD_PASSWORD=
      - ZO_ETCD_PREFIX=/zinc/observe/
      - ZO_ETCD_TRUSTED_CA_FILE=
      - ZO_ETCD_USER=
      - ZO_FEATURE_FULLTEXT_ON_ALL_FIELDS=false
      - ZO_FEATURE_PER_THREAD_LOCK=false
      - ZO_FILE_EXT_JSON=.json
      - ZO_FILE_EXT_PARQUET=.parquet
      - ZO_FILE_MOVE_THREAD_NUM=0
      - ZO_FILE_PUSH_INTERVAL=10
      - ZO_GRPC_ORG_HEADER_KEY=zinc-org-id
      - ZO_GRPC_PORT=5081
      - ZO_GRPC_TIMEOUT=600
      - ZO_HEARTBEAT_INTERVAL=30
      - ZO_HTTP_IPV6_ENABLED=false
      - ZO_HTTP_PORT=5080
      - ZO_INSTANCE_NAME=
      - ZO_JSON_LIMIT=209715200
      - ZO_LOCAL_MODE=false
      - ZO_LOCAL_MODE_STORAGE=disk
      - ZO_LUA_FN_ENABLED=false
      - ZO_MAX_FILE_RETENTION_TIME=10
      - ZO_MAX_FILE_SIZE_ON_DISK=1
      - ZO_MEMORY_CACHE_CACHE_LATEST_FILES=false
      - ZO_MEMORY_CACHE_ENABLED=true
      - ZO_MEMORY_CACHE_MAX_SIZE=0
      - ZO_MEMORY_CACHE_RELEASE_SIZE=0
      - ZO_METRICS_DEDUP_ENABLED=true
      - ZO_METRICS_LEADER_ELECTION_INTERVAL=30
      - ZO_METRICS_LEADER_PUSH_INTERVAL=15
      - ZO_PARQUET_COMPRESSION=zstd
      - ZO_PAYLOAD_LIMIT=209715200
      - ZO_PROMETHEUS_HA_CLUSTER=cluster
      - ZO_PROMETHEUS_HA_REPLICA=__replica__
      - ZO_QUERY_THREAD_NUM=0
      - ZO_ROUTE_TIMEOUT=600
      - ZO_S3_BUCKET_NAME=mysuperduperbucket
      - ZO_S3_BUCKET_PREFIX=mysuperduperbucket
      - ZO_S3_PROVIDER=minio
      - ZO_S3_REGION_NAME=us-east-1
      - ZO_S3_SERVER_URL=http://minio:9000
      - ZO_SKIP_SCHEMA_VALIDATION=false
      - ZO_SLED_DATA_DIR=
      - ZO_SLED_PREFIX=/zinc/observe/
      - ZO_TELEMETRY=true
      - ZO_TELEMETRY_URL=https://e1.zinclabs.dev
      - ZO_TIME_STAMP_COL=_timestamp
      - ZO_TRACING_ENABLED=false
      - ZO_TRACING_HEADER_KEY=Authorization
      - ZO_TRACING_HEADER_VALUE=Basic YWRtaW46Q29tcGxleHBhc3MjMTIz
      - ZO_TS_ALLOWED_UPTO=5
      - ZO_UI_ENABLED=true
      - ZO_WAL_LINE_MODE_ENABLED=true
      - ZO_WAL_MEMORY_MODE_ENABLED=false
      - ZO_WIDENING_SCHEMA_EVOLUTION=false
      - ZO_ROOT_USER_EMAIL=root@example.com
      - ZO_ROOT_USER_PASSWORD=Complexpass#123
      - ZO_S3_ACCESS_KEY=rootuser
      - ZO_S3_SECRET_KEY=rootpass123
 
  compactor:
    image: public.ecr.aws/zinclabs/openobserve:latest
    restart: on-failure
    depends_on:
      - etcd-1
      - etcd-2
      - minio
    expose:
      - 5080
      - 5081
    environment:
      - ZO_NODE_ROLE=compactor
      - OTEL_OTLP_HTTP_ENDPOINT=http://127.0.0.1:5080/api/nexus/traces
      - RUST_BACKTRACE=1
      - RUST_LOG=info
      - ZO_BASE_URI=
      - ZO_COLS_PER_RECORD_LIMIT=200
      - ZO_COMPACT_BLOCKED_ORGS=
      - ZO_COMPACT_DATA_RETENTION_DAYS=0
      - ZO_COMPACT_ENABLED=true
      - ZO_COMPACT_FAKE_MODE=false
      - ZO_COMPACT_INTERVAL=60
      - ZO_COMPACT_MAX_FILE_SIZE=2
      - ZO_DATA_DIR=./data/
      - ZO_DATA_STREAM_DIR=
      - ZO_DATA_WAL_DIR=
      - ZO_ETCD_ADDR=etcd-1:2379
      - ZO_ETCD_CERT_FILE=
      - ZO_ETCD_CLIENT_CERT_AUTH=false
      - ZO_ETCD_COMMAND_TIMEOUT=5
      - ZO_ETCD_CONNECT_TIMEOUT=2
      - ZO_ETCD_DOMAIN_NAME=
      - ZO_ETCD_KEY_FILE=
      - ZO_ETCD_LOAD_PAGE_SIZE=10000
      - ZO_ETCD_LOCK_WAIT_TIMEOUT=600
      - ZO_ETCD_PASSWORD=
      - ZO_ETCD_PREFIX=/zinc/observe/
      - ZO_ETCD_TRUSTED_CA_FILE=
      - ZO_ETCD_USER=
      - ZO_FEATURE_FULLTEXT_ON_ALL_FIELDS=false
      - ZO_FEATURE_PER_THREAD_LOCK=false
      - ZO_FILE_EXT_JSON=.json
      - ZO_FILE_EXT_PARQUET=.parquet
      - ZO_FILE_MOVE_THREAD_NUM=0
      - ZO_FILE_PUSH_INTERVAL=10
      - ZO_GRPC_ORG_HEADER_KEY=zinc-org-id
      - ZO_GRPC_PORT=5081
      - ZO_GRPC_TIMEOUT=600
      - ZO_HEARTBEAT_INTERVAL=30
      - ZO_HTTP_IPV6_ENABLED=false
      - ZO_HTTP_PORT=5080
      - ZO_INSTANCE_NAME=
      - ZO_JSON_LIMIT=209715200
      - ZO_LOCAL_MODE=false
      - ZO_LOCAL_MODE_STORAGE=disk
      - ZO_LUA_FN_ENABLED=false
      - ZO_MAX_FILE_RETENTION_TIME=10
      - ZO_MAX_FILE_SIZE_ON_DISK=1
      - ZO_MEMORY_CACHE_CACHE_LATEST_FILES=false
      - ZO_MEMORY_CACHE_ENABLED=true
      - ZO_MEMORY_CACHE_MAX_SIZE=0
      - ZO_MEMORY_CACHE_RELEASE_SIZE=0
      - ZO_METRICS_DEDUP_ENABLED=true
      - ZO_METRICS_LEADER_ELECTION_INTERVAL=30
      - ZO_METRICS_LEADER_PUSH_INTERVAL=15
      - ZO_PARQUET_COMPRESSION=zstd
      - ZO_PAYLOAD_LIMIT=209715200
      - ZO_PROMETHEUS_HA_CLUSTER=cluster
      - ZO_PROMETHEUS_HA_REPLICA=__replica__
      - ZO_QUERY_THREAD_NUM=0
      - ZO_ROUTE_TIMEOUT=600
      - ZO_S3_BUCKET_NAME=mysuperduperbucket
      - ZO_S3_BUCKET_PREFIX=mysuperduperbucket
      - ZO_S3_PROVIDER=minio
      - ZO_S3_REGION_NAME=us-east-1
      - ZO_S3_SERVER_URL=http://minio:9000
      - ZO_SKIP_SCHEMA_VALIDATION=false
      - ZO_SLED_DATA_DIR=
      - ZO_SLED_PREFIX=/zinc/observe/
      - ZO_TELEMETRY=true
      - ZO_TELEMETRY_URL=https://e1.zinclabs.dev
      - ZO_TIME_STAMP_COL=_timestamp
      - ZO_TRACING_ENABLED=false
      - ZO_TRACING_HEADER_KEY=Authorization
      - ZO_TRACING_HEADER_VALUE=Basic YWRtaW46Q29tcGxleHBhc3MjMTIz
      - ZO_TS_ALLOWED_UPTO=5
      - ZO_UI_ENABLED=true
      - ZO_WAL_LINE_MODE_ENABLED=true
      - ZO_WAL_MEMORY_MODE_ENABLED=false
      - ZO_WIDENING_SCHEMA_EVOLUTION=false
      - ZO_ROOT_USER_EMAIL=root@example.com
      - ZO_ROOT_USER_PASSWORD=Complexpass#123
      - ZO_S3_ACCESS_KEY=rootuser
      - ZO_S3_SECRET_KEY=rootpass123
 
  minio:
    image: quay.io/minio/minio:latest
    container_name: example-minio
    environment:
      MINIO_ROOT_USER: rootuser
      MINIO_ROOT_PASSWORD: rootpass123
    volumes:
      - minio:/data
    command: server --address :9000 --console-address ":9001" /data
    ports:
      - 9000:9000
      - 9001:9001
 
  etcd-1:
    image: docker.io/bitnami/etcd:3.5.8-debian-11-r4
    expose:
      - 2379
      - 2380
    volumes:
      - etcd1:/bitnami/etcd
    environment:
      - ETCD_NAME=etcd-1
      - ETCD_DATA_DIR=/bitnami/etcd/data
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd-1:2379
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd-1:2380
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-k8s
      - ETCD_INITIAL_CLUSTER_STATE=new
      - ETCD_INITIAL_CLUSTER=etcd-1=http://etcd-1:2380,etcd-2=http://etcd-2:2380
      - ALLOW_NONE_AUTHENTICATION=yes
  etcd-2:
    image: docker.io/bitnami/etcd:3.5.8-debian-11-r4
    expose:
      - 2379
      - 2380
    volumes:
      - etcd2:/bitnami/etcd
    environment:
      - ETCD_NAME=etcd-2
      - ETCD_DATA_DIR=/bitnami/etcd/data
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd-2:2379
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd-2:2380
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-k8s
      - ETCD_INITIAL_CLUSTER_STATE=new
      - ETCD_INITIAL_CLUSTER=etcd-1=http://etcd-1:2380,etcd-2=http://etcd-2:2380
      - ALLOW_NONE_AUTHENTICATION=yes
 
volumes:
  minio:
  etcd1:
  etcd2:

docker compose up -d で動いた

シングルノード+S3で動かす

シングルノード(一つのコンテナで全機能を動かす)モードで、ストレージはS3を使った場合の実行例

services:
  app:
    image: public.ecr.aws/zinclabs/openobserve:latest
    ports:
      - 5601:5601
    depends_on:
      etcd-1:
        condition: service_healthy
      etcd-2:
        condition: service_healthy
    volumes:
      - ./data:/data
      - ./awsconfig:/root/.aws/config
    environment:
      - ZO_DATA_DIR=/data
      - ZO_HTTP_PORT=5601
      - ZO_ROOT_USER_EMAIL=root@example.com
      - ZO_ROOT_USER_PASSWORD=Complexpass#123
      - ZO_S3_REGION_NAME=ap-northeast-1
      - ZO_S3_BUCKET_NAME=mybucket
      - ZO_MAX_FILE_SIZE_ON_DISK=50
      - ZO_MAX_FILE_RETENTION_TIME=10
      - ZO_LOCAL_MODE=false
      - ZO_ETCD_ADDR=etcd-1:2379
      - ZO_PROMETHEUS_ENABLED=true
 
  etcd-1:
    image: docker.io/bitnami/etcd:3.5.8-debian-11-r4
    ports:
      - 2379:2379
      - 2380:2380
    expose:
      - 2379
      - 2380
    volumes:
      - etcd1:/bitnami/etcd
    healthcheck:
      test: "etcdctl endpoint health"
      interval: 10s
      timeout: 10s
      retries: 3
      start_period: 10s
    environment:
      - ETCD_NAME=etcd-1
      - ETCD_DEBUG=true
      - ETCD_DATA_DIR=/bitnami/etcd/data
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd-1:2379
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd-1:2380
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-k8s
      - ETCD_INITIAL_CLUSTER_STATE=new
      - ETCD_INITIAL_CLUSTER=etcd-1=http://etcd-1:2380,etcd-2=http://etcd-2:2380
      - ALLOW_NONE_AUTHENTICATION=yes
  etcd-2:
    image: docker.io/bitnami/etcd:3.5.8-debian-11-r4
    expose:
      - 2379
      - 2380
    volumes:
      - etcd2:/bitnami/etcd
    healthcheck:
      test: "etcdctl endpoint health"
      interval: 10s
      timeout: 10s
      retries: 3
      start_period: 10s
    environment:
      - ETCD_NAME=etcd-2
      - ETCD_DEBUG=true
      - ETCD_DATA_DIR=/bitnami/etcd/data
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd-2:2379
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd-2:2380
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-k8s
      - ETCD_INITIAL_CLUSTER_STATE=new
      - ETCD_INITIAL_CLUSTER=etcd-1=http://etcd-1:2380,etcd-2=http://etcd-2:2380
      - ALLOW_NONE_AUTHENTICATION=yes
 
volumes:
  etcd1:
  etcd2:

注意点

  • シングルノードだとデフォルトでローカルのディスクストレージを使用するため、 ZO_LOCAL_MODE=false を設定した。
    • このとき、コンテナに ~/.aws/config が存在しないとエラーになってしまったため、 ./awsconfig:/root/.aws/config をマウントした (https://github.com/openobserve/openobserve/issues/1099)
    • awsconfigの中身は以下のようにして、EC2のinstance profileが使われるようにした。ACCESS_KEYやSECRETでもいい。
[default]
region = ap-northeast-1
credential_source=Ec2InstanceMetadata

ElasticsearchのAPIでデータ投入する

Elasticsearchとコンパチのインターフェースを備えており、 /api/{organization}/_bulk のAPIで投入することができる。

https://openobserve.ai/docs/api/ingestion/logs/bulk/

ES8のクライアント(https://github.com/elastic/go-elasticsearch)を使って作成する

package main
 
import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
 
	"github.com/elastic/go-elasticsearch/v8"
	"github.com/elastic/go-elasticsearch/v8/esutil"
)
 
func newElasticsearchBulkIndexer(ctx context.Context) (esutil.BulkIndexer, error) {
	es, err := elasticsearch.NewClient(elasticsearch.Config{
		Username: "root@example.com",
		Password: "Complexpass#123",
		Addresses: []string{
			"http://localhost:5080/api/default",
		},
		EnableDebugLogger: true,
	})
	if err != nil {
		return nil, err
	}
 
	indexer, err := esutil.NewBulkIndexer(esutil.BulkIndexerConfig{
		Client: es,
	})
	if err != nil {
		return nil, err
	}
 
	return indexer, nil
}
 
func insert(filename string) error {
 
	ctx := context.Background()
 
	indexer, err := newElasticsearchBulkIndexer(ctx)
	if err != nil {
		return err
	}
 
	body, err := os.ReadFile(filename)
	if err != nil {
		return err
	}
 
	scanner := bufio.NewScanner(bytes.NewReader(body))
	logs := make([]accessLog, 0)
	for scanner.Scan() {
		logs = append(logs, ParseLog(scanner.Text()))
	}
 
	for _, v := range logs {
		js, err := json.Marshal(v)
		if err != nil {
			return err
		}
		err = indexer.Add(
			ctx,
			esutil.BulkIndexerItem{
				Action: "index",
				Index:  fmt.Sprintf("log-%s-%s", "mygroup1", v.Datetime.Format("20060102")),
				Body:   bytes.NewReader(js),
			},
		)
		if err != nil {
			return err
		}
 
	}
 
	fmt.Printf("Stats: %+v\n", indexer.Stats())
	if err := indexer.Close(ctx); err != nil {
		return err
	}
 
	return nil
}
 
func main() {
	if err := insert("testdata.txt"); err != nil {
		log.Fatalf("%v", err)
	}
}