diff --git a/helm-chart/.helmignore b/helm-chart/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/helm-chart/.helmignore @@ -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/ diff --git a/helm-chart/Chart.yaml b/helm-chart/Chart.yaml new file mode 100644 index 00000000..1a3b6447 --- /dev/null +++ b/helm-chart/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: popeye +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +appVersion: 0.1.0 diff --git a/helm-chart/README.md b/helm-chart/README.md new file mode 100644 index 00000000..bb1a3575 --- /dev/null +++ b/helm-chart/README.md @@ -0,0 +1,11 @@ +### Now you can use this helm-char to run a cronjob with possibility feed prometheus with an pushgateway, serve http/s page of popeye's report. + +``` +git clone git@github.com:derailed/popeye.git +cd popeye/helm-chart +helm install popeye -n popeye --create-namespace . +``` + +You can set a many values on values.yaml or pass using --set parameter:value, like a helm. + +If you have any questios or sugestions please can contact me adonai@ascsystem.com.br diff --git a/helm-chart/grafana/alerts-from-popeye.json b/helm-chart/grafana/alerts-from-popeye.json new file mode 100644 index 00000000..7765e073 --- /dev/null +++ b/helm-chart/grafana/alerts-from-popeye.json @@ -0,0 +1,311 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "7.5.5" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "report generated by popeye", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1621092285922, + "links": [ + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Popeye Report", + "tooltip": "", + "type": "link", + "url": "http://popeye.domain.com" + } + ], + "panels": [ + { + "datasource": null, + "description": "Saúde dos $resource do Cluster", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Warning" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Errors" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Info" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 26, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "7.5.5", + "targets": [ + { + "exemplar": true, + "expr": "sum(popeye_sanitizer_reports_count{resource=\"$resource\",level=\"ok\"}) by (level)", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "OK", + "refId": "OK" + }, + { + "exemplar": true, + "expr": "sum(popeye_sanitizer_reports_count{resource=\"$resource\",level=\"warn\"}) by(level)", + "hide": false, + "instant": false, + "interval": "", + "legendFormat": "Warning", + "refId": "Warning" + }, + { + "exemplar": true, + "expr": "sum(popeye_sanitizer_reports_count{resource=\"$resource\",level=\"error\"}) by(level)", + "hide": false, + "instant": false, + "interval": "", + "legendFormat": "Errors", + "refId": "Errors" + }, + { + "exemplar": true, + "expr": "sum(popeye_sanitizer_reports_count{resource=\"$resource\",level=\"info\"}) by(level)", + "hide": false, + "interval": "", + "legendFormat": "Info", + "refId": "Info" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "$resource", + "type": "gauge" + }, + { + "datasource": null, + "description": "Nota do Cluster", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-RdYlGr" + }, + "displayName": "Score", + "mappings": [], + "max": 100, + "min": 10, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "green", + "value": 95 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 13, + "y": 0 + }, + "id": 12, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "7.5.5", + "targets": [ + { + "exemplar": true, + "expr": "popeye_cluster_score_total", + "format": "time_series", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Cluster Score Summary", + "type": "gauge" + } + ], + "refresh": "5s", + "schemaVersion": 27, + "style": "dark", + "tags": [ + "popeye", + "monitoring" + ], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(popeye_sanitizer_reports_count, resource)", + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "resource", + "multi": false, + "name": "resource", + "options": [], + "query": { + "query": "label_values(popeye_sanitizer_reports_count, resource)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "utc", + "title": "Alerts from Popeye", + "uid": "srljAVCGk", + "version": 2 +} \ No newline at end of file diff --git a/helm-chart/templates/_helpers.tpl b/helm-chart/templates/_helpers.tpl new file mode 100644 index 00000000..0276eae0 --- /dev/null +++ b/helm-chart/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "popeye.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "popeye.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 "popeye.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "popeye.labels" -}} +helm.sh/chart: {{ include "popeye.chart" . }} +{{ include "popeye.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "popeye.selectorLabels" -}} +app.kubernetes.io/name: {{ include "popeye.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "popeye.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "popeye.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm-chart/templates/clusterrole.yaml b/helm-chart/templates/clusterrole.yaml new file mode 100644 index 00000000..91782af4 --- /dev/null +++ b/helm-chart/templates/clusterrole.yaml @@ -0,0 +1,53 @@ +--- +# Popeye needs get/list access on the following Kubernetes resources. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: popeye +rules: +- apiGroups: ["apps",""] + resources: + - configmaps + - deployments + - endpoints + - horizontalpodautoscalers + - namespaces + - nodes + - persistentvolumes + - persistentvolumeclaims + - pods + - secrets + - serviceaccounts + - services + - statefulsets + - daemonsets + - replicasets + verbs: ["get", "list"] +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: ["get", "list"] +- apiGroups: ["networking.k8s.io"] + resources: + - ingresses + - networkpolicies + verbs: ["get","list"] +- apiGroups: ["policy"] + resources: + - poddisruptionbudgets + - podsecuritypolicies + verbs: ["get","list"] +- apiGroups: ["rbac.authorization.k8s.io"] + resources: + - clusterroles + - clusterrolebindings + - roles + - rolebindings + verbs: ["get", "list"] +- apiGroups: ["metrics.k8s.io"] + resources: + - pods + - nodes + verbs: ["get", "list"] + + diff --git a/helm-chart/templates/clusterrolebinding.yaml b/helm-chart/templates/clusterrolebinding.yaml new file mode 100644 index 00000000..a5ae77d7 --- /dev/null +++ b/helm-chart/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +# Binds Popeye to this ClusterRole. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: popeye +subjects: +- kind: ServiceAccount + name: {{ include "popeye.serviceAccountName" . }} + namespace: {{ .Values.namespace }} +roleRef: + kind: ClusterRole + name: popeye + apiGroup: rbac.authorization.k8s.io + + diff --git a/helm-chart/templates/configmap.yaml b/helm-chart/templates/configmap.yaml new file mode 100644 index 00000000..9d128a6f --- /dev/null +++ b/helm-chart/templates/configmap.yaml @@ -0,0 +1,66 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app: popeye-reports + name: spinach + namespace: {{ .Values.namespace }} +data: +{{ if .Values.configMap }} +{{- with .Values.configMap }} + {{- toYaml . | nindent 2 }} +{{- end }} +{{- else }} + spinach: |- + # A Popeye sample configuration file + popeye: + allocations: + cpu: + underPercUtilization: 200 # Checks if cpu is under allocated by more than 200% at current load. + overPercUtilization: 50 # Checks if cpu is over allocated by more than 50% at current load. + memory: + underPercUtilization: 200 # Checks if mem is under allocated by more than 200% at current load. + overPercUtilization: 50 # Checks if mem is over allocated by more than 50% usage at current load. + + excludes: + v1/pods: + - name: rx:kube-system + codes: + - 102 + - 105 + - 106 + - 107 + - 206 + - 301 + - 302 + - 306 + - 206 + - 104 + - name: rx:popeye-reports + - name: rx:icx/.* + containers: + - istio-proxy + - istio-init + v1/configmaps: + - name: rx:fred.+\.v\d+ + v1/namespaces: + - name: rx:kube + codes: + - 404 + - name: rx:istio + autoscaling/v1/horizontalpodautoscalers: + - name: rx:.* + + node: + limits: + cpu: 90 + memory: 80 + + pod: + restarts: + 3 + limits: + cpu: 80 + memory: 75 +{{- end }} diff --git a/helm-chart/templates/cronjob.yaml b/helm-chart/templates/cronjob.yaml new file mode 100644 index 00000000..403f79c7 --- /dev/null +++ b/helm-chart/templates/cronjob.yaml @@ -0,0 +1,111 @@ +--- +apiVersion: batch/v1beta1 +kind: CronJob +metadata: + labels: + app: popeye-reports + name: popeye-reports + namespace: {{ .Values.namespace }} +spec: + schedule: {{ .Values.schedule }} + concurrencyPolicy: Forbid + failedJobsHistoryLimit: {{ .Values.failedJobsHistoryLimit | default "20" }} + successfulJobsHistoryLimit: {{ .Values.successfulJobsHistoryLimit | default "20" }} + jobTemplate: + spec: + template: + metadata: + labels: + app: popeye-reports + spec: + containers: + - image: "{{ .Values.image.web.name }}:{{ .Values.image.web.tag }}" + imagePullPolicy: {{ .Values.image.web.pullPolicy }} + name: nginx + ports: + - containerPort: 80 + name: http + protocol: TCP + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /usr/share/nginx/html + name: www + - image: "{{ .Values.image.recycle.name }}:{{ .Values.image.recycle.tag }}" + imagePullPolicy: {{ .Values.image.recycle.pullPolicy }} + name: popeye-recycle + resources: {} + command: + - sh + - -c + - | + sleep {{ .Values.rotation }} && kill $(pgrep nginx) && exit 0 + dnsPolicy: ClusterFirst + initContainers: +{{- if .Values.pushgateway.enabled }} + - args: + - -A + - -f + - /etc/config/popeye/spinach.yml + - -o + - prometheus + - --pushgateway-address + - {{ .Values.pushgateway.url }} + - --force-exit-zero + volumeMounts: + - name: spinach + mountPath: /etc/config/popeye + image: {{ .Values.image.popeye.name }} + imagePullPolicy: {{ .Values.image.popeye.pullPolicy }} + name: popeye + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File +{{- end }} + - args: + - -A + - -f + - /etc/config/popeye/spinach.yml + - -o + - html + - --save + - --output-file + - index.html + - --force-exit-zero + image: {{ .Values.image.popeye.name }} + imagePullPolicy: {{ .Values.image.popeye.pullPolicy }} + name: popeye-report + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /tmp + name: www + - mountPath: /etc/config/popeye + name: spinach + securityContext: {} + serviceAccount: {{ include "popeye.serviceAccountName" . }} + serviceAccountName: {{ include "popeye.serviceAccountName" . }} + shareProcessNamespace: true + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + terminationGracePeriodSeconds: 30 + volumes: + - emptyDir: {} + name: www + - name: spinach + configMap: + name: spinach + items: + - key: spinach + path: spinach.yml + + diff --git a/helm-chart/templates/ingress.yaml b/helm-chart/templates/ingress.yaml new file mode 100644 index 00000000..d1fe4af5 --- /dev/null +++ b/helm-chart/templates/ingress.yaml @@ -0,0 +1,38 @@ +{{- if .Values.ingress.enabled -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + labels: + app: popeye-reports + annotations: + nginx.ingress.kubernetes.io/app-root: /popeye + {{- with .Values.ingress.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + name: popeye-reports + namespace: {{ .Values.namespace }} +spec: + rules: + - host: {{ .Values.ingress.host }} + http: + paths: + - path: / + backend: + serviceName: popeye-reports + servicePort: 80 + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} +{{- end }} + diff --git a/helm-chart/templates/service.yaml b/helm-chart/templates/service.yaml new file mode 100644 index 00000000..0acf230b --- /dev/null +++ b/helm-chart/templates/service.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: popeye-reports + name: popeye-reports + namespace: {{ .Values.namespace }} +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: popeye-reports + diff --git a/helm-chart/templates/serviceaccount.yaml b/helm-chart/templates/serviceaccount.yaml new file mode 100644 index 00000000..957280eb --- /dev/null +++ b/helm-chart/templates/serviceaccount.yaml @@ -0,0 +1,20 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "popeye.serviceAccountName" . }} + namespace: {{ .Values.namespace }} + labels: + {{- include "popeye.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- else }} +apiVersion: v1 +kind: ServiceAccount +metadata: + creationTimestamp: null + name: popeye + namespace: {{ .Values.namespace }} +{{- end }} diff --git a/helm-chart/values.yaml b/helm-chart/values.yaml new file mode 100644 index 00000000..82edab3e --- /dev/null +++ b/helm-chart/values.yaml @@ -0,0 +1,125 @@ +# Default values for popeye. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Rotation in seconds popeye will be execute scan, feed pushgateway/prometheus and create new html report +# this is the same time of cronjob will be executed +# e.g. +# 2 hours of rescan = +# rotation: 7200 +# schedule: "0 */2 * * *" +# | | | | | +# | | | | -- 0-7 = day of week (0 or 7 is Sun) +# | | | ---- 1-12 = month +# | | ------ 1-31 = day of month +# | --------- 0-23 = hour +# ------------ 0-59 = minute +rotation: 7200 +schedule: "0 */2 * * *" + +# How many Pods will be keep to tell history of executions +successfulJobsHistoryLimit: 15 +failedJobsHistoryLimit: 10 + +nameOverride: "" +fullnameOverride: "" + +namespace: popeye + +image: + web: + name: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: stable-alpine + recycle: + name: alpine + pullPolicy: IfNotPresent + tag: latest + popeye: + name: quay.io/derailed/popeye + pullPolicy: Always + +# Instaladed from helm chart prometheus-community/prometheus-pushgateway +# https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-pushgateway + +pushgateway: + enabled: true + url: http://pushgateway-prometheus-pushgateway.monitoring.svc:9091 + +configMap: {} +# spinach: |- +# # A Popeye sample configuration file +# popeye: +# allocations: +# cpu: +# underPercUtilization: 200 # Checks if cpu is under allocated by more than 200% at current load. +# overPercUtilization: 50 # Checks if cpu is over allocated by more than 50% at current load. +# memory: +# underPercUtilization: 200 # Checks if mem is under allocated by more than 200% at current load. +# overPercUtilization: 50 # Checks if mem is over allocated by more than 50% usage at current load. +# +# excludes: +# v1/pods: +# - name: rx:kube-system +# codes: +# - 102 +# - 105 +# - 106 +# - 107 +# - 206 +# - 301 +# - 302 +# - 306 +# - 206 +# - 104 +# - name: rx:popeye-reports +# - name: rx:icx/.* +# containers: +# - istio-proxy +# - istio-init +# v1/configmaps: +# - name: rx:fred.+\.v\d+ +# v1/namespaces: +# - name: rx:kube +# codes: +# - 404 +# - name: rx:istio +# autoscaling/v1/horizontalpodautoscalers: +# - name: rx:.* +# +# node: +# limits: +# cpu: 90 +# memory: 80 +# +# pod: +# restarts: +# 3 +# limits: +# cpu: 80 +# memory: 75 + +ingress: + enabled: enabled + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + host: popeye.domain.com + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +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: "" + +nodeSelector: {} + +tolerations: []