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

Conversation

@Random-Liu
Copy link
Member

Add port forward support. The implementation is the same with the dockershim.

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

@Random-Liu Random-Liu force-pushed the add-port-forward branch 2 times, most recently from b0db171 to ae91a27 Compare August 14, 2017 02:55

func (s *streamRuntime) PortForward(podSandboxID string, port int32, stream io.ReadWriteCloser) error {
return errors.New("not implemented")
if port < 0 || port > math.MaxUint16 {
Copy link
Member

Choose a reason for hiding this comment

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

port <= 0 ?

Copy link
Member Author

Choose a reason for hiding this comment

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

The orignal code in kubelet is using port < 0. However, you are right, we should check ==0 as well. Will update.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
)

// PortForward prepares a streaming endpoint to forward ports from a PodSandbox, and returns the address.
Copy link
Member

@mikebrow mikebrow Aug 15, 2017

Choose a reason for hiding this comment

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

Comment does not follow what is happening in the api. Currently it's validating that the sandbox is running then returns the serving URL for specified streaming port.

Copy link
Member Author

Choose a reason for hiding this comment

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

The comment is the same with dockershim https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/dockershim/docker_streaming.go#L115.
And I think it explains what the function is doing. :)

Copy link
Member

Choose a reason for hiding this comment

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

ok I'm confused .. where does the api "prepare a streaming endpoint to forward ports from a PodSandbox" all I see is ensuring the running state for the sandbox and calling GetPortForward which I presume just does a get?

Copy link
Member Author

Choose a reason for hiding this comment

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

GetPortForward prepares the streaming endpoint and returns the URL.

Copy link
Member

Choose a reason for hiding this comment

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

kk thx!

}

// portForward requires `nsenter` and `socat` on the node.
func (c *criContainerdService) portForward(id string, port int32, stream io.ReadWriteCloser) error {
Copy link
Member

Choose a reason for hiding this comment

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

should this api be here or over in streaming.go

Copy link
Member Author

Choose a reason for hiding this comment

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

I put attach, portForward and exec in corresponding source file.

Copy link
Member

Choose a reason for hiding this comment

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

Don't understand the answer. There is a PortForward api in streaming.go that calls portForward. The PortForward api in sandbox_portforward.go does not call portForward. Thus my question.

return nil, errors.New("sandbox container is not running")
}
// TODO(random-liu): Verify that ports are exposed.
return c.streamServer.GetPortForward(r)
Copy link
Member

Choose a reason for hiding this comment

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

Curious.. why all the above validation on the running status? Are there expected errors if the sandbox isn't running?

Copy link
Member Author

Choose a reason for hiding this comment

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

Portforward nsenters a the pause container namespace, and running a socat server to do portforwarding.

I believe this requires the pause container is running, because we use the pid to find it's namespace.

We could probably use permanent network namespace to prevent this in the future.

Copy link
Member

Choose a reason for hiding this comment

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

Does the GetPortForward api require we make sure this is the case, or will it return an appropriate error if we have not. IOW are we double checking what the API is going to check anyway?

Copy link
Member Author

@Random-Liu Random-Liu Aug 16, 2017

Choose a reason for hiding this comment

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

streamServer doesn't even know CRI, it can't check container status.

Copy link
Member

Choose a reason for hiding this comment

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

not what I meant but ok..

I presumed you wanted to ensure there is a pid and associated namespace before calling.. and also presumed that the streamServer would also check and return an error message if not vs using a static table of some sort. But I'm not looking at it's code so..

Copy link
Member

Choose a reason for hiding this comment

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

I see.. one of "those" apis :-) should probably be called Reserve instead of Get.. now it makes sense.

Copy link
Member

Choose a reason for hiding this comment

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

Just for my understanding :
Even if the task is paused/stopped the namespace is still available to nsenter right?
How is this supposed to work with windows in the future.

Copy link
Member Author

@Random-Liu Random-Liu Aug 16, 2017

Choose a reason for hiding this comment

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

Even if the task is paused/stopped the namespace is still available to nsenter right?

Offline talked with @yujuhong. Yeah, we only need network namespace here. I had a concern that we run a pod specific process but only in its network namespace, it means that the process could access other host namespaces. However, socat is on the node, the cluster admin should make sure it's friendly. :)

