Marvin Preuss xsteadfastx photo

github twitter mastodon flickr

linux

NGINX im Container und docker-gen

/// d794cd8 /// nginx docker linux

Das hatte ich lange auf meiner Liste. Bei mir lief immer noch der NGINX nicht im Container. Um ehrlich zu sein hatte ich mir alles schwieriger vorgestellt als es dann am Ende war. Ich halte mir immer alles in docker-compose.yml-Files fest. nginx: image: nginx ports: - "80:80" - "443:443" volumes: - /etc/nginx:/etc/nginx - /etc/letsencrypt:/etc/letsencrypt - /var/log/nginx:/var/log/nginx Dies läßt eine funktionierende Ubuntu-NGINX-Config mit dem offiziellen NGINX-Dockerimage laufen. Der NGINX macht fungiert nur als Reverse-Proxy für ein paar Anwendungen.

https://gifsboom.net/post/106865490574/fail-container-video

Das hatte ich lange auf meiner Liste. Bei mir lief immer noch der NGINX nicht im Container. Um ehrlich zu sein hatte ich mir alles schwieriger vorgestellt als es dann am Ende war. Ich halte mir immer alles in docker-compose.yml-Files fest.

nginx:
  image: nginx
  ports:
    - "80:80"
    - "443:443"
  volumes:
    - /etc/nginx:/etc/nginx
    - /etc/letsencrypt:/etc/letsencrypt
    - /var/log/nginx:/var/log/nginx

Dies läßt eine funktionierende Ubuntu-NGINX-Config mit dem offiziellen NGINX-Dockerimage laufen. Der NGINX macht fungiert nur als Reverse-Proxy für ein paar Anwendungen. Also werden Requests an ein Upstream Server weitergeleitet. NGINX macht manchmal Probleme wenn der Upstream Server Hostname nicht auflösbar ist und bricht dann sofort ab. Und dann sitzt man da und wundert sich wieso der Container immer wieder aussteigt. IP-Adressen sind auch auf ihre Art problematisch. Sie können sich unter Docker öfters ändern wenn man nach einem Image-Update den Container neustartet. Also was tun? Ich setze nun docker-gen ein. Der überwacht den Docker-Daemon und erstellt aus einem Template Config-Files. In diesem Fall eine upstream.conf. Die docker-compose.yml sieht so aus:

gen:
  image: jwilder/docker-gen
  volumes:
    - /var/run/docker.sock:/tmp/docker.sock:ro
    - /opt/docker-gen:/data
  volumes_from:
    - nginx_nginx_1
  command: -notify-sighup nginx_nginx_1 -watch -only-exposed /data/nginx.tmpl /etc/nginx/upstream.conf

docker-gen braucht den docker.sock um aus dem Container mit dem Daemon zu kommunizieren. Schließlich muss er mitbekommen wenn es Veränderungen gibt. Sprich Container gestartet werden oder Container nicht mehr da sind. Ich mounte das Arbeitsverzeichnis um auf das Template aus dem Container zugreifen zu können. Dazu binde ich alle Volumes des NGINX Containers ein. Schließlich soll das finale Config-File an die richtige Stelle geschoben werden. -notify-sighup nginx_nginx_1 sagt das er den NGINX Container neustarten soll. Mit -watch beobachtet er den Docker Daemon auf Änderungen. Mit -only-exposed werden nur Container betrachtet die Ports exposen. Dahinter kommt dann das Template welches benutzt werden soll und wohin die Finale Datei geschrieben werden soll. Ich habe mich dafür entschieden nicht die ganze nginx.conf aus dem Template zu generieren. Ich lasse nur die upstream.conf bauen. Dieses inkludiere ich dann in der nginx.conf.

upstream cloud {
                        # ownclouddocker_owncloud_1
                        server 172.17.0.6:80;
}
upstream gogs {
                        # gogs_gogs_1
                        server 172.17.0.5:3000;
}
upstream ttrss {
                        # ttrssdocker_ttrss_1
                        server 172.17.0.8:80;
}

Damit so eine Config erzeugt wird benutze ich dieses Template:

{{ range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }}
upstream {{ $host }} {

{{ range $index, $value := $containers }}

	{{ $addrLen := len $value.Addresses }}
	{{ $network := index $value.Networks 0 }}

	{{/* If only 1 port exposed, use that */}}
	{{ if eq $addrLen 1 }}
		{{ with $address := index $value.Addresses 0 }}
			# {{$value.Name}}
			server {{ $network.IP }}:{{ $address.Port }};
		{{ end }}

	{{/* If more than one port exposed, use the one matching VIRTUAL_PORT env var */}}
	{{ else if $value.Env.VIRTUAL_PORT }}
		{{ range $i, $address := $value.Addresses }}
			{{ if eq $address.Port $value.Env.VIRTUAL_PORT }}
			# {{$value.Name}}
			server {{ $network.IP }}:{{ $address.Port }};
			{{ end }}
		{{ end }}

	{{/* Else default to standard web port 80 */}}
	{{ else }}
		{{ range $i, $address := $value.Addresses }}
			{{ if eq $address.Port "80" }}
			# {{$value.Name}}
			server {{ $network.IP }}:{{ $address.Port }};
			{{ end }}
		{{ end }}
	{{ end }}
{{ end }}
}

