DevOpsCon Keynote – Security ist jetzt Teil von DevOps?

written by Martin Häcker on

Metapher auf Teams die jeweils Sicherheits-Interessierte enthalten, die einfach von Spezialisten Unterstützung erhalten können

Ich konnte auf der DevOpsCon der Keynote "From Static to Strategic: Reimagining Application Security for a DevOps World" von John D. Wood nicht entgehen. Um ehrlich zu sein: Die Keynote hat mich nicht begeistert. Am ehesten noch fand ich interessant das er Zahlen hatte, das die meisten Sicherheitslücken (auch nach Bekanntwerden) noch über ein Dreiviertel-Jahr offen sind. Aua. Ein Satz am Ende ist bei mir hängengeblieben:

"DevOps bekommt jetzt auch Security."

Was simpel klingt, ist in der Realität alles andere als einfach – und betrifft uns ganz konkret. In einer Zeit, in der wir als Unternehmen KRITIS-relevant geworden sind, ist es für viele Risiken nicht mehr möglich sie einfach zu übernehmen (AKA aussitzen). Wir müssen sie aktiv mitigieren – und das gilt besonders auch für Security-Risiken.

Security: Aus DevOps wird "DevSecOps"?

Dev ist schon schwer. Ops noch schwieriger. Und jetzt kommt Security obendrauf. Nicht jedes Team kann oder will alle drei Disziplinen gleich gut abdecken. Und dennoch ist klar: Es kommt mehr Arbeit auf uns zu.

Wir werden bei bestimmten Anwendungen in Zukunft viel stärker darauf achten müssen:

  • Dass Betriebssysteme (in Docker-Containern) aktuell sind,
  • Dass Projektabhängigkeiten regelmäßig gepflegt werden,
  • Dass wir verstehen, welche Sicherheitslücken für uns relevant sind – nicht nur, weil ein Scanner sie anmeckert, sondern weil unsere eigene Risikoabwägung sie als kritisch einstuft.

Wunsch-Szenario: Expertise teilen, nicht duplizieren

Mein Wunsch wäre, dass nicht jedes Team die komplette Security-Expertise selbst aufbauen muss. Stattdessen sollten sich diejenigen, die sich besonders für das Thema interessieren, tiefer einarbeiten können – und jederzeit unkompliziert Zugang zu Spezialist\:innen haben. Idealerweise entsteht daraus eine Art Mentoring-Beziehung.

Das Ziel: Schnell und unbürokratisch Expertise bekommen, wenn man merkt, dass man sie braucht. Entwickler\:innen sollen lernen, Security-relevante Situationen zu erkennen und wissen, wo sie gezielt und niederschwellig Unterstützung finden.

Compliance-Checkbox oder echte Verteidigung?

Ein starkes Bild aus dem Vortrag war die Kritik an klassischen Security-Prozessen: Wöchentliche Scans, lange Backlogs mit offenen CVEs, endlos False Positives, wenig konkreter Nutzen. All das erzeugt ungeplante Arbeit, und widerspricht damit dem DevOps-Grundsatz "No unplanned work" – und hilft im Ernstfall wenig. Letztlich müssen wir ja die Daten unserer Versicherten Schützen, dass der Bug den ein Angreifer bei uns Ausgenützt hat schon lange bekannt war, hilft uns nicht weiter.

Fazit

Ich nehme aus dem Talk vor allem eines mit: Security können wir in Zukunft nicht länger als "Problem von jemand anderem" verstehen. Sie ist jetzt (oder wird es bald) integraler Teil von DevOps – ob uns das passt oder nicht.

Und wir müssen Wege finden, wie wir das gemeinsam schultern können – weil wir eben nicht jeden Entwickler zum Security-Experten machen können.

Die bittere Realität: Container-Sicherheit ist Kaputt

written by Martin Häcker on

Container Security Vor einigen Wochen war ich auf der DevOpsCon in Berlin. Einer der spannenderen Vorträge war für mich: "Supply Chain Security and the real world: Lessons from Incidents". Offiziell ging es um Sicherheit in Container-Umgebungen. Inoffiziell war es eine Abrechnung mit dem Chaos, das wir im Alltag mit Docker-Containern erleben.

Wir alle lieben Docker Hub: Schnell ein Image ziehen, starten, fertig. Aber was dabei oft vergessen wird: Selbst die als "offiziell" markierten Container bieten keinerlei Garantien. Weder über die Aktualität noch über Sicherheit. Fast alle dieser Container werden monatelang nicht aktualisiert, obwohl es CVEs für enthaltene Komponenten gibt.

Wenn man das ernst nimmt, müsste man:

  • Alle Container regelmäßig selbst neu bauen und dabei Updates der darin enthaltenen Distributionen installieren
  • Bei jeder Abhängigkeit überwachen, ob es CVEs oder Updates gibt
  • Die Upstream-Projekte verstehen, ihre Update-Kanäle abonnieren
  • Alle Dockerfiles durchdringen (insbesondere bizarr manuell installierter Binaries)

Kurz: Wer Container sicher betreiben will, muss eigentlich selbst zur Distribution werden.

Die Lösung: "Start Left" statt "Shift Left"

Die Firma Chainguard hat in dem Vortrag ihre Alternative vorgestellt: Ein Repository von sicherheitsoptimierten, rootlosen Containern, die alle:

  • ohne bekannte CVEs ausgeliefert werden
  • auf einem selbstgebauten, deterministischen OS basieren ("Wolfi", im wesentlichen Alpine mit GLibC statt Musl)
  • reproduzierbar gebaut werden (jede\:r kann sie nachbauen, wenn auch nicht Bit für Bit)
  • mit Software-Bill-of-Materials (SBOM) ausgeliefert werden
  • Auch im Container als normale Nutzer ausgeführt werden anstatt als `root`
  • und bei neuen Upstream-Vulnerabilities innerhalb von 7 Tagen gepatcht werden

