Cross podman-compose Namensauflösung

Annahme: Zwei Verzeichnisse mit docker-compose.yaml die mit podman-compose ins Leben gerufen werden.

Defaultverhalten: Selbst bei Angabe von “networks:” im docker-compose.yaml sehen sich die zwei Deployments nicht weil sie in zwei Podman Netzwerken erzeugt werden. Die Netzwerke werden immer mit dem Verzeichnisnamen prefixiert (podman network ls).

Ziel: Container aus Deployment A sollen Container aus Deployment B namensmäßig auflösen und auch netzwerkmäßig erreichen können.

Lösung: Identen Projektnamen beim Aufruf von podman-compose für beide Deployments angeben

podman-compose -p meinprojekt up -d

❗ Sollten networks: im yaml verwendet werden müssen die Container die miteinander kommunizieren sollen natürlich auch im gleichen Network sein – der Projektname ist nur der Prefix des Netzwerks.

Debian + fail2ban = Have not found any log file for sshd jail

Gemäß Issue ist das ein Problem von allen systemd-basierten Distros die nur mehr in journald loggen – in /etc/fail2ban/jail.local in Sektion [DEFAULT] das Setting backend auf systemd setzen:

# /etc/fail2ban/jail.local 
# (gemäß Doku von /etc/fail2ban/jail.conf kopiert)

[DEFAULT]
backend = systemd

[sshd]
enabled = true

Damit das funktioniert muss man noch folgendes Paket installieren:

sudo apt install python3-systemd

Wie man im Issue auch nachlesen kann bringt das natürlich alle Jails um die in Logfiles suchen wollen 😐

Inter-Container Kommunikation mit rootless podman auf Debian

Notwendige Pakete für podman

podman
slirp4netns
uidmap
podman-compose

Danach am besten Reboot weil sonst a) die subuids/subguids von uidmap und b) die netns Geschichten von slirp4netns nicht greifen und podman-compose auf die Nase fliegt mit “podman failed to mount runtime directory for rootless netns” failed.

Aber – damit können zwei Container noch nicht miteinander kommunizieren. Podman benutzt dann per default CNI als Netzwerkmethode und das überall beschriebene Paket “podman-plugins” gibts auf Debian offenbar nicht (erlebt auf bookworm), das notwendige Paket mit dem plugin “dnsname” (landet dann auf /usr/lib/cni/) heißt

golang-github-containernetworking-plugin-dnsname

Das installiert eben das dnsname CNI plugin und auch dnsmasq-base damit Inter-Container DNS Lookups darüber geführt werden können.

Das alleine hilft aber noch nicht weil das Default Netzwerk “podman” (podman network ls) hat DNS lookups nicht enabled (podman network inspect podman – Property “dns_enabled” steht auf false).

Erzeugt man aber nach der Installation vom DNSNAME plugin ein Netzwerk hat dieses dns_enabled=true, entweder auf der commandline

podman create network whatevernet
podman run whatever:latest --net whatevernet

oder im compose file als network:

networks:
   whatevernet:


services:
   whatever:
      image: whatever:latest
      networks:
         - whatevernet

UPDATE

Keine Ahnung warum mein podman mit CNI als Netzwerkbackend installiert wurde aber seit 4.0 sollte eigentlich netavark Default sein – welches das alles out of the box kann. Umstellung:

  • podman system reset
    (Reboot um Reste zu entfernen)
  • sudo cp /usr/share/containers.conf /etc/containers/
  • unter [network] Eintrag network_backend entkommentieren und auf “netavark” setzen
  • sudo apt install netavark
  • sudo apt install aavark
  • podman info | grep networkBackend
    (sollte netavark sein)

Custom Moniker (URL Protocol) erzeugen

Um ein beliebiges Programm über eine URL zu starten braucht es nicht viel, am Beispiel outlook:// für überraschenderweise Outlook:

Für den User:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\SOFTWARE\Classes\outlook]
@="URL:outlook"
"URL Protocol"=""
"EditFlags"=dword:00000002
"Source Filter"="{E436EBB6-524F-11CE-9F53-0020AF0BA770}"

