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

kubelet: add a generic pod lifecycle event generator #13571

Merged
merged 3 commits into from
Nov 16, 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
2 changes: 1 addition & 1 deletion cmd/kubelet/app/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func NewKubeletServer() *KubeletServer {
RootDirectory: defaultRootDir,
SerializeImagePulls: true,
StreamingConnectionIdleTimeout: 5 * time.Minute,
SyncFrequency: 10 * time.Second,
SyncFrequency: 1 * time.Minute,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a pretty big change that is not strictly related to the point of this PR... am I missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The primary focus of this PR is to reduce redundant syncs (10 second periodic syncs) when there is no change. The added PLEG already checks the container runtime frequently for any container changes. We keep the periodic sync as a fallback, in case anything is missed, but it should be less frequent.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yujuhong cool, that makes sense to me -- this seems like the kind of thing that could affect some of the E2Es that are outside the merge path -- have you run any of those?

SystemContainer: "",
ReconcileCIDR: true,
KubeAPIQPS: 5.0,
Expand Down
4 changes: 2 additions & 2 deletions docs/admin/kubelet.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,13 @@ kubelet
--runonce[=false]: If true, exit after spawning pods from local manifests or remote urls. Exclusive with --api-servers, and --enable-server
--serialize-image-pulls[=true]: Pull images one at a time. We recommend *not* changing the default value on nodes that run docker daemon with version < 1.9 or an Aufs storage backend. Issue #10959 has more details. [default=true]
--streaming-connection-idle-timeout=5m0s: Maximum time a streaming connection can be idle before the connection is automatically closed. Example: '5m'
--sync-frequency=10s: Max period between synchronizing running containers and config
--sync-frequency=1m0s: Max period between synchronizing running containers and config
--system-container="": Optional resource-only container in which to place all non-kernel processes that are not already in a container. Empty for no container. Rolling back the flag requires a reboot. (Default: "").
--tls-cert-file="": File containing x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert). If --tls-cert-file and --tls-private-key-file are not provided, a self-signed certificate and key are generated for the public address and saved to the directory passed to --cert-dir.
--tls-private-key-file="": File containing x509 private key matching --tls-cert-file.
```

###### Auto generated by spf13/cobra on 10-Nov-2015
###### Auto generated by spf13/cobra on 11-Nov-2015


<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
Expand Down
5 changes: 5 additions & 0 deletions pkg/kubelet/container/fake_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type FakeRuntime struct {
sync.Mutex
CalledFunctions []string
PodList []*Pod
AllPodList []*Pod
ImageList []Image
PodStatus api.PodStatus
StartedPods []string
Expand Down Expand Up @@ -89,6 +90,7 @@ func (f *FakeRuntime) ClearCalls() {

f.CalledFunctions = []string{}
f.PodList = []*Pod{}
f.AllPodList = []*Pod{}
f.PodStatus = api.PodStatus{}
f.StartedPods = []string{}
f.KilledPods = []string{}
Expand Down Expand Up @@ -155,6 +157,9 @@ func (f *FakeRuntime) GetPods(all bool) ([]*Pod, error) {
defer f.Unlock()

f.CalledFunctions = append(f.CalledFunctions, "GetPods")
if all {
return f.AllPodList, f.Err
}
return f.PodList, f.Err
}

Expand Down
11 changes: 11 additions & 0 deletions pkg/kubelet/container/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,15 @@ func (c *ContainerID) UnmarshalJSON(data []byte) error {
return c.ParseString(string(data))
}

type ContainerStatus string

const (
ContainerStatusRunning ContainerStatus = "running"
ContainerStatusExited ContainerStatus = "exited"
// This unknown encompasses all the statuses that we currently don't care.
ContainerStatusUnknown ContainerStatus = "unknown"
)

// Container provides the runtime information for a container, such as ID, hash,
// status of the container.
type Container struct {
Expand All @@ -215,6 +224,8 @@ type Container struct {
// The timestamp of the creation time of the container.
// TODO(yifan): Consider to move it to api.ContainerStatus.
Created int64
// Status is the status of the container.
Status ContainerStatus
}

// Basic information about a container image.
Expand Down
16 changes: 16 additions & 0 deletions pkg/kubelet/dockertools/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package dockertools

import (
"fmt"
"strings"

docker "github.com/fsouza/go-dockerclient"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
Expand All @@ -27,6 +28,19 @@ import (
// This file contains helper functions to convert docker API types to runtime
// (kubecontainer) types.

func mapStatus(status string) kubecontainer.ContainerStatus {
// Parse the status string in docker.APIContainers. This could break when
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you think this would break?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might break because we are parsing a human readable string. On the other hand, it should be easy to verify when upgrading docker.

// we upgrade docker.
switch {
case strings.HasPrefix(status, "Up"):
return kubecontainer.ContainerStatusRunning
case strings.HasPrefix(status, "Exited"):
return kubecontainer.ContainerStatusExited
default:
return kubecontainer.ContainerStatusUnknown
}
}

// Converts docker.APIContainers to kubecontainer.Container.
func toRuntimeContainer(c *docker.APIContainers) (*kubecontainer.Container, error) {
if c == nil {
Expand All @@ -37,12 +51,14 @@ func toRuntimeContainer(c *docker.APIContainers) (*kubecontainer.Container, erro
if err != nil {
return nil, err
}

return &kubecontainer.Container{
ID: kubetypes.DockerID(c.ID).ContainerID(),
Name: dockerName.ContainerName,
Image: c.Image,
Hash: hash,
Created: c.Created,
Status: mapStatus(c.Status),
}, nil
}

Expand Down
20 changes: 20 additions & 0 deletions pkg/kubelet/dockertools/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,39 @@ import (
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
)

func TestMapStatus(t *testing.T) {
testCases := []struct {
input string
expected kubecontainer.ContainerStatus
}{
{input: "Up 5 hours", expected: kubecontainer.ContainerStatusRunning},
{input: "Exited (0) 2 hours ago", expected: kubecontainer.ContainerStatusExited},
{input: "Created", expected: kubecontainer.ContainerStatusUnknown},
{input: "Random string", expected: kubecontainer.ContainerStatusUnknown},
}

for i, test := range testCases {
if actual := mapStatus(test.input); actual != test.expected {
t.Errorf("Test[%d]: expected %q, got %q", i, test.expected, actual)
}
}
}

func TestToRuntimeContainer(t *testing.T) {
original := &docker.APIContainers{
ID: "ab2cdf",
Image: "bar_image",
Created: 12345,
Names: []string{"/k8s_bar.5678_foo_ns_1234_42"},
Status: "Up 5 hours",
}
expected := &kubecontainer.Container{
ID: kubecontainer.ContainerID{"docker", "ab2cdf"},
Name: "bar",
Image: "bar_image",
Hash: 0x5678,
Created: 12345,
Status: kubecontainer.ContainerStatusRunning,
}

actual, err := toRuntimeContainer(original)
Expand Down
56 changes: 32 additions & 24 deletions pkg/kubelet/dockertools/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,14 +580,16 @@ func TestFindContainersByPod(t *testing.T) {
Namespace: "ns",
Containers: []*kubecontainer.Container{
{
ID: kubetypes.DockerID("foobar").ContainerID(),
Name: "foobar",
Hash: 0x1234,
ID: kubetypes.DockerID("foobar").ContainerID(),
Name: "foobar",
Hash: 0x1234,
Status: kubecontainer.ContainerStatusUnknown,
},
{
ID: kubetypes.DockerID("baz").ContainerID(),
Name: "baz",
Hash: 0x1234,
ID: kubetypes.DockerID("baz").ContainerID(),
Name: "baz",
Hash: 0x1234,
Status: kubecontainer.ContainerStatusUnknown,
},
},
},
Expand All @@ -597,9 +599,10 @@ func TestFindContainersByPod(t *testing.T) {
Namespace: "ns",
Containers: []*kubecontainer.Container{
{
ID: kubetypes.DockerID("barbar").ContainerID(),
Name: "barbar",
Hash: 0x1234,
ID: kubetypes.DockerID("barbar").ContainerID(),
Name: "barbar",
Hash: 0x1234,
Status: kubecontainer.ContainerStatusUnknown,
},
},
},
Expand Down Expand Up @@ -638,19 +641,22 @@ func TestFindContainersByPod(t *testing.T) {
Namespace: "ns",
Containers: []*kubecontainer.Container{
{
ID: kubetypes.DockerID("foobar").ContainerID(),
Name: "foobar",
Hash: 0x1234,
ID: kubetypes.DockerID("foobar").ContainerID(),
Name: "foobar",
Hash: 0x1234,
Status: kubecontainer.ContainerStatusUnknown,
},
{
ID: kubetypes.DockerID("barfoo").ContainerID(),
Name: "barfoo",
Hash: 0x1234,
ID: kubetypes.DockerID("barfoo").ContainerID(),
Name: "barfoo",
Hash: 0x1234,
Status: kubecontainer.ContainerStatusUnknown,
},
{
ID: kubetypes.DockerID("baz").ContainerID(),
Name: "baz",
Hash: 0x1234,
ID: kubetypes.DockerID("baz").ContainerID(),
Name: "baz",
Hash: 0x1234,
Status: kubecontainer.ContainerStatusUnknown,
},
},
},
Expand All @@ -660,9 +666,10 @@ func TestFindContainersByPod(t *testing.T) {
Namespace: "ns",
Containers: []*kubecontainer.Container{
{
ID: kubetypes.DockerID("barbar").ContainerID(),
Name: "barbar",
Hash: 0x1234,
ID: kubetypes.DockerID("barbar").ContainerID(),
Name: "barbar",
Hash: 0x1234,
Status: kubecontainer.ContainerStatusUnknown,
},
},
},
Expand All @@ -672,9 +679,10 @@ func TestFindContainersByPod(t *testing.T) {
Namespace: "ns",
Containers: []*kubecontainer.Container{
{
ID: kubetypes.DockerID("bazbaz").ContainerID(),
Name: "bazbaz",
Hash: 0x1234,
ID: kubetypes.DockerID("bazbaz").ContainerID(),
Name: "bazbaz",
Hash: 0x1234,
Status: kubecontainer.ContainerStatusUnknown,
},
},
},
Expand Down
24 changes: 12 additions & 12 deletions pkg/kubelet/image_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func TestDetectImagesInitialDetect(t *testing.T) {
makeImage(0, 1024),
makeImage(1, 2048),
}
fakeRuntime.PodList = []*container.Pod{
fakeRuntime.AllPodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(1),
Expand Down Expand Up @@ -114,7 +114,7 @@ func TestDetectImagesWithNewImage(t *testing.T) {
makeImage(0, 1024),
makeImage(1, 2048),
}
fakeRuntime.PodList = []*container.Pod{
fakeRuntime.AllPodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(1),
Expand Down Expand Up @@ -159,7 +159,7 @@ func TestDetectImagesContainerStopped(t *testing.T) {
makeImage(0, 1024),
makeImage(1, 2048),
}
fakeRuntime.PodList = []*container.Pod{
fakeRuntime.AllPodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(1),
Expand All @@ -175,7 +175,7 @@ func TestDetectImagesContainerStopped(t *testing.T) {
require.True(t, ok)

// Simulate container being stopped.
fakeRuntime.PodList = []*container.Pod{}
fakeRuntime.AllPodList = []*container.Pod{}
err = manager.detectImages(time.Now())
require.NoError(t, err)
assert.Equal(manager.imageRecordsLen(), 2)
Expand All @@ -195,7 +195,7 @@ func TestDetectImagesWithRemovedImages(t *testing.T) {
makeImage(0, 1024),
makeImage(1, 2048),
}
fakeRuntime.PodList = []*container.Pod{
fakeRuntime.AllPodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(1),
Expand All @@ -221,7 +221,7 @@ func TestFreeSpaceImagesInUseContainersAreIgnored(t *testing.T) {
makeImage(0, 1024),
makeImage(1, 2048),
}
fakeRuntime.PodList = []*container.Pod{
fakeRuntime.AllPodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(1),
Expand All @@ -242,7 +242,7 @@ func TestFreeSpaceRemoveByLeastRecentlyUsed(t *testing.T) {
makeImage(0, 1024),
makeImage(1, 2048),
}
fakeRuntime.PodList = []*container.Pod{
fakeRuntime.AllPodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(0),
Expand All @@ -253,15 +253,15 @@ func TestFreeSpaceRemoveByLeastRecentlyUsed(t *testing.T) {

// Make 1 be more recently used than 0.
require.NoError(t, manager.detectImages(zero))
fakeRuntime.PodList = []*container.Pod{
fakeRuntime.AllPodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(1),
},
},
}
require.NoError(t, manager.detectImages(time.Now()))
fakeRuntime.PodList = []*container.Pod{
fakeRuntime.AllPodList = []*container.Pod{
{
Containers: []*container.Container{},
},
Expand All @@ -281,7 +281,7 @@ func TestFreeSpaceTiesBrokenByDetectedTime(t *testing.T) {
fakeRuntime.ImageList = []container.Image{
makeImage(0, 1024),
}
fakeRuntime.PodList = []*container.Pod{
fakeRuntime.AllPodList = []*container.Pod{
{
Containers: []*container.Container{
makeContainer(0),
Expand All @@ -296,7 +296,7 @@ func TestFreeSpaceTiesBrokenByDetectedTime(t *testing.T) {
makeImage(1, 2048),
}
require.NoError(t, manager.detectImages(time.Now()))
fakeRuntime.PodList = []*container.Pod{}
fakeRuntime.AllPodList = []*container.Pod{}
require.NoError(t, manager.detectImages(time.Now()))
require.Equal(t, manager.imageRecordsLen(), 2)

Expand All @@ -317,7 +317,7 @@ func TestFreeSpaceImagesAlsoDoesLookupByRepoTags(t *testing.T) {
Size: 2048,
},
}
fakeRuntime.PodList = []*container.Pod{
fakeRuntime.AllPodList = []*container.Pod{
{
Containers: []*container.Container{
{
Expand Down