From c80a5cc3e973227fc0ad16e9fe4ddd2162cbe2ba Mon Sep 17 00:00:00 2001 From: savitaashture Date: Tue, 13 Oct 2020 21:55:30 +0530 Subject: [PATCH] [multi-container]Add samples for multi container support (#2732) * [multi-container]Add samples for multi container support * Fix review comments * Fix CI issue * Fix review comments * Fix review comments * Removed trailing whitespaces * Addressed review comments and updated go version to use 1.15 instead of 1.13 * Addressed review comments --- docs/serving/samples/README.md | 1 + .../serving/samples/multi-container/README.md | 259 ++++++++++++++++++ .../serving/samples/multi-container/_index.md | 6 + .../samples/multi-container/service.yaml | 27 ++ .../servingcontainer/Dockerfile | 31 +++ .../multi-container/servingcontainer/go.mod | 3 + .../servingcontainer/servingcontainer.go | 43 +++ .../sidecarcontainer/Dockerfile | 31 +++ .../multi-container/sidecarcontainer/go.mod | 3 + .../sidecarcontainer/sidecarcontainer.go | 34 +++ 10 files changed, 438 insertions(+) create mode 100644 docs/serving/samples/multi-container/README.md create mode 100644 docs/serving/samples/multi-container/_index.md create mode 100644 docs/serving/samples/multi-container/service.yaml create mode 100644 docs/serving/samples/multi-container/servingcontainer/Dockerfile create mode 100644 docs/serving/samples/multi-container/servingcontainer/go.mod create mode 100644 docs/serving/samples/multi-container/servingcontainer/servingcontainer.go create mode 100644 docs/serving/samples/multi-container/sidecarcontainer/Dockerfile create mode 100644 docs/serving/samples/multi-container/sidecarcontainer/go.mod create mode 100644 docs/serving/samples/multi-container/sidecarcontainer/sidecarcontainer.go diff --git a/docs/serving/samples/README.md b/docs/serving/samples/README.md index 0f116dc35..bfcc1a256 100644 --- a/docs/serving/samples/README.md +++ b/docs/serving/samples/README.md @@ -17,3 +17,4 @@ Serving resources and how they can be applied across common use cases. | REST API | A simple Restful service that exposes an endpoint defined by an environment variable described in the Knative Configuration. | [Go](./rest-api-go/README.md) | | Telemetry | This sample runs a simple web server that makes calls to other in-cluster services and responds to requests with "Hello World!". The purpose of this sample is to show generating metrics, logs, and distributed traces. | [Go](./telemetry-go/README.md) | | Traffic Splitting | This samples builds off the [Creating a RESTful Service](./rest-api-go) sample to illustrate applying a revision, then using that revision for manual traffic splitting. | [YAML](./traffic-splitting/README.md) | +| Multi Container | A quick introduction that highlights how to build and deploy an app using Knative Serving for multiple containers. | [Go](./multi-container/README.md) | diff --git a/docs/serving/samples/multi-container/README.md b/docs/serving/samples/multi-container/README.md new file mode 100644 index 000000000..82fae8040 --- /dev/null +++ b/docs/serving/samples/multi-container/README.md @@ -0,0 +1,259 @@ +A simple web app written in Go that you can use for multi container testing. + +## Prerequisites + +- A Kubernetes cluster with Knative installed and DNS configured. Follow the + [installation instructions](../../../install/README.md) if you need to + create one. +- [Docker](https://www.docker.com) installed and running on your local machine, + and a Docker Hub account configured (we'll use it for a container registry). +- Make sure multi-container flag is enabled as part of `config-features` configmap. + +The following steps show how you can use the sample code and deploy the app to your +cluster. + +You can download a working copy of the sample, by entering the +following command: + +```shell +git clone -b "{{< branch >}}" https://github.com/knative/docs knative-docs +``` + +## Using the sample code + +To test multi container functionality, you must create two containers: a serving container, and a sidecar container. + +The `multi-container` directory is provided in the sample code, and contains predefined code and dockerfiles for creating the containers. + +You can update the default files and YAML by using the steps outlined in this section. + +### Serving Container +1. After you have cloned the sample repository, navigate to the servingcontainer directory: + + `cd knative-docs/docs/serving/samples/multi-container/servingcontainer` +1. Create a basic web server which listens on port 8881. +You can do this by copying the following code into the `servingcontainer.go` file: + + ```go + package main + import ( + "fmt" + "io/ioutil" + "log" + "net/http" + ) + func handler(w http.ResponseWriter, r *http.Request) { + log.Println("serving container received a request.") + res, err := http.Get("http://127.0.0.1:8882") + if err != nil { + log.Fatal(err) + } + resp, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Fatal(err) + } + fmt.Fprintln(w, string(resp)) + } + func main() { + log.Print("serving container started...") + http.HandleFunc("/", handler) + log.Fatal(http.ListenAndServe(":8881", nil)) + } + ``` +1. Copy the following code into the `Dockerfile` file: + + ```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.15 as builder + # Create and change to the app directory. + WORKDIR /app + # Retrieve application dependencies using go modules. + # Allows container builds to reuse downloaded dependencies. + COPY go.* ./ + RUN go mod download + # Copy local code to the container image. + COPY . ./ + # Build the binary. + # -mod=readonly ensures immutable go.mod and go.sum in container builds. + RUN CGO_ENABLED=0 GOOS=linux go build -mod=readonly -v -o servingcontainer + # Use the official Alpine image for a lean production container. + # https://hub.docker.com/_/alpine + # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds + FROM alpine:3 + RUN apk add --no-cache ca-certificates + # Copy the binary to the production image from the builder stage. + COPY --from=builder /app/servingcontainer /servingcontainer + # Run the web service on container startup. + CMD ["/servingcontainer"] + ``` + +### Sidecar Container +1. After you have cloned the sample repository, navigate to the sidecarcontainer directory: + ```text + cd - + cd knative-docs/docs/serving/samples/multi-container/sidecarcontainer + ``` + +1. Create a basic web server which listens on port 8882. +You can do this by copying the following code into the `sidecarcontainer.go` file: + + ```go + package main + import ( + "fmt" + "log" + "net/http" + ) + func handler(w http.ResponseWriter, r *http.Request) { + log.Println("sidecar container received a request.") + fmt.Fprintln(w, "Yay!! multi-container works") + } + func main() { + log.Print("sidecar container started...") + http.HandleFunc("/", handler) + log.Fatal(http.ListenAndServe(":8882", nil)) + } + ``` + +1. Copy the following code into the `Dockerfile` file: + + ```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.15 as builder + # Create and change to the app directory. + WORKDIR /app + # Retrieve application dependencies using go modules. + # Allows container builds to reuse downloaded dependencies. + COPY go.* ./ + RUN go mod download + # Copy local code to the container image. + COPY . ./ + # Build the binary. + # -mod=readonly ensures immutable go.mod and go.sum in container builds. + RUN CGO_ENABLED=0 GOOS=linux go build -mod=readonly -v -o sidecarcontainer + # Use the official Alpine image for a lean production container. + # https://hub.docker.com/_/alpine + # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds + FROM alpine:3 + RUN apk add --no-cache ca-certificates + # Copy the binary to the production image from the builder stage. + COPY --from=builder /app/sidecarcontainer /sidecarcontainer + # Run the web service on container startup. + CMD ["/sidecarcontainer"] + ``` + +### Writing Knative Service YAML + +1. After you have cloned the sample repository, navigate to the `multi-container` directory: + 1. `cd -` + 2. `cd knative-docs/docs/serving/samples/multi-container/` + +1. Copy the following YAML service definition into the `service.yaml` file: + + ```yaml + apiVersion: serving.knative.dev/v1 + kind: Service + metadata: + name: multi-container + namespace: default + spec: + template: + spec: + containers: + - image: docker.io/{username}/servingcontainer + ports: + - containerPort: 8881 + - image: docker.io/{username}/sidecarcontainer + ``` + +**NOTE:** Replace `{username}` with your Docker Hub username. + +1. Use Go tool to create a + [`go.mod`](https://github.com/golang/go/wiki/Modules#gomod) manifest: + + servingcontainer + ```shell + cd - + cd knative-docs/docs/serving/samples/multi-container/servingcontainer + go mod init github.com/knative/docs/docs/serving/samples/multi-container/servingcontainer + ``` + sidecarcontainer + ```shell + cd - + cd knative-docs/docs/serving/samples/multi-container/sidecarcontainer + go mod init github.com/knative/docs/docs/serving/samples/multi-container/sidecarcontainer + ``` + +## Building and deploying the sample + +After you have modified the sample code files you can 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 + cd - + cd knative-docs/docs/serving/samples/multi-container/servingcontainer + docker build -t {username}/servingcontainer . + cd - + cd knative-docs/docs/serving/samples/multi-container/sidecarcontainer + docker build -t {username}/sidecarcontainer . + # Push the container to docker registry + docker push {username}/servingcontainer + docker push {username}/sidecarcontainer + ``` + +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 + cd - + cd knative-docs/docs/serving/samples/multi-container + 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. Run the following command to find the domain URL for your service: + + ```shell + kubectl get ksvc multi-container --output=custom-columns=NAME:.metadata.name,URL:.status.url + ``` + + Example: + + ```shell + NAME URL + multi-container http://multi-container.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://multi-container.default.1.2.3.4.xip.io + Yay!! multi-container works + ``` + + > Note: Add `-v` option to get more detail if the `curl` command failed. + +## Removing the sample app deployment + +To remove the sample app from your cluster, delete the service record: + +```shell +kubectl delete --filename service.yaml +``` diff --git a/docs/serving/samples/multi-container/_index.md b/docs/serving/samples/multi-container/_index.md new file mode 100644 index 000000000..97a3cffa6 --- /dev/null +++ b/docs/serving/samples/multi-container/_index.md @@ -0,0 +1,6 @@ +--- +title: "Knative multi-container samples" +linkTitle: "A simple golang web app" +weight: 1 +type: "docs" +--- diff --git a/docs/serving/samples/multi-container/service.yaml b/docs/serving/samples/multi-container/service.yaml new file mode 100644 index 000000000..49f83cb8f --- /dev/null +++ b/docs/serving/samples/multi-container/service.yaml @@ -0,0 +1,27 @@ +# Copyright 2020 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: serving.knative.dev/v1 +kind: Service +metadata: + name: multi-container + namespace: default +spec: + template: + spec: + containers: + - image: docker.io/savita3020/servingcontainer + ports: + - containerPort: 8881 + - image: docker.io/savita3020/sidecarcontainer diff --git a/docs/serving/samples/multi-container/servingcontainer/Dockerfile b/docs/serving/samples/multi-container/servingcontainer/Dockerfile new file mode 100644 index 000000000..4f8bce92e --- /dev/null +++ b/docs/serving/samples/multi-container/servingcontainer/Dockerfile @@ -0,0 +1,31 @@ +# 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.15 as builder + +# Create and change to the app directory. +WORKDIR /app + +# Retrieve application dependencies using go modules. +# Allows container builds to reuse downloaded dependencies. +COPY go.* ./ +RUN go mod download + +# Copy local code to the container image. +COPY . ./ + +# Build the binary. +# -mod=readonly ensures immutable go.mod and go.sum in container builds. +RUN CGO_ENABLED=0 GOOS=linux go build -mod=readonly -v -o servingcontainer + +# Use the official Alpine image for a lean production container. +# https://hub.docker.com/_/alpine +# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds +FROM alpine:3 +RUN apk add --no-cache ca-certificates + +# Copy the binary to the production image from the builder stage. +COPY --from=builder /app/servingcontainer /servingcontainer + +# Run the web service on container startup. +CMD ["/servingcontainer"] diff --git a/docs/serving/samples/multi-container/servingcontainer/go.mod b/docs/serving/samples/multi-container/servingcontainer/go.mod new file mode 100644 index 000000000..db0c28599 --- /dev/null +++ b/docs/serving/samples/multi-container/servingcontainer/go.mod @@ -0,0 +1,3 @@ +module github.com/knative/docs/docs/serving/samples/multi-container/servingcontainer + +go 1.15 diff --git a/docs/serving/samples/multi-container/servingcontainer/servingcontainer.go b/docs/serving/samples/multi-container/servingcontainer/servingcontainer.go new file mode 100644 index 000000000..f469e4bf4 --- /dev/null +++ b/docs/serving/samples/multi-container/servingcontainer/servingcontainer.go @@ -0,0 +1,43 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "io/ioutil" + "log" + "net/http" +) + +func handler(w http.ResponseWriter, r *http.Request) { + log.Println("serving container received a request.") + res, err := http.Get("http://127.0.0.1:8882") + if err != nil { + log.Fatal(err) + } + resp, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Fatal(err) + } + fmt.Fprintln(w, string(resp)) +} + +func main() { + log.Print("serving container started...") + http.HandleFunc("/", handler) + log.Fatal(http.ListenAndServe(":8881", nil)) +} diff --git a/docs/serving/samples/multi-container/sidecarcontainer/Dockerfile b/docs/serving/samples/multi-container/sidecarcontainer/Dockerfile new file mode 100644 index 000000000..1c60e74ae --- /dev/null +++ b/docs/serving/samples/multi-container/sidecarcontainer/Dockerfile @@ -0,0 +1,31 @@ +# 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.15 as builder + +# Create and change to the app directory. +WORKDIR /app + +# Retrieve application dependencies using go modules. +# Allows container builds to reuse downloaded dependencies. +COPY go.* ./ +RUN go mod download + +# Copy local code to the container image. +COPY . ./ + +# Build the binary. +# -mod=readonly ensures immutable go.mod and go.sum in container builds. +RUN CGO_ENABLED=0 GOOS=linux go build -mod=readonly -v -o sidecarcontainer + +# Use the official Alpine image for a lean production container. +# https://hub.docker.com/_/alpine +# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds +FROM alpine:3 +RUN apk add --no-cache ca-certificates + +# Copy the binary to the production image from the builder stage. +COPY --from=builder /app/sidecarcontainer /sidecarcontainer + +# Run the web service on container startup. +CMD ["/sidecarcontainer"] diff --git a/docs/serving/samples/multi-container/sidecarcontainer/go.mod b/docs/serving/samples/multi-container/sidecarcontainer/go.mod new file mode 100644 index 000000000..8a4c490f5 --- /dev/null +++ b/docs/serving/samples/multi-container/sidecarcontainer/go.mod @@ -0,0 +1,3 @@ +module github.com/knative/docs/docs/serving/samples/multi-container/sidecarcontainer + +go 1.15 diff --git a/docs/serving/samples/multi-container/sidecarcontainer/sidecarcontainer.go b/docs/serving/samples/multi-container/sidecarcontainer/sidecarcontainer.go new file mode 100644 index 000000000..0e05839d1 --- /dev/null +++ b/docs/serving/samples/multi-container/sidecarcontainer/sidecarcontainer.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "log" + "net/http" +) + +func handler(w http.ResponseWriter, r *http.Request) { + log.Println("sidecar container received a request.") + fmt.Fprintln(w, "Yay!! multi-container works") +} + +func main() { + log.Print("sidecar container started...") + http.HandleFunc("/", handler) + log.Fatal(http.ListenAndServe(":8882", nil)) +}