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

refactor: the node convert/revert feature #206

Merged
merged 1 commit into from
Feb 8, 2021

Conversation

Peeknut
Copy link
Member

@Peeknut Peeknut commented Jan 27, 2021

Ⅰ. Describe what this PR does

1.Refactor the node convert/revert feature by golang.
2.Add subcommand yurtctl convert edgenode and yurtctl revert edgenode, so that single node could convert/revert Kubernetes edgenode to an Openyurt edgenode.

Ⅱ. Does this pull request fix one issue?

fixes #190

Ⅲ. List the added test cases (unit test/integration test) if any, please explain if no tests are needed.

Ⅳ. Describe how to verify it

make test
make build
cp _output/bin/yurtctl /bin/
yurtctl convert
yurtctl revert
yurtctl convert edgenode
yurtctl revert edgenode

Ⅴ. Special notes for reviews

@CLAassistant
Copy link

CLAassistant commented Jan 27, 2021

CLA assistant check
All committers have signed the CLA.

Copy link
Member

@charleszheng44 charleszheng44 left a comment

Choose a reason for hiding this comment

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

Thanks for submitting the PR! It looks good except for some minor issues. If these changes are applied, do we need to change the way of running yurtctl convert/revert? If so, would you also update the tutorial? Thanks!

@@ -1,4 +1 @@
FROM alpine:3.8
Copy link
Member

Choose a reason for hiding this comment

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

why use ubuntu instead of alpine?

Copy link
Member Author

Choose a reason for hiding this comment

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

When the pod Yurtctl-servant-convert runs the command nsenter -t 1 -m -u -n -i /bin/yurtctl convert edgenode --yurthub-image {{.yurthub_image}} --join-token {{.joinToken}} --pod-manifest-path {{.pod_manifest_path}} , command nsenter in alpine will parse --yurthub-image into the parameters of nsenter. It will not have this problem with ubuntu.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the explanation. Would you try nsenter -t 1 -m -u -n -i -- /bin/yurtctl convert edgenode --yurthub-image {{.yurthub_image}} --join-token {{.joinToken}} --pod-manifest-path {{.pod_manifest_path}} in alpine? Let's use '--' to tell nsenter to stop option parsing. As the size of the alpine is smaller than the ubuntu, using it can help us reduce the network throughput when setting up a large cluster.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks!I test it and it works!

openyurtDir string
}

func NewConvertEdgeNodeOptions() *ConvertEdgeNodeOptions {
Copy link
Member

Choose a reason for hiding this comment

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

Could you add GoDoc comment for the function and other exposed functions?

Copy link
Member Author

Choose a reason for hiding this comment

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

👌

},
}

cmd.Flags().String("join-token", "", "the join token.")
Copy link
Member

Choose a reason for hiding this comment

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

The token used by yurthub for joining the cluster.

@@ -0,0 +1,276 @@
package convert
Copy link
Member

Choose a reason for hiding this comment

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

Please add the license.

Copy link
Member Author

Choose a reason for hiding this comment

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

How to add the license? Make verify?

Copy link
Member

Choose a reason for hiding this comment

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

The OpenSource License : )

/*
Copyright 2021 The OpenYurt 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.
*/

@@ -0,0 +1,182 @@
package revert
Copy link
Member

Choose a reason for hiding this comment

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

Please add the license.

@@ -0,0 +1,76 @@
package edgenode
Copy link
Member

Choose a reason for hiding this comment

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

Please add the license.


// Exec run command and exit formatted error, callers can print err directly
// Any running error or non-zero exitcode is consider as error
func (cmd *Command) Exec() error {
Copy link
Member

Choose a reason for hiding this comment

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

why not use os/exec package?

Copy link
Member Author

Choose a reason for hiding this comment

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

The struct Command contains all the information about cmd running and can be used in other places. If wants to be simpler, os/exec can be uses here.

@@ -0,0 +1,105 @@
package edgenode
Copy link
Member

Choose a reason for hiding this comment

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

Please add the license.

}
if contents == nil {
return "", fmt.Errorf("no matching string %s in file %s", regularExpression, filename)
} else if len(contents) > 1 {
Copy link
Member

Choose a reason for hiding this comment

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

else if len(contents) > 1 {} => if len(contents) > 1 {}

var wg sync.WaitGroup
var servantJobTemplate string
Copy link
Member

Choose a reason for hiding this comment

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

servantJobTemplate := constants.ConvertServantJobTemplate
if !convert {
    servantJobTemplate = constants.RevertServantJobTemplate
}

return err
}
klog.Infof("found backup file %s, will use it to revert the node", kubeletSvcBk)
err = os.Rename(kubeletSvcBk, r.kubeletSvcPath)
Copy link
Member