Die Container sind FIPS-kompatibel, in zwei Varianten (Production vs. Dev - mit mehr Tools) verfügbar und mit bekannten Tools wie trivy problemlos scannbar. Offen Statistiken zeigen beeindruckend wie viel weniger CVEs sieh in Ihren Containern haben. Nämlich in der Regel gar keine.

Warum das für viele ein Game-Changer sein könnte

Wie in vielen Unternehmen, ist auch bei uns die Nutzung von Docker-Containern ein "Free for All": Jeder zieht, was er braucht, hauptsache es läuft. Sicherheitsrichtlinien? Nicht vorhanden. Updates? Machen wir Manuell alle Jubeljahre. Genau hier setzen die Container von Chainguard (oder auch Dockers eigene "Hardened Images") an:

Man könnte sagen:

Was sonst niemand zuverlässig macht, macht ChainGuard automatisch.

Und das Beste: Die Basis-Container sind sogar kostenlos (und damit z.B. auch für Open Source Projekte) verwendbar. Damit kann man ohne großen Aufwand den Produktivbetrieb auf eine wesentlich sicherere Basis stellen.

Gerade wenn man – wie bei KRITIS-Vorgegeben – innerhalb eines festen Zeitrahmens Sicherheitsupdates einspielen muss, ist eine verlässliche Update-Garantie Gold wert.

Mein Fazit

Container sind kein Selbstzweck – und sie haben einen großen Nachteil gegenüber Veränderbarer Infrastruktur: Man verliert die automatisch installierten Updates der Linux Distributionen. Wer diesen Aufwand nicht selbst stemmen will, braucht Alternativen. Die gehärteten Container von ChainGuard oder Docker sind ein vielversprechender Weg, um mit minimalem Aufwand viel weniger CVEs und fehlender Updates, sowie weit mehr Transparenz gewinnen kann.

Probiert es doch mal aus. Ich würde mich sehr über Feedback freuen wo die Grenzen und Probleme dieses Ansatzes liegen. Offensichtlich ist schon mal, dass dort nicht so viele Container gibt.

Grundsätzlich aber immer: Bitte Entscheidet euch bewusst für Images, die gepflegt werden. Und nicht für das erste, das die Suche auf Docker Hub zurück gibt.

Nützliche Shell-Kommandos: sort, uniq

written by Martin Häcker on

Set Operations Weil ich es heute wiederholt nachschlagen musste, hier noch eine Erinnerung an mich selbst, wie einfach es ist auf der Shell set Operationen durchzuführen.

In unserem Beispiel: ~10k Datenbank-IDs hier, ~15k Datenbank-IDs da, und die Frage welche davon nur in der einen Liste enthalten sind. Das ist dann einfach zu beantworten, wenn man die auf eine ID pro Zeile ausgibt, und dann einfach mit set_difference bearbeitet.

set_union () {
   sort $1 $2 | uniq
}

set_intersection () {
   sort $1 $2 | uniq --repeated
}

set_difference () {
   sort $1 $2 $2 | uniq --unique
}

set_symmetric_difference() {
   sort $1 $2 | uniq --unique
}

Quelle

DevOpsCon: Stolperfallen beim Aufbau interner Developer Platforms (IDP)

written by Martin Häcker on

Heute gibts den Start meines Berichts von der DevOpsCon 25. So viel allgemeines vorweg: War schön. Druckbetankung wie es sich gehört.

Los ging es mit einer Keynote über interne Entwickler-Plattformen und was dabei gerne schief geht.

1 | Reality-Check: 90 % der Devs nutzen schon eine IDP – wir auch

  • Laut Jessica arbeiten rund 90 % aller Entwickler:innen mittlerweile mit einer internen Plattform – oft, ohne es zu merken.
  • Wir auch? Was ist unsere Plattform?

2 | Das theoretische Fundament

Jessica empfahl vier Bücher, die jede:r Platform‑Builder kennen sollte. (Lustigerweise gab Sie zu, das Sie selbst noch nicht alle davon gelesen komplett gelesen hat.)

Buch Kernaussage für IDP Mein Take‑away
Transformed Von Silos zu empowereden Produkt‑Teams Auch Plattform‑Teams brauchen Produktdenken und Produkt-Manager.
Team Topologies Team‑Typen & Schnittstellen (u. a. Platform & Enabling Teams) Klingt sehr ähnlich zu dem wie wir organisiert sind. Unterschiede: Komplizierte Subsysteme brauchen eigene Teams. Enabling‑Teams sind hier fast immer temporär.
Accelerate Deploy‑Freq., Lead‑Time, Failure‑Rate, MTTR DORA‑Scores = Proxy für Platform-Team‑Erfolg. Nugget: Im Raum war niemand der alle 4 Metriken einsetzt, oder jemanden kennt der das tut…
Platform Engineering Plattform ersetzt Glue‑Code & schafft Self‑Service Eine IDP ist Software, kein Ops‑Team.

3 | Typische Fallstricke

  1. Menschen im Plattform-Team bringen ihre Erfahrungen mit
    • „It’s faster if I just do it.“ Sorgt gerne dafür das das Ergebnis auch nur Sie benutzen können.
    • Damit erzeugt man ein neues Ops-Silo. Dringend zu vermeiden. Das Ziel ist, das andere Teams sich selbst helfen können.
  2. Rudis Resterampe (Scope Creep)
    • Plattform‑Team sammelt alles, was sonst niemand machen will.
    • Konsequenz: Keine Zeit mehr für strategische Funktionen.
    • Braucht eine klare Vision, und insbesondere By-In von Leadership. Dann Iterationen und viel Kommunikation.
  3. Alles sofort lösen wollen (Rudis Resterampe 2.0)
    • Minimalismus ist King 👑. Nicht jedes Problem muss gleich gelöst werden.
    • Priorisiere Onboarding, Self‑Service & Empowerment.
  4. Das falsche Problem Lösen
    1. Es ist sehr einfach das falsche Problem zu lösen. Schließlich sind wir alle Entwickler und wissen was wir brauchen.
    2. Aber jedes Team ist anders und hat andere Aufgaben. Daher ist es unglaublich wichtig mit den Menschen intensiv zu sprechen die man beglücken will.
    3. Plattform-Engineering braucht genauso Produkt-Management und einen Produkt-Manager wie andere Themen. Wenn das Budget dafür nicht vorhanden ist, muss man diese Aufgaben trotzdem erfüllen.
  5. Plattform‑Migrationen unterschätzen
    • Jede Migration ist Schmerzhaft und kostet Vertrauen (Vertrauen ist wie eine Währung. Wenn man es ausgegeben hat, ists wech).
    • Daher so wenig Migrationen wie möglich, und diese gut vorbereiten, auch wenn es viel Aufwand erzeugt.
    • Ziel: Automatisierte, Low‑Impact‑Migrationspfade.

4 | Fragen an den Leser

  1. Was ist deine aktuelle Plattform?
  2. Wo klemmt es eigentlich derzeit?
  3. Macht es Sinn die DORA‑Baselines zu messen?

5 | Fazit

Ein internes Developer‑Platform‑Team ist kein Sonder‑Ops‑Team, sondern ein Produkt‑Team mit klarer Vision, fokussiertem Scope und messbarem Impact. Je einfacher, desto besser – und Vertrauen ist kostbar.

„Minimalismus ist King – löse die wichtigsten 20 % zuerst, die den Teams 80 % des Schmerzes nehmen.“ – Jessica Anderson

Die Freuden einer gut eingerichteten Shell: fzf

written by Martin Häcker on

fzf

Nachdem es bisher in der Serie um die grundlegende Einrichtung der Shell, einen guten Prompt und funktionierende autoomatische Vervollständigung ging, geht es jetzt eine Weile um Werkzeuge um mit der Shell effizient zu navigieren und Dateien und Inhalte zu finden.

Einleitung

Hier geht es mir darum das die Arbeit auf der Shell (auf dem eigenen Rechner vor allem) nur dann schnell und Effizient ist, wenn man schnel und einfach in die Ordner kommt in denen man arbeiten möchte, und die Dateien findet in denen etwas interessantes steht das man entweder lesen oder verändern möchte.

Und natürlich ist das Skillset auch auf beliebige Server transferierbar, weil man alle diese Werkzeuge (oder deren etwas primitivere Variante, dazu später mehr) auch auf einem Server, oder in einem Docker-Container, gerne auch auf einem Kubernetes-Cluster in Produktion einsetzen kann, wo man sonst halt nicht so viele Werkzeuge hat, und schon gar nicht seine IDE anschließen kann um zu versuchen dort Herr der Lage zu werden.

Dazu möchte ich euch die Tools zoxide, grep/ripgrep, fzf, less/cat/bat und direnv vorstellen.

Diese Tools erleichtern viele täglich oft wiederholte Arbeitsabläufe dramatisch, und sie ermöglichen viele Use-Cases, die viele grafischen IDEs und Text-Editoren gar nicht unterstützen. Los geht es mit dem flauschigsten der Tools, fzf.

Zackig die richtige Datei finden: fzf

fzf frei Eingezangendeutscht "der flauschige Kommandozeilen Finder", ist ein werkzeug um Dateien (aber auch beliebige andere Dinge) anhand von teilen des Namens oder Mustern wie jeder erste Buchstabe der Wörter ihres Namens zu finden. Dazu bietet dieses Werkzeug eine Oberfläche die interaktiv die Liste der Auswahlmöglichkeiten filtert während man tippt. Die meisten IDEs bieten so eine Funktion irgendwo mehr oder weniger gut versteckt an, und dieses Werkzeug portiert diese Funktionalität als generisches Werkzeug in die Shell.

Als beispiel: Ich möchte einen bestimmten UnitTest ausführen:

$ bin/run_tests_in_docker.sh $(fzf)

Mit diesem Kommando, wird zuerst fzf aufgerufen (wegen $(fzf)) was dann eine oberfläche präsentiert, mit der man interktiv die richtige oder die richtigen Dateien auswählen kann.

# ich verwende die fish shell, daher brauch ich das $ nicht
❯ bin/run_tests_in_docker.sh (fzf)
  src/models/dokumente/tests/document_distribution_test.py
  src/controller/process_distribution/tests/models_test.py
  src/models/dokumente/tests/dokumente_test.py
  src/integration/d3/api/test/models_test.py
▌ src/models/tests/kontaktdaten_test.py
  5/448 ────────────────────────────────
> models 'test.py

In dem Interface kann man auch mit den Pfeiltasten navigieren, oder einen Eintrag anklicken. Der von mir eingegebene Suchstring "models 'test.py" bedeutet, dass 'models' irgendwo in dem Treffer diese Buchstaben in dieser Reihenfolge vorkommen müssen, während "'test.py" erzwingt das der exakte String 'test.py' vorkommen muss.

Wenn man die fzf-Integration mit der eigenen Shell aktiviert, kriegt man viele weitere Integrationen in die Shell dazu. Zwei Beispiele:

  • ⌃-T sucht (mit Vorschau!) nach Dateien unterhalb des aktuellen Verzeichnisses. Das ist immer dann Praktisch wenn man für ein Kommando eine Datei aus dem aktuellen Projekt als Argument übergeben muss, und spart das tippen von $(fzf). Klar, mit Auto-Vervollständigung kommt man auch ans Ziel, aber das ist soo viel schneller. Insbesondere wenn man nicht genau im Kopf hat wo die Datei liegt, aber noch weiß was in Ihrem Namen oder Pfad vorkommen muss. Das verwende ich die ganze Zeit.

  • ⌃-R sucht mit fzf in der Shell-Historie. Das funktioniert viel besser als die Standard-Suche, die nur nach direkt zusammenhängenden Buchstaben suchen kann. Ein Beispiel: Das Wenn ich das Kommando helm template extensions ./k8s/extensions/ --values ./k8s/extensions/values.dev.yaml | yq aus meiner historie suchen möchte, müsste ich ohne fzf den exakten Text schreiben der in dem Kommando vorkommt.

