diff --git a/README.md b/README.md index 38cca73..bd5c872 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # node-cert-exporter + [![Build Status](https://travis-ci.org/amimof/node-cert-exporter.svg?branch=master)](https://travis-ci.org/amimof/node-cert-exporter) [![Go Report Card](https://goreportcard.com/badge/github.com/amimof/node-cert-exporter)](https://goreportcard.com/report/github.com/amimof/node-cert-exporter) [![huego](https://godoc.org/github.com/amimof/node-cert-exporter?status.svg)](https://godoc.org/github.com/amimof/node-cert-exporter) --- @@ -7,40 +8,59 @@ *This project is currently in beta and is looking for contributors. Feel free to leave your feedback using issues or pull requests.* -# Kubernetes DaemonSet -``` +## Kubernetes DaemonSet + +```bash kubectl apply -f https://raw.githubusercontent.com/amimof/node-cert-exporter/master/deploy/daemonset.yml ``` -# Docker +## Openshift DaemonSet + +__Tip__: This YAML files configured via jsonnet for prometheus-operator in OKD 3.11 and for the project `monitoring` + +```bash +oc create -f https://raw.githubusercontent.com/amimof/node-cert-exporter/master/okd/rendered/node-cert-exporter-service.yaml +oc create -f https://raw.githubusercontent.com/amimof/node-cert-exporter/master/okd/rendered/node-cert-exporter-serviceMonitor.yaml +oc create -f https://raw.githubusercontent.com/amimof/node-cert-exporter/master/okd/rendered/node-cert-exporter-serviceAccount.yaml +oc adm policy add-scc-to-user hostmount-anyuid -n monitoring -z node-cert-exporter +oc create -f https://raw.githubusercontent.com/amimof/node-cert-exporter/master/okd/rendered/node-cert-exporter-daemonset.yaml ``` + +## Docker + +```bash docker run -p 9117:9117 amimof/node-cert-exporter --logtostderr=true --path=/etc/ssl,/dir/with/certs ``` -# Helm -``` +## Helm + +```bash helm repo add node-cert-exporter https://amimof.github.io/node-cert-exporter helm repo update helm install node-cert-exporter node-cert-exporter/node-cert-exporter ``` -# Binary -``` +## Binary + +```bash curl -LOs https://github.com/amimof/node-cert-exporter/releases/latest/download/node-cert-exporter-linux-amd64 && chmod +x node-cert-exporter-linux-amd64 ./node-cert-exporter-linux-amd64 --path=/etc/ssl,/dir/with/certs ``` -# Building from source -``` +## Building from source + +```bash git clone https://github.com/amimof/node-cert-exporter.git cd node-cert-exporter make ``` -# Grafana Dashboard +## Grafana Dashboard + Once the the node-cert-exporter is scraped by Prometheus, the metrics can easily be visualized using [Grafana](https://grafana.com). Get started by using the [Node Cert Exporter](https://grafana.com/dashboards/9999) dashboard hosted at grafana.com. -![](./img/grafana.png) +![Grafana dashboard](./img/grafana.png) + +## Contribute -# Contribute All help in any form is highly appreciated and your are welcome participate in developing together. To contribute submit a Pull Request. If you want to provide feedback, open up a Github Issue or contact me personally. \ No newline at end of file diff --git a/deploy/okd/grafana/k8s-cert-expire.json b/deploy/okd/grafana/k8s-cert-expire.json new file mode 100644 index 0000000..a915502 --- /dev/null +++ b/deploy/okd/grafana/k8s-cert-expire.json @@ -0,0 +1,164 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Dashboard for certificates in OKD 3.11", + "editable": false, + "gnetId": 9999, + "graphTooltip": 0, + "id": 18, + "links": [], + "panels": [ + { + "columns": [], + "datasource": "prometheus", + "fontSize": "100%", + "gridPos": { + "h": 16, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "links": [], + "options": {}, + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 3, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Expires In", + "align": "auto", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "Value", + "thresholds": [ + "7889231.49", + "15778463" + ], + "type": "number", + "unit": "dtdurations" + }, + { + "alias": "Node", + "align": "auto", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "nodename", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Path", + "align": "auto", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "mappingType": 1, + "pattern": "path", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(ssl_certificate_expiry_seconds{path!~\"/opt/etc/etcd/generated_certs/.+|/opt/etc/etcd/ca/.+\"}) by (nodename,path)", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "{{ nodename }}", + "refId": "A" + } + ], + "title": "Node Certificates", + "transform": "table", + "type": "table" + } + ], + "refresh": "30s", + "schemaVersion": 22, + "style": "dark", + "tags": [ + "kubernetes", + "node-cert-exporter" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-1m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Cert Expire", + "uid": "F_gILm6iz", + "version": 1 +} \ No newline at end of file diff --git a/deploy/okd/jsonnet/cert-exporter.libsonnet b/deploy/okd/jsonnet/cert-exporter.libsonnet new file mode 100644 index 0000000..8d4203c --- /dev/null +++ b/deploy/okd/jsonnet/cert-exporter.libsonnet @@ -0,0 +1,123 @@ +local k = import '../../vendor/ksonnet/ksonnet.beta.4/k.libsonnet'; + +{ + _config+:: { + namespace: 'default', + + versions+:: { + nodeCertExporter: '1.0.0', + }, + + imageRepos+:: { + nodeCertExporter: 'amimof/node-cert-exporter', + }, + + nodeCertExporter+:: { + port: 9117, + labels: { + 'k8s-app': 'node-cert-exporter', + }, + container: { + requests: { cpu: '100m', memory: '128Mi' }, + limits: { cpu: '250m', memory: '256Mi' }, + }, + }, + }, + + nodeCertExporter+:: { + daemonset: + local daemonset = k.apps.v1.daemonSet; + local container = daemonset.mixin.spec.template.spec.containersType; + local volume = daemonset.mixin.spec.template.spec.volumesType; + local containerPort = container.portsType; + local targetPort = $._config.nodeCertExporter.port; + local portName = 'metric'; + local containerVolumeMount = container.volumeMountsType; + local podSelector = daemonset.mixin.spec.template.spec.selectorType; + local containerEnv = container.envType; + + local podLabels = $._config.nodeCertExporter.labels; + + local etcdVolumeName = 'etcd'; + local etcdVolume = volume.fromHostPath(etcdVolumeName, '/etc/etcd'); + local etcdVolumeMount = containerVolumeMount.new(etcdVolumeName, '/opt/etc/etcd'). + withReadOnly(true); + + local masterVolumeName = 'master'; + local masterVolume = volume.fromHostPath(masterVolumeName, '/etc/origin/master'); + local masterVolumeMount = containerVolumeMount.new(masterVolumeName, '/opt/etc/master'). + withReadOnly(true); + + local nodeVolumeName = 'node'; + local nodeVolume = volume.fromHostPath(nodeVolumeName, '/etc/origin/node/certificates'); + local nodeVolumeMount = containerVolumeMount.new(nodeVolumeName, '/opt/etc/node'). + withReadOnly(true); + + local nodename = containerEnv.fromFieldPath('NODE_NAME', 'spec.nodeName'); + + local nodeCertExporter = + container.new('node-cert-exporter', $._config.imageRepos.nodeCertExporter + ':' + $._config.versions.nodeCertExporter) + + container.withArgs([ + '--v=2', + '--logtostderr=true', + '--path=/opt/etc/etcd/,/opt/etc/master/,/opt/etc/node/' + ]) + + container.withVolumeMounts([etcdVolumeMount, masterVolumeMount, nodeVolumeMount]) + + container.mixin.resources.withRequests($._config.nodeCertExporter.container.requests) + + container.withPorts(containerPort.newNamed(targetPort, portName)) + + container.withEnv([nodename]) + + container.mixin.resources.withLimits($._config.nodeCertExporter.container.limits); + + local c = [nodeCertExporter]; + + daemonset.new() + + daemonset.mixin.metadata.withName('node-cert-exporter') + + daemonset.mixin.metadata.withNamespace($._config.namespace) + + daemonset.mixin.metadata.withLabels(podLabels) + + daemonset.mixin.spec.selector.withMatchLabels(podLabels) + + daemonset.mixin.spec.template.metadata.withLabels(podLabels) + + daemonset.mixin.spec.template.spec.withNodeSelector({ 'beta.kubernetes.io/os': 'linux' }) + + daemonset.mixin.spec.template.spec.withContainers(c) + + daemonset.mixin.spec.template.spec.withVolumes([etcdVolume, masterVolume, nodeVolume]) + + daemonset.mixin.spec.template.spec.withServiceAccountName('node-cert-exporter') + + daemonset.mixin.spec.template.spec.securityContext.withRunAsUser(0), + + serviceAccount: + local serviceAccount = k.core.v1.serviceAccount; + + serviceAccount.new('node-cert-exporter') + + serviceAccount.mixin.metadata.withNamespace($._config.namespace), + + serviceMonitor: + { + apiVersion: 'monitoring.coreos.com/v1', + kind: 'ServiceMonitor', + metadata: { + name: 'node-cert-exporter', + namespace: $._config.namespace, + labels: $._config.nodeCertExporter.labels, + }, + spec: { + selector: { + matchLabels: $._config.nodeCertExporter.labels, + }, + endpoints: [ + { + port: 'metric', + interval: '15s', + }, + ], + }, + }, + + service: + local service = k.core.v1.service; + local servicePort = k.core.v1.service.mixin.spec.portsType; + + local nodeCertExporterPort = servicePort.newNamed('metric', $._config.nodeCertExporter.port, 'metric'); + + service.new('node-cert-exporter', $.nodeCertExporter.daemonset.spec.selector.matchLabels, nodeCertExporterPort) + + service.mixin.metadata.withNamespace($._config.namespace) + + service.mixin.metadata.withLabels($._config.nodeCertExporter.labels), + }, +} diff --git a/deploy/okd/rendered/node-cert-exporter-daemonset.yaml b/deploy/okd/rendered/node-cert-exporter-daemonset.yaml new file mode 100644 index 0000000..aa6c0d5 --- /dev/null +++ b/deploy/okd/rendered/node-cert-exporter-daemonset.yaml @@ -0,0 +1,63 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + labels: + k8s-app: node-cert-exporter + name: node-cert-exporter + namespace: monitoring +spec: + selector: + matchLabels: + k8s-app: node-cert-exporter + template: + metadata: + labels: + k8s-app: node-cert-exporter + spec: + containers: + - args: + - --v=2 + - --logtostderr=true + - --path=/opt/etc/etcd/,/opt/etc/master/,/opt/etc/node/ + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + image: amimof/node-cert-exporter:1.0.0 + name: node-cert-exporter + ports: + - containerPort: 9117 + name: metric + resources: + limits: + cpu: 250m + memory: 256Mi + requests: + cpu: 100m + memory: 128Mi + volumeMounts: + - mountPath: /opt/etc/etcd + name: etcd + readOnly: true + - mountPath: /opt/etc/master + name: master + readOnly: true + - mountPath: /opt/etc/node + name: node + readOnly: true + nodeSelector: + beta.kubernetes.io/os: linux + securityContext: + runAsUser: 0 + serviceAccountName: node-cert-exporter + volumes: + - hostPath: + path: /etc/etcd + name: etcd + - hostPath: + path: /etc/origin/master + name: master + - hostPath: + path: /etc/origin/node/certificates + name: node diff --git a/deploy/okd/rendered/node-cert-exporter-service.yaml b/deploy/okd/rendered/node-cert-exporter-service.yaml new file mode 100644 index 0000000..885763e --- /dev/null +++ b/deploy/okd/rendered/node-cert-exporter-service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + k8s-app: node-cert-exporter + name: node-cert-exporter + namespace: monitoring +spec: + ports: + - name: metric + port: 9117 + targetPort: metric + selector: + k8s-app: node-cert-exporter diff --git a/deploy/okd/rendered/node-cert-exporter-serviceAccount.yaml b/deploy/okd/rendered/node-cert-exporter-serviceAccount.yaml new file mode 100644 index 0000000..564105c --- /dev/null +++ b/deploy/okd/rendered/node-cert-exporter-serviceAccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: node-cert-exporter + namespace: monitoring diff --git a/deploy/okd/rendered/node-cert-exporter-serviceMonitor.yaml b/deploy/okd/rendered/node-cert-exporter-serviceMonitor.yaml new file mode 100644 index 0000000..18230f0 --- /dev/null +++ b/deploy/okd/rendered/node-cert-exporter-serviceMonitor.yaml @@ -0,0 +1,14 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: + k8s-app: node-cert-exporter + name: node-cert-exporter + namespace: monitoring +spec: + endpoints: + - interval: 15s + port: metric + selector: + matchLabels: + k8s-app: node-cert-exporter \ No newline at end of file