diff --git a/.vscode/settings.json b/.vscode/settings.json index 53fccd6..f302235 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,10 +6,10 @@ "files.trimTrailingWhitespace": true, "sops.defaults.ageKeyFile": "age.key", "vs-kubernetes": { - "vs-kubernetes.kubeconfig": "./kubeconfig", + "vs-kubernetes.kubeconfig": "/home/laur/dev/ai/ops/homelab/kubeconfig", "vs-kubernetes.knownKubeconfigs": [ - "./kubeconfig" - ] + "/home/laur/dev/ai/ops/homelab/kubeconfig" + ] }, "yaml.schemaStore.enable": true, "yaml.schemas": { diff --git a/kubernetes/apps/database-system/dragonfly-operator/app.ks.yaml b/kubernetes/apps/database-system/dragonfly-operator/app.ks.yaml new file mode 100644 index 0000000..e69de29 diff --git a/kubernetes/apps/default/homepage/ks.yaml b/kubernetes/apps/default/homepage/ks.yaml new file mode 100644 index 0000000..83093f8 --- /dev/null +++ b/kubernetes/apps/default/homepage/ks.yaml @@ -0,0 +1 @@ +# TODO: Fix this via homelab-u3p: Install homepage dashboard [dashboard, deployment, homepage] \ No newline at end of file diff --git a/kubernetes/apps/default/publish-k8s-schemas/app/externalsecrets.yaml b/kubernetes/apps/default/publish-k8s-schemas/app/externalsecrets.yaml new file mode 100644 index 0000000..6266c7d --- /dev/null +++ b/kubernetes/apps/default/publish-k8s-schemas/app/externalsecrets.yaml @@ -0,0 +1 @@ +# TODO: see implementation of external secrets \ No newline at end of file diff --git a/kubernetes/apps/default/publish-k8s-schemas/app/helmrelease.yaml b/kubernetes/apps/default/publish-k8s-schemas/app/helmrelease.yaml new file mode 100644 index 0000000..d5ea3f4 --- /dev/null +++ b/kubernetes/apps/default/publish-k8s-schemas/app/helmrelease.yaml @@ -0,0 +1,130 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrelease-helm-v2.json +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: &app publish-k8s-schemas +spec: + interval: 1h + chartRef: + kind: OCIRepository + name: app-template + values: + controllers: + *app : + type: cronjob + cronjob: + backoffLimit: 0 + concurrencyPolicy: 'Replace' + failedJobsHistory: 1 + schedule: '0 */4 * * *' + successfulJobsHistory: 0 + + initContainers: + generate-schemas: + image: + repository: ghcr.io/bjw-s-labs/k8s-crd-extractor + tag: 2025.12.22@sha256:176cc556053abba6fda83eeb398531cd33c3092553cab8a49a736f68972c057b + command: [/usr/bin/catatonit, --, sh] + args: + - -c + - /app/crd-extractor.sh && exec sh /config/map/generate-index.sh + resources: + requests: + cpu: 10m + memory: 128Mi + limits: + memory: 2Gi + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: { drop: [ALL] } + + containers: + app: + image: + repository: ghcr.io/bjw-s-labs/wrangler + tag: 4.63.0@sha256:1e9dc1c872a6e9cc84ccfc50704c7a2fdfec1f8c8e28672dd7c083a008e4bf39 + envFrom: + - secretRef: + name: *app + args: + - pages + - deploy + - /data/crdSchemas + - --project-name + - kubernetes-schemas + resources: + requests: + cpu: 10m + memory: 128Mi + limits: + memory: 1Gi + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: { drop: [ALL] } + defaultPodOptions: + restartPolicy: OnFailure + securityContext: + runAsGroup: 65534 + runAsNonRoot: true + runAsUser: 65534 + + persistence: + tmpfs: + type: emptyDir + advancedMounts: + *app : + generate-schemas: + - path: /config/.datree + subPath: data + - path: /tmp + subPath: tmp + app: + - path: /config + subPath: config + - path: /data + subPath: data + config: + type: configMap + name: *app + advancedMounts: + *app : + generate-schemas: + - path: /config/map + readOnly: true + + serviceAccount: + *app : {} + + rbac: + roles: + *app : + type: ClusterRole + rules: + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + - customresourcedefinitions/status + verbs: + - get + - list + - watch + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + - apiservices/status + verbs: + - get + - list + - watch + bindings: + *app : + type: ClusterRoleBinding + roleRef: + identifier: *app + subjects: + - identifier: *app \ No newline at end of file diff --git a/kubernetes/apps/default/publish-k8s-schemas/app/kustomization.yaml b/kubernetes/apps/default/publish-k8s-schemas/app/kustomization.yaml new file mode 100644 index 0000000..e69de29 diff --git a/kubernetes/apps/default/publish-k8s-schemas/app/resources/generate-index.sh b/kubernetes/apps/default/publish-k8s-schemas/app/resources/generate-index.sh new file mode 100644 index 0000000..9f538c6 --- /dev/null +++ b/kubernetes/apps/default/publish-k8s-schemas/app/resources/generate-index.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +cd /config/.datree/crdSchemas/ + +echo "creating index" + +# Count stats +group_count=$(find . -maxdepth 1 -type d | wc -l) +group_count=$((group_count - 1)) +schema_count=$(find . -name "*.json" | wc -l) +updated=$(date -u +"%Y-%m-%d") + +echo "groups: $group_count - schemas: $schema_count" + +# Generate schema cards HTML +schemas_html="" +for dir in */; do + dir_name="${dir%/}" + file_count=$(find "$dir" -maxdepth 1 -name "*.json" | wc -l) + files_html="" + for file in "$dir"*.json; do + if [ -f "$file" ]; then + filename=$(basename "$file") + files_html="${files_html}${filename}" + fi + done + schemas_html="${schemas_html}
${dir_name}${file_count}
${files_html}
" +done + +# Copy template and inject data +cp /config/map/index.html index.html +sed -i "s||${schemas_html}|g" index.html +sed -i "s|
-
|
${group_count}
|g" index.html +sed -i "s|
-
|
${schema_count}
|g" index.html +sed -i "s|
-
|
${updated}
|g" index.html + +echo "index created" \ No newline at end of file diff --git a/kubernetes/apps/default/publish-k8s-schemas/app/resources/index.html b/kubernetes/apps/default/publish-k8s-schemas/app/resources/index.html new file mode 100644 index 0000000..1a67a77 --- /dev/null +++ b/kubernetes/apps/default/publish-k8s-schemas/app/resources/index.html @@ -0,0 +1,391 @@ + + + + + + + Kubernetes Schemas | tholinka.dev + + + + + +
+
+ +

Kubernetes Schemas

+

CRD JSON schemas from the tholinka.dev cluster

+
+ +
+

Usage

+
+ # yaml-language-server: $schema=https://schemas.tholinka.dev/{group}/{kind}_{version}.json +
+
+ +
+ +
+ +
+
+
-
+
API Groups
+
+
+
-
+
Schemas
+
+
+
-
+
Last Updated
+
+
+ +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/kubernetes/apps/default/publish-k8s-schemas/ks.yaml b/kubernetes/apps/default/publish-k8s-schemas/ks.yaml new file mode 100644 index 0000000..41df6ea --- /dev/null +++ b/kubernetes/apps/default/publish-k8s-schemas/ks.yaml @@ -0,0 +1,20 @@ +--- +# yaml-language-server: $schema=https://schemas.tholinka.dev/kustomize.toolkit.fluxcd.io/kustomization_v1.json +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: publish-k8s-schemas + namespace: &namespace self-hosted +spec: + interval: 1h + path: ./kubernetes/apps/self-hosted/publish-k8s-schemas/app + postBuild: + substituteFrom: + - name: cluster-secrets + kind: Secret + prune: true + sourceRef: + kind: GitRepository + name: flux-system + namespace: flux-system + targetNamespace: *namespace \ No newline at end of file diff --git a/kubernetes/apps/observability/grafana/instance.ks.yaml b/kubernetes/apps/observability/grafana/instance.ks.yaml new file mode 100644 index 0000000..257dde9 --- /dev/null +++ b/kubernetes/apps/observability/grafana/instance.ks.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: grafana-instance +spec: + path: ./kubernetes/apps/monitoring-system/grafana/instance + sourceRef: + kind: GitRepository + name: flux-system + namespace: flux-system + targetNamespace: monitoring-system + interval: 10m + prune: true + wait: true + dependsOn: + #? wait for the 1password-connect secret store to be ready + - name: 1password-connect + namespace: security-system + - name: grafana-operator + - name: envoy-gateway + namespace: network-system + - name: openebs + namespace: storage-system \ No newline at end of file diff --git a/kubernetes/apps/observability/grafana/instance/admin.externalsecret.yaml b/kubernetes/apps/observability/grafana/instance/admin.externalsecret.yaml new file mode 100644 index 0000000..ed2ab71 --- /dev/null +++ b/kubernetes/apps/observability/grafana/instance/admin.externalsecret.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: grafana-admin-password-secret +spec: + refreshInterval: 1h + + secretStoreRef: + name: onepassword + kind: ClusterSecretStore + + target: + name: grafana-admin-password-secret + creationPolicy: Owner + + data: + - secretKey: GF_SECURITY_ADMIN_PASSWORD + remoteRef: + key: Grafana Admin + property: password \ No newline at end of file diff --git a/kubernetes/apps/observability/grafana/instance/data-sources.yaml b/kubernetes/apps/observability/grafana/instance/data-sources.yaml new file mode 100644 index 0000000..6de8ebf --- /dev/null +++ b/kubernetes/apps/observability/grafana/instance/data-sources.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDatasource +metadata: + name: prometheus +spec: + instanceSelector: + matchLabels: + grafana.internal/instance: grafana + + datasource: + type: prometheus + name: prometheus + access: proxy + isDefault: true + url: http://prometheus-operated:9090 + +--- +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDatasource +metadata: + name: alertmanager +spec: + instanceSelector: + matchLabels: + grafana.internal/instance: grafana + + datasource: + type: alertmanager + name: alertmanager + access: proxy + jsonData: + implementation: prometheus + url: http://alertmanager-operated:9093 \ No newline at end of file diff --git a/kubernetes/apps/observability/grafana/instance/grafana.yaml b/kubernetes/apps/observability/grafana/instance/grafana.yaml new file mode 100644 index 0000000..642363e --- /dev/null +++ b/kubernetes/apps/observability/grafana/instance/grafana.yaml @@ -0,0 +1,75 @@ +--- +apiVersion: grafana.integreatly.org/v1beta1 +kind: Grafana +metadata: + name: grafana + labels: + grafana.internal/instance: grafana + +spec: + config: + analytics: + check_for_updates: "false" + check_for_plugin_updates: "false" + feedback_links_enabled: "false" + reporting_enabled: "false" + + server: + enable_gzip: "true" + root_url: https://grafana.admin.mirceanton.com + + auth: {disable_login_form: "false"} + auth.anonymous: {enabled: "true"} + metrics: {enabled: "true"} + news: {news_feed_enabled: "false"} + plugins: {plugin_admin_enabled: "false"} + security: {angular_support_enabled: "true"} + + deployment: + spec: + strategy: + type: Recreate + template: + spec: + containers: + - name: grafana + env: + - name: GF_SECURITY_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: grafana-admin-password-secret + key: GF_SECURITY_ADMIN_PASSWORD + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: {drop: ["ALL"]} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + volumes: + - name: grafana-data + persistentVolumeClaim: + claimName: grafana-pvc + + httpRoute: + spec: + hostnames: ["grafana.admin.mirceanton.com"] + parentRefs: + - name: envoy-admin + namespace: network-system + rules: + - backendRefs: + - name: grafana-service + port: 3000 + + persistentVolumeClaim: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 10Gi + storageClassName: openebs-hostpath + disableDefaultSecurityContext: All \ No newline at end of file diff --git a/kubernetes/apps/observability/grafana/instance/kustomization.yaml b/kubernetes/apps/observability/grafana/instance/kustomization.yaml new file mode 100644 index 0000000..4799cfc --- /dev/null +++ b/kubernetes/apps/observability/grafana/instance/kustomization.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + #- ./admin.externalsecret.yaml + - ./data-sources.yaml + - ./grafana.yaml + - ./service-monitor.yaml \ No newline at end of file diff --git a/kubernetes/apps/observability/grafana/instance/service-monitor.yaml b/kubernetes/apps/observability/grafana/instance/service-monitor.yaml new file mode 100644 index 0000000..03ebc8d --- /dev/null +++ b/kubernetes/apps/observability/grafana/instance/service-monitor.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: grafana +spec: + jobLabel: grafana + + endpoints: + - port: grafana + path: /metrics + honorLabels: true + + namespaceSelector: + matchNames: ["monitoring-system"] + + selector: + matchLabels: + grafana.internal/instance: grafana \ No newline at end of file diff --git a/kubernetes/apps/observability/grafana/kustomization.yaml b/kubernetes/apps/observability/grafana/kustomization.yaml new file mode 100644 index 0000000..74ee524 --- /dev/null +++ b/kubernetes/apps/observability/grafana/kustomization.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: [] + #- ./operator.ks.yaml + #- ./instance.ks.yaml \ No newline at end of file diff --git a/kubernetes/apps/observability/grafana/operator.ks.yaml b/kubernetes/apps/observability/grafana/operator.ks.yaml new file mode 100644 index 0000000..91ef38b --- /dev/null +++ b/kubernetes/apps/observability/grafana/operator.ks.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: grafana-operator +spec: + path: ./kubernetes/apps/monitoring-system/grafana/operator + sourceRef: + kind: GitRepository + name: flux-system + namespace: flux-system + targetNamespace: monitoring-system + interval: 10m + prune: true + wait: true \ No newline at end of file diff --git a/kubernetes/apps/observability/grafana/operator/grafana-dashboard.yaml b/kubernetes/apps/observability/grafana/operator/grafana-dashboard.yaml new file mode 100644 index 0000000..03ca540 --- /dev/null +++ b/kubernetes/apps/observability/grafana/operator/grafana-dashboard.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: grafana-operator +spec: + allowCrossNamespaceImport: true + instanceSelector: + matchLabels: + grafana.internal/instance: grafana + datasources: + - datasourceName: prometheus + inputName: DS_PROMETHEUS + configMapRef: + name: grafana-operator-dashboard + key: grafana-operator.json \ No newline at end of file diff --git a/kubernetes/apps/observability/grafana/operator/helm-release.yaml b/kubernetes/apps/observability/grafana/operator/helm-release.yaml new file mode 100644 index 0000000..f983012 --- /dev/null +++ b/kubernetes/apps/observability/grafana/operator/helm-release.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: grafana-operator +spec: + interval: 10m + chartRef: + kind: OCIRepository + name: grafana-operator + + values: + replicas: 1 + resources: + requests: + cpu: 20m + memory: 32Mi + limits: + memory: 64Mi + + serviceMonitor: {enabled: true} + dashboard: {enabled: true} + + maxConcurrentReconciles: 4 + logging: + level: info + encoder: json \ No newline at end of file diff --git a/kubernetes/apps/observability/grafana/operator/oci-repository.yaml b/kubernetes/apps/observability/grafana/operator/oci-repository.yaml new file mode 100644 index 0000000..ed34ec0 --- /dev/null +++ b/kubernetes/apps/observability/grafana/operator/oci-repository.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: grafana-operator +spec: + interval: 15m + url: oci://ghcr.io/grafana/helm-charts/grafana-operator + ref: {tag: 5.21.4} + + layerSelector: + mediaType: application/vnd.cncf.helm.chart.content.v1.tar+gzip + operation: copy \ No newline at end of file diff --git a/kubernetes/apps/observability/headlamp/app.ks.yaml b/kubernetes/apps/observability/headlamp/app.ks.yaml new file mode 100644 index 0000000..2089636 --- /dev/null +++ b/kubernetes/apps/observability/headlamp/app.ks.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/kustomization-kustomize-v1.json +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: &app headlamp +spec: + commonMetadata: + labels: + app.kubernetes.io/name: *app + path: ./kubernetes/apps/observability/headlamp/app + prune: true + sourceRef: + kind: GitRepository + name: flux-system + namespace: flux-system + interval: 1h + retryInterval: 2m + timeout: 5m + + # TODO: Add OAuth integration. \ No newline at end of file diff --git a/kubernetes/apps/observability/headlamp/app/helmrelease.yaml b/kubernetes/apps/observability/headlamp/app/helmrelease.yaml new file mode 100644 index 0000000..e69de29 diff --git a/kubernetes/apps/observability/headlamp/app/httproute.yaml b/kubernetes/apps/observability/headlamp/app/httproute.yaml new file mode 100644 index 0000000..1c413c1 --- /dev/null +++ b/kubernetes/apps/observability/headlamp/app/httproute.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + labels: + app.kubernetes.io/instance: headlamp + app.kubernetes.io/name: headlamp + app.kubernetes.io/part-of: headlamp + name: headlamp +spec: + hostnames: + - headlamp.kantai.xyz + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: envoy-internal + namespace: network + rules: + - backendRefs: + - name: headlamp + port: 80 \ No newline at end of file diff --git a/kubernetes/apps/observability/headlamp/app/kustomization.yaml b/kubernetes/apps/observability/headlamp/app/kustomization.yaml new file mode 100644 index 0000000..e69de29 diff --git a/kubernetes/apps/observability/headlamp/app/ocirepository.yaml b/kubernetes/apps/observability/headlamp/app/ocirepository.yaml new file mode 100644 index 0000000..e3924ad --- /dev/null +++ b/kubernetes/apps/observability/headlamp/app/ocirepository.yaml @@ -0,0 +1,19 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/source.toolkit.fluxcd.io/ocirepository_v1.json +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: headlamp +spec: + interval: 1h + layerSelector: + mediaType: application/vnd.cncf.helm.chart.content.v1.tar+gzip + operation: copy + ref: + tag: 0.40.0 + url: oci://ghcr.io/home-operations/charts-mirror/headlamp + verify: + provider: cosign + matchOIDCIdentity: + - issuer: ^https://token.actions.githubusercontent.com$ + subject: ^https://github.com/home-operations/charts-mirror.*$ \ No newline at end of file diff --git a/kubernetes/apps/observability/headlamp/kustomization.yaml b/kubernetes/apps/observability/headlamp/kustomization.yaml new file mode 100644 index 0000000..bffe7fc --- /dev/null +++ b/kubernetes/apps/observability/headlamp/kustomization.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ./app.ks.yaml \ No newline at end of file diff --git a/kubernetes/apps/observability/kube-prometheus-stack/app.ks.yaml b/kubernetes/apps/observability/kube-prometheus-stack/app.ks.yaml new file mode 100644 index 0000000..e91fc46 --- /dev/null +++ b/kubernetes/apps/observability/kube-prometheus-stack/app.ks.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: kube-prometheus-stack +spec: + path: ./kubernetes/apps/monitoring-system/kube-prometheus-stack/app + sourceRef: + kind: GitRepository + name: flux-system + namespace: flux-system + targetNamespace: monitoring-system + interval: 10m + prune: true + wait: true + dependsOn: + - name: openebs + namespace: storage-system + - name: envoy-gateway + namespace: network-system \ No newline at end of file diff --git a/kubernetes/apps/observability/kube-prometheus-stack/app/grafana-dashboards.yaml b/kubernetes/apps/observability/kube-prometheus-stack/app/grafana-dashboards.yaml new file mode 100644 index 0000000..7ffdd7d --- /dev/null +++ b/kubernetes/apps/observability/kube-prometheus-stack/app/grafana-dashboards.yaml @@ -0,0 +1,143 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/grafana.integreatly.org/grafanadashboard_v1beta1.json +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: kubernetes-api-server +spec: + allowCrossNamespaceImport: true + instanceSelector: + matchLabels: + grafana.internal/instance: grafana + datasources: + - datasourceName: prometheus + inputName: DS_PROMETHEUS + url: https://grafana.com/api/dashboards/15761/revisions/20/download + +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/grafana.integreatly.org/grafanadashboard_v1beta1.json +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: kubernetes-coredns +spec: + allowCrossNamespaceImport: true + instanceSelector: + matchLabels: + grafana.internal/instance: grafana + datasources: + - datasourceName: prometheus + inputName: DS_PROMETHEUS + url: https://grafana.com/api/dashboards/15762/revisions/22/download + +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/grafana.integreatly.org/grafanadashboard_v1beta1.json +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: kubernetes-global +spec: + allowCrossNamespaceImport: true + instanceSelector: + matchLabels: + grafana.internal/instance: grafana + datasources: + - datasourceName: prometheus + inputName: DS_PROMETHEUS + url: https://grafana.com/api/dashboards/15757/revisions/43/download + +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/grafana.integreatly.org/grafanadashboard_v1beta1.json +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: kubernetes-namespaces +spec: + allowCrossNamespaceImport: true + instanceSelector: + matchLabels: + grafana.internal/instance: grafana + datasources: + - datasourceName: prometheus + inputName: DS_PROMETHEUS + url: https://grafana.com/api/dashboards/15758/revisions/44/download + +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/grafana.integreatly.org/grafanadashboard_v1beta1.json +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: kubernetes-nodes +spec: + allowCrossNamespaceImport: true + instanceSelector: + matchLabels: + grafana.internal/instance: grafana + datasources: + - datasourceName: prometheus + inputName: DS_PROMETHEUS + url: https://grafana.com/api/dashboards/15759/revisions/40/download + +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/grafana.integreatly.org/grafanadashboard_v1beta1.json +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: kubernetes-pods +spec: + allowCrossNamespaceImport: true + instanceSelector: + matchLabels: + grafana.internal/instance: grafana + datasources: + - datasourceName: prometheus + inputName: DS_PROMETHEUS + url: https://grafana.com/api/dashboards/15760/revisions/37/download + +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/grafana.integreatly.org/grafanadashboard_v1beta1.json +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: kubernetes-volumes +spec: + allowCrossNamespaceImport: true + instanceSelector: + matchLabels: + grafana.internal/instance: grafana + datasources: + - datasourceName: prometheus + inputName: DS_PROMETHEUS + url: https://grafana.com/api/dashboards/11454/revisions/14/download + +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/grafana.integreatly.org/grafanadashboard_v1beta1.json +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: node-exporter-full +spec: + allowCrossNamespaceImport: true + instanceSelector: + matchLabels: + grafana.internal/instance: grafana + datasources: + - datasourceName: prometheus + inputName: DS_PROMETHEUS + url: https://grafana.com/api/dashboards/1860/revisions/42/download + +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/grafana.integreatly.org/grafanadashboard_v1beta1.json +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: prometheus +spec: + allowCrossNamespaceImport: true + instanceSelector: + matchLabels: + grafana.internal/instance: grafana + datasources: + - datasourceName: prometheus + inputName: DS_PROMETHEUS + url: https://grafana.com/api/dashboards/19105/revisions/8/download \ No newline at end of file diff --git a/kubernetes/apps/observability/kube-prometheus-stack/app/helm-release.yaml b/kubernetes/apps/observability/kube-prometheus-stack/app/helm-release.yaml new file mode 100644 index 0000000..8028bc6 --- /dev/null +++ b/kubernetes/apps/observability/kube-prometheus-stack/app/helm-release.yaml @@ -0,0 +1,208 @@ +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: kube-prometheus-stack +spec: + interval: 10m + chartRef: + kind: OCIRepository + name: kube-prometheus-stack + + values: + crds: {enabled: true} + cleanPrometheusOperatorObjectNames: true + + # ========================================================================== + # Alertmanager + # ========================================================================== + alertmanager: + enabled: true + route: + main: + enabled: true + hostnames: ["alertmanager.admin.mirceanton.com"] + parentRefs: + - name: envoy-admin + namespace: network-system + + alertmanagerSpec: + # alertmanagerConfiguration: {name: alertmanager} + # ======================================= + # App Settings + # ======================================= + externalUrl: "https://alertmanager.admin.mirceanton.com" + logFormat: json + logLevel: info + + # ======================================= + # Resources + # ======================================= + replicas: 1 + resources: + requests: + cpu: 20m + memory: 32Mi + limits: + memory: 128Mi + storage: + volumeClaimTemplate: + spec: + storageClassName: openebs-hostpath + resources: + requests: + storage: 1Gi + + # ========================================================================== + # Prometheus Operator + # ========================================================================== + prometheusOperator: + enabled: true + # ======================================= + # App Settings + # ======================================= + logFormat: json + logLevel: info + + # ======================================= + # Resources + # ======================================= + resources: + requests: + cpu: 20m + memory: 64Mi + limits: + memory: 128Mi + + # ========================================================================== + # Prometheus + # ========================================================================== + prometheus: + enabled: true + route: + main: + enabled: true + hostnames: ["prometheus.admin.mirceanton.com"] + parentRefs: + - name: envoy-admin + namespace: network-system + + prometheusSpec: + # ======================================= + # App Settings + # ======================================= + externalUrl: "https://prometheus.admin.mirceanton.com" + enableAdminAPI: true + retention: 14d + retentionSize: 50GB + logLevel: info + logFormat: json + + # ======================================= + #? Replace default Prometheus image with prompp and + #? override 'unsupported Prometheus version' error + # ======================================= + version: v2.55.1 + image: + registry: mirror.gcr.io + repository: prompp/prompp + tag: 0.7.4 + + # ======================================= + # Security + # ======================================= + securityContext: + runAsNonRoot: true + runAsUser: 64535 + runAsGroup: 64535 + fsGroup: 64535 + + # ======================================= + #? Disable prometheus resource to be created with selectors based on + #? values in the helm deployment if a nil or {} value is provided + # ======================================= + podMonitorSelectorNilUsesHelmValues: false + probeSelectorNilUsesHelmValues: false + ruleSelectorNilUsesHelmValues: false + scrapeConfigSelectorNilUsesHelmValues: false + serviceMonitorSelectorNilUsesHelmValues: false + + # ======================================= + # Resources + # ======================================= + replicas: 1 + shards: 1 + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + memory: 1Gi + storageSpec: + volumeClaimTemplate: + spec: + storageClassName: openebs-hostpath + resources: + requests: + storage: 50Gi + + + # ========================================================================== + # Grafana + # ========================================================================== + grafana: + enabled: false + forceDeployDashboards: true + operator: + dashboardsConfigMapRefEnabled: true + folder: monitoring-system + matchLabels: + grafana.internal/instance: grafana + + # ========================================================================== + # Exporters + # ========================================================================== + coreDns: {enabled: true} + kubelet: {enabled: true} + kubeApiServer: {enabled: true} + kubeControllerManager: {enabled: true} + kubeScheduler: {enabled: true} + kubeProxy: {enabled: true} + kubeEtcd: + enabled: true + service: + selector: + component: kube-apiserver + + nodeExporter: {enabled: true} + prometheus-node-exporter: + resources: + requests: + cpu: 20m + memory: 32Mi + limits: + memory: 64Mi + + kubeStateMetrics: {enabled: true} + kube-state-metrics: + resources: + requests: + cpu: 20m + memory: 64Mi + limits: + memory: 128Mi + + # ========================================================================== + # Additional Settings + # ========================================================================== + additionalPrometheusRulesMap: + oom-rules: + groups: + - name: oom + rules: + - alert: OomKilled + annotations: + summary: Container {{ $labels.container }} in pod {{ $labels.namespace }}/{{ $labels.pod }} has been OOMKilled {{ $value }} times in the last 10 minutes. + expr: (kube_pod_container_status_restarts_total - kube_pod_container_status_restarts_total offset 10m >= 1) and ignoring (reason) min_over_time(kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}[10m]) == 1 + labels: + severity: critical \ No newline at end of file diff --git a/kubernetes/apps/observability/kube-prometheus-stack/app/oci-repository.yaml b/kubernetes/apps/observability/kube-prometheus-stack/app/oci-repository.yaml new file mode 100644 index 0000000..61b41bc --- /dev/null +++ b/kubernetes/apps/observability/kube-prometheus-stack/app/oci-repository.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: kube-prometheus-stack +spec: + interval: 15m + url: oci://ghcr.io/prometheus-community/charts/kube-prometheus-stack + ref: {tag: 81.5.0} + + layerSelector: + mediaType: application/vnd.cncf.helm.chart.content.v1.tar+gzip + operation: copy \ No newline at end of file diff --git a/kubernetes/apps/observability/kube-prometheus-stack/kustomization.yaml b/kubernetes/apps/observability/kube-prometheus-stack/kustomization.yaml new file mode 100644 index 0000000..bffe7fc --- /dev/null +++ b/kubernetes/apps/observability/kube-prometheus-stack/kustomization.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ./app.ks.yaml \ No newline at end of file diff --git a/kubernetes/apps/observability/kustomization.yaml b/kubernetes/apps/observability/kustomization.yaml new file mode 100644 index 0000000..d2cc41e --- /dev/null +++ b/kubernetes/apps/observability/kustomization.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: monitoring-system + +resources: + - ./namespace.yaml + #- ./grafana + #- ./kube-prometheus-stack \ No newline at end of file diff --git a/kubernetes/apps/observability/namespace.yaml b/kubernetes/apps/observability/namespace.yaml new file mode 100644 index 0000000..7fad8e4 --- /dev/null +++ b/kubernetes/apps/observability/namespace.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: _ + annotations: + kustomize.toolkit.fluxcd.io/prune: disabled \ No newline at end of file diff --git a/kubernetes/apps/security/kustomization.yaml b/kubernetes/apps/security/kustomization.yaml new file mode 100644 index 0000000..6cc154c --- /dev/null +++ b/kubernetes/apps/security/kustomization.yaml @@ -0,0 +1,4 @@ +# External secrets should be implemented. +# Most popular is 1password, but it's paid +# https://github.com/tholinka/home-ops implements secrets via bitwarden (which is free) +