Answers: <p>Possibly you are looking for this  <a href="https://github.com/kubernetes/kubeadm/issues/1392" rel="nofollow noreferrer">feature</a> which is closed with no action since there are ways to work around this problem.</p>
  
  <blockquote>
    <p>kubeadm already allows to set taints for the joining node using the configuration file at join time (<strong><em>check my other <a href="https://devops.stackexchange.com/a/10717/19264">answer</a> for details on how to do that</em></strong>)</p>
  </blockquote>
  
  <p>One Other way to achieve this is by running join as usual but taking few extra steps as below after join</p>
  
  <blockquote>
    <p>1) After successful join , <strong>Force Drain the new node</strong> to make sure it removes unwanted pod which might have scaled to it post join operation <code>kubectl drain &lt;node name&gt; --force</code> </p>
    
    <p>2) <strong>Drain command will auto cordon</strong> off the node. (Note : also <strong>consider special handling to remove any daemonset</strong> which might have scaled to this node after join)</p>
    
    <p>3) Now <strong>Taint the new node</strong> as needed <strong>and then uncordon</strong> it</p>
    
    <p>4) <strong>Add nodeselector plus tolerance to pods</strong> you want to be scheduled on this new node.</p>
  </blockquote>
  
  <p>Logs of above steps for reference are listed below.</p>
  
  <p>On below example i have joined a new node-02 and assume that some pod were scaled in an existing deployment so new node got used immediately on join, so before adding we need drain action and then taint the node so going forward no scheduling can be done unless pod has tolerance to the taint added</p>
  
  <p><strong>Nodes Before Drain or Taint</strong></p>
  
  <pre><code>$ kubectl get all -o wide
  NAME                         READY   STATUS    RESTARTS   AGE   IP               NODE                NOMINATED NODE   READINESS GATES
  pod/nginx-86c57db685-8cdkx   1/1     Running   0          27s   192.168.58.120   k8s-node02-calico   &lt;none&gt;           &lt;none&gt;
  pod/nginx-86c57db685-xnh6q   1/1     Running   0          65s   192.168.182.78   k8s-node01-calico   &lt;none&gt;           &lt;none&gt;
  
  NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
  service/kubernetes   ClusterIP   10.96.0.1    &lt;none&gt;        443/TCP   2d    &lt;none&gt;
  
  NAME                    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR
  deployment.apps/nginx   2/2     2            2           65s   nginx        nginx    app=nginx
  
  NAME                               DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES   SELECTOR
  replicaset.apps/nginx-86c57db685   2         2         2       65s   nginx        nginx    app=nginx,pod-template-hash=86c57db685
  </code></pre>
  
  <p><strong>Drain The node</strong></p>
  
  <pre><code>$ kubectl drain k8s-node02-calico
  node/k8s-node02-calico cordoned
  evicting pod "nginx-86c57db685-8cdkx"
  pod/nginx-86c57db685-8cdkx evicted
  node/k8s-node02-calico evicted
  
  
  $ kubectl get nodes
  NAME                STATUS                     ROLES    AGE   VERSION
  k8s-master-calico   Ready                      master   2d    v1.17.2
  k8s-node01-calico   Ready                      &lt;none&gt;   2d    v1.17.2
  k8s-node02-calico   Ready,SchedulingDisabled   &lt;none&gt;   2d    v1.17.2
  </code></pre>
  
  <p><strong>Taint the new node</strong></p>
  
  <pre><code>$ kubectl taint node k8s-node02-calico newnode=nobodyallowed:NoSchedule
  node/k8s-node02-calico tainted
  </code></pre>
  
  <p><strong>Now we are good to uncordon the node, no more pods should be able to use this noe unless they add toleration to the new taint</strong>.</p>
  
  <pre><code>$ kubectl uncordon k8s-node02-calico
  node/k8s-node02-calico uncordoned
  
  
  $ kubectl get nodes
  NAME                STATUS   ROLES    AGE   VERSION
  k8s-master-calico   Ready    master   2d    v1.17.2
  k8s-node01-calico   Ready    &lt;none&gt;   2d    v1.17.2
  k8s-node02-calico   Ready    &lt;none&gt;   2d    v1.17.2
  </code></pre>
  
  <p><strong>We test by scaling the deployment and nothign should be added on node02</strong></p>
  
  <pre><code>$ kubectl scale deployment --replicas=3 nginx
  deployment.apps/nginx scaled
  
  $ kubectl get all -o wide
  NAME                         READY   STATUS    RESTARTS   AGE     IP               NODE                NOMINATED NODE   READINESS GATES
  pod/nginx-86c57db685-vm8ql   1/1     Running   0          3m30s   192.168.182.75   k8s-node01-calico   &lt;none&gt;           &lt;none&gt;
  pod/nginx-86c57db685-xnh6q   1/1     Running   0          10m     192.168.182.78   k8s-node01-calico   &lt;none&gt;           &lt;none&gt;
  pod/nginx-86c57db685-zh2sj   1/1     Running   0          8m19s   192.168.182.76   k8s-node01-calico   &lt;none&gt;           &lt;none&gt;
  
  NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
  service/kubernetes   ClusterIP   10.96.0.1    &lt;none&gt;        443/TCP   2d    &lt;none&gt;
  
  NAME                    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR
  deployment.apps/nginx   3/3     3            3           10m   nginx        nginx    app=nginx
  
  NAME                               DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES   SELECTOR
  replicaset.apps/nginx-86c57db685   3         3         3       10m   nginx        nginx    app=nginx,pod-template-hash=86c57db685
  </code></pre>
  