~
Search History> helmtemplateexten
  76/32637 (0)
  02-17 18:07:03 │ helm template extensions ./k8s/extensions/ --values ./k8s/extensions/values.dev.yaml
  02-17 18:06:10 │ helm template extensions ./k8s/extensions/ --values ./k8s/extensions/values.dev.yaml | yq
  02-17 17:59:53 │ helm template extensions ./k8s/extensions/ --values ./k8s/extensions/values-dev.yaml
  02-17 20:22:18 │ helm template  extensions ./k8s/extensions/ --values ./k8s/extensions/values.dev.yaml
  02-17 18:15:27 │ helm template --debug extensions ./k8s/extensions/ --values ./k8s/extensions/values.dev.yaml
  02-17 17:59:42 │ helm template --dry-run --debug extensions ./k8s/extensions/ --values ./k8s/extensions/values-dev.yaml
▌ 02-17 17:59:29 │ helm template --dry-run --debug  ./k8s/extensions/ --values ./k8s/extensions/values-dev.yaml
  02-17 17:59:36 │ helm template --dry-run --debug foo ./k8s/extensions/ --values ./k8s/extensions/values-dev.yaml
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
│ helm template --dry-run --debug ./k8s/extensions/ --values ./k8s/extensions/values-dev.yaml  │
╰──────────────────────────────────────────────────────────────────────────────────────────────╯

Wenn ich oft, wenn ich ein neues Terminal öffne in die gleichen Projekte navigiere, dann geht das prima über die Shell-History:

# ctrl-r für history suche
Search History> cdmkkapi
  352/32638 (0) ──────────────────────────
  08-12 11:56:19 │ cd mkk/api
  08-24 19:05:13 │ cd ../mkk/api
▌ 05-26 08:39:19 │ cd Code/Projekte/mkk/api
  07-29 17:02:48 │ cd Code/Projekte/mkk/api_infra/
  02-15 08:37:01 │ cd Code/Projekte/mkk/api_infra/monitoring/
╭──────────────────────────╮
│ cd Code/Projekte/mkk/api │
╰──────────────────────────╯

Mit Zoxide geht das noch besser, aber dazu später mehr.

So habe ich meine fzf Integration konfiguriert:

# configure key-bindings for fzf-fish
# ctrl-f directory search
# ctrl-r history search
# ctlr-v variables search
# ctrl-l git log search
# ctrl-s git status search
# ctrl-p processes pid search
fzf_configure_bindings --git_log=\f --directory=\cF --git_status=\cS --processes=\cP

Das geniale an fzf ist, dass es sich so wunderbar in andere Tools integrieren lässt. Hat man es installiert wird es z.B. von KubeCTX verwendet um in kubectx die liste der verbundenen Kubernetes Cluster zu filtern. Oder von kubens um die Liste der Namespaces. Tatsächlich verwenden viele Werkzeuge intern fzf wenn es instaliert ist. Für mich immer wieder eine schöne Überrachung, wenn ein weiteres Werkzeug das ich gerne einsetze fzf verwendet.

Die Freuden einer gut eingerichteten Shell: Autocomplete

written by Martin Häcker on

Was ist schlechte Vervollständigung?

Um zu verstehen was ich mit guter Auto-Completion für Shells meine, brauchen wir erst einmal eine Baseline wie eine schlechte Completion aussieht. Das lässt sich sehr gut mit Docker demonstrieren: 

docker run --rm -it --hostname shell-completion-demo debian

Erstes Experiment: ls⇥⇥ (kein Leerzeichen vor den Tabs!)

Automatische Vervollständigung von Kommandos - unkonfiguriert

Zeigt alle Kommandos die mit ls anfangen Zweites Experiment: ls ⇥⇥ Das zeigt bei mir:

Automatische Vervollständigung von Dateien - unkonfiguriert

Schon mal gut, denn hier werden die Dateien im aktuellen Ordner vervollständigt.

Nächste Schwierigkeitsstufe - kurze und lange Optionen: ls -⇥⇥ (Minus vor dem Tab) Das zeigt hier nichts, genauso für lange Optionen ls --⇥⇥ (zwei mal Minus vor dem Tab)

Keine Ausgabe. ls ist eigentlich so ungefähr das einfachste Programm das jeder Shell beiliegt. Wenn automatische Vervollständigung also irgend etwas kann, dann sollte ls gut funktionieren.

Was ist gute Vervollständigung?

Dagegen mal ein Beispiel von meinem System:

ls⇥ zeigt die Kommandos die mit ls anfangen, mit einer Kurzbeschreibung was diese Kommandos tun.

Vervollständigung von Kommandos mit der Fish-Shell

Schon mit einem Tab sehe ich die Dateien, und zusätzlich sehe ich als Vorschlag den letzten Befehl den ich mit ls abgesetzt habe und kann diesen mit ⌃→ im ganzen, oder mit wortweise akzeptieren kann.

Automatische Vervollständigung von Dateien mit der Fish Shell

