1
0
mirror of https://github.com/google/nomulus synced 2025-12-23 06:15:42 +00:00

Add GKE readiness probe (#2735)

This commit is contained in:
Pavlo Tkach
2025-04-04 17:33:43 -04:00
committed by GitHub
parent 9dc3215624
commit 1096f201cd
10 changed files with 153 additions and 13 deletions

View File

@@ -0,0 +1,96 @@
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.module;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
import com.google.common.flogger.FluentLogger;
import google.registry.request.Action;
import google.registry.request.Action.GaeService;
import google.registry.request.Action.GkeService;
import google.registry.request.auth.Auth;
import jakarta.inject.Inject;
import jakarta.servlet.http.HttpServletResponse;
public class ReadinessProbeAction implements Runnable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final HttpServletResponse rsp;
public ReadinessProbeAction(HttpServletResponse rsp) {
this.rsp = rsp;
}
/**
* Executes the readiness check.
*
* <p>Performs a simple database query and sets the HTTP response status to OK (200) upon
* successful completion. Throws a runtime exception if the database query fails.
*/
@Override
public final void run() {
logger.atInfo().log("Performing readiness check database query...");
try {
tm().transact(() -> tm().query("SELECT version()", Void.class));
rsp.setStatus(SC_OK);
logger.atInfo().log("Readiness check successful.");
} catch (Exception e) {
logger.atWarning().withCause(e).log("Readiness check failed:");
throw new RuntimeException("Readiness check failed during database query", e);
}
}
@Action(
service = GaeService.DEFAULT,
gkeService = GkeService.CONSOLE,
path = ReadinessProbeConsoleAction.PATH,
auth = Auth.AUTH_PUBLIC)
public static class ReadinessProbeConsoleAction extends ReadinessProbeAction {
public static final String PATH = "/ready/console";
@Inject
public ReadinessProbeConsoleAction(HttpServletResponse rsp) {
super(rsp);
}
}
@Action(
service = GaeService.PUBAPI,
gkeService = GkeService.PUBAPI,
path = ReadinessProbeActionPubApi.PATH,
auth = Auth.AUTH_PUBLIC)
public static class ReadinessProbeActionPubApi extends ReadinessProbeAction {
public static final String PATH = "/ready/pubapi";
@Inject
public ReadinessProbeActionPubApi(HttpServletResponse rsp) {
super(rsp);
}
}
@Action(
service = GaeService.DEFAULT,
gkeService = GkeService.FRONTEND,
path = ReadinessProbeActionFrontend.PATH,
auth = Auth.AUTH_PUBLIC)
public static final class ReadinessProbeActionFrontend extends ReadinessProbeAction {
public static final String PATH = "/ready/frontend";
@Inject
public ReadinessProbeActionFrontend(HttpServletResponse rsp) {
super(rsp);
}
}
}

View File