[HKEY_CURRENT_USER\SOFTWARE\Classes\outlook\shell]

[HKEY_CURRENT_USER\SOFTWARE\Classes\outlook\shell\open]

[HKEY_CURRENT_USER\SOFTWARE\Classes\outlook\shell\open\command]
@="outlook.exe"

Oder rechnerweit:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\outlook]
@="URL:outlook"
"URL Protocol"=""
"EditFlags"=dword:00000002
"Source Filter"="{E436EBB6-524F-11CE-9F53-0020AF0BA770}"

[HKEY_CLASSES_ROOT\outlook\shell]

[HKEY_CLASSES_ROOT\outlook\shell\open]

[HKEY_CLASSES_ROOT\outlook\shell\open\command]
@="outlook.exe"

Kubernetes: Autoimageupdate mit keel.sh mit private Registry mit custom Root CA

ConfigMap für keel.sh für die custom Root CA erzeugen

apiVersion: v1
kind: ConfigMap
metadata:
  name: ca-gallauner
  namespace: "keel"
data:
   ca-gallauner.pem: |
     -----BEGIN CERTIFICATE-----
     ....
     -----END CERTIFICATE-----

keel.sh via YAML installieren

  • Basic Auth für Dashboard (PortForward 9300 von Pod)
  • ConfigMap für CA mounten
      containers:
        - name: keel
          image: "keelhq/keel:latest"
          imagePullPolicy: Always
          command: ["/bin/keel"]
          env:
            - name: NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            # Basic auth (to enable UI/API)
            - name: BASIC_AUTH_USER
              value: "admin"
            - name: BASIC_AUTH_PASSWORD
              value: "admin"
            # Enable insecure registries
            - name: INSECURE_REGISTRY
              value: "false"
          ports:
            - containerPort: 9300
          livenessProbe:
            httpGet:
              path: /healthz
              port: 9300
            initialDelaySeconds: 30
            timeoutSeconds: 10
          resources:
            limits:
              cpu: 100m
              memory: 128Mi
            requests:
              cpu: 50m
              memory: 64Mi
          volumeMounts:
          - name: ca-gallauner
            mountPath: /etc/ssl/certs/ca-gallauner.pem
            subPath: ca-gallauner.pem
            readOnly: false
      volumes:
      - name: ca-gallauner
        configMap:
          name: ca-gallauner

keel.sh Annotations im Zieldeployment einfügen

    metadata:
      labels:
        app: homer
      annotations:
        keel.sh/policy: all
        keel.sh/trigger: poll
        keel.sh/pollSchedule: "@every 1m"
        keel.sh/approvals: "0"

Private Registry mit Custom Root CA in Kubernetes benutzen

In Kubernetes ImagePullSecret erzeugen:

kubectl create secret docker-registry myregistry --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>

Im Pod/Deployment imagePullSecret hinzufügen

    spec:
      containers:
      - name: nginx
        image: myregistry/gallauner/homer:latest
      ports:
        - containerPort: 443
      imagePullSecrets:
      - name: myregistry

Gitea+Actions zum vollelektrischen Containerupdate hinter Proxy

Gitea von Binary installieren: https://docs.gitea.com/installation/install-from-binary

  • Debian nach eigenem Standard
  • git installieren
  • User “git” erzeugen
  • Verzeichnisse unter /var/lib/gitea erzeugen und schützen
  • /etc/gitea erzeugen und schützen
  • passendes gitea von https://dl.gitea.com/gitea/ holen, auf /usr/local/bin/ kopieren
  • systemd Unit erzeugen – https://docs.gitea.com/installation/linux-service
  • Environment=HTTP_PROXY=xxxx einfügen
  • Environment=HTTPS_PROXY=xxxx einfügen
  • Environment=NO_PROXY=xxxx einfügen

Gitea Actions und Migrations (=Replica) über Proxy erlauben (/etc/gitea/app.ini):

[proxy]
PROXY_ENABLED = true
PROXY_URL =

[migrations]
ALLOW_LOCALNETWORKS = true
ALLOWED_DOMAINS = gitea.com

