Skip to content

Commit

Permalink
WIP kindnet 0.6
Browse files Browse the repository at this point in the history
  • Loading branch information
aojea committed Aug 23, 2019
1 parent 75f8961 commit 3205861
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 78 deletions.
28 changes: 20 additions & 8 deletions cmd/kindnetd/cni.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,32 @@ import (

// CNIConfigInputs is supplied to the CNI config template
type CNIConfigInputs struct {
PodCIDR string
DefaultRoute string
PodCIDRs []string
DefaultRoutes []string
}

// ComputeCNIConfigInputs computes the template inputs for CNIConfigWriter
func ComputeCNIConfigInputs(node corev1.Node) CNIConfigInputs {
podCIDR := node.Spec.PodCIDR
defaultRoute := "0.0.0.0/0"
if net.IsIPv6CIDRString(podCIDR) {
defaultRoute = "::/0"

defaultRoutes := []string{"0.0.0.0/0", "::/0"}
// check if is a dual-stack cluster
if len(node.Spec.PodCIDRs) > 1 {
return CNIConfigInputs{
PodCIDRs: node.Spec.PodCIDRs,
DefaultRoutes: defaultRoutes,
}
}
// the cluster is single stack
// we use the legacy node.Spec.PodCIDR for backwards compatibility
podCIDRs := []string{"node.Spec.PodCIDR"}
// This is a single stack cluster
defaultRoute := defaultRoutes[:1]
if net.IsIPv6CIDRString(podCIDRs[0]) {
defaultRoute := defaultRoutes[1:]
}
return CNIConfigInputs{
PodCIDR: podCIDR,
DefaultRoute: defaultRoute,
PodCIDRs: podCIDRs,
DefaultRoutes: defaultRoute,
}
}

Expand Down
40 changes: 33 additions & 7 deletions cmd/kindnetd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,25 @@ import (
// input envs:
// - HOST_IP: hould be populated by downward API
// - POD_IP: should be populated by downward API
// - POD_IPS: should be populated by downward API (only with dual-stack clusters)
// - CNI_CONFIG_TEMPLATE: the cni .conflist template, run with {{ .PodCIDR }}

// TODO: improve logging & error handling

// IPFamily defines kindnet networking operating model
type IPFamily string

const (
// IPv4Family sets IPFamily to ipv4
IPv4Family IPFamily = "ipv4"
// IPv6Family sets IPFamily to ipv6
IPv6Family IPFamily = "ipv6"
// DualStackFamily sets ClusterIPFamily to dual-stack
DualStackFamily IPFamily = "dual-stack"
)

func main() {

// create a Kubernetes client
config, err := rest.InClusterConfig()
if err != nil {
Expand All @@ -52,25 +66,36 @@ func main() {
}

// obtain the host and pod ip addresses
// if both ips are different we are not using the host network
hostIP, podIP := os.Getenv("HOST_IP"), os.Getenv("POD_IP")
// if both ips are different we are not using the host network
fmt.Printf("hostIP = %s\npodIP = %s\n", hostIP, podIP)
if hostIP != podIP {
panic(fmt.Sprintf(
"hostIP(= %q) != podIP(= %q) but must be running with host network: ",
hostIP, podIP,
))
}
// obtain all pod ip addresses if they exist
podIPs := strings.Split(os.Getenv("POD_IPS"),",")
// detect the cluster IP family
if len(podIPs) > 1 && net.IsDualStackIPStrings(podIPs) {
ipFamily := DualStackFamily
} else if net.IsIPv6String(podIP) {
ipFamily := IPv6Family
} else {
ipFamily := IPv4Family
}


// used to track if the cni config inputs changed and write the config
cniConfigWriter := &CNIConfigWriter{
path: cniConfigPath,
}

// enforce ip masquerade rules
// TODO: dual stack...?
masqAgent, _ := NewIPMasqAgent(
net.IsIPv6String(hostIP),
noMasqSubnets := getNoMasqueradeSubnets(clientset)
masqAgentIPv4, _ := NewIPMasqAgent(
false,
getNoMasqueradeSubnets(clientset),
)
go func() {
Expand Down Expand Up @@ -155,11 +180,12 @@ func makeNodesReconciler(cniConfig *CNIConfigWriter, hostIP string) func(*corev1
}

// internalIP returns the internalIP address for node
func internalIP(node corev1.Node) string {
func internalIP(node corev1.Node) []string] {
var ips []string
for _, address := range node.Status.Addresses {
if address.Type == "InternalIP" {
return address.Address
ips = append(ips, address.Address)
}
}
return ""
return ips
}
110 changes: 55 additions & 55 deletions cmd/kindnetd/subnets.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,87 +18,87 @@ package main

import (
"os"
"strings"
"regexp"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/kubernetes"
)

const (
kubeadmClusterCIDRRegex = `\s*podSubnet: (.*)\n`
kubeproxyClusterCIDRRegex = `\s*clusterCIDR: (.*)\n`
)

type subnets struct {
pods sets.String
services sets.String
type kubeSubnets struct {
regex string
configmap string
namespace string
}

func newSubnets() *subnets {
return &subnets{
pods: sets.NewString(),
services: sets.NewString(),
func newKubeSubnets(regex, configmap, namespace string) *kubeSubnets {
return &kubeSubnets{
regex: regex
configmap: configmap
namespace: namespace
}
}

func (s *subnets) All() []string {
return s.pods.Union(s.services).List()
}

func (ks *kubeSubnets) Get(clientset *kubernetes.Clientset) (string, error) {
cidrRegexp:= regexp.MustCompile(ks.regex)
configMap, err := clientset.CoreV1().ConfigMaps(ks.namespace).Get(ks.configmap, metav1.GetOptions{})
if err != nil {
println("ERROR: " + err.Error())
return "", err
}
for _, data := range configMap.Data {
matches = cidrRegexp.FindStringSubmatch(data)
if len(matches) > 0 {
println("MATCH POD: " + matches[1])
return matches[1], nil
}
}
return "", nil
}

// getNoMasqueradeSubnets tries to get the POD networks subnets to not Masquerade them
// It returns an array of strings with the Cluster CIDR subnets
// It can only obtain the POD subnet parameter from one place for consistency
// The order is:
// 1. POD_SUBNET environment variables
// 2. Pod subnet value in kubeadm configmap
// 3. Cluster CIDR value in kube-proxy configmap
func getNoMasqueradeSubnets(clientset *kubernetes.Clientset) []string {
s := newSubnets()

// check for environment variables (legacy)
podSubnetEnv := os.Getenv("POD_SUBNET")
if podSubnetEnv != "" {
s.pods.Insert(podSubnetEnv)
}
serviceSubnetEnv := os.Getenv("SERVICE_SUBNET")
if serviceSubnetEnv != "" {
s.services.Insert(serviceSubnetEnv)
return strings.Split(podSubnetEnv, ",")
}

// try getting from kubeadm config
kubeadmSubnets := getKubeadmSubnets(clientset)
s.pods = s.pods.Union(kubeadmSubnets.pods)
s.services = s.services.Union(kubeadmSubnets.services)
// try getting from kubeadm configmap
kubeadmSubnets := newKubeSubnets(kubeadmClusterCIDRRegex,"kubeadm-config", "kube-system")
podSubnetKubeadm := kubeadmSubnets.Get(clientset)
if podSubnetKubeadm != "" {
return strings.Split(podSubnetKubeadm, ",")
}

// try getting from kubeproxy configmap
kubeproxySubnets := newKubeSubnets(kubeproxyClusterCIDRRegex,"kube-proxy", "kube-system")
podSubnetKubeproxy := kubeproxySubnets.Get(clientset)
if podSubnetKubeproxy != "" {
return strings.Split(podSubnetKubeproxy, ",")

}

// TODO: we have other fallback options for completeness including:
// - kube-apiserver flags
// - component config
// - defaults

return s.All()
return nil
}




const (
kubeadmServiceCIDRRegex = `\s*serviceSubnet: (.*)\n`
kubeadmClusterCIDRRegex = `\s*podSubnet: (.*)\n`
)
var (
kubeadmServiceCIDRRegexp = regexp.MustCompile(kubeadmServiceCIDRRegex)
kubeadmClusterCIDRRegexp = regexp.MustCompile(kubeadmClusterCIDRRegex)
)

func getKubeadmSubnets(clientset *kubernetes.Clientset) *subnets {
s := newSubnets()
configMap, err := clientset.CoreV1().ConfigMaps("kube-system").Get("kubeadm-config", metav1.GetOptions{})
if err != nil {
println("ERROR: "+err.Error())
return s
}
for _, data := range configMap.Data {
matches := kubeadmServiceCIDRRegexp.FindAllStringSubmatch(data, 1)
if len(matches) > 0 {
println("MATCH SERVICE: " + matches[0][1])
s.services.Insert(matches[0][1])
}
matches = kubeadmClusterCIDRRegexp.FindAllStringSubmatch(data, 1)
if len(matches) > 0 {
println("MATCH POD: " + matches[0][1])
s.pods.Insert(matches[0][1])
}
}
return s
}

5 changes: 0 additions & 5 deletions hack/ci/e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,9 @@ build() {

# up a cluster with kind
create_cluster() {
<<<<<<< HEAD
# create the config file
cat <<EOF > "${ARTIFACTS}/kind-config.yaml"
=======
IP_FAMILY="dual-stack"
# create the config file
cat <<EOF > "${ARTIFACTS}/kind-config.yaml"
>>>>>>> TEMP: ci testing
# config for 1 control plane node and 2 workers
# necessary for conformance
kind: Cluster
Expand Down
7 changes: 4 additions & 3 deletions pkg/build/node/cni.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ var defaultCNIImages = []string{"kindest/kindnetd:0.6.0"}

const defaultCNIManifest = `
# kindnetd networking manifest
# would you kindly template this file
---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
Expand Down Expand Up @@ -160,8 +159,10 @@ spec:
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: POD_SUBNET
value: {{ .PodSubnet }}
- name: POD_IPS
valueFrom:
fieldRef:
fieldPath: status.podIPs
volumeMounts:
- name: cni-cfg
mountPath: /etc/cni/net.d
Expand Down
Loading

0 comments on commit 3205861

Please sign in to comment.