āĻ•āĻŋāĻ­āĻžāĻŦā§‡ kubectl exec āĻ•āĻžāĻœ āĻ•āĻ°ā§‡?

āĻŦāĻŋāĻƒāĻĻā§āĻ°āĻƒ. āĻ…āĻ¨ā§āĻŦāĻžāĻĻ: āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§ā§‡āĻ° āĻ˛ā§‡āĻ–āĻ• - āĻāĻ°āĻ•āĻžāĻ¨ āĻāĻ°ā§‹āĻ˛, āĻāĻ¸āĻāĻĒāĻŋ-āĻāĻ° āĻāĻ•āĻœāĻ¨ āĻĒā§āĻ°āĻ•ā§ŒāĻļāĻ˛ā§€ - āĻĻāĻ˛ā§‡āĻ° āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻžāĻ°āĻŋāĻ¤āĻžāĻ° āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ¤āĻžāĻ° āĻ…āĻ§ā§āĻ¯āĻ¯āĻŧāĻ¨ āĻļā§‡āĻ¯āĻŧāĻžāĻ° āĻ•āĻ°ā§‡āĻ›ā§‡āĻ¨ kubectl exec, āĻ•ā§āĻŦāĻžāĻ°āĻ¨ā§‡āĻŸāĻ¸ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ•āĻžāĻœ āĻ•āĻ°ā§‡ āĻāĻŽāĻ¨ āĻĒā§āĻ°āĻ¤ā§āĻ¯ā§‡āĻ•ā§‡āĻ° āĻ•āĻžāĻ›ā§‡ āĻ–ā§āĻŦ āĻĒāĻ°āĻŋāĻšāĻŋāĻ¤āĨ¤ āĻ¤āĻŋāĻ¨āĻŋ Kubernetes āĻ¸ā§‹āĻ°ā§āĻ¸ āĻ•ā§‹āĻĄ (āĻāĻŦāĻ‚ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•āĻŋāĻ¤ āĻĒā§āĻ°āĻ•āĻ˛ā§āĻĒ) āĻāĻ° āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻ¸āĻš āĻ¸āĻŽāĻ—ā§āĻ° āĻ…ā§āĻ¯āĻžāĻ˛āĻ—āĻ°āĻŋāĻĻāĻŽ āĻ¸āĻšāĻ¯āĻžāĻ¨, āĻ¯āĻž āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧ āĻŦāĻŋāĻˇāĻ¯āĻŧā§‡āĻ° āĻ—āĻ­ā§€āĻ°āĻ­āĻžāĻŦā§‡ āĻŦā§āĻāĻ¤ā§‡ āĻĻā§‡āĻ¯āĻŧāĨ¤

āĻ•āĻŋāĻ­āĻžāĻŦā§‡ kubectl exec āĻ•āĻžāĻœ āĻ•āĻ°ā§‡?