[actions]
ENABLED=true
DEFAULT_ACTIONS_URL=self
STORAGE_TYPE=local
  • HTTP_PORT, ROOT_URL, CERT_FILE, PROTOCOL für HTTPS

Notwendige actions von Gitea.com replizieren (leicht modifizierte Namen damit alles unter “actions” liegt):

  • Gitea Organisation “actions” erzeugen
  • Migration von https://gitea.com/docker/login-action auf docker-login in actions
  • Migration von https://gitea.com/docker/setup-buildx-action auf docker-setup-buildx in actions
  • Migration von https://gitea.com/docker/build-push-action auf docker-build-push in actions
  • Migration von https://gitea.com/actions/checkout auf checkout in actions

act_runner (ausführendes Organ) konfigurieren (https://docs.gitea.com/usage/actions/quickstart)

  • passendes Binary von https://dl.gitea.com/act_runner/ holen
  • auf passendem Level (Instance, Organization, Repository) Token erzeugen und Runner registrieren
  • –labels linux_x64 beim Register angeben (sollte im config.yaml unter runner:/labels stehen)
  • config erzeugen (./act_runner generate-config > config.yaml)
  • unter “runner:” Block “envs:” mit HTTP_PROXY: xxxx, HTTPS_PROXY: xxxx, NO_PROXY: xxxx einfügen
  • mit config starten: ./act_runner daemon -c ./config.yaml

Action secret GIT_ACCESS_TOKEN erzeugen

  • https://gitea-host/api/swagger#/user/userCreateToken
  • nur für single User sinnvoll weil Token vom User sein muss der git push durchführt

Action secrets für Webserverzertifikat erzeugen

  • CERT_CRT mit public key
  • CERT_KEY mit private key

Im Repository .gitea/workflows/docker.yaml erzeugen:

jobs:
  Homer-Build-and-Push-Docker-Image:
    runs-on: linux_x64
    steps:
      - run: echo "${{ gitea.actor }} did ${{ gitea.event_name }} to ${{ gitea.repository }}, branch ${{ gitea.ref }}"
      - name: Check out repository code
        uses: actions/checkout@v3
        with:
          username: ${{ gitea.actor }}
          password: ${{ secrets.GIT_ACCESS_TOKEN }}
      - run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
      - run: echo "🖥️ The workflow is now ready to test your code on the runner."
      - name: List files in the repository
        run: ls ${{ gitea.workspace }}
      - name: Login docker
        uses: actions/docker-login@v2
        with:
          registry: ${{ env.DOCKER_REGISTRY }}
          username: ${{ gitea.actor }}
          password: ${{ secrets.GIT_ACCESS_TOKEN }}
      - name: Setup docker buildx
        uses: actions/docker-setup-buildx@v2
        env:
          HTTP_PROXY: ${{ env.HTTP_PROXY }}
          HTTPS_PROXY: ${{ env.HTTPS_PROXY }}
          NO_PROXY: ${{ env.NO_PROXY }}
        with:
           driver-opts: |
             env.http_proxy=${{ env.HTTP_PROXY }}
             env.https_proxy=${{ env.HTTPS_PROXY }}
             "env.no_proxy='${{ env.NO_PROXY }}'" 
           config-inline: |
             [registry."${{ env.DOCKER_REGISTRY }}"]
               ca=["/etc/docker/certs.d/${{ env.DOCKER_REGISTRY }}/GallaunerCA.crt"]             
      - name: Build and push docker image
        uses: actions/docker-build-push@v4
        env:
          ACTIONS_RUNTIME_TOKEN: ''
        with:
          context: .
          push: true
          tags: ${{ env.DOCKER_REGISTRY }}/gallauner/homer
          secrets: |
             "CERT_CRT=${{ secrets.CERT_CRT }}"
             "CERT_KEY=${{ secrets.CERT_KEY }}"
      - run: echo "🍏 This job's status is ${{ job.status }}."
  • runs-on: linux_x64 entspricht dem Label vom act_runner
  • Proxywerte aus dem Environment werden für pull von Basisimages benötigt
  • Custom CA der privaten Registry wird im config-inline von docker-setup-build eingefügt
  • Zertifikat für Webserver wird über secrets von docker-build-push eingefügt (siehe Dockerfile)

Dockerfile

FROM nginx:alpine
COPY homer /usr/share/nginx/html/
RUN --mount=type=secret,id=CERT_CRT \
   cp /run/secrets/CERT_CRT /etc/ssl/certs/homer.crt
RUN --mount=type=secret,id=CERT_KEY \
   cp /run/secrets/CERT_KEY /etc/ssl/private/homer.key
COPY <<EOF /etc/nginx/conf.d/default.conf
server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;
    ssl_certificate /etc/ssl/certs/homer.crt;
    ssl_certificate_key /etc/ssl/private/homer.key;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
EOF
  • durch die “secrets” in der Action können die Secrets gemounted und kopiert werden

Zertifikat mit easy-rsa erzeugen

Private key erzeugen

openssl genrsa -out myserver.key 4096

Zertifikatsrequest erzeugen

openssl req -new -key myserver.key -out myserver.req -subj "/C=AT/L=Vienna/O=Gallauner/CN=myserver.fqdn"

Request in easy-rsa importieren

./easyrsa import-req myserver.req myserver

Request in easy-rsa signieren, optional mit SAN(s) – CN wird per default als SAN eingetragen wenn –san nicht extra angegeben ist:

./easyrsa --san=DNS:myserver.fqdn,DNS:alternatename.fqdn sign-req server myserver

Ergebnis in

./pki/myserver.crt

EU Lebensmittelcodes

Auf Lebensmitteln mit Inhaltsbestandteilen aus tierischer Herkunft muss ja der zuletzt beteiligte Betrieb als Code abgedruckt werden – in DE gibts da öffentliche Datenbanken mit Suchfunktion in AT ist das ein wenig schwieriger (ich hab zumindestens nix gefunden) – hier gibts aber alle Codes in PDF-Listenform:

https://vis.statistik.at/fileadmin/ovis/pdf/index.html

Die erste Stelle der Nummer zeigt übrigens das Bundesland:

  • 1 = Burgenland
  • 2 = Kärnten
  • 3 = Niederösterreich
  • 4 = Oberösterreich
  • 5 = Salzburg
  • 6 = Steiermark
  • 7 = Tirol
  • 8 = Vorarlberg
  • 9 = Wien

OpenShift Persistent Volume im Ceph FS finden

Hatte die Herausforderung dass ich PVC erweitert habe (Größe verdoppelt) und das Ding Events vom Typ

NodeExpandVolume.NodeExpandVolume failed for volume "pvc-....guid...." : Expander.NodeExpand found CSI plugin kubernetes.io/csi/openshift-storage.cephfs.csi.ceph.com to not support node expansion

gespuckt hat obwohl das Webinterface überall die neue Größe angezeigt hat. Wollte schauen wie Ceph das sieht.

Schritt 1: Ceph Tools Pod erzeugen

oc patch OCSInitialization ocsinit -n openshift-storage --type json --patch  '[{ "op": "replace", "path": "/spec/enableCephTools", "value": true }]'

erzeugt im Namespace openshift-storage einen Pod mit Namen “rook-ceph-tools-*”, dort Shell öffnen:

oc rsh -n openshift-storage rook-ceph-tools-tralala-dada

Schritt 2: Name vom Filesystem/Volume rausfinden (zu finden auch in den Specs vom PV):

ceph fs ls    (oder ceph fs volume ls)

Schritt 3: SubVolumeGroup rausfinden

ceph fs subvolumegroup ls <Name aus Schritt 2>

Schritt 4: Volumes in der SubVolumeGroup auflisten

ceph fs subvolume ls <Name aus Schritt 2> --group_name <Name aus Schritt 3>

Schritt 5: Infos zu Volume/PV anzeigen (Name des Volumes aus YAML des PV – “subvolumeName”)

ceph fs subvolume info <Name aus Schritt 2> <Name aus Schritt 4> --group_name <Name aus Schritt 3>