kubectl exec เจ•เจฟเจตเฉ‡เจ‚ เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ?

เจจเฉ‹เจŸ เจ•เจฐเฉ‹เฅค เจ…เจจเฉเจตเจพเจฆ: เจฒเฉ‡เจ– เจฆเจพ เจฒเฉ‡เจ–เจ• - เจเจฐเจ•เจจ เจเจฐเฉ‹เจฒ, เจเจธเจเจชเฉ€ เจฆเจพ เจ‡เฉฑเจ• เจ‡เฉฐเจœเฉ€เจจเฉ€เจ…เจฐ - เจŸเฉ€เจฎ เจฆเฉ‡ เจ•เฉฐเจฎเจ•เจพเจœ เจฆเฉ‡ เจคเฉฐเจคเจฐ เจฆเจพ เจ†เจชเจฃเจพ เจ…เจงเจฟเจเจจ เจธเจพเจ‚เจเจพ เจ•เจฐเจฆเจพ เจนเฉˆ kubectl exec, เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจจเจพเจฒ เจ•เฉฐเจฎ เจ•เจฐเจจ เจตเจพเจฒเฉ‡ เจนเจฐเฉ‡เจ• เจตเจฟเจ…เจ•เจคเฉ€ เจฒเจˆ เจฌเจนเฉเจค เจœเจพเจฃเฉ‚ เจนเฉˆเฅค เจ‰เจน เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจธเจฐเฉ‹เจค เจ•เฉ‹เจก (เจ…เจคเฉ‡ เจธเฉฐเจฌเฉฐเจงเจฟเจค เจชเฉเจฐเฉ‹เจœเฉˆเจ•เจŸเจพเจ‚) เจฆเฉ€เจ†เจ‚ เจธเฉ‚เจšเฉ€เจ†เจ‚ เจฆเฉ‡ เจจเจพเจฒ เจชเฉ‚เจฐเฉ‡ เจเจฒเจ—เฉ‹เจฐเจฟเจฆเจฎ เจฆเฉ‡ เจจเจพเจฒ เจนเฉˆ, เจœเฉ‹ เจคเฉเจนเจพเจจเฉ‚เฉฐ เจฒเฉ‹เฉœ เจ…เจจเฉเจธเจพเจฐ เจตเจฟเจธเจผเฉ‡ เจจเฉ‚เฉฐ เจกเฉ‚เฉฐเจ˜เจพเจˆ เจจเจพเจฒ เจธเจฎเจเจฃ เจฆเฉ€ เจ‡เจœเจพเจœเจผเจค เจฆเจฟเฉฐเจฆเจพ เจนเฉˆเฅค

kubectl exec เจ•เจฟเจตเฉ‡เจ‚ เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ?

เจ‡เฉฑเจ• เจธเจผเฉเฉฑเจ•เจฐเจตเจพเจฐ, เจ‡เฉฑเจ• เจธเจนเจฟเจ•เจฐเจฎเฉ€ เจฎเฉ‡เจฐเฉ‡ เจ•เฉ‹เจฒ เจ†เจ‡เจ† เจ…เจคเฉ‡ เจชเฉเฉฑเจ›เจฟเจ† เจ•เจฟ เจ‡เฉฑเจ• เจชเฉŒเจก เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจ•เจฎเจพเจ‚เจก เจจเฉ‚เฉฐ เจ•เจฟเจตเฉ‡เจ‚ เจšเจฒเจพเจ‰เจฃเจพ เจนเฉˆ เจ—เจพเจนเจ•-เจœเจพเจ“. เจฎเฉˆเจ‚ เจ‰เจธเจจเฉ‚เฉฐ เจœเจตเจพเจฌ เจจเจนเฉ€เจ‚ เจฆเฉ‡ เจธเจ•เจฟเจ† เจ…เจคเฉ‡ เจ…เจšเจพเจจเจ• เจฎเจนเจฟเจธเฉ‚เจธ เจ•เฉ€เจคเจพ เจ•เจฟ เจฎเฉˆเจจเฉ‚เฉฐ เจ“เจชเจฐเฉ‡เจธเจผเจจ เจฆเฉ€ เจตเจฟเจงเฉ€ เจฌเจพเจฐเฉ‡ เจ•เฉเจ เจจเจนเฉ€เจ‚ เจชเจคเจพ เจธเฉ€ kubectl exec. เจนเจพเจ‚, เจฎเฉ‡เจฐเฉ‡ เจ•เฉ‹เจฒ เจ‡เจธเจฆเฉ€ เจฌเจฃเจคเจฐ เจฌเจพเจฐเฉ‡ เจ•เฉเจ เจตเจฟเจšเจพเจฐ เจธเจจ, เจชเจฐ เจฎเฉˆเจ‚ เจ‰เจนเจจเจพเจ‚ เจฆเฉ€ เจธเจผเฉเฉฑเจงเจคเจพ เจฌเจพเจฐเฉ‡ 100% เจฏเจ•เฉ€เจจเฉ€ เจจเจนเฉ€เจ‚ เจธเฉ€ เจ…เจคเฉ‡ เจ‡เจธ เจฒเจˆ เจ‡เจธ เจฎเฉเฉฑเจฆเฉ‡ เจจเจพเจฒ เจจเจœเจฟเฉฑเจ เจฃ เจฆเจพ เจซเฉˆเจธเจฒเจพ เจ•เฉ€เจคเจพเฅค เจฌเจฒเฉŒเจ—, เจฆเจธเจคเจพเจตเฉ‡เจœเจผ เจ…เจคเฉ‡ เจธเจฐเฉ‹เจค เจ•เฉ‹เจก เจฆเจพ เจ…เจงเจฟเจเจจ เจ•เจฐเจจ เจคเฉ‹เจ‚ เจฌเจพเจ…เจฆ, เจฎเฉˆเจ‚ เจฌเจนเฉเจค เจธเจพเจฐเฉ€เจ†เจ‚ เจจเจตเฉ€เจ†เจ‚ เจšเฉ€เจœเจผเจพเจ‚ เจธเจฟเฉฑเจ–เฉ€เจ†เจ‚, เจ…เจคเฉ‡ เจ‡เจธ เจฒเฉ‡เจ– เจตเจฟเฉฑเจš เจฎเฉˆเจ‚ เจ†เจชเจฃเฉ€เจ†เจ‚ เจ–เฉ‹เจœเจพเจ‚ เจ…เจคเฉ‡ เจธเจฎเจ เจจเฉ‚เฉฐ เจธเจพเจ‚เจเจพ เจ•เจฐเจจเจพ เจšเจพเจนเฉเฉฐเจฆเจพ เจนเจพเจ‚เฅค เจœเฉ‡ เจ•เฉเจ เจ—เจฒเจค เจนเฉˆ, เจคเจพเจ‚ เจ•เจฟเจฐเจชเจพ เจ•เจฐเจ•เฉ‡ เจฎเฉ‡เจฐเฉ‡ 'เจคเฉ‡ เจธเฉฐเจชเจฐเจ• เจ•เจฐเฉ‹ เจŸเจตเจฟเฉฑเจŸเจฐ.