āĻāĻ• āĻļā§āĻ•ā§āĻ°āĻŦāĻžāĻ°, āĻāĻ•āĻœāĻ¨ āĻ¸āĻšāĻ•āĻ°ā§āĻŽā§€ āĻ†āĻŽāĻžāĻ° āĻ•āĻžāĻ›ā§‡ āĻāĻ¸ā§‡ āĻœāĻŋāĻœā§āĻžāĻžāĻ¸āĻž āĻ•āĻ°āĻ˛ā§‡āĻ¨ āĻ•ā§€āĻ­āĻžāĻŦā§‡ āĻāĻ•āĻŸāĻŋ āĻĒāĻĄ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻāĻ•āĻŸāĻŋ āĻ•āĻŽāĻžāĻ¨ā§āĻĄ āĻšāĻžāĻ˛āĻžāĻ¨ā§‹ āĻ¯āĻžāĻ¯āĻŧ āĻ•ā§āĻ˛āĻžāĻ¯āĻŧā§‡āĻ¨ā§āĻŸ-āĻ—ā§‹. āĻ†āĻŽāĻŋ āĻ¤āĻžāĻ•ā§‡ āĻ‰āĻ¤ā§āĻ¤āĻ° āĻĻāĻŋāĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋāĻ¨āĻŋ āĻāĻŦāĻ‚ āĻšāĻ āĻžā§Ž āĻŦā§āĻāĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋ āĻ¯ā§‡ āĻ†āĻŽāĻŋ āĻ…āĻĒāĻžāĻ°ā§‡āĻļāĻ¨ā§‡āĻ° āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ•āĻŋāĻ›ā§āĻ‡ āĻœāĻžāĻ¨āĻŋ āĻ¨āĻž kubectl exec. āĻšā§āĻ¯āĻžāĻ, āĻāĻ° āĻ—āĻ āĻ¨ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ†āĻŽāĻžāĻ° āĻ•āĻŋāĻ›ā§ āĻ§āĻžāĻ°āĻŖāĻž āĻ›āĻŋāĻ˛, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻ†āĻŽāĻŋ āĻ¤āĻžāĻĻā§‡āĻ° āĻ¸āĻ āĻŋāĻ•āĻ¤āĻž āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ 100% āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻ¨āĻ‡ āĻāĻŦāĻ‚ āĻ¤āĻžāĻ‡ āĻāĻ‡ āĻ¸āĻŽāĻ¸ā§āĻ¯āĻžāĻŸāĻŋ āĻŽā§‹āĻ•āĻžāĻŦā§‡āĻ˛āĻž āĻ•āĻ°āĻžāĻ° āĻ¸āĻŋāĻĻā§āĻ§āĻžāĻ¨ā§āĻ¤ āĻ¨āĻŋāĻ¯āĻŧā§‡āĻ›āĻŋāĨ¤ āĻŦā§āĻ˛āĻ—, āĻĄāĻ•ā§āĻŽā§‡āĻ¨ā§āĻŸā§‡āĻļāĻ¨ āĻāĻŦāĻ‚ āĻ¸ā§‹āĻ°ā§āĻ¸ āĻ•ā§‹āĻĄ āĻ…āĻ§ā§āĻ¯āĻ¯āĻŧāĻ¨ āĻ•āĻ°āĻžāĻ° āĻĒāĻ°ā§‡, āĻ†āĻŽāĻŋ āĻ…āĻ¨ā§‡āĻ• āĻ¨āĻ¤ā§āĻ¨ āĻœāĻŋāĻ¨āĻŋāĻ¸ āĻļāĻŋāĻ–ā§‡āĻ›āĻŋ, āĻāĻŦāĻ‚ āĻāĻ‡ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§ā§‡ āĻ†āĻŽāĻŋ āĻ†āĻŽāĻžāĻ° āĻ†āĻŦāĻŋāĻˇā§āĻ•āĻžāĻ° āĻāĻŦāĻ‚ āĻŦā§‹āĻāĻžāĻ° āĻ­āĻžāĻ— āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ‡āĨ¤ āĻ•āĻŋāĻ›ā§ āĻ­ā§āĻ˛ āĻšāĻ˛ā§‡, āĻ†āĻŽāĻžāĻ° āĻ¸āĻžāĻĨā§‡ āĻ¯ā§‹āĻ—āĻžāĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨ Twitter.

āĻĒā§āĻ°āĻļāĻŋāĻ•ā§āĻˇāĻŖ

āĻāĻ•āĻŸāĻŋ āĻŽā§āĻ¯āĻžāĻ•āĻŦā§āĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻ•ā§āĻ˛āĻžāĻ¸ā§āĻŸāĻžāĻ° āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻ¤ā§‡, āĻ†āĻŽāĻŋ āĻ•ā§āĻ˛ā§‹āĻ¨ āĻ•āĻ°ā§‡āĻ›āĻŋ ecomm-integration-ballerina/kubernetes-cluster. āĻ¤āĻžāĻ°āĻĒāĻ°ā§‡ āĻ†āĻŽāĻŋ āĻ•ā§āĻŦā§‡āĻ˛ā§‡āĻŸ āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨ā§‡ āĻ¨ā§‹āĻĄāĻ—ā§āĻ˛āĻŋāĻ° āĻ†āĻ‡āĻĒāĻŋ āĻ āĻŋāĻ•āĻžāĻ¨āĻžāĻ—ā§āĻ˛āĻŋ āĻ¸āĻ‚āĻļā§‹āĻ§āĻ¨ āĻ•āĻ°ā§‡āĻ›āĻŋ, āĻ¯ā§‡āĻšā§‡āĻ¤ā§ āĻĄāĻŋāĻĢāĻ˛ā§āĻŸ āĻ¸ā§‡āĻŸāĻŋāĻ‚āĻ¸ āĻ…āĻ¨ā§āĻŽāĻ¤āĻŋ āĻĻā§‡āĻ¯āĻŧ āĻ¨āĻž kubectl exec. āĻ†āĻĒāĻ¨āĻŋ āĻāĻ° āĻĒā§āĻ°āĻ§āĻžāĻ¨ āĻ•āĻžāĻ°āĻŖ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ†āĻ°āĻ“ āĻĒāĻĄāĻŧāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ āĻāĻ–āĻžāĻ¨ā§‡.

  • āĻ¯ā§‡āĻ•ā§‹āĻ¨ā§‹ āĻ—āĻžāĻĄāĻŧāĻŋ = āĻ†āĻŽāĻžāĻ° āĻŽā§āĻ¯āĻžāĻ•āĻŦā§āĻ•
  • āĻŽāĻžāĻ¸ā§āĻŸāĻžāĻ° āĻ¨ā§‹āĻĄ āĻ†āĻ‡āĻĒāĻŋ = 192.168.205.10
  • āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻ•āĻžāĻ° āĻ¨ā§‹āĻĄ āĻ†āĻ‡āĻĒāĻŋ = 192.168.205.11
  • API āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ° āĻĒā§‹āĻ°ā§āĻŸ = 6443

