Create web server for infinity

This commit is contained in:
dvirlabs 2026-04-21 04:29:12 +03:00
parent 8b837e5b40
commit 8fb9810cc4
11 changed files with 637 additions and 0 deletions

View File

@ -0,0 +1,29 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: gitops-status-server
namespace: argocd
spec:
project: observability-stack
source:
repoURL: ssh://git@gitea-ssh.dev-tools.svc.cluster.local:2222/dvirlabs/observability-stack.git
targetRevision: HEAD
path: charts/gitops-status-server
helm:
valueFiles:
- ../../manifests/gitops-status-server/values.yaml
destination:
server: https://kubernetes.default.svc
namespace: observability-stack
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m

View File

@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

View File

@ -0,0 +1,14 @@
apiVersion: v2
name: gitops-status-server
description: A minimal HTTP server that serves GitOps status information as JSON
type: application
version: 1.0.0
appVersion: "1.25.5"
keywords:
- gitops
- status
- monitoring
- nginx
maintainers:
- name: DevOps Team
home: https://github.com/your-org/observability-stack

View File

@ -0,0 +1,228 @@
# GitOps Status Server Helm Chart
A minimal HTTP server that serves GitOps status information as JSON for monitoring and observability purposes.
## Overview
This chart deploys a lightweight nginx-based server that exposes a single endpoint (`/status.json`) containing GitOps synchronization status, drift information, and changed files. It's designed to be consumed by Grafana's Infinity datasource or other monitoring tools.
## Features
- **Minimal footprint**: Uses nginx-unprivileged with minimal resource requirements
- **Secure by default**: Runs as non-root with read-only root filesystem
- **Internal only**: ClusterIP service for cluster-internal access
- **ConfigMap-based**: JSON content stored in ConfigMap for easy updates
- **ArgoCD compatible**: Automatically rolls deployment when ConfigMap changes
- **Production-ready**: Includes health checks, security contexts, and resource limits
## Installation
### Using Helm
```bash
# Install with default values
helm install gitops-status ./charts/gitops-status-server
# Install with custom namespace
helm install gitops-status ./charts/gitops-status-server -n monitoring --create-namespace
# Install with custom values
helm install gitops-status ./charts/gitops-status-server -f custom-values.yaml
```
### Using ArgoCD
Create an Application manifest:
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: gitops-status-server
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/observability-stack
targetRevision: main
path: charts/gitops-status-server
helm:
values: |
statusJson:
repo: "my-repo"
server: "my-server"
sync_status: "SYNCED"
drift_count: 0
files: []
last_check: "2026-04-21T10:00:00Z"
destination:
server: https://kubernetes.default.svc
namespace: monitoring
syncPolicy:
automated:
prune: true
selfHeal: true
```
## Configuration
### Key Values
| Parameter | Description | Default |
|-----------|-------------|---------|
| `replicaCount` | Number of replicas | `1` |
| `image.repository` | Container image repository | `nginxinc/nginx-unprivileged` |
| `image.tag` | Container image tag | `1.25-alpine` |
| `service.type` | Kubernetes service type | `ClusterIP` |
| `service.port` | Service port | `80` |
| `service.targetPort` | Container target port | `8080` |
| `resources.limits.cpu` | CPU limit | `100m` |
| `resources.limits.memory` | Memory limit | `64Mi` |
| `statusJson` | JSON content to serve | See values.yaml |
### Custom Status JSON
Override the status JSON content in your values:
```yaml
statusJson:
repo: "production-apps"
server: "prod-cluster-01"
sync_status: "SYNCED"
drift_count: 2
files:
- "deployment.yaml"
- "service.yaml"
last_check: "2026-04-21T12:30:00Z"
```
## Usage
### Access the Status Endpoint
From inside the cluster:
```bash
# Using the service DNS name
curl http://gitops-status-server/status.json
# With namespace
curl http://gitops-status-server.monitoring.svc.cluster.local/status.json
```
### Grafana Infinity Datasource Configuration
1. Add an Infinity datasource in Grafana
2. Configure URL: `http://gitops-status-server.monitoring.svc.cluster.local/status.json`
3. Parser: JSON
4. Use fields from the JSON response in your dashboard
Example query fields:
- `sync_status` - Current sync status
- `drift_count` - Number of drifted resources
- `files` - List of changed files
- `last_check` - Timestamp of last check
## Updating Status Data
### Manual Update
Edit the ConfigMap directly:
```bash
kubectl edit configmap gitops-status-server -n monitoring
```
The deployment will automatically roll out with the new content due to the ConfigMap checksum annotation.
### Automated Update via Pipeline
Use `kubectl` in your CI/CD pipeline:
```bash
kubectl create configmap gitops-status-server \
--from-file=status.json=./status.json \
--dry-run=client -o yaml | kubectl apply -f -
```
### ArgoCD Hook (Advanced)
Create a PostSync hook that updates the ConfigMap with current sync status:
```yaml
apiVersion: batch/v1
kind: Job
metadata:
name: update-status
annotations:
argocd.argoproj.io/hook: PostSync
spec:
template:
spec:
containers:
- name: update
image: bitnami/kubectl
command:
- /bin/sh
- -c
- |
# Update status.json with current sync status
kubectl patch configmap gitops-status-server \
--patch '{"data":{"status.json":"..."}}'
restartPolicy: Never
```
## Security Considerations
- Runs as non-root user (UID 101)
- Read-only root filesystem
- No privilege escalation
- Minimal capabilities (all dropped)
- No external network access required
- ClusterIP only (no external exposure)
## Resource Requirements
Minimal resource footprint suitable for small clusters:
- CPU: 50m request / 100m limit
- Memory: 32Mi request / 64Mi limit
## Troubleshooting
### Check pod status
```bash
kubectl get pods -l app.kubernetes.io/name=gitops-status-server
```
### View logs
```bash
kubectl logs -l app.kubernetes.io/name=gitops-status-server
```
### Test endpoint
```bash
kubectl run -it --rm curl --image=curlimages/curl --restart=Never -- \
curl http://gitops-status-server/status.json
```
### Common Issues
**Pod not starting**: Check security context compatibility with your cluster's PSP/PSA policies.
**Empty response**: Verify the ConfigMap is mounted correctly:
```bash
kubectl describe pod -l app.kubernetes.io/name=gitops-status-server
```
**Service not accessible**: Ensure you're accessing from within the cluster and using the correct namespace.
## License
This chart is part of the observability-stack project.
## Maintainers
- DevOps Team