เจธเจฟเจ–เจฒเจพเจˆ

เจ‡เฉฑเจ• เจฎเฉˆเจ•เจฌเฉเฉฑเจ• 'เจคเฉ‡ เจ‡เฉฑเจ• เจ•เจฒเฉฑเจธเจŸเจฐ เจฌเจฃเจพเจ‰เจฃ เจฒเจˆ, เจฎเฉˆเจ‚ เจ•เจฒเฉ‹เจจ เจ•เฉ€เจคเจพ ecomm-integration-ballerina/kubernetes-cluster. เจซเจฟเจฐ เจฎเฉˆเจ‚ เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจธเฉฐเจฐเจšเจจเจพ เจตเจฟเฉฑเจš เจจเฉ‹เจกเจพเจ‚ เจฆเฉ‡ IP เจเจกเจฐเฉˆเฉฑเจธ เจจเฉ‚เฉฐ เจ เฉ€เจ• เจ•เฉ€เจคเจพ, เจ•เจฟเจ‰เจ‚เจ•เจฟ เจกเจฟเจซเฉŒเจฒเจŸ เจธเฉˆเจŸเจฟเฉฐเจ—เจพเจ‚ เจจเฉ‡ เจ‡เจœเจพเจœเจผเจค เจจเจนเฉ€เจ‚ เจฆเจฟเฉฑเจคเฉ€ kubectl exec. เจคเฉเจธเฉ€เจ‚ เจ‡เจธ เจฆเฉ‡ เจฎเฉเฉฑเจ– เจ•เจพเจฐเจจ เจฌเจพเจฐเฉ‡ เจนเฉ‹เจฐ เจชเฉœเฉเจน เจธเจ•เจฆเฉ‡ เจนเฉ‹ เจ‡เฉฑเจฅเฉ‡.

  • เจ•เฉ‹เจˆ เจตเฉ€ เจ•เจพเจฐ = เจฎเฉ‡เจฐเฉ€ เจฎเฉˆเจ•เจฌเฉเฉฑเจ•
  • เจฎเจพเจธเจŸเจฐ เจจเฉ‹เจก IP = 192.168.205.10
  • เจตเจฐเจ•เจฐ เจจเฉ‹เจก IP = 192.168.205.11
  • API เจธเจฐเจตเจฐ เจชเฉ‹เจฐเจŸ = 6443

เจ•เฉฐเจชเฉ‹เจจเฉˆเจ‚เจŸเจธ

