從源碼了解istio如何構(gòu)建listener

背景

從源碼了解istio如何構(gòu)建listener

源碼

listener相關(guān)

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

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

構(gòu)建所有sidecar outbound listener配置
func (lb *ListenerBuilder) buildSidecarOutboundListeners(node *model.Proxy,
    push *model.PushContext,
) []*listener.Listener {
    ...
    獲取通配符和本地主機(jī)名
    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)

                }

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


構(gòu)建sidecar outbound listener配置
func (lb *ListenerBuilder) buildSidecarOutboundListener(listenerOpts outboundListenerOpts,
    listenerMap map[listenerKey]*outboundListenerEntry, virtualServices []*config.Config, actualWildcards []string,
) {
    ...
    內(nèi)部端口協(xié)議轉(zhuǎn)換為listener協(xié)議
    listenerProtocol := istionetworking.ModelProtocolToListenerProtocol(listenerOpts.port.Protocol)
    ...
    switch listenerProtocol {
    case istionetworking.ListenerProtocolTCP, istionetworking.ListenerProtocolAuto:
      ...
        if listenerOpts.bind.Primary() == "" {
            獲取服務(wù)監(jiān)聽地址
            svcListenAddress := listenerOpts.service.GetAddressForProxy(listenerOpts.proxy)
            if len(svcListenAddress) > 0 {
                if !strings.Contains(svcListenAddress, "/") {
                    設(shè)置svc地址作為listener地址
                    listenerOpts.bind.binds = append([]string{svcListenAddress}, svcExtraListenAddresses...)
                } else {
                    設(shè)置通配符作為listener地址
                    listenerOpts.bind.binds = actualWildcards
                    listenerOpts.cidr = append([]string{svcListenAddress}, svcExtraListenAddresses...)
                }
            }
        }
        ...
    case istionetworking.ListenerProtocolHTTP:
        設(shè)置通配符作為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
}

協(xié)議相關(guān)

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

k8s port到內(nèi)部端口表示轉(zhuǎn)換
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中

轉(zhuǎn)換協(xié)議
func ConvertProtocol(port int32, portName string, proto corev1.Protocol, appProto *string) protocol.Instance {
    // 如果協(xié)議是UDP,則返回UDP
    if proto == corev1.ProtocolUDP {
        return protocol.UDP
    }


    根據(jù)appProto判斷協(xié)議
    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協(xié)議
    if len(name) >= grpcWebLen && strings.EqualFold(name[:grpcWebLen], grpcWeb) {
        return protocol.GRPCWeb
    }

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

    從端口名解析協(xié)議
    p := protocol.Parse(name)
    如果不支持的協(xié)議判斷是不是知名端口
    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

從端口名解析協(xié)議
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中

內(nèi)部端口協(xié)議轉(zhuǎn)換為listener協(xié)議
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
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容