一个 Go 语言编写的极简 web 应用,用于测试。它读取环境变量 TARGET 并打印 Hello ${TARGET}!。如果未指定 TARGET,将 TARGET 内容替换为 World

可以按照下面的步骤创建示例代码,然后将应用程序部署到集群。也可以直接运行以下命令下载示例的代码:

1
2
git clone -b branch https://github.com/knative/docs knative-docs
cd knative-docs/docs/serving/samples/hello-world/helloworld-go

开始前

  • 一个已安装 Knetive 的 Kubernetes 集群。如果需要创建可以参考 安装说明
  • 在本地计算机上安装运行 Docker,并配置 Docker Hub 帐户(将来推送镜像)。

重新创建示例代码

  1. 创建一个名为 helloworld.go 的新文件,然后粘贴以下代码。这段代码创建了一个监听 8080 端口上的 web 服务:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
)

func handler(w http.ResponseWriter, r *http.Request) {
    log.Print("Hello world received a request.")
    target := os.Getenv("TARGET")
    if target == "" {
      target = "World"
    }
    fmt.Fprintf(w, "Hello %s!\n", target)
}

func main() {
    log.Print("Hello world sample started.")

    http.HandleFunc("/", handler)

    port := os.Getenv("PORT")
    if port == "" {
      port = "8080"
    }

    log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}
  1. 在项目的目录中,创建一个名为 Dockerfile 的文件,并将下面的代码复制到其中。有关对 Go 应用进行容器化的详细说明,请参见使用 Docker 部署 Go 服务
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 使用 Golang 官方镜像创建构建制品。
# 这是基于 Debian 的,并将GOPATH设置为 /go
# https://hub.docker.com/_/golang
FROM golang:1.13 as builder

# 创建并更改到 app 目录。
WORKDIR /app

# 检索应用依赖项。
# 这允许容器构建重用缓存的依赖项。
COPY go.* ./
RUN go mod download

# 将本地代码复制到容器镜像。
COPY . ./

# 编译二进制
RUN CGO_ENABLED=0 GOOS=linux go build -mod=readonly -v -o server

# 使用 Alpine 镜像用于生产
# 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

# 从 builder 阶段拷贝二进制到生产镜像
COPY --from=builder /app/server /server

# 启动时运行 web service
CMD ["/server"]
  1. 创建一个新文件 service.yaml,并将以下 service 定义复制到该文件中。请确保将 {username} 替换为你的 Docker Hub 用户名。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
  name: helloworld-go
  namespace: default
spec:
  template:
    spec:
      containers:
        - image: docker.io/{username}/helloworld-go
          env:
            - name: TARGET
              value: "Go Sample v1"
  1. 使用 go tool 创建 go.mod manifest。
1
go mod init github.com/knative/docs/docs/serving/samples/hello-world/helloworld-go

构建示例并部署

重新创建示例代码文件(或使用 sample 文件夹中的文件)后,就可以构建和部署示例应用了。

  1. 使用 Docker 将示例代码构建为容器镜像。运行以下命令构建并推送到 Docker Hub,用你的 Docker Hub 用户名替换 {username}
1
2
3
4
5
# 在本地计算机上构建镜像
docker build -t {username}/helloworld-go .

# 推送镜像到 docker 仓库
docker push {username}/helloworld-go
  1. 构建完成并将镜像推送到 Docker Hub 之后,可以将应用部署到集群中。确保 service.yaml 中的容器镜像与上一步中构建镜像内容一致。使用 kubectl 应用配置:
1
kubectl apply --filename service.yaml
  1. 现在你的服务已经创建,Knative 将执行以下步骤:

    • 为此版本的应用程序创建一个新的不可变版本。
    • 为应用创建路由(route)、入口(ingress)、服务(service)和负载均衡(load balance)的网络编程。
    • 自动缩放你的Pod(包括活动的 Pod 为零)。
  2. 运行以下命令来找到 service 的域名 URL: 返回集群的 ingress IP。如果只是创建集群,则可能需要等待并重新运行命令,直到为 service 分配了外部 IP 地址。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    # In Knative 0.2.x and prior versions, the `knative-ingressgateway` service was used instead of `istio-ingressgateway`.
    INGRESSGATEWAY=knative-ingressgateway
    
    # The use of `knative-ingressgateway` is deprecated in Knative v0.3.x.
    # Use `istio-ingressgateway` instead, since `knative-ingressgateway`
    # will be removed in Knative v0.4.
    if kubectl get configmap config-istio -n knative-serving &> /dev/null; then
        INGRESSGATEWAY=istio-ingressgateway
    fi
    
    kubectl get svc $INGRESSGATEWAY --namespace istio-system
    

    示例:

    1
    2
    
    NAME                     TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)                                      AGE
    xxxxxxx-ingressgateway   LoadBalancer   10.23.247.74   35.203.155.229   80:32380/TCP,443:32390/TCP,32400:32400/TCP   2d
    
  3. 运行以下命令来找到 service 的域名 URL:

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

示例:

1
2
NAME                URL
helloworld-go       http://helloworld-go.default.example.com
  1. 通过发送请求来测试应用。将以下 curl 命令与在上一个域中获取的域 URL helloworld-go.default.example.comEXTERNAL-IP 地址一起使用脚步:

    1
    
    curl -H "Host: helloworld-go.default.example.com" http://{EXTERNAL_IP_ADDRESS}
    

    示例:

    1
    2
    
    curl -H "Host: helloworld-go.default.example.com" http://35.203.155.229
    Hello Go Sample v1!
    

    注意:如果 curl 命令失败,请添加 -v 选项以获取更多详细信息。

移除示例应用的 Deployment

要从集群中删除示例应用,请删除 service 记录:

1
kubectl delete --filename service.yaml

排错

执行 curl 命令与预期不符

检查 isito ingressgateway 是否为 pending 状态,如果是有 2 种方法,给设置个外部 IP 或者 NodePort 方式访问。