Files
kubernetes/cmd/kubeadm/app/phases/kubelet/flags.go
Rostislav M. Georgiev f97770b175 kubeadm: Detect CRIs automatically
In order to allow for a smoother UX with CRIs different than Docker, we have to
make the --cri-socket command line flag optional when just one CRI is
installed.

This change does that by doing the following:

- Introduce a new runtime function (DetectCRISocket) that will attempt to
  detect a CRI socket, or return an appropriate error.
- Default to using the above function if --cri-socket is not specified and
  CRISocket in NodeRegistrationOptions is empty.
- Stop static defaulting to DefaultCRISocket. And rename it to
  DefaultDockerCRISocket. Its use is now narrowed to "Docker or not"
  distinguishment and tests.
- Introduce AddCRISocketFlag function that adds --cri-socket flag to a flagSet.
  Use that in all commands, that support --cri-socket.
- Remove the deprecated --cri-socket-path flag from kubeadm config images pull
  and deprecate --cri-socket in kubeadm upgrade apply.

Signed-off-by: Rostislav M. Georgiev <rostislavg@vmware.com>
2019-01-21 16:12:04 +02:00

132 lines
4.9 KiB
Go

/*
Copyright 2018 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 kubelet
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/pkg/errors"
"k8s.io/klog"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/images"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
nodeutil "k8s.io/kubernetes/pkg/util/node"
"k8s.io/kubernetes/pkg/util/procfs"
utilsexec "k8s.io/utils/exec"
)
type kubeletFlagsOpts struct {
nodeRegOpts *kubeadmapi.NodeRegistrationOptions
featureGates map[string]bool
pauseImage string
registerTaintsUsingFlags bool
execer utilsexec.Interface
pidOfFunc func(string) ([]int, error)
defaultHostname string
}
// WriteKubeletDynamicEnvFile writes an environment file with dynamic flags to the kubelet.
// Used at "kubeadm init" and "kubeadm join" time.
func WriteKubeletDynamicEnvFile(cfg *kubeadmapi.InitConfiguration, registerTaintsUsingFlags bool, kubeletDir string) error {
hostName, err := nodeutil.GetHostname("")
if err != nil {
return err
}
flagOpts := kubeletFlagsOpts{
nodeRegOpts: &cfg.NodeRegistration,
featureGates: cfg.FeatureGates,
pauseImage: images.GetPauseImage(&cfg.ClusterConfiguration),
registerTaintsUsingFlags: registerTaintsUsingFlags,
execer: utilsexec.New(),
pidOfFunc: procfs.PidOf,
defaultHostname: hostName,
}
stringMap := buildKubeletArgMap(flagOpts)
argList := kubeadmutil.BuildArgumentListFromMap(stringMap, cfg.NodeRegistration.KubeletExtraArgs)
envFileContent := fmt.Sprintf("%s=%s\n", constants.KubeletEnvFileVariableName, strings.Join(argList, " "))
return writeKubeletFlagBytesToDisk([]byte(envFileContent), kubeletDir)
}
// buildKubeletArgMap takes a InitConfiguration object and builds based on that a string-string map with flags
// that should be given to the local kubelet daemon.
func buildKubeletArgMap(opts kubeletFlagsOpts) map[string]string {
kubeletFlags := map[string]string{}
if opts.nodeRegOpts.CRISocket == constants.DefaultDockerCRISocket {
// These flags should only be set when running docker
kubeletFlags["network-plugin"] = "cni"
driver, err := kubeadmutil.GetCgroupDriverDocker(opts.execer)
if err != nil {
klog.Warningf("cannot automatically assign a '--cgroup-driver' value when starting the Kubelet: %v\n", err)
} else {
kubeletFlags["cgroup-driver"] = driver
}
if opts.pauseImage != "" {
kubeletFlags["pod-infra-container-image"] = opts.pauseImage
}
} else {
kubeletFlags["container-runtime"] = "remote"
kubeletFlags["container-runtime-endpoint"] = opts.nodeRegOpts.CRISocket
}
if opts.registerTaintsUsingFlags && opts.nodeRegOpts.Taints != nil && len(opts.nodeRegOpts.Taints) > 0 {
taintStrs := []string{}
for _, taint := range opts.nodeRegOpts.Taints {
taintStrs = append(taintStrs, taint.ToString())
}
kubeletFlags["register-with-taints"] = strings.Join(taintStrs, ",")
}
if pids, _ := opts.pidOfFunc("systemd-resolved"); len(pids) > 0 {
// procfs.PidOf only returns an error if the regex is empty or doesn't compile, so we can ignore it
kubeletFlags["resolv-conf"] = "/run/systemd/resolve/resolv.conf"
}
// Make sure the node name we're passed will work with Kubelet
if opts.nodeRegOpts.Name != "" && opts.nodeRegOpts.Name != opts.defaultHostname {
klog.V(1).Infof("setting kubelet hostname-override to %q", opts.nodeRegOpts.Name)
kubeletFlags["hostname-override"] = opts.nodeRegOpts.Name
}
// TODO: Conditionally set `--cgroup-driver` to either `systemd` or `cgroupfs` for CRI other than Docker
return kubeletFlags
}
// writeKubeletFlagBytesToDisk writes a byte slice down to disk at the specific location of the kubelet flag overrides file
func writeKubeletFlagBytesToDisk(b []byte, kubeletDir string) error {
kubeletEnvFilePath := filepath.Join(kubeletDir, constants.KubeletEnvFileName)
fmt.Printf("[kubelet-start] Writing kubelet environment file with flags to file %q\n", kubeletEnvFilePath)
// creates target folder if not already exists
if err := os.MkdirAll(kubeletDir, 0700); err != nil {
return errors.Wrapf(err, "failed to create directory %q", kubeletDir)
}
if err := ioutil.WriteFile(kubeletEnvFilePath, b, 0644); err != nil {
return errors.Wrapf(err, "failed to write kubelet configuration to the file %q", kubeletEnvFilePath)
}
return nil
}