-
Notifications
You must be signed in to change notification settings - Fork 40.1k
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
kubeadm: Support custom env in control plane component #118867
Conversation
cc other members signed with the v1beta4. I tested this against v1beta3, and it works, set the
|
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.
thanks @chendave
added some comments
@@ -51,6 +53,9 @@ func TestGetStaticPodSpecs(t *testing.T) { | |||
// Creates a Cluster Configuration | |||
cfg := &kubeadmapi.ClusterConfiguration{ | |||
KubernetesVersion: "v1.9.0", | |||
Scheduler: kubeadmapi.ControlPlaneComponent{ExtraEnvs: []v1.EnvVar{ | |||
{Name: "Foo", Value: "Bar"}, |
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 should have override / de-dup tests
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 will be tested in cmd/kubeadm/app/util/env
package.
@@ -28,8 +28,10 @@ import ( | |||
"strings" | |||
"testing" | |||
|
|||
"github.com/google/go-cmp/cmp" |
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 already import reflect. maybe we can use it instead of the extra import of cmp
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.
Actually, I think we should move from the reflect.DeepEqual
to cmp.Diff
,
here is the context,
- https://pkg.go.dev/github.com/google/go-cmp/cmp
- Use go-cmp instead of reflect.DeepEqual stretchr/testify#535
I remember there is problem to compare two struct with embed struct when compare with reflect.DeepEqual
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.
reflect should be fine for slices, but i don't insist on not using cmp
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.
Gotcha, I will switch to reflect in the next iteration.
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.
@neolit123 have switched to reflect.
5df01d7
to
4b22b8b
Compare
cmd/kubeadm/app/util/env.go
Outdated
@@ -41,3 +41,17 @@ func GetProxyEnvVars() []v1.EnvVar { | |||
} | |||
return envs | |||
} | |||
|
|||
// MergedEnv merge the extraEnvs with proxyEnv, extraEnvs take precedence over the proxyEnv. |
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.
func should be called with a verb. MergeEnv
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.
it should be a generic, variadic argument function that takes a slice if env slices and makes the last slices override / take precedence.
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, pls let me know if the current version address your comment.
8bf3cb8
to
1f56b3d
Compare
|
||
if tc.env != nil { | ||
envs := []v1.EnvVar{} | ||
// Just compare the env that testcase set as the proxy env might be set an arbitrary value on the test node. |
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 must remove the "_proxy" env here, as the test node has the "no_proxy"env configured.
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 sounds like it needs refactor to not have tests that depend on the host env. i am talking without checking, but the host env could be passed only on actual runs / outside of tests.
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 am not sure if am following here, correct me pls, how the host env is set seems not matter here as we just need to make sure the env set in the clusterCfg is parsed correctly.
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.
you've mentioned "test node", which i understood as the host where the unit test is run.
we must remove the "_proxy" env here, as the test node has the "no_proxy"env configured.
where does the no_proxy env come from?
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.
@neolit123 pls see the test result without the tweak here: https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/118867/pull-kubernetes-unit/1673936678231740416
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.
seems to me we should refactor our test / tested function here not to get:
[{no_proxy 127.0.0.1,localhost nil}
if i am not mistaken these come from the host?
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.
yes, this comes from the host. I will leave a TODO here so that we can revisit it later if we have a better way to tackle it.
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 think we can fix it here as it's relatively simple.
- make GetStaticPodSpecs() accept a []v1.EnvVar called proxyEnvs
- if the slice is passed as nil populate it with GetProxyEnvVars() inside GetStaticPodSpecs() and use it in manifest construction
- if the slice is non-nil use its value instead of GetProxyEnvVars()
- then in this unit test just pass an empty slice
does it make sense to you?
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, thanks for the guidance!
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.
@pacoxu I replied all your comments, pls let me know is that make sense to you, thanks!
// - TODO https://github.com/kubernetes/kubeadm/issues/2890 | ||
// - Support custom environment variables in control plane components under `ClusterConfiguration`. | ||
// Use `APIServer.ExtraEnvs`, `ControllerManager.ExtraEnvs`, `Scheduler.ExtraEnvs`, `Etcd.Local.ExtraEnvs`. |
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.
look like to me addons are not the resource maintained by kubeadm. @neolit123 @SataQiu anything to comment here?
// Get the required hostpath mounts | ||
mounts := getHostPathVolumesForTheControlPlane(cfg) | ||
if proxyEnvs == nil { | ||
proxyEnvs = kubeadmutil.GetProxyEnvVars() | ||
} |
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 was discussed here: #118867 (comment), I am fine with either of them but a little in favor of the current approach (we cannot guarantee extraEnv is always the last env, and actually it's a slice and we cannot inspect easily how many envs the user sets), the original approach is filter the proxy env out, @neolit123 suggest me to remove the dep over the host.
}{ | ||
{ | ||
name: "normal case without duplicated env", | ||
proxyEnv: []v1.EnvVar{ |
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.
+1, this is just a testcase.
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: chendave, neolit123, pacoxu The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
@@ -262,6 +267,10 @@ type LocalEtcd struct { | |||
// command line except without leading dash(es). | |||
ExtraArgs map[string]string | |||
|
|||
// ExtraEnvs is an extra set of environment variables to pass to the control plane component. | |||
// +optional | |||
ExtraEnvs []v1.EnvVar |
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.
Comments are not updated. https://github.com/kubernetes/kubernetes/pull/118867/files#diff-a919b4d8ff1a3b03bb5691a0725e0683ff5e3fa4e12c4f81690ed46b156816d7R290 too,
Overall LGTM.
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.
@pacoxu this is etcd, there is no such proxy env passed to etcd compared with ControlPlaneComponent
, and we haven't overridden anything like what we do for ControlPlaneComponent
.
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.
/hold
please add it everywhere. doesn't matter if we skip proxy.
actually why are we not adding proxy envs to etcd? isn't that a bug?
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.
Generally etcd will not access outside, only peers should be accessed by etcd. And only local apiserver can access etcd.
For apiserver, it may access webhooks. Scheduler also can have webhook.
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.
hm, maybe a peer would not be able to reach a peer because of proxy.
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 no such a request for passing the proxy env so far, we can add it when there is a clear usecase, and this is not a API change, it will be easy to address then.
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.
added the comment for all the occurrences! @pacoxu @neolit123 looking for LGTM again.
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 sounds like a corner case that is nice to support😄. Either is OK with me for this point.
@pacoxu anything more to add? |
/lgtm |
LGTM label has been added. Git tree hash: 8fb2cfb6b573ae8592b2bd2197ea3903e389444e
|
Signed-off-by: Dave Chen <dave.chen@arm.com>
…nent Signed-off-by: Dave Chen <dave.chen@arm.com>
/lgtm |
LGTM label has been added. Git tree hash: 6c132e46b561d7c7442d9d2acb5e1b37749c0fc4
|
// ExtraEnvs is an extra set of environment variables to pass to the control plane component. | ||
// Environment variables passed using ExtraEnvs will override any existing environment variables, or *_proxy environment variables that kubeadm adds by default. | ||
// +optional | ||
ExtraEnvs []corev1.EnvVar `json:"extraEnvs,omitempty"` |
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 caused the import of apis/core/v1 in generated.defaults below.
Should we avoid that or how to avoid the defaulting logic?
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 already had this import:
https://github.com/chendave/kubernetes/blob/c68a6b07456301f6a8102c01e99ba8a53bc9bf4f/cmd/kubeadm/app/apis/kubeadm/v1beta4/types.go#L20
https://github.com/chendave/kubernetes/blob/c68a6b07456301f6a8102c01e99ba8a53bc9bf4f/cmd/kubeadm/app/apis/kubeadm/v1beta4/types.go#L226
https://github.com/chendave/kubernetes/blob/c68a6b07456301f6a8102c01e99ba8a53bc9bf4f/cmd/kubeadm/app/apis/kubeadm/v1beta4/types.go#L244
https://github.com/chendave/kubernetes/blob/c68a6b07456301f6a8102c01e99ba8a53bc9bf4f/cmd/kubeadm/app/apis/kubeadm/v1beta4/types.go#L441
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.
So this not results to the import
in generated_default.go?
https://github.com/kubernetes/kubernetes/pull/118867/files#r1321045615
@@ -23,6 +23,7 @@ package v1beta4 | |||
|
|||
import ( | |||
runtime "k8s.io/apimachinery/pkg/runtime" | |||
v1 "k8s.io/kubernetes/pkg/apis/core/v1" |
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.
As I tested, this is the key import that is related.
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.
We must drop this import
first.
In the past, we have made a lot of efforts to do this, and we cannot go back.
But I'm confused, why didn't the .import-restrictions prevent PRs from being merged?
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.
perhaps the import-boss tool is not running or buggy.
it can be tested with a simple PR for cmd/kubeadm or other packages that have an .import-restrictions file.
EDIT: i do remember a recent contributor PR that failed with an import restriction problem.
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 tested it locally, and it seems that the generated code(zz_generated.defaults.go
) won't be checked...
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.
It makes sense. So generated code are skipped for that import restrictions.
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 think code-gen here makes the decision poorly. it imports v1 "k8s.io/kubernetes/pkg/apis/core/v1"
so that it can call the defaulter v1.SetDefaults_ObjectFieldSelector
.
we have two options:
-
play around with our types to make code-gen not import defaulters.
seems to boil down toif a.ValueFrom != nil {
an alias might trick the defaulter tootype EnvVars []corev1.EnvVar
...has to be tested. -
ask #sig-api-machinery if we can patch code-gen to not import the defaulters under certain conditions.
maybe there is already+foo
directive for it, like+optional
.
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.
2. maybe there is already
+foo
directive for it, like+optional
.
~/go/src/k8s.io/kubernetes$ git diff
diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta4/defaults.go b/cmd/kubeadm/app/apis/kubeadm/v1beta4/defaults.go
index 314be0b30c7..38819c814f4 100644
--- a/cmd/kubeadm/app/apis/kubeadm/v1beta4/defaults.go
+++ b/cmd/kubeadm/app/apis/kubeadm/v1beta4/defaults.go
@@ -74,6 +74,7 @@ func SetDefaults_InitConfiguration(obj *InitConfiguration) {
}
// SetDefaults_ClusterConfiguration assigns default values for the ClusterConfiguration
+// +k8s:defaulter-gen=covers
func SetDefaults_ClusterConfiguration(obj *ClusterConfiguration) {
if obj.KubernetesVersion == "" {
obj.KubernetesVersion = DefaultKubernetesVersion
results in no import of k8s.io/kubernetes/pkg/api
, after running ./hack/update-codegen.sh
// An existing defaulter method (
SetDefaults_TYPE
) can provide the
// comment tag:
//
// // +k8s:defaulter-gen=covers
//
// to indicate that the defaulter does not or should not call any nested
// defaulters.
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.
result diff:
diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta4/zz_generated.defaults.go b/cmd/kubeadm/app/apis/kubeadm/v1beta4/zz_generated.defaults.go
index b36b0f0f952..d2409b0de6a 100644
--- a/cmd/kubeadm/app/apis/kubeadm/v1beta4/zz_generated.defaults.go
+++ b/cmd/kubeadm/app/apis/kubeadm/v1beta4/zz_generated.defaults.go
@@ -23,7 +23,6 @@ package v1beta4
import (
runtime "k8s.io/apimachinery/pkg/runtime"
- v1 "k8s.io/kubernetes/pkg/apis/core/v1"
)
// RegisterDefaults adds defaulters functions to the given scheme.
@@ -39,41 +38,6 @@ func RegisterDefaults(scheme *runtime.Scheme) error {
func SetObjectDefaults_ClusterConfiguration(in *ClusterConfiguration) {
SetDefaults_ClusterConfiguration(in)
- if in.Etcd.Local != nil {
- for i := range in.Etcd.Local.ExtraEnvs {
- a := &in.Etcd.Local.ExtraEnvs[i]
- if a.ValueFrom != nil {
- if a.ValueFrom.FieldRef != nil {
- v1.SetDefaults_ObjectFieldSelector(a.ValueFrom.FieldRef)
- }
- }
- }
- }
- SetDefaults_APIServer(&in.APIServer)
- for i := range in.APIServer.ControlPlaneComponent.ExtraEnvs {
- a := &in.APIServer.ControlPlaneComponent.ExtraEnvs[i]
- if a.ValueFrom != nil {
- if a.ValueFrom.FieldRef != nil {
- v1.SetDefaults_ObjectFieldSelector(a.ValueFrom.FieldRef)
- }
- }
- }
- for i := range in.ControllerManager.ExtraEnvs {
- a := &in.ControllerManager.ExtraEnvs[i]
- if a.ValueFrom != nil {
- if a.ValueFrom.FieldRef != nil {
- v1.SetDefaults_ObjectFieldSelector(a.ValueFrom.FieldRef)
- }
- }
- }
questions:
- would that be a problem for us in the future? probably no, because if we want a defaulter for some field in ClusterConfiguration we can explicitly call it in SetDefaults_ClusterConfiguration()
- can this missing defaulting for
a.ValueFrom.FieldRef
be a problem? i think no. it just sets that field selector to "v1", but technically the kube-apiserver must also do this defaulting when the mirror Pod (of the static pod) is created, right?
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.
okay, I like this approach, it's more neat to look!
/kind feature
What type of PR is this?
What this PR does / why we need it:
Which issue(s) this PR fixes:
xref: kubernetes/kubeadm#2890
Special notes for your reviewer:
Does this PR introduce a user-facing change?
Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.: