From 2b86360df42c73da43432a77a68d4a2cedbbad9b Mon Sep 17 00:00:00 2001 From: Adam Janikowski Date: Mon, 23 Mar 2020 21:07:41 +0100 Subject: [PATCH] [Feature] Allow to override default images (#536) --- CHANGELOG.md | 2 + chart/kube-arangodb/templates/deployment.yaml | 6 ++ chart/kube-arangodb/values.yaml | 4 ++ main.go | 32 +++++++--- pkg/apis/deployment/v1/deployment_spec.go | 6 +- pkg/deployment/context_impl.go | 8 +++ pkg/deployment/deployment.go | 10 ++-- pkg/deployment/resources/context.go | 4 ++ pkg/deployment/resources/pod_creator.go | 1 + .../resources/pod_creator_arangod.go | 2 +- pkg/operator/operator.go | 2 + pkg/operator/operator_deployment.go | 10 ++-- pkg/util/env.go | 59 +++++++++++++++++++ 13 files changed, 127 insertions(+), 19 deletions(-) create mode 100644 pkg/util/env.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f3e8b20a..df9e81d77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Change Log ## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A) +- Added possibility to override default images used by ArangoDeployment +- Added possibility to set probes on all groups - Added Image Discovery type in ArangoDeployment spec - Prevent Agency Members recreation - Added Customizable Volumes and VolumeMounts for ArangoDB server container diff --git a/chart/kube-arangodb/templates/deployment.yaml b/chart/kube-arangodb/templates/deployment.yaml index 3f15bc4b8..e6f79faba 100644 --- a/chart/kube-arangodb/templates/deployment.yaml +++ b/chart/kube-arangodb/templates/deployment.yaml @@ -98,6 +98,12 @@ spec: valueFrom: fieldRef: fieldPath: status.podIP + - name: RELATED_IMAGE_UBI + value: "{{ .Values.operator.images.base }}" + - name: RELATED_IMAGE_METRICSEXPORTER + value: "{{ .Values.operator.images.metricsExporter }}" + - name: RELATED_IMAGE_DATABASE + value: "{{ .Values.operator.images.arango }}" ports: - name: metrics containerPort: 8528 diff --git a/chart/kube-arangodb/values.yaml b/chart/kube-arangodb/values.yaml index 06d30131a..ad03e2fc7 100644 --- a/chart/kube-arangodb/values.yaml +++ b/chart/kube-arangodb/values.yaml @@ -31,5 +31,9 @@ operator: storage: false backup: false + images: + base: alpine:3.11 + metricsExporter: arangodb/arangodb-exporter:0.1.6 + arango: arangodb/arangodb:latest rbac: enabled: true \ No newline at end of file diff --git a/main.go b/main.go index 508ca60ae..42f02d426 100644 --- a/main.go +++ b/main.go @@ -31,6 +31,10 @@ import ( "strings" "time" + deploymentApi "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" + + "github.com/arangodb/kube-arangodb/pkg/util" + utilsError "github.com/arangodb/kube-arangodb/pkg/util/errors" "github.com/pkg/errors" @@ -58,11 +62,17 @@ import ( ) const ( - defaultServerHost = "0.0.0.0" - defaultServerPort = 8528 - defaultLogLevel = "debug" - defaultAdminSecretName = "arangodb-operator-dashboard" - defaultAlpineImage = "alpine:3.7" + defaultServerHost = "0.0.0.0" + defaultServerPort = 8528 + defaultLogLevel = "debug" + defaultAdminSecretName = "arangodb-operator-dashboard" + defaultAlpineImage = "alpine:3.7" + defaultMetricsExporterImage = "arangodb/arangodb-exporter:0.1.6" + defaultArangoImage = "arangodb/arangodb:latest" + + UBIImageEnv util.EnvironmentVariable = "RELATED_IMAGE_UBI" + ArangoImageEnv util.EnvironmentVariable = "RELATED_IMAGE_DATABASE" + MetricsExporterImageEnv util.EnvironmentVariable = "RELATED_IMAGE_METRICSEXPORTER" ) var ( @@ -91,7 +101,8 @@ var ( enableDeploymentReplication bool // Run deployment-replication operator enableStorage bool // Run local-storage operator enableBackup bool // Run backup operator - alpineImage string + + alpineImage, metricsExporterImage, arangoImage string } chaosOptions struct { allowed bool @@ -104,6 +115,7 @@ var ( ) func init() { + f := cmdMain.Flags() f.StringVar(&serverOptions.host, "server.host", defaultServerHost, "Host to listen on") f.IntVar(&serverOptions.port, "server.port", defaultServerPort, "Port to listen on") @@ -115,7 +127,9 @@ func init() { f.BoolVar(&operatorOptions.enableDeploymentReplication, "operator.deployment-replication", false, "Enable to run the ArangoDeploymentReplication operator") f.BoolVar(&operatorOptions.enableStorage, "operator.storage", false, "Enable to run the ArangoLocalStorage operator") f.BoolVar(&operatorOptions.enableBackup, "operator.backup", false, "Enable to run the ArangoBackup operator") - f.StringVar(&operatorOptions.alpineImage, "operator.alpine-image", defaultAlpineImage, "Docker image used for alpine containers") + f.StringVar(&operatorOptions.alpineImage, "operator.alpine-image", UBIImageEnv.GetOrDefault(defaultAlpineImage), "Docker image used for alpine containers") + f.StringVar(&operatorOptions.metricsExporterImage, "operator.metrics-exporter-image", MetricsExporterImageEnv.GetOrDefault(defaultMetricsExporterImage), "Docker image used for metrics containers by default") + f.StringVar(&operatorOptions.arangoImage, "operator.arango-image", ArangoImageEnv.GetOrDefault(defaultArangoImage), "Docker image used for arango by default") f.BoolVar(&chaosOptions.allowed, "chaos.allowed", false, "Set to allow chaos in deployments. Only activated when allowed and enabled in deployment") } @@ -137,6 +151,8 @@ func cmdMainRun(cmd *cobra.Command, args []string) { name := os.Getenv(constants.EnvOperatorPodName) ip := os.Getenv(constants.EnvOperatorPodIP) + deploymentApi.DefaultImage = operatorOptions.arangoImage + // Prepare log service var err error logService, err = logging.NewService(logLevel) @@ -277,6 +293,8 @@ func newOperatorConfigAndDeps(id, namespace, name string) (operator.Config, oper EnableBackup: operatorOptions.enableBackup, AllowChaos: chaosOptions.allowed, AlpineImage: operatorOptions.alpineImage, + MetricsExporterImage: operatorOptions.metricsExporterImage, + ArangoImage: operatorOptions.arangoImage, } deps := operator.Dependencies{ LogService: logService, diff --git a/pkg/apis/deployment/v1/deployment_spec.go b/pkg/apis/deployment/v1/deployment_spec.go index be073abf0..311d63875 100644 --- a/pkg/apis/deployment/v1/deployment_spec.go +++ b/pkg/apis/deployment/v1/deployment_spec.go @@ -30,8 +30,8 @@ import ( v1 "k8s.io/api/core/v1" ) -const ( - defaultImage = "arangodb/arangodb:latest" +var ( + DefaultImage = "arangodb/arangodb:latest" ) // validatePullPolicy the image pull policy. @@ -223,7 +223,7 @@ func (s *DeploymentSpec) SetDefaults(deploymentName string) { s.StorageEngine = NewStorageEngine(StorageEngineRocksDB) } if s.GetImage() == "" && s.IsDevelopment() { - s.Image = util.NewString(defaultImage) + s.Image = util.NewString(DefaultImage) } if s.GetImagePullPolicy() == "" { s.ImagePullPolicy = util.NewPullPolicy(v1.PullIfNotPresent) diff --git a/pkg/deployment/context_impl.go b/pkg/deployment/context_impl.go index 28128ad4d..d0563c743 100644 --- a/pkg/deployment/context_impl.go +++ b/pkg/deployment/context_impl.go @@ -475,3 +475,11 @@ func (d *Deployment) RenderPodForMember(spec api.DeploymentSpec, status api.Depl func (d *Deployment) SelectImage(spec api.DeploymentSpec, status api.DeploymentStatus) (api.ImageInfo, bool) { return d.resources.SelectImage(spec, status) } + +func (d *Deployment) GetMetricsExporterImage() string { + return d.config.MetricsExporterImage +} + +func (d *Deployment) GetArangoImage() string { + return d.config.ArangoImage +} diff --git a/pkg/deployment/deployment.go b/pkg/deployment/deployment.go index ed57e7f7f..b02ca0e97 100644 --- a/pkg/deployment/deployment.go +++ b/pkg/deployment/deployment.go @@ -52,10 +52,12 @@ import ( // Config holds configuration settings for a Deployment type Config struct { - ServiceAccount string - AllowChaos bool - LifecycleImage string - AlpineImage string + ServiceAccount string + AllowChaos bool + LifecycleImage string + AlpineImage string + MetricsExporterImage string + ArangoImage string } // Dependencies holds dependent services for a Deployment diff --git a/pkg/deployment/resources/context.go b/pkg/deployment/resources/context.go index 3ef6dafa2..6b7085857 100644 --- a/pkg/deployment/resources/context.go +++ b/pkg/deployment/resources/context.go @@ -63,6 +63,10 @@ type Context interface { GetLifecycleImage() string // GetAlpineImage returns the image name containing the alpine environment GetAlpineImage() string + // GetMetricsExporterImage returns the image name containing the default metrics exporter image + GetMetricsExporterImage() string + // GetArangoImage returns the image name containing the default arango image + GetArangoImage() string // GetNamespace returns the namespace that contains the deployment GetNamespace() string // CreateEvent creates a given event. diff --git a/pkg/deployment/resources/pod_creator.go b/pkg/deployment/resources/pod_creator.go index 9d6f43ef0..88c460d9d 100644 --- a/pkg/deployment/resources/pod_creator.go +++ b/pkg/deployment/resources/pod_creator.go @@ -427,6 +427,7 @@ func (r *Resources) RenderPodForMember(spec api.DeploymentSpec, status api.Deplo group: group, resources: r, imageInfo: imageInfo, + context: r.context, } return RenderArangoPod(apiObject, role, m.ID, m.PodName, args, &memberPod) diff --git a/pkg/deployment/resources/pod_creator_arangod.go b/pkg/deployment/resources/pod_creator_arangod.go index d5c08bb73..7e02bc4c3 100644 --- a/pkg/deployment/resources/pod_creator_arangod.go +++ b/pkg/deployment/resources/pod_creator_arangod.go @@ -180,7 +180,7 @@ func (m *MemberArangoDPod) GetServiceAccountName() string { func (m *MemberArangoDPod) GetSidecars(pod *core.Pod) { if isMetricsEnabledForGroup(m.spec, m.group) { - image := m.spec.GetImage() + image := m.context.GetMetricsExporterImage() if m.spec.Metrics.HasImage() { image = m.spec.Metrics.GetImage() } diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index dda11270b..01990a119 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -85,6 +85,8 @@ type Config struct { ServiceAccount string LifecycleImage string AlpineImage string + ArangoImage string + MetricsExporterImage string EnableDeployment bool EnableDeploymentReplication bool EnableStorage bool diff --git a/pkg/operator/operator_deployment.go b/pkg/operator/operator_deployment.go index a28522ec4..1ef97e420 100644 --- a/pkg/operator/operator_deployment.go +++ b/pkg/operator/operator_deployment.go @@ -204,10 +204,12 @@ func (o *Operator) handleDeploymentEvent(event *Event) error { // makeDeploymentConfigAndDeps creates a Config & Dependencies object for a new Deployment. func (o *Operator) makeDeploymentConfigAndDeps(apiObject *api.ArangoDeployment) (deployment.Config, deployment.Dependencies) { cfg := deployment.Config{ - ServiceAccount: o.Config.ServiceAccount, - LifecycleImage: o.Config.LifecycleImage, - AlpineImage: o.Config.AlpineImage, - AllowChaos: o.Config.AllowChaos, + ServiceAccount: o.Config.ServiceAccount, + LifecycleImage: o.Config.LifecycleImage, + AlpineImage: o.Config.AlpineImage, + MetricsExporterImage: o.MetricsExporterImage, + ArangoImage: o.ArangoImage, + AllowChaos: o.Config.AllowChaos, } deps := deployment.Dependencies{ Log: o.Dependencies.LogService.MustGetLogger("deployment").With(). diff --git a/pkg/util/env.go b/pkg/util/env.go new file mode 100644 index 000000000..658676a8c --- /dev/null +++ b/pkg/util/env.go @@ -0,0 +1,59 @@ +// +// DISCLAIMER +// +// Copyright 2020 ArangoDB GmbH, Cologne, Germany +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// +// Author Adam Janikowski +// + +package util + +import "os" + +// EnvironmentVariable is a wrapper to get environment variables +type EnvironmentVariable string + +// String return string representation of environment variable name +func (e EnvironmentVariable) String() string { + return string(e) +} + +// Lookup for environment variable +func (e EnvironmentVariable) Lookup() (string, bool) { + return os.LookupEnv(e.String()) +} + +// Exists check if variable is defined +func (e EnvironmentVariable) Exists() bool { + _, exists := e.Lookup() + return exists +} + +// Get fetch variable. If variable does not exist empty string is returned +func (e EnvironmentVariable) Get() string { + value, _ := e.Lookup() + return value +} + +// GetOrDefault fetch variable. If variable is not defined default value is returned +func (e EnvironmentVariable) GetOrDefault(d string) string { + if value, exists := e.Lookup(); exists { + return value + } + + return d +}