Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deploy an Echo app with HTTPS in GKE?

How to deploy an Echo app with HTTPS in GKE?

Using Echo framework developed a web app. Set https://<DOMAIN> feature with its 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"))
    }
}

Deployed it in Kubernetes.

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

service.yml

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

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

managedcertificate.yml

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

After deployed these resources, access domain arealdomain.com, got 502 error:

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

From GCP's network loadbalancer, got one service is unhealthy.

enter image description here

Maybe firewall issue: https://cloud.google.com/load-balancing/docs/https/ext-http-lb-simple#firewall

Check kubernetes's deployment pod, found this error:

Readiness probe failed: HTTP probe failed with statuscode: 400

Since want to deploy this web app can be used by https, so deployed it with 8443 port only. Use site like: https://arealdomain.com But if do healthcheck, does GCP need other port? What's the best practice to do this deployment to GCP? Is it necessary to use Nginx to serve both 9000 and 8443 port inside app?


Update

When change to use 80 port in Ingress, also deployed application on 9000 port, the pod can start but neg check seems can't pass.

  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.

I found this article, how to set cloud.google.com/load-balancer-neg-ready to True?

The GCP network's Load balancer details still showing unhealthy.

enter image description here

From Health Check details, the path didn't been set to /healthcheck but /. Where is wrong?

enter image description here

like image 524
warmwinter Avatar asked Mar 14 '26 22:03

warmwinter


1 Answers

If you are just starting with GKE I recommend you to just create the service and deployment and use the UI to create the ingress and the managed certs

I created and deploy a sample application:

Code in 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

With that in place, you will have at least an http ingress which you can access through the internet. After that, and when you have validated that your service is up and running, you can edit the front-end of the load balancer to add the https rules and your managed cert

Update

After verifying that the lb is up and running lb veryfication access web site

To edit the load balancer go to the ingress detailskubernetes engine services and ingress

At the bottom of the page there are links to the load balancers managed by GCE managed load balancers

Select the load balancer and edit it edit load balancer

Go to front end configuration and configure a new front end and port for https enter image description here

Update 2

You can also create directly the new ingress with the managed cert. For example: First, create the managed cert

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

After that, just create a new ingress in the services and ingresses section of GKE create ingress

like image 190
Pablo Flores Avatar answered Mar 16 '26 11:03

Pablo Flores