View File

@ -0,0 +1,63 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "gitops-status-server.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "gitops-status-server.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "gitops-status-server.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "gitops-status-server.labels" -}}
helm.sh/chart: {{ include "gitops-status-server.chart" . }}
{{ include "gitops-status-server.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- with .Values.labels }}
{{ toYaml . }}
{{- end }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "gitops-status-server.selectorLabels" -}}
app.kubernetes.io/name: {{ include "gitops-status-server.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "gitops-status-server.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "gitops-status-server.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,19 @@
{{/*
ConfigMap containing the status.json file
This file will be mounted into the nginx container
*/}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "gitops-status-server.fullname" . }}
labels:
{{- include "gitops-status-server.labels" . | nindent 4 }}
{{- with .Values.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
data:
# The status.json file that will be served by nginx
# This can be updated by your GitOps pipeline or ArgoCD hooks
status.json: |
{{- .Values.statusJson | toJson | nindent 4 }}

View File

@ -0,0 +1,103 @@
{{/*
Deployment for the gitops-status-server
Runs nginx-unprivileged to serve the status.json file
*/}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "gitops-status-server.fullname" . }}
labels:
{{- include "gitops-status-server.labels" . | nindent 4 }}
{{- with .Values.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "gitops-status-server.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
# Automatically roll deployment when ConfigMap changes
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "gitops-status-server.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "gitops-status-server.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: nginx
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
securityContext:
{{- toYaml .Values.securityContext | nindent 10 }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
# Health checks
livenessProbe:
httpGet:
path: /status.json
port: http
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /status.json
port: http
initialDelaySeconds: 2
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 2
resources:
{{- toYaml .Values.resources | nindent 10 }}
volumeMounts:
# Mount the status.json file from ConfigMap
# We mount it as a subPath to avoid overwriting the entire directory
- name: status-json
mountPath: /usr/share/nginx/html/status.json
subPath: status.json
readOnly: true
# nginx-unprivileged needs writable directories for cache and run
- name: cache
mountPath: /var/cache/nginx
- name: run
mountPath: /var/run
volumes:
# ConfigMap volume containing the status.json
- name: status-json
configMap:
name: {{ include "gitops-status-server.fullname" . }}
items:
- key: status.json
path: status.json
# Empty directories for nginx runtime
- name: cache
emptyDir: {}
- name: run
emptyDir: {}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@ -0,0 +1,24 @@
{{/*
Service for the gitops-status-server
Exposes the nginx server inside the cluster (ClusterIP)
This allows Grafana to query the status.json endpoint
*/}}
apiVersion: v1
kind: Service
metadata:
name: {{ include "gitops-status-server.fullname" . }}
labels:
{{- include "gitops-status-server.labels" . | nindent 4 }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.targetPort }}
protocol: TCP
name: http
selector:
{{- include "gitops-status-server.selectorLabels" . | nindent 4 }}

View File

@ -0,0 +1,15 @@
{{/*
ServiceAccount for the gitops-status-server
*/}}
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "gitops-status-server.serviceAccountName" . }}
labels:
{{- include "gitops-status-server.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,93 @@
# Default values for gitops-status-server
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# Number of replicas for the deployment
replicaCount: 1
# Container image configuration
image:
# Use nginx-unprivileged for better security (runs as non-root)
repository: nginxinc/nginx-unprivileged
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion
tag: "1.25-alpine"
# Image pull secrets for private registries
imagePullSecrets: []
# Override the name of the chart
nameOverride: ""
fullnameOverride: ""
# Service configuration
service:
# Service type - ClusterIP for internal-only access
type: ClusterIP
# Port where the service will be exposed
port: 80
# Target port on the container (nginx default)
targetPort: 8080
# Annotations to add to the service
annotations: {}
# Resource limits and requests
resources:
limits:
cpu: 100m
memory: 64Mi
requests:
cpu: 50m
memory: 32Mi
# Node selector for pod assignment
nodeSelector: {}
# Tolerations for pod assignment
tolerations: []
# Affinity rules for pod assignment
affinity: {}
# Security context for the pod
podSecurityContext:
runAsNonRoot: true
runAsUser: 101
fsGroup: 101
# Security context for the container
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
# Status JSON content
# This can be overridden in your values to customize the status information
statusJson:
repo: "rsyslog"
server: "rsyslog-lab"
sync_status: "UNKNOWN"
drift_count: 0
files: []
last_check: ""
# Labels to add to all resources
labels: {}
# Annotations to add to all resources
annotations: {}
# Pod annotations
podAnnotations: {}
# Service account configuration
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""

View File

@ -0,0 +1,26 @@
# Minimal values for gitops-status-server
# Override default chart values as needed
# Status JSON content
# Update this with your actual GitOps status information
statusJson:
repo: "observability-stack"
server: "rsyslog-lab"
sync_status: "UNKNOWN"
drift_count: 0
files: []
last_check: ""
# Resource limits (optional override)
# resources:
# limits:
# cpu: 100m
# memory: 64Mi
# requests:
# cpu: 50m
# memory: 32Mi
# Service configuration (optional override)
# service:
# type: ClusterIP
# port: 80