Merge pull request #3892 from 11janci/jjanik-expose-pod-cidr

Expose ‘—pod-network-cidr’ argument in minikube
pull/4296/head
Thomas Strömberg 2019-05-20 08:14:03 -07:00 committed by GitHub
commit 35dc6a2ff2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 380 additions and 21 deletions

View File

@ -42,6 +42,7 @@ import (
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
cmdutil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/bootstrapper/kubeadm"
"k8s.io/minikube/pkg/minikube/cluster"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/console"
@ -145,7 +146,8 @@ func init() {
startCmd.Flags().Var(&extraOptions, "extra-config",
`A set of key=value pairs that describe configuration that may be passed to different components.
The key should be '.' separated, and the first part before the dot is the component to apply the configuration to.
Valid components are: kubelet, kubeadm, apiserver, controller-manager, etcd, proxy, scheduler.`)
Valid components are: kubelet, kubeadm, apiserver, controller-manager, etcd, proxy, scheduler
Valid kubeadm parameters: `+fmt.Sprintf("%s, %s", strings.Join(kubeadm.KubeadmExtraArgsWhitelist[kubeadm.KubeadmCmdParam], ", "), strings.Join(kubeadm.KubeadmExtraArgsWhitelist[kubeadm.KubeadmConfigParam], ",")))
startCmd.Flags().String(uuid, "", "Provide VM UUID to restore MAC address (only supported with Hyperkit driver).")
startCmd.Flags().String(vpnkitSock, "", "Location of the VPNKit socket used for networking. If empty, disables Hyperkit VPNKitSock, if 'auto' uses Docker for Mac VPNKit connection, otherwise uses the specified VSock.")
startCmd.Flags().StringSlice(vsockPorts, []string{}, "List of guest VSock ports that should be exposed as sockets on the host (Only supported on with hyperkit now).")
@ -336,6 +338,14 @@ func validateConfig() {
if viper.GetBool(hidden) && viper.GetString(vmDriver) != "kvm2" {
exit.Usage("Sorry, the --hidden feature is currently only supported with --vm-driver=kvm2")
}
// check that kubeadm extra args contain only whitelisted parameters
for param := range extraOptions.AsMap().Get(kubeadm.Kubeadm) {
if !pkgutil.ContainsString(kubeadm.KubeadmExtraArgsWhitelist[kubeadm.KubeadmCmdParam], param) &&
!pkgutil.ContainsString(kubeadm.KubeadmExtraArgsWhitelist[kubeadm.KubeadmConfigParam], param) {
exit.Usage("Sorry, the kubeadm.%s parameter is currently not supported by --extra-config", param)
}
}
}
// doCacheBinaries caches Kubernetes binaries in the foreground

View File

@ -44,6 +44,35 @@ import (
"k8s.io/minikube/pkg/util"
)
// enum to differentiate kubeadm command line parameters from kubeadm config file parameters (see the
// KubeadmExtraArgsWhitelist variable below for more info)
const (
KubeadmCmdParam = iota
KubeadmConfigParam = iota
)
// KubeadmExtraArgsWhitelist is a whitelist of supported kubeadm params that can be supplied to kubeadm through
// minikube's ExtraArgs parameter. The list is split into two parts - params that can be supplied as flags on the
// command line and params that have to be inserted into the kubeadm config file. This is because of a kubeadm
// constraint which allows only certain params to be provided from the command line when the --config parameter
// is specified
var KubeadmExtraArgsWhitelist = map[int][]string{
KubeadmCmdParam: {
"ignore-preflight-errors",
"dry-run",
"kubeconfig",
"kubeconfig-dir",
"node-name",
"cri-socket",
"experimental-upload-certs",
"certificate-key",
"rootfs",
},
KubeadmConfigParam: {
"pod-network-cidr",
},
}
// SkipPreflights are preflight checks we always skip.
var SkipPreflights = []string{
// We use --ignore-preflight-errors=DirAvailable since we have our own custom addons
@ -163,6 +192,21 @@ func (k *Bootstrapper) LogCommands(o bootstrapper.LogOptions) map[string]string
}
}
// createFlagsFromExtraArgs converts kubeadm extra args into flags to be supplied from the commad linne
func createFlagsFromExtraArgs(extraOptions util.ExtraOptionSlice) string {
kubeadmExtraOpts := extraOptions.AsMap().Get(Kubeadm)
// kubeadm allows only a small set of parameters to be supplied from the command line when the --config param
// is specified, here we remove those that are not allowed
for opt := range kubeadmExtraOpts {
if !util.ContainsString(KubeadmExtraArgsWhitelist[KubeadmCmdParam], opt) {
// kubeadmExtraOpts is a copy so safe to delete
delete(kubeadmExtraOpts, opt)
}
}
return convertToFlags(kubeadmExtraOpts)
}
// StartCluster starts the cluster
func (k *Bootstrapper) StartCluster(k8s config.KubernetesConfig) error {
version, err := ParseKubernetesVersion(k8s.KubernetesVersion)
@ -170,11 +214,7 @@ func (k *Bootstrapper) StartCluster(k8s config.KubernetesConfig) error {
return errors.Wrap(err, "parsing kubernetes version")
}
extraOpts, err := ExtraConfigForComponent(Kubeadm, k8s.ExtraOptions, version)
if err != nil {
return errors.Wrap(err, "generating extra configuration for kubelet")
}
extraFlags := convertToFlags(extraOpts)
extraFlags := createFlagsFromExtraArgs(k8s.ExtraOptions)
r, err := cruntime.New(cruntime.Config{Type: k8s.ContainerRuntime})
if err != nil {
@ -475,6 +515,25 @@ sudo systemctl start kubelet
return nil
}
// createExtraComponentConfig generates a map of component to extra args for all of the components except kubeadm
func createExtraComponentConfig(extraOptions util.ExtraOptionSlice, version semver.Version, componentFeatureArgs string) ([]ComponentExtraArgs, error) {
extraArgsSlice, err := NewComponentExtraArgs(extraOptions, version, componentFeatureArgs)
if err != nil {
return nil, err
}
// kubeadm extra args should not be included in the kubeadm config in the extra args section (instead, they must
// be inserted explicitly in the appropriate places or supplied from the command line); here we remove all of the
// kubeadm extra args from the slice
for i, extraArgs := range extraArgsSlice {
if extraArgs.Component == Kubeadm {
extraArgsSlice = append(extraArgsSlice[:i], extraArgsSlice[i+1:]...)
break
}
}
return extraArgsSlice, nil
}
func generateConfig(k8s config.KubernetesConfig, r cruntime.Manager) (string, error) {
version, err := ParseKubernetesVersion(k8s.KubernetesVersion)
if err != nil {
@ -487,8 +546,7 @@ func generateConfig(k8s config.KubernetesConfig, r cruntime.Manager) (string, er
return "", errors.Wrap(err, "parses feature gate config for kubeadm and component")
}
// generates a map of component to extra args for apiserver, controller-manager, and scheduler
extraComponentConfig, err := NewComponentExtraArgs(k8s.ExtraOptions, version, componentFeatureArgs)
extraComponentConfig, err := createExtraComponentConfig(k8s.ExtraOptions, version, componentFeatureArgs)
if err != nil {
return "", errors.Wrap(err, "generating extra component config for kubeadm")
}
@ -502,6 +560,7 @@ func generateConfig(k8s config.KubernetesConfig, r cruntime.Manager) (string, er
opts := struct {
CertDir string
ServiceCIDR string
PodSubnet string
AdvertiseAddress string
APIServerPort int
KubernetesVersion string
@ -515,6 +574,7 @@ func generateConfig(k8s config.KubernetesConfig, r cruntime.Manager) (string, er
}{
CertDir: util.DefaultCertPath,
ServiceCIDR: util.DefaultServiceCIDR,
PodSubnet: k8s.ExtraOptions.Get("pod-network-cidr", Kubeadm),
AdvertiseAddress: k8s.NodeIP,
APIServerPort: nodePort,
KubernetesVersion: k8s.KubernetesVersion,

View File

@ -153,6 +153,24 @@ func TestGenerateConfig(t *testing.T) {
Key: "scheduler-name",
Value: "mini-scheduler",
},
util.ExtraOption{
Component: Kubeadm,
Key: "ignore-preflight-errors",
Value: "true",
},
util.ExtraOption{
Component: Kubeadm,
Key: "dry-run",
Value: "true",
},
}
extraOptsPodCidr := util.ExtraOptionSlice{
util.ExtraOption{
Component: Kubeadm,
Key: "pod-network-cidr",
Value: "192.168.32.0/20",
},
}
// Test version policy: Last 4 major releases (slightly looser than our general policy)
@ -177,6 +195,7 @@ func TestGenerateConfig(t *testing.T) {
{"crio-options-gates", "crio", false, config.KubernetesConfig{ExtraOptions: extraOpts, FeatureGates: "a=b"}},
{"unknown-component", "docker", true, config.KubernetesConfig{ExtraOptions: util.ExtraOptionSlice{util.ExtraOption{Component: "not-a-real-component", Key: "killswitch", Value: "true"}}}},
{"containerd-api-port", "containerd", false, config.KubernetesConfig{NodePort: 12345}},
{"containerd-pod-network-cidr", "containerd", false, config.KubernetesConfig{ExtraOptions: extraOptsPodCidr}},
{"image-repository", "docker", false, config.KubernetesConfig{ImageRepository: "test/repo"}},
}
for vname, version := range versions {

View File

@ -85,7 +85,7 @@ etcd:
kubernetesVersion: {{.KubernetesVersion}}
networking:
dnsDomain: cluster.local
podSubnet: ""
podSubnet: {{if .PodSubnet}}{{.PodSubnet}}{{else}}""{{end}}
serviceSubnet: {{.ServiceCIDR}}
---
apiVersion: kubelet.config.k8s.io/v1beta1

View File

@ -0,0 +1,43 @@
apiVersion: kubeadm.k8s.io/v1beta1
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 1.1.1.1
bindPort: 8443
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
ttl: 24h0m0s
usages:
- signing
- authentication
nodeRegistration:
criSocket: /run/containerd/containerd.sock
name: mk
taints: []
---
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
apiServer:
extraArgs:
enable-admission-plugins: "NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota"
certificatesDir: /var/lib/minikube/certs/
clusterName: kubernetes
controlPlaneEndpoint: localhost:8443
dns:
type: CoreDNS
etcd:
local:
dataDir: /data/minikube
kubernetesVersion: v1.14.1
networking:
dnsDomain: cluster.local
podSubnet: ""
serviceSubnet: 10.96.0.0/12
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
imageGCHighThresholdPercent: 100
evictionHard:
nodefs.available: "0%"
nodefs.inodesFree: "0%"
imagefs.available: "0%"

View File

@ -0,0 +1,43 @@
apiVersion: kubeadm.k8s.io/v1beta1
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 1.1.1.1
bindPort: 8443
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
ttl: 24h0m0s
usages:
- signing
- authentication
nodeRegistration:
criSocket: /run/containerd/containerd.sock
name: mk
taints: []
---
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
apiServer:
extraArgs:
enable-admission-plugins: "NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota"
certificatesDir: /var/lib/minikube/certs/
clusterName: kubernetes
controlPlaneEndpoint: localhost:8443
dns:
type: CoreDNS
etcd:
local:
dataDir: /data/minikube
kubernetesVersion: v1.14.0
networking:
dnsDomain: cluster.local
podSubnet: ""
serviceSubnet: 10.96.0.0/12
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
imageGCHighThresholdPercent: 100
evictionHard:
nodefs.available: "0%"
nodefs.inodesFree: "0%"
imagefs.available: "0%"

View File

@ -0,0 +1,17 @@
apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
noTaintMaster: true
api:
advertiseAddress: 1.1.1.1
bindPort: 8443
controlPlaneEndpoint: localhost
kubernetesVersion: v1.10.0
certificatesDir: /var/lib/minikube/certs/
networking:
serviceSubnet: 10.96.0.0/12
etcd:
dataDir: /data/minikube
nodeName: mk
criSocket: /run/containerd/containerd.sock
apiServerExtraArgs:
admission-control: "Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota"

View File

@ -0,0 +1,39 @@
apiVersion: kubeadm.k8s.io/v1alpha3
kind: InitConfiguration
apiEndpoint:
advertiseAddress: 1.1.1.1
bindPort: 8443
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
ttl: 24h0m0s
usages:
- signing
- authentication
nodeRegistration:
criSocket: /run/containerd/containerd.sock
name: mk
taints: []
---
apiVersion: kubeadm.k8s.io/v1alpha3
kind: ClusterConfiguration
apiServerExtraArgs:
enable-admission-plugins: "Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota"
certificatesDir: /var/lib/minikube/certs/
clusterName: kubernetes
controlPlaneEndpoint: localhost:8443
etcd:
local:
dataDir: /data/minikube
kubernetesVersion: v1.12.0
networking:
dnsDomain: cluster.local
podSubnet: 192.168.32.0/20
serviceSubnet: 10.96.0.0/12
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
evictionHard:
nodefs.available: "0%"
nodefs.inodesFree: "0%"
imagefs.available: "0%"

View File

@ -0,0 +1,39 @@
apiVersion: kubeadm.k8s.io/v1alpha3
kind: InitConfiguration
apiEndpoint:
advertiseAddress: 1.1.1.1
bindPort: 8443
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
ttl: 24h0m0s
usages:
- signing
- authentication
nodeRegistration:
criSocket: /run/containerd/containerd.sock
name: mk
taints: []
---
apiVersion: kubeadm.k8s.io/v1alpha3
kind: ClusterConfiguration
apiServerExtraArgs:
enable-admission-plugins: "Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota"
certificatesDir: /var/lib/minikube/certs/
clusterName: kubernetes
controlPlaneEndpoint: localhost:8443
etcd:
local:
dataDir: /data/minikube
kubernetesVersion: v1.13.0
networking:
dnsDomain: cluster.local
podSubnet: 192.168.32.0/20
serviceSubnet: 10.96.0.0/12
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
evictionHard:
nodefs.available: "0%"
nodefs.inodesFree: "0%"
imagefs.available: "0%"

View File

@ -26,9 +26,6 @@ controllerManager:
extraArgs:
feature-gates: "a=b"
kube-api-burst: "32"
kubeadm:
extraArgs:
feature-gates: "a=b"
scheduler:
extraArgs:
feature-gates: "a=b"

View File

@ -26,9 +26,6 @@ controllerManager:
extraArgs:
feature-gates: "a=b"
kube-api-burst: "32"
kubeadm:
extraArgs:
feature-gates: "a=b"
scheduler:
extraArgs:
feature-gates: "a=b"

View File

@ -20,8 +20,6 @@ apiServerExtraArgs:
controllerManagerExtraArgs:
feature-gates: "a=b"
kube-api-burst: "32"
kubeadmExtraArgs:
feature-gates: "a=b"
schedulerExtraArgs:
feature-gates: "a=b"
scheduler-name: "mini-scheduler"

View File

@ -24,8 +24,6 @@ apiServerExtraArgs:
controllerManagerExtraArgs:
feature-gates: "a=b"
kube-api-burst: "32"
kubeadmExtraArgs:
feature-gates: "a=b"
schedulerExtraArgs:
feature-gates: "a=b"
scheduler-name: "mini-scheduler"

View File

@ -24,8 +24,6 @@ apiServerExtraArgs:
controllerManagerExtraArgs:
feature-gates: "a=b"
kube-api-burst: "32"
kubeadmExtraArgs:
feature-gates: "a=b"
schedulerExtraArgs:
feature-gates: "a=b"
scheduler-name: "mini-scheduler"

View File

@ -35,6 +35,9 @@ func (e *ExtraOption) String() string {
// ExtraOptionSlice is a slice of ExtraOption
type ExtraOptionSlice []ExtraOption
// ComponentExtraOptionMap maps components to their extra opts, which is a map of keys to values
type ComponentExtraOptionMap map[string]map[string]string
// Set parses the string value into a slice
func (es *ExtraOptionSlice) Set(value string) error {
// The component is the value before the first dot.
@ -68,7 +71,39 @@ func (es *ExtraOptionSlice) String() string {
return strings.Join(s, " ")
}
// Get finds and returns the value of an argument with the specified key and component (optional) or an empty string
// if not found. If component contains more than one value, the value for the first component found is returned. If
// component is not specified, all of the components are used.
func (es *ExtraOptionSlice) Get(key string, component ...string) string {
for _, opt := range *es {
if component == nil || ContainsString(component, opt.Component) {
if opt.Key == key {
return opt.Value
}
}
}
return ""
}
// AsMap converts the slice to a map of components to a map of keys and values.
func (es *ExtraOptionSlice) AsMap() ComponentExtraOptionMap {
ret := ComponentExtraOptionMap{}
for _, opt := range *es {
if _, ok := ret[opt.Component]; !ok {
ret[opt.Component] = map[string]string{opt.Key: opt.Value}
} else {
ret[opt.Component][opt.Key] = opt.Value
}
}
return ret
}
// Type returns the type
func (es *ExtraOptionSlice) Type() string {
return "ExtraOption"
}
// Get returns the extra option map of keys to values for the specified component
func (cm ComponentExtraOptionMap) Get(component string) map[string]string {
return cm[component]
}

View File

@ -78,3 +78,57 @@ func TestValidFlags(t *testing.T) {
}
}
}
func TestGet(t *testing.T) {
extraOptions := ExtraOptionSlice{
ExtraOption{Component: "c1", Key: "bar", Value: "c1-bar"},
ExtraOption{Component: "c1", Key: "bar-baz", Value: "c1-bar-baz"},
ExtraOption{Component: "c2", Key: "bar", Value: "c2-bar"},
ExtraOption{Component: "c3", Key: "bar", Value: "c3-bar"},
}
for _, tc := range []struct {
searchKey string
searchComponent []string
expRes string
values ExtraOptionSlice
}{
{"nonexistent", nil, "", extraOptions},
{"nonexistent", []string{"c1"}, "", extraOptions},
{"bar", []string{"c2"}, "c2-bar", extraOptions},
{"bar", []string{"c2", "c3"}, "c2-bar", extraOptions},
{"bar", nil, "c1-bar", extraOptions},
} {
if res := tc.values.Get(tc.searchKey, tc.searchComponent...); res != tc.expRes {
t.Errorf("Unexpected value. Expected %s, got %s", tc.expRes, res)
}
}
}
func TestAsMap(t *testing.T) {
extraOptions := ExtraOptionSlice{
ExtraOption{Component: "c1", Key: "bar", Value: "c1-bar"},
ExtraOption{Component: "c1", Key: "bar-baz", Value: "c1-bar-baz"},
ExtraOption{Component: "c2", Key: "bar", Value: "c2-bar"},
ExtraOption{Component: "c3", Key: "bar", Value: "c3-bar"},
}
expectedRes := ComponentExtraOptionMap{
"c1": {
"bar": "c1-bar",
"bar-baz": "c1-bar-baz",
},
"c2": {
"bar": "c2-bar",
},
"c3": {
"bar": "c3-bar",
},
}
res := extraOptions.AsMap()
if !reflect.DeepEqual(expectedRes, res) {
t.Errorf("Unexpected value. Expected %s, got %s", expectedRes, res)
}
}

View File

@ -273,3 +273,14 @@ func ConcatStrings(src []string, prefix string, postfix string) []string {
}
return ret
}
// ContainsString checks if a given slice of strings contains the provided string.
// If a modifier func is provided, it is called with the slice item before the comparation.
func ContainsString(slice []string, s string) bool {
for _, item := range slice {
if item == s {
return true
}
}
return false
}

View File

@ -44,6 +44,7 @@ func TestStartStop(t *testing.T) {
"ServerSideApply=true",
"--network-plugin=cni",
"--extra-config=kubelet.network-plugin=cni",
"--extra-config=kubeadm.pod-network-cidr=192.168.111.111/16",
fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion),
}},
{"containerd_and_non_default_apiserver_port", []string{