shardingsphere-operator/pkg/reconcile/computenode/deployment.go (213 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package computenode
import (
"context"
"fmt"
"github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/api/v1alpha1"
"github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/kubernetes"
"github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/kubernetes/configmap"
"github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/kubernetes/container"
"github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/kubernetes/deployment"
"github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/pkg/kubernetes/metadata"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// Build returns a new Deployment
func (b builder) BuildDeployment(ctx context.Context, cn *v1alpha1.ComputeNode) *appsv1.Deployment {
ssbuilder := NewShardingSphereDeploymentBuilder(cn.GetObjectMeta(), cn.GetObjectKind().GroupVersionKind())
b.buildMetadata(ssbuilder, cn)
b.buildSpec(ssbuilder, cn)
return ssbuilder.BuildShardingSphereDeployment()
}
type ShardingSphereDeploymentBuilder interface {
deployment.DeploymentBuilder
SetMySQLConnector(cn *v1alpha1.ComputeNode) ShardingSphereDeploymentBuilder
SetAgentBin(cn *v1alpha1.ComputeNode) ShardingSphereDeploymentBuilder
SetAgentScript(cn *v1alpha1.ComputeNode) ShardingSphereDeploymentBuilder
BuildShardingSphereDeployment() *appsv1.Deployment
}
// NewShardingSphereDeploymentBuilder creates a new ShardingSphereDeploymentBuilder
func NewShardingSphereDeploymentBuilder(meta metav1.Object, gvk schema.GroupVersionKind) ShardingSphereDeploymentBuilder {
db := deployment.NewDeploymentBuilder()
dp := db.BuildDeployment()
return &shardingsphereDeploymentBuilder{
DeploymentBuilder: db,
deployment: dp,
}
}
type shardingsphereDeploymentBuilder struct {
deployment.DeploymentBuilder
deployment *appsv1.Deployment
}
func (b builder) buildMetadata(ssbuilder ShardingSphereDeploymentBuilder, cn *v1alpha1.ComputeNode) {
ssbuilder.SetName(cn.Name).
SetNamespace(cn.Namespace).
SetLabels(cn.Labels).
SetAnnotations(cn.Annotations).
SetOwnerReferences([]metav1.OwnerReference{
*metav1.NewControllerRef(cn.GetObjectMeta(), cn.GetObjectKind().GroupVersionKind()),
})
}
func (b builder) buildSpec(ssbuilder ShardingSphereDeploymentBuilder, cn *v1alpha1.ComputeNode) {
ssbuilder.SetSelectors(cn.Spec.Selector)
ssbuilder.SetReplicas(&cn.Spec.Replicas)
ssbuilder.SetRollingUpdateStrategy(0, 3)
tpl := &corev1.PodTemplateSpec{}
tm := metadata.NewMetadataBuilder()
tm.SetLabels(cn.Labels)
ports := getContainerPortsFromComputeNode(cn)
scb := NewShardingSphereProxyContainerBuilder().
SetVersion(cn.Spec.ServerVersion).
SetPorts(ports).
SetResources(cn.Spec.Resources)
b.buildProbes(scb, cn)
vcb := deployment.NewSharedVolumeAndMountBuilder().
SetVolumeMountSize(1).
SetName(defaultConfigVolumeName).
SetVolumeSourceConfigMap(cn.Name).
SetMountPath(0, defaultConfigVolumeMountPath)
vc, vmc := vcb.Build()
ssbuilder.AppendVolumes([]corev1.Volume{
*vc,
})
scb.AppendVolumeMounts([]corev1.VolumeMount{*vmc[0]})
sc := scb.BuildContainer()
ssbuilder.AppendContainers([]corev1.Container{
*sc,
})
if enabled, ok := cn.Annotations[DefaultAnnotationJavaAgentEnabled]; ok && enabled == "true" {
ssbuilder.SetAgentBin(cn)
}
if cn.Spec.StorageNodeConnector != nil {
if cn.Spec.StorageNodeConnector.Type == v1alpha1.ConnectorTypeMySQL {
ssbuilder.SetMySQLConnector(cn)
}
}
tpl.ObjectMeta = *tm.BuildMetadata()
tpl.Spec = *ssbuilder.BuildPodSpec()
ssbuilder.SetPodTemplateSpec(tpl)
}
func (b builder) buildProbes(scb container.ContainerBuilder, cn *v1alpha1.ComputeNode) {
if cn.Spec.Probes == nil {
return
}
if cn.Spec.Probes.LivenessProbe != nil {
scb.SetLivenessProbe(cn.Spec.Probes.LivenessProbe)
}
if cn.Spec.Probes.ReadinessProbe != nil {
scb.SetReadinessProbe(cn.Spec.Probes.ReadinessProbe)
}
if cn.Spec.Probes.StartupProbe != nil {
scb.SetStartupProbe(cn.Spec.Probes.StartupProbe)
}
}
// SetMySQLConnector will set an init container to download mysql jar and mount files for proxy container.
func (d *shardingsphereDeploymentBuilder) SetMySQLConnector(cn *v1alpha1.ComputeNode) ShardingSphereDeploymentBuilder {
proxy := d.FindContainerByName("shardingsphere-proxy")
proxy.AppendEnv([]corev1.EnvVar{
{
Name: defaultMySQLDriverEnvName,
Value: cn.Spec.StorageNodeConnector.Version,
},
})
cb := d.FindInitContainerByName("download-mysql-jar")
if cb == nil {
cb = NewBootstrapContainerBuilderForMysqlJar()
}
cb.AppendEnv([]corev1.EnvVar{
{
Name: defaultMySQLDriverEnvName,
Value: cn.Spec.StorageNodeConnector.Version,
},
})
vb := deployment.NewSharedVolumeAndMountBuilder().
SetVolumeMountSize(2).
SetName(defaultMySQLDriverVolumeName).
SetVolumeSourceEmptyDir().
SetMountPath(0, defaultExtlibPath).
SetMountPath(1, absoluteMySQLDriverMountName(defaultExtlibPath, cn.Spec.StorageNodeConnector.Version)).
SetSubPath(1, relativeMySQLDriverMountName(cn.Spec.StorageNodeConnector.Version))
v, vms := vb.Build()
cb.AppendVolumeMounts([]corev1.VolumeMount{*vms[0]})
proxy.AppendVolumeMounts([]corev1.VolumeMount{*vms[1]})
d.UpdateContainerByName(proxy.BuildContainer())
d.UpdateInitContainerByName(cb.BuildContainer())
d.AppendVolumes([]corev1.Volume{*v})
return d
}
// SetAgentBin set `agent bin` for ShardingSphereProxy with [observability](https://shardingsphere.apache.org/document/current/en/user-manual/shardingsphere-proxy/observability/)
func (d *shardingsphereDeploymentBuilder) SetAgentBin(cn *v1alpha1.ComputeNode) ShardingSphereDeploymentBuilder {
// set env JAVA_TOOL_OPTIONS to proxy container, make sure proxy will apply agent-bin.jar
// agent-bin's version is always equals to shardingsphere proxy image's version
metricsAnnos := map[string]string{}
metricsAnnos[commonAnnotationPrometheusMetricsPath] = cn.Annotations[commonAnnotationPrometheusMetricsPath]
metricsAnnos[commonAnnotationPrometheusMetricsPort] = cn.Annotations[commonAnnotationPrometheusMetricsPort]
metricsAnnos[commonAnnotationPrometheusMetricsScrape] = cn.Annotations[commonAnnotationPrometheusMetricsScrape]
metricsAnnos[commonAnnotationPrometheusMetricsScheme] = cn.Annotations[commonAnnotationPrometheusMetricsScheme]
if d.deployment.Spec.Template.Annotations == nil {
d.deployment.Spec.Template.Annotations = map[string]string{}
}
d.deployment.Spec.Template.Annotations = metricsAnnos
proxy := d.FindContainerByName("shardingsphere-proxy")
if kubernetes.VersionBetween(cn.Spec.ServerVersion, "5.3.0", "5.4.0") {
proxy.AppendEnv([]corev1.EnvVar{
{
Name: defaultJavaToolOptionsName,
Value: fmt.Sprintf(defaultJavaAgentEnvValue, cn.Spec.ServerVersion),
},
})
} else if kubernetes.VersionGreaterAndEqualThan(cn.Spec.ServerVersion, "5.4.0") {
proxy.SetArgs([]string{"-g"})
}
vbAgentConf := deployment.NewSharedVolumeAndMountBuilder().
SetVolumeMountSize(1).
SetName(defaultJavaAgentConfigVolumeName).
SetVolumeSourceConfigMap(cn.Name, corev1.KeyToPath{Key: configmap.ConfigDataKeyForAgent, Path: configmap.ConfigDataKeyForAgent}).
SetMountPath(0, defaultJavaAgentConfigVolumeMountPath)
vc, vmc := vbAgentConf.Build()
vbAgent := deployment.NewSharedVolumeAndMountBuilder().
SetVolumeMountSize(1).
SetName(defaultJavaAgentVolumeName).
SetVolumeSourceEmptyDir().
SetMountPath(0, defaultJavaAgentVolumeMountPath)
va, vma := vbAgent.Build()
d.AppendVolumes([]corev1.Volume{*vc, *va})
cb := d.FindInitContainerByName("download-agent-bin-jar")
if cb == nil {
cb = NewBootstrapContainerBuilderForAgentBin()
}
cb.AppendVolumeMounts([]corev1.VolumeMount{*vma[0]}).
AppendEnv([]corev1.EnvVar{
{
Name: defaultAgentBinVersionEnvName,
Value: cn.Spec.ServerVersion,
},
})
d.UpdateInitContainerByName(cb.BuildContainer())
proxy.AppendVolumeMounts([]corev1.VolumeMount{*vmc[0], *vma[0]})
if kubernetes.VersionExactEqualTo(cn.Spec.ServerVersion, "5.3.2") {
d.SetAgentScript(cn)
}
d.UpdateContainerByName(proxy.BuildContainer())
return d
}
func (d *shardingsphereDeploymentBuilder) SetAgentScript(cn *v1alpha1.ComputeNode) ShardingSphereDeploymentBuilder {
proxy := d.FindContainerByName("shardingsphere-proxy")
sv := deployment.NewSharedVolumeAndMountBuilder().
SetVolumeMountSize(1).
SetName("replace-start-script").
SetVolumeSourceEmptyDir().
SetMountPath(0, "/opt/shardingsphere-proxy/bin")
va, vma := sv.Build()
d.AppendVolumes([]corev1.Volume{
*va,
})
proxy.AppendVolumeMounts([]corev1.VolumeMount{*vma[0]})
// NOTE: This mountpath is not same with init container
vma[0].MountPath = "/opt/shardingsphere-proxy/tmpbin"
cb := d.FindInitContainerByName("replace-start-script")
if cb == nil {
cb = NewBootstrapContainerBuilderForStartScripts()
}
cb.AppendVolumeMounts([]corev1.VolumeMount{*vma[0]})
d.UpdateInitContainerByName(cb.BuildContainer())
return d
}
func (d *shardingsphereDeploymentBuilder) BuildShardingSphereDeployment() *appsv1.Deployment {
dp := d.DeploymentBuilder.BuildDeployment()
return dp
}