Skip to content
This repository was archived by the owner on Mar 9, 2022. It is now read-only.

Avoid containerd access as much as possible.#571

Merged
Random-Liu merged 1 commit intocontainerd:masterfrom
Random-Liu:do-not-list-task
Jan 26, 2018
Merged

Avoid containerd access as much as possible.#571
Random-Liu merged 1 commit intocontainerd:masterfrom
Random-Liu:do-not-list-task

Conversation

@Random-Liu
Copy link
Copy Markdown
Member

@Random-Liu Random-Liu commented Jan 25, 2018

Related to containerd/containerd#2020.

This PR:

  1. Cache sandbox status in sandbox store.
  2. Update sandbox status based on containerd event.
  3. Recover sandbox cache during restart.

This should reduce the containerd/containerd-shim cpu/memory usage.

Signed-off-by: Lantao Liu [email protected]

@miaoyq
Copy link
Copy Markdown
Member

miaoyq commented Jan 25, 2018

golint failed.

I0125 01:26:35.928] pkg/store/sandbox/status.go:33:2:warning: don't use underscores in Go names; const PodSandboxState_UNKNOWN should be PodSandboxStateUNKNOWN (golint)
I0125 01:26:35.929] pkg/store/sandbox/status.go:36:2:warning: don't use underscores in Go names; const PodSandboxState_READY should be PodSandboxStateREADY (golint)
I0125 01:26:35.930] pkg/store/sandbox/status.go:42:2:warning: don't use underscores in Go names; const PodSandboxState_NOTREADY should be PodSandboxStateNOTREADY (golint)

@Random-Liu
Copy link
Copy Markdown
Member Author

@miaoyq Fixing it. :)

@Random-Liu Random-Liu force-pushed the do-not-list-task branch 3 times, most recently from 5121ea6 to 099c13d Compare January 25, 2018 02:09
// NetNSPath is the network namespace used by the sandbox.
NetNSPath string
// IP of Pod if it is attached to non host network
IP string
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@abhi This moves IP from Sandbox into Metadata. This doesn't make any logical difference, just a minor cleanup.