kubectl exec เจ•เจฟเจตเฉ‡เจ‚ เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ?

  • kubectl exec เจชเฉเจฐเจ•เจฟเจฐเจฟเจ†: เจœเจฆเฉ‹เจ‚ เจ…เจธเฉ€เจ‚ "kubectl exec..." เจจเฉ‚เฉฐ เจšเจฒเจพเจ‰เจ‚เจฆเฉ‡ เจนเจพเจ‚ เจคเจพเจ‚ เจชเฉเจฐเจ•เจฟเจฐเจฟเจ† เจธเจผเฉเจฐเฉ‚ เจนเฉ‹ เจœเจพเจ‚เจฆเฉ€ เจนเฉˆเฅค เจ‡เจน K8s API เจธเจฐเจตเจฐ เจคเฉฑเจ• เจชเจนเฉเฉฐเจš เจตเจพเจฒเฉ€ เจ•เจฟเจธเฉ‡ เจตเฉ€ เจฎเจธเจผเฉ€เจจ 'เจคเฉ‡ เจ•เฉ€เจคเจพ เจœเจพ เจธเจ•เจฆเจพ เจนเฉˆเฅค เจจเฉ‹เจŸ เจ•เจฐเฉ‹ เจ…เจจเฉเจตเจพเจฆ: เจ…เฉฑเจ—เฉ‡ เจ•เฉฐเจธเฉ‹เจฒ เจธเฉ‚เจšเฉ€เจ†เจ‚ เจตเจฟเฉฑเจš, เจฒเฉ‡เจ–เจ• "เจ•เฉ‹เจˆ เจฎเจธเจผเฉ€เจจ" เจŸเจฟเฉฑเจชเจฃเฉ€ เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐเจฆเจพ เจนเฉˆ, เจœเจฟเจธเจฆเจพ เจฎเจคเจฒเจฌ เจนเฉˆ เจ•เจฟ เจ…เจ—เจฒเฉ€เจ†เจ‚ เจ•เจฎเจพเจ‚เจกเจพเจ‚ เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจคเฉฑเจ• เจชเจนเฉเฉฐเจš เจตเจพเจฒเฉ€เจ†เจ‚ เจ…เจœเจฟเจนเฉ€เจ†เจ‚ เจฎเจธเจผเฉ€เจจเจพเจ‚ 'เจคเฉ‡ เจšเจฒเจพเจˆเจ†เจ‚ เจœเจพ เจธเจ•เจฆเฉ€เจ†เจ‚ เจนเจจเฅค
  • api เจธเจฐเจตเจฐ: เจฎเจพเจธเจŸเจฐ เจจเฉ‹เจก 'เจคเฉ‡ เจ‡เฉฑเจ• เจ•เฉฐเจชเฉ‹เจจเฉˆเจ‚เจŸ เจœเฉ‹ เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ API เจคเฉฑเจ• เจชเจนเฉเฉฐเจš เจชเฉเจฐเจฆเจพเจจ เจ•เจฐเจฆเจพ เจนเฉˆเฅค เจ‡เจน เจ•เฉเจฌเจฐเจจเฉ‡เจŸเจธ เจตเจฟเฉฑเจš เจ•เฉฐเจŸเจฐเฉ‹เจฒ เจชเจฒเฉ‡เจจ เจฒเจˆ เจซเจฐเฉฐเจŸเจเจ‚เจก เจนเฉˆเฅค
  • เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ: เจ‡เฉฑเจ• เจเจœเฉฐเจŸ เจœเฉ‹ เจ•เจฒเฉฑเจธเจŸเจฐ เจตเจฟเฉฑเจš เจนเจฐ เจจเฉ‹เจก 'เจคเฉ‡ เจšเฉฑเจฒเจฆเจพ เจนเฉˆเฅค เจ‡เจน เจชเฉŒเจก เจตเจฟเฉฑเจš เจ•เฉฐเจŸเฉ‡เจจเจฐเจพเจ‚ เจฆเฉ‡ เจธเฉฐเจšเจพเจฒเจจ เจจเฉ‚เฉฐ เจฏเจ•เฉ€เจจเฉ€ เจฌเจฃเจพเจ‰เจ‚เจฆเจพ เจนเฉˆเฅค
  • เจ•เฉฐเจŸเฉ‡เจจเจฐ เจฐเจจเจŸเจพเจˆเจฎ (เจ•เฉฐเจŸเฉ‡เจจเจฐ เจฐเจจเจŸเจพเจˆเจฎ): เจ•เฉฐเจŸเฉ‡เจจเจฐเจพเจ‚ เจจเฉ‚เฉฐ เจšเจฒเจพเจ‰เจฃ เจฒเจˆ เจœเจผเจฟเฉฐเจฎเฉ‡เจตเจพเจฐ เจธเฉŒเจซเจŸเจตเฉ‡เจ…เจฐเฅค เจ‰เจฆเจพเจนเจฐเจจเจพเจ‚: เจกเฉŒเจ•เจฐ, เจธเฉ€เจ†เจฐเจ†เจˆ-เจ“, เจ•เฉฐเจŸเฉ‡เจจเจฐเจกโ€ฆ
  • เจ•เจฐเจจเจฒ: เจตเจฐเจ•เจฐ เจจเฉ‹เจก 'เจคเฉ‡ OS เจ•เจฐเจจเจฒ; เจชเฉเจฐเจ•เจฟเจฐเจฟเจ† เจชเฉเจฐเจฌเฉฐเจงเจจ เจฒเจˆ เจœเจผเจฟเฉฐเจฎเฉ‡เจตเจพเจฐ เจนเฉˆเฅค
  • เจŸเฉ€เจšเจพ (เจจเจฟเจธเจผเจพเจจเจพ) เจ•เฉฐเจŸเฉ‡เจจเจฐ: เจ‡เฉฑเจ• เจ•เฉฐเจŸเฉ‡เจจเจฐ เจœเฉ‹ เจ‡เฉฑเจ• เจชเฉ‹เจก เจฆเจพ เจนเจฟเฉฑเจธเจพ เจนเฉˆ เจ…เจคเฉ‡ เจ‡เฉฑเจ• เจตเจฐเจ•เจฐ เจจเฉ‹เจก 'เจคเฉ‡ เจšเฉฑเจฒเจฆเจพ เจนเฉˆเฅค

