2017-10-29 11:45:21 +02:00
package services
import (
2018-01-09 15:10:56 -07:00
"context"
2018-02-13 02:47:56 +02:00
"fmt"
2017-12-09 01:05:55 +02:00
"github.com/docker/docker/api/types/container"
2018-05-30 16:30:12 +08:00
"github.com/docker/go-connections/nat"
2017-12-09 01:05:55 +02:00
"github.com/rancher/rke/docker"
"github.com/rancher/rke/hosts"
2018-01-09 15:10:56 -07:00
"github.com/rancher/rke/log"
2020-07-11 09:24:19 -07:00
v3 "github.com/rancher/rke/types"
2018-10-18 00:26:54 +02:00
"github.com/rancher/rke/util"
2018-03-21 19:20:58 +02:00
"github.com/sirupsen/logrus"
2017-10-29 11:45:21 +02:00
)
const (
2017-10-31 15:55:35 +02:00
ETCDRole = "etcd"
ControlRole = "controlplane"
WorkerRole = "worker"
2017-12-14 23:56:19 +02:00
SidekickServiceName = "sidekick"
RBACAuthorizationMode = "rbac"
2017-12-13 01:29:24 +01:00
2020-09-28 14:59:44 +02: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-20 00:18:27 +02:00
2017-12-22 03:01:53 +02:00
KubeAPIPort = 6443
2017-12-20 00:18:27 +02:00
SchedulerPort = 10251
KubeControllerPort = 10252
2019-07-18 22:42:01 +02:00
KubeletPort = 10248
2017-12-20 00:18:27 +02:00
KubeproxyPort = 10256
2018-10-18 00:26:54 +02:00
WorkerThreads = util . WorkerThreads
2019-08-14 12:53:32 +02:00
ContainerNameLabel = "io.rancher.rke.container.name"
MCSLabel = "label=level:s0:c1000,c1001"
2021-03-16 10:54:01 +01:00
SELinuxLabel = "label=type:rke_container_t"
2017-10-29 11:45:21 +02:00
)
2019-01-14 19:51:20 +02:00
type RestartFunc func ( context . Context , * hosts . Host ) error
2018-02-13 02:47:56 +02:00
func runSidekick ( ctx context . Context , host * hosts . Host , prsMap map [ string ] v3 . PrivateRegistry , sidecarProcess v3 . Process ) error {
2018-01-09 15:10:56 -07:00
isRunning , err := docker . IsContainerRunning ( ctx , host . DClient , host . Address , SidekickContainerName , true )
2017-12-09 01:05:55 +02:00
if err != nil {
return err
}
2019-08-14 12:53:32 +02:00
imageCfg , hostCfg , _ := GetProcessConfig ( sidecarProcess , host )
2018-08-02 02:33:29 +02:00
isUpgradable := false
2017-12-09 01:05:55 +02:00
if isRunning {
2018-08-02 02:33:29 +02: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-09 01:05:55 +02:00
}
2018-02-13 02:47:56 +02:00
2018-08-02 02:33:29 +02:00
if err := docker . UseLocalOrPull ( ctx , host . DClient , host . Address , sidecarProcess . Image , SidekickServiceName , prsMap ) ; err != nil {
2017-12-09 01:05:55 +02:00
return err
}
2018-08-02 02:33:29 +02:00
if isUpgradable {
if err := docker . DoRemoveContainer ( ctx , host . DClient , SidekickContainerName , host . Address ) ; err != nil {
return err
}
}
2018-04-24 14:44:17 +02:00
if _ , err := docker . CreateContainer ( ctx , host . DClient , host . Address , SidekickContainerName , imageCfg , hostCfg ) ; err != nil {
2017-12-09 01:05:55 +02:00
return err
}
2019-07-05 12:23:48 +08: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-09 01:05:55 +02:00
return nil
}
2018-01-09 15:10:56 -07:00
func removeSidekick ( ctx context . Context , host * hosts . Host ) error {
return docker . DoRemoveContainer ( ctx , host . DClient , SidekickContainerName , host . Address )
2017-12-09 01:05:55 +02:00
}
2018-02-13 02:47:56 +02:00
2019-08-14 12:53:32 +02:00
func GetProcessConfig ( process v3 . Process , host * hosts . Host ) ( * container . Config , * container . HostConfig , string ) {
2018-02-13 02:47:56 +02:00
imageCfg := & container . Config {
Entrypoint : process . Command ,
Cmd : process . Args ,
Env : process . Env ,
Image : process . Image ,
2018-05-03 22:07:41 +02:00
Labels : process . Labels ,
2019-07-24 21:58:50 +02:00
User : process . User ,
2018-02-13 02:47:56 +02:00
}
// var pidMode container.PidMode
// pidMode = process.PidMode
2018-05-30 16:30:12 +08:00
_ , portBindings , _ := nat . ParsePortSpecs ( process . Publish )
2018-02-13 02:47:56 +02:00
hostCfg := & container . HostConfig {
2018-05-30 16:30:12 +08: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 02:47:56 +02:00
}
if len ( process . RestartPolicy ) > 0 {
hostCfg . RestartPolicy = container . RestartPolicy { Name : process . RestartPolicy }
}
2019-08-30 16:33:22 +02: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 21:50:24 +02: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 12:53:32 +02:00
}
}
2021-03-16 10:54:01 +01:00
// We apply the label because we do not rewrite SELinux labels anymore on volume mounts (no :z)
logrus . Debugf ( "Applying security opt label [%s] for etcd container on host [%s]" , SELinuxLabel , host . Address )
hostCfg . SecurityOpt = append ( hostCfg . SecurityOpt , SELinuxLabel )
2019-08-14 12:53:32 +02:00
}
2018-02-13 02:47:56 +02: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 19:20:58 +02: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 20:37:51 +02:00
containerLogLink := fmt . Sprintf ( "%s/%s_%s.log" , hosts . RKELogsPath , containerName , containerID )
2018-03-21 19:20:58 +02:00
imageCfg := & container . Config {
Image : image ,
Tty : true ,
Cmd : [ ] string {
"sh" ,
"-c" ,
2018-06-27 20:37:51 +02:00
fmt . Sprintf ( "mkdir -p %s ; ln -s %s %s" , hosts . RKELogsPath , containerLogPath , containerLogLink ) ,
2018-03-21 19:20:58 +02:00
} ,
}
hostCfg := & container . HostConfig {
Binds : [ ] string {
2018-06-25 20:40:51 +02:00
"/var/lib:/var/lib" ,
2018-03-21 19:20:58 +02: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
}