Skip to content

Commit

Permalink
feat: deploy grpc gateway to cloud run with an apigee proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
OmidTahouri committed Jul 4, 2024
1 parent 328b46b commit 1f81496
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 2 deletions.
63 changes: 61 additions & 2 deletions tools/grpc-http-gateway-generator/pipeline.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@

set -e # exit on first error

SCRIPTPATH="$( cd "$(dirname "$0")" || exit >/dev/null 2>&1 ; pwd -P )"
export PATH="$PATH:$SCRIPTPATH/../../tools/apigee-sackmesser/bin"

GCP_REGION=europe-west2

# Run a currency mock service
docker run --name grpc-mock --detach \
-p 9090:9090 -e PORT=9090 \
-e DISABLE_PROFILER=1 -e DISABLE_DEBUGGER=1 \
gcr.io/google-samples/microservices-demo/currencyservice:v0.10.0 &> /dev/null

# Trap for cleanup
Expand All @@ -37,7 +43,60 @@ GATEWAY_PID=$!
trap 'docker kill grpc-mock &> /dev/null || true; docker rm grpc-mock &> /dev/null || true; kill $GATEWAY_PID || true' EXIT INT TERM

# Smoke test the gRPC Gateway
curl --fail -X POST localhost:8080/hipstershop.CurrencyService/Convert \
curl -X POST localhost:8080/hipstershop.CurrencyService/Convert \
-d '{"from": {"units": 3, "currency_code": "USD", "nanos": 0}, "to_code": "CHF"}'

curl --fail -X POST localhost:8080/hipstershop.CurrencyService/GetSupportedCurrencies
curl -X POST localhost:8080/hipstershop.CurrencyService/GetSupportedCurrencies

# Build the grpc-gateway container and push it to Artifact Registry
(cd generated/gateway && docker build -t grpc-gateway:latest .)

DOCKER_REPO="docker"
if [ -z "$(gcloud artifacts repositories describe $DOCKER_REPO --location=$GCP_REGION --format='get(name)')" ]; then \
gcloud artifacts repositories create $DOCKER_REPO \
--repository-format=docker \
--location=$GCP_REGION \
--project=$APIGEE_X_ORG
fi

IMAGE_PATH="$GCP_REGION-docker.pkg.dev/$APIGEE_X_ORG/$DOCKER_REPO/grpc-gateway"
docker tag grpc-gateway:latest "$IMAGE_PATH:latest"
docker push "$IMAGE_PATH"

sed -i.bak "s|GRPC_GATEWAY_IMAGE|$IMAGE_PATH|g" "templates/cloud-run-service.yaml"

gcloud run services replace templates/cloud-run-service.yaml \
--project $APIGEE_X_ORG --region $GCP_REGION \
--platform managed

# Generate and deploy an Apigee API proxy for the currency-service
SA_EMAIL="apigee-runtime@$APIGEE_X_ORG.iam.gserviceaccount.com"

if [ -z "$(gcloud iam service-accounts list --filter "$SA_EMAIL" --format="value(email)" --project "$APIGEE_X_ORG")" ]; then
gcloud iam service-accounts create apigee-runtime \
--description="Apigee Runtime" --project "$APIGEE_X_ORG"
fi

gcloud run services add-iam-policy-binding currency-service \
--member="serviceAccount:$SA_EMAIL" \
--role='roles/run.invoker' \
--region=$GCP_REGION \
--platform=managed --project "$APIGEE_X_ORG"

CLOUD_RUN_URL=$(gcloud run services list --filter currency-service --format="value(status.url)" --limit 1)
sed -i "s|CLOUD_RUN_URL|$CLOUD_RUN_URL|g" "templates/apiproxy/targets/default.xml"

TOKEN="$(gcloud config config-helper --force-auth-refresh --format json | jq -r '.credential.access_token')"
sackmesser deploy -d "$SCRIPTPATH/templates" -o "$APIGEE_X_ORG" -e "$APIGEE_X_ENV" -t "$TOKEN" --deployment-sa "$SA_EMAIL"

# Test the Apigee API
curl -X GET "https://$APIGEE_X_HOSTNAME/currency/v1/currencies"

curl -X POST "https://$APIGEE_X_HOSTNAME/currency/v1/convert" \
-d '{"from": {"units": 3, "currency_code": "USD", "nanos": 0}, "to_code": "CHF"}'