เจฎเฉˆเจจเฉ‚เฉฐ เจ•เฉ€ เจ–เฉ‹เจœเจฟเจ†

1. เจ•เจฒเจพเจ‡เฉฐเจŸ เจธเจพเจˆเจก เจ—เจคเฉ€เจตเจฟเจงเฉ€

เจ‡เฉฑเจ• เจจเฉ‡เจฎเจธเจชเฉ‡เจธ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจชเฉŒเจก เจฌเจฃเจพเจ“ default:

// any machine
$ kubectl run exec-test-nginx --image=nginx

เจซเจฟเจฐ เจ…เจธเฉ€เจ‚ exec เจ•เจฎเจพเจ‚เจก เจจเฉ‚เฉฐ เจšเจฒเจพเจ‰เจ‚เจฆเฉ‡ เจนเจพเจ‚ เจ…เจคเฉ‡ เจนเฉ‹เจฐ เจจเจฟเจฐเฉ€เจ–เจฃเจพเจ‚ เจฒเจˆ 5000 เจธเจ•เจฟเฉฐเจŸ เจฆเฉ€ เจ‰เจกเฉ€เจ• เจ•เจฐเจฆเฉ‡ เจนเจพเจ‚:

// any machine
$ kubectl exec -it exec-test-nginx-6558988d5-fgxgg -- sh
# sleep 5000

kubectl เจชเฉเจฐเจ•เจฟเจฐเจฟเจ† เจฆเจฟเจ–เจพเจˆ เจฆเจฟเฉฐเจฆเฉ€ เจนเฉˆ (เจธเจพเจกเฉ‡ เจ•เฉ‡เจธ เจตเจฟเฉฑเจš 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 exec เจ‰เจช เจธเจฐเฉ‹เจค เจจเจพเจฒ เจ‡เฉฑเจ• 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)

(kubectl/pkg/cmd/exec/exec.go)

kubectl exec เจ•เจฟเจตเฉ‡เจ‚ เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ?

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 เจฌเฉ‡เจจเจคเฉ€ เจตเจฟเฉฑเจš เจชเฉเจฐเฉ‹เจŸเฉ‹เจ•เฉ‹เจฒ เจจเฉ‚เฉฐ เจฌเจฆเจฒเจฃ เจฆเฉ€ เจฌเฉ‡เจจเจคเฉ€ เจธเจผเจพเจฎเจฒ เจนเฉเฉฐเจฆเฉ€ เจนเฉˆเฅค เจเจธเจชเฉ€เจกเฉ€เจตเจพเจˆ เจคเฉเจนเจพเจจเฉ‚เฉฐ เจ‡เฉฑเจ• เจธเจฟเฉฐเจ—เจฒ TCP เจ•เฉเจจเฉˆเจ•เจธเจผเจจ เจ‰เฉฑเจคเฉ‡ เจตเจฟเจ…เจ•เจคเฉ€เจ—เจค stdin/stdout/stderr/spdy-เจ—เจฒเจคเฉ€ "เจธเจŸเฉเจฐเฉ€เจฎเจพเจ‚" เจจเฉ‚เฉฐ เจฎเจฒเจŸเฉ€เจชเจฒเฉˆเจ•เจธ เจ•เจฐเจจ เจฆเฉ€ เจ‡เจœเจพเจœเจผเจค เจฆเจฟเฉฐเจฆเจพ เจนเฉˆเฅค

API เจธเจฐเจตเจฐ เจฌเฉ‡เจจเจคเฉ€ เจชเฉเจฐเจพเจชเจค เจ•เจฐเจฆเจพ เจนเฉˆ เจ…เจคเฉ‡ เจ‡เจธเจจเฉ‚เฉฐ เจตเจฟเฉฑเจš เจฌเจฆเจฒเจฆเจพ เจนเฉˆ 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
}

(pkg/apis/core/types.go)

เจฒเฉ‹เฉœเฉ€เจ‚เจฆเฉ€เจ†เจ‚ เจ•เจพเจฐเจตเจพเจˆเจ†เจ‚ เจ•เจฐเจจ เจฒเจˆ, เจเจชเฉ€เจ†เจˆ-เจธเจฐเจตเจฐ เจจเฉ‚เฉฐ เจชเจคเจพ เจนเฉ‹เจฃเจพ เจšเจพเจนเฉ€เจฆเจพ เจนเฉˆ เจ•เจฟ เจ‰เจธเจจเฉ‚เฉฐ เจ•เจฟเจธ เจชเฉ‹เจก เจจเจพเจฒ เจธเฉฐเจชเจฐเจ• เจ•เจฐเจจ เจฆเฉ€ เจฒเฉ‹เฉœ เจนเฉˆ:

// 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")
}

(pkg/registry/core/pod/strategy.go)

เจฌเฉ‡เจธเจผเฉฑเจ•, เจ…เฉฐเจคเจฎ เจฌเจฟเฉฐเจฆเฉ‚ เจฌเจพเจฐเฉ‡ เจกเฉ‡เจŸเจพ เจจเฉ‹เจก เจฌเจพเจฐเฉ‡ เจœเจพเจฃเจ•เจพเจฐเฉ€ เจคเฉ‹เจ‚ เจฒเจฟเจ† เจ—เจฟเจ† เจนเฉˆ:

        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)

