go - 如何在 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
细节来看,路径没有设置为/healthcheck
but /
。哪里错了?
解决方案
如果您刚开始使用 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 规则和您的托管证书
更新
更新 2
您还可以使用托管证书直接创建新入口。例如:首先,创建托管证书
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
name: test-cert
spec:
domains:
- test-domain.com