2017-10-29 09:45:21 +00:00
package services
import (
2018-01-09 22:10:56 +00:00
"context"
2018-02-13 00:47:56 +00:00
"fmt"
2017-12-08 23:05:55 +00:00
"github.com/docker/docker/api/types/container"
2018-05-30 08:30:12 +00:00
"github.com/docker/go-connections/nat"
2017-12-08 23:05:55 +00:00
"github.com/rancher/rke/docker"
"github.com/rancher/rke/hosts"
2018-01-09 22:10:56 +00:00
"github.com/rancher/rke/log"
2020-07-11 16:24:19 +00:00
v3 "github.com/rancher/rke/types"
2018-10-17 22:26:54 +00:00
"github.com/rancher/rke/util"
2018-03-21 17:20:58 +00:00
"github.com/sirupsen/logrus"
2017-10-29 09:45:21 +00:00
)
const (
2017-10-31 13:55:35 +00:00
ETCDRole = "etcd"
ControlRole = "controlplane"
WorkerRole = "worker"
2017-12-14 21:56:19 +00:00
SidekickServiceName = "sidekick"
RBACAuthorizationMode = "rbac"
2017-12-13 00:29:24 +00:00
2020-09-28 12:59:44 +00:00
KubeAPIContainerName = "kube-apiserver"
KubeletContainerName = "kubelet"
KubeproxyContainerName = "kube-proxy"
KubeControllerContainerName = "kube-controller-manager"
SchedulerContainerName = "kube-scheduler"
EtcdContainerName = "etcd"
EtcdSnapshotContainerName = "etcd-rolling-snapshots"
EtcdSnapshotOnceContainerName = "etcd-snapshot-once"
EtcdSnapshotRemoveContainerName = "etcd-remove-snapshot"
EtcdRestoreContainerName = "etcd-restore"
EtcdDownloadBackupContainerName = "etcd-download-backup"
EtcdServeBackupContainerName = "etcd-Serve-backup"
EtcdChecksumContainerName = "etcd-checksum-checker"
EtcdStateFileContainerName = "etcd-extract-statefile"
ControlPlaneConfigMapStateFileContainerName = "extract-statefile-configmap"
NginxProxyContainerName = "nginx-proxy"
SidekickContainerName = "service-sidekick"
LogLinkContainerName = "rke-log-linker"
LogCleanerContainerName = "rke-log-cleaner"
2017-12-19 22:18:27 +00:00
2017-12-22 01:01:53 +00:00
KubeAPIPort = 6443
2017-12-19 22:18:27 +00:00
SchedulerPort = 10251
KubeControllerPort = 10252
2019-07-18 20:42:01 +00:00
KubeletPort = 10248
2017-12-19 22:18:27 +00:00
KubeproxyPort = 10256
2018-10-17 22:26:54 +00:00
WorkerThreads = util . WorkerThreads
2019-08-14 10:53:32 +00:00
ContainerNameLabel = "io.rancher.rke.container.name"
MCSLabel = "label=level:s0:c1000,c1001"
2017-10-29 09:45:21 +00:00
)
2019-01-14 17:51:20 +00:00
type RestartFunc func ( context . Context , * hosts . Host ) error
2018-02-13 00:47:56 +00:00
func runSidekick ( ctx context . Context , host * hosts . Host , prsMap map [ string ] v3 . PrivateRegistry , sidecarProcess v3 . Process ) error {
2018-01-09 22:10:56 +00:00
isRunning , err := docker . IsContainerRunning ( ctx , host . DClient , host . Address , SidekickContainerName , true )
2017-12-08 23:05:55 +00:00
if err != nil {
return err
}
2019-08-14 10:53:32 +00:00
imageCfg , hostCfg , _ := GetProcessConfig ( sidecarProcess , host )
2018-08-02 00:33:29 +00:00
isUpgradable := false
2017-12-08 23:05:55 +00:00
if isRunning {
2018-08-02 00:33:29 +00:00
isUpgradable , err = docker . IsContainerUpgradable ( ctx , host . DClient , imageCfg , hostCfg , SidekickContainerName , host . Address , SidekickServiceName )
if err != nil {
return err
}
if ! isUpgradable {
log . Infof ( ctx , "[%s] Sidekick container already created on host [%s]" , SidekickServiceName , host . Address )
return nil
}
2017-12-08 23:05:55 +00:00
}
2018-02-13 00:47:56 +00:00
2018-08-02 00:33:29 +00:00
if err := docker . UseLocalOrPull ( ctx , host . DClient , host . Address , sidecarProcess . Image , SidekickServiceName , prsMap ) ; err != nil {
2017-12-08 23:05:55 +00:00
return err
}
2018-08-02 00:33:29 +00:00
if isUpgradable {
if err := docker . DoRemoveContainer ( ctx , host . DClient , SidekickContainerName , host . Address ) ; err != nil {
return err
}
}
2018-04-24 12:44:17 +00:00
if _ , err := docker . CreateContainer ( ctx , host . DClient , host . Address , SidekickContainerName , imageCfg , hostCfg ) ; err != nil {
2017-12-08 23:05:55 +00:00
return err
}
2019-07-05 04:23:48 +00:00
if host . DockerInfo . OSType == "windows" {
// windows dockerfile VOLUME declaration must to satisfy one of them:
// - a non-existing or empty directory
// - a drive other than C:
// so we could use a script to **start** the container to put expected resources into the "shared" directory,
// like the action of `/usr/bin/sidecar.ps1` for windows rke-tools container
return docker . StartContainer ( ctx , host . DClient , host . Address , SidekickContainerName )
}
2017-12-08 23:05:55 +00:00
return nil
}
2018-01-09 22:10:56 +00:00
func removeSidekick ( ctx context . Context , host * hosts . Host ) error {
return docker . DoRemoveContainer ( ctx , host . DClient , SidekickContainerName , host . Address )
2017-12-08 23:05:55 +00:00
}
2018-02-13 00:47:56 +00:00
2019-08-14 10:53:32 +00:00
func GetProcessConfig ( process v3 . Process , host * hosts . Host ) ( * container . Config , * container . HostConfig , string ) {
2018-02-13 00:47:56 +00:00
imageCfg := & container . Config {
Entrypoint : process . Command ,
Cmd : process . Args ,
Env : process . Env ,
Image : process . Image ,
2018-05-03 20:07:41 +00:00
Labels : process . Labels ,
2019-07-24 19:58:50 +00:00
User : process . User ,
2018-02-13 00:47:56 +00:00
}
// var pidMode container.PidMode
// pidMode = process.PidMode
2018-05-30 08:30:12 +00:00
_ , portBindings , _ := nat . ParsePortSpecs ( process . Publish )
2018-02-13 00:47:56 +00:00
hostCfg := & container . HostConfig {
2018-05-30 08:30:12 +00:00
VolumesFrom : process . VolumesFrom ,
Binds : process . Binds ,
NetworkMode : container . NetworkMode ( process . NetworkMode ) ,
PidMode : container . PidMode ( process . PidMode ) ,
Privileged : process . Privileged ,
PortBindings : portBindings ,
2018-02-13 00:47:56 +00:00
}
if len ( process . RestartPolicy ) > 0 {
hostCfg . RestartPolicy = container . RestartPolicy { Name : process . RestartPolicy }
}
2019-08-30 14:33:22 +00:00
// The MCS label only needs to be applied when container is not running privileged, and running privileged negates need for applying the label
2020-05-19 19:50:24 +00:00
// If Docker is configured with selinux-enabled:true, we need to specify MCS label to allow files from service-sidekick to be shared between containers
if ! process . Privileged && hosts . IsDockerSELinuxEnabled ( host ) {
logrus . Debugf ( "Found selinux in DockerInfo.SecurityOptions on host [%s]" , host . Address )
// Check for containers having the sidekick container
for _ , volumeFrom := range hostCfg . VolumesFrom {
if volumeFrom == SidekickContainerName {
logrus . Debugf ( "Found [%s] in VolumesFrom on host [%s], applying MCSLabel [%s]" , SidekickContainerName , host . Address , MCSLabel )
hostCfg . SecurityOpt = [ ] string { MCSLabel }
}
}
// Check for sidekick container itself
if value , ok := imageCfg . Labels [ ContainerNameLabel ] ; ok {
if value == SidekickContainerName {
logrus . Debugf ( "Found [%s=%s] in Labels on host [%s], applying MCSLabel [%s]" , ContainerNameLabel , SidekickContainerName , host . Address , MCSLabel )
hostCfg . SecurityOpt = [ ] string { MCSLabel }
2019-08-14 10:53:32 +00:00
}
}
}
2018-02-13 00:47:56 +00:00
return imageCfg , hostCfg , process . HealthCheck . URL
}
func GetHealthCheckURL ( useTLS bool , port int ) string {
if useTLS {
return fmt . Sprintf ( "%s%s:%d%s" , HTTPSProtoPrefix , HealthzAddress , port , HealthzEndpoint )
}
return fmt . Sprintf ( "%s%s:%d%s" , HTTPProtoPrefix , HealthzAddress , port , HealthzEndpoint )
}
2018-03-21 17:20:58 +00:00
func createLogLink ( ctx context . Context , host * hosts . Host , containerName , plane , image string , prsMap map [ string ] v3 . PrivateRegistry ) error {
logrus . Debugf ( "[%s] Creating log link for Container [%s] on host [%s]" , plane , containerName , host . Address )
containerInspect , err := docker . InspectContainer ( ctx , host . DClient , host . Address , containerName )
if err != nil {
return err
}
containerID := containerInspect . ID
containerLogPath := containerInspect . LogPath
2018-06-27 18:37:51 +00:00
containerLogLink := fmt . Sprintf ( "%s/%s_%s.log" , hosts . RKELogsPath , containerName , containerID )
2018-03-21 17:20:58 +00:00
imageCfg := & container . Config {
Image : image ,
Tty : true ,
Cmd : [ ] string {
"sh" ,
"-c" ,
2018-06-27 18:37:51 +00:00
fmt . Sprintf ( "mkdir -p %s ; ln -s %s %s" , hosts . RKELogsPath , containerLogPath , containerLogLink ) ,
2018-03-21 17:20:58 +00:00
} ,
}
hostCfg := & container . HostConfig {
Binds : [ ] string {
2018-06-25 18:40:51 +00:00
"/var/lib:/var/lib" ,
2018-03-21 17:20:58 +00:00
} ,
Privileged : true ,
}
if err := docker . DoRemoveContainer ( ctx , host . DClient , LogLinkContainerName , host . Address ) ; err != nil {
return err
}
if err := docker . DoRunContainer ( ctx , host . DClient , imageCfg , hostCfg , LogLinkContainerName , host . Address , plane , prsMap ) ; err != nil {
return err
}
if err := docker . DoRemoveContainer ( ctx , host . DClient , LogLinkContainerName , host . Address ) ; err != nil {
return err
}
logrus . Debugf ( "[%s] Successfully created log link for Container [%s] on host [%s]" , plane , containerName , host . Address )
return nil
}