defer timeoutTimer.Stop()
for {
// Poll once before waiting for stopCheckPollInterval.
// TODO(random-liu): Use channel with event handler instead of polling.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@miaoyq We should also change this to channel.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

OK, will change this after this pr merged.

pid uint32, processStatus containerd.ProcessStatus, verbose bool) (map[string]string, error) {
if !verbose {
return nil, nil
func toCRISandboxInfo(ctx context.Context, sandbox sandboxstore.Sandbox) (map[string]string, error) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@mikebrow I change this function to return error instead of logging. We are going to merge cri-containerd and containerd, this won't be a problem then.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ok

@Random-Liu
Copy link
Copy Markdown
Member Author

@mikebrow @yanxuean @miaoyq PR ready for review.

return nil, fmt.Errorf("failed to list sandbox containers: %v", err)
}

var sandboxes []*runtime.PodSandbox
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

make slice with len?

Copy link
Copy Markdown
Member Author

@Random-Liu Random-Liu Jan 25, 2018

Choose a reason for hiding this comment

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

Let's do this kind of optimization when we see this is a bottleneck. :)

I don't think it will make too much difference.

func (s *Store) Get(id string) (Sandbox, error) {
sb, err := s.GetAll(id)
if err != nil {
return sb, err
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sandbox{},err

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's fine here. I think. :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

it's fine..

Comment thread pkg/server/events.go
@@ -106,53 +107,20 @@ func (em *eventMonitor) handleEvent(evt *events.Envelope) {
e := any.(*eventtypes.TaskExit)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we not handle sandbox with TaskOOM?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah, we don't need to do that. Even we handle, what can we do? :)

Comment thread pkg/server/sandbox_run.go Outdated
defer func() {
if retErr != nil {
// Cleanup the sandbox container if an error is returned.
if _, err := task.Delete(ctx, containerd.WithProcessKill); err != nil {
Copy link
Copy Markdown
Member

@yanxuean yanxuean Jan 25, 2018

Choose a reason for hiding this comment

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

Now we also do task.Delete with unknown state in event.handleSandboxExit, so we should check that if the err is NotFound. The NotFound is a normal case.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Changed both sandbox_run.go and container_start.go to check IsNotFound. Good catch!

Comment thread pkg/server/events.go
func handleSandboxExit(e *eventtypes.TaskExit, sb sandboxstore.Sandbox) {
// Don't need to check pid because sandbox container should only have one process.
// No stream attached to sandbox container.
task, err := sb.Container.Task(context.Background(), nil)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should not do this on unknown state. Let RunPodSandbox do it.
Or else we maybe do task.Delete both in handleSandboxExit and RunPodSandbox.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

On a second thought, I still prefer put task.Delete out of `Update.

Update will hold a lock of the container/sandbox, and List (which is a critical operation for kubelet) will be blocked until the lock is released.

We should put as little logic as possible into Update. The issue you mentioned can be handled by #571 (comment).

}

pid = task.Pid()
processStatus = taskStatus.Status
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we also store the pid and processStatus to sandboxstore?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

processState keeps changing, it's hard to maintain it in our store. I'd prefer not to do that until we have to.

I'll do pid.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done

@Random-Liu
Copy link
Copy Markdown
Member Author

Test failure seems like a GCE flake.

/test pull-cri-containerd-node-e2e

Copy link
Copy Markdown
Member

@mikebrow mikebrow left a comment

Choose a reason for hiding this comment

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

See comments & questions.

return false, err
}
return status.GetState() == runtime.PodSandboxState_SANDBOX_NOTREADY, nil
}, time.Second, 30*time.Second), "sandbox state should become NOTREADY")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

todo for configuring timeout for becoming ready.. possibly receive direction over cri api

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think fixed 30 second for test is fine. This should happen very soon.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's fine to, but people not wanting to wait for a new pod might not like it..

Copy link
Copy Markdown
Member Author

@Random-Liu Random-Liu Jan 25, 2018

Choose a reason for hiding this comment

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

Hm, what do you mean?

Here, we kill the corresponding task from containerd, and wait for the pod sandbox status to be updated NOTREADY by cri-containerd. It usually only takes several microseconds I guess?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

NVM I was distracted. Ignore :-)

// List all sandboxes from store.
sandboxesInStore := c.sandboxStore.List()

response, err := c.client.TaskService().List(ctx, &tasks.ListTasksRequest{})
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

whoot!!!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Consider adding a todo for running a validate routine to make sure we have stayed in sync and didn't just miss an event.. I like this pattern of working off the push of events, but without some periodic validation there is a risk of an event failing to reach us, low but risk nonetheless? Or are all the events returning successful delivery to containerd?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good point. Will add a TODO for that.

We sometimes see Docker stay in weird state because it missed an event and not in sync with containerd.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done.

pid uint32, processStatus containerd.ProcessStatus, verbose bool) (map[string]string, error) {
if !verbose {
return nil, nil
func toCRISandboxInfo(ctx context.Context, sandbox sandboxstore.Sandbox) (map[string]string, error) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ok

info, err := toCRISandboxInfo(ctx, sandbox, pid, processStatus, r.GetVerbose())

// Generate verbose information.
info, err := toCRISandboxInfo(ctx, sandbox)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

if r.GetVerbose() there is no need to get info here..

Copy link
Copy Markdown
Member Author

@Random-Liu Random-Liu Jan 25, 2018

Choose a reason for hiding this comment

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

If !r.GetVerbose() it will return directly above.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

oh there it is :-)


// stopCheckPollInterval is the the interval to check whether a sandbox
// is stopped successfully.
const stopCheckPollInterval = 100 * time.Millisecond
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

todo make configurable

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We'll remove this very soon by adding a stop channel. @yanxuean @miaoyq are going to do that.
See #570


if err := c.stopSandboxContainer(ctx, sandbox.Container); err != nil {
return nil, fmt.Errorf("failed to stop sandbox container %q: %v", id, err)
// Only stop sandbox container when it's running.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

is no error the the expected CRI behavior if it's not running, seems like we should tell them they can't stop a non running podsandbox ...
At least log a warning?

Copy link
Copy Markdown
Member Author

@Random-Liu Random-Liu Jan 25, 2018

Choose a reason for hiding this comment

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

Actually we expect StopPodSandbox to be idempotent. Caller should be able to call this many times.

And kubelet does call this function multiple times for one pod sandbox.

See https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/apis/cri/v1alpha1/runtime/api.proto#L28.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ok. just checking, odd behavior IMO Maybe they call stop multiple times cause no one threw an already stopped error that they could easily ignore if they wanted to treat it as idempotent for their use case.

func (s *Store) Get(id string) (Sandbox, error) {
sb, err := s.GetAll(id)
if err != nil {
return sb, err
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

it's fine..

@Random-Liu
Copy link
Copy Markdown
Member Author

/test pull-cri-containerd-node-e2e

Copy link
Copy Markdown
Member

@mikebrow mikebrow left a comment

Choose a reason for hiding this comment

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

/LGTM


if err := c.stopSandboxContainer(ctx, sandbox.Container); err != nil {
return nil, fmt.Errorf("failed to stop sandbox container %q: %v", id, err)
// Only stop sandbox container when it's running.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ok. just checking, odd behavior IMO Maybe they call stop multiple times cause no one threw an already stopped error that they could easily ignore if they wanted to treat it as idempotent for their use case.

return false, err
}
return status.GetState() == runtime.PodSandboxState_SANDBOX_NOTREADY, nil
}, time.Second, 30*time.Second), "sandbox state should become NOTREADY")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

NVM I was distracted. Ignore :-)

Comment thread pkg/server/events.go
// eventMonitor monitors containerd event and updates internal state correspondingly.
// TODO(random-liu): [P1] Is it possible to drop event during containerd is running?
// TODO(random-liu): [P1] Figure out is it possible to drop event during containerd
// is running. If it is, we should do periodically list to sync state with containerd.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

looks good!

@Random-Liu
Copy link
Copy Markdown
Member Author

Random-Liu commented Jan 25, 2018

Rebased.
@mikebrow Thanks for reviewing!
@miaoyq @yanxuean Are you 2 OK with this PR now? :)

@yanxuean
Copy link
Copy Markdown
Member

/lgtm

@miaoyq
Copy link
Copy Markdown
Member

miaoyq commented Jan 26, 2018

/lgtm

@Random-Liu Random-Liu merged commit f401662 into containerd:master Jan 26, 2018
@Random-Liu Random-Liu deleted the do-not-list-task branch January 26, 2018 00:13
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants