首页 > 解决方案 > 如何在 GKE 中使用 HTTPS 部署 Echo 应用程序?

问题描述

如何在 GKE 中使用 HTTPS 部署 Echo 应用程序?

使用Echo框架开发了一个 web 应用程序。https://<DOMAIN>使用其Auto TLS设置功能。

package main

import (
    "net/http"

    "github.com/labstack/echo/v4"
    "github.com/labstack/echo/v4/middleware"
    "golang.org/x/crypto/acme/autocert"
)

func main() {
    e := echo.New()
    env := os.Getenv("ENV")
    if env == "prod" {
        e.AutoTLSManager.HostPolicy = autocert.HostWhitelist("arealdomain.com")
        e.AutoTLSManager.Cache = autocert.DirCache("/var/www/cert")
        e.Pre(middleware.HTTPSWWWRedirect())
    }

    e.GET("/healthcheck", func(c echo.Context) error {
        return c.JSON(http.StatusOK, {"ok"})
    })

    switch env {
    case "prod":
        e.Logger.Fatal(e.StartAutoTLS(":8443"))
    case "dev":
        e.Logger.Fatal(e.Start(":9000"))
    default:
        e.Logger.Fatal(e.Start(":9000"))
    }
}

将其部署在 Kubernetes 中。

开发.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: testapp
spec:
  selector:
    matchLabels:
      app: testapp
  replicas: 3
  template:
    metadata:
      labels:
        app: testapp
    spec:
      containers:
        - name: testapp
          image: gcr.io/<PROJECT_ID>/testapp
      ports:
      - containerPort: 9000
      - containerPort: 8443
      livenessProbe:
        initialDelaySeconds: 10
        periodSeconds: 10
        exec:
          command:
            - "true"
      readinessProbe:
        initialDelaySeconds: 5
        periodSeconds: 20
        httpGet:
          path: /healthcheck
          port: 9000

服务.yml

apiVersion: v1
kind: Service
metadata:
  name: testapp
spec:
  type: NodePort
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 9000
  selector:
    app: testapp

入口.yml

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: testingress
  annotations:
    kubernetes.io/ingress.global-static-ip-name: testip // a real IP
    networking.gke.io/managed-certificates: testcertificate
    kubernetes.io/ingress.class: "gce"
spec:
  backend:
    serviceName: testapp
    servicePort: 80

托管证书.yml

apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
  name: testcertificate
spec:
  domains:
    - arealdomain.com  // a real domain

部署这些资源后,访问域arealdomain.com,得到 502 错误:

Error: Server Error
The server encountered a temporary error and could not complete your request.
Please try again in 30 seconds.

从 GCP 的网络负载均衡器中,得到一项服务不健康。

在此处输入图像描述

也许是防火墙问题:https ://cloud.google.com/load-balancing/docs/https/ext-http-lb-simple#firewall

查看kubernetes的deployment pod,发现这个错误:

Readiness probe failed: HTTP probe failed with statuscode: 400

由于想部署这个 web 应用可以被 https 使用,所以只部署了 8443 端口。使用类似的站点:https ://arealdomain.com 但是如果进行健康检查,GCP 是否需要其他端口?将此部署到 GCP 的最佳做法是什么?是否有必要使用 Nginx 在应用程序内同时服务 9000 和 8443 端口?


更新

