从源码了解istio如何构建listener

背景

从源码了解istio如何构建listener

源码

listener相关

pilot/pkg/networking/core/listener.go中

构建sidecar listener配置
func (configgen *ConfigGeneratorImpl) buildSidecarListeners(builder *ListenerBuilder) *ListenerBuilder {
    if builder.push.Mesh.ProxyListenPort > 0 {
        builder.appendSidecarInboundListeners().
            appendSidecarOutboundListeners().
            buildHTTPProxyListener().
            buildVirtualOutboundListener()
    }
    return builder
}

构建所有sidecar outbound listener配置
func (lb *ListenerBuilder) buildSidecarOutboundListeners(node *model.Proxy,
    push *model.PushContext,
) []*listener.Listener {
    ...
    获取通配符和本地主机名
    actualWildcards, actualLocalHosts := getWildcardsAndLocalHost(node.GetIPMode())
    ...
    for _, egressListener := range node.SidecarScope.EgressListeners {
        ...
        如果egressListener.IstioListener.Bind非空,则使用egressListener.IstioListener.Bind
        if egressListener.IstioListener != nil && egressListener.IstioListener.Bind != "" {
            bind.binds = []string{egressListener.IstioListener.Bind}
        }
        ...
        if egressListener.IstioListener != nil &&
            egressListener.IstioListener.Port != nil {
            for _, service := range services {
                listenerOpts := outboundListenerOpts{
                    push:    push,
                    proxy:   node,
                    bind:    bind,
                    port:    listenPort,
                    service: service,
                }
                // Set service specific attributes here.
                lb.buildSidecarOutboundListener(listenerOpts, listenerMap, virtualServices, actualWildcards)
            }
        } else {
           ...
            for _, service := range services {
                saddress := service.GetAddressForProxy(node)
                for _, servicePort := range service.Ports {
                    ...
                    listenerOpts := outboundListenerOpts{
                        push:    push,
                        proxy:   node,
                        bind:    bind,
                        port:    servicePort,
                        service: service,
                    }
                    ...
                    lb.buildSidecarOutboundListener(listenerOpts, listenerMap, virtualServices, actualWildcards)

                }

            }
            ...
        }
        ...
    }
    ...
}


构建sidecar outbound listener配置
func (lb *ListenerBuilder) buildSidecarOutboundListener(listenerOpts outboundListenerOpts,
    listenerMap map[listenerKey]*outboundListenerEntry, virtualServices []*config.Config, actualWildcards []string,
) {
    ...
    内部端口协议转换为listener协议
    listenerProtocol := istionetworking.ModelProtocolToListenerProtocol(listenerOpts.port.Protocol)
    ...
    switch listenerProtocol {
    case istionetworking.ListenerProtocolTCP, istionetworking.ListenerProtocolAuto:
      ...
        if listenerOpts.bind.Primary() == "" {
            获取服务监听地址
            svcListenAddress := listenerOpts.service.GetAddressForProxy(listenerOpts.proxy)
            if len(svcListenAddress) > 0 {
                if !strings.Contains(svcListenAddress, "/") {
                    设置svc地址作为listener地址
                    listenerOpts.bind.binds = append([]string{svcListenAddress}, svcExtraListenAddresses...)
                } else {
                    设置通配符作为listener地址
                    listenerOpts.bind.binds = actualWildcards
                    listenerOpts.cidr = append([]string{svcListenAddress}, svcExtraListenAddresses...)
                }
            }
        }
        ...
    case istionetworking.ListenerProtocolHTTP:
        设置通配符作为listener地址
        if len(listenerOpts.bind.Primary()) == 0 {
            listenerOpts.bind.binds = actualWildcards
        }
        listenerMapKey = listenerKey{listenerOpts.bind.Primary(), listenerOpts.port.Port}
    ...
    }
    ...
}

pilot/pkg/networking/core/listener_builder.go中

添加sidecar outbound listener配置
func (lb *ListenerBuilder) appendSidecarOutboundListeners() *ListenerBuilder {
    lb.outboundListeners = lb.buildSidecarOutboundListeners(lb.node, lb.push)
    return lb
}

协议相关

pilot/pkg/serviceregistry/kube/conversion.go中

k8s port到内部端口表示转换
func convertPort(port corev1.ServicePort) *model.Port {
    return &model.Port{
        Name:     port.Name,
        Port:     int(port.Port),
        Protocol: kube.ConvertProtocol(port.Port, port.Name, port.Protocol, port.AppProtocol),
    }
}

pkg/config/kube/conversion.go中

转换协议
func ConvertProtocol(port int32, portName string, proto corev1.Protocol, appProto *string) protocol.Instance {
    // 如果协议是UDP,则返回UDP
    if proto == corev1.ProtocolUDP {
        return protocol.UDP
    }


    根据appProto判断协议
    name := portName
    if appProto != nil {
        name = *appProto
        switch name {
        case "kubernetes.io/h2c":
            return protocol.HTTP2
        case "kubernetes.io/ws":
            return protocol.HTTP
        case "kubernetes.io/wss":
            return protocol.HTTPS
        }
    }

    如果端口名是grpc-web开头,则返回GRPCWeb协议
    if len(name) >= grpcWebLen && strings.EqualFold(name[:grpcWebLen], grpcWeb) {
        return protocol.GRPCWeb
    }

    仅保留-前面的内容
    i := strings.IndexByte(name, '-')
    if i >= 0 {
        name = name[:i]
    }

    从端口名解析协议
    p := protocol.Parse(name)
    如果不支持的协议判断是不是知名端口
    if p == protocol.Unsupported {
        if wellKnownPorts.Contains(port) {
            return protocol.TCP
        }
    }
    return p
}


知名端口
const (
    SMTP    = 25
    DNS     = 53
    MySQL   = 3306
    MongoDB = 27017
)

var wellKnownPorts = sets.New[int32](
    SMTP,
    DNS,
    MySQL,
    MongoDB,
)

pkg/config/protocol/instance.go

从端口名解析协议
func Parse(s string) Instance {
    switch strings.ToLower(s) {
    case "tcp":
        return TCP
    case "udp":
        return UDP
    case "grpc":
        return GRPC
    case "grpc-web":
        return GRPCWeb
    case "http":
        return HTTP
    case "http_proxy":
        return HTTP_PROXY
    case "http2":
        return HTTP2
    case "https":
        return HTTPS
    case "tls":
        return TLS
    case "mongo":
        return Mongo
    case "redis":
        return Redis
    case "mysql":
        return MySQL
    case "DoubleHBONE":
        return DoubleHBONE
    }

    return Unsupported
}

pilot/pkg/networking/networking.go中

内部端口协议转换为listener协议
func ModelProtocolToListenerProtocol(p protocol.Instance) ListenerProtocol {
    switch p {
    case protocol.HTTP, protocol.HTTP2, protocol.HTTP_PROXY, protocol.GRPC, protocol.GRPCWeb:
        return ListenerProtocolHTTP
    case protocol.TCP, protocol.HTTPS, protocol.TLS,
        protocol.Mongo, protocol.Redis, protocol.MySQL:
        return ListenerProtocolTCP
    case protocol.UDP:
        return ListenerProtocolUnknown
    case protocol.Unsupported:
        return ListenerProtocolAuto
    default:
        return ListenerProtocolAuto
    }
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容