Skip to content

Commit 06a392e

Browse files
committed
Refactor karpenter deployment to CPOv2
This commit refactors the karpenter deployment and assets which are managed by the karpenter operator to CPOv2. This removes the ability to pass in the karpenter aws image as an argument to the karpenter-operator deployment, since we can directly get the karpenter aws image from the payload image itself from within the karpenter-operator releaseImage lookup code. This commit also removes the deprecated karpenter code. Signed-off-by: Max Cao <[email protected]>
1 parent fc3e56a commit 06a392e

File tree

16 files changed

+356
-642
lines changed

16 files changed

+356
-642
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: karpenter
5+
namespace: HCP_NAMESPACE
6+
labels:
7+
app: karpenter
8+
spec:
9+
replicas: 1
10+
selector:
11+
matchLabels:
12+
app: karpenter
13+
template:
14+
metadata:
15+
labels:
16+
app: karpenter
17+
spec:
18+
serviceAccountName: karpenter
19+
terminationGracePeriodSeconds: 10
20+
tolerations:
21+
- key: "node-role.kubernetes.io/master"
22+
effect: "NoSchedule"
23+
volumes:
24+
- name: target-kubeconfig
25+
secret:
26+
# secretName: to be replaced by adaptDeployment
27+
defaultMode: 0640
28+
items:
29+
- key: value
30+
path: target-kubeconfig
31+
- name: serviceaccount-token
32+
emptyDir: {}
33+
- name: provider-creds
34+
secret:
35+
secretName: "karpenter-credentials"
36+
containers:
37+
- name: karpenter
38+
image: karpenter # replaced by payload
39+
args:
40+
- "--log-level=debug"
41+
env:
42+
- name: KUBECONFIG
43+
value: "/mnt/kubeconfig/target-kubeconfig"
44+
- name: SYSTEM_NAMESPACE
45+
valueFrom:
46+
fieldRef:
47+
fieldPath: metadata.namespace
48+
- name: DISABLE_WEBHOOK
49+
value: "true"
50+
- name: DISABLE_LEADER_ELECTION
51+
value: "true"
52+
- name: FEATURE_GATES
53+
value: "Drift=true"
54+
- name: AWS_SHARED_CREDENTIALS_FILE
55+
value: "/etc/provider/credentials"
56+
- name: AWS_SDK_LOAD_CONFIG
57+
value: "true"
58+
- name: HEALTH_PROBE_PORT
59+
value: "8081"
60+
- name: CLUSTER_ENDPOINT
61+
value: "https://fake.com"
62+
ports:
63+
- name: metrics
64+
containerPort: 8080
65+
- name: http
66+
containerPort: 8081
67+
protocol: TCP
68+
resources:
69+
requests:
70+
memory: "60Mi"
71+
cpu: "10m"
72+
volumeMounts:
73+
- name: target-kubeconfig
74+
mountPath: "/mnt/kubeconfig"
75+
- name: provider-creds
76+
mountPath: "/etc/provider"
77+
- name: serviceaccount-token
78+
mountPath: "/var/run/secrets/openshift/serviceaccount"
79+
livenessProbe:
80+
httpGet:
81+
path: /healthz
82+
port: http
83+
scheme: HTTP
84+
initialDelaySeconds: 60
85+
periodSeconds: 60
86+
successThreshold: 1
87+
failureThreshold: 5
88+
timeoutSeconds: 5
89+
readinessProbe:
90+
httpGet:
91+
path: /readyz
92+
port: http
93+
scheme: HTTP
94+
periodSeconds: 10
95+
successThreshold: 1
96+
failureThreshold: 3
97+
timeoutSeconds: 5
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: Role
3+
metadata:
4+
name: karpenter
5+
namespace: HCP_NAMESPACE
6+
rules:
7+
- apiGroups:
8+
- "coordination.k8s.io"
9+
resources:
10+
- "leases"
11+
verbs:
12+
- "get"
13+
- "watch"
14+
- "create"
15+
- apiGroups:
16+
- "coordination.k8s.io"
17+
resources:
18+
- "leases"
19+
verbs:
20+
- "patch"
21+
- "update"
22+
resourceNames:
23+
- "karpenter-leader-election"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: RoleBinding
3+
metadata:
4+
name: karpenter
5+
namespace: HCP_NAMESPACE
6+
roleRef:
7+
apiGroup: rbac.authorization.k8s.io
8+
kind: Role
9+
name: karpenter
10+
subjects:
11+
- kind: ServiceAccount
12+
name: karpenter
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
apiVersion: v1
2+
kind: ServiceAccount
3+
metadata:
4+
name: karpenter
5+
namespace: HCP_NAMESPACE
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package karpenter
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/manifests"
7+
karpenteroperatorv2 "github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator"
8+
component "github.com/openshift/hypershift/support/controlplane-component"
9+
"github.com/openshift/hypershift/support/util"
10+
11+
"sigs.k8s.io/controller-runtime/pkg/client"
12+
)
13+
14+
const (
15+
ComponentName = "karpenter"
16+
)
17+
18+
var _ component.ComponentOptions = &karpenterOptions{}
19+
20+
type karpenterOptions struct{}
21+
22+
// IsRequestServing implements controlplanecomponent.ComponentOptions.
23+
func (c *karpenterOptions) IsRequestServing() bool {
24+
return false
25+
}
26+
27+
// MultiZoneSpread implements controlplanecomponent.ComponentOptions.
28+
func (c *karpenterOptions) MultiZoneSpread() bool {
29+
return false
30+
}
31+
32+
// NeedsManagementKASAccess implements controlplanecomponent.ComponentOptions.
33+
func (c *karpenterOptions) NeedsManagementKASAccess() bool {
34+
return true
35+
}
36+
37+
func NewComponent() component.ControlPlaneComponent {
38+
return component.NewDeploymentComponent(ComponentName, &karpenterOptions{}).
39+
WithAdaptFunction(adaptDeployment).
40+
WithManifestAdapter(
41+
"role.yaml",
42+
component.WithAdaptFunction(adaptRole),
43+
).
44+
WithPredicate(predicate).
45+
WithDependencies(karpenteroperatorv2.ComponentName).
46+
InjectAvailabilityProberContainer(util.AvailabilityProberOpts{}).
47+
Build()
48+
}
49+
50+
func predicate(cpContext component.WorkloadContext) (bool, error) {
51+
hcp := cpContext.HCP
52+
53+
// The deployment depends on the kubeconfig being reported.
54+
if hcp.Status.KubeConfig == nil {
55+
return false, nil
56+
}
57+
// Resolve the kubeconfig secret for CAPI which the autoscaler is deployed alongside of.
58+
capiKubeConfigSecret := manifests.KASServiceCAPIKubeconfigSecret(hcp.Namespace, hcp.Spec.InfraID)
59+
err := cpContext.Client.Get(cpContext, client.ObjectKeyFromObject(capiKubeConfigSecret), capiKubeConfigSecret)
60+
if err != nil {
61+
return false, fmt.Errorf("failed to get hosted controlplane kubeconfig secret %q: %w", capiKubeConfigSecret.Name, err)
62+
}
63+
64+
return true, nil
65+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package karpenter
2+
3+
import (
4+
hyperkarpenterv1 "github.com/openshift/hypershift/api/karpenter/v1beta1"
5+
"github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/manifests"
6+
"github.com/openshift/hypershift/support/util"
7+
corev1 "k8s.io/api/core/v1"
8+
"k8s.io/apimachinery/pkg/api/resource"
9+
"k8s.io/utils/ptr"
10+
11+
component "github.com/openshift/hypershift/support/controlplane-component"
12+
13+
appsv1 "k8s.io/api/apps/v1"
14+
)
15+
16+
const (
17+
kubeconfigVolumeName = "target-kubeconfig"
18+
)
19+
20+
func adaptDeployment(cpContext component.WorkloadContext, deployment *appsv1.Deployment) error {
21+
hcp := cpContext.HCP
22+
23+
karpenterProviderAWSOverride, exists := hcp.Annotations[hyperkarpenterv1.KarpenterProviderAWSImage]
24+
if exists {
25+
util.UpdateContainer(ComponentName, deployment.Spec.Template.Spec.Containers, func(c *corev1.Container) {
26+
c.Image = karpenterProviderAWSOverride
27+
})
28+
}
29+
30+
util.UpdateVolume(kubeconfigVolumeName, deployment.Spec.Template.Spec.Volumes, func(v *corev1.Volume) {
31+
v.Secret.SecretName = manifests.KASServiceCAPIKubeconfigSecret(hcp.Namespace, hcp.Spec.InfraID).Name
32+
})
33+
34+
util.UpdateContainer(ComponentName, deployment.Spec.Template.Spec.Containers, func(c *corev1.Container) {
35+
c.Env = append(c.Env,
36+
corev1.EnvVar{
37+
Name: "AWS_REGION",
38+
Value: hcp.Spec.Platform.AWS.Region,
39+
},
40+
corev1.EnvVar{
41+
Name: "CLUSTER_NAME",
42+
Value: hcp.Spec.InfraID,
43+
},
44+
)
45+
// Override the image if specified in the HCP annotations.
46+
karpenterProviderAWSOverride, exists := hcp.Annotations[hyperkarpenterv1.KarpenterProviderAWSImage]
47+
if exists {
48+
c.Image = karpenterProviderAWSOverride
49+
}
50+
})
51+
52+
deployment.Spec.Template.Spec.InitContainers = append(deployment.Spec.Template.Spec.InitContainers,
53+
corev1.Container{
54+
Name: "token-minter",
55+
Image: "token-minter",
56+
Command: []string{"/usr/bin/control-plane-operator", "token-minter"},
57+
Args: []string{
58+
"--service-account-namespace=kube-system",
59+
"--service-account-name=karpenter",
60+
"--token-file=/var/run/secrets/openshift/serviceaccount/token",
61+
"--kubeconfig=/mnt/kubeconfig/target-kubeconfig",
62+
},
63+
Resources: corev1.ResourceRequirements{
64+
Requests: corev1.ResourceList{
65+
corev1.ResourceCPU: resource.MustParse("10m"),
66+
corev1.ResourceMemory: resource.MustParse("30Mi"),
67+
},
68+
},
69+
RestartPolicy: ptr.To(corev1.ContainerRestartPolicyAlways),
70+
StartupProbe: &corev1.Probe{
71+
ProbeHandler: corev1.ProbeHandler{
72+
Exec: &corev1.ExecAction{
73+
Command: []string{"cat", "/var/run/secrets/openshift/serviceaccount/token"}, // waits until the token file is created.
74+
},
75+
},
76+
FailureThreshold: 10,
77+
},
78+
VolumeMounts: []corev1.VolumeMount{
79+
{
80+
Name: "target-kubeconfig",
81+
MountPath: "/mnt/kubeconfig",
82+
},
83+
{
84+
Name: "serviceaccount-token",
85+
MountPath: "/var/run/secrets/openshift/serviceaccount",
86+
},
87+
},
88+
},
89+
)
90+
91+
return nil
92+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package karpenter
2+
3+
import (
4+
"github.com/openshift/hypershift/support/config"
5+
component "github.com/openshift/hypershift/support/controlplane-component"
6+
7+
rbacv1 "k8s.io/api/rbac/v1"
8+
)
9+
10+
func adaptRole(cpContext component.WorkloadContext, role *rbacv1.Role) error {
11+
ownerRef := config.OwnerRefFrom(cpContext.HCP)
12+
ownerRef.ApplyTo(role)
13+
14+
return nil
15+
}

control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/component.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/manifests"
77
component "github.com/openshift/hypershift/support/controlplane-component"
8+
"github.com/openshift/hypershift/support/util"
89

910
"sigs.k8s.io/controller-runtime/pkg/client"
1011
)
@@ -18,8 +19,6 @@ var _ component.ComponentOptions = &KarpenterOperatorOptions{}
1819
type KarpenterOperatorOptions struct {
1920
HyperShiftOperatorImage string
2021
ControlPlaneOperatorImage string
21-
KarpenterProviderAWSImage string
22-
ControlPlaneContext component.ControlPlaneContext
2322
}
2423

2524
// IsRequestServing implements controlplanecomponent.ComponentOptions.
@@ -51,6 +50,7 @@ func NewComponent(options *KarpenterOperatorOptions) component.ControlPlaneCompo
5150
ServiceAccountNameSpace: "kube-system",
5251
KubeconfigSecretName: "service-network-admin-kubeconfig",
5352
}).
53+
InjectAvailabilityProberContainer(util.AvailabilityProberOpts{}).
5454
Build()
5555
}
5656

