Skip to content

Commit

Permalink
kubelet: Introduce PodInfraContainerChanged().
Browse files Browse the repository at this point in the history
This functions computes in ahead whether we need to restart the pod
infra container.
  • Loading branch information
Yifan Gu committed Apr 9, 2015
1 parent 015b13f commit de82552
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 18 deletions.
2 changes: 1 addition & 1 deletion pkg/kubelet/dockertools/fake_docker_client.go
Expand Up @@ -141,7 +141,7 @@ func (f *FakeDockerClient) InspectContainer(id string) (*docker.Container, error
return container, f.Err
}
}
return f.Container, f.Err
return nil, fmt.Errorf("No container is found for %q", id)
}

// InspectImage is a test-spy implementation of DockerInterface.InspectImage.
Expand Down
81 changes: 81 additions & 0 deletions pkg/kubelet/dockertools/manager.go
Expand Up @@ -23,6 +23,7 @@ import (
"io/ioutil"
"os"
"path"
"reflect"
"strconv"
"strings"

Expand Down Expand Up @@ -455,3 +456,83 @@ func makeCapabilites(capAdd []api.CapabilityType, capDrop []api.CapabilityType)
}
return addCaps, dropCaps
}

// PodInfraContainer returns true if the pod infra container has changed.
func (self *DockerManager) PodInfraContainerChanged(pod *api.Pod, podInfraContainer *kubecontainer.Container) (bool, error) {
networkMode := ""
var ports, actualPorts []api.ContainerPort

dockerPodInfraContainer, err := self.client.InspectContainer(string(podInfraContainer.ID))
if err != nil {
return false, err
}

// Check network mode.
if dockerPodInfraContainer.HostConfig != nil {
networkMode = dockerPodInfraContainer.HostConfig.NetworkMode
}
if pod.Spec.HostNetwork && networkMode != "host" {
return true, nil
}

// Docker only exports ports from the pod infra container. Let's
// collect all of the relevant ports and export them.
for _, container := range pod.Spec.Containers {
for _, port := range container.Ports {
// Unify the port, filter the 'Name' since it's not
// used in the docker container.
ports = append(ports, api.ContainerPort{
HostPort: port.HostPort,
ContainerPort: port.ContainerPort,
Protocol: api.Protocol(strings.ToLower(string(port.Protocol))),
HostIP: port.HostIP,
})
}
}
expectedContainer := api.Container{
Name: PodInfraContainerName,
Image: PodInfraContainerImage,
Ports: ports,
}

dockerName, _, err := ParseDockerName(dockerPodInfraContainer.Name)
if err != nil {
return false, err
}

// Parse the port information in the docker container retrived by 'docker inspect'.
if dockerPodInfraContainer.NetworkSettings != nil {
for dockerPort, portBindings := range dockerPodInfraContainer.NetworkSettings.Ports {
for _, portBinding := range portBindings {
// 'dockerPort' is in the form of 'port/protocol', e.g. '80/tcp'.
p := strings.Split(string(dockerPort), "/")
if len(p) != 2 {
return false, fmt.Errorf("Invalid docker port: %v", dockerPort)
}
containerPort, err := strconv.Atoi(p[0])
if err != nil {
return false, err
}
protocol := api.Protocol(strings.ToLower(p[1]))
hostPort, err := strconv.Atoi(portBinding.HostPort)
hostIP := portBinding.HostIP
if err != nil {
return false, err
}
actualPorts = append(actualPorts, api.ContainerPort{
HostPort: hostPort,
ContainerPort: containerPort,
Protocol: protocol,
HostIP: hostIP,
})
}
}
}

actualContainer := api.Container{
Name: dockerName.ContainerName,
Image: dockerPodInfraContainer.Config.Image,
Ports: actualPorts,
}
return reflect.DeepEqual(expectedContainer, actualContainer), nil
}
31 changes: 14 additions & 17 deletions pkg/kubelet/kubelet.go
Expand Up @@ -1107,15 +1107,23 @@ func (kl *Kubelet) computePodContainerChanges(pod *api.Pod, runningPod kubeconta
createPodInfraContainer := false

var podInfraContainerID dockertools.DockerID
var changed bool
podInfraContainer := runningPod.FindContainerByName(dockertools.PodInfraContainerName)
if podInfraContainer != nil {
glog.V(4).Infof("Found infra pod for %q", podFullName)
podInfraContainerID = dockertools.DockerID(podInfraContainer.ID)
containersToKeep[podInfraContainerID] = -1
glog.V(4).Infof("Found pod infra container for %q", podFullName)
changed, err = kl.containerManager.PodInfraContainerChanged(pod, podInfraContainer)
if err != nil {
return podContainerChangesSpec{}, err
}
}

} else {
glog.V(2).Infof("No Infra Container for %q found. All containers will be restarted.", podFullName)
if podInfraContainer == nil || changed {
glog.V(4).Infof("Need to restart pod infra container for %q because it is not found or changed", podFullName)
createPodInfraContainer = true
} else {
glog.V(4).Infof("Pod infra container looks good, keep it %q", podFullName)
podInfraContainerID = dockertools.DockerID(podInfraContainer.ID)
containersToKeep[podInfraContainerID] = -1
}

// Do not use the cache here since we need the newest status to check
Expand Down Expand Up @@ -1157,21 +1165,10 @@ func (kl *Kubelet) computePodContainerChanges(pod *api.Pod, runningPod kubeconta
continue
}
glog.Infof("pod %q container %q is unhealthy (probe result: %v). Container will be killed and re-created.", podFullName, container.Name, result)
containersToStart[index] = empty{}
} else {
glog.Infof("pod %q container %q hash changed (%d vs %d). Pod will be killed and re-created.", podFullName, container.Name, hash, expectedHash)
createPodInfraContainer = true
delete(containersToKeep, podInfraContainerID)
// If we are to restart Infra Container then we move containersToKeep into containersToStart
// if RestartPolicy allows restarting failed containers.
if pod.Spec.RestartPolicy != api.RestartPolicyNever {
for _, v := range containersToKeep {
containersToStart[v] = empty{}
}
}
containersToStart[index] = empty{}
containersToKeep = make(map[dockertools.DockerID]int)
}
containersToStart[index] = empty{}
} else { // createPodInfraContainer == true and Container exists
// If we're creating infra containere everything will be killed anyway
// If RestartPolicy is Always or OnFailure we restart containers that were running before we
Expand Down
14 changes: 14 additions & 0 deletions pkg/kubelet/kubelet_test.go
Expand Up @@ -455,6 +455,20 @@ func TestSyncPodsDoesNothing(t *testing.T) {
ID: "9876",
},
}

fakeDocker.ContainerMap = map[string]*docker.Container{
"1234": {
ID: "1234",
HostConfig: &docker.HostConfig{},
Config: &docker.Config{},
},
"9876": {
ID: "9876",
HostConfig: &docker.HostConfig{},
Config: &docker.Config{},
},
}

pods := []api.Pod{
{
ObjectMeta: api.ObjectMeta{
Expand Down

0 comments on commit de82552

Please sign in to comment.