Ein ls -⇥ergibt sofort eine Optionsliste - kurz und lang - mit einer Kurzbeschreibung was dieses Schalter tun. Ein zweites Minus und Tabls --⇥` zeigt nur noch die langen Optionen an:

Vervollständigung von Optionen mit der Fish-Shell Vervollständigung von langen Optionen mit der Fish-Shell

Natürlich kann ich mit den Pfeiltasten oder mit Tab eine der Optionen auswählen - natürlich mit ordentlichem Highlighting. So macht arbeiten auf der Shell Spaß!

Falls Ihr verwirrt seid das mein ls andere Optionen anbietet als eures, dann liegt das daran das ich ls durch exa ersetzt habe.

Wie könnt Ihr das bei euch nutzen?

Ich nutze die Fish-Shell, da diese von Haus aus eine sehr gute Autocompletion anbietet. Das ist aber nicht für jede, denn die Syntax der Fish Shell ist etwas anders als bei Bash/ZSH - eben nicht posix kompatibel. Ich mag das Weil es logischer und Kürzer ist, aber ich komme auch nicht durcheinander mit den verschiedenen Shell-Syntaxen da ich sie schon so lange verwende.

Fast alle Shell Konfigrurations-Frameworks wie oh-my-zsh oder Prezto bieten zumindest etwas an das diesem Nahe kommen. Alle automatische Konfiguration stößt aber irgendwann an Ihre Grenzen wenn es um die Kommandos geht, die wir täglich benutzen. docker vervollständigt dann nicht compose und oder kennt die Unterkommandos davon nicht oder nur unvollständig, kubectl und helm sind notorische Kandidaten für die man sich selber kümmern muss.

Jetzt könnte man natürlich versuchen automatisch aus der Hilfsausgabe dieser Kommandos etwas zu generieren (das macht z.B. die Fish shell von sich aus) oder man schreibt selber etwas (argh).

Oder man wendet sich vertrauensvoll an das tool carapace, mit dem man die Completion für Programme komfortabel für alle Shells nachrüsten kann. Als Beispiel um die die Autocompletions für kubectl nachzurüsten, einfach source <(carapace kubectl zsh) oder carapace kubectl fish | source (je nach shell) eingeben und ausprobieren ob es gefällt, und wenn ja, diese Zeile in die User-Konfiguration deiner shell eintragen und viel glücklicher sein.

Obacht: Man kann mit so einem Snippet

# ~/.zshrc 
export CARAPACE_BRIDGES='zsh,fish,bash,inshellisense' # optional
zstyle ':completion:*' format $'\e[2;37mCompleting %d\e[m'
source <(carapace _carapace)

in seiner Shell-Konfiguration alle completer des Carapace Projekts aktivieren. Das hat mir allerdings nicht gefallen,, da ich manche der eingebauten Completer der Fish-Shell noch etwas besser finde als das was Carapace bereit stellt. Aber um Lücken zu ergänzen? Perfekt!

Meine Shell-Completion Konfiguration (fish!) sieht daher so aus:

# enable shell completions
set --global --export CARAPACE_BRIDGES 'zsh,fish,bash,inshellisense'
# I didn't have much luck enabling all carapace completions, but I do like some of them - especially if there is no built in fish completion for them
# carapace _carapace | source
carapace fd | source
carapace bat | source
carapace brew | source
carapace rg | source
carapace docker | source
uv generate-shell-completion fish | source
yq completion fish | source

Die Freuden einer gut eingerichteten Shell: Der Prompt

written by Martin Häcker on

Terminal

Es fängt natürlich mit der Frage an: welche Shell?

Das ist sehr einfach zu beantworten. Auf MacOS ist die zsh die Standard-Shell - und daher sollte man die auch benutzen. Artikel Fertig, vielen Dank fürs Lesen! 😅

Windows hat die PowerShell - wer damit Arbeiten (muss) sollte sie lernen!

Die nackte Shell ist ziemlich schlecht konfiguriert, da die Möglichkeiten der Shell gar nicht ausgenutzt werden. Auf Linux-Distributionen ist es Standard, dass die Shell von der Distribution eingerichtet wird, daher kann man damit meistens schon gut arbeiten.

Aber für MacOS (und Windows) gibt es viel zu tun.

So sieht die zsh unkonfiguriert aus:

dwt@NB1321 ~ % cd Library/Favorites
dwt@NB1321 Favorites %

Das ist schon gar nicht schlecht, denn man sieht einiges:

  • dwt: Welcher Nutzer man gerade ist. Wichtig, wenn man viel mit sudo arbeitet, damit man nicht versehentlich Kommandos als root mit zu vielen Rechten ausführt.
  • NB1321: Auf welchem Rechner man gerade eingeloggt ist. Wichtig wenn man auf vielen Rechnern arbeitet und nicht
  • Den aktuellen Ordner in dem man ist (Favorites). Wichtig damit man z.B. nicht versehentlich die falschen Dateien löscht.
  • Der Prompt % trennt die Meta-Informationen von dem was man selbst eingibt.

Da geht aber noch wesentlich mehr. Bei mir z.B. sieht der Prompt so aus:

~/C/P/m/api ❄️ 🧪 nix-shell-env   🐍 venv ⛵️ mkk-itsc-dev (api) 🌱 main $!  4s
❯

Da ist enthalten:

  • ~/C/P/m/api - nicht nur der aktuelle Ordner, sondern auch jeweils der Anfangsbuchstabe der darüber liegenden Ordner. Das liefert platzsparend viel mehr Kontext, wo man gerade ist. Super wenn man in vielen Projekten gleichnamige Ordner wie z.B. etc, src oder dist hat.
  • ❄️ 🧪 nix-shell-env Zeigt an, dass gerade eine 'dreckige' Nix-Shell aktiv ist. Das verwende ich um Projek-spezifische Abhängigkeiten (Shell-Tools, bestimmte Vesionen von Python etc.) zu installieren die ich deklarativ im Projekt tracke. Gut vergleichbar mit Python-Virtual-Envs - aber eben für alles, nicht nur Python-Pakete. Dreckig ('impure') ist Sie, da nicht nur die Shell-Tools aus der Nix-Shell sichtbar sind, sondern auch alles andere was ich im Betriebsystem installiert habe.
  • 🐍 venv - zeigt an, dass gerade ein Python-Virtual-Env aktiv ist. Da ich hauptsächlich mit Pyton entwickle ist das natürlich entscheidend weil es bedeutet das ich die Projekt-Werkzeuge direkt verwenden kann, da sie im $PATH und $PYTHONPATH sind.
  • ⛵️ mkk-itsc-dev (api) zeigt an, dass ich mit dem mkk-itsc-dev Kubernetes Cluster verbunden bin, und den Namespace api aktiviert habe. Das ist mir sehr wichtig, damit ich nicht versehentlich mit kubectl Befehlen versehentlich den Produktiv-Cluster zerstöre. (Rate wieso mir das so wichtig ist…)
  • 🌱 main $! zeigt an, dass ich in einem Git-Repository bin, auf dem main branch, das ich dinge ge-'stash't habe (die vergisst man sonst sehr leicht) und das ich Änderungen habe die ich noch nicht commited habe. Hier gibt es auch noch mehr informationen wenn das Repo den entsprechenden Zustand hat.
  • Zuletzt sehe ich da das letzte Kommando 4 Sekunden gedauert hat. Das wird nur angezeigt wenn das letzte Programm mehr als 3 Sekunden gedauert hat und ist immer wiede ein hilfreiche Information um bei langlaufenden Prozesen zu verstehen ob es sich lohnt da etwas zu optimieren.

Natürlich könnte man hier noch viel mehr anzeigen, je nachdem an was man gerade arbeitet. Ich habe hier eben die Informationen aufgenommen die ich am meisten benötige.

Jetzt kommt der Clou: Früher habe ich das alles von hand Konfiguriert. Das war ein ewiges und mühsammes gefummel um $PS1 und konsorten so hinzufummeln das das alles funktioniert hat, und hat nie Spaß gemacht. Der Standard ist derzeit, das man einen Shell-Konfigurations-Framework wie Oh-My-Zsh oder Prezto verwendet. Und die sind auch gut. Aber auch langsam, und komplex und kompliziert. Wenn man da mal etwas anders haben will dann gott bewahre wenn das nicht schon vorbereitet ist oder man darf sich nicht nur mit den Komplexitäten von $PS1 auseinandersetzen, sondern auch noch damit wie genau dieser Framework das handhabt.

Inzwischen bin ich weiser geworden, und verwende Starship. Damit kann ich meinen Prompt deklarativ in einer .toml-Datei konfigurieren und diesen auch mitnehmen wenn ich mal die Shell wechsle. (Was häufiger vorkommt als mir lieb ist). Und: Starship funktioniert auch mit der PowerShell.

So sieht meine Konfiguration aus

Wie richtet man das ein?

  1. brew install starship (oder mit nix)
  2. nano ~/.zshrc und am Ende eval "$(starship init zsh)" einfügen.
  3. Konfigurationsdatei erstellen: nano ~/.config/starship.toml und z.b. den Inhalt aus der Datei oben einfügen.
  4. Shell neu starten oder neues Terminal öffnen.

Danke sagen für die grandiose Verbesserung eures Shell-Lebens bei mir nicht vergessen. 😅

A Nix'le in a Büchse und a goldigs Warteweile

written by Martin Häcker on

Das Nix Hasenloch … ist ein schwäbisches Sprichwort und passt gar nicht so schlecht für die vielen schlechten Wortwitze die sich automatisch ergeben, wenn man anfängt, sich in das Nix Projekt einzuarbeiten.

Zunächst mal die Karotte mit der ich mich ködern ließ:

  • Deklarative Konfiguration von Software-Builds, System-Konfigurationen, und wenn man möchte auch Deployments z.B. in Kubernetes und was man sonst gerne möchte
  • Ein funktionaler Paket-Manager, das heißt: Jede Software kann ihre eigenen Abhängigkeiten in der passenden Version haben. Wenn ich mal ein Tool in der Version von vor 10 Jahren brauche - einfach zusätzlich installieren, ohne dass dadurch etwas gestört wird. Wenn ich mal eine neuere Version von etwas brauche als die aktuelle Distribution anbietet: Einfach installieren, ohne dass dadurch etwas gestört wird.
  • Rollback: Systemkonfiguration hat etwas kaputt gemacht? Einfach Rückgängig machen.
  • Update auf eine neue Version des Betriebssystems: Man kriegt fehlermeldungen für alle Konfigurationen die man vorgenommen hat die jetzt umbenannt wurden oder anders funktionieren. 🤯
  • Reproduzierbarkeit: Vollständige Erfassung der Inputs und Ablegen derselben in einem Lock-File.
  • Eine riesige Community, die beste Praktiken zum Betrieb von Linux (und mehr) Systemen in die größte Software-Bibliothek kodiert, die wir bisher gesehen haben.

Was sollte man da nicht mögen?

Auf MacOs gibt es mit nix-darwin ein Projekt mit dem man die System-Konfiguration deklarativ vornehmen kann - und auch homebrew (was sonst so gut wie gar nicht reproduzierbar ist) unter Kontrolle kriegt. Und wenn man möchte, verwaltet es einem auch die dotfiles.

Es gibt allerdings einen gewaltigen Nachteil: Das Ganze ist echt komplex und kompliziert. Und die Dokumentation ist nicht schlecht, aber könnte deutlich besser sein.

Wenn man diese Hürde überwindet, wird man mit einer erstaunlich kompakten und sehr schnell anzuwendenden System-Konfiguration belohnt. Damit kann man zum Beispiel auf einem Mac ein vollständig konfiguriertes System-Image für einen Raspberry Pi erstellen. Dann noch flaschen, starten und läuft! Oder auf meinem Mac Bauen, und via ssh auf dem RasPi deployen, ohne dort irgendwas zu machen was dessen CPU stresst.

Ich habe inzwischen angefangen, meine Rechner damit zu verwalten und konfigurieren.

Nix ist vielleicht nichts für dich…

… aber wenn Du ein bisschen nerdig bist, und gerne auf der Kommandozeile lebst, infrastruktur as Code magst oder lernen magst und DevOps für dich eh normal ist. Dann könnte Nix auch für dich genau das richtige sein.

Wie lernt man Nix am besten?

Was mir beim Lernen von Nix gefehlt hat, wäre eine Leitlinie gewesen, in welcher Reihenfolge ich mich an die vielen Features von Nix heran tasten sollte. Eine Reihenfolge, die sicherstellt, das die Lernkurve zu jedem Zeitpunkt erträglich bleibt. Und besonders wichtig: Die Sicherstellt, das zu jedem Zeitpunkt sichtbar ist wie cool und wertvoll diese Technologie ist. Sonst läuft man Gefahr, ob der steilen Lernkurve abzuspringen.

Das hätte ich gerne gehabt: Wenn du anfängst Nix zu lernen, dann am besten in dieser Reihenfolge:

1. Schritt: Installieren, ohne was bestehendes kaputt zu machen

Zuerst sollte man Nix neben dem aktuellen OS installieren. Der Standard ist der Determinate Installer, aber ich mag das Lix Projekt lieber, da es schneller ist. Alternativ ist auch der Nix-Docker-Container super um es mal auszuprobieren. Wenn man möchte, kann man Nix (auf Linux) auch einfach in einen Ordner installieren und so verwenden (siehe "Single-User Mode"). Das würde ich aber nur für ein paar Experimente empfehlen. Sowohl der Determinate als auch der Lix-Installer haben sehr gute Uninstaller die das Projekt auch wieder komplett entfernen können.

2. Schritt: Imperativ verwenden

Nix erlaubt es jederzeit ein Paket zu benutzen, ohne es zu installieren. Das ist eine Konsequenz davon wie der Paket-Manager aufgebaut ist. Ein Paket kann 'im /nix/store/ sein' - ohne das es aktiv ist. Und der Befehl nix run nixpkgs#fzf startet es dann einfach - ohne es zu installieren. Alternativ gibt es auch nix shell nixpkgs#fzf. Damit erhällt man eine Shell, in der fzf installiert ist. Schließt man die Shell, ist es auch wieder weg. 😳

Dass ist der Hammer, weil man so Pakete ohne Reue ausprobieren kann. Ohne Sorgen, dass doch noch irgendwelche Abhängigkeiten evtl. auf dem System herum gurken und man vergessen könnte ein Experiment wieder zu entfernen. Und das beste: Auch später wird man dieses Feature die ganze Zeit verwenden.

Vorsicht vor nix-env und nix profile - das ist das Äquivalent zu dem wie man mit homebrew und anderen Paketmanagern Pakete installieren würde. Diese sollte man so selten wie möglich verwenden. Besser ist…

3. Schritt: Entwicklungsumgebungen shell.nix

Das, was nix shell nixpkgs#fzf macht, kann man auch in eine Datei schreiben, und damit einfach in ein Repo mit einchecken. Schon hat man Deklarativ die ganzen Tools im Repo dokumentiert, die man braucht um mit einem Projekt zu arbeiten. Bonus: Ich kann für jedes Projekt eigene Versionen der Abhängigkeiten haben (wenn ich das brauche). Python-Virtual-Envs auf Steroiden!

Hier ein Beispiel:

{
  pkgs ? import <nixpkgs> { },
}:
pkgs.mkShell {
  buildInputs = with pkgs; [
    # Add your build inputs here
    pkgs.python313
    pkgs.uv
  ];
  env = {
    UV_PYTHON = pkgs.python313;
    UV_DOWNLOAD_PYTHON = "never";
  };
}

Wenn man das mit nix-shell aufruft, dann hat man diese Python-Version zur Hand. uv verwendet diese und lädt selber keine Python-Versionen herunter. Nice! Extra nice: mit nix-shell --pure hat man eine Shell in der nur das sichtbar ist was in dem shell.nix steht, und man kriegt Fehler für alles was man verwendet und in der shell.nix vergessen hat. 🤯

Bonus: Direnv verwenden um automatisch die shell.nix und das .env zu laden. Dazu zoxide um schnell in der Shell zwischen vielen Projekten hin und zu springen. Eine richtig geniale Entwicklungsumgebung.

Ich empfehle erst mal eine weile auf diesem Niveau zu bleiben, denn das ist schon ziemlich cool!

4. Schritt: Mehr Tooling um besser mit Nix klar zu kommen

  • Pakete findet man am besten über die Webseite search.nixos.org - aber ich mag eigentlich in der shell suchen. nix run nixpkgs#nh search ut1999 funktioniert besser als alles was ich sonst bisher getestet habe.
  • Anzeigen was gerade installiert ist und wieso ist aufgrund der Architektur von nix gar nicht so einfach. nix run nixpkgs#nix-tree aproximiert das und gibt einen guten überblick darüber was man auf dem System hat.
  • nom - der Nix-Output-Monitor nix run nixpkgs#nix-output-monitor macht den output von längeren nix builds viel informativer und spannender. Verwenden kann man das so: nix run $something |& nix run nixpkgs#nix-output-monitor
  • nix store gc um alles zu löschen, was man mal testweise runtergeladen hat und nicht mehr auf der Platte braucht. (Einer Der Nachteile von Nix: Es verbraucht schnell viel Plattenplatz).

5. Schritt: Tief in das Hasenloch fallen

Jetzt gibt es verschiedene Sachen die man sich anschauen könnte

Grundlegende Funktionen und Einstellungen des Terminals

written by Martin Häcker on

Der Terminal-Emulator ist ein zentrales Werkzeug, mit dem wir Entwickler mit unseren Rechnern interagieren. Jedes bisschen Wissen und jede Effizienz, die du hier gewinnst, zahlt sich in kürzester Zeit hundertfach aus.

Natürlich gibt es viele Terminals, wie iTerm2, Alacritty oder Kitty. Aber ich finde, diese solltest du nur verwenden, wenn sie deinen Workflow wirklich verbessern. Und dafür musst du zuerst wissen, was Apple standardmäßig mitliefert.

Das Schöne am Terminal ist, dass du unglaublich wenig anpassen musst, da es von Haus aus sehr gut funktioniert.

Ich nutze das eingebaute Terminal von macOS mit nur zwei (!) Konfigurationsanpassungen.

Wortweise Löschen

Wortweise Löschen

Die erste wirklich wichtige Anpassung für mich ist, dass ⌥-⌫ (Alt-Delete) als Standard-Keybinding gesetzt wird, damit wortweise nach links gelöscht wird. Damit passt du das Terminal an den Mac-Standard an, der in fast allen anderen Programmen ebenfalls funktioniert.

So geht's:

  1. Terminal → Einstellungen öffnen (⌘-,).
  2. Auf der linken Seite alle Profile auswählen, damit alle Einstellungen gleichzeitig bearbeitet werden.
  3. Auf der rechten Seite → "Tastatur" auswählen.
  4. Einen neuen Shortcut hinzufügen.
  5. Die Felder wie im Screenshot ausfüllen. \027 steht für ⌃-w (ctrl-w), den Standard-Shortcut für wortweises Löschen in der Shell.

Ausgabe navigieren, selektieren und löschen

Die nächst-wichtigsten Shortcuts sind:

  • ⌘-N / ⌘-T / ⌘-W: Alles Standard, aber trotzdem meine meistbenutzten Shortcuts.
  • ⌘-↑ und ⌘-↓: Zum Anfang des vorherigen bzw. nächsten ausgeführten Befehls springen. Das ist super praktisch, um schnell nachzusehen, was die vorherigen Kommandos waren.
  • ⌘-Shift-↑ und ⌘-Shift-↓: Wie oben, aber selektiert zusätzlich. Damit kannst du schnell einen Befehl und dessen Ausgabe kopieren. Das ist super praktisch, um Anleitungen zu schreiben oder einem Kollegen zu zeigen, wie etwas gemacht wurde.
  • ⌘-L: Löscht nur die Ausgabe des letzten Kommandos. Sehr praktisch, um ein nicht mehr benötigtes Shell-Experiment zu entfernen – besonders bei Fehlern mit viel Output. Oft nutze ich das, wenn ich zuerst eine Hilfe anzeige und dann darunter verschiedene Experimente ausführe, um die richtigen Flags zu finden. (Genauer: ⌘-L löscht vom Ende bis zur aktuellen Selektion und funktioniert daher hervorragend mit ⌘-↑.)
  • ⌘-K: Terminal löschen. Die nukleare Option – sie löscht alles im aktuellen Terminal. Großer Nachteil: Was weg ist, ist weg. Also nicht benutzen, wenn du den Output noch brauchst. Dennoch ist dies einer meiner am häufigsten benutzten Shortcuts.

Unbegrenzter Puffer

Unbegrenzter Puffer

Die zweite Anpassung, die ich vornehme, ist, den Scrollback-Puffer auf unbegrenzt zu stellen, damit ich die Ausgabe von langen Kommandos nicht verliere. Das geht so:

  1. Terminal → Einstellungen öffnen (⌘-,).
  2. Wie zuvor alle Profile auswählen.
  3. Auf der rechten Seite → "Fenster" → "Zeilenpuffer" auf „auf den verfügbaren Speicher begrenzen“ stellen.

Fazit

Mit diesen Shortcuts kannst du ultraschnell zwischen den letzten Kommandos navigieren, deren Ausgabe selektieren (und kopieren) oder löschen.

Diese Anpassungen und Shortcuts sind für mich auch einer der Hauptgründe, warum ich die eingebauten Terminals in IDEs nicht gerne benutze. Denn dort funktionieren sie oftmals nicht gut.

Viele dieser Einstellungen und Shortcuts gibt es auch auf der Ebene der Shell. Der Vorteil, sie über das Terminal zu konfigurieren, ist, dass diese Shortcuts auch auf anderen Servern oder in Docker- bzw. Kubernetes-Containern funktionieren.

Ich hoffe, diese Tipps helfen dir, das Terminal noch besser zu nutzen.

Kennst du weitere nützliche Shortcuts oder Einstellungen, die ich nicht erwähnt habe? Hast du Fragen zu den vorgestellten Tipps? Lass es mich wissen!

Happy Shelling!

Wie kann KI beim Lernen mit Blooms-Taxonomie unterstützen?

written by Martin Häcker on

Blooms Taxonomie

Nachem ich jetzt lange über Blooms Taxonomie und was die Ebenen im Detail bedeuten geschrieben habe, kann ich jetzt endlich zu dem kommen, was mir eigentlich am Herzen liegt:

Mein ganzes Leben lang haben andere die Ebenen von Blooms Taxonomie verwendet um zu beurteilen wie gut ich etwas verstanden habe - aber man kann diesen Spieß auch umdrehen, und das wissen um diese Ebenen des Verständnisses nutzen um selbst besser zu lernen! (Ehrlich gesagt, bin ich ziemlich angepisst das mir das nicht von Vorne herein genau dafür erklärt und beigebracht wurde)

Wie funktioniert das? Wenn Mensch ohne Plan lernt, dann neigen wir dazu uns zunächst auf den unteren Ebenen zu bewegen. Denn das ist (vermeintlich) einfacher und erscheint logisch. Aber aus der Forschung wissen wir, dass sich von vorne herein auf Fragen der 4. und 5. Ebene (also Analysieren und Bewerten) zu konzentrieren, nicht nur schneller, sondern auch tieferes Verständnis bringt.

Warum? Weil sich die Art und Weise verändert mit der wir uns mit dem Lern-Material beschäftigen. Auswendig Lernen ist ja nicht verzichtbar. Man muss sich die Fakten ja merken. Aber das passiert auch, wenn man sie Analysiert und Bewertet - ABER - wir kriegen die Analyse und Bewertung gratis dazu. (Wohlgemerkt, für etwas mehr Kognitive Anstrengung, aber Entspannung ist ja nicht das Ziel.)

Und das ist der Clou. Gleicher Zeiteinsatz, aber tieferes Verständnis.

🤯

Jetzt ist natürlich nicht jeder mit der Fähigkeit geboren, sich selbst einfach so Fragen auf der 4. und 5. Ebene zu stellen. Aber das ist auch gar nicht nötig. Denn KI kann dabei prima helfen.

Chat-GPT hat ein sehr gutes Verständnis von Blooms-Modell und kann endlos fragen auf Bloom Level 4 und 5 zu jedem Thema generieren. Die sind nicht immer perfekt, es reicht aber, um sich darauf einzustimmnen wie solche Fragen aussehen und effizient selbst zu solchen Fragen zu kommen.

Und das ist für mich ein gamechanger, und super sinnvoller Einsatz von KI.

Hier mal ein Auszug aus einem Chat mit Chat-GPT. Das ist sicher nicht perfekt, aber ein starker Anfang. Chapeau, Chat-GPT!