2018-02-13 00:47:56 +00:00
package cluster
import (
"context"
2018-06-13 02:10:48 +00:00
"crypto/md5"
2019-07-05 04:23:48 +00:00
b64 "encoding/base64"
"encoding/json"
2018-02-13 00:47:56 +00:00
"fmt"
2019-01-08 02:14:42 +00:00
"net"
2018-04-11 22:54:47 +00:00
"path"
2018-02-13 00:47:56 +00:00
"strconv"
2018-02-14 20:58:35 +00:00
"strings"
2018-02-13 00:47:56 +00:00
2018-04-11 22:54:47 +00:00
"github.com/docker/docker/api/types"
2018-04-03 20:18:51 +00:00
"github.com/rancher/rke/docker"
2018-02-13 00:47:56 +00:00
"github.com/rancher/rke/hosts"
2018-04-03 19:27:04 +00:00
"github.com/rancher/rke/k8s"
2019-05-28 18:51:53 +00:00
"github.com/rancher/rke/metadata"
2018-02-13 00:47:56 +00:00
"github.com/rancher/rke/pki"
"github.com/rancher/rke/services"
2018-10-04 08:54:04 +00:00
"github.com/rancher/rke/util"
2019-10-28 22:45:48 +00:00
v3 "github.com/rancher/types/apis/management.cattle.io/v3"
2018-08-09 15:03:28 +00:00
"github.com/sirupsen/logrus"
2018-02-13 00:47:56 +00:00
)
2018-02-14 20:58:35 +00:00
const (
2019-07-05 04:23:48 +00:00
ClusterCIDREnv = "RKE_CLUSTER_CIDR"
ClusterServiceCIDREnv = "RKE_CLUSTER_SERVICE_CIDR"
ClusterDNSServerEnv = "RKE_CLUSTER_DNS_SERVER"
ClusterDomainEnv = "RKE_CLUSTER_DOMAIN"
NodeAddressEnv = "RKE_NODE_ADDRESS"
NodeInternalAddressEnv = "RKE_NODE_INTERNAL_ADDRESS"
NodeNameOverrideEnv = "RKE_NODE_NAME_OVERRIDE"
NetworkConfigurationEnv = "RKE_NETWORK_CONFIGURATION"
EtcdPathPrefix = "/registry"
CloudConfigSumEnv = "RKE_CLOUD_CONFIG_CHECKSUM"
CloudProviderNameEnv = "RKE_CLOUD_PROVIDER_NAME"
2018-08-03 22:01:58 +00:00
2018-08-05 01:10:48 +00:00
DefaultToolsEntrypoint = "/opt/rke-tools/entrypoint.sh"
DefaultToolsEntrypointVersion = "0.1.13"
LegacyToolsEntrypoint = "/opt/rke/entrypoint.sh"
2018-08-29 00:23:41 +00:00
KubeletDockerConfigEnv = "RKE_KUBELET_DOCKER_CONFIG"
KubeletDockerConfigFileEnv = "RKE_KUBELET_DOCKER_FILE"
KubeletDockerConfigPath = "/var/lib/kubelet/config.json"
2019-04-30 10:28:10 +00:00
2019-06-24 20:16:37 +00:00
// MaxEtcdOldEnvVersion The versions are maxed out for minor versions because -rancher1 suffix will cause semver to think its older, example: v1.15.0 > v1.15.0-rancher1
MaxEtcdOldEnvVersion = "v3.2.99"
MaxK8s115Version = "v1.15"
2018-02-14 20:58:35 +00:00
)
2018-08-29 21:42:12 +00:00
var admissionControlOptionNames = [ ] string { "enable-admission-plugins" , "admission-control" }
2019-09-06 22:53:14 +00:00
func GetServiceOptionData ( data map [ string ] interface { } ) map [ string ] * v3 . KubernetesServicesOptions {
svcOptionsData := map [ string ] * v3 . KubernetesServicesOptions { }
k8sServiceOptions , _ := data [ "k8s-service-options" ] . ( * v3 . KubernetesServicesOptions )
if k8sServiceOptions != nil {
svcOptionsData [ "k8s-service-options" ] = k8sServiceOptions
}
k8sWServiceOptions , _ := data [ "k8s-windows-service-options" ] . ( * v3 . KubernetesServicesOptions )
if k8sWServiceOptions != nil {
svcOptionsData [ "k8s-windows-service-options" ] = k8sWServiceOptions
}
return svcOptionsData
}
func GeneratePlan ( ctx context . Context , rkeConfig * v3 . RancherKubernetesEngineConfig , hostsInfoMap map [ string ] types . Info , data map [ string ] interface { } ) ( v3 . RKEPlan , error ) {
2018-02-13 00:47:56 +00:00
clusterPlan := v3 . RKEPlan { }
2019-10-03 01:56:39 +00:00
myCluster , err := InitClusterObject ( ctx , rkeConfig , ExternalFlags { } , "" )
2018-04-19 15:54:15 +00:00
if err != nil {
return clusterPlan , err
}
2018-02-13 00:47:56 +00:00
// rkeConfig.Nodes are already unique. But they don't have role flags. So I will use the parsed cluster.Hosts to make use of the role flags.
uniqHosts := hosts . GetUniqueHostList ( myCluster . EtcdHosts , myCluster . ControlPlaneHosts , myCluster . WorkerHosts )
2019-09-06 22:53:14 +00:00
svcOptionData := GetServiceOptionData ( data )
2018-02-13 00:47:56 +00:00
for _ , host := range uniqHosts {
2018-04-25 22:02:40 +00:00
host . DockerInfo = hostsInfoMap [ host . Address ]
2019-09-06 22:53:14 +00:00
clusterPlan . Nodes = append ( clusterPlan . Nodes , BuildRKEConfigNodePlan ( ctx , myCluster , host , hostsInfoMap [ host . Address ] , svcOptionData ) )
2018-02-13 00:47:56 +00:00
}
return clusterPlan , nil
}
2019-09-06 22:53:14 +00:00
func BuildRKEConfigNodePlan ( ctx context . Context , myCluster * Cluster , host * hosts . Host , hostDockerInfo types . Info , svcOptionData map [ string ] * v3 . KubernetesServicesOptions ) v3 . RKEConfigNodePlan {
2018-06-25 22:50:45 +00:00
prefixPath := hosts . GetPrefixPath ( hostDockerInfo . OperatingSystem , myCluster . PrefixPath )
2018-02-24 13:08:46 +00:00
processes := map [ string ] v3 . Process { }
2018-02-13 00:47:56 +00:00
portChecks := [ ] v3 . PortCheck { }
// Everybody gets a sidecar and a kubelet..
2019-07-05 04:23:48 +00:00
processes [ services . SidekickContainerName ] = myCluster . BuildSidecarProcess ( host , prefixPath )
2019-09-06 22:53:14 +00:00
processes [ services . KubeletContainerName ] = myCluster . BuildKubeletProcess ( host , prefixPath , svcOptionData )
processes [ services . KubeproxyContainerName ] = myCluster . BuildKubeProxyProcess ( host , prefixPath , svcOptionData )
2018-02-13 00:47:56 +00:00
portChecks = append ( portChecks , BuildPortChecksFromPortList ( host , WorkerPortList , ProtocolTCP ) ... )
// Do we need an nginxProxy for this one ?
2018-04-14 17:18:51 +00:00
if ! host . IsControl {
2019-07-05 04:23:48 +00:00
processes [ services . NginxProxyContainerName ] = myCluster . BuildProxyProcess ( host , prefixPath )
2018-02-13 00:47:56 +00:00
}
if host . IsControl {
2019-09-06 22:53:14 +00:00
processes [ services . KubeAPIContainerName ] = myCluster . BuildKubeAPIProcess ( host , prefixPath , svcOptionData )
processes [ services . KubeControllerContainerName ] = myCluster . BuildKubeControllerProcess ( host , prefixPath , svcOptionData )
processes [ services . SchedulerContainerName ] = myCluster . BuildSchedulerProcess ( host , prefixPath , svcOptionData )
2018-02-13 00:47:56 +00:00
portChecks = append ( portChecks , BuildPortChecksFromPortList ( host , ControlPlanePortList , ProtocolTCP ) ... )
}
if host . IsEtcd {
2018-04-14 18:38:07 +00:00
processes [ services . EtcdContainerName ] = myCluster . BuildEtcdProcess ( host , myCluster . EtcdReadyHosts , prefixPath )
2018-02-13 00:47:56 +00:00
portChecks = append ( portChecks , BuildPortChecksFromPortList ( host , EtcdPortList , ProtocolTCP ) ... )
}
2019-10-03 01:56:39 +00:00
files := [ ] v3 . File {
v3 . File {
Name : cloudConfigFileName ,
Contents : b64 . StdEncoding . EncodeToString ( [ ] byte ( myCluster . CloudConfigFile ) ) ,
} ,
}
if myCluster . IsEncryptionEnabled ( ) {
files = append ( files , v3 . File {
Name : EncryptionProviderFilePath ,
Contents : b64 . StdEncoding . EncodeToString ( [ ] byte ( myCluster . EncryptionConfig . EncryptionProviderFile ) ) ,
} )
2018-03-29 20:58:46 +00:00
}
2018-02-13 00:47:56 +00:00
return v3 . RKEConfigNodePlan {
Address : host . Address ,
2019-07-05 04:23:48 +00:00
Processes : osLimitationFilter ( hostDockerInfo . OSType , processes ) ,
2018-02-13 00:47:56 +00:00
PortChecks : portChecks ,
2019-10-03 01:56:39 +00:00
Files : files ,
2018-04-03 19:27:04 +00:00
Annotations : map [ string ] string {
k8s . ExternalAddressAnnotation : host . Address ,
k8s . InternalAddressAnnotation : host . InternalAddress ,
} ,
2018-04-04 10:02:11 +00:00
Labels : host . ToAddLabels ,
2018-02-13 00:47:56 +00:00
}
}
2019-07-05 04:23:48 +00:00
func osLimitationFilter ( osType string , processes map [ string ] v3 . Process ) map [ string ] v3 . Process {
if osType != "windows" {
return processes
}
// windows limitations
for name , process := range processes {
// doesn't support host network on windows
if process . NetworkMode == "host" {
process . NetworkMode = ""
}
// doesn't support PID on windows
if process . PidMode != "" {
process . PidMode = ""
}
// doesn't support privileged mode on windows
if process . Privileged {
process . Privileged = false
}
// doesn't execute health check
process . HealthCheck = v3 . HealthCheck { }
processes [ name ] = process
}
return processes
}
2019-09-06 22:53:14 +00:00
func ( c * Cluster ) BuildKubeAPIProcess ( host * hosts . Host , prefixPath string , svcOptionData map [ string ] * v3 . KubernetesServicesOptions ) v3 . Process {
2018-02-14 20:58:35 +00:00
// check if external etcd is used
2019-05-31 16:39:56 +00:00
etcdConnectionString := services . GetEtcdConnString ( c . EtcdHosts , host . InternalAddress )
2018-02-14 20:58:35 +00:00
etcdPathPrefix := EtcdPathPrefix
etcdClientCert := pki . GetCertPath ( pki . KubeNodeCertName )
etcdClientKey := pki . GetKeyPath ( pki . KubeNodeCertName )
etcdCAClientCert := pki . GetCertPath ( pki . CACertName )
2018-06-12 21:02:05 +00:00
2018-02-14 20:58:35 +00:00
if len ( c . Services . Etcd . ExternalURLs ) > 0 {
etcdConnectionString = strings . Join ( c . Services . Etcd . ExternalURLs , "," )
etcdPathPrefix = c . Services . Etcd . Path
etcdClientCert = pki . GetCertPath ( pki . EtcdClientCertName )
etcdClientKey = pki . GetKeyPath ( pki . EtcdClientCertName )
etcdCAClientCert = pki . GetCertPath ( pki . EtcdClientCACertName )
}
2018-02-13 00:47:56 +00:00
Command := [ ] string {
2018-08-03 22:01:58 +00:00
c . getRKEToolsEntryPoint ( ) ,
2018-02-13 00:47:56 +00:00
"kube-apiserver" ,
}
2019-05-28 18:51:53 +00:00
2018-03-14 23:37:04 +00:00
CommandArgs := map [ string ] string {
2019-08-07 15:35:19 +00:00
"client-ca-file" : pki . GetCertPath ( pki . CACertName ) ,
"cloud-provider" : c . CloudProvider . Name ,
"etcd-cafile" : etcdCAClientCert ,
"etcd-certfile" : etcdClientCert ,
"etcd-keyfile" : etcdClientKey ,
"etcd-prefix" : etcdPathPrefix ,
"etcd-servers" : etcdConnectionString ,
"kubelet-client-certificate" : pki . GetCertPath ( pki . KubeAPICertName ) ,
"kubelet-client-key" : pki . GetKeyPath ( pki . KubeAPICertName ) ,
"proxy-client-cert-file" : pki . GetCertPath ( pki . APIProxyClientCertName ) ,
"proxy-client-key-file" : pki . GetKeyPath ( pki . APIProxyClientCertName ) ,
"requestheader-allowed-names" : pki . APIProxyClientCertName ,
"requestheader-client-ca-file" : pki . GetCertPath ( pki . RequestHeaderCACertName ) ,
"service-account-key-file" : pki . GetKeyPath ( pki . ServiceAccountTokenKeyName ) ,
"service-cluster-ip-range" : c . Services . KubeAPI . ServiceClusterIPRange ,
"service-node-port-range" : c . Services . KubeAPI . ServiceNodePortRange ,
"tls-cert-file" : pki . GetCertPath ( pki . KubeAPICertName ) ,
"tls-private-key-file" : pki . GetKeyPath ( pki . KubeAPICertName ) ,
2018-03-14 23:37:04 +00:00
}
2019-02-11 23:21:29 +00:00
if len ( c . CloudProvider . Name ) > 0 {
2018-12-28 16:41:37 +00:00
CommandArgs [ "cloud-config" ] = cloudConfigFileName
}
if c . Authentication . Webhook != nil {
CommandArgs [ "authentication-token-webhook-config-file" ] = authnWebhookFileName
CommandArgs [ "authentication-token-webhook-cache-ttl" ] = c . Authentication . Webhook . CacheTimeout
2018-03-28 19:46:28 +00:00
}
2018-06-13 02:10:48 +00:00
if len ( c . CloudProvider . Name ) > 0 {
c . Services . KubeAPI . ExtraEnv = append (
c . Services . KubeAPI . ExtraEnv ,
2018-12-06 23:35:11 +00:00
fmt . Sprintf ( "%s=%s" , CloudConfigSumEnv , getCloudConfigChecksum ( c . CloudConfigFile ) ) )
2018-06-13 02:10:48 +00:00
}
2019-10-03 01:56:39 +00:00
if c . EncryptionConfig . EncryptionProviderFile != "" {
CommandArgs [ "experimental-encryption-provider-config" ] = EncryptionProviderFilePath
}
2019-09-06 22:53:14 +00:00
serviceOptions := c . GetKubernetesServicesOptions ( host . DockerInfo . OSType , svcOptionData )
2018-04-17 23:08:21 +00:00
if serviceOptions . KubeAPI != nil {
2018-04-11 17:28:26 +00:00
for k , v := range serviceOptions . KubeAPI {
2018-10-01 21:12:53 +00:00
// if the value is empty, we remove that option
if len ( v ) == 0 {
delete ( CommandArgs , k )
continue
}
2018-04-11 17:28:26 +00:00
CommandArgs [ k ] = v
}
}
2018-06-12 21:02:05 +00:00
// check api server count for k8s v1.8
2019-02-26 23:14:01 +00:00
if util . GetTagMajorVersion ( c . Version ) == "v1.8" {
2018-06-12 21:02:05 +00:00
CommandArgs [ "apiserver-count" ] = strconv . Itoa ( len ( c . ControlPlaneHosts ) )
}
2018-04-11 17:28:26 +00:00
2018-02-13 00:47:56 +00:00
if c . Authorization . Mode == services . RBACAuthorizationMode {
2018-03-14 23:37:04 +00:00
CommandArgs [ "authorization-mode" ] = "Node,RBAC"
2018-02-13 00:47:56 +00:00
}
2019-01-07 19:52:57 +00:00
2019-01-08 02:14:42 +00:00
if len ( host . InternalAddress ) > 0 && net . ParseIP ( host . InternalAddress ) != nil {
CommandArgs [ "advertise-address" ] = host . InternalAddress
}
2019-10-18 18:07:47 +00:00
admissionControlOptionName := ""
for _ , optionName := range admissionControlOptionNames {
if _ , ok := CommandArgs [ optionName ] ; ok {
admissionControlOptionName = optionName
break
}
}
2018-02-13 00:47:56 +00:00
if c . Services . KubeAPI . PodSecurityPolicy {
2019-09-09 17:51:53 +00:00
CommandArgs [ "runtime-config" ] = "policy/v1beta1/podsecuritypolicy=true"
2019-10-18 18:07:47 +00:00
CommandArgs [ admissionControlOptionName ] = CommandArgs [ admissionControlOptionName ] + ",PodSecurityPolicy"
}
if c . Services . KubeAPI . AlwaysPullImages {
CommandArgs [ admissionControlOptionName ] = CommandArgs [ admissionControlOptionName ] + ",AlwaysPullImages"
2018-02-13 00:47:56 +00:00
}
VolumesFrom := [ ] string {
services . SidekickContainerName ,
}
Binds := [ ] string {
2018-04-11 22:54:47 +00:00
fmt . Sprintf ( "%s:/etc/kubernetes:z" , path . Join ( prefixPath , "/etc/kubernetes" ) ) ,
2018-02-13 00:47:56 +00:00
}
2018-03-14 23:37:04 +00:00
// Override args if they exist, add additional args
2018-02-13 00:47:56 +00:00
for arg , value := range c . Services . KubeAPI . ExtraArgs {
2018-03-14 23:37:04 +00:00
if _ , ok := c . Services . KubeAPI . ExtraArgs [ arg ] ; ok {
CommandArgs [ arg ] = value
}
}
for arg , value := range CommandArgs {
2018-02-13 00:47:56 +00:00
cmd := fmt . Sprintf ( "--%s=%s" , arg , value )
Command = append ( Command , cmd )
}
2018-03-16 03:20:42 +00:00
Binds = append ( Binds , c . Services . KubeAPI . ExtraBinds ... )
2018-02-13 00:47:56 +00:00
healthCheck := v3 . HealthCheck {
URL : services . GetHealthCheckURL ( true , services . KubeAPIPort ) ,
}
2018-04-03 20:18:51 +00:00
registryAuthConfig , _ , _ := docker . GetImageRegistryConfig ( c . Services . KubeAPI . Image , c . PrivateRegistriesMap )
2018-02-13 00:47:56 +00:00
return v3 . Process {
2018-04-03 20:18:51 +00:00
Name : services . KubeAPIContainerName ,
Command : Command ,
VolumesFrom : VolumesFrom ,
2018-07-19 20:41:56 +00:00
Binds : getUniqStringList ( Binds ) ,
2018-06-13 02:10:48 +00:00
Env : getUniqStringList ( c . Services . KubeAPI . ExtraEnv ) ,
2018-04-03 20:18:51 +00:00
NetworkMode : "host" ,
RestartPolicy : "always" ,
Image : c . Services . KubeAPI . Image ,
HealthCheck : healthCheck ,
ImageRegistryAuthConfig : registryAuthConfig ,
2018-05-03 20:07:41 +00:00
Labels : map [ string ] string {
2019-08-14 10:53:32 +00:00
services . ContainerNameLabel : services . KubeAPIContainerName ,
2018-05-03 20:07:41 +00:00
} ,
2018-02-13 00:47:56 +00:00
}
}
2019-09-06 22:53:14 +00:00
func ( c * Cluster ) BuildKubeControllerProcess ( host * hosts . Host , prefixPath string , svcOptionData map [ string ] * v3 . KubernetesServicesOptions ) v3 . Process {
2018-03-14 23:37:04 +00:00
Command := [ ] string {
2018-08-03 22:01:58 +00:00
c . getRKEToolsEntryPoint ( ) ,
2018-02-13 00:47:56 +00:00
"kube-controller-manager" ,
}
2018-03-14 23:37:04 +00:00
CommandArgs := map [ string ] string {
2019-01-07 19:52:57 +00:00
"cloud-provider" : c . CloudProvider . Name ,
"cluster-cidr" : c . ClusterCIDR ,
"kubeconfig" : pki . GetConfigPath ( pki . KubeControllerCertName ) ,
2018-03-14 23:37:04 +00:00
"root-ca-file" : pki . GetCertPath ( pki . CACertName ) ,
2019-01-07 19:52:57 +00:00
"service-account-private-key-file" : pki . GetKeyPath ( pki . ServiceAccountTokenKeyName ) ,
"service-cluster-ip-range" : c . Services . KubeController . ServiceClusterIPRange ,
}
// Best security practice is to listen on localhost, but DinD uses private container network instead of Host.
if c . DinD {
CommandArgs [ "address" ] = "0.0.0.0"
2018-03-14 23:37:04 +00:00
}
2019-02-11 23:21:29 +00:00
if len ( c . CloudProvider . Name ) > 0 {
2018-12-28 16:41:37 +00:00
CommandArgs [ "cloud-config" ] = cloudConfigFileName
2018-03-28 19:46:28 +00:00
}
2018-06-13 02:10:48 +00:00
if len ( c . CloudProvider . Name ) > 0 {
c . Services . KubeController . ExtraEnv = append (
c . Services . KubeController . ExtraEnv ,
2018-12-06 23:35:11 +00:00
fmt . Sprintf ( "%s=%s" , CloudConfigSumEnv , getCloudConfigChecksum ( c . CloudConfigFile ) ) )
2018-06-13 02:10:48 +00:00
}
2019-09-06 22:53:14 +00:00
serviceOptions := c . GetKubernetesServicesOptions ( host . DockerInfo . OSType , svcOptionData )
2018-04-17 23:08:21 +00:00
if serviceOptions . KubeController != nil {
2018-04-11 17:28:26 +00:00
for k , v := range serviceOptions . KubeController {
2018-10-01 21:12:53 +00:00
// if the value is empty, we remove that option
if len ( v ) == 0 {
delete ( CommandArgs , k )
continue
}
2018-04-11 17:28:26 +00:00
CommandArgs [ k ] = v
}
}
2018-02-13 00:47:56 +00:00
args := [ ] string { }
if c . Authorization . Mode == services . RBACAuthorizationMode {
args = append ( args , "--use-service-account-credentials=true" )
}
VolumesFrom := [ ] string {
services . SidekickContainerName ,
}
Binds := [ ] string {
2018-04-11 22:54:47 +00:00
fmt . Sprintf ( "%s:/etc/kubernetes:z" , path . Join ( prefixPath , "/etc/kubernetes" ) ) ,
2018-02-13 00:47:56 +00:00
}
for arg , value := range c . Services . KubeController . ExtraArgs {
2018-03-14 23:37:04 +00:00
if _ , ok := c . Services . KubeController . ExtraArgs [ arg ] ; ok {
CommandArgs [ arg ] = value
}
}
for arg , value := range CommandArgs {
2018-02-13 00:47:56 +00:00
cmd := fmt . Sprintf ( "--%s=%s" , arg , value )
Command = append ( Command , cmd )
}
2018-03-16 03:20:42 +00:00
Binds = append ( Binds , c . Services . KubeController . ExtraBinds ... )
2018-02-13 00:47:56 +00:00
healthCheck := v3 . HealthCheck {
URL : services . GetHealthCheckURL ( false , services . KubeControllerPort ) ,
}
2018-04-03 20:18:51 +00:00
registryAuthConfig , _ , _ := docker . GetImageRegistryConfig ( c . Services . KubeController . Image , c . PrivateRegistriesMap )
2018-02-13 00:47:56 +00:00
return v3 . Process {
2018-04-03 20:18:51 +00:00
Name : services . KubeControllerContainerName ,
Command : Command ,
Args : args ,
VolumesFrom : VolumesFrom ,
2018-07-19 20:41:56 +00:00
Binds : getUniqStringList ( Binds ) ,
2018-06-13 02:10:48 +00:00
Env : getUniqStringList ( c . Services . KubeController . ExtraEnv ) ,
2018-04-03 20:18:51 +00:00
NetworkMode : "host" ,
RestartPolicy : "always" ,
Image : c . Services . KubeController . Image ,
HealthCheck : healthCheck ,
ImageRegistryAuthConfig : registryAuthConfig ,
2018-05-03 20:07:41 +00:00
Labels : map [ string ] string {
2019-08-14 10:53:32 +00:00
services . ContainerNameLabel : services . KubeControllerContainerName ,
2018-05-03 20:07:41 +00:00
} ,
2018-02-13 00:47:56 +00:00
}
}
2019-09-06 22:53:14 +00:00
func ( c * Cluster ) BuildKubeletProcess ( host * hosts . Host , prefixPath string , svcOptionData map [ string ] * v3 . KubernetesServicesOptions ) v3 . Process {
2018-03-14 23:37:04 +00:00
Command := [ ] string {
2018-08-03 22:01:58 +00:00
c . getRKEToolsEntryPoint ( ) ,
2018-02-13 00:47:56 +00:00
"kubelet" ,
2018-03-14 23:37:04 +00:00
}
2019-07-05 04:23:48 +00:00
if host . DockerInfo . OSType == "windows" { // compatible with Windows
Command = [ ] string {
"pwsh" , "-NoLogo" , "-NonInteractive" , "-File" , "c:/usr/bin/entrypoint.ps1" ,
"kubelet" ,
}
}
2018-03-14 23:37:04 +00:00
CommandArgs := map [ string ] string {
2019-05-28 18:51:53 +00:00
"client-ca-file" : pki . GetCertPath ( pki . CACertName ) ,
"cloud-provider" : c . CloudProvider . Name ,
"cluster-dns" : c . ClusterDNSServer ,
"cluster-domain" : c . ClusterDomain ,
"fail-swap-on" : strconv . FormatBool ( c . Services . Kubelet . FailSwapOn ) ,
"hostname-override" : host . HostnameOverride ,
"kubeconfig" : pki . GetConfigPath ( pki . KubeNodeCertName ) ,
"pod-infra-container-image" : c . Services . Kubelet . InfraContainerImage ,
"root-dir" : path . Join ( prefixPath , "/var/lib/kubelet" ) ,
2018-02-13 00:47:56 +00:00
}
2019-07-05 04:23:48 +00:00
if host . DockerInfo . OSType == "windows" { // compatible with Windows
CommandArgs [ "kubeconfig" ] = path . Join ( prefixPath , pki . GetConfigPath ( pki . KubeNodeCertName ) )
CommandArgs [ "client-ca-file" ] = path . Join ( prefixPath , pki . GetCertPath ( pki . CACertName ) )
// this's a stopgap, we could drop this after https://github.com/kubernetes/kubernetes/pull/75618 merged
CommandArgs [ "pod-infra-container-image" ] = c . SystemImages . WindowsPodInfraContainer
}
2019-07-18 20:42:01 +00:00
if c . DinD {
CommandArgs [ "healthz-bind-address" ] = "0.0.0.0"
}
2018-06-22 06:35:52 +00:00
if host . IsControl && ! host . IsWorker {
CommandArgs [ "register-with-taints" ] = unschedulableControlTaint
}
2018-03-26 22:53:28 +00:00
if host . Address != host . InternalAddress {
CommandArgs [ "node-ip" ] = host . InternalAddress
}
2019-02-11 23:21:29 +00:00
if len ( c . CloudProvider . Name ) > 0 {
2018-12-28 16:41:37 +00:00
CommandArgs [ "cloud-config" ] = cloudConfigFileName
2019-07-05 04:23:48 +00:00
if host . DockerInfo . OSType == "windows" { // compatible with Windows
CommandArgs [ "cloud-config" ] = path . Join ( prefixPath , cloudConfigFileName )
}
2018-03-28 19:46:28 +00:00
}
2018-06-13 02:10:48 +00:00
if len ( c . CloudProvider . Name ) > 0 {
c . Services . Kubelet . ExtraEnv = append (
c . Services . Kubelet . ExtraEnv ,
2018-12-06 23:35:11 +00:00
fmt . Sprintf ( "%s=%s" , CloudConfigSumEnv , getCloudConfigChecksum ( c . CloudConfigFile ) ) )
2018-06-13 02:10:48 +00:00
}
2018-08-29 00:23:41 +00:00
if len ( c . PrivateRegistriesMap ) > 0 {
2019-01-07 19:52:57 +00:00
kubeletDockerConfig , _ := docker . GetKubeletDockerConfig ( c . PrivateRegistriesMap )
2018-08-29 00:23:41 +00:00
c . Services . Kubelet . ExtraEnv = append (
c . Services . Kubelet . ExtraEnv ,
fmt . Sprintf ( "%s=%s" , KubeletDockerConfigEnv ,
2019-01-07 19:52:57 +00:00
b64 . StdEncoding . EncodeToString ( [ ] byte ( kubeletDockerConfig ) ) ) )
2018-08-29 00:23:41 +00:00
c . Services . Kubelet . ExtraEnv = append (
c . Services . Kubelet . ExtraEnv ,
fmt . Sprintf ( "%s=%s" , KubeletDockerConfigFileEnv , path . Join ( prefixPath , KubeletDockerConfigPath ) ) )
}
2019-09-06 22:53:14 +00:00
serviceOptions := c . GetKubernetesServicesOptions ( host . DockerInfo . OSType , svcOptionData )
2018-04-17 23:08:21 +00:00
if serviceOptions . Kubelet != nil {
2018-04-11 17:28:26 +00:00
for k , v := range serviceOptions . Kubelet {
2018-10-01 21:12:53 +00:00
// if the value is empty, we remove that option
if len ( v ) == 0 {
delete ( CommandArgs , k )
continue
}
2019-07-05 04:23:48 +00:00
// if the value is '', we set that option to empty string,
// e.g.: there's not cgroup on windows, we need to empty `enforce-node-allocatable` option
if v == "''" {
CommandArgs [ k ] = ""
continue
}
// if the value has [PREFIX_PATH] prefix, we need to replace it with `prefixPath`,
// e.g.: windows allows to use other drivers than `c:`
if strings . HasPrefix ( v , "[PREFIX_PATH]" ) {
CommandArgs [ k ] = path . Join ( prefixPath , strings . Replace ( v , "[PREFIX_PATH]" , "" , - 1 ) )
continue
}
2018-04-11 17:28:26 +00:00
CommandArgs [ k ] = v
}
}
2018-02-13 00:47:56 +00:00
VolumesFrom := [ ] string {
services . SidekickContainerName ,
}
Binds := [ ] string {
2018-04-11 22:54:47 +00:00
fmt . Sprintf ( "%s:/etc/kubernetes:z" , path . Join ( prefixPath , "/etc/kubernetes" ) ) ,
2018-04-24 20:43:50 +00:00
"/etc/cni:/etc/cni:rw,z" ,
"/opt/cni:/opt/cni:rw,z" ,
2018-04-11 22:54:47 +00:00
fmt . Sprintf ( "%s:/var/lib/cni:z" , path . Join ( prefixPath , "/var/lib/cni" ) ) ,
2018-04-26 03:10:53 +00:00
"/var/lib/calico:/var/lib/calico:z" ,
2018-02-13 00:47:56 +00:00
"/etc/resolv.conf:/etc/resolv.conf" ,
2018-03-05 08:42:49 +00:00
"/sys:/sys:rprivate" ,
2018-04-10 16:49:38 +00:00
host . DockerInfo . DockerRootDir + ":" + host . DockerInfo . DockerRootDir + ":rw,rslave,z" ,
2018-04-11 22:54:47 +00:00
fmt . Sprintf ( "%s:%s:shared,z" , path . Join ( prefixPath , "/var/lib/kubelet" ) , path . Join ( prefixPath , "/var/lib/kubelet" ) ) ,
2018-04-18 20:53:14 +00:00
"/var/lib/rancher:/var/lib/rancher:shared,z" ,
2018-03-05 08:42:49 +00:00
"/var/run:/var/run:rw,rprivate" ,
"/run:/run:rprivate" ,
2018-04-11 22:54:47 +00:00
fmt . Sprintf ( "%s:/etc/ceph" , path . Join ( prefixPath , "/etc/ceph" ) ) ,
2018-03-30 18:00:19 +00:00
"/dev:/host/dev:rprivate" ,
2018-06-25 18:40:51 +00:00
"/var/log/containers:/var/log/containers:z" ,
"/var/log/pods:/var/log/pods:z" ,
2018-04-24 08:43:06 +00:00
"/usr:/host/usr:ro" ,
"/etc:/host/etc:ro" ,
2018-02-13 00:47:56 +00:00
}
2018-08-01 18:10:58 +00:00
// Special case to simplify using flex volumes
if path . Join ( prefixPath , "/var/lib/kubelet" ) != "/var/lib/kubelet" {
Binds = append ( Binds , "/var/lib/kubelet/volumeplugins:/var/lib/kubelet/volumeplugins:shared,z" )
}
2019-07-05 04:23:48 +00:00
if host . DockerInfo . OSType == "windows" { // compatible with Windows
Binds = [ ] string {
2019-09-10 14:31:54 +00:00
// put the execution binaries and cloud provider configuration to the host
2019-07-05 04:23:48 +00:00
fmt . Sprintf ( "%s:c:/host/etc/kubernetes" , path . Join ( prefixPath , "/etc/kubernetes" ) ) ,
// put the flexvolume plugins or private registry docker configuration to the host
fmt . Sprintf ( "%s:c:/host/var/lib/kubelet" , path . Join ( prefixPath , "/var/lib/kubelet" ) ) ,
// exchange resources with other components
fmt . Sprintf ( "%s:c:/host/run" , path . Join ( prefixPath , "/run" ) ) ,
}
}
Env := c . Services . Kubelet . ExtraEnv
if host . DockerInfo . OSType == "windows" { // compatible with Windows
Env = append ( Env ,
fmt . Sprintf ( "%s=%s" , ClusterCIDREnv , c . ClusterCIDR ) ,
fmt . Sprintf ( "%s=%s" , ClusterDomainEnv , c . ClusterDomain ) ,
fmt . Sprintf ( "%s=%s" , ClusterDNSServerEnv , c . ClusterDNSServer ) ,
fmt . Sprintf ( "%s=%s" , ClusterServiceCIDREnv , c . Services . KubeController . ServiceClusterIPRange ) ,
fmt . Sprintf ( "%s=%s" , NodeAddressEnv , host . Address ) ,
fmt . Sprintf ( "%s=%s" , NodeInternalAddressEnv , host . InternalAddress ) ,
fmt . Sprintf ( "%s=%s" , CloudProviderNameEnv , c . CloudProvider . Name ) ,
)
}
2018-02-13 00:47:56 +00:00
for arg , value := range c . Services . Kubelet . ExtraArgs {
2018-03-14 23:37:04 +00:00
if _ , ok := c . Services . Kubelet . ExtraArgs [ arg ] ; ok {
CommandArgs [ arg ] = value
}
}
for arg , value := range CommandArgs {
2018-02-13 00:47:56 +00:00
cmd := fmt . Sprintf ( "--%s=%s" , arg , value )
Command = append ( Command , cmd )
}
2018-03-16 03:20:42 +00:00
Binds = append ( Binds , c . Services . Kubelet . ExtraBinds ... )
2018-02-13 00:47:56 +00:00
healthCheck := v3 . HealthCheck {
2019-07-18 20:42:01 +00:00
URL : services . GetHealthCheckURL ( false , services . KubeletPort ) ,
2018-02-13 00:47:56 +00:00
}
2018-04-03 20:18:51 +00:00
registryAuthConfig , _ , _ := docker . GetImageRegistryConfig ( c . Services . Kubelet . Image , c . PrivateRegistriesMap )
2018-02-13 00:47:56 +00:00
return v3 . Process {
2018-04-03 20:18:51 +00:00
Name : services . KubeletContainerName ,
Command : Command ,
VolumesFrom : VolumesFrom ,
2018-07-19 20:41:56 +00:00
Binds : getUniqStringList ( Binds ) ,
2019-07-05 04:23:48 +00:00
Env : getUniqStringList ( Env ) ,
2018-04-03 20:18:51 +00:00
NetworkMode : "host" ,
RestartPolicy : "always" ,
Image : c . Services . Kubelet . Image ,
PidMode : "host" ,
Privileged : true ,
HealthCheck : healthCheck ,
ImageRegistryAuthConfig : registryAuthConfig ,
2018-05-03 20:07:41 +00:00
Labels : map [ string ] string {
2019-08-14 10:53:32 +00:00
services . ContainerNameLabel : services . KubeletContainerName ,
2018-05-03 20:07:41 +00:00
} ,
2018-02-13 00:47:56 +00:00
}
}
2019-09-06 22:53:14 +00:00
func ( c * Cluster ) BuildKubeProxyProcess ( host * hosts . Host , prefixPath string , svcOptionData map [ string ] * v3 . KubernetesServicesOptions ) v3 . Process {
2018-03-14 23:37:04 +00:00
Command := [ ] string {
2018-08-03 22:01:58 +00:00
c . getRKEToolsEntryPoint ( ) ,
2018-02-13 00:47:56 +00:00
"kube-proxy" ,
}
2019-07-05 04:23:48 +00:00
if host . DockerInfo . OSType == "windows" { // compatible with Windows
Command = [ ] string {
"pwsh" , "-NoLogo" , "-NonInteractive" , "-File" , "c:/usr/bin/entrypoint.ps1" ,
"kube-proxy" ,
}
}
2018-03-14 23:37:04 +00:00
CommandArgs := map [ string ] string {
2019-05-28 18:51:53 +00:00
"cluster-cidr" : c . ClusterCIDR ,
"hostname-override" : host . HostnameOverride ,
"kubeconfig" : pki . GetConfigPath ( pki . KubeProxyCertName ) ,
2019-01-07 19:52:57 +00:00
}
2019-07-05 04:23:48 +00:00
if host . DockerInfo . OSType == "windows" { // compatible with Windows
CommandArgs [ "kubeconfig" ] = path . Join ( prefixPath , pki . GetConfigPath ( pki . KubeProxyCertName ) )
}
2019-05-28 18:51:53 +00:00
2019-09-06 22:53:14 +00:00
serviceOptions := c . GetKubernetesServicesOptions ( host . DockerInfo . OSType , svcOptionData )
2018-04-17 23:08:21 +00:00
if serviceOptions . Kubeproxy != nil {
2018-04-11 17:28:26 +00:00
for k , v := range serviceOptions . Kubeproxy {
2018-10-01 21:12:53 +00:00
// if the value is empty, we remove that option
if len ( v ) == 0 {
delete ( CommandArgs , k )
continue
}
2018-04-11 17:28:26 +00:00
CommandArgs [ k ] = v
}
}
2019-09-20 12:40:53 +00:00
// If cloudprovider is set (not empty), set the bind address because the node will not be able to retrieve it's IP address in case cloud provider changes the node object name (i.e. AWS and Openstack)
if c . CloudProvider . Name != "" {
if host . InternalAddress != "" && host . Address != host . InternalAddress {
CommandArgs [ "bind-address" ] = host . InternalAddress
} else {
CommandArgs [ "bind-address" ] = host . Address
}
}
2018-04-11 17:28:26 +00:00
2019-05-28 18:51:53 +00:00
// Best security practice is to listen on localhost, but DinD uses private container network instead of Host.
if c . DinD {
CommandArgs [ "healthz-bind-address" ] = "0.0.0.0"
}
2018-02-13 00:47:56 +00:00
VolumesFrom := [ ] string {
services . SidekickContainerName ,
}
2019-10-28 22:45:48 +00:00
//TODO: we should reevaluate if any of the bind mounts here should be using read-only mode
2018-02-13 00:47:56 +00:00
Binds := [ ] string {
2018-04-11 22:54:47 +00:00
fmt . Sprintf ( "%s:/etc/kubernetes:z" , path . Join ( prefixPath , "/etc/kubernetes" ) ) ,
2019-04-10 17:59:58 +00:00
"/run:/run" ,
2019-10-28 22:45:48 +00:00
fmt . Sprintf ( "%s:/lib/modules:z,ro" , path . Join ( prefixPath , "/lib/modules" ) ) ,
2018-02-13 00:47:56 +00:00
}
2019-07-05 04:23:48 +00:00
if host . DockerInfo . OSType == "windows" { // compatible with Windows
Binds = [ ] string {
2019-09-10 14:31:54 +00:00
// put the execution binaries to the host
2019-07-05 04:23:48 +00:00
fmt . Sprintf ( "%s:c:/host/etc/kubernetes" , path . Join ( prefixPath , "/etc/kubernetes" ) ) ,
// exchange resources with other components
fmt . Sprintf ( "%s:c:/host/run" , path . Join ( prefixPath , "/run" ) ) ,
2019-10-28 22:45:48 +00:00
fmt . Sprintf ( "%s:c:/host/lib/modules" , path . Join ( prefixPath , "/lib/modules" ) ) ,
2019-07-05 04:23:48 +00:00
}
}
Env := c . Services . Kubeproxy . ExtraEnv
if host . DockerInfo . OSType == "windows" { // compatible with Windows
Env = append ( Env ,
fmt . Sprintf ( "%s=%s" , ClusterCIDREnv , c . ClusterCIDR ) ,
fmt . Sprintf ( "%s=%s" , ClusterDomainEnv , c . ClusterDomain ) ,
fmt . Sprintf ( "%s=%s" , ClusterDNSServerEnv , c . ClusterDNSServer ) ,
fmt . Sprintf ( "%s=%s" , ClusterServiceCIDREnv , c . Services . KubeController . ServiceClusterIPRange ) ,
fmt . Sprintf ( "%s=%s" , NodeAddressEnv , host . Address ) ,
fmt . Sprintf ( "%s=%s" , NodeInternalAddressEnv , host . InternalAddress ) ,
fmt . Sprintf ( "%s=%s" , CloudProviderNameEnv , c . CloudProvider . Name ) ,
)
}
2018-02-13 00:47:56 +00:00
for arg , value := range c . Services . Kubeproxy . ExtraArgs {
2018-03-14 23:37:04 +00:00
if _ , ok := c . Services . Kubeproxy . ExtraArgs [ arg ] ; ok {
CommandArgs [ arg ] = value
}
}
for arg , value := range CommandArgs {
2018-02-13 00:47:56 +00:00
cmd := fmt . Sprintf ( "--%s=%s" , arg , value )
Command = append ( Command , cmd )
}
2018-03-16 03:20:42 +00:00
Binds = append ( Binds , c . Services . Kubeproxy . ExtraBinds ... )
2018-02-13 00:47:56 +00:00
healthCheck := v3 . HealthCheck {
URL : services . GetHealthCheckURL ( false , services . KubeproxyPort ) ,
}
2018-04-03 20:18:51 +00:00
registryAuthConfig , _ , _ := docker . GetImageRegistryConfig ( c . Services . Kubeproxy . Image , c . PrivateRegistriesMap )
2018-02-13 00:47:56 +00:00
return v3 . Process {
2018-11-07 23:54:08 +00:00
Name : services . KubeproxyContainerName ,
Command : Command ,
VolumesFrom : VolumesFrom ,
Binds : getUniqStringList ( Binds ) ,
2019-07-05 04:23:48 +00:00
Env : getUniqStringList ( Env ) ,
2018-11-07 23:54:08 +00:00
NetworkMode : "host" ,
RestartPolicy : "always" ,
PidMode : "host" ,
Privileged : true ,
HealthCheck : healthCheck ,
Image : c . Services . Kubeproxy . Image ,
2018-04-03 20:18:51 +00:00
ImageRegistryAuthConfig : registryAuthConfig ,
2018-05-03 20:07:41 +00:00
Labels : map [ string ] string {
2019-08-14 10:53:32 +00:00
services . ContainerNameLabel : services . KubeproxyContainerName ,
2018-05-03 20:07:41 +00:00
} ,
2018-02-13 00:47:56 +00:00
}
}
2019-07-05 04:23:48 +00:00
func ( c * Cluster ) BuildProxyProcess ( host * hosts . Host , prefixPath string ) v3 . Process {
Command := [ ] string {
"nginx-proxy" ,
}
if host . DockerInfo . OSType == "windows" { // compatible with Windows
Command = [ ] string {
"pwsh" , "-NoLogo" , "-NonInteractive" , "-File" , "c:/usr/bin/nginx-proxy.ps1" ,
}
}
2018-02-13 00:47:56 +00:00
nginxProxyEnv := ""
for i , host := range c . ControlPlaneHosts {
nginxProxyEnv += fmt . Sprintf ( "%s" , host . InternalAddress )
if i < ( len ( c . ControlPlaneHosts ) - 1 ) {
nginxProxyEnv += ","
}
}
Env := [ ] string { fmt . Sprintf ( "%s=%s" , services . NginxProxyEnvName , nginxProxyEnv ) }
2019-07-05 04:23:48 +00:00
VolumesFrom := [ ] string { }
if host . DockerInfo . OSType == "windows" { // compatible withe Windows
VolumesFrom = [ ] string {
services . SidekickContainerName ,
}
}
Binds := [ ] string { }
if host . DockerInfo . OSType == "windows" { // compatible with Windows
Binds = [ ] string {
2019-09-10 14:31:54 +00:00
// put the execution binaries and generate the configuration to the host
2019-07-05 04:23:48 +00:00
fmt . Sprintf ( "%s:c:/host/etc/nginx" , path . Join ( prefixPath , "/etc/nginx" ) ) ,
// exchange resources with other components
fmt . Sprintf ( "%s:c:/host/run" , path . Join ( prefixPath , "/run" ) ) ,
}
}
2018-04-03 20:18:51 +00:00
registryAuthConfig , _ , _ := docker . GetImageRegistryConfig ( c . SystemImages . NginxProxy , c . PrivateRegistriesMap )
2018-02-13 00:47:56 +00:00
return v3 . Process {
2018-04-22 20:55:34 +00:00
Name : services . NginxProxyContainerName ,
Env : Env ,
// we do this to force container update when CP hosts change.
2018-11-07 23:54:08 +00:00
Args : Env ,
2019-07-05 04:23:48 +00:00
Command : Command ,
2018-11-07 23:54:08 +00:00
NetworkMode : "host" ,
RestartPolicy : "always" ,
2019-07-05 04:23:48 +00:00
Binds : Binds ,
VolumesFrom : VolumesFrom ,
2018-11-07 23:54:08 +00:00
HealthCheck : v3 . HealthCheck { } ,
Image : c . SystemImages . NginxProxy ,
2018-04-03 20:18:51 +00:00
ImageRegistryAuthConfig : registryAuthConfig ,
2018-05-03 20:07:41 +00:00
Labels : map [ string ] string {
2019-08-14 10:53:32 +00:00
services . ContainerNameLabel : services . NginxProxyContainerName ,
2018-05-03 20:07:41 +00:00
} ,
2018-02-13 00:47:56 +00:00
}
}
2019-09-06 22:53:14 +00:00
func ( c * Cluster ) BuildSchedulerProcess ( host * hosts . Host , prefixPath string , svcOptionData map [ string ] * v3 . KubernetesServicesOptions ) v3 . Process {
2018-03-14 23:37:04 +00:00
Command := [ ] string {
2018-08-03 22:01:58 +00:00
c . getRKEToolsEntryPoint ( ) ,
2018-02-13 00:47:56 +00:00
"kube-scheduler" ,
}
2018-03-14 23:37:04 +00:00
CommandArgs := map [ string ] string {
2019-05-28 18:51:53 +00:00
"kubeconfig" : pki . GetConfigPath ( pki . KubeSchedulerCertName ) ,
2018-03-14 23:37:04 +00:00
}
2019-01-07 19:52:57 +00:00
// Best security practice is to listen on localhost, but DinD uses private container network instead of Host.
if c . DinD {
CommandArgs [ "address" ] = "0.0.0.0"
}
2019-09-06 22:53:14 +00:00
serviceOptions := c . GetKubernetesServicesOptions ( host . DockerInfo . OSType , svcOptionData )
2018-04-17 23:08:21 +00:00
if serviceOptions . Scheduler != nil {
2018-04-11 17:28:26 +00:00
for k , v := range serviceOptions . Scheduler {
2018-10-01 21:12:53 +00:00
// if the value is empty, we remove that option
if len ( v ) == 0 {
delete ( CommandArgs , k )
continue
}
2018-04-11 17:28:26 +00:00
CommandArgs [ k ] = v
}
}
2018-02-13 00:47:56 +00:00
VolumesFrom := [ ] string {
services . SidekickContainerName ,
}
Binds := [ ] string {
2018-04-11 22:54:47 +00:00
fmt . Sprintf ( "%s:/etc/kubernetes:z" , path . Join ( prefixPath , "/etc/kubernetes" ) ) ,
2018-02-13 00:47:56 +00:00
}
for arg , value := range c . Services . Scheduler . ExtraArgs {
2018-03-14 23:37:04 +00:00
if _ , ok := c . Services . Scheduler . ExtraArgs [ arg ] ; ok {
CommandArgs [ arg ] = value
}
}
for arg , value := range CommandArgs {
2018-02-13 00:47:56 +00:00
cmd := fmt . Sprintf ( "--%s=%s" , arg , value )
Command = append ( Command , cmd )
}
2018-03-16 03:20:42 +00:00
Binds = append ( Binds , c . Services . Scheduler . ExtraBinds ... )
2018-02-13 00:47:56 +00:00
healthCheck := v3 . HealthCheck {
URL : services . GetHealthCheckURL ( false , services . SchedulerPort ) ,
}
2018-04-03 20:18:51 +00:00
registryAuthConfig , _ , _ := docker . GetImageRegistryConfig ( c . Services . Scheduler . Image , c . PrivateRegistriesMap )
2018-02-13 00:47:56 +00:00
return v3 . Process {
2018-04-03 20:18:51 +00:00
Name : services . SchedulerContainerName ,
Command : Command ,
2018-07-19 20:41:56 +00:00
Binds : getUniqStringList ( Binds ) ,
2018-06-07 09:38:39 +00:00
Env : c . Services . Scheduler . ExtraEnv ,
2018-04-03 20:18:51 +00:00
VolumesFrom : VolumesFrom ,
NetworkMode : "host" ,
RestartPolicy : "always" ,
Image : c . Services . Scheduler . Image ,
HealthCheck : healthCheck ,
ImageRegistryAuthConfig : registryAuthConfig ,
2018-05-03 20:07:41 +00:00
Labels : map [ string ] string {
2019-08-14 10:53:32 +00:00
services . ContainerNameLabel : services . SchedulerContainerName ,
2018-05-03 20:07:41 +00:00
} ,
2018-02-13 00:47:56 +00:00
}
}
2019-07-05 04:23:48 +00:00
func ( c * Cluster ) BuildSidecarProcess ( host * hosts . Host , prefixPath string ) v3 . Process {
Command := [ ] string {
"/bin/bash" ,
}
if host . DockerInfo . OSType == "windows" { // compatible with Windows
// windows docker doesn't support host network mode,
// so we can't use the network components installed by addon like Linux.
// we use sidecar container to maintain the network components
Command = [ ] string {
"pwsh" , "-NoLogo" , "-NonInteractive" , "-File" , "c:/usr/bin/sidecar.ps1" ,
}
}
Env := [ ] string { }
if host . DockerInfo . OSType == "windows" { // compatible with Windows
Env = append ( Env ,
fmt . Sprintf ( "%s=%s" , ClusterCIDREnv , c . ClusterCIDR ) ,
fmt . Sprintf ( "%s=%s" , ClusterDomainEnv , c . ClusterDomain ) ,
fmt . Sprintf ( "%s=%s" , ClusterDNSServerEnv , c . ClusterDNSServer ) ,
fmt . Sprintf ( "%s=%s" , ClusterServiceCIDREnv , c . Services . KubeController . ServiceClusterIPRange ) ,
fmt . Sprintf ( "%s=%s" , NodeAddressEnv , host . Address ) ,
fmt . Sprintf ( "%s=%s" , NodeInternalAddressEnv , host . InternalAddress ) ,
fmt . Sprintf ( "%s=%s" , CloudProviderNameEnv , c . CloudProvider . Name ) ,
// sidekick needs the node name to drive the cni network management, e.g: flanneld
fmt . Sprintf ( "%s=%s" , NodeNameOverrideEnv , host . HostnameOverride ) ,
// sidekick use the network configuration to drive the cni network management, e.g: flanneld
fmt . Sprintf ( "%s=%s" , NetworkConfigurationEnv , getNetworkJSON ( c . Network ) ) ,
)
}
Binds := [ ] string { }
if host . DockerInfo . OSType == "windows" { // compatible with Windows
Binds = [ ] string {
2019-09-10 14:31:54 +00:00
// put the execution binaries and the cni binaries to the host
fmt . Sprintf ( "%s:c:/host/opt" , path . Join ( prefixPath , "/opt" ) ) ,
2019-07-05 04:23:48 +00:00
// put the cni configuration to the host
fmt . Sprintf ( "%s:c:/host/etc/cni/net.d" , path . Join ( prefixPath , "/etc/cni/net.d" ) ) ,
// put the cni network component configuration to the host
fmt . Sprintf ( "%s:c:/host/etc/kube-flannel" , path . Join ( prefixPath , "/etc/kube-flannel" ) ) ,
// exchange resources with other components
fmt . Sprintf ( "%s:c:/host/run" , path . Join ( prefixPath , "/run" ) ) ,
}
}
RestartPolicy := ""
if host . DockerInfo . OSType == "windows" { // compatible with Windows
RestartPolicy = "always"
}
2019-09-10 14:31:54 +00:00
NetworkMode := "none"
if host . DockerInfo . OSType == "windows" { // compatible with Windows
NetworkMode = ""
}
2018-04-03 20:18:51 +00:00
registryAuthConfig , _ , _ := docker . GetImageRegistryConfig ( c . SystemImages . KubernetesServicesSidecar , c . PrivateRegistriesMap )
2018-02-13 00:47:56 +00:00
return v3 . Process {
2018-04-03 20:18:51 +00:00
Name : services . SidekickContainerName ,
2019-09-10 14:31:54 +00:00
NetworkMode : NetworkMode ,
2019-07-05 04:23:48 +00:00
RestartPolicy : RestartPolicy ,
Binds : getUniqStringList ( Binds ) ,
Env : getUniqStringList ( Env ) ,
2018-04-03 20:18:51 +00:00
Image : c . SystemImages . KubernetesServicesSidecar ,
HealthCheck : v3 . HealthCheck { } ,
ImageRegistryAuthConfig : registryAuthConfig ,
2018-05-03 20:07:41 +00:00
Labels : map [ string ] string {
2019-08-14 10:53:32 +00:00
services . ContainerNameLabel : services . SidekickContainerName ,
2018-05-03 20:07:41 +00:00
} ,
2019-07-05 04:23:48 +00:00
Command : Command ,
2018-02-13 00:47:56 +00:00
}
}
2018-04-11 22:54:47 +00:00
func ( c * Cluster ) BuildEtcdProcess ( host * hosts . Host , etcdHosts [ ] * hosts . Host , prefixPath string ) v3 . Process {
2019-08-07 15:35:19 +00:00
nodeName := pki . GetEtcdCrtName ( host . InternalAddress )
2018-02-13 00:47:56 +00:00
initCluster := ""
2019-03-08 21:02:44 +00:00
architecture := "amd64"
2018-02-13 00:47:56 +00:00
if len ( etcdHosts ) == 0 {
initCluster = services . GetEtcdInitialCluster ( c . EtcdHosts )
2019-02-28 07:54:35 +00:00
if len ( c . EtcdHosts ) > 0 {
architecture = c . EtcdHosts [ 0 ] . DockerInfo . Architecture
}
2018-02-13 00:47:56 +00:00
} else {
initCluster = services . GetEtcdInitialCluster ( etcdHosts )
2019-02-28 07:54:35 +00:00
architecture = etcdHosts [ 0 ] . DockerInfo . Architecture
2018-02-13 00:47:56 +00:00
}
clusterState := "new"
if host . ExistingEtcdCluster {
clusterState = "existing"
}
2018-03-14 23:37:04 +00:00
args := [ ] string {
"/usr/local/bin/etcd" ,
2018-02-13 00:47:56 +00:00
"--peer-client-cert-auth" ,
"--client-cert-auth" ,
2018-03-14 23:37:04 +00:00
}
2018-04-20 04:07:44 +00:00
// If InternalAddress is not explicitly set, it's set to the same value as Address. This is all good until we deploy on a host with a DNATed public address like AWS, in that case we can't bind to that address so we fall back to 0.0.0.0
listenAddress := host . InternalAddress
if host . Address == host . InternalAddress {
listenAddress = "0.0.0.0"
}
2018-03-14 23:37:04 +00:00
CommandArgs := map [ string ] string {
"name" : "etcd-" + host . HostnameOverride ,
2018-05-15 21:06:05 +00:00
"data-dir" : services . EtcdDataDir ,
2018-03-14 23:37:04 +00:00
"advertise-client-urls" : "https://" + host . InternalAddress + ":2379,https://" + host . InternalAddress + ":4001" ,
2018-04-20 04:07:44 +00:00
"listen-client-urls" : "https://" + listenAddress + ":2379" ,
2018-03-14 23:37:04 +00:00
"initial-advertise-peer-urls" : "https://" + host . InternalAddress + ":2380" ,
2018-04-20 04:07:44 +00:00
"listen-peer-urls" : "https://" + listenAddress + ":2380" ,
2018-03-14 23:37:04 +00:00
"initial-cluster-token" : "etcd-cluster-1" ,
"initial-cluster" : initCluster ,
"initial-cluster-state" : clusterState ,
"trusted-ca-file" : pki . GetCertPath ( pki . CACertName ) ,
"peer-trusted-ca-file" : pki . GetCertPath ( pki . CACertName ) ,
"cert-file" : pki . GetCertPath ( nodeName ) ,
"key-file" : pki . GetKeyPath ( nodeName ) ,
"peer-cert-file" : pki . GetCertPath ( nodeName ) ,
"peer-key-file" : pki . GetKeyPath ( nodeName ) ,
2018-02-13 00:47:56 +00:00
}
Binds := [ ] string {
2018-05-15 21:06:05 +00:00
fmt . Sprintf ( "%s:%s:z" , path . Join ( prefixPath , "/var/lib/etcd" ) , services . EtcdDataDir ) ,
2018-04-11 22:54:47 +00:00
fmt . Sprintf ( "%s:/etc/kubernetes:z" , path . Join ( prefixPath , "/etc/kubernetes" ) ) ,
2018-02-13 00:47:56 +00:00
}
2018-03-16 03:20:42 +00:00
2018-02-13 00:47:56 +00:00
for arg , value := range c . Services . Etcd . ExtraArgs {
2018-03-14 23:37:04 +00:00
if _ , ok := c . Services . Etcd . ExtraArgs [ arg ] ; ok {
CommandArgs [ arg ] = value
}
}
for arg , value := range CommandArgs {
2018-02-13 00:47:56 +00:00
cmd := fmt . Sprintf ( "--%s=%s" , arg , value )
args = append ( args , cmd )
}
2018-03-16 03:20:42 +00:00
Binds = append ( Binds , c . Services . Etcd . ExtraBinds ... )
2018-02-13 00:47:56 +00:00
healthCheck := v3 . HealthCheck {
2018-04-20 20:17:45 +00:00
URL : fmt . Sprintf ( "https://%s:2379/health" , host . InternalAddress ) ,
2018-02-13 00:47:56 +00:00
}
2018-04-03 20:18:51 +00:00
registryAuthConfig , _ , _ := docker . GetImageRegistryConfig ( c . Services . Etcd . Image , c . PrivateRegistriesMap )
2019-04-30 10:28:10 +00:00
// Determine etcd version for correct etcdctl environment variables
etcdTag , err := util . GetImageTagFromImage ( c . Services . Etcd . Image )
if err != nil {
logrus . Warn ( err )
}
etcdSemVer , err := util . StrToSemVer ( etcdTag )
if err != nil {
logrus . Warn ( err )
}
2019-06-24 20:16:37 +00:00
maxEtcdOldEnvSemVer , err := util . StrToSemVer ( MaxEtcdOldEnvVersion )
2019-04-30 10:28:10 +00:00
if err != nil {
logrus . Warn ( err )
}
// Configure default etcdctl environment variables
2018-05-02 11:47:53 +00:00
Env := [ ] string { }
Env = append ( Env , "ETCDCTL_API=3" )
Env = append ( Env , fmt . Sprintf ( "ETCDCTL_CACERT=%s" , pki . GetCertPath ( pki . CACertName ) ) )
Env = append ( Env , fmt . Sprintf ( "ETCDCTL_CERT=%s" , pki . GetCertPath ( nodeName ) ) )
Env = append ( Env , fmt . Sprintf ( "ETCDCTL_KEY=%s" , pki . GetKeyPath ( nodeName ) ) )
2019-03-09 02:36:21 +00:00
2019-04-30 10:28:10 +00:00
// Apply old configuration to avoid replacing etcd container
2019-06-24 20:16:37 +00:00
if etcdSemVer . LessThan ( * maxEtcdOldEnvSemVer ) {
logrus . Debugf ( "Version [%s] is less than version [%s]" , etcdSemVer , maxEtcdOldEnvSemVer )
2019-04-30 10:28:10 +00:00
Env = append ( Env , fmt . Sprintf ( "ETCDCTL_ENDPOINT=https://%s:2379" , listenAddress ) )
} else {
2019-06-24 20:16:37 +00:00
logrus . Debugf ( "Version [%s] is equal or higher than version [%s]" , etcdSemVer , maxEtcdOldEnvSemVer )
2019-04-30 10:28:10 +00:00
// Point etcdctl to localhost in case we have listen all (0.0.0.0) configured
if listenAddress == "0.0.0.0" {
Env = append ( Env , "ETCDCTL_ENDPOINTS=https://127.0.0.1:2379" )
// If internal address is configured, set endpoint to that address as well
} else {
Env = append ( Env , fmt . Sprintf ( "ETCDCTL_ENDPOINTS=https://%s:2379" , listenAddress ) )
}
}
2019-03-09 02:36:21 +00:00
if architecture == "aarch64" {
architecture = "arm64"
}
2019-03-08 21:02:44 +00:00
Env = append ( Env , fmt . Sprintf ( "ETCD_UNSUPPORTED_ARCH=%s" , architecture ) )
2019-02-28 07:54:35 +00:00
2018-06-07 09:38:39 +00:00
Env = append ( Env , c . Services . Etcd . ExtraEnv ... )
2019-07-24 19:58:50 +00:00
var user string
if c . Services . Etcd . UID != 0 && c . Services . Etcd . GID != 0 {
user = fmt . Sprintf ( "%d:%d" , c . Services . Etcd . UID , c . Services . Etcd . UID )
}
2018-02-13 00:47:56 +00:00
return v3 . Process {
2018-04-03 20:18:51 +00:00
Name : services . EtcdContainerName ,
Args : args ,
2018-07-19 20:41:56 +00:00
Binds : getUniqStringList ( Binds ) ,
2018-05-02 11:47:53 +00:00
Env : Env ,
2019-07-24 19:58:50 +00:00
User : user ,
2018-04-03 20:18:51 +00:00
NetworkMode : "host" ,
RestartPolicy : "always" ,
Image : c . Services . Etcd . Image ,
HealthCheck : healthCheck ,
ImageRegistryAuthConfig : registryAuthConfig ,
2018-05-03 20:07:41 +00:00
Labels : map [ string ] string {
2019-08-14 10:53:32 +00:00
services . ContainerNameLabel : services . EtcdContainerName ,
2018-05-03 20:07:41 +00:00
} ,
2018-02-13 00:47:56 +00:00
}
}
func BuildPortChecksFromPortList ( host * hosts . Host , portList [ ] string , proto string ) [ ] v3 . PortCheck {
portChecks := [ ] v3 . PortCheck { }
for _ , port := range portList {
intPort , _ := strconv . Atoi ( port )
portChecks = append ( portChecks , v3 . PortCheck {
Address : host . Address ,
Port : intPort ,
Protocol : proto ,
} )
}
return portChecks
}
2018-04-11 22:54:47 +00:00
2019-09-06 22:53:14 +00:00
func ( c * Cluster ) GetKubernetesServicesOptions ( osType string , data map [ string ] * v3 . KubernetesServicesOptions ) v3 . KubernetesServicesOptions {
if osType == "windows" {
if svcOption , ok := data [ "k8s-windows-service-options" ] ; ok {
return * svcOption
}
} else {
if svcOption , ok := data [ "k8s-service-options" ] ; ok {
return * svcOption
}
}
return c . getDefaultKubernetesServicesOptions ( osType )
}
func ( c * Cluster ) getDefaultKubernetesServicesOptions ( osType string ) v3 . KubernetesServicesOptions {
2019-07-05 04:23:48 +00:00
var serviceOptionsTemplate map [ string ] v3 . KubernetesServicesOptions
switch osType {
case "windows" :
serviceOptionsTemplate = metadata . K8sVersionToWindowsServiceOptions
default :
serviceOptionsTemplate = metadata . K8sVersionToServiceOptions
}
// read service options from minor version first
if serviceOptions , ok := serviceOptionsTemplate [ c . Version ] ; ok {
2019-07-19 19:03:40 +00:00
return serviceOptions
}
2019-02-26 23:14:01 +00:00
clusterMajorVersion := util . GetTagMajorVersion ( c . Version )
2019-04-30 10:28:10 +00:00
k8sImageTag , err := util . GetImageTagFromImage ( c . SystemImages . Kubernetes )
if err != nil {
logrus . Warn ( err )
}
2018-04-18 06:52:55 +00:00
2019-02-26 23:14:01 +00:00
k8sImageMajorVersion := util . GetTagMajorVersion ( k8sImageTag )
2018-04-18 03:16:57 +00:00
2018-04-18 06:52:55 +00:00
if clusterMajorVersion != k8sImageMajorVersion && k8sImageMajorVersion != "" {
2018-04-18 03:16:57 +00:00
clusterMajorVersion = k8sImageMajorVersion
}
2019-07-05 04:23:48 +00:00
if serviceOptions , ok := serviceOptionsTemplate [ clusterMajorVersion ] ; ok {
2018-04-17 23:08:21 +00:00
return serviceOptions
}
2019-07-05 04:23:48 +00:00
2018-04-17 23:08:21 +00:00
return v3 . KubernetesServicesOptions { }
}
2018-04-18 03:16:57 +00:00
2018-12-06 23:35:11 +00:00
func getCloudConfigChecksum ( config string ) string {
configByteSum := md5 . Sum ( [ ] byte ( config ) )
2018-06-13 02:10:48 +00:00
return fmt . Sprintf ( "%x" , configByteSum )
}
func getUniqStringList ( l [ ] string ) [ ] string {
m := map [ string ] bool { }
ul := [ ] string { }
for _ , k := range l {
if _ , ok := m [ k ] ; ! ok {
m [ k ] = true
ul = append ( ul , k )
}
}
return ul
}
2018-08-03 22:01:58 +00:00
func ( c * Cluster ) getRKEToolsEntryPoint ( ) string {
v := strings . Split ( c . SystemImages . KubernetesServicesSidecar , ":" )
2018-08-09 15:03:28 +00:00
last := v [ len ( v ) - 1 ]
2018-10-04 08:54:04 +00:00
sv , err := util . StrToSemVer ( last )
2018-08-09 15:03:28 +00:00
if err != nil {
2018-08-05 01:10:48 +00:00
return DefaultToolsEntrypoint
2018-08-03 22:01:58 +00:00
}
2018-10-04 08:54:04 +00:00
svdefault , err := util . StrToSemVer ( DefaultToolsEntrypointVersion )
2018-08-09 15:03:28 +00:00
if err != nil {
return DefaultToolsEntrypoint
}
if sv . LessThan ( * svdefault ) {
2018-08-05 01:10:48 +00:00
return LegacyToolsEntrypoint
2018-08-03 22:01:58 +00:00
}
2018-08-05 01:10:48 +00:00
return DefaultToolsEntrypoint
2018-08-03 22:01:58 +00:00
}
2019-07-05 04:23:48 +00:00
func getNetworkJSON ( netconfig v3 . NetworkConfig ) string {
ret , err := json . Marshal ( netconfig )
if err != nil {
return "{}"
}
return string ( ret )
}