Merge pull request #5964 from crosbymichael/cni-pref

add ip_pref CNI options for primary pod ip
This commit is contained in:
Phil Estes 2021-09-10 12:06:23 -04:00 committed by GitHub
commit 6589876d20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 21 deletions

View File

@ -238,6 +238,12 @@ version = 2
# This will be deprecated when kubenet is deprecated. # This will be deprecated when kubenet is deprecated.
# See the "CNI Config Template" section for more details. # See the "CNI Config Template" section for more details.
conf_template = "" conf_template = ""
# ip_pref specifies the strategy to use when selecting the main IP address for a pod.
# options include:
# * ipv4, "" - (default) select the first ipv4 address
# * ipv6 - select the first ipv6 address
# * cni - use the order returned by the CNI plugins, returning the first IP address from the results
ip_pref = "ipv4"
# 'plugins."io.containerd.grpc.v1.cri".image_decryption' contains config related # 'plugins."io.containerd.grpc.v1.cri".image_decryption' contains config related
# to handling decryption of encrypted container images. # to handling decryption of encrypted container images.

View File

@ -111,6 +111,13 @@ type CniConfig struct {
// a temporary backward-compatible solution for them. // a temporary backward-compatible solution for them.
// TODO(random-liu): Deprecate this option when kubenet is deprecated. // TODO(random-liu): Deprecate this option when kubenet is deprecated.
NetworkPluginConfTemplate string `toml:"conf_template" json:"confTemplate"` NetworkPluginConfTemplate string `toml:"conf_template" json:"confTemplate"`
// IPPreference specifies the strategy to use when selecting the main IP address for a pod.
//
// Options include:
// * ipv4, "" - (default) select the first ipv4 address
// * ipv6 - select the first ipv6 address
// * cni - use the order returned by the CNI plugins, returning the first IP address from the results
IPPreference string `toml:"ip_pref" json:"ipPref"`
} }
// Mirror contains the config related to the registry mirror // Mirror contains the config related to the registry mirror

View File

@ -372,7 +372,7 @@ func (c *criService) setupPodNetwork(ctx context.Context, sandbox *sandboxstore.
logDebugCNIResult(ctx, id, result) logDebugCNIResult(ctx, id, result)
// Check if the default interface has IP config // Check if the default interface has IP config
if configs, ok := result.Interfaces[defaultIfName]; ok && len(configs.IPConfigs) > 0 { if configs, ok := result.Interfaces[defaultIfName]; ok && len(configs.IPConfigs) > 0 {
sandbox.IP, sandbox.AdditionalIPs = selectPodIPs(configs.IPConfigs) sandbox.IP, sandbox.AdditionalIPs = selectPodIPs(ctx, configs.IPConfigs, c.config.IPPreference)
sandbox.CNIResult = result sandbox.CNIResult = result
return nil return nil
} }
@ -475,28 +475,46 @@ func toCNIDNS(dns *runtime.DNSConfig) *cni.DNS {
} }
} }
// selectPodIPs select an ip from the ip list. It prefers ipv4 more than ipv6 // selectPodIPs select an ip from the ip list.
// and returns the additional ips func selectPodIPs(ctx context.Context, configs []*cni.IPConfig, preference string) (string, []string) {
// TODO(random-liu): Revisit the ip order in the ipv6 beta stage. (cri#1278) if len(configs) == 1 {
func selectPodIPs(ipConfigs []*cni.IPConfig) (string, []string) { return ipString(configs[0]), nil
var ( }
additionalIPs []string toStrings := func(ips []*cni.IPConfig) (o []string) {
ip string for _, i := range ips {
) o = append(o, ipString(i))
for _, c := range ipConfigs {
if c.IP.To4() != nil && ip == "" {
ip = c.IP.String()
} else {
additionalIPs = append(additionalIPs, c.IP.String())
} }
return o
} }
if ip != "" { var extra []string
return ip, additionalIPs switch preference {
default:
if preference != "ipv4" && preference != "" {
log.G(ctx).WithField("ip_pref", preference).Warn("invalid ip_pref, falling back to ipv4")
}
for i, ip := range configs {
if ip.IP.To4() != nil {
return ipString(ip), append(extra, toStrings(configs[i+1:])...)
}
extra = append(extra, ipString(ip))
}
case "ipv6":
for i, ip := range configs {
if ip.IP.To16() != nil {
return ipString(ip), append(extra, toStrings(configs[i+1:])...)
}
extra = append(extra, ipString(ip))
}
case "cni":
// use func default return
} }
if len(ipConfigs) == 1 {
return additionalIPs[0], nil all := toStrings(configs)
} return all[0], all[1:]
return additionalIPs[0], additionalIPs[1:] }
func ipString(ip *cni.IPConfig) string {
return ip.IP.String()
} }
// untrustedWorkload returns true if the sandbox contains untrusted workload. // untrustedWorkload returns true if the sandbox contains untrusted workload.

View File

@ -26,6 +26,7 @@ import (
imagespec "github.com/opencontainers/image-spec/specs-go/v1" imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtimespec "github.com/opencontainers/runtime-spec/specs-go" runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"golang.org/x/net/context"
runtime "k8s.io/cri-api/pkg/apis/runtime/v1" runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
"github.com/containerd/containerd/pkg/cri/annotations" "github.com/containerd/containerd/pkg/cri/annotations"
@ -260,12 +261,26 @@ func TestSelectPodIP(t *testing.T) {
ips []string ips []string
expectedIP string expectedIP string
expectedAdditionalIPs []string expectedAdditionalIPs []string
pref string
}{ }{
"ipv4 should be picked even if ipv6 comes first": { "ipv4 should be picked even if ipv6 comes first": {
ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43"}, ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43"},
expectedIP: "192.168.17.43", expectedIP: "192.168.17.43",
expectedAdditionalIPs: []string{"2001:db8:85a3::8a2e:370:7334"}, expectedAdditionalIPs: []string{"2001:db8:85a3::8a2e:370:7334"},
}, },
"ipv6 should be picked even if ipv4 comes first": {
ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43"},
expectedIP: "2001:db8:85a3::8a2e:370:7334",
expectedAdditionalIPs: []string{"192.168.17.43"},
pref: "ipv6",
},
"order should reflect ip selection": {
ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43"},
expectedIP: "2001:db8:85a3::8a2e:370:7334",
expectedAdditionalIPs: []string{"192.168.17.43"},
pref: "cni",
},
"ipv4 should be picked when there is only ipv4": { "ipv4 should be picked when there is only ipv4": {
ips: []string{"192.168.17.43"}, ips: []string{"192.168.17.43"},
expectedIP: "192.168.17.43", expectedIP: "192.168.17.43",
@ -289,7 +304,7 @@ func TestSelectPodIP(t *testing.T) {
IP: net.ParseIP(ip), IP: net.ParseIP(ip),
}) })
} }
ip, additionalIPs := selectPodIPs(ipConfigs) ip, additionalIPs := selectPodIPs(context.Background(), ipConfigs, test.pref)
assert.Equal(t, test.expectedIP, ip) assert.Equal(t, test.expectedIP, ip)
assert.Equal(t, test.expectedAdditionalIPs, additionalIPs) assert.Equal(t, test.expectedAdditionalIPs, additionalIPs)
} }