mirror of
https://github.com/rancher/k3k.git
synced 2026-08-23 22:36:17 +00:00
Mirror host nodes (#389)
* mirror host nodes Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * add mirror host nodes feature Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * Add controllername to secrets/configmap syncer Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * golint Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * wsl Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * wsl Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * wsl Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * build docs Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * setting controller namespace env Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * fix typo Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * Add a controller_namespace env to the test Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * fix tests Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * fix tests Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * Add mirrorHostNodes spec to conformance tests Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * Fixes Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * Fixes Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * fixes Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * wsl Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * change the ptr int to int Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * fix map key name Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> --------- Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/registry/core/service/portallocator"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
)
|
||||
|
||||
const (
|
||||
kubeletPortRangeConfigMapName = "k3k-kubelet-port-range"
|
||||
webhookPortRangeConfigMapName = "k3k-webhook-port-range"
|
||||
)
|
||||
|
||||
type PortAllocator struct {
|
||||
KubeletCM *v1.ConfigMap
|
||||
WebhookCM *v1.ConfigMap
|
||||
}
|
||||
|
||||
func NewPortAllocator(ctx context.Context, client ctrlruntimeclient.Client, kubeletPortRange, webhookPortRange string) (*PortAllocator, error) {
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
log.Info("starting port allocator")
|
||||
|
||||
var kubeletPortRangeCM, webhookPortRangeCM v1.ConfigMap
|
||||
|
||||
portRangeConfigMapNamespace := os.Getenv("CONTROLLER_NAMESPACE")
|
||||
if portRangeConfigMapNamespace == "" {
|
||||
return nil, fmt.Errorf("failed to find k3k controller namespace")
|
||||
}
|
||||
|
||||
kubeletPortRangeCM.Name = kubeletPortRangeConfigMapName
|
||||
kubeletPortRangeCM.Namespace = portRangeConfigMapNamespace
|
||||
|
||||
webhookPortRangeCM.Name = webhookPortRangeConfigMapName
|
||||
webhookPortRangeCM.Namespace = portRangeConfigMapNamespace
|
||||
|
||||
return &PortAllocator{
|
||||
KubeletCM: &kubeletPortRangeCM,
|
||||
WebhookCM: &webhookPortRangeCM,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *PortAllocator) InitPortAllocatorConfig(ctx context.Context, client ctrlruntimeclient.Client, kubeletPortRange, webhookPortRange string) manager.Runnable {
|
||||
return manager.RunnableFunc(func(ctx context.Context) error {
|
||||
if err := a.getOrCreate(ctx, client, a.KubeletCM, kubeletPortRange); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := a.getOrCreate(ctx, client, a.WebhookCM, webhookPortRange); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (a *PortAllocator) cm(name, namespace, portRange string) *v1.ConfigMap {
|
||||
return &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Data: map[string]string{
|
||||
"range": portRange,
|
||||
"allocatedPorts": "",
|
||||
},
|
||||
BinaryData: map[string][]byte{
|
||||
"snapshotData": []byte(""),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (a *PortAllocator) getOrCreate(ctx context.Context, client ctrlruntimeclient.Client, configmap *v1.ConfigMap, portRange string) error {
|
||||
nn := types.NamespacedName{
|
||||
Name: configmap.Name,
|
||||
Namespace: configmap.Namespace,
|
||||
}
|
||||
if err := client.Get(ctx, nn, configmap); err != nil {
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// creating the configMap for the first time
|
||||
configmap = a.cm(configmap.Name, configmap.Namespace, portRange)
|
||||
if err := client.Create(ctx, configmap); err != nil {
|
||||
return fmt.Errorf("failed to create port range configmap: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *PortAllocator) AllocateWebhookPort(ctx context.Context, cfg *Config) (int, error) {
|
||||
return a.allocatePort(ctx, cfg, a.WebhookCM)
|
||||
}
|
||||
|
||||
func (a *PortAllocator) DeallocateWebhookPort(ctx context.Context, client ctrlruntimeclient.Client, clusterName, clusterNamespace string, webhookPort int) error {
|
||||
return a.deallocatePort(ctx, client, clusterName, clusterNamespace, a.WebhookCM, webhookPort)
|
||||
}
|
||||
|
||||
func (a *PortAllocator) AllocateKubeletPort(ctx context.Context, cfg *Config) (int, error) {
|
||||
return a.allocatePort(ctx, cfg, a.KubeletCM)
|
||||
}
|
||||
|
||||
func (a *PortAllocator) DeallocateKubeletPort(ctx context.Context, client ctrlruntimeclient.Client, clusterName, clusterNamespace string, kubeletPort int) error {
|
||||
return a.deallocatePort(ctx, client, clusterName, clusterNamespace, a.KubeletCM, kubeletPort)
|
||||
}
|
||||
|
||||
// allocatePort will assign port to the cluster from a port Range configured for k3k
|
||||
func (a *PortAllocator) allocatePort(ctx context.Context, cfg *Config, configMap *v1.ConfigMap) (int, error) {
|
||||
portRange, ok := configMap.Data["range"]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("port range is not initialized")
|
||||
}
|
||||
// get configMap first to avoid conflicts
|
||||
if err := a.getOrCreate(ctx, cfg.client, configMap, portRange); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
clusterNamespaceName := cfg.cluster.Namespace + "/" + cfg.cluster.Name
|
||||
|
||||
portsMap, err := parsePortMap(configMap.Data["allocatedPorts"])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if _, ok := portsMap[clusterNamespaceName]; ok {
|
||||
return portsMap[clusterNamespaceName], nil
|
||||
}
|
||||
// allocate a new port and save the snapshot
|
||||
snapshot := core.RangeAllocation{
|
||||
Range: configMap.Data["range"],
|
||||
Data: configMap.BinaryData["snapshotData"],
|
||||
}
|
||||
|
||||
pa, err := portallocator.NewFromSnapshot(&snapshot)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
next, err := pa.AllocateNext()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
portsMap[clusterNamespaceName] = next
|
||||
|
||||
if err := saveSnapshot(pa, &snapshot, configMap, portsMap); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := cfg.client.Update(ctx, configMap); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return next, nil
|
||||
}
|
||||
|
||||
// deallocatePort will remove the port used by the cluster from the port range
|
||||
func (a *PortAllocator) deallocatePort(ctx context.Context, client ctrlruntimeclient.Client, clusterName, clusterNamespace string, configMap *v1.ConfigMap, port int) error {
|
||||
portRange, ok := configMap.Data["range"]
|
||||
if !ok {
|
||||
return fmt.Errorf("port range is not initialized")
|
||||
}
|
||||
|
||||
if err := a.getOrCreate(ctx, client, configMap, portRange); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clusterNamespaceName := clusterNamespace + "/" + clusterName
|
||||
|
||||
portsMap, err := parsePortMap(configMap.Data["allocatedPorts"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// check if the cluster already exists in the configMap
|
||||
if usedPort, ok := portsMap[clusterNamespaceName]; ok {
|
||||
if usedPort != port {
|
||||
return fmt.Errorf("port %d does not match used port %d for the cluster", port, usedPort)
|
||||
}
|
||||
|
||||
snapshot := core.RangeAllocation{
|
||||
Range: configMap.Data["range"],
|
||||
Data: configMap.BinaryData["snapshotData"],
|
||||
}
|
||||
|
||||
pa, err := portallocator.NewFromSnapshot(&snapshot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := pa.Release(port); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
delete(portsMap, clusterNamespaceName)
|
||||
|
||||
if err := saveSnapshot(pa, &snapshot, configMap, portsMap); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return client.Update(ctx, configMap)
|
||||
}
|
||||
|
||||
// parsePortMap will convert ConfigMap Data to a portMap of string keys and values of ints
|
||||
func parsePortMap(portMapData string) (map[string]int, error) {
|
||||
portMap := make(map[string]int)
|
||||
if err := yaml.Unmarshal([]byte(portMapData), &portMap); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse allocatedPorts: %w", err)
|
||||
}
|
||||
|
||||
return portMap, nil
|
||||
}
|
||||
|
||||
// serializePortMap will convert a portMap of string keys and values of ints to ConfigMap Data
|
||||
func serializePortMap(m map[string]int) (string, error) {
|
||||
out, err := yaml.Marshal(m)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to serialize allocatedPorts: %w", err)
|
||||
}
|
||||
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
func saveSnapshot(portAllocator *portallocator.PortAllocator, snapshot *core.RangeAllocation, configMap *v1.ConfigMap, portsMap map[string]int) error {
|
||||
// save the new snapshot
|
||||
if err := portAllocator.Snapshot(snapshot); err != nil {
|
||||
return err
|
||||
}
|
||||
// update the configmap with the new portsMap and the new snapshot
|
||||
configMap.BinaryData["snapshotData"] = snapshot.Data
|
||||
configMap.Data["range"] = snapshot.Range
|
||||
|
||||
allocatedPortsData, err := serializePortMap(portsMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configMap.Data["allocatedPorts"] = allocatedPortsData
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -34,15 +34,19 @@ type SharedAgent struct {
|
||||
image string
|
||||
imagePullPolicy string
|
||||
token string
|
||||
kubeletPort int
|
||||
webhookPort int
|
||||
}
|
||||
|
||||
func NewSharedAgent(config *Config, serviceIP, image, imagePullPolicy, token string) *SharedAgent {
|
||||
func NewSharedAgent(config *Config, serviceIP, image, imagePullPolicy, token string, kubeletPort, webhookPort int) *SharedAgent {
|
||||
return &SharedAgent{
|
||||
Config: config,
|
||||
serviceIP: serviceIP,
|
||||
image: image,
|
||||
imagePullPolicy: imagePullPolicy,
|
||||
token: token,
|
||||
kubeletPort: kubeletPort,
|
||||
webhookPort: webhookPort,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +76,7 @@ func (s *SharedAgent) ensureObject(ctx context.Context, obj ctrlruntimeclient.Ob
|
||||
}
|
||||
|
||||
func (s *SharedAgent) config(ctx context.Context) error {
|
||||
config := sharedAgentData(s.cluster, s.Name(), s.token, s.serviceIP)
|
||||
config := sharedAgentData(s.cluster, s.Name(), s.token, s.serviceIP, s.kubeletPort, s.webhookPort)
|
||||
|
||||
configSecret := &v1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
@@ -91,7 +95,7 @@ func (s *SharedAgent) config(ctx context.Context) error {
|
||||
return s.ensureObject(ctx, configSecret)
|
||||
}
|
||||
|
||||
func sharedAgentData(cluster *v1alpha1.Cluster, serviceName, token, ip string) string {
|
||||
func sharedAgentData(cluster *v1alpha1.Cluster, serviceName, token, ip string, kubeletPort, webhookPort int) string {
|
||||
version := cluster.Spec.Version
|
||||
if cluster.Spec.Version == "" {
|
||||
version = cluster.Status.HostVersion
|
||||
@@ -101,9 +105,12 @@ func sharedAgentData(cluster *v1alpha1.Cluster, serviceName, token, ip string) s
|
||||
clusterNamespace: %s
|
||||
serverIP: %s
|
||||
serviceName: %s
|
||||
token: %s
|
||||
version: %s`,
|
||||
cluster.Name, cluster.Namespace, ip, serviceName, token, version)
|
||||
token: %v
|
||||
mirrorHostNodes: %t
|
||||
version: %s
|
||||
webhookPort: %d
|
||||
kubeletPort: %d`,
|
||||
cluster.Name, cluster.Namespace, ip, serviceName, token, cluster.Spec.MirrorHostNodes, version, webhookPort, kubeletPort)
|
||||
}
|
||||
|
||||
func (s *SharedAgent) daemonset(ctx context.Context) error {
|
||||
@@ -140,7 +147,17 @@ func (s *SharedAgent) daemonset(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (s *SharedAgent) podSpec() v1.PodSpec {
|
||||
hostNetwork := false
|
||||
dnsPolicy := v1.DNSClusterFirst
|
||||
|
||||
if s.cluster.Spec.MirrorHostNodes {
|
||||
hostNetwork = true
|
||||
dnsPolicy = v1.DNSClusterFirstWithHostNet
|
||||
}
|
||||
|
||||
return v1.PodSpec{
|
||||
HostNetwork: hostNetwork,
|
||||
DNSPolicy: dnsPolicy,
|
||||
ServiceAccountName: s.Name(),
|
||||
NodeSelector: s.cluster.Spec.NodeSelector,
|
||||
Volumes: []v1.Volume{
|
||||
@@ -203,6 +220,15 @@ func (s *SharedAgent) podSpec() v1.PodSpec {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "POD_IP",
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
FieldRef: &v1.ObjectFieldSelector{
|
||||
APIVersion: "v1",
|
||||
FieldPath: "status.podIP",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, s.cluster.Spec.AgentEnvs...),
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
@@ -217,10 +243,15 @@ func (s *SharedAgent) podSpec() v1.PodSpec {
|
||||
},
|
||||
},
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
Name: "kubelet-port",
|
||||
Protocol: v1.ProtocolTCP,
|
||||
ContainerPort: int32(s.kubeletPort),
|
||||
},
|
||||
{
|
||||
Name: "webhook-port",
|
||||
Protocol: v1.ProtocolTCP,
|
||||
ContainerPort: 9443,
|
||||
ContainerPort: int32(s.webhookPort),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -249,13 +280,13 @@ func (s *SharedAgent) service(ctx context.Context) error {
|
||||
{
|
||||
Name: "k3s-kubelet-port",
|
||||
Protocol: v1.ProtocolTCP,
|
||||
Port: 10250,
|
||||
Port: int32(s.kubeletPort),
|
||||
},
|
||||
{
|
||||
Name: "webhook-server",
|
||||
Protocol: v1.ProtocolTCP,
|
||||
Port: 9443,
|
||||
TargetPort: intstr.FromInt32(9443),
|
||||
Port: int32(s.webhookPort),
|
||||
TargetPort: intstr.FromInt32(int32(s.webhookPort)),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,6 +14,8 @@ func Test_sharedAgentData(t *testing.T) {
|
||||
cluster *v1alpha1.Cluster
|
||||
serviceName string
|
||||
ip string
|
||||
kubeletPort int
|
||||
webhookPort int
|
||||
token string
|
||||
}
|
||||
|
||||
@@ -34,6 +36,8 @@ func Test_sharedAgentData(t *testing.T) {
|
||||
Version: "v1.2.3",
|
||||
},
|
||||
},
|
||||
kubeletPort: 10250,
|
||||
webhookPort: 9443,
|
||||
ip: "10.0.0.21",
|
||||
serviceName: "service-name",
|
||||
token: "dnjklsdjnksd892389238",
|
||||
@@ -45,6 +49,9 @@ func Test_sharedAgentData(t *testing.T) {
|
||||
"serviceName": "service-name",
|
||||
"token": "dnjklsdjnksd892389238",
|
||||
"version": "v1.2.3",
|
||||
"mirrorHostNodes": "false",
|
||||
"kubeletPort": "10250",
|
||||
"webhookPort": "9443",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -63,6 +70,8 @@ func Test_sharedAgentData(t *testing.T) {
|
||||
},
|
||||
},
|
||||
ip: "10.0.0.21",
|
||||
kubeletPort: 10250,
|
||||
webhookPort: 9443,
|
||||
serviceName: "service-name",
|
||||
token: "dnjklsdjnksd892389238",
|
||||
},
|
||||
@@ -73,6 +82,9 @@ func Test_sharedAgentData(t *testing.T) {
|
||||
"serviceName": "service-name",
|
||||
"token": "dnjklsdjnksd892389238",
|
||||
"version": "v1.2.3",
|
||||
"mirrorHostNodes": "false",
|
||||
"kubeletPort": "10250",
|
||||
"webhookPort": "9443",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -87,6 +99,8 @@ func Test_sharedAgentData(t *testing.T) {
|
||||
HostVersion: "v1.3.3",
|
||||
},
|
||||
},
|
||||
kubeletPort: 10250,
|
||||
webhookPort: 9443,
|
||||
ip: "10.0.0.21",
|
||||
serviceName: "service-name",
|
||||
token: "dnjklsdjnksd892389238",
|
||||
@@ -98,13 +112,16 @@ func Test_sharedAgentData(t *testing.T) {
|
||||
"serviceName": "service-name",
|
||||
"token": "dnjklsdjnksd892389238",
|
||||
"version": "v1.3.3",
|
||||
"mirrorHostNodes": "false",
|
||||
"kubeletPort": "10250",
|
||||
"webhookPort": "9443",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
config := sharedAgentData(tt.args.cluster, tt.args.serviceName, tt.args.token, tt.args.ip)
|
||||
config := sharedAgentData(tt.args.cluster, tt.args.serviceName, tt.args.token, tt.args.ip, tt.args.kubeletPort, tt.args.webhookPort)
|
||||
|
||||
data := make(map[string]string)
|
||||
err := yaml.Unmarshal([]byte(config), data)
|
||||
|
||||
@@ -64,10 +64,11 @@ type ClusterReconciler struct {
|
||||
SharedAgentImagePullPolicy string
|
||||
K3SImage string
|
||||
K3SImagePullPolicy string
|
||||
PortAllocator *agent.PortAllocator
|
||||
}
|
||||
|
||||
// Add adds a new controller to the manager
|
||||
func Add(ctx context.Context, mgr manager.Manager, sharedAgentImage, sharedAgentImagePullPolicy string, k3SImage string, k3SImagePullPolicy string) error {
|
||||
func Add(ctx context.Context, mgr manager.Manager, sharedAgentImage, sharedAgentImagePullPolicy, k3SImage string, k3SImagePullPolicy string, kubeletPortRange, webhookPortRange string) error {
|
||||
discoveryClient, err := discovery.NewDiscoveryClientForConfig(mgr.GetConfig())
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -77,6 +78,11 @@ func Add(ctx context.Context, mgr manager.Manager, sharedAgentImage, sharedAgent
|
||||
return errors.New("missing shared agent image")
|
||||
}
|
||||
|
||||
portAllocator, err := agent.NewPortAllocator(ctx, mgr.GetClient(), kubeletPortRange, webhookPortRange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// initialize a new Reconciler
|
||||
reconciler := ClusterReconciler{
|
||||
DiscoveryClient: discoveryClient,
|
||||
@@ -86,6 +92,11 @@ func Add(ctx context.Context, mgr manager.Manager, sharedAgentImage, sharedAgent
|
||||
SharedAgentImagePullPolicy: sharedAgentImagePullPolicy,
|
||||
K3SImage: k3SImage,
|
||||
K3SImagePullPolicy: k3SImagePullPolicy,
|
||||
PortAllocator: portAllocator,
|
||||
}
|
||||
|
||||
if err := mgr.Add(portAllocator.InitPortAllocatorConfig(ctx, mgr.GetClient(), kubeletPortRange, webhookPortRange)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
@@ -148,7 +159,7 @@ func (c *ClusterReconciler) Reconcile(ctx context.Context, req reconcile.Request
|
||||
}
|
||||
|
||||
// add finalizers
|
||||
if !controllerutil.AddFinalizer(&cluster, clusterFinalizerName) {
|
||||
if controllerutil.AddFinalizer(&cluster, clusterFinalizerName) {
|
||||
if err := c.Client.Update(ctx, &cluster); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
@@ -603,7 +614,7 @@ func (c *ClusterReconciler) server(ctx context.Context, cluster *v1alpha1.Cluste
|
||||
}
|
||||
|
||||
func (c *ClusterReconciler) bindClusterRoles(ctx context.Context, cluster *v1alpha1.Cluster) error {
|
||||
clusterRoles := []string{"k3k-node-proxy", "k3k-priorityclass"}
|
||||
clusterRoles := []string{"k3k-kubelet-node", "k3k-priorityclass"}
|
||||
|
||||
var err error
|
||||
|
||||
@@ -639,7 +650,29 @@ func (c *ClusterReconciler) ensureAgent(ctx context.Context, cluster *v1alpha1.C
|
||||
if cluster.Spec.Mode == agent.VirtualNodeMode {
|
||||
agentEnsurer = agent.NewVirtualAgent(config, serviceIP, token, c.K3SImage, c.K3SImagePullPolicy)
|
||||
} else {
|
||||
agentEnsurer = agent.NewSharedAgent(config, serviceIP, c.SharedAgentImage, c.SharedAgentImagePullPolicy, token)
|
||||
// Assign port from pool if shared agent enabled mirroring of host nodes
|
||||
kubeletPort := 10250
|
||||
webhookPort := 9443
|
||||
|
||||
if cluster.Spec.MirrorHostNodes {
|
||||
var err error
|
||||
|
||||
kubeletPort, err = c.PortAllocator.AllocateKubeletPort(ctx, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cluster.Status.KubeletPort = kubeletPort
|
||||
|
||||
webhookPort, err = c.PortAllocator.AllocateWebhookPort(ctx, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cluster.Status.WebhookPort = webhookPort
|
||||
}
|
||||
|
||||
agentEnsurer = agent.NewSharedAgent(config, serviceIP, c.SharedAgentImage, c.SharedAgentImagePullPolicy, token, kubeletPort, webhookPort)
|
||||
}
|
||||
|
||||
return agentEnsurer.EnsureResources(ctx)
|
||||
|
||||
@@ -47,6 +47,19 @@ func (c *ClusterReconciler) finalizeCluster(ctx context.Context, cluster v1alpha
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Dellaocate ports for kubelet and webhook if used
|
||||
if cluster.Spec.Mode == v1alpha1.SharedClusterMode && cluster.Spec.MirrorHostNodes {
|
||||
log.Info("dellocating ports for kubelet and webhook")
|
||||
|
||||
if err := c.PortAllocator.DeallocateKubeletPort(ctx, c.Client, cluster.Name, cluster.Namespace, cluster.Status.KubeletPort); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
if err := c.PortAllocator.DeallocateWebhookPort(ctx, c.Client, cluster.Name, cluster.Namespace, cluster.Status.WebhookPort); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if controllerutil.ContainsFinalizer(&cluster, clusterFinalizerName) {
|
||||
// remove finalizer from the cluster and update it.
|
||||
controllerutil.RemoveFinalizer(&cluster, clusterFinalizerName)
|
||||
@@ -60,7 +73,7 @@ func (c *ClusterReconciler) finalizeCluster(ctx context.Context, cluster v1alpha
|
||||
}
|
||||
|
||||
func (c *ClusterReconciler) unbindClusterRoles(ctx context.Context, cluster *v1alpha1.Cluster) error {
|
||||
clusterRoles := []string{"k3k-node-proxy", "k3k-priorityclass"}
|
||||
clusterRoles := []string{"k3k-kubelet-node", "k3k-priorityclass"}
|
||||
|
||||
var err error
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package cluster_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
@@ -44,6 +45,10 @@ var _ = BeforeSuite(func() {
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "charts", "k3k", "crds")},
|
||||
ErrorIfCRDPathMissing: true,
|
||||
}
|
||||
|
||||
// setting controller namespace env to activate port range allocator
|
||||
os.Setenv("CONTROLLER_NAMESPACE", "default")
|
||||
|
||||
cfg, err := testEnv.Start()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
@@ -60,7 +65,7 @@ var _ = BeforeSuite(func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
ctx, cancel = context.WithCancel(context.Background())
|
||||
err = cluster.Add(ctx, mgr, "rancher/k3k-kubelet:latest", "", "rancher/k3s", "")
|
||||
err = cluster.Add(ctx, mgr, "rancher/k3k-kubelet:latest", "", "rancher/k3s", "", "50000-51000", "51001-52000")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
go func() {
|
||||
|
||||
Reference in New Issue
Block a user