node.jskubernetesftpload-balancingservice-node-port-range

Can open Active FTP data connection via kubernetes LoadBalancer service but not via NodePort service


I am using active FTP to transfer file(via the PORT command). I can initiate active FTP sessions using LoadBalancer IP and Loadbalancer Service Target Port. I tried a similar way to initiate active FTP session using Node External IP and Node Port but I am not able to do it. I am using npm.js basic-ftp module for it. The code for my connection is given below:

let client = new ftp.Client(ftpTimeout * 1000);
client.prepareTransfer = prepareTransfer;

And prepareTransfer has implementation like:

export async function prepareTransfer(ftp: FTPContext): Promise<FTPResponse> {
  // Gets the  ip address of either LoadBalancer(for LoadBalancer service) or Node(For NodePort Service)
   const ip = await getIp();
  // Gets a TargetPort for LoadBalancer service or Node Port for NodePort service
  const port = await getFtpPort();

  // Example command: PORT 192,168,150,80,14,178
  // The first four octets are the IP address while the last two octets comprise the 
  //port that will be used for the data connection.
  // To find the actual port multiply the fifth octet by 256 and then add the sixth 
  //octet to the total.
  // Thus in the example above the port number is ( (14*256) + 178), or 3762
  const p1 = Math.floor(port / 256);
  const p2 = port % 256;
  const command = `PORT ${ip.replace(/\./g, ',')},${p1},${p2}`;

  // https://github.com/patrickjuchli/basic-ftp/issues/195
  // Data socket pipes before the connection so use the mock socket.
  const mockSocket = new MockSocket();
  ftp.dataSocket = mockSocket as any;

  let ftpResponse = new Promise<FTPResponse>((resolve, reject) => {
    let response: FTPResponse;
    const server = createServer(function (socket) {
      console.log('FTP Client connected');
      mockSocket.setSocket(socket, server, port);
    });

    server.on('error', err => {
      reject(err);
    });
    server.listen(port, async () => {
      console.log(`socket server for FTP started at port ${port}`);
      // send the port request
      response = await ftp.request(command);
      if (response.code !== 200) {
        reject('Could not connect');
        server.close();
      }
      resolve(response);
    });
  });

  return ftpResponse;
}

Any idea why NodePort is not working here?

Helm Chart for NodePort:

apiVersion: v1
kind: Service
metadata:
  name: "ftp-service"
spec:
  type: NodePort
  externalTrafficPolicy: Local
  selector:
    statefulset.kubernetes.io/pod-name: "pod1"
  ports:
  - protocol: TCP
    name: ftp-8000
    port: 8000
    targetPort: 8000
    nodePort: 30014

Helm chart for loadbalancer:

apiVersion: v1
kind: Service
metadata:
  name: "ftp-service-load"
spec:
  type: LoadBalancer 
  externalTrafficPolicy: Local
  selector:
    statefulset.kubernetes.io/pod-name: "pod1"
  ports:
  - protocol: TCP
    name: ftp-8000
    port: 8000
    targetPort: 8000
    nodePort: 30014

Solution

  • ok, finally I figured out the solution. I have been using Azure Kubernetes Service(AKS). Need to set the inbound port rule for the appropriate NodePort(under Virtual machine scale sets, selecting the right node pools whose public IPs are enabled, and under Networking tab). Also, need to make externalTrafficPolicy to Cluster or simply remove the line externalTrafficPolicy: Local from the helm chart.