-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
V1.32.0+k3s1 #11478
V1.32.0+k3s1 #11478
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
ARG GOLANG=golang:1.22.9-alpine3.19 | ||
ARG GOLANG=golang:1.23.3-alpine3.20 | ||
FROM ${GOLANG} AS infra | ||
|
||
ARG http_proxy | ||
|
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,10 +9,12 @@ import ( | |
goruntime "runtime" | ||
"strings" | ||
|
||
"github.com/k3s-io/k3s/pkg/agent/util" | ||
agentutil "github.com/k3s-io/k3s/pkg/agent/util" | ||
"github.com/k3s-io/k3s/pkg/daemons/config" | ||
"github.com/k3s-io/k3s/pkg/util" | ||
"github.com/pkg/errors" | ||
"github.com/sirupsen/logrus" | ||
authorizationv1 "k8s.io/api/authorization/v1" | ||
v1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/fields" | ||
|
@@ -64,9 +66,22 @@ func Prepare(ctx context.Context, nodeConfig *config.Node) error { | |
return createFlannelConf(nodeConfig) | ||
} | ||
|
||
func Run(ctx context.Context, nodeConfig *config.Node, nodes typedcorev1.NodeInterface) error { | ||
func Run(ctx context.Context, nodeConfig *config.Node) error { | ||
logrus.Infof("Starting flannel with backend %s", nodeConfig.FlannelBackend) | ||
if err := waitForPodCIDR(ctx, nodeConfig.AgentConfig.NodeName, nodes); err != nil { | ||
|
||
if err := util.WaitForRBACReady(ctx, nodeConfig.AgentConfig.KubeConfigK3sController, util.DefaultAPIServerReadyTimeout, authorizationv1.ResourceAttributes{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This avoids having flannel spam the log with errors while we wait for the RBAC manifest to be applied. |
||
Verb: "list", | ||
Resource: "nodes", | ||
}, ""); err != nil { | ||
return errors.Wrap(err, "flannel failed to wait for RBAC") | ||
} | ||
|
||
coreClient, err := util.GetClientSet(nodeConfig.AgentConfig.KubeConfigK3sController) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if err := waitForPodCIDR(ctx, nodeConfig.AgentConfig.NodeName, coreClient.CoreV1().Nodes()); err != nil { | ||
return errors.Wrap(err, "flannel failed to wait for PodCIDR assignment") | ||
} | ||
|
||
|
@@ -75,7 +90,7 @@ func Run(ctx context.Context, nodeConfig *config.Node, nodes typedcorev1.NodeInt | |
return errors.Wrap(err, "failed to check netMode for flannel") | ||
} | ||
go func() { | ||
err := flannel(ctx, nodeConfig.FlannelIface, nodeConfig.FlannelConfFile, nodeConfig.AgentConfig.KubeConfigKubelet, nodeConfig.FlannelIPv6Masq, netMode) | ||
err := flannel(ctx, nodeConfig.FlannelIface, nodeConfig.FlannelConfFile, nodeConfig.AgentConfig.KubeConfigK3sController, nodeConfig.FlannelIPv6Masq, netMode) | ||
if err != nil && !errors.Is(err, context.Canceled) { | ||
logrus.Errorf("flannel exited: %v", err) | ||
os.Exit(1) | ||
|
@@ -123,7 +138,7 @@ func createCNIConf(dir string, nodeConfig *config.Node) error { | |
|
||
if nodeConfig.AgentConfig.FlannelCniConfFile != "" { | ||
logrus.Debugf("Using %s as the flannel CNI conf", nodeConfig.AgentConfig.FlannelCniConfFile) | ||
return util.CopyFile(nodeConfig.AgentConfig.FlannelCniConfFile, p, false) | ||
return agentutil.CopyFile(nodeConfig.AgentConfig.FlannelCniConfFile, p, false) | ||
} | ||
|
||
cniConfJSON := cniConf | ||
|
@@ -138,7 +153,7 @@ func createCNIConf(dir string, nodeConfig *config.Node) error { | |
cniConfJSON = strings.ReplaceAll(cniConfJSON, "%SERVICE_CIDR%", nodeConfig.AgentConfig.ServiceCIDR.String()) | ||
} | ||
|
||
return util.WriteFile(p, cniConfJSON) | ||
return agentutil.WriteFile(p, cniConfJSON) | ||
} | ||
|
||
func createFlannelConf(nodeConfig *config.Node) error { | ||
|
@@ -235,7 +250,7 @@ func createFlannelConf(nodeConfig *config.Node) error { | |
confJSON = strings.ReplaceAll(confJSON, "%backend%", backendConf) | ||
|
||
logrus.Debugf("The flannel configuration is %s", confJSON) | ||
return util.WriteFile(nodeConfig.FlannelConfFile, confJSON) | ||
return agentutil.WriteFile(nodeConfig.FlannelConfFile, confJSON) | ||
} | ||
|
||
// fundNetMode returns the mode (ipv4, ipv6 or dual-stack) in which flannel is operating | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,14 @@ import ( | |
"github.com/pkg/errors" | ||
"github.com/sirupsen/logrus" | ||
authorizationv1 "k8s.io/api/authorization/v1" | ||
v1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
k8sruntime "k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/watch" | ||
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" | ||
"k8s.io/client-go/tools/cache" | ||
toolswatch "k8s.io/client-go/tools/watch" | ||
cloudproviderapi "k8s.io/cloud-provider/api" | ||
logsapi "k8s.io/component-base/logs/api/v1" | ||
"k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" | ||
"k8s.io/kubernetes/pkg/registry/core/node" | ||
|
@@ -157,8 +164,36 @@ func scheduler(ctx context.Context, cfg *config.Control) error { | |
|
||
args := config.GetArgs(argsMap, cfg.ExtraSchedulerAPIArgs) | ||
|
||
schedulerNodeReady := make(chan struct{}) | ||
|
||
go func() { | ||
defer close(schedulerNodeReady) | ||
|
||
apiReadyLoop: | ||
for { | ||
select { | ||
case <-ctx.Done(): | ||
return | ||
case <-cfg.Runtime.APIServerReady: | ||
break apiReadyLoop | ||
case <-time.After(30 * time.Second): | ||
logrus.Infof("Waiting for API server to become available to start kube-scheduler") | ||
} | ||
} | ||
|
||
// If we're running the embedded cloud controller, wait for it to untaint at least one | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved this here from |
||
// node (usually, the local node) before starting the scheduler to ensure that it | ||
// finds a node that is ready to run pods during its initial scheduling loop. | ||
if !cfg.DisableCCM { | ||
logrus.Infof("Waiting for untainted node") | ||
if err := waitForUntaintedNode(ctx, runtime.KubeConfigScheduler); err != nil { | ||
logrus.Fatalf("failed to wait for untained node: %v", err) | ||
} | ||
} | ||
}() | ||
|
||
logrus.Infof("Running kube-scheduler %s", config.ArgString(args)) | ||
return executor.Scheduler(ctx, cfg.Runtime.APIServerReady, args) | ||
return executor.Scheduler(ctx, schedulerNodeReady, args) | ||
} | ||
|
||
func apiServer(ctx context.Context, cfg *config.Control) error { | ||
|
@@ -323,7 +358,6 @@ func cloudControllerManager(ctx context.Context, cfg *config.Control) error { | |
"authentication-kubeconfig": runtime.KubeConfigCloudController, | ||
"node-status-update-frequency": "1m0s", | ||
"bind-address": cfg.Loopback(false), | ||
"feature-gates": "CloudDualStackNodeIPs=true", | ||
} | ||
if cfg.NoLeaderElect { | ||
argsMap["leader-elect"] = "false" | ||
|
@@ -359,7 +393,7 @@ func cloudControllerManager(ctx context.Context, cfg *config.Control) error { | |
case <-cfg.Runtime.APIServerReady: | ||
break apiReadyLoop | ||
case <-time.After(30 * time.Second): | ||
logrus.Infof("Waiting for API server to become available") | ||
logrus.Infof("Waiting for API server to become available to start cloud-controller-manager") | ||
} | ||
} | ||
|
||
|
@@ -449,3 +483,50 @@ func promise(f func() error) <-chan error { | |
}() | ||
return c | ||
} | ||
|
||
// waitForUntaintedNode watches nodes, waiting to find one not tainted as | ||
// uninitialized by the external cloud provider. | ||
func waitForUntaintedNode(ctx context.Context, kubeConfig string) error { | ||
|
||
restConfig, err := util.GetRESTConfig(kubeConfig) | ||
if err != nil { | ||
return err | ||
} | ||
coreClient, err := typedcorev1.NewForConfig(restConfig) | ||
if err != nil { | ||
return err | ||
} | ||
nodes := coreClient.Nodes() | ||
|
||
lw := &cache.ListWatch{ | ||
ListFunc: func(options metav1.ListOptions) (object k8sruntime.Object, e error) { | ||
return nodes.List(ctx, options) | ||
}, | ||
WatchFunc: func(options metav1.ListOptions) (i watch.Interface, e error) { | ||
return nodes.Watch(ctx, options) | ||
}, | ||
} | ||
|
||
condition := func(ev watch.Event) (bool, error) { | ||
if node, ok := ev.Object.(*v1.Node); ok { | ||
return getCloudTaint(node.Spec.Taints) == nil, nil | ||
} | ||
return false, errors.New("event object not of type v1.Node") | ||
} | ||
|
||
if _, err := toolswatch.UntilWithSync(ctx, lw, &v1.Node{}, nil, condition); err != nil { | ||
return errors.Wrap(err, "failed to wait for untainted node") | ||
} | ||
return nil | ||
} | ||
|
||
// getCloudTaint returns the external cloud provider taint, if present. | ||
// Cribbed from k8s.io/cloud-provider/controllers/node/node_controller.go | ||
func getCloudTaint(taints []v1.Taint) *v1.Taint { | ||
for _, taint := range taints { | ||
if taint.Key == cloudproviderapi.TaintExternalCloudProvider { | ||
return &taint | ||
} | ||
} | ||
return nil | ||
} |
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 matches the RBAC from upstream flannel: https://github.com/flannel-io/flannel/blob/master/chart/kube-flannel/templates/rbac.yaml#L6-L21
I'm not super stoked on all agents being able to patch each others status, but it seems like this is how flannel works at the moment.