| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513 | 
							- = Linux Metrics Exporter for OpenShift Nodes =
 
- Grega Bremec <gregab-at-p0f-dot-net>
 
- :revnumber: 1.0
 
- :revdate: 6th November 2022
 
- ifdef::env-github[]
 
- :status:
 
- :toc: macro
 
- :toclevels: 3
 
- :tip-caption: :bulb:
 
- :note-caption: :information_source:
 
- :important-caption: :heavy_exclamation_mark:
 
- :caution-caption: :fire:
 
- :warning-caption: :warning:
 
- endif::[]
 
- A composite pod that can be run in a `DaemonSet` and exposes standard Linux system activity data collector (`sadc`) and process accounting (`psacct`) data as scrapable Prometheus metrics.
 
- toc::[]
 
- == Components ==
 
- . Container Image for SAR
 
- . Container Image for PSACCT
 
- . Container Image for Exporter
 
- == How It All Works ==
 
- Very simple: two sidecar containers, `collector-sysstat` and
 
- `collector-psacct`, produce data on a shared ephemeral volume, and the third
 
- container, `metrics-exporter`, consumes the data and exposes it on the
 
- `/q/metrics` endpoint where Prometheus can pick them up.
 
- The specific thing about how the entire composition works is that care has been
 
- taken, especially with `psacct` (which can grow excessively during periods of
 
- high activity), that accounting files are regularly truncated or moved out of
 
- the way in order to keep the disk space utilisation as low as possible.
 
- == OpenShift Deployment ==
 
- === Defaults ===
 
- The easiest? Just use Kustomize to deploy existing resource definitions from
 
- the `exporter` manifest in `deployment/`:
 
- [subs=+quotes]
 
- ------
 
