Skip to content

Commit

Permalink
Clean up auto-generated resources in leader and member clusters
Browse files Browse the repository at this point in the history
1. Split existing stale controller into leader and member folders.
2. The new stale controller in the leader cluster will do following things:
  * Check MemberClusterAnnounce periodically in the leader cluster and
    delete the stale CR if its last timestamp annotation `touch-ts` is over 24 hours.
  * Clean up all corresponding ResourceExports when a MemberClusterAnnounce is deleted.
  * Clean up stale ResourceExports if there is no existing MemberClusterAnnounce when
    the controller is started.
  * Clean up all MemberClusterAnnounces and corresponding ResourceExports when the controller
    is started with no ClusterSet CR.
3. The ClusterSet controller in leader will remove all remaining ResourceExports and
   MemberClusterAnnounces when the ClusterSet CR is deleted in the leader cluster.
4. The new stale controller in the member cluster will do following things:
  * Clean up any stale resources when the ClusterSet is ready.
  * Clean up any stale resources when the controller is restarted.
5. The ClusterSet controller will be responsible to remove all imported and exported
   resources for the member cluster when the ClusterSet CR is deleted.

Signed-off-by: Lan Luo <luola@vmware.com>
  • Loading branch information
luolanzone committed Oct 18, 2023
1 parent 62a440a commit 9b8d6f8
Show file tree
Hide file tree
Showing 22 changed files with 1,413 additions and 315 deletions.
73 changes: 71 additions & 2 deletions docs/multicluster/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,25 @@
- [Installation](#installation)
- [Preparation](#preparation)
- [Deploy Antrea Multi-cluster Controller](#deploy-antrea-multi-cluster-controller)
- [Deploy in a Dedicated Leader Cluster](#deploy-in-a-dedicated-leader-cluster)
- [Deploy in a Member Cluster](#deploy-in-a-member-cluster)
- [Deploy Leader and Member in One Cluster](#deploy-leader-and-member-in-one-cluster)
- [Create ClusterSet](#create-clusterset)
- [Set up Access to Leader Cluster](#set-up-access-to-leader-cluster)
- [Initialize ClusterSet](#initialize-clusterset)
- [Initialize ClusterSet for a Dual-role Cluster](#initialize-clusterset-for-a-dual-role-cluster)
- [Multi-cluster Gateway Configuration](#multi-cluster-gateway-configuration)
- [Multi-cluster WireGuard Encryption](#multi-cluster-wireguard-encryption)
- [Multi-cluster Service](#multi-cluster-service)
- [Multi-cluster Pod to Pod Connectivity](#multi-cluster-pod-to-pod-connectivity)
- [Multi-cluster Pod-to-Pod Connectivity](#multi-cluster-pod-to-pod-connectivity)
- [Multi-cluster NetworkPolicy](#multi-cluster-networkpolicy)
- [Egress Rule to Multi-cluster Services](#egress-rule-to-multi-cluster-service)
- [Egress Rule to Multi-cluster Service](#egress-rule-to-multi-cluster-service)
- [Ingress Rule](#ingress-rule)
- [ClusterNetworkPolicy Replication](#clusternetworkpolicy-replication)
- [Build Antrea Multi-cluster Controller Image](#build-antrea-multi-cluster-controller-image)
- [Uninstallation](#uninstallation)
- [Remove a Member Cluster](#remove-a-member-cluster)
- [Remove a Leader Cluster](#remove-a-leader-cluster)
- [Known Issue](#known-issue)
<!-- /toc -->

Expand Down Expand Up @@ -812,6 +821,66 @@ the image.
3. Copy the image file `antrea-mcs.tar` to the Nodes of your local cluster.
4. Run `docker load < antrea-mcs.tar` in each Node of your local cluster.

## Uninstallation

### Remove a Member Cluster

If you want to remove a member cluster from a ClusterSet and uninstall Antrea
Multi-cluster, please follow the following steps.

Note: please replace `kube-system` with the right Namespace in the example
commands and manifest if Antrea Multi-cluster is not deployed in
the default Namespace.

1. Delete all ServiceExports and the Multi-cluster Gateway annotation on the
Gateway Nodes.

2. Delete the ClusterSet CR. Antrea Multi-cluster Controller will be
responsible for cleaning up all resources created by itself automatically.

3. Delete the Antrea Multi-cluster Deployment:

```bash
kubectl delete -f https://github.com/antrea-io/antrea/releases/download/$TAG/antrea-multicluster-member.yml
```

### Remove a Leader Cluster

If you want to delete a ClusterSet and uninstall Antrea Multi-cluster in
a leader cluster, please follow the following steps. You should first
[remove all member clusters](#remove-a-member-cluster) before removing
a leader cluster from a ClusterSet.

Note: please replace `antrea-multicluster` with the right Namespace in the
following example commands and manifest if Antrea Multi-cluster is not
deployed in the default Namespace.

1. Delete AntreaClusterNetworkPolicy ResourceExports in the leader cluster.

2. Verify that there is no remaining MemberClusterAnnounces.

```bash
kubectl get memberclusterannounce -n antrea-multicluster
```

3. Delete the ClusterSet CR. Antrea Multi-cluster Controller will be
responsible for cleaning up all resources created by itself automatically.

4. Check there is no remaining ResourceExports and ResourceImports:

```bash
kubectl get resourceexports -n antrea-multicluster
kubectl get resourceimports -n antrea-multicluster
```

Note: you can follow the [Known Issue section](#known-issue) to delete the left-over ResourceExports.

5. Delete the Antrea Multi-cluster Deployment:

```bash
kubectl delete -f https://github.com/antrea-io/antrea/releases/download/$TAG/antrea-multicluster-leader.yml
```

## Known Issue

We recommend user to redeploy or update Antrea Multi-cluster Controller through
Expand Down
1 change: 0 additions & 1 deletion hack/.notableofcontents
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ docs/multicluster/architecture.md
docs/multicluster/policy-only-mode.md
docs/multicluster/quick-start.md
docs/multicluster/upgrade.md
docs/multicluster/user-guide.md
docs/network-requirements.md
docs/noencap-hybrid-modes.md
docs/octant-plugin-installation.md
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ import (

//+kubebuilder:webhook:path=/validate-multicluster-crd-antrea-io-v1alpha2-clusterset,mutating=false,failurePolicy=fail,sideEffects=None,groups=multicluster.crd.antrea.io,resources=clustersets,verbs=create;update;delete,versions=v1alpha2,name=vclusterset.kb.io,admissionReviewVersions={v1,v1beta1}

const (
mcControllerSAName = "antrea-mc-controller"
)

// ClusterSet validator
type clusterSetValidator struct {
Client client.Client
Expand Down
3 changes: 2 additions & 1 deletion multicluster/cmd/multicluster-controller/gateway_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import (
)

const (
antreaAgentSAName = "antrea-agent"
antreaAgentSAName = "antrea-agent"
mcControllerSAName = "antrea-mc-controller"
)

//+kubebuilder:webhook:path=/validate-multicluster-crd-antrea-io-v1alpha1-gateway,mutating=false,failurePolicy=fail,sideEffects=None,groups=multicluster.crd.antrea.io,resources=gateways,verbs=create;update,versions=v1alpha1,name=vgateway.kb.io,admissionReviewVersions={v1,v1beta1}
Expand Down
12 changes: 6 additions & 6 deletions multicluster/cmd/multicluster-controller/leader.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook"

multiclusterv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1"
multiclustercontrollers "antrea.io/antrea/multicluster/controllers/multicluster"
"antrea.io/antrea/multicluster/controllers/multicluster/leader"
"antrea.io/antrea/pkg/log"
"antrea.io/antrea/pkg/signals"
Expand Down Expand Up @@ -114,15 +113,16 @@ func runLeader(o *Options) error {
return fmt.Errorf("error creating ResourceExport webhook: %v", err)
}

staleController := multiclustercontrollers.NewStaleResCleanupController(
staleController := leader.NewLeaderStaleResCleanupController(
mgr.GetClient(),
mgr.GetScheme(),
env.GetPodNamespace(),
nil,
multiclustercontrollers.LeaderCluster,
)

go staleController.Run(stopCh)
if err = staleController.SetupWithManager(mgr, stopCh); err != nil {
return fmt.Errorf("error creating LeaderStaleResCleanupController: %v", err)
}
go staleController.RunPeriodically(stopCh)
go staleController.RunOnce(stopCh)

klog.InfoS("Leader MC Controller Starting Manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
Expand Down
2 changes: 2 additions & 0 deletions multicluster/cmd/multicluster-controller/leader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"k8s.io/client-go/rest"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/cache/informertest"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
"sigs.k8s.io/controller-runtime/pkg/webhook"
Expand Down Expand Up @@ -59,6 +60,7 @@ func initMockManager(mockManager *mocks.MockManager) {
mockManager.EXPECT().Start(gomock.Any()).Return(nil).AnyTimes()
mockManager.EXPECT().GetConfig().Return(&rest.Config{}).AnyTimes()
mockManager.EXPECT().GetRESTMapper().Return(&meta.DefaultRESTMapper{}).AnyTimes()
mockManager.EXPECT().GetFieldIndexer().Return(&informertest.FakeInformers{}).AnyTimes()
}

func TestRunLeader(t *testing.T) {
Expand Down
8 changes: 4 additions & 4 deletions multicluster/cmd/multicluster-controller/member.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"

multiclustercontrollers "antrea.io/antrea/multicluster/controllers/multicluster"
"antrea.io/antrea/multicluster/controllers/multicluster/member"
"antrea.io/antrea/pkg/log"
"antrea.io/antrea/pkg/signals"
Expand Down Expand Up @@ -122,14 +121,15 @@ func runMember(o *Options) error {
return fmt.Errorf("error creating Node controller: %v", err)
}

staleController := multiclustercontrollers.NewStaleResCleanupController(
staleController := member.NewMemberStaleResCleanupController(
mgr.GetClient(),
mgr.GetScheme(),
env.GetPodNamespace(),
commonAreaGetter,
multiclustercontrollers.MemberCluster,
)

if err = staleController.SetupWithManager(mgr); err != nil {
return fmt.Errorf("error creating MemberStaleResCleanupController: %v", err)
}
go staleController.Run(stopCh)
// Member runs ResourceImportReconciler from RemoteCommonArea only

Expand Down
4 changes: 2 additions & 2 deletions multicluster/cmd/multicluster-controller/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ func (o *Options) complete(args []string) error {
o.EndpointIPType = ctrlConfig.EndpointIPType
}
o.EnableStretchedNetworkPolicy = ctrlConfig.EnableStretchedNetworkPolicy
klog.InfoS("Using config from file", "config", o.options)
klog.InfoS("Using config from file", "config", o.configFile)
} else {
klog.InfoS("Using default config", "config", o.options)
klog.InfoS("Using default config")
}
return nil
}
Expand Down
172 changes: 172 additions & 0 deletions multicluster/controllers/multicluster/common/cleanup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
Copyright 2023 Antrea Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package common

import (
"context"
"reflect"

corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"
k8smcv1alpha1 "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1"

mcv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1"
mcv1alpha2 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha2"
crdv1beta1 "antrea.io/antrea/pkg/apis/crd/v1beta1"
)

var DeleteEventPredicate = predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
return false
},
UpdateFunc: func(e event.UpdateEvent) bool {
return false
},
}

var StatusReadyPredicate = func(e event.UpdateEvent) bool {
if e.ObjectOld == nil || e.ObjectNew == nil {
return false
}
oldClusterSet := e.ObjectOld.(*mcv1alpha2.ClusterSet)
newClusterSet := e.ObjectNew.(*mcv1alpha2.ClusterSet)
if !reflect.DeepEqual(oldClusterSet.Status.Conditions, newClusterSet.Status.Conditions) {
oldConditionSize := len(oldClusterSet.Status.Conditions)
newConditionSize := len(newClusterSet.Status.Conditions)
if oldConditionSize == 0 && newConditionSize > 0 && newClusterSet.Status.Conditions[0].Status == corev1.ConditionTrue {
return true
}
if oldConditionSize > 0 && newConditionSize > 0 &&
(oldClusterSet.Status.Conditions[0].Status == corev1.ConditionFalse || oldClusterSet.Status.Conditions[0].Status == corev1.ConditionUnknown) &&
newClusterSet.Status.Conditions[0].Status == corev1.ConditionTrue {
return true
}
}
return false
}

func CleanUpResourcesCreatedByMC(ctx context.Context, mgrClient client.Client) error {
var err error
if err = cleanUpMCServicesAndServiceImports(ctx, mgrClient); err != nil {
return err
}
if err = cleanUpReplicatedACNPs(ctx, mgrClient); err != nil {
return err
}
if err = cleanUpLabelIdentities(ctx, mgrClient); err != nil {
return err
}
if err = cleanUpClusterInfoImports(ctx, mgrClient); err != nil {
return err
}
if err = cleanUpGateways(ctx, mgrClient); err != nil {
return err
}
return nil
}

func cleanUpMCServicesAndServiceImports(ctx context.Context, mgrClient client.Client) error {
svcImpList := &k8smcv1alpha1.ServiceImportList{}
err := mgrClient.List(ctx, svcImpList, &client.ListOptions{})
if err != nil {
return err
}
for _, svcImp := range svcImpList.Items {
svcImpTmp := svcImp
mcsvc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Namespace: svcImp.Namespace,
Name: ToMCResourceName(svcImp.Name),
},
}
err = mgrClient.Delete(ctx, mcsvc, &client.DeleteOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return err
}
err = mgrClient.Delete(ctx, &svcImpTmp, &client.DeleteOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return err
}
}
return nil
}

func cleanUpReplicatedACNPs(ctx context.Context, mgrClient client.Client) error {
acnpList := &crdv1beta1.ClusterNetworkPolicyList{}
if err := mgrClient.List(ctx, acnpList, &client.ListOptions{}); err != nil {
return err
}
for _, acnp := range acnpList.Items {
acnpTmp := acnp
if metav1.HasAnnotation(acnp.ObjectMeta, AntreaMCACNPAnnotation) {
err := mgrClient.Delete(ctx, &acnpTmp, &client.DeleteOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return err
}
}
}
return nil
}

func cleanUpLabelIdentities(ctx context.Context, mgrClient client.Client) error {
labelIdentityList := &mcv1alpha1.LabelIdentityList{}
if err := mgrClient.List(ctx, labelIdentityList, &client.ListOptions{}); err != nil {
return err
}
for _, labelIdt := range labelIdentityList.Items {
labelIdtTmp := labelIdt
err := mgrClient.Delete(ctx, &labelIdtTmp, &client.DeleteOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return err
}
}
return nil
}

func cleanUpClusterInfoImports(ctx context.Context, mgrClient client.Client) error {
ciImpList := &mcv1alpha1.ClusterInfoImportList{}
if err := mgrClient.List(ctx, ciImpList, &client.ListOptions{}); err != nil {
return err
}
for _, ciImp := range ciImpList.Items {
ciImpTmp := ciImp
err := mgrClient.Delete(ctx, &ciImpTmp, &client.DeleteOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return err
}
}
return nil
}

func cleanUpGateways(ctx context.Context, mgrClient client.Client) error {
gwList := &mcv1alpha1.GatewayList{}
if err := mgrClient.List(ctx, gwList, &client.ListOptions{}); err != nil {
return err
}
for _, gw := range gwList.Items {
gwTmp := gw
err := mgrClient.Delete(ctx, &gwTmp, &client.DeleteOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return err
}
}
return nil
}
Loading

0 comments on commit 9b8d6f8

Please sign in to comment.