(pkg/registry/core/pod/strategy.go)

เจนเฉ‚เจฐเฉ‡! เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจ•เฉ‹เจฒ เจนเฉเจฃ เจ‡เฉฑเจ• เจชเฉ‹เจฐเจŸ เจนเฉˆ (node.Status.DaemonEndpoints.KubeletEndpoint.Port), เจœเจฟเจธ เจจเจพเจฒ API เจธเจฐเจตเจฐ เจœเฉเฉœ เจธเจ•เจฆเจพ เจนเฉˆ:

// 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
}

(pkg/kubelet/client/kubelet_client.go)

เจฆเจธเจคเจพเจตเฉ‡เจœเจผ เจคเฉ‹เจ‚ เจฎเจพเจธเจŸเจฐ-เจจเฉ‹เจก เจธเฉฐเจšเจพเจฐ > เจฎเจพเจธเจŸเจฐ เจคเฉ‹เจ‚ เจ•เจฒเฉฑเจธเจŸเจฐ > เจเจชเฉ€เจธเจฐเจตเจฐ เจคเฉ‹เจ‚ เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ:

เจ‡เจน เจ•เฉเจจเฉˆเจ•เจธเจผเจจ เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจฆเฉ‡ HTTPS เจเจ‚เจกเจชเฉเจ†เจ‡เฉฐเจŸ เจจเจพเจฒ เจฌเจฃเจพเจ เจ—เจ เจนเจจเฅค เจฎเฉ‚เจฒ เจฐเฉ‚เจช เจตเจฟเฉฑเจš, apiserver เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจฆเฉ‡ เจธเจฐเจŸเฉ€เจซเจฟเจ•เฉ‡เจŸ เจฆเฉ€ เจชเฉเจธเจผเจŸเฉ€ เจจเจนเฉ€เจ‚ เจ•เจฐเจฆเจพ เจนเฉˆ, เจœเฉ‹ เจ•เจฟ เจฎเฉˆเจจ-เจ‡เจจ-เจฆเฉ€-เจฎเจฟเจกเจฒ (MITM) เจนเจฎเจฒเจฟเจ†เจ‚ เจฒเจˆ เจ•เฉเจจเฉˆเจ•เจธเจผเจจ เจจเฉ‚เฉฐ เจ•เจฎเจœเจผเฉ‹เจฐ เจฌเจฃเจพเจ‰เจ‚เจฆเจพ เจนเฉˆ เจ…เจคเฉ‡ เจ…เจธเฉเจฐเฉฑเจ–เจฟเจ…เจค เจ—เฉˆเจฐ-เจญเจฐเฉ‹เจธเฉ‡เจฏเฉ‹เจ— เจ…เจคเฉ‡/เจœเจพเจ‚ เจœเจจเจคเจ• เจจเฉˆเฉฑเจŸเจตเจฐเจ•เจพเจ‚ เจตเจฟเฉฑเจš เจ•เฉฐเจฎ เจ•เจฐเจจ เจฒเจˆเฅค

เจนเฉเจฃ API เจธเจฐเจตเจฐ เจ…เฉฐเจคเจฎ เจฌเจฟเฉฐเจฆเฉ‚ เจจเฉ‚เฉฐ เจœเจพเจฃเจฆเจพ เจนเฉˆ เจ…เจคเฉ‡ เจ•เฉเจจเฉˆเจ•เจธเจผเจจ เจธเจฅเจพเจชเจค เจ•เจฐเจฆเจพ เจนเฉˆ:

// 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
}

(pkg/registry/core/pod/rest/subresources.go)

เจ†เจ“ เจฆเฉ‡เจ–เฉ€เจ เจ•เจฟ เจฎเจพเจธเจŸเจฐ เจจเฉ‹เจก 'เจคเฉ‡ เจ•เฉ€ เจนเฉ‹ เจฐเจฟเจนเจพ เจนเฉˆเฅค

เจชเจนเจฟเจฒเจพเจ‚, เจ…เจธเฉ€เจ‚ เจตเจฐเจ•เจฐ เจจเฉ‹เจก เจฆเจพ IP เจฒเฉฑเจญเจฆเฉ‡ เจนเจพเจ‚. เจธเจพเจกเฉ‡ เจ•เฉ‡เจธ เจตเจฟเฉฑเจš เจ‡เจน 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, เจ‡เจน เจ…เจฒเฉ‹เจช เจนเฉ‹ เจœเจพเจตเฉ‡เจ—เจพ, เจ‡เจธเจฒเจˆ เจฎเฉˆเจ‚ เจœเจพเจฃเจฆเจพ เจนเจพเจ‚ เจ•เจฟ เจ•เฉเจจเฉˆเจ•เจธเจผเจจ เจเจชเฉ€เจ†เจˆ-เจธเจฐเจตเจฐ เจฆเฉเจ†เจฐเจพ เจเจ—เจœเจผเฉ€เจ•เจฟเจŠเจŸ เจ•เฉ€เจคเฉ‡ เจ—เจ 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 exec เจ•เจฟเจตเฉ‡เจ‚ เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ?

