diff --git a/community/samples/README.md b/community/samples/README.md index 898cccf4240..106bfa7f8f3 100644 --- a/community/samples/README.md +++ b/community/samples/README.md @@ -12,9 +12,9 @@ something isn't working, lend a helping hand and fix it in a PR. Knative Serving sample apps. -| Sample Name | Description | Language(s) | -| ----------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Hello World | A quick introduction to Knative Serving that highlights how to deploy an app. | [Clojure](./serving/helloworld-clojure/README.md), [Dart](./serving/helloworld-dart/README.md), [Elixir](./serving/helloworld-elixir/README.md), [Haskell](./serving/helloworld-haskell/README.md), [Java - Micronaut](./serving/helloworld-java-micronaut/README.md), [Java - Quarkus](./serving/helloworld-java-quarkus/README.md), [Rust](./serving/helloworld-rust/README.md), [Swift](./serving/helloworld-swift/README.md), [Vertx](./serving/helloworld-vertx/README.md) | +| Sample Name | Description | Language(s) | +| ----------- | ----------- | ----------- | +| Hello World | A quick introduction to Knative Serving that highlights how to deploy an app. | [Clojure](./serving/helloworld-clojure/README.md), [Dart](./serving/helloworld-dart/README.md), [Elixir](./serving/helloworld-elixir/README.md), [Haskell](./serving/helloworld-haskell/README.md), [Java - Micronaut](./serving/helloworld-java-micronaut/README.md), [Java - Quarkus](./serving/helloworld-java-quarkus/README.md), [R - Go Server](./serving/helloworld-r/README.md), [R](./serving/hellowolrd-rserver/README.md), [Rust](./serving/helloworld-rust/README.md), [Swift](./serving/helloworld-swift/README.md), [Vertx](./serving/helloworld-vertx/README.md) | #### Eventing and Eventing Resources samples diff --git a/community/samples/serving/helloworld-rserver/Dockerfile b/community/samples/serving/helloworld-rserver/Dockerfile new file mode 100644 index 00000000000..3b3c450ec18 --- /dev/null +++ b/community/samples/serving/helloworld-rserver/Dockerfile @@ -0,0 +1,13 @@ +# The official R base image +# https://hub.docker.com/_/r-base +FROM r-base:3.6.0 + +# Copy local code to the container image. +WORKDIR /usr/src/app +COPY . . + +# Install R packages +RUN Rscript -e "install.packages('plumber', repos='http://cran.us.r-project.org/')" + +# Run the web service on container startup. +CMD ["Rscript", "server.R"] diff --git a/community/samples/serving/helloworld-rserver/HelloWorld.R b/community/samples/serving/helloworld-rserver/HelloWorld.R new file mode 100644 index 00000000000..f09d12f34e3 --- /dev/null +++ b/community/samples/serving/helloworld-rserver/HelloWorld.R @@ -0,0 +1,9 @@ +#' HelloWorld function +#' @get / +#' @html +function() { + TARGET <- Sys.getenv("TARGET", "World") + + message = paste("Hello ", TARGET, "!", sep = "") + print(message) +} diff --git a/community/samples/serving/helloworld-rserver/README.md b/community/samples/serving/helloworld-rserver/README.md new file mode 100644 index 00000000000..fdef8cc3280 --- /dev/null +++ b/community/samples/serving/helloworld-rserver/README.md @@ -0,0 +1,186 @@ +--- +title: "Hello World - R server" +linkTitle: "R server" +weight: 1 +type: "docs" +--- + +A simple web app created with R package, [plumber](https://www.rplumber.io). +plumber creates a REST API by adding annotations to your R code. The R script +reads an environment variable `TARGET` and prints `Hello ${TARGET}!`. If the +`TARGET` environment variable is not specified, the script uses `World`. + +Follow the steps below to create the sample code and then deploy the app to your +cluster. You can also download a working copy of the sample, by running the +following commands: + +```shell +git clone -b "{{< branch >}}" https://github.com/knative/docs knative-docs +cd knative-docs/docs/serving/samples/hello-world/helloworld-r +``` + +## Before you begin + +- A Kubernetes cluster with Knative installed. Follow the + [installation instructions](../../../../install/README.md) if you need to + create one. +- [Docker](https://www.docker.com) installed and running on your local machine, + and a Docker Hub account configured (we'll use it for a container registry). + +## Recreating the sample code + +1. Create a new file named `HelloWorld.R` and paste the following script: + + ```R + #' HelloWorld function + #' @get / + #' @html + function() { + TARGET <- Sys.getenv("TARGET", "World") + + message = paste("Hello ", TARGET, "!", sep = "") + print(message) + } + ``` + + This file defines the endpoint `/`, using plumber annotations. + + 1. Create a new file named `server.R` and paste the following code: + + ```R + library(plumber) # https://www.rplumber.io/ + + # Translate the HelloWorld file into a Plumber API + r <- plumb("HelloWorld.R") + # Get the PORT env var + PORT <- strtoi(Sys.getenv("PORT", 8080)) + # Run the API + r$run(port=PORT, host="0.0.0.0") + ``` + + 1. Create a new file named `Dockerfile` and paste the following code: + + ```docker + # The official R base image + # https://hub.docker.com/_/r-base + FROM r-base:3.6.0 + + # Copy local code to the container image. + WORKDIR /usr/src/app + COPY . . + + # Install R packages + RUN Rscript -e "install.packages('plumber', repos='http://cran.us.r-project.org/')" + + # Run the web service on container startup. + CMD ["Rscript", "server.R"] + ``` + + +1. Create a new file, `service.yaml` and copy the following service definition + into the file. Make sure to replace `{username}` with your Docker Hub + username. + + ```yaml + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + metadata: + name: helloworld-rserver + namespace: default + spec: + template: + spec: + containers: + - image: docker.io/{username}/helloworld-rserver + env: + - name: TARGET + value: "R Server Sample v1" + ``` + +## Building and deploying the sample + +Once you have recreated the sample code files (or used the files in the sample +folder) you're ready to build and deploy the sample app. + +1. Use Docker to build the sample code into a container. To build and push with + Docker Hub, run these commands replacing `{username}` with your Docker Hub + username: + + ```shell + # Build the container on your local machine + docker build -t {username}/helloworld-rserver . + + # Push the container to docker registry + docker push {username}/helloworld-rserver + ``` + +1. After the build has completed and the container is pushed to docker hub, you + can deploy the app into your cluster. Ensure that the container image value + in `service.yaml` matches the container you built in the previous step. Apply + the configuration using `kubectl`: + + ```shell + kubectl apply --filename service.yaml + ``` + +1. Now that your service is created, Knative performs the following steps: + + - Create a new immutable revision for this version of the app. + - Network programming to create a route, ingress, service, and load balance + for your app. + - Automatically scale your pods up and down (including to zero active pods). + +1. Run the following command to find the external IP address for your service. + The ingress IP for your cluster is returned. If you just created your + cluster, you might need to wait and rerun the command until your service gets + asssigned an external IP address. + + ```shell + kubectl get svc knative-ingressgateway --namespace istio-system + ``` + + Example: + + ```shell + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + knative-ingressgateway LoadBalancer 10.23.247.74 35.203.155.229 80:32380/TCP,443:32390/TCP,32400:32400/TCP 2d + + ``` + +1. Run the following command to find the domain URL for your service: + + ```shell + kubectl get ksvc helloworld-r --output=custom-columns=NAME:.metadata.name,URL:.status.url + ``` + + Example: + + ```shell + NAME URL + helloworld-r http://helloworld-r.default.example.com + ``` + +1. Test your app by sending it a request. Use the following `curl` command with + the domain URL `helloworld-rserver.default.example.com` and `EXTERNAL-IP` + address that you retrieved in the previous steps: + + ```shell + curl -H "Host: helloworld-rserver.default.example.com" http://{EXTERNAL_IP_ADDRESS} + ``` + + Example: + + ```shell + curl -H "Host: helloworld-rserver.default.example.com" http://35.203.155.229 + [1] "Hello R Sample v1!" + ``` + + > Note: Add `-v` option to get more detail if the `curl` command failed. + +## Removing the sample app deployment + +To remove the sample app from your cluster, delete the service record: + +```shell +kubectl delete --filename service.yaml +``` diff --git a/community/samples/serving/helloworld-rserver/server.R b/community/samples/serving/helloworld-rserver/server.R new file mode 100644 index 00000000000..5c05dba0f2b --- /dev/null +++ b/community/samples/serving/helloworld-rserver/server.R @@ -0,0 +1,8 @@ +library(plumber) # https://www.rplumber.io/ + +# Translate the HelloWorld file into a Plumber API +r <- plumb("HelloWorld.R") +# Get the PORT env var +PORT <- strtoi(Sys.getenv("PORT", 8080)) +# Run the API +r$run(port=PORT, host="0.0.0.0") diff --git a/community/samples/serving/helloworld-rserver/service.yaml b/community/samples/serving/helloworld-rserver/service.yaml new file mode 100644 index 00000000000..dbf64914ef8 --- /dev/null +++ b/community/samples/serving/helloworld-rserver/service.yaml @@ -0,0 +1,13 @@ +apiVersion: serving.knative.dev/v1alpha1 +kind: Service +metadata: + name: helloworld-rserver + namespace: default +spec: + template: + spec: + containers: + - image: docker.io/{username}/helloworld-rserver + env: + - name: TARGET + value: "R Server Sample v1"