{{ end }}

Damit docker-gen die passenden Container findet die er betrachten soll, müssen den Containern ein paar Environment-Variabeln mitgegeben werden. Hier zum Beispiel mit Gogs:

gogs:
  image: gogs/gogs
  ports:
    - "3000"
  volumes:
    - "/srv/www/gogs:/data"
  environment:
    - VIRTUAL_HOST=gogs
    - VIRTUAL_PORT=3000

VIRTUAL_HOST gibt dem ganzen einen Namen. Den brauchen wir dann in der eigentlichen vhost-Config. VIRTUAL_PORT wird gebraucht wenn der Port nicht 80 ist. Dann ignoriert docker-gen sonst den Container.

Die NGINX-Config sieht dann so aus:

server {
        listen 443;
        server_name git.foo.bar;

        ssl on;
        ssl_certificate /etc/letsencrypt/live/git.foo.bar/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/git.foo.bar/privkey.pem;

        client_max_body_size 50m;

        location / {
                proxy_pass http://gogs;
                proxy_set_header X-Forwarded-Host $server_name;
                proxy_set_header X-Forwarded-Proto https;
                proxy_set_header X-Forwarded-For $remote_addr;
        }

}

Unter proxy_pass taucht VIRTUAL_HOST wieder auf. In der NGINX Config spiegelt sich das wie folgt wieder:

http {

        ##
        # Basic Settings
        ##

        ...
        ...
        ...

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;

        ##
        # Upstream
        ##

        include /etc/nginx/upstream.conf;

}

Nun alles Container starten und genießen oder sowas.



Ansible Playbooks und variable Hosts

/// d794cd8 /// ansible python linux

Ich benutze Ansible für viele Sachen. Unter anderem habe ich ein Set an Playbooks und Roles um meine Server so anzupassen das ich mich auf ihnen wohl fühle. Bis jetzt habe ich immer Ansible auch auf den Servern installiert und es dann lokal ausgeführt. Aber dabei nutze ich nicht das eigentlich Ansible Feature: das Ganze Remote über SSH auszurollen. Problem: In den Playbooks muss es die Zeile - hosts: geben. Aber eigentlich will ich das alles Variabel ausführen können.

Ich benutze Ansible für viele Sachen. Unter anderem habe ich ein Set an Playbooks und Roles um meine Server so anzupassen das ich mich auf ihnen wohl fühle. Bis jetzt habe ich immer Ansible auch auf den Servern installiert und es dann lokal ausgeführt. Aber dabei nutze ich nicht das eigentlich Ansible Feature: das Ganze Remote über SSH auszurollen. Problem: In den Playbooks muss es die Zeile - hosts: geben. Aber eigentlich will ich das alles Variabel ausführen können. Zum Beispiel nutze ich die gleichen Files auch um meine Vagrant Container einzurichten. Wieso also beim Aufruf die Hosts dem Playbook nicht einfach übergeben? Die Lösung ist dann doch wieder einmal einfacher als man denkt. Man benutzt die Möglichkeit in Playbooks und Roles Variabeln einzusetzen.

---
- hosts: "{{ hosts }}"
  roles:
    - git
    - tmux
    - vim
    - zsh

Diese Variabel übergeben wir beim Aufruf von Ansible.

ansible-playbook base.yml --extra-vars="hosts=myservers"



Jenkins und die Dockerception

/// d794cd8 /// jenkins docker linux

Nach meinen ersten Experimenten mit Jenkins und Docker geht es nun wieder einen Schritt weiter. Mein Jenkins läuft im Docker-Container hinter einem NGINX im Docker-Container. Was könnte also noch eine Steigerung sein? Noch schöner wäre es wenn die Tests bzw Builds in eigenen Containern laufen, die dann nach dem Run wieder in sich zusammen fallen. Ich versuche mal alles zusammen zuschreiben. Docker in Docker Der beste Weg ist es den Docker-Socket als Volume an den Container durchzureichen.

Nach meinen ersten Experimenten mit Jenkins und Docker geht es nun wieder einen Schritt weiter. Mein Jenkins läuft im Docker-Container hinter einem NGINX im Docker-Container. Was könnte also noch eine Steigerung sein? Noch schöner wäre es wenn die Tests bzw Builds in eigenen Containern laufen, die dann nach dem Run wieder in sich zusammen fallen. Ich versuche mal alles zusammen zuschreiben.

Docker in Docker

Der beste Weg ist es den Docker-Socket als Volume an den Container durchzureichen. Hier der docker-compose-Eintrag:

jenkins:
  container_name: jenkins
  build: ./jenkins/
  volumes:
    - "/srv/www/jenkins:/var/jenkins_home"
    - "/usr/bin/docker:/bin/docker"
    - "/usr/lib/x86_64-linux-gnu/libapparmor.so.1.1.0:/usr/lib/x86_64-linux-gnu/libapparmor.so.1"
    - "/var/run/docker.sock:/var/run/docker.sock"
  ports:
    - "8080:8080"
    - "50000:50000"

Wir müssen nicht nur den Socket durchreichen, sondern auch das Docker-Binary und eine Library (war in diesem Fall nötig). Sonst nichts besonderes hier. Die Ports sind einmal für die Jenkins Weboberfläche und einmal für die Kommunikation mit den Slaves die sich im Netz befinden. In meinem Fall ein Windows Build Slave.

Docker in Jenkins

Ich benutze das offizielle Jenkins Docker Image mit ein paar Anpassungen. Das Dockerfile sieht wie folgt aus:

FROM jenkins

USER root

RUN apt-get update \
 && apt-get install -y \
    rsync \
 && rm -rf /var/lib/apt/lists/*

RUN addgroup --gid 116 docker \
 && usermod -a -G docker jenkins

USER jenkins

Ich installiere ein rsync und füge den Benutzer jenkins der docker-Gruppe hinzu damit der die Container starten, beenden und löschen kann.

Jenkins hat viele Plugins. Diese wiederum haben kaum bis garkeine Dokumentation oder klaffende Lücken in ihr. Also habe ich erstmal, ziemlich naiv, das Docker Plugin installiert. Jenkins braucht erstmal eine Connection zu Docker. Dazu gehen wie in die Jenkins System Konfiguration in die Cloud Sektion. Neben einem Namen sollten wir auch die Docker URL eintragen. Die kann auch ein Socket sein. In diesem Fall unix:///var/run/docker.sock. Nun klappt die Kommunikation.

tox-jenkins-slave

Nun brauchen wir ein Docker-Image das als Jenkins-Slave taugt. Ich habe mich ganz an dem Image von evarga orientiert. Mein Image beinhaltet ein paar Änderungen. Zum Beispiel installiere ich nicht das gesammte JDK, sondern nur ein Headless-JRE. Sonst installiert er mir schön diverse X-Libraries. Die braucht man nicht um den Jenkins-Slave-Client auszuführen. Ich bin riesen tox-Fan. Ein Tool um Tests in diversen Python Versionen auszuführen. Alles getrennt durch Virtualenv’s. Dazu braucht tox aber auch die Python Versionen installiert. Dies funktioniert dank dem PPA von fkrull ganz wunderbar. Zum Schluß installiere ich tox selber und fertig ist das Image. Ach ja, ein openssh-server und git wird auch noch gebraucht. Hier das Dockerfile:

FROM ubuntu:trusty

RUN gpg --keyserver keyserver.ubuntu.com --recv-keys DB82666C \
 && gpg --export DB82666C | apt-key add -

RUN echo deb http://ppa.launchpad.net/fkrull/deadsnakes/ubuntu trusty main >> /etc/apt/sources.list \
 && echo deb-src http://ppa.launchpad.net/fkrull/deadsnakes/ubuntu trusty main >> /etc/apt/sources.list

RUN apt-get update \
 && apt-get install -y \
    git \
    openssh-server \
    openjdk-7-jre-headless \
    python-pip \
    python2.3 \
    python2.4 \
    python2.5 \
    python2.6 \
    python3.1 \
    python3.2 \
    python3.3 \
    python3.4 \
    python3.5 \
 && rm -rf /var/lib/apt/lists/*

RUN pip install tox

RUN sed -i 's|session    required     pam_loginuid.so|session    optional     pam_loginuid.so|g' /etc/pam.d/sshd \
 && mkdir -p /var/run/sshd

RUN adduser --quiet jenkins \
 && echo "jenkins:jenkins" | chpasswd

EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

Es wird ein jenkins Benutzer mit dem Password jenkins angelegt. Wenn sich jemand daran stört soll er sich das Image selber bauen und dies verändern.

Um es zum Einsatz zu bringen müssen wir unter Configure System -> Cloud -> Docker -> Add Docker Template folgendes einstellen:

  1. Docker Image: xsteadfastx/tox-jenkins-slave
  2. Remote Filing System Root: /home/jenkins
  3. Labels: tox-jenkins-slave
  4. Launch method: Docker SSH computer launcher
  • Credentials: Add a new one with username jenkins and password jenkins
  1. Remote FS Root Mapping: /home/jenkins
  2. Remove volumes: True

Mir war nicht klar das das Label ausschlaggebend ist um den Job auch wirklich auf den passenden Container laufen zu lassen. Ohne Label kann dieser nicht getriggert werden.

Nun können wir im Job den Container einsetzen:

  1. Docker Container: True
  2. Restrict where this project can be run: True
  • Label Expression: tox-jenkins-slave

Sachen mit denen ich noch so gekämpft habe

Aus irgendeinem Grund hatte ich riesige Probleme mit den Locales in dem Container. Einige Tests haben Vergleichsdaten in Textfiles gespeichert. Falsche Locales haben die Tests gebrochen. Das Absurde… egal was ich tat, es half einfach nichts. LANG setzen in der .bashrc oder in /etc/profile wurde vollständig ignoriert. Startete ich den Container manuell und loggte mich per SSH ein, kein Problem, die Tests liefen durch. Der Slave gestartet von Jenkins, völlige Ingoranz meiner Config. Also musste ich es direkt in das Python Job Script packen:

import os
import tox

os .environ['LANG'] = 'C.UTF-8'
os.chdir(os.environ['WORKSPACE'])

tox.cmdline()

Ich setze die Environment-Variabel direkt im Script, gehe in den Jenkins-Workspace und führe tox aus. Ein Umweg, aber es funktioniert.

Schenkt den PyPI-Servern eine Auszeit

Noch eine Kleinigkeit: Da die Abhängigkeiten für die Tests bei jedem Durchlauf neu heruntergeladen werden lohnt sich der Einsatz von devpi. Der kann sehr viel mehr, wird aber von mir als einfacher PyPI-Mirror missbraucht. Ich habe dafür auch ein kleines Image. Läuft der Container sieht mein Jenkins Job kompletto so aus:

import os
import tox

os.environ['LANG'] = 'C.UTF-8'

os.makedirs('/home/jenkins/.config/pip')
with open('/home/jenkins/.config/pip/pip.conf', 'w') as f:
  f.write('[install]\ntrusted-host = 192.168.1.8')

os.environ['PIP_INDEX_URL'] = 'http://192.168.1.8:3141/root/pypi/+simple/'

os.chdir(os.environ['WORKSPACE'])

tox.cmdline(['-e py33,py34,py35'])

Von nun an wird der Mirror benutzt.

https://www.tumblr.com



Das Letsencrypt Docker Moped

/// d794cd8 /// docker linux letsencrypt ssl nginx

Darauf haben wir lange gewartet: SSL für alle!!1!!!111! Wie oft musste ich Leuten erzählen das sie keine Angst haben müssen vor dem Polizisten mit dem Schlagstock (zumindestens nicht vor dem im Chrome Browser). Ich hatte persöhnlich nie etwas gegen selbstsignierte Zertifikate, wenn ich nicht gerade Geld über diese Seiten schubsen musste. Aber könnte nun alles der Vergangenheit angehören. Letsencrypt bieten nun einen einfachen Weg an um sich seine Zertifikate unterschreiben zu lassen.

Darauf haben wir lange gewartet: SSL für alle!!1!!!111! Wie oft musste ich Leuten erzählen das sie keine Angst haben müssen vor dem Polizisten mit dem Schlagstock (zumindestens nicht vor dem im Chrome Browser). Ich hatte persöhnlich nie etwas gegen selbstsignierte Zertifikate, wenn ich nicht gerade Geld über diese Seiten schubsen musste. Aber könnte nun alles der Vergangenheit angehören. Letsencrypt bieten nun einen einfachen Weg an um sich seine Zertifikate unterschreiben zu lassen. Und nicht nur das. Sie wollen Tools mitliefern, die ohne viel Vorwissen die Arbeit für einen erledigen. Sprich Keys erzeugen und den Zertfikatsrequest. Dann findet eine überprüfung statt ob die Domain für die ihr das Zertifikat haben wollt, auch wirklich euch gehört. Ein wichtiger Schritt. Nur weil ihr keine Hunderte von Euro für ein Zertifikat ausgibt, sollt ihr trotzdem das Recht haben das der Transport über das Netz verschlüßelt ist. Ohne Schlagstock-Polizisten-Warning. Nun geht das Projekt in die BETA-Phase und die üblich Verdächtigen(WARNUNG: fefe link) ranten rum. Räudiges Python und alles viel zu einfach… und vor allem… jeder weiß doch wie man openssl richtig bedient und wo man richtige Zertifikate bekommt. Ich finde den Ansatz gut. Natürlich ist der Client noch nicht dort angekommen wo er ankommen will. Aber es funktioniert. Der Client bietet mehrere Modi an. Der eine öffent die Ports 80 und 443 und Letsencrypt schaut dann ob sie erreichbar sind und tauschen ein paar Sachen aus. Problem: Auf dem Server läuft meist schon ein Webserver und blockiert die Ports. Ich muss also NGINX stoppen, den Client starten und dann NGINX wieder anschieben. Irgendwie nicht so schön. Eine andere Möglichkeit ist webroot. Dafür legt der Client ein paar Ordner in das Root-Verzeichnis des Webservers und der Dienst schaut dann dort nach. Problem hierbei: Ich habe in meine NGINX keine Files im Root. Ich benutze NGINX nur als Reverse-Proxy. Es gibt Hilfe:

Das NGINX Snippet

location /.well-known/acme-challenge {
    alias /etc/letsencrypt/webrootauth/.well-known/acme-challenge;
    location ~ /.well-known/acme-challenge/(.*) {
        add_header Content-Type application/jose+json;
    }
}

Und wenn wir dieses Snippet nun in den server-Teil der NGINX config “includen” haben wir die passende Location damit Letsencrypt alles findet.

Letsencrypt im Docker-Container

Der Client versucht sich vor jedem Ausführen nochmal selber zu updaten. Keine schlechte Idee in der BETA-Phase. Ich dachte nur ich versuche alles ein wenig aufzubrechen und in ein Docker-Image zu gießen. Dies sollte (Dank Alpine-Linux) schön klein Sein und schon alle wichtigen Optionen im ENTRYPOINT beinhalten. Das man nur noch die Domains, für die man Zertifikate haben will, anhängt. Der Gedanke dahinter: Man kann es einfach in die Crontab packen und alle Abhängigkeiten sind im Container gefangen. Die Repo liegt hier. Für noch mehr Convenience nutze ich auch mein geliebtes docker-compose.

letsencrypt:
  build: letsencrypt/
  volumes:
    - /etc/letsencrypt:/etc/letsencrypt
    - /var/lib/letsencrypt:/var/lib/letsencrypt
  environment:
    EMAIL: marvin@xsteadfastx.org
    WEBROOTPATH: /etc/letsencrypt/webrootauth
  command:
    "-d emby.xsteadfastx.org -d cloud.xsteadfastx.org -d reader.xsteadfastx.org -d git.xsteadfastx.org"

Ich benutze Compose so oft wie es geht. Dort kann ich schön alles definieren wie der Container ausgeführt werden soll. Eine saubere Sache. Erstmal werden die Volumes eingebunden. Diese beiden Verzeichnise braucht der Letsencrypt-Client. Dann werden zwei Environment-Variablen definiert. Email und der Pfad in dem der Client die Files zur Authentifizierung ablegt. Als command werden die Domains jeweils mit der Option -d angehängt. Mit docker-compose up wird erst das Image gebaut und dann ausgeführt.

Ich bin gespannt wie es weitergeht. Natürlich ist mein Container auch nur der erste Entwurf… aber ich werde weiter daran basteln.



Emby mit NGINX als Reverse-Proxy

/// d794cd8 /// emby nginx linux

Ich bin ja vor einiger Zeit von Plex auf Emby gewächselt um sich meiner Mediendateien anzunehmen. Auch wenn Plex seinen Job gut machte, gibt es dort in mir ein kleinen Ort der bei nicht Open-Source Software ein wenig rebelliert und sich nicht so fluffig anfühlt. Zum Glück gibt es Emby. Es fühlt sich an manchen Ecken noch nicht so perfekt an wie Plex, macht seinen Job aber anständig. Dazu kommt ein Feature was ich stark vermisst habe: Encoding bei Audio-Files.

Ich bin ja vor einiger Zeit von Plex auf Emby gewächselt um sich meiner Mediendateien anzunehmen. Auch wenn Plex seinen Job gut machte, gibt es dort in mir ein kleinen Ort der bei nicht Open-Source Software ein wenig rebelliert und sich nicht so fluffig anfühlt. Zum Glück gibt es Emby. Es fühlt sich an manchen Ecken noch nicht so perfekt an wie Plex, macht seinen Job aber anständig. Dazu kommt ein Feature was ich stark vermisst habe: Encoding bei Audio-Files. Ich will über mein Handy kein FLAC streamen. Emby kann auch Serien selber verwalten. Das bedeutet, dass man die Files in ein Verzeichnis schmeißt und Emby die dann umbenennt und wegsortiert. Emby läuft bei mir in einem Docker Container und ich leite den Port an meinem Router weiter. Eine noch schönere Lösung ist ein Reverse-Proxy. Dann könnte alles unter einer Subdomain aufrufbar sein. Ein NGINX ist schon im Einsatz. Als Proxy für ein paar andere Docker Container. Also wieso nicht einfach auch für Emby benutzen? Bis jetzt läuft auch alles ziemlich gscheit.

server {
    listen 80;
    server_name emby.meinedomain.tld;

    keepalive_timeout 180;
    client_max_body_size 1024M;

    location / {
        proxy_pass http://127.0.0.1:8096;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-for $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $remote_addr;
        proxy_set_header X-Forwarded-Protocol $scheme;
        proxy_redirect off;

        # Send websocket data to the backend aswell
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Wichtig ist hier auch der Teil mit dem Websockets. Die müssen natürlich auch weitergeschubst werden. Zum Glück bietet NGINX da den passenden Support. Ja ich weiß, noch kein SSL. Wird aber nachgeholt.

Danke an Karbowiak.



Probleme zwischen NetworkManager und dnsmasq

/// 7ab0ec1 /// linux ubuntu dnsmasq networkmanager

Neuer Wohnort und das Generve sein Netzwerk neu einzurichten. So betreibe ich einen kleinen Raspberry Pi der sich um mein VPN, DNS und DHCP kümmert. Für die beiden letzteren Dienste setze ich auf dnsmasq. Ein ziemlich kleiner und Schlanker DNS und DHCP Server. Mein Problem was das es auf meinen Ubuntu Laptops immer wieder zu komische DNS Abfrage Problemen kam. Irgendwie wollte er manchmal Domains nicht richtig auflösen. Einfach nervig. Anscheinend gibt es ein Problem zwischen dem NetworkManager unter Ubuntu und dnsmasq.

Neuer Wohnort und das Generve sein Netzwerk neu einzurichten. So betreibe ich einen kleinen Raspberry Pi der sich um mein VPN, DNS und DHCP kümmert. Für die beiden letzteren Dienste setze ich auf dnsmasq. Ein ziemlich kleiner und Schlanker DNS und DHCP Server. Mein Problem was das es auf meinen Ubuntu Laptops immer wieder zu komische DNS Abfrage Problemen kam. Irgendwie wollte er manchmal Domains nicht richtig auflösen. Einfach nervig. Anscheinend gibt es ein Problem zwischen dem NetworkManager unter Ubuntu und dnsmasq. Der NetworkManager setzt dnsmasq selber auf dem Client ein um den Resolver zu stellen. Da scheint in manchen Fällen auch das Problem zu liegen. Was in meinem Fall geholfen hat: den NetworkManager so zu konfigurieren das er wieder normal die /etc/resolv.conf benutzt. Dazu editieren wir /etc/NetworkManager/NetworkManager.conf und kommentieren die Zeile dns=dnsmasq aus.



Dockerize all die Sachen

/// 7ab0ec1 /// docker linux

Docker ist manchmal immer noch ein Buch mit sieben Siegeln für mich. In meinem Fall war die Lernnkurve nicht gerade die Beste. Aber was solls. Das meiste lernt man dann doch durch Trial and error. Ein paar kleine selbstgeschriebene Web-Apps laufen bei mir schon in Docker Containern nun wollte ich bestehende Dienste auf meinem Heimserver in Container auslagern. Vor allem die Sachen denen ich immer noch ein wenig kritisch gegenüber stehe.

Docker ist manchmal immer noch ein Buch mit sieben Siegeln für mich. In meinem Fall war die Lernnkurve nicht gerade die Beste. Aber was solls. Das meiste lernt man dann doch durch Trial and error. Ein paar kleine selbstgeschriebene Web-Apps laufen bei mir schon in Docker Containern nun wollte ich bestehende Dienste auf meinem Heimserver in Container auslagern. Vor allem die Sachen denen ich immer noch ein wenig kritisch gegenüber stehe. Da wären zum Beispiel Owncloud, Plex und tiny tiny rss. Was ich gelernt habe: Jede Anwendung fordert individuelle Entscheidungen die manchmal erst auf den zweiten Blick Sinn machen :).

Owncloud

Meine lokale Owncloud Installation hat schon lange keine Liebe mehr gesehen. Oft benutze ich es nicht mehr und um Updates hatte ich mich auch nicht so wirklich gekümmert. Ich musste mir erstmal Gedanken was ich zum Beispiel mit PHP Anwednungen machen. Bei Python starte ich Gunicorn im Container und richte einfach einen Reverse-Proxy (Nginx) drauf. Bei PHP brauche ich einen Layer dazwischen. Ich habe mich dafür entschieden einen minimalen Nginx mit php-fpm im Container laufen zu lassen. Davor kommt dann der Reverse Proxy mit SSL und Soße und Scharf. Und da ich php-fpm und Nginx im Container laufen haben muss, muss ich die Prozesse per Supervisor starten. Normalerweise versuche ich die einzelnen Prozesse in verschiedene Container zu packen. Hier habe ich mich explizit dagegen entschieden. Die Config dazu sieht in diesem Fall so aus:

[supervisord]
nodaemon = true

[program:nginx]
command = nginx
user = root
autostart = true

[program:php]
command = php5-fpm --nodaemonize
user = root
autostart = true

Sehr wichtig ist das Supervisor nicht als daemon läuft. Sonst schließt sich der Docker Container sofort wieder nach dem ausführen. Mein Dockerfile sieht so aus:

FROM nginx

RUN apt-get update && apt-get -y install bzip2 curl supervisor php5-fpm php5-gd php5-json php5-mysql php5-curl php5-intl php5-mcrypt php5-imagick php5-sqlite
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

RUN mkdir -p /var/log/supervisor
RUN mkdir /var/www

RUN curl -k https://download.owncloud.org/community/owncloud-8.0.4.tar.bz2 | tar jx -C /var/www/
RUN chown -Rv www-data:www-data /var/www

COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY php.ini /etc/php5/fpm/
COPY nginx.conf /etc/nginx/nginx.conf

VOLUME ["/var/www/owncloud/data", "/var/www/owncloud/config"]
EXPOSE 80
CMD ["/usr/bin/supervisord"]

Eigentlich auch nichts wildes. Die Verzeichnisse /var/www/owncloud/data und /var/www/owncloud/config sind als Volumes deklariert. Die werde ich dann mit lokalen Verzeichnissen auf dem Host verbinden. Alle anderen Files liegen in dem passenden Repository.

Grundlegend benutze ich docker-compose. Es macht den Workflow für mich so viel besser. Ich schreibe in docker-compose.yml all meine Optionen die ich haben will (zum Beispiel die Volumes oder Ports) und mit docker-compose up wird alles hochgefahren. Ich muss mir mein ursprüngliches docker run-Kommando nicht merken. Am schönsten wird es wenn wir mehrere Container miteinander verkleben. Bei Owncloud hantieren wir mit nur einem Container. Das File sieht dann so aus:

owncloud:
  build: .
  ports:
    - "127.0.0.1:9998:80"
  volumes:
    - "/srv/www/owncloud/config:/var/www/owncloud/config"
    - "/srv/www/owncloud/data:/var/www/owncloud/data"

Wie man sieht steht nicht wirklich viel drin aber es erleichtert das starten und bauen sehr.

tiny tiny rss

tiny tiny rss war dann meine Master-Arbeit. Hier gab es dann gleich mehrere Problemszenarien die zu bewältigen waren. Ich finge also an ein einfaches Dockerfile zusammen zu hacken. Es gab dann aber ein paar Probleme. Zum Beispiel muss die Datenbank bestehen bleiben auch wenn ich den Container lösche. Das einrichten der Datenbank erfolgt aber durch einen Setup Screen von tt-rss bei ersten aufrufen. Das gleiche gilt für das Configfile. Im Dockerfile kann man nicht andere Volumes von anderen Container definieren die zum speichern von Daten genutzt werden (dies ist ein Weg bestimmte Daten vor dem löschen zu bewahren). Also war mir klar das ich ein Script haben muss welches bei jedem erstellen des Containers sicherstellt das das tt-rss Datenbankschema in der Datenbank sich befindet und die richtige Config an der richtigen Stelle liegt. Da kommt ein Liebling von mir ins Spiel: Ansible. Ich definiere einen ENTRYPOINT. Ein einfaches Bash-Script welches Ansible aufruft und danach Supervisor um alles zu starten. Mein Ansible-Playbook sieht so aus:

---
- hosts: localhost
  remote_user: root

  tasks:

    - name: create ttrss config.php
      template: src=templates/config.php.j2
                dest=/var/www/tt-rss/config.php

    - name: pause everything
      pause: seconds=30

    - name: ttrss db
      mysql_db: name=ttrss
                state=present
                login_host={{ lookup('env','DB_PORT_3306_TCP_ADDR') }}
                login_user=root
                login_password={{ lookup('env','DB_ENV_MYSQL_ROOT_PASSWORD') }}
      notify: import ttrss schema

  handlers:

    - name: import ttrss schema
      mysql_db: name=ttrss
                state=import
                target=/var/www/tt-rss/schema/ttrss_schema_mysql.sql
                login_host={{ lookup('env','DB_PORT_3306_TCP_ADDR') }}
                login_user=root
                login_password={{ lookup('env','DB_ENV_MYSQL_ROOT_PASSWORD') }}

Ich erstelle die Config aus einem Template. Dann kommt der “hacky” Teil. Ich muss 30 Sekunden warten. Dies beruht darauf das docker-compose alle Container parallel startet und dadruch bekomme ich Connection Probleme bei einrichten der Datenbank weil diese einfach noch nicht hochgefahren ist. Nicht schön… läuft aber. Dann gehen wir sicher das es eine DB mit dem Namen “ttrss” gibt. Wenn nicht wird der Handler import ttrss schema angestoßen der dann das Schema importiert. Die Supervisor-Config sieht so aus:

[supervisord]
nodaemon = true

[program:nginx]
command = nginx
user = root
autostart = true

[program:php]
command = php5-fpm --nodaemonize
user = root
autostart = true

[program:ttrss-update-daemon]
command = php /var/www/tt-rss/update_daemon2.php
user = www-data
autostart=true

Was dazu kam ist der ttrss-update-daemon. Er wird gestartet um die Feeds, im Hintergrund, zu aktualisieren. Die docker-compose.yml sieht wie folgt aus:

ttrss:
  build: .
  ports:
    - "127.0.0.1:9997:80"
  environment:
    - URL_PATH=https://reader.domain.foo
  links:
    - db
db:
  image: mariadb
  volumes_from:
    - ttrss-data
  environment:
    - MYSQL_ROOT_PASSWORD=mysecretpassword

Hier sieht mand ie ganze docker-compose Magic. Wir definieren alle Container die gebraucht werden und vor allem wie sie verlinkt werden sollen. Dann können wir auch gleich noch ein paar Variabeln mitgeben. URL_PATH wird für die tt-rss Config gebraucht und MYSQL_ROOT_PASSWORD um MariaDB zu initialisieren. Wir benutzen einen Data-Only-Container um die Datenbank zu speichern. Diesen legen wir mit docker run --name ttrss-data mariadb true an. Wir benutzen hier das mariadb-Image damit die Permissions mit dem Server übereinstimmen. docker-compose up und den Reverse Proxy setzen. Zack fertig! Hier gibt es alle benötigten Files.

Plex Media Server

Ich liebe Plex ja. Auch wenn es teilweise closed-source ist komme ich einfach nicht davon weg. Von der Usability habe ich bis jetzt nicht vergleichbares gefunden. Also was liegt näher als Plex auch im Container laufen zu lassen. Komischerweise war Plex die einfachste Aufgabe bis jetzt. Alles ziemlich straight-forward. Deswegen einfach hier alle Files. Bis jetzt rennt Plex. Na mal schauen :)

Hier sind die Links zu meinen Dockerfiles und den dazugehörigen Helper.



Weg mit dem Splashscreen

/// d794cd8 /// ubuntu linux

Irgendwie habe ich auf 90% der Linux Systeme Probleme mit dem Splashscreen bei Booten. Manchmal taucht er einfach nicht auf und manchmal ist irgendein Foo mit der Auflösung. Eigentlich brauche ich den Splashscreen auch nicht. Also weg damit… Unter Ubuntu geht es wie folgt. Man editiert /etc/default/grub: GRUB_CMDLINE_LINUX_DEFAULT="" Und danach updated man GRUB mit: sudo update-grub Zack… Fertig!

Irgendwie habe ich auf 90% der Linux Systeme Probleme mit dem Splashscreen bei Booten. Manchmal taucht er einfach nicht auf und manchmal ist irgendein Foo mit der Auflösung. Eigentlich brauche ich den Splashscreen auch nicht. Also weg damit…

Unter Ubuntu geht es wie folgt. Man editiert /etc/default/grub:

GRUB_CMDLINE_LINUX_DEFAULT=""

Und danach updated man GRUB mit:

sudo update-grub

Zack… Fertig!



Clay Shirky spricht darüber wie das Internet Regierungen verändern könnte oder wird

/// d794cd8 /// bundestag clayshirky github linux opensource politics ted

Sind wir mal ehrlich. Ich habe das Gefühl das die Politik, wie sie ist, die letzten Zuckungen durchlebt. Zu sehr hat sich die Gesellschaft verändert in den Zeiten des Informationsflusses. Es ist viel schwieriger geworden seine Bevölkerung hinter dem Vorhang der Unwissenheit zu halten. Egal wie man die Entwicklung den Ländern des arabischen Frühlings hält, das Internet war die Infrastruktur die welche, die Revolution trug und den Ball des Anstoßes der Proteste in das eigene Land und die Welt transportierte.

internetshirky

Sind wir mal ehrlich. Ich habe das Gefühl das die Politik, wie sie ist, die letzten Zuckungen durchlebt. Zu sehr hat sich die Gesellschaft verändert in den Zeiten des Informationsflusses. Es ist viel schwieriger geworden seine Bevölkerung hinter dem Vorhang der Unwissenheit zu halten. Egal wie man die Entwicklung den Ländern des arabischen Frühlings hält, das Internet war die Infrastruktur die welche, die Revolution trug und den Ball des Anstoßes der Proteste in das eigene Land und die Welt transportierte. Als letzte Möglichkeit, des Regimes stand immer die Abschaltung des Internetzes. Den Datenfluss einzudämmen.

Es muss nicht immer um die Auflösung von Regierungen oder Revolutionen gehen. Ich glaube daran das sich die Relationen verändert haben und die Bürger ganz anders einbezogen werden müssen. Die technischen Hilfsmittel sind da! Ich glaube es wird Zeit für ein Umdenken. Nicht nur auf der Seite der Politiker. Auch die Bürger sollten endlich ihre Rechte einfordern und nicht nur passiv teilnehmen.

Clay Shirky spricht über die Vorbildfunktion der Open-Source Welt und wie sie die Regierungen inspirieren könnte. Als Beispiel führt er Linux und GitHub auf. Dort gibt es schon das Repository mit dem Namen “Bundestag". Dort werden Gesetzestexte gesammelt und die Veränderungen per “Pull Request” eingepflegt. So werden die Veränderungen der Texte dokumentiert und nichts geht verloren. Ich bin gespannt in welche Richtung das Projekt geht. Es ist kein offizielles Regierungsprojekt, sondern ein Projekt der Bürger. Ich persönlich bin immer wieder begeistert das Open Source auch außerhalb der Computerwelt anwendbar ist und die Menschen inspiriert. Und TED-Talks sind eh immer super…

The open-source world has learned to deal with a flood of new, oftentimes divergent, ideas using hosting services like GitHub – so why can’t governments? In this rousing talk Clay Shirky shows how democracies can take a lesson from the Internet, to be not just transparent but also to draw on the knowledge of all their citizens.
Beschreibung des Youtube Videos

(via)



Der Raspberry Pi Supercomputer

/// d794cd8 /// linux raspberrypi

Wieso haben ich eigentlich noch keinen Raspberry Pi? Ds ist ein kleiner Computer für wenig Geld auf dem man problemlos Linux laufen lassen kann. Perfekt für einen kleinen Server oder eine Medienzentrale für das Wohnzimmer. Aber eigentlich will man damit nur rumspielen und Sachen aus dem Grund machen, das man sie machen kann. Zum Beispiel einen Supercomputer aus diesen kleinen Computer bauen. Das haben die Studenten von der Universität Southampton gemacht.

raspberry-pi-supercomputer-5

Wieso haben ich eigentlich noch keinen Raspberry Pi? Ds ist ein kleiner Computer für wenig Geld auf dem man problemlos Linux laufen lassen kann. Perfekt für einen kleinen Server oder eine Medienzentrale für das Wohnzimmer. Aber eigentlich will man damit nur rumspielen und Sachen aus dem Grund machen, das man sie machen kann.

Zum Beispiel einen Supercomputer aus diesen kleinen Computer bauen. Das haben die Studenten von der Universität Southampton gemacht. 64 Keincomputer wurden dafür zusammen geschaltet. Alle Informationen zum Nachbauen gibt es im Internetz. Und LEGO ey… wie geil seit ihr denn bitte?!



2 of 3