Skip to content

Commit 72c4fa9

Browse files
committed
feat: add thanos style storage config
Signed-off-by: Joel Verezhak <[email protected]>
1 parent 3bce0f7 commit 72c4fa9

File tree

10 files changed

+151
-86
lines changed

10 files changed

+151
-86
lines changed

README.md

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,44 @@ We recommend to use `nix` to fulfill all development dependencies. Visit [Nix Do
1313
- to build the binary run `nix-shell --run 'make build'`
1414
- to run tests run `nix-shell --run 'make test'`
1515

16+
## Configuration
17+
18+
This gateway supports the same object storage configuration as the main Thanos project. You can use the `--objstore.config-file` or `--objstore.config` flags to specify your storage backend.
19+
20+
### Supported Storage Backends
21+
22+
Thanks to the integration with [thanos-io/objstore](https://github.com/thanos-io/objstore), the gateway supports all major cloud storage providers:
23+
24+
- **Amazon S3** (and S3-compatible like MinIO)
25+
- **Google Cloud Storage (GCS)**
26+
- **Microsoft Azure Blob Storage**
27+
- **OpenStack Swift**
28+
- **Tencent Cloud Object Storage (COS)**
29+
- **Alibaba Cloud Object Storage Service (OSS)**
30+
- **Local Filesystem**
31+
32+
### Configuration Examples
33+
34+
See the [`examples/`](examples/) directory for configuration examples:
35+
36+
- [`objstore-s3.yaml`](examples/objstore-s3.yaml) - Amazon S3 configuration
37+
- [`objstore-gcs.yaml`](examples/objstore-gcs.yaml) - Google Cloud Storage configuration
38+
- [`objstore-azure.yaml`](examples/objstore-azure.yaml) - Azure Blob Storage configuration
39+
- [`objstore-filesystem.yaml`](examples/objstore-filesystem.yaml) - Local filesystem configuration
40+
- [`objstore-minio.yaml`](examples/objstore-minio.yaml) - MinIO/S3-compatible configuration
41+
42+
For complete configuration format details, see the [Thanos Storage Documentation](https://thanos.io/tip/thanos/storage.md/#configuration).
43+
1644
## Running
1745

1846
### Server
1947

20-
Once built, you can run the server using something like:
48+
Once built, you can run the server using:
2149

2250
```bash
23-
parquet-gateway serve \
24-
--storage.prefix my-prefix \
51+
# Using config file (recommended)
52+
thanos-parquet-gateway serve \
53+
--objstore.config-file=examples/objstore-s3.yaml \
2554
--http.internal.port=6060 \
2655
--http.prometheus.port=9090 \
2756
--http.thanos.port=9091 \
@@ -31,11 +60,23 @@ parquet-gateway serve \
3160
--block.discovery.concurrency=32 \
3261
--query.external-label=prometheus=my-prometheus \
3362
--query.external-label=replica=ha-1
63+
64+
# Using inline config
65+
thanos-parquet-gateway serve \
66+
--objstore.config="
67+
type: S3
68+
config:
69+
bucket: my-bucket
70+
endpoint: s3.amazonaws.com
71+
" \
72+
--http.internal.port=6060 \
73+
--http.prometheus.port=9090 \
74+
--http.thanos.port=9091
3475
```
3576

3677
This will:
3778

38-
- load blocks from the `.data/my-prefix` directory
79+
- load blocks from your configured object storage
3980
- expose internal metrics and readiness handlers on port 6060
4081
- expose a subset of the Prometheus HTTP API on port 9090
4182
- expose an Thanos Info, Series and Query gRPC service on port 9091
@@ -62,19 +103,33 @@ curl 'http://0.0.0.0:9000/api/v1/query' \
62103
]
63104
}
64105
}
65-
66106
```
67107

68108
### Converter
69109

70-
To convert TSDB blocks in the `.data/source` directory that overlap `09/2021` and write the resulting parquet files into the `.data/destination` directory.
110+
To convert TSDB blocks from one storage to another, you can specify separate configurations for source (TSDB) and destination (Parquet) storage:
71111

72112
```bash
73-
parquet-gateway convert \
74-
--tsdb.storage.prefix source \
75-
--parquet.storage.prefix destination \
113+
# Using separate config files
114+
thanos-parquet-gateway convert \
115+
--tsdb.objstore.config-file=tsdb-storage.yaml \
116+
--parquet.objstore.config-file=parquet-storage.yaml \
76117
--convert.sorting.label=__name__ \
77118
--convert.sorting.label=namespace
119+
120+
# Using inline configs
121+
thanos-parquet-gateway convert \
122+
--tsdb.objstore.config="
123+
type: S3
124+
config:
125+
bucket: tsdb-source-bucket
126+
" \
127+
--parquet.objstore.config="
128+
type: S3
129+
config:
130+
bucket: parquet-destination-bucket
131+
" \
132+
--convert.sorting.label=__name__
78133
```
79134

80135
## Note

cmd/config.go

Lines changed: 30 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@ import (
1010
"log/slog"
1111
"net/http"
1212
"net/http/pprof"
13+
"os"
1314
"strings"
1415
"time"
1516

16-
"gopkg.in/yaml.v3"
17-
1817
"go.opentelemetry.io/otel"
1918
"go.opentelemetry.io/otel/exporters/jaeger"
2019
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
@@ -29,6 +28,7 @@ import (
2928
"github.com/thanos-io/objstore"
3029
"github.com/thanos-io/objstore/client"
3130
"github.com/thanos-io/thanos/pkg/runutil"
31+
"gopkg.in/alecthomas/kingpin.v2"
3232

3333
"github.com/thanos-io/thanos-parquet-gateway/locate"
3434
)
@@ -45,65 +45,42 @@ func setupInterrupt(ctx context.Context, g *run.Group, log *slog.Logger) {
4545
}
4646

4747
type bucketOpts struct {
48-
storage string
49-
prefix string
50-
51-
// filesystem options
52-
filesystemDirectory string
53-
54-
// s3 options
55-
s3Bucket string
56-
s3Endpoint string
57-
s3AccessKey string
58-
s3SecretKey string
59-
s3Insecure bool
48+
// Thanos-style configuration
49+
configFile string
50+
config string
51+
}
6052

61-
retries int
53+
// registerThanosStyleFlags registers the standard Thanos objstore flags
54+
func (opts *bucketOpts) registerThanosStyleFlags(cmd *kingpin.CmdClause, prefix string) {
55+
configFlagSuffix := ".objstore.config"
56+
configFlag := strings.TrimPrefix(prefix+configFlagSuffix, ".")
57+
cmd.Flag(configFlag, "Alternative to 'objstore.config-file' flag (mutually exclusive). Content of YAML file that contains object store configuration. See format details: https://thanos.io/tip/thanos/storage.md/#configuration").
58+
PlaceHolder("<content>").StringVar(&opts.config)
59+
60+
configFileFlagSuffix := ".objstore.config-file"
61+
configFileFlag := strings.TrimPrefix(prefix+configFileFlagSuffix, ".")
62+
cmd.Flag(configFileFlag, "Path to YAML file that contains object store configuration. See format details: https://thanos.io/tip/thanos/storage.md/#configuration").
63+
PlaceHolder("<file-path>").StringVar(&opts.configFile)
6264
}
6365

6466
func setupBucket(log *slog.Logger, opts bucketOpts) (objstore.Bucket, error) {
65-
prov := objstore.ObjProvider(strings.ToUpper(opts.storage))
66-
cfg := client.BucketConfig{
67-
Type: prov,
68-
Prefix: opts.prefix,
69-
}
70-
var subCfg any
71-
switch prov {
72-
case objstore.FILESYSTEM:
73-
subCfg = struct {
74-
Directory string `yaml:"directory"`
75-
}{
76-
Directory: opts.filesystemDirectory,
77-
}
78-
case objstore.S3:
79-
subCfg = struct {
80-
Bucket string `yaml:"bucket"`
81-
Endpoint string `yaml:"endpoint"`
82-
AccessKey string `yaml:"access_key"`
83-
SecretKey string `yaml:"secret_key"`
84-
MaxRetries int `yaml:"max_retries"`
85-
Insecure bool `yaml:"insecure"`
86-
}{
87-
Bucket: opts.s3Bucket,
88-
Endpoint: opts.s3Endpoint,
89-
AccessKey: opts.s3AccessKey,
90-
SecretKey: opts.s3SecretKey,
91-
Insecure: opts.s3Insecure,
92-
MaxRetries: opts.retries,
93-
}
94-
default:
95-
return nil, fmt.Errorf("unknown bucket type: %s", prov)
96-
}
67+
var confContentYaml []byte
68+
var err error
9769

98-
cfg.Config = subCfg
99-
bytes, err := yaml.Marshal(cfg)
100-
if err != nil {
101-
return nil, fmt.Errorf("unable to marshal bucket config yaml: %w", err)
70+
if opts.configFile != "" {
71+
confContentYaml, err = os.ReadFile(opts.configFile)
72+
if err != nil {
73+
return nil, fmt.Errorf("reading config file: %w", err)
74+
}
75+
} else if opts.config != "" {
76+
confContentYaml = []byte(opts.config)
77+
} else {
78+
return nil, fmt.Errorf("no objstore configuration provided. Use --objstore.config-file or --objstore.config")
10279
}
10380

104-
bkt, err := client.NewBucket(slogAdapter{log}, bytes, "parquet-gateway", nil)
81+
bkt, err := client.NewBucket(slogAdapter{log}, confContentYaml, "thanos-parquet-gateway", nil)
10582
if err != nil {
106-
return nil, fmt.Errorf("unable to create bucket client: %w", err)
83+
return nil, fmt.Errorf("creating bucket client: %w", err)
10784
}
10885

10986
return bkt, nil

cmd/convert.go

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -79,25 +79,13 @@ func (opts *conversionOpts) registerFlags(cmd *kingpin.CmdClause) {
7979
}
8080

8181
func (opts *bucketOpts) registerConvertParquetFlags(cmd *kingpin.CmdClause) {
82-
cmd.Flag("parquet.storage.type", "type of storage").Default("filesystem").EnumVar(&opts.storage, "filesystem", "s3")
83-
cmd.Flag("parquet.storage.prefix", "prefix for the storage").Default("").StringVar(&opts.prefix)
84-
cmd.Flag("parquet.storage.filesystem.directory", "directory for filesystem").Default(".data").StringVar(&opts.filesystemDirectory)
85-
cmd.Flag("parquet.storage.s3.bucket", "bucket for s3").Default("").StringVar(&opts.s3Bucket)
86-
cmd.Flag("parquet.storage.s3.endpoint", "endpoint for s3").Default("").StringVar(&opts.s3Endpoint)
87-
cmd.Flag("parquet.storage.s3.access_key", "access key for s3").Default("").Envar("PARQUET_STORAGE_S3_ACCESS_KEY").StringVar(&opts.s3AccessKey)
88-
cmd.Flag("parquet.storage.s3.secret_key", "secret key for s3").Default("").Envar("PARQUET_STORAGE_S3_SECRET_KEY").StringVar(&opts.s3SecretKey)
89-
cmd.Flag("parquet.storage.s3.insecure", "use http").Default("false").BoolVar(&opts.s3Insecure)
82+
// Add Thanos-style flags
83+
opts.registerThanosStyleFlags(cmd, "parquet")
9084
}
9185

9286
func (opts *bucketOpts) registerConvertTSDBFlags(cmd *kingpin.CmdClause) {
93-
cmd.Flag("tsdb.storage.type", "type of storage").Default("filesystem").EnumVar(&opts.storage, "filesystem", "s3")
94-
cmd.Flag("tsdb.storage.prefix", "prefix for the storage").Default("").StringVar(&opts.prefix)
95-
cmd.Flag("tsdb.storage.filesystem.directory", "directory for filesystem").Default(".data").StringVar(&opts.filesystemDirectory)
96-
cmd.Flag("tsdb.storage.s3.bucket", "bucket for s3").Default("").StringVar(&opts.s3Bucket)
97-
cmd.Flag("tsdb.storage.s3.endpoint", "endpoint for s3").Default("").StringVar(&opts.s3Endpoint)
98-
cmd.Flag("tsdb.storage.s3.access_key", "access key for s3").Default("").Envar("TSDB_STORAGE_S3_ACCESS_KEY").StringVar(&opts.s3AccessKey)
99-
cmd.Flag("tsdb.storage.s3.secret_key", "secret key for s3").Default("").Envar("TSDB_STORAGE_S3_SECRET_KEY").StringVar(&opts.s3SecretKey)
100-
cmd.Flag("tsdb.storage.s3.insecure", "use http").Default("false").BoolVar(&opts.s3Insecure)
87+
// Add Thanos-style flags
88+
opts.registerThanosStyleFlags(cmd, "tsdb")
10189
}
10290

10391
func (opts *discoveryOpts) registerConvertParquetFlags(cmd *kingpin.CmdClause) {

cmd/serve.go

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,8 @@ func (opts *serveOpts) registerFlags(cmd *kingpin.CmdClause) {
6363
}
6464

6565
func (opts *bucketOpts) registerServeFlags(cmd *kingpin.CmdClause) {
66-
cmd.Flag("storage.type", "type of storage").Default("filesystem").EnumVar(&opts.storage, "filesystem", "s3")
67-
cmd.Flag("storage.prefix", "prefix for the storage").Default("").StringVar(&opts.prefix)
68-
cmd.Flag("storage.filesystem.directory", "directory for filesystem").Default(".data").StringVar(&opts.filesystemDirectory)
69-
cmd.Flag("storage.s3.bucket", "bucket for s3").Default("").StringVar(&opts.s3Bucket)
70-
cmd.Flag("storage.s3.endpoint", "endpoint for s3").Default("").StringVar(&opts.s3Endpoint)
71-
cmd.Flag("storage.s3.access_key", "access key for s3").Default("").Envar("STORAGE_S3_ACCESS_KEY").StringVar(&opts.s3AccessKey)
72-
cmd.Flag("storage.s3.secret_key", "secret key for s3").Default("").Envar("STORAGE_S3_SECRET_KEY").StringVar(&opts.s3SecretKey)
73-
cmd.Flag("storage.s3.insecure", "use http").Default("false").BoolVar(&opts.s3Insecure)
66+
// Add Thanos-style flags
67+
opts.registerThanosStyleFlags(cmd, "")
7468
}
7569

7670
func (opts *tracingOpts) registerServeFlags(cmd *kingpin.CmdClause) {

examples/objstore-azure.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
type: AZURE
2+
config:
3+
storage_account: ""
4+
storage_account_key: ""
5+
container: "thanos"
6+
endpoint: ""
7+
max_retries: 0

examples/objstore-filesystem.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
type: FILESYSTEM
2+
config:
3+
directory: "./data"

examples/objstore-gcs.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
type: GCS
2+
config:
3+
bucket: "my-thanos-bucket"
4+
service_account: ""

examples/objstore-minio.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
type: S3
2+
config:
3+
bucket: "thanos"
4+
endpoint: "minio.example.com:9000"
5+
access_key: "minio"
6+
secret_key: "minio123"
7+
insecure: true
8+
signature_version2: false
9+
http_config:
10+
idle_conn_timeout: 90s
11+
response_header_timeout: 2m

examples/objstore-minio.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
type: S3
2+
config:
3+
bucket: "thanos"
4+
endpoint: "minio.example.com:9000"
5+
access_key: "minio"
6+
secret_key: "minio123"
7+
insecure: true
8+
signature_version2: false
9+
http_config:
10+
idle_conn_timeout: 90s
11+
response_header_timeout: 2m

examples/objstore-s3.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
type: S3
2+
config:
3+
bucket: "my-thanos-bucket"
4+
endpoint: "s3.amazonaws.com"
5+
region: "us-east-1"
6+
access_key: ""
7+
secret_key: ""
8+
insecure: false
9+
signature_version2: false
10+
put_user_metadata: {}
11+
http_config:
12+
idle_conn_timeout: 90s
13+
response_header_timeout: 2m
14+
trace:
15+
enable: false

0 commit comments

Comments
 (0)