internal/https: add health checking support and use it
CL 454935 broke the Kubernetes ingress by requiring IAP on health
checks. Move /healthz handling into internal/https, where it
automatically bypasses authentication and removes some duplicate trivial
implementations.
Unfortunately, GKE is not capable of inferring health check parameters
from a multi-container pod like relui, so we have to change our
BackendConfig. That sets off a yak shave -- I made the questionable
decision to use the same backend for all our IAP services, and the
coordinator doesn't currently support /healthz. Split all them up and
delete the devapp configuration I was using for testing way back in the
day.
Change-Id: I45e866d30508a07e9a805de70af731dd64c22d7f
Reviewed-on: https://go-review.googlesource.com/c/build/+/455215
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Heschi Kreinick <heschi@google.com>
Run-TryBot: Heschi Kreinick <heschi@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/cmd/coordinator/deployment-prod.yaml b/cmd/coordinator/deployment-prod.yaml
index 15e6246..ddfaebe 100644
--- a/cmd/coordinator/deployment-prod.yaml
+++ b/cmd/coordinator/deployment-prod.yaml
@@ -67,7 +67,7 @@
namespace: prod
name: coordinator-internal-iap
annotations:
- cloud.google.com/backend-config: '{"default": "build-ingress-iap-backend"}'
+ cloud.google.com/backend-config: '{"default": "coordinator-iap-backend"}'
cloud.google.com/neg: '{"ingress": false}'
cloud.google.com/app-protocols: '{"https":"HTTP2"}'
spec:
@@ -95,3 +95,15 @@
selector:
app: coordinator
type: NodePort
+---
+apiVersion: cloud.google.com/v1
+kind: BackendConfig
+metadata:
+ namespace: prod
+ name: coordinator-iap-backend
+spec:
+ iap:
+ enabled: true
+ oauthclientCredentials:
+ secretName: iap-oauth
+ timeoutSec: 86400 # For long-running gomote RPCs. See https://go.dev/issue/56423.
diff --git a/cmd/relui/deployment-prod.yaml b/cmd/relui/deployment-prod.yaml
index e49eb8e..0f87e19 100644
--- a/cmd/relui/deployment-prod.yaml
+++ b/cmd/relui/deployment-prod.yaml
@@ -43,6 +43,11 @@
- "--serving-files-base=gs://golang"
- "--edge-cache-url=https://dl.google.com/go"
- "--website-upload-url=https://go.dev/dl/upload"
+ readinessProbe:
+ httpGet:
+ path: /healthz
+ port: 444
+ scheme: HTTPS
ports:
- containerPort: 444
env:
@@ -100,7 +105,7 @@
namespace: prod
name: relui-internal
annotations:
- cloud.google.com/backend-config: '{"default": "build-ingress-iap-backend"}'
+ cloud.google.com/backend-config: '{"default": "relui-iap-backend"}'
cloud.google.com/neg: '{"ingress": false}'
cloud.google.com/app-protocols: '{"https":"HTTP2"}'
spec:
@@ -111,3 +116,19 @@
selector:
app: relui
type: NodePort
+---
+apiVersion: cloud.google.com/v1
+kind: BackendConfig
+metadata:
+ namespace: prod
+ name: relui-iap-backend
+spec:
+ iap:
+ enabled: true
+ oauthclientCredentials:
+ secretName: iap-oauth
+ healthCheck:
+ timeoutSec: 10
+ checkIntervalSec: 15
+ type: HTTPS
+ requestPath: /healthz
diff --git a/deploy/build-ingress.yaml b/deploy/build-ingress.yaml
index bb22ac3..4df8635 100644
--- a/deploy/build-ingress.yaml
+++ b/deploy/build-ingress.yaml
@@ -18,13 +18,6 @@
http:
paths:
- pathType: ImplementationSpecific
- path: /owners
- backend:
- service:
- name: devapp-internal-iap
- port:
- number: 444
- - pathType: ImplementationSpecific
path: /*
backend:
service:
@@ -137,26 +130,6 @@
enabled: true
responseCodeName: FOUND
---
-apiVersion: cloud.google.com/v1
-kind: BackendConfig
-metadata:
- namespace: prod
- name: build-ingress-iap-backend
-spec:
- iap:
- enabled: true
- oauthclientCredentials:
- secretName: iap-oauth
- timeoutSec: 86400 # For long-running gomote RPCs. See https://go.dev/issue/56423.
----
-apiVersion: cloud.google.com/v1
-kind: BackendConfig
-metadata:
- namespace: prod
- name: build-ingress-maintnerd-backend
-spec:
- timeoutSec: 60 # For long-poll support on the /logs endpoint. See go.dev/issue/53569.
----
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
diff --git a/devapp/deployment-prod.yaml b/devapp/deployment-prod.yaml
index a7f61c4..4dc5c88 100644
--- a/devapp/deployment-prod.yaml
+++ b/devapp/deployment-prod.yaml
@@ -46,24 +46,6 @@
kind: Service
metadata:
namespace: prod
- name: devapp-internal-iap
- annotations:
- cloud.google.com/backend-config: '{"default": "build-ingress-iap-backend"}'
- cloud.google.com/neg: '{"ingress": false}'
- cloud.google.com/app-protocols: '{"https":"HTTP2"}'
-spec:
- ports:
- - port: 444
- targetPort: 444
- name: https
- selector:
- app: devapp
- type: NodePort
----
-apiVersion: v1
-kind: Service
-metadata:
- namespace: prod
name: devapp-internal
annotations:
cloud.google.com/neg: '{"ingress": false}'
diff --git a/devapp/server.go b/devapp/server.go
index dcfd5b6..ec92619 100644
--- a/devapp/server.go
+++ b/devapp/server.go
@@ -64,7 +64,6 @@
userMapping: map[int]*maintner.GitHubUser{},
}
s.mux.Handle("/", http.FileServer(http.Dir(s.staticDir)))
- s.mux.HandleFunc("/healthz", handleHealthz)
s.mux.HandleFunc("/favicon.ico", s.handleFavicon)
s.mux.HandleFunc("/release", s.withTemplate("/release.tmpl", s.handleRelease))
s.mux.HandleFunc("/reviews", s.withTemplate("/reviews.tmpl", s.handleReviews))
@@ -203,11 +202,6 @@
return issues
}
-func handleHealthz(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(http.StatusOK)
- w.Write([]byte("ok"))
-}
-
func (s *server) handleFavicon(w http.ResponseWriter, r *http.Request) {
// Need to specify content type for consistent tests, without this it's
// determined from mime.types on the box the test is running on
diff --git a/internal/https/https.go b/internal/https/https.go
index 767269e..81f2512 100644
--- a/internal/https/https.go
+++ b/internal/https/https.go
@@ -34,6 +34,8 @@
SelfSignedAddr string
// If non-empty, listen on this address and serve HTTP.
HTTPAddr string
+ // If non-empty, respond unconditionally with 200 OK to requests on this path.
+ HealthPath string
}
var DefaultOptions = &Options{}
@@ -47,6 +49,7 @@
set.StringVar(&DefaultOptions.AutocertAddr, "listen-https-autocert", "", "if non-empty, listen on this address and serve HTTPS using a Let's Encrypt cert stored in autocert-bucket")
set.StringVar(&DefaultOptions.SelfSignedAddr, "listen-https-selfsigned", "", "if non-empty, listen on this address and serve HTTPS using a self-signed cert")
set.StringVar(&DefaultOptions.HTTPAddr, "listen-http", "", "if non-empty, listen on this address and serve HTTP")
+ set.StringVar(&DefaultOptions.HealthPath, "health-path", "/healthz", "if non-empty, respond unconditionally with 200 OK to requests on this path")
}
// ListenAndServe runs the servers configured by DefaultOptions. It always
@@ -60,6 +63,18 @@
func ListenAndServeOpts(ctx context.Context, handler http.Handler, opts *Options) error {
errc := make(chan error, 3)
+ if opts.HealthPath != "" {
+ wrapped := handler
+ handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path == opts.HealthPath {
+ w.WriteHeader(http.StatusOK)
+ w.Write([]byte("ok"))
+ } else {
+ wrapped.ServeHTTP(w, r)
+ }
+ })
+ }
+
if opts.HTTPAddr != "" {
server := &http.Server{Addr: opts.HTTPAddr, Handler: handler}
defer server.Close()
diff --git a/maintner/maintnerd/deployment-prod.yaml b/maintner/maintnerd/deployment-prod.yaml
index f2d3ec9..2b3266e 100644
--- a/maintner/maintnerd/deployment-prod.yaml
+++ b/maintner/maintnerd/deployment-prod.yaml
@@ -74,3 +74,11 @@
selector:
app: maintnerd
type: NodePort
+---
+apiVersion: cloud.google.com/v1
+kind: BackendConfig
+metadata:
+ namespace: prod
+ name: build-ingress-maintnerd-backend
+spec:
+ timeoutSec: 60 # For long-poll support on the /logs endpoint. See go.dev/issue/53569.
diff --git a/perf/app/app.go b/perf/app/app.go
index be4b0f8..4dcb32e 100644
--- a/perf/app/app.go
+++ b/perf/app/app.go
@@ -59,7 +59,6 @@
mux.HandleFunc("/search", a.search)
mux.HandleFunc("/compare", a.compare)
mux.HandleFunc("/cron/syncinflux", a.syncInflux)
- mux.HandleFunc("/healthz", a.healthz)
a.dashboardRegisterOnMux(mux)
}
@@ -82,9 +81,3 @@
//q := r.Form.Get("q")
a.compare(w, r)
}
-
-// healthz handles /healthz.
-func (a *App) healthz(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(http.StatusOK)
- w.Write([]byte("ok"))
-}