рдЯрд┐рдкреНрдкрдгреАред рдЕрдиреБрд╡рд╛рджред: рд▓реЗрдЦ рдХреЗ рд▓реЗрдЦрдХ - рдПрд╕рдПрдкреА рдХреЗ рдПрдХ рдЗрдВрдЬреАрдирд┐рдпрд░ рдПрд░рдХрди рдПрд░реЛрд▓ - рдЯреАрдо рдХреЗ рдХрд╛рдордХрд╛рдЬ рдХреЗ рддрдВрддреНрд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдкрдиреЗ рдЕрдзреНрдпрдпрди рдХреЛ рд╕рд╛рдЭрд╛ рдХрд░рддреЗ рд╣реИрдВ kubectl exec, рдЬреЛ рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╕рднреА рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдкрд░рд┐рдЪрд┐рдд рд╣реИред рд╡рд╣ рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕ рд╕реНрд░реЛрдд рдХреЛрдб (рдФрд░ рд╕рдВрдмрдВрдзрд┐рдд рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ) рдХреА рд╕реВрдЪреА рдХреЗ рд╕рд╛рде рд╕рдВрдкреВрд░реНрдг рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЗ рд╕рд╛рде рдЖрддрд╛ рд╣реИ, рдЬреЛ рдЖрдкрдХреЛ рд╡рд┐рд╖рдп рдХреЛ рдЖрд╡рд╢реНрдпрдХрддрд╛рдиреБрд╕рд╛рд░ рдЧрд╣рд░рд╛рдИ рд╕реЗ рд╕рдордЭрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред

рдПрдХ рд╢реБрдХреНрд░рд╡рд╛рд░ рдХреЛ, рдПрдХ рд╕рд╣рдХрд░реНрдореА рдореЗрд░реЗ рдкрд╛рд╕ рдЖрдпрд╛ рдФрд░ рдкреВрдЫрд╛ рдХрд┐ рдкреЙрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрдорд╛рдВрдб рдХреЛ рдХреИрд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдП . рдореИрдВ рдЙрд╕рдХрд╛ рдЙрддреНрддрд░ рдирд╣реАрдВ рджреЗ рд╕рдХрд╛ рдФрд░ рдЕрдЪрд╛рдирдХ рдореБрдЭреЗ рдПрд╣рд╕рд╛рд╕ рд╣реБрдЖ рдХрд┐ рдореИрдВ рдСрдкрд░реЗрд╢рди рдХреЗ рддрдВрддреНрд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рдерд╛ kubectl exec. рд╣рд╛рдВ, рдЗрд╕рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдореЗрд░реЗ рдХреБрдЫ рд╡рд┐рдЪрд╛рд░ рдереЗ, рд▓реЗрдХрд┐рди рдореИрдВ рдЙрдирдХреА рд╢реБрджреНрдзрддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ 100% рдЖрд╢реНрд╡рд╕реНрдд рдирд╣реАрдВ рдерд╛ рдФрд░ рдЗрд╕рд▓рд┐рдП рдЗрд╕ рдореБрджреНрджреЗ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред рдмреНрд▓реЙрдЧ, рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдФрд░ рд╕реНрд░реЛрдд рдХреЛрдб рдХрд╛ рдЕрдзреНрдпрдпрди рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдореИрдВрдиреЗ рдмрд╣реБрдд рд╕реА рдирдИ рдЪреАрдЬрд╝реЗрдВ рд╕реАрдЦреАрдВ, рдФрд░ рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЕрдкрдиреА рдЦреЛрдЬреЛрдВ рдФрд░ рд╕рдордЭ рдХреЛ рд╕рд╛рдЭрд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред рдпрджрд┐ рдХреБрдЫ рднреА рдЧрд▓рдд рд╣реЛ рддреЛ рдХреГрдкрдпрд╛ рдореБрдЭрд╕реЗ рд╕рдВрдкрд░реНрдХ рдХрд░реЗрдВ .
рдЯреНрд░реЗрдирд┐рдВрдЧ
рдореИрдХрдмреБрдХ рдкрд░ рдХреНрд▓рд╕реНрдЯрд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдХреНрд▓реЛрди рдХрд┐рдпрд╛ . рдлрд┐рд░ рдореИрдВрдиреЗ рдХреНрдпреВрдмрд▓реЗрдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ рдиреЛрдбреНрд╕ рдХреЗ рдЖрдИрдкреА рдкрддреЗ рдХреЛ рд╕рд╣реА рдХрд┐рдпрд╛, рдХреНрдпреЛрдВрдХрд┐ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдЗрд╕рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддреА рдереАрдВ kubectl exec. рдЗрд╕рдХреЗ рдореБрдЦреНрдп рдХрд╛рд░рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЖрдк рдЕрдзрд┐рдХ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВ .
- рдХреЛрдИ рднреА рдХрд╛рд░ = рдореЗрд░рд╛ рдореИрдХрдмреБрдХ
- рдорд╛рд╕реНрдЯрд░ рдиреЛрдб рдЖрдИрдкреА = 192.168.205.10
- рд╡рд░реНрдХрд░ рдиреЛрдб рдЖрдИрдкреА = 192.168.205.11
- рдПрдкреАрдЖрдИ рд╕рд░реНрд╡рд░ рдкреЛрд░реНрдЯ = 6443
рдЕрд╡рдпрд╡