Actually, there are other issues with the current solution - the socat is not in pod cgroup, so the resource usage will be charged to the system.

How is this supposed to work with windows in the future.

@abhinandanpb Good question. Currently, Kubelet only has limited windows support. Many critical kubelet features doesn't have corresponding windows support, e.g. pod level cgroup, cadvisor monitoring etc. There is an ongoing effort to make kubelet work better on windows.

Actually, we should be able to run a port forward container inside the pod sandbox to do port forward, which makes more sense because:

  1. The resource overhead will be charged to the pod;
  2. If containerd container exec support different platforms, this solution could be platform agnostic.

I'll add a TODO here, we could do this in near future. :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

Copy link
Member

Choose a reason for hiding this comment

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

got it. Thanks for explaining.

return c.streamServer.GetPortForward(r)
}

// portForward requires `nsenter` and `socat` on the node.
Copy link
Member

Choose a reason for hiding this comment

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

maybe some explanation about what the api does.

Copy link
Member Author

Choose a reason for hiding this comment

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

Will do.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

return fmt.Errorf("unable to find socat: %v", err)
}

args := []string{"-t", fmt.Sprintf("%d", pid), "-n", socat,
Copy link
Member

@mikebrow mikebrow Aug 15, 2017

Choose a reason for hiding this comment

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

maybe a comment or pointer about the options being used.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea. Will do.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

if err := cmd.Run(); err != nil {
return fmt.Errorf("nsenter command returns error: %v, stderr: %q", err, stderr.String())
}

Copy link
Member

@mikebrow mikebrow Aug 15, 2017

Choose a reason for hiding this comment

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

should we use a channel to wait on the go func io.Copy err? Maybe pipe the err in the go func after the in.Close() call and wait on the channel before the final return..?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we want the goroutine to keep serving even after the function returns, until the client disconnects.

Copy link
Member

Choose a reason for hiding this comment

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

kk didn't know that was a long running task. Maybe a comment about that..

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll add some comment to describe what port forward is doing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, you are correct, we should wait on the go func. Will update.

Copy link
Member Author

Choose a reason for hiding this comment

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

The implementation is the same with https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/dockershim/docker_streaming.go#L162. And based on the original comment and code analysis, the code should be safe.

I added more logs so that if in the future there are any problem, we could figure it out.

Copy link
Member

Choose a reason for hiding this comment

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

Logging works if we have the right test buckets... hate leaving what might be a dangling pipe thread but at least we'll have an unbalanced lvl 4 log to identify it if it happens.

Copy link
Member Author

@Random-Liu Random-Liu Aug 16, 2017

Choose a reason for hiding this comment

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

@mikebrow Run already contains a Wait, and the wait makes sure that the stream will be closed. And there is no context passed in by streaming server, so there is no cancellation, either.

If we don't use Run and a context is passed in, I'd prefer adding a channel and do select. :)

Copy link
Member

Choose a reason for hiding this comment

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

Makes sense.

Copy link
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.

@Random-Liu
Copy link
Member Author

@mikebrow Addressed comments.

Copy link
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

}
id := sandbox.ID

info, err := c.taskService.Get(ctx, &tasks.GetTaskRequest{ContainerID: id})
Copy link
Member

Choose a reason for hiding this comment

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

Can you please add a TODO to replace this with client API

Copy link
Member

Choose a reason for hiding this comment

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

or TODO to use permanent network namespace ( discussed below)

Copy link
Member Author

Choose a reason for hiding this comment

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

Will do.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

@abhi
Copy link
Member

abhi commented Aug 16, 2017

Minor comments, LGTM

@Random-Liu
Copy link
Member Author

Random-Liu commented Aug 16, 2017

@abhinandanpb Addressed comments. Thanks for reviewing!

Signed-off-by: Lantao Liu <[email protected]>
@Random-Liu
Copy link
Member Author

Just updated this PR to use the containerd client.

@Random-Liu Random-Liu merged commit 860dac2 into containerd:master Aug 17, 2017
@Random-Liu Random-Liu deleted the add-port-forward branch August 17, 2017 00:47
@Random-Liu Random-Liu mentioned this pull request Aug 17, 2017
42 tasks
lanchongyizu pushed a commit to lanchongyizu/cri-containerd that referenced this pull request Sep 3, 2017
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