parent
0ed92ed04e
commit
93bfed3e75
|
|
@ -69,6 +69,8 @@ configAwsOrGcp:
|
|||
# kube_iam_role: ""
|
||||
# log_s3_bucket: ""
|
||||
# wal_s3_bucket: ""
|
||||
# additional_secret_mount: "some-secret-name"
|
||||
# additional_secret_mount_path: "/some/dir"
|
||||
|
||||
configLogicalBackup:
|
||||
logical_backup_schedule: "30 00 * * *"
|
||||
|
|
|
|||
|
|
@ -333,3 +333,19 @@ The operator can manage k8s cron jobs to run logical backups of Postgres cluster
|
|||
4. You may use your own image by overwriting the relevant field in the operator configuration. Any such image must ensure the logical backup is able to finish [in presence of pod restarts](https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#handling-pod-and-container-failures) and [simultaneous invocations](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#cron-job-limitations) of the backup cron job.
|
||||
|
||||
5. For that feature to work, your RBAC policy must enable operations on the `cronjobs` resource from the `batch` API group for the operator service account. See [example RBAC](../manifests/operator-service-account-rbac.yaml)
|
||||
|
||||
## Access to cloud resources from clusters in non cloud environment
|
||||
|
||||
To access cloud resources like S3 from a cluster in a bare metal setup you can use
|
||||
`additional_secret_mount` and `additional_secret_mount_path` config parameters.
|
||||
With this you can provision cloud credentials to the containers in the pods of the StatefulSet.
|
||||
This works this way that it mounts a volume from the given secret in the pod and this can
|
||||
then accessed in the container over the configured mount path. Via [Custum Pod Environment Variables](#custom-pod-environment-variables)
|
||||
you can then point the different cloud sdk's (aws, google etc.) to this mounted secret.
|
||||
With this credentials the cloud sdk can then access cloud resources to upload logs etc.
|
||||
|
||||
A secret can be pre provisioned in different ways:
|
||||
|
||||
* Generic secret created via `kubectl create secret generic some-cloud-creds --from-file=some-cloud-credentials-file.json`
|
||||
|
||||
* Automaticly provisioned via a Controller like [kube-aws-iam-controller](https://github.com/mikkeloscar/kube-aws-iam-controller). This controller would then also rotate the credentials. Please visit the documention for more information.
|
||||
|
|
|
|||
|
|
@ -407,6 +407,12 @@ yet officially supported.
|
|||
* **aws_region**
|
||||
AWS region used to store ESB volumes. The default is `eu-central-1`.
|
||||
|
||||
* **additional_secret_mount**
|
||||
Additional Secret (aws or gcp credentials) to mount in the pod. The default is empty.
|
||||
|
||||
* **additional_secret_mount_path**
|
||||
Path to mount the above Secret in the filesystem of the container(s). The default is empty.
|
||||
|
||||
## Debugging the operator
|
||||
|
||||
Options to aid debugging of the operator itself. Grouped under the `debug` key.
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ data:
|
|||
# https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees
|
||||
# inherited_labels: ""
|
||||
aws_region: eu-central-1
|
||||
# additional_secret_mount: "some-secret-name"
|
||||
# additional_secret_mount_path: "/some/dir"
|
||||
db_hosted_zone: db.example.com
|
||||
master_dns_name_format: '{cluster}.{team}.staging.{hostedzone}'
|
||||
replica_dns_name_format: '{cluster}-repl.{team}.staging.{hostedzone}'
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ configuration:
|
|||
# log_s3_bucket: ""
|
||||
# kube_iam_role: ""
|
||||
aws_region: eu-central-1
|
||||
# additional_secret_mount: "some-secret-name"
|
||||
# additional_secret_mount_path: "/some/dir"
|
||||
debug:
|
||||
debug_logging: true
|
||||
enable_database_access: true
|
||||
|
|
|
|||
|
|
@ -101,10 +101,12 @@ type LoadBalancerConfiguration struct {
|
|||
// AWSGCPConfiguration defines the configuration for AWS
|
||||
// TODO complete Google Cloud Platform (GCP) configuration
|
||||
type AWSGCPConfiguration struct {
|
||||
WALES3Bucket string `json:"wal_s3_bucket,omitempty"`
|
||||
AWSRegion string `json:"aws_region,omitempty"`
|
||||
LogS3Bucket string `json:"log_s3_bucket,omitempty"`
|
||||
KubeIAMRole string `json:"kube_iam_role,omitempty"`
|
||||
WALES3Bucket string `json:"wal_s3_bucket,omitempty"`
|
||||
AWSRegion string `json:"aws_region,omitempty"`
|
||||
LogS3Bucket string `json:"log_s3_bucket,omitempty"`
|
||||
KubeIAMRole string `json:"kube_iam_role,omitempty"`
|
||||
AdditionalSecretMount string `json:"additional_secret_mount,omitempty"`
|
||||
AdditionalSecretMountPath string `json:"additional_secret_mount_path" default:"/meta/credentials"`
|
||||
}
|
||||
|
||||
// OperatorDebugConfiguration defines options for the debug mode
|
||||
|
|
|
|||
|
|
@ -384,7 +384,7 @@ func generateContainer(
|
|||
VolumeMounts: volumeMounts,
|
||||
Env: envVars,
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
Privileged: &privilegedMode,
|
||||
Privileged: &privilegedMode,
|
||||
ReadOnlyRootFilesystem: &falseBool,
|
||||
},
|
||||
}
|
||||
|
|
@ -445,6 +445,8 @@ func generatePodTemplate(
|
|||
shmVolume bool,
|
||||
podAntiAffinity bool,
|
||||
podAntiAffinityTopologyKey string,
|
||||
additionalSecretMount string,
|
||||
additionalSecretMountPath string,
|
||||
) (*v1.PodTemplateSpec, error) {
|
||||
|
||||
terminateGracePeriodSeconds := terminateGracePeriod
|
||||
|
|
@ -479,6 +481,10 @@ func generatePodTemplate(
|
|||
podSpec.PriorityClassName = priorityClassName
|
||||
}
|
||||
|
||||
if additionalSecretMount != "" {
|
||||
addSecretVolume(&podSpec, additionalSecretMount, additionalSecretMountPath)
|
||||
}
|
||||
|
||||
template := v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: labels,
|
||||
|
|
@ -864,7 +870,9 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*v1beta1.State
|
|||
effectivePodPriorityClassName,
|
||||
mountShmVolumeNeeded(c.OpConfig, spec),
|
||||
c.OpConfig.EnablePodAntiAffinity,
|
||||
c.OpConfig.PodAntiAffinityTopologyKey); err != nil {
|
||||
c.OpConfig.PodAntiAffinityTopologyKey,
|
||||
c.OpConfig.AdditionalSecretMount,
|
||||
c.OpConfig.AdditionalSecretMountPath); err != nil {
|
||||
return nil, fmt.Errorf("could not generate pod template: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -1013,6 +1021,28 @@ func addShmVolume(podSpec *v1.PodSpec) {
|
|||
podSpec.Volumes = volumes
|
||||
}
|
||||
|
||||
func addSecretVolume(podSpec *v1.PodSpec, additionalSecretMount string, additionalSecretMountPath string) {
|
||||
volumes := append(podSpec.Volumes, v1.Volume{
|
||||
Name: additionalSecretMount,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Secret: &v1.SecretVolumeSource{
|
||||
SecretName: additionalSecretMount,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
for i := range podSpec.Containers {
|
||||
mounts := append(podSpec.Containers[i].VolumeMounts,
|
||||
v1.VolumeMount{
|
||||
Name: additionalSecretMount,
|
||||
MountPath: additionalSecretMountPath,
|
||||
})
|
||||
podSpec.Containers[i].VolumeMounts = mounts
|
||||
}
|
||||
|
||||
podSpec.Volumes = volumes
|
||||
}
|
||||
|
||||
func generatePersistentVolumeClaimTemplate(volumeSize, volumeStorageClass string) (*v1.PersistentVolumeClaim, error) {
|
||||
|
||||
var storageClassName *string
|
||||
|
|
@ -1395,6 +1425,8 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1beta1.CronJob, error) {
|
|||
"",
|
||||
false,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
""); err != nil {
|
||||
return nil, fmt.Errorf("could not generate pod template for logical backup pod: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -389,3 +389,74 @@ func TestCloneEnv(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecretVolume(t *testing.T) {
|
||||
testName := "TestSecretVolume"
|
||||
tests := []struct {
|
||||
subTest string
|
||||
podSpec *v1.PodSpec
|
||||
secretPos int
|
||||
}{
|
||||
{
|
||||
subTest: "empty PodSpec",
|
||||
podSpec: &v1.PodSpec{
|
||||
Volumes: []v1.Volume{},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
VolumeMounts: []v1.VolumeMount{},
|
||||
},
|
||||
},
|
||||
},
|
||||
secretPos: 0,
|
||||
},
|
||||
{
|
||||
subTest: "non empty PodSpec",
|
||||
podSpec: &v1.PodSpec{
|
||||
Volumes: []v1.Volume{{}},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "data",
|
||||
ReadOnly: false,
|
||||
MountPath: "/data",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
secretPos: 1,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
additionalSecretMount := "aws-iam-s3-role"
|
||||
additionalSecretMountPath := "/meta/credentials"
|
||||
|
||||
numMounts := len(tt.podSpec.Containers[0].VolumeMounts)
|
||||
|
||||
addSecretVolume(tt.podSpec, additionalSecretMount, additionalSecretMountPath)
|
||||
|
||||
volumeName := tt.podSpec.Volumes[tt.secretPos].Name
|
||||
|
||||
if volumeName != additionalSecretMount {
|
||||
t.Errorf("%s %s: Expected volume %s was not created, have %s instead",
|
||||
testName, tt.subTest, additionalSecretMount, volumeName)
|
||||
}
|
||||
|
||||
for i := range tt.podSpec.Containers {
|
||||
volumeMountName := tt.podSpec.Containers[i].VolumeMounts[tt.secretPos].Name
|
||||
|
||||
if volumeMountName != additionalSecretMount {
|
||||
t.Errorf("%s %s: Expected mount %s was not created, have %s instead",
|
||||
testName, tt.subTest, additionalSecretMount, volumeMountName)
|
||||
}
|
||||
}
|
||||
|
||||
numMountsCheck := len(tt.podSpec.Containers[0].VolumeMounts)
|
||||
|
||||
if numMountsCheck != numMounts+1 {
|
||||
t.Errorf("Unexpected number of VolumeMounts: got %v instead of %v",
|
||||
numMountsCheck, numMounts+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
|
|||
result.AWSRegion = fromCRD.AWSGCP.AWSRegion
|
||||
result.LogS3Bucket = fromCRD.AWSGCP.LogS3Bucket
|
||||
result.KubeIAMRole = fromCRD.AWSGCP.KubeIAMRole
|
||||
result.AdditionalSecretMount = fromCRD.AWSGCP.AdditionalSecretMount
|
||||
result.AdditionalSecretMountPath = fromCRD.AWSGCP.AdditionalSecretMountPath
|
||||
|
||||
result.DebugLogging = fromCRD.OperatorDebug.DebugLogging
|
||||
result.EnableDBAccess = fromCRD.OperatorDebug.EnableDBAccess
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@ type Config struct {
|
|||
WALES3Bucket string `name:"wal_s3_bucket"`
|
||||
LogS3Bucket string `name:"log_s3_bucket"`
|
||||
KubeIAMRole string `name:"kube_iam_role"`
|
||||
AdditionalSecretMount string `name:"additional_secret_mount"`
|
||||
AdditionalSecretMountPath string `name:"additional_secret_mount_path" default:"/meta/credentials"`
|
||||
DebugLogging bool `name:"debug_logging" default:"true"`
|
||||
EnableDBAccess bool `name:"enable_database_access" default:"true"`
|
||||
EnableTeamsAPI bool `name:"enable_teams_api" default:"true"`
|
||||
|
|
|
|||
Loading…
Reference in New Issue