- Kubectl рдХрд╛рд░реНрдпрдХрд╛рд░реА рдкреНрд░рдХреНрд░рд┐рдпрд╛: рдЬрдм рд╣рдо "kubectl exec..." рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╢реБрд░реВ рд╣реЛ рдЬрд╛рддреА рд╣реИред рдпрд╣ K8s API рд╕рд░реНрд╡рд░ рддрдХ рдкрд╣реБрдВрдЪ рд╡рд╛рд▓реА рдХрд┐рд╕реА рднреА рдорд╢реАрди рдкрд░ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЯрд┐рдкреНрдкрдгреА рдЕрдиреБрд╡рд╛рдж: рдХрдВрд╕реЛрд▓ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдореЗрдВ рдЖрдЧреЗ, рд▓реЗрдЦрдХ "рдХрд┐рд╕реА рднреА рдорд╢реАрди" рдЯрд┐рдкреНрдкрдгреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдмрд╛рдж рдХреЗ рдЖрджреЗрд╢реЛрдВ рдХреЛ рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕ рддрдХ рдкрд╣реБрдВрдЪ рдХреЗ рд╕рд╛рде рдРрд╕реА рдХрд┐рд╕реА рднреА рдорд╢реАрди рдкрд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
- : рдорд╛рд╕реНрдЯрд░ рдиреЛрдб рдкрд░ рдПрдХ рдШрдЯрдХ рдЬреЛ рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕ рдПрдкреАрдЖрдИ рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕ рдореЗрдВ рдирд┐рдпрдВрддреНрд░рдг рд╡рд┐рдорд╛рди рдХрд╛ рдЕрдЧреНрд░рднрд╛рдЧ рд╣реИред
- : рдПрдХ рдПрдЬреЗрдВрдЯ рдЬреЛ рдХреНрд▓рд╕реНрдЯрд░ рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдиреЛрдб рдкрд░ рдЪрд▓рддрд╛ рд╣реИред рдпрд╣ рдкреЙрдб рдореЗрдВ рдХрдВрдЯреЗрдирд░реЛрдВ рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреЛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИред
- (рдХрдВрдЯреЗрдирд░ рд░рдирдЯрд╛рдЗрдо): рдХрдВрдЯреЗрдирд░ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ред рдЙрджрд╛рд╣рд░рдг: рдбреЙрдХрд░, рд╕реАрдЖрд░рдЖрдИ-рдУ, рдХрдВрдЯреЗрдирд░рдбтАж
- рдЧрд┐рд░реА: рд╡рд░реНрдХрд░ рдиреЛрдб рдкрд░ рдУрдПрд╕ рдХрд░реНрдиреЗрд▓; рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкреНрд░рдмрдВрдзрди рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред
- рд▓рдХреНрд╖реНрдп (рд▓рдХреНрд╖реНрдп) рдХрдВрдЯреЗрдирд░: рдПрдХ рдХрдВрдЯреЗрдирд░ рдЬреЛ рдкреЙрдб рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╣реИ рдФрд░ рд╡рд░реНрдХрд░ рдиреЛрдбреНрд╕ рдореЗрдВ рд╕реЗ рдПрдХ рдкрд░ рдЪрд▓рддрд╛ рд╣реИред
рдореИрдВрдиреЗ рдХреНрдпрд╛ рдЦреЛрдЬрд╛
1. рдЧреНрд░рд╛рд╣рдХ рдкрдХреНрд╖ рдЧрддрд┐рд╡рд┐рдзрд┐
рдиреЗрдорд╕реНрдкреЗрд╕ рдореЗрдВ рдПрдХ рдкреЙрдб рдмрдирд╛рдПрдВ default:
// any machine
$ kubectl run exec-test-nginx --image=nginxрдлрд┐рд░ рд╣рдо рдирд┐рд╖реНрдкрд╛рджрди рдХрдорд╛рдВрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЖрдЧреЗ рдХреЗ рдЕрд╡рд▓реЛрдХрди рдХреЗ рд▓рд┐рдП 5000 рд╕реЗрдХрдВрдб рддрдХ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддреЗ рд╣реИрдВ:
// any machine
$ kubectl exec -it exec-test-nginx-6558988d5-fgxgg -- sh
# sleep 5000Kubectl рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкреНрд░рдХрдЯ рд╣реЛрддреА рд╣реИ (рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ pid=8507 рдХреЗ рд╕рд╛рде):
// any machine
$ ps -ef |grep kubectl
501 8507 8409 0 7:19PM ttys000 0:00.13 kubectl exec -it exec-test-nginx-6558988d5-fgxgg -- shрдпрджрд┐ рд╣рдо рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреА рдиреЗрдЯрд╡рд░реНрдХ рдЧрддрд┐рд╡рд┐рдзрд┐ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдкрд╛рдПрдВрдЧреЗ рдХрд┐ рдЗрд╕рдХрд╛ рдПрдкреАрдЖрдИ-рд╕рд░реНрд╡рд░ (192.168.205.10.6443) рд╕реЗ рдХрдиреЗрдХреНрд╢рди рд╣реИ:
// any machine
$ netstat -atnv |grep 8507
tcp4 0 0 192.168.205.1.51673 192.168.205.10.6443 ESTABLISHED 131072 131768 8507 0 0x0102 0x00000020
tcp4 0 0 192.168.205.1.51672 192.168.205.10.6443 ESTABLISHED 131072 131768 8507 0 0x0102 0x00000028рдЖрдЗрдП рдХреЛрдб рджреЗрдЦреЗрдВ. Kubectl рдХрд╛рд░реНрдпрдХрд╛рд░реА рдЙрдкрд╕рдВрд╕рд╛рдзрди рдХреЗ рд╕рд╛рде рдПрдХ POST рдЕрдиреБрд░реЛрдз рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рдПрдХ REST рдЕрдиреБрд░реЛрдз рднреЗрдЬрддрд╛ рд╣реИ:
req := restClient.Post().
Resource("pods").
Name(pod.Name).
Namespace(pod.Namespace).
SubResource("exec")
req.VersionedParams(&corev1.PodExecOptions{
Container: containerName,
Command: p.Command,
Stdin: p.Stdin,
Stdout: p.Out != nil,
Stderr: p.ErrOut != nil,
TTY: t.Raw,
}, scheme.ParameterCodec)
return p.Executor.Execute("POST", req.URL(), p.Config, p.In, p.Out, p.ErrOut, t.Raw, sizeQueue)()