āĻ‰āĻĒāĻžāĻĻāĻžāĻ¨

āĻ•āĻŋāĻ­āĻžāĻŦā§‡ kubectl exec āĻ•āĻžāĻœ āĻ•āĻ°ā§‡?

  • kubectl exec āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž: āĻ¯āĻ–āĻ¨ āĻ†āĻŽāĻ°āĻž "kubectl exec..." āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ•āĻ°āĻŋ āĻ¤āĻ–āĻ¨ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻŸāĻŋ āĻļā§āĻ°ā§ āĻšāĻ¯āĻŧāĨ¤ āĻāĻŸāĻŋ K8s API āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ¸āĻš āĻ¯ā§‡āĻ•ā§‹āĻ¨ā§‹ āĻŽā§‡āĻļāĻŋāĻ¨ā§‡ āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤ āĻŦāĻŋāĻƒāĻĻā§āĻ°āĻƒ āĻ…āĻ¨ā§āĻŦāĻžāĻĻ: āĻ†āĻ°āĻ“ āĻ•āĻ¨āĻ¸ā§‹āĻ˛ āĻ¤āĻžāĻ˛āĻŋāĻ•āĻžāĻ¯āĻŧ, āĻ˛ā§‡āĻ–āĻ• "āĻ¯ā§‡āĻ•ā§‹āĻ¨ āĻŽā§‡āĻļāĻŋāĻ¨" āĻŽāĻ¨ā§āĻ¤āĻŦā§āĻ¯ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡āĻ¨, āĻ¯āĻž āĻŦā§‹āĻāĻžāĻ¯āĻŧ āĻ¯ā§‡ āĻĒāĻ°āĻŦāĻ°ā§āĻ¤ā§€ āĻ•āĻŽāĻžāĻ¨ā§āĻĄāĻ—ā§āĻ˛āĻŋ āĻ•ā§āĻŦāĻžāĻ°āĻ¨ā§‡āĻŸā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ¸āĻš āĻāĻ‡ āĻœāĻžāĻ¤ā§€āĻ¯āĻŧ āĻ¯ā§‡ āĻ•ā§‹āĻ¨āĻ“ āĻŽā§‡āĻļāĻŋāĻ¨ā§‡ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤
  • āĻāĻĒāĻŋāĻ†āĻ‡ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°: āĻŽāĻžāĻ¸ā§āĻŸāĻžāĻ° āĻ¨ā§‹āĻĄā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻ‰āĻĒāĻžāĻĻāĻžāĻ¨ āĻ¯āĻž Kubernetes API-āĻ¤ā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻ•āĻ°ā§‡āĨ¤ āĻāĻŸāĻŋ Kubernetes āĻ āĻ•āĻ¨ā§āĻŸā§āĻ°ā§‹āĻ˛ āĻĒā§āĻ˛ā§‡āĻ¨ā§‡āĻ° āĻĢā§āĻ°āĻ¨ā§āĻŸāĻāĻ¨ā§āĻĄāĨ¤
  • āĻ•ā§āĻŦāĻ˛ā§‡āĻŸ: āĻāĻ•āĻŸāĻŋ āĻāĻœā§‡āĻ¨ā§āĻŸ āĻ¯āĻž āĻ•ā§āĻ˛āĻžāĻ¸ā§āĻŸāĻžāĻ°ā§‡āĻ° āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻ¨ā§‹āĻĄā§‡ āĻšāĻ˛ā§‡āĨ¤ āĻāĻŸāĻŋ āĻĒāĻĄā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻĒāĻžāĻ¤ā§āĻ°ā§‡āĻ° āĻ…āĻĒāĻžāĻ°ā§‡āĻļāĻ¨ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻ•āĻ°ā§‡āĨ¤
  • āĻ§āĻžāĻ°āĻ• āĻ°āĻžāĻ¨āĻŸāĻžāĻ‡āĻŽ (āĻ•āĻ¨ā§āĻŸā§‡āĻ‡āĻ¨āĻžāĻ° āĻ°āĻžāĻ¨āĻŸāĻžāĻ‡āĻŽ): āĻ•āĻ¨ā§āĻŸā§‡āĻ‡āĻ¨āĻžāĻ° āĻšāĻžāĻ˛āĻžāĻ¨ā§‹āĻ° āĻœāĻ¨ā§āĻ¯ āĻĻāĻžāĻ¯āĻŧā§€ āĻ¸āĻĢā§āĻŸāĻ“āĻ¯āĻŧā§āĻ¯āĻžāĻ°āĨ¤ āĻ‰āĻĻāĻžāĻšāĻ°āĻŖ: āĻĄāĻ•āĻžāĻ°, āĻ¸āĻŋāĻ†āĻ°āĻ†āĻ‡-āĻ“, āĻ•āĻ¨ā§āĻŸā§‡āĻ‡āĻ¨āĻžāĻ°āĻĄâ€Ļ
  • āĻļāĻžāĻāĻ¸: āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻ•āĻžāĻ° āĻ¨ā§‹āĻĄā§‡ āĻ“āĻāĻ¸ āĻ•āĻžāĻ°ā§āĻ¨ā§‡āĻ˛; āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻ¨āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻĻāĻžāĻ¯āĻŧā§€āĨ¤
  • āĻ˛āĻ•ā§āĻˇā§āĻ¯ (āĻ˛āĻ•ā§āĻˇā§āĻ¯) āĻ†āĻ§āĻžāĻ°: āĻāĻ•āĻŸāĻŋ āĻ§āĻžāĻ°āĻ• āĻ¯āĻž āĻāĻ•āĻŸāĻŋ āĻĒāĻĄā§‡āĻ° āĻ…āĻ‚āĻļ āĻāĻŦāĻ‚ āĻ•āĻ°ā§āĻŽā§€ āĻ¨ā§‹āĻĄāĻ—ā§āĻ˛āĻŋāĻ° āĻāĻ•āĻŸāĻŋāĻ¤ā§‡ āĻšāĻ˛ā§‡āĨ¤

