[16] 為什麼使用 security group for pod 使用 liveness/readiness probes 需要設定環境變數 DISABLE_TCP_EARLY_DEMUX
根據 EKS Security groups for pods [1] 文件,如果 Pod 使用 liveness/readiness probes 時,則需要設置 VPC CNI plugin DISABLE_TCP_EARLY_DEMUX=ture 環境變數。
環境變數 DISABLE_TCP_EARLY_DEMUX
VPC CNI plugin [2] 若在 DISABLE_TCP_EARLY_DEMUX=ture,則會在 initContainer [3]amazon-k8s-cni-init  設定對應的 kernel 參數 net.ipv4.tcp_early_demux。
# Set DISABLE_TCP_EARLY_DEMUX to true to enable kubelet to pod-eni TCP communication
# https://lwn.net/Articles/503420/ and https://github.com/aws/amazon-vpc-cni-k8s/pull/1212 for background
if [ "${DISABLE_TCP_EARLY_DEMUX:-false}" == "true" ]; then
    sysctl -w "net.ipv4.tcp_early_demux=0"
else
    sysctl -e -w "net.ipv4.tcp_early_demux=1"
fi
不過提到此變數將會 提高些微的本地端 TCP 連線延遲。
This will increase the local TCP connection latency slightly.
而根據 kernel 參數 [4]
tcp_early_demux - BOOLEAN
    Enable early demux for established TCP sockets.
    Default: 1
然而上述 kernel 參數文件並未完整解釋 tcp_early_demux 及為什麼可能影響本地端 TCP 延遲問題。
而在 VPC CNI plugin - Add support to toggle TCP early demux #1212 解釋為什麼需要啟用此 kernel 參數:
了解一下運作
可以確認 net->ipv4.sysctl_ip_early_demux 作為 kernel 參數使用於 ip_rcv_finish function:
static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
    const struct iphdr *iph = ip_hdr(skb);
    int (*edemux)(struct sk_buff *skb);
    struct net_device *dev = skb->dev;
    struct rtable *rt;
    int err;
    /* if ingress device is enslaved to an L3 master device pass the
    * skb to its handler for processing
    */
    skb = l3mdev_ip_rcv(skb);
    if (!skb)
        return NET_RX_SUCCESS;
    if (net->ipv4.sysctl_ip_early_demux &&                      ---> kernel parameter: sysctl_ip_early_demux
        !skb_dst(skb) &&
        !skb->sk &&
        !ip_is_fragment(iph)) {
        const struct net_protocol *ipprot;
        int protocol = iph->protocol;
        ipprot = rcu_dereference(inet_protos[protocol]);
        if (ipprot && (edemux = READ_ONCE(ipprot->early_demux))) {
            err = edemux(skb);
            if (unlikely(err))
                goto drop_error;
            /* must reload iph, skb->head might have changed */
            iph = ip_hdr(skb);
        }
    }
    /*
    *    Initialise the virtual path cache for the packet. It describes
    *    how the packet travels inside Linux networking.
    */
    if (!skb_valid_dst(skb)) {
        err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
                    iph->tos, dev);
        if (unlikely(err))
            goto drop_error;
    }
int tcp_v4_early_demux(struct sk_buff *skb)
{
....
....
    sk = __inet_lookup_established(dev_net(skb->dev), &tcp_hashinfo,
                    iph->saddr, th->source,
                    iph->daddr, ntohs(th->dest),
                    skb->skb_iif, inet_sdif(skb));
    if (sk) {
        skb->sk = sk;
        skb->destructor = sock_edemux;
        if (sk_fullsock(sk)) {
            struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst);
            if (dst)
                dst = dst_check(dst, 0);
            if (dst &&
                inet_sk(sk)->rx_dst_ifindex == skb->skb_iif)
                skb_dst_set_noref(skb, dst);
        }
    }
    return 0;
}
由上述可以了解 tcp_v4_early_demux 檢查是否有建立連線的 socket,若有找到則將 dst 設定到 socket cache 中,因此可以節省尋找 routing 的過程。
問題
如前兩天討論 security group for pod 流程,是使用額外的 Trunk interface 介接設定 vlan 對接 Pod veth。因此使用 security group for pod 的 Pod,流量從 eth0 出去並經由 Trunk interface 回來,因此 Pod SYN-ACK 或 ACK 封包會因 tcp_early_demux 機制而被丟棄。
- 從 Kubelet 到 pod-eni:Kubelet 發送 SYN 封包,Pod 以 SYN-ACK 響應,但 kernel 在主機 veth dev 中接收到封包後丟棄了該封包。
- 從 pod-eni 到 kubelet:Pod-eni 發送 ACK 以響應來自 kubelet 的 SYN-ACK,但 ACK pkt 在主機 veth dev 後再次被 kernel 丟棄。
總結
tcp_v4_early_demux kernel 參數可以作為 kernel socket protocol stack 的 cache 機制,但是在使用 security group for pod 時,則會導致 kubelet 在進行 liveness/readiness probes 時被 kernel 機制判定而丟棄封包。因此需要啟用此 DISABLE_TCP_EARLY_DEMUX=ture 環境變數。
參考文件
- Security groups for pods - Configure the Amazon VPC CNI add-on for security groups for pods - https://docs.aws.amazon.com/eks/latest/userguide/security-groups-for-pods.html#security-groups-pods-deployment
- https://github.com/aws/amazon-vpc-cni-k8s#disable_tcp_early_demux-v173
- https://github.com/aws/amazon-vpc-cni-k8s/blob/master/scripts/init.sh#L53-L59
- https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
- https://github.com/aws/amazon-vpc-cni-k8s/pull/1212#issuecomment-693540666