diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml index 03827cebc93..72498c3ef1d 100644 --- a/.github/workflows/build_and_test.yaml +++ b/.github/workflows/build_and_test.yaml @@ -25,7 +25,7 @@ jobs: - run: make -k lint gen-check: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 - uses: ./tools/github-actions/setup-deps diff --git a/.github/workflows/cherrypick.yaml b/.github/workflows/cherrypick.yaml index 3ec9091a884..260d4cc9674 100644 --- a/.github/workflows/cherrypick.yaml +++ b/.github/workflows/cherrypick.yaml @@ -7,7 +7,7 @@ on: jobs: cherry_pick_release_v0_5: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 name: Cherry pick into release-v0.5 if: ${{ contains(github.event.pull_request.labels.*.name, 'cherrypick/release-v0.5') && github.event.pull_request.merged == true }} steps: diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index be276b9c321..1d0d351749e 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -13,7 +13,7 @@ on: jobs: docs-lint: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Check out code uses: actions/checkout@v3 diff --git a/.github/workflows/latest_release.yaml b/.github/workflows/latest_release.yaml index 6aa63facb86..86eb302e6b1 100644 --- a/.github/workflows/latest_release.yaml +++ b/.github/workflows/latest_release.yaml @@ -9,7 +9,7 @@ on: jobs: latest-release: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 24d26f1e6c3..1dee002cb29 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -7,7 +7,7 @@ on: - "v*.*.*" jobs: release: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 3d96d5ab95d..1e8967a0352 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -9,7 +9,7 @@ jobs: issues: write # for actions/stale to close stale issues pull-requests: write # for actions/stale to close stale PRs name: Prune Stale - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 # do not run it in forked repos if: github.repository == 'envoyproxy/gateway' diff --git a/README.md b/README.md index 03bbcf56da9..653c90bd0a8 100644 --- a/README.md +++ b/README.md @@ -26,15 +26,13 @@ Kubernetes-based application gateway. ## Community Meeting -The Envoy Gateway team meets every Tuesday and Thursday. We also have a separate meeting to be held in the +The Envoy Gateway team meets every Tuesday and Thursday. We also have a separate meeting to be held in the Chinese timezone every two weeks to better accommodate our Chinese community members who face scheduling difficulties for the weekly meetings. Please refer to the meeting details for additional information. * [Meeting details][meeting] - [meeting]: https://docs.google.com/document/d/1leqwsHX8N-XxNEyTflYjRur462ukFxd19Rnk3Uzy55I/edit?usp=sharing -[group]: https://groups.google.com/forum/#!forum/envoy-gateway-developers [blog]: https://blog.envoyproxy.io/introducing-envoy-gateway-ad385cc59532 [Envoy Slack workspace]: https://communityinviter.com/apps/envoyproxy/envoy [Envoy Gateway channel]: https://envoyproxy.slack.com/archives/C03E6NHLESV diff --git a/docs/latest/user/multicluster-service.md b/docs/latest/user/multicluster-service.md new file mode 100644 index 00000000000..414020557ad --- /dev/null +++ b/docs/latest/user/multicluster-service.md @@ -0,0 +1,84 @@ +# Multicluster Service Routing + +The Multicluster Service API ServiceImport object can be used as part of the GatewayAPI backendRef for configuring routes. For more information about multicluster service API follow [sig documentation](https://multicluster.sigs.k8s.io/concepts/multicluster-services-api/). + +We will use [Submariner project](https://github.com/submariner-io/submariner) for setting up the multicluster environment for exporting the service to be routed from peer clusters. + +# Setting KIND clusters and installing Submariner. + +- We will be using KIND clusters to demonstrate this example. + +```shell +git clone https://github.com/submariner-io/submariner-operator +cd submariner-operator +make clusters +``` + +Note: remain in submariner-operator directory for the rest of the steps in this section + +- Install subctl: + +```shell +curl -Ls https://get.submariner.io | VERSION=v0.14.6 bash +``` + +- Set up multicluster service API and submariner for cross cluster traffic using ServiceImport + +```shell +subctl deploy-broker --kubeconfig output/kubeconfigs/kind-config-cluster1 --globalnet +subctl join --kubeconfig output/kubeconfigs/kind-config-cluster1 broker-info.subm --clusterid cluster1 --natt=false +subctl join --kubeconfig output/kubeconfigs/kind-config-cluster2 broker-info.subm --clusterid cluster2 --natt=false +``` + +Once the above steps are done and all the pods are up in both the clusters. We are ready for installing envoy gateway. + +# Install EnvoyGateway + +Install the Gateway API CRDs and Envoy Gateway in cluster1: + +```shell +helm install eg oci://docker.io/envoyproxy/gateway-helm --version v0.0.0-latest -n envoy-gateway-system --create-namespace --kubeconfig output/kubeconfigs/kind-config-cluster1 +``` + +Wait for Envoy Gateway to become available: + +```shell +kubectl wait --timeout=5m -n envoy-gateway-system deployment/envoy-gateway --for=condition=Available --kubeconfig output/kubeconfigs/kind-config-cluster1 +``` + +# Install Application + +Install the backend application in cluster2 and export it through subctl command. + +```shell +kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/latest/examples/kubernetes/application.yaml --kubeconfig output/kubeconfigs/kind-config-cluster2 +subctl export service backend --namespace default --kubeconfig output/kubeconfigs/kind-config-cluster2 +``` + +# Create GatewayAPI Objects + +Create the GatewayAPI objects GatewayClass, Gateway and HTTPRoute in cluster1 to set up the routing. + +```shell +kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/latest/examples/kubernetes/multicluster-service.yaml --kubeconfig output/kubeconfigs/kind-config-cluster1 +``` + +## Testing the Configuration + +Get the name of the Envoy service created the by the example Gateway: + +```shell +export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}') +``` + +Port forward to the Envoy service: + +```shell +kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8888:80 & +``` + +Curl the example app through Envoy proxy: + +```shell +curl --verbose --header "Host: www.example.com" http://localhost:8888/get +``` \ No newline at end of file diff --git a/examples/kubernetes/application.yaml b/examples/kubernetes/application.yaml new file mode 100644 index 00000000000..27df9d63dd5 --- /dev/null +++ b/examples/kubernetes/application.yaml @@ -0,0 +1,53 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: backend +--- +apiVersion: v1 +kind: Service +metadata: + name: backend + labels: + app: backend + service: backend +spec: + ports: + - name: http + port: 3000 + targetPort: 3000 + selector: + app: backend +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backend +spec: + replicas: 1 + selector: + matchLabels: + app: backend + version: v1 + template: + metadata: + labels: + app: backend + version: v1 + spec: + serviceAccountName: backend + containers: + - image: gcr.io/k8s-staging-ingressconformance/echoserver:v20221109-7ee2f3e + imagePullPolicy: IfNotPresent + name: backend + ports: + - containerPort: 3000 + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace diff --git a/examples/kubernetes/multicluster-service.yaml b/examples/kubernetes/multicluster-service.yaml new file mode 100644 index 00000000000..06b29a40941 --- /dev/null +++ b/examples/kubernetes/multicluster-service.yaml @@ -0,0 +1,54 @@ +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: GatewayClass +metadata: + name: eg +spec: + controllerName: gateway.envoyproxy.io/gatewayclass-controller +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: Gateway +metadata: + name: eg + namespace: default +spec: + gatewayClassName: eg + listeners: + - name: http + protocol: HTTP + port: 80 +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: HTTPRoute +metadata: + name: backend + namespace: default +spec: + parentRefs: + - name: eg + hostnames: + - "www.example.com" + rules: + - backendRefs: + - group: multicluster.x-k8s.io + kind: ServiceImport + name: backend-default-cluster2 + namespace: submariner-operator + port: 3000 + matches: + - path: + type: PathPrefix + value: / +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: ReferenceGrant +metadata: + namespace: submariner-operator + name: referencegrant-1 +spec: + from: + - group: gateway.networking.k8s.io + kind: HTTPRoute + namespace: default + to: + - group: multicluster.x-k8s.io + kind: ServiceImport diff --git a/internal/provider/kubernetes/routes.go b/internal/provider/kubernetes/routes.go index b796af65a8d..d3d9fbea6d4 100644 --- a/internal/provider/kubernetes/routes.go +++ b/internal/provider/kubernetes/routes.go @@ -56,7 +56,7 @@ func (r *gatewayAPIReconciler) processTLSRoutes(ctx context.Context, gatewayName if backendNamespace != tlsRoute.Namespace { from := ObjectKindNamespacedName{kind: gatewayapi.KindTLSRoute, namespace: tlsRoute.Namespace, name: tlsRoute.Name} - to := ObjectKindNamespacedName{kind: gatewayapi.KindService, namespace: backendNamespace, name: string(backendRef.Name)} + to := ObjectKindNamespacedName{kind: gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService), namespace: backendNamespace, name: string(backendRef.Name)} refGrant, err := r.findReferenceGrant(ctx, from, to) switch { case err != nil: @@ -142,7 +142,7 @@ func (r *gatewayAPIReconciler) processGRPCRoutes(ctx context.Context, gatewayNam name: grpcRoute.Name, } to := ObjectKindNamespacedName{ - kind: gatewayapi.KindService, + kind: gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService), namespace: backendNamespace, name: string(backendRef.Name), } @@ -293,7 +293,7 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam name: httpRoute.Name, } to := ObjectKindNamespacedName{ - kind: gatewayapi.KindService, + kind: gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService), namespace: backendNamespace, name: string(backendRef.Name), } @@ -360,7 +360,7 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam name: httpRoute.Name, } to := ObjectKindNamespacedName{ - kind: gatewayapi.KindService, + kind: gatewayapi.KindDerefOr(mirrorBackendRef.Kind, gatewayapi.KindService), namespace: backendNamespace, name: string(mirrorBackendRef.Name), } @@ -468,7 +468,7 @@ func (r *gatewayAPIReconciler) processTCPRoutes(ctx context.Context, gatewayName if backendNamespace != tcpRoute.Namespace { from := ObjectKindNamespacedName{kind: gatewayapi.KindTCPRoute, namespace: tcpRoute.Namespace, name: tcpRoute.Name} - to := ObjectKindNamespacedName{kind: gatewayapi.KindService, namespace: backendNamespace, name: string(backendRef.Name)} + to := ObjectKindNamespacedName{kind: gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService), namespace: backendNamespace, name: string(backendRef.Name)} refGrant, err := r.findReferenceGrant(ctx, from, to) switch { case err != nil: @@ -530,7 +530,7 @@ func (r *gatewayAPIReconciler) processUDPRoutes(ctx context.Context, gatewayName if backendNamespace != udpRoute.Namespace { from := ObjectKindNamespacedName{kind: gatewayapi.KindUDPRoute, namespace: udpRoute.Namespace, name: udpRoute.Name} - to := ObjectKindNamespacedName{kind: gatewayapi.KindService, namespace: backendNamespace, name: string(backendRef.Name)} + to := ObjectKindNamespacedName{kind: gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService), namespace: backendNamespace, name: string(backendRef.Name)} refGrant, err := r.findReferenceGrant(ctx, from, to) switch { case err != nil: