Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shared IPC namespace for containers in a pod #3817

Merged
merged 1 commit into from
Jan 27, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/kubelet/kubelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ var (
address = util.IP(net.ParseIP("127.0.0.1"))
port = flag.Uint("port", ports.KubeletPort, "The port for the info server to serve on")
hostnameOverride = flag.String("hostname_override", "", "If non-empty, will use this string as identification instead of the actual hostname.")
networkContainerImage = flag.String("network_container_image", kubelet.NetworkContainerImage, "The image that network containers in each pod will use.")
podInfraContainerImage = flag.String("pod_infra_container_image", kubelet.PodInfraContainerImage, "The image whose network/ipc namespaces containers in each pod will use.")
dockerEndpoint = flag.String("docker_endpoint", "", "If non-empty, use this for the docker endpoint to communicate with")
etcdServerList util.StringList
etcdConfigFile = flag.String("etcd_config", "", "The config file for the etcd client. Mutually exclusive with -etcd_servers")
Expand Down Expand Up @@ -136,7 +136,7 @@ func main() {
ManifestURL: *manifestURL,
FileCheckFrequency: *fileCheckFrequency,
HttpCheckFrequency: *httpCheckFrequency,
NetworkContainerImage: *networkContainerImage,
PodInfraContainerImage: *podInfraContainerImage,
SyncFrequency: *syncFrequency,
RegistryPullQPS: *registryPullQPS,
RegistryBurst: *registryBurst,
Expand Down
18 changes: 11 additions & 7 deletions pkg/kubelet/dockertools/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ import (
"github.com/golang/glog"
)

const (
PodInfraContainerName = "POD" // This should match the constant defined in kubelet
)

// DockerInterface is an abstract interface for testability. It abstracts the interface of docker.Client.
type DockerInterface interface {
ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error)
Expand Down Expand Up @@ -372,8 +376,8 @@ var (
// ErrNoContainersInPod is returned when there are no containers for a given pod
ErrNoContainersInPod = errors.New("no containers exist for this pod")

// ErrNoNetworkContainerInPod is returned when there is no network container for a given pod
ErrNoNetworkContainerInPod = errors.New("No network container exists for this pod")
// ErrNoPodInfraContainerInPod is returned when there is no pod infra container for a given pod
ErrNoPodInfraContainerInPod = errors.New("No pod infra container exists for this pod")

// ErrContainerCannotRun is returned when a container is created, but cannot run properly
ErrContainerCannotRun = errors.New("Container cannot run")
Expand Down Expand Up @@ -401,7 +405,7 @@ func inspectContainer(client DockerInterface, dockerID, containerName, tPath str
containerStatus.State.Running = &api.ContainerStateRunning{
StartedAt: util.NewTime(inspectResult.State.StartedAt),
}
if containerName == "net" && inspectResult.NetworkSettings != nil {
if containerName == PodInfraContainerName && inspectResult.NetworkSettings != nil {
containerStatus.PodIP = inspectResult.NetworkSettings.IPAddress
}
waiting = false
Expand Down Expand Up @@ -454,7 +458,7 @@ func GetDockerPodInfo(client DockerInterface, manifest api.PodSpec, podFullName
for _, container := range manifest.Containers {
expectedContainers[container.Name] = container
}
expectedContainers["net"] = api.Container{}
expectedContainers[PodInfraContainerName] = api.Container{}

containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
if err != nil {
Expand Down Expand Up @@ -498,9 +502,9 @@ func GetDockerPodInfo(client DockerInterface, manifest api.PodSpec, podFullName
return nil, ErrNoContainersInPod
}

// First make sure we are not missing network container
if _, found := info["net"]; !found {
return nil, ErrNoNetworkContainerInPod
// First make sure we are not missing pod infra container
if _, found := info[PodInfraContainerName]; !found {
return nil, ErrNoPodInfraContainerInPod
}

if len(info) < (len(manifest.Containers) + 1) {
Expand Down
3 changes: 2 additions & 1 deletion pkg/kubelet/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"strconv"

"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/golang/glog"
Expand Down Expand Up @@ -77,7 +78,7 @@ func (h *httpActionHandler) Run(podFullName string, uid types.UID, container *ap
glog.Errorf("unable to get pod info, event handlers may be invalid.")
return err
}
netInfo, found := status.Info[networkContainerName]
netInfo, found := status.Info[dockertools.PodInfraContainerName]
if found {
host = netInfo.PodIP
} else {
Expand Down
71 changes: 36 additions & 35 deletions pkg/kubelet/kubelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func NewMainKubelet(
etcdClient tools.EtcdClient,
kubeClient *client.Client,
rootDirectory string,
networkContainerImage string,
podInfraContainerImage string,
resyncInterval time.Duration,
pullQPS float32,
pullBurst int,
Expand Down Expand Up @@ -106,7 +106,7 @@ func NewMainKubelet(
kubeClient: kubeClient,
rootDirectory: rootDirectory,
resyncInterval: resyncInterval,
networkContainerImage: networkContainerImage,
podInfraContainerImage: podInfraContainerImage,
podWorkers: newPodWorkers(),
dockerIDToRef: map[dockertools.DockerID]*api.ObjectReference{},
runner: dockertools.NewDockerContainerCommandRunner(dockerClient),
Expand Down Expand Up @@ -142,15 +142,15 @@ type serviceLister interface {

// Kubelet is the main kubelet implementation.
type Kubelet struct {
hostname string
dockerClient dockertools.DockerInterface
kubeClient *client.Client
rootDirectory string
networkContainerImage string
podWorkers *podWorkers
resyncInterval time.Duration
pods []api.BoundPod
sourceReady SourceReadyFn
hostname string
dockerClient dockertools.DockerInterface
kubeClient *client.Client
rootDirectory string
podInfraContainerImage string
podWorkers *podWorkers
resyncInterval time.Duration
pods []api.BoundPod
sourceReady SourceReadyFn

// Needed to report events for containers belonging to deleted/modified pods.
// Tracks references for reporting events
Expand Down Expand Up @@ -583,7 +583,7 @@ func containerRef(pod *api.BoundPod, container *api.Container) (*api.ObjectRefer
fieldPath, err := fieldPath(pod, container)
if err != nil {
// TODO: figure out intelligent way to refer to containers that we implicitly
// start (like the network container). This is not a good way, ugh.
// start (like the pod infra container). This is not a good way, ugh.
fieldPath = "implicitly required container " + container.Name
}
ref, err := api.GetPartialReference(pod, fieldPath)
Expand Down Expand Up @@ -619,7 +619,7 @@ func (kl *Kubelet) getRef(id dockertools.DockerID) (ref *api.ObjectReference, ok
}

// Run a single container from a pod. Returns the docker container ID
func (kl *Kubelet) runContainer(pod *api.BoundPod, container *api.Container, podVolumes volumeMap, netMode string) (id dockertools.DockerID, err error) {
func (kl *Kubelet) runContainer(pod *api.BoundPod, container *api.Container, podVolumes volumeMap, netMode, ipcMode string) (id dockertools.DockerID, err error) {
ref, err := containerRef(pod, container)
if err != nil {
glog.Errorf("Couldn't make a ref to pod %v, container %v: '%v'", pod.Name, container.Name, err)
Expand Down Expand Up @@ -684,6 +684,7 @@ func (kl *Kubelet) runContainer(pod *api.BoundPod, container *api.Container, pod
PortBindings: portBindings,
Binds: binds,
NetworkMode: netMode,
IpcMode: ipcMode,
Privileged: privileged,
}
if pod.Spec.DNSPolicy == api.DNSClusterFirst {
Expand Down Expand Up @@ -878,21 +879,20 @@ func (kl *Kubelet) killContainerByID(ID, name string) error {
}

const (
networkContainerName = "net"
NetworkContainerImage = "kubernetes/pause:latest"
PodInfraContainerImage = "kubernetes/pause:latest"
)

// createNetworkContainer starts the network container for a pod. Returns the docker container ID of the newly created container.
func (kl *Kubelet) createNetworkContainer(pod *api.BoundPod) (dockertools.DockerID, error) {
// createPodInfraContainer starts the pod infra container for a pod. Returns the docker container ID of the newly created container.
func (kl *Kubelet) createPodInfraContainer(pod *api.BoundPod) (dockertools.DockerID, error) {
var ports []api.Port
// Docker only exports ports from the network container. Let's
// 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 {
ports = append(ports, container.Ports...)
}
container := &api.Container{
Name: networkContainerName,
Image: kl.networkContainerImage,
Name: dockertools.PodInfraContainerName,
Image: kl.podInfraContainerImage,
Ports: ports,
}
ref, err := containerRef(pod, container)
Expand All @@ -915,7 +915,7 @@ func (kl *Kubelet) createNetworkContainer(pod *api.BoundPod) (dockertools.Docker
if ref != nil {
record.Eventf(ref, "pulled", "Successfully pulled image %q", container.Image)
}
return kl.runContainer(pod, container, nil, "")
return kl.runContainer(pod, container, nil, "", "")
}

func (kl *Kubelet) pullImage(img string, ref *api.ObjectReference) error {
Expand Down Expand Up @@ -987,19 +987,19 @@ func (kl *Kubelet) syncPod(pod *api.BoundPod, dockerContainers dockertools.Docke
return err
}

// Make sure we have a network container
var netID dockertools.DockerID
if netDockerContainer, found, _ := dockerContainers.FindPodContainer(podFullName, uid, networkContainerName); found {
netID = dockertools.DockerID(netDockerContainer.ID)
// Make sure we have a pod infra container
var podInfraContainerID dockertools.DockerID
if podInfraDockerContainer, found, _ := dockerContainers.FindPodContainer(podFullName, uid, dockertools.PodInfraContainerName); found {
podInfraContainerID = dockertools.DockerID(podInfraDockerContainer.ID)
} else {
glog.V(2).Infof("Network container doesn't exist for pod %q, killing and re-creating the pod", podFullName)
count, err := kl.killContainersInPod(pod, dockerContainers)
if err != nil {
return err
}
netID, err = kl.createNetworkContainer(pod)
podInfraContainerID, err = kl.createPodInfraContainer(pod)
if err != nil {
glog.Errorf("Failed to introspect network container: %v; Skipping pod %q", err, podFullName)
glog.Errorf("Failed to introspect pod infra container: %v; Skipping pod %q", err, podFullName)
return err
}
if count > 0 {
Expand All @@ -1011,7 +1011,7 @@ func (kl *Kubelet) syncPod(pod *api.BoundPod, dockerContainers dockertools.Docke
}
}
}
containersToKeep[netID] = empty{}
containersToKeep[podInfraContainerID] = empty{}

podVolumes, err := kl.mountExternalVolumes(pod)
if err != nil {
Expand All @@ -1023,7 +1023,7 @@ func (kl *Kubelet) syncPod(pod *api.BoundPod, dockerContainers dockertools.Docke
if err != nil {
glog.Errorf("Unable to get pod with name %q and uid %q info, health checks may be invalid", podFullName, uid)
}
netInfo, found := podStatus.Info[networkContainerName]
netInfo, found := podStatus.Info[dockertools.PodInfraContainerName]
if found {
podStatus.PodIP = netInfo.PodIP
}
Expand Down Expand Up @@ -1058,10 +1058,10 @@ func (kl *Kubelet) syncPod(pod *api.BoundPod, dockerContainers dockertools.Docke
}
killedContainers[containerID] = empty{}

// Also kill associated network container
if netContainer, found, _ := dockerContainers.FindPodContainer(podFullName, uid, networkContainerName); found {
if err := kl.killContainer(netContainer); err != nil {
glog.V(1).Infof("Failed to kill network container %q: %v", netContainer.ID, err)
// Also kill associated pod infra container
if podInfraContainer, found, _ := dockerContainers.FindPodContainer(podFullName, uid, dockertools.PodInfraContainerName); found {
if err := kl.killContainer(podInfraContainer); err != nil {
glog.V(1).Infof("Failed to kill pod infra container %q: %v", podInfraContainer.ID, err)
continue
}
}
Expand Down Expand Up @@ -1112,7 +1112,8 @@ func (kl *Kubelet) syncPod(pod *api.BoundPod, dockerContainers dockertools.Docke
}
}
// TODO(dawnchen): Check RestartPolicy.DelaySeconds before restart a container
containerID, err := kl.runContainer(pod, &container, podVolumes, "container:"+string(netID))
namespaceMode := fmt.Sprintf("container:%v", podInfraContainerID)
containerID, err := kl.runContainer(pod, &container, podVolumes, namespaceMode, namespaceMode)
if err != nil {
// TODO(bburns) : Perhaps blacklist a container after N failures?
glog.Errorf("Error running pod %q container %q: %v", podFullName, container.Name, err)
Expand Down Expand Up @@ -1222,7 +1223,7 @@ func (kl *Kubelet) SyncPods(pods []api.BoundPod) error {
desiredPods[uid] = empty{}

// Add all containers (including net) to the map.
desiredContainers[podContainer{podFullName, uid, networkContainerName}] = empty{}
desiredContainers[podContainer{podFullName, uid, dockertools.PodInfraContainerName}] = empty{}
for _, cont := range pod.Spec.Containers {
desiredContainers[podContainer{podFullName, uid, cont.Name}] = empty{}
}
Expand Down