k3s/pkg/daemons/agent/agent.go
Erik Wilson fa03a0df3c Run kubelet with containerd flag
The containerd flag was accidentally added to kubelet and is
deprecated, but needed for cadvisor to properly connect with
the k3s containerd socket, so adding for now.
2020-01-16 10:25:57 -07:00

207 lines
5.8 KiB
Go

package agent
import (
"bufio"
"context"
"math/rand"
"os"
"path/filepath"
"strings"
"time"
"github.com/opencontainers/runc/libcontainer/system"
"github.com/rancher/k3s/pkg/daemons/config"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/util/net"
"k8s.io/component-base/logs"
proxy "k8s.io/kubernetes/cmd/kube-proxy/app"
kubelet "k8s.io/kubernetes/cmd/kubelet/app"
"k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
_ "k8s.io/component-base/metrics/prometheus/restclient" // for client metric registration
_ "k8s.io/component-base/metrics/prometheus/version" // for version metric registration
)
func Agent(config *config.Agent) error {
rand.Seed(time.Now().UTC().UnixNano())
logs.InitLogs()
defer logs.FlushLogs()
startKubelet(config)
startKubeProxy(config)
return nil
}
func startKubeProxy(cfg *config.Agent) {
argsMap := map[string]string{
"proxy-mode": "iptables",
"healthz-bind-address": "127.0.0.1",
"kubeconfig": cfg.KubeConfigKubeProxy,
"cluster-cidr": cfg.ClusterCIDR.String(),
}
if cfg.NodeName != "" {
argsMap["hostname-override"] = cfg.NodeName
}
args := config.GetArgsList(argsMap, cfg.ExtraKubeProxyArgs)
command := proxy.NewProxyCommand()
command.SetArgs(args)
go func() {
logrus.Infof("Running kube-proxy %s", config.ArgString(args))
logrus.Fatalf("kube-proxy exited: %v", command.Execute())
}()
}
func startKubelet(cfg *config.Agent) {
argsMap := map[string]string{
"healthz-bind-address": "127.0.0.1",
"read-only-port": "0",
"cluster-domain": cfg.ClusterDomain,
"kubeconfig": cfg.KubeConfigKubelet,
"eviction-hard": "imagefs.available<5%,nodefs.available<5%",
"eviction-minimum-reclaim": "imagefs.available=10%,nodefs.available=10%",
"fail-swap-on": "false",
//"cgroup-root": "/k3s",
"cgroup-driver": "cgroupfs",
"authentication-token-webhook": "true",
"anonymous-auth": "false",
"authorization-mode": modes.ModeWebhook,
}
if cfg.RootDir != "" {
argsMap["root-dir"] = cfg.RootDir
argsMap["cert-dir"] = filepath.Join(cfg.RootDir, "pki")
argsMap["seccomp-profile-root"] = filepath.Join(cfg.RootDir, "seccomp")
}
if cfg.CNIConfDir != "" {
argsMap["cni-conf-dir"] = cfg.CNIConfDir
}
if cfg.CNIBinDir != "" {
argsMap["cni-bin-dir"] = cfg.CNIBinDir
}
if cfg.CNIPlugin {
argsMap["network-plugin"] = "cni"
}
if len(cfg.ClusterDNS) > 0 {
argsMap["cluster-dns"] = cfg.ClusterDNS.String()
}
if cfg.ResolvConf != "" {
argsMap["resolv-conf"] = cfg.ResolvConf
}
if cfg.RuntimeSocket != "" {
argsMap["container-runtime"] = "remote"
argsMap["container-runtime-endpoint"] = cfg.RuntimeSocket
argsMap["containerd"] = cfg.RuntimeSocket
argsMap["serialize-image-pulls"] = "false"
} else if cfg.PauseImage != "" {
argsMap["pod-infra-container-image"] = cfg.PauseImage
}
if cfg.ListenAddress != "" {
argsMap["address"] = cfg.ListenAddress
}
if cfg.ClientCA != "" {
argsMap["anonymous-auth"] = "false"
argsMap["client-ca-file"] = cfg.ClientCA
}
if cfg.ServingKubeletCert != "" && cfg.ServingKubeletKey != "" {
argsMap["tls-cert-file"] = cfg.ServingKubeletCert
argsMap["tls-private-key-file"] = cfg.ServingKubeletKey
}
if cfg.NodeName != "" {
argsMap["hostname-override"] = cfg.NodeName
}
defaultIP, err := net.ChooseHostInterface()
if err != nil || defaultIP.String() != cfg.NodeIP {
argsMap["node-ip"] = cfg.NodeIP
}
root, hasCFS, hasPIDs := checkCgroups()
if !hasCFS {
logrus.Warn("Disabling CPU quotas due to missing cpu.cfs_period_us")
argsMap["cpu-cfs-quota"] = "false"
}
if !hasPIDs {
logrus.Warn("Disabling pod PIDs limit feature due to missing cgroup pids support")
argsMap["cgroups-per-qos"] = "false"
argsMap["enforce-node-allocatable"] = ""
argsMap["feature-gates"] = addFeatureGate(argsMap["feature-gates"], "SupportPodPidsLimit=false")
}
if root != "" {
argsMap["runtime-cgroups"] = root
argsMap["kubelet-cgroups"] = root
}
if system.RunningInUserNS() {
argsMap["feature-gates"] = addFeatureGate(argsMap["feature-gates"], "DevicePlugins=false")
}
argsMap["node-labels"] = strings.Join(cfg.NodeLabels, ",")
if len(cfg.NodeTaints) > 0 {
argsMap["register-with-taints"] = strings.Join(cfg.NodeTaints, ",")
}
if !cfg.DisableCCM {
argsMap["cloud-provider"] = "external"
}
if cfg.Rootless {
// flags are from https://github.com/rootless-containers/usernetes/blob/v20190826.0/boot/kubelet.sh
argsMap["cgroup-driver"] = "none"
argsMap["feature-gates=SupportNoneCgroupDriver"] = "true"
argsMap["cgroups-per-qos"] = "false"
argsMap["enforce-node-allocatable"] = ""
}
args := config.GetArgsList(argsMap, cfg.ExtraKubeletArgs)
command := kubelet.NewKubeletCommand(context.Background().Done())
command.SetArgs(args)
go func() {
logrus.Infof("Running kubelet %s", config.ArgString(args))
logrus.Fatalf("kubelet exited: %v", command.Execute())
}()
}
func addFeatureGate(current, new string) string {
if current == "" {
return new
}
return current + "," + new
}
func checkCgroups() (root string, hasCFS bool, hasPIDs bool) {
f, err := os.Open("/proc/self/cgroup")
if err != nil {
return "", false, false
}
defer f.Close()
scan := bufio.NewScanner(f)
for scan.Scan() {
parts := strings.Split(scan.Text(), ":")
if len(parts) < 3 {
continue
}
systems := strings.Split(parts[1], ",")
for _, system := range systems {
if system == "pids" {
hasPIDs = true
} else if system == "cpu" {
p := filepath.Join("/sys/fs/cgroup", parts[1], parts[2], "cpu.cfs_period_us")
if _, err := os.Stat(p); err == nil {
hasCFS = true
}
} else if system == "name=systemd" {
last := parts[len(parts)-1]
i := strings.LastIndex(last, ".slice")
if i > 0 {
root = "/systemd" + last[:i+len(".slice")]
} else {
root = "/systemd"
}
}
}
}
return root, hasCFS, hasPIDs
}