当在 Ingress 中更改为使用80端口时,也在 9000 端口上部署了应用程序,pod 可以启动但neg检查似乎无法通过。

  Events:
  Type    Reason                             Age    From                                                  Message
  ----    ------                             ----   ----                                                  -------
  Normal  LoadBalancerNegNotReady            115s   neg-readiness-reflector                               Waiting for pod to become healthy in at least one of the NEG(s): [k8s1-173zho00-default-testapp-80-l4cadn29]
  Normal  Scheduled                          115s   default-scheduler                                     Successfully assigned default/testapp-2c6f02f021-afjls to gke-<project_name>-default-pool-asfjo2c5-afjl
  Normal  Pulling                            114s   kubelet, gke-<project_name>-default-pool-asfdl0-asl3  Pulling image "gcr.io/<project_name>/testapp"
  Normal  Pulled                             109s   kubelet, gke-<project_name>-default-pool-asfdl0-asl3  Successfully pulled image "gcr.io/<project_name>/testapp"
  Normal  Created                            109s   kubelet, gke-<project_name>-default-pool-asfdl0-asl3  Created container testapp
  Normal  Started                            109s   kubelet, gke-<project_name>-default-pool-asfdl0-asl3  Started container testapp
  Normal  LoadBalancerNegWithoutHealthCheck  94s    neg-readiness-reflector                               Pod is in NEG "Key{\"k8s1-173zho00-default-testapp-80-l4cadn29\", zone: \"southamerica-east1-c\"}". NEG is not attached to any BackendService with health checking. Marking condition "cloud.google.com/load-balancer-neg-ready" to True.

我找到了这篇文章,如何cloud.google.com/load-balancer-neg-ready设置True

GCP 网络Load balancer details仍然显示不正常。

在此处输入图像描述

Health Check细节来看,路径没有设置为/healthcheckbut /。哪里错了?

在此处输入图像描述

标签: gokubernetesgoogle-cloud-platformhttpsgoogle-kubernetes-engine

解决方案


如果您刚开始使用 GKE,我建议您只创建服务和部署并使用 UI 创建入口和托管证书

我创建并部署了一个示例应用程序:

main.go 中的代码

package main

import (
    "log"
    "net/http"
)

func main() {
    // change this handlers for echo handlers
    http.HandleFunc("/", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
        rw.WriteHeader(http.StatusOK)
        rw.Write([]byte("Hello World..."))
    }))
    http.HandleFunc("/health", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
        rw.WriteHeader(http.StatusOK)
    }))
    log.Panic(http.ListenAndServe(":8080", nil))
}

Dockerfile

FROM golang:alpine AS builder
RUN apk add --no-cache git
WORKDIR /go/src/app
COPY . .
RUN go build -o bin main.go

#final stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /go/src/app/bin /app
ENTRYPOINT ./app
EXPOSE 8080

k8s-artifacts.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: testapp
spec:
  selector:
    matchLabels:
      app: testapp
  replicas: 3
  template:
    metadata:
      labels:
        app: testapp
    spec:
      containers:
        - name: testapp
          image: gcr.io/<ACCOUNT>/test  
          ports:
            - containerPort: 8080
          livenessProbe:
            initialDelaySeconds: 10
            periodSeconds: 10
            exec:
              command:
                - "true"
          readinessProbe:
            initialDelaySeconds: 5
            periodSeconds: 20
            httpGet:
              path: /health
              port: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: testapp
spec:
  type: NodePort
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 8080
  selector:
    app: testapp
---
apiVersion: "extensions/v1beta1"
kind: "Ingress"
metadata:
  name: "lb-2"
  namespace: "default"
spec:
  backend:
    serviceName: "testapp"
    servicePort: 80

有了这些,您将至少拥有一个可以通过互联网访问的 http 入口。之后,当您验证您的服务已启动并运行时,您可以编辑负载均衡器的前端以添加 https 规则和您的托管证书

更新

验证 lb 已启动并运行后 lb非常化 访问网站

要编辑负载均衡器,请转到入口详细信息Kubernetes 引擎服务和入口

在页面底部有 GCE 管理的负载均衡器的链接托管负载平衡器

选择负载均衡器并进行编辑编辑负载均衡器

转到前端配置并为 https 配置新的前端和端口 在此处输入图像描述

更新 2

您还可以使用托管证书直接创建新入口。例如:首先,创建托管证书

apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
  name: test-cert
spec:
  domains:
    - test-domain.com

之后,只需在 GKE 的服务和入口部分创建一个新入口 创建入口


推荐阅读