Jeder von uns hat seinen ganz eigenen Ablauf seinen PC einzurichten. Für gewöhnlich dauert es immer ein paar Tage bis man alle Programme installiert und konfiguriert, alle Git Repositories gecloned und die Entwicklungsumgebung eingerichtet hat. Nachdem das immer sehr Zeit aufwendig und um ehrlich zu sein auch ein bisschen nervig ist, habe ich damit begonnen mein PC Setup in Infrastructure as Code (IaC) Manier zu beschreiben, um schließlich meinen PC automatisiert einrichten zu können. IaC Tools gibt es wie Sand am Meer ich hab mich hierbei für Ansible entschieden, da es Open Source Software ist und ich mit Ansible bereits zuvor gearbeitet habe.
Nachdem ich meinen privaten Linux PC bereits mit einem Ansible Setup automatisiert aufsetze und verwalte, habe ich auch ein solches Setup für mein Arbeits-Macbook bei Miragon erstellt. Die Basis dieses Setups verwenden wir bei Miragon mittlerweile sogar, um Macbooks für neue Kollegen einzurichten und die bereits vorhandenen Macbooks auf einem aktuellen Stand zu halten.
In diesem Blogpost zeige ich, wie wir Ansible einsetzen, um Software auf unseren Macs mit Homebrew zu installieren, die Konfiguration von Entwicklungstools vorzunehmen und Git Repositories zu clonen und zu aktualisieren.
Ansible ist ein Open-Source-Automatisierungswerkzeug zur Orchestrierung und allgemeinen Konfiguration und Administration von Computern
Mit Ansible beschreibt man den Zielzustand eines Systems in sogenannten Playbooks (.yml
Dateien).
Zusätzlich definiert man in einem sogenannten Inventory File die Zielsysteme auf denen das Playbook ausgeführt wird.
Wenn man anschließend das Playbook ausführt baut Ansible eine SSH Verbindung zu den Zielsystemen auf und führt die einzelnen Tasks des Playbooks aus.
Ansible ist agentless und dementsprechend muss Ansible nur auf dem Host System und nicht auf den Zielsystemen installiert werden.
Infrastructure as Code ist heute zum Standard für die Serveradministration geworden. In diesem Kontext gehört Ansible auch am zu den Bekanntesten und Verbreitesten IaC Tools. Um Ansible (oder ein anderes IaC Tool) führt kein Weg herum bei der Administration von Server. In diesem Kontext trifft man auch besonders häufig auf diese Tools. Aber nachdem ein Desktop Betriebssystem nichts anderes ist, wie ein Server mit grafischer Oberfläche, kann Ansible auch hier problemlos eingesetzt werden. Insbesondere wenn man Linux aber auch Mac als Betriebssystem verwendet.
Vor der Verwendung von Ansible müssen lediglich drei manuelle Einrichtungsschritte ausgeführt werden: Den Paketmanager Homebrew installieren, Ansible installieren und unseren SSH-Key in Github hinterlegen.
Homebrew Homebrew verwenden wir als Paketmanager, um Programme zu installieren (https://brew.sh/index_de)
SSH Key Bevor wir Git Repositories von z.B. Github clonen können muss zuerst ein SSH Key erstellt und in Github hinterlegt werden
Ansible
Nachdem wir Homebrew installiert haben muss nur noch Ansible mit brew install ansible
installiert werden und wir sind startklar.
Die einfachste Art Software zu installieren ist mit einem Paketmanager. Unter Mac verwenden wir den Paketmanager Homebrew, den wir zuvor bereits installiert haben.
Um ein Programm wie z.B. asciiquarium mit Homebrew zu installieren verwenden wir das Ansible Module homebrew. Folgender Ansible Task entspricht dem Befehl brew install asciiquarium
.
- name: Install packages with homebrew homebrew: name: - asciiquarium
Software mit einer grafischen Oberfläche (GUI) kann in Mac OS über Homebrew Cask installiert werden.
Hierfür gibt es leider kein eigenes Ansible Module, jedoch können wir hierfür das Shell Module verwenden und direkt den Befehl brew install --cask firefox
ausführen.
Bei Ansible definieren wir hierfür einen eigenen Task, der das Shell Modul verwendet und das Command brew install --cask firefox
ausführt.
In diesem speziellen Fall müssen wir noch zusätzlich die Shell angeben, in der der Befehl ausgeführt werden soll. In unserem Fall ist das die /bin/zsh
Shell.
Ansible führt jeden Befehl in einer eigenen non interactive Shell aus. Dabei werden Shell Hooks nicht ausgeführt und Konfigurationsdateien wie z.B. die
.zshrc
oder.bashrc
nicht berücksichtigt. In unserem konkreten Fall kann es passieren, das dasbrew
Executable nicht zur Verfügung steht in einer solchen Shell. Um das Problem zu beseitigen muss der Befehl in der richtigen Shell ausgeführt werden. In diesem Fall ist das diebin/zsh
.
- name: Install homebrew cask packages shell: cmd: brew install --cask {{ item }} executable: /bin/zsh with_items: - google-chrome - firefox
Um mehrere Ansible Befehl hintereinander auszuführen kann das with_items
Feature von Ansible verwendet werden.
Dieses Feature erlaubt es über einen Task mit einer Liste an Werten zu iterieren.
Bei der Installation von Cask Paketen müssen wir auf dieses Feature zurückgreifen, um mehrere Programme zu installieren.
Eine weitere Aufgabe von Server-Administrator ist es, die auf den Servern installierte Software aktuell zu halten.
Bei PCs sind die Benutzer dafür selbst verantwortlich. Auch diese Aufgabe lässt sich mit Ansible vereinfachen.
Das Homebrew Module verfügt hierfür über die Optionen update_homebrew
, um Homebrew selbst zu aktualisieren und upgrade_all
, um alle installierten Homebrew Pakete zu aktualisieren.
Der dazugehörige Ansible Task sieht wie folgt aus.
- name: Update homebrew homebrew: update_homebrew: true upgrade_all: true
Ich füge einen solchen Update Task gerne am Anfang eines Playbooks ein, damit dieser jedes mal ausgeführt wird. Dadurch kann sichergestellt werden, dass Homebrew und alle von Homebrew installierten Pakete auf einem aktuellen Stand sind.
Konfigurationen werden unter Linux und Mac OS in speziellen Konfigurationsdateien vorgenommen. Um Konfigurationen automatisch anzupassen können diese Dateien mit Ansible bearbeitet werden.
Es gibt unterschiedliche Möglichkeiten Konfigurationsdateien mit Ansible zu bearbeiten. Zum einen können Konfigurationsdateien erstellt werden, in dem diese an die richtige Stelle im System kopiert werden. Zum anderen können auch nur einzelne Zeilen zu einer bereits bestehenden Datei hinzugefügt werden. Zusätzlich gibt es noch viele weitere Möglichkeiten Konfigurationen vorzunehmen.
Beispielsweise haben wir eine (sehr) einfach gestaltete .zshrc
Datei in unserem Ansible Setup, die bei erstmaliger Ausführung erstellt wird.
Diese Datei beinhaltet lediglich einige praktische Aliase, um die tägliche Entwicklung zu vereinfachen.
alias ll='ls -la'
Diese .zshrc
Datei wird mit folgendem Ansible Command in das Home Verzeichnis des Users kopiert mit der passenden Berechtigung, falls die Datei nicht bereits vorhanden ist.
- name: Create .zshrc if it does not exist copy: dest: ~/ src: .zshrc mode: 0644 force: no
Die andere Alternative, die wir für Konfigurationen verwenden ist eine zusätzlich Zeile zu einer Datei hinzuzufügen.
Hierfür kann man das Ansible Module lineinfile
verwendet werden.
In unserem Ansible Setup nutzen wir dieses Module, um z.B. einen Hook für das Tool direnv in der .zshrc
zu registrieren.
Der Vorteil dieses Vorgehens im Vergleich zum Kopieren einer Konfigurationsdatei ist, dass sichergestellt ist, dass die Zeile in der Konfigurationsdatei vorhanden ist.
- name: Enable direnv lineinfile: path: ~/.zshrc line: eval "$(direnv hook zsh)"
Insbesondere wenn man mit vielen Repos Git Repositories arbeiten muss, weil man beispielsweise einem Poly Repo Ansatz folgt oder an unterschiedlichen Projekten arbeitet verliert man schnell den Überblick. Mit Ansible kann man dem ein bisschen Abhilfe schaffen, in dem man die Git Repos in einem eigenen Task oder Playbook verwaltet.
Um Git Repos zu clonen und aktuell zu halten kann folgender Task definiert werden.
Analog zu Homebrew Cask Installationen kann auch hier das with_items
Feature verwendet werden.
Zusätzlich sollte man zu diesem Task ignore_errors
aktiviert werden, damit das Playbook nicht beendet wird sollte der Task fehlschlagen.
- name: Clone Miragon Git Repos git: repo: "git@github.com:Miragon/{{item}}.git" clone: yes update: yes dest: "~/source/miragon/{{item}}" ignore_errors: yes with_items: - code-examples
Sobald Uncommited Changes im Repository sind oder der Branch auf dem man sich aktuell befindet nicht existiert schlägt der Task fehl und das Playbook wird abgebrochen, wenn
ignore_errors
nicht aktiviert ist.
In den vorangegangenen Abschnitten habe ich einen kurzen Überblick über Ansible gegeben habe und erklärt welche Ansible Module und Tasks wir bei Miragon verwenden, um Software auf unseren Macs zu installieren, aktuell zu halten und Git Repositories zu clonen. An dieser Stelle soll es jetzt noch konkreter werden, in dem ich erkläre, wie unser aktuelles Mac Setup aufgebaut ist und wie wir es verwenden.
Für unser Mac Setup verwenden wir Roles.
Aktuell haben wir die beiden Playbooks initial.yml
und site.yml
.
Roles in Ansible sind eine Möglichkeit wiederverwendbare Bausteine zu definieren. Zusätzlich geben Roles eine Struktur für den Quellcode vor, die den Code übersichtlicher und verständlicher macht.
Das Playbook initial.yml
nutzen wir für die Ersteinrichtung eines neuen Macbooks.
Hierbei wird die Role mac auf jedem Mac und die Roles macdev und miragon zusätzlich nur auf Entwicklerpcs ausgeführt.
--- - hosts: - mac roles: - mac - hosts: - macdev roles: - macdev - miragon
Die Role mac installiert mit Homebrew eine Auswahl an Standardprogrammen, die jeder von uns im täglichen Doing gebrauchen kann.
Darunter fallen die Browser Firefox und Google Chrome, der Passwordmanager 1Password, die Office 365 Tools und der Window Manager Rectangle.
Zusätzlich fügen wir auf dem Desktop des Users eine links.txt
Datei hinzu mit den wichtigsten Links zu den Cloud Tools, die wir bei Miragon verwenden.
. ├── README.md ├── roles │ ├── acs │ │ ├── tasks │ │ └── vars │ ├── itm │ │ ├── tasks │ │ └── vars │ ├── mac │ │ └── tasks │ ├── macdev │ │ ├── files │ │ ├── tasks │ │ └── vars │ ├── miragon │ │ ├── tasks │ │ └── vars │ └── processide │ ├── tasks │ └── vars ├── initial.yml └── site.yml
Die Role macdev funktioniert analog zur mac Role. Sie installiert zusätzlich eine Auswahl an Software mit Homebrew, die die Entwickler für ihre tägliche Arbeit benötigen. Darunter fallen bekannte Commandline Tools wie z.B. curl, wget, direnv, maven, gradle und die kubernetes-cli. Zusätzlich installieren wir die Java jdks, die wir aktuell für unsere Anwendungen verwenden sowie den Nodejs Versions Manager nvm.
Zudem führen wir auf Entwickler-PCs auch noch die Role miragon aus.
Diese fügt einige allgemeine Git Repositories von Miragon auf dem PC in dem Ordner ~/source/miragon/
hinzu.
Darunter fällt unsere Miragon Website, Code Beispiele und Templates sowie user Ansible Mac Setup.
Nachdem das Playbook inital.yml
sehr viel Zeit bei der Ausführung in Anspruch nehmen kann, habe ich mich dazu entschlossen für die alltägliche Nutzung ein eigenes Playbook anzulegen.
Diese Playbook ist die site.yml
und dient dazu Homebrew sowie die installierten Pakete aktuell zu halten und für unsere verschiedenen Projekte die Git Repositories zur Verfügung zu stellen.
--- - hosts: - mac - macdev tasks: - name: Update homebrew homebrew: update_homebrew: true upgrade_all: true ignore_errors: yes - hosts: - macdev - miragon roles: - miragon - hosts: - acs roles: - acs - hosts: - itm roles: - itm - hosts: - processide roles: - processide
Auch wenn jeder Entwickler Zugriff auf die vollständige Code Base von Miragon hat, braucht nicht jeder alle Projekte auf seinem PC für die täglich Arbeit.
Deswegen legen wir für jedes Projekt eine eigene Role mit dem Projektnamen sowie einen Task in der site.yml
an.
Um diese Role auszuführen muss der User nur noch eine Gruppe mit dem Projektnamen im Inventory anlegen.
Dadurch kann jeder Entwickler selbst entscheiden, von welchen Projekten er die Git Repositories clonen möchte.
Bei der Landeshauptstadt München sind wir Teil eines Entwicklungsteams, das die Prozessautomatisierungsplattform DigiWF entwickelt. Du möchtest mehr über DigiWF erfahren, dann schau dir gerne unseren Blog Post zu DigiWF bei der Landeshauptstadt München an.
Wenn beispielsweise ein Entwickler in unserm Kundenprojekt bei der Landeshauptstadt München startet, kann dieser folgende 2 Zeilen im Inventory hinzufügen und bekommt alle Repositories, die für das Projekt benötigt werden in den Ordner ~/source/miragon/itm/
gecloned.
[itm] localhost ansible_user=<your-username> ansible_connection=local ansible_python_interpreter=python3
Rechtliches