2. рдорд╛рд╕реНрдЯрд░ рдиреЛрдб рдкрдХреНрд╖ рдкрд░ рдЧрддрд┐рд╡рд┐рдзрд┐
рд╣рдо рдПрдкреАрдЖрдИ-рд╕рд░реНрд╡рд░ рдкрдХреНрд╖ рдкрд░ рднреА рдЕрдиреБрд░реЛрдз рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:
handler.go:143] kube-apiserver: POST "/api/v1/namespaces/default/pods/exec-test-nginx-6558988d5-fgxgg/exec" satisfied by gorestful with webservice /api/v1
upgradeaware.go:261] Connecting to backend proxy (intercepting redirects) https://192.168.205.11:10250/exec/default/exec-test-nginx-6558988d5-fgxgg/exec-test-nginx?command=sh&input=1&output=1&tty=1
Headers: map[Connection:[Upgrade] Content-Length:[0] Upgrade:[SPDY/3.1] User-Agent:[kubectl/v1.12.10 (darwin/amd64) kubernetes/e3c1340] X-Forwarded-For:[192.168.205.1] X-Stream-Protocol-Version:[v4.channel.k8s.io v3.channel.k8s.io v2.channel.k8s.io channel.k8s.io]]рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ HTTP рдЕрдиреБрд░реЛрдз рдореЗрдВ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдмрджрд▓рдиреЗ рдХрд╛ рдЕрдиреБрд░реЛрдз рд╢рд╛рдорд┐рд▓ рд╣реИред рдЖрдкрдХреЛ рдПрдХ рд╣реА рдЯреАрд╕реАрдкреА рдХрдиреЗрдХреНрд╢рди рдкрд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ stdin/stdout/stderr/spdy-error "рд╕реНрдЯреНрд░реАрдо" рдХреЛ рдорд▓реНрдЯреАрдкреНрд▓реЗрдХреНрд╕ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред
рдПрдкреАрдЖрдИ рд╕рд░реНрд╡рд░ рдЕрдиреБрд░реЛрдз рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рддрд╛ рд╣реИ PodExecOptions:
// PodExecOptions is the query options to a Pod's remote exec call
type PodExecOptions struct {
metav1.TypeMeta
// Stdin if true indicates that stdin is to be redirected for the exec call
Stdin bool
// Stdout if true indicates that stdout is to be redirected for the exec call
Stdout bool
// Stderr if true indicates that stderr is to be redirected for the exec call
Stderr bool
// TTY if true indicates that a tty will be allocated for the exec call
TTY bool
// Container in which to execute the command.
Container string
// Command is the remote command to execute; argv array; not executed within a shell.
Command []string
}()
рдЖрд╡рд╢реНрдпрдХ рдХреНрд░рд┐рдпрд╛рдПрдВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдкреАрдЖрдИ-рд╕рд░реНрд╡рд░ рдХреЛ рдкрддрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдЙрд╕реЗ рдХрд┐рд╕ рдкреЙрдб рд╕реЗ рд╕рдВрдкрд░реНрдХ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
// ExecLocation returns the exec URL for a pod container. If opts.Container is blank
// and only one container is present in the pod, that container is used.
func ExecLocation(
getter ResourceGetter,
connInfo client.ConnectionInfoGetter,
ctx context.Context,
name string,
opts *api.PodExecOptions,
) (*url.URL, http.RoundTripper, error) {
return streamLocation(getter, connInfo, ctx, name, opts, opts.Container, "exec")
}()
рдмреЗрд╢рдХ, рд╕рдорд╛рдкрди рдмрд┐рдВрджреБ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдбреЗрдЯрд╛ рдиреЛрдб рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рд╕реЗ рд▓рд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:
nodeName := types.NodeName(pod.Spec.NodeName)
if len(nodeName) == 0 {
// If pod has not been assigned a host, return an empty location
return nil, nil, errors.NewBadRequest(fmt.Sprintf("pod %s does not have a host assigned", name))
}
nodeInfo, err := connInfo.GetConnectionInfo(ctx, nodeName)()
рд╣реБрд░реНрд░реЗ! рдХреНрдпреВрдмрд▓реЗрдЯ рдореЗрдВ рдЕрдм рдПрдХ рдмрдВрджрд░рдЧрд╛рд╣ рд╣реИ (node.Status.DaemonEndpoints.KubeletEndpoint.Port), рдЬрд┐рд╕рд╕реЗ рдПрдкреАрдЖрдИ рд╕рд░реНрд╡рд░ рдХрдиреЗрдХреНрдЯ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ:
// GetConnectionInfo retrieves connection info from the status of a Node API object.
func (k *NodeConnectionInfoGetter) GetConnectionInfo(ctx context.Context, nodeName types.NodeName) (*ConnectionInfo, error) {
node, err := k.nodes.Get(ctx, string(nodeName), metav1.GetOptions{})
if err != nil {
return nil, err
}
// Find a kubelet-reported address, using preferred address type
host, err := nodeutil.GetPreferredNodeAddress(node, k.preferredAddressTypes)
if err != nil {
return nil, err
}
// Use the kubelet-reported port, if present
port := int(node.Status.DaemonEndpoints.KubeletEndpoint.Port)
if port <= 0 {
port = k.defaultPort
}
return &ConnectionInfo{
Scheme: k.scheme,
Hostname: host,
Port: strconv.Itoa(port),
Transport: k.transport,
}, nil
}()
рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рд╕реЗ :
рдпреЗ рдХрдиреЗрдХреНрд╢рди рдХреНрдпреВрдмрд▓реЗрдЯ рдХреЗ HTTPS рдПрдВрдбрдкреЙрдЗрдВрдЯ рд╕реЗ рдмрдирд╛рдП рдЧрдП рд╣реИрдВред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, рдПрдкреАрд╕рд░реНрд╡рд░ рдХреНрдпреВрдмрд▓реЗрдЯ рдХреЗ рдкреНрд░рдорд╛рдгрдкрддреНрд░ рдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдХрдиреЗрдХреНрд╢рди рдХреЛ рдореИрди-рдЗрди-рдж-рдорд┐рдбрд┐рд▓ (рдПрдордЖрдИрдЯреАрдПрдо) рд╣рдорд▓реЛрдВ рдХреЗ рдкреНрд░рддрд┐ рд╕рдВрд╡реЗрджрдирд╢реАрд▓ рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рдЕрд╕реБрд░рдХреНрд╖рд┐рдд рдЕрд╡рд┐рд╢реНрд╡рд╕рдиреАрдп рдФрд░/рдпрд╛ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рдиреЗрдЯрд╡рд░реНрдХ рдореЗрдВ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред
рдЕрдм рдПрдкреАрдЖрдИ рд╕рд░реНрд╡рд░ рд╕рдорд╛рдкрди рдмрд┐рдВрджреБ рдЬрд╛рдирддрд╛ рд╣реИ рдФрд░ рдХрдиреЗрдХреНрд╢рди рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддрд╛ рд╣реИ:
// Connect returns a handler for the pod exec proxy
func (r *ExecREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
execOpts, ok := opts.(*api.PodExecOptions)
if !ok {
return nil, fmt.Errorf("invalid options object: %#v", opts)
}
location, transport, err := pod.ExecLocation(r.Store, r.KubeletConn, ctx, name, execOpts)
if err != nil {
return nil, err
}
return newThrottledUpgradeAwareProxyHandler(location, transport, false, true, true, responder), nil
}()
рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдорд╛рд╕реНрдЯрд░ рдиреЛрдб рдкрд░ рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рд╡рд░реНрдХрд░ рдиреЛрдб рдХрд╛ рдЖрдИрдкреА рдкрддрд╛ рд▓рдЧрд╛рддреЗ рд╣реИрдВред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдпрд╣ 192.168.205.11 рд╣реИ:
// any machine
$ kubectl get nodes k8s-node-1 -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-node-1 Ready <none> 9h v1.15.3 192.168.205.11 <none> Ubuntu 16.04.6 LTS 4.4.0-159-generic docker://17.3.3рдлрд┐рд░ рдХреНрдпреВрдмрд▓реЗрдЯ рдкреЛрд░реНрдЯ рд╕реЗрдЯ рдХрд░реЗрдВ (рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ 10250):
// any machine
$ kubectl get nodes k8s-node-1 -o jsonpath='{.status.daemonEndpoints.kubeletEndpoint}'
map[Port:10250] рдЕрдм рдиреЗрдЯрд╡рд░реНрдХ рдЬрд╛рдВрдЪрдиреЗ рдХрд╛ рд╕рдордп рдЖ рдЧрдпрд╛ рд╣реИред рдХреНрдпрд╛ рд╡рд░реНрдХрд░ рдиреЛрдб (192.168.205.11) рд╕реЗ рдХреЛрдИ рд╕рдВрдмрдВрдз рд╣реИ? рдпрд╣ рд╣реИ! рдпрджрд┐ рдЖрдк рдХрд┐рд╕реА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдЦрд╝рддреНрдо рдХрд░ рджреЗрддреЗ рд╣реИрдВ exec, рдпрд╣ рдЧрд╛рдпрдм рд╣реЛ рдЬрд╛рдПрдЧрд╛, рдЗрд╕рд▓рд┐рдП рдореБрдЭреЗ рдкрддрд╛ рд╣реИ рдХрд┐ рдХрдиреЗрдХреНрд╢рди рдПрдкреАрдЖрдИ-рд╕рд░реНрд╡рд░ рджреНрд╡рд╛рд░рд╛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдирд┐рд╖реНрдкрд╛рджрди рдХрдорд╛рдВрдб рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред
// master node
$ netstat -atn |grep 192.168.205.11
tcp 0 0 192.168.205.10:37870 192.168.205.11:10250 ESTABLISHED
тАж 
Kubectl рдФрд░ рдПрдкреАрдЖрдИ-рд╕рд░реНрд╡рд░ рдХреЗ рдмреАрдЪ рдХрдиреЗрдХреНрд╢рди рдЕрднреА рднреА рдЦреБрд▓рд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд, рдПрдХ рдФрд░ рдХрдиреЗрдХреНрд╢рди рд╣реИ рдЬреЛ рдПрдкреАрдЖрдИ-рд╕рд░реНрд╡рд░ рдФрд░ рдХреНрдпреВрдмрд▓реЗрдЯ рдХреЛ рдЬреЛрдбрд╝рддрд╛ рд╣реИред
3. рд╡рд░реНрдХрд░ рдиреЛрдб рдкрд░ рдЧрддрд┐рд╡рд┐рдзрд┐
рдЕрдм рдЖрдЗрдП рд╡рд░реНрдХрд░ рдиреЛрдб рд╕реЗ рдЬреБрдбрд╝реЗрдВ рдФрд░ рджреЗрдЦреЗрдВ рдХрд┐ рдЗрд╕ рдкрд░ рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдЗрд╕рдХрд╛ рдХрдиреЗрдХреНрд╢рди рднреА рд╕реНрдерд╛рдкрд┐рдд рд╣реЛ рдЧрдпрд╛ рд╣реИ (рджреВрд╕рд░реА рдкрдВрдХреНрддрд┐); 192.168.205.10 рдорд╛рд╕реНрдЯрд░ рдиреЛрдб рдХрд╛ рдЖрдИрдкреА рд╣реИ:
// worker node
$ netstat -atn |grep 10250
tcp6 0 0 :::10250 :::* LISTEN
tcp6 0 0 192.168.205.11:10250 192.168.205.10:37870 ESTABLISHED рд╣рдорд╛рд░реА рдЯреАрдо рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛? sleep? рд╣реБрд░реНрд░реЗ, рд╡рд╣ рднреА рд╡рд╣рд╛рдБ рд╣реИ!
// worker node
$ ps -afx
...
31463 ? Sl 0:00 _ docker-containerd-shim 7d974065bbb3107074ce31c51f5ef40aea8dcd535ae11a7b8f2dd180b8ed583a /var/run/docker/libcontainerd/7d974065bbb3107074ce31c51
31478 pts/0 Ss 0:00 _ sh
31485 pts/0 S+ 0:00 _ sleep 5000
тАжрд▓реЗрдХрд┐рди рд░реБрдХрд┐рдП: рдХреНрдпреВрдмрд▓реЗрдЯ рдиреЗ рдЗрд╕реЗ рдХреИрд╕реЗ рдкреВрд░рд╛ рдХрд┐рдпрд╛? рдХреНрдпреВрдмрд▓реЗрдЯ рдореЗрдВ рдПрдХ рдбреЗрдореЙрди рд╣реИ рдЬреЛ рдПрдкреАрдЖрдИ-рд╕рд░реНрд╡рд░ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рд▓рд┐рдП рдкреЛрд░реНрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдкреАрдЖрдИ рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:
// Server is the library interface to serve the stream requests.
type Server interface {
http.Handler
// Get the serving URL for the requests.
// Requests must not be nil. Responses may be nil iff an error is returned.
GetExec(*runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error)
GetAttach(req *runtimeapi.AttachRequest) (*runtimeapi.AttachResponse, error)
GetPortForward(*runtimeapi.PortForwardRequest) (*runtimeapi.PortForwardResponse, error)
// Start the server.
// addr is the address to serve on (address:port) stayUp indicates whether the server should
// listen until Stop() is called, or automatically stop after all expected connections are
// closed. Calling Get{Exec,Attach,PortForward} increments the expected connection count.
// Function does not return until the server is stopped.
Start(stayUp bool) error
// Stop the server, and terminate any open connections.
Stop() error
}()
рдХреНрдпреВрдмрд▓реЗрдЯ рдирд┐рд╖реНрдкрд╛рджрди рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рд▓рд┐рдП рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕рдорд╛рдкрди рдмрд┐рдВрджреБ рдХреА рдЧрдгрдирд╛ рдХрд░рддрд╛ рд╣реИ:
func (s *server) GetExec(req *runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error) {
if err := validateExecRequest(req); err != nil {
return nil, err
}
token, err := s.cache.Insert(req)
if err != nil {
return nil, err
}
return &runtimeapi.ExecResponse{
Url: s.buildURL("exec", token),
}, nil
}()
рднреНрд░рдорд┐рдд рдордд рд╣реЛрдЗрдП. рдпрд╣ рдЖрджреЗрд╢ рдХрд╛ рдкрд░рд┐рдгрд╛рдо рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рд╕рдВрдЪрд╛рд░ рдХрд╛ рдЕрдВрддрд┐рдо рдмрд┐рдВрджреБ рд▓реМрдЯрд╛рддрд╛ рд╣реИ:
type ExecResponse struct {
// Fully qualified URL of the exec streaming server.
Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_sizecache int32 `json:"-"`
}()
рдХреНрдпреВрдмрд▓реЗрдЯ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ RuntimeServiceClient, рдЬреЛ рдХрдВрдЯреЗрдирд░ рд░рдирдЯрд╛рдЗрдо рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╣реИ (рд╣рдордиреЗ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдФрд░ рдЕрдзрд┐рдХ рд▓рд┐рдЦрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, - рд▓рдЧрднрдЧред рдЕрдиреБрд╡рд╛рджред):
рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕/рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕ рдореЗрдВ рдХреНрд░рд┐-рдПрдкреАрдЖрдИ рд╕реЗ рд▓рдВрдмреА рд╕реВрдЪреА
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type RuntimeServiceClient interface {
// Version returns the runtime name, runtime version, and runtime API version.
Version(ctx context.Context, in *VersionRequest, opts ...grpc.CallOption) (*VersionResponse, error)
// RunPodSandbox creates and starts a pod-level sandbox. Runtimes must ensure
// the sandbox is in the ready state on success.
RunPodSandbox(ctx context.Context, in *RunPodSandboxRequest, opts ...grpc.CallOption) (*RunPodSandboxResponse, error)
// StopPodSandbox stops any running process that is part of the sandbox and
// reclaims network resources (e.g., IP addresses) allocated to the sandbox.
// If there are any running containers in the sandbox, they must be forcibly
// terminated.
// This call is idempotent, and must not return an error if all relevant
// resources have already been reclaimed. kubelet will call StopPodSandbox
// at least once before calling RemovePodSandbox. It will also attempt to
// reclaim resources eagerly, as soon as a sandbox is not needed. Hence,
// multiple StopPodSandbox calls are expected.
StopPodSandbox(ctx context.Context, in *StopPodSandboxRequest, opts ...grpc.CallOption) (*StopPodSandboxResponse, error)
// RemovePodSandbox removes the sandbox. If there are any running containers
// in the sandbox, they must be forcibly terminated and removed.
// This call is idempotent, and must not return an error if the sandbox has
// already been removed.
RemovePodSandbox(ctx context.Context, in *RemovePodSandboxRequest, opts ...grpc.CallOption) (*RemovePodSandboxResponse, error)
// PodSandboxStatus returns the status of the PodSandbox. If the PodSandbox is not
// present, returns an error.
PodSandboxStatus(ctx context.Context, in *PodSandboxStatusRequest, opts ...grpc.CallOption) (*PodSandboxStatusResponse, error)
// ListPodSandbox returns a list of PodSandboxes.
ListPodSandbox(ctx context.Context, in *ListPodSandboxRequest, opts ...grpc.CallOption) (*ListPodSandboxResponse, error)
// CreateContainer creates a new container in specified PodSandbox
CreateContainer(ctx context.Context, in *CreateContainerRequest, opts ...grpc.CallOption) (*CreateContainerResponse, error)
// StartContainer starts the container.
StartContainer(ctx context.Context, in *StartContainerRequest, opts ...grpc.CallOption) (*StartContainerResponse, error)
// StopContainer stops a running container with a grace period (i.e., timeout).
// This call is idempotent, and must not return an error if the container has
// already been stopped.
// TODO: what must the runtime do after the grace period is reached?
StopContainer(ctx context.Context, in *StopContainerRequest, opts ...grpc.CallOption) (*StopContainerResponse, error)
// RemoveContainer removes the container. If the container is running, the
// container must be forcibly removed.
// This call is idempotent, and must not return an error if the container has
// already been removed.
RemoveContainer(ctx context.Context, in *RemoveContainerRequest, opts ...grpc.CallOption) (*RemoveContainerResponse, error)
// ListContainers lists all containers by filters.
ListContainers(ctx context.Context, in *ListContainersRequest, opts ...grpc.CallOption) (*ListContainersResponse, error)
// ContainerStatus returns status of the container. If the container is not
// present, returns an error.
ContainerStatus(ctx context.Context, in *ContainerStatusRequest, opts ...grpc.CallOption) (*ContainerStatusResponse, error)
// UpdateContainerResources updates ContainerConfig of the container.
UpdateContainerResources(ctx context.Context, in *UpdateContainerResourcesRequest, opts ...grpc.CallOption) (*UpdateContainerResourcesResponse, error)
// ReopenContainerLog asks runtime to reopen the stdout/stderr log file
// for the container. This is often called after the log file has been
// rotated. If the container is not running, container runtime can choose
// to either create a new log file and return nil, or return an error.
// Once it returns error, new container log file MUST NOT be created.
ReopenContainerLog(ctx context.Context, in *ReopenContainerLogRequest, opts ...grpc.CallOption) (*ReopenContainerLogResponse, error)
// ExecSync runs a command in a container synchronously.
ExecSync(ctx context.Context, in *ExecSyncRequest, opts ...grpc.CallOption) (*ExecSyncResponse, error)
// Exec prepares a streaming endpoint to execute a command in the container.
Exec(ctx context.Context, in *ExecRequest, opts ...grpc.CallOption) (*ExecResponse, error)
// Attach prepares a streaming endpoint to attach to a running container.
Attach(ctx context.Context, in *AttachRequest, opts ...grpc.CallOption) (*AttachResponse, error)
// PortForward prepares a streaming endpoint to forward ports from a PodSandbox.
PortForward(ctx context.Context, in *PortForwardRequest, opts ...grpc.CallOption) (*PortForwardResponse, error)
// ContainerStats returns stats of the container. If the container does not
// exist, the call returns an error.
ContainerStats(ctx context.Context, in *ContainerStatsRequest, opts ...grpc.CallOption) (*ContainerStatsResponse, error)
// ListContainerStats returns stats of all running containers.
ListContainerStats(ctx context.Context, in *ListContainerStatsRequest, opts ...grpc.CallOption) (*ListContainerStatsResponse, error)
// UpdateRuntimeConfig updates the runtime configuration based on the given request.
UpdateRuntimeConfig(ctx context.Context, in *UpdateRuntimeConfigRequest, opts ...grpc.CallOption) (*UpdateRuntimeConfigResponse, error)
// Status returns the status of the runtime.
Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error)
} ()
рдпрд╣ рдХрдВрдЯреЗрдирд░ рд░рдирдЯрд╛рдЗрдо рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдХ рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╕ рдЬреАрдЖрд░рдкреАрд╕реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ:
type runtimeServiceClient struct {
cc *grpc.ClientConn
}()
func (c *runtimeServiceClient) Exec(ctx context.Context, in *ExecRequest, opts ...grpc.CallOption) (*ExecResponse, error) {
out := new(ExecResponse)
err := c.cc.Invoke(ctx, "/runtime.v1alpha2.RuntimeService/Exec", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}()
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдХрдВрдЯреЗрдирд░ рд░рдирдЯрд╛рдЗрдо рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ RuntimeServiceServer:
рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕/рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕ рдореЗрдВ рдХреНрд░рд┐-рдПрдкреАрдЖрдИ рд╕реЗ рд▓рдВрдмреА рд╕реВрдЪреА
// RuntimeServiceServer is the server API for RuntimeService service.
type RuntimeServiceServer interface {
// Version returns the runtime name, runtime version, and runtime API version.
Version(context.Context, *VersionRequest) (*VersionResponse, error)
// RunPodSandbox creates and starts a pod-level sandbox. Runtimes must ensure
// the sandbox is in the ready state on success.
RunPodSandbox(context.Context, *RunPodSandboxRequest) (*RunPodSandboxResponse, error)
// StopPodSandbox stops any running process that is part of the sandbox and
// reclaims network resources (e.g., IP addresses) allocated to the sandbox.
// If there are any running containers in the sandbox, they must be forcibly
// terminated.
// This call is idempotent, and must not return an error if all relevant
// resources have already been reclaimed. kubelet will call StopPodSandbox
// at least once before calling RemovePodSandbox. It will also attempt to
// reclaim resources eagerly, as soon as a sandbox is not needed. Hence,
// multiple StopPodSandbox calls are expected.
StopPodSandbox(context.Context, *StopPodSandboxRequest) (*StopPodSandboxResponse, error)
// RemovePodSandbox removes the sandbox. If there are any running containers
// in the sandbox, they must be forcibly terminated and removed.
// This call is idempotent, and must not return an error if the sandbox has
// already been removed.
RemovePodSandbox(context.Context, *RemovePodSandboxRequest) (*RemovePodSandboxResponse, error)
// PodSandboxStatus returns the status of the PodSandbox. If the PodSandbox is not
// present, returns an error.
PodSandboxStatus(context.Context, *PodSandboxStatusRequest) (*PodSandboxStatusResponse, error)
// ListPodSandbox returns a list of PodSandboxes.
ListPodSandbox(context.Context, *ListPodSandboxRequest) (*ListPodSandboxResponse, error)
// CreateContainer creates a new container in specified PodSandbox
CreateContainer(context.Context, *CreateContainerRequest) (*CreateContainerResponse, error)
// StartContainer starts the container.
StartContainer(context.Context, *StartContainerRequest) (*StartContainerResponse, error)
// StopContainer stops a running container with a grace period (i.e., timeout).
// This call is idempotent, and must not return an error if the container has
// already been stopped.
// TODO: what must the runtime do after the grace period is reached?
StopContainer(context.Context, *StopContainerRequest) (*StopContainerResponse, error)
// RemoveContainer removes the container. If the container is running, the
// container must be forcibly removed.
// This call is idempotent, and must not return an error if the container has
// already been removed.
RemoveContainer(context.Context, *RemoveContainerRequest) (*RemoveContainerResponse, error)
// ListContainers lists all containers by filters.
ListContainers(context.Context, *ListContainersRequest) (*ListContainersResponse, error)
// ContainerStatus returns status of the container. If the container is not
// present, returns an error.
ContainerStatus(context.Context, *ContainerStatusRequest) (*ContainerStatusResponse, error)
// UpdateContainerResources updates ContainerConfig of the container.
UpdateContainerResources(context.Context, *UpdateContainerResourcesRequest) (*UpdateContainerResourcesResponse, error)
// ReopenContainerLog asks runtime to reopen the stdout/stderr log file
// for the container. This is often called after the log file has been
// rotated. If the container is not running, container runtime can choose
// to either create a new log file and return nil, or return an error.
// Once it returns error, new container log file MUST NOT be created.
ReopenContainerLog(context.Context, *ReopenContainerLogRequest) (*ReopenContainerLogResponse, error)
// ExecSync runs a command in a container synchronously.
ExecSync(context.Context, *ExecSyncRequest) (*ExecSyncResponse, error)
// Exec prepares a streaming endpoint to execute a command in the container.
Exec(context.Context, *ExecRequest) (*ExecResponse, error)
// Attach prepares a streaming endpoint to attach to a running container.
Attach(context.Context, *AttachRequest) (*AttachResponse, error)
// PortForward prepares a streaming endpoint to forward ports from a PodSandbox.
PortForward(context.Context, *PortForwardRequest) (*PortForwardResponse, error)
// ContainerStats returns stats of the container. If the container does not
// exist, the call returns an error.
ContainerStats(context.Context, *ContainerStatsRequest) (*ContainerStatsResponse, error)
// ListContainerStats returns stats of all running containers.
ListContainerStats(context.Context, *ListContainerStatsRequest) (*ListContainerStatsResponse, error)
// UpdateRuntimeConfig updates the runtime configuration based on the given request.
UpdateRuntimeConfig(context.Context, *UpdateRuntimeConfigRequest) (*UpdateRuntimeConfigResponse, error)
// Status returns the status of the runtime.
Status(context.Context, *StatusRequest) (*StatusResponse, error)
} ()

рдпрджрд┐ рд╣рд╛рдВ, рддреЛ рд╣рдореЗрдВ рдХреНрдпреВрдмрд▓реЗрдЯ рдФрд░ рдХрдВрдЯреЗрдирд░ рд░рдирдЯрд╛рдЗрдо рдХреЗ рдмреАрдЪ рдПрдХ рд╕рдВрдмрдВрдз рджреЗрдЦрдирд╛ рдЪрд╛рд╣рд┐рдП, рд╣реИ рдирд╛? рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВред
рдЗрд╕ рдХрдорд╛рдВрдб рдХреЛ exec рдХрдорд╛рдВрдб рд╕реЗ рдкрд╣рд▓реЗ рдФрд░ рдмрд╛рдж рдореЗрдВ рдЪрд▓рд╛рдПрдБ рдФрд░ рдЕрдВрддрд░ рджреЗрдЦреЗрдВред рдореЗрд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдЕрдВрддрд░ рдпрд╣ рд╣реИ:
// worker node
$ ss -a -p |grep kubelet
...
u_str ESTAB 0 0 * 157937 * 157387 users:(("kubelet",pid=5714,fd=33))
...рд╣рдореНрдореНрдо... рдХреНрдпреВрдмрд▓реЗрдЯ (рдкреАрдЖрдИрдбреА=5714) рдФрд░ рдХреБрдЫ рдЕрдЬреНрдЮрд╛рдд рдХреЗ рдмреАрдЪ рдпреВрдирд┐рдХреНрд╕ рд╕реЙрдХреЗрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдХ рдирдпрд╛ рдХрдиреЗрдХреНрд╢рдиред рдХреНрдпрд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ? рдпрд╣ рд╕рд╣реА рд╣реИ, рдпрд╣ рдбреЙрдХрд░ рд╣реИ (рдкреАрдЖрдИрдбреА=1186)!
// worker node
$ ss -a -p |grep 157387
...
u_str ESTAB 0 0 * 157937 * 157387 users:(("kubelet",pid=5714,fd=33))
u_str ESTAB 0 0 /var/run/docker.sock 157387 * 157937 users:(("dockerd",pid=1186,fd=14))
...рдЬреИрд╕рд╛ рдХрд┐ рдЖрдкрдХреЛ рдпрд╛рдж рд╣реИ, рдпрд╣ рдбреЙрдХрд░ рдбреЗрдореЙрди рдкреНрд░рдХреНрд░рд┐рдпрд╛ (pid=1186) рд╣реИ рдЬреЛ рд╣рдорд╛рд░реЗ рдЖрджреЗрд╢ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреА рд╣реИ:
// worker node
$ ps -afx
...
1186 ? Ssl 0:55 /usr/bin/dockerd -H fd://
17784 ? Sl 0:00 _ docker-containerd-shim 53a0a08547b2f95986402d7f3b3e78702516244df049ba6c5aa012e81264aa3c /var/run/docker/libcontainerd/53a0a08547b2f95986402d7f3
17801 pts/2 Ss 0:00 _ sh
17827 pts/2 S+ 0:00 _ sleep 5000
...4. рдХрдВрдЯреЗрдирд░ рд░рдирдЯрд╛рдЗрдо рдореЗрдВ рдЧрддрд┐рд╡рд┐рдзрд┐
рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдЗрдП рд╕реАрдЖрд░рдЖрдИ-рдУ рд╕реНрд░реЛрдд рдХреЛрдб рдХреА рдЬрд╛рдВрдЪ рдХрд░реЗрдВред рдбреЙрдХрд░ рдореЗрдВ рддрд░реНрдХ рд╕рдорд╛рди рд╣реИред
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд░реНрд╡рд░ рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ RuntimeServiceServer:
// Server implements the RuntimeService and ImageService
type Server struct {
config libconfig.Config
seccompProfile *seccomp.Seccomp
stream StreamService
netPlugin ocicni.CNIPlugin
hostportManager hostport.HostPortManager
appArmorProfile string
hostIP string
bindAddress string
*lib.ContainerServer
monitorsChan chan struct{}
defaultIDMappings *idtools.IDMappings
systemContext *types.SystemContext // Never nil
updateLock sync.RWMutex
seccompEnabled bool
appArmorEnabled bool
}()
// Exec prepares a streaming endpoint to execute a command in the container.
func (s *Server) Exec(ctx context.Context, req *pb.ExecRequest) (resp *pb.ExecResponse, err error) {
const operation = "exec"
defer func() {
recordOperation(operation, time.Now())
recordError(operation, err)
}()
resp, err = s.getExec(req)
if err != nil {
return nil, fmt.Errorf("unable to prepare exec endpoint: %v", err)
}
return resp, nil
}()
рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХреЗ рдЕрдВрдд рдореЗрдВ, рдХрдВрдЯреЗрдирд░ рд░рдирдЯрд╛рдЗрдо рд╡рд░реНрдХрд░ рдиреЛрдб рдкрд░ рдХрдорд╛рдВрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддрд╛ рд╣реИ:
// ExecContainer prepares a streaming endpoint to execute a command in the container.
func (r *runtimeOCI) ExecContainer(c *Container, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error {
processFile, err := prepareProcessExec(c, cmd, tty)
if err != nil {
return err
}
defer os.RemoveAll(processFile.Name())
args := []string{rootFlag, r.root, "exec"}
args = append(args, "--process", processFile.Name(), c.ID())
execCmd := exec.Command(r.path, args...)
if v, found := os.LookupEnv("XDG_RUNTIME_DIR"); found {
execCmd.Env = append(execCmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", v))
}
var cmdErr, copyError error
if tty {
cmdErr = ttyCmd(execCmd, stdin, stdout, resize)
} else {
if stdin != nil {
// Use an os.Pipe here as it returns true *os.File objects.
// This way, if you run 'kubectl exec <pod> -i bash' (no tty) and type 'exit',
// the call below to execCmd.Run() can unblock because its Stdin is the read half
// of the pipe.
r, w, err := os.Pipe()
if err != nil {
return err
}
go func() { _, copyError = pools.Copy(w, stdin) }()
execCmd.Stdin = r
}
if stdout != nil {
execCmd.Stdout = stdout
}
if stderr != nil {
execCmd.Stderr = stderr
}
cmdErr = execCmd.Run()
}
if copyError != nil {
return copyError
}
if exitErr, ok := cmdErr.(*exec.ExitError); ok {
return &utilexec.ExitErrorWrapper{ExitError: exitErr}
}
return cmdErr
}()

рдЕрдВрдд рдореЗрдВ, рдХрд░реНрдиреЗрд▓ рдХрдорд╛рдВрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддрд╛ рд╣реИ:

╨░╨┐╨╛╨╝╨╕╨╜╨░╨╜╨╕╤П
- рдПрдкреАрдЖрдИ рд╕рд░реНрд╡рд░ рдХреНрдпреВрдмрд▓реЗрдЯ рд╕реЗ рдХрдиреЗрдХреНрд╢рди рднреА рдЖрд░рдВрдн рдХрд░ рд╕рдХрддрд╛ рд╣реИред
- рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдирд┐рд╖реНрдкрд╛рджрди рд╕рддреНрд░ рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рддрдХ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрдиреЗрдХреНрд╢рди рдмрдиреЗ рд░рд╣рддреЗ рд╣реИрдВ:
- Kubectl рдФрд░ рдПрдкреАрдЖрдИ-рд╕рд░реНрд╡рд░ рдХреЗ рдмреАрдЪ;
- рдПрдкреАрдЖрдИ-рд╕рд░реНрд╡рд░ рдФрд░ рдХреНрдпреВрдмреЗрдХреНрдЯрд▓ рдХреЗ рдмреАрдЪ;
- рдХреНрдпреВрдмрд▓реЗрдЯ рдФрд░ рдХрдВрдЯреЗрдирд░ рд░рдирдЯрд╛рдЗрдо рдХреЗ рдмреАрдЪред
- Kubectl рдпрд╛ рдПрдкреАрдЖрдИ-рд╕рд░реНрд╡рд░ рд╡рд░реНрдХрд░ рдиреЛрдбреНрд╕ рдкрд░ рдХреБрдЫ рднреА рдирд╣реАрдВ рдЪрд▓рд╛ рд╕рдХрддрд╛ рд╣реИред рдХреНрдпреВрдмрд▓реЗрдЯ рдЪрд▓ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЙрди рдЪреАрдЬреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдВрдЯреЗрдирд░ рд░рдирдЯрд╛рдЗрдо рдХреЗ рд╕рд╛рде рдЗрдВрдЯрд░реИрдХреНрдЯ рднреА рдХрд░рддрд╛ рд╣реИред
╨а╨╡╤Б╤Г╤А╤Б╤Л
- рдмрд╣рд╕ ""рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕-рджреЗрд╡ рдореЗрдВ;
- рд▓реЗрдЦ "";
- рдмрд╣рд╕ ""рд╕рд░реНрд╡рд░ рджреЛрд╖ рдкрд░.
рдЕрдиреБрд╡рд╛рджрдХ рд╕реЗ рдкреА.рдПрд╕
рд╣рдорд╛рд░реЗ рдмреНрд▓реЙрдЧ рдкрд░ рднреА рдкрдврд╝реЗрдВ:
- "рдЬрдм рдЖрдк рдХреБрдмреЗрдХреНрдЯрд▓ рд░рди рдЪрд▓рд╛рддреЗ рд╣реИрдВ рддреЛ рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕ рдореЗрдВ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ?" ╨╕ ;
- ┬л";
- ┬л";
- ┬л'.
рд╕реНрд░реЛрдд: www.habr.com
