diff --git a/README.md b/README.md index b5f7b1b2..4e6641d2 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,9 @@ https://cloud.google.com/run/docs/quickstarts/build-and-deploy [Google App Engine]: https://cloud.google.com/appengine/docs/go/ [Google Cloud Functions]: https://cloud.google.com/functions/ [Knative]: https://github.com/knative/ -[quickstart]: examples/site/howto_local_development/README.md +[quickstart-local]: /examples/site/howto_local_development/README.md +[quickstart-container]: /examples/site/howto_create_container/README.md +[quickstart-cloud-run]: /examples/site/howto_deploy_to_cloud_run/README.md > :warning: This is not ready for production. Expect breaking changes. > We're sharing our progress with the developer community and appreciate @@ -47,8 +49,10 @@ functions -- brought to you by Google. The Functions Framework lets you write lightweight functions that run in many different environments, including: -- Your local development machine - +- Your local development machine - see how to build and run a function in + [local container][quickstart-container] +- [Google Cloud Run] - see how to [deploy functions][quickstart-cloud-run] + to Cloud Run - [Knative]-based environments [Google Cloud Functions] does not currently provide an officially supported C++ @@ -59,7 +63,6 @@ Framework projects. The framework allows you to go from: [examples/hello_world/hello_world.cc] - ```cc #include #include diff --git a/examples/site/howto_create_container/README.md b/examples/site/howto_create_container/README.md index b0032a27..a2471b37 100644 --- a/examples/site/howto_create_container/README.md +++ b/examples/site/howto_create_container/README.md @@ -1,41 +1,117 @@ # How-to Guide: Running your function as Docker container -1. Install [Docker](https://store.docker.com/search?type=edition&offering=community) and - the [`pack` tool](https://buildpacks.io/docs/install-pack/). - -1. Create the `pack` builder for C++. The first time your run this it can take - several minutes, maybe as long as an hour, depending on the capabilities of - your workstation. - ```shell - cd $HOME/functions-framework-cpp - docker build -t gcf-cpp-runtime --target gcf-cpp-runtime -f build_scripts/Dockerfile . - docker build -t gcf-cpp-develop --target gcf-cpp-develop -f build_scripts/Dockerfile . - pack create-builder gcf-cpp-builder:bionic --config pack/builder.toml - pack trust-builder gcf-cpp-builder:bionic - ``` - -1. Build a Docker image from your function using this buildpack: - ```shell - pack build \ - --builder gcf-cpp-builder:bionic \ - --env FUNCTION_SIGNATURE_TYPE=http \ - --env TARGET_FUNCTION=HelloWorld \ - --path examples/site/hello_world_http \ - gcf-cpp-hello-world-http - ``` - -1. Start a Docker container in the background with this image: - ```shell - ID=$(docker run --detach --rm -p 8080:8080 gcf-cpp-hello-world-http) - ``` - -1. Send requests to this function using `curl`: - ```shell - curl http://localhost:8080 - # Output: Hello, World! - ``` - -1. Stop the background container: - ```shell - docker kill "${ID}" - ``` +[repository-gh]: https://github.com/GoogleCloudPlatform/functions-framework-cpp +[docker-install]: https://store.docker.com/search?type=edition&offering=community +[pack-install]: https://buildpacks.io/docs/install-pack/ +[hello-world-http]: /examples/site/hello_world_http/hello_world_http.cc + +This guide shows you how to create a container image for an example function, +and how to run said image in a local container on your workstation. + +## Pre-requisites + +This guide also assumes that you have installed [Docker][docker-install] and +the [pack tool][pack-install] on your workstation. + +In this guide we will be using the [HTTP hello word][hello-world-http] function: + +```cc +#include +#include +#include + +namespace gcf = ::google::cloud::functions; + +gcf::HttpResponse hello_world_http(gcf::HttpRequest request) { + auto greeting = [r = std::move(request)] { + auto request_json = nlohmann::json::parse(r.payload(), /*cb=*/nullptr, + /*allow_exceptions=*/false); + if (request_json.count("name") && request_json["name"].is_string()) { + return "Hello " + request_json.value("name", "World") + "!"; + } + return std::string("Hello World!"); + }; + + gcf::HttpResponse response; + response.set_payload(greeting()); + response.set_header("content-type", "text/plain"); + return response; +} +``` + +## Getting the code for this example + +This example is included in the Functions Framework for C++ +[source code repository][repository]. Download this code as usual: + +```shell +cd $HOME +git clone https://github.com/GoogleCloudPlatform/functions-framework-cpp +``` + +The rest of this guide will assume you are issuing commands in the framework's +clone: + +```shell +cd $HOME/functions-framework-cpp +``` + +## Setting up the buildpacks builder + +We will be using a [buildpacks][buildpacks] builder to create the container +image deployed to Cloud Run. The first time your run these commands it can take +several minutes, maybe as long as an hour, depending on your workstation's +performance. + +```sh +docker build -t gcf-cpp-develop -f build_scripts/Dockerfile . +docker build -t gcf-cpp-runtime --target gcf-cpp-runtime -f build_scripts/Dockerfile build_scripts +pack create-builder gcf-cpp-builder:bionic --config pack/builder.toml +pack trust-builder gcf-cpp-builder:bionic +pack set-default-builder gcf-cpp-builder:bionic +``` + +## Building a Docker image + +Build a Docker image from your function using this buildpack: + +```shell +pack build \ + --builder gcf-cpp-builder:bionic \ + --env FUNCTION_SIGNATURE_TYPE=http \ + --env TARGET_FUNCTION=hello_world_http \ + --path examples/site/hello_world_http \ + gcf-cpp-hello-world-http +``` + +## Starting a local container + +Start a Docker container in the background the image you just created: + +```shell +ID=$(docker run --detach --rm -p 8080:8080 gcf-cpp-hello-world-http) +``` + +## Send a request to your function + +You can use `curl` (or a similar HTTP client) to send requests to your +function: + +```shell +curl http://localhost:8080 +# Output: Hello, World! +``` + +## Cleanup + +Stop the background container: + +```shell +docker kill "${ID}" +``` + +And delete the local image: + +```shell +docker image rm gcf-cpp-hello-world-http +``` \ No newline at end of file diff --git a/examples/site/howto_deploy_to_cloud_run/README.md b/examples/site/howto_deploy_to_cloud_run/README.md new file mode 100644 index 00000000..08e94122 --- /dev/null +++ b/examples/site/howto_deploy_to_cloud_run/README.md @@ -0,0 +1,149 @@ +# How-to Guide: Deploy your function to Cloud Run + +[repository-gh]: https://github.com/GoogleCloudPlatform/functions-framework-cpp +[howto-create-container]: /examples/site/howto_create_container/README.md +[cloud-run-quickstarts]: https://cloud.google.com/run/docs/quickstarts +[gcp-quickstarts]: https://cloud.google.com/gcp/getting-started +[buildpacks]: https://buildpacks.io +[docker-install]: https://store.docker.com/search?type=edition&offering=community +[pack-install]: https://buildpacks.io/docs/install-pack/ +[hello-world-http]: /examples/site/hello_world_http/hello_world_http.cc + +## Pre-requisites + +This guide assumes you are familiar with Google Cloud, and that you have a GCP +project with Cloud Run enabled. If needed, consult: +* the [GCP quickstarts][gcp-quickstarts] to setup a GCP project +* the [cloud run quickstarts][cloud-run-quickstarts] to setup Cloud Run in your + project + +This guide also assumes that you have installed [Docker][docker-install] and +the [pack tool][pack-install] on your workstation. + +In this guide we will be using the [HTTP hello word][hello-world-http] function: + +```cc +#include +#include +#include + +namespace gcf = ::google::cloud::functions; + +gcf::HttpResponse hello_world_http(gcf::HttpRequest request) { + auto greeting = [r = std::move(request)] { + auto request_json = nlohmann::json::parse(r.payload(), /*cb=*/nullptr, + /*allow_exceptions=*/false); + if (request_json.count("name") && request_json["name"].is_string()) { + return "Hello " + request_json.value("name", "World") + "!"; + } + return std::string("Hello World!"); + }; + + gcf::HttpResponse response; + response.set_payload(greeting()); + response.set_header("content-type", "text/plain"); + return response; +} +``` + +## Getting the code for this example + +This example is included in the Functions Framework for C++ +[source code repository][repository]. Download this code as usual: + +```shell +cd $HOME +git clone https://github.com/GoogleCloudPlatform/functions-framework-cpp +``` + +The rest of this guide will assume you are issuing commands in the framework's +clone: + +```shell +cd $HOME/functions-framework-cpp +``` + +## Setting up the buildpacks builder + +We will be using a [buildpacks][buildpacks] builder to create the container +image deployed to Cloud Run. The first time your run these commands it can take +several minutes, maybe as long as an hour, depending on your workstation's +performance. + +```sh +docker build -t gcf-cpp-develop -f build_scripts/Dockerfile . +docker build -t gcf-cpp-runtime --target gcf-cpp-runtime -f build_scripts/Dockerfile build_scripts +pack create-builder gcf-cpp-builder:bionic --config pack/builder.toml +pack trust-builder gcf-cpp-builder:bionic +pack set-default-builder gcf-cpp-builder:bionic +``` + +## Building a Docker image + +Set the `GOOGLE_CLOUD_PROJECT` shell variable to the project id of your GCP +project, and create a docker image with your function: + +```shell +GOOGLE_CLOUD_PROJECT=... # put the right value here +pack build \ + --builder gcf-cpp-builder:bionic \ + --env FUNCTION_SIGNATURE_TYPE=http \ + --env TARGET_FUNCTION=hello_world_http \ + --path examples/site/hello_world_http \ + "gcr.io/${GOOGLE_CLOUD_PROJECT}/gcf-cpp-hello-world-http" +``` + +Push this new container image to Google Container Registry: + +```shell +docker push "gcr.io/${GOOGLE_CLOUD_PROJECT}/gcf-cpp-hello-world-http:latest" +``` + +## Deploy to Cloud Run + +To deploy this image in Cloud Run use this command. You need to select +a Cloud Run region for your deployment. We will use `us-central1` in this +guide: + +```sh +gcloud run deploy gcf-cpp-hello-world-http \ + --project="${GOOGLE_CLOUD_PROJECT}" \ + --image="gcr.io/${GOOGLE_CLOUD_PROJECT}/gcf-cpp-hello-world-http:latest" \ + --region="us-central1" \ + --platform="managed" \ + --allow-unauthenticated +``` + +## Send a request to your function + +Find out what URL was assigned to your function, and use `curl` to send a request: + +```shell +HTTP_SERVICE_URL=$(gcloud run services describe \ + --project="${GOOGLE_CLOUD_PROJECT}" \ + --platform="managed" \ + --region="us-central1" \ + --format="value(status.url)" \ + gcf-cpp-hello-world-http) + +curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" "${HTTP_SERVICE_URL}" +# Output: Hello World! +``` + +## Cleanup + +Delete the Cloud Run deployment: + +```sh +gcloud run services delete gcf-cpp-hello-world-http \ + --project="${GOOGLE_CLOUD_PROJECT}" \ + --region="us-central1" \ + --platform="managed" +``` + +And the container image: + +```shell +gcloud container images delete \ + "gcr.io/${GOOGLE_CLOUD_PROJECT}/gcf-cpp-hello-world-http:latest" +```