mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 02:43:36 +00:00
vendor files
This commit is contained in:
51
vendor/k8s.io/kubernetes/cmd/kube-proxy/BUILD
generated
vendored
Normal file
51
vendor/k8s.io/kubernetes/cmd/kube-proxy/BUILD
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
)
|
||||
load("//pkg/version:def.bzl", "version_x_defs")
|
||||
|
||||
go_binary(
|
||||
name = "kube-proxy",
|
||||
gc_linkopts = [
|
||||
"-linkmode",
|
||||
"external",
|
||||
"-extldflags",
|
||||
"-static",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/cmd/kube-proxy",
|
||||
library = ":go_default_library",
|
||||
x_defs = version_x_defs(),
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["proxy.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kube-proxy",
|
||||
deps = [
|
||||
"//cmd/kube-proxy/app:go_default_library",
|
||||
"//pkg/client/metrics/prometheus:go_default_library",
|
||||
"//pkg/version/prometheus:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/logs:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//cmd/kube-proxy/app:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
115
vendor/k8s.io/kubernetes/cmd/kube-proxy/app/BUILD
generated
vendored
Normal file
115
vendor/k8s.io/kubernetes/cmd/kube-proxy/app/BUILD
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"conntrack.go",
|
||||
"server.go",
|
||||
"server_others.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
"server_windows.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
importpath = "k8s.io/kubernetes/cmd/kube-proxy/app",
|
||||
deps = [
|
||||
"//pkg/apis/componentconfig:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubelet/qos:go_default_library",
|
||||
"//pkg/master/ports:go_default_library",
|
||||
"//pkg/proxy:go_default_library",
|
||||
"//pkg/proxy/apis/kubeproxyconfig:go_default_library",
|
||||
"//pkg/proxy/apis/kubeproxyconfig/scheme:go_default_library",
|
||||
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1:go_default_library",
|
||||
"//pkg/proxy/apis/kubeproxyconfig/validation:go_default_library",
|
||||
"//pkg/proxy/config:go_default_library",
|
||||
"//pkg/proxy/healthcheck:go_default_library",
|
||||
"//pkg/proxy/iptables:go_default_library",
|
||||
"//pkg/proxy/ipvs:go_default_library",
|
||||
"//pkg/proxy/metrics:go_default_library",
|
||||
"//pkg/proxy/userspace:go_default_library",
|
||||
"//pkg/util/configz:go_default_library",
|
||||
"//pkg/util/dbus:go_default_library",
|
||||
"//pkg/util/ipset:go_default_library",
|
||||
"//pkg/util/iptables:go_default_library",
|
||||
"//pkg/util/ipvs:go_default_library",
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//pkg/util/oom:go_default_library",
|
||||
"//pkg/util/pointer:go_default_library",
|
||||
"//pkg/util/resourcecontainer:go_default_library",
|
||||
"//pkg/util/sysctl:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
"//pkg/version/verflag:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
"//pkg/proxy/winkernel:go_default_library",
|
||||
"//pkg/proxy/winuserspace:go_default_library",
|
||||
"//pkg/util/netsh:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["server_test.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kube-proxy/app",
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/proxy/apis/kubeproxyconfig:go_default_library",
|
||||
"//pkg/util/configz:go_default_library",
|
||||
"//pkg/util/iptables:go_default_library",
|
||||
"//pkg/util/pointer:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
142
vendor/k8s.io/kubernetes/cmd/kube-proxy/app/conntrack.go
generated
vendored
Normal file
142
vendor/k8s.io/kubernetes/cmd/kube-proxy/app/conntrack.go
generated
vendored
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
"k8s.io/kubernetes/pkg/util/sysctl"
|
||||
)
|
||||
|
||||
// Conntracker is an interface to the global sysctl. Descriptions of the various
|
||||
// sysctl fields can be found here:
|
||||
//
|
||||
// https://www.kernel.org/doc/Documentation/networking/nf_conntrack-sysctl.txt
|
||||
type Conntracker interface {
|
||||
// SetMax adjusts nf_conntrack_max.
|
||||
SetMax(max int) error
|
||||
// SetTCPEstablishedTimeout adjusts nf_conntrack_tcp_timeout_established.
|
||||
SetTCPEstablishedTimeout(seconds int) error
|
||||
// SetTCPCloseWaitTimeout nf_conntrack_tcp_timeout_close_wait.
|
||||
SetTCPCloseWaitTimeout(seconds int) error
|
||||
}
|
||||
|
||||
type realConntracker struct{}
|
||||
|
||||
var readOnlySysFSError = errors.New("readOnlySysFS")
|
||||
|
||||
func (rct realConntracker) SetMax(max int) error {
|
||||
if err := rct.setIntSysCtl("nf_conntrack_max", max); err != nil {
|
||||
return err
|
||||
}
|
||||
glog.Infof("Setting nf_conntrack_max to %d", max)
|
||||
|
||||
// Linux does not support writing to /sys/module/nf_conntrack/parameters/hashsize
|
||||
// when the writer process is not in the initial network namespace
|
||||
// (https://github.com/torvalds/linux/blob/v4.10/net/netfilter/nf_conntrack_core.c#L1795-L1796).
|
||||
// Usually that's fine. But in some configurations such as with github.com/kinvolk/kubeadm-nspawn,
|
||||
// kube-proxy is in another netns.
|
||||
// Therefore, check if writing in hashsize is necessary and skip the writing if not.
|
||||
hashsize, err := readIntStringFile("/sys/module/nf_conntrack/parameters/hashsize")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if hashsize >= (max / 4) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// sysfs is expected to be mounted as 'rw'. However, it may be
|
||||
// unexpectedly mounted as 'ro' by docker because of a known docker
|
||||
// issue (https://github.com/docker/docker/issues/24000). Setting
|
||||
// conntrack will fail when sysfs is readonly. When that happens, we
|
||||
// don't set conntrack hashsize and return a special error
|
||||
// readOnlySysFSError here. The caller should deal with
|
||||
// readOnlySysFSError differently.
|
||||
writable, err := isSysFSWritable()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !writable {
|
||||
return readOnlySysFSError
|
||||
}
|
||||
// TODO: generify this and sysctl to a new sysfs.WriteInt()
|
||||
glog.Infof("Setting conntrack hashsize to %d", max/4)
|
||||
return writeIntStringFile("/sys/module/nf_conntrack/parameters/hashsize", max/4)
|
||||
}
|
||||
|
||||
func (rct realConntracker) SetTCPEstablishedTimeout(seconds int) error {
|
||||
return rct.setIntSysCtl("nf_conntrack_tcp_timeout_established", seconds)
|
||||
}
|
||||
|
||||
func (rct realConntracker) SetTCPCloseWaitTimeout(seconds int) error {
|
||||
return rct.setIntSysCtl("nf_conntrack_tcp_timeout_close_wait", seconds)
|
||||
}
|
||||
|
||||
func (realConntracker) setIntSysCtl(name string, value int) error {
|
||||
entry := "net/netfilter/" + name
|
||||
|
||||
glog.Infof("Set sysctl '%v' to %v", entry, value)
|
||||
if err := sysctl.New().SetSysctl(entry, value); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// isSysFSWritable checks /proc/mounts to see whether sysfs is 'rw' or not.
|
||||
func isSysFSWritable() (bool, error) {
|
||||
const permWritable = "rw"
|
||||
const sysfsDevice = "sysfs"
|
||||
m := mount.New("" /* default mount path */)
|
||||
mountPoints, err := m.List()
|
||||
if err != nil {
|
||||
glog.Errorf("failed to list mount points: %v", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, mountPoint := range mountPoints {
|
||||
if mountPoint.Type != sysfsDevice {
|
||||
continue
|
||||
}
|
||||
// Check whether sysfs is 'rw'
|
||||
if len(mountPoint.Opts) > 0 && mountPoint.Opts[0] == permWritable {
|
||||
return true, nil
|
||||
}
|
||||
glog.Errorf("sysfs is not writable: %+v (mount options are %v)",
|
||||
mountPoint, mountPoint.Opts)
|
||||
return false, readOnlySysFSError
|
||||
}
|
||||
|
||||
return false, errors.New("No sysfs mounted")
|
||||
}
|
||||
|
||||
func readIntStringFile(filename string) (int, error) {
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return strconv.Atoi(strings.TrimSpace(string(b)))
|
||||
}
|
||||
|
||||
func writeIntStringFile(filename string, value int) error {
|
||||
return ioutil.WriteFile(filename, []byte(strconv.Itoa(value)), 0640)
|
||||
}
|
595
vendor/k8s.io/kubernetes/cmd/kube-proxy/app/server.go
generated
vendored
Normal file
595
vendor/k8s.io/kubernetes/cmd/kube-proxy/app/server.go
generated
vendored
Normal file
@ -0,0 +1,595 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package app does all of the work necessary to configure and run a
|
||||
// Kubernetes app process.
|
||||
package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"os"
|
||||
goruntime "runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/server/healthz"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
clientgoclientset "k8s.io/client-go/kubernetes"
|
||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubelet/qos"
|
||||
"k8s.io/kubernetes/pkg/master/ports"
|
||||
"k8s.io/kubernetes/pkg/proxy"
|
||||
"k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig"
|
||||
"k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/scheme"
|
||||
"k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
|
||||
"k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/validation"
|
||||
"k8s.io/kubernetes/pkg/proxy/config"
|
||||
"k8s.io/kubernetes/pkg/proxy/healthcheck"
|
||||
"k8s.io/kubernetes/pkg/proxy/iptables"
|
||||
"k8s.io/kubernetes/pkg/proxy/ipvs"
|
||||
"k8s.io/kubernetes/pkg/proxy/userspace"
|
||||
"k8s.io/kubernetes/pkg/util/configz"
|
||||
utilipset "k8s.io/kubernetes/pkg/util/ipset"
|
||||
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
|
||||
utilipvs "k8s.io/kubernetes/pkg/util/ipvs"
|
||||
utilnode "k8s.io/kubernetes/pkg/util/node"
|
||||
"k8s.io/kubernetes/pkg/util/oom"
|
||||
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
|
||||
"k8s.io/kubernetes/pkg/util/resourcecontainer"
|
||||
"k8s.io/kubernetes/pkg/version"
|
||||
"k8s.io/kubernetes/pkg/version/verflag"
|
||||
"k8s.io/utils/exec"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
const (
|
||||
proxyModeUserspace = "userspace"
|
||||
proxyModeIPTables = "iptables"
|
||||
proxyModeIPVS = "ipvs"
|
||||
proxyModeKernelspace = "kernelspace"
|
||||
)
|
||||
|
||||
// Options contains everything necessary to create and run a proxy server.
|
||||
type Options struct {
|
||||
// ConfigFile is the location of the proxy server's configuration file.
|
||||
ConfigFile string
|
||||
// WriteConfigTo is the path where the default configuration will be written.
|
||||
WriteConfigTo string
|
||||
// CleanupAndExit, when true, makes the proxy server clean up iptables rules, then exit.
|
||||
CleanupAndExit bool
|
||||
// CleanupIPVS, when true, makes the proxy server clean up ipvs rules before running.
|
||||
CleanupIPVS bool
|
||||
// config is the proxy server's configuration object.
|
||||
config *kubeproxyconfig.KubeProxyConfiguration
|
||||
|
||||
// The fields below here are placeholders for flags that can't be directly mapped into
|
||||
// kubeproxyconfig.KubeProxyConfiguration.
|
||||
//
|
||||
// TODO remove these fields once the deprecated flags are removed.
|
||||
|
||||
// master is used to override the kubeconfig's URL to the apiserver.
|
||||
master string
|
||||
// healthzPort is the port to be used by the healthz server.
|
||||
healthzPort int32
|
||||
|
||||
scheme *runtime.Scheme
|
||||
codecs serializer.CodecFactory
|
||||
}
|
||||
|
||||
// AddFlags adds flags to fs and binds them to options.
|
||||
func AddFlags(options *Options, fs *pflag.FlagSet) {
|
||||
fs.StringVar(&options.ConfigFile, "config", options.ConfigFile, "The path to the configuration file.")
|
||||
fs.StringVar(&options.WriteConfigTo, "write-config-to", options.WriteConfigTo, "If set, write the default configuration values to this file and exit.")
|
||||
fs.BoolVar(&options.CleanupAndExit, "cleanup-iptables", options.CleanupAndExit, "If true cleanup iptables and ipvs rules and exit.")
|
||||
fs.MarkDeprecated("cleanup-iptables", "This flag is replaced by --cleanup.")
|
||||
fs.BoolVar(&options.CleanupAndExit, "cleanup", options.CleanupAndExit, "If true cleanup iptables and ipvs rules and exit.")
|
||||
fs.BoolVar(&options.CleanupIPVS, "cleanup-ipvs", options.CleanupIPVS, "If true make kube-proxy cleanup ipvs rules before running. Default is true")
|
||||
|
||||
// All flags below here are deprecated and will eventually be removed.
|
||||
|
||||
fs.Var(componentconfig.IPVar{Val: &options.config.BindAddress}, "bind-address", "The IP address for the proxy server to serve on (set to `0.0.0.0` for all IPv4 interfaces and `::` for all IPv6 interfaces)")
|
||||
fs.StringVar(&options.master, "master", options.master, "The address of the Kubernetes API server (overrides any value in kubeconfig)")
|
||||
fs.Int32Var(&options.healthzPort, "healthz-port", options.healthzPort, "The port to bind the health check server. Use 0 to disable.")
|
||||
fs.Var(componentconfig.IPVar{Val: &options.config.HealthzBindAddress}, "healthz-bind-address", "The IP address and port for the health check server to serve on (set to `0.0.0.0` for all IPv4 interfaces and `::` for all IPv6 interfaces)")
|
||||
fs.Var(componentconfig.IPVar{Val: &options.config.MetricsBindAddress}, "metrics-bind-address", "The IP address and port for the metrics server to serve on (set to `0.0.0.0` for all IPv4 interfaces and `::` for all IPv6 interfaces)")
|
||||
fs.Int32Var(options.config.OOMScoreAdj, "oom-score-adj", utilpointer.Int32PtrDerefOr(options.config.OOMScoreAdj, int32(qos.KubeProxyOOMScoreAdj)), "The oom-score-adj value for kube-proxy process. Values must be within the range [-1000, 1000]")
|
||||
fs.StringVar(&options.config.ResourceContainer, "resource-container", options.config.ResourceContainer, "Absolute name of the resource-only container to create and run the Kube-proxy in (Default: /kube-proxy).")
|
||||
fs.MarkDeprecated("resource-container", "This feature will be removed in a later release.")
|
||||
fs.StringVar(&options.config.ClientConnection.KubeConfigFile, "kubeconfig", options.config.ClientConnection.KubeConfigFile, "Path to kubeconfig file with authorization information (the master location is set by the master flag).")
|
||||
fs.Var(componentconfig.PortRangeVar{Val: &options.config.PortRange}, "proxy-port-range", "Range of host ports (beginPort-endPort, inclusive) that may be consumed in order to proxy service traffic. If unspecified (0-0) then ports will be randomly chosen.")
|
||||
fs.StringVar(&options.config.HostnameOverride, "hostname-override", options.config.HostnameOverride, "If non-empty, will use this string as identification instead of the actual hostname.")
|
||||
fs.Var(&options.config.Mode, "proxy-mode", "Which proxy mode to use: 'userspace' (older) or 'iptables' (faster) or 'ipvs'(experimental)'. If blank, use the best-available proxy (currently iptables). If the iptables proxy is selected, regardless of how, but the system's kernel or iptables versions are insufficient, this always falls back to the userspace proxy.")
|
||||
fs.Int32Var(options.config.IPTables.MasqueradeBit, "iptables-masquerade-bit", utilpointer.Int32PtrDerefOr(options.config.IPTables.MasqueradeBit, 14), "If using the pure iptables proxy, the bit of the fwmark space to mark packets requiring SNAT with. Must be within the range [0, 31].")
|
||||
fs.DurationVar(&options.config.IPTables.SyncPeriod.Duration, "iptables-sync-period", options.config.IPTables.SyncPeriod.Duration, "The maximum interval of how often iptables rules are refreshed (e.g. '5s', '1m', '2h22m'). Must be greater than 0.")
|
||||
fs.DurationVar(&options.config.IPTables.MinSyncPeriod.Duration, "iptables-min-sync-period", options.config.IPTables.MinSyncPeriod.Duration, "The minimum interval of how often the iptables rules can be refreshed as endpoints and services change (e.g. '5s', '1m', '2h22m').")
|
||||
fs.DurationVar(&options.config.IPVS.SyncPeriod.Duration, "ipvs-sync-period", options.config.IPVS.SyncPeriod.Duration, "The maximum interval of how often ipvs rules are refreshed (e.g. '5s', '1m', '2h22m'). Must be greater than 0.")
|
||||
fs.DurationVar(&options.config.IPVS.MinSyncPeriod.Duration, "ipvs-min-sync-period", options.config.IPVS.MinSyncPeriod.Duration, "The minimum interval of how often the ipvs rules can be refreshed as endpoints and services change (e.g. '5s', '1m', '2h22m').")
|
||||
fs.DurationVar(&options.config.ConfigSyncPeriod.Duration, "config-sync-period", options.config.ConfigSyncPeriod.Duration, "How often configuration from the apiserver is refreshed. Must be greater than 0.")
|
||||
fs.BoolVar(&options.config.IPTables.MasqueradeAll, "masquerade-all", options.config.IPTables.MasqueradeAll, "If using the pure iptables proxy, SNAT all traffic sent via Service cluster IPs (this not commonly needed)")
|
||||
fs.StringVar(&options.config.ClusterCIDR, "cluster-cidr", options.config.ClusterCIDR, "The CIDR range of pods in the cluster. When configured, traffic sent to a Service cluster IP from outside this range will be masqueraded and traffic sent from pods to an external LoadBalancer IP will be directed to the respective cluster IP instead")
|
||||
fs.StringVar(&options.config.ClientConnection.ContentType, "kube-api-content-type", options.config.ClientConnection.ContentType, "Content type of requests sent to apiserver.")
|
||||
fs.Float32Var(&options.config.ClientConnection.QPS, "kube-api-qps", options.config.ClientConnection.QPS, "QPS to use while talking with kubernetes apiserver")
|
||||
fs.Int32Var(&options.config.ClientConnection.Burst, "kube-api-burst", options.config.ClientConnection.Burst, "Burst to use while talking with kubernetes apiserver")
|
||||
fs.DurationVar(&options.config.UDPIdleTimeout.Duration, "udp-timeout", options.config.UDPIdleTimeout.Duration, "How long an idle UDP connection will be kept open (e.g. '250ms', '2s'). Must be greater than 0. Only applicable for proxy-mode=userspace")
|
||||
if options.config.Conntrack.Max == nil {
|
||||
options.config.Conntrack.Max = utilpointer.Int32Ptr(0)
|
||||
}
|
||||
fs.Int32Var(options.config.Conntrack.Max, "conntrack-max", *options.config.Conntrack.Max,
|
||||
"Maximum number of NAT connections to track (0 to leave as-is). This overrides conntrack-max-per-core and conntrack-min.")
|
||||
fs.MarkDeprecated("conntrack-max", "This feature will be removed in a later release.")
|
||||
fs.Int32Var(options.config.Conntrack.MaxPerCore, "conntrack-max-per-core", *options.config.Conntrack.MaxPerCore,
|
||||
"Maximum number of NAT connections to track per CPU core (0 to leave the limit as-is and ignore conntrack-min).")
|
||||
fs.Int32Var(options.config.Conntrack.Min, "conntrack-min", *options.config.Conntrack.Min,
|
||||
"Minimum number of conntrack entries to allocate, regardless of conntrack-max-per-core (set conntrack-max-per-core=0 to leave the limit as-is).")
|
||||
fs.DurationVar(&options.config.Conntrack.TCPEstablishedTimeout.Duration, "conntrack-tcp-timeout-established", options.config.Conntrack.TCPEstablishedTimeout.Duration, "Idle timeout for established TCP connections (0 to leave as-is)")
|
||||
fs.DurationVar(
|
||||
&options.config.Conntrack.TCPCloseWaitTimeout.Duration, "conntrack-tcp-timeout-close-wait",
|
||||
options.config.Conntrack.TCPCloseWaitTimeout.Duration,
|
||||
"NAT timeout for TCP connections in the CLOSE_WAIT state")
|
||||
fs.BoolVar(&options.config.EnableProfiling, "profiling", options.config.EnableProfiling, "If true enables profiling via web interface on /debug/pprof handler.")
|
||||
fs.StringVar(&options.config.IPVS.Scheduler, "ipvs-scheduler", options.config.IPVS.Scheduler, "The ipvs scheduler type when proxy mode is ipvs")
|
||||
utilfeature.DefaultFeatureGate.AddFlag(fs)
|
||||
}
|
||||
|
||||
func NewOptions() *Options {
|
||||
return &Options{
|
||||
config: new(kubeproxyconfig.KubeProxyConfiguration),
|
||||
healthzPort: ports.ProxyHealthzPort,
|
||||
scheme: scheme.Scheme,
|
||||
codecs: scheme.Codecs,
|
||||
CleanupIPVS: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Complete completes all the required options.
|
||||
func (o *Options) Complete() error {
|
||||
if len(o.ConfigFile) == 0 && len(o.WriteConfigTo) == 0 {
|
||||
glog.Warning("WARNING: all flags other than --config, --write-config-to, and --cleanup are deprecated. Please begin using a config file ASAP.")
|
||||
o.applyDeprecatedHealthzPortToConfig()
|
||||
}
|
||||
|
||||
// Load the config file here in Complete, so that Validate validates the fully-resolved config.
|
||||
if len(o.ConfigFile) > 0 {
|
||||
if c, err := o.loadConfigFromFile(o.ConfigFile); err != nil {
|
||||
return err
|
||||
} else {
|
||||
o.config = c
|
||||
// Make sure we apply the feature gate settings in the config file.
|
||||
utilfeature.DefaultFeatureGate.Set(o.config.FeatureGates)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate validates all the required options.
|
||||
func (o *Options) Validate(args []string) error {
|
||||
if len(args) != 0 {
|
||||
return errors.New("no arguments are supported")
|
||||
}
|
||||
|
||||
if errs := validation.Validate(o.config); len(errs) != 0 {
|
||||
return errs.ToAggregate()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Options) Run() error {
|
||||
if len(o.WriteConfigTo) > 0 {
|
||||
return o.writeConfigFile()
|
||||
}
|
||||
|
||||
proxyServer, err := NewProxyServer(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return proxyServer.Run()
|
||||
}
|
||||
|
||||
func (o *Options) writeConfigFile() error {
|
||||
var encoder runtime.Encoder
|
||||
mediaTypes := o.codecs.SupportedMediaTypes()
|
||||
for _, info := range mediaTypes {
|
||||
if info.MediaType == "application/yaml" {
|
||||
encoder = info.Serializer
|
||||
break
|
||||
}
|
||||
}
|
||||
if encoder == nil {
|
||||
return errors.New("unable to locate yaml encoder")
|
||||
}
|
||||
encoder = json.NewYAMLSerializer(json.DefaultMetaFactory, o.scheme, o.scheme)
|
||||
encoder = o.codecs.EncoderForVersion(encoder, v1alpha1.SchemeGroupVersion)
|
||||
|
||||
configFile, err := os.Create(o.WriteConfigTo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer configFile.Close()
|
||||
|
||||
if err := encoder.Encode(o.config, configFile); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
glog.Infof("Wrote configuration to: %s\n", o.WriteConfigTo)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// applyDeprecatedHealthzPortToConfig sets o.config.HealthzBindAddress from
|
||||
// flags passed on the command line based on the following rules:
|
||||
//
|
||||
// 1. If --healthz-port is 0, disable the healthz server.
|
||||
// 2. Otherwise, use the value of --healthz-port for the port portion of
|
||||
// o.config.HealthzBindAddress
|
||||
func (o *Options) applyDeprecatedHealthzPortToConfig() {
|
||||
if o.healthzPort == 0 {
|
||||
o.config.HealthzBindAddress = ""
|
||||
return
|
||||
}
|
||||
|
||||
index := strings.Index(o.config.HealthzBindAddress, ":")
|
||||
if index != -1 {
|
||||
o.config.HealthzBindAddress = o.config.HealthzBindAddress[0:index]
|
||||
}
|
||||
|
||||
o.config.HealthzBindAddress = fmt.Sprintf("%s:%d", o.config.HealthzBindAddress, o.healthzPort)
|
||||
}
|
||||
|
||||
// loadConfigFromFile loads the contents of file and decodes it as a
|
||||
// KubeProxyConfiguration object.
|
||||
func (o *Options) loadConfigFromFile(file string) (*kubeproxyconfig.KubeProxyConfiguration, error) {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return o.loadConfig(data)
|
||||
}
|
||||
|
||||
// loadConfig decodes data as a KubeProxyConfiguration object.
|
||||
func (o *Options) loadConfig(data []byte) (*kubeproxyconfig.KubeProxyConfiguration, error) {
|
||||
configObj, gvk, err := o.codecs.UniversalDecoder().Decode(data, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config, ok := configObj.(*kubeproxyconfig.KubeProxyConfiguration)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("got unexpected config type: %v", gvk)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (o *Options) ApplyDefaults(in *kubeproxyconfig.KubeProxyConfiguration) (*kubeproxyconfig.KubeProxyConfiguration, error) {
|
||||
external, err := o.scheme.ConvertToVersion(in, v1alpha1.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
o.scheme.Default(external)
|
||||
|
||||
internal, err := o.scheme.ConvertToVersion(external, kubeproxyconfig.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := internal.(*kubeproxyconfig.KubeProxyConfiguration)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// NewProxyCommand creates a *cobra.Command object with default parameters
|
||||
func NewProxyCommand() *cobra.Command {
|
||||
opts := NewOptions()
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "kube-proxy",
|
||||
Long: `The Kubernetes network proxy runs on each node. This
|
||||
reflects services as defined in the Kubernetes API on each node and can do simple
|
||||
TCP and UDP stream forwarding or round robin TCP and UDP forwarding across a set of backends.
|
||||
Service cluster IPs and ports are currently found through Docker-links-compatible
|
||||
environment variables specifying ports opened by the service proxy. There is an optional
|
||||
addon that provides cluster DNS for these cluster IPs. The user must create a service
|
||||
with the apiserver API to configure the proxy.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
verflag.PrintAndExitIfRequested()
|
||||
cmdutil.CheckErr(opts.Complete())
|
||||
cmdutil.CheckErr(opts.Validate(args))
|
||||
cmdutil.CheckErr(opts.Run())
|
||||
},
|
||||
}
|
||||
|
||||
var err error
|
||||
opts.config, err = opts.ApplyDefaults(opts.config)
|
||||
if err != nil {
|
||||
glog.Fatalf("unable to create flag defaults: %v", err)
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
AddFlags(opts, flags)
|
||||
|
||||
cmd.MarkFlagFilename("config", "yaml", "yml", "json")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ProxyServer represents all the parameters required to start the Kubernetes proxy server. All
|
||||
// fields are required.
|
||||
type ProxyServer struct {
|
||||
Client clientset.Interface
|
||||
EventClient v1core.EventsGetter
|
||||
IptInterface utiliptables.Interface
|
||||
IpvsInterface utilipvs.Interface
|
||||
IpsetInterface utilipset.Interface
|
||||
execer exec.Interface
|
||||
Proxier proxy.ProxyProvider
|
||||
Broadcaster record.EventBroadcaster
|
||||
Recorder record.EventRecorder
|
||||
ConntrackConfiguration kubeproxyconfig.KubeProxyConntrackConfiguration
|
||||
Conntracker Conntracker // if nil, ignored
|
||||
ProxyMode string
|
||||
NodeRef *v1.ObjectReference
|
||||
CleanupAndExit bool
|
||||
CleanupIPVS bool
|
||||
MetricsBindAddress string
|
||||
EnableProfiling bool
|
||||
OOMScoreAdj *int32
|
||||
ResourceContainer string
|
||||
ConfigSyncPeriod time.Duration
|
||||
ServiceEventHandler config.ServiceHandler
|
||||
EndpointsEventHandler config.EndpointsHandler
|
||||
HealthzServer *healthcheck.HealthzServer
|
||||
}
|
||||
|
||||
// createClients creates a kube client and an event client from the given config and masterOverride.
|
||||
// TODO remove masterOverride when CLI flags are removed.
|
||||
func createClients(config kubeproxyconfig.ClientConnectionConfiguration, masterOverride string) (clientset.Interface, v1core.EventsGetter, error) {
|
||||
var kubeConfig *rest.Config
|
||||
var err error
|
||||
|
||||
if len(config.KubeConfigFile) == 0 && len(masterOverride) == 0 {
|
||||
glog.Info("Neither kubeconfig file nor master URL was specified. Falling back to in-cluster config.")
|
||||
kubeConfig, err = rest.InClusterConfig()
|
||||
} else {
|
||||
// This creates a client, first loading any specified kubeconfig
|
||||
// file, and then overriding the Master flag, if non-empty.
|
||||
kubeConfig, err = clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
|
||||
&clientcmd.ClientConfigLoadingRules{ExplicitPath: config.KubeConfigFile},
|
||||
&clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterOverride}}).ClientConfig()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
kubeConfig.AcceptContentTypes = config.AcceptContentTypes
|
||||
kubeConfig.ContentType = config.ContentType
|
||||
kubeConfig.QPS = config.QPS
|
||||
//TODO make config struct use int instead of int32?
|
||||
kubeConfig.Burst = int(config.Burst)
|
||||
|
||||
client, err := clientset.NewForConfig(kubeConfig)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
eventClient, err := clientgoclientset.NewForConfig(kubeConfig)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return client, eventClient.CoreV1(), nil
|
||||
}
|
||||
|
||||
// Run runs the specified ProxyServer. This should never exit (unless CleanupAndExit is set).
|
||||
func (s *ProxyServer) Run() error {
|
||||
// To help debugging, immediately log version
|
||||
glog.Infof("Version: %+v", version.Get())
|
||||
// remove iptables rules and exit
|
||||
if s.CleanupAndExit {
|
||||
encounteredError := userspace.CleanupLeftovers(s.IptInterface)
|
||||
encounteredError = iptables.CleanupLeftovers(s.IptInterface) || encounteredError
|
||||
encounteredError = ipvs.CleanupLeftovers(s.IpvsInterface, s.IptInterface, s.IpsetInterface, s.CleanupIPVS) || encounteredError
|
||||
if encounteredError {
|
||||
return errors.New("encountered an error while tearing down rules.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO(vmarmol): Use container config for this.
|
||||
var oomAdjuster *oom.OOMAdjuster
|
||||
if s.OOMScoreAdj != nil {
|
||||
oomAdjuster = oom.NewOOMAdjuster()
|
||||
if err := oomAdjuster.ApplyOOMScoreAdj(0, int(*s.OOMScoreAdj)); err != nil {
|
||||
glog.V(2).Info(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.ResourceContainer) != 0 {
|
||||
// Run in its own container.
|
||||
if err := resourcecontainer.RunInResourceContainer(s.ResourceContainer); err != nil {
|
||||
glog.Warningf("Failed to start in resource-only container %q: %v", s.ResourceContainer, err)
|
||||
} else {
|
||||
glog.V(2).Infof("Running in resource-only container %q", s.ResourceContainer)
|
||||
}
|
||||
}
|
||||
|
||||
if s.Broadcaster != nil && s.EventClient != nil {
|
||||
s.Broadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: s.EventClient.Events("")})
|
||||
}
|
||||
|
||||
// Start up a healthz server if requested
|
||||
if s.HealthzServer != nil {
|
||||
s.HealthzServer.Run()
|
||||
}
|
||||
|
||||
// Start up a metrics server if requested
|
||||
if len(s.MetricsBindAddress) > 0 {
|
||||
mux := http.NewServeMux()
|
||||
healthz.InstallHandler(mux)
|
||||
mux.HandleFunc("/proxyMode", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "%s", s.ProxyMode)
|
||||
})
|
||||
mux.Handle("/metrics", prometheus.Handler())
|
||||
if s.EnableProfiling {
|
||||
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
||||
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
}
|
||||
configz.InstallHandler(mux)
|
||||
go wait.Until(func() {
|
||||
err := http.ListenAndServe(s.MetricsBindAddress, mux)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("starting metrics server failed: %v", err))
|
||||
}
|
||||
}, 5*time.Second, wait.NeverStop)
|
||||
}
|
||||
|
||||
// Tune conntrack, if requested
|
||||
// Conntracker is always nil for windows
|
||||
if s.Conntracker != nil {
|
||||
max, err := getConntrackMax(s.ConntrackConfiguration)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if max > 0 {
|
||||
err := s.Conntracker.SetMax(max)
|
||||
if err != nil {
|
||||
if err != readOnlySysFSError {
|
||||
return err
|
||||
}
|
||||
// readOnlySysFSError is caused by a known docker issue (https://github.com/docker/docker/issues/24000),
|
||||
// the only remediation we know is to restart the docker daemon.
|
||||
// Here we'll send an node event with specific reason and message, the
|
||||
// administrator should decide whether and how to handle this issue,
|
||||
// whether to drain the node and restart docker.
|
||||
// TODO(random-liu): Remove this when the docker bug is fixed.
|
||||
const message = "DOCKER RESTART NEEDED (docker issue #24000): /sys is read-only: " +
|
||||
"cannot modify conntrack limits, problems may arise later."
|
||||
s.Recorder.Eventf(s.NodeRef, api.EventTypeWarning, err.Error(), message)
|
||||
}
|
||||
}
|
||||
|
||||
if s.ConntrackConfiguration.TCPEstablishedTimeout != nil && s.ConntrackConfiguration.TCPEstablishedTimeout.Duration > 0 {
|
||||
timeout := int(s.ConntrackConfiguration.TCPEstablishedTimeout.Duration / time.Second)
|
||||
if err := s.Conntracker.SetTCPEstablishedTimeout(timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.ConntrackConfiguration.TCPCloseWaitTimeout != nil && s.ConntrackConfiguration.TCPCloseWaitTimeout.Duration > 0 {
|
||||
timeout := int(s.ConntrackConfiguration.TCPCloseWaitTimeout.Duration / time.Second)
|
||||
if err := s.Conntracker.SetTCPCloseWaitTimeout(timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
informerFactory := informers.NewSharedInformerFactory(s.Client, s.ConfigSyncPeriod)
|
||||
|
||||
// Create configs (i.e. Watches for Services and Endpoints)
|
||||
// Note: RegisterHandler() calls need to happen before creation of Sources because sources
|
||||
// only notify on changes, and the initial update (on process start) may be lost if no handlers
|
||||
// are registered yet.
|
||||
serviceConfig := config.NewServiceConfig(informerFactory.Core().InternalVersion().Services(), s.ConfigSyncPeriod)
|
||||
serviceConfig.RegisterEventHandler(s.ServiceEventHandler)
|
||||
go serviceConfig.Run(wait.NeverStop)
|
||||
|
||||
endpointsConfig := config.NewEndpointsConfig(informerFactory.Core().InternalVersion().Endpoints(), s.ConfigSyncPeriod)
|
||||
endpointsConfig.RegisterEventHandler(s.EndpointsEventHandler)
|
||||
go endpointsConfig.Run(wait.NeverStop)
|
||||
|
||||
// This has to start after the calls to NewServiceConfig and NewEndpointsConfig because those
|
||||
// functions must configure their shared informer event handlers first.
|
||||
go informerFactory.Start(wait.NeverStop)
|
||||
|
||||
// Birth Cry after the birth is successful
|
||||
s.birthCry()
|
||||
|
||||
// Just loop forever for now...
|
||||
s.Proxier.SyncLoop()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ProxyServer) birthCry() {
|
||||
s.Recorder.Eventf(s.NodeRef, api.EventTypeNormal, "Starting", "Starting kube-proxy.")
|
||||
}
|
||||
|
||||
func getConntrackMax(config kubeproxyconfig.KubeProxyConntrackConfiguration) (int, error) {
|
||||
if config.Max != nil && *config.Max > 0 {
|
||||
if config.MaxPerCore != nil && *config.MaxPerCore > 0 {
|
||||
return -1, fmt.Errorf("invalid config: Conntrack Max and Conntrack MaxPerCore are mutually exclusive")
|
||||
}
|
||||
glog.V(3).Infof("getConntrackMax: using absolute conntrack-max (deprecated)")
|
||||
return int(*config.Max), nil
|
||||
}
|
||||
if config.MaxPerCore != nil && *config.MaxPerCore > 0 {
|
||||
floor := 0
|
||||
if config.Min != nil {
|
||||
floor = int(*config.Min)
|
||||
}
|
||||
scaled := int(*config.MaxPerCore) * goruntime.NumCPU()
|
||||
if scaled > floor {
|
||||
glog.V(3).Infof("getConntrackMax: using scaled conntrack-max-per-core")
|
||||
return scaled, nil
|
||||
}
|
||||
glog.V(3).Infof("getConntrackMax: using conntrack-min")
|
||||
return floor, nil
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func getNodeIP(client clientset.Interface, hostname string) net.IP {
|
||||
var nodeIP net.IP
|
||||
node, err := client.Core().Nodes().Get(hostname, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
glog.Warningf("Failed to retrieve node info: %v", err)
|
||||
return nil
|
||||
}
|
||||
nodeIP, err = utilnode.InternalGetNodeHostIP(node)
|
||||
if err != nil {
|
||||
glog.Warningf("Failed to retrieve node IP: %v", err)
|
||||
return nil
|
||||
}
|
||||
return nodeIP
|
||||
}
|
323
vendor/k8s.io/kubernetes/cmd/kube-proxy/app/server_others.go
generated
vendored
Normal file
323
vendor/k8s.io/kubernetes/cmd/kube-proxy/app/server_others.go
generated
vendored
Normal file
@ -0,0 +1,323 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package app does all of the work necessary to configure and run a
|
||||
// Kubernetes app process.
|
||||
package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/proxy"
|
||||
proxyconfigapi "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig"
|
||||
proxyconfig "k8s.io/kubernetes/pkg/proxy/config"
|
||||
"k8s.io/kubernetes/pkg/proxy/healthcheck"
|
||||
"k8s.io/kubernetes/pkg/proxy/iptables"
|
||||
"k8s.io/kubernetes/pkg/proxy/ipvs"
|
||||
"k8s.io/kubernetes/pkg/proxy/metrics"
|
||||
"k8s.io/kubernetes/pkg/proxy/userspace"
|
||||
"k8s.io/kubernetes/pkg/util/configz"
|
||||
utildbus "k8s.io/kubernetes/pkg/util/dbus"
|
||||
utilipset "k8s.io/kubernetes/pkg/util/ipset"
|
||||
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
|
||||
utilipvs "k8s.io/kubernetes/pkg/util/ipvs"
|
||||
utilnode "k8s.io/kubernetes/pkg/util/node"
|
||||
utilsysctl "k8s.io/kubernetes/pkg/util/sysctl"
|
||||
"k8s.io/utils/exec"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// NewProxyServer returns a new ProxyServer.
|
||||
func NewProxyServer(o *Options) (*ProxyServer, error) {
|
||||
return newProxyServer(o.config, o.CleanupAndExit, o.CleanupIPVS, o.scheme, o.master)
|
||||
}
|
||||
|
||||
func newProxyServer(
|
||||
config *proxyconfigapi.KubeProxyConfiguration,
|
||||
cleanupAndExit bool,
|
||||
cleanupIPVS bool,
|
||||
scheme *runtime.Scheme,
|
||||
master string) (*ProxyServer, error) {
|
||||
|
||||
if config == nil {
|
||||
return nil, errors.New("config is required")
|
||||
}
|
||||
|
||||
if c, err := configz.New(proxyconfigapi.GroupName); err == nil {
|
||||
c.Set(config)
|
||||
} else {
|
||||
return nil, fmt.Errorf("unable to register configz: %s", err)
|
||||
}
|
||||
|
||||
protocol := utiliptables.ProtocolIpv4
|
||||
if net.ParseIP(config.BindAddress).To4() == nil {
|
||||
glog.V(0).Infof("IPv6 bind address (%s), assume IPv6 operation", config.BindAddress)
|
||||
protocol = utiliptables.ProtocolIpv6
|
||||
}
|
||||
|
||||
var iptInterface utiliptables.Interface
|
||||
var ipvsInterface utilipvs.Interface
|
||||
var ipsetInterface utilipset.Interface
|
||||
var dbus utildbus.Interface
|
||||
|
||||
// Create a iptables utils.
|
||||
execer := exec.New()
|
||||
|
||||
dbus = utildbus.New()
|
||||
iptInterface = utiliptables.New(execer, dbus, protocol)
|
||||
ipvsInterface = utilipvs.New(execer)
|
||||
ipsetInterface = utilipset.New(execer)
|
||||
|
||||
// We omit creation of pretty much everything if we run in cleanup mode
|
||||
if cleanupAndExit {
|
||||
return &ProxyServer{
|
||||
execer: execer,
|
||||
IptInterface: iptInterface,
|
||||
IpvsInterface: ipvsInterface,
|
||||
IpsetInterface: ipsetInterface,
|
||||
CleanupAndExit: cleanupAndExit,
|
||||
}, nil
|
||||
}
|
||||
|
||||
client, eventClient, err := createClients(config.ClientConnection, master)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create event recorder
|
||||
hostname := utilnode.GetHostname(config.HostnameOverride)
|
||||
eventBroadcaster := record.NewBroadcaster()
|
||||
recorder := eventBroadcaster.NewRecorder(scheme, v1.EventSource{Component: "kube-proxy", Host: hostname})
|
||||
|
||||
nodeRef := &v1.ObjectReference{
|
||||
Kind: "Node",
|
||||
Name: hostname,
|
||||
UID: types.UID(hostname),
|
||||
Namespace: "",
|
||||
}
|
||||
|
||||
var healthzServer *healthcheck.HealthzServer
|
||||
var healthzUpdater healthcheck.HealthzUpdater
|
||||
if len(config.HealthzBindAddress) > 0 {
|
||||
healthzServer = healthcheck.NewDefaultHealthzServer(config.HealthzBindAddress, 2*config.IPTables.SyncPeriod.Duration, recorder, nodeRef)
|
||||
healthzUpdater = healthzServer
|
||||
}
|
||||
|
||||
var proxier proxy.ProxyProvider
|
||||
var serviceEventHandler proxyconfig.ServiceHandler
|
||||
var endpointsEventHandler proxyconfig.EndpointsHandler
|
||||
|
||||
proxyMode := getProxyMode(string(config.Mode), iptInterface, ipsetInterface, iptables.LinuxKernelCompatTester{})
|
||||
if proxyMode == proxyModeIPTables {
|
||||
glog.V(0).Info("Using iptables Proxier.")
|
||||
nodeIP := net.ParseIP(config.BindAddress)
|
||||
if nodeIP.Equal(net.IPv4zero) || nodeIP.Equal(net.IPv6zero) {
|
||||
nodeIP = getNodeIP(client, hostname)
|
||||
}
|
||||
if config.IPTables.MasqueradeBit == nil {
|
||||
// MasqueradeBit must be specified or defaulted.
|
||||
return nil, fmt.Errorf("unable to read IPTables MasqueradeBit from config")
|
||||
}
|
||||
|
||||
// TODO this has side effects that should only happen when Run() is invoked.
|
||||
proxierIPTables, err := iptables.NewProxier(
|
||||
iptInterface,
|
||||
utilsysctl.New(),
|
||||
execer,
|
||||
config.IPTables.SyncPeriod.Duration,
|
||||
config.IPTables.MinSyncPeriod.Duration,
|
||||
config.IPTables.MasqueradeAll,
|
||||
int(*config.IPTables.MasqueradeBit),
|
||||
config.ClusterCIDR,
|
||||
hostname,
|
||||
nodeIP,
|
||||
recorder,
|
||||
healthzUpdater,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create proxier: %v", err)
|
||||
}
|
||||
metrics.RegisterMetrics()
|
||||
proxier = proxierIPTables
|
||||
serviceEventHandler = proxierIPTables
|
||||
endpointsEventHandler = proxierIPTables
|
||||
// No turning back. Remove artifacts that might still exist from the userspace Proxier.
|
||||
glog.V(0).Info("Tearing down inactive rules.")
|
||||
// TODO this has side effects that should only happen when Run() is invoked.
|
||||
userspace.CleanupLeftovers(iptInterface)
|
||||
// IPVS Proxier will generate some iptables rules, need to clean them before switching to other proxy mode.
|
||||
// Besides, ipvs proxier will create some ipvs rules as well. Because there is no way to tell if a given
|
||||
// ipvs rule is created by IPVS proxier or not. Users should explicitly specify `--clean-ipvs=true` to flush
|
||||
// all ipvs rules when kube-proxy start up. Users do this operation should be with caution.
|
||||
ipvs.CleanupLeftovers(ipvsInterface, iptInterface, ipsetInterface, cleanupIPVS)
|
||||
} else if proxyMode == proxyModeIPVS {
|
||||
glog.V(0).Info("Using ipvs Proxier.")
|
||||
proxierIPVS, err := ipvs.NewProxier(
|
||||
iptInterface,
|
||||
ipvsInterface,
|
||||
ipsetInterface,
|
||||
utilsysctl.New(),
|
||||
execer,
|
||||
config.IPVS.SyncPeriod.Duration,
|
||||
config.IPVS.MinSyncPeriod.Duration,
|
||||
config.IPTables.MasqueradeAll,
|
||||
int(*config.IPTables.MasqueradeBit),
|
||||
config.ClusterCIDR,
|
||||
hostname,
|
||||
getNodeIP(client, hostname),
|
||||
recorder,
|
||||
healthzServer,
|
||||
config.IPVS.Scheduler,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create proxier: %v", err)
|
||||
}
|
||||
metrics.RegisterMetrics()
|
||||
proxier = proxierIPVS
|
||||
serviceEventHandler = proxierIPVS
|
||||
endpointsEventHandler = proxierIPVS
|
||||
glog.V(0).Info("Tearing down inactive rules.")
|
||||
// TODO this has side effects that should only happen when Run() is invoked.
|
||||
userspace.CleanupLeftovers(iptInterface)
|
||||
iptables.CleanupLeftovers(iptInterface)
|
||||
} else {
|
||||
glog.V(0).Info("Using userspace Proxier.")
|
||||
// This is a proxy.LoadBalancer which NewProxier needs but has methods we don't need for
|
||||
// our config.EndpointsConfigHandler.
|
||||
loadBalancer := userspace.NewLoadBalancerRR()
|
||||
// set EndpointsConfigHandler to our loadBalancer
|
||||
endpointsEventHandler = loadBalancer
|
||||
|
||||
// TODO this has side effects that should only happen when Run() is invoked.
|
||||
proxierUserspace, err := userspace.NewProxier(
|
||||
loadBalancer,
|
||||
net.ParseIP(config.BindAddress),
|
||||
iptInterface,
|
||||
execer,
|
||||
*utilnet.ParsePortRangeOrDie(config.PortRange),
|
||||
config.IPTables.SyncPeriod.Duration,
|
||||
config.IPTables.MinSyncPeriod.Duration,
|
||||
config.UDPIdleTimeout.Duration,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create proxier: %v", err)
|
||||
}
|
||||
serviceEventHandler = proxierUserspace
|
||||
proxier = proxierUserspace
|
||||
|
||||
// Remove artifacts from the iptables and ipvs Proxier, if not on Windows.
|
||||
glog.V(0).Info("Tearing down inactive rules.")
|
||||
// TODO this has side effects that should only happen when Run() is invoked.
|
||||
iptables.CleanupLeftovers(iptInterface)
|
||||
// IPVS Proxier will generate some iptables rules, need to clean them before switching to other proxy mode.
|
||||
// Besides, ipvs proxier will create some ipvs rules as well. Because there is no way to tell if a given
|
||||
// ipvs rule is created by IPVS proxier or not. Users should explicitly specify `--clean-ipvs=true` to flush
|
||||
// all ipvs rules when kube-proxy start up. Users do this operation should be with caution.
|
||||
ipvs.CleanupLeftovers(ipvsInterface, iptInterface, ipsetInterface, cleanupIPVS)
|
||||
}
|
||||
|
||||
iptInterface.AddReloadFunc(proxier.Sync)
|
||||
|
||||
return &ProxyServer{
|
||||
Client: client,
|
||||
EventClient: eventClient,
|
||||
IptInterface: iptInterface,
|
||||
IpvsInterface: ipvsInterface,
|
||||
IpsetInterface: ipsetInterface,
|
||||
execer: execer,
|
||||
Proxier: proxier,
|
||||
Broadcaster: eventBroadcaster,
|
||||
Recorder: recorder,
|
||||
ConntrackConfiguration: config.Conntrack,
|
||||
Conntracker: &realConntracker{},
|
||||
ProxyMode: proxyMode,
|
||||
NodeRef: nodeRef,
|
||||
MetricsBindAddress: config.MetricsBindAddress,
|
||||
EnableProfiling: config.EnableProfiling,
|
||||
OOMScoreAdj: config.OOMScoreAdj,
|
||||
ResourceContainer: config.ResourceContainer,
|
||||
ConfigSyncPeriod: config.ConfigSyncPeriod.Duration,
|
||||
ServiceEventHandler: serviceEventHandler,
|
||||
EndpointsEventHandler: endpointsEventHandler,
|
||||
HealthzServer: healthzServer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getProxyMode(proxyMode string, iptver iptables.IPTablesVersioner, ipsetver ipvs.IPSetVersioner, kcompat iptables.KernelCompatTester) string {
|
||||
if proxyMode == proxyModeUserspace {
|
||||
return proxyModeUserspace
|
||||
}
|
||||
|
||||
if len(proxyMode) > 0 && proxyMode == proxyModeIPTables {
|
||||
return tryIPTablesProxy(iptver, kcompat)
|
||||
}
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.SupportIPVSProxyMode) {
|
||||
if proxyMode == proxyModeIPVS {
|
||||
return tryIPVSProxy(iptver, ipsetver, kcompat)
|
||||
} else {
|
||||
glog.Warningf("Can't use ipvs proxier, trying iptables proxier")
|
||||
return tryIPTablesProxy(iptver, kcompat)
|
||||
}
|
||||
}
|
||||
glog.Warningf("Flag proxy-mode=%q unknown, assuming iptables proxy", proxyMode)
|
||||
return tryIPTablesProxy(iptver, kcompat)
|
||||
}
|
||||
|
||||
func tryIPVSProxy(iptver iptables.IPTablesVersioner, ipsetver ipvs.IPSetVersioner, kcompat iptables.KernelCompatTester) string {
|
||||
// guaranteed false on error, error only necessary for debugging
|
||||
// IPVS Proxier relies on ipset
|
||||
useIPVSProxy, err := ipvs.CanUseIPVSProxier(ipsetver)
|
||||
if err != nil {
|
||||
// Try to fallback to iptables before falling back to userspace
|
||||
utilruntime.HandleError(fmt.Errorf("can't determine whether to use ipvs proxy, error: %v", err))
|
||||
}
|
||||
if useIPVSProxy {
|
||||
return proxyModeIPVS
|
||||
}
|
||||
|
||||
// Try to fallback to iptables before falling back to userspace
|
||||
glog.V(1).Infof("Can't use ipvs proxier, trying iptables proxier")
|
||||
return tryIPTablesProxy(iptver, kcompat)
|
||||
}
|
||||
|
||||
func tryIPTablesProxy(iptver iptables.IPTablesVersioner, kcompat iptables.KernelCompatTester) string {
|
||||
// guaranteed false on error, error only necessary for debugging
|
||||
useIPTablesProxy, err := iptables.CanUseIPTablesProxier(iptver, kcompat)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("can't determine whether to use iptables proxy, using userspace proxier: %v", err))
|
||||
return proxyModeUserspace
|
||||
}
|
||||
if useIPTablesProxy {
|
||||
return proxyModeIPTables
|
||||
}
|
||||
// Fallback.
|
||||
glog.V(1).Infof("Can't use iptables proxy, using userspace proxier")
|
||||
return proxyModeUserspace
|
||||
}
|
431
vendor/k8s.io/kubernetes/cmd/kube-proxy/app/server_test.go
generated
vendored
Normal file
431
vendor/k8s.io/kubernetes/cmd/kube-proxy/app/server_test.go
generated
vendored
Normal file
@ -0,0 +1,431 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig"
|
||||
"k8s.io/kubernetes/pkg/util/configz"
|
||||
"k8s.io/kubernetes/pkg/util/iptables"
|
||||
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
|
||||
)
|
||||
|
||||
type fakeNodeInterface struct {
|
||||
node api.Node
|
||||
}
|
||||
|
||||
func (fake *fakeNodeInterface) Get(hostname string, options metav1.GetOptions) (*api.Node, error) {
|
||||
return &fake.node, nil
|
||||
}
|
||||
|
||||
type fakeIPTablesVersioner struct {
|
||||
version string // what to return
|
||||
err error // what to return
|
||||
}
|
||||
|
||||
func (fake *fakeIPTablesVersioner) GetVersion() (string, error) {
|
||||
return fake.version, fake.err
|
||||
}
|
||||
|
||||
type fakeIPSetVersioner struct {
|
||||
version string // what to return
|
||||
err error // what to return
|
||||
}
|
||||
|
||||
func (fake *fakeIPSetVersioner) GetVersion() (string, error) {
|
||||
return fake.version, fake.err
|
||||
}
|
||||
|
||||
type fakeKernelCompatTester struct {
|
||||
ok bool
|
||||
}
|
||||
|
||||
func (fake *fakeKernelCompatTester) IsCompatible() error {
|
||||
if !fake.ok {
|
||||
return fmt.Errorf("error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Test_getProxyMode(t *testing.T) {
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skip("skipping on non-Linux")
|
||||
}
|
||||
var cases = []struct {
|
||||
flag string
|
||||
annotationKey string
|
||||
annotationVal string
|
||||
iptablesVersion string
|
||||
ipsetVersion string
|
||||
kernelCompat bool
|
||||
iptablesError error
|
||||
ipsetError error
|
||||
expected string
|
||||
}{
|
||||
{ // flag says userspace
|
||||
flag: "userspace",
|
||||
expected: proxyModeUserspace,
|
||||
},
|
||||
{ // flag says iptables, error detecting version
|
||||
flag: "iptables",
|
||||
iptablesError: fmt.Errorf("oops!"),
|
||||
expected: proxyModeUserspace,
|
||||
},
|
||||
{ // flag says iptables, version too low
|
||||
flag: "iptables",
|
||||
iptablesVersion: "0.0.0",
|
||||
expected: proxyModeUserspace,
|
||||
},
|
||||
{ // flag says iptables, version ok, kernel not compatible
|
||||
flag: "iptables",
|
||||
iptablesVersion: iptables.MinCheckVersion,
|
||||
kernelCompat: false,
|
||||
expected: proxyModeUserspace,
|
||||
},
|
||||
{ // flag says iptables, version ok, kernel is compatible
|
||||
flag: "iptables",
|
||||
iptablesVersion: iptables.MinCheckVersion,
|
||||
kernelCompat: true,
|
||||
expected: proxyModeIPTables,
|
||||
},
|
||||
{ // detect, error
|
||||
flag: "",
|
||||
iptablesError: fmt.Errorf("oops!"),
|
||||
expected: proxyModeUserspace,
|
||||
},
|
||||
{ // detect, version too low
|
||||
flag: "",
|
||||
iptablesVersion: "0.0.0",
|
||||
expected: proxyModeUserspace,
|
||||
},
|
||||
{ // detect, version ok, kernel not compatible
|
||||
flag: "",
|
||||
iptablesVersion: iptables.MinCheckVersion,
|
||||
kernelCompat: false,
|
||||
expected: proxyModeUserspace,
|
||||
},
|
||||
{ // detect, version ok, kernel is compatible
|
||||
flag: "",
|
||||
iptablesVersion: iptables.MinCheckVersion,
|
||||
kernelCompat: true,
|
||||
expected: proxyModeIPTables,
|
||||
},
|
||||
}
|
||||
for i, c := range cases {
|
||||
versioner := &fakeIPTablesVersioner{c.iptablesVersion, c.iptablesError}
|
||||
kcompater := &fakeKernelCompatTester{c.kernelCompat}
|
||||
ipsetver := &fakeIPSetVersioner{c.ipsetVersion, c.ipsetError}
|
||||
r := getProxyMode(c.flag, versioner, ipsetver, kcompater)
|
||||
if r != c.expected {
|
||||
t.Errorf("Case[%d] Expected %q, got %q", i, c.expected, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This test verifies that NewProxyServer does not crash when CleanupAndExit is true.
|
||||
func TestProxyServerWithCleanupAndExit(t *testing.T) {
|
||||
// Each bind address below is a separate test case
|
||||
bindAddresses := []string{
|
||||
"0.0.0.0",
|
||||
"::",
|
||||
}
|
||||
for _, addr := range bindAddresses {
|
||||
options := NewOptions()
|
||||
|
||||
options.config = &kubeproxyconfig.KubeProxyConfiguration{
|
||||
BindAddress: addr,
|
||||
}
|
||||
options.CleanupAndExit = true
|
||||
|
||||
proxyserver, err := NewProxyServer(options)
|
||||
|
||||
assert.Nil(t, err, "unexpected error in NewProxyServer, addr: %s", addr)
|
||||
assert.NotNil(t, proxyserver, "nil proxy server obj, addr: %s", addr)
|
||||
assert.NotNil(t, proxyserver.IptInterface, "nil iptables intf, addr: %s", addr)
|
||||
assert.True(t, proxyserver.CleanupAndExit, "false CleanupAndExit, addr: %s", addr)
|
||||
|
||||
// Clean up config for next test case
|
||||
configz.Delete(kubeproxyconfig.GroupName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConntrackMax(t *testing.T) {
|
||||
ncores := runtime.NumCPU()
|
||||
testCases := []struct {
|
||||
min int32
|
||||
max int32
|
||||
maxPerCore int32
|
||||
expected int
|
||||
err string
|
||||
}{
|
||||
{
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
max: 12345,
|
||||
expected: 12345,
|
||||
},
|
||||
{
|
||||
max: 12345,
|
||||
maxPerCore: 67890,
|
||||
expected: -1,
|
||||
err: "mutually exclusive",
|
||||
},
|
||||
{
|
||||
maxPerCore: 67890, // use this if Max is 0
|
||||
min: 1, // avoid 0 default
|
||||
expected: 67890 * ncores,
|
||||
},
|
||||
{
|
||||
maxPerCore: 1, // ensure that Min is considered
|
||||
min: 123456,
|
||||
expected: 123456,
|
||||
},
|
||||
{
|
||||
maxPerCore: 0, // leave system setting
|
||||
min: 123456,
|
||||
expected: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
cfg := kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
Min: utilpointer.Int32Ptr(tc.min),
|
||||
Max: utilpointer.Int32Ptr(tc.max),
|
||||
MaxPerCore: utilpointer.Int32Ptr(tc.maxPerCore),
|
||||
}
|
||||
x, e := getConntrackMax(cfg)
|
||||
if e != nil {
|
||||
if tc.err == "" {
|
||||
t.Errorf("[%d] unexpected error: %v", i, e)
|
||||
} else if !strings.Contains(e.Error(), tc.err) {
|
||||
t.Errorf("[%d] expected an error containing %q: %v", i, tc.err, e)
|
||||
}
|
||||
} else if x != tc.expected {
|
||||
t.Errorf("[%d] expected %d, got %d", i, tc.expected, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadConfig tests proper operation of loadConfig()
|
||||
func TestLoadConfig(t *testing.T) {
|
||||
|
||||
yamlTemplate := `apiVersion: kubeproxy.config.k8s.io/v1alpha1
|
||||
bindAddress: %s
|
||||
clientConnection:
|
||||
acceptContentTypes: "abc"
|
||||
burst: 100
|
||||
contentType: content-type
|
||||
kubeconfig: "/path/to/kubeconfig"
|
||||
qps: 7
|
||||
clusterCIDR: "%s"
|
||||
configSyncPeriod: 15s
|
||||
conntrack:
|
||||
max: 4
|
||||
maxPerCore: 2
|
||||
min: 1
|
||||
tcpCloseWaitTimeout: 10s
|
||||
tcpEstablishedTimeout: 20s
|
||||
featureGates: "all"
|
||||
healthzBindAddress: "%s"
|
||||
hostnameOverride: "foo"
|
||||
iptables:
|
||||
masqueradeAll: true
|
||||
masqueradeBit: 17
|
||||
minSyncPeriod: 10s
|
||||
syncPeriod: 60s
|
||||
ipvs:
|
||||
minSyncPeriod: 10s
|
||||
syncPeriod: 60s
|
||||
kind: KubeProxyConfiguration
|
||||
metricsBindAddress: "%s"
|
||||
mode: "%s"
|
||||
oomScoreAdj: 17
|
||||
portRange: "2-7"
|
||||
resourceContainer: /foo
|
||||
udpTimeoutMilliseconds: 123ms
|
||||
`
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
mode string
|
||||
bindAddress string
|
||||
clusterCIDR string
|
||||
healthzBindAddress string
|
||||
metricsBindAddress string
|
||||
}{
|
||||
{
|
||||
name: "iptables mode, IPv4 all-zeros bind address",
|
||||
mode: "iptables",
|
||||
bindAddress: "0.0.0.0",
|
||||
clusterCIDR: "1.2.3.0/24",
|
||||
healthzBindAddress: "1.2.3.4:12345",
|
||||
metricsBindAddress: "2.3.4.5:23456",
|
||||
},
|
||||
{
|
||||
name: "iptables mode, non-zeros IPv4 config",
|
||||
mode: "iptables",
|
||||
bindAddress: "9.8.7.6",
|
||||
clusterCIDR: "1.2.3.0/24",
|
||||
healthzBindAddress: "1.2.3.4:12345",
|
||||
metricsBindAddress: "2.3.4.5:23456",
|
||||
},
|
||||
{
|
||||
// Test for 'bindAddress: "::"' (IPv6 all-zeros) in kube-proxy
|
||||
// config file. The user will need to put quotes around '::' since
|
||||
// 'bindAddress: ::' is invalid yaml syntax.
|
||||
name: "iptables mode, IPv6 \"::\" bind address",
|
||||
mode: "iptables",
|
||||
bindAddress: "\"::\"",
|
||||
clusterCIDR: "fd00:1::0/64",
|
||||
healthzBindAddress: "[fd00:1::5]:12345",
|
||||
metricsBindAddress: "[fd00:2::5]:23456",
|
||||
},
|
||||
{
|
||||
// Test for 'bindAddress: "[::]"' (IPv6 all-zeros in brackets)
|
||||
// in kube-proxy config file. The user will need to use
|
||||
// surrounding quotes here since 'bindAddress: [::]' is invalid
|
||||
// yaml syntax.
|
||||
name: "iptables mode, IPv6 \"[::]\" bind address",
|
||||
mode: "iptables",
|
||||
bindAddress: "\"[::]\"",
|
||||
clusterCIDR: "fd00:1::0/64",
|
||||
healthzBindAddress: "[fd00:1::5]:12345",
|
||||
metricsBindAddress: "[fd00:2::5]:23456",
|
||||
},
|
||||
{
|
||||
// Test for 'bindAddress: ::0' (another form of IPv6 all-zeros).
|
||||
// No surrounding quotes are required around '::0'.
|
||||
name: "iptables mode, IPv6 ::0 bind address",
|
||||
mode: "iptables",
|
||||
bindAddress: "::0",
|
||||
clusterCIDR: "fd00:1::0/64",
|
||||
healthzBindAddress: "[fd00:1::5]:12345",
|
||||
metricsBindAddress: "[fd00:2::5]:23456",
|
||||
},
|
||||
{
|
||||
name: "ipvs mode, IPv6 config",
|
||||
mode: "ipvs",
|
||||
bindAddress: "2001:db8::1",
|
||||
clusterCIDR: "fd00:1::0/64",
|
||||
healthzBindAddress: "[fd00:1::5]:12345",
|
||||
metricsBindAddress: "[fd00:2::5]:23456",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
expBindAddr := tc.bindAddress
|
||||
if tc.bindAddress[0] == '"' {
|
||||
// Surrounding double quotes will get stripped by the yaml parser.
|
||||
expBindAddr = expBindAddr[1 : len(tc.bindAddress)-1]
|
||||
}
|
||||
expected := &kubeproxyconfig.KubeProxyConfiguration{
|
||||
BindAddress: expBindAddr,
|
||||
ClientConnection: kubeproxyconfig.ClientConnectionConfiguration{
|
||||
AcceptContentTypes: "abc",
|
||||
Burst: 100,
|
||||
ContentType: "content-type",
|
||||
KubeConfigFile: "/path/to/kubeconfig",
|
||||
QPS: 7,
|
||||
},
|
||||
ClusterCIDR: tc.clusterCIDR,
|
||||
ConfigSyncPeriod: metav1.Duration{Duration: 15 * time.Second},
|
||||
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||
Max: utilpointer.Int32Ptr(4),
|
||||
MaxPerCore: utilpointer.Int32Ptr(2),
|
||||
Min: utilpointer.Int32Ptr(1),
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 10 * time.Second},
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 20 * time.Second},
|
||||
},
|
||||
FeatureGates: "all",
|
||||
HealthzBindAddress: tc.healthzBindAddress,
|
||||
HostnameOverride: "foo",
|
||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
MasqueradeBit: utilpointer.Int32Ptr(17),
|
||||
MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
SyncPeriod: metav1.Duration{Duration: 60 * time.Second},
|
||||
},
|
||||
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||
MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
SyncPeriod: metav1.Duration{Duration: 60 * time.Second},
|
||||
},
|
||||
MetricsBindAddress: tc.metricsBindAddress,
|
||||
Mode: kubeproxyconfig.ProxyMode(tc.mode),
|
||||
OOMScoreAdj: utilpointer.Int32Ptr(17),
|
||||
PortRange: "2-7",
|
||||
ResourceContainer: "/foo",
|
||||
UDPIdleTimeout: metav1.Duration{Duration: 123 * time.Millisecond},
|
||||
}
|
||||
|
||||
options := NewOptions()
|
||||
|
||||
yaml := fmt.Sprintf(
|
||||
yamlTemplate, tc.bindAddress, tc.clusterCIDR,
|
||||
tc.healthzBindAddress, tc.metricsBindAddress, tc.mode)
|
||||
config, err := options.loadConfig([]byte(yaml))
|
||||
assert.NoError(t, err, "unexpected error for %s: %v", tc.name, err)
|
||||
if !reflect.DeepEqual(expected, config) {
|
||||
t.Fatalf("unexpected config for %s, diff = %s", tc.name, diff.ObjectDiff(config, expected))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadConfigFailures tests failure modes for loadConfig()
|
||||
func TestLoadConfigFailures(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
config string
|
||||
expErr string
|
||||
}{
|
||||
{
|
||||
name: "Decode error test",
|
||||
config: "Twas bryllyg, and ye slythy toves",
|
||||
expErr: "could not find expected ':'",
|
||||
},
|
||||
{
|
||||
name: "Bad config type test",
|
||||
config: "kind: KubeSchedulerConfiguration",
|
||||
expErr: "no kind",
|
||||
},
|
||||
{
|
||||
name: "Missing quotes around :: bindAddress",
|
||||
config: "bindAddress: ::",
|
||||
expErr: "mapping values are not allowed in this context",
|
||||
},
|
||||
}
|
||||
version := "apiVersion: kubeproxy.config.k8s.io/v1alpha1"
|
||||
for _, tc := range testCases {
|
||||
options := NewOptions()
|
||||
config := fmt.Sprintf("%s\n%s", version, tc.config)
|
||||
_, err := options.loadConfig([]byte(config))
|
||||
if assert.Error(t, err, tc.name) {
|
||||
assert.Contains(t, err.Error(), tc.expErr, tc.name)
|
||||
}
|
||||
}
|
||||
}
|
191
vendor/k8s.io/kubernetes/cmd/kube-proxy/app/server_windows.go
generated
vendored
Normal file
191
vendor/k8s.io/kubernetes/cmd/kube-proxy/app/server_windows.go
generated
vendored
Normal file
@ -0,0 +1,191 @@
|
||||
// +build windows
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package app does all of the work necessary to configure and run a
|
||||
// Kubernetes app process.
|
||||
package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
_ "net/http/pprof"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/kubernetes/pkg/proxy"
|
||||
proxyconfigapi "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig"
|
||||
proxyconfig "k8s.io/kubernetes/pkg/proxy/config"
|
||||
"k8s.io/kubernetes/pkg/proxy/healthcheck"
|
||||
"k8s.io/kubernetes/pkg/proxy/winkernel"
|
||||
"k8s.io/kubernetes/pkg/proxy/winuserspace"
|
||||
"k8s.io/kubernetes/pkg/util/configz"
|
||||
utilnetsh "k8s.io/kubernetes/pkg/util/netsh"
|
||||
utilnode "k8s.io/kubernetes/pkg/util/node"
|
||||
"k8s.io/utils/exec"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// NewProxyServer returns a new ProxyServer.
|
||||
func NewProxyServer(o *Options) (*ProxyServer, error) {
|
||||
return newProxyServer(o.config, o.CleanupAndExit, o.scheme, o.master)
|
||||
}
|
||||
|
||||
func newProxyServer(config *proxyconfigapi.KubeProxyConfiguration, cleanupAndExit bool, scheme *runtime.Scheme, master string) (*ProxyServer, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("config is required")
|
||||
}
|
||||
|
||||
if c, err := configz.New(proxyconfigapi.GroupName); err == nil {
|
||||
c.Set(config)
|
||||
} else {
|
||||
return nil, fmt.Errorf("unable to register configz: %s", err)
|
||||
}
|
||||
|
||||
// We omit creation of pretty much everything if we run in cleanup mode
|
||||
if cleanupAndExit {
|
||||
return &ProxyServer{CleanupAndExit: cleanupAndExit}, nil
|
||||
}
|
||||
|
||||
client, eventClient, err := createClients(config.ClientConnection, master)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create event recorder
|
||||
hostname := utilnode.GetHostname(config.HostnameOverride)
|
||||
eventBroadcaster := record.NewBroadcaster()
|
||||
recorder := eventBroadcaster.NewRecorder(scheme, v1.EventSource{Component: "kube-proxy", Host: hostname})
|
||||
|
||||
nodeRef := &v1.ObjectReference{
|
||||
Kind: "Node",
|
||||
Name: hostname,
|
||||
UID: types.UID(hostname),
|
||||
Namespace: "",
|
||||
}
|
||||
|
||||
var healthzServer *healthcheck.HealthzServer
|
||||
var healthzUpdater healthcheck.HealthzUpdater
|
||||
if len(config.HealthzBindAddress) > 0 {
|
||||
healthzServer = healthcheck.NewDefaultHealthzServer(config.HealthzBindAddress, 2*config.IPTables.SyncPeriod.Duration, recorder, nodeRef)
|
||||
healthzUpdater = healthzServer
|
||||
}
|
||||
|
||||
var proxier proxy.ProxyProvider
|
||||
var serviceEventHandler proxyconfig.ServiceHandler
|
||||
var endpointsEventHandler proxyconfig.EndpointsHandler
|
||||
|
||||
proxyMode := getProxyMode(string(config.Mode), winkernel.WindowsKernelCompatTester{})
|
||||
if proxyMode == proxyModeKernelspace {
|
||||
glog.V(0).Info("Using Kernelspace Proxier.")
|
||||
proxierKernelspace, err := winkernel.NewProxier(
|
||||
config.IPTables.SyncPeriod.Duration,
|
||||
config.IPTables.MinSyncPeriod.Duration,
|
||||
config.IPTables.MasqueradeAll,
|
||||
int(*config.IPTables.MasqueradeBit),
|
||||
config.ClusterCIDR,
|
||||
hostname,
|
||||
getNodeIP(client, hostname),
|
||||
recorder,
|
||||
healthzUpdater,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create proxier: %v", err)
|
||||
}
|
||||
proxier = proxierKernelspace
|
||||
endpointsEventHandler = proxierKernelspace
|
||||
serviceEventHandler = proxierKernelspace
|
||||
} else {
|
||||
glog.V(0).Info("Using userspace Proxier.")
|
||||
execer := exec.New()
|
||||
var netshInterface utilnetsh.Interface
|
||||
netshInterface = utilnetsh.New(execer)
|
||||
|
||||
// This is a proxy.LoadBalancer which NewProxier needs but has methods we don't need for
|
||||
// our config.EndpointsConfigHandler.
|
||||
loadBalancer := winuserspace.NewLoadBalancerRR()
|
||||
|
||||
// set EndpointsConfigHandler to our loadBalancer
|
||||
endpointsEventHandler = loadBalancer
|
||||
proxierUserspace, err := winuserspace.NewProxier(
|
||||
loadBalancer,
|
||||
net.ParseIP(config.BindAddress),
|
||||
netshInterface,
|
||||
*utilnet.ParsePortRangeOrDie(config.PortRange),
|
||||
// TODO @pires replace below with default values, if applicable
|
||||
config.IPTables.SyncPeriod.Duration,
|
||||
config.UDPIdleTimeout.Duration,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create proxier: %v", err)
|
||||
}
|
||||
proxier = proxierUserspace
|
||||
serviceEventHandler = proxierUserspace
|
||||
glog.V(0).Info("Tearing down pure-winkernel proxy rules.")
|
||||
winkernel.CleanupLeftovers()
|
||||
}
|
||||
|
||||
return &ProxyServer{
|
||||
Client: client,
|
||||
EventClient: eventClient,
|
||||
Proxier: proxier,
|
||||
Broadcaster: eventBroadcaster,
|
||||
Recorder: recorder,
|
||||
ProxyMode: proxyMode,
|
||||
NodeRef: nodeRef,
|
||||
MetricsBindAddress: config.MetricsBindAddress,
|
||||
EnableProfiling: config.EnableProfiling,
|
||||
OOMScoreAdj: config.OOMScoreAdj,
|
||||
ResourceContainer: config.ResourceContainer,
|
||||
ConfigSyncPeriod: config.ConfigSyncPeriod.Duration,
|
||||
ServiceEventHandler: serviceEventHandler,
|
||||
EndpointsEventHandler: endpointsEventHandler,
|
||||
HealthzServer: healthzServer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getProxyMode(proxyMode string, kcompat winkernel.KernelCompatTester) string {
|
||||
if proxyMode == proxyModeUserspace {
|
||||
return proxyModeUserspace
|
||||
} else if proxyMode == proxyModeKernelspace {
|
||||
return tryWinKernelSpaceProxy(kcompat)
|
||||
}
|
||||
return proxyModeUserspace
|
||||
}
|
||||
|
||||
func tryWinKernelSpaceProxy(kcompat winkernel.KernelCompatTester) string {
|
||||
// Check for Windows Kernel Version if we can support Kernel Space proxy
|
||||
// Check for Windows Version
|
||||
|
||||
// guaranteed false on error, error only necessary for debugging
|
||||
useWinKerelProxy, err := winkernel.CanUseWinKernelProxier(kcompat)
|
||||
if err != nil {
|
||||
glog.Errorf("Can't determine whether to use windows kernel proxy, using userspace proxier: %v", err)
|
||||
return proxyModeUserspace
|
||||
}
|
||||
if useWinKerelProxy {
|
||||
return proxyModeKernelspace
|
||||
}
|
||||
// Fallback.
|
||||
glog.V(1).Infof("Can't use winkernel proxy, using userspace proxier")
|
||||
return proxyModeUserspace
|
||||
}
|
49
vendor/k8s.io/kubernetes/cmd/kube-proxy/proxy.go
generated
vendored
Normal file
49
vendor/k8s.io/kubernetes/cmd/kube-proxy/proxy.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
goflag "flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
utilflag "k8s.io/apiserver/pkg/util/flag"
|
||||
"k8s.io/apiserver/pkg/util/logs"
|
||||
"k8s.io/kubernetes/cmd/kube-proxy/app"
|
||||
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
|
||||
_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
|
||||
)
|
||||
|
||||
func main() {
|
||||
command := app.NewProxyCommand()
|
||||
|
||||
// TODO: once we switch everything over to Cobra commands, we can go back to calling
|
||||
// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
|
||||
// normalize func and add the go flag set by hand.
|
||||
pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc)
|
||||
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
|
||||
// utilflag.InitFlags()
|
||||
logs.InitLogs()
|
||||
defer logs.FlushLogs()
|
||||
|
||||
if err := command.Execute(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user