Choose a reason for hiding this comment

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

maybe we need delete the converted kubeletSvcPath file before rename the backup file?

Copy link
Member Author

@Peeknut Peeknut Jan 27, 2021

Choose a reason for hiding this comment

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

The effect of os.Rename() is similar to mv, it will overwrite original file. So the converted kubeletSvcPath file will be deleted at the same time. : )

Copy link
Member

Choose a reason for hiding this comment

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

ok, i got it

- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
`
Copy link
Member

Choose a reason for hiding this comment

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

env STATIC_POD_PATH is missed

Copy link
Member Author

Choose a reason for hiding this comment

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

yurtctl convert provides the value of STATIC_POD_PATH:

if err = kubeutil.RunServantJobs(co.clientSet, map[string]string{
"provider": string(co.Provider),
"action": "convert",
"yurtctl_servant_image": co.YurctlServantImage,
"yurthub_image": co.YurhubImage,
"joinToken": joinToken,
"pod_manifest_path": co.PodMainfestPath,
}, edgeNodeNames, true);

however, yurtctl revert not provides it:

if err = kubeutil.RunServantJobs(ro.clientSet,
map[string]string{
"action": "revert",
"yurtctl_servant_image": ro.YurtctlServantImage,
},
edgeNodeNames, false);

so I delete the env STATIC_POD_PATH in RevertServantJobTemplate

Copy link
Member

Choose a reason for hiding this comment

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

yeah, must had missed STATIC_POD_PATH var for yurtctl revert command, how ablout add STATIC_POD_PATH for yurtctl revert cmd?

Copy link
Member Author

Choose a reason for hiding this comment

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

OK.

return content
}

func GetNodeName() (string, error) {
Copy link
Member

Choose a reason for hiding this comment

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

how about use env NODE_NAME in convert and revert command instead of new GetNodeName() function?

Copy link
Member Author

Choose a reason for hiding this comment

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

Does NODE_NAME refer to the env HOSTNAME?
If so, kubelet startup parameters --hostname-override can be used to configure the host name of the node displayed in the cluster, so the node name in cluster can be different from env HOSTNAME. And it need to get the node name in cluster accurately, because we need to get node resources through node name later.
So maybe it's better to use GetNodeName() function?

Copy link
Member

Choose a reason for hiding this comment

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

using NODE_NAME means we can add the following setting to the pod spec

...
env:
- name: NODE_NAME
  valueFrom:
    fieldRef:
      fieldPath: spec.nodeName
...

But yes, I think we should try to get the correct nodename from the service configuration directly, if --hostname-override can be used to overwrite the nodename.

Copy link
Member

Choose a reason for hiding this comment

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

@Peeknut as @charleszheng44 had said, env NODE_NAME is set in ServantJobTemplate by spec.nodeName field, so in spite of --hostname-override is set or not, we can get the node name accurately by env NODE_NAME .

Copy link
Member Author

Choose a reason for hiding this comment

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

That's right. For yurtctl convert/revert, we can directly use NODE_NAME. However, for directly calling yurtctl convert/revert edgenode, NODE_NAME may not be set, we need to read the configuration file to get it. Both approaches may be required. Maybe I should add steps to read env NODE_NAME in GetNodeName() function?

isEdgeNode, ok := node.Labels[projectinfo.GetEdgeWorkerLabelKey()]
if ok && isEdgeNode == "true" {
// 2.1. check the state of worker nodes
_, condition := nodeutil.GetNodeCondition(&node.Status, v1.NodeReady)
Copy link
Member

Choose a reason for hiding this comment

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

maybe we need add node ready status check at the begin of edgenode convert and revert command.

Copy link
Member Author

Choose a reason for hiding this comment

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

yurtctl revert has node ready status check at the beginning of the command.

yurctl revert edgenode also has node status check. Before node status check, checking the server version and getting node resource are necessary. Does the check time need to be changed?

Copy link
Member

Choose a reason for hiding this comment

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

We can check the node status before conversion/reversion, but the node can still fail when the conversion/reversion is ongoing. To eliminate this, we need to add a CRD/Controller to manage the OpenYurt cluster state, but that can be another new feature. I think we can keep the concurrent implementation just for now.

Copy link
Member

Choose a reason for hiding this comment

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

+1 keep the current implementation

@rambohe-ch
Copy link
Member

@Peeknut Please merge all commits in this pr(now has 3 commits) into one commit.

@Peeknut
Copy link
Member Author

Peeknut commented Jan 27, 2021

@Peeknut Please merge all commits in this pr(now has 3 commits) into one commit.

OK!

}
c.PodMainfestPath = podMainfestPath

c.clientSet, err = kubeutil.GenClientSet(flags)
Copy link

Choose a reason for hiding this comment

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

if there is no kubeconfig in all flag, KUBECONFIG, ~/.kube/config, it will return err.

@rambohe-ch , how about use /etc/kubernetes/kubelet.conf if err occurs? kubelet.conf has enougth authority to set label for current edge node.

Copy link
Member

Choose a reason for hiding this comment

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

+1 for using /etc/kubernetes/kubelet.conf as the default.

Copy link
Member

Choose a reason for hiding this comment

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

@GsssC how about use InClusterConfig at the edge node? plus add a serviceaccount and rabc for servant pod.

Copy link
Member Author

Choose a reason for hiding this comment

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

yurtctl convert/revert edgenode could be used directly on the single node. In this case, we can't use InClusterConfig at the edge node because it is not running in a pod environment. Maybe using /etc/kubernetes/kubelet.conf as the default is better?

@@ -0,0 +1,276 @@
package convert
Copy link
Member

Choose a reason for hiding this comment

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

The OpenSource License : )

/*
Copyright 2021 The OpenYurt 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.
*/

}
c.PodMainfestPath = podMainfestPath

c.clientSet, err = kubeutil.GenClientSet(flags)
Copy link
Member

Choose a reason for hiding this comment

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

+1 for using /etc/kubernetes/kubelet.conf as the default.

isEdgeNode, ok := node.Labels[projectinfo.GetEdgeWorkerLabelKey()]
if ok && isEdgeNode == "true" {
// 2.1. check the state of worker nodes
_, condition := nodeutil.GetNodeCondition(&node.Status, v1.NodeReady)
Copy link
Member

Choose a reason for hiding this comment

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

We can check the node status before conversion/reversion, but the node can still fail when the conversion/reversion is ongoing. To eliminate this, we need to add a CRD/Controller to manage the OpenYurt cluster state, but that can be another new feature. I think we can keep the concurrent implementation just for now.

return content
}

func GetNodeName() (string, error) {
Copy link
Member

Choose a reason for hiding this comment

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

using NODE_NAME means we can add the following setting to the pod spec

...
env:
- name: NODE_NAME
  valueFrom:
    fieldRef:
      fieldPath: spec.nodeName
...

But yes, I think we should try to get the correct nodename from the service configuration directly, if --hostname-override can be used to overwrite the nodename.

@Peeknut
Copy link
Member Author

Peeknut commented Jan 29, 2021

@rambohe-ch @charleszheng44 @GsssC
PTAL

func NewConvertEdgeNodeCmd() *cobra.Command {
c := NewConvertEdgeNodeOptions()
cmd := &cobra.Command{
Use: "edgenode",
Copy link
Member

Choose a reason for hiding this comment

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

i think we should specify node name for this subcommand, like yurtctl convert/revert edgenode node-name --xxx=xxx, so this subcommand can be worked at everywhere with kubeconfig.

Copy link
Member

Choose a reason for hiding this comment

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

And this subcommand can work only on the edge node that user want to convert or revert in current design, I think it's not user-friendly.

Copy link
Member

Choose a reason for hiding this comment

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

so this sub command can need run servant pod to exec convert or revert command.

@Peeknut
Copy link
Member Author

Peeknut commented Feb 2, 2021

PTAL @rambohe-ch @charleszheng44

}
}

// 2.2. check the state of worker nodes
Copy link
Member

Choose a reason for hiding this comment

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

not check worker nodes here, so how about check the state of EdgeNodes

Copy link
Member

Choose a reason for hiding this comment

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

+1 for EdgeNodes

Copy link
Member

@charleszheng44 charleszheng44 left a comment

Choose a reason for hiding this comment

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

LGTM

}
}

// 2.2. check the state of worker nodes
Copy link
Member

Choose a reason for hiding this comment

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

+1 for EdgeNodes

@rambohe-ch
Copy link
Member

LGTM

@rambohe-ch rambohe-ch merged commit 074711d into openyurtio:master Feb 8, 2021
@Peeknut Peeknut deleted the refactor branch February 25, 2021 11:36
MrGirl pushed a commit to MrGirl/openyurt that referenced this pull request Mar 29, 2022
refactor: the node convert/revert feature
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants