Blog

Ich weiß nicht, ob Sie es wussten: Aber Linux, das braucht jetzt jeder

Jun 13, 2018

Das Interesse an Linux ist derzeit groß. Verständlich ist das, denn das Betriebssystem hat sich in beinahe jedem Bereich, in dem Computer eingesetzt werden, verbreitet. Auch für .NET-Entwickler ist es ratsam, sich ein wenig mit Linux auszukennen. Für viele ist der Schritt allerdings schwierig, da alles ganz anders ist als unter Windows.

Im Februar 2018 habe ich einige Recherchen angestellt, und daraus ergab sich, dass Linux 96 Prozent der populärsten Million Domains im Internet betreibt. Seit November 2017 laufen alle 500 schnellsten Supercomputer der Welt mit Linux, und aufgrund der Verbreitung von Android ist die Verbreitung bei Mobilgeräten mit etwa 70 Prozent angenommen. Das System unterstützt mehr als 30 Prozessorplattformen, und ein Kernelrelease kommt im Schnitt mit etwa 10 000 Patches daher, die von mehr als eintausend Personen zur Verfügung gestellt werden.

Sehr beeindruckende Zahlen! Aber nun zurück zu dem, was man über Linux wirklich wissen sollte. Zunächst ist da der Aufbau des Systems, mal ganz grob. Linux selbst ist eigentlich nur der Kernel (Kern), in dem z. B. Dateisystemstreiber und ähnliche Komponenten auf unterster Ebene enthalten sind. Na gut, eine Zahl noch: Der Kernel hat derzeit mehr als 20 Millionen Zeilen Code!

.NET-Famework & C# Track auf der BASTA! 2018

Verteilte Entwicklung

Zu einem typischen, auf Linux basierenden System braucht man natürlich noch vieles mehr, und das kommt alles aus dritter Hand, also aus anderen Open-Source-Projekten. Spezifische Treiber für Hardware, System- und Anwendungssoftware, Shells für den Umgang mit der Kommandozeile, grafische Oberflächen, Paketverwaltung und vieles mehr ist getrennt vom Kernel zu sehen. Trotzdem ist meistens, wenn der Begriff Linux verwendet wird, ein Gesamtsystem aus all diesen Elementen gemeint. Tatsächlich handelt es sich bei einem solchen Gesamtsystem gewöhnlich um eine Distribution, wie sie von verschiedenen Anbietern zusammengestellt wird. Diese Anbieter sorgen dafür, dass sämtliche enthaltene Software auf aktuellem Stand ist, dass Abhängigkeiten zwischen Software und Systembibliotheken korrekt aufgelöst werden können, dass es einen schönen bunten Installer für das System gibt sowie regelmäßige Updates.

Nun bin ich schon oft gefragt worden, warum ein .NET-Entwickler irgendwas zu Linux wissen sollte oder gar das System selbst im Alltag einsetzen. Nun, dazu gibts viele Antworten. Zum Beispiel ist Linux eine großartige Ausführungsplattform – schnell, performant, skalierbar und gratis! Natürlich ist das Adjektiv „gratis“ mit Vorsicht zu genießen: Die Pflege jedes Systems kostet schließlich Geld. Aber gerade in modernen Cloud-Umgebungen ist es letztlich so, dass Systeme einfach und ersetzbar sein sollen. Mit Linux fließen keine Lizenzgebühren an einen Hersteller, sodass eine Linux VM immer weniger kostet als eine mit Windows.

Total alltagstauglich

Ich selbst verwende Linux im Alltag, auf meinem Computer im Büro wie auch auf meinem Laptop. Ich bin Enthusiast und ich bin ein fortgeschrittener Anwender, mit mehr Bedürfnissen und Erwartungen an mein System der Wahl, dessen Flexibilität und Anpassbarkeit an meine Arbeitsweise. Mit Linux habe ich ein System gefunden, das ich überall einsetzen kann, in großen und kleinen Umgebungen, konsistent und flexibel, standardkonform und anpassbar. Kurz: Linux tut genau, was ich will.

Wenn Sie selbst Linux einmal ausprobieren wollen, haben Sie heute mehrere Möglichkeiten. Die beste ist, eine Distribution herunterzuladen (ich empfehle Ubuntu, für den allgemeinen Einsatz wie auch für den Einsteiger) und zu installieren. Das gelingt mit einem USB-Stick auf einem alten Laptop, oder auch einfach mit einem ISO-Image in einer VM. Bei der Installation passiert nichts, das einem geübten Computernutzer Sorgen bereiten sollte.

Alternativ können Sie auch eine virtuelle Maschine in der Cloud starten. Ob Azure, Amazon oder andere Anbieter, Linux-VMs sind in der Cloud einfach und schnell zu starten und kosten wenig. Mit einer solchen virtuellen Umgebung verbinden Sie sich im Anschluss mit SSH, der Secure Shell – dazu gleich etwas mehr.

Als letzte Variante zum Einstieg sei noch erwähnt, dass für Windows 10 und Windows Server auch das Windows Subsystem for Linux (WSL) verfügbar ist. Sie müssen dazu den Developer Mode auf diesen Systemen aktivieren und dann bash.exe ausführen, um etwa Ubuntu zu installieren. Alternativ können Sie auch andere Distributionen für WSL aus dem Microsoft Store herunterladen.

Schnittstellen aller Art

Ein wesentlicher Unterschied zwischen einer Installation auf eigener Hardware oder in einer lokalen VM und den Varianten in der Cloud oder mit WSL besteht in der Bedienoberfläche, mit der Sie konfrontiert werden. Es gibt eine Vielfalt grafischer Oberflächen für Linux, KDE und Gnome, Xfce, MATE, LXDE und viele mehr. Diese Umgebungen enthalten gewöhnlich einen Window Manager (die Komponente, die für den Umgang mit grafischen Fenstern verantwortlich ist) und basieren auf einer bestimmten Philosophie für das visuelle Erscheinungsbild und die Bedienung. Außerdem gibt es, für Entwickler interessant, bestimmte Libraries für Grafikausgabe und andere Systemfunktionalität (etwa GTK und Qt), die direkt mit den grafischen Oberflächen zusammenhängen.

Ich selbst verwende einen eigenständigen Window Manager namens i3, der sich besonders dadurch auszeichnet, dass der Anwender sich gar nicht mit der Maus um die Verwaltung der Fenster kümmern muss – meiner Meinung nach eine große Erleichterung. Darin besteht gerade der Spaß an Linux: Eigene Prioritäten können beliebig einbezogen werden. Anwendungssoftware ist übrigens von der Wahl einer grafischen Oberfläche unabhängig, sie lässt sich immer einsetzen.

Nun gibt es viele Gelegenheiten, zu denen Linux im praktischen Einsatz ohne grafische Oberfläche daherkommt. Das ist etwa bei der Cloud-VM so, aber natürlich auch bei anderen Hosting-Providern und sogar bei WSL. Es gibt sogar Anwender, die den Umgang mit einer Kommandozeile grundsätzlich vorziehen. Ich selbst zähle mich nicht zu Letzteren, aber ich muss sagen, dass unter den Fenstern, die ich im Alltag auf meinem System öffne, sehr viele Kommandozeilen zu finden sind. Tippen geht letztlich oft schneller als Klicken, besonders wenn man weiß, was man tut.

Shells und Kommandos

Die Kommandozeile auf einem Unix-System basiert auf der Shell. Die Shell zeigt einen Prompt an (gewöhnlich das aktuelle Verzeichnis im Dateisystem und ein paar andere Details) und erlaubt die Eingabe von Kommandos. Das klingt einfach, aber es gibt viele verschiedene Shells mit unterschiedlichen Prioritäten. Moderne Shells bieten automatische Vervollständigung von Kommandos mit spezifischem Verständnis für gewisse Kommandogruppen (z. B. git), Historie, Verwaltung von Hintergrundprozessen und vieles mehr, und sie können mit Shell-Skripten automatisiert werden, was besonders für Programmierer sehr nützlich ist. Meine persönliche Präferenz ist Zsh, zusammen mit den Plug-ins des Projekts oh-my-zsh.

Eine besondere Shell ist die bereits erwähnte Secure Shell (SSH). Diese baut eine gesicherte Verbindung zu einem anderen System auf (dazu dient ein Schlüssel, basierend auf einem Public-Key-Verfahren – bitte verwenden Sie nicht die einfache Passwortautorisierung!) und startet dort wiederum eine der eben beschriebenen normalen Shells. SSH hat viele weitergehende Mechanismen, die etwa das sichere Kopieren von Dateien ermöglichen oder das Tunneln beliebiger Datenverbindungen durch eine SSH-Verbindung. Für den interaktiven Umgang mit Systemen über SSH empfehle ich auch das Tool tmux (oder alternativ, etwas traditioneller, screen), das eine Art Fensterumgebung an der Kommandozeile ermöglicht, sodass mehrere Shells parallel verwendet werden können.

Das wichtigste Kommando für den Umgang mit einem Unix-System ist man für Manual, also Handbuch oder Anleitung. Mit diesem Kommando können Sie Informationen zur Verwendung anderer Kommandos anzeigen oder auch zu man selbst: man man. Ich empfehle, für alle im folgenden genannten Kommandos man auszuführen, um mehr Details zur Verwendung kennen zu lernen.

Darüber hinaus gibt es viele Standardkommandos, die gewöhnlich kurz benannt sind, damit man sie schneller eintippen kann, und viele mögliche Parameter haben, um Flexibilität zu erzeugen. Shell-Skripte zu schreiben bedeutet größtenteils, parametrisierte Kommandos aneinanderzureihen, bis etwas Nützliches passiert (Tabelle 1 und 2).

 

ls list: Liste von Dateien ausgeben
cp copy: Datei(en) kopieren
mv move: Datei(en) verschieben oder umbenennen
rm remove: Datei(en) löschen
mkdir make directory: Ordner anlegen
rmdir remove directory: Ordner löschen (muss leer sein!)
ln link: Verknüpfungen erzeugen
cat concatenate: Datei(en) ausgeben bzw. aneinander hängen
find Dateien suchen
grep In Dateien suchen
less Inhalte seitenweise anzeigen
ps processes: Prozesse anzeigen
Table 1: Wichtigste Kommandos

 

cd change directory: Ordner wechseln
alias Kommandoaliase erzeugen, ausgeben usw.
Table 2: In der Shell eingebaute Kommandos

 

Abgesehen von den Kommandos sollten Sie sich auch mit den Möglichkeiten vertraut machen, diese an der Kommondozeile zu kombinieren. Die erste Möglichkeit dafür ist die „Pipe“, dargestellt durch |, mit der die Ausgabe eines Kommandos (stdout) an ein anderes weitergeleitet wird (stdin). Zum Beispiel listet dieses Kommando alle Dateien im Systemverzeichnis /bin auf, zeilenweise in einer Langform, und leitet die Ausgabe dann weiter an less, um sie seitenweise anzuzeigen: ls -l /bin | less. Ein zweites Feature ist die Substitution, wobei die Ausgabe eines Kommandos in ein anderes eingebaut wird. Folgende Zeile verwendet which, um herauszufinden, wo das Kommando cat zu finden ist, und führt dann ls -l aus, um die ausführbare Datei von cat im Dateisystem anzuzeigen: ls -l `which cat`. Für Substitution kann auch diese etwas längere Form verwendet werden, falls der Umgang mit den richtigen Anführungszeichen schwierig ist: ls -l $(which cat)

Dateien und Rechte

Im Dateisystem gibt es keine Laufwerkbuchstaben. Stattdessen ist alles als Teil eines Baums organisiert, der bei / beginnt. Man nennt diese Wurzel passenderweise root. Es gibt viele Standardordner und -pfade wie /bin, /etc, /usr/lib und andere, und zusätzliche physikalische oder virtuelle Laufwerke werden in die Hierarchie eingehängt (gemountet). Dazu dient das Kommando mount bzw. die Konfigurationsdatei /etc/fstab.

Datei- und Ordnernamen unterscheiden zwischen Groß- und Kleinschreibung, und wenn sie mit einem . (Punkt) beginnen, werden sie nur von ls angezeigt, wenn die Option -a übergeben wird.

Natürlich sind im Dateisystem Zugriffsrechte wichtig. Wenn Sie sich die Ausgabe des Kommandos ls -l /bin/ls ansehen, finden Sie etwa an erster Stelle diesen kryptisch anmutenden String: -rwxr-xr-x. Unterteilt in drei Gruppen ist hier ersichtlich, welche Rechte der Besitzer der Datei hat (rwx: Read, Write, eXecute), sowie die besitzende Gruppe (r-x) und der Rest der Welt (r-x). Manchmal wird die Angabe auch numerisch dargestellt, sozusagen binär, mit dem Wert 4 für r, 2 für w und 1 für x. Die Rechte, die /bin/ls zugewiesen bekommen hat, können also als 755 geschrieben werden, ein Standardrecht, das besagt, dass jeder die Datei lesen und ausführen darf, aber nur der Besitzer Schreibrechte hat.

Um Berechtigungen zu konfigurieren, gibt es die Kommandos chown (change owner) und chgrp (change group), mit denen der Besitzer bzw. die besitzende Gruppe einer Datei oder eines Ordners gesetzt werden können. chmod ändert die Berechtigungen selbst, mithilfe verschiedener kreativer Parametersyntax. Zum Beispiel erteilt chmod u+x dem Besitzer (u: user) das Ausführungsrecht, chmod +w setzt Schreibrechte für alle drei Berechtigungsebenen, und chmod 644 erteilt explizit das Recht -rw-r–r–. Für Ordner ist es wichtig zu wissen, dass ein Benutzer das Recht x haben muss, damit er in den Ordner hinein navigieren kann (mit cd).

Zum Schluss ist für den Umgang mit Berechtigungen natürlich noch wichtig zu wissen, mit welchem Account Sie eigentlich im System unterwegs sind. Der allmächtige Superuser auf einem Unix-System heißt „root“ und hat die Benutzer-ID 0, aber mit diesem Konto sollten Sie aus Sicherheitsgründen praktisch niemals direkt arbeiten. whoami zeigt an, wie ihr aktueller Benutzer heißt, und Sie können mit adduser, addgroup und usermod andere Konten anlegen und modifizieren. Tatsächlich wird dies allerdings normalerweise fehlschlagen, da Sie als normaler Anwender nicht die Rechte haben, Benutzerkonten zu administrieren. Um temporär mit root-Berechtigungen zu arbeiten, stellen Sie einem Kommando sudo (super user do) voran. Damit können Sie alles machen im System, aber natürlich auch alles zerstören – also bitte Vorsicht!

Wenn dann was passiert

Das Kommando ps zeigt Prozesse an, die aktuell im System laufen. Alle Prozesse sehen Sie, wenn Sie Optionen angeben: ps aux. top oder htop stellen die laufenden Prozesse tabellarisch dar und bieten interaktive Features, um die Ausgabe zu sortieren oder weitere Details abzurufen.

Mit kill schicken Sie einem Prozess ein Signal, alle Signale können Sie mit kill -l abrufen. Ein Prozess kann generell auf bestimmte Signale reagieren. Oft tut er das allerdings, indem er sich beendet, womit sich der Name des Kommandos erklärt. Um einen hängenden Prozess zu beenden, verwenden sie kill -9. Sie müssen nach dem Signal selbst noch die PID (process ID) des Prozesses übergeben, wie sie in der Ausgabe von ps erscheint. Alternativ können Sie auch skill verwenden, das einen Prozess namentlich identifizieren kann.

Die Konfiguration eines Linux-Systems basiert zum größten Teil auf Textdateien, die im Ordner /etc (und dessen Unterordnern) zu finden sind. Wenn eine Konfigurationsdatei für einen einzelnen Benutzer angepasst werden kann (die man-Page sagt Ihnen das), gibt es oft eine entsprechende Datei mit einem Punkt vor dem Namen im Home Directory des Benutzers. Seit einiger Zeit hat sich auch die Verwendung des Ordners ~/.config verbreitet (also der Ordner .config im Home Directory des Benutzers). In das Home Directory gelangen Sie übrigens am einfachsten, indem Sie cd ohne Parameter ausführen. Gewöhnlich lautet der Pfad /home/, aber ~ (Tilde) ist ein Kürzel, das immer verwendbar ist.

Admin in spe