kubectl เจ…เจคเฉ‡ api-เจธเจฐเจตเจฐ เจตเจฟเจšเจ•เจพเจฐ เจ•เฉเจจเฉˆเจ•เจธเจผเจจ เจ…เจœเฉ‡ เจตเฉ€ เจ–เฉเฉฑเจฒเฉเจนเจพ เจนเฉˆเฅค เจ‡เจธ เจคเฉ‹เจ‚ เจ‡เจฒเจพเจตเจพ, เจ‡เฉฑเจ• เจนเฉ‹เจฐ เจ•เฉเจจเฉˆเจ•เจธเจผเจจ เจนเฉˆ เจœเฉ‹ เจเจชเฉ€เจ†เจˆ-เจธเจฐเจตเจฐ เจ…เจคเฉ‡ เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจจเฉ‚เฉฐ เจœเฉ‹เฉœเจฆเจพ เจนเฉˆเฅค

3. เจตเจฐเจ•เจฐ เจจเฉ‹เจก 'เจคเฉ‡ เจ—เจคเฉ€เจตเจฟเจงเฉ€

เจนเฉเจฃ เจ†เจ“ เจตเจฐเจ•เจฐ เจจเฉ‹เจก เจจเจพเจฒ เจœเฉเฉœเฉ€เจ เจ…เจคเฉ‡ เจฆเฉ‡เจ–เจฆเฉ‡ เจนเจพเจ‚ เจ•เจฟ เจ‡เจธ 'เจคเฉ‡ เจ•เฉ€ เจนเฉ‹ เจฐเจฟเจนเจพ เจนเฉˆเฅค

เจธเจญ เจคเฉ‹เจ‚ เจชเจนเจฟเจฒเจพเจ‚, เจ…เจธเฉ€เจ‚ เจฆเฉ‡เจ–เจฆเฉ‡ เจนเจพเจ‚ เจ•เจฟ เจ‡เจธ เจจเจพเจฒ เจ•เฉเจจเฉˆเจ•เจธเจผเจจ เจตเฉ€ เจธเจฅเจพเจชเจฟเจค เจนเฉˆ (เจฆเฉ‚เจœเฉ€ เจฒเจพเจˆเจจ); 192.168.205.10 เจฎเจพเจธเจŸเจฐ เจจเฉ‹เจก เจฆเจพ IP เจนเฉˆ:

 // 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
  โ€ฆ

เจชเจฐ เจ‡เฉฐเจคเจœเจผเจพเจฐ เจ•เจฐเฉ‹: เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจจเฉ‡ เจ‡เจธเจจเฉ‚เฉฐ เจ•เจฟเจตเฉ‡เจ‚ เจ–เจฟเฉฑเจšเจฟเจ†? เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจกเฉˆเจฎเจจ เจนเฉˆ เจœเฉ‹ API-เจธเจฐเจตเจฐ เจฌเฉ‡เจจเจคเฉ€เจ†เจ‚ เจฒเจˆ เจชเฉ‹เจฐเจŸ เจฐเจพเจนเฉ€เจ‚ API เจคเฉฑเจ• เจชเจนเฉเฉฐเจš เจชเฉเจฐเจฆเจพเจจ เจ•เจฐเจฆเจพ เจนเฉˆ:

// 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
}

(pkg/kubelet/server/streaming/server.go)

เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจเจ—เจœเจผเฉ€เจ•เจฟเจŠเจธเจผเจจ เจฌเฉ‡เจจเจคเฉ€เจ†เจ‚ เจฒเจˆ เจœเจตเจพเจฌ เจ…เฉฐเจคเจฎ เจฌเจฟเฉฐเจฆเฉ‚ เจฆเฉ€ เจ—เจฃเจจเจพ เจ•เจฐเจฆเจพ เจนเฉˆ:

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
}

(pkg/kubelet/server/streaming/server.go)

