Skip to content

Commit 97ca0d6

Browse files
committed
Adding Azure blob support
1 parent c6f9d95 commit 97ca0d6

15 files changed

Lines changed: 423 additions & 152 deletions

File tree

README.md

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,66 @@ To view a dump of the LMDB contents:
112112
You can browse the snapshots in MinIO at <http://localhost:4731/buckets/lightningstream/browse>
113113
(login with minioadmin / minioadmin).
114114

115+
## Using Azure Blob storage
115116

117+
Lightning Stream supports Azure Blob Storage as a backend for storing snapshots. You can configure it to use either static credentials (account name and key) or Azure service principal authentication.
118+
119+
### Basic configuration with static credentials
120+
121+
```yaml
122+
storage:
123+
type: azure
124+
options:
125+
account_name: myaccountname
126+
account_key: myaccountkey
127+
container: lightningstream
128+
create_container: true
129+
```
130+
131+
### Configuration with Azure service principal (recommended for production)
132+
133+
When using service principal authentication, set `use_env_creds: true` and ensure the following environment variables are set:
134+
- `AZURE_CLIENT_ID`
135+
- `AZURE_TENANT_ID`
136+
- `AZURE_CLIENT_SECRET`
137+
138+
```yaml
139+
storage:
140+
type: azure
141+
options:
142+
use_env_creds: true
143+
container: lightningstream
144+
endpoint_url: https://myaccount.blob.core.windows.net/
145+
create_container: true
146+
```
147+
148+
### Available options
149+
150+
| Option | Type | Summary |
151+
|--------|------|---------|
152+
| account_name | string | Azure storage account name (required if not using `use_env_creds`) |
153+
| account_key | string | Azure storage account key (required if not using `use_env_creds`) |
154+
| use_env_creds | bool | Use Azure service principal authentication via environment variables |
155+
| container | string | Azure blob container name (required) |
156+
| create_container | bool | Create container if it does not exist |
157+
| endpoint_url | string | Custom endpoint URL (defaults to `https://<account_name>.blob.core.windows.net/`) |
158+
| global_prefix | string | Transparently apply a global prefix to all blob names |
159+
| disable_send_content_md5 | bool | Disable sending the Content-MD5 header |
160+
| tls | [tlsconfig.Config](https://github.com/PowerDNS/go-tlsconfig) | TLS configuration |
161+
| init_timeout | duration | Time allowed for initialisation (default: "20s") |
162+
| use_update_marker | bool | Reduce LIST commands by using an update marker (see below) |
163+
| update_marker_force_list_interval | duration | Force full LIST sync at this interval (default: "5m") |
164+
| concurrency | int | Max number of concurrent uploads (default: 1) |
165+
166+
The `use_update_marker` option can reduce Azure costs by replacing LIST operations (which are more expensive) with GET operations. However, it cannot be used if the container itself is replicated in an active-active fashion between data centers.
167+
168+
You can see a working example in the docker-compose setup, which uses [Azurite](https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite) (Azure Storage Emulator):
169+
170+
```bash
171+
docker-compose up
172+
```
173+
174+
For all available Azure backend options with full descriptions, see [Simpleblob's Azure backend Options struct](https://github.com/PowerDNS/simpleblob/blob/main/backends/azure/azure.go).
116175

117176
## Open Source
118177

@@ -123,5 +182,3 @@ For more information on how we provide support for Open Source products, please
123182
PowerDNS also offers an Enterprise edition of Lightning Stream that includes professional support, advanced features, deployment
124183
tooling for large deployments, Kubernetes integration, and more.
125184

126-
127-

cmd/lightningstream/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/PowerDNS/lightningstream/cmd/lightningstream/commands"
55

66
// Register storage backends
7+
_ "github.com/PowerDNS/simpleblob/backends/azure"
78
_ "github.com/PowerDNS/simpleblob/backends/fs"
89
_ "github.com/PowerDNS/simpleblob/backends/memory"
910
_ "github.com/PowerDNS/simpleblob/backends/s3"

config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ type DBIOptions struct {
302302
}
303303

304304
type Storage struct {
305-
Type string `yaml:"type"` // "fs", "s3", "memory"
305+
Type string `yaml:"type"` // "fs", "s3", "memory", "azure"
306306
Options map[string]interface{} `yaml:"options"` // backend specific
307307

308308
// FIXME: Configure per LMDB instead, since we run a cleaner per LMDB?

docker-compose.yml

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ version: '2.4'
66
volumes:
77
lmdb:
88
driver: local
9+
azurite_data:
910
minio:
1011
driver: local
1112
#snapshots:
@@ -21,7 +22,22 @@ services:
2122
command: server /data --console-address :9001
2223
volumes:
2324
- "minio:/data"
24-
25+
# https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite
26+
azurite:
27+
image: mcr.microsoft.com/azure-storage/azurite
28+
container_name: azurite
29+
hostname: azurite
30+
restart: always
31+
ports:
32+
- "10000:10000"
33+
- "10001:10001"
34+
- "10002:10002"
35+
command: azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0
36+
volumes:
37+
- azurite_data:/data
38+
- ./azure/certs:/certs
39+
environment:
40+
- AZURITE_ACCOUNTS=devstoreaccount1:key1
2541
auth1:
2642
image: powerdns/pdns-auth-49
2743
environment:
@@ -78,7 +94,7 @@ services:
7894
dockerfile: Dockerfile
7995
context: .
8096
environment:
81-
instance: 1 # used in config file
97+
- instance=1 # used in config file
8298
ports:
8399
- "${DEVENV_BIND_IP:-127.0.0.1}:${PORT_PREFIX:-47}91:8500"
84100
volumes:
@@ -94,7 +110,7 @@ services:
94110
dockerfile: Dockerfile
95111
context: .
96112
environment:
97-
instance: 2 # used in config file
113+
- instance=2 # used in config file
98114
ports:
99115
- "${DEVENV_BIND_IP:-127.0.0.1}:${PORT_PREFIX:-47}92:8500"
100116
volumes:
@@ -110,13 +126,12 @@ services:
110126
dockerfile: Dockerfile
111127
context: .
112128
environment:
113-
instance: 3 # used in config file
129+
- instance=3 # used in config file
114130
ports:
115131
- "${DEVENV_BIND_IP:-127.0.0.1}:${PORT_PREFIX:-47}93:8500"
116132
volumes:
117133
- "lmdb:/lmdb"
118134
- "./docker/pdns/lightningstream.yaml:/lightningstream.yaml:ro"
119-
#- "snapshots:/snapshots"
120135
working_dir: /
121136
user: "953" # pdns
122137
command: --minimum-pid 50 receive

docker/pdns/lightningstream.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ storage:
4040
interval: 15m
4141
must_keep_interval: 24h
4242
remove_old_instances_interval: 168h
43+
# type: azure
44+
# options:
45+
# account_name: devstoreaccount1
46+
# account_key: key1
47+
# container: lightningstreamcontainer
48+
# endpoint_url: http://azurite:10000/devstoreaccount1
49+
# create_container: true
50+
# use_update_marker: false
51+
# cleanup:
52+
# enabled: true
53+
# interval: 2m
54+
# must_keep_interval: 24h
55+
# remove_old_instances_interval: 168h
4356

4457
http:
4558
address: ":8500"

go.mod

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,36 @@
11
module github.com/PowerDNS/lightningstream
22

3-
go 1.24
3+
go 1.24.0
4+
5+
toolchain go1.24.5
46

57
require (
68
github.com/CrowdStrike/csproto v0.23.1
79
github.com/PowerDNS/lmdb-go v1.9.3
8-
github.com/PowerDNS/simpleblob v0.3.0
10+
github.com/PowerDNS/simpleblob v0.4.0
911
github.com/bufbuild/buf v0.56.0
1012
github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2
1113
github.com/gogo/protobuf v1.3.2
12-
github.com/klauspost/compress v1.17.11
14+
github.com/klauspost/compress v1.18.0
1315
github.com/pkg/errors v0.9.1
14-
github.com/prometheus/client_golang v1.20.4
16+
github.com/prometheus/client_golang v1.23.0
1517
github.com/samber/lo v1.37.0
1618
github.com/sirupsen/logrus v1.9.3
1719
github.com/spf13/cobra v1.9.1
18-
github.com/stretchr/testify v1.9.0
20+
github.com/stretchr/testify v1.11.1
1921
github.com/wojas/go-healthz v0.2.0
2022
go.uber.org/atomic v1.10.0
2123
golang.org/x/exp v0.0.0-20230111222715-75897c7a292a
22-
golang.org/x/sync v0.15.0
24+
golang.org/x/sync v0.16.0
2325
gopkg.in/yaml.v2 v2.4.0
2426
)
2527

2628
require (
29+
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 // indirect
30+
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.0 // indirect
31+
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
32+
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 // indirect
33+
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect
2734
github.com/PowerDNS/go-tlsconfig v0.0.0-20221101135152-0956853b28df // indirect
2835
github.com/beorn7/perks v1.0.1 // indirect
2936
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
@@ -32,39 +39,45 @@ require (
3239
github.com/davecgh/go-spew v1.1.1 // indirect
3340
github.com/dustin/go-humanize v1.0.1 // indirect
3441
github.com/go-ini/ini v1.67.0 // indirect
35-
github.com/go-logr/logr v1.4.2 // indirect
36-
github.com/goccy/go-json v0.10.3 // indirect
42+
github.com/go-logr/logr v1.4.3 // indirect
43+
github.com/goccy/go-json v0.10.5 // indirect
3744
github.com/gofrs/flock v0.8.1 // indirect
3845
github.com/gofrs/uuid v4.0.0+incompatible // indirect
46+
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
3947
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
4048
github.com/golang/protobuf v1.5.2 // indirect
4149
github.com/google/uuid v1.6.0 // indirect
4250
github.com/inconshreveable/mousetrap v1.1.0 // indirect
4351
github.com/jhump/protoreflect v1.9.1-0.20210817181203-db1a327a393e // indirect
44-
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
52+
github.com/klauspost/cpuid/v2 v2.2.11 // indirect
4553
github.com/klauspost/pgzip v1.2.5 // indirect
54+
github.com/kylelemons/godebug v1.1.0 // indirect
55+
github.com/minio/crc64nvme v1.0.2 // indirect
4656
github.com/minio/md5-simd v1.1.2 // indirect
47-
github.com/minio/minio-go/v7 v7.0.78 // indirect
57+
github.com/minio/minio-go/v7 v7.0.95 // indirect
4858
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
59+
github.com/philhofer/fwd v1.2.0 // indirect
60+
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
4961
github.com/pkg/profile v1.6.0 // indirect
5062
github.com/pmezard/go-difflib v1.0.0 // indirect
51-
github.com/prometheus/client_model v0.6.1 // indirect
52-
github.com/prometheus/common v0.55.0 // indirect
53-
github.com/prometheus/procfs v0.15.1 // indirect
63+
github.com/prometheus/client_model v0.6.2 // indirect
64+
github.com/prometheus/common v0.65.0 // indirect
65+
github.com/prometheus/procfs v0.16.1 // indirect
5466
github.com/rs/xid v1.6.0 // indirect
5567
github.com/russross/blackfriday/v2 v2.1.0 // indirect
5668
github.com/spf13/pflag v1.0.6 // indirect
69+
github.com/tinylib/msgp v1.3.0 // indirect
5770
github.com/twitchtv/twirp v8.1.0+incompatible // indirect
58-
go.opencensus.io v0.23.0 // indirect
71+
go.opencensus.io v0.24.0 // indirect
5972
go.uber.org/multierr v1.7.0 // indirect
6073
go.uber.org/zap v1.19.0 // indirect
61-
golang.org/x/crypto v0.39.0 // indirect
62-
golang.org/x/net v0.41.0 // indirect
63-
golang.org/x/sys v0.33.0 // indirect
64-
golang.org/x/term v0.32.0 // indirect
65-
golang.org/x/text v0.26.0 // indirect
74+
golang.org/x/crypto v0.41.0 // indirect
75+
golang.org/x/net v0.43.0 // indirect
76+
golang.org/x/sys v0.35.0 // indirect
77+
golang.org/x/term v0.34.0 // indirect
78+
golang.org/x/text v0.28.0 // indirect
6679
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
6780
google.golang.org/grpc v1.43.0 // indirect
68-
google.golang.org/protobuf v1.34.2 // indirect
81+
google.golang.org/protobuf v1.36.6 // indirect
6982
gopkg.in/yaml.v3 v3.0.1 // indirect
70-
)
83+
)

0 commit comments

Comments
 (0)