欢迎关注我的公众号:
目前刚开始写一个月,一共写了18篇原创文章,文章目录如下:
istio防故障利器,你知道几个,istio新手不要读,太难!
不懂envoyfilter也敢说精通istio系列-http-rbac-不要只会用AuthorizationPolicy配置权限
不懂envoyfilter也敢说精通istio系列-02-http-corsFilter-不要只会vs
不懂envoyfilter也敢说精通istio系列-03-http-csrf filter-再也不用再代码里写csrf逻辑了
不懂envoyfilter也敢说精通istio系列http-jwt_authn-不要只会RequestAuthorization
不懂envoyfilter也敢说精通istio系列-05-fault-filter-故障注入不止是vs
不懂envoyfilter也敢说精通istio系列-06-http-match-配置路由不只是vs
不懂envoyfilter也敢说精通istio系列-07-负载均衡配置不止是dr
不懂envoyfilter也敢说精通istio系列-08-连接池和断路器
不懂envoyfilter也敢说精通istio系列-09-http-route filter
不懂envoyfilter也敢说精通istio系列-network filter-redis proxy
不懂envoyfilter也敢说精通istio系列-network filter-HttpConnectionManager
不懂envoyfilter也敢说精通istio系列-ratelimit-istio ratelimit完全手册
————————————————
type AttachOptions struct {//attach结构体
exec.StreamOptions
// whether to disable use of standard error when streaming output from tty
DisableStderr bool
CommandName string
ParentCommandName string
EnableSuggestedCmdUsage bool
Pod *corev1.Pod
AttachFunc func(*AttachOptions, *corev1.Container, bool, remotecommand.TerminalSizeQueue) func() error
Resources []string
Builder func() *resource.Builder
AttachablePodFn polymorphichelpers.AttachablePodForObjectFunc
restClientGetter genericclioptions.RESTClientGetter
Attach RemoteAttach
GetPodTimeout time.Duration
Config *restclient.Config
}
func NewAttachOptions(streams genericclioptions.IOStreams) *AttachOptions {
return &AttachOptions{//初始化结构体
StreamOptions: exec.StreamOptions{
IOStreams: streams,
},
Attach: &DefaultRemoteAttach{},
AttachFunc: DefaultAttachFunc,
}
}
//创建attach命令
func NewCmdAttach(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := NewAttachOptions(streams)//初始化结构体
cmd := &cobra.Command{//创建cobra命令
Use: "attach (POD | TYPE/NAME) -c CONTAINER",
DisableFlagsInUseLine: true,
Short: i18n.T("Attach to a running container"),
Long: "Attach to a process that is already running inside an existing container.",
Example: attachExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))//准备
cmdutil.CheckErr(o.Validate())//校验
cmdutil.CheckErr(o.Run())//运行
},
}
cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodAttachTimeout)//pod-running-timeout选项
cmd.Flags().StringVarP(&o.ContainerName, "container", "c", o.ContainerName, "Container name. If omitted, the first container in the pod will be chosen")//container选项
cmd.Flags().BoolVarP(&o.Stdin, "stdin", "i", o.Stdin, "Pass stdin to the container")//stdin选项
cmd.Flags().BoolVarP(&o.TTY, "tty", "t", o.TTY, "Stdin is a TTY")//tty选项
return cmd
}
//准备
func (o *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()//设置namespace
if err != nil {
return err
}
o.AttachablePodFn = polymorphichelpers.AttachablePodForObjectFn//设置AttachablePodFn函数
o.GetPodTimeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd)//设置pod-running-timeout
if err != nil {
return cmdutil.UsageErrorf(cmd, err.Error())
}
o.Builder = f.NewBuilder//设置builder
o.Resources = args//设置resource
o.restClientGetter = f//设置restclientgetter
cmdParent := cmd.Parent()//获取父命令
if cmdParent != nil {
o.ParentCommandName = cmdParent.CommandPath()//设置父命令名称
}
if len(o.ParentCommandName) > 0 && cmdutil.IsSiblingCommandExists(cmd, "describe") {
o.EnableSuggestedCmdUsage = true//设置启用提示信息
}
config, err := f.ToRESTConfig()//获取restconfig
if err != nil {
return err
}
o.Config = config//设置restconfig
if o.CommandName == "" {
o.CommandName = cmd.CommandPath()//设置命令名称
}
return nil
}
//校验
func (o *AttachOptions) Validate() error {
if len(o.Resources) == 0 {//如果资源名称为空则拨错
return fmt.Errorf("at least 1 argument is required for attach")
}
if len(o.Resources) > 2 {//如果资源大于2个则报错
return fmt.Errorf("expected POD, TYPE/NAME, or TYPE NAME, (at most 2 arguments) saw %d: %v", len(o.Resources), o.Resources)
}
if o.GetPodTimeout <= 0 {//pod-running-timeout不能小于0
return fmt.Errorf("--pod-running-timeout must be higher than zero")
}
return nil
}
//运行
func (o *AttachOptions) Run() error {
if o.Pod == nil {
b := o.Builder().
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
NamespaceParam(o.Namespace).DefaultNamespace()//构造result对象
switch len(o.Resources) {
case 1:
b.ResourceNames("pods", o.Resources[0])
case 2:
b.ResourceNames(o.Resources[0], o.Resources[1])
}
obj, err := b.Do().Object()//获取object
if err != nil {
return err
}
o.Pod, err = o.findAttachablePod(obj)//找到pod
if err != nil {
return err
}
if o.Pod.Status.Phase == corev1.PodSucceeded || o.Pod.Status.Phase == corev1.PodFailed {//判断pod是否可attach
return fmt.Errorf("cannot attach a container in a completed pod; current phase is %s", o.Pod.Status.Phase)
}
// TODO: convert this to a clean "wait" behavior
}
// check for TTY
containerToAttach, err := o.containerToAttachTo(o.Pod)//获取可attach容器
if err != nil {
return fmt.Errorf("cannot attach to the container: %v", err)
}
if o.TTY && !containerToAttach.TTY {//如果容器不支持tty,则tty改为false
o.TTY = false
if o.ErrOut != nil {
fmt.Fprintf(o.ErrOut, "Unable to use a TTY - container %s did not allocate one\n", containerToAttach.Name)
}
} else if !o.TTY && containerToAttach.TTY {// 如果tty为fales容器支持tty,则tty改为true
// the container was launched with a TTY, so we have to force a TTY here, otherwise you'll get
// an error "Unrecognized input header"
o.TTY = true
}
// ensure we can recover the terminal while attached
t := o.SetupTTY()//设置tty
var sizeQueue remotecommand.TerminalSizeQueue
if t.Raw {
if size := t.GetSize(); size != nil {
// fake resizing +1 and then back to normal so that attach-detach-reattach will result in the
// screen being redrawn
sizePlusOne := *size
sizePlusOne.Width++
sizePlusOne.Height++
// this call spawns a goroutine to monitor/update the terminal size
sizeQueue = t.MonitorSize(&sizePlusOne, size)
}
o.DisableStderr = true
}
if !o.Quiet {//如果quiet为false,则输出提示
fmt.Fprintln(o.ErrOut, "If you don't see a command prompt, try pressing enter.")
}
if err := t.Safe(o.AttachFunc(o, containerToAttach, t.Raw, sizeQueue)); err != nil {//执行attach
return err
}
if o.Stdin && t.Raw && o.Pod.Spec.RestartPolicy == corev1.RestartPolicyAlways {//session结束,提示信息
fmt.Fprintf(o.Out, "Session ended, resume using '%s %s -c %s -i -t' command when the pod is running\n", o.CommandName, o.Pod.Name, containerToAttach.Name)
}
return nil
}
//找到可attach的pod
func (o *AttachOptions) findAttachablePod(obj runtime.Object) (*corev1.Pod, error) {
attachablePod, err := o.AttachablePodFn(o.restClientGetter, obj, o.GetPodTimeout)//查找可attach的pod
if err != nil {
return nil, err
}
o.StreamOptions.PodName = attachablePod.Name//设置StreamOptions名称
return attachablePod, nil// 返回pod
}
//查找可attach的pod
func attachablePodForObject(restClientGetter genericclioptions.RESTClientGetter, object runtime.Object, timeout time.Duration) (*corev1.Pod, error) {
switch t := object.(type) {//如果object为pod直接返回
case *corev1.Pod:
return t, nil
}
clientConfig, err := restClientGetter.ToRESTConfig()//获取restconfig
if err != nil {
return nil, err
}
clientset, err := corev1client.NewForConfig(clientConfig)//通过restconfig获取clientset
if err != nil {
return nil, err
}
namespace, selector, err := SelectorsForObject(object)//获取namespace和selector
if err != nil {
return nil, fmt.Errorf("cannot attach to %T: %v", object, err)
}
sortBy := func(pods []*corev1.Pod) sort.Interface { return sort.Reverse(podutils.ActivePods(pods)) }//排序函数
pod, _, err := GetFirstPod(clientset, namespace, selector.String(), timeout, sortBy)//获取第一个pod
return pod, err//返回pod
}
//获取attach的container
func (o *AttachOptions) containerToAttachTo(pod *corev1.Pod) (*corev1.Container, error) {
if len(o.ContainerName) > 0 {//如果指定了--container
for i := range pod.Spec.Containers {//遍历pod的containers,判断名称是否相同
if pod.Spec.Containers[i].Name == o.ContainerName {
return &pod.Spec.Containers[i], nil
}
}
for i := range pod.Spec.InitContainers {//遍历pod的initContainer,判断名称是否相同
if pod.Spec.InitContainers[i].Name == o.ContainerName {
return &pod.Spec.InitContainers[i], nil
}
}
for i := range pod.Spec.EphemeralContainers {//遍历EphemeralContainers ,判断名称是否相同
if pod.Spec.EphemeralContainers[i].Name == o.ContainerName {
return (*corev1.Container)(&pod.Spec.EphemeralContainers[i].EphemeralContainerCommon), nil
}
}
return nil, fmt.Errorf("container not found (%s)", o.ContainerName)//没找到返回错误
}
if o.EnableSuggestedCmdUsage {//如果启用提示,则输出提示信息
fmt.Fprintf(o.ErrOut, "Defaulting container name to %s.\n", pod.Spec.Containers[0].Name)
fmt.Fprintf(o.ErrOut, "Use '%s describe pod/%s -n %s' to see all of the containers in this pod.\n", o.ParentCommandName, o.PodName, o.Namespace)
}
klog.V(4).Infof("defaulting container name to %s", pod.Spec.Containers[0].Name)
return &pod.Spec.Containers[0], nil//返回第一个容器
}
// GetContainerName returns the name of the container to attach to, with a fallback.
//获取容器名称
func (o *AttachOptions) GetContainerName(pod *corev1.Pod) (string, error) {
c, err := o.containerToAttachTo(pod)//如果容器
if err != nil {
return "", err
}
return c.Name, nil// 返回容器名称
}
//attach函数
func DefaultAttachFunc(o *AttachOptions, containerToAttach *corev1.Container, raw bool, sizeQueue remotecommand.TerminalSizeQueue) func() error {
return func() error {
restClient, err := restclient.RESTClientFor(o.Config)//获取restConfig
if err != nil {
return err
}
req := restClient.Post().
Resource("pods").
Name(o.Pod.Name).
Namespace(o.Pod.Namespace).
SubResource("attach")// 构造request对象
req.VersionedParams(&corev1.PodAttachOptions{
Container: containerToAttach.Name,
Stdin: o.Stdin,
Stdout: o.Out != nil,
Stderr: !o.DisableStderr,
TTY: raw,
}, scheme.ParameterCodec)
return o.Attach.Attach("POST", req.URL(), o.Config, o.In, o.Out, o.ErrOut, raw, sizeQueue)//执行attach
}
}