-
Notifications
You must be signed in to change notification settings - Fork 13
delete guest cluster nodes from Kubernetes API #484
Conversation
# Conflicts: # Gopkg.lock
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got successfully tested on gorgoth
.
@@ -93,6 +103,10 @@ | |||
name = "k8s.io/client-go" | |||
version = "kubernetes-1.9.3" | |||
|
|||
[[constraint]] | |||
branch = "release-1.9" | |||
name = "k8s.io/kubernetes" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to pin this. There was no other way I found to get the stupid deps right. This maybe improves again with the move to 1.10.4
.
K8sClient kubernetes.Interface | ||
K8sExtClient apiextensionsclient.Interface | ||
Logger micrologger.Logger | ||
CertsSearcher certs.Interface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is some refactoring because of the injection of the certs searcher. This is because different controllers need it.
if err != nil { | ||
return nil, microerror.Mask(err) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the latest resource package got introduced it was not properly wired. Doing this here to get going.
*controller.Controller | ||
} | ||
|
||
func NewDeleter(config DeleterConfig) (*Deleter, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the new deleter controller which does the job of the node controller which we remove now.
Watcher: config.G8sClient.ProviderV1alpha1().KVMConfigs(""), | ||
|
||
RateWait: informer.DefaultRateWait, | ||
ResyncPeriod: 30 * time.Second, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We check for nodes to be deleted every 30 seconds.
"github.com/giantswarm/kvm-operator/service/controller/v13/key" | ||
) | ||
|
||
func (r *Resource) EnsureCreated(ctx context.Context, obj interface{}) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here happens the magic.
// Fetch the list of pods running on the host cluster. These pods serve VMs | ||
// which in turn run the guest cluster nodes. We use the pods to compare them | ||
// against the guest cluster nodes below. | ||
var pods []corev1.Pod |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The old implementation was about some cloud provider interface. This effectively listed pods. Lots of boilerplate and complexity and indirection is gone now. We simply compare pods with nodes. This is better now.
var guestAPINotAvailableError = microerror.New("guest API not available") | ||
|
||
// IsGuestAPINotAvailable asserts guestAPINotAvailableError. | ||
func IsGuestAPINotAvailable(err error) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took this from cluster-operator
and extended it with the EOF checks. We should separate this and use the same mechanism everywhere. I can imagine the EOF errors are a thing in other places as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xh3b4sd Yes we need this logic in multiple places including helmclient. I've already created the repo but I got distracted by other things. I'll pick this up next.
// it and assume we are done. | ||
// informer's watch event is outdated and the pod got already deleted in | ||
// the Kubernetes API. This is a normal transition behaviour, so we just | ||
// ignore it and assume we are done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Boyscouting.
@@ -12,8 +15,6 @@ import ( | |||
"k8s.io/client-go/kubernetes" | |||
"k8s.io/client-go/rest" | |||
|
|||
"github.com/giantswarm/apiextensions/pkg/clientset/versioned" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Boyscouting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM,
one thing that are still to be covered is complex network thing described here.
giantswarm/kvm-operator-node-controller#5
I've fixed it by adding healthz endpoint and killing node-controller pod if there were errors connecting guest API. Problem is that k8sclient multiplexes multiple http connections thru one TCP connection and when TCP connection dead (but in established state), there is no way to force use new TCP connection.
See issues in client-go
kubernetes/client-go#342
kubernetes/client-go#374
As workaround, is it possible to kill go routine or reinitialize completely new instance of k8sclient if we detected errors?
return nil | ||
} | ||
|
||
func doesNodeExistAsPod(pods []corev1.Pod, n corev1.Node) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure how often we need this, but there is also second use case, when we want to clean up node. When pod is not in Running phase. this covers situations, when pod crashed or stuck in terminating for some reason.
https://github.com/giantswarm/kvm-operator-node-controller/blob/master/provider/instances.go#L70
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a test case for this? I ensured all two test cases you mentioned in the original issue are covered. Anyway, this support is super easy to add. Not here, but above in the loop where we already check for the ready condition. Thanks for the hint. I will add this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quite a big diff. In general looks good. One note about possibly missing resource cancellation.
if IsGuestAPINotAvailable(err) { | ||
r.logger.LogCtx(ctx, "level", "debug", "message", "guest cluster is not available") | ||
r.logger.LogCtx(ctx, "level", "debug", "message", "canceling resource for custom object") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is resource cancelling missing here or should the above log message be changed_
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Canceling works with the default resource by simply returning. The context cancelation has to be used with CRUD resources. This here is no CRUD resource. See also https://github.com/giantswarm/operatorkit/blob/master/docs/control_flow_primitives.md#default-resources.
I remember the case but couldn't see any issue in this direction while testing yesterday. What would be the test case for this so I could maybe play it through? Also note that the design here is slightly different. The k8s client for the guest clusters is created from scratch all the time. So far I couldn't figure a problem. We also work in different goroutines all the time but I am not sure how this would affect connection handling. Back then I was quite baffled about the problem we saw and I didn't have an explanation for it. Maybe the garbage collection changed or is differently applied now. |
I tested this successfully on |
If so than it should be fine. Problem was that client initialized only once in main routine. |
AFAIK the test case was killing master pod and then see if after killing the master pod the controller is still working and cleaning nodes. |
Towards giantswarm/kvm-operator-node-controller#2.