Knative multi-container samples

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 if you need to create one.
  • Docker 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:

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

  2. Create a basic web server which listens on port 8881. You can do this by copying the following code into the servingcontainer.go file:

    1. package main
    2. import (
    3. "fmt"
    4. "io/ioutil"
    5. "log"
    6. "net/http"
    7. )
    8. func handler(w http.ResponseWriter, r *http.Request) {
    9. log.Println("serving container received a request.")
    10. res, err := http.Get("http://127.0.0.1:8882")
    11. if err != nil {
    12. log.Fatal(err)
    13. }
    14. resp, err := ioutil.ReadAll(res.Body)
    15. if err != nil {
    16. log.Fatal(err)
    17. }
    18. fmt.Fprintln(w, string(resp))
    19. }
    20. func main() {
    21. log.Print("serving container started...")
    22. http.HandleFunc("/", handler)
    23. log.Fatal(http.ListenAndServe(":8881", nil))
    24. }
  3. Copy the following code into the Dockerfile file:

    1. # Use the official Golang image to create a build artifact.
    2. # This is based on Debian and sets the GOPATH to /go.
    3. # https://hub.docker.com/_/golang
    4. FROM golang:1.15 as builder
    5. # Create and change to the app directory.
    6. WORKDIR /app
    7. # Retrieve application dependencies using go modules.
    8. # Allows container builds to reuse downloaded dependencies.
    9. COPY go.* ./
    10. RUN go mod download
    11. # Copy local code to the container image.
    12. COPY . ./
    13. # Build the binary.
    14. # -mod=readonly ensures immutable go.mod and go.sum in container builds.
    15. RUN CGO_ENABLED=0 GOOS=linux go build -mod=readonly -v -o servingcontainer
    16. # Use the official Alpine image for a lean production container.
    17. # https://hub.docker.com/_/alpine
    18. # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    19. FROM alpine:3
    20. RUN apk add --no-cache ca-certificates
    21. # Copy the binary to the production image from the builder stage.
    22. COPY --from=builder /app/servingcontainer /servingcontainer
    23. # Run the web service on container startup.
    24. CMD ["/servingcontainer"]

Sidecar Container

  1. After you have cloned the sample repository, navigate to the sidecarcontainer directory:

    1. cd -
    2. cd knative-docs/docs/serving/samples/multi-container/sidecarcontainer
  2. Create a basic web server which listens on port 8882. You can do this by copying the following code into the sidecarcontainer.go file:

    1. package main
    2. import (
    3. "fmt"
    4. "log"
    5. "net/http"
    6. )
    7. func handler(w http.ResponseWriter, r *http.Request) {
    8. log.Println("sidecar container received a request.")
    9. fmt.Fprintln(w, "Yay!! multi-container works")
    10. }
    11. func main() {
    12. log.Print("sidecar container started...")
    13. http.HandleFunc("/", handler)
    14. log.Fatal(http.ListenAndServe(":8882", nil))
    15. }
  3. Copy the following code into the Dockerfile file:

    1. # Use the official Golang image to create a build artifact.
    2. # This is based on Debian and sets the GOPATH to /go.
    3. # https://hub.docker.com/_/golang
    4. FROM golang:1.15 as builder
    5. # Create and change to the app directory.
    6. WORKDIR /app
    7. # Retrieve application dependencies using go modules.
    8. # Allows container builds to reuse downloaded dependencies.
    9. COPY go.* ./
    10. RUN go mod download
    11. # Copy local code to the container image.
    12. COPY . ./
    13. # Build the binary.
    14. # -mod=readonly ensures immutable go.mod and go.sum in container builds.
    15. RUN CGO_ENABLED=0 GOOS=linux go build -mod=readonly -v -o sidecarcontainer
    16. # Use the official Alpine image for a lean production container.
    17. # https://hub.docker.com/_/alpine
    18. # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    19. FROM alpine:3
    20. RUN apk add --no-cache ca-certificates
    21. # Copy the binary to the production image from the builder stage.
    22. COPY --from=builder /app/sidecarcontainer /sidecarcontainer
    23. # Run the web service on container startup.
    24. 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/
  2. Copy the following YAML service definition into the service.yaml file:

    1. apiVersion: serving.knative.dev/v1
    2. kind: Service
    3. metadata:
    4. name: multi-container
    5. namespace: default
    6. spec:
    7. template:
    8. spec:
    9. containers:
    10. - image: docker.io/{username}/servingcontainer
    11. ports:
    12. - containerPort: 8881
    13. - image: docker.io/{username}/sidecarcontainer

NOTE: Replace {username} with your Docker Hub username.

  1. Use Go tool to create a go.mod manifest:

    servingcontainer

    1. cd -
    2. cd knative-docs/docs/serving/samples/multi-container/servingcontainer
    3. go mod init github.com/knative/docs/docs/serving/samples/multi-container/servingcontainer

    sidecarcontainer

    1. cd -
    2. cd knative-docs/docs/serving/samples/multi-container/sidecarcontainer
    3. 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:

    1. # Build the container on your local machine
    2. cd -
    3. cd knative-docs/docs/serving/samples/multi-container/servingcontainer
    4. docker build -t {username}/servingcontainer .
    5. cd -
    6. cd knative-docs/docs/serving/samples/multi-container/sidecarcontainer
    7. docker build -t {username}/sidecarcontainer .
    8. # Push the container to docker registry
    9. docker push {username}/servingcontainer
    10. docker push {username}/sidecarcontainer
  2. 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:

    1. cd -
    2. cd knative-docs/docs/serving/samples/multi-container
    3. kubectl apply --filename service.yaml
  3. 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).
  4. Run the following command to find the domain URL for your service:

    1. kubectl get ksvc multi-container --output=custom-columns=NAME:.metadata.name,URL:.status.url

    Example:

    1. NAME URL
    2. multi-container http://multi-container.default.1.2.3.4.xip.io
  5. 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.

    1. curl http://multi-container.default.1.2.3.4.xip.io
    2. 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:

  1. kubectl delete --filename service.yaml