Konfigurieren einer Continuous Integration Testing-Umgebung mit Docker und Docker Compose unter Ubuntu 14.04

Ein Artikel von Docker

Einführung

Continuous Integration (CI) bezieht sich auf die Vorgehensweise, bei der Entwickler Code so oft wie möglich integrieren und jedes Commit vor und nach dem Zusammenführen in einem gemeinsam genutzten Repository durch einen automated Build getestet wird.

CI beschleunigt Ihren Entwicklungsprozess und minimiert das Risiko kritischer Probleme in der Produktion, ist jedoch nicht einfach einzurichten. Automatisierte Builds werden in einer anderen Umgebung ausgeführt, in der die Installation von * Laufzeitabhängigkeiten * und die Konfiguration von * externen Diensten * möglicherweise anders sind als in Ihrer lokalen Umgebung und Ihrer Entwicklungsumgebung.

Docker ist eine Containerisierungsplattform, mit der die Probleme der Umgebungsstandardisierung vereinfacht werden sollen, sodass die Bereitstellung von Anwendungen auch standardisiert werden kann (https://www.digitalocean.com/community/tutorials) / das-docker-ökosystem-eine-übersicht-über-containerisierung [erfahren sie mehr über docker]). Mit Docker können Entwickler Produktionsumgebungen auf lokalen Computern simulieren, indem Anwendungskomponenten in lokalen Containern ausgeführt werden. Diese Container können mithilfe von Docker Compose unabhängig von der Anwendung und dem zugrunde liegenden Betriebssystem problemlos automatisiert werden.

In diesem Tutorial wird Docker Compose verwendet, um die Automatisierung von CI-Workflows zu demonstrieren.

Wir werden eine dockerisierte Python-Anwendung vom Typ "Hallo Welt" und ein Bash-Testskript erstellen. Für die Ausführung der Python-Anwendung sind zwei Container erforderlich: einer für die App selbst und ein Redis-Container für den Speicher, der als Abhängigkeit für die App erforderlich ist.

Anschließend wird das Testskript in einem eigenen Container angedockt und die gesamte Testumgebung in eine * docker-compose.test.yml * -Datei verschoben, damit wir sicherstellen können, dass jede Testausführung in einer neuen und einheitlichen Anwendungsumgebung ausgeführt wird.

Dieser Ansatz zeigt, wie Sie bei jedem Test eine identische, frische Testumgebung für Ihre Anwendung erstellen können, einschließlich ihrer Abhängigkeiten.

So automatisieren wir die CI-Workflows unabhängig von der zu testenden Anwendung und der zugrunde liegenden Infrastruktur.

Bedarf

Bevor Sie beginnen, benötigen Sie:

  • Ein Ubuntu 14.04 Server

  • Ein Benutzer ohne Rootberechtigung mit sudo-Berechtigungen. Sie können diesem tutorial folgen, um dies einzurichten

  • Etwas Vertrautheit mit Docker und https://www.digitalocean.com/community/tutorials/how- Docker-Compose-on-Ubuntu-14-04-installieren und-verwenden [Docker Compose]; Die Links dienen als Referenz, da wir die Software während dieses Tutorials installieren

  • * Testen, Testen und mehr (automatisiertes) Testen! * Sie sollten bereits von den Vorteilen des Testens und Anwendens von CI in Ihren Entwicklungsworkflows überzeugt sein

Schritt 1 - Installieren Sie Docker

Wenn Docker noch nicht auf Ihrem Server verfügbar ist, können Sie am einfachsten das offizielle Docker-Installationsskript herunterladen und ausführen, das Sie zur Eingabe eines Sudo-Kennworts auffordert (weitere Informationen zur Installation von Docker finden Sie unter https://www.digitalocean.com/community/tutorials) / Wie installiere und verwende ich Docker? [hier]):

wget -qO- https://get.docker.com/ | sh

Um die Arbeit mit Docker zu vereinfachen, fügen Sie Ihren Benutzer mit dem folgenden Befehl der Gruppe * docker * hinzu:

sudo usermod -aG docker $(whoami)

Melden Sie sich ab und dann bei Ihrem Server an, um die Gruppe * docker * für Ihren Benutzer zu aktivieren.

Schritt 2 - Installieren Sie Docker Compose

Docker Compose ist ein Open-Source-Tool zum Definieren und Ausführen von Anwendungen mit mehreren Containern mithilfe eines deklarativen Ansatzes. Führen Sie die folgenden Befehle aus, um Docker Compose zu installieren:

sudo apt-get update
sudo apt-get -y install python-pip
sudo pip install docker-compose

Stellen Sie sicher, dass + docker-compose + korrekt installiert ist, indem Sie Folgendes ausführen:

docker-compose --version

Sie sollten etwas sehen wie:

Ausgabe

docker-compose version 1.6.2, build 4d72027

Dies sollte Ihnen die installierte Docker-Compose-Version mitteilen.

Schritt 3 - Erstellen Sie die Python-Anwendung "Hello World"

In diesem Schritt erstellen wir eine einfache Python-Anwendung als Beispiel für den Anwendungstyp, den Sie mit diesem Setup testen können.

Erstellen Sie einen neuen Ordner für unsere Anwendung, indem Sie Folgendes ausführen:

cd ~
mkdir hello_world
cd hello_world

Bearbeite eine neue Datei + app.py + mit nano:

nano app.py

Fügen Sie den folgenden Inhalt hinzu:

app.py

from flask import Flask
from redis import Redis

app = Flask(__name__)
redis = Redis(host="redis")

@app.route("/")
def hello():
   visits = redis.incr('counter')
   html = "<h3>Hello World!</h3>" \
          "<b>Visits:</b> {visits}" \
          "<br/>"
   return html.format(visits=visits)

if __name__ == "__main__":
   app.run(host="0.0.0.0", port=80)

+ app.py + ist eine auf Flask basierende Webanwendung, die eine Verbindung zu einem Redis-Datendienst herstellt. Die Zeile + visitors = redis.incr ('counter') + erhöht die Anzahl der Besuche und behält diesen Wert in Redis bei. Schließlich wird eine "+ Hello World +" - Nachricht mit der Anzahl der Besuche in HTML zurückgegeben.

Unsere Anwendung hat zwei Abhängigkeiten, "+ Flask " und " Redis +", die Sie in den ersten beiden Zeilen sehen können. Diese Abhängigkeiten müssen definiert werden, bevor wir die Anwendung ausführen können. Bearbeiten Sie eine neue Datei:

nano requirements.txt

Fügen Sie den Inhalt hinzu:

requirements.txt

Flask
Redis

Schritt 4 - Dockerisieren Sie die Anwendung „Hello World“

Docker verwendet eine Datei mit dem Namen "+ Dockerfile +", um die erforderlichen Schritte zum Erstellen eines Docker-Images für eine bestimmte Anwendung anzugeben. Bearbeiten Sie eine neue Datei:

nano Dockerfile

Fügen Sie den folgenden Inhalt hinzu:

Dockerfile

FROM python:2.7

WORKDIR /app

ADD requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt

ADD app.py /app/app.py

EXPOSE 80

CMD ["python", "app.py"]

Analysieren wir die Bedeutung jeder Zeile:

  • + FROM python: 2.7 +: Gibt an, dass unser "Hello World" -Anwendungsimage aus dem offiziellen Docker-Image von + python: 2.7 + erstellt wurde

  • + WORKDIR / app +: Setzt das Arbeitsverzeichnis im Docker-Image auf + / app +

  • + ADD requirements.txt / app / requirements.txt: Fügt die Datei` + requirements.txt` zu Ihrem Docker-Image hinzu

  • + RUN pip install -r requirements.txt +: Installiert die Abhängigkeiten der Anwendung + pip +

  • + ADD app.py / app / app.py +: Fügt unseren Anwendungsquellcode zum Docker-Image hinzu

  • + EXPOSE 80 +: Zeigt an, dass unsere Anwendung unter Port 80 (dem Standard-Port für öffentliche Webanwendungen) erreichbar ist.

  • + CMD [" python "," app.py "] +: Der Befehl, der unsere Anwendung startet

Diese + Dockerfile + -Datei enthält alle Informationen, die zum Erstellen der Hauptkomponente unserer „Hello World“ -Anwendung erforderlich sind.

  • Die Abhängigkeit *

Jetzt kommen wir zum komplexeren Teil des Beispiels. Unsere Anwendung erfordert Redis als externen Dienst. Dies ist die Art von Abhängigkeit, die in einer herkömmlichen Linux-Umgebung möglicherweise nur schwer auf die gleiche Weise eingerichtet werden kann. Mit Docker Compose können wir sie jedoch jedes Mal auf wiederholbare Weise einrichten.

Erstellen wir eine + docker-compose.yml + -Datei, um Docker Compose zu verwenden.

Bearbeiten Sie eine neue Datei:

nano docker-compose.yml

Fügen Sie den folgenden Inhalt hinzu:

docker-compose.yml

web:
 build: .
 dockerfile: Dockerfile
 links:
   - redis
 ports:
   - "80:80"
redis:
 image: redis

In dieser Docker Compose-Datei wird angegeben, wie die Anwendung „Hello World“ lokal in zwei Docker-Containern hochgefahren wird.

Es definiert zwei Container, "+ web " und " redis +".

  • + web + verwendet den aktuellen Ordner für den + build -Kontext und erstellt Ihre Python-Anwendung aus der soeben erstellten` + Dockerfile`-Datei. Dies ist ein lokales Docker-Image, das wir nur für unsere Python-Anwendung erstellt haben. Es definiert eine Verknüpfung zum Container "+ redis ", um Zugriff auf die Container-IP " redis +" zu erhalten. Über die öffentliche IP-Adresse Ihres Ubuntu-Servers können Sie auch über das Internet auf Port 80 zugreifen

  • + redis + wird von einem öffentlichen Standard-Docker-Image mit dem Namen + redis + ausgeführt

Schritt 5 - Stellen Sie die Anwendung „Hello World“ bereit

In diesem Schritt stellen wir die Anwendung bereit und am Ende wird sie über das Internet zugänglich sein. Für die Zwecke Ihres Bereitstellungsworkflows können Sie dies als Entwicklungs-, Staging- oder Produktionsumgebung betrachten, da Sie die Anwendung mehrmals auf dieselbe Weise bereitstellen können.

Mit den Dateien + docker-compose.yml + und + Dockerfile + können Sie die Bereitstellung lokaler Umgebungen automatisieren, indem Sie Folgendes ausführen:

docker-compose -f ~/hello_world/docker-compose.yml build
docker-compose -f ~/hello_world/docker-compose.yml up -d

In der ersten Zeile wird unser lokales Anwendungsbild aus der Datei + Dockerfile + erstellt. In der zweiten Zeile werden die Container "+ web " und " redis " im Dämonmodus (" -d ") ausgeführt, wie in der Datei " docker-compose.yml +" angegeben.

Überprüfen Sie, ob die Anwendungscontainer erstellt wurden, indem Sie Folgendes ausführen:

docker ps

Dies sollte zwei laufende Container mit den Namen "+ helloworld_web_1 " und " helloworld_redis_1 +" anzeigen.

Überprüfen wir, ob die Anwendung aktiv ist. Wir können die IP des Containers + helloworld_web_1 + ermitteln, indem wir Folgendes ausführen:

WEB_APP_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' helloworld_web_1)
echo $WEB_APP_IP

Überprüfen Sie, ob die Webanwendung die richtige Nachricht zurückgibt:

curl http://${WEB_APP_IP}:80

Dies sollte ungefähr so ​​aussehen:

Ausgabe

<h3>Hello World!</h3><b>Visits:</b> 1<br/>

Die Anzahl der Besuche wird jedes Mal erhöht, wenn Sie diesen Endpunkt erreichen. Sie können auch über Ihren Browser auf die Anwendung „Hello World“ zugreifen, indem Sie die öffentliche IP-Adresse Ihres Ubuntu-Servers aufrufen.

  • Wie für Ihre eigene Anwendung anpassen *

Der Schlüssel zum Einrichten Ihrer eigenen Anwendung besteht darin, Ihre Anwendung in einem eigenen Docker-Container abzulegen und jede Abhängigkeit in einem eigenen Container auszuführen. Anschließend können Sie die Beziehungen zwischen den Containern mit Docker Compose definieren, wie im Beispiel gezeigt. Docker Compose wird in diesem Docker Compose article ausführlicher behandelt.

In diesem Artikel erfahren Sie, wie Sie eine Anwendung in mehreren Containern ausführen können -on-ubuntu-14-04 [WordPress und phpMyAdmin mit Docker Compose].

Schritt 6 - Erstellen Sie das Testskript

Jetzt erstellen wir ein Testskript für Ihre Python-Anwendung. Dies ist ein einfaches Skript, das die HTTP-Ausgabe der Anwendung überprüft. Das Skript ist ein Beispiel für den Testtyp, den Sie möglicherweise als Teil Ihres Bereitstellungsprozesses für die kontinuierliche Integration ausführen möchten.

Bearbeiten Sie eine neue Datei:

nano test.sh

Fügen Sie den folgenden Inhalt hinzu:

test.sh

sleep 5
if curl web | grep -q '<b>Visits:</b> '; then
 echo "Tests passed!"
 exit 0
else
 echo "Tests failed!"
 exit 1
fi

+ test.sh + testet die grundlegende Web-Konnektivität unserer "Hello World" -Anwendung. Es verwendet cURL, um die Anzahl der Besuche abzurufen und darüber zu berichten, ob der Test bestanden wurde oder nicht.

Schritt 7 - Erstellen Sie die Testumgebung

Um unsere Anwendung zu testen, müssen wir eine Testumgebung bereitstellen. Und wir möchten sicherstellen, dass es mit der Live-Anwendungsumgebung identisch ist, die wir in * Schritt 5 * erstellt haben.

Zuerst müssen wir unser Testskript andocken, indem wir eine neue Dockerfile-Datei erstellen. Bearbeiten Sie eine neue Datei:

nano Dockerfile.test

Fügen Sie den folgenden Inhalt hinzu:

Dockerfile.test

FROM ubuntu:trusty

RUN apt-get update && apt-get install -yq curl && apt-get clean

WORKDIR /app

ADD test.sh /app/test.sh

CMD ["bash", "test.sh"]

+ Dockerfile.test + erweitert das offizielle + ubuntu: trusty + Image, um die Abhängigkeit von + curl + zu installieren, fügt + tests.sh + zum Image-Dateisystem hinzu und gibt den Befehl + CMD + an, der das Testskript ausführt mit Bash.

Sobald unsere Tests Dockerized sind, können sie auf reproduzierbare und agnostische Weise ausgeführt werden.

Der nächste Schritt ist die Verknüpfung unseres Testcontainers mit unserer Anwendung „Hello World“. Hier kommt Docker Compose wieder zur Hilfe. Bearbeiten Sie eine neue Datei:

nano docker-compose.test.yml

Fügen Sie den folgenden Inhalt hinzu:

docker-compose.test.yml

sut:
 build: .
 dockerfile: Dockerfile.test
 links:
   - web
web:
 build: .
 dockerfile: Dockerfile
 links:
   - redis
redis:
 image: redis

In der zweiten Hälfte der Docker Compose-Datei werden die Hauptanwendung "+ web " und ihre Abhängigkeit " redis " auf die gleiche Weise wie in der vorherigen Datei " docker-compose.yml " bereitgestellt. Dies ist der Teil der Datei, der die Container " web " und " redis " angibt. Der einzige Unterschied besteht darin, dass der Container " web +" den Port 80 nicht mehr freigibt, sodass die Anwendung während der Tests nicht über das öffentliche Internet verfügbar ist. Sie sehen also, dass wir die Anwendung und ihre Abhängigkeiten genauso erstellen wie in der Live-Bereitstellung.

Die Datei + docker-compose.test.yml + definiert auch einen Container + sut + (benannt nach system under tests), der für die Ausführung unserer Integrationstests verantwortlich ist. Der Container "+ sut " gibt das aktuelle Verzeichnis als unser " build " - Verzeichnis an und gibt unsere " Dockerfile.test " - Datei an. Es ist mit dem Container " web " verknüpft, sodass die IP-Adresse des Anwendungscontainers für unser Skript " test.sh +" zugänglich ist.

  • Wie für Ihre eigene Anwendung anpassen *

Beachten Sie, dass "+ docker-compose.test.yml +" möglicherweise Dutzende externer Services und mehrere Testcontainer enthält. Docker kann alle diese Abhängigkeiten auf einem einzelnen Host ausführen, da jeder Container das zugrunde liegende Betriebssystem gemeinsam nutzt.

Wenn Sie mehr Tests für Ihre Anwendung ausführen möchten, können Sie zusätzliche Dockerdateien für diese erstellen, ähnlich wie in der oben gezeigten Datei + Dockerfile.test +.

Anschließend können Sie zusätzliche Container unter dem Container "+ sut " in der Datei " docker-compose.test.yml +" hinzufügen, wobei auf die zusätzlichen Dockerdateien verwiesen wird.

Schritt 8 - Testen Sie die Anwendung „Hello World“

Wenn wir die Docker-Ideen von lokalen Umgebungen auf Testumgebungen ausweiten, können wir unsere Anwendung mithilfe von Docker automatisiert testen, indem wir Folgendes ausführen:

docker-compose -f ~/hello_world/docker-compose.test.yml -p ci build

Dieser Befehl erstellt die lokalen Images, die von + docker-compose.test.yml + benötigt werden. Beachten Sie, dass wir "+ -f " verwenden, um auf " docker-compose.test.yml " zu verweisen, und " -p +", um einen bestimmten Projektnamen anzugeben.

Starten Sie jetzt Ihre neue Testumgebung, indem Sie Folgendes ausführen:

docker-compose -f ~/hello_world/docker-compose.test.yml -p ci up -d

Überprüfen Sie die Ausgabe des Containers + sut +, indem Sie Folgendes ausführen:

docker logs -f ci_sut_1

Ausgabe

 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                Dload  Upload   Total   Spent    Left  Speed
100    42  100    42    0     0   3902      0 --:--:-- --:--:-- --:--:--  4200
Tests passed!

Überprüfen Sie abschließend den Exit-Code des Containers "+ sut +", um zu überprüfen, ob Ihre Tests bestanden wurden:

docker wait ci_sut_1

Ausgabe

0

Nach der Ausführung dieses Befehls ist der Wert von "+ $? " " 0 +", wenn die Tests bestanden wurden. Ansonsten sind unsere Anwendungstests fehlgeschlagen.

Beachten Sie, dass andere CI-Tools unser Code-Repository klonen und diese wenigen Befehle ausführen können, um zu überprüfen, ob die Tests mit den neuesten Bits Ihrer Anwendung bestanden werden, ohne sich um Laufzeitabhängigkeiten oder externe Dienstkonfigurationen zu sorgen.

Das ist es! Wir haben unseren Test erfolgreich in einer frisch gebauten Umgebung durchgeführt, die mit unserer Produktionsumgebung identisch ist.

Fazit

Dank Docker und Docker Compose konnten wir automatisieren, wie eine Anwendung erstellt wird (+ Dockerfile +), wie eine lokale Umgebung bereitgestellt wird (+ docker-compose.yml +), wie ein Test-Image erstellt wird () + Dockerfile.test + `) und wie man (Integrations-) Tests ( + docker-compose.test.yml + `) für jede Anwendung ausführt.

Die Verwendung der Datei + docker-compose.test.yml + zum Testen hat insbesondere folgende Vorteile:

  • * Automatisch *: Die Art und Weise, wie ein Tool die Datei "+ docker-compose.test.yml +" ausführt, ist unabhängig von der zu testenden Anwendung

  • * Geringes Gewicht *: Hunderte von externen Diensten können bereitgestellt werden ein einzelner Host, der komplexe (Integrations-) Testumgebungen simuliert

  • * Agnostisch *: Vermeiden Sie die Sperre von CI-Anbietern, und Ihre Tests können in jedem ausgeführt werden Infrastruktur und auf jedem Betriebssystem, das Docker unterstützt

  • * Unveränderlich *: Tests, die auf Ihrem lokalen Computer bestanden werden, werden in Ihrem CI-Tool bestanden

Dieses Tutorial zeigt ein Beispiel für das Testen einer einfachen „Hello World“ -Anwendung.

Jetzt ist es an der Zeit, Ihre eigenen Anwendungsdateien zu verwenden, Ihre eigenen Anwendungstestskripte zu docken und Ihre eigene docker-compose.test.yml zu erstellen, um Ihre Anwendung in einer frischen und unveränderlichen Umgebung zu testen.