āĻ¯āĻž āĻ†āĻŦāĻŋāĻˇā§āĻ•āĻžāĻ° āĻ•āĻ°āĻ˛āĻžāĻŽ

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

āĻ¯āĻĻāĻŋ āĻ†āĻŽāĻ°āĻž āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻŸāĻŋāĻ° āĻ¨ā§‡āĻŸāĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻ• āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ˛āĻžāĻĒ āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻž āĻ•āĻ°āĻŋ, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻ†āĻŽāĻ°āĻž āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻŦ āĻ¯ā§‡ āĻāĻŸāĻŋāĻ° api-āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡ (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 āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ā§‡ āĻĒā§āĻ°ā§‹āĻŸā§‹āĻ•āĻ˛ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻžāĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ…āĻ¨ā§āĻ¤āĻ°ā§āĻ­ā§āĻ•ā§āĻ¤ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤ -āĻ SPDY āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻāĻ•āĻ• 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)

āĻšāĻ˛ā§āĻ¨ āĻĻā§‡āĻ–āĻŋ āĻŽāĻžāĻ¸ā§āĻŸāĻžāĻ° āĻ¨ā§‹āĻĄā§‡ āĻ•āĻŋ āĻ˜āĻŸāĻ›ā§‡āĨ¤

āĻĒā§āĻ°āĻĨāĻŽāĻ¤, āĻ†āĻŽāĻ°āĻž āĻ•āĻ°ā§āĻŽā§€ āĻ¨ā§‹āĻĄā§‡āĻ° āĻ†āĻ‡āĻĒāĻŋ āĻ–ā§āĻāĻœā§‡ āĻŦā§‡āĻ° āĻ•āĻ°āĻŋāĨ¤ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡ āĻāĻŸāĻŋ 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 āĻ•āĻŽāĻžāĻ¨ā§āĻĄ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ•āĻ°āĻžāĻ° āĻĢāĻ˛ā§‡ āĻ¸āĻ‚āĻ¯ā§‹āĻ—āĻŸāĻŋ api-āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ° āĻĻā§āĻŦāĻžāĻ°āĻž āĻĒā§āĻ°āĻ¤āĻŋāĻˇā§āĻ āĻŋāĻ¤ āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛āĨ¤

