feat: support connect one namespace but proxy workload in another namespace (#496)

This commit is contained in:
naison
2025-03-30 11:50:11 +08:00
committed by GitHub
parent 08bcbe1611
commit a030dc582b
31 changed files with 545 additions and 615 deletions

View File

@@ -11,12 +11,13 @@ import (
func TestAddVirtualRule(t *testing.T) {
testdatas := []struct {
Rule []*controlplane.Virtual
Ports []controlplane.ContainerPort
Headers map[string]string
TunIP util.PodRouteConfig
Uid string
PortMap map[int32]string
Rule []*controlplane.Virtual
Ports []controlplane.ContainerPort
Headers map[string]string
TunIP util.PodRouteConfig
Uid string
Namespace string
PortMap map[int32]string
Expect []*controlplane.Virtual
}{
@@ -52,7 +53,7 @@ func TestAddVirtualRule(t *testing.T) {
},
}
for _, data := range testdatas {
rule := addVirtualRule(data.Rule, data.Uid, data.Ports, data.Headers, data.TunIP, nil)
rule := addVirtualRule(data.Rule, data.Namespace, data.Uid, data.Ports, data.Headers, data.TunIP, nil)
if !reflect.DeepEqual(rule, data.Expect) {
t.FailNow()
}

View File

@@ -28,7 +28,7 @@ import (
// InjectEnvoySidecar patch a sidecar, using iptables to do port-forward let this pod decide should go to 233.254.254.100 or request to 127.0.0.1
// https://istio.io/latest/docs/ops/deployment/requirements/#ports-used-by-istio
func InjectEnvoySidecar(ctx context.Context, f cmdutil.Factory, clientset *kubernetes.Clientset, namespace, workload string, object *runtimeresource.Info, headers map[string]string, portMap []string) (err error) {
func InjectEnvoySidecar(ctx context.Context, f cmdutil.Factory, clientset *kubernetes.Clientset, connectNamespace string, object *runtimeresource.Info, headers map[string]string, portMap []string) (err error) {
u := object.Object.(*unstructured.Unstructured)
var templateSpec *v1.PodTemplateSpec
var path []string
@@ -48,23 +48,23 @@ func InjectEnvoySidecar(ctx context.Context, f cmdutil.Factory, clientset *kuber
port[i].EnvoyListenerPort = int32(randomPort)
containerPort2EnvoyListenerPort[port[i].ContainerPort] = int32(randomPort)
}
err = addEnvoyConfig(clientset.CoreV1().ConfigMaps(namespace), nodeID, c, headers, port, portmap)
err = addEnvoyConfig(clientset.CoreV1().ConfigMaps(connectNamespace), object.Namespace, nodeID, c, headers, port, portmap)
if err != nil {
plog.G(ctx).Errorf("Failed to add envoy config: %v", err)
return err
}
workload := fmt.Sprintf("%s/%s", object.Mapping.Resource.Resource, object.Name)
// already inject container envoy-proxy, do nothing
containerNames := sets.New[string]()
for _, container := range templateSpec.Spec.Containers {
containerNames.Insert(container.Name)
}
if containerNames.HasAll(config.ContainerSidecarVPN, config.ContainerSidecarEnvoyProxy) {
plog.G(ctx).Infof("Workload %s/%s has already been injected with sidecar", namespace, workload)
plog.G(ctx).Infof("Workload %s/%s has already been injected with sidecar", object.Namespace, workload)
return
}
enableIPv6, _ := util.DetectPodSupportIPv6(ctx, f, namespace)
enableIPv6, _ := util.DetectPodSupportIPv6(ctx, f, connectNamespace)
// (1) add mesh container
AddEnvoyContainer(templateSpec, nodeID, enableIPv6)
helper := pkgresource.NewHelper(object.Client, object.Mapping)
@@ -86,13 +86,13 @@ func InjectEnvoySidecar(ctx context.Context, f cmdutil.Factory, clientset *kuber
return err
}
plog.G(ctx).Infof("Patching workload %s", workload)
err = util.RolloutStatus(ctx, f, namespace, workload, time.Minute*60)
err = util.RolloutStatus(ctx, f, object.Namespace, workload, time.Minute*60)
if err != nil {
return err
}
// 2) modify service containerPort to envoy listener port
err = ModifyServiceTargetPort(ctx, clientset, namespace, templateSpec.Labels, containerPort2EnvoyListenerPort)
err = ModifyServiceTargetPort(ctx, clientset, object.Namespace, templateSpec.Labels, containerPort2EnvoyListenerPort)
if err != nil {
return err
}

View File

@@ -31,7 +31,7 @@ import (
// https://istio.io/latest/docs/ops/deployment/requirements/#ports-used-by-istio
// InjectVPNAndEnvoySidecar patch a sidecar, using iptables to do port-forward let this pod decide should go to 233.254.254.100 or request to 127.0.0.1
func InjectVPNAndEnvoySidecar(ctx context.Context, f cmdutil.Factory, clientset v12.ConfigMapInterface, namespace, workload string, object *runtimeresource.Info, c util.PodRouteConfig, headers map[string]string, portMaps []string) (err error) {
func InjectVPNAndEnvoySidecar(ctx context.Context, f cmdutil.Factory, mapInterface v12.ConfigMapInterface, connectNamespace string, object *runtimeresource.Info, c util.PodRouteConfig, headers map[string]string, portMaps []string) (err error) {
u := object.Object.(*unstructured.Unstructured)
var templateSpec *v1.PodTemplateSpec
var path []string
@@ -72,23 +72,23 @@ func InjectVPNAndEnvoySidecar(ctx context.Context, f cmdutil.Factory, clientset
nodeID := fmt.Sprintf("%s.%s", object.Mapping.Resource.GroupResource().String(), object.Name)
err = addEnvoyConfig(clientset, nodeID, c, headers, ports, portmap)
err = addEnvoyConfig(mapInterface, object.Namespace, nodeID, c, headers, ports, portmap)
if err != nil {
plog.G(ctx).Errorf("Failed to add envoy config: %v", err)
return err
}
workload := fmt.Sprintf("%s/%s", object.Mapping.Resource.Resource, object.Name)
// already inject container vpn and envoy-proxy, do nothing
containerNames := sets.New[string]()
for _, container := range templateSpec.Spec.Containers {
containerNames.Insert(container.Name)
}
if containerNames.HasAll(config.ContainerSidecarVPN, config.ContainerSidecarEnvoyProxy) {
plog.G(ctx).Infof("Workload %s/%s has already been injected with sidecar", namespace, workload)
plog.G(ctx).Infof("Workload %s/%s has already been injected with sidecar", connectNamespace, workload)
return nil
}
enableIPv6, _ := util.DetectPodSupportIPv6(ctx, f, namespace)
enableIPv6, _ := util.DetectPodSupportIPv6(ctx, f, connectNamespace)
// (1) add mesh container
AddMeshContainer(templateSpec, nodeID, c, enableIPv6)
helper := pkgresource.NewHelper(object.Client, object.Mapping)
@@ -110,7 +110,7 @@ func InjectVPNAndEnvoySidecar(ctx context.Context, f cmdutil.Factory, clientset
return err
}
plog.G(ctx).Infof("Patching workload %s", workload)
err = util.RolloutStatus(ctx, f, namespace, workload, time.Minute*60)
err = util.RolloutStatus(ctx, f, object.Namespace, workload, time.Minute*60)
return err
}
@@ -125,7 +125,7 @@ func UnPatchContainer(ctx context.Context, factory cmdutil.Factory, mapInterface
nodeID := fmt.Sprintf("%s.%s", object.Mapping.Resource.GroupResource().String(), object.Name)
workload := util.ConvertUidToWorkload(nodeID)
var empty, found bool
empty, found, err = removeEnvoyConfig(mapInterface, nodeID, isMeFunc)
empty, found, err = removeEnvoyConfig(mapInterface, object.Namespace, nodeID, isMeFunc)
if err != nil {
plog.G(ctx).Errorf("Failed to remove envoy config: %v", err)
return false, err
@@ -173,7 +173,7 @@ func UnPatchContainer(ctx context.Context, factory cmdutil.Factory, mapInterface
return empty, err
}
func addEnvoyConfig(mapInterface v12.ConfigMapInterface, nodeID string, tunIP util.PodRouteConfig, headers map[string]string, port []controlplane.ContainerPort, portmap map[int32]string) error {
func addEnvoyConfig(mapInterface v12.ConfigMapInterface, ns, nodeID string, tunIP util.PodRouteConfig, headers map[string]string, port []controlplane.ContainerPort, portmap map[int32]string) error {
configMap, err := mapInterface.Get(context.Background(), config.ConfigMapPodTrafficManager, metav1.GetOptions{})
if err != nil {
return err
@@ -185,7 +185,7 @@ func addEnvoyConfig(mapInterface v12.ConfigMapInterface, nodeID string, tunIP ut
}
}
v = addVirtualRule(v, nodeID, port, headers, tunIP, portmap)
v = addVirtualRule(v, ns, nodeID, port, headers, tunIP, portmap)
marshal, err := yaml.Marshal(v)
if err != nil {
return err
@@ -195,10 +195,10 @@ func addEnvoyConfig(mapInterface v12.ConfigMapInterface, nodeID string, tunIP ut
return err
}
func addVirtualRule(v []*controlplane.Virtual, nodeID string, port []controlplane.ContainerPort, headers map[string]string, tunIP util.PodRouteConfig, portmap map[int32]string) []*controlplane.Virtual {
func addVirtualRule(v []*controlplane.Virtual, ns, nodeID string, port []controlplane.ContainerPort, headers map[string]string, tunIP util.PodRouteConfig, portmap map[int32]string) []*controlplane.Virtual {
var index = -1
for i, virtual := range v {
if nodeID == virtual.Uid {
if nodeID == virtual.Uid && virtual.Namespace == ns {
index = i
break
}
@@ -206,8 +206,9 @@ func addVirtualRule(v []*controlplane.Virtual, nodeID string, port []controlplan
// 1) if not found uid, means nobody proxying it, just add it
if index < 0 {
return append(v, &controlplane.Virtual{
Uid: nodeID,
Ports: port,
Uid: nodeID,
Namespace: ns,
Ports: port,
Rules: []*controlplane.Rule{{
Headers: headers,
LocalTunIPv4: tunIP.LocalTunIPv4,
@@ -258,7 +259,7 @@ func addVirtualRule(v []*controlplane.Virtual, nodeID string, port []controlplan
return v
}
func removeEnvoyConfig(mapInterface v12.ConfigMapInterface, nodeID string, isMeFunc func(isFargateMode bool, rule *controlplane.Rule) bool) (empty bool, found bool, err error) {
func removeEnvoyConfig(mapInterface v12.ConfigMapInterface, namespace string, nodeID string, isMeFunc func(isFargateMode bool, rule *controlplane.Rule) bool) (empty bool, found bool, err error) {
configMap, err := mapInterface.Get(context.Background(), config.ConfigMapPodTrafficManager, metav1.GetOptions{})
if k8serrors.IsNotFound(err) {
return true, false, nil
@@ -275,7 +276,7 @@ func removeEnvoyConfig(mapInterface v12.ConfigMapInterface, nodeID string, isMeF
return false, false, err
}
for _, virtual := range v {
if nodeID == virtual.Uid {
if nodeID == virtual.Uid && namespace == virtual.Namespace {
var isFargateMode bool
for _, port := range virtual.Ports {
if port.EnvoyListenerPort != 0 {
@@ -297,7 +298,7 @@ func removeEnvoyConfig(mapInterface v12.ConfigMapInterface, nodeID string, isMeF
// remove default
for i := 0; i < len(v); i++ {
if nodeID == v[i].Uid && len(v[i].Rules) == 0 {
if nodeID == v[i].Uid && namespace == v[i].Namespace && len(v[i].Rules) == 0 {
v = append(v[:i], v[i+1:]...)
i--
empty = true

View File

@@ -24,7 +24,7 @@ import (
util2 "github.com/wencaiwulue/kubevpn/v2/pkg/util"
)
func InjectVPNSidecar(ctx context.Context, f util.Factory, namespace, workload string, object *resource.Info, c util2.PodRouteConfig) error {
func InjectVPNSidecar(ctx context.Context, f util.Factory, connectNamespace string, object *resource.Info, c util2.PodRouteConfig) error {
u := object.Object.(*unstructured.Unstructured)
podTempSpec, path, err := util2.GetPodTemplateSpecPath(u)
@@ -45,7 +45,7 @@ func InjectVPNSidecar(ctx context.Context, f util.Factory, namespace, workload s
for _, port := range ports {
portmap[port.ContainerPort] = fmt.Sprintf("%d", port.ContainerPort)
}
err = addEnvoyConfig(clientset.CoreV1().ConfigMaps(namespace), nodeID, c, nil, controlplane.ConvertContainerPort(ports...), portmap)
err = addEnvoyConfig(clientset.CoreV1().ConfigMaps(connectNamespace), object.Namespace, nodeID, c, nil, controlplane.ConvertContainerPort(ports...), portmap)
if err != nil {
plog.G(ctx).Errorf("Failed to add envoy config: %v", err)
return err
@@ -53,10 +53,11 @@ func InjectVPNSidecar(ctx context.Context, f util.Factory, namespace, workload s
AddContainer(&podTempSpec.Spec, c)
workload := fmt.Sprintf("%s/%s", object.Mapping.Resource.Resource, object.Name)
helper := resource.NewHelper(object.Client, object.Mapping)
// pods without controller
if len(path) == 0 {
plog.G(ctx).Infof("Workload %s/%s is not controlled by any controller", namespace, workload)
plog.G(ctx).Infof("Workload %s is not controlled by any controller", workload)
p := &v1.Pod{ObjectMeta: podTempSpec.ObjectMeta, Spec: podTempSpec.Spec}
CleanupUselessInfo(p)
if err = CreateAfterDeletePod(ctx, f, p, helper); err != nil {
@@ -80,7 +81,7 @@ func InjectVPNSidecar(ctx context.Context, f util.Factory, namespace, workload s
return err
}
}
err = util2.RolloutStatus(ctx, f, namespace, workload, time.Minute*60)
err = util2.RolloutStatus(ctx, f, object.Namespace, workload, time.Minute*60)
return err
}