# Clean up
# undeploy and delete proxy
# delete CR service
# delete SA
# delete AR registry
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
Copyright 2024 Google LLC
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.
-->
<APIProxy revision="1" name="currency-v1">
</APIProxy>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!--
Copyright 2024 Google LLC
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.
-->
<AssignMessage name="AM.SetConversionPath">
<AssignVariable>
<Name>flow.target.pathsuffix</Name>
<Value>/hipstershop.CurrencyService/Convert</Value>
</AssignVariable>
</AssignMessage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!--
Copyright 2024 Google LLC
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.
-->
<AssignMessage name="AM.SetCurrenciesPath">
<AssignVariable>
<Name>flow.target.pathsuffix</Name>
<Value>/hipstershop.CurrencyService/GetSupportedCurrencies</Value>
</AssignVariable>
</AssignMessage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!--
Copyright 2024 Google LLC
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.
-->
<HTTPModifier continueOnError="false" enabled="true" name="HM.SetTargetMethod">
<Set>
<Verb>POST</Verb>
</Set>
</HTTPModifier>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!--
Copyright 2024 Google LLC
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.
-->
<Javascript timeLimit="200" name="JS.SetTargetPath">
<ResourceURL>jsc://set-target-path.js</ResourceURL>
</Javascript>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<!--
Copyright 2024 Google LLC
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.
-->
<ProxyEndpoint name="default">
<Flows>
<Flow>
<Condition>request.verb = "GET" and proxy.pathsuffix = "/currencies"</Condition>
<Request>
<Step>
<Name>AM.SetCurrenciesPath</Name>
</Step>
</Request>
</Flow>
<Flow>
<Condition>request.verb = "POST" and proxy.pathsuffix = "/convert"</Condition>
<Request>
<Step>
<Name>AM.SetConversionPath</Name>
</Step>
</Request>
</Flow>
</Flows>
<PostFlow>
<Request>
<Step>
<Name>HM.SetTargetMethod</Name>
</Step>
</Request>
</PostFlow>
<HTTPProxyConnection>
<BasePath>/currency/v1</BasePath>
</HTTPProxyConnection>
<RouteRule name="default">
<TargetEndpoint>default</TargetEndpoint>
</RouteRule>
</ProxyEndpoint>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
Copyright 2024 Google LLC
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.
*/

context.setVariable("target.copy.pathsuffix", false)

var existingTargetUrl = context.getVariable("target.url");
var targetPath = context.getVariable("flow.target.pathsuffix") || ""; // retrieve custom path, set by AM policies
var queryString = context.getVariable("request.querystring") || "";

var updatedTargetUrl = existingTargetUrl + targetPath + (queryString ? "?"+queryString : "");

context.setVariable("target.url",
existingTargetUrl + // use target base URL
targetPath + // append custom path
(queryString ? "?"+queryString : "") // conditionally append query params
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!--
Copyright 2024 Google LLC
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.
-->
<TargetEndpoint name="default">
<PreFlow>
<Request>
<Step>
<Name>JS.SetTargetPath</Name>
</Step>
</Request>
</PreFlow>
<HTTPTargetConnection>
<Authentication>
<GoogleIDToken>
<Audience>CLOUD_RUN_URL</Audience>
</GoogleIDToken>
</Authentication>
<URL>CLOUD_RUN_URL</URL>
</HTTPTargetConnection>
</TargetEndpoint>
53 changes: 53 additions & 0 deletions tools/grpc-http-gateway-generator/templates/cloud-run-service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright 2024 Google LLC

# 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.

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: currency-service
spec:
template:
spec:
containers:
- name: grpc-gateway

Check failure on line 23 in tools/grpc-http-gateway-generator/templates/cloud-run-service.yaml

View workflow job for this annotation

GitHub Actions / Lint Codebase

[indentation] wrong indentation: expected 8 but found 6
image: GRPC_GATEWAY_IMAGE
ports:
- name: http1

Check failure on line 26 in tools/grpc-http-gateway-generator/templates/cloud-run-service.yaml

View workflow job for this annotation

GitHub Actions / Lint Codebase

[indentation] wrong indentation: expected 10 but found 8
containerPort: 8080
resources:
limits:
cpu: 1000m
memory: 512Mi
startupProbe:
timeoutSeconds: 240
periodSeconds: 240
failureThreshold: 1
tcpSocket:
port: 8080
- name: currencyservice-1
image: gcr.io/google-samples/microservices-demo/currencyservice@sha256:e08a1f5d4e4b74fc3d6222d535a11615e8201e7075a090c1ba4436ef1f1cbe7b
env:
- name: PORT

Check failure on line 41 in tools/grpc-http-gateway-generator/templates/cloud-run-service.yaml

View workflow job for this annotation

GitHub Actions / Lint Codebase

[indentation] wrong indentation: expected 10 but found 8
value: '9090'
resources:
limits:
cpu: 1000m
memory: 512Mi
startupProbe:
timeoutSeconds: 1
periodSeconds: 10
failureThreshold: 3
grpc:
port: 9090
service: currencyservice-v1

0 comments on commit 1f81496

Please sign in to comment.