Skip to content
Permalink
Browse files

Merge pull request #5371 from PayFit/feat/add-sql-storage-driver

[storage] Add an SQL storage driver
  • Loading branch information...
bacongobbler committed May 9, 2019
2 parents 39283f9 + f405282 commit a93ebe17d69e8bf99bdf4880acb40499653dd033
Showing with 783 additions and 22 deletions.
  1. +29 −11 cmd/tiller/tiller.go
  2. +31 −3 docs/install.md
  3. +16 −0 glide.lock
  4. +11 −8 glide.yaml
  5. +16 −0 pkg/storage/driver/mock_test.go
  6. +336 −0 pkg/storage/driver/sql.go
  7. +344 −0 pkg/storage/driver/sql_test.go
@@ -66,6 +66,7 @@ const (
storageMemory = "memory"
storageConfigMap = "configmap"
storageSecret = "secret"
storageSQL = "sql"

traceAddr = ":44136"

@@ -74,18 +75,23 @@ const (
)

var (
grpcAddr = flag.String("listen", fmt.Sprintf(":%v", environment.DefaultTillerPort), "address:port to listen on")
probeAddr = flag.String("probe-listen", fmt.Sprintf(":%v", environment.DefaultTillerProbePort), "address:port to listen on for probes")
enableTracing = flag.Bool("trace", false, "enable rpc tracing")
store = flag.String("storage", storageConfigMap, "storage driver to use. One of 'configmap', 'memory', or 'secret'")
grpcAddr = flag.String("listen", fmt.Sprintf(":%v", environment.DefaultTillerPort), "address:port to listen on")
probeAddr = flag.String("probe-listen", fmt.Sprintf(":%v", environment.DefaultTillerProbePort), "address:port to listen on for probes")
enableTracing = flag.Bool("trace", false, "enable rpc tracing")
store = flag.String("storage", storageConfigMap, "storage driver to use. One of 'configmap', 'memory', 'sql' or 'secret'")

sqlDialect = flag.String("sql-dialect", "postgres", "SQL dialect to use (only postgres is supported for now")
sqlConnectionString = flag.String("sql-connection-string", "", "SQL connection string to use")

remoteReleaseModules = flag.Bool("experimental-release", false, "enable experimental release modules")
tlsEnable = flag.Bool("tls", tlsEnableEnvVarDefault(), "enable TLS")
tlsVerify = flag.Bool("tls-verify", tlsVerifyEnvVarDefault(), "enable TLS and verify remote certificate")
keyFile = flag.String("tls-key", tlsDefaultsFromEnv("tls-key"), "path to TLS private key file")
certFile = flag.String("tls-cert", tlsDefaultsFromEnv("tls-cert"), "path to TLS certificate file")
caCertFile = flag.String("tls-ca-cert", tlsDefaultsFromEnv("tls-ca-cert"), "trust certificates signed by this CA")
maxHistory = flag.Int("history-max", historyMaxFromEnv(), "maximum number of releases kept in release history, with 0 meaning no limit")
printVersion = flag.Bool("version", false, "print the version number")

tlsEnable = flag.Bool("tls", tlsEnableEnvVarDefault(), "enable TLS")
tlsVerify = flag.Bool("tls-verify", tlsVerifyEnvVarDefault(), "enable TLS and verify remote certificate")
keyFile = flag.String("tls-key", tlsDefaultsFromEnv("tls-key"), "path to TLS private key file")
certFile = flag.String("tls-cert", tlsDefaultsFromEnv("tls-cert"), "path to TLS certificate file")
caCertFile = flag.String("tls-ca-cert", tlsDefaultsFromEnv("tls-ca-cert"), "trust certificates signed by this CA")
maxHistory = flag.Int("history-max", historyMaxFromEnv(), "maximum number of releases kept in release history, with 0 meaning no limit")
printVersion = flag.Bool("version", false, "print the version number")

// rootServer is the root gRPC server.
//
@@ -143,6 +149,18 @@ func start() {

env.Releases = storage.Init(secrets)
env.Releases.Log = newLogger("storage").Printf
case storageSQL:
sqlDriver, err := driver.NewSQL(
*sqlDialect,
*sqlConnectionString,
newLogger("storage/driver").Printf,
)
if err != nil {
logger.Fatalf("Cannot initialize SQL storage driver: %v", err)
}

env.Releases = storage.Init(sqlDriver)
env.Releases.Log = newLogger("storage").Printf
}

if *maxHistory > 0 {
@@ -353,10 +353,13 @@ in JSON format.

### Storage backends
By default, `tiller` stores release information in `ConfigMaps` in the namespace
where it is running. As of Helm 2.7.0, there is now a beta storage backend that
where it is running.

#### Secret storage backend
As of Helm 2.7.0, there is now a beta storage backend that
uses `Secrets` for storing release information. This was added for additional
security in protecting charts in conjunction with the release of `Secret`
encryption in Kubernetes.
security in protecting charts in conjunction with the release of `Secret`
encryption in Kubernetes.

To enable the secrets backend, you'll need to init Tiller with the following
options:
@@ -369,6 +372,31 @@ Currently, if you want to switch from the default backend to the secrets
backend, you'll have to do the migration for this on your own. When this backend
graduates from beta, there will be a more official path of migration

#### SQL storage backend
As of Helm 2.14.0 there is now a beta SQL storage backend that stores release
information in an SQL database (only postgres has been tested so far).

Using such a storage backend is particularly useful if your release information
weighs more than 1MB (in which case, it can't be stored in ConfigMaps/Secrets
because of internal limits in Kubernetes' underlying etcd key-value store).

To enable the SQL backend, you'll need to deploy a SQL database and init Tiller
with the following options:

```shell
helm init \
--override \
'spec.template.spec.containers[0].args'='{--storage=sql,--sql-dialect=postgres,--sql-connection-string=postgresql://tiller-postgres:5432/helm?user=helm&password=changeme}'
```

**PRODUCTION NOTES**: it's recommended to change the username and password of
the SQL database in production deployments. Enabling SSL is also a good idea.
Last, but not least, perform regular backups/snapshots of your SQL database.

Currently, if you want to switch from the default backend to the SQL backend,
you'll have to do the migration for this on your own. When this backend
graduates from beta, there will be a more official migration path.

## Conclusion

In most cases, installation is as simple as getting a pre-built `helm` binary

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -2,11 +2,10 @@ package: k8s.io/helm
import:
- package: golang.org/x/net
subpackages:
- context
- context
- package: golang.org/x/sync
subpackages:
- semaphore
# This is temporary and can probably be removed the next time gRPC is updated
- package: golang.org/x/sys
version: b90733256f2e882e81d52f9126de08df5615afd9
subpackages:
@@ -17,7 +16,6 @@ import:
- package: github.com/spf13/pflag
version: ~1.0.1
- package: github.com/Masterminds/vcs
# Pin version of mergo that is compatible with both sprig and Kubernetes
- package: github.com/imdario/mergo
version: v0.3.5
- package: github.com/Masterminds/sprig
@@ -30,18 +28,18 @@ import:
- package: github.com/golang/protobuf
version: 1.2.0
subpackages:
- proto
- ptypes/any
- ptypes/timestamp
- proto
- ptypes/any
- ptypes/timestamp
- package: google.golang.org/grpc
version: 1.18.0
- package: github.com/gosuri/uitable
- package: github.com/asaskevich/govalidator
version: ^4.0.0
- package: golang.org/x/crypto
subpackages:
- openpgp
- ssh/terminal
- openpgp
- ssh/terminal
- package: github.com/gobwas/glob
version: ^0.2.1
- package: github.com/evanphx/json-patch
@@ -66,9 +64,14 @@ import:
version: kubernetes-1.14.1
- package: github.com/cyphar/filepath-securejoin
version: ^0.2.1
- package: github.com/jmoiron/sqlx
version: ^1.2.0
- package: github.com/rubenv/sql-migrate

testImports:
- package: github.com/stretchr/testify
version: ^1.1.4
subpackages:
- assert
- package: github.com/DATA-DOG/go-sqlmock
version: ^1.3.2
@@ -20,6 +20,8 @@ import (
"fmt"
"testing"

sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/jmoiron/sqlx"
"k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -231,3 +233,17 @@ func (mock *MockSecretsInterface) Delete(name string, opts *metav1.DeleteOptions
delete(mock.objects, name)
return nil
}

// newTestFixtureSQL mocks the SQL database (for testing purposes)
func newTestFixtureSQL(t *testing.T, releases ...*rspb.Release) (*SQL, sqlmock.Sqlmock) {
sqlDB, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("error when opening stub database connection: %v", err)
}

sqlxDB := sqlx.NewDb(sqlDB, "sqlmock")
return &SQL{
db: sqlxDB,
Log: func(_ string, _ ...interface{}) {},
}, mock
}
Oops, something went wrong.

0 comments on commit a93ebe1

Please sign in to comment.
You can’t perform that action at this time.