diff --git a/demos/frp/kind/test.py b/demos/frp/kind/test.py new file mode 100755 index 00000000..593388c2 --- /dev/null +++ b/demos/frp/kind/test.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +# Copyright (c) The ClusterLink Authors. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################ +# Name: Simple iperf3 test +# Desc: create 2 kind clusters : +# 1) GW and iperf3 client +# 2) GW and iperf3 server +############################################################### +import os +import sys +import time +projDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname( os.path.abspath(__file__))))) +sys.path.insert(0,f'{projDir}') + +from demos.utils.common import printHeader +from demos.utils.kind import Cluster +from demos.iperf3.kind.iperf3_client_start import directTestIperf3,testIperf3Client +from demos.frp.test import iperf3Test + +testOutputFolder = f"{projDir}/bin/tests/iperf3" + +############################### MAIN ########################## +if __name__ == "__main__": + printHeader("\n\nStart Kind Test\n\n") + printHeader("Start pre-setting") + + # cl parameters + cl1= Cluster("peer1") + cl2= Cluster("peer2") + cl3= Cluster("peer3") + srcSvc = "iperf3-client" + destSvc = "iperf3-server" + destPort = 5000 + iperf3DirectPort = "30001" + + # Setup + iperf3Test(cl1, cl2, cl3, testOutputFolder) + #Testing + printHeader("\n\nStart Iperf3 testing") + cl2.useCluster() + cl2.setKindIp() + directTestIperf3(cl1, srcSvc, cl2.ip, iperf3DirectPort) + time.sleep(5) + testIperf3Client(cl1, srcSvc, destSvc, destPort) + testIperf3Client(cl3, srcSvc, destSvc, destPort) + + + diff --git a/demos/frp/test.py b/demos/frp/test.py new file mode 100755 index 00000000..e1ba9256 --- /dev/null +++ b/demos/frp/test.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +# Copyright (c) The ClusterLink Authors. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################ +# Name: Simple iperf3 test +# Desc: create 2 kind clusters : +# 1) GW and iPerf3 client +# 2) GW and iPerf3 server +############################################################### +import os +import sys +projDir = os.path.dirname(os.path.dirname(os.path.dirname( os.path.abspath(__file__)))) + +sys.path.insert(0,f'{projDir}') + +from demos.utils.common import printHeader, runcmd +from demos.utils.kind import Cluster as KindCluster +from demos.utils.common import printHeader + +testOutputFolder = f"{projDir}/bin/tests/iperf3" + +# Folders +folCl=f"{projDir}/demos/iperf3/testdata/manifests/iperf3-client" +folSv=f"{projDir}/demos/iperf3/testdata/manifests/iperf3-server" +folFrp=f"{projDir}/demos/frp/testdata/manifests/" +#services +srcSvc = "iperf3-client" +destSvc = "iperf3-server" +destPort = 5000 +namespace = "default" + +# iperf3Test setup two cluster for creating iPerf3 test. +def iperf3Test(cl1:KindCluster, cl2:KindCluster,cl3:KindCluster, testOutputFolder): + print(f'Working directory {projDir}') + os.chdir(projDir) + + # build docker environment + printHeader("Build docker image") + os.system("make docker-build") + os.system("make install") + + # Create Kind clusters environment + cl1.createCluster(runBg=True) + cl3.createCluster(runBg=True) + cl2.createCluster(runBg=False) + + # Start Kind clusters environment + cl1.create_fabric(testOutputFolder) + cl1.startCluster(testOutputFolder) + cl2.startCluster(testOutputFolder) + cl3.startCluster(testOutputFolder) + + # Create iPerf3 micro-services + cl1.loadService(srcSvc, "mlabbe/iperf3",f"{folCl}/iperf3-client.yaml" ) + cl2.loadService(destSvc, "mlabbe/iperf3",f"{folSv}/iperf3.yaml" ) + cl3.loadService(srcSvc, "mlabbe/iperf3",f"{folCl}/iperf3-client.yaml" ) + os.environ['FRP_SERVER_IP'] = cl1.ip + + # Use envsubst to replace the placeholder and apply the ConfigMap + runcmd(f"envsubst < {folFrp}/server/frps-configmap.yaml | kubectl apply -f -") + # Create peers + printHeader("Create peers") + cl1.useCluster() + runcmd(f"kubectl apply -f {folFrp}/server/frps-configmap.yaml") + runcmd(f"kubectl apply -f {folFrp}/server/frps.yaml") + + cl1.useCluster() + runcmd(f"envsubst < {folFrp}/client/peer1/frpc-configmap.yaml| kubectl apply -f -") + runcmd(f"kubectl apply -f {folFrp}/client/frpc.yaml") + runcmd(f"kubectl apply -f {folFrp}/client/peer1/peer.yaml") + cl2.useCluster() + runcmd(f"envsubst < {folFrp}/client/peer2/frpc-configmap.yaml| kubectl apply -f -") + runcmd(f"kubectl apply -f {folFrp}/client/frpc.yaml") + runcmd(f"kubectl apply -f {folFrp}/client/peer2/peer.yaml") + cl3.useCluster() + runcmd(f"envsubst < {folFrp}/client/peer3/frpc-configmap.yaml| kubectl apply -f -") + runcmd(f"kubectl apply -f {folFrp}/client/frpc.yaml") + runcmd(f"kubectl apply -f {folFrp}/client/peer3/peer.yaml") + # Create exports + cl2.exports.create(destSvc, namespace, destPort) + + #Import destination service + printHeader(f"\n\nStart Importing {destSvc} service to {cl1.name}") + cl1.imports.create(destSvc,namespace,destPort,cl2.name,destSvc,namespace) + cl3.imports.create(destSvc,namespace,destPort,cl2.name,destSvc,namespace) + + #Add policy + printHeader("Applying policies") + cl1.policies.create(name="allow-all",namespace=namespace, action="allow", from_attribute=[{"workloadSelector": {}}],to_attribute=[{"workloadSelector": {}}]) + cl2.policies.create(name="allow-all",namespace=namespace, action="allow", from_attribute=[{"workloadSelector": {}}],to_attribute=[{"workloadSelector": {}}]) + cl3.policies.create(name="allow-all",namespace=namespace, action="allow", from_attribute=[{"workloadSelector": {}}],to_attribute=[{"workloadSelector": {}}]) + + + diff --git a/demos/frp/testdata/manifests/client/frpc.yaml b/demos/frp/testdata/manifests/client/frpc.yaml new file mode 100644 index 00000000..b02157c3 --- /dev/null +++ b/demos/frp/testdata/manifests/client/frpc.yaml @@ -0,0 +1,27 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frpc + namespace: clusterlink-system +spec: + replicas: 1 + selector: + matchLabels: + app: frpc + template: + metadata: + labels: + app: frpc + spec: + # hostNetwork: true + containers: + - name: frpc + image: snowdreamtech/frpc + volumeMounts: + - name: frpc-config-volume + mountPath: /etc/frp + volumes: + - name: frpc-config-volume + configMap: + name: frpc-config + restartPolicy: Always \ No newline at end of file diff --git a/demos/frp/testdata/manifests/client/peer1/frpc-configmap.yaml b/demos/frp/testdata/manifests/client/peer1/frpc-configmap.yaml new file mode 100644 index 00000000..4647f9fa --- /dev/null +++ b/demos/frp/testdata/manifests/client/peer1/frpc-configmap.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: frpc-config + namespace: clusterlink-system +data: + frpc.toml: | + # Set server address + serverAddr = "${FRP_SERVER_IP}" + serverPort = 30444 + + [[proxies]] + name = "clusterlink-peer1" + type = "stcp" + localIP = "clusterlink.clusterlink-system.svc.cluster.local" + localPort = 443 + secretKey = "abcdefg" + + [[visitors]] + name = "clusterlink-peer1-to-peer2-visitor" + type = "stcp" + serverName = "clusterlink-peer2" + secretKey = "abcdefg" + bindAddr = "::" + bindPort = 6002 + + [[visitors]] + name = "clusterlink-peer1-to-peer3-visitor" + type = "stcp" + serverName = "clusterlink-peer3" + secretKey = "abcdefg" + bindAddr = "::" + bindPort = 6003 diff --git a/demos/frp/testdata/manifests/client/peer1/peer.yaml b/demos/frp/testdata/manifests/client/peer1/peer.yaml new file mode 100644 index 00000000..3fa05691 --- /dev/null +++ b/demos/frp/testdata/manifests/client/peer1/peer.yaml @@ -0,0 +1,47 @@ +apiVersion: clusterlink.net/v1alpha1 +kind: Peer +metadata: + name: peer2 + namespace: clusterlink-system +spec: + gateways: + - host: frp-peer2-clusterlink.clusterlink-system.svc.cluster.local + port: 6002 + +--- +apiVersion: v1 +kind: Service +metadata: + name: frp-peer2-clusterlink + namespace: clusterlink-system +spec: + type: ClusterIP + selector: + app: frpc + ports: + - port: 6002 + targetPort: 6002 +--- +apiVersion: clusterlink.net/v1alpha1 +kind: Peer +metadata: + name: peer3 + namespace: clusterlink-system +spec: + gateways: + - host: frp-peer3-clusterlink.clusterlink-system.svc.cluster.local + port: 6003 + +--- +apiVersion: v1 +kind: Service +metadata: + name: frp-peer3-clusterlink + namespace: clusterlink-system +spec: + type: ClusterIP + selector: + app: frpc + ports: + - port: 6003 + targetPort: 6003 \ No newline at end of file diff --git a/demos/frp/testdata/manifests/client/peer2/frpc-configmap.yaml b/demos/frp/testdata/manifests/client/peer2/frpc-configmap.yaml new file mode 100644 index 00000000..addbe7e3 --- /dev/null +++ b/demos/frp/testdata/manifests/client/peer2/frpc-configmap.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: frpc-config + namespace: clusterlink-system +data: + frpc.toml: | + # Set server address + serverAddr = "${FRP_SERVER_IP}" + serverPort = 30444 + + [[proxies]] + name = "clusterlink-peer2" + type = "stcp" + localIP = "clusterlink.clusterlink-system.svc.cluster.local" + localPort = 443 + secretKey = "abcdefg" + + [[visitors]] + name = "clusterlink-peer2-to-peer1-visitor" + type = "stcp" + serverName = "clusterlink-peer1" + secretKey = "abcdefg" + bindAddr = "::" + bindPort = 6001 + + [[visitors]] + name = "clusterlink-peer2-to-peer3-visitor" + type = "stcp" + serverName = "clusterlink-peer3" + secretKey = "abcdefg" + bindAddr = "::" + bindPort = 6003 diff --git a/demos/frp/testdata/manifests/client/peer2/peer.yaml b/demos/frp/testdata/manifests/client/peer2/peer.yaml new file mode 100644 index 00000000..4830590b --- /dev/null +++ b/demos/frp/testdata/manifests/client/peer2/peer.yaml @@ -0,0 +1,45 @@ +apiVersion: clusterlink.net/v1alpha1 +kind: Peer +metadata: + name: peer1 + namespace: clusterlink-system +spec: + gateways: + - host: frp-peer1-clusterlink.clusterlink-system.svc.cluster.local + port: 6001 +--- +apiVersion: v1 +kind: Service +metadata: + name: frp-peer1-clusterlink + namespace: clusterlink-system +spec: + type: ClusterIP + selector: + app: frpc + ports: + - port: 6001 + targetPort: 6001 +--- +apiVersion: clusterlink.net/v1alpha1 +kind: Peer +metadata: + name: peer3 + namespace: clusterlink-system +spec: + gateways: + - host: frp-peer3-clusterlink.clusterlink-system.svc.cluster.local + port: 6003 +--- +apiVersion: v1 +kind: Service +metadata: + name: frp-peer3-clusterlink + namespace: clusterlink-system +spec: + type: ClusterIP + selector: + app: frpc + ports: + - port: 6003 + targetPort: 6003 \ No newline at end of file diff --git a/demos/frp/testdata/manifests/client/peer3/frpc-configmap.yaml b/demos/frp/testdata/manifests/client/peer3/frpc-configmap.yaml new file mode 100644 index 00000000..fa8136c4 --- /dev/null +++ b/demos/frp/testdata/manifests/client/peer3/frpc-configmap.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: frpc-config + namespace: clusterlink-system +data: + frpc.toml: | + # Set server address + serverAddr = "${FRP_SERVER_IP}" + serverPort = 30444 + + [[proxies]] + name = "clusterlink-peer3" + type = "stcp" + localIP = "clusterlink.clusterlink-system.svc.cluster.local" + localPort = 443 + secretKey = "abcdefg" + + [[visitors]] + name = "clusterlink-peer3-to-peer1-visitor" + type = "stcp" + serverName = "clusterlink-peer1" + secretKey = "abcdefg" + bindAddr = "::" + bindPort = 6001 + + [[visitors]] + name = "clusterlink-peer3-to-peer2-visitor" + type = "stcp" + serverName = "clusterlink-peer2" + secretKey = "abcdefg" + bindAddr = "::" + bindPort = 6002 \ No newline at end of file diff --git a/demos/frp/testdata/manifests/client/peer3/peer.yaml b/demos/frp/testdata/manifests/client/peer3/peer.yaml new file mode 100644 index 00000000..be6caec7 --- /dev/null +++ b/demos/frp/testdata/manifests/client/peer3/peer.yaml @@ -0,0 +1,47 @@ +apiVersion: clusterlink.net/v1alpha1 +kind: Peer +metadata: + name: peer1 + namespace: clusterlink-system +spec: + gateways: + - host: frp-peer1-clusterlink.clusterlink-system.svc.cluster.local + port: 6001 + +--- +apiVersion: v1 +kind: Service +metadata: + name: frp-peer1-clusterlink + namespace: clusterlink-system +spec: + type: ClusterIP + selector: + app: frpc + ports: + - port: 6001 + targetPort: 6001 +--- +apiVersion: clusterlink.net/v1alpha1 +kind: Peer +metadata: + name: peer2 + namespace: clusterlink-system +spec: + gateways: + - host: frp-peer2-clusterlink.clusterlink-system.svc.cluster.local + port: 6002 + +--- +apiVersion: v1 +kind: Service +metadata: + name: frp-peer2-clusterlink + namespace: clusterlink-system +spec: + type: ClusterIP + selector: + app: frpc + ports: + - port: 6002 + targetPort: 6002 diff --git a/demos/frp/testdata/manifests/server/frps-configmap.yaml b/demos/frp/testdata/manifests/server/frps-configmap.yaml new file mode 100644 index 00000000..0ac51071 --- /dev/null +++ b/demos/frp/testdata/manifests/server/frps-configmap.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: frps-config + namespace: clusterlink-system +data: + frps.toml: | + bindPort = 4443 diff --git a/demos/frp/testdata/manifests/server/frps.yaml b/demos/frp/testdata/manifests/server/frps.yaml new file mode 100644 index 00000000..904c1cc3 --- /dev/null +++ b/demos/frp/testdata/manifests/server/frps.yaml @@ -0,0 +1,42 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frps + namespace: clusterlink-system +spec: + replicas: 1 + selector: + matchLabels: + app: frps + template: + metadata: + labels: + app: frps + spec: + hostNetwork: true + containers: + - name: frps + image: snowdreamtech/frps + volumeMounts: + - name: frps-config-volume + mountPath: /etc/frp/frps.toml + subPath: frps.toml + volumes: + - name: frps-config-volume + configMap: + name: frps-config + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: clusterlink-frps + namespace: clusterlink-system +spec: + type: NodePort + selector: + app: frps + ports: + - port: 4443 + targetPort: 4443 + nodePort: 30444 diff --git a/website/content/en/docs/main/tasks/private-networks/index.md b/website/content/en/docs/main/tasks/private-networks/index.md new file mode 100644 index 00000000..96607270 --- /dev/null +++ b/website/content/en/docs/main/tasks/private-networks/index.md @@ -0,0 +1,394 @@ +--- +title: Private Networks +description: Running ClusterLink in a private network when the K8s cluster is behind a NAT or firewall. +--- + + +This task involves connecting ClusterLink behind a NAT or firewall. +To connect the ClusterLink gateway, each peer should have a public IP that will be reachable from other peers to enable cross-cluster communications. In many cases, this is not possible because clusters are behind corporate NAT or firewalls that allow outgoing connections only. For this scenario, we will use the [Fast Reverse Proxy][] (FRP) open-source project to create reverse tunnels and connect all clusters behind a private network. With FRP, only one IP needs to be public to connect all the clusters in the fabric. + +To create connectivity between the ClusterLink gateways, we need to set up one FRP server with a public IP and create an FRP client for each ClusterLink gateway, as illustrated below. + +This task includes instructions on how to connect the peers using FRP. Instructions for creating full connectivity between applications to remote services can be found in the [Nginx tutorial][] and [iPerf3 tutorial][]. + +In this task, we will extend the peer connectivity instructions to use FRP. + +## Create FRP Server + +In this step, we will create the FRP server on the same cluster we use for ClusterLink, but it can be on any peer or Kubernetes cluster. + +1. Create a configmap that contains the server configuration: + + ```sh + echo " + apiVersion: v1 + kind: ConfigMap + metadata: + name: frps-config + namespace: clusterlink-system + data: + frps.toml: | + bindPort = 4443 + " | kubectl apply -f - + ``` + + In this setup, we expose the FRP server pod on port `4443`. +2. Create FRP server deployment: + + ```sh + echo " + apiVersion: apps/v1 + kind: Deployment + metadata: + name: frps + namespace: clusterlink-system + spec: + replicas: 1 + selector: + matchLabels: + app: frps + template: + metadata: + labels: + app: frps + spec: + hostNetwork: true + containers: + - name: frps + image: snowdreamtech/frps + volumeMounts: + - name: frps-config-volume + mountPath: /etc/frp/frps.toml + subPath: frps.toml + volumes: + - name: frps-config-volume + configMap: + name: frps-config + restartPolicy: Always + " | kubectl apply -f - + ``` + +3. Create sn ingress service to expose the FRP server: + + ```sh + echo " + apiVersion: v1 + kind: Service + metadata: + name: clusterlink-frps + namespace: clusterlink-system + spec: + type: NodePort + selector: + app: frps + ports: + - port: 4443 + targetPort: 4443 + nodePort: 30444 + " | kubectl apply -f - + ``` + + In this case, we use a `NodePort` service, but it can be other types like `LoadBalancer`. + +## Create FRPs Clients + +1. Set the `FRP_SERVER_IP` variable for each cluster: + + *Client cluster*: + + ```sh + export FRP_SERVER_IP=`docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' client-control-plane` + ``` + + *Client cluster*: + + ```sh + export FRP_SERVER_IP=`docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' client-control-plane` + ``` + +2. Deploy FRP client configuration on each cluster: + + *Client cluster*: + + ```sh + echo " + apiVersion: v1 + kind: ConfigMap + metadata: + name: frpc-config + namespace: clusterlink-system + data: + frpc.toml: | + # Set server address + serverAddr = \""${FRP_SERVER_IP}"\" + serverPort = 30444 + + [[proxies]] + name = \"clusterlink-client\" + type = \"stcp\" + localIP = \"clusterlink.clusterlink-system.svc.cluster.local\" + localPort = 443 + secretKey = \"abcdefg\" + + [[visitors]] + name = \"clusterlink-client-to-server-visitor\" + type = \"stcp\" + serverName = \"clusterlink-server\" + secretKey = \"abcdefg\" + bindAddr = \"::\" + bindPort = 6002 + " | kubectl apply -f - + ``` + + *Server cluster*: + + ```sh + echo " + apiVersion: v1 + kind: ConfigMap + metadata: + name: frpc-config + namespace: clusterlink-system + data: + frpc.toml: | + # Set server address + serverAddr = \""${FRP_SERVER_IP}"\" + serverPort = 30444 + + [[proxies]] + name = \"clusterlink-server\" + type = \"stcp\" + localIP = \"clusterlink.clusterlink-system.svc.cluster.local\" + localPort = 443 + secretKey = \"abcdefg\" + + [[visitors]] + name = \"clusterlink-server-to-client-visitor\" + type = \"stcp\" + serverName = \"clusterlink-client\" + secretKey = \"abcdefg\" + bindAddr = \"::\" + bindPort = 6001 + " | kubectl apply -f - + ``` + + For each configuration, we first set the FRP server IP and port number. + We create a `proxy` that connects to the ClusterLink gateway and establishes a reverse tunnel to allow other clients to connect. + We also create an FRP `visitor` that specifies which other peers this client wants to connect to (you need to create a visitor for every peer you want to connect). + +4. Create a K8s service that connects to the FRP client `visitor`, allowing ClusterLink to connect to it: + + *Client cluster*: + + ```sh + echo ' + apiVersion: v1 + kind: Service + metadata: + name: server-peer-clusterlink + namespace: clusterlink-system + spec: + type: ClusterIP + selector: + app: frpc + ports: + - port: 6002 + targetPort: 6002 + ' | kubectl apply -f - + ``` + + *Server cluster*: + + ```sh + echo ' + apiVersion: v1 + kind: Service + metadata: + name: client-peer-clusterlink + namespace: clusterlink-system + spec: + type: ClusterIP + selector: + app: frpc + ports: + - port: 6001 + targetPort: 6001 + ' | kubectl apply -f - + ``` + +4. Create FRP client deployment for each cluster: + + *Client cluster*: + + ```sh + echo " + apiVersion: apps/v1 + kind: Deployment + metadata: + name: frpc + namespace: clusterlink-system + spec: + replicas: 1 + selector: + matchLabels: + app: frpc + template: + metadata: + labels: + app: frpc + spec: + containers: + - name: frpc + image: snowdreamtech/frpc + volumeMounts: + - name: frpc-config-volume + mountPath: /etc/frp + volumes: + - name: frpc-config-volume + configMap: + name: frpc-config + restartPolicy: Always + " | kubectl apply -f - + ``` + + *Server cluster*: + + ```sh + echo " + apiVersion: apps/v1 + kind: Deployment + metadata: + name: frpc + namespace: clusterlink-system + spec: + replicas: 1 + selector: + matchLabels: + app: frpc + template: + metadata: + labels: + app: frpc + spec: + containers: + - name: frpc + image: snowdreamtech/frpc + volumeMounts: + - name: frpc-config-volume + mountPath: /etc/frp + volumes: + - name: frpc-config-volume + configMap: + name: frpc-config + restartPolicy: Always + " | kubectl apply -f - + ``` + +## Create Peer CRDs + +1. Create Peer CRDs for each peer: + + *Client cluster*: + + ```sh + echo " + apiVersion: clusterlink.net/v1alpha1 + kind: Peer + metadata: + name: server + namespace: clusterlink-system + spec: + gateways: + - host: server-peer-clusterlink.clusterlink-system.svc.cluster.local + port: 6002 + " | kubectl apply -f - + ``` + + *Server cluster*: + + ```sh + echo " + apiVersion: clusterlink.net/v1alpha1 + kind: Peer + metadata: + name: client + namespace: clusterlink-system + spec: + gateways: + - host: client-peer-clusterlink.clusterlink-system.svc.cluster.local + port: 6001 + " | kubectl apply -f - + ``` + + To verify that the connectivity between the peers is established correctly, + please check if the condition `PeerReachable` has been added to the peer CR status in each cluster. + + ```sh + kubectl describe peers.clusterlink.net -A + ``` + + {{% expand summary="Sample output" %}} + + ``` + Name: client + Namespace: clusterlink-system + Labels: + Annotations: + API Version: clusterlink.net/v1alpha1 + Kind: Peer + Metadata: + Creation Timestamp: 2024-05-28T12:47:33Z + Generation: 1 + Resource Version: 807 + UID: 1fdeafff-707a-43e2-bb3a-826f003a42ed + Spec: + Gateways: + Host: 172.18.0.4 + Port: 30443 + Status: + Conditions: + Last Transition Time: 2024-05-28T12:47:33Z + Message: + Reason: Heartbeat + Status: True + Type: PeerReachable + ``` + + {{% /expand %}} + +## Connect Application Services + +After creating the peer connectivity using FRP, continue to the next step of exporting services, importing services, and creating policies as described in the tutorials [Nginx tutorial][] and [iPerf3 tutorial][]. + +## Cleanup + +To remove all FRP components: + +1. Delete FRP server deployment, config-map and ingress service : + + ```sh + kubectl delete deployments -n clusterlink-system frps + kubectl delete services -n clusterlink-system clusterlink-frps + kubectl delete configmaps -n clusterlink-system frps-config + +1. Delete FRP client deployment, config-map and ingress service on each cluster: + + *Client cluster*: + + ```sh + kubectl delete deployments -n clusterlink-system frpc + kubectl delete services -n clusterlink-system server-peer-clusterlink + kubectl delete configmaps -n clusterlink-system frpc-config + ``` + + *Server cluster*: + + ```sh + kubectl delete deployments -n clusterlink-system frpc + kubectl delete services -n clusterlink-system client-peer-clusterlink + kubectl delete configmaps -n clusterlink-system frpc-config + ``` + +[Nginx tutorial]: {{< relref "../../tutorials/nginx/_index.md" >}} +[iPerf3 tutorial]: {{< relref "../../tutorials/iperf/_index.md" >}} +[Fast Reverse Proxy]: https://github.com/fatedier/frp \ No newline at end of file