Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions pkg/clouds/pulumi/kubernetes/simple_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ const (
LabelParentStack = "simple-container.com/parent-stack"
LabelClientStack = "simple-container.com/client-stack"
LabelCustomStack = "simple-container.com/custom-stack"

// Standard Kubernetes labels (https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/)
LabelKubernetesName = "app.kubernetes.io/name"
LabelKubernetesInstance = "app.kubernetes.io/instance"
LabelKubernetesVersion = "app.kubernetes.io/version"
LabelKubernetesComponent = "app.kubernetes.io/component"
LabelKubernetesPartOf = "app.kubernetes.io/part-of"
LabelKubernetesManagedBy = "app.kubernetes.io/managed-by"
LabelKubernetesCreatedBy = "app.kubernetes.io/created-by"
)

// sanitizeK8sResourceName converts a name to be RFC 1123 compliant for Kubernetes resources
Expand Down Expand Up @@ -144,6 +153,13 @@ func NewSimpleContainer(ctx *sdk.Context, args *SimpleContainerArgs, opts ...sdk
LabelScEnv: args.ScEnv,
}

// Add standard Kubernetes labels
appLabels[LabelKubernetesName] = sanitizedService
appLabels[LabelKubernetesInstance] = sanitizedDeployment
appLabels[LabelKubernetesPartOf] = "simple-container"
appLabels[LabelKubernetesManagedBy] = "simple-container"
appLabels[LabelKubernetesCreatedBy] = "simple-container-cli"

// Add parentEnv labels for custom stacks
if args.ParentEnv != nil && lo.FromPtr(args.ParentEnv) != "" && lo.FromPtr(args.ParentEnv) != args.ScEnv {
appLabels[LabelParentEnv] = lo.FromPtr(args.ParentEnv)
Expand Down Expand Up @@ -182,6 +198,15 @@ func NewSimpleContainer(ctx *sdk.Context, args *SimpleContainerArgs, opts ...sdk
appAnnotations[k] = v
}

// Copy standard Kubernetes labels from annotations if provided
// This allows users to specify version and component via annotations
if version, ok := appAnnotations["app.kubernetes.io/version"]; ok {
appLabels[LabelKubernetesVersion] = version
}
if component, ok := appAnnotations["app.kubernetes.io/component"]; ok {
appLabels[LabelKubernetesComponent] = component
}

// Namespace
// Sanitize namespace name to comply with Kubernetes RFC 1123 requirements
sanitizedNamespace := sanitizeK8sName(args.Namespace)
Expand Down Expand Up @@ -458,6 +483,17 @@ func NewSimpleContainer(ctx *sdk.Context, args *SimpleContainerArgs, opts ...sdk
},
}
}
// Use minimal, stable labels for selector to avoid breaking deployments when labels are added
selectorLabels := map[string]string{
LabelAppType: appLabels[LabelAppType],
LabelAppName: appLabels[LabelAppName],
LabelScEnv: appLabels[LabelScEnv],
}
// Add parent-stack label to selector if present for proper multi-stack isolation
if val, ok := appLabels[LabelParentStack]; ok {
selectorLabels[LabelParentStack] = val
}

deployment, err := v1.NewDeployment(ctx, sanitizedDeployment, &v1.DeploymentArgs{
Metadata: &metav1.ObjectMetaArgs{
Name: sdk.String(sanitizedDeployment),
Expand All @@ -469,7 +505,7 @@ func NewSimpleContainer(ctx *sdk.Context, args *SimpleContainerArgs, opts ...sdk
Strategy: strategy,
Replicas: sdk.Int(args.Replicas),
Selector: &metav1.LabelSelectorArgs{
MatchLabels: sdk.ToStringMap(appLabels),
MatchLabels: sdk.ToStringMap(selectorLabels),
},
Template: &corev1.PodTemplateSpecArgs{
Metadata: &metav1.ObjectMetaArgs{
Expand Down Expand Up @@ -565,7 +601,7 @@ ${proto}://${domain} {
Annotations: sdk.ToStringMap(serviceAnnotations),
},
Spec: &corev1.ServiceSpecArgs{
Selector: sdk.ToStringMap(appLabels),
Selector: sdk.ToStringMap(selectorLabels),
Ports: servicePorts,
Type: serviceType,
},
Expand Down Expand Up @@ -623,7 +659,7 @@ ${proto}://${domain} {
if args.PodDisruption != nil {
pdbArgs := policyv1.PodDisruptionBudgetSpecArgs{
Selector: &metav1.LabelSelectorArgs{
MatchLabels: sdk.ToStringMap(appLabels),
MatchLabels: sdk.ToStringMap(selectorLabels),
},
}
if args.PodDisruption.MinAvailable != nil {
Expand Down