Answers: CC BY-SA 4.0
Answers: 2020-02-05T15:18:33.397Z
Answers: I am speechless... this is the perfect answer, @DT. Thank you very much!
Answers: RooSoft
Answers: CC BY-SA 4.0
Answers: 2020-02-05T15:22:57.380Z
Answers: in my view my second answer below is better approach because it will taint the node directly at join time so that not even a deamonset can come into your new space.
Answers: DT.
Answers: CC BY-SA 4.0
Answers: 2020-02-04T17:09:52.413Z
Answers: 2020-02-05T11:39:20.160Z
Answers: 2020-02-05T11:39:20.160Z
Answers: DT.
Answers: <blockquote>
    <p><strong>kubeadm already allows to set taints for the joining node using the configuration file at join time</strong>.</p>
  </blockquote>
  
  <p><strong>Steps on how to do this at node join time are as below</strong></p>
  
  <p>Construct a <strong>Config.yaml file with taint details and bootstrap details</strong> as recived from master at kubeadm init time.</p>
  
  <p><strong>Example config.yaml</strong> you should update values as per your cluster info on below</p>
  
  <pre><code>apiVersion: kubeadm.k8s.io/v1beta1
  kind: JoinConfiguration
  discovery:
    bootstrapToken:
      apiServerEndpoint: "&lt;control_plain_ip&gt;:6443"
      token: "your_token"
      caCertHashes:
      - sha256:$CERT_HASH
  nodeRegistration:
    taints:
    - effect: NoSchedule
      key: specialnode1.kubernetes.io/SpecialNode1
  </code></pre>
  
  <p><strong>Pass this config from node you want to join</strong> it will join with a taint set at startup.</p>
  
  <pre><code>root@k8s-node01:# kubeadm join --config=config.yaml
  
  [kubelet-start] Starting the kubelet
  [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
  
  This node has joined the cluster:
  * Certificate signing request was sent to apiserver and a response was received.
  * The Kubelet was informed of the new secure connection details.
  
  Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
  </code></pre>
  
  <p><strong>Node should join the cluster and will have a taint at startup time so pods not having  tolerance will not be scheduled on this new node</strong>.</p>
  
  <pre><code>ubuntu@k8s-master:~$ kubectl get nodes
  NAME         STATUS   ROLES    AGE     VERSION
  k8s-master   Ready    master   18m     v1.17.2
  k8s-node01   Ready    &lt;none&gt;   8m11s   v1.17.2
  </code></pre>
  
  <p><strong>Verify the taint as below</strong></p>
  
  <pre><code>$ kubectl describe node k8s-node01 | grep -i Taint
  
  Taints:             specialnode1.kubernetes.io/SpecialNode1:NoSchedule
  </code></pre>
  
  <p><strong>To further test this we will create a daemon set which will run on node01 and add another node02 with new taint , daemon set should not autoscale to new node with new taint</strong>.</p>
  
  <pre><code>ubuntu@k8s-master:~$ kubectl get nodes
  NAME         STATUS   ROLES    AGE   VERSION
  k8s-master   Ready    master   24m   v1.17.2
  k8s-node01   Ready    &lt;none&gt;   14m   v1.17.2
  
  
  ubuntu@k8s-master:~$ kubectl get all -o wide
  NAME              READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
  pod/nginx-npmz5   1/1     Running   0          50s   192.168.85.193   k8s-node01   &lt;none&gt;           &lt;none&gt;
  
  NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
  service/kubernetes   ClusterIP   10.96.0.1    &lt;none&gt;        443/TCP   24m   &lt;none&gt;
  
  NAME                   DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE   CONTAINERS   IMAGES   SELECTOR
  daemonset.apps/nginx   1         1         1       1            1           &lt;none&gt;          50s   nginx        nginx    app=nginx
  </code></pre>
  
  <p><strong>Add new Node with new config.yaml and verify the node is ready and taint is set on new node added to cluster</strong></p>
  
  <pre><code>apiVersion: kubeadm.k8s.io/v1beta1
      kind: JoinConfiguration
      discovery:
        bootstrapToken:
          apiServerEndpoint: "&lt;control_plain_ip&gt;:6443"
          token: "your_token"
          caCertHashes:
          - sha256:$CERT_HASH
      nodeRegistration:
        taints:
        - effect: NoSchedule
          key: specialnode2.kubernetes.io/SpecialNode2
  
  $ kubectl get nodes
  NAME         STATUS   ROLES    AGE   VERSION
  k8s-master   Ready    master   25m   v1.17.2
  k8s-node01   Ready    &lt;none&gt;   15m   v1.17.2
  k8s-node02   Ready    &lt;none&gt;   22s   v1.17.2
  </code></pre>
  
  <p><strong>Note the new taint on node02</strong></p>
  
  <pre><code>$ kubectl describe node k8s-node02 | grep -i Taint
  Taints:             specialnode2.kubernetes.io/SpecialNode2:NoSchedule
  </code></pre>
  
  <p><strong>Now check if daemon set has scaled to new node or not, it will not unless we remove the taint or add tolerance to daemonset</strong></p>
  
  <pre><code>$ kubectl get all -o wide
  NAME              READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
  pod/nginx-npmz5   1/1     Running   0          3m46s   192.168.85.193   k8s-node01   &lt;none&gt;           &lt;none&gt;
  
  NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
  service/kubernetes   ClusterIP   10.96.0.1    &lt;none&gt;        443/TCP   27m   &lt;none&gt;
  
  NAME                   DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE     CONTAINERS   IMAGES   SELECTOR
  daemonset.apps/nginx   1         1         1       1            1           &lt;none&gt;          3m46s   nginx        nginx    app=nginx
  </code></pre>
  
  <blockquote>
    <p><strong>So we can use above steps to add  a new node to a running cluster and choose what is scheduled on it using taints</strong>.</p>
  </blockquote>
  
Answers: CC BY-SA 4.0
Answers: 2020-02-05T09:37:27.330Z
Answers: 2020-02-05T11:43:51.547Z
Answers: 2020-02-05T11:43:51.547Z
Answers: DT.
Body: <p>Given a working Kubernetes cluster consisting of a master and some workers.</p>
  
  <p>We need to add a node to run a very specific pod and be part of the cluster for networking reasons. Then being largely ignored for later pod creation by the master.</p>
  
  <p>Adding selectors to every deployment to avoid this node is out of question.</p>
  
  <p>Thanks!</p>
  
Tags: <kubernetes><kubeadm>
Title: How to introduce(join) new worker node to an existing k8s cluster with selective scheduling only
UserDisplayName: RooSoft
ThreadText: # How to introduce(join) new worker node to an existing k8s cluster with selective scheduling only
  
  (Asked by: username_0 on 2020-02-04)
  
  Given a working Kubernetes cluster consisting of a master and some workers.
  
  We need to add a node to run a very specific pod and be part of the cluster for networking reasons. Then being largely ignored for later pod creation by the master.
  
  Adding selectors to every deployment to avoid this node is out of question.
  
  Thanks!
  
  **Tags:** kubernetes, kubeadm
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_1 on 2020-02-04. Score: 2 | Accepted answer
  
  Possibly you are looking for this [feature](https://github.com/kubernetes/kubeadm/issues/1392) which is closed with no action since there are ways to work around this problem.
  
  > kubeadm already allows to set taints for the joining node using the configuration file at join time (***check my other [answer](https://devops.stackexchange.com/a/10717/19264) for details on how to do that***)
  
  One Other way to achieve this is by running join as usual but taking few extra steps as below after join
  
  > 1) After successful join , **Force Drain the new node** to make sure it removes unwanted pod which might have scaled to it post join operation `kubectl drain <node name> --force`
  >
  > 2) **Drain command will auto cordon** off the node. (Note : also **consider special handling to remove any daemonset** which might have scaled to this node after join)
  >
  > 3) Now **Taint the new node** as needed **and then uncordon** it
  >
  > 4) **Add nodeselector plus tolerance to pods** you want to be scheduled on this new node.
  
  Logs of above steps for reference are listed below.
  
  On below example i have joined a new node-02 and assume that some pod were scaled in an existing deployment so new node got used immediately on join, so before adding we need drain action and then taint the node so going forward no scheduling can be done unless pod has tolerance to the taint added
  
  **Nodes Before Drain or Taint**
  
  ```
  $ kubectl get all -o wide
  NAME                         READY   STATUS    RESTARTS   AGE   IP               NODE                NOMINATED NODE   READINESS GATES
  pod/nginx-86c57db685-8cdkx   1/1     Running   0          27s   192.168.58.120   k8s-node02-calico   <none>           <none>
  pod/nginx-86c57db685-xnh6q   1/1     Running   0          65s   192.168.182.78   k8s-node01-calico   <none>           <none>
  
  NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
  service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   2d    <none>
  
  NAME                    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR
  deployment.apps/nginx   2/2     2            2           65s   nginx        nginx    app=nginx
  
  NAME                               DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES   SELECTOR
  replicaset.apps/nginx-86c57db685   2         2         2       65s   nginx        nginx    app=nginx,pod-template-hash=86c57db685
  
  ```
  
  **Drain The node**
  
  ```
  $ kubectl drain k8s-node02-calico
  node/k8s-node02-calico cordoned
  evicting pod "nginx-86c57db685-8cdkx"
  pod/nginx-86c57db685-8cdkx evicted
  node/k8s-node02-calico evicted
  
  $ kubectl get nodes
  NAME                STATUS                     ROLES    AGE   VERSION
  k8s-master-calico   Ready                      master   2d    v1.17.2
  k8s-node01-calico   Ready                      <none>   2d    v1.17.2
  k8s-node02-calico   Ready,SchedulingDisabled   <none>   2d    v1.17.2
  
  ```
  
  **Taint the new node**
  
  ```
  $ kubectl taint node k8s-node02-calico newnode=nobodyallowed:NoSchedule
  node/k8s-node02-calico tainted
  
  ```
  
  **Now we are good to uncordon the node, no more pods should be able to use this noe unless they add toleration to the new taint**.
  
  ```
  $ kubectl uncordon k8s-node02-calico
  node/k8s-node02-calico uncordoned
  
  $ kubectl get nodes
  NAME                STATUS   ROLES    AGE   VERSION
  k8s-master-calico   Ready    master   2d    v1.17.2
  k8s-node01-calico   Ready    <none>   2d    v1.17.2
  k8s-node02-calico   Ready    <none>   2d    v1.17.2
  
  ```
  
  **We test by scaling the deployment and nothign should be added on node02**
  
  ```
  $ kubectl scale deployment --replicas=3 nginx
  deployment.apps/nginx scaled
  
  $ kubectl get all -o wide
  NAME                         READY   STATUS    RESTARTS   AGE     IP               NODE                NOMINATED NODE   READINESS GATES
  pod/nginx-86c57db685-vm8ql   1/1     Running   0          3m30s   192.168.182.75   k8s-node01-calico   <none>           <none>
  pod/nginx-86c57db685-xnh6q   1/1     Running   0          10m     192.168.182.78   k8s-node01-calico   <none>           <none>
  pod/nginx-86c57db685-zh2sj   1/1     Running   0          8m19s   192.168.182.76   k8s-node01-calico   <none>           <none>
  
  NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
  service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   2d    <none>
  
  NAME                    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR
  deployment.apps/nginx   3/3     3            3           10m   nginx        nginx    app=nginx
  
  NAME                               DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES   SELECTOR
  replicaset.apps/nginx-86c57db685   3         3         3       10m   nginx        nginx    app=nginx,pod-template-hash=86c57db685
  
  ```
  
  > **Comments:**
  > **username_0**: I am speechless... this is the perfect answer, @DT. Thank you very much!  
  > **username_1**: in my view my second answer below is better approach because it will taint the node directly at join time so that not even a deamonset can come into your new space.  
  
  ---
  
  ### Answer by username_1 on 2020-02-05. Score: 1
  
  > **kubeadm already allows to set taints for the joining node using the configuration file at join time**.
  
  **Steps on how to do this at node join time are as below**
  
  Construct a **Config.yaml file with taint details and bootstrap details** as recived from master at kubeadm init time.
  
  **Example config.yaml** you should update values as per your cluster info on below
  
  ```
  apiVersion: kubeadm.k8s.io/v1beta1
  kind: JoinConfiguration
  discovery:
    bootstrapToken:
      apiServerEndpoint: "<control_plain_ip>:6443"
      token: "your_token"
      caCertHashes:
      - sha256:$CERT_HASH
  nodeRegistration:
    taints:
    - effect: NoSchedule
      key: specialnode1.kubernetes.io/SpecialNode1
  
  ```
  
  **Pass this config from node you want to join** it will join with a taint set at startup.
  
  ```
  root@k8s-node01:# kubeadm join --config=config.yaml
  
  [kubelet-start] Starting the kubelet
  [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
  
  This node has joined the cluster:
  * Certificate signing request was sent to apiserver and a response was received.
  * The Kubelet was informed of the new secure connection details.
  
  Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
  
  ```
  
  **Node should join the cluster and will have a taint at startup time so pods not having tolerance will not be scheduled on this new node**.
  
  ```
  ubuntu@k8s-master:~$ kubectl get nodes
  NAME         STATUS   ROLES    AGE     VERSION
  k8s-master   Ready    master   18m     v1.17.2
  k8s-node01   Ready    <none>   8m11s   v1.17.2
  
  ```
  
  **Verify the taint as below**
  
  ```
  $ kubectl describe node k8s-node01 | grep -i Taint
  
  Taints:             specialnode1.kubernetes.io/SpecialNode1:NoSchedule
  
  ```
  
  **To further test this we will create a daemon set which will run on node01 and add another node02 with new taint , daemon set should not autoscale to new node with new taint**.
  
  ```
  ubuntu@k8s-master:~$ kubectl get nodes
  NAME         STATUS   ROLES    AGE   VERSION
  k8s-master   Ready    master   24m   v1.17.2
  k8s-node01   Ready    <none>   14m   v1.17.2
  
  ubuntu@k8s-master:~$ kubectl get all -o wide
  NAME              READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
  pod/nginx-npmz5   1/1     Running   0          50s   192.168.85.193   k8s-node01   <none>           <none>
  
  NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
  service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   24m   <none>
  
  NAME                   DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE   CONTAINERS   IMAGES   SELECTOR
  daemonset.apps/nginx   1         1         1       1            1           <none>          50s   nginx        nginx    app=nginx
  
  ```
  
  **Add new Node with new config.yaml and verify the node is ready and taint is set on new node added to cluster**
  
  ```
  apiVersion: kubeadm.k8s.io/v1beta1
      kind: JoinConfiguration
      discovery:
        bootstrapToken:
          apiServerEndpoint: "<control_plain_ip>:6443"
          token: "your_token"
          caCertHashes:
          - sha256:$CERT_HASH
      nodeRegistration:
        taints:
        - effect: NoSchedule
          key: specialnode2.kubernetes.io/SpecialNode2
  
  $ kubectl get nodes
  NAME         STATUS   ROLES    AGE   VERSION
  k8s-master   Ready    master   25m   v1.17.2
  k8s-node01   Ready    <none>   15m   v1.17.2
  k8s-node02   Ready    <none>   22s   v1.17.2
  
  ```
  
  **Note the new taint on node02**
  
  ```
  $ kubectl describe node k8s-node02 | grep -i Taint
  Taints:             specialnode2.kubernetes.io/SpecialNode2:NoSchedule
  
  ```
  
  **Now check if daemon set has scaled to new node or not, it will not unless we remove the taint or add tolerance to daemonset**
  
  ```
  $ kubectl get all -o wide
  NAME              READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
  pod/nginx-npmz5   1/1     Running   0          3m46s   192.168.85.193   k8s-node01   <none>           <none>
  
  NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
  service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   27m   <none>
  
  NAME                   DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE     CONTAINERS   IMAGES   SELECTOR
  daemonset.apps/nginx   1         1         1       1            1           <none>          3m46s   nginx        nginx    app=nginx
  
  ```
  
  > **So we can use above steps to add a new node to a running cluster and choose what is scheduled on it using taints**.
  
  
  ---
  
  