Wenn Sie Konfigurationsdateien bearbeiten, sollten Sie sehr vorsichtig vorgehen, insbesondere bei denen in /etc. Sie können damit sehr leicht zumindest einzelne Systemdienste beschädigen. Trotz dieser Gefahr ist es regelmäßig nötig, solche Dateien zu bearbeiten, und dafür brauchen Sie natürlich einen Editor. Erfahrene Unix-Benutzer unterteilen sich im Allgemeinen in zwei Gruppen: Anwender des Editors vi (oder vim, der moderneren Version davon), und Anwender von Emacs. Beide Editoren sind extrem mächtig, es gibt dazu unter Windows oder anderen Systemen nichts Vergleichbares – gleichzeitig sind sie aber nicht besonders einfach im praktischen Einsatz. Ich empfehle daher den Editor nano für Einsteiger, der gewöhnlich auch von den Distributionen als Standardpaket verfügbar gemacht wird. Der wichtigste Vorteil besteht darin, dass nano die verfügbaren Tastaturkommandos visuell anzeigt und so den Einstieg wesentlich einfacher macht.

Nun fehlen in diesem Rundumschlag für den werdenden Linux-Administrator noch zwei wichtige Informationen. Daher hier erstens ein paar Worte zur Paketverwaltung. Pakete sind die Bausteine jeder Distribution. Sie enthalten Dateien, etwa für ein bestimmtes Programm, und Skripte, die bei der Installation des Pakets und bei anderen Anlässen automatisch ausgeführt werden. Leider gibt es allerdings verschiedene Paketsysteme, je nach der Distribution, für die Sie sich entschieden haben. Für die verbreiteten Distributionen Debian und Ubuntu verwenden Sie das Kommando apt (oder in älteren Versionen apt-get), während bei Red Hat und Derivaten rpm das zentrale Kommando ist. Auf den Webseiten der Distribution sollten Sie die notwendigen Details recht einfach finden können, da die Paketverwaltung ein zentraler Bestandteil des Systems ist.

Der zweite und letzte ausstehende Punkt besteht in ein paar Details auf niedriger Ebene. Zum Beispiel müssen Sie das System eventuell einmal neu starten oder herunterfahren. sudo reboot startet ein Linux-System neu, und sudo shutdown now beendet alle Prozesse, fährt das System herunter und schaltet es aus. Im Verzeichnis /var/log finden Sie Systemprotokolle – dies sollte der erste Anlaufpunkt sein, wenn im System einmal etwas nicht funktioniert!

Und dann: .NET

Nun möchte ich diese Einleitung mit einer Beschreibung der Schritte, die zur Ausführung einer .NET-Core-MVC-Anwendung notwendig sind, abschließen. Wenn Sie dem Beispiel folgen mögen, haben Sie letztlich Ihren ersten eigenen Linux-Server aufgesetzt.

Zunächst benötigen Sie .NET Core selbst. Microsoft hat hierzu unter “Get started with .NET in 10 minutes” Anleitungen publiziert, die sich je nach Distribution aufgrund der angesprochenen Unterschiede in der Paketverwaltung unterscheiden. Gewöhnlich sind dort fünf oder sechs Kommandos zu finden, nach deren Ausführung Sie .NET Core vollständig installiert haben.

Wenn Sie auf dem System selbst gern entwickeln wollen und Ihnen einen grafische Oberfläche zur Verfügung steht, empfehle ich auch sehr die Installation von Visual Studio Code. Auch hierzu stellt Microsoft eine detaillierte Anleitung unter “Running VS Code on Linux” bereit.

Nun haben Sie womöglich bereits eine .NET-Core-MVC-Anwendung, doch Sie können mit folgenden Kommandos auch einfach eine erzeugen und ausführen:

 

mkdir demoapp
cd demoapp
dotnet new mvc
dotnet run

 

Um diese Anwendung nun als Systemdienst ausführbar zu machen, sind mehrere Schritte erforderlich oder zumindest ratsam. Zunächst sollten Sie die Anwendung im Dateisystem installieren, also nicht etwa direkt aus dem Entwicklungsverzeichnis heraus starten. Die folgenden Kommandos sind dafür erforderlich:

 

dotnet publish
sudo mkdir /usr/local/demoapp
sudo cp -r bin/Debug/netcoreapp2.0/publish/\* /usr/local/demoapp
sudo chown -R www-data.root /usr/local/demoapp

 

