mirror of https://github.com/knative/docs.git
Move community files to index.md (#3471)
This commit is contained in:
parent
ca68fa17b0
commit
73e076f5b1
|
|
@ -1,6 +0,0 @@
|
||||||
Welcome to the Knative Annual Reports page. Feedback and comments are welcome at [knative-steering@googlegroups.com](mailto:knative-steering@googlegroups.com).
|
|
||||||
|
|
||||||
| Annual Reports |
|
|
||||||
| -------------- |
|
|
||||||
| [2019](https://github.com/knative/community/tree/main/annual_reports/Knative%202019%20Annual%20Report.pdf) |
|
|
||||||
| [2020](https://github.com/knative/community/tree/main/annual_reports/Knative%202020%20Annual%20Report.pdf) |
|
|
||||||
|
|
@ -5,4 +5,10 @@ weight: 40
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
Welcome to the Knative Annual Reports page. Feedback and comments are welcome at [knative-steering@googlegroups.com](mailto:knative-steering@googlegroups.com).
|
||||||
|
|
||||||
|
| Annual Reports |
|
||||||
|
| -------------- |
|
||||||
|
| [2019](https://github.com/knative/community/tree/main/annual_reports/Knative%202019%20Annual%20Report.pdf) |
|
||||||
|
| [2020](https://github.com/knative/community/tree/main/annual_reports/Knative%202020%20Annual%20Report.pdf) |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
Welcome to the Knative Community Meetup page!
|
|
||||||
|
|
||||||
The virtual event is designed for end users, a space for our community to meet, get to know each other, and learn about uses and applications of Knative.
|
|
||||||
|
|
||||||
Catch up with past community meetups on our [YouTube channel](https://www.youtube.com/playlist?list=PLQjzPfIiEQLLyCyLBKLlwDLfE_A-P7nyg).
|
|
||||||
|
|
||||||
Here we will list all the information related to past and future events.
|
|
||||||
|
|
||||||
Stay tuned for new events by subscribing to our [calendar](https://calendar.google.com/calendar/embed?src=knative.team_9q83bg07qs5b9rrslp5jor4l6s%40group.calendar.google.com&ctz=America%2FLos_Angeles) ([iCal export file](https://calendar.google.com/calendar/ical/knative.team_9q83bg07qs5b9rrslp5jor4l6s%40group.calendar.google.com/public/basic.ics)) and following us on [Twitter](https://twitter.com/KnativeProject).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2020-05-14 – Knative Community Meetup #2
|
|
||||||
|
|
||||||
Video: https://youtu.be/24owwOKj86E
|
|
||||||
|
|
||||||
## Agenda
|
|
||||||
- Welcome! (5’)
|
|
||||||
- Announce recording of meeting.
|
|
||||||
- Update from the Steering Committee (15’)
|
|
||||||
- TOC election results (Tomas Isdal)
|
|
||||||
- Working groups updates (5’)
|
|
||||||
- Demo - "Automating service delivery with bindings" by Evan Anderson, software engineer at VMware (30’)
|
|
||||||
- Demo discussion / conversation (15’-20’)
|
|
||||||
- Close (5’)
|
|
||||||
- Take the [survey](https://docs.google.com/forms/d/e/1FAIpQLSebw2IOjmnStiUhPpnndpjyuBUoziZOw9PK9fnJeFBQX0QxWw/viewform)! (it’s good karma)
|
|
||||||
|
|
||||||
## TOC Election results
|
|
||||||
- Nghia Tran (Google) - new member
|
|
||||||
- Markus Thömmes (Red Hat) - new member
|
|
||||||
- Grant Rodgers (Google) - new member
|
|
||||||
- Matt Moore (VMWare) - existing member
|
|
||||||
- Evan Anderson (VMWare) - existing member
|
|
||||||
Congratulations to the newly elected members! ✨
|
|
||||||
|
|
||||||
## Working group updates
|
|
||||||
- Autoscaling WG
|
|
||||||
- Big improvements to the autoscaling documentation, both internally and user-facing. Go check them out!
|
|
||||||
- User facing docs: https://knative.dev/docs/serving/configuring-autoscaling/
|
|
||||||
- Technical docs: https://github.com/knative/serving/blob/main/docs/scaling/SYSTEM.md
|
|
||||||
- A lot of improvements to the loadbalancing in Knative has landed, vastly improving latency for concurrency-limited revisions. Give HEAD a whirl if you’re seeing issues there.
|
|
||||||
- Speaking of issues: We need your input!
|
|
||||||
- We’re preparing a questionnaire to gather structured feedback regarding the types of workloads you’re running and which settings you find yourself tweaking to make autoscaling work in your favor.
|
|
||||||
- While we’re preparing that (will likely be sent out via the knative-users list), please feel free to give us free-form feedback on anything autoscaling. That can either be Github issues if you’re having issues, a thread on knative-users or send it to me privately if you can’t share publicly.
|
|
||||||
|
|
||||||
## Eventing
|
|
||||||
- Update on Brokers
|
|
||||||
- https://github.com/knative/eventing/issues/3139
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2020-04-16 – Knative Community Meetup #1
|
|
||||||
Video: https://www.youtube.com/watch?v=k0QJEyV4U-4
|
|
||||||
|
|
||||||
Agenda:
|
|
||||||
- Welcome! (5’)
|
|
||||||
- Announce recording of meeting.
|
|
||||||
- Update from the Steering Committee (5’)
|
|
||||||
- TOC election announcement (Brenda Chan)
|
|
||||||
- Working groups updates (15’-20’)
|
|
||||||
- Eventing (Aleksander Slominski and Davy Odom)
|
|
||||||
- Networking (Nghia Tran)
|
|
||||||
- Operation (Vincent Hou)
|
|
||||||
- Client (Roland Huss)
|
|
||||||
- [Demo - "Tracking the Bitcoin ledger" - by Johana Saladas (IBM) (30’)](https://www.youtube.com/watch?v=sGi_LuAaaT0)
|
|
||||||
- Demo discussion / conversation (15’-20’)
|
|
||||||
- Close (5’)
|
|
||||||
- Take the [survey](https://docs.google.com/forms/d/e/1FAIpQLSebw2IOjmnStiUhPpnndpjyuBUoziZOw9PK9fnJeFBQX0QxWw/viewform)! (it’s good karma)
|
|
||||||
|
|
||||||
The demo for this first community meetup is "Tracking the Bitcoin ledger", designed and carried out by @josiemundi, software engineer at IBM. Thank you for volunteering, Johana!
|
|
||||||
|
|
||||||
Here are the resources from the demo:
|
|
||||||
- https://github.com/josiemundi/knative-eventing-blockchain-demo
|
|
||||||
- https://github.com/josiemundi/knative-bitcoin-websocket-eventsource
|
|
||||||
|
|
@ -5,4 +5,78 @@ weight: 30
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
Welcome to the Knative Community Meetup page!
|
||||||
|
|
||||||
|
The virtual event is designed for end users, a space for our community to meet, get to know each other, and learn about uses and applications of Knative.
|
||||||
|
|
||||||
|
Catch up with past community meetups on our [YouTube channel](https://www.youtube.com/playlist?list=PLQjzPfIiEQLLyCyLBKLlwDLfE_A-P7nyg).
|
||||||
|
|
||||||
|
Here we will list all the information related to past and future events.
|
||||||
|
|
||||||
|
Stay tuned for new events by subscribing to our [calendar](https://calendar.google.com/calendar/embed?src=knative.team_9q83bg07qs5b9rrslp5jor4l6s%40group.calendar.google.com&ctz=America%2FLos_Angeles) ([iCal export file](https://calendar.google.com/calendar/ical/knative.team_9q83bg07qs5b9rrslp5jor4l6s%40group.calendar.google.com/public/basic.ics)) and following us on [Twitter](https://twitter.com/KnativeProject).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2020-05-14 – Knative Community Meetup #2
|
||||||
|
|
||||||
|
Video: https://youtu.be/24owwOKj86E
|
||||||
|
|
||||||
|
## Agenda
|
||||||
|
- Welcome! (5’)
|
||||||
|
- Announce recording of meeting.
|
||||||
|
- Update from the Steering Committee (15’)
|
||||||
|
- TOC election results (Tomas Isdal)
|
||||||
|
- Working groups updates (5’)
|
||||||
|
- Demo - "Automating service delivery with bindings" by Evan Anderson, software engineer at VMware (30’)
|
||||||
|
- Demo discussion / conversation (15’-20’)
|
||||||
|
- Close (5’)
|
||||||
|
- Take the [survey](https://docs.google.com/forms/d/e/1FAIpQLSebw2IOjmnStiUhPpnndpjyuBUoziZOw9PK9fnJeFBQX0QxWw/viewform)! (it’s good karma)
|
||||||
|
|
||||||
|
## TOC Election results
|
||||||
|
- Nghia Tran (Google) - new member
|
||||||
|
- Markus Thömmes (Red Hat) - new member
|
||||||
|
- Grant Rodgers (Google) - new member
|
||||||
|
- Matt Moore (VMWare) - existing member
|
||||||
|
- Evan Anderson (VMWare) - existing member
|
||||||
|
Congratulations to the newly elected members! ✨
|
||||||
|
|
||||||
|
## Working group updates
|
||||||
|
- Autoscaling WG
|
||||||
|
- Big improvements to the autoscaling documentation, both internally and user-facing. Go check them out!
|
||||||
|
- User facing docs: https://knative.dev/docs/serving/configuring-autoscaling/
|
||||||
|
- Technical docs: https://github.com/knative/serving/blob/main/docs/scaling/SYSTEM.md
|
||||||
|
- A lot of improvements to the loadbalancing in Knative has landed, vastly improving latency for concurrency-limited revisions. Give HEAD a whirl if you’re seeing issues there.
|
||||||
|
- Speaking of issues: We need your input!
|
||||||
|
- We’re preparing a questionnaire to gather structured feedback regarding the types of workloads you’re running and which settings you find yourself tweaking to make autoscaling work in your favor.
|
||||||
|
- While we’re preparing that (will likely be sent out via the knative-users list), please feel free to give us free-form feedback on anything autoscaling. That can either be Github issues if you’re having issues, a thread on knative-users or send it to me privately if you can’t share publicly.
|
||||||
|
|
||||||
|
## Eventing
|
||||||
|
- Update on Brokers
|
||||||
|
- https://github.com/knative/eventing/issues/3139
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2020-04-16 – Knative Community Meetup #1
|
||||||
|
Video: https://www.youtube.com/watch?v=k0QJEyV4U-4
|
||||||
|
|
||||||
|
Agenda:
|
||||||
|
- Welcome! (5’)
|
||||||
|
- Announce recording of meeting.
|
||||||
|
- Update from the Steering Committee (5’)
|
||||||
|
- TOC election announcement (Brenda Chan)
|
||||||
|
- Working groups updates (15’-20’)
|
||||||
|
- Eventing (Aleksander Slominski and Davy Odom)
|
||||||
|
- Networking (Nghia Tran)
|
||||||
|
- Operation (Vincent Hou)
|
||||||
|
- Client (Roland Huss)
|
||||||
|
- [Demo - "Tracking the Bitcoin ledger" - by Johana Saladas (IBM) (30’)](https://www.youtube.com/watch?v=sGi_LuAaaT0)
|
||||||
|
- Demo discussion / conversation (15’-20’)
|
||||||
|
- Close (5’)
|
||||||
|
- Take the [survey](https://docs.google.com/forms/d/e/1FAIpQLSebw2IOjmnStiUhPpnndpjyuBUoziZOw9PK9fnJeFBQX0QxWw/viewform)! (it’s good karma)
|
||||||
|
|
||||||
|
The demo for this first community meetup is "Tracking the Bitcoin ledger", designed and carried out by @josiemundi, software engineer at IBM. Thank you for volunteering, Johana!
|
||||||
|
|
||||||
|
Here are the resources from the demo:
|
||||||
|
- https://github.com/josiemundi/knative-eventing-blockchain-demo
|
||||||
|
- https://github.com/josiemundi/knative-bitcoin-websocket-eventsource
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
Get up and running with one of the community code samples. These samples are
|
|
||||||
contributed and maintained by members of the Knative community.
|
|
||||||
|
|
||||||
Note: It is possible that one or more samples might become outdated or the
|
|
||||||
original author is unable to maintain their contribution. If you find that
|
|
||||||
something isn't working, lend a helping hand and fix it in a PR.
|
|
||||||
|
|
||||||
[Learn more about the lifespan of samples](https://github.com/knative/docs/tree/main/CONTRIBUTING.md#user-focused-content)
|
|
||||||
|
|
||||||
[**See all Knative code samples**](../../docs/samples.md)
|
|
||||||
|
|
||||||
### Interactive serving sample
|
|
||||||
|
|
||||||
Check out [this Katacoda
|
|
||||||
tutorial](https://www.katacoda.com/swapb/scenarios/knative-intro) which will
|
|
||||||
walk you through installing Knative and the `kn` command line tool, deploying a
|
|
||||||
sample container, updating your deployment, and performing a traffic split
|
|
||||||
between the two versions.
|
|
||||||
|
|
||||||
### Serving samples
|
|
||||||
|
|
||||||
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), [R - Go Server](./serving/helloworld-r/README.md), [Rust](./serving/helloworld-rust/README.md), [Swift](./serving/helloworld-swift/README.md), [Vertx](./serving/helloworld-vertx/README.md) |
|
|
||||||
| Machine Learning | A quick introduction to using Knative Serving to serve machine learning models | [Python - BentoML](./serving/machinelearning-python-bentoml)
|
|
||||||
|
|
||||||
#### Eventing and Eventing Resources samples
|
|
||||||
|
|
||||||
- _Be the first to contribute an Eventing or Eventing Sources code sample to the
|
|
||||||
community collection._
|
|
||||||
|
|
||||||
### Client samples
|
|
||||||
|
|
||||||
Knative `kn` Client sample workflows and apps.
|
|
||||||
|
|
||||||
| Sample Name | Description |
|
|
||||||
| ----------- | ----------- |
|
|
||||||
| [knfun](https://github.com/maximilien/knfun) | Knative micro-functions (Twitter and Watson APIs) demo using the `kn` client. |
|
|
||||||
|
|
@ -5,4 +5,44 @@ weight: 40
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
Get up and running with one of the community code samples. These samples are
|
||||||
|
contributed and maintained by members of the Knative community.
|
||||||
|
|
||||||
|
Note: It is possible that one or more samples might become outdated or the
|
||||||
|
original author is unable to maintain their contribution. If you find that
|
||||||
|
something isn't working, lend a helping hand and fix it in a PR.
|
||||||
|
|
||||||
|
[Learn more about the lifespan of samples](https://github.com/knative/docs/tree/main/CONTRIBUTING.md#user-focused-content)
|
||||||
|
|
||||||
|
[**See all Knative code samples**](../../docs/samples.md)
|
||||||
|
|
||||||
|
### Interactive serving sample
|
||||||
|
|
||||||
|
Check out [this Katacoda
|
||||||
|
tutorial](https://www.katacoda.com/swapb/scenarios/knative-intro) which will
|
||||||
|
walk you through installing Knative and the `kn` command line tool, deploying a
|
||||||
|
sample container, updating your deployment, and performing a traffic split
|
||||||
|
between the two versions.
|
||||||
|
|
||||||
|
### Serving samples
|
||||||
|
|
||||||
|
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), [R - Go Server](./serving/helloworld-r/README.md), [Rust](./serving/helloworld-rust/README.md), [Swift](./serving/helloworld-swift/README.md), [Vertx](./serving/helloworld-vertx/README.md) |
|
||||||
|
| Machine Learning | A quick introduction to using Knative Serving to serve machine learning models | [Python - BentoML](./serving/machinelearning-python-bentoml)
|
||||||
|
|
||||||
|
#### Eventing and Eventing Resources samples
|
||||||
|
|
||||||
|
- _Be the first to contribute an Eventing or Eventing Sources code sample to the
|
||||||
|
community collection._
|
||||||
|
|
||||||
|
### Client samples
|
||||||
|
|
||||||
|
Knative `kn` Client sample workflows and apps.
|
||||||
|
|
||||||
|
| Sample Name | Description |
|
||||||
|
| ----------- | ----------- |
|
||||||
|
| [knfun](https://github.com/maximilien/knfun) | Knative micro-functions (Twitter and Watson APIs) demo using the `kn` client. |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
A simple web app written in Clojure that you can use for testing. It reads in an
|
|
||||||
env variable `TARGET` and prints "Hello \${TARGET}!". If TARGET is not
|
|
||||||
specified, it will use "World" as the TARGET.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- A Kubernetes cluster with Knative installed and DNS configured. Follow the
|
|
||||||
[installation instructions](../../../../docs/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
|
|
||||||
|
|
||||||
While you can clone all of the code from this directory, hello world apps are
|
|
||||||
generally more useful if you build them step-by-step. The following instructions
|
|
||||||
recreate the source files from this folder.
|
|
||||||
|
|
||||||
1. Create a new file named `src/helloworld/core.clj` and paste the following
|
|
||||||
code. This code creates a basic web server which listens on port 8080:
|
|
||||||
|
|
||||||
```clojure
|
|
||||||
(ns helloworld.core
|
|
||||||
(:use ring.adapter.jetty)
|
|
||||||
(:gen-class))
|
|
||||||
|
|
||||||
(defn handler [request]
|
|
||||||
{:status 200
|
|
||||||
:headers {"Content-Type" "text/html"}
|
|
||||||
:body (str "Hello "
|
|
||||||
(if-let [target (System/getenv "TARGET")]
|
|
||||||
target
|
|
||||||
"World")
|
|
||||||
"!\n")})
|
|
||||||
|
|
||||||
(defn -main [& args]
|
|
||||||
(run-jetty handler {:port (if-let [port (System/getenv "PORT")]
|
|
||||||
(Integer/parseInt port)
|
|
||||||
8080)}))
|
|
||||||
```
|
|
||||||
|
|
||||||
1. In your project directory, create a file named `project.clj` and copy the
|
|
||||||
code below into it. This code defines the project's dependencies and
|
|
||||||
entrypoint.
|
|
||||||
|
|
||||||
```clojure
|
|
||||||
(defproject helloworld "1.0.0-SNAPSHOT"
|
|
||||||
:description "Hello World - Clojure sample"
|
|
||||||
:dependencies [[org.clojure/clojure "1.9.0"]
|
|
||||||
[ring/ring-core "1.6.3"]
|
|
||||||
[ring/ring-jetty-adapter "1.6.3"]]
|
|
||||||
:main helloworld.core)
|
|
||||||
```
|
|
||||||
|
|
||||||
1. In your project directory, create a file named `Dockerfile` and copy the code
|
|
||||||
block below into it. For detailed instructions on dockerizing a Clojure app,
|
|
||||||
see
|
|
||||||
[the clojure image documentation](https://github.com/docker-library/docs/tree/master/clojure).
|
|
||||||
|
|
||||||
```docker
|
|
||||||
# Use the official Clojure image.
|
|
||||||
# https://hub.docker.com/_/clojure
|
|
||||||
FROM clojure
|
|
||||||
|
|
||||||
# Create the project and download dependencies.
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
COPY project.clj .
|
|
||||||
RUN lein deps
|
|
||||||
|
|
||||||
# Copy local code to the container image.
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Build an uberjar release artifact.
|
|
||||||
RUN mv "$(lein uberjar | sed -n 's/^Created \(.*standalone\.jar\)/\1/p')" app-standalone.jar
|
|
||||||
|
|
||||||
# Run the web service on container startup.
|
|
||||||
CMD ["java", "-jar", "app-standalone.jar"]
|
|
||||||
```
|
|
||||||
|
|
||||||
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/v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: helloworld-clojure
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: docker.io/{username}/helloworld-clojure
|
|
||||||
env:
|
|
||||||
- name: TARGET
|
|
||||||
value: "Clojure 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-clojure .
|
|
||||||
|
|
||||||
# Push the container to docker registry
|
|
||||||
docker push {username}/helloworld-clojure
|
|
||||||
```
|
|
||||||
|
|
||||||
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 will perform 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. To find the URL for your service, use
|
|
||||||
|
|
||||||
```
|
|
||||||
kubectl get ksvc helloworld-clojure --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
|
||||||
NAME URL
|
|
||||||
helloworld-clojure http://helloworld-clojure.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now you can make a request to your app and see the result. Replace
|
|
||||||
the URL below with the URL returned in the previous command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-clojure.default.1.2.3.4.xip.io
|
|
||||||
Hello World!
|
|
||||||
```
|
|
||||||
|
|
||||||
## Removing the sample app deployment
|
|
||||||
|
|
||||||
To remove the sample app from your cluster, delete the service record:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl delete --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,159 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
A simple web app written in Clojure that you can use for testing. It reads in an
|
||||||
|
env variable `TARGET` and prints "Hello \${TARGET}!". If TARGET is not
|
||||||
|
specified, it will use "World" as the TARGET.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- A Kubernetes cluster with Knative installed and DNS configured. Follow the
|
||||||
|
[installation instructions](../../../../docs/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
|
||||||
|
|
||||||
|
While you can clone all of the code from this directory, hello world apps are
|
||||||
|
generally more useful if you build them step-by-step. The following instructions
|
||||||
|
recreate the source files from this folder.
|
||||||
|
|
||||||
|
1. Create a new file named `src/helloworld/core.clj` and paste the following
|
||||||
|
code. This code creates a basic web server which listens on port 8080:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(ns helloworld.core
|
||||||
|
(:use ring.adapter.jetty)
|
||||||
|
(:gen-class))
|
||||||
|
|
||||||
|
(defn handler [request]
|
||||||
|
{:status 200
|
||||||
|
:headers {"Content-Type" "text/html"}
|
||||||
|
:body (str "Hello "
|
||||||
|
(if-let [target (System/getenv "TARGET")]
|
||||||
|
target
|
||||||
|
"World")
|
||||||
|
"!\n")})
|
||||||
|
|
||||||
|
(defn -main [& args]
|
||||||
|
(run-jetty handler {:port (if-let [port (System/getenv "PORT")]
|
||||||
|
(Integer/parseInt port)
|
||||||
|
8080)}))
|
||||||
|
```
|
||||||
|
|
||||||
|
1. In your project directory, create a file named `project.clj` and copy the
|
||||||
|
code below into it. This code defines the project's dependencies and
|
||||||
|
entrypoint.
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(defproject helloworld "1.0.0-SNAPSHOT"
|
||||||
|
:description "Hello World - Clojure sample"
|
||||||
|
:dependencies [[org.clojure/clojure "1.9.0"]
|
||||||
|
[ring/ring-core "1.6.3"]
|
||||||
|
[ring/ring-jetty-adapter "1.6.3"]]
|
||||||
|
:main helloworld.core)
|
||||||
|
```
|
||||||
|
|
||||||
|
1. In your project directory, create a file named `Dockerfile` and copy the code
|
||||||
|
block below into it. For detailed instructions on dockerizing a Clojure app,
|
||||||
|
see
|
||||||
|
[the clojure image documentation](https://github.com/docker-library/docs/tree/master/clojure).
|
||||||
|
|
||||||
|
```docker
|
||||||
|
# Use the official Clojure image.
|
||||||
|
# https://hub.docker.com/_/clojure
|
||||||
|
FROM clojure
|
||||||
|
|
||||||
|
# Create the project and download dependencies.
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
COPY project.clj .
|
||||||
|
RUN lein deps
|
||||||
|
|
||||||
|
# Copy local code to the container image.
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build an uberjar release artifact.
|
||||||
|
RUN mv "$(lein uberjar | sed -n 's/^Created \(.*standalone\.jar\)/\1/p')" app-standalone.jar
|
||||||
|
|
||||||
|
# Run the web service on container startup.
|
||||||
|
CMD ["java", "-jar", "app-standalone.jar"]
|
||||||
|
```
|
||||||
|
|
||||||
|
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/v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: helloworld-clojure
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: docker.io/{username}/helloworld-clojure
|
||||||
|
env:
|
||||||
|
- name: TARGET
|
||||||
|
value: "Clojure 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-clojure .
|
||||||
|
|
||||||
|
# Push the container to docker registry
|
||||||
|
docker push {username}/helloworld-clojure
|
||||||
|
```
|
||||||
|
|
||||||
|
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 will perform 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. To find the URL for your service, use
|
||||||
|
|
||||||
|
```
|
||||||
|
kubectl get ksvc helloworld-clojure --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||||
|
NAME URL
|
||||||
|
helloworld-clojure http://helloworld-clojure.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now you can make a request to your app and see the result. Replace
|
||||||
|
the URL below with the URL returned in the previous command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-clojure.default.1.2.3.4.xip.io
|
||||||
|
Hello World!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Removing the sample app deployment
|
||||||
|
|
||||||
|
To remove the sample app from your cluster, delete the service record:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete --filename service.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,153 +0,0 @@
|
||||||
A simple web app written in the [Dart](https://www.dart.dev) programming language
|
|
||||||
that you can use for testing. It reads in the env variable `TARGET` and prints
|
|
||||||
`"Hello $TARGET"`. If `TARGET` is not specified, it will use `"World"` as
|
|
||||||
`TARGET`.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- A Kubernetes cluster with Knative installed and DNS configured. Follow the
|
|
||||||
[installation instructions](../../../../docs/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).
|
|
||||||
- [dart-sdk](https://www.dart.dev/tools/sdk#install) installed and
|
|
||||||
configured if you want to run the program locally.
|
|
||||||
|
|
||||||
## Recreating the sample code
|
|
||||||
|
|
||||||
While you can clone all of the code from this directory, it is useful to know
|
|
||||||
how to build a hello world Dart application step-by-step. This application can
|
|
||||||
be created using the following instructions.
|
|
||||||
|
|
||||||
1. Create a new directory and write `pubspec.yaml` as follows:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: hello_world_dart
|
|
||||||
publish_to: none # let's not accidentally publish this to pub.dartlang.org
|
|
||||||
|
|
||||||
environment:
|
|
||||||
sdk: ">=2.12.0 <3.0.0"
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
shelf: ^1.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
2. If you want to run locally, install dependencies. If you only want to run in
|
|
||||||
Docker or Knative, you can skip this step.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
> pub get
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Create a new file `bin/server.dart` and write the following code:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:shelf/shelf.dart';
|
|
||||||
import 'package:shelf/shelf_io.dart';
|
|
||||||
|
|
||||||
Future main() async {
|
|
||||||
// Find port to listen on from environment variable.
|
|
||||||
final port = int.parse(Platform.environment['PORT'] ?? '8080');
|
|
||||||
|
|
||||||
// Read $TARGET from environment variable.
|
|
||||||
final target = Platform.environment['TARGET'] ?? 'World';
|
|
||||||
|
|
||||||
Response handler(Request request) => Response.ok('Hello $target');
|
|
||||||
|
|
||||||
// Serve handler on given port.
|
|
||||||
final server = await serve(
|
|
||||||
const Pipeline().addMiddleware(logRequests()).addHandler(handler),
|
|
||||||
InternetAddress.anyIPv4,
|
|
||||||
port,
|
|
||||||
);
|
|
||||||
print('Serving at http://${server.address.host}:${server.port}');
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Create a new file named `Dockerfile`, this file defines instructions for
|
|
||||||
dockerizing your applications, for dart apps this can be done as follows:
|
|
||||||
|
|
||||||
```Dockerfile
|
|
||||||
# Use Google's official Dart image.
|
|
||||||
# https://hub.docker.com/r/google/dart-runtime/
|
|
||||||
FROM google/dart-runtime
|
|
||||||
```
|
|
||||||
|
|
||||||
5. 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/v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: helloworld-dart
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: docker.io/{username}/helloworld-dart
|
|
||||||
env:
|
|
||||||
- name: TARGET
|
|
||||||
value: "Dart 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-dart .
|
|
||||||
|
|
||||||
# Push the container to docker registry
|
|
||||||
docker push {username}/helloworld-dart
|
|
||||||
```
|
|
||||||
|
|
||||||
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 will perform 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. To find the URL for your service, use
|
|
||||||
|
|
||||||
```
|
|
||||||
kubectl get ksvc helloworld-dart --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
|
||||||
NAME URL
|
|
||||||
helloworld-dart http://helloworld-dart.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now you can make a request to your app and see the result. Replace
|
|
||||||
the URL below with the URL returned in the previous command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-dart.default.1.2.3.4.xip.io
|
|
||||||
Hello Dart Sample v1
|
|
||||||
```
|
|
||||||
|
|
||||||
## Removing the sample app deployment
|
|
||||||
|
|
||||||
To remove the sample app from your cluster, delete the service record:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl delete --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,156 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
A simple web app written in the [Dart](https://www.dart.dev) programming language
|
||||||
|
that you can use for testing. It reads in the env variable `TARGET` and prints
|
||||||
|
`"Hello $TARGET"`. If `TARGET` is not specified, it will use `"World"` as
|
||||||
|
`TARGET`.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- A Kubernetes cluster with Knative installed and DNS configured. Follow the
|
||||||
|
[installation instructions](../../../../docs/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).
|
||||||
|
- [dart-sdk](https://www.dart.dev/tools/sdk#install) installed and
|
||||||
|
configured if you want to run the program locally.
|
||||||
|
|
||||||
|
## Recreating the sample code
|
||||||
|
|
||||||
|
While you can clone all of the code from this directory, it is useful to know
|
||||||
|
how to build a hello world Dart application step-by-step. This application can
|
||||||
|
be created using the following instructions.
|
||||||
|
|
||||||
|
1. Create a new directory and write `pubspec.yaml` as follows:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: hello_world_dart
|
||||||
|
publish_to: none # let's not accidentally publish this to pub.dartlang.org
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ">=2.12.0 <3.0.0"
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
shelf: ^1.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
2. If you want to run locally, install dependencies. If you only want to run in
|
||||||
|
Docker or Knative, you can skip this step.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
> pub get
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Create a new file `bin/server.dart` and write the following code:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:shelf/shelf.dart';
|
||||||
|
import 'package:shelf/shelf_io.dart';
|
||||||
|
|
||||||
|
Future main() async {
|
||||||
|
// Find port to listen on from environment variable.
|
||||||
|
final port = int.parse(Platform.environment['PORT'] ?? '8080');
|
||||||
|
|
||||||
|
// Read $TARGET from environment variable.
|
||||||
|
final target = Platform.environment['TARGET'] ?? 'World';
|
||||||
|
|
||||||
|
Response handler(Request request) => Response.ok('Hello $target');
|
||||||
|
|
||||||
|
// Serve handler on given port.
|
||||||
|
final server = await serve(
|
||||||
|
const Pipeline().addMiddleware(logRequests()).addHandler(handler),
|
||||||
|
InternetAddress.anyIPv4,
|
||||||
|
port,
|
||||||
|
);
|
||||||
|
print('Serving at http://${server.address.host}:${server.port}');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Create a new file named `Dockerfile`, this file defines instructions for
|
||||||
|
dockerizing your applications, for dart apps this can be done as follows:
|
||||||
|
|
||||||
|
```Dockerfile
|
||||||
|
# Use Google's official Dart image.
|
||||||
|
# https://hub.docker.com/r/google/dart-runtime/
|
||||||
|
FROM google/dart-runtime
|
||||||
|
```
|
||||||
|
|
||||||
|
5. 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/v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: helloworld-dart
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: docker.io/{username}/helloworld-dart
|
||||||
|
env:
|
||||||
|
- name: TARGET
|
||||||
|
value: "Dart 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-dart .
|
||||||
|
|
||||||
|
# Push the container to docker registry
|
||||||
|
docker push {username}/helloworld-dart
|
||||||
|
```
|
||||||
|
|
||||||
|
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 will perform 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. To find the URL for your service, use
|
||||||
|
|
||||||
|
```
|
||||||
|
kubectl get ksvc helloworld-dart --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||||
|
NAME URL
|
||||||
|
helloworld-dart http://helloworld-dart.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now you can make a request to your app and see the result. Replace
|
||||||
|
the URL below with the URL returned in the previous command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-dart.default.1.2.3.4.xip.io
|
||||||
|
Hello Dart Sample v1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Removing the sample app deployment
|
||||||
|
|
||||||
|
To remove the sample app from your cluster, delete the service record:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete --filename service.yaml
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
A simple web app written in Deno.
|
|
||||||
|
|
||||||
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-deno
|
|
||||||
```
|
|
||||||
|
|
||||||
## Before you begin
|
|
||||||
|
|
||||||
- A Kubernetes cluster with Knative installed. Follow the
|
|
||||||
[installation instructions](../../../../docs/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 `deps.ts` and paste the following script:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
export { serve } from "https://deno.land/std@std@0.50.0/http/server.ts";
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create a new file named `main.ts` and paste the following script:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { serve } from "./deps.ts";
|
|
||||||
import "https://deno.land/x/dotenv/mod.ts";
|
|
||||||
|
|
||||||
const PORT = Deno.env.get('PORT') || 8080;
|
|
||||||
const s = serve(`0.0.0.0:${PORT}`);
|
|
||||||
const body = new TextEncoder().encode("Hello Deno\n");
|
|
||||||
|
|
||||||
console.log(`Server started on port ${PORT}`);
|
|
||||||
for await (const req of s) {
|
|
||||||
req.respond({ body });
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create a new file named `Dockerfile` and copy the code block below into it.
|
|
||||||
|
|
||||||
```docker
|
|
||||||
FROM hayd/alpine-deno:1.0.0-rc2
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# These steps will be re-run upon each file change in your working directory:
|
|
||||||
COPY . ./
|
|
||||||
|
|
||||||
# Added to ENTRYPOINT of base image.
|
|
||||||
CMD ["run", "--allow-env", "--allow-net", "main.ts"]
|
|
||||||
```
|
|
||||||
|
|
||||||
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/v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: helloworld-deno
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: docker.io/{username}/helloworld-deno
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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-deno .
|
|
||||||
|
|
||||||
# Push the container to docker registry
|
|
||||||
docker push {username}/helloworld-deno
|
|
||||||
```
|
|
||||||
|
|
||||||
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 domain URL for your service:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl get ksvc helloworld-deno --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
NAME URL
|
|
||||||
helloworld-deno http://helloworld-deno.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now you can make a request to your app and see the result. Replace
|
|
||||||
the URL below with the URL returned in the previous command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-deno.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-deno.default.1.2.3.4.xip.io
|
|
||||||
[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
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,146 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
A simple web app written in Deno.
|
||||||
|
|
||||||
|
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-deno
|
||||||
|
```
|
||||||
|
|
||||||
|
## Before you begin
|
||||||
|
|
||||||
|
- A Kubernetes cluster with Knative installed. Follow the
|
||||||
|
[installation instructions](../../../../docs/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 `deps.ts` and paste the following script:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export { serve } from "https://deno.land/std@std@0.50.0/http/server.ts";
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create a new file named `main.ts` and paste the following script:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { serve } from "./deps.ts";
|
||||||
|
import "https://deno.land/x/dotenv/mod.ts";
|
||||||
|
|
||||||
|
const PORT = Deno.env.get('PORT') || 8080;
|
||||||
|
const s = serve(`0.0.0.0:${PORT}`);
|
||||||
|
const body = new TextEncoder().encode("Hello Deno\n");
|
||||||
|
|
||||||
|
console.log(`Server started on port ${PORT}`);
|
||||||
|
for await (const req of s) {
|
||||||
|
req.respond({ body });
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create a new file named `Dockerfile` and copy the code block below into it.
|
||||||
|
|
||||||
|
```docker
|
||||||
|
FROM hayd/alpine-deno:1.0.0-rc2
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# These steps will be re-run upon each file change in your working directory:
|
||||||
|
COPY . ./
|
||||||
|
|
||||||
|
# Added to ENTRYPOINT of base image.
|
||||||
|
CMD ["run", "--allow-env", "--allow-net", "main.ts"]
|
||||||
|
```
|
||||||
|
|
||||||
|
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/v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: helloworld-deno
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: docker.io/{username}/helloworld-deno
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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-deno .
|
||||||
|
|
||||||
|
# Push the container to docker registry
|
||||||
|
docker push {username}/helloworld-deno
|
||||||
|
```
|
||||||
|
|
||||||
|
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 domain URL for your service:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get ksvc helloworld-deno --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
NAME URL
|
||||||
|
helloworld-deno http://helloworld-deno.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now you can make a request to your app and see the result. Replace
|
||||||
|
the URL below with the URL returned in the previous command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-deno.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-deno.default.1.2.3.4.xip.io
|
||||||
|
[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
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,292 +0,0 @@
|
||||||
A simple web application written in [Elixir](https://elixir-lang.org/) using the
|
|
||||||
[Phoenix Framework](https://phoenixframework.org/). The application prints all
|
|
||||||
environment variables to the main page.
|
|
||||||
|
|
||||||
# Set up Elixir and Phoenix Locally
|
|
||||||
|
|
||||||
Following the
|
|
||||||
[Phoenix Installation Guide](https://hexdocs.pm/phoenix/installation.html) is
|
|
||||||
the best way to get your computer set up for developing, building, running, and
|
|
||||||
packaging Elixir Web applications.
|
|
||||||
|
|
||||||
# Running Locally
|
|
||||||
|
|
||||||
To start your Phoenix server:
|
|
||||||
|
|
||||||
- Install dependencies with `mix deps.get`
|
|
||||||
- Install Node.js dependencies with `cd assets && npm install`
|
|
||||||
- Start Phoenix endpoint with `mix phx.server`
|
|
||||||
|
|
||||||
Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
|
|
||||||
|
|
||||||
# Recreating the sample code
|
|
||||||
|
|
||||||
1. Generate a new project.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
mix phoenix.new helloelixir
|
|
||||||
```
|
|
||||||
|
|
||||||
When asked, if you want to `Fetch and install dependencies? [Yn]` select `y`
|
|
||||||
|
|
||||||
1. Follow the direction in the output to change directories into start your
|
|
||||||
local server with `mix phoenix.server`
|
|
||||||
|
|
||||||
1. In the new directory, create a new Dockerfile for packaging your application
|
|
||||||
for deployment
|
|
||||||
|
|
||||||
```docker
|
|
||||||
# Start from a base image for elixir
|
|
||||||
# Phoenix works best on pre 1.7 at the moment.
|
|
||||||
FROM elixir:1.6.6-alpine
|
|
||||||
|
|
||||||
# Set up Elixir and Phoenix
|
|
||||||
ARG APP_NAME=hello
|
|
||||||
ARG PHOENIX_SUBDIR=.
|
|
||||||
ENV MIX_ENV=prod REPLACE_OS_VARS=true TERM=xterm
|
|
||||||
WORKDIR /opt/app
|
|
||||||
|
|
||||||
# Update nodejs, rebar, and hex.
|
|
||||||
RUN apk update \
|
|
||||||
&& apk --no-cache --update add nodejs nodejs-npm \
|
|
||||||
&& mix local.rebar --force \
|
|
||||||
&& mix local.hex --force
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Download and compile dependencies, then compile Web app.
|
|
||||||
RUN mix do deps.get, deps.compile, compile
|
|
||||||
RUN cd ${PHOENIX_SUBDIR}/assets \
|
|
||||||
&& npm install \
|
|
||||||
&& ./node_modules/brunch/bin/brunch build -p \
|
|
||||||
&& cd .. \
|
|
||||||
&& mix phx.digest
|
|
||||||
|
|
||||||
# Create a release version of the application
|
|
||||||
RUN mix release --env=prod --verbose \
|
|
||||||
&& mv _build/prod/rel/${APP_NAME} /opt/release \
|
|
||||||
&& mv /opt/release/bin/${APP_NAME} /opt/release/bin/start_server
|
|
||||||
|
|
||||||
# Prepare final layer
|
|
||||||
FROM alpine:latest
|
|
||||||
RUN apk update && apk --no-cache --update add bash openssl-dev ca-certificates
|
|
||||||
|
|
||||||
# Add a user so the server will run as a non-root user.
|
|
||||||
RUN addgroup -g 1000 appuser && \
|
|
||||||
adduser -S -u 1000 -G appuser appuser
|
|
||||||
# Pre-create necessary temp directory for erlang and set permissions.
|
|
||||||
RUN mkdir -p /opt/app/var
|
|
||||||
RUN chown appuser /opt/app/var
|
|
||||||
# Run everything else as 'appuser'
|
|
||||||
USER appuser
|
|
||||||
|
|
||||||
ENV MIX_ENV=prod REPLACE_OS_VARS=true
|
|
||||||
WORKDIR /opt/app
|
|
||||||
COPY --from=0 /opt/release .
|
|
||||||
ENV RUNNER_LOG_DIR /var/log
|
|
||||||
|
|
||||||
# Command to execute the application.
|
|
||||||
CMD ["/opt/app/bin/start_server", "foreground", "boot_var=/tmp"]
|
|
||||||
```
|
|
||||||
|
|
||||||
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/v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: helloworld-elixir
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: docker.io/{username}/helloworld-elixir
|
|
||||||
env:
|
|
||||||
- name: TARGET
|
|
||||||
value: "elixir Sample v1"
|
|
||||||
```
|
|
||||||
|
|
||||||
# Building and deploying the sample
|
|
||||||
|
|
||||||
The sample in this directory is ready to build and deploy without changes. You
|
|
||||||
can deploy the sample as is, or use you created version following the directions
|
|
||||||
above.
|
|
||||||
|
|
||||||
1. Generate a new `secret_key_base` in the `config/prod.secret.exs` file.
|
|
||||||
Phoenix applications use a secrets file on production deployments and, by
|
|
||||||
default, that file is not checked into source control. We have provides
|
|
||||||
shell of an example on `config/prod.secret.exs.sample` and you can use the
|
|
||||||
following command to generate a new prod secrets file.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
SECRET_KEY_BASE=$(elixir -e ":crypto.strong_rand_bytes(48) |> Base.encode64 |> IO.puts")
|
|
||||||
sed "s|SECRET+KEY+BASE|$SECRET_KEY_BASE|" config/prod.secret.exs.sample >config/prod.secret.exs
|
|
||||||
```
|
|
||||||
|
|
||||||
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-elixir .
|
|
||||||
|
|
||||||
# Push the container to docker registry
|
|
||||||
docker push {username}/helloworld-elixir
|
|
||||||
```
|
|
||||||
|
|
||||||
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 will perform 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. To find the URL for your service, use
|
|
||||||
|
|
||||||
```
|
|
||||||
kubectl get ksvc helloworld-elixir --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
|
||||||
|
|
||||||
NAME URL
|
|
||||||
helloworld-elixir http://helloworld-elixir.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now you can make a request to your app to see the results. Replace
|
|
||||||
`{IP_ADDRESS}` with the address you see returned in the previous step.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-elixir.default.1.2.3.4.xip.io
|
|
||||||
|
|
||||||
...
|
|
||||||
# HTML from your application is returned.
|
|
||||||
```
|
|
||||||
|
|
||||||
Here is the HTML returned from our deployed sample application:
|
|
||||||
|
|
||||||
```HTML
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="author" content="">
|
|
||||||
|
|
||||||
<title>Hello Knative</title>
|
|
||||||
<link rel="stylesheet" type="text/css" href="/css/app-833cc7e8eeed7a7953c5a02e28130dbd.css?vsn=d">
|
|
||||||
</head>
|
|
||||||
```
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<header class="header">
|
|
||||||
<nav role="navigation">
|
|
||||||
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<p class="alert alert-info" role="alert"></p>
|
|
||||||
<p class="alert alert-danger" role="alert"></p>
|
|
||||||
|
|
||||||
<main role="main">
|
|
||||||
|
|
||||||
<div class="jumbotron">
|
|
||||||
<h2>Welcome to Knative and Elixir</h2>
|
|
||||||
|
|
||||||
<p>$TARGET = elixir Sample v1</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Environment</h3>
|
|
||||||
<ul>
|
|
||||||
<li>BINDIR = /opt/app/erts-9.3.2/bin</li>
|
|
||||||
<li>DEST_SYS_CONFIG_PATH = /opt/app/var/sys.config</li>
|
|
||||||
<li>DEST_VMARGS_PATH = /opt/app/var/vm.args</li>
|
|
||||||
<li>DISTILLERY_TASK = foreground</li>
|
|
||||||
<li>EMU = beam</li>
|
|
||||||
<li>ERL_LIBS = /opt/app/lib</li>
|
|
||||||
<li>ERL_OPTS = </li>
|
|
||||||
<li>ERTS_DIR = /opt/app/erts-9.3.2</li>
|
|
||||||
<li>ERTS_LIB_DIR = /opt/app/erts-9.3.2/../lib</li>
|
|
||||||
<li>ERTS_VSN = 9.3.2</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT = tcp://10.35.241.50:80</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT_80_TCP = tcp://10.35.241.50:80</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT_80_TCP_ADDR = 10.35.241.50</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT_80_TCP_PORT = 80</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT_80_TCP_PROTO = tcp</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_SERVICE_HOST = 10.35.241.50</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_SERVICE_PORT = 80</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_SERVICE_PORT_HTTP = 80</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_PORT = tcp://10.35.253.90:80</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_PORT_80_TCP = tcp://10.35.253.90:80</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_PORT_80_TCP_ADDR = 10.35.253.90</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_PORT_80_TCP_PORT = 80</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_PORT_80_TCP_PROTO = tcp</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_SERVICE_HOST = 10.35.253.90</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_SERVICE_PORT = 80</li>
|
|
||||||
<li>HELLOWORLD_ELIXIR_SERVICE_PORT_HTTP = 80</li>
|
|
||||||
<li>HOME = /root</li>
|
|
||||||
<li>HOSTNAME = helloworld-elixir-00001-deployment-84f68946b4-76hcv</li>
|
|
||||||
<li>KUBERNETES_PORT = tcp://10.35.240.1:443</li>
|
|
||||||
<li>KUBERNETES_PORT_443_TCP = tcp://10.35.240.1:443</li>
|
|
||||||
<li>KUBERNETES_PORT_443_TCP_ADDR = 10.35.240.1</li>
|
|
||||||
<li>KUBERNETES_PORT_443_TCP_PORT = 443</li>
|
|
||||||
<li>KUBERNETES_PORT_443_TCP_PROTO = tcp</li>
|
|
||||||
<li>KUBERNETES_SERVICE_HOST = 10.35.240.1</li>
|
|
||||||
<li>KUBERNETES_SERVICE_PORT = 443</li>
|
|
||||||
<li>KUBERNETES_SERVICE_PORT_HTTPS = 443</li>
|
|
||||||
<li>LD_LIBRARY_PATH = /opt/app/erts-9.3.2/lib:</li>
|
|
||||||
<li>MIX_ENV = prod</li>
|
|
||||||
<li>NAME = hello@127.0.0.1</li>
|
|
||||||
<li>NAME_ARG = -name hello@127.0.0.1</li>
|
|
||||||
<li>NAME_TYPE = -name</li>
|
|
||||||
<li>OLDPWD = /opt/app</li>
|
|
||||||
<li>OTP_VER = 20</li>
|
|
||||||
<li>PATH = /opt/app/erts-9.3.2/bin:/opt/app/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin</li>
|
|
||||||
<li>PORT = 8080</li>
|
|
||||||
<li>PROGNAME = opt/app/releases/0.0.1/hello.sh</li>
|
|
||||||
<li>PWD = /opt/app</li>
|
|
||||||
<li>RELEASES_DIR = /opt/app/releases</li>
|
|
||||||
<li>RELEASE_CONFIG_DIR = /opt/app</li>
|
|
||||||
<li>RELEASE_ROOT_DIR = /opt/app</li>
|
|
||||||
<li>REL_NAME = hello</li>
|
|
||||||
<li>REL_VSN = 0.0.1</li>
|
|
||||||
<li>REPLACE_OS_VARS = true</li>
|
|
||||||
<li>ROOTDIR = /opt/app</li>
|
|
||||||
<li>RUNNER_LOG_DIR = /var/log</li>
|
|
||||||
<li>RUN_ERL_ENV = </li>
|
|
||||||
<li>SHLVL = 1</li>
|
|
||||||
<li>SRC_SYS_CONFIG_PATH = /opt/app/releases/0.0.1/sys.config</li>
|
|
||||||
<li>SRC_VMARGS_PATH = /opt/app/releases/0.0.1/vm.args</li>
|
|
||||||
<li>SYS_CONFIG_PATH = /opt/app/var/sys.config</li>
|
|
||||||
<li>TARGET = elixir Sample v1</li>
|
|
||||||
<li>TERM = xterm</li>
|
|
||||||
<li>VMARGS_PATH = /opt/app/var/vm.args</li>
|
|
||||||
</ul>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
</div> <!-- /container -->
|
|
||||||
<script src="/js/app-930ab1950e10d7b5ab5083423c28f06e.js?vsn=d"></script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Removing the sample app deployment
|
|
||||||
|
|
||||||
To remove the sample app from your cluster, delete the service record:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl delete --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,295 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
A simple web application written in [Elixir](https://elixir-lang.org/) using the
|
||||||
|
[Phoenix Framework](https://phoenixframework.org/). The application prints all
|
||||||
|
environment variables to the main page.
|
||||||
|
|
||||||
|
# Set up Elixir and Phoenix Locally
|
||||||
|
|
||||||
|
Following the
|
||||||
|
[Phoenix Installation Guide](https://hexdocs.pm/phoenix/installation.html) is
|
||||||
|
the best way to get your computer set up for developing, building, running, and
|
||||||
|
packaging Elixir Web applications.
|
||||||
|
|
||||||
|
# Running Locally
|
||||||
|
|
||||||
|
To start your Phoenix server:
|
||||||
|
|
||||||
|
- Install dependencies with `mix deps.get`
|
||||||
|
- Install Node.js dependencies with `cd assets && npm install`
|
||||||
|
- Start Phoenix endpoint with `mix phx.server`
|
||||||
|
|
||||||
|
Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
|
||||||
|
|
||||||
|
# Recreating the sample code
|
||||||
|
|
||||||
|
1. Generate a new project.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mix phoenix.new helloelixir
|
||||||
|
```
|
||||||
|
|
||||||
|
When asked, if you want to `Fetch and install dependencies? [Yn]` select `y`
|
||||||
|
|
||||||
|
1. Follow the direction in the output to change directories into start your
|
||||||
|
local server with `mix phoenix.server`
|
||||||
|
|
||||||
|
1. In the new directory, create a new Dockerfile for packaging your application
|
||||||
|
for deployment
|
||||||
|
|
||||||
|
```docker
|
||||||
|
# Start from a base image for elixir
|
||||||
|
# Phoenix works best on pre 1.7 at the moment.
|
||||||
|
FROM elixir:1.6.6-alpine
|
||||||
|
|
||||||
|
# Set up Elixir and Phoenix
|
||||||
|
ARG APP_NAME=hello
|
||||||
|
ARG PHOENIX_SUBDIR=.
|
||||||
|
ENV MIX_ENV=prod REPLACE_OS_VARS=true TERM=xterm
|
||||||
|
WORKDIR /opt/app
|
||||||
|
|
||||||
|
# Update nodejs, rebar, and hex.
|
||||||
|
RUN apk update \
|
||||||
|
&& apk --no-cache --update add nodejs nodejs-npm \
|
||||||
|
&& mix local.rebar --force \
|
||||||
|
&& mix local.hex --force
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Download and compile dependencies, then compile Web app.
|
||||||
|
RUN mix do deps.get, deps.compile, compile
|
||||||
|
RUN cd ${PHOENIX_SUBDIR}/assets \
|
||||||
|
&& npm install \
|
||||||
|
&& ./node_modules/brunch/bin/brunch build -p \
|
||||||
|
&& cd .. \
|
||||||
|
&& mix phx.digest
|
||||||
|
|
||||||
|
# Create a release version of the application
|
||||||
|
RUN mix release --env=prod --verbose \
|
||||||
|
&& mv _build/prod/rel/${APP_NAME} /opt/release \
|
||||||
|
&& mv /opt/release/bin/${APP_NAME} /opt/release/bin/start_server
|
||||||
|
|
||||||
|
# Prepare final layer
|
||||||
|
FROM alpine:latest
|
||||||
|
RUN apk update && apk --no-cache --update add bash openssl-dev ca-certificates
|
||||||
|
|
||||||
|
# Add a user so the server will run as a non-root user.
|
||||||
|
RUN addgroup -g 1000 appuser && \
|
||||||
|
adduser -S -u 1000 -G appuser appuser
|
||||||
|
# Pre-create necessary temp directory for erlang and set permissions.
|
||||||
|
RUN mkdir -p /opt/app/var
|
||||||
|
RUN chown appuser /opt/app/var
|
||||||
|
# Run everything else as 'appuser'
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
ENV MIX_ENV=prod REPLACE_OS_VARS=true
|
||||||
|
WORKDIR /opt/app
|
||||||
|
COPY --from=0 /opt/release .
|
||||||
|
ENV RUNNER_LOG_DIR /var/log
|
||||||
|
|
||||||
|
# Command to execute the application.
|
||||||
|
CMD ["/opt/app/bin/start_server", "foreground", "boot_var=/tmp"]
|
||||||
|
```
|
||||||
|
|
||||||
|
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/v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: helloworld-elixir
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: docker.io/{username}/helloworld-elixir
|
||||||
|
env:
|
||||||
|
- name: TARGET
|
||||||
|
value: "elixir Sample v1"
|
||||||
|
```
|
||||||
|
|
||||||
|
# Building and deploying the sample
|
||||||
|
|
||||||
|
The sample in this directory is ready to build and deploy without changes. You
|
||||||
|
can deploy the sample as is, or use you created version following the directions
|
||||||
|
above.
|
||||||
|
|
||||||
|
1. Generate a new `secret_key_base` in the `config/prod.secret.exs` file.
|
||||||
|
Phoenix applications use a secrets file on production deployments and, by
|
||||||
|
default, that file is not checked into source control. We have provides
|
||||||
|
shell of an example on `config/prod.secret.exs.sample` and you can use the
|
||||||
|
following command to generate a new prod secrets file.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
SECRET_KEY_BASE=$(elixir -e ":crypto.strong_rand_bytes(48) |> Base.encode64 |> IO.puts")
|
||||||
|
sed "s|SECRET+KEY+BASE|$SECRET_KEY_BASE|" config/prod.secret.exs.sample >config/prod.secret.exs
|
||||||
|
```
|
||||||
|
|
||||||
|
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-elixir .
|
||||||
|
|
||||||
|
# Push the container to docker registry
|
||||||
|
docker push {username}/helloworld-elixir
|
||||||
|
```
|
||||||
|
|
||||||
|
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 will perform 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. To find the URL for your service, use
|
||||||
|
|
||||||
|
```
|
||||||
|
kubectl get ksvc helloworld-elixir --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||||
|
|
||||||
|
NAME URL
|
||||||
|
helloworld-elixir http://helloworld-elixir.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now you can make a request to your app to see the results. Replace
|
||||||
|
`{IP_ADDRESS}` with the address you see returned in the previous step.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-elixir.default.1.2.3.4.xip.io
|
||||||
|
|
||||||
|
...
|
||||||
|
# HTML from your application is returned.
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is the HTML returned from our deployed sample application:
|
||||||
|
|
||||||
|
```HTML
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="author" content="">
|
||||||
|
|
||||||
|
<title>Hello Knative</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/css/app-833cc7e8eeed7a7953c5a02e28130dbd.css?vsn=d">
|
||||||
|
</head>
|
||||||
|
```
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<header class="header">
|
||||||
|
<nav role="navigation">
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<p class="alert alert-info" role="alert"></p>
|
||||||
|
<p class="alert alert-danger" role="alert"></p>
|
||||||
|
|
||||||
|
<main role="main">
|
||||||
|
|
||||||
|
<div class="jumbotron">
|
||||||
|
<h2>Welcome to Knative and Elixir</h2>
|
||||||
|
|
||||||
|
<p>$TARGET = elixir Sample v1</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Environment</h3>
|
||||||
|
<ul>
|
||||||
|
<li>BINDIR = /opt/app/erts-9.3.2/bin</li>
|
||||||
|
<li>DEST_SYS_CONFIG_PATH = /opt/app/var/sys.config</li>
|
||||||
|
<li>DEST_VMARGS_PATH = /opt/app/var/vm.args</li>
|
||||||
|
<li>DISTILLERY_TASK = foreground</li>
|
||||||
|
<li>EMU = beam</li>
|
||||||
|
<li>ERL_LIBS = /opt/app/lib</li>
|
||||||
|
<li>ERL_OPTS = </li>
|
||||||
|
<li>ERTS_DIR = /opt/app/erts-9.3.2</li>
|
||||||
|
<li>ERTS_LIB_DIR = /opt/app/erts-9.3.2/../lib</li>
|
||||||
|
<li>ERTS_VSN = 9.3.2</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT = tcp://10.35.241.50:80</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT_80_TCP = tcp://10.35.241.50:80</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT_80_TCP_ADDR = 10.35.241.50</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT_80_TCP_PORT = 80</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT_80_TCP_PROTO = tcp</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_00001_SERVICE_SERVICE_HOST = 10.35.241.50</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_00001_SERVICE_SERVICE_PORT = 80</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_00001_SERVICE_SERVICE_PORT_HTTP = 80</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_PORT = tcp://10.35.253.90:80</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_PORT_80_TCP = tcp://10.35.253.90:80</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_PORT_80_TCP_ADDR = 10.35.253.90</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_PORT_80_TCP_PORT = 80</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_PORT_80_TCP_PROTO = tcp</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_SERVICE_HOST = 10.35.253.90</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_SERVICE_PORT = 80</li>
|
||||||
|
<li>HELLOWORLD_ELIXIR_SERVICE_PORT_HTTP = 80</li>
|
||||||
|
<li>HOME = /root</li>
|
||||||
|
<li>HOSTNAME = helloworld-elixir-00001-deployment-84f68946b4-76hcv</li>
|
||||||
|
<li>KUBERNETES_PORT = tcp://10.35.240.1:443</li>
|
||||||
|
<li>KUBERNETES_PORT_443_TCP = tcp://10.35.240.1:443</li>
|
||||||
|
<li>KUBERNETES_PORT_443_TCP_ADDR = 10.35.240.1</li>
|
||||||
|
<li>KUBERNETES_PORT_443_TCP_PORT = 443</li>
|
||||||
|
<li>KUBERNETES_PORT_443_TCP_PROTO = tcp</li>
|
||||||
|
<li>KUBERNETES_SERVICE_HOST = 10.35.240.1</li>
|
||||||
|
<li>KUBERNETES_SERVICE_PORT = 443</li>
|
||||||
|
<li>KUBERNETES_SERVICE_PORT_HTTPS = 443</li>
|
||||||
|
<li>LD_LIBRARY_PATH = /opt/app/erts-9.3.2/lib:</li>
|
||||||
|
<li>MIX_ENV = prod</li>
|
||||||
|
<li>NAME = hello@127.0.0.1</li>
|
||||||
|
<li>NAME_ARG = -name hello@127.0.0.1</li>
|
||||||
|
<li>NAME_TYPE = -name</li>
|
||||||
|
<li>OLDPWD = /opt/app</li>
|
||||||
|
<li>OTP_VER = 20</li>
|
||||||
|
<li>PATH = /opt/app/erts-9.3.2/bin:/opt/app/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin</li>
|
||||||
|
<li>PORT = 8080</li>
|
||||||
|
<li>PROGNAME = opt/app/releases/0.0.1/hello.sh</li>
|
||||||
|
<li>PWD = /opt/app</li>
|
||||||
|
<li>RELEASES_DIR = /opt/app/releases</li>
|
||||||
|
<li>RELEASE_CONFIG_DIR = /opt/app</li>
|
||||||
|
<li>RELEASE_ROOT_DIR = /opt/app</li>
|
||||||
|
<li>REL_NAME = hello</li>
|
||||||
|
<li>REL_VSN = 0.0.1</li>
|
||||||
|
<li>REPLACE_OS_VARS = true</li>
|
||||||
|
<li>ROOTDIR = /opt/app</li>
|
||||||
|
<li>RUNNER_LOG_DIR = /var/log</li>
|
||||||
|
<li>RUN_ERL_ENV = </li>
|
||||||
|
<li>SHLVL = 1</li>
|
||||||
|
<li>SRC_SYS_CONFIG_PATH = /opt/app/releases/0.0.1/sys.config</li>
|
||||||
|
<li>SRC_VMARGS_PATH = /opt/app/releases/0.0.1/vm.args</li>
|
||||||
|
<li>SYS_CONFIG_PATH = /opt/app/var/sys.config</li>
|
||||||
|
<li>TARGET = elixir Sample v1</li>
|
||||||
|
<li>TERM = xterm</li>
|
||||||
|
<li>VMARGS_PATH = /opt/app/var/vm.args</li>
|
||||||
|
</ul>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</div> <!-- /container -->
|
||||||
|
<script src="/js/app-930ab1950e10d7b5ab5083423c28f06e.js?vsn=d"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Removing the sample app deployment
|
||||||
|
|
||||||
|
To remove the sample app from your cluster, delete the service record:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete --filename service.yaml
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,181 +0,0 @@
|
||||||
A simple web app written in Haskell that you can use for testing. It reads in an
|
|
||||||
env variable `TARGET` and prints "Hello \${TARGET}!". If TARGET is not
|
|
||||||
specified, it will use "World" as the TARGET.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- A Kubernetes cluster with Knative installed and DNS configured. Follow the
|
|
||||||
[installation instructions](../../../../docs/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
|
|
||||||
|
|
||||||
While you can clone all of the code from this directory, hello world apps are
|
|
||||||
generally more useful if you build them step-by-step. The following instructions
|
|
||||||
recreate the source files from this folder.
|
|
||||||
|
|
||||||
1. Create a new file named `stack.yaml` and paste the following code:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
flags: {}
|
|
||||||
packages:
|
|
||||||
- .
|
|
||||||
extra-deps: []
|
|
||||||
resolver: lts-10.7
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create a new file named `package.yaml` and paste the following code
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: helloworld-haskell
|
|
||||||
version: 0.1.0.0
|
|
||||||
dependencies:
|
|
||||||
- base >= 4.7 && < 5
|
|
||||||
- scotty
|
|
||||||
- text
|
|
||||||
|
|
||||||
executables:
|
|
||||||
helloworld-haskell-exe:
|
|
||||||
main: Main.hs
|
|
||||||
source-dirs: app
|
|
||||||
ghc-options:
|
|
||||||
- -threaded
|
|
||||||
- -rtsopts
|
|
||||||
- -with-rtsopts=-N
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create a `app` folder, then create a new file named `Main.hs` in that folder
|
|
||||||
and paste the following code. This code creates a basic web server which
|
|
||||||
listens on port 8080:
|
|
||||||
|
|
||||||
```haskell
|
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
|
|
||||||
import Data.Maybe
|
|
||||||
import Data.Monoid ((<>))
|
|
||||||
import Data.Text.Lazy (Text)
|
|
||||||
import Data.Text.Lazy
|
|
||||||
import System.Environment (lookupEnv)
|
|
||||||
import Web.Scotty (ActionM, ScottyM, scotty)
|
|
||||||
import Web.Scotty.Trans
|
|
||||||
|
|
||||||
main :: IO ()
|
|
||||||
main = do
|
|
||||||
t <- fromMaybe "World" <$> lookupEnv "TARGET"
|
|
||||||
pStr <- fromMaybe "8080" <$> lookupEnv "PORT"
|
|
||||||
let p = read pStr :: Int
|
|
||||||
scotty p (route t)
|
|
||||||
|
|
||||||
route :: String -> ScottyM()
|
|
||||||
route t = get "/" $ hello t
|
|
||||||
|
|
||||||
hello :: String -> ActionM()
|
|
||||||
hello t = text $ pack ("Hello " ++ t)
|
|
||||||
```
|
|
||||||
|
|
||||||
1. In your project directory, create a file named `Dockerfile` and copy the code
|
|
||||||
block below into it.
|
|
||||||
|
|
||||||
```docker
|
|
||||||
# Use the official Haskell image to create a build artifact.
|
|
||||||
# https://hub.docker.com/_/haskell/
|
|
||||||
FROM haskell:8.2.2 as builder
|
|
||||||
|
|
||||||
# Copy local code to the container image.
|
|
||||||
WORKDIR /app
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Build and test our code, then build the “helloworld-haskell-exe” executable.
|
|
||||||
RUN stack setup
|
|
||||||
RUN stack build --copy-bins
|
|
||||||
|
|
||||||
# Use a Docker multi-stage build to create a lean production image.
|
|
||||||
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
|
|
||||||
FROM fpco/haskell-scratch:integer-gmp
|
|
||||||
|
|
||||||
# Copy the "helloworld-haskell-exe" executable from the builder stage to the production image.
|
|
||||||
WORKDIR /root/
|
|
||||||
COPY --from=builder /root/.local/bin/helloworld-haskell-exe .
|
|
||||||
|
|
||||||
# Run the web service on container startup.
|
|
||||||
CMD ["./helloworld-haskell-exe"]
|
|
||||||
```
|
|
||||||
|
|
||||||
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/v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: helloworld-haskell
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: docker.io/{username}/helloworld-haskell
|
|
||||||
env:
|
|
||||||
- name: TARGET
|
|
||||||
value: "Haskell Sample v1"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Build and deploy this 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, enter these commands replacing `{username}` with your Docker Hub
|
|
||||||
username:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Build the container on your local machine
|
|
||||||
docker build -t {username}/helloworld-haskell .
|
|
||||||
|
|
||||||
# Push the container to docker registry
|
|
||||||
docker push {username}/helloworld-haskell
|
|
||||||
```
|
|
||||||
|
|
||||||
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 will perform 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. To find the URL for your service, enter:
|
|
||||||
|
|
||||||
```
|
|
||||||
kubectl get ksvc helloworld-haskell --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
|
||||||
NAME URL
|
|
||||||
helloworld-haskell http://helloworld-haskell.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now you can make a request to your app and see the result. Replace
|
|
||||||
the URL below with the URL returned in the previous command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-haskell.default.1.2.3.4.xip.io
|
|
||||||
Hello world: Haskell Sample v1
|
|
||||||
```
|
|
||||||
|
|
||||||
## Removing the sample app deployment
|
|
||||||
|
|
||||||
To remove the sample app from your cluster, delete the service record:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl delete --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,185 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
A simple web app written in Haskell that you can use for testing. It reads in an
|
||||||
|
env variable `TARGET` and prints "Hello \${TARGET}!". If TARGET is not
|
||||||
|
specified, it will use "World" as the TARGET.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- A Kubernetes cluster with Knative installed and DNS configured. Follow the
|
||||||
|
[installation instructions](../../../../docs/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
|
||||||
|
|
||||||
|
While you can clone all of the code from this directory, hello world apps are
|
||||||
|
generally more useful if you build them step-by-step. The following instructions
|
||||||
|
recreate the source files from this folder.
|
||||||
|
|
||||||
|
1. Create a new file named `stack.yaml` and paste the following code:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
flags: {}
|
||||||
|
packages:
|
||||||
|
- .
|
||||||
|
extra-deps: []
|
||||||
|
resolver: lts-10.7
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create a new file named `package.yaml` and paste the following code
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: helloworld-haskell
|
||||||
|
version: 0.1.0.0
|
||||||
|
dependencies:
|
||||||
|
- base >= 4.7 && < 5
|
||||||
|
- scotty
|
||||||
|
- text
|
||||||
|
|
||||||
|
executables:
|
||||||
|
helloworld-haskell-exe:
|
||||||
|
main: Main.hs
|
||||||
|
source-dirs: app
|
||||||
|
ghc-options:
|
||||||
|
- -threaded
|
||||||
|
- -rtsopts
|
||||||
|
- -with-rtsopts=-N
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create a `app` folder, then create a new file named `Main.hs` in that folder
|
||||||
|
and paste the following code. This code creates a basic web server which
|
||||||
|
listens on port 8080:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
import Data.Maybe
|
||||||
|
import Data.Monoid ((<>))
|
||||||
|
import Data.Text.Lazy (Text)
|
||||||
|
import Data.Text.Lazy
|
||||||
|
import System.Environment (lookupEnv)
|
||||||
|
import Web.Scotty (ActionM, ScottyM, scotty)
|
||||||
|
import Web.Scotty.Trans
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
t <- fromMaybe "World" <$> lookupEnv "TARGET"
|
||||||
|
pStr <- fromMaybe "8080" <$> lookupEnv "PORT"
|
||||||
|
let p = read pStr :: Int
|
||||||
|
scotty p (route t)
|
||||||
|
|
||||||
|
route :: String -> ScottyM()
|
||||||
|
route t = get "/" $ hello t
|
||||||
|
|
||||||
|
hello :: String -> ActionM()
|
||||||
|
hello t = text $ pack ("Hello " ++ t)
|
||||||
|
```
|
||||||
|
|
||||||
|
1. In your project directory, create a file named `Dockerfile` and copy the code
|
||||||
|
block below into it.
|
||||||
|
|
||||||
|
```docker
|
||||||
|
# Use the official Haskell image to create a build artifact.
|
||||||
|
# https://hub.docker.com/_/haskell/
|
||||||
|
FROM haskell:8.2.2 as builder
|
||||||
|
|
||||||
|
# Copy local code to the container image.
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build and test our code, then build the “helloworld-haskell-exe” executable.
|
||||||
|
RUN stack setup
|
||||||
|
RUN stack build --copy-bins
|
||||||
|
|
||||||
|
# Use a Docker multi-stage build to create a lean production image.
|
||||||
|
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
|
||||||
|
FROM fpco/haskell-scratch:integer-gmp
|
||||||
|
|
||||||
|
# Copy the "helloworld-haskell-exe" executable from the builder stage to the production image.
|
||||||
|
WORKDIR /root/
|
||||||
|
COPY --from=builder /root/.local/bin/helloworld-haskell-exe .
|
||||||
|
|
||||||
|
# Run the web service on container startup.
|
||||||
|
CMD ["./helloworld-haskell-exe"]
|
||||||
|
```
|
||||||
|
|
||||||
|
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/v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: helloworld-haskell
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: docker.io/{username}/helloworld-haskell
|
||||||
|
env:
|
||||||
|
- name: TARGET
|
||||||
|
value: "Haskell Sample v1"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build and deploy this 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, enter these commands replacing `{username}` with your Docker Hub
|
||||||
|
username:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Build the container on your local machine
|
||||||
|
docker build -t {username}/helloworld-haskell .
|
||||||
|
|
||||||
|
# Push the container to docker registry
|
||||||
|
docker push {username}/helloworld-haskell
|
||||||
|
```
|
||||||
|
|
||||||
|
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 will perform 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. To find the URL for your service, enter:
|
||||||
|
|
||||||
|
```
|
||||||
|
kubectl get ksvc helloworld-haskell --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||||
|
NAME URL
|
||||||
|
helloworld-haskell http://helloworld-haskell.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now you can make a request to your app and see the result. Replace
|
||||||
|
the URL below with the URL returned in the previous command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-haskell.default.1.2.3.4.xip.io
|
||||||
|
Hello world: Haskell Sample v1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Removing the sample app deployment
|
||||||
|
|
||||||
|
To remove the sample app from your cluster, delete the service record:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete --filename service.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,282 +0,0 @@
|
||||||
Learn how to deploy a simple web app that is written in Java and uses Micronaut.
|
|
||||||
|
|
||||||
This samples uses Docker to build locally. The app reads in a `TARGET` env
|
|
||||||
variable and then prints "Hello World: \${TARGET}!". If a value for `TARGET` is
|
|
||||||
not specified, the "NOT SPECIFIED" default value is used.
|
|
||||||
|
|
||||||
Use this sample to walk you through the steps of creating and modifying the
|
|
||||||
sample app, building and pushing your container image to a registry, and then
|
|
||||||
deploying your app to your Knative cluster.
|
|
||||||
|
|
||||||
## Before you begin
|
|
||||||
|
|
||||||
You must meet the following requirements to complete this sample:
|
|
||||||
|
|
||||||
- A version of the Knative Serving component installed and DNS configured. Follow the
|
|
||||||
[Knative installation instructions](../../../../docs/install/README.md) if you need
|
|
||||||
to create a Knative cluster.
|
|
||||||
- The following software downloaded and install on your loacal machine:
|
|
||||||
- [Java SE 8 or later JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html).
|
|
||||||
- [Micronaut 1.1](https://micronaut.io/).
|
|
||||||
- [Docker](https://www.docker.com) for building and pushing your container
|
|
||||||
image.
|
|
||||||
- [curl](https://curl.haxx.se/) to test the sample app after deployment.
|
|
||||||
- A [Docker Hub](https://hub.docker.com/) account where you can push your
|
|
||||||
container image.
|
|
||||||
|
|
||||||
**Tip**: You can clone the [Knatve/docs repo](https://github.com/knative/docs)
|
|
||||||
and then modify the source files. Alternatively, learn more by manually creating
|
|
||||||
the files yourself.
|
|
||||||
|
|
||||||
## Creating and configuring the sample code
|
|
||||||
|
|
||||||
To create and configure the source files in the root of your working directory:
|
|
||||||
|
|
||||||
1. Create the `pom.xml` file:
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>com.example.micronaut</groupId>
|
|
||||||
<artifactId>helloworld</artifactId>
|
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
|
||||||
<properties>
|
|
||||||
<micronaut.version>1.1.0</micronaut.version>
|
|
||||||
<jdk.version>1.8</jdk.version>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<exec.mainClass>com.example.helloworld.Application</exec.mainClass>
|
|
||||||
</properties>
|
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.micronaut</groupId>
|
|
||||||
<artifactId>micronaut-bom</artifactId>
|
|
||||||
<version>${micronaut.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.micronaut</groupId>
|
|
||||||
<artifactId>micronaut-inject</artifactId>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.micronaut</groupId>
|
|
||||||
<artifactId>micronaut-validation</artifactId>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.micronaut</groupId>
|
|
||||||
<artifactId>micronaut-runtime</artifactId>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.micronaut</groupId>
|
|
||||||
<artifactId>micronaut-http-client</artifactId>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.micronaut</groupId>
|
|
||||||
<artifactId>micronaut-http-server-netty</artifactId>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ch.qos.logback</groupId>
|
|
||||||
<artifactId>logback-classic</artifactId>
|
|
||||||
<version>1.2.3</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
|
||||||
<version>3.1.0</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>shade</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<transformers>
|
|
||||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
|
||||||
<mainClass>${exec.mainClass}</mainClass>
|
|
||||||
</transformer>
|
|
||||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
|
||||||
</transformers>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create the `HelloWorldController.java` file in the
|
|
||||||
`src/main/java/com/example/helloworld` directory. The
|
|
||||||
`[ROOT]/src/main/java/com/example/helloworld/HelloWorldController.java` file
|
|
||||||
handles requests to the root URI `/`.
|
|
||||||
|
|
||||||
```java
|
|
||||||
package com.example.helloworld;
|
|
||||||
|
|
||||||
import io.micronaut.http.MediaType;
|
|
||||||
import io.micronaut.http.annotation.Controller;
|
|
||||||
import io.micronaut.http.annotation.Get;
|
|
||||||
|
|
||||||
@Controller("/")
|
|
||||||
public class HelloWorldController {
|
|
||||||
|
|
||||||
@Get(value = "/", produces = MediaType.TEXT_PLAIN)
|
|
||||||
public String index() {
|
|
||||||
String target = System.getenv("TARGET");
|
|
||||||
if (target == null) {
|
|
||||||
target = "NOT SPECIFIED";
|
|
||||||
}
|
|
||||||
return "Hello World: " + target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. The Micronaut application is configured via
|
|
||||||
`src/main/resources/application.yml`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
micronaut:
|
|
||||||
application:
|
|
||||||
name: helloworld-java-micronaut
|
|
||||||
server:
|
|
||||||
port: ${PORT:8080}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create the `Dockerfile` file:
|
|
||||||
|
|
||||||
```docker
|
|
||||||
# Use the official maven/Java 8 image to create a build artifact.
|
|
||||||
# https://hub.docker.com/_/maven
|
|
||||||
FROM maven:3.5-jdk-8-alpine as builder
|
|
||||||
|
|
||||||
# Copy local code to the container image.
|
|
||||||
WORKDIR /app
|
|
||||||
COPY pom.xml .
|
|
||||||
COPY src ./src
|
|
||||||
|
|
||||||
# Build a release artifact.
|
|
||||||
RUN mvn package -DskipTests
|
|
||||||
|
|
||||||
# Use AdoptOpenJDK for base image.
|
|
||||||
# It's important to use OpenJDK 8u191 or above that has container support enabled.
|
|
||||||
# https://hub.docker.com/r/adoptopenjdk/openjdk8
|
|
||||||
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
|
|
||||||
FROM adoptopenjdk/openjdk8:jdk8u202-b08-alpine-slim
|
|
||||||
|
|
||||||
# Copy the jar to the production image from the builder stage.
|
|
||||||
COPY --from=builder /app/target/helloworld-1.0.0-SNAPSHOT.jar /helloworld.jar
|
|
||||||
|
|
||||||
# Run the web service on container startup.
|
|
||||||
CMD ["java","-jar","/helloworld.jar"]
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create the `service.yaml` file. You must specify your Docker Hub username in
|
|
||||||
`{username}`. You can also configure the `TARGET`, for example you can modify
|
|
||||||
the `Micronaut Sample v1` value.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: serving.knative.dev/v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: helloworld-java-micronaut
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: docker.io/{username}/helloworld-java-micronaut
|
|
||||||
env:
|
|
||||||
- name: TARGET
|
|
||||||
value: "Micronaut Sample v1"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Building and deploying the sample
|
|
||||||
|
|
||||||
To build a container image, push your image to the registry, and then deploy
|
|
||||||
your sample app to your cluster:
|
|
||||||
|
|
||||||
1. Use Docker to build your container image and then push that image to your
|
|
||||||
Docker Hub registry. You must replace the `{username}` variables in the
|
|
||||||
following commands with your Docker Hub username.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Build the container on your local machine
|
|
||||||
docker build -t {username}/helloworld-java-micronaut .
|
|
||||||
|
|
||||||
# Push the container to docker registry
|
|
||||||
docker push {username}/helloworld-java-micronaut
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now that your container image is in the registry, you can deploy it to your
|
|
||||||
Knative cluster by running the `kubectl apply` command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl apply --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
Result: A service name `helloworld-java-micronaut` is created in your cluster
|
|
||||||
along with the following resources:
|
|
||||||
|
|
||||||
- A new immutable revision for the version of the app that you just deployed.
|
|
||||||
- The following networking resources are created for your app:
|
|
||||||
- route
|
|
||||||
- ingress
|
|
||||||
- service
|
|
||||||
- load balancer
|
|
||||||
- Auto scaling is enable to allow your pods to scale up to meet traffic, and
|
|
||||||
also back down to zero when there is no traffic.
|
|
||||||
|
|
||||||
## Testing the sample app
|
|
||||||
|
|
||||||
To verify that your sample app has been successfully deployed:
|
|
||||||
|
|
||||||
1. Retrieve the URL for your service, by running the following `kubectl get`
|
|
||||||
command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl get ksvc helloworld-java-micronaut --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
|
||||||
```
|
|
||||||
|
|
||||||
Example result:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
NAME URL
|
|
||||||
helloworld-java-micronaut http://helloworld-java-micronaut.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now you can make a request to your app and see the result. Replace
|
|
||||||
the URL below with the URL returned in the previous command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-java-micronaut.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
Example result:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
Hello World: Micronaut Sample v1
|
|
||||||
```
|
|
||||||
|
|
||||||
Congratulations on deploying your sample Java app to Knative!
|
|
||||||
|
|
||||||
## Removing the sample app deployment
|
|
||||||
|
|
||||||
To remove the sample app from your cluster, run the following `kubectl delete`
|
|
||||||
command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl delete --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,285 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
Learn how to deploy a simple web app that is written in Java and uses Micronaut.
|
||||||
|
|
||||||
|
This samples uses Docker to build locally. The app reads in a `TARGET` env
|
||||||
|
variable and then prints "Hello World: \${TARGET}!". If a value for `TARGET` is
|
||||||
|
not specified, the "NOT SPECIFIED" default value is used.
|
||||||
|
|
||||||
|
Use this sample to walk you through the steps of creating and modifying the
|
||||||
|
sample app, building and pushing your container image to a registry, and then
|
||||||
|
deploying your app to your Knative cluster.
|
||||||
|
|
||||||
|
## Before you begin
|
||||||
|
|
||||||
|
You must meet the following requirements to complete this sample:
|
||||||
|
|
||||||
|
- A version of the Knative Serving component installed and DNS configured. Follow the
|
||||||
|
[Knative installation instructions](../../../../docs/install/README.md) if you need
|
||||||
|
to create a Knative cluster.
|
||||||
|
- The following software downloaded and install on your loacal machine:
|
||||||
|
- [Java SE 8 or later JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html).
|
||||||
|
- [Micronaut 1.1](https://micronaut.io/).
|
||||||
|
- [Docker](https://www.docker.com) for building and pushing your container
|
||||||
|
image.
|
||||||
|
- [curl](https://curl.haxx.se/) to test the sample app after deployment.
|
||||||
|
- A [Docker Hub](https://hub.docker.com/) account where you can push your
|
||||||
|
container image.
|
||||||
|
|
||||||
|
**Tip**: You can clone the [Knatve/docs repo](https://github.com/knative/docs)
|
||||||
|
and then modify the source files. Alternatively, learn more by manually creating
|
||||||
|
the files yourself.
|
||||||
|
|
||||||
|
## Creating and configuring the sample code
|
||||||
|
|
||||||
|
To create and configure the source files in the root of your working directory:
|
||||||
|
|
||||||
|
1. Create the `pom.xml` file:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.example.micronaut</groupId>
|
||||||
|
<artifactId>helloworld</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
<properties>
|
||||||
|
<micronaut.version>1.1.0</micronaut.version>
|
||||||
|
<jdk.version>1.8</jdk.version>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<exec.mainClass>com.example.helloworld.Application</exec.mainClass>
|
||||||
|
</properties>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.micronaut</groupId>
|
||||||
|
<artifactId>micronaut-bom</artifactId>
|
||||||
|
<version>${micronaut.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.micronaut</groupId>
|
||||||
|
<artifactId>micronaut-inject</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.micronaut</groupId>
|
||||||
|
<artifactId>micronaut-validation</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.micronaut</groupId>
|
||||||
|
<artifactId>micronaut-runtime</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.micronaut</groupId>
|
||||||
|
<artifactId>micronaut-http-client</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.micronaut</groupId>
|
||||||
|
<artifactId>micronaut-http-server-netty</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.2.3</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<transformers>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>${exec.mainClass}</mainClass>
|
||||||
|
</transformer>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||||
|
</transformers>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create the `HelloWorldController.java` file in the
|
||||||
|
`src/main/java/com/example/helloworld` directory. The
|
||||||
|
`[ROOT]/src/main/java/com/example/helloworld/HelloWorldController.java` file
|
||||||
|
handles requests to the root URI `/`.
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.example.helloworld;
|
||||||
|
|
||||||
|
import io.micronaut.http.MediaType;
|
||||||
|
import io.micronaut.http.annotation.Controller;
|
||||||
|
import io.micronaut.http.annotation.Get;
|
||||||
|
|
||||||
|
@Controller("/")
|
||||||
|
public class HelloWorldController {
|
||||||
|
|
||||||
|
@Get(value = "/", produces = MediaType.TEXT_PLAIN)
|
||||||
|
public String index() {
|
||||||
|
String target = System.getenv("TARGET");
|
||||||
|
if (target == null) {
|
||||||
|
target = "NOT SPECIFIED";
|
||||||
|
}
|
||||||
|
return "Hello World: " + target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. The Micronaut application is configured via
|
||||||
|
`src/main/resources/application.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
micronaut:
|
||||||
|
application:
|
||||||
|
name: helloworld-java-micronaut
|
||||||
|
server:
|
||||||
|
port: ${PORT:8080}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create the `Dockerfile` file:
|
||||||
|
|
||||||
|
```docker
|
||||||
|
# Use the official maven/Java 8 image to create a build artifact.
|
||||||
|
# https://hub.docker.com/_/maven
|
||||||
|
FROM maven:3.5-jdk-8-alpine as builder
|
||||||
|
|
||||||
|
# Copy local code to the container image.
|
||||||
|
WORKDIR /app
|
||||||
|
COPY pom.xml .
|
||||||
|
COPY src ./src
|
||||||
|
|
||||||
|
# Build a release artifact.
|
||||||
|
RUN mvn package -DskipTests
|
||||||
|
|
||||||
|
# Use AdoptOpenJDK for base image.
|
||||||
|
# It's important to use OpenJDK 8u191 or above that has container support enabled.
|
||||||
|
# https://hub.docker.com/r/adoptopenjdk/openjdk8
|
||||||
|
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
|
||||||
|
FROM adoptopenjdk/openjdk8:jdk8u202-b08-alpine-slim
|
||||||
|
|
||||||
|
# Copy the jar to the production image from the builder stage.
|
||||||
|
COPY --from=builder /app/target/helloworld-1.0.0-SNAPSHOT.jar /helloworld.jar
|
||||||
|
|
||||||
|
# Run the web service on container startup.
|
||||||
|
CMD ["java","-jar","/helloworld.jar"]
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create the `service.yaml` file. You must specify your Docker Hub username in
|
||||||
|
`{username}`. You can also configure the `TARGET`, for example you can modify
|
||||||
|
the `Micronaut Sample v1` value.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: serving.knative.dev/v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: helloworld-java-micronaut
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: docker.io/{username}/helloworld-java-micronaut
|
||||||
|
env:
|
||||||
|
- name: TARGET
|
||||||
|
value: "Micronaut Sample v1"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building and deploying the sample
|
||||||
|
|
||||||
|
To build a container image, push your image to the registry, and then deploy
|
||||||
|
your sample app to your cluster:
|
||||||
|
|
||||||
|
1. Use Docker to build your container image and then push that image to your
|
||||||
|
Docker Hub registry. You must replace the `{username}` variables in the
|
||||||
|
following commands with your Docker Hub username.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Build the container on your local machine
|
||||||
|
docker build -t {username}/helloworld-java-micronaut .
|
||||||
|
|
||||||
|
# Push the container to docker registry
|
||||||
|
docker push {username}/helloworld-java-micronaut
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now that your container image is in the registry, you can deploy it to your
|
||||||
|
Knative cluster by running the `kubectl apply` command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl apply --filename service.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: A service name `helloworld-java-micronaut` is created in your cluster
|
||||||
|
along with the following resources:
|
||||||
|
|
||||||
|
- A new immutable revision for the version of the app that you just deployed.
|
||||||
|
- The following networking resources are created for your app:
|
||||||
|
- route
|
||||||
|
- ingress
|
||||||
|
- service
|
||||||
|
- load balancer
|
||||||
|
- Auto scaling is enable to allow your pods to scale up to meet traffic, and
|
||||||
|
also back down to zero when there is no traffic.
|
||||||
|
|
||||||
|
## Testing the sample app
|
||||||
|
|
||||||
|
To verify that your sample app has been successfully deployed:
|
||||||
|
|
||||||
|
1. Retrieve the URL for your service, by running the following `kubectl get`
|
||||||
|
command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get ksvc helloworld-java-micronaut --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||||
|
```
|
||||||
|
|
||||||
|
Example result:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
NAME URL
|
||||||
|
helloworld-java-micronaut http://helloworld-java-micronaut.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now you can make a request to your app and see the result. Replace
|
||||||
|
the URL below with the URL returned in the previous command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-java-micronaut.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
Example result:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
Hello World: Micronaut Sample v1
|
||||||
|
```
|
||||||
|
|
||||||
|
Congratulations on deploying your sample Java app to Knative!
|
||||||
|
|
||||||
|
## Removing the sample app deployment
|
||||||
|
|
||||||
|
To remove the sample app from your cluster, run the following `kubectl delete`
|
||||||
|
command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete --filename service.yaml
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,269 +0,0 @@
|
||||||
A simple [JAX-RS REST API](https://github.com/jax-rs) application that is
|
|
||||||
written in Java and uses [Quarkus](https://quarkus.io/).
|
|
||||||
|
|
||||||
This samples uses Docker to build locally. The app reads in a `TARGET` env
|
|
||||||
variable and then prints "Hello World: \${TARGET}!". If a value for `TARGET` is
|
|
||||||
not specified, the "NOT SPECIFIED" default value is used.
|
|
||||||
|
|
||||||
## Before you begin
|
|
||||||
|
|
||||||
You must meet the following requirements to run this sample:
|
|
||||||
|
|
||||||
- Have a Kubernetes cluster running with the Knative Serving component
|
|
||||||
installed. For more information, see the
|
|
||||||
[Knative instruction guides](https://github.com/knative/docs/blob/main/docs/install/README.md).
|
|
||||||
- An installed version of the following tools:
|
|
||||||
- [Docker](https://www.docker.com)
|
|
||||||
- [Java SE 8 or later JDK](https://www.eclipse.org/openj9/)
|
|
||||||
- [Maven](https://maven.apache.org/download.cgi)
|
|
||||||
- A [Docker Hub account](https://hub.docker.com/) to which you are able to
|
|
||||||
upload your sample's container image.
|
|
||||||
|
|
||||||
## Getting the code
|
|
||||||
|
|
||||||
You can either clone a working copy of the sample code from the repository, or
|
|
||||||
following the steps in the
|
|
||||||
[Recreating the sample code](#recreating-the-sample-code) to walk through the
|
|
||||||
steps of updating all the files.
|
|
||||||
|
|
||||||
### Cloning the sample code
|
|
||||||
|
|
||||||
Use this method to clone and then immediate run the sample. To clone the sample
|
|
||||||
code, run the following commands:
|
|
||||||
|
|
||||||
```
|
|
||||||
git clone -b "{{< branch >}}" https://github.com/knative/docs.git knative/docs
|
|
||||||
cd knative/docs/community/samples/serving/helloworld-java-quarkus
|
|
||||||
```
|
|
||||||
|
|
||||||
You are now ready to [run the sample locally](#locally-testing-your-sample).
|
|
||||||
|
|
||||||
### Recreating the sample code
|
|
||||||
|
|
||||||
Use the following steps to obtain an incomplete copy of the sample code for
|
|
||||||
which you update and create the necessary build and configuration files:
|
|
||||||
|
|
||||||
1. From the console, create a new empty web project using the Maven archetype
|
|
||||||
commands:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
mvn io.quarkus:quarkus-maven-plugin:0.13.3:create \
|
|
||||||
-DprojectGroupId=com.redhat.developer.demos \
|
|
||||||
-DprojectArtifactId=helloworld-java-quarkus \
|
|
||||||
-DclassName="com.redhat.developer.demos.GreetingResource" \
|
|
||||||
-Dpath="/"
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Update the `GreetingResource` class in
|
|
||||||
`src/main/java/com/redhat/developer/demos/GreetingResource.java` to handle
|
|
||||||
the "/" mapping and also add a `@ConfigProperty` field to provide the TARGET
|
|
||||||
environment variable:
|
|
||||||
|
|
||||||
```java
|
|
||||||
package com.redhat.developer.demos;
|
|
||||||
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.Produces;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
|
||||||
|
|
||||||
@Path("/")
|
|
||||||
public class GreeterResource {
|
|
||||||
@ConfigProperty(name = "TARGET", defaultValue="World")
|
|
||||||
String target;
|
|
||||||
|
|
||||||
@GET
|
|
||||||
@Produces(MediaType.TEXT_PLAIN)
|
|
||||||
public String greet() {
|
|
||||||
return "Hello " + target + "!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Update `src/main/resources/application.properties` to configuration the
|
|
||||||
application to default to port 8080, but allow the port to be overridden by
|
|
||||||
the `PORT` environmental variable:
|
|
||||||
|
|
||||||
```
|
|
||||||
# Configuration file
|
|
||||||
# key = value
|
|
||||||
|
|
||||||
quarkus.http.port=${PORT:8080}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Update `src/test/java/com/redhat/developer/demos/GreetingResourceTest.java`
|
|
||||||
test to reflect the change:
|
|
||||||
|
|
||||||
```java
|
|
||||||
package com.redhat.developer.demos;
|
|
||||||
|
|
||||||
import io.quarkus.test.junit.QuarkusTest;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static io.restassured.RestAssured.given;
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
|
||||||
|
|
||||||
@QuarkusTest
|
|
||||||
public class GreetingResourceTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHelloEndpoint() {
|
|
||||||
given()
|
|
||||||
.when().get("/")
|
|
||||||
.then()
|
|
||||||
.statusCode(200)
|
|
||||||
.body(is("Hello World!"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Remove `src/main/resources/META-INF/resources/index.html` file since it's
|
|
||||||
unncessary for this example.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
rm src/main/resources/META-INF/resources/index.html
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Remove `.dockerignore` file since it's unncessary for this example.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
rm .dockerignore
|
|
||||||
```
|
|
||||||
|
|
||||||
1. In your project directory, create a file named `Dockerfile` and copy the code
|
|
||||||
block below into it.
|
|
||||||
|
|
||||||
```docker
|
|
||||||
FROM quay.io/rhdevelopers/quarkus-java-builder:graal-1.0.0-rc15 as builder
|
|
||||||
COPY . /project
|
|
||||||
WORKDIR /project
|
|
||||||
# uncomment this to set the MAVEN_MIRROR_URL of your choice, to make faster builds
|
|
||||||
# ARG MAVEN_MIRROR_URL=<your-maven-mirror-url>
|
|
||||||
# e.g.
|
|
||||||
#ARG MAVEN_MIRROR_URL=http://192.168.64.1:8081/nexus/content/groups/public
|
|
||||||
|
|
||||||
RUN /usr/local/bin/entrypoint-run.sh mvn -DskipTests clean package
|
|
||||||
|
|
||||||
FROM fabric8/java-jboss-openjdk8-jdk:1.5.4
|
|
||||||
USER jboss
|
|
||||||
ENV JAVA_APP_DIR=/deployments
|
|
||||||
|
|
||||||
COPY --from=builder /project/target/lib/* /deployments/lib/
|
|
||||||
COPY --from=builder /project/target/*-runner.jar /deployments/app.jar
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/deployments/run-java.sh" ]
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want to build Quarkus native image, then copy the following code block
|
|
||||||
in to file called `Dockerfile.native`
|
|
||||||
|
|
||||||
```docker
|
|
||||||
FROM quay.io/rhdevelopers/quarkus-java-builder:graal-1.0.0-rc15 as builder
|
|
||||||
COPY . /project
|
|
||||||
# uncomment this to set the MAVEN_MIRROR_URL of your choice, to make faster builds
|
|
||||||
# ARG MAVEN_MIRROR_URL=<your-maven-mirror-url>
|
|
||||||
# e.g.
|
|
||||||
# ARG MAVEN_MIRROR_URL=http://192.168.64.1:8081/nexus/content/groups/public
|
|
||||||
|
|
||||||
RUN /usr/local/bin/entrypoint-run.sh mvn -DskipTests clean package -Pnative
|
|
||||||
|
|
||||||
FROM registry.fedoraproject.org/fedora-minimal
|
|
||||||
|
|
||||||
COPY --from=builder /project/target/helloworld-java-quarkus-runner /app
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/app" ]
|
|
||||||
```
|
|
||||||
|
|
||||||
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/v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: helloworld-java-quarkus
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: docker.io/{username}/helloworld-java-quarkus
|
|
||||||
env:
|
|
||||||
- name: TARGET
|
|
||||||
value: "Quarkus Sample v1"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Locally testing your sample
|
|
||||||
|
|
||||||
1. Run the application locally:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./mvnw compile quarkus:dev
|
|
||||||
```
|
|
||||||
|
|
||||||
Go to `http://localhost:8080/` to see your `Hello World!` message.
|
|
||||||
|
|
||||||
## 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-java-quarkus .
|
|
||||||
|
|
||||||
# (OR)
|
|
||||||
# Build the container on your local machine - Quarkus native mode
|
|
||||||
docker build -t {username}/helloworld-java-quarkus -f Dockerfile.native .
|
|
||||||
|
|
||||||
# Push the container to docker registry
|
|
||||||
docker push {username}/helloworld-java-quarkus
|
|
||||||
```
|
|
||||||
|
|
||||||
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 will perform the following steps:
|
|
||||||
|
|
||||||
- Create a new immutable revision for this version of the app.
|
|
||||||
- Network programming to create a route, ingress, service, and load balancer
|
|
||||||
for your app.
|
|
||||||
- Automatically scale your pods up and down (including to zero active pods).
|
|
||||||
|
|
||||||
1. To find the URL for your service, use
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl get ksvc helloworld-java-quarkus
|
|
||||||
|
|
||||||
NAME URL
|
|
||||||
helloworld-java-quarkus http://helloworld-java-quarkus.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now you can make a request to your app and see the result. Replace
|
|
||||||
the URL below with the URL returned in the previous command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-java-quarkus.default.1.2.3.4.xip.io
|
|
||||||
|
|
||||||
Namaste Knative World!
|
|
||||||
```
|
|
||||||
|
|
||||||
## Removing the sample app deployment
|
|
||||||
|
|
||||||
To remove the sample app from your cluster, delete the service record:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl delete --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,272 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
A simple [JAX-RS REST API](https://github.com/jax-rs) application that is
|
||||||
|
written in Java and uses [Quarkus](https://quarkus.io/).
|
||||||
|
|
||||||
|
This samples uses Docker to build locally. The app reads in a `TARGET` env
|
||||||
|
variable and then prints "Hello World: \${TARGET}!". If a value for `TARGET` is
|
||||||
|
not specified, the "NOT SPECIFIED" default value is used.
|
||||||
|
|
||||||
|
## Before you begin
|
||||||
|
|
||||||
|
You must meet the following requirements to run this sample:
|
||||||
|
|
||||||
|
- Have a Kubernetes cluster running with the Knative Serving component
|
||||||
|
installed. For more information, see the
|
||||||
|
[Knative instruction guides](https://github.com/knative/docs/blob/main/docs/install/README.md).
|
||||||
|
- An installed version of the following tools:
|
||||||
|
- [Docker](https://www.docker.com)
|
||||||
|
- [Java SE 8 or later JDK](https://www.eclipse.org/openj9/)
|
||||||
|
- [Maven](https://maven.apache.org/download.cgi)
|
||||||
|
- A [Docker Hub account](https://hub.docker.com/) to which you are able to
|
||||||
|
upload your sample's container image.
|
||||||
|
|
||||||
|
## Getting the code
|
||||||
|
|
||||||
|
You can either clone a working copy of the sample code from the repository, or
|
||||||
|
following the steps in the
|
||||||
|
[Recreating the sample code](#recreating-the-sample-code) to walk through the
|
||||||
|
steps of updating all the files.
|
||||||
|
|
||||||
|
### Cloning the sample code
|
||||||
|
|
||||||
|
Use this method to clone and then immediate run the sample. To clone the sample
|
||||||
|
code, run the following commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone -b "{{< branch >}}" https://github.com/knative/docs.git knative/docs
|
||||||
|
cd knative/docs/community/samples/serving/helloworld-java-quarkus
|
||||||
|
```
|
||||||
|
|
||||||
|
You are now ready to [run the sample locally](#locally-testing-your-sample).
|
||||||
|
|
||||||
|
### Recreating the sample code
|
||||||
|
|
||||||
|
Use the following steps to obtain an incomplete copy of the sample code for
|
||||||
|
which you update and create the necessary build and configuration files:
|
||||||
|
|
||||||
|
1. From the console, create a new empty web project using the Maven archetype
|
||||||
|
commands:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mvn io.quarkus:quarkus-maven-plugin:0.13.3:create \
|
||||||
|
-DprojectGroupId=com.redhat.developer.demos \
|
||||||
|
-DprojectArtifactId=helloworld-java-quarkus \
|
||||||
|
-DclassName="com.redhat.developer.demos.GreetingResource" \
|
||||||
|
-Dpath="/"
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Update the `GreetingResource` class in
|
||||||
|
`src/main/java/com/redhat/developer/demos/GreetingResource.java` to handle
|
||||||
|
the "/" mapping and also add a `@ConfigProperty` field to provide the TARGET
|
||||||
|
environment variable:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.redhat.developer.demos;
|
||||||
|
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||||
|
|
||||||
|
@Path("/")
|
||||||
|
public class GreeterResource {
|
||||||
|
@ConfigProperty(name = "TARGET", defaultValue="World")
|
||||||
|
String target;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.TEXT_PLAIN)
|
||||||
|
public String greet() {
|
||||||
|
return "Hello " + target + "!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Update `src/main/resources/application.properties` to configuration the
|
||||||
|
application to default to port 8080, but allow the port to be overridden by
|
||||||
|
the `PORT` environmental variable:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Configuration file
|
||||||
|
# key = value
|
||||||
|
|
||||||
|
quarkus.http.port=${PORT:8080}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Update `src/test/java/com/redhat/developer/demos/GreetingResourceTest.java`
|
||||||
|
test to reflect the change:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.redhat.developer.demos;
|
||||||
|
|
||||||
|
import io.quarkus.test.junit.QuarkusTest;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static io.restassured.RestAssured.given;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
|
||||||
|
@QuarkusTest
|
||||||
|
public class GreetingResourceTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHelloEndpoint() {
|
||||||
|
given()
|
||||||
|
.when().get("/")
|
||||||
|
.then()
|
||||||
|
.statusCode(200)
|
||||||
|
.body(is("Hello World!"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Remove `src/main/resources/META-INF/resources/index.html` file since it's
|
||||||
|
unncessary for this example.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
rm src/main/resources/META-INF/resources/index.html
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Remove `.dockerignore` file since it's unncessary for this example.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
rm .dockerignore
|
||||||
|
```
|
||||||
|
|
||||||
|
1. In your project directory, create a file named `Dockerfile` and copy the code
|
||||||
|
block below into it.
|
||||||
|
|
||||||
|
```docker
|
||||||
|
FROM quay.io/rhdevelopers/quarkus-java-builder:graal-1.0.0-rc15 as builder
|
||||||
|
COPY . /project
|
||||||
|
WORKDIR /project
|
||||||
|
# uncomment this to set the MAVEN_MIRROR_URL of your choice, to make faster builds
|
||||||
|
# ARG MAVEN_MIRROR_URL=<your-maven-mirror-url>
|
||||||
|
# e.g.
|
||||||
|
#ARG MAVEN_MIRROR_URL=http://192.168.64.1:8081/nexus/content/groups/public
|
||||||
|
|
||||||
|
RUN /usr/local/bin/entrypoint-run.sh mvn -DskipTests clean package
|
||||||
|
|
||||||
|
FROM fabric8/java-jboss-openjdk8-jdk:1.5.4
|
||||||
|
USER jboss
|
||||||
|
ENV JAVA_APP_DIR=/deployments
|
||||||
|
|
||||||
|
COPY --from=builder /project/target/lib/* /deployments/lib/
|
||||||
|
COPY --from=builder /project/target/*-runner.jar /deployments/app.jar
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/deployments/run-java.sh" ]
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to build Quarkus native image, then copy the following code block
|
||||||
|
in to file called `Dockerfile.native`
|
||||||
|
|
||||||
|
```docker
|
||||||
|
FROM quay.io/rhdevelopers/quarkus-java-builder:graal-1.0.0-rc15 as builder
|
||||||
|
COPY . /project
|
||||||
|
# uncomment this to set the MAVEN_MIRROR_URL of your choice, to make faster builds
|
||||||
|
# ARG MAVEN_MIRROR_URL=<your-maven-mirror-url>
|
||||||
|
# e.g.
|
||||||
|
# ARG MAVEN_MIRROR_URL=http://192.168.64.1:8081/nexus/content/groups/public
|
||||||
|
|
||||||
|
RUN /usr/local/bin/entrypoint-run.sh mvn -DskipTests clean package -Pnative
|
||||||
|
|
||||||
|
FROM registry.fedoraproject.org/fedora-minimal
|
||||||
|
|
||||||
|
COPY --from=builder /project/target/helloworld-java-quarkus-runner /app
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/app" ]
|
||||||
|
```
|
||||||
|
|
||||||
|
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/v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: helloworld-java-quarkus
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: docker.io/{username}/helloworld-java-quarkus
|
||||||
|
env:
|
||||||
|
- name: TARGET
|
||||||
|
value: "Quarkus Sample v1"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Locally testing your sample
|
||||||
|
|
||||||
|
1. Run the application locally:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
./mvnw compile quarkus:dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Go to `http://localhost:8080/` to see your `Hello World!` message.
|
||||||
|
|
||||||
|
## 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-java-quarkus .
|
||||||
|
|
||||||
|
# (OR)
|
||||||
|
# Build the container on your local machine - Quarkus native mode
|
||||||
|
docker build -t {username}/helloworld-java-quarkus -f Dockerfile.native .
|
||||||
|
|
||||||
|
# Push the container to docker registry
|
||||||
|
docker push {username}/helloworld-java-quarkus
|
||||||
|
```
|
||||||
|
|
||||||
|
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 will perform the following steps:
|
||||||
|
|
||||||
|
- Create a new immutable revision for this version of the app.
|
||||||
|
- Network programming to create a route, ingress, service, and load balancer
|
||||||
|
for your app.
|
||||||
|
- Automatically scale your pods up and down (including to zero active pods).
|
||||||
|
|
||||||
|
1. To find the URL for your service, use
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get ksvc helloworld-java-quarkus
|
||||||
|
|
||||||
|
NAME URL
|
||||||
|
helloworld-java-quarkus http://helloworld-java-quarkus.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now you can make a request to your app and see the result. Replace
|
||||||
|
the URL below with the URL returned in the previous command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-java-quarkus.default.1.2.3.4.xip.io
|
||||||
|
|
||||||
|
Namaste Knative World!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Removing the sample app deployment
|
||||||
|
|
||||||
|
To remove the sample app from your cluster, delete the service record:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete --filename service.yaml
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,190 +0,0 @@
|
||||||
A simple web app that executes an R script. The R script reads an env
|
|
||||||
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](../../../../docs/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
|
|
||||||
#!/usr/bin/Rscript
|
|
||||||
TARGET <- Sys.getenv("TARGET", "World")
|
|
||||||
|
|
||||||
message = paste("Hello ", TARGET, "!", sep = "")
|
|
||||||
print(message)
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create a new file named `invoke.go` and paste the following code. We use a
|
|
||||||
basic web server written in Go to execute the shell script:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
func handler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
cmd := exec.CommandContext(r.Context(), "Rscript", "HelloWorld.R")
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
out, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(500)
|
|
||||||
}
|
|
||||||
w.Write(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
http.HandleFunc("/", handler)
|
|
||||||
|
|
||||||
port := os.Getenv("PORT")
|
|
||||||
if port == "" {
|
|
||||||
port = "8080"
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create a new file named `Dockerfile` and copy the code block below into it.
|
|
||||||
|
|
||||||
```docker
|
|
||||||
# Use the official Golang image to create a build artifact.
|
|
||||||
# This is based on Debian and sets the GOPATH to /go.
|
|
||||||
# https://hub.docker.com/_/golang
|
|
||||||
FROM golang:1.12 as builder
|
|
||||||
|
|
||||||
# Copy local code to the container image.
|
|
||||||
WORKDIR /go/src/github.com/knative/docs/helloworld-r
|
|
||||||
COPY invoke.go .
|
|
||||||
|
|
||||||
# Build the command inside the container.
|
|
||||||
# (You may fetch or manage dependencies here,
|
|
||||||
# either manually or with a tool like "godep".)
|
|
||||||
RUN CGO_ENABLED=0 GOOS=linux go build -v -o invoke
|
|
||||||
|
|
||||||
# The official R base image
|
|
||||||
# https://hub.docker.com/_/r-base
|
|
||||||
# Use a Docker multi-stage build to create a lean production image.
|
|
||||||
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
|
|
||||||
FROM r-base:3.6.0
|
|
||||||
|
|
||||||
# Copy Go binary
|
|
||||||
COPY --from=builder /go/src/github.com/knative/docs/helloworld-r/invoke /invoke
|
|
||||||
COPY HelloWorld.R .
|
|
||||||
|
|
||||||
# Run the web service on container startup.
|
|
||||||
CMD ["/invoke"]
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
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/v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: helloworld-r
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: docker.io/{username}/helloworld-r
|
|
||||||
env:
|
|
||||||
- name: TARGET
|
|
||||||
value: "R 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-r .
|
|
||||||
|
|
||||||
# Push the container to docker registry
|
|
||||||
docker push {username}/helloworld-r
|
|
||||||
```
|
|
||||||
|
|
||||||
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 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.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now you can make a request to your app and see the result. Replace
|
|
||||||
the URL below with the URL returned in the previous command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-r.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-r.default.1.2.3.4.xip.io
|
|
||||||
[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
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,194 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
A simple web app that executes an R script. The R script reads an env
|
||||||
|
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](../../../../docs/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
|
||||||
|
#!/usr/bin/Rscript
|
||||||
|
TARGET <- Sys.getenv("TARGET", "World")
|
||||||
|
|
||||||
|
message = paste("Hello ", TARGET, "!", sep = "")
|
||||||
|
print(message)
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create a new file named `invoke.go` and paste the following code. We use a
|
||||||
|
basic web server written in Go to execute the shell script:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
cmd := exec.CommandContext(r.Context(), "Rscript", "HelloWorld.R")
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(500)
|
||||||
|
}
|
||||||
|
w.Write(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
http.HandleFunc("/", handler)
|
||||||
|
|
||||||
|
port := os.Getenv("PORT")
|
||||||
|
if port == "" {
|
||||||
|
port = "8080"
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create a new file named `Dockerfile` and copy the code block below into it.
|
||||||
|
|
||||||
|
```docker
|
||||||
|
# Use the official Golang image to create a build artifact.
|
||||||
|
# This is based on Debian and sets the GOPATH to /go.
|
||||||
|
# https://hub.docker.com/_/golang
|
||||||
|
FROM golang:1.12 as builder
|
||||||
|
|
||||||
|
# Copy local code to the container image.
|
||||||
|
WORKDIR /go/src/github.com/knative/docs/helloworld-r
|
||||||
|
COPY invoke.go .
|
||||||
|
|
||||||
|
# Build the command inside the container.
|
||||||
|
# (You may fetch or manage dependencies here,
|
||||||
|
# either manually or with a tool like "godep".)
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -v -o invoke
|
||||||
|
|
||||||
|
# The official R base image
|
||||||
|
# https://hub.docker.com/_/r-base
|
||||||
|
# Use a Docker multi-stage build to create a lean production image.
|
||||||
|
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
|
||||||
|
FROM r-base:3.6.0
|
||||||
|
|
||||||
|
# Copy Go binary
|
||||||
|
COPY --from=builder /go/src/github.com/knative/docs/helloworld-r/invoke /invoke
|
||||||
|
COPY HelloWorld.R .
|
||||||
|
|
||||||
|
# Run the web service on container startup.
|
||||||
|
CMD ["/invoke"]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
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/v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: helloworld-r
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: docker.io/{username}/helloworld-r
|
||||||
|
env:
|
||||||
|
- name: TARGET
|
||||||
|
value: "R 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-r .
|
||||||
|
|
||||||
|
# Push the container to docker registry
|
||||||
|
docker push {username}/helloworld-r
|
||||||
|
```
|
||||||
|
|
||||||
|
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 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.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now you can make a request to your app and see the result. Replace
|
||||||
|
the URL below with the URL returned in the previous command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-r.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-r.default.1.2.3.4.xip.io
|
||||||
|
[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
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
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](../../../../docs/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/v1
|
|
||||||
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 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.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now you can make a request to your app and see the result. Replace
|
|
||||||
the URL below with the URL returned in the previous command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-rserver.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-rserver.default.1.2.3.4.xip.io
|
|
||||||
[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
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,164 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
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](../../../../docs/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/v1
|
||||||
|
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 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.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now you can make a request to your app and see the result. Replace
|
||||||
|
the URL below with the URL returned in the previous command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-rserver.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-rserver.default.1.2.3.4.xip.io
|
||||||
|
[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
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,179 +0,0 @@
|
||||||
A simple web app written in Rust that you can use for testing. It reads in an
|
|
||||||
env variable `TARGET` and prints "Hello \${TARGET}!". If
|
|
||||||
|
|
||||||
TARGET is not specified, it will use "World" as the TARGET.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- A Kubernetes cluster with Knative installed and DNS configured. Follow the
|
|
||||||
[installation instructions](../../../../docs/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).
|
|
||||||
|
|
||||||
## Steps to recreate the sample code
|
|
||||||
|
|
||||||
While you can clone all of the code from this directory, hello world apps are
|
|
||||||
generally more useful if you build them step-by-step. The following instructions
|
|
||||||
recreate the source files from this folder.
|
|
||||||
|
|
||||||
1. Create a new file named `Cargo.toml` and paste the following code:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[package]
|
|
||||||
name = "hellorust"
|
|
||||||
version = "0.0.0"
|
|
||||||
publish = false
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
hyper = "0.12.3"
|
|
||||||
pretty_env_logger = "0.2.3"
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create a `src` folder, then create a new file named `main.rs` in that folder
|
|
||||||
and paste the following code. This code creates a basic web server which
|
|
||||||
listens on port 8080:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#![deny(warnings)]
|
|
||||||
extern crate hyper;
|
|
||||||
extern crate pretty_env_logger;
|
|
||||||
|
|
||||||
use hyper::{Body, Response, Server};
|
|
||||||
use hyper::service::service_fn_ok;
|
|
||||||
use hyper::rt::{self, Future};
|
|
||||||
use std::env;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
pretty_env_logger::init();
|
|
||||||
|
|
||||||
let mut port: u16 = 8080;
|
|
||||||
match env::var("PORT") {
|
|
||||||
Ok(p) => {
|
|
||||||
match p.parse::<u16>() {
|
|
||||||
Ok(n) => {port = n;},
|
|
||||||
Err(_e) => {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Err(_e) => {},
|
|
||||||
};
|
|
||||||
let addr = ([0, 0, 0, 0], port).into();
|
|
||||||
|
|
||||||
let new_service = || {
|
|
||||||
service_fn_ok(|_| {
|
|
||||||
|
|
||||||
let mut hello = "Hello ".to_string();
|
|
||||||
match env::var("TARGET") {
|
|
||||||
Ok(target) => {hello.push_str(&target);},
|
|
||||||
Err(_e) => {hello.push_str("World")},
|
|
||||||
};
|
|
||||||
|
|
||||||
Response::new(Body::from(hello))
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let server = Server::bind(&addr)
|
|
||||||
.serve(new_service)
|
|
||||||
.map_err(|e| eprintln!("server error: {}", e));
|
|
||||||
|
|
||||||
println!("Listening on http://{}", addr);
|
|
||||||
|
|
||||||
rt::run(server);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. In your project directory, create a file named `Dockerfile` and copy the code
|
|
||||||
block below into it.
|
|
||||||
|
|
||||||
```docker
|
|
||||||
# Use the official Rust image.
|
|
||||||
# https://hub.docker.com/_/rust
|
|
||||||
FROM rust:1.27.0
|
|
||||||
|
|
||||||
# Copy local code to the container image.
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Install production dependencies and build a release artifact.
|
|
||||||
RUN cargo install
|
|
||||||
|
|
||||||
# Run the web service on container startup.
|
|
||||||
CMD ["hellorust"]
|
|
||||||
```
|
|
||||||
|
|
||||||
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/v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: helloworld-rust
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: docker.io/{username}/helloworld-rust
|
|
||||||
env:
|
|
||||||
- name: TARGET
|
|
||||||
value: "Rust Sample v1"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Build and deploy this 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, enter these commands replacing `{username}` with your Docker Hub
|
|
||||||
username:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Build the container on your local machine
|
|
||||||
docker build -t {username}/helloworld-rust .
|
|
||||||
|
|
||||||
# Push the container to docker registry
|
|
||||||
docker push {username}/helloworld-rust
|
|
||||||
```
|
|
||||||
|
|
||||||
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 will perform 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. To find the URL for your service, enter:
|
|
||||||
|
|
||||||
```
|
|
||||||
kubectl get ksvc helloworld-rust --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
|
||||||
NAME URL
|
|
||||||
helloworld-rust http://helloworld-rust.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now you can make a request to your app and see the result. Replace
|
|
||||||
the URL below with the URL returned in the previous command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-rust.default.1.2.3.4.xip.io
|
|
||||||
Hello World!
|
|
||||||
```
|
|
||||||
|
|
||||||
## Removing the sample app deployment
|
|
||||||
|
|
||||||
To remove the sample app from your cluster, delete the service record:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl delete --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,183 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
A simple web app written in Rust that you can use for testing. It reads in an
|
||||||
|
env variable `TARGET` and prints "Hello \${TARGET}!". If
|
||||||
|
|
||||||
|
TARGET is not specified, it will use "World" as the TARGET.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- A Kubernetes cluster with Knative installed and DNS configured. Follow the
|
||||||
|
[installation instructions](../../../../docs/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).
|
||||||
|
|
||||||
|
## Steps to recreate the sample code
|
||||||
|
|
||||||
|
While you can clone all of the code from this directory, hello world apps are
|
||||||
|
generally more useful if you build them step-by-step. The following instructions
|
||||||
|
recreate the source files from this folder.
|
||||||
|
|
||||||
|
1. Create a new file named `Cargo.toml` and paste the following code:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[package]
|
||||||
|
name = "hellorust"
|
||||||
|
version = "0.0.0"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
hyper = "0.12.3"
|
||||||
|
pretty_env_logger = "0.2.3"
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create a `src` folder, then create a new file named `main.rs` in that folder
|
||||||
|
and paste the following code. This code creates a basic web server which
|
||||||
|
listens on port 8080:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#![deny(warnings)]
|
||||||
|
extern crate hyper;
|
||||||
|
extern crate pretty_env_logger;
|
||||||
|
|
||||||
|
use hyper::{Body, Response, Server};
|
||||||
|
use hyper::service::service_fn_ok;
|
||||||
|
use hyper::rt::{self, Future};
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
pretty_env_logger::init();
|
||||||
|
|
||||||
|
let mut port: u16 = 8080;
|
||||||
|
match env::var("PORT") {
|
||||||
|
Ok(p) => {
|
||||||
|
match p.parse::<u16>() {
|
||||||
|
Ok(n) => {port = n;},
|
||||||
|
Err(_e) => {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Err(_e) => {},
|
||||||
|
};
|
||||||
|
let addr = ([0, 0, 0, 0], port).into();
|
||||||
|
|
||||||
|
let new_service = || {
|
||||||
|
service_fn_ok(|_| {
|
||||||
|
|
||||||
|
let mut hello = "Hello ".to_string();
|
||||||
|
match env::var("TARGET") {
|
||||||
|
Ok(target) => {hello.push_str(&target);},
|
||||||
|
Err(_e) => {hello.push_str("World")},
|
||||||
|
};
|
||||||
|
|
||||||
|
Response::new(Body::from(hello))
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let server = Server::bind(&addr)
|
||||||
|
.serve(new_service)
|
||||||
|
.map_err(|e| eprintln!("server error: {}", e));
|
||||||
|
|
||||||
|
println!("Listening on http://{}", addr);
|
||||||
|
|
||||||
|
rt::run(server);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. In your project directory, create a file named `Dockerfile` and copy the code
|
||||||
|
block below into it.
|
||||||
|
|
||||||
|
```docker
|
||||||
|
# Use the official Rust image.
|
||||||
|
# https://hub.docker.com/_/rust
|
||||||
|
FROM rust:1.27.0
|
||||||
|
|
||||||
|
# Copy local code to the container image.
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Install production dependencies and build a release artifact.
|
||||||
|
RUN cargo install
|
||||||
|
|
||||||
|
# Run the web service on container startup.
|
||||||
|
CMD ["hellorust"]
|
||||||
|
```
|
||||||
|
|
||||||
|
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/v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: helloworld-rust
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: docker.io/{username}/helloworld-rust
|
||||||
|
env:
|
||||||
|
- name: TARGET
|
||||||
|
value: "Rust Sample v1"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build and deploy this 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, enter these commands replacing `{username}` with your Docker Hub
|
||||||
|
username:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Build the container on your local machine
|
||||||
|
docker build -t {username}/helloworld-rust .
|
||||||
|
|
||||||
|
# Push the container to docker registry
|
||||||
|
docker push {username}/helloworld-rust
|
||||||
|
```
|
||||||
|
|
||||||
|
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 will perform 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. To find the URL for your service, enter:
|
||||||
|
|
||||||
|
```
|
||||||
|
kubectl get ksvc helloworld-rust --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||||
|
NAME URL
|
||||||
|
helloworld-rust http://helloworld-rust.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now you can make a request to your app and see the result. Replace
|
||||||
|
the URL below with the URL returned in the previous command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-rust.default.1.2.3.4.xip.io
|
||||||
|
Hello World!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Removing the sample app deployment
|
||||||
|
|
||||||
|
To remove the sample app from your cluster, delete the service record:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete --filename service.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,162 +0,0 @@
|
||||||
A simple web app written in Swift that you can use for testing. The app reads in
|
|
||||||
an env variable `TARGET` and prints "Hello \${TARGET}!". If TARGET is not
|
|
||||||
specified, the app uses "World" as the TARGET.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- You must have a Kubernetes cluster with Knative installed and DNS configured.
|
|
||||||
If you need to create a cluster, follow the
|
|
||||||
[installation instructions](../../../../docs/install/README.md).
|
|
||||||
- You must have [Docker](https://www.docker.com) installed and running on your
|
|
||||||
local machine, and a Docker Hub account configured (used for container
|
|
||||||
registry).
|
|
||||||
|
|
||||||
## Recreating the sample code
|
|
||||||
|
|
||||||
While you can clone all of the code from this directory, it might be more useful
|
|
||||||
if you build this app step-by-step. The following instructions recreate the
|
|
||||||
source files from this folder.
|
|
||||||
|
|
||||||
1. Create a the `Package.swift` to declare your package and its dependencies.
|
|
||||||
This app uses [Swifter](https://github.com/httpswift/swifter), a tiny http
|
|
||||||
server engine for Swift.
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// swift-tools-version:4.0
|
|
||||||
|
|
||||||
import PackageDescription
|
|
||||||
|
|
||||||
let package = Package(
|
|
||||||
name: "HelloSwift",
|
|
||||||
dependencies: [
|
|
||||||
.package(url: "https://github.com/httpswift/swifter.git", .upToNextMajor(from: "1.4.5"))
|
|
||||||
],
|
|
||||||
targets: [
|
|
||||||
.target(
|
|
||||||
name: "HelloSwift",
|
|
||||||
dependencies: ["Swifter"],
|
|
||||||
path: "./Sources")
|
|
||||||
]
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Add the web server code to a file named `main.swift` in a
|
|
||||||
`Sources/HelloSwift/` folder:
|
|
||||||
|
|
||||||
```swift
|
|
||||||
import Swifter
|
|
||||||
import Dispatch
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
let server = HttpServer()
|
|
||||||
server["/"] = { r in
|
|
||||||
let target = ProcessInfo.processInfo.environment["TARGET"] ?? "World"
|
|
||||||
return HttpResponse.ok(.html("Hello \(target)"))
|
|
||||||
}
|
|
||||||
|
|
||||||
let semaphore = DispatchSemaphore(value: 0)
|
|
||||||
do {
|
|
||||||
let port = UInt16(ProcessInfo.processInfo.environment["PORT"] ?? "8080")
|
|
||||||
try server.start(port!, forceIPv4: true)
|
|
||||||
print("Server has started ( port = \(try server.port()) ). Try to connect now...")
|
|
||||||
semaphore.wait()
|
|
||||||
} catch {
|
|
||||||
print("Server start error: \(error)")
|
|
||||||
semaphore.signal()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. In your project directory, create a file named `Dockerfile` and copy the code
|
|
||||||
block below into it.
|
|
||||||
|
|
||||||
```Dockerfile
|
|
||||||
# Use the official Swift image.
|
|
||||||
# https://hub.docker.com/_/swift
|
|
||||||
FROM swift:4.2
|
|
||||||
|
|
||||||
# Copy local code to the container image.
|
|
||||||
WORKDIR /app
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Install dependencies and build.
|
|
||||||
RUN swift build -c release
|
|
||||||
|
|
||||||
# Run the web service on container startup.
|
|
||||||
CMD [ ".build/release/HelloSwift"]
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create a new file, `service.yaml`, and copy the following service definition
|
|
||||||
into the file. Replace `{username}` with your Docker Hub username.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: serving.knative.dev/v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: helloworld-swift
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: docker.io/{username}/helloworld-swift
|
|
||||||
env:
|
|
||||||
- name: TARGET
|
|
||||||
value: "Swift"
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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-swift .
|
|
||||||
|
|
||||||
# Push the container to docker registry
|
|
||||||
docker push {username}/helloworld-swift
|
|
||||||
```
|
|
||||||
|
|
||||||
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 the `service.yaml` file matches the container you built in the previous
|
|
||||||
step. Apply the configuration using the `kubectl` command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl apply --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now that your service is created, Knative performs the following steps:
|
|
||||||
|
|
||||||
- Creates a new immutable revision for this version of the app.
|
|
||||||
- Network programming to create a route, ingress, service, and load balancing
|
|
||||||
for your app.
|
|
||||||
- Automatically scales your pods up and down (including to zero active pods).
|
|
||||||
|
|
||||||
1. To find the URL for your service, use the following command:
|
|
||||||
|
|
||||||
```
|
|
||||||
kubectl get ksvc helloworld-swift --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
|
||||||
NAME URL
|
|
||||||
helloworld-swift http://helloworld-swift.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now you can make a request to your app and see the result. Replace
|
|
||||||
the URL below with the URL returned in the previous command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-swift.default.1.2.3.4.xip.io
|
|
||||||
Hello Swift
|
|
||||||
```
|
|
||||||
|
|
||||||
## Removing the sample app deployment
|
|
||||||
|
|
||||||
To remove the sample app from your cluster, delete the service record:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl delete --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,165 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
A simple web app written in Swift that you can use for testing. The app reads in
|
||||||
|
an env variable `TARGET` and prints "Hello \${TARGET}!". If TARGET is not
|
||||||
|
specified, the app uses "World" as the TARGET.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- You must have a Kubernetes cluster with Knative installed and DNS configured.
|
||||||
|
If you need to create a cluster, follow the
|
||||||
|
[installation instructions](../../../../docs/install/README.md).
|
||||||
|
- You must have [Docker](https://www.docker.com) installed and running on your
|
||||||
|
local machine, and a Docker Hub account configured (used for container
|
||||||
|
registry).
|
||||||
|
|
||||||
|
## Recreating the sample code
|
||||||
|
|
||||||
|
While you can clone all of the code from this directory, it might be more useful
|
||||||
|
if you build this app step-by-step. The following instructions recreate the
|
||||||
|
source files from this folder.
|
||||||
|
|
||||||
|
1. Create a the `Package.swift` to declare your package and its dependencies.
|
||||||
|
This app uses [Swifter](https://github.com/httpswift/swifter), a tiny http
|
||||||
|
server engine for Swift.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
// swift-tools-version:4.0
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "HelloSwift",
|
||||||
|
dependencies: [
|
||||||
|
.package(url: "https://github.com/httpswift/swifter.git", .upToNextMajor(from: "1.4.5"))
|
||||||
|
],
|
||||||
|
targets: [
|
||||||
|
.target(
|
||||||
|
name: "HelloSwift",
|
||||||
|
dependencies: ["Swifter"],
|
||||||
|
path: "./Sources")
|
||||||
|
]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Add the web server code to a file named `main.swift` in a
|
||||||
|
`Sources/HelloSwift/` folder:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
import Swifter
|
||||||
|
import Dispatch
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
let server = HttpServer()
|
||||||
|
server["/"] = { r in
|
||||||
|
let target = ProcessInfo.processInfo.environment["TARGET"] ?? "World"
|
||||||
|
return HttpResponse.ok(.html("Hello \(target)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let semaphore = DispatchSemaphore(value: 0)
|
||||||
|
do {
|
||||||
|
let port = UInt16(ProcessInfo.processInfo.environment["PORT"] ?? "8080")
|
||||||
|
try server.start(port!, forceIPv4: true)
|
||||||
|
print("Server has started ( port = \(try server.port()) ). Try to connect now...")
|
||||||
|
semaphore.wait()
|
||||||
|
} catch {
|
||||||
|
print("Server start error: \(error)")
|
||||||
|
semaphore.signal()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. In your project directory, create a file named `Dockerfile` and copy the code
|
||||||
|
block below into it.
|
||||||
|
|
||||||
|
```Dockerfile
|
||||||
|
# Use the official Swift image.
|
||||||
|
# https://hub.docker.com/_/swift
|
||||||
|
FROM swift:4.2
|
||||||
|
|
||||||
|
# Copy local code to the container image.
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Install dependencies and build.
|
||||||
|
RUN swift build -c release
|
||||||
|
|
||||||
|
# Run the web service on container startup.
|
||||||
|
CMD [ ".build/release/HelloSwift"]
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create a new file, `service.yaml`, and copy the following service definition
|
||||||
|
into the file. Replace `{username}` with your Docker Hub username.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: serving.knative.dev/v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: helloworld-swift
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: docker.io/{username}/helloworld-swift
|
||||||
|
env:
|
||||||
|
- name: TARGET
|
||||||
|
value: "Swift"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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-swift .
|
||||||
|
|
||||||
|
# Push the container to docker registry
|
||||||
|
docker push {username}/helloworld-swift
|
||||||
|
```
|
||||||
|
|
||||||
|
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 the `service.yaml` file matches the container you built in the previous
|
||||||
|
step. Apply the configuration using the `kubectl` command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl apply --filename service.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now that your service is created, Knative performs the following steps:
|
||||||
|
|
||||||
|
- Creates a new immutable revision for this version of the app.
|
||||||
|
- Network programming to create a route, ingress, service, and load balancing
|
||||||
|
for your app.
|
||||||
|
- Automatically scales your pods up and down (including to zero active pods).
|
||||||
|
|
||||||
|
1. To find the URL for your service, use the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
kubectl get ksvc helloworld-swift --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||||
|
NAME URL
|
||||||
|
helloworld-swift http://helloworld-swift.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now you can make a request to your app and see the result. Replace
|
||||||
|
the URL below with the URL returned in the previous command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-swift.default.1.2.3.4.xip.io
|
||||||
|
Hello Swift
|
||||||
|
```
|
||||||
|
|
||||||
|
## Removing the sample app deployment
|
||||||
|
|
||||||
|
To remove the sample app from your cluster, delete the service record:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete --filename service.yaml
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,250 +0,0 @@
|
||||||
Learn how to deploy a simple web app that is written in Java and uses Eclipse
|
|
||||||
Vert.x. This samples uses Docker to build locally. The app reads in a `TARGET`
|
|
||||||
env variable and then prints "Hello World: \${TARGET}!". If a value for `TARGET`
|
|
||||||
is not specified, the "NOT SPECIFIED" default value is used.
|
|
||||||
|
|
||||||
Use this sample to walk you through the steps of creating and modifying the
|
|
||||||
sample app, building and pushing your container image to a registry, and then
|
|
||||||
deploying your app to your Knative cluster.
|
|
||||||
|
|
||||||
## Before you begin
|
|
||||||
|
|
||||||
You must meet the following requirements to complete this sample:
|
|
||||||
|
|
||||||
- A version of the Knative Serving component installed and running on your
|
|
||||||
Kubernetes cluster. Follow the
|
|
||||||
[Knative installation instructions](../../../../docs/install/README.md) if you need to
|
|
||||||
create a Knative cluster.
|
|
||||||
- The following software downloaded and install on your loacal machine:
|
|
||||||
- [Java SE 8 or later JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html).
|
|
||||||
- [Eclipse Vert.x v3.5.4](https://vertx.io/).
|
|
||||||
- [Docker](https://www.docker.com) for building and pushing your container
|
|
||||||
image.
|
|
||||||
- [curl](https://curl.haxx.se/) to test the sample app after deployment.
|
|
||||||
- A [Docker Hub](https://hub.docker.com/) account where you can push your
|
|
||||||
container image.
|
|
||||||
|
|
||||||
**Tip**: You can clone the [Knative/docs repo](https://github.com/knative/docs)
|
|
||||||
and then modify the source files. Alternatively, learn more by manually creating
|
|
||||||
the files yourself.
|
|
||||||
|
|
||||||
## Creating and configuring the sample code
|
|
||||||
|
|
||||||
To create and configure the source files in the root of your working directory:
|
|
||||||
|
|
||||||
1. Create the `pom.xml` file:
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
|
||||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>com.example.vertx</groupId>
|
|
||||||
<artifactId>helloworld</artifactId>
|
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.vertx</groupId>
|
|
||||||
<artifactId>vertx-core</artifactId>
|
|
||||||
<version>${version.vertx}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.vertx</groupId>
|
|
||||||
<artifactId>vertx-rx-java2</artifactId>
|
|
||||||
<version>${version.vertx}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.8.0</version>
|
|
||||||
<configuration>
|
|
||||||
<source>1.8</source>
|
|
||||||
<target>1.8</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
|
||||||
<version>3.2.0</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>shade</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<transformers>
|
|
||||||
<transformer
|
|
||||||
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
|
||||||
<manifestEntries>
|
|
||||||
<Main-Class>io.vertx.core.Launcher</Main-Class>
|
|
||||||
<Main-Verticle>com.example.helloworld.HelloWorld</Main-Verticle>
|
|
||||||
</manifestEntries>
|
|
||||||
</transformer>
|
|
||||||
</transformers>
|
|
||||||
<artifactSet/>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
<properties>
|
|
||||||
<version.vertx>3.5.4</version.vertx>
|
|
||||||
</properties>
|
|
||||||
</project>
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create the `HelloWorld.java` file in the
|
|
||||||
`src/main/java/com/example/helloworld` directory. The
|
|
||||||
`[ROOT]/src/main/java/com/example/helloworld/HelloWorld.java` file creates a
|
|
||||||
basic web server that listens on port `8080`.
|
|
||||||
|
|
||||||
```java
|
|
||||||
package com.example.helloworld;
|
|
||||||
|
|
||||||
import io.reactivex.Flowable;
|
|
||||||
import io.vertx.reactivex.core.AbstractVerticle;
|
|
||||||
import io.vertx.reactivex.core.http.HttpServer;
|
|
||||||
import io.vertx.reactivex.core.http.HttpServerRequest;
|
|
||||||
|
|
||||||
public class HelloWorld extends AbstractVerticle {
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
|
|
||||||
final HttpServer server = vertx.createHttpServer();
|
|
||||||
final Flowable<HttpServerRequest> requestFlowable = server.requestStream().toFlowable();
|
|
||||||
|
|
||||||
requestFlowable.subscribe(httpServerRequest -> {
|
|
||||||
|
|
||||||
String target = System.getenv("TARGET");
|
|
||||||
if (target == null) {
|
|
||||||
target = "NOT SPECIFIED";
|
|
||||||
}
|
|
||||||
|
|
||||||
httpServerRequest.response().setChunked(true)
|
|
||||||
.putHeader("content-type", "text/plain")
|
|
||||||
.setStatusCode(200) // OK
|
|
||||||
.end("Hello World: " + target);
|
|
||||||
});
|
|
||||||
|
|
||||||
server.listen(8080);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create the `Dockerfile` file:
|
|
||||||
|
|
||||||
```docker
|
|
||||||
# Use fabric8's s2i Builder image.
|
|
||||||
# https://hub.docker.com/r/fabric8/s2i-java
|
|
||||||
FROM fabric8/s2i-java:2.0
|
|
||||||
|
|
||||||
# Copy the JAR file to the deployment directory.
|
|
||||||
ENV JAVA_APP_DIR=/deployments
|
|
||||||
COPY target/helloworld-1.0.0-SNAPSHOT.jar /deployments/
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create the `service.yaml` file. You must specify your Docker Hub username in
|
|
||||||
`{username}`. You can also configure the `TARGET`, for example you can modify
|
|
||||||
the `Eclipse Vert.x Sample v1` value.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: serving.knative.dev/v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: helloworld-vertx
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: docker.io/{username}/helloworld-vertx
|
|
||||||
env:
|
|
||||||
- name: TARGET
|
|
||||||
value: "Eclipse Vert.x Sample v1"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Building and deploying the sample
|
|
||||||
|
|
||||||
To build a container image, push your image to the registry, and then deploy
|
|
||||||
your sample app to your cluster:
|
|
||||||
|
|
||||||
1. Use Docker to build your container image and then push that image to your
|
|
||||||
Docker Hub registry. You must replace the `{username}` variables in the
|
|
||||||
following commands with your Docker Hub username.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Build the container on your local machine
|
|
||||||
docker build -t {username}/helloworld-vertx .
|
|
||||||
|
|
||||||
# Push the container to docker registry
|
|
||||||
docker push {username}/helloworld-vertx
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now that your container image is in the registry, you can deploy it to your
|
|
||||||
Knative cluster by running the `kubectl apply` command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl apply --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
Result: A service name `helloworld-vertx` is created in your cluster along
|
|
||||||
with the following resources:
|
|
||||||
|
|
||||||
- A new immutable revision for the version of the app that you just deployed.
|
|
||||||
- The following networking resources are created for your app:
|
|
||||||
- route
|
|
||||||
- ingress
|
|
||||||
- service
|
|
||||||
- load balancer
|
|
||||||
- Auto scaling is enable to allow your pods to scale up to meet traffic, and
|
|
||||||
also back down to zero when there is no traffic.
|
|
||||||
|
|
||||||
## Testing the sample app
|
|
||||||
|
|
||||||
To verify that your sample app has been successfully deployed:
|
|
||||||
|
|
||||||
1. Retrieve the URL for your service, by running the following `kubectl get`
|
|
||||||
command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl get ksvc helloworld-vertx --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
|
||||||
```
|
|
||||||
|
|
||||||
Example result:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
NAME URL
|
|
||||||
helloworld-vertx http://helloworld-vertx.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Now you can make a request to your app and see the result. Replace
|
|
||||||
the URL below with the URL returned in the previous command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl http://helloworld-vertx.default.1.2.3.4.xip.io
|
|
||||||
```
|
|
||||||
|
|
||||||
Example result:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
Hello World: Eclipse Vert.x Sample v1
|
|
||||||
```
|
|
||||||
|
|
||||||
Congratulations on deploying your sample Java app to Knative!
|
|
||||||
|
|
||||||
## Removing the sample app deployment
|
|
||||||
|
|
||||||
To remove the sample app from your cluster, run the following `kubectl delete`
|
|
||||||
command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl delete --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,253 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
Learn how to deploy a simple web app that is written in Java and uses Eclipse
|
||||||
|
Vert.x. This samples uses Docker to build locally. The app reads in a `TARGET`
|
||||||
|
env variable and then prints "Hello World: \${TARGET}!". If a value for `TARGET`
|
||||||
|
is not specified, the "NOT SPECIFIED" default value is used.
|
||||||
|
|
||||||
|
Use this sample to walk you through the steps of creating and modifying the
|
||||||
|
sample app, building and pushing your container image to a registry, and then
|
||||||
|
deploying your app to your Knative cluster.
|
||||||
|
|
||||||
|
## Before you begin
|
||||||
|
|
||||||
|
You must meet the following requirements to complete this sample:
|
||||||
|
|
||||||
|
- A version of the Knative Serving component installed and running on your
|
||||||
|
Kubernetes cluster. Follow the
|
||||||
|
[Knative installation instructions](../../../../docs/install/README.md) if you need to
|
||||||
|
create a Knative cluster.
|
||||||
|
- The following software downloaded and install on your loacal machine:
|
||||||
|
- [Java SE 8 or later JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html).
|
||||||
|
- [Eclipse Vert.x v3.5.4](https://vertx.io/).
|
||||||
|
- [Docker](https://www.docker.com) for building and pushing your container
|
||||||
|
image.
|
||||||
|
- [curl](https://curl.haxx.se/) to test the sample app after deployment.
|
||||||
|
- A [Docker Hub](https://hub.docker.com/) account where you can push your
|
||||||
|
container image.
|
||||||
|
|
||||||
|
**Tip**: You can clone the [Knative/docs repo](https://github.com/knative/docs)
|
||||||
|
and then modify the source files. Alternatively, learn more by manually creating
|
||||||
|
the files yourself.
|
||||||
|
|
||||||
|
## Creating and configuring the sample code
|
||||||
|
|
||||||
|
To create and configure the source files in the root of your working directory:
|
||||||
|
|
||||||
|
1. Create the `pom.xml` file:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||||
|
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.example.vertx</groupId>
|
||||||
|
<artifactId>helloworld</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.vertx</groupId>
|
||||||
|
<artifactId>vertx-core</artifactId>
|
||||||
|
<version>${version.vertx}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.vertx</groupId>
|
||||||
|
<artifactId>vertx-rx-java2</artifactId>
|
||||||
|
<version>${version.vertx}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.0</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<transformers>
|
||||||
|
<transformer
|
||||||
|
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<manifestEntries>
|
||||||
|
<Main-Class>io.vertx.core.Launcher</Main-Class>
|
||||||
|
<Main-Verticle>com.example.helloworld.HelloWorld</Main-Verticle>
|
||||||
|
</manifestEntries>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
<artifactSet/>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<properties>
|
||||||
|
<version.vertx>3.5.4</version.vertx>
|
||||||
|
</properties>
|
||||||
|
</project>
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create the `HelloWorld.java` file in the
|
||||||
|
`src/main/java/com/example/helloworld` directory. The
|
||||||
|
`[ROOT]/src/main/java/com/example/helloworld/HelloWorld.java` file creates a
|
||||||
|
basic web server that listens on port `8080`.
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.example.helloworld;
|
||||||
|
|
||||||
|
import io.reactivex.Flowable;
|
||||||
|
import io.vertx.reactivex.core.AbstractVerticle;
|
||||||
|
import io.vertx.reactivex.core.http.HttpServer;
|
||||||
|
import io.vertx.reactivex.core.http.HttpServerRequest;
|
||||||
|
|
||||||
|
public class HelloWorld extends AbstractVerticle {
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
|
||||||
|
final HttpServer server = vertx.createHttpServer();
|
||||||
|
final Flowable<HttpServerRequest> requestFlowable = server.requestStream().toFlowable();
|
||||||
|
|
||||||
|
requestFlowable.subscribe(httpServerRequest -> {
|
||||||
|
|
||||||
|
String target = System.getenv("TARGET");
|
||||||
|
if (target == null) {
|
||||||
|
target = "NOT SPECIFIED";
|
||||||
|
}
|
||||||
|
|
||||||
|
httpServerRequest.response().setChunked(true)
|
||||||
|
.putHeader("content-type", "text/plain")
|
||||||
|
.setStatusCode(200) // OK
|
||||||
|
.end("Hello World: " + target);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(8080);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create the `Dockerfile` file:
|
||||||
|
|
||||||
|
```docker
|
||||||
|
# Use fabric8's s2i Builder image.
|
||||||
|
# https://hub.docker.com/r/fabric8/s2i-java
|
||||||
|
FROM fabric8/s2i-java:2.0
|
||||||
|
|
||||||
|
# Copy the JAR file to the deployment directory.
|
||||||
|
ENV JAVA_APP_DIR=/deployments
|
||||||
|
COPY target/helloworld-1.0.0-SNAPSHOT.jar /deployments/
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create the `service.yaml` file. You must specify your Docker Hub username in
|
||||||
|
`{username}`. You can also configure the `TARGET`, for example you can modify
|
||||||
|
the `Eclipse Vert.x Sample v1` value.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: serving.knative.dev/v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: helloworld-vertx
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: docker.io/{username}/helloworld-vertx
|
||||||
|
env:
|
||||||
|
- name: TARGET
|
||||||
|
value: "Eclipse Vert.x Sample v1"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building and deploying the sample
|
||||||
|
|
||||||
|
To build a container image, push your image to the registry, and then deploy
|
||||||
|
your sample app to your cluster:
|
||||||
|
|
||||||
|
1. Use Docker to build your container image and then push that image to your
|
||||||
|
Docker Hub registry. You must replace the `{username}` variables in the
|
||||||
|
following commands with your Docker Hub username.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Build the container on your local machine
|
||||||
|
docker build -t {username}/helloworld-vertx .
|
||||||
|
|
||||||
|
# Push the container to docker registry
|
||||||
|
docker push {username}/helloworld-vertx
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now that your container image is in the registry, you can deploy it to your
|
||||||
|
Knative cluster by running the `kubectl apply` command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl apply --filename service.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: A service name `helloworld-vertx` is created in your cluster along
|
||||||
|
with the following resources:
|
||||||
|
|
||||||
|
- A new immutable revision for the version of the app that you just deployed.
|
||||||
|
- The following networking resources are created for your app:
|
||||||
|
- route
|
||||||
|
- ingress
|
||||||
|
- service
|
||||||
|
- load balancer
|
||||||
|
- Auto scaling is enable to allow your pods to scale up to meet traffic, and
|
||||||
|
also back down to zero when there is no traffic.
|
||||||
|
|
||||||
|
## Testing the sample app
|
||||||
|
|
||||||
|
To verify that your sample app has been successfully deployed:
|
||||||
|
|
||||||
|
1. Retrieve the URL for your service, by running the following `kubectl get`
|
||||||
|
command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get ksvc helloworld-vertx --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||||
|
```
|
||||||
|
|
||||||
|
Example result:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
NAME URL
|
||||||
|
helloworld-vertx http://helloworld-vertx.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Now you can make a request to your app and see the result. Replace
|
||||||
|
the URL below with the URL returned in the previous command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl http://helloworld-vertx.default.1.2.3.4.xip.io
|
||||||
|
```
|
||||||
|
|
||||||
|
Example result:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
Hello World: Eclipse Vert.x Sample v1
|
||||||
|
```
|
||||||
|
|
||||||
|
Congratulations on deploying your sample Java app to Knative!
|
||||||
|
|
||||||
|
## Removing the sample app deployment
|
||||||
|
|
||||||
|
To remove the sample app from your cluster, run the following `kubectl delete`
|
||||||
|
command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete --filename service.yaml
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,186 +0,0 @@
|
||||||
A simple machine learning model with API serving that is written in python and
|
|
||||||
using [BentoML](https://github.com/bentoml/BentoML). BentoML is an open source
|
|
||||||
framework for high performance ML model serving, which supports all major machine
|
|
||||||
learning frameworks including Keras, Tensorflow, PyTorch, Fast.ai, XGBoost and etc.
|
|
||||||
|
|
||||||
This sample will walk you through the steps of creating and deploying a machine learning
|
|
||||||
model using python. It will use BentoML to package a classifier model trained
|
|
||||||
on the Iris dataset. Afterward, it will create a container image and
|
|
||||||
deploy the image to Knative.
|
|
||||||
|
|
||||||
Knative deployment guide with BentoML is also available in the
|
|
||||||
[BentoML documentation](https://docs.bentoml.org/en/latest/deployment/knative.html)
|
|
||||||
|
|
||||||
## Before you begin
|
|
||||||
|
|
||||||
- A Kubernetes cluster with Knative installed. Follow the
|
|
||||||
[installation instructions](../../../../docs/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. Docker Hub will be used for a container registry).
|
|
||||||
- Python 3.6 or above installed and running on your local machine.
|
|
||||||
- Install `scikit-learn` and `bentoml` packages:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pip install scikit-learn
|
|
||||||
pip install bentoml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Recreating sample code
|
|
||||||
|
|
||||||
Run the following code on your local machine, to train a machine learning model and deploy it
|
|
||||||
as API endpoint with KNative Serving.
|
|
||||||
|
|
||||||
1. BentoML creates a model API server, via prediction service abstraction. In
|
|
||||||
`iris_classifier.py`, it defines a prediction service that requires a scikit-learn
|
|
||||||
model, asks BentoML to figure out the required pip dependencies, also defines an
|
|
||||||
API, which is the entry point for accessing this machine learning service.
|
|
||||||
|
|
||||||
{{% readfile file="iris_classifier.py" %}}
|
|
||||||
|
|
||||||
2. In `main.py`, it uses the classic
|
|
||||||
[iris flower data set](https://en.wikipedia.org/wiki/Iris_flower_data_set)
|
|
||||||
to train a classification model which can predict the species of an iris flower with
|
|
||||||
given data and then save the model with BentoML to local disk.
|
|
||||||
|
|
||||||
{{% readfile file="main.py" %}}
|
|
||||||
|
|
||||||
Run the `main.py` file to train and save the model:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
python main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Use BentoML CLI to check saved model's information.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
bentoml get IrisClassifier:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
> bentoml get IrisClassifier:latest
|
|
||||||
{
|
|
||||||
"name": "IrisClassifier",
|
|
||||||
"version": "20200305171229_0A1411",
|
|
||||||
"uri": {
|
|
||||||
"type": "LOCAL",
|
|
||||||
"uri": "/Users/bozhaoyu/bentoml/repository/IrisClassifier/20200305171229_0A1411"
|
|
||||||
},
|
|
||||||
"bentoServiceMetadata": {
|
|
||||||
"name": "IrisClassifier",
|
|
||||||
"version": "20200305171229_0A1411",
|
|
||||||
"createdAt": "2020-03-06T01:12:49.431011Z",
|
|
||||||
"env": {
|
|
||||||
"condaEnv": "name: bentoml-IrisClassifier\nchannels:\n- defaults\ndependencies:\n- python=3.7.3\n- pip\n",
|
|
||||||
"pipDependencies": "bentoml==0.6.2\nscikit-learn",
|
|
||||||
"pythonVersion": "3.7.3"
|
|
||||||
},
|
|
||||||
"artifacts": [
|
|
||||||
{
|
|
||||||
"name": "model",
|
|
||||||
"artifactType": "SklearnModelArtifact"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"apis": [
|
|
||||||
{
|
|
||||||
"name": "predict",
|
|
||||||
"handlerType": "DataframeHandler",
|
|
||||||
"docs": "BentoService API",
|
|
||||||
"handlerConfig": {
|
|
||||||
"orient": "records",
|
|
||||||
"typ": "frame",
|
|
||||||
"input_dtypes": null,
|
|
||||||
"output_orient": "records"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Test run API server. BentoML can start an API server from the saved model. Use
|
|
||||||
BentoML CLI command to start an API server locally and test it with the `curl` command.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
bentoml serve IrisClassifier:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
In another terminal window, make `curl` request with sample data to the API server
|
|
||||||
and get prediction result:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl -v -i \
|
|
||||||
--header "Content-Type: application/json" \
|
|
||||||
--request POST \
|
|
||||||
--data '[[5.1, 3.5, 1.4, 0.2]]' \
|
|
||||||
127.0.0.1:5000/predict
|
|
||||||
```
|
|
||||||
|
|
||||||
## Building and deploying the sample
|
|
||||||
|
|
||||||
BentoML supports creating an API server docker image from its saved model directory, where
|
|
||||||
a Dockerfile is automatically generated when saving the model.
|
|
||||||
|
|
||||||
1. To build an API model server docker image, replace `{username}` with your Docker Hub
|
|
||||||
username and run the following commands.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# jq might not be installed on your local system, please follow jq install
|
|
||||||
# instruction at https://stedolan.github.io/jq/download/
|
|
||||||
saved_path=$(bentoml get IrisClassifier:latest -q | jq -r ".uri.uri")
|
|
||||||
|
|
||||||
# Build the container on your local machine
|
|
||||||
docker build - t {username}/iris-classifier $saved_path
|
|
||||||
|
|
||||||
# Push the container to docker registry
|
|
||||||
docker push {username}/iris-classifier
|
|
||||||
```
|
|
||||||
|
|
||||||
2. In `service.yaml`, replace `{username}` with your Docker hub username, and then deploy
|
|
||||||
the service to Knative Serving with `kubectl`:
|
|
||||||
|
|
||||||
{{% readfile file="service.yaml" %}}
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl apply --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
3. 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 application.
|
|
||||||
- Automatically scale your pods up and down (including to zero active
|
|
||||||
pods).
|
|
||||||
|
|
||||||
4. Run the following command to find the domain URL for your service:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl get ksvc iris-classifier --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
|
||||||
|
|
||||||
NAME URL
|
|
||||||
iris-classifier http://iris-classifer.default.example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Replace the request URL with the URL return in the previous command, and execute the
|
|
||||||
command to get prediction result from the deployed model API endpoint.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl -v -i \
|
|
||||||
--header "Content-Type: application/json" \
|
|
||||||
--request POST \
|
|
||||||
--data '[[5.1, 3.5, 1.4, 0.2]]' \
|
|
||||||
http://iris-classifier.default.example.com/predict
|
|
||||||
|
|
||||||
[0]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Removing the sample app deployment
|
|
||||||
|
|
||||||
To remove the application from your cluster, delete the service record:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl delete --filename service.yaml
|
|
||||||
```
|
|
||||||
|
|
@ -5,4 +5,189 @@ weight: 1
|
||||||
type: "docs"
|
type: "docs"
|
||||||
---
|
---
|
||||||
|
|
||||||
{{% readfile file="README.md" %}}
|
A simple machine learning model with API serving that is written in python and
|
||||||
|
using [BentoML](https://github.com/bentoml/BentoML). BentoML is an open source
|
||||||
|
framework for high performance ML model serving, which supports all major machine
|
||||||
|
learning frameworks including Keras, Tensorflow, PyTorch, Fast.ai, XGBoost and etc.
|
||||||
|
|
||||||
|
This sample will walk you through the steps of creating and deploying a machine learning
|
||||||
|
model using python. It will use BentoML to package a classifier model trained
|
||||||
|
on the Iris dataset. Afterward, it will create a container image and
|
||||||
|
deploy the image to Knative.
|
||||||
|
|
||||||
|
Knative deployment guide with BentoML is also available in the
|
||||||
|
[BentoML documentation](https://docs.bentoml.org/en/latest/deployment/knative.html)
|
||||||
|
|
||||||
|
## Before you begin
|
||||||
|
|
||||||
|
- A Kubernetes cluster with Knative installed. Follow the
|
||||||
|
[installation instructions](../../../../docs/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. Docker Hub will be used for a container registry).
|
||||||
|
- Python 3.6 or above installed and running on your local machine.
|
||||||
|
- Install `scikit-learn` and `bentoml` packages:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
pip install scikit-learn
|
||||||
|
pip install bentoml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Recreating sample code
|
||||||
|
|
||||||
|
Run the following code on your local machine, to train a machine learning model and deploy it
|
||||||
|
as API endpoint with KNative Serving.
|
||||||
|
|
||||||
|
1. BentoML creates a model API server, via prediction service abstraction. In
|
||||||
|
`iris_classifier.py`, it defines a prediction service that requires a scikit-learn
|
||||||
|
model, asks BentoML to figure out the required pip dependencies, also defines an
|
||||||
|
API, which is the entry point for accessing this machine learning service.
|
||||||
|
|
||||||
|
{{% readfile file="iris_classifier.py" %}}
|
||||||
|
|
||||||
|
2. In `main.py`, it uses the classic
|
||||||
|
[iris flower data set](https://en.wikipedia.org/wiki/Iris_flower_data_set)
|
||||||
|
to train a classification model which can predict the species of an iris flower with
|
||||||
|
given data and then save the model with BentoML to local disk.
|
||||||
|
|
||||||
|
{{% readfile file="main.py" %}}
|
||||||
|
|
||||||
|
Run the `main.py` file to train and save the model:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Use BentoML CLI to check saved model's information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
bentoml get IrisClassifier:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
> bentoml get IrisClassifier:latest
|
||||||
|
{
|
||||||
|
"name": "IrisClassifier",
|
||||||
|
"version": "20200305171229_0A1411",
|
||||||
|
"uri": {
|
||||||
|
"type": "LOCAL",
|
||||||
|
"uri": "/Users/bozhaoyu/bentoml/repository/IrisClassifier/20200305171229_0A1411"
|
||||||
|
},
|
||||||
|
"bentoServiceMetadata": {
|
||||||
|
"name": "IrisClassifier",
|
||||||
|
"version": "20200305171229_0A1411",
|
||||||
|
"createdAt": "2020-03-06T01:12:49.431011Z",
|
||||||
|
"env": {
|
||||||
|
"condaEnv": "name: bentoml-IrisClassifier\nchannels:\n- defaults\ndependencies:\n- python=3.7.3\n- pip\n",
|
||||||
|
"pipDependencies": "bentoml==0.6.2\nscikit-learn",
|
||||||
|
"pythonVersion": "3.7.3"
|
||||||
|
},
|
||||||
|
"artifacts": [
|
||||||
|
{
|
||||||
|
"name": "model",
|
||||||
|
"artifactType": "SklearnModelArtifact"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"apis": [
|
||||||
|
{
|
||||||
|
"name": "predict",
|
||||||
|
"handlerType": "DataframeHandler",
|
||||||
|
"docs": "BentoService API",
|
||||||
|
"handlerConfig": {
|
||||||
|
"orient": "records",
|
||||||
|
"typ": "frame",
|
||||||
|
"input_dtypes": null,
|
||||||
|
"output_orient": "records"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Test run API server. BentoML can start an API server from the saved model. Use
|
||||||
|
BentoML CLI command to start an API server locally and test it with the `curl` command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
bentoml serve IrisClassifier:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
In another terminal window, make `curl` request with sample data to the API server
|
||||||
|
and get prediction result:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -v -i \
|
||||||
|
--header "Content-Type: application/json" \
|
||||||
|
--request POST \
|
||||||
|
--data '[[5.1, 3.5, 1.4, 0.2]]' \
|
||||||
|
127.0.0.1:5000/predict
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building and deploying the sample
|
||||||
|
|
||||||
|
BentoML supports creating an API server docker image from its saved model directory, where
|
||||||
|
a Dockerfile is automatically generated when saving the model.
|
||||||
|
|
||||||
|
1. To build an API model server docker image, replace `{username}` with your Docker Hub
|
||||||
|
username and run the following commands.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# jq might not be installed on your local system, please follow jq install
|
||||||
|
# instruction at https://stedolan.github.io/jq/download/
|
||||||
|
saved_path=$(bentoml get IrisClassifier:latest -q | jq -r ".uri.uri")
|
||||||
|
|
||||||
|
# Build the container on your local machine
|
||||||
|
docker build - t {username}/iris-classifier $saved_path
|
||||||
|
|
||||||
|
# Push the container to docker registry
|
||||||
|
docker push {username}/iris-classifier
|
||||||
|
```
|
||||||
|
|
||||||
|
2. In `service.yaml`, replace `{username}` with your Docker hub username, and then deploy
|
||||||
|
the service to Knative Serving with `kubectl`:
|
||||||
|
|
||||||
|
{{% readfile file="service.yaml" %}}
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl apply --filename service.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 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 application.
|
||||||
|
- Automatically scale your pods up and down (including to zero active
|
||||||
|
pods).
|
||||||
|
|
||||||
|
4. Run the following command to find the domain URL for your service:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get ksvc iris-classifier --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||||
|
|
||||||
|
NAME URL
|
||||||
|
iris-classifier http://iris-classifer.default.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Replace the request URL with the URL return in the previous command, and execute the
|
||||||
|
command to get prediction result from the deployed model API endpoint.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -v -i \
|
||||||
|
--header "Content-Type: application/json" \
|
||||||
|
--request POST \
|
||||||
|
--data '[[5.1, 3.5, 1.4, 0.2]]' \
|
||||||
|
http://iris-classifier.default.example.com/predict
|
||||||
|
|
||||||
|
[0]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Removing the sample app deployment
|
||||||
|
|
||||||
|
To remove the application from your cluster, delete the service record:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete --filename service.yaml
|
||||||
|
```
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue