Outshift Logo

4 min read

Blog thumbnail
Published on 11/28/2017
Last updated on 02/05/2024

Nodes successfully joined, not!


Debug 101

Today we're starting a new series called Debug 101, which deals with those issues that gave us particularly bad headaches and took a large amount of time to debug, understand and fix. We believe strongly in open source software and open issue resolution, and we try to describe our problems and suggest fixes as we go, so you don't have to shave that yak. We already have, and they yak looks awesome.

Nodes successfully joined, not!

We use different cloud providers (typically Kubernetes-managed) to develop and launch workloads on Kubernetes. One of the E2E automated tests we run utilizes AWS EC2, wherein we install the Kubernetes cluster (using kubadm). Custom installations give us the flexibility of custom setups and profiles, and allow us to test Pipeline with different k8s versions. From time to time, we encountered strange behavior in the cluster - the foremost of which was that, although we started EC2 instances, they did not show up in the Kubernetes cluster. This issue occured sporadically and was undeterministic. After some test runs we identified a (potential) common source. Either the node instances in question were of a stronger instance variety, or the cluster size was particularly small (less than three or four nodes). Since we run our automated tests on spot price instances, and the pool is recommended by an internal tool/project (which we will open source soon), it's hard for us to know what our instance types will be beforehand (unless explicitely specified), since Hollowtrees determines this according to a variety of factors (rulesets, spot price history, price trend in the AZ, fleet diversity, etc). To cut to the chase, the problem is that, though master and node start in parallel, after some time the controller removes the node from the cluster. Here's the sequence of events:
  • Master starts sucessfully
  • Node starts and tries to join to the master: (kubeadm join --token ${TOKEN} ${MASTER})
  • Eventually, Node goes missing from the cluster node list (kubectl get node)
  • The logs on the Node say that it's successfully joined the Master
[bootstrap] The server supports the Certificates API (certificates.k8s.io/v1beta1)
    and the Node join is complete:
    * Certificate signing request is sent to master and response received.
    * Kubelet informed of new secure connection details.
  • The running kubectl get nodes on the Master register the machine as joined
  • We have now arrived at the kubectl event, which allows us see what's happening cronologically
1m 1m 1 ip-10-0-100-184.eu-west-1.compute.internal.14fb501a0ae334a3 Node Normal RegisteredNode controllermanager       Node ip-10-0-100-184.eu-west-1.compute.internal event: Registered Node ip-10-0-100-184.eu-west-1.compute.internal in Controller
1m 1m 1 ip-10-0-100-184.eu-west-1.compute.internal.14fb501a19555324 Node Normal DeletingNode   controllermanager       Node ip-10-0-100-184.eu-west-1.compute.internal event: Deleting Node ip-10-0-100-184.eu-west-1.compute.internal because it's not present according to cloud provider
1m 1m 1 ip-10-0-100-184.eu-west-1.compute.internal.14fb501b435fa741 Node Normal RemovingNode   controllermanager       Node ip-10-0-100-184.eu-west-1.compute.internal event: Removing Node ip-10-0-100-184.eu-west-1.compute.internal from Controller
1m 1m 1 ip-10-0-100-184.eu-west-1.compute.internal.14fb501c241eff24 Node Normal Starting       kubelet, ip-10-0-100-18
This can be paired down to Removing Node ip-10-0-100-184.eu-west-1.compute.internal from Controller. As you can see, once the controller loop calls the Amazon controller (realizes that the cluster is running on EC2), it removes the node immediately. If we dig a bit deeper into the code and annotate it back after introducing our changes, we have this PR. If the PR is operating correctly, the Amazon controller loop removes instances from the cluster if it thinks that the node is gone or no longer available. This is likely done so that the EC2 instance can die, removed as the result of spot price surgery or due to other communication issues which affect RAFT gossip. We've built Hollowtrees with the exact purpose of avoiding these kinds of problems in the cloud (subscribe to our social channels or check back next week for more on this and other topics). With a simple loop, this issue can actually be fixed.

until kubectl get node | grep $(hostname -f)
  kubeadm reset
  kubeadm join --token ${TOKEN} ${MASTER}
  echo "Waiting for Master to start up..."
  sleep 10

How it works

On the first check there is no kubeconfig configuration, so the initial join occurs. In the second iteration the credentials do not work from the first join, and it checks if the node has joined the cluster. If the node has not joined, it retries and repeats this process until the actual join happens. A successful join will look like this.
NAME                                         STATUS    ROLES     AGE       VERSION
ip-10-0-0-51.eu-west-1.compute.internal      Ready     master    4m        v1.8.3
ip-10-0-100-184.eu-west-1.compute.internal   Ready     <none>    3m        v1.8.3
Subscribe card background
Subscribe to
the Shift!

Get emerging insights on emerging technology straight to your inbox.

Unlocking Multi-Cloud Security: Panoptica's Graph-Based Approach

Discover why security teams rely on Panoptica's graph-based technology to navigate and prioritize risks across multi-cloud landscapes, enhancing accuracy and resilience in safeguarding diverse ecosystems.

the Shift
emerging insights
on emerging technology straight to your inbox.

The Shift keeps you at the forefront of cloud native modern applications, application security, generative AI, quantum computing, and other groundbreaking innovations that are shaping the future of technology.

Outshift Background