Add gateway api to docs. And ESLint rules.

This commit is contained in:
djeinstine 2024-11-10 20:21:00 +00:00
parent c584d5d020
commit 60eee26ac4
5 changed files with 58 additions and 37 deletions

View File

@ -8,6 +8,7 @@ The Kubernetes connectivity has the following requirements:
- Kubernetes 1.19+ - Kubernetes 1.19+
- Metrics Service - Metrics Service
- An Ingress controller - An Ingress controller
- Optionally: Gateway-API
The Kubernetes connection is configured in the `kubernetes.yaml` file. There are 3 modes to choose from: The Kubernetes connection is configured in the `kubernetes.yaml` file. There are 3 modes to choose from:
@ -19,6 +20,12 @@ The Kubernetes connection is configured in the `kubernetes.yaml` file. There are
mode: default mode: default
``` ```
To enable Kubernetes gateway-api compatibility, add the following setting:
```yaml
route: gateway
```
## Services ## Services
Once the Kubernetes connection is configured, individual services can be configured to pull statistics. Only CPU and Memory are currently supported. Once the Kubernetes connection is configured, individual services can be configured to pull statistics. Only CPU and Memory are currently supported.
@ -140,6 +147,9 @@ spec:
If the `href` attribute is not present, Homepage will ignore the specific IngressRoute. If the `href` attribute is not present, Homepage will ignore the specific IngressRoute.
### Gateway API HttpRoute support
Homepage also features automatic service discovery for gateway-api. Service definitions are read by annotating the HttpRoute custom resource definition and are indentical to the Ingress example as defined in [Automatic Service Discovery](#automatic-service-discovery).
## Caveats ## Caveats
Similarly to Docker service discovery, there currently is no rigid ordering to discovered services and discovered services will be displayed above those specified in the `services.yaml`. Similarly to Docker service discovery, there currently is no rigid ordering to discovered services and discovered services will be displayed above those specified in the `services.yaml`.

View File

@ -215,6 +215,15 @@ rules:
verbs: verbs:
- get - get
- list - list
# if using gateway api add the following:
# - apiGroups:
# - gateway.networking.k8s.io
# resources:
# - httproutes
# - gateways
# verbs:
# - get
# - list
- apiGroups: - apiGroups:
- metrics.k8s.io - metrics.k8s.io
resources: resources:

View File

@ -7,30 +7,27 @@ import { KubeConfig } from "@kubernetes/client-node";
import checkAndCopyConfig, { CONF_DIR, substituteEnvironmentVars } from "utils/config/config"; import checkAndCopyConfig, { CONF_DIR, substituteEnvironmentVars } from "utils/config/config";
const extractKubeData = (config) => { const extractKubeData = (config) => {
//kubeconfig // kubeconfig
const kc = new KubeConfig(); const kc = new KubeConfig();
kc.loadFromCluster(); kc.loadFromCluster();
//route // route
let route = "ingress"; let route = "ingress";
if (config?.route == "gateway") { if (config?.route === "gateway") {
route = "gateway"; route = "gateway";
} }
//traefik // traefik
let traefik = true; let traefik = true;
if (config?.traefik == "disable") { if (config?.traefik === "disable") {
traefik = false; traefik = false;
} }
//traefik return {
let metrics = true; "config": kc,
if (config?.metrics == "disable") { "route": route,
metrics = false; "traefik": traefik
} };
//return
return { config: kc, route: route, traefik: traefik, metrics: metrics };
}; };
export default function getKubeArguments() { export default function getKubeArguments() {

View File

@ -3,7 +3,6 @@ import path from "path";
import yaml from "js-yaml"; import yaml from "js-yaml";
import Docker from "dockerode"; import Docker from "dockerode";
import { ApiextensionsV1Api } from "@kubernetes/client-node";
import createLogger from "utils/logger"; import createLogger from "utils/logger";
import checkAndCopyConfig, { CONF_DIR, getSettings, substituteEnvironmentVars } from "utils/config/config"; import checkAndCopyConfig, { CONF_DIR, getSettings, substituteEnvironmentVars } from "utils/config/config";
@ -159,7 +158,7 @@ export async function servicesFromKubernetes() {
checkAndCopyConfig("kubernetes.yaml"); checkAndCopyConfig("kubernetes.yaml");
try { try {
const routeList = await getRouteList(); const routeList = await getRouteList(ANNOTATION_BASE);
if (!routeList) { if (!routeList) {
return []; return [];

View File

@ -1,4 +1,5 @@
import { CustomObjectsApi, NetworkingV1Api, CoreV1Api, ApiextensionsV1Api } from "@kubernetes/client-node"; import { CustomObjectsApi, NetworkingV1Api, CoreV1Api, ApiextensionsV1Api } from "@kubernetes/client-node";
import getKubeArguments from "utils/config/kubernetes"; import getKubeArguments from "utils/config/kubernetes";
import createLogger from "utils/logger"; import createLogger from "utils/logger";
@ -16,7 +17,7 @@ let networking;
let routingType; let routingType;
let traefik; let traefik;
export async function checkCRD(kc, name) { export async function checkCRD(name) {
const apiExtensions = kc.makeApiClient(ApiextensionsV1Api); const apiExtensions = kc.makeApiClient(ApiextensionsV1Api);
const exist = await apiExtensions const exist = await apiExtensions
.readCustomResourceDefinitionStatus(name) .readCustomResourceDefinitionStatus(name)
@ -37,19 +38,24 @@ export async function checkCRD(kc, name) {
} }
const getSchemaFromGateway = async (gatewayRef) => { const getSchemaFromGateway = async (gatewayRef) => {
try {
const gateway = await crd.getNamespacedCustomObject( const schema = await crd.getNamespacedCustomObject(
apiGroup, apiGroup,
version, version,
gatewayRef.namespace, gatewayRef.namespace,
"gateways", "gateways",
gatewayRef.name, gatewayRef.name,
); )
const listener = gateway.body.spec.listeners.filter((listener) => listener.name == gatewayRef.sectionName)[0]; .then((response) => {
return listener.protocol.toLowerCase(); const listner = response.body.spec.listeners.filter((listener) => listener.name === gatewayRef.sectionName)[0]
} catch (err) { return listner.protocol.toLowerCase();
console.error(err); })
} .catch((error) => {
logger.error("Error getting gateways: %d %s %s", error.statusCode, error.body, error.response);
logger.debug(error);
return "";
});
return schema;
}; };
async function getUrlFromHttpRoute(ingress) { async function getUrlFromHttpRoute(ingress) {
@ -67,7 +73,7 @@ function getUrlFromIngress(ingress) {
} }
async function getHttpRouteList() { async function getHttpRouteList() {
const httpRouteList = new Array(); const httpRouteList = [];
const namespaces = await core const namespaces = await core
.listNamespace() .listNamespace()
@ -95,7 +101,7 @@ async function getHttpRouteList() {
return httpRouteList; return httpRouteList;
} }
async function getIngressList() { async function getIngressList(ANNOTATION_BASE) {
const ingressList = await networking const ingressList = await networking
.listIngressForAllNamespaces(null, null, null, null) .listIngressForAllNamespaces(null, null, null, null)
.then((response) => response.body) .then((response) => response.body)
@ -106,8 +112,8 @@ async function getIngressList() {
}); });
if (traefik) { if (traefik) {
const traefikContainoExists = await checkCRD(kc, "ingressroutes.traefik.containo.us"); const traefikContainoExists = await checkCRD("ingressroutes.traefik.containo.us");
const traefikExists = await checkCRD(kc, "ingressroutes.traefik.io"); const traefikExists = await checkCRD("ingressroutes.traefik.io");
const traefikIngressListContaino = await crd const traefikIngressListContaino = await crd
.listClusterCustomObject("traefik.containo.us", "v1alpha1", "ingressroutes") .listClusterCustomObject("traefik.containo.us", "v1alpha1", "ingressroutes")
@ -156,8 +162,8 @@ async function getIngressList() {
return ingressList.items; return ingressList.items;
} }
export async function getRouteList() { export async function getRouteList(ANNOTATION_BASE) {
let routeList = new Array(); let routeList = [];
if (!kc) { if (!kc) {
return []; return [];
@ -172,13 +178,13 @@ export async function getRouteList() {
switch (routingType) { switch (routingType) {
case "ingress": case "ingress":
routeList = await getIngressList(); routeList = await getIngressList(ANNOTATION_BASE);
break; break;
case "gateway": case "gateway":
routeList = await getHttpRouteList(); routeList = await getHttpRouteList();
break; break;
default: default:
routeList = await getIngressList(); routeList = await getIngressList(ANNOTATION_BASE);
} }
return routeList; return routeList;