@@ -58,6 +58,9 @@ import google.registry.flows.TlsCredentials.EppTlsModule;
import google.registry.flows.custom.CustomLogicModule;
import google.registry.loadtest.LoadTestAction;
import google.registry.loadtest.LoadTestModule;
import google.registry.module.ReadinessProbeAction.ReadinessProbeActionFrontend;
import google.registry.module.ReadinessProbeAction.ReadinessProbeActionPubApi;
import google.registry.module.ReadinessProbeAction.ReadinessProbeConsoleAction;
import google.registry.monitoring.whitebox.WhiteboxModule;
import google.registry.rdap.RdapAutnumAction;
import google.registry.rdap.RdapDomainAction;
@@ -256,6 +259,12 @@ interface RequestComponent {
PublishSpec11ReportAction publishSpec11ReportAction();
ReadinessProbeConsoleAction readinessProbeConsoleAction();
ReadinessProbeActionPubApi readinessProbeActionPubApi();
ReadinessProbeActionFrontend readinessProbeActionFrontend();
RdapAutnumAction rdapAutnumAction();
RdapDomainAction rdapDomainAction();

View File

@@ -21,6 +21,8 @@ import google.registry.dns.DnsModule;
import google.registry.flows.EppTlsAction;
import google.registry.flows.FlowComponent;
import google.registry.flows.TlsCredentials.EppTlsModule;
import google.registry.module.ReadinessProbeAction.ReadinessProbeActionFrontend;
import google.registry.module.ReadinessProbeAction.ReadinessProbeConsoleAction;
import google.registry.monitoring.whitebox.WhiteboxModule;
import google.registry.request.RequestComponentBuilder;
import google.registry.request.RequestModule;
@@ -82,6 +84,10 @@ public interface FrontendRequestComponent {
FlowComponent.Builder flowComponentBuilder();
ReadinessProbeActionFrontend readinessProbeActionFrontend();
ReadinessProbeConsoleAction readinessProbeConsoleAction();
RegistrarsAction registrarsAction();
SecurityAction securityAction();

View File

@@ -20,6 +20,7 @@ import google.registry.dns.DnsModule;
import google.registry.flows.CheckApiAction;
import google.registry.flows.CheckApiAction.CheckApiModule;
import google.registry.flows.TlsCredentials.EppTlsModule;
import google.registry.module.ReadinessProbeAction.ReadinessProbeActionPubApi;
import google.registry.monitoring.whitebox.WhiteboxModule;
import google.registry.rdap.RdapAutnumAction;
import google.registry.rdap.RdapDomainAction;
@@ -56,15 +57,16 @@ public interface PubApiRequestComponent {
RdapAutnumAction rdapAutnumAction();
RdapDomainAction rdapDomainAction();
RdapDomainSearchAction rdapDomainSearchAction();
RdapEmptyAction rdapEmptyAction();
RdapEntityAction rdapEntityAction();
RdapEntitySearchAction rdapEntitySearchAction();
RdapHelpAction rdapHelpAction();
RdapIpAction rdapDefaultAction();
RdapNameserverAction rdapNameserverAction();
RdapNameserverSearchAction rdapNameserverSearchAction();
ReadinessProbeActionPubApi readinessProbeActionPubApi();
WhoisHttpAction whoisHttpAction();
WhoisAction whoisAction();

View File

@@ -143,8 +143,11 @@ public class RequestHandler<C> {
GkeService service = Action.ServiceGetter.get(route.get().action());
String expectedDomain = RegistryConfig.getServiceUrl(service).getHost();
String actualDomain = req.getServerName();
// If the hostname is "localhost", it must have come from the sidecar proxy.
if (!Objects.equals("localhost", actualDomain)
// If the request doesn't come from GKE readiness prober
String maybeUserAgent = Optional.ofNullable(req.getHeader("User-Agent")).orElse("");
if (!maybeUserAgent.startsWith("kube-probe")
// If the hostname is "localhost", it must have come from the sidecar proxy.
&& !Objects.equals("localhost", actualDomain)
&& !Objects.equals(actualDomain, expectedDomain)) {
logger.atWarning().log(
"Actual domain %s does not match expected domain %s", actualDomain, expectedDomain);

View File

@@ -1,5 +1,6 @@
SERVICE PATH CLASS METHODS OK MIN USER_POLICY
FRONTEND /_dr/epp EppTlsAction POST n APP ADMIN
FRONTEND /ready/frontend ReadinessProbeActionFrontend GET n NONE PUBLIC
CONSOLE /console-api/bulk-domain ConsoleBulkDomainAction POST n USER PUBLIC
CONSOLE /console-api/domain ConsoleDomainGetAction GET n USER PUBLIC
CONSOLE /console-api/domain-list ConsoleDomainListAction GET n USER PUBLIC
@@ -15,3 +16,4 @@ CONSOLE /console-api/settings/security SecurityAction POST
CONSOLE /console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n USER PUBLIC
CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC
CONSOLE /console-api/users ConsoleUsersAction GET,POST,DELETE,PUT n USER PUBLIC
CONSOLE /ready/console ReadinessProbeConsoleAction GET n NONE PUBLIC

View File

@@ -11,4 +11,5 @@ PUBAPI /rdap/help(*) RdapHelpAction GET,HEAD n NONE PUBLIC
PUBAPI /rdap/ip/(*) RdapIpAction GET,HEAD n NONE PUBLIC
PUBAPI /rdap/nameserver/(*) RdapNameserverAction GET,HEAD n NONE PUBLIC
PUBAPI /rdap/nameservers RdapNameserverSearchAction GET,HEAD n NONE PUBLIC
PUBAPI /ready/pubapi ReadinessProbeActionPubApi GET n NONE PUBLIC
PUBAPI /whois/(*) WhoisHttpAction GET n NONE PUBLIC

View File

@@ -1,5 +1,6 @@
SERVICE PATH CLASS METHODS OK MIN USER_POLICY
FRONTEND /_dr/epp EppTlsAction POST n APP ADMIN
FRONTEND /ready/frontend ReadinessProbeActionFrontend GET n NONE PUBLIC
BACKEND /_dr/admin/createGroups CreateGroupsAction POST n APP ADMIN
BACKEND /_dr/admin/list/domains ListDomainsAction GET,POST n APP ADMIN
BACKEND /_dr/admin/list/hosts ListHostsAction GET,POST n APP ADMIN
@@ -66,6 +67,7 @@ PUBAPI /rdap/help(*) RdapHelpAction
PUBAPI /rdap/ip/(*) RdapIpAction GET,HEAD n NONE PUBLIC
PUBAPI /rdap/nameserver/(*) RdapNameserverAction GET,HEAD n NONE PUBLIC
PUBAPI /rdap/nameservers RdapNameserverSearchAction GET,HEAD n NONE PUBLIC
PUBAPI /ready/pubapi ReadinessProbeActionPubApi GET n NONE PUBLIC
PUBAPI /whois/(*) WhoisHttpAction GET n NONE PUBLIC
CONSOLE /console-api/bulk-domain ConsoleBulkDomainAction POST n USER PUBLIC
CONSOLE /console-api/domain ConsoleDomainGetAction GET n USER PUBLIC
@@ -82,3 +84,4 @@ CONSOLE /console-api/settings/security SecurityAction
CONSOLE /console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n USER PUBLIC
CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC
CONSOLE /console-api/users ConsoleUsersAction GET,POST,DELETE,PUT n USER PUBLIC
CONSOLE /ready/console ReadinessProbeConsoleAction GET n NONE PUBLIC

View File

@@ -20,6 +20,15 @@ spec:
ports:
- containerPort: 8080
name: http
startupProbe:
httpGet:
port: 8080
path: /ready/console
initialDelaySeconds: 1
timeoutSeconds: 60
successThreshold: 1
failureThreshold: 3
periodSeconds: 30
resources:
requests:
# explicit pod-slots 0 is required in order to downgrade node

View File

@@ -20,6 +20,15 @@ spec:
ports:
- containerPort: 8080
name: http
startupProbe:
httpGet:
port: 8080
path: /ready/pubapi
initialDelaySeconds: 1
timeoutSeconds: 60
successThreshold: 1
failureThreshold: 3
periodSeconds: 30
resources:
requests:
# explicit pod-slots 0 is required in order to downgrade node
@@ -62,12 +71,12 @@ spec:
minReplicas: 5
maxReplicas: 15
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 100
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 100
---
apiVersion: v1
kind: Service
@@ -77,9 +86,9 @@ spec:
selector:
service: pubapi
ports:
- port: 80
targetPort: http
name: http
- port: 80
targetPort: http
name: http
---
apiVersion: net.gke.io/v1
kind: ServiceExport