// Determined whether the specified pod is allowed to use host networking func allowHostNetwork(pod *api.Pod) (bool, error) { podSource, err := getPodSource(pod) if err != nil { return false, err } for _, source := range capabilities.Get().HostNetworkSources { if source == podSource { return true, nil } } return false, nil }
func validateContainers(containers []api.Container, volumes util.StringSet) errs.ValidationErrorList { allErrs := errs.ValidationErrorList{} if len(containers) == 0 { return append(allErrs, errs.NewFieldRequired("")) } allNames := util.StringSet{} for i, ctr := range containers { cErrs := errs.ValidationErrorList{} capabilities := capabilities.Get() if len(ctr.Name) == 0 { cErrs = append(cErrs, errs.NewFieldRequired("name")) } else if !util.IsDNS1123Label(ctr.Name) { cErrs = append(cErrs, errs.NewFieldInvalid("name", ctr.Name, dns1123LabelErrorMsg)) } else if allNames.Has(ctr.Name) { cErrs = append(cErrs, errs.NewFieldDuplicate("name", ctr.Name)) } else if ctr.Privileged && !capabilities.AllowPrivileged { cErrs = append(cErrs, errs.NewFieldForbidden("privileged", ctr.Privileged)) } else { allNames.Insert(ctr.Name) } if len(ctr.Image) == 0 { cErrs = append(cErrs, errs.NewFieldRequired("image")) } if ctr.Lifecycle != nil { cErrs = append(cErrs, validateLifecycle(ctr.Lifecycle).Prefix("lifecycle")...) } cErrs = append(cErrs, validateProbe(ctr.LivenessProbe).Prefix("livenessProbe")...) cErrs = append(cErrs, validateProbe(ctr.ReadinessProbe).Prefix("readinessProbe")...) cErrs = append(cErrs, validatePorts(ctr.Ports).Prefix("ports")...) cErrs = append(cErrs, validateEnv(ctr.Env).Prefix("env")...) cErrs = append(cErrs, validateVolumeMounts(ctr.VolumeMounts, volumes).Prefix("volumeMounts")...) cErrs = append(cErrs, validatePullPolicy(&ctr).Prefix("pullPolicy")...) cErrs = append(cErrs, validateResourceRequirements(&ctr).Prefix("resources")...) allErrs = append(allErrs, cErrs.PrefixIndex(i)...) } // Check for colliding ports across all containers. // TODO(thockin): This really is dependent on the network config of the host (IP per pod?) // and the config of the new manifest. But we have not specced that out yet, so we'll just // make some assumptions for now. As of now, pods share a network namespace, which means that // every Port.HostPort across the whole pod must be unique. allErrs = append(allErrs, checkHostPortConflicts(containers)...) return allErrs }
// Run a single container from a pod. Returns the docker container ID func (kl *Kubelet) runContainer(pod *Pod, container *api.Container, podVolumes volumeMap, netMode string) (id dockertools.DockerID, err error) { envVariables := makeEnvironmentVariables(container) binds := makeBinds(pod, container, podVolumes) exposedPorts, portBindings := makePortsAndBindings(container) opts := docker.CreateContainerOptions{ Name: dockertools.BuildDockerName(pod.Manifest.UUID, GetPodFullName(pod), container), Config: &docker.Config{ Cmd: container.Command, Env: envVariables, ExposedPorts: exposedPorts, Hostname: pod.Name, Image: container.Image, Memory: int64(container.Memory), CpuShares: int64(milliCPUToShares(container.CPU)), WorkingDir: container.WorkingDir, }, } dockerContainer, err := kl.dockerClient.CreateContainer(opts) if err != nil { return "", err } privileged := false if capabilities.Get().AllowPrivileged { privileged = container.Privileged } else if container.Privileged { return "", fmt.Errorf("Container requested privileged mode, but it is disallowed globally.") } err = kl.dockerClient.StartContainer(dockerContainer.ID, &docker.HostConfig{ PortBindings: portBindings, Binds: binds, NetworkMode: netMode, Privileged: privileged, }) if err == nil && container.Lifecycle != nil && container.Lifecycle.PostStart != nil { handlerErr := kl.runHandler(GetPodFullName(pod), pod.Manifest.UUID, container, container.Lifecycle.PostStart) if handlerErr != nil { kl.killContainerByID(dockerContainer.ID, "") return dockertools.DockerID(""), fmt.Errorf("failed to call event handler: %v", handlerErr) } } return dockertools.DockerID(dockerContainer.ID), err }
// Check whether we have the capabilities to run the specified pod. func canRunPod(pod *api.Pod) error { if pod.Spec.HostNetwork { allowed, err := allowHostNetwork(pod) if err != nil { return err } if !allowed { return fmt.Errorf("pod with UID %q specified host networking, but is disallowed", pod.UID) } } if !capabilities.Get().AllowPrivileged { for _, container := range pod.Spec.Containers { if securitycontext.HasPrivilegedRequest(&container) { return fmt.Errorf("pod with UID %q specified privileged container, but is disallowed", pod.UID) } } } return nil }
// 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) { 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) } envVariables := makeEnvironmentVariables(container) binds := makeBinds(pod, container, podVolumes) exposedPorts, portBindings := makePortsAndBindings(container) opts := docker.CreateContainerOptions{ Name: dockertools.BuildDockerName(pod.UID, GetPodFullName(pod), container), Config: &docker.Config{ Cmd: container.Command, Env: envVariables, ExposedPorts: exposedPorts, Hostname: pod.Name, Image: container.Image, Memory: container.Memory.Value(), CPUShares: milliCPUToShares(container.CPU.MilliValue()), WorkingDir: container.WorkingDir, }, } dockerContainer, err := kl.dockerClient.CreateContainer(opts) if err != nil { if ref != nil { record.Eventf(ref, "failed", "failed", "Failed to create docker container with error: %v", err) } return "", err } // Remember this reference so we can report events about this container if ref != nil { kl.setRef(dockertools.DockerID(dockerContainer.ID), ref) record.Eventf(ref, "waiting", "created", "Created with docker id %v", dockerContainer.ID) } if len(container.TerminationMessagePath) != 0 { p := kl.GetPodContainerDir(pod.UID, container.Name) if err := os.MkdirAll(p, 0750); err != nil { glog.Errorf("Error on creating %q: %v", p, err) } else { containerLogPath := path.Join(p, dockerContainer.ID) fs, err := os.Create(containerLogPath) if err != nil { glog.Errorf("Error on creating termination-log file %q: %v", containerLogPath, err) } defer fs.Close() b := fmt.Sprintf("%s:%s", containerLogPath, container.TerminationMessagePath) binds = append(binds, b) } } privileged := false if capabilities.Get().AllowPrivileged { privileged = container.Privileged } else if container.Privileged { return "", fmt.Errorf("container requested privileged mode, but it is disallowed globally.") } hc := &docker.HostConfig{ PortBindings: portBindings, Binds: binds, NetworkMode: netMode, Privileged: privileged, } if pod.Spec.DNSPolicy == api.DNSClusterFirst { if err := kl.applyClusterDNS(hc, pod); err != nil { return "", err } } err = kl.dockerClient.StartContainer(dockerContainer.ID, hc) if err != nil { if ref != nil { record.Eventf(ref, "failed", "failed", "Failed to start with docker id %v with error: %v", dockerContainer.ID, err) } return "", err } if ref != nil { record.Eventf(ref, "running", "started", "Started with docker id %v", dockerContainer.ID) } if container.Lifecycle != nil && container.Lifecycle.PostStart != nil { handlerErr := kl.runHandler(GetPodFullName(pod), pod.UID, container, container.Lifecycle.PostStart) if handlerErr != nil { kl.killContainerByID(dockerContainer.ID, "") return dockertools.DockerID(""), fmt.Errorf("failed to call event handler: %v", handlerErr) } } return dockertools.DockerID(dockerContainer.ID), err }
func newUpgradeAwareProxyHandler(location *url.URL, transport http.RoundTripper, upgradeRequired bool) *genericrest.UpgradeAwareProxyHandler { handler := genericrest.NewUpgradeAwareProxyHandler(location, transport, upgradeRequired) handler.MaxBytesPerSec = capabilities.Get().PerConnectionBandwidthLimitBytesPerSec return handler }
func (dm *DockerManager) runContainer(pod *api.Pod, container *api.Container, opts *kubecontainer.RunContainerOptions, ref *api.ObjectReference) (string, error) { dockerName := KubeletContainerName{ PodFullName: kubecontainer.GetPodFullName(pod), PodUID: pod.UID, ContainerName: container.Name, } exposedPorts, portBindings := makePortsAndBindings(container) // TODO(vmarmol): Handle better. // Cap hostname at 63 chars (specification is 64bytes which is 63 chars and the null terminating char). const hostnameMaxLen = 63 containerHostname := pod.Name if len(containerHostname) > hostnameMaxLen { containerHostname = containerHostname[:hostnameMaxLen] } dockerOpts := docker.CreateContainerOptions{ Name: BuildDockerName(dockerName, container), Config: &docker.Config{ Env: opts.Envs, ExposedPorts: exposedPorts, Hostname: containerHostname, Image: container.Image, Memory: container.Resources.Limits.Memory().Value(), CPUShares: milliCPUToShares(container.Resources.Limits.Cpu().MilliValue()), WorkingDir: container.WorkingDir, }, } setEntrypointAndCommand(container, &dockerOpts) glog.V(3).Infof("Container %v/%v/%v: setting entrypoint \"%v\" and command \"%v\"", pod.Namespace, pod.Name, container.Name, dockerOpts.Config.Entrypoint, dockerOpts.Config.Cmd) dockerContainer, err := dm.client.CreateContainer(dockerOpts) if err != nil { if ref != nil { dm.recorder.Eventf(ref, "failed", "Failed to create docker container with error: %v", err) } return "", err } if ref != nil { dm.recorder.Eventf(ref, "created", "Created with docker id %v", dockerContainer.ID) } // The reason we create and mount the log file in here (not in kubelet) is because // the file's location depends on the ID of the container, and we need to create and // mount the file before actually starting the container. // TODO(yifan): Consider to pull this logic out since we might need to reuse it in // other container runtime. if opts.PodContainerDir != "" && len(container.TerminationMessagePath) != 0 { containerLogPath := path.Join(opts.PodContainerDir, dockerContainer.ID) fs, err := os.Create(containerLogPath) if err != nil { // TODO: Clean up the previouly created dir? return the error? glog.Errorf("Error on creating termination-log file %q: %v", containerLogPath, err) } else { fs.Close() // Close immediately; we're just doing a `touch` here b := fmt.Sprintf("%s:%s", containerLogPath, container.TerminationMessagePath) opts.Binds = append(opts.Binds, b) } } privileged := false if capabilities.Get().AllowPrivileged { privileged = container.Privileged } else if container.Privileged { return "", fmt.Errorf("container requested privileged mode, but it is disallowed globally.") } capAdd, capDrop := makeCapabilites(container.Capabilities.Add, container.Capabilities.Drop) hc := &docker.HostConfig{ PortBindings: portBindings, Binds: opts.Binds, NetworkMode: opts.NetMode, IpcMode: opts.IpcMode, Privileged: privileged, CapAdd: capAdd, CapDrop: capDrop, } if len(opts.DNS) > 0 { hc.DNS = opts.DNS } if len(opts.DNSSearch) > 0 { hc.DNSSearch = opts.DNSSearch } if err = dm.client.StartContainer(dockerContainer.ID, hc); err != nil { if ref != nil { dm.recorder.Eventf(ref, "failed", "Failed to start with docker id %v with error: %v", dockerContainer.ID, err) } return "", err } if ref != nil { dm.recorder.Eventf(ref, "started", "Started with docker id %v", dockerContainer.ID) } return dockerContainer.ID, nil }