control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/deployment.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ func (karp *KarpenterOperatorOptions) adaptDeployment(cpContext component.Worklo
5353
)
5454
c.Args = append(c.Args,
5555
"--control-plane-operator-image="+karp.ControlPlaneOperatorImage,
56-
"--karpenter-provider-aws-image="+karp.KarpenterProviderAWSImage,
5756
)
5857
})
5958
}

hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,6 +1881,7 @@ func (r *HostedClusterReconciler) reconcile(ctx context.Context, req ctrl.Reques
18811881

18821882
imageProvider := imageprovider.New(releaseImage)
18831883
imageProvider.ComponentImages()["token-minter"] = utilitiesImage
1884+
imageProvider.ComponentImages()[hyperutil.AvailabilityProberImageName] = utilitiesImage
18841885
cpContext := controlplanecomponent.ControlPlaneContext{
18851886
Context: ctx,
18861887
Client: r.Client,

hypershift-operator/controllers/hostedcluster/karpenter.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
karpenteroperatorv2 "github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator"
2121
"github.com/openshift/hypershift/hypershift-operator/controllers/nodepool"
2222
haproxy "github.com/openshift/hypershift/hypershift-operator/controllers/nodepool/apiserver-haproxy"
23-
"github.com/openshift/hypershift/karpenter-operator/controllers/karpenter/assets"
2423
controlplanecomponent "github.com/openshift/hypershift/support/controlplane-component"
2524

2625
"github.com/openshift/hypershift/support/releaseinfo"
@@ -109,16 +108,9 @@ spec:
109108

110109
// Run karpenter Operator to manage CRs management and guest side.
111110

112-
// TODO(jkyros): Grab the karpenter image in the proper place at the beginning with args, not here?
113-
karpenterProviderAWSImage, hasImage := releaseImage.ComponentImages()["aws-karpenter-provider-aws"]
114-
if !hasImage {
115-
karpenterProviderAWSImage = assets.DefaultKarpenterProviderAWSImage
116-
}
117-
118111
karpenteroperator := karpenteroperatorv2.NewComponent(&karpenteroperatorv2.KarpenterOperatorOptions{
119112
HyperShiftOperatorImage: hypershiftOperatorImage,
120113
ControlPlaneOperatorImage: controlPlaneOperatorImage,
121-
KarpenterProviderAWSImage: karpenterProviderAWSImage,
122114
})
123115

124116
if err := karpenteroperator.Reconcile(cpContext); err != nil {

0 commit comments

Comments
 (0)