diff --git a/Dockerfile b/Dockerfile index f226ee977..de93ce527 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ -ARG SERVER_VERSION=v0.34.2 -ARG SERVER_VERSION_STRING=v0.34.2 +ARG SERVER_VERSION=v0.34.5 +ARG SERVER_VERSION_STRING=v0.34.5 # Builder image to compile the website FROM ubuntu:24.04 AS builder diff --git a/Jenkinsfile b/Jenkinsfile index e86a41f08..11584f654 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -20,6 +20,19 @@ pipeline { - mountPath: "/home/default/.kube" name: "dot-kube" readOnly: false + - name: eks + image: eclipsefdn/aws:alpine-latest + command: + - cat + tty: true + resources: + limits: + cpu: 1 + memory: 1Gi + volumeMounts: + - mountPath: "/home/default/.kube" + name: "dot-kube" + readOnly: false - name: jnlp resources: limits: @@ -79,6 +92,24 @@ pipeline { } } + stage('Deploy to EKS staging environment') { + when { + anyOf { + expression { return env.BRANCH_NAME.startsWith('feature') } + branch 'eks-main' + } + } + steps { + container('eks') { + withKubeConfig([credentialsId: 'ci-bot-eks-staging-token', serverUrl: 'https://5CF0970816FA7A7C340E6BEF8575A8D4.gr7.eu-central-1.eks.amazonaws.com']) { + sh ''' + ./kubernetes/helm-deploy.sh aws-staging "${IMAGE_TAG}" + ''' + } + } + } + } + stage('Deploy test') { when { branch 'test' diff --git a/charts/openvsx/Chart.lock b/charts/openvsx/Chart.lock index d3dcdc1a0..7ef977a9b 100644 --- a/charts/openvsx/Chart.lock +++ b/charts/openvsx/Chart.lock @@ -2,5 +2,11 @@ dependencies: - name: alloy repository: https://grafana.github.io/helm-charts version: 1.1.2 -digest: sha256:66403884b7f293e86e2a61d0d822fd0878a6b4a64e5e88f181b93022bc4f9bcd -generated: "2025-08-20T12:51:18.346537659+03:00" +- name: postgresql-ha + repository: https://charts.bitnami.com/bitnami + version: 16.3.2 +- name: aws-load-balancer-controller + repository: https://aws.github.io/eks-charts + version: 1.14.0 +digest: sha256:e2c6dcf71280bba07adec1bf48d16ede03c8e30b5075a1899e460a6c393eaf16 +generated: "2026-03-21T12:01:49.110601-04:00" diff --git a/charts/openvsx/Chart.yaml b/charts/openvsx/Chart.yaml index fd7e3dfb4..175f0f3f3 100644 --- a/charts/openvsx/Chart.yaml +++ b/charts/openvsx/Chart.yaml @@ -8,3 +8,11 @@ dependencies: - name: alloy version: 1.1.2 repository: https://grafana.github.io/helm-charts + - name: postgresql-ha + version: 16.3.2 + repository: https://charts.bitnami.com/bitnami + condition: eks.enabled + - name: aws-load-balancer-controller + version: 1.14.0 + repository: https://aws.github.io/eks-charts + condition: eks.enabled diff --git a/charts/openvsx/crds/service-monitor.yaml b/charts/openvsx/crds/service-monitor.yaml new file mode 100644 index 000000000..bf5166e4a --- /dev/null +++ b/charts/openvsx/crds/service-monitor.yaml @@ -0,0 +1,1412 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + operator.prometheus.io/version: 0.88.1 + name: servicemonitors.monitoring.coreos.com +spec: + group: monitoring.coreos.com + names: + categories: + - prometheus-operator + kind: ServiceMonitor + listKind: ServiceMonitorList + plural: servicemonitors + shortNames: + - smon + singular: servicemonitor + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: |- + The `ServiceMonitor` custom resource definition (CRD) defines how `Prometheus` and `PrometheusAgent` can scrape metrics from a group of services. + Among other things, it allows to specify: + * The services to scrape via label selectors. + * The container ports to scrape. + * Authentication credentials to use. + * Target and metric relabeling. + + `Prometheus` and `PrometheusAgent` objects select `ServiceMonitor` objects using label and namespace selectors. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + spec defines the specification of desired Service selection for target discovery by + Prometheus. + properties: + attachMetadata: + description: |- + attachMetadata defines additional metadata which is added to the + discovered targets. + + It requires Prometheus >= v2.37.0. + properties: + node: + description: |- + node when set to true, Prometheus attaches node metadata to the discovered + targets. + + The Prometheus service account must have the `list` and `watch` + permissions on the `Nodes` objects. + type: boolean + type: object + bodySizeLimit: + description: |- + bodySizeLimit when defined, bodySizeLimit specifies a job level limit on the size + of uncompressed response body that will be accepted by Prometheus. + + It requires Prometheus >= v2.28.0. + pattern: (^0|([0-9]*[.])?[0-9]+((K|M|G|T|E|P)i?)?B)$ + type: string + convertClassicHistogramsToNHCB: + description: |- + convertClassicHistogramsToNHCB defines whether to convert all scraped classic histograms into a native histogram with custom buckets. + It requires Prometheus >= v3.0.0. + type: boolean + endpoints: + description: |- + endpoints defines the list of endpoints part of this ServiceMonitor. + Defines how to scrape metrics from Kubernetes [Endpoints](https://kubernetes.io/docs/concepts/services-networking/service/#endpoints) objects. + In most cases, an Endpoints object is backed by a Kubernetes [Service](https://kubernetes.io/docs/concepts/services-networking/service/) object with the same name and labels. + items: + description: |- + Endpoint defines an endpoint serving Prometheus metrics to be scraped by + Prometheus. + properties: + authorization: + description: |- + authorization configures the Authorization header credentials used by + the client. + + Cannot be set at the same time as `basicAuth`, `bearerTokenSecret` or `oauth2`. + properties: + credentials: + description: credentials defines a key of a Secret in the + namespace that contains the credentials for authentication. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + type defines the authentication type. The value is case-insensitive. + + "Basic" is not a supported value. + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + basicAuth defines the Basic Authentication credentials used by the + client. + + Cannot be set at the same time as `authorization`, `bearerTokenSecret` or `oauth2`. + properties: + password: + description: |- + password defines a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + username defines a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenFile: + description: |- + bearerTokenFile defines the file to read bearer token for scraping the target. + + Deprecated: use `authorization` instead. + type: string + bearerTokenSecret: + description: |- + bearerTokenSecret defines a key of a Secret containing the bearer token + used by the client for authentication. The secret needs to be in the + same namespace as the custom resource and readable by the Prometheus + Operator. + + Cannot be set at the same time as `authorization`, `basicAuth` or `oauth2`. + + Deprecated: use `authorization` instead. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + enableHttp2: + description: enableHttp2 can be used to disable HTTP2. + type: boolean + filterRunning: + description: |- + filterRunning when true, the pods which are not running (e.g. either in Failed or + Succeeded state) are dropped during the target discovery. + + If unset, the filtering is enabled. + + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase + type: boolean + followRedirects: + description: |- + followRedirects defines whether the client should follow HTTP 3xx + redirects. + type: boolean + honorLabels: + description: |- + honorLabels defines when true the metric's labels when they collide + with the target's labels. + type: boolean + honorTimestamps: + description: |- + honorTimestamps defines whether Prometheus preserves the timestamps + when exposed by the target. + type: boolean + interval: + description: |- + interval at which Prometheus scrapes the metrics from the target. + + If empty, Prometheus uses the global scrape interval. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + metricRelabelings: + description: |- + metricRelabelings defines the relabeling rules to apply to the + samples before ingestion. + items: + description: |- + RelabelConfig allows dynamic rewriting of the label set for targets, alerts, + scraped samples and remote write samples. + + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + properties: + action: + default: replace + description: |- + action to perform based on the regex matching. + + `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. + `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. + + Default: "Replace" + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + description: |- + modulus to take of the hash of the source label values. + + Only applicable when the action is `HashMod`. + format: int64 + type: integer + regex: + description: regex defines the regular expression against + which the extracted value is matched. + type: string + replacement: + description: |- + replacement value against which a Replace action is performed if the + regular expression matches. + + Regex capture groups are available. + type: string + separator: + description: separator defines the string between concatenated + SourceLabels. + type: string + sourceLabels: + description: |- + sourceLabels defines the source labels select values from existing labels. Their content is + concatenated using the configured Separator and matched against the + configured regular expression. + items: + description: |- + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. + type: string + type: array + targetLabel: + description: |- + targetLabel defines the label to which the resulting string is written in a replacement. + + It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, + `KeepEqual` and `DropEqual` actions. + + Regex capture groups are available. + type: string + type: object + type: array + noProxy: + description: |- + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names + that should be excluded from proxying. IP and domain names can + contain port numbers. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: string + oauth2: + description: |- + oauth2 defines the OAuth2 settings used by the client. + + It requires Prometheus >= 2.27.0. + + Cannot be set at the same time as `authorization`, `basicAuth` or `bearerTokenSecret`. + properties: + clientId: + description: |- + clientId defines a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: configMap defines the ConfigMap containing + data to use for the targets. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: secret defines the Secret containing data + to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + clientSecret defines a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + endpointParams configures the HTTP parameters to append to the token + URL. + type: object + noProxy: + description: |- + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names + that should be excluded from proxying. IP and domain names can + contain port numbers. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: string + proxyConnectHeader: + additionalProperties: + items: + description: SecretKeySelector selects a key of a Secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: array + description: |- + proxyConnectHeader optionally specifies headers to send to + proxies during CONNECT requests. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: object + x-kubernetes-map-type: atomic + proxyFromEnvironment: + description: |- + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: boolean + proxyUrl: + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ + type: string + scopes: + description: scopes defines the OAuth2 scopes used for the + token request. + items: + type: string + type: array + tlsConfig: + description: |- + tlsConfig defines the TLS configuration to use when connecting to the OAuth2 server. + It requires Prometheus >= v2.43.0. + properties: + ca: + description: ca defines the Certificate authority used + when verifying server certificates. + properties: + configMap: + description: configMap defines the ConfigMap containing + data to use for the targets. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: secret defines the Secret containing + data to use for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: cert defines the Client certificate to + present when doing client-authentication. + properties: + configMap: + description: configMap defines the ConfigMap containing + data to use for the targets. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: secret defines the Secret containing + data to use for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: insecureSkipVerify defines how to disable + target certificate validation. + type: boolean + keySecret: + description: keySecret defines the Secret containing + the client key file for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + maxVersion: + description: |- + maxVersion defines the maximum acceptable TLS version. + + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. + enum: + - TLS10 + - TLS11 + - TLS12 + - TLS13 + type: string + minVersion: + description: |- + minVersion defines the minimum acceptable TLS version. + + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. + enum: + - TLS10 + - TLS11 + - TLS12 + - TLS13 + type: string + serverName: + description: serverName is used to verify the hostname + for the targets. + type: string + type: object + tokenUrl: + description: tokenUrl defines the URL to fetch the token + from. + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + params: + additionalProperties: + items: + type: string + type: array + description: params define optional HTTP URL parameters. + type: object + path: + description: |- + path defines the HTTP path from which to scrape for metrics. + + If empty, Prometheus uses the default value (e.g. `/metrics`). + type: string + port: + description: |- + port defines the name of the Service port which this endpoint refers to. + + It takes precedence over `targetPort`. + type: string + proxyConnectHeader: + additionalProperties: + items: + description: SecretKeySelector selects a key of a Secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: array + description: |- + proxyConnectHeader optionally specifies headers to send to + proxies during CONNECT requests. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: object + x-kubernetes-map-type: atomic + proxyFromEnvironment: + description: |- + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: boolean + proxyUrl: + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ + type: string + relabelings: + description: |- + relabelings defines the relabeling rules to apply the target's + metadata labels. + + The Operator automatically adds relabelings for a few standard Kubernetes fields. + + The original scrape job's name is available via the `__tmp_prometheus_job_name` label. + + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + items: + description: |- + RelabelConfig allows dynamic rewriting of the label set for targets, alerts, + scraped samples and remote write samples. + + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + properties: + action: + default: replace + description: |- + action to perform based on the regex matching. + + `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. + `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. + + Default: "Replace" + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + description: |- + modulus to take of the hash of the source label values. + + Only applicable when the action is `HashMod`. + format: int64 + type: integer + regex: + description: regex defines the regular expression against + which the extracted value is matched. + type: string + replacement: + description: |- + replacement value against which a Replace action is performed if the + regular expression matches. + + Regex capture groups are available. + type: string + separator: + description: separator defines the string between concatenated + SourceLabels. + type: string + sourceLabels: + description: |- + sourceLabels defines the source labels select values from existing labels. Their content is + concatenated using the configured Separator and matched against the + configured regular expression. + items: + description: |- + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. + type: string + type: array + targetLabel: + description: |- + targetLabel defines the label to which the resulting string is written in a replacement. + + It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, + `KeepEqual` and `DropEqual` actions. + + Regex capture groups are available. + type: string + type: object + type: array + scheme: + description: scheme defines the HTTP scheme to use when scraping + the metrics. + enum: + - http + - https + - HTTP + - HTTPS + type: string + scrapeTimeout: + description: |- + scrapeTimeout defines the timeout after which Prometheus considers the scrape to be failed. + + If empty, Prometheus uses the global scrape timeout unless it is less + than the target's scrape interval value in which the latter is used. + The value cannot be greater than the scrape interval otherwise the operator will reject the resource. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + targetPort: + anyOf: + - type: integer + - type: string + description: |- + targetPort defines the name or number of the target port of the `Pod` object behind the + Service. The port must be specified with the container's port property. + x-kubernetes-int-or-string: true + tlsConfig: + description: tlsConfig defines TLS configuration used by the + client. + properties: + ca: + description: ca defines the Certificate authority used when + verifying server certificates. + properties: + configMap: + description: configMap defines the ConfigMap containing + data to use for the targets. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: secret defines the Secret containing data + to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + description: caFile defines the path to the CA cert in the + Prometheus container to use for the targets. + type: string + cert: + description: cert defines the Client certificate to present + when doing client-authentication. + properties: + configMap: + description: configMap defines the ConfigMap containing + data to use for the targets. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: secret defines the Secret containing data + to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + description: certFile defines the path to the client cert + file in the Prometheus container for the targets. + type: string + insecureSkipVerify: + description: insecureSkipVerify defines how to disable target + certificate validation. + type: boolean + keyFile: + description: keyFile defines the path to the client key + file in the Prometheus container for the targets. + type: string + keySecret: + description: keySecret defines the Secret containing the + client key file for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + maxVersion: + description: |- + maxVersion defines the maximum acceptable TLS version. + + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. + enum: + - TLS10 + - TLS11 + - TLS12 + - TLS13 + type: string + minVersion: + description: |- + minVersion defines the minimum acceptable TLS version. + + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. + enum: + - TLS10 + - TLS11 + - TLS12 + - TLS13 + type: string + serverName: + description: serverName is used to verify the hostname for + the targets. + type: string + type: object + trackTimestampsStaleness: + description: |- + trackTimestampsStaleness defines whether Prometheus tracks staleness of + the metrics that have an explicit timestamp present in scraped data. + Has no effect if `honorTimestamps` is false. + + It requires Prometheus >= v2.48.0. + type: boolean + type: object + type: array + fallbackScrapeProtocol: + description: |- + fallbackScrapeProtocol defines the protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. + + It requires Prometheus >= v3.0.0. + enum: + - PrometheusProto + - OpenMetricsText0.0.1 + - OpenMetricsText1.0.0 + - PrometheusText0.0.4 + - PrometheusText1.0.0 + type: string + jobLabel: + description: |- + jobLabel selects the label from the associated Kubernetes `Service` + object which will be used as the `job` label for all metrics. + + For example if `jobLabel` is set to `foo` and the Kubernetes `Service` + object is labeled with `foo: bar`, then Prometheus adds the `job="bar"` + label to all ingested metrics. + + If the value of this field is empty or if the label doesn't exist for + the given Service, the `job` label of the metrics defaults to the name + of the associated Kubernetes `Service`. + type: string + keepDroppedTargets: + description: |- + keepDroppedTargets defines the per-scrape limit on the number of targets dropped by relabeling + that will be kept in memory. 0 means no limit. + + It requires Prometheus >= v2.47.0. + format: int64 + type: integer + labelLimit: + description: |- + labelLimit defines the per-scrape limit on number of labels that will be accepted for a sample. + + It requires Prometheus >= v2.27.0. + format: int64 + type: integer + labelNameLengthLimit: + description: |- + labelNameLengthLimit defines the per-scrape limit on length of labels name that will be accepted for a sample. + + It requires Prometheus >= v2.27.0. + format: int64 + type: integer + labelValueLengthLimit: + description: |- + labelValueLengthLimit defines the per-scrape limit on length of labels value that will be accepted for a sample. + + It requires Prometheus >= v2.27.0. + format: int64 + type: integer + namespaceSelector: + description: |- + namespaceSelector defines in which namespace(s) Prometheus should discover the services. + By default, the services are discovered in the same namespace as the `ServiceMonitor` object but it is possible to select pods across different/all namespaces. + properties: + any: + description: |- + any defines the boolean describing whether all namespaces are selected in contrast to a + list restricting them. + type: boolean + matchNames: + description: matchNames defines the list of namespace names to + select from. + items: + type: string + type: array + type: object + nativeHistogramBucketLimit: + description: |- + nativeHistogramBucketLimit defines ff there are more than this many buckets in a native histogram, + buckets will be merged to stay within the limit. + It requires Prometheus >= v2.45.0. + format: int64 + type: integer + nativeHistogramMinBucketFactor: + anyOf: + - type: integer + - type: string + description: |- + nativeHistogramMinBucketFactor defines if the growth factor of one bucket to the next is smaller than this, + buckets will be merged to increase the factor sufficiently. + It requires Prometheus >= v2.50.0. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + podTargetLabels: + description: |- + podTargetLabels defines the labels which are transferred from the + associated Kubernetes `Pod` object onto the ingested metrics. + items: + type: string + type: array + sampleLimit: + description: |- + sampleLimit defines a per-scrape limit on the number of scraped samples + that will be accepted. + format: int64 + type: integer + scrapeClass: + description: scrapeClass defines the scrape class to apply. + minLength: 1 + type: string + scrapeClassicHistograms: + description: |- + scrapeClassicHistograms defines whether to scrape a classic histogram that is also exposed as a native histogram. + It requires Prometheus >= v2.45.0. + + Notice: `scrapeClassicHistograms` corresponds to the `always_scrape_classic_histograms` field in the Prometheus configuration. + type: boolean + scrapeNativeHistograms: + description: |- + scrapeNativeHistograms defines whether to enable scraping of native histograms. + It requires Prometheus >= v3.8.0. + type: boolean + scrapeProtocols: + description: |- + scrapeProtocols defines the protocols to negotiate during a scrape. It tells clients the + protocols supported by Prometheus in order of preference (from most to least preferred). + + If unset, Prometheus uses its default value. + + It requires Prometheus >= v2.49.0. + items: + description: |- + ScrapeProtocol represents a protocol used by Prometheus for scraping metrics. + Supported values are: + * `OpenMetricsText0.0.1` + * `OpenMetricsText1.0.0` + * `PrometheusProto` + * `PrometheusText0.0.4` + * `PrometheusText1.0.0` + enum: + - PrometheusProto + - OpenMetricsText0.0.1 + - OpenMetricsText1.0.0 + - PrometheusText0.0.4 + - PrometheusText1.0.0 + type: string + type: array + x-kubernetes-list-type: set + selector: + description: selector defines the label selector to select the Kubernetes + `Endpoints` objects to scrape metrics from. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + selectorMechanism: + description: |- + selectorMechanism defines the mechanism used to select the endpoints to scrape. + By default, the selection process relies on relabel configurations to filter the discovered targets. + Alternatively, you can opt in for role selectors, which may offer better efficiency in large clusters. + Which strategy is best for your use case needs to be carefully evaluated. + + It requires Prometheus >= v2.17.0. + enum: + - RelabelConfig + - RoleSelector + type: string + serviceDiscoveryRole: + description: |- + serviceDiscoveryRole defines the service discovery role used to discover targets. + + If set, the value should be either "Endpoints" or "EndpointSlice". + Otherwise it defaults to the value defined in the + Prometheus/PrometheusAgent resource. + enum: + - Endpoints + - EndpointSlice + type: string + targetLabels: + description: |- + targetLabels defines the labels which are transferred from the + associated Kubernetes `Service` object onto the ingested metrics. + items: + type: string + type: array + targetLimit: + description: |- + targetLimit defines a limit on the number of scraped targets that will + be accepted. + format: int64 + type: integer + required: + - endpoints + - selector + type: object + status: + description: |- + status defines the status subresource. It is under active development and is updated only when the + "StatusForConfigurationResources" feature gate is enabled. + + Most recent observed status of the ServiceMonitor. Read-only. + More info: + https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + bindings: + description: bindings defines the list of workload resources (Prometheus, + PrometheusAgent, ThanosRuler or Alertmanager) which select the configuration + resource. + items: + description: WorkloadBinding is a link between a configuration resource + and a workload resource. + properties: + conditions: + description: conditions defines the current state of the configuration + resource when bound to the referenced Workload object. + items: + description: ConfigResourceCondition describes the status + of configuration resources linked to Prometheus, PrometheusAgent, + Alertmanager or ThanosRuler. + properties: + lastTransitionTime: + description: lastTransitionTime defines the time of the + last update to the current status property. + format: date-time + type: string + message: + description: message defines the human-readable message + indicating details for the condition's last transition. + type: string + observedGeneration: + description: |- + observedGeneration defines the .metadata.generation that the + condition was set based upon. For instance, if `.metadata.generation` is + currently 12, but the `.status.conditions[].observedGeneration` is 9, the + condition is out of date with respect to the current state of the object. + format: int64 + type: integer + reason: + description: reason for the condition's last transition. + type: string + status: + description: status of the condition. + minLength: 1 + type: string + type: + description: |- + type of the condition being reported. + Currently, only "Accepted" is supported. + enum: + - Accepted + minLength: 1 + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + group: + description: group defines the group of the referenced resource. + enum: + - monitoring.coreos.com + type: string + name: + description: name defines the name of the referenced object. + minLength: 1 + type: string + namespace: + description: namespace defines the namespace of the referenced + object. + minLength: 1 + type: string + resource: + description: resource defines the type of resource being referenced + (e.g. Prometheus, PrometheusAgent, ThanosRuler or Alertmanager). + enum: + - prometheuses + - prometheusagents + - thanosrulers + - alertmanagers + type: string + required: + - group + - name + - namespace + - resource + type: object + type: array + x-kubernetes-list-map-keys: + - group + - resource + - name + - namespace + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/openvsx/templates/clamav-rest/deployment.yaml b/charts/openvsx/templates/clamav-rest/statefulset.yaml similarity index 84% rename from charts/openvsx/templates/clamav-rest/deployment.yaml rename to charts/openvsx/templates/clamav-rest/statefulset.yaml index 648431b32..5b9135bbd 100644 --- a/charts/openvsx/templates/clamav-rest/deployment.yaml +++ b/charts/openvsx/templates/clamav-rest/statefulset.yaml @@ -1,6 +1,6 @@ {{- if .Values.clamav.enabled }} apiVersion: apps/v1 -kind: Deployment +kind: StatefulSet metadata: name: {{ .Values.clamav.name }}-{{ .Values.environment }} namespace: {{ .Values.namespace }} @@ -8,6 +8,7 @@ metadata: app: {{ .Values.name }} environment: {{ .Values.environment }} spec: + serviceName: {{ .Values.clamav.name }}-{{ .Values.environment }} revisionHistoryLimit: 1 replicas: {{ .Values.clamav.replicas }} selector: @@ -15,8 +16,6 @@ spec: app: {{ .Values.name }} environment: {{ .Values.environment }} component: {{ .Values.clamav.name }}-{{ .Values.environment }} - strategy: - type: Recreate template: metadata: labels: @@ -24,6 +23,7 @@ spec: environment: {{ .Values.environment }} component: {{ .Values.clamav.name }}-{{ .Values.environment }} spec: + terminationGracePeriodSeconds: 10 containers: - name: {{ .Values.clamav.name }}-{{ .Values.environment }} image: "{{ .Values.clamav.image.repository }}:{{ .Values.clamav.image.tag }}" @@ -70,9 +70,15 @@ spec: volumes: - name: run-dir emptyDir: {} - - name: clamav-db - persistentVolumeClaim: - claimName: clamav-db - name: tmp-scans emptyDir: {} + volumeClaimTemplates: + - metadata: + name: clamav-db + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: {{ .Values.clamav.persistence.storageClass | quote }} + resources: + requests: + storage: {{ .Values.clamav.persistence.size | default "5Gi" }} {{- end }} diff --git a/charts/openvsx/templates/deployment.yaml b/charts/openvsx/templates/deployment.yaml index 5bd0eaf1d..7340f1521 100644 --- a/charts/openvsx/templates/deployment.yaml +++ b/charts/openvsx/templates/deployment.yaml @@ -9,7 +9,9 @@ metadata: spec: progressDeadlineSeconds: 3600 revisionHistoryLimit: 1 + {{- if not .Values.autoscaling.enabled }} replicas: {{ .Values.replicaCount }} + {{- end }} selector: matchLabels: app: {{ .Values.name }} diff --git a/charts/openvsx/templates/grafana-alloy.yaml b/charts/openvsx/templates/grafana-alloy.yaml index 8a4f1f706..1b1fd5838 100644 --- a/charts/openvsx/templates/grafana-alloy.yaml +++ b/charts/openvsx/templates/grafana-alloy.yaml @@ -57,6 +57,10 @@ data: {{- end }} prometheus.remote_write "default" { + external_labels = { + cluster = sys.env("CLUSTER_NAME"), + __replica__ = sys.env("POD_NAME"), + } endpoint { name = "hosted-prometheus" url = sys.env("PROMETHEUS_URL") diff --git a/charts/openvsx/templates/hpa-postgresql.yaml b/charts/openvsx/templates/hpa-postgresql.yaml new file mode 100644 index 000000000..0da8e5cf2 --- /dev/null +++ b/charts/openvsx/templates/hpa-postgresql.yaml @@ -0,0 +1,25 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: postgresql-{{ .Values.environment }}-hpa + namespace: {{ .Release.Namespace | quote }} + labels: + app.kubernetes.io/name: postgresql-ha + app.kubernetes.io/instance: {{ .Release.Name }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: StatefulSet + # Matches your 'staging-postgresql-ha-postgresql' naming logic + name: {{ .Values.environment }}-postgresql-ha-postgresql + minReplicas: 3 + maxReplicas: 9 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 60 +{{- end }} diff --git a/charts/openvsx/templates/ingress.yaml b/charts/openvsx/templates/ingress.yaml new file mode 100644 index 000000000..08360a2bc --- /dev/null +++ b/charts/openvsx/templates/ingress.yaml @@ -0,0 +1,43 @@ +{{- if .Values.eks.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + labels: + app: {{ .Values.name }} + environment: {{ .Values.environment }} + name: {{ .Values.name }}-{{ .Values.environment }} + namespace: {{ .Values.namespace }} + annotations: + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06 + alb.ingress.kubernetes.io/target-type: ip + alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=60 + alb.ingress.kubernetes.io/certificate-arn: {{ .Values.ingress.certArn }} + alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80},{"HTTPS":443}]' + alb.ingress.kubernetes.io/ssl-redirect: "443" + alb.ingress.kubernetes.io/actions.forward-cors: > + {"type":"fixed-response","fixedResponseConfig":{"contentType":"text/plain","statusCode":"204"}} + alb.ingress.kubernetes.io/conditions.forward-cors: > + [{"field":"http-request-method","httpRequestMethodConfig":{"values":["OPTIONS"]}}] + alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=60,client_keep_alive.seconds=60 +spec: + ingressClassName: alb + rules: + - host: {{ .Values.host }} + - http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: forward-cors + port: + name: use-annotation + - path: / + pathType: Prefix + backend: + service: + name: {{ .Values.name }}-{{ .Values.environment }} + port: + number: {{ .Values.service.port }} +{{- end }} diff --git a/charts/openvsx/templates/keda-openvsx-app.yaml b/charts/openvsx/templates/keda-openvsx-app.yaml new file mode 100644 index 000000000..bbd475f4d --- /dev/null +++ b/charts/openvsx/templates/keda-openvsx-app.yaml @@ -0,0 +1,51 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + name: {{ .Values.name }}-{{ .Values.environment }}-keda + namespace: {{ .Values.namespace }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ .Values.name }}-{{ .Values.environment }} + minReplicaCount: {{ .Values.autoscaling.minReplicas }} + maxReplicaCount: {{ .Values.autoscaling.maxReplicas }} + pollingInterval: {{ .Values.autoscaling.pollingInterval }} # query every 30s, not 15s — reduces noise + cooldownPeriod: {{ .Values.autoscaling.cooldownPeriod }} # wait 10 mins before scaling down — let I/O settle + advanced: + horizontalPodAutoscalerConfig: + behavior: + scaleUp: + stabilizationWindowSeconds: {{ .Values.autoscaling.scaleUp.stabilizationWindowSeconds }} # sustained pressure for 3 mins before scaling up + policies: + - type: Pods + value: {{ .Values.autoscaling.scaleUp.pods }} # add max 2 pods at a time + periodSeconds: {{ .Values.autoscaling.scaleUp.periodSeconds }} # add max 2 pods every 2 mins — gradual + scaleDown: + stabilizationWindowSeconds: {{ .Values.autoscaling.scaleDown.stabilizationWindowSeconds }} # hold for 10 mins before scaling down + policies: + - type: Pods + value: {{ .Values.autoscaling.scaleDown.pods }} + periodSeconds: {{ .Values.autoscaling.scaleDown.periodSeconds }} # remove only 1 pod every 3 mins — conservative + triggers: + - type: prometheus + authenticationRef: + name: keda-prometheus-trigger-auth + metadata: + serverAddress: {{ .Values.autoscaling.prometheusUrl }} # ← add this line + authModes: "basic" + metricName: jetty_queue_utilization_sustained + query: | + avg( + avg_over_time( + ( + executor_queued_tasks{environment="{{ .Values.environment }}"} + / + (executor_queued_tasks{environment="{{ .Values.environment }}"} + executor_queue_remaining_tasks{environment="{{ .Values.environment }}"}) + * 100 + )[5m:15s] + ) + ) + threshold: "70" +{{- end }} diff --git a/charts/openvsx/templates/kube-state-metrics-monitor.yaml b/charts/openvsx/templates/kube-state-metrics-monitor.yaml new file mode 100644 index 000000000..60d75002b --- /dev/null +++ b/charts/openvsx/templates/kube-state-metrics-monitor.yaml @@ -0,0 +1,21 @@ +{{- if .Values.eks.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: kube-state-metrics-monitor + namespace: open-vsx-org-staging + labels: + app: open-vsx-org + environment: staging +spec: + namespaceSelector: + matchNames: + - kube-state-metrics + selector: + matchLabels: + app.kubernetes.io/name: kube-state-metrics + endpoints: + - path: /metrics + interval: 60s + targetPort: 8080 +{{- end }} diff --git a/charts/openvsx/templates/node-exporter-service-monitor.yaml b/charts/openvsx/templates/node-exporter-service-monitor.yaml new file mode 100644 index 000000000..f5aa3384c --- /dev/null +++ b/charts/openvsx/templates/node-exporter-service-monitor.yaml @@ -0,0 +1,21 @@ +{{- if .Values.eks.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: node-exporter-monitor + namespace: open-vsx-org-staging + labels: + app: open-vsx-org + environment: staging +spec: + namespaceSelector: + matchNames: + - prometheus-node-exporter + selector: + matchLabels: + app.kubernetes.io/name: prometheus-node-exporter + endpoints: + - path: /metrics + interval: 60s + targetPort: 9100 +{{- end }} diff --git a/charts/openvsx/templates/route.yaml b/charts/openvsx/templates/route.yaml index f074afaf2..e2b3887b3 100644 --- a/charts/openvsx/templates/route.yaml +++ b/charts/openvsx/templates/route.yaml @@ -1,3 +1,4 @@ +{{- if not .Values.eks.enabled }} apiVersion: route.openshift.io/v1 kind: Route metadata: @@ -47,3 +48,4 @@ spec: name: {{ .Values.name }}-{{ .Values.environment }} weight: 100 {{- end }} +{{- end }} diff --git a/charts/openvsx/templates/trigger-auth.yaml b/charts/openvsx/templates/trigger-auth.yaml new file mode 100644 index 000000000..e1931ae51 --- /dev/null +++ b/charts/openvsx/templates/trigger-auth.yaml @@ -0,0 +1,15 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: keda-prometheus-trigger-auth + namespace: {{ .Values.namespace }} +spec: + secretTargetRef: + - parameter: username + name: grafana-cloud-secret-{{ .Values.environment }} + key: PROMETHEUS_USERNAME + - parameter: password + name: grafana-cloud-secret-{{ .Values.environment }} + key: PROMETHEUS_PASSWORD +{{- end }} diff --git a/charts/openvsx/templates/yara-rest/deployment.yaml b/charts/openvsx/templates/yara-rest/deployment.yaml index 7c2ef4e9c..ebdef8794 100644 --- a/charts/openvsx/templates/yara-rest/deployment.yaml +++ b/charts/openvsx/templates/yara-rest/deployment.yaml @@ -24,10 +24,18 @@ spec: environment: {{ .Values.environment }} component: {{ .Values.yara.name }}-{{ .Values.environment }} spec: + terminationGracePeriodSeconds: 10 containers: - name: {{ .Values.yara.name }}-{{ .Values.environment }} image: "{{ .Values.yara.image.repository }}:{{ .Values.yara.image.tag }}" imagePullPolicy: {{ .Values.yara.image.pullPolicy }} + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsNonRoot: true + capabilities: + drop: + - ALL ports: - name: http containerPort: {{ .Values.yara.service.port }} @@ -71,11 +79,4 @@ spec: claimName: yara-rules - name: tmp-scans emptyDir: {} - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - runAsNonRoot: true - capabilities: - drop: - - ALL {{- end }} diff --git a/charts/openvsx/values-aws-staging.yaml b/charts/openvsx/values-aws-staging.yaml new file mode 100644 index 000000000..06177df92 --- /dev/null +++ b/charts/openvsx/values-aws-staging.yaml @@ -0,0 +1,291 @@ +# Default values for openvsx eks staging. + +name: &name open-vsx-org +environment: &environment staging +platform: &platform eks +namespace: &namespace open-vsx-org-staging +host: staging.open-vsx.org + +replicaCount: 6 +esReplicaCount: 3 +autoscaling: + enabled: true + minReplicas: 12 + maxReplicas: 18 + prometheusUrl: "https://prometheus-prod-32-prod-ca-east-0.grafana.net/api/prom" + pollingInterval: 30 + cooldownPeriod: 600 + scaleUp: + stabilizationWindowSeconds: 180 + pods: 2 + periodSeconds: 120 + scaleDown: + stabilizationWindowSeconds: 600 + pods: 1 + periodSeconds: 180 + +image: + repository: ghcr.io/eclipsefdn/openvsx-website + pullPolicy: Always + # Overrides the image tag whose default is the chart appVersion. + tag: 97e1417-99 + +eks: + enabled: true # Switch to false for OKD installations + +aws-load-balancer-controller: + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 200m + memory: 256Mi + clusterName: eks-staging + region: eu-central-1 + vpcId: vpc-0285cbfe9bfb7e4fd + serviceAccount: + create: false + name: aws-load-balancer-controller-staging + +ingress: + certArn: arn:aws:acm:eu-central-1:365555376529:certificate/c247a8c7-31fa-4116-bd4a-c1e5aebad840 + +website: + jvmArgs: > + -Xms4G -Xmx6G + -XX:+AlwaysPreTouch + -XX:+HeapDumpOnOutOfMemoryError + -XX:+UseStringDeduplication + -XX:+ParallelRefProcEnabled + -XX:+DisableExplicitGC + -XX:+UnlockExperimentalVMOptions + -XX:+UnlockDiagnosticVMOptions + -XX:-OmitStackTraceInFastThrow + -Dlog4j2.formatMsgNoLookups=true + -Dlog4j.formatMsgNoLookups=true + -Dorg.jooq.no-logo=true + -Dorg.jooq.no-tips=true + --enable-native-access=ALL-UNNAMED + +resources: + limits: + cpu: 5000m + memory: 8Gi + requests: + cpu: 3000m + memory: 8Gi + +# elastic search +es: + commonAnnotations: + "karpenter.sh/do-not-disrupt": "true" + "cluster-autoscaler.kubernetes.io/safe-to-evict": "false" + pdb: + create: true + minAvailable: 1 + java_opts: -Xms1g -Xmx1g -Dlog4j2.formatMsgNoLookups=true + resources: + limits: + cpu: 4 + memory: 8Gi + requests: + cpu: 1 + memory: 8Gi + storage_class: gp3 + +postgresql-ha: + metrics: + enabled: true + image: + repository: bitnamilegacy/postgres-exporter + tag: 0.17.1-debian-12-r14 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 200m + memory: 256Mi + serviceMonitor: + enabled: true + interval: 60s + labels: + app: open-vsx-org + environment: staging + postgresql: + image: + repository: bitnamilegacy/postgresql-repmgr + tag: 17.6.0-debian-12-r2 + podSecurityContext: + enabled: true + fsGroup: 1001 + containerSecurityContext: + enabled: true + runAsUser: 1001 + database: openvsx-staging + createDatabase: true + passwordEncryption: "scram-sha-256" + enablePostgresUser: true + extraEnvVars: + - name: POSTGRESQL_SR_CHECK_PASSWORD + authenticationConfiguration: | + host all all 0.0.0.0/0 scram-sha-256 + local all all peer + extendedConf: |- + max_connections = 1000 + # Reduced to ~20% of RAM to leave room for connection overhead + shared_buffers = 800MB + # Critical: Set low because it can be allocated multiple times per query + work_mem = 1MB + # Lowered to avoid spikes during maintenance + maintenance_work_mem = 64MB + # 50-75% of total RAM is the standard planner hint + effective_cache_size = 3000MB + resources: + requests: + cpu: "500m" + memory: "3Gi" + limits: + cpu: "2" + memory: "4Gi" + pdb: + create: true + minAvailable: 1 + podAnnotations: + "karpenter.sh/do-not-disrupt": "true" + "cluster-autoscaler.kubernetes.io/safe-to-evict": "false" + pgpool: + replicaCount: 0 + +# redis +redis: + master: + pdb: + create: true + minAvailable: 1 + podAnnotations: + "karpenter.sh/do-not-disrupt": "true" + "cluster-autoscaler.kubernetes.io/safe-to-evict": "false" + replica: + pdb: + create: true + minAvailable: 1 + podAnnotations: + "karpenter.sh/do-not-disrupt": "true" + "cluster-autoscaler.kubernetes.io/safe-to-evict": "false" + name: redis + replicas: 6 + image: + repository: redis + tag: "7.2.10" + pullPolicy: IfNotPresent + maxmemory: "896mb" + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1536Mi" + cpu: "500m" + persistence: + storageGi: 5 + storageClass: "gp3" + serviceAccountName: redis-cluster-operator + clusterRoleName: redis-cluster-operator-role-cluster + clusterRoleBindingName: redis-cluster-operator-role-binding-cluster + roleName: redis-cluster-operator-role + roleBinding: redis-cluster-operator-role-binding + +# grafana alloy +alloy: + alloy: + clustering: + enabled: true + configMap: + create: false + name: "grafana-alloy-configmap-staging" + key: "config.river" + envFrom: + - secretRef: + name: grafana-cloud-secret-staging + - secretRef: + name: redis-secret-staging + extraEnv: + - name: CLUSTER_NAME + value: "eks-staging" + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + extraPorts: + - name: zipkin + port: 9411 + targetPort: 9411 + - name: loki + port: 3100 + targetPort: 3100 + crds: + create: true + controller: + type: "daemonset" + podLabels: + app: *name + environment: *environment + nodeSelector: + openvsx-production-alloy: null + fullnameOverride: grafana-alloy-staging + namespaceOverride: *namespace + +clamav: + enabled: true + name: "clamav" + replicas: 3 + persistence: + storageClass: "gp3" + image: + repository: "ghcr.io/eclipsefdn/clamav-rest-new" + tag: "v0.1.1" + pullPolicy: Always + resources: + requests: + cpu: 2 + memory: 4Gi + limits: + cpu: 4 + memory: 6Gi + service: + port: 9000 + env: + MAX_UPLOAD_SIZE_MB: 512 + MAX_EXTRACTED_SIZE_MB: 512 + MAX_FILE_COUNT: 100000 + MAX_SINGLE_FILE_MB: 300 + MAX_RECURSION: 16 + MAX_THREADS: 4 + SCAN_TIMEOUT_MINUTES: 5 + +yara: + enabled: true + name: "yara" + replicas: 1 + image: + repository: "ghcr.io/eclipsefdn/yara-rest" + tag: "v0.1.0" + pullPolicy: Always + resources: + requests: + cpu: 1 + memory: 1Gi + limits: + cpu: 2 + memory: 2Gi + service: + port: 9001 + env: + MAX_UPLOAD_SIZE_MB: 512 + MAX_EXTRACTED_SIZE_MB: 1024 + MAX_FILE_COUNT: 100000 + MAX_SINGLE_FILE_MB: 300 + MAX_RECURSION: 0 + SCAN_TIMEOUT_MINUTES: 5 diff --git a/charts/openvsx/values-staging.yaml b/charts/openvsx/values-staging.yaml index e95ae76c1..fae101611 100644 --- a/charts/openvsx/values-staging.yaml +++ b/charts/openvsx/values-staging.yaml @@ -8,6 +8,8 @@ host: staging.open-vsx.org replicaCount: 1 esReplicaCount: 1 +autoscaling: + enabled: false image: repository: ghcr.io/eclipsefdn/openvsx-website @@ -15,6 +17,9 @@ image: # Overrides the image tag whose default is the chart appVersion. tag: 6d777ca-570 +eks: + enabled: false + website: jvmArgs: > -Dspring.datasource.hikari.maximum-pool-size=5 diff --git a/charts/openvsx/values-test.yaml b/charts/openvsx/values-test.yaml index 2e780fb7b..e623a66ad 100644 --- a/charts/openvsx/values-test.yaml +++ b/charts/openvsx/values-test.yaml @@ -8,6 +8,8 @@ host: test.open-vsx.org replicaCount: 1 esReplicaCount: 1 +autoscaling: + enabled: false image: repository: ghcr.io/eclipsefdn/openvsx-website diff --git a/charts/openvsx/values.yaml b/charts/openvsx/values.yaml index 1a7b96365..a588f5298 100644 --- a/charts/openvsx/values.yaml +++ b/charts/openvsx/values.yaml @@ -8,6 +8,8 @@ host: open-vsx.org replicaCount: 6 esReplicaCount: 3 +autoscaling: + enabled: false image: repository: ghcr.io/eclipsefdn/openvsx-website @@ -15,6 +17,9 @@ image: # Overrides the image tag whose default is the chart appVersion. tag: 97e1417-99 +eks: + enabled: false + website: jvmArgs: > -Xms4G -Xmx6G @@ -122,7 +127,7 @@ clamav: replicas: 1 image: repository: "ghcr.io/eclipsefdn/clamav-rest-new" - tag: "v0.1.1" + tag: "v0.1.2" pullPolicy: Always resources: requests: @@ -148,7 +153,7 @@ yara: replicas: 1 image: repository: "ghcr.io/eclipsefdn/yara-rest" - tag: "v0.1.0" + tag: "v0.1.1" pullPolicy: Always resources: requests: diff --git a/configuration/application.yml b/configuration/application.yml index a33e1a600..0a2a9eece 100644 --- a/configuration/application.yml +++ b/configuration/application.yml @@ -29,8 +29,9 @@ server: min-response-size: 1024 jetty: threads: - max-queue-capacity: 100 - connection-idle-timeout: 10000 + max: 450 + max-queue-capacity: 50 + connection-idle-timeout: 65000 spring: application: name: openvsx-server @@ -134,7 +135,7 @@ ovsx: cdn: enabled: true services: - aws: https://openvsx-staging.eclipsecontent.org/ + aws: https://openvsx.eclipsecontent.org/ migration: enabled: false primary-service: aws @@ -237,7 +238,7 @@ ovsx: # Shared archive limits for all scanning checks (secret detection, blocklist, etc.) max-archive-size-bytes: 1073741824 # 1 GB total archive limit - max-single-file-bytes: 268435456 # 256 MB per-file limit + max-single-file-bytes: 536870912 # 512 MB per-file limit max-entry-count: 100000 # Max ZIP entries to process blocklist-check: enabled: true @@ -306,6 +307,7 @@ ovsx: file-field: "file" response: format: json + error-path: "$.error" # Our wrapper returns: { status, threats[], scanned_files, scan_time_ms } threats-path: "$.threats[*]" threat-mapping: @@ -347,6 +349,7 @@ ovsx: file-field: "file" response: format: json + error-path: "$.error" # Matches are returned as an array threats-path: "$.matches[*]" threat-mapping: diff --git a/kubernetes/README.md b/kubernetes/README.md index 72247ae2c..2e79c571a 100644 --- a/kubernetes/README.md +++ b/kubernetes/README.md @@ -1,3 +1,9 @@ +## How to deploy aws-staging instance for a given image? + +```bash +./helm-deploy.sh aws-staging +``` + ## How to deploy staging instance for a given image? ```bash diff --git a/kubernetes/helm-deploy.sh b/kubernetes/helm-deploy.sh index 128c82c94..97efa3a7a 100755 --- a/kubernetes/helm-deploy.sh +++ b/kubernetes/helm-deploy.sh @@ -30,7 +30,7 @@ image_tag="${2:-}" # check that environment is not empty if [[ -z "${environment}" ]]; then - printf "ERROR: an environment ('test', 'staging' or 'production') must be given.\n" + printf "ERROR: an environment ('test', 'staging', 'aws-staging' or 'production') must be given.\n" exit 1 fi @@ -44,6 +44,10 @@ if [[ "${environment}" == "staging" ]]; then values_file="${ROOT_DIR}/charts/${chart_name}/values-staging.yaml" release_name="${release_name_staging}" namespace="${namespace_staging}" +elif [[ "${environment}" == "aws-staging" ]]; then + values_file="${ROOT_DIR}/charts/${chart_name}/values-aws-staging.yaml" + release_name="${release_name_staging}" + namespace="${namespace_staging}" elif [[ "${environment}" == "test" ]]; then values_file="${ROOT_DIR}/charts/${chart_name}/values-test.yaml" release_name="${release_name_test}" @@ -52,11 +56,11 @@ elif [[ "${environment}" == "production" ]]; then values_file="${ROOT_DIR}/charts/${chart_name}/values.yaml" release_name="${release_name_production}" else - printf "ERROR: Unknown environment. Only 'test', 'staging' or 'production' are supported.\n" + printf "ERROR: Unknown environment. Only 'test', 'staging', 'aws-staging' or 'production' are supported.\n" exit 1 fi -chmod 600 "${KUBECONFIG}" +#chmod 600 "${KUBECONFIG}" export HELM_CACHE_HOME="${ROOT_DIR}/.helm/cache" export HELM_CONFIG_HOME="${ROOT_DIR}/.helm/config" @@ -68,5 +72,7 @@ mkdir -p "${HELM_DATA_HOME}" helm version helm repo add grafana https://grafana.github.io/helm-charts +helm repo add postgresql-ha https://charts.bitnami.com/bitnami +helm repo add eks https://aws.github.io/eks-charts helm dependency build "${ROOT_DIR}/charts/openvsx" -helm upgrade --install "${release_name}" "${ROOT_DIR}/charts/openvsx" -f "${values_file}" --set image.tag="${image_tag}" --namespace "${namespace}" +helm upgrade --install "${release_name}" "${ROOT_DIR}/charts/openvsx" -f "${values_file}" --set image.tag="${image_tag}" --namespace "${namespace}" --create-namespace diff --git a/website/package.json b/website/package.json index 3360c50cb..6df5ba9be 100644 --- a/website/package.json +++ b/website/package.json @@ -10,7 +10,7 @@ }, "type": "module", "dependencies": { - "openvsx-webui": "^0.20.2" + "openvsx-webui": "^0.20.3" }, "resolutions": { "qs": "^6.14.1" diff --git a/website/yarn.lock b/website/yarn.lock index 1d03f8bf3..7ed2839a6 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -2091,13 +2091,13 @@ __metadata: linkType: hard "axios@npm:^1": - version: 1.15.0 - resolution: "axios@npm:1.15.0" + version: 1.16.0 + resolution: "axios@npm:1.16.0" dependencies: - follow-redirects: "npm:^1.15.11" + follow-redirects: "npm:^1.16.0" form-data: "npm:^4.0.5" proxy-from-env: "npm:^2.1.0" - checksum: 10/d39a2c0ebc7ff4739401b282e726cc2673377949d6c46d60eb619458f8d7a2f7eadbcada7097f4dbc7d5c59abb4d3bf6fac33d474412bc3415d3f5aa7ed45530 + checksum: 10/cf8b521ff732c21550b38c8739aef556ea5e14b268468bb89e4307416ab262b462e582474e810963a3d61c2392ab47ad35c11d05eff027de7c97113bc7411623 languageName: node linkType: hard @@ -3205,7 +3205,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.15.11": +"follow-redirects@npm:^1.16.0": version: 1.16.0 resolution: "follow-redirects@npm:1.16.0" peerDependenciesMeta: @@ -3591,9 +3591,9 @@ __metadata: linkType: hard "ip-address@npm:^10.0.1": - version: 10.1.0 - resolution: "ip-address@npm:10.1.0" - checksum: 10/a6979629d1ad9c1fb424bc25182203fad739b40225aebc55ec6243bbff5035faf7b9ed6efab3a097de6e713acbbfde944baacfa73e11852bb43989c45a68d79e + version: 10.2.0 + resolution: "ip-address@npm:10.2.0" + checksum: 10/12fec399e1af5753ac322e47a6d81a50d3a528b3abb17c09525b2a2edcaedcca628c40520706f7037bc4d8e951b0296c47e7b86d0a8e6e2335c8f0ba4afcfac1 languageName: node linkType: hard @@ -4415,7 +4415,7 @@ __metadata: eslint: "npm:^9.39.0" eslint-config-prettier: "npm:^10.1.8" eslint-plugin-react: "npm:^7.37.0" - openvsx-webui: "npm:^0.20.2" + openvsx-webui: "npm:^0.20.3" prettier: "npm:^3.8.1" rollup-plugin-visualizer: "npm:^7.0.1" typescript: "npm:^5.9.0" @@ -4439,9 +4439,9 @@ __metadata: languageName: node linkType: hard -"openvsx-webui@npm:^0.20.2": - version: 0.20.2 - resolution: "openvsx-webui@npm:0.20.2" +"openvsx-webui@npm:^0.20.3": + version: 0.20.3 + resolution: "openvsx-webui@npm:0.20.3" dependencies: "@emotion/react": "npm:^11.11.1" "@emotion/styled": "npm:^11.11.0" @@ -4471,7 +4471,7 @@ __metadata: react-infinite-scroller: "npm:^1.2.6" react-router: "npm:^6.30.3" react-router-dom: "npm:^6.30.3" - checksum: 10/e79dec1e2376ef68d767abffc0908b02778be98ef90fa9ed462d7eb3f1e16bd7daf35ae2764b6ab46b9588c94e9b6f1f959827ac44084b9c5815deb0e77eafbc + checksum: 10/76877a3dd692c117835b60f9782f0df8d7b0501596a482fc35367d8dd39b46fac50223779e774f21590e892f0dffae3e416b7f5f964836b5f5728a4eb3f4649e languageName: node linkType: hard