Damit die Anwendung beim Systemstart automatisch ausgeführt wird, müssen Sie nun einen Dienst einrichten. Dazu erzeugen Sie zunächst eine neue Datei in /etc/systemd/system:

 

sudo nano /etc/systemd/system/demoapp.service

 

In dieser Datei werden Details zur Ausführung der Anwendung eingetragen. Die Datei könnte folgendermaßen aussehen:

 

[Unit]
Description=Demo App

[Service]
WorkingDirectory=/usr/local/demoapp
ExecStart=/usr/bin/dotnet /usr/local/demoapp/demoapp.dll
Restart=always
RestartSec=10
SyslogIdentifier=demoapp
User=www-data
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

 

Nun können Sie den neu erzeugten Dienst aktivieren und sofort starten:

 

sudo systemctl enable demoapp
sudo systemctl start demoapp

 

Wenn Sie an dieser Stelle (wie zuvor nach dem Kommando dotnet run) den URL http://localhost:5000 im Browser ansteuern, sollten Sie die laufende Anwendung zu sehen bekommen. Allerdings ist es eine wichtige und dringliche Empfehlung von Microsoft, den Server Kestrel nicht für den Rest der Welt zugänglich zu machen. Stattdessen sollte hierfür ein Proxy-Server verwendet werden. Es bleibt also als letzter Schritt die Aufgabe, diesen ebenfalls einzurichten. Ich entscheide mich für diesen Zweck für nginx, das Sie zunächst (für Ubuntu) folgendermaßen installieren müssen:

 

sudo apt install nginx

 

Nun erzeugen Sie eine neue Konfigurationsdatei für demoapp:

 

cd /etc/nginx
sudo vi sites-available/demoapp

 

Die Datei sollte mindestens diesen Inhalt haben:

 

server {
  listen 80;
  location / {
    proxy_pass http://localhost:5000;
  }
}

 

Es ist ziemlich leicht ersichtlich, was hier passiert: Zugriffe auf Port 80 des Servers werden an den Kestrel-URL weitergeleitet. Microsoft empfiehlt, bei der Konfiguration von nginx noch einige weitere optionale Schritte zu machen, weitere Details können Sie unter “Host ASP.NET Core on Linux with Ngix” nachlesen.

Es ist möglich, dass das Standard-Set-up von nginx auf Ihrem System bereits einen Dienst auf Port 80 betreibt. Sie können diesen Dienst entfernen, falls notwendig:

 

sudo rm sites-enabled/default

 

Nun aktivieren Sie Ihren eigenen neuen Dienst und sorgen dafür, dass nginx seine Konfiguration neu lädt:

 

sudo ln -s sites-available/demoapp sites-enabled/
sudo nginx -s reload

 

Damit ist der Vorgang abgeschlossen. Sie können nun mit dem Browser auf Port 80 des Linux-Systems zugreifen und dort die laufende Anwendung sehen.

Wenn dieser Artikel Ihr Interesse an Linux geweckt oder neu entflammt hat, sind die Sessions „Linux 101 für .NET-Entwickler“ von Oliver Sturm und “Linux Sicherheit für .NET Entwickler” von Tobias Kopf genau die richtigen für Sie.

Alternativ gibt es von Oliver Sturm den Architektur Workshop am Montag oder den Architektur Day am Donnerstag, mit vielen Themen rund um die aktuelle Software-Entwicklung im Microsoft-Umfeld.

Ihr aktueller Zugang zur .NET- und Microsoft-Welt.
Der BASTA! Newsletter:

Behind the Tracks

.NET Framework & C#
Visual Studio, .NET, Git, C# & mehr

Agile & DevOps
Agile Methoden, wie Scrum oder Kanban und Tools wie Visual Studio, Azure DevOps usw.

Web Development
Alle Wege führen ins Web

Data Access & Storage
Alles rund um´s Thema Data

JavaScript
Leichtegewichtig entwickeln

UI Technology
Alles rund um UI- und UX-Aspekte

Microservices & APIs
Services, die sich über APIs via REST und JavaScript nutzen lassen

Security
Tools und Methoden für sicherere Applikationen

Cloud & Azure
Cloud-basierte & Native Apps