// 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-āĻ¤ā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻ•āĻ°ā§‡:

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

āĻ•ā§āĻŦā§‡āĻ˛ā§‡āĻŸ exec āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻļā§‡āĻˇ āĻĒāĻ¯āĻŧā§‡āĻ¨ā§āĻŸ āĻ—āĻŖāĻ¨āĻž āĻ•āĻ°ā§‡:

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))
...

āĻšā§āĻŽ... āĻāĻ•āĻŸāĻŋ āĻ•ā§āĻŦā§‡āĻ˛ā§‡āĻŸ (āĻĒāĻŋāĻĄ=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 āĻ•āĻžāĻœ āĻ•āĻ°ā§‡?

āĻ¨āĻžāĻŽ

  • āĻāĻĒāĻŋāĻ†āĻ‡ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°āĻ“ āĻ•ā§āĻŦā§‡āĻ˛ā§‡āĻŸā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻāĻ•āĻŸāĻŋ āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻļā§āĻ°ā§ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤
  • āĻ‡āĻ¨ā§āĻŸāĻžāĻ°ā§‡āĻ•ā§āĻŸāĻŋāĻ­ āĻāĻ•ā§āĻ¸āĻŋāĻ• āĻ¸ā§‡āĻļāĻ¨ āĻļā§‡āĻˇ āĻ¨āĻž āĻšāĻ“āĻ¯āĻŧāĻž āĻĒāĻ°ā§āĻ¯āĻ¨ā§āĻ¤ āĻ¨āĻŋāĻŽā§āĻ¨āĻ˛āĻŋāĻ–āĻŋāĻ¤ āĻ¸āĻ‚āĻ¯ā§‹āĻ—āĻ—ā§āĻ˛āĻŋ āĻŸāĻŋāĻ•ā§‡ āĻĨāĻžāĻ•ā§‡:
    • kubectl āĻāĻŦāĻ‚ api-āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡;
    • api-server āĻāĻŦāĻ‚ kubectl āĻāĻ° āĻŽāĻ§ā§āĻ¯ā§‡;
    • āĻ•ā§āĻŦā§‡āĻ˛ā§‡āĻŸ āĻāĻŦāĻ‚ āĻ•āĻ¨ā§āĻŸā§‡āĻ‡āĻ¨āĻžāĻ° āĻ°āĻžāĻ¨āĻŸāĻžāĻ‡āĻŽā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡āĨ¤
  • Kubectl āĻŦāĻž api-āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ° āĻ•āĻ°ā§āĻŽā§€ āĻ¨ā§‹āĻĄāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻ•āĻŋāĻ›ā§ āĻšāĻžāĻ˛āĻžāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ āĻ¨āĻžāĨ¤ āĻ•ā§āĻŦā§‡āĻ˛ā§‡āĻŸ āĻšāĻžāĻ˛āĻžāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡, āĻ¤āĻŦā§‡ āĻāĻŸāĻŋ āĻ¸ā§‡āĻ‡ āĻœāĻŋāĻ¨āĻŋāĻ¸āĻ—ā§āĻ˛āĻŋ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ•āĻ¨ā§āĻŸā§‡āĻ‡āĻ¨āĻžāĻ° āĻ°āĻžāĻ¨āĻŸāĻžāĻ‡āĻŽā§‡āĻ° āĻ¸āĻžāĻĨā§‡āĻ“ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻ…ā§āĻ¯āĻžāĻ•ā§āĻŸ āĻ•āĻ°ā§‡āĨ¤

āĻ¸āĻŽā§āĻĒāĻĻ

āĻ…āĻ¨ā§āĻŦāĻžāĻĻāĻ• āĻĨā§‡āĻ•ā§‡ PS

āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻŦā§āĻ˛āĻ—ā§‡āĻ“ āĻĒāĻĄāĻŧā§āĻ¨:

āĻ‰āĻ¤ā§āĻ¸: www.habr.com

āĻāĻ•āĻŸāĻŋ āĻŽāĻ¨ā§āĻ¤āĻŦā§āĻ¯ āĻœā§āĻĄāĻŧā§āĻ¨