- $ *oc apply -k ./deployment/exporter/base/*
 
- ------
 
- The above will create everything in the `exporter` project. See below for
 
- kustomizations.
 
- To integrate the application with Prometheus in the `prometheus` project, just
 
- use the `integrate` manifest as it is:
 
- [subs=+quotes]
 
- ------
 
- $ *oc apply -k ./deployment/integrate/base/*
 
- ------
 
- === Kustomizations ===
 
- If you need to change the names of namespaces or some other settings, feel free
 
- to have a look at the `custom` kustomization next to `base`, then apply it
 
- instead of the base set of resources.
 
- [subs=+quotes]
 
- ------
 
- $ *cat deployment/exporter/custom/use-custom-namespace.yml*
 
- apiVersion: builtin
 
- kind: NamespaceTransformer
 
- metadata:
 
-   namespace: *my-very-own-namespace*
 
- setRoleBindingSubjects: allServiceAccounts
 
- fieldSpecs:
 
-   - path: metadata/name
 
-     kind: Namespace
 
- $ *oc apply -k ./deployment/exporter/custom/*
 
- ------
 
- You will probably already have Prometheus deployed somewhere prior to deploying
 
- the exporter, so you might also want to have a look at the kustomizations for
 
- the `integrate` manifest in order to target the right places.
 
- That one is a bit more complicated as a single manifest targets multiple
 
- namespaces. So a `NamespaceTransformer` is used for the `Role` and
 
- `RoleBinding` in the exporter project, and then two patches are used for the
 
- the `ServiceAccount` namespace in the `RoleBinding` (giving the right
 
- `prometheus-k8s` service account access to your project), and the `PodMonitor`
 
- namespace (which will be affected by the initial namespace transformation).
 
- [subs=+quotes]
 
- ------
 
- $ ls -1 deployment/integrate/custom/
 
- fix-podmonitor-namespace.json              <1>
 
- fix-podmonitor-namespace.yml
 
- fix-prometheus-namespace.json              <2>
 
- fix-prometheus-namespace.yml
 
- kustomization.yml
 
- use-custom-namespace.yml                   <3>
 
- ------
 
- <1> This is the namespace the `PodMonitor` will be created in.
 
- <2> This is where the `RoleBinding` target `ServiceAccount` is fixed.
 
- <3> This is where every other resource will be created.
 
- === No Prometheus? No Problem. ===
 
- If you still need to deploy Prometheus, there is a sample manifest in there as
 
- well. Two, actually. One to deploy the Prometheus and Grafana operators (you
 
- won't believe it, it's called `operators`), and once those are running, you can
 
- use the other one (called very innovatively `prometheus`) to deploy their
 
- actual instances. That will also target the `prometheus` OpenShift project, so
 
- kustomize away if that's not what you want.
 
- == Standalone Containers ==
 
- Start the composition.
 
- // TODO: podman pod
 
- [subs=+quotes]
 
- ------
 
- $ *podman volume create metrics*
 
- metrics
 
- $ *podman run -d --rm -v metrics:/var/account --cap-add SYS_PACCT --pid=host collector-psacct:latest*
 
- dd9f4825d23614df2acefdcd70ec1e6c3ea18a58b86c9d17ddc4f91038487919
 
- $ *podman run -d --rm -v metrics:/var/log/sa collector-sysstat*
 
- ec3d0957525cc907023956a185b15123c20947460a48d37196d511ae42de2e27
 
- $ *podman run --name exporter -d --rm -v metrics:/metrics -p 8080:8080 metrics-exporter*
 
- d4840ad57bfffd4b069e7c2357721ff7aaa6b6ee77f90ad4866a76a1ceb6adb7
 
- ------
 
- Configure Prometheus with a data source from the `exporter` container.
 
- [subs=+quotes]
 
- ------
 
- $ *podman inspect -f '{{.NetworkSettings.IPAddress}}' exporter*
 
- 10.88.0.8
 
- $ *tail -n15 tmp-test/prometheus.yml*
 
- scrape_configs:
 
-   # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
 
-   - job_name: "prometheus"
 
-     static_configs:
 
-       - targets: ["localhost:9090"]
 
-   **- job_name: "exporter"
 
-     metrics_path: "/q/metrics"
 
-     scheme: "http"
 
-     static_configs:
 
-       - targets: ["10.88.0.8:8080"]
 
-     scrape_interval: 10s
 
-     scrape_timeout: 5s**
 
- ------
 
- Add Prometheus and Grafana.
 
- [subs=+quotes]
 
- ------
 
- $ *podman run --name prometheus \*
 
- 		*-d --rm \*
 
- 		*-v ./test/prometheus.yml:/etc/prometheus/prometheus.yml*
 
- 		*-v prometheus:/prometheus \*
 
- 		*-p 9090:9090 \*
 
- 		*registry.redhat.io/openshift4/ose-prometheus:v4.11*
 
- 6eae04677fcded65bbe1cb7f66aa887d94587977a0616f7ec838f9453702474c
 
- $ *podman run --name grafana -d --rm -p 3000:3000 \*
 
- 		*-v ./test/grafana.ini:/etc/grafana/grafana.ini \*
 
- 		*registry.redhat.io/openshift4/ose-grafana:v4.11*
 
- 78d5bfa7977923b828c1818bb877fa87bdd96086cc8c875fbc46073489f6760e
 
- ------
 
- Configure Grafana with Prometheus as the datasource and dashboard away!
 
- .Process Accounting Graphs from a Single Host
 
- image::pics/psacct-sample.png[scaledwidth="95%" width="95%"]
 
- .Sysstat Scheduler Information, Single Host
 
- image::pics/sysstat-sample-sched.png[scaledwidth="95%" width="95%"]
 
- .Sysstat I/O Information, Single Host
 
- image::pics/sysstat-sample-io.png[scaledwidth="95%" width="95%"]
 
- == Container Images ==
 
- This set of images requires a valid entitlement for RHEL (and consequently
 
- either a RHEL system to build on or a RHEL system to create an entitlement
 
- secret from).
 
- IMPORTANT: You do not have to build the images, I have already built them (for
 
-     `x86_64` architecture only) and made them available on `quay.io/benko/`.
 
- === SAR ===
 
- The _system activity reporting_ image is based on `ubi-minimal` and includes
 
- just the `sysstat` package.
 
- It expects a volume to be attached at `/var/log/sa`.
 
- Entrypoint takes care of initialising the `saXX` files.
 
- // TODO: and rotating any old files out of the way.
 
- It *requires* to be executed under `root` UID (can be rootless, but that may
 
- affect your data depending on host and container configuration).
 
- It also *requires* access to host's network namespace if you want to measure
 
- global network statistics.
 
- ==== Parameters ====
 
- `PERIOD`::
 
-     Sampling period in seconds. Defaults to `10`. Increase this to something
 
-     like `30` (or more) for hosts with many network interfaces, block devices,
 
-     and/or CPUs.
 
- `STARTUP_SCRATCH`::
 
-     Whether to scratch existing `sa1` data at startup. Defaults to `0`, but
 
-     could be anything except `1`, `yes`, or `true`, which activates it.
 
-     
 
- `STARTUP_ROTATE`::
 
-     Whether to mark data as rotated at startup. Basically just writes a marker
 
-     in the previous `sadc` data file. Defaults to `0`, but could be anything
 
-     except `1`, `yes`, or `true`, which activates it.
 
- === PSACCT ===
 
- The _process accounting_ image is based on `ubi-minimal` and includes just the
 
- `psacct` package.
 
- It expects a volume to be attached at `/var/account`.
 
- Entrypoint takes care of rotating any old `pacct` files out of the way.
 
- In addition to *requiring* execution under a *real* `root` UID (i.e. *NOT* a
 
- rootless container), it also *requires* the `CAP_SYS_PACCT` capability
 
- (`--cap-add=SYS_PACCT`) and access to host's PID namespace (`--pid=host`).
 
- ==== Parameters ====
 
- `PERIOD`::
 
-     Sampling period in seconds. Defaults to `10`. Increase this to something
 
-     like `30` (or more) for hosts with many thousands of processes.
 
- `CUMULATIVE`::
 
-     Tells the collection process to never reset the `pacct` file and just keep
 
-     it growing, thus reporting cumulative stats since container start. Beware
 
-     that the `pacct` file will grow correspondinly large as time goes by.
 
- `STARTUP_SCRATCH`::
 
-     Whether to scratch existing `pacct` data at startup. Defaults to `0`, but
 
-     could be anything except `1`, `yes`, or `true`, which activates it.
 
- === Exporter ===
 
- The brain of the group.
 
- // TODO: Add support for hostname overrides in app.
 
- // run a maven registry.access.redhat.com/ubi9/openjdk-17 container:
 
- //
 
- // podman volume create maven
 
- //
 
- // podman run -it \
 
- //		    --name exporter \
 
- //		    -v maven:/home/default/.m2/repository \
 
- //		    -v metrics:/metrics \
 
- //		    -v /Users/johndoe/Documents/workspaces/projects/p0f/linux-metrics-exporter/exporter:/exporter \
 
- //		    -p 8080:8080 \
 
- //	    registry.access.redhat.com/ubi9/openjdk-17 bash
 
- //
 
- // $ cd /exporter
 
- // $ mvn quarkus:dev
 
- ==== Parameters ====
 
- In `application.properties` or as Java system properties:
 
- `exporter.data.path`::
 
-     Override the location where the metrics files are expected to show up.
 
-     Defaults to `/metrics` but obviously can't be that for testing outside of a
 
-     container.
 
- You can set the same settings https://quarkus.io/guides/config-reference[from environment variables].
 
- ==== Debugging ====
 
- There are a couple of logger categories that might help you see what's going on.
 
- By default, the routes are fairly noisy, as apparently `TRACE` level logging
 
- doesn't work for some reason, so I had to bump everything up a level, so at
 
- `INFO` you already see a note about every record that's been processed - you
 
- will see their unmarshaled bodies (completely shameless, I know).
 
- These can be bumped up to `DEBUG` if you need more info:
 
- `psacct-reader`::
 
-     The route reading process accounting files from `psacct-dump-all` file.
 
-     Pretty much all the logic is here, but since there can be a large number of
 
-     process records in the file it is split and each record is processed
 
-     asynchronously by the dispatch route.
 
- `psacct-dispatch`::
 
-     The route dispatching the records to the registration service.
 
- `psacct-reset`::
 
-     To be able to work with instantaneous data, rather than cumulative, all
 
-     previously registered records are synchronously reset to zero upon the
 
-     arrival of a new snapshot. This prevents metrics for previously registered
 
-     processes from disappearing.
 
- `sysstat-reader`::
 
-     The route that reads `sysstat-dump.json` file. All the logic is here.
 
- `net.p0f.openshift.metrics`::
 
-     Non-camel stuff is all logged in this category.
 
- `net.p0f.openshift.metrics.exporter`::
 
-     Metric registration and a silly REST endpoint that reports the version.
 
- `net.p0f.openshift.metrics.model`::
 
-     `ProcessAccountingRecord` and `SysstatMeasurement` live here.
 
- `net.p0f.openshift.metrics.processor`::
 
-     Just a simple processor that transforms a `psacct` record into CSV.
 
- `net.p0f.openshift.metrics.routes`::
 
-     Camel routes. See the first four categories for this.
 
- === Building with Podman ===
 
- If building the images using `podman` on an entitled host, no extra steps need
 
- to be performed as host entitlements will automatically be imported into the
 
- build container.
 
- [NOTE]
 
- ========
 
- When building for an architecture without the `ubi-minimal` image or on a
 
- host that can not be entitled (f.e. Fedora CoreOS), you can choose a different
 
- base image by using the `--from` option in `podman build`.
 
- [subs=+quotes]
 
- -------------------------------
 
- $ *podman build --from=registry.fedoraproject.org/fedora-minimal:36 -f ./images/Containerfile-sysstat -t collector-sysstat:latest*
 
- -------------------------------
 
- ========
 
- You will have noticed there is no `Containerfile` for exporter. That is because
 
- `quarkus-maven-plugin` can do just fine
 
- https://quarkus.io/guides/container-image[building an image on its own]. Just
 
- add the `jib` extension and tell it to push the image somewhere.
 
- [subs=+quotes]
 
- -------------------------------
 
- $ *mvn package -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true -Dquarkus.container-image.registry=foo*
 
- -------------------------------
 
- === Building in OpenShift ===
 
- ==== Collector Images ====
 
- If building the images in OpenShift Container Platform, you must make sure an
 
- entitlement secret and corresponding RHSM certificate secret are mounted inside
 
- the build pod in order for packages to be found and installed.
 
- NOTE: The entitled system architecture needs to match the container host!
 
- The process is as follows.
 
- .Verify access to host entitlement data.
 
- [subs=+quotes]
 
- -------------------------------
 
- $ **ls -l /etc/pki/entitlement/*.pem /etc/rhsm/ca/*.pem**
 
- -rw-r--r--. 1 root root   3272 Oct 31 06:09 /etc/pki/entitlement/_6028779042203586857_-key.pem
 
- -rw-r--r--. 1 root root 149007 Oct 31 06:09 /etc/pki/entitlement/_6028779042203586857_.pem
 
- -rw-r--r--. 1 root root   2305 Sep  2  2021 /etc/rhsm/ca/redhat-entitlement-authority.pem
 
- -rw-r--r--. 1 root root   7411 Sep  2  2021 /etc/rhsm/ca/redhat-uep.pem
 
- -------------------------------
 
- .Create corresponding secrets.
 
- [subs=+quotes]
 
- -------------------------------
 
- $ *oc create secret generic etc-pki-entitlement \*
 
-     *--from-file=/etc/pki/entitlement/_6028779042203586857_-key.pem \*
 
-     *--from-file=/etc/pki/entitlement/_6028779042203586857_.pem*
 
- secret/etc-pki-entitlement created
 
- $ *oc create secret generic rhsm-ca \*
 
-     *--from-file=/etc/rhsm/ca/redhat-entitlement-authority.pem \*
 
-     *--from-file=/etc/rhsm/ca/redhat-uep.pem*
 
- secret/rhsm-ca created
 
- -------------------------------
 
- .Make sure the BuildConfig mounts those secrets.
 
- [subs=+quotes]
 
- -------------------------------
 
- apiVersion: build.openshift.io/v1
 
- kind: BuildConfig
 
- ...
 
-   strategy:
 
-     type: Docker
 
-     dockerStrategy:
 
-       dockerfilePath: Containerfile-psacct
 
-       from:
 
-         kind: ImageStreamTag
 
-         name: ubi-minimal:latest
 
-       **volumes:
 
-         - source:
 
-             type: Secret
 
-             secret:
 
-               secretName: etc-pki-entitlement
 
-           name: etc-pki-entitlement
 
-           mounts:
 
-             - destinationPath: /etc/pki/entitlement
 
-         - source:
 
-             type: Secret
 
-             secret:
 
-               secretName: rhsm-ca
 
-           name: rhsm-ca
 
-           mounts:
 
-             - destinationPath: /etc/rhsm/ca**
 
- -------------------------------
 
- `Containerfile` instructions are written such that they should work without
 
- modification regardless of whether the build is running in `podman` on an
 
- entitled host or inside a correctly configured OpenShift builder pod.
 
- NOTE: Key thing in `Containerfile` steps is to remove `/etc/rhsm-host` at some
 
-       point unless `/etc/pki/entitlement-host` contains something (such as for
 
-       example, valid entitlemets). Both are symlinks to `/run/secrets`.
 
- ==== Exporter Image ====
 
- ===== Java Build =====
 
- Java build is relatively simple.
 
- Figure out what OpenJDK image is available in the cluster and create a new build.
 
- [subs=+quotes]
 
- -------------------------------
 
- $ *oc new-build openjdk-11-rhel8:1.0~https://github.com/benko/linux-metrics-exporter.git --context-dir=exporter*
 
- -------------------------------
 
- Wait for the build to complete (it's going to take quite some time to download all deps) and that's it!
 
- If you're experimenting with the code, don't forget to mark the build as incremental.
 
- [subs=+quotes]
 
- -------------------------------
 
- $ *oc patch bc/linux-metrics-exporter -p '{"spec": {"strategy": {"sourceStrategy": {"incremental": true}}}}'*
 
- -------------------------------
 
- ===== Native Build =====
 
- TBD
 
- // For the native build, you need a specific Mandrel image. Import it first.
 
- // 
 
- // $ oc import-image mandrel --from=registry.redhat.io/quarkus/mandrel-21-rhel8:latest --confirm
 
- // imagestream.image.openshift.io/mandrel imported
 
- // ...
 
- ===== Publishing the Image =====
 
- Make sure the internal OpenShift image registry is exposed if you want to copy the image somewhere else.
 
- [subs=+quotes]
 
- -------------------------------
 
- $ *oc patch config.imageregistry/cluster --type=merge -p '{"spec": {"defaultRoute": true}}'*
 
- -------------------------------
 
- Login to both source and target registries.
 
- [subs=+quotes]
 
- -------------------------------
 
- $ *podman login quay.io*
 
- Username: *youruser*
 
- Password: *yourpassword*
 
- Login Succeeded!
 
- $ *oc whoami -t*
 
- sha256~8tIizkcLNroDEcWXJgoPMsVYUriK1sGnJ6N94WSveEU
 
- $ podman login default-route-openshift-image-registry.apps.your.openshift.cluster
 
- Username: _this-is-irrelevant_
 
- Password: *token-pasted-here*
 
- Login Succeeded!
 
- -------------------------------
 
- Then simply copy the image using `skopeo`.
 
- [subs=+quotes]
 
- -------------------------------
 
- $ *skopeo copy \*
 
-     *docker://default-route-openshift-image-registry.apps.your.openshift.cluster/project/linux-metrics-exporter:latest \*
 
-     *docker://quay.io/youruser/yourimage:latest*
 
- -------------------------------
 
- == Acknowledgements ==
 
- Many thanks to Piotr Baranowski <https://github.com/divinitus[@divinitus]> for the idea about running `sa1` in a DaemonSet.
 
 
  |