Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#4958): Supporting node selectors for the builder pod #4968

Merged
merged 12 commits into from
Dec 7, 2023
Merged

feat(#4958): Supporting node selectors for the builder pod #4968

merged 12 commits into from
Dec 7, 2023

Conversation

lsergio
Copy link
Contributor

@lsergio lsergio commented Dec 5, 2023

This is PR is to support specifying node selectors for the builder pods by adding a nodeSelector parameter to the Builder Trait and Build custom resources.

This my first attempt to submit a PR to the camel-k code base, so there's a high chance I'm missing something.

Release Note

feature: support for nodeSelector on Integration Builder Traits

@squakez squakez added the kind/feature New feature or request label Dec 5, 2023
@squakez squakez linked an issue Dec 5, 2023 that may be closed by this pull request
@squakez squakez added this to the 2.2.0 milestone Dec 5, 2023
@squakez
Copy link
Contributor

squakez commented Dec 5, 2023

Cool stuff. Thanks for contributing. I'll give a deeper look on Thursday. In the while you need to run make generate to regen CRDs and trait documentation and it could be good to add some extra documentation to explain how the trait has to be specified with a simple example. You can add some code after this line

// End of autogenerated code - DO NOT EDIT! (configuration)
and follow the example we provide for instance in other traits, ie,
== Sidecar containers

Feel free to have a look to unit test as well. It would be good to cover a basic scenario, here a reference as well

func TestInvalidMavenProfilesBuilderTrait(t *testing.T) {

I just saw the build failed because we have many pending PRs running simultaneously. @christophd or @claudio4j please, re-trigger the checks tomorrow when there is no high PR traffic.

Copy link
Contributor

github-actions bot commented Dec 5, 2023

🐫 Thank you for contributing! 🐫

Unable to create Coverage Report ⚠️.
Merge conflicts found.

@lsergio
Copy link
Contributor Author

lsergio commented Dec 5, 2023

I added the generated code from make generate. I'll try and work on unit tests and doc tomorrow.

@lsergio lsergio marked this pull request as ready for review December 6, 2023 12:53
Copy link
Contributor

@squakez squakez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work indeed. Thanks for taking care of it. Just one remark in order to maintain the actual design. Builder tasks configuration is defined at [1]. Ideally the NodeSelector configuration should be added here instead of the Environment. In the builder trait, you will be able to get the value passed from the user into the specific builder task configuration, see [2]. Finally, when you're setting up the Pod, you should be able to use those values for the correct NodeSelector, similar to what we're doing with container resources, see [3].

[1]

type BuildConfiguration struct {

[2]
builderTask, err := t.builderTask(e, taskConfOrDefault(tasksConf, "builder"))

[3]
func configureResources(taskName string, build *v1.Build, container *corev1.Container) {


== Node Selectors

With this trait you will also be able to define node selectors for the `builder`` pod when using the `pod`` build strategy.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
With this trait you will also be able to define node selectors for the `builder`` pod when using the `pod`` build strategy.
With this trait you will also be able to define node selectors for the `builder` pod when using the `pod` build strategy.

size: large
----

The `builder` pod will be created with a node selector that allows it to run only on nodes where the `size`` label is equal to `large`.`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The `builder` pod will be created with a node selector that allows it to run only on nodes where the `size`` label is equal to `large`.`
The `builder` pod will be created with a node selector that allows it to run only on nodes where the `size` label is equal to `large`.

docs/modules/traits/pages/builder.adoc Show resolved Hide resolved
@@ -66,4 +66,6 @@ type BuilderTrait struct {
TasksLimitCPU []string `property:"tasks-limit-cpu" json:"tasksLimitCPU,omitempty"`
// A list of limit memory configuration for the specific task with format `<task-name>:<limit-memory-conf>`.
TasksLimitMemory []string `property:"tasks-limit-memory" json:"tasksLimitMemory,omitempty"`
// Defines a set of nodes the builder pod is eligible to be scheduled on, based on labels on the node.
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's missing the property:"node-selector"

@lsergio lsergio marked this pull request as draft December 7, 2023 15:10
@lsergio lsergio marked this pull request as ready for review December 7, 2023 15:24
@lsergio
Copy link
Contributor Author

lsergio commented Dec 7, 2023

After my latest changes, I tested the code applying this CR to my cluster:

apiVersion: camel.apache.org/v1
kind: Integration
metadata:
  name: test
spec:
  sources:
  - name: main.groovy
    content: |-
      rest("/test-mode")
          .post()
          .to("direct:start")

      from("direct:start").to("log:info")
  traits:
    quarkus:
      buildMode:
      - "native"
    builder:
      nodeSelector:
        size: large

and this is the builder pod:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2023-12-07T15:23:06Z"
  labels:
    camel.apache.org/build: kit-clou6miqjnf7ksc5tj6g
    camel.apache.org/component: builder
    camel.apache.org/created.by.kind: Integration
    camel.apache.org/created.by.name: test
    camel.apache.org/created.by.namespace: sensedia
    camel.apache.org/created.by.version: "1028014"
  name: camel-k-kit-clou6miqjnf7ksc5tj6g-builder
  namespace: sensedia
  ownerReferences:
  - apiVersion: camel.apache.org/v1
    blockOwnerDeletion: true
    controller: true
    kind: Build
    name: kit-clou6miqjnf7ksc5tj6g
    uid: 1f7dfb6c-48c4-492b-ab9e-2dbb1408d44e
  resourceVersion: "1028038"
  uid: 45b52b58-671f-4247-9f92-89d553e7a5ff
spec:
  containers:
  - command:
    - kamel
    - builder
    - --namespace
    - sensedia
    - --build-name
    - kit-clou6miqjnf7ksc5tj6g
    - --task-name
    - spectrum
    env:
    - name: HOME
      value: /builder/kit-clou6miqjnf7ksc5tj6g
    image: docker.io/apache/camel-k:2.2.0-SNAPSHOT
    imagePullPolicy: IfNotPresent
    name: spectrum
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /builder/kit-clou6miqjnf7ksc5tj6g
      name: camel-k-builder
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-dv2xz
      readOnly: true
    workingDir: /builder/kit-clou6miqjnf7ksc5tj6g
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  initContainers:
  - command:
    - kamel
    - builder
    - --namespace
    - sensedia
    - --build-name
    - kit-clou6miqjnf7ksc5tj6g
    - --task-name
    - builder
    env:
    - name: HOME
      value: /builder/kit-clou6miqjnf7ksc5tj6g
    image: docker.io/apache/camel-k:2.2.0-SNAPSHOT
    imagePullPolicy: IfNotPresent
    name: builder
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /builder/kit-clou6miqjnf7ksc5tj6g
      name: camel-k-builder
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-dv2xz
      readOnly: true
    workingDir: /builder/kit-clou6miqjnf7ksc5tj6g
  - command:
    - /bin/bash
    - -c
    - cd maven && ./mvnw $(cat MAVEN_CONTEXT) package -Dquarkus.package.type=native
      -Dmaven.repo.local=./repo
    image: quay.io/quarkus/ubi-quarkus-mandrel-builder-image:23.0-jdk-17
    imagePullPolicy: IfNotPresent
    name: quarkus-native
    resources:
      requests:
        cpu: "1"
        memory: 4Gi
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /builder/kit-clou6miqjnf7ksc5tj6g
      name: camel-k-builder
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-dv2xz
      readOnly: true
    workingDir: /builder/kit-clou6miqjnf7ksc5tj6g
  - command:
    - kamel
    - builder
    - --namespace
    - sensedia
    - --build-name
    - kit-clou6miqjnf7ksc5tj6g
    - --task-name
    - package
    env:
    - name: HOME
      value: /builder/kit-clou6miqjnf7ksc5tj6g
    image: docker.io/apache/camel-k:2.2.0-SNAPSHOT
    imagePullPolicy: IfNotPresent
    name: package
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /builder/kit-clou6miqjnf7ksc5tj6g
      name: camel-k-builder
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-dv2xz
      readOnly: true
    workingDir: /builder/kit-clou6miqjnf7ksc5tj6g
  nodeSelector:
    size: large
  preemptionPolicy: PreemptLowerPriority
  priority: 0
  restartPolicy: Never
  schedulerName: default-scheduler
  securityContext:
    fsGroup: 1001
    runAsGroup: 1001
    runAsUser: 1001
  serviceAccount: camel-k-builder
  serviceAccountName: camel-k-builder
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - emptyDir: {}
    name: camel-k-builder
  - name: kube-api-access-dv2xz
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2023-12-07T15:23:06Z"
    message: '0/3 nodes are available: 3 node(s) didn''t match Pod''s node affinity/selector.
      preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling..'
    reason: Unschedulable
    status: "False"
    type: PodScheduled
  phase: Pending
  qosClass: Burstable

The nodeSelector was generated as expected

@claudio4j
Copy link
Contributor

I tried to run with an integration with label that didn't exist on any node -t builder.node-selector.test=null and the build run in the camel-k-operator pod as is in strategy: routine, not in a camel-k-kit pod.
In name of simplicity I am happy to have this feature as it is, but it would be good to add to the builder trait doc that if the nodeSelector label it not set in any node, then the build will run in the camel-k-operator pod.

@lsergio
Copy link
Contributor Author

lsergio commented Dec 7, 2023

@claudio4j In my test none of the nodes has the size=large label. As my Integration requests a native build, it spawned a new pod.
With a regular jvm build, I changed my Integration platform buildConfiguration strategy to pod and it spawned a builder pod as well.
With routine strategy and jvm build, the nodeSelector configuration has no effect.

The builder pod status also shows that there are no available nodes:

    message: '0/3 nodes are available: 3 node(s) didn''t match Pod''s node affinity/selector.
      preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling..'

@claudio4j
Copy link
Contributor

I am using minikube with kvm2 driver, there is the standard single node, named "minikube". The build strategy is pod and this is the cli: kamel run teste2.yaml -t builder.node-selector.teste=nul
I will have a look later why there is not a builder pod.

Copy link
Contributor

@squakez squakez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work, thanks!


[source,console]
----
$ kamel run --trait builder.node-selector.size=large integration.groovy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is something like builder.node-selector.'size'=large, is it?

Copy link
Contributor Author

@lsergio lsergio Dec 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested it exactly like this and it worked. I think quotes are not required as there are no spaces in the label.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, possibly in this case it works because "size" is a simple string. However, it may fail when using more complex annotations, so, better to be safe and keep the notation we're using for a map in the rest of the project.

@squakez
Copy link
Contributor

squakez commented Dec 7, 2023

I am using minikube with kvm2 driver, there is the standard single node, named "minikube". The build strategy is pod and this is the cli: kamel run teste2.yaml -t builder.node-selector.teste=nul I will have a look later why there is not a builder pod.

Maybe it's because the notation from CLI has to be builder.node-selector.'size'=large - please, give it a try.

@squakez squakez merged commit ed869f7 into apache:main Dec 7, 2023
14 of 16 checks passed
@squakez
Copy link
Contributor

squakez commented Dec 7, 2023

Many thanks for the contribution @lsergio !!

@lsergio
Copy link
Contributor Author

lsergio commented Dec 7, 2023

Thanks for the quick feedback, @squakez . This feature will be very helpful in our project.
We'll test the 2.2 release as soon as it's available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Ability to apply node selectors/affinity configuration
3 participants