Skip to content

Commit 4dc05dd

Browse files
authored
Merge pull request kubernetes#76320 from JieJhih/config/kube_proxy
support ipv6 in bind address
2 parents a143d07 + 08e320f commit 4dc05dd

File tree

7 files changed

+181
-40
lines changed

7 files changed

+181
-40
lines changed

cmd/kube-proxy/app/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ go_library(
3131
"//pkg/proxy/iptables:go_default_library",
3232
"//pkg/proxy/ipvs:go_default_library",
3333
"//pkg/proxy/userspace:go_default_library",
34+
"//pkg/proxy/util:go_default_library",
3435
"//pkg/util/configz:go_default_library",
3536
"//pkg/util/filesystem:go_default_library",
3637
"//pkg/util/flag:go_default_library",

cmd/kube-proxy/app/server.go

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import (
6161
"k8s.io/kubernetes/pkg/proxy/iptables"
6262
"k8s.io/kubernetes/pkg/proxy/ipvs"
6363
"k8s.io/kubernetes/pkg/proxy/userspace"
64+
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
6465
"k8s.io/kubernetes/pkg/util/configz"
6566
"k8s.io/kubernetes/pkg/util/filesystem"
6667
utilflag "k8s.io/kubernetes/pkg/util/flag"
@@ -213,8 +214,8 @@ func NewOptions() *Options {
213214
func (o *Options) Complete() error {
214215
if len(o.ConfigFile) == 0 && len(o.WriteConfigTo) == 0 {
215216
klog.Warning("WARNING: all flags other than --config, --write-config-to, and --cleanup are deprecated. Please begin using a config file ASAP.")
216-
o.applyDeprecatedHealthzPortToConfig()
217-
o.applyDeprecatedMetricsPortToConfig()
217+
o.config.HealthzBindAddress = addressFromDeprecatedFlags(o.config.HealthzBindAddress, o.healthzPort)
218+
o.config.MetricsBindAddress = addressFromDeprecatedFlags(o.config.MetricsBindAddress, o.metricsPort)
218219
}
219220

220221
// Load the config file here in Complete, so that Validate validates the fully-resolved config.
@@ -359,38 +360,15 @@ func (o *Options) writeConfigFile() error {
359360
return nil
360361
}
361362

362-
// applyDeprecatedHealthzPortToConfig sets o.config.HealthzBindAddress from
363-
// flags passed on the command line based on the following rules:
364-
//
365-
// 1. If --healthz-port is 0, disable the healthz server.
366-
// 2. Otherwise, use the value of --healthz-port for the port portion of
367-
// o.config.HealthzBindAddress
368-
func (o *Options) applyDeprecatedHealthzPortToConfig() {
369-
if o.healthzPort == 0 {
370-
o.config.HealthzBindAddress = ""
371-
return
363+
// addressFromDeprecatedFlags returns server address from flags
364+
// passed on the command line based on the following rules:
365+
// 1. If port is 0, disable the server (e.g. set address to empty).
366+
// 2. Otherwise, set the port portion of the config accordingly.
367+
func addressFromDeprecatedFlags(addr string, port int32) string {
368+
if port == 0 {
369+
return ""
372370
}
373-
374-
index := strings.Index(o.config.HealthzBindAddress, ":")
375-
if index != -1 {
376-
o.config.HealthzBindAddress = o.config.HealthzBindAddress[0:index]
377-
}
378-
379-
o.config.HealthzBindAddress = fmt.Sprintf("%s:%d", o.config.HealthzBindAddress, o.healthzPort)
380-
}
381-
382-
func (o *Options) applyDeprecatedMetricsPortToConfig() {
383-
if o.metricsPort == 0 {
384-
o.config.MetricsBindAddress = ""
385-
return
386-
}
387-
388-
index := strings.Index(o.config.MetricsBindAddress, ":")
389-
if index != -1 {
390-
o.config.MetricsBindAddress = o.config.MetricsBindAddress[0:index]
391-
}
392-
393-
o.config.MetricsBindAddress = fmt.Sprintf("%s:%d", o.config.MetricsBindAddress, o.metricsPort)
371+
return proxyutil.AppendPortIfNeeded(addr, port)
394372
}
395373

396374
// loadConfigFromFile loads the contents of file and decodes it as a

cmd/kube-proxy/app/server_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,3 +549,79 @@ func (s *fakeProxyServerError) Run() error {
549549
return fmt.Errorf("mocking error from ProxyServer.Run()")
550550
}
551551
}
552+
553+
func TestAddressFromDeprecatedFlags(t *testing.T) {
554+
testCases := []struct {
555+
name string
556+
healthzPort int32
557+
healthzBindAddress string
558+
metricsPort int32
559+
metricsBindAddress string
560+
expHealthz string
561+
expMetrics string
562+
}{
563+
{
564+
name: "IPv4 bind address",
565+
healthzBindAddress: "1.2.3.4",
566+
healthzPort: 12345,
567+
metricsBindAddress: "2.3.4.5",
568+
metricsPort: 23456,
569+
expHealthz: "1.2.3.4:12345",
570+
expMetrics: "2.3.4.5:23456",
571+
},
572+
{
573+
name: "IPv4 bind address has port",
574+
healthzBindAddress: "1.2.3.4:12345",
575+
healthzPort: 23456,
576+
metricsBindAddress: "2.3.4.5:12345",
577+
metricsPort: 23456,
578+
expHealthz: "1.2.3.4:12345",
579+
expMetrics: "2.3.4.5:12345",
580+
},
581+
{
582+
name: "IPv6 bind address",
583+
healthzBindAddress: "fd00:1::5",
584+
healthzPort: 12345,
585+
metricsBindAddress: "fd00:1::6",
586+
metricsPort: 23456,
587+
expHealthz: "[fd00:1::5]:12345",
588+
expMetrics: "[fd00:1::6]:23456",
589+
},
590+
{
591+
name: "IPv6 bind address has port",
592+
healthzBindAddress: "[fd00:1::5]:12345",
593+
healthzPort: 56789,
594+
metricsBindAddress: "[fd00:1::6]:56789",
595+
metricsPort: 12345,
596+
expHealthz: "[fd00:1::5]:12345",
597+
expMetrics: "[fd00:1::6]:56789",
598+
},
599+
{
600+
name: "Invalid IPv6 Config",
601+
healthzBindAddress: "[fd00:1::5]",
602+
healthzPort: 12345,
603+
metricsBindAddress: "[fd00:1::6]",
604+
metricsPort: 56789,
605+
expHealthz: "[fd00:1::5]",
606+
expMetrics: "[fd00:1::6]",
607+
},
608+
}
609+
610+
for i := range testCases {
611+
gotHealthz := addressFromDeprecatedFlags(testCases[i].healthzBindAddress, testCases[i].healthzPort)
612+
gotMetrics := addressFromDeprecatedFlags(testCases[i].metricsBindAddress, testCases[i].metricsPort)
613+
614+
errFn := func(name, except, got string) {
615+
t.Errorf("case %s: expected %v, got %v", name, except, got)
616+
}
617+
618+
if gotHealthz != testCases[i].expHealthz {
619+
errFn(testCases[i].name, testCases[i].expHealthz, gotHealthz)
620+
}
621+
622+
if gotMetrics != testCases[i].expMetrics {
623+
errFn(testCases[i].name, testCases[i].expMetrics, gotMetrics)
624+
}
625+
626+
}
627+
}

pkg/proxy/apis/config/v1alpha1/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ go_library(
2020
"//pkg/kubelet/qos:go_default_library",
2121
"//pkg/master/ports:go_default_library",
2222
"//pkg/proxy/apis/config:go_default_library",
23+
"//pkg/proxy/util:go_default_library",
2324
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
2425
"//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library",
2526
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",

pkg/proxy/apis/config/v1alpha1/defaults.go

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,16 @@ package v1alpha1
1818

1919
import (
2020
"fmt"
21-
"strings"
21+
"net"
2222
"time"
2323

2424
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2525
kruntime "k8s.io/apimachinery/pkg/runtime"
2626
kubeproxyconfigv1alpha1 "k8s.io/kube-proxy/config/v1alpha1"
27+
2728
"k8s.io/kubernetes/pkg/kubelet/qos"
2829
"k8s.io/kubernetes/pkg/master/ports"
30+
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
2931
"k8s.io/utils/pointer"
3032
)
3133

@@ -34,19 +36,24 @@ func addDefaultingFuncs(scheme *kruntime.Scheme) error {
3436
}
3537

3638
func SetDefaults_KubeProxyConfiguration(obj *kubeproxyconfigv1alpha1.KubeProxyConfiguration) {
39+
3740
if len(obj.BindAddress) == 0 {
3841
obj.BindAddress = "0.0.0.0"
3942
}
43+
44+
defaultHealthzAddress, defaultMetricsAddress := getDefaultAddresses(obj.BindAddress)
45+
4046
if obj.HealthzBindAddress == "" {
41-
obj.HealthzBindAddress = fmt.Sprintf("0.0.0.0:%v", ports.ProxyHealthzPort)
42-
} else if !strings.Contains(obj.HealthzBindAddress, ":") {
43-
obj.HealthzBindAddress += fmt.Sprintf(":%v", ports.ProxyHealthzPort)
47+
obj.HealthzBindAddress = fmt.Sprintf("%s:%v", defaultHealthzAddress, ports.ProxyHealthzPort)
48+
} else {
49+
obj.HealthzBindAddress = proxyutil.AppendPortIfNeeded(obj.HealthzBindAddress, ports.ProxyHealthzPort)
4450
}
4551
if obj.MetricsBindAddress == "" {
46-
obj.MetricsBindAddress = fmt.Sprintf("127.0.0.1:%v", ports.ProxyStatusPort)
47-
} else if !strings.Contains(obj.MetricsBindAddress, ":") {
48-
obj.MetricsBindAddress += fmt.Sprintf(":%v", ports.ProxyStatusPort)
52+
obj.MetricsBindAddress = fmt.Sprintf("%s:%v", defaultMetricsAddress, ports.ProxyStatusPort)
53+
} else {
54+
obj.MetricsBindAddress = proxyutil.AppendPortIfNeeded(obj.MetricsBindAddress, ports.ProxyStatusPort)
4955
}
56+
5057
if obj.OOMScoreAdj == nil {
5158
temp := int32(qos.KubeProxyOOMScoreAdj)
5259
obj.OOMScoreAdj = &temp
@@ -121,3 +128,13 @@ func SetDefaults_KubeProxyConfiguration(obj *kubeproxyconfigv1alpha1.KubeProxyCo
121128
obj.FeatureGates = make(map[string]bool)
122129
}
123130
}
131+
132+
// getDefaultAddresses returns default address of healthz and metrics server
133+
// based on the given bind address. IPv6 addresses are enclosed in square
134+
// brackets for appending port.
135+
func getDefaultAddresses(bindAddress string) (defaultHealthzAddress, defaultMetricsAddress string) {
136+
if net.ParseIP(bindAddress).To4() != nil {
137+
return "0.0.0.0", "127.0.0.1"
138+
}
139+
return "[::]", "[::1]"
140+
}

pkg/proxy/util/utils.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,24 @@ func filterWithCondition(strs []string, expectedCondition bool, conditionFunc fu
214214
}
215215
return corrects, incorrects
216216
}
217+
218+
// AppendPortIfNeeded appends the given port to IP address unless it is already in
219+
// "ipv4:port" or "[ipv6]:port" format.
220+
func AppendPortIfNeeded(addr string, port int32) string {
221+
// Return if address is already in "ipv4:port" or "[ipv6]:port" format.
222+
if _, _, err := net.SplitHostPort(addr); err == nil {
223+
return addr
224+
}
225+
226+
// Simply return for invalid case. This should be caught by validation instead.
227+
ip := net.ParseIP(addr)
228+
if ip == nil {
229+
return addr
230+
}
231+
232+
// Append port to address.
233+
if ip.To4() != nil {
234+
return fmt.Sprintf("%s:%d", addr, port)
235+
}
236+
return fmt.Sprintf("[%s]:%d", addr, port)
237+
}

pkg/proxy/util/utils_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,3 +396,50 @@ func TestGetNodeAddressses(t *testing.T) {
396396
}
397397
}
398398
}
399+
400+
func TestAppendPortIfNeeded(t *testing.T) {
401+
testCases := []struct {
402+
name string
403+
addr string
404+
port int32
405+
expect string
406+
}{
407+
{
408+
name: "IPv4 all-zeros bind address has port",
409+
addr: "0.0.0.0:12345",
410+
port: 23456,
411+
expect: "0.0.0.0:12345",
412+
},
413+
{
414+
name: "non-zeros IPv4 config",
415+
addr: "9.8.7.6",
416+
port: 12345,
417+
expect: "9.8.7.6:12345",
418+
},
419+
{
420+
name: "IPv6 \"[::]\" bind address has port",
421+
addr: "[::]:12345",
422+
port: 23456,
423+
expect: "[::]:12345",
424+
},
425+
{
426+
name: "IPv6 config",
427+
addr: "fd00:1::5",
428+
port: 23456,
429+
expect: "[fd00:1::5]:23456",
430+
},
431+
{
432+
name: "Invalid IPv6 Config",
433+
addr: "[fd00:1::5]",
434+
port: 12345,
435+
expect: "[fd00:1::5]",
436+
},
437+
}
438+
439+
for i := range testCases {
440+
got := AppendPortIfNeeded(testCases[i].addr, testCases[i].port)
441+
if testCases[i].expect != got {
442+
t.Errorf("case %s: expected %v, got %v", testCases[i].name, testCases[i].expect, got)
443+
}
444+
}
445+
}

0 commit comments

Comments
 (0)