เจ‰เจฒเจเจฃ เจตเจฟเฉฑเจš เจจเจพ เจชเจ“เฅค เจ‡เจน เจ•เจฎเจพเจ‚เจก เจฆเจพ เจจเจคเฉ€เจœเจพ เจจเจนเฉ€เจ‚ เจฆเจฟเฉฐเจฆเจพ, เจชเจฐ เจธเฉฐเจšเจพเจฐ เจฒเจˆ เจ…เฉฐเจคเจฎ เจฌเจฟเฉฐเจฆเฉ‚:

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:"-"`
}

(cri-api/pkg/apis/runtime/v1alpha2/api.pb.go)

เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจ‡เฉฐเจŸเจฐเจซเฉ‡เจธ เจจเฉ‚เฉฐ เจฒเจพเจ—เฉ‚ เจ•เจฐเจฆเจพ เจนเฉˆ RuntimeServiceClient, เจœเฉ‹ เจ•เจฟ เจ•เฉฐเจŸเฉ‡เจจเจฐ เจฐเจจเจŸเจพเจˆเจฎ เจ‡เฉฐเจŸเจฐเจซเฉ‡เจธ เจฆเจพ เจนเจฟเฉฑเจธเจพ เจนเฉˆ (เจ…เจธเฉ€เจ‚ เจ‡เจธ เจฌเจพเจฐเฉ‡ เจนเฉ‹เจฐ เจฒเจฟเจ–เจฟเจ†, เจ‰เจฆเจพเจนเจฐเจจ เจฒเจˆ, เจ‡เฉฑเจฅเฉ‡ - เจฒเจ—เจญเจ— เจ…เจจเฉเจตเจพเจฆเฅค):

kubernetes/kubernetes เจตเจฟเฉฑเจš cri-api เจคเฉ‹เจ‚ เจฒเฉฐเจฌเฉ€ เจธเฉ‚เจšเฉ€

// 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)
}

(cri-api/pkg/apis/runtime/v1alpha2/api.pb.go)
เจ‡เจน เจ•เฉฐเจŸเฉ‡เจจเจฐ เจฐเจจเจŸเจพเจˆเจฎ เจ‡เฉฐเจŸเจฐเจซเฉ‡เจธ เจฆเฉเจ†เจฐเจพ เจ‡เฉฑเจ• เจตเจฟเจงเฉ€ เจจเฉ‚เฉฐ เจ•เจพเจฒ เจ•เจฐเจจ เจฒเจˆ เจฌเจธ gRPC เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐเจฆเจพ เจนเฉˆ:

type runtimeServiceClient struct {
        cc *grpc.ClientConn
}

(cri-api/pkg/apis/runtime/v1alpha2/api.pb.go)

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
}

(cri-api/pkg/apis/runtime/v1alpha2/api.pb.go)

เจ•เฉฐเจŸเฉ‡เจจเจฐ เจฐเจจเจŸเจพเจˆเจฎ เจฒเจพเจ—เฉ‚ เจ•เจฐเจจ เจฒเจˆ เจœเจผเจฟเฉฐเจฎเฉ‡เจตเจพเจฐ เจนเฉˆ RuntimeServiceServer:

kubernetes/kubernetes เจตเจฟเฉฑเจš cri-api เจคเฉ‹เจ‚ เจฒเฉฐเจฌเฉ€ เจธเฉ‚เจšเฉ€

// 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)
}

(cri-api/pkg/apis/runtime/v1alpha2/api.pb.go)
kubectl exec เจ•เจฟเจตเฉ‡เจ‚ เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ?

เจœเฉ‡ เจ…เจœเจฟเจนเจพ เจนเฉˆ, เจคเจพเจ‚ เจธเจพเจจเฉ‚เฉฐ เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจ…เจคเฉ‡ เจ•เฉฐเจŸเฉ‡เจจเจฐ เจฐเจจเจŸเจพเจˆเจฎ เจฆเฉ‡ เจตเจฟเจšเจ•เจพเจฐ เจ‡เฉฑเจ• เจ•เจจเฉˆเจ•เจธเจผเจจ เจฆเฉ‡เจ–เจฃเจพ เจšเจพเจนเฉ€เจฆเจพ เจนเฉˆ, เจ เฉ€เจ• เจนเฉˆ? เจฆเฉ€ เจœเจพเจ‚เจš เจ•เจฐเฉ€เจเฅค

exec เจ•เจฎเจพเจ‚เจก เจคเฉ‹เจ‚ เจชเจนเจฟเจฒเจพเจ‚ เจ…เจคเฉ‡ เจฌเจพเจ…เจฆ เจตเจฟเฉฑเจš เจ‡เจธ เจ•เจฎเจพเจ‚เจก เจจเฉ‚เฉฐ เจšเจฒเจพเจ“ เจ…เจคเฉ‡ เจ…เฉฐเจคเจฐ เจฆเฉ‡เจ–เฉ‹เฅค เจฎเฉ‡เจฐเฉ‡ เจ•เฉ‡เจธ เจตเจฟเฉฑเจš เจซเจฐเจ• เจ‡เจน เจนเฉˆ:

// worker node
$ ss -a -p |grep kubelet
...
u_str  ESTAB      0      0       * 157937                * 157387                users:(("kubelet",pid=5714,fd=33))
...

เจนเจพเจ‚... เจ‡เฉฑเจ• เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ (pid=5714) เจ…เจคเฉ‡ เจ•เฉเจ เจ…เจฃเจœเจพเจฃ เจตเจฟเจšเจ•เจพเจฐ เจฏเฉ‚เจจเจฟเจ•เจธ เจธเจพเจ•เจŸเจพเจ‚ เจฐเจพเจนเฉ€เจ‚ เจ‡เฉฑเจ• เจจเจตเจพเจ‚ เจ•เฉเจจเฉˆเจ•เจธเจผเจจเฅค เจ‡เจน เจ•เฉ€ เจนเฉ‹ เจธเจ•เจฆเจพ เจนเฉˆ? เจ‡เจน เจธเจนเฉ€ เจนเฉˆ, เจ‡เจน เจกเฉŒเจ•เจฐ เจนเฉˆ (pid=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. เจ•เฉฐเจŸเฉ‡เจจเจฐ เจฐเจจเจŸเจพเจˆเจฎ เจตเจฟเฉฑเจš เจ—เจคเฉ€เจตเจฟเจงเฉ€

เจ†เจ‰ เจ‡เจน เจธเจฎเจเจฃ เจฒเจˆ CRI-O เจธเจฐเฉ‹เจค เจ•เฉ‹เจก เจฆเฉ€ เจœเจพเจ‚เจš เจ•เจฐเฉ€เจ เจ•เจฟ เจ•เฉ€ เจนเฉ‹ เจฐเจฟเจนเจพ เจนเฉˆเฅค เจกเฉŒเจ•เจฐ เจตเจฟเฉฑเจš เจคเจฐเจ• เจธเจฎเจพเจจ เจนเฉˆ.

เจฒเจพเจ—เฉ‚ เจ•เจฐเจจ เจฒเจˆ เจ‡เฉฑเจ• เจธเจฐเจตเจฐ เจœเจผเจฟเฉฐเจฎเฉ‡เจตเจพเจฐ เจนเฉˆ 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
}

(cri-o/server/server.go)

// 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
}

(cri-o/erver/container_exec.go)

เจšเฉ‡เจจ เจฆเฉ‡ เจ…เฉฐเจค 'เจคเฉ‡, เจ•เฉฐเจŸเฉ‡เจจเจฐ เจฐเจจเจŸเจพเจˆเจฎ เจตเจฐเจ•เจฐ เจจเฉ‹เจก 'เจคเฉ‡ เจ•เจฎเจพเจ‚เจก เจจเฉ‚เฉฐ เจšเจฒเจพเจ‰เจ‚เจฆเจพ เจนเฉˆ:

// 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
}

(cri-o/internal/oci/runtime_oci.go)

kubectl exec เจ•เจฟเจตเฉ‡เจ‚ เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ?

เจ…เฉฐเจค เจตเจฟเฉฑเจš, เจ•เจฐเจจเจฒ เจ•เจฎเจพเจ‚เจกเจพเจ‚ เจจเฉ‚เฉฐ เจšเจฒเจพเจ‰เจ‚เจฆเจพ เจนเฉˆ:

kubectl exec เจ•เจฟเจตเฉ‡เจ‚ เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ?

เจฐเฉ€เจฎเจพเจˆเจ‚เจกเจฐ

  • API เจธเจฐเจตเจฐ เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจจเจพเจฒ เจ•เฉเจจเฉˆเจ•เจธเจผเจจ เจตเฉ€ เจธเจผเฉเจฐเฉ‚ เจ•เจฐ เจธเจ•เจฆเจพ เจนเฉˆเฅค
  • เจนเฉ‡เจ เจพเจ‚ เจฆเจฟเฉฑเจคเฉ‡ เจ•เจจเฉˆเจ•เจธเจผเจจ เจ‰เจฆเฉ‹เจ‚ เจคเฉฑเจ• เจœเจพเจฐเฉ€ เจฐเจนเจฟเฉฐเจฆเฉ‡ เจนเจจ เจœเจฆเฉ‹เจ‚ เจคเฉฑเจ• เจ‡เฉฐเจŸเจฐเจเจ•เจŸเจฟเจต เจเจ—เจœเจผเฉ€เจ•เจฟเจŠเจธเจผเจจ เจธเฉˆเจธเจผเจจ เจ–เจคเจฎ เจจเจนเฉ€เจ‚ เจนเฉเฉฐเจฆเจพ:
    • kubectl เจ…เจคเฉ‡ api-เจธเจฐเจตเจฐ เจตเจฟเจšเจ•เจพเจฐ;
    • api-เจธเจฐเจตเจฐ เจ…เจคเฉ‡ kubectl เจตเจฟเจšเจ•เจพเจฐ;
    • เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจ…เจคเฉ‡ เจ•เฉฐเจŸเฉ‡เจจเจฐ เจฐเจจเจŸเจพเจˆเจฎ เจฆเฉ‡ เจตเจฟเจšเจ•เจพเจฐเฅค
  • เจ•เจฟเจŠเจฌเฉˆเจ•เจŸเจฒ เจœเจพเจ‚ เจเจชเฉ€เจ†เจˆ-เจธเจฐเจตเจฐ เจตเจฐเจ•เจฐ เจจเฉ‹เจกเจพเจ‚ 'เจคเฉ‡ เจ•เฉเจ เจตเฉ€ เจจเจนเฉ€เจ‚ เจšเจฒเจพ เจธเจ•เจฆเจพ เจนเฉˆเฅค เจ•เฉเจฌเฉ‡เจฒเฉ‡เจŸ เจšเฉฑเจฒ เจธเจ•เจฆเจพ เจนเฉˆ, เจชเจฐ เจ‡เจน เจ‰เจนเจจเจพเจ‚ เจšเฉ€เจœเจผเจพเจ‚ เจจเฉ‚เฉฐ เจ•เจฐเจจ เจฒเจˆ เจ•เฉฐเจŸเฉ‡เจจเจฐ เจฐเจจเจŸเจพเจˆเจฎ เจจเจพเจฒ เจตเฉ€ เจ‡เฉฐเจŸเจฐเฉˆเจ•เจŸ เจ•เจฐเจฆเจพ เจนเฉˆเฅค

เจธเจฐเฉ‹เจค

เจ…เจจเฉเจตเจพเจฆเจ• เจคเฉ‹เจ‚ เจชเฉ€.เจเจธ

เจธเจพเจกเฉ‡ เจฌเจฒเฉŒเจ— 'เจคเฉ‡ เจตเฉ€ เจชเฉœเฉเจนเฉ‹:

เจธเจฐเฉ‹เจค: www.habr.com

เจ‡เฉฑเจ• เจŸเจฟเฉฑเจชเจฃเฉ€ เจœเฉ‹เฉœเฉ‹