Testserver für das Entwicklungsteam

Hallo Habr! In diesem Artikel möchte ich die Erfahrungen mit der Bereitstellung eines Testservers für das Entwicklungsteam teilen. Kurz die Essenz des Problems - es gibt ein Entwicklungsteam und mehrere Projekte in PHP. Während es nur wenige von uns gab und das Projekt im Wesentlichen eines war, verwendeten wir 1 Testserver. Um dem Kunden die Aufgabe zu zeigen, „spaltete“ der Entwickler den Server für eine bestimmte Zeit. Wenn es nicht rechtzeitig „Fenster“ gab, mussten wir warten. Im Laufe der Zeit nahmen das Team und die Komplexität der Aufgaben zu, die Überprüfungszeit und die Geschäftigkeit des Testservers nahmen zu, was sich negativ auf die Vorlaufzeit und den Bonus auswirkte. Deshalb musste ich nach einer Lösung suchen und sie ist unter dem Schnitt.

Einführung


Was war:

  1. Ein Testserver
  2. Gitlab und Redmine auf einem anderen Server
  3. Wunsch, ein Problem zu lösen

Alle Server befinden sich in unserem lokalen Netzwerk, der Testserver ist von außen nicht zugänglich.

Was war erforderlich:

  1. Möglichkeit, mehrere Projekte / Zweige gleichzeitig zu testen
  2. Der Entwickler kann zum Server gehen, ihn einrichten und nichts von anderen trennen
  3. Alles sollte so bequem wie möglich sein und auf einer Taste erledigt werden, vorzugsweise von Gitlab (CI / CD).

Entscheidungsmöglichkeiten


1. Ein Server, viele Hosts


Die einfachste Option. Wir verwenden denselben Testserver. Nur der Entwickler muss für jeden Zweig / jedes Projekt einen Host erstellen und ihn der Konfiguration von nginx / apache2 hinzufügen.

Vorteile:

  1. Schnell und jeder versteht
  2. Kann automatisieren

Nachteile:

  1. Klausel 2 der Anforderungen ist nicht erfüllt - der Entwickler kann mit der Aktualisierung der Datenbank beginnen und unter bestimmten Umständen alles eingeben (Hi Andrey!)
  2. Ziemlich komplexe Automatisierung mit einer Reihe von Konfigurationsdateien

2. An jeden Entwickler auf dem Server!


Ordnen Sie jedem Server zu, und der Entwickler ist für seine Wirtschaftlichkeit verantwortlich.

Vorteile:

  1. Der Entwickler kann den Server vollständig an Ihr Projekt anpassen

Nachteile:

  1. Ziffer 2 der Anforderungen ist nicht erfüllt
  2. Teuer und Ressourcen können einfach untätig bleiben, während die Entwicklung läuft, und nicht testen
  3. Die Automatisierung ist aufgrund unterschiedlicher Server noch komplizierter als in Punkt 1

3. Containerisierung - Docker, Kubernetes


Diese Technologie dringt zunehmend in unser Leben ein. Zu Hause benutze ich Docker schon lange für meine Projekte.
Docker ist eine Software zur Automatisierung der Bereitstellung und Verwaltung von Anwendungen in einer Virtualisierungsumgebung auf Betriebssystemebene. Ermöglicht das "Packen" der Anwendung mit all ihren Umgebungen und Abhängigkeiten in einen Container, der auf jedes Linux-System mit Unterstützung von cgroups im Kernel portiert werden kann, und bietet außerdem eine Containerverwaltungsumgebung.
Vorteile:

  1. Ein Server wird verwendet
  2. Alle Anforderungen sind erfüllt.

Nachteile:

  1. Bilder und Behälter nehmen manchmal viel Platz ein. Sie müssen die bereits veralteten Kronen reinigen, um Platz freizugeben.

Docker-Implementierung


Bei der Verwendung von gitlab, AutoDevOps, fielen mir sehr oft die Einstellungen von kubernetes auf. Außerdem erzählen bärtige Männer in verschiedenen Meetups, wie cool sie mit Kubernetes arbeiten. Aus diesem Grund wurde beschlossen, den Cluster in seinen Einrichtungen bereitzustellen. Der Server wurde angefordert (und Sie können den Test nicht berühren, die Leute testen dort), und er wurde gestartet.

Da ich Erfahrung mit kubernetes 0 habe, wurde alles gemäß dem Handbuch durchgeführt, um zu verstehen, wie all diese Cluster funktionieren. Nach einiger Zeit gelang es mir, den Cluster zu erhöhen, aber dann gab es Probleme mit Zertifikaten, Schlüsseln und tatsächlich mit der Schwierigkeit der Bereitstellung. Ich brauchte eine einfachere Lösung, um meinen Kollegen den Umgang damit beizubringen (zum Beispiel möchte ich nicht denselben Urlaub auf Skype verbringen und bei der Einrichtung helfen). Deshalb wurde kubernetes allein gelassen. Docker selbst blieb und es war notwendig, eine Lösung für das Container-Routing zu finden. Da sie an verschiedenen Ports abgeholt werden könnten, könnte derselbe Nginx für die interne Umleitung verwendet werden. Dies wird als Reverse-Proxy-Server bezeichnet.
Ein Reverse-Proxy-Server ist eine Art Proxy-Server, der Client-Anforderungen von einem externen Netzwerk an einen oder mehrere Server weiterleitet, die sich logisch im internen Netzwerk befinden. Gleichzeitig sieht es für den Client so aus, als ob sich die angeforderten Ressourcen direkt auf dem Proxyserver befinden.

Reverse Proxy


Um das Rad nicht neu zu erfinden, suchte ich nach vorgefertigten Lösungen. Und es wurde gefunden - das ist Traefik .

Træfik ist ein moderner HTTP-Reverse-Proxy und Load Balancer, der die Bereitstellung von Microservices vereinfacht. Træfik lässt sich in vorhandene Infrastrukturkomponenten (Docker, Schwarmmodus, Kubernetes, Marathon, Konsul, usw., Rancher, Amazon ECS usw.) integrieren und wird automatisch und dynamisch konfiguriert. Um mit Docker arbeiten zu können, müssen Sie nur den Socket angeben und fertig. Dann findet Træfik selbst alle Container und leitet sie weiter (weitere Informationen finden Sie unter „Packen von Anwendungen in Docker“).

Træfik Containerkonfiguration
Ich starte es über docker-compose.yml

version: '3' services: traefik: image: traefik:latest # The official Traefik docker image command: --api --docker # Enables the web UI and tells Træfik to listen to docker ports: - 443:443 - 80:80 # The HTTP port - 8080:8080 # The Web UI (enabled by --api) volumes: - /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events - /opt/traefik/traefik.toml:/traefik.toml - /opt/traefik/certs/:/certs/ networks: - proxy container_name: traefik restart: always networks: proxy: external: true 


Hier informieren wir den Proxy, dass wir die Ports 80, 443 und 8080 (das Webface des Proxys) abhören, den Docker-Socket, die Konfigurationsdatei und den Zertifikatordner bereitstellen müssen. Um die Benennung von Testseiten zu vereinfachen, haben wir beschlossen, eine lokale Domänenzone * .test zu erstellen. Wenn der Benutzer auf eine Site darauf zugreift, gelangt er zu unserem Testserver. Daher sind die Zertifikate im Ordner "traefik" selbstsigniert, unterstützen jedoch "Let's Encrypt".

Zertifikatserstellung

 openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout domain.key -out domain.crt 

Bevor Sie beginnen, müssen Sie im Docker ein Proxy-Netzwerk erstellen (Sie können es selbst benennen).

 docker network create proxy 

Dies wird das Netzwerk für die Verbindung von Traefik mit Containern von PHP-Sites sein. Daher geben wir es im Netzwerkparameter des Dienstes und in den Netzwerken der gesamten Datei an, indem wir im Parameter external: true angeben.

Traefik.toml-Datei
 debug = false logLevel = "DEBUG" defaultEntryPoints = ["https","http"] #  insecureSkipVerify = true #   [entryPoints] [entryPoints.http] address = ":80" [entryPoints.https] address = ":443" [entryPoints.https.tls] [docker] endpoint = "unix:///var/run/docker.sock" domain = "docker.localhost" watch = true exposedbydefault = false 


Hier ist alles ganz einfach - wir geben die Einstiegspunkte für den http- und https-Verkehr an. Vergessen Sie nicht, unsicher zu setzen. SkipVerify = true, wenn die Zertifikate lokal sind. Im Abschnitt entryPoints.https.tls können Sie keine Zertifikate angeben. Anschließend ersetzt traefik das Zertifikat.

Sie können den Dienst starten

 docker-compose up -d 

Wenn Sie zu site.test gehen, wird ein 404-Fehler angezeigt , da diese Domain an keinen Container gebunden ist.

Wir packen Anwendungen in Docker


Jetzt müssen Sie den Container mit der Anwendung konfigurieren, nämlich:

1. Geben Sie ein Proxy-Netzwerk in den Netzwerken an
2. Fügen Sie Etiketten mit Traefik-Konfiguration hinzu

Unten finden Sie die Konfiguration einer der Anwendungen

docker-compose.yml-Anwendungen
 version: '3' services: app: build: data/docker/php #   restart: always working_dir: /var/www/html/public volumes: - ./:/var/www/html #    - /home/develop/site-files/f:/var/www/html/public/f #       links: - mailcatcher - memcached - mysql labels: - traefik.enabled=true - traefik.frontend.rule=Host:TEST_DOMAIN,crm.TEST_DOMAIN,bonus.TEST_DOMAIN - traefik.docker.network=proxy - traefik.port=443 - traefik.protocol=https networks: - proxy - default mailcatcher: image: schickling/mailcatcher:latest restart: always memcached: image: memcached restart: always mysql: image: mysql:5.7 restart: always command: --max_allowed_packet=902505856 --sql-mode="" environment: MYSQL_ROOT_PASSWORD: 12345 MYSQL_DATABASE: site volumes: - ./data/cache/mysql-db:/var/lib/mysql #      phpmyadmin: image: phpmyadmin/phpmyadmin restart: always links: - mysql environment: MYSQL_USERNAME: root MYSQL_ROOT_PASSWORD: 12345 PMA_ARBITRARY: 1 PMA_HOST: mysql_1 labels: - traefik.enabled=true - traefik.frontend.rule=Host:pma.TEST_DOMAIN - traefik.docker.network=proxy - traefik.port=80 - traefik.default.protocol=http networks: - proxy - default networks: proxy: external: true 


Im App-Dienst müssen Sie im Netzwerkbereich Proxy und Standard angeben. Dies bedeutet, dass es in zwei Netzwerken verfügbar ist. Wie aus der Konfiguration hervorgeht, leite ich keine Ports nach außen weiter, alles geht im Netzwerk.

Konfigurieren Sie als Nächstes die Beschriftungen

  - traefik.enabled=true # traefik    - traefik.frontend.rule=Host:TEST_DOMAIN,crm.TEST_DOMAIN,bonus.TEST_DOMAIN #    traefik     - traefik.docker.network=proxy #   - traefik.port=443 #,     ssl   80   http - traefik.protocol=https #  #  phpmyadmin   http  

Geben Sie im Abschnitt Allgemeine Netzwerke external: true an

Die Konstante TEST_DOMAIN muss durch eine Domäne ersetzt werden, z. B. site.test

Starten Sie die Anwendung

 docker-compose up -d 

Wenn Sie nun zu den Domains site.test, crm.site.test, Bonus.site.test gehen, können Sie die Arbeitswebsite sehen. Und auf der Domain pma.site.test gibt es phpmyadmin für die bequeme Arbeit mit der Datenbank.

Konfigurieren Sie GitLab


Wir erstellen einen Task-Handler, für den wir ausführen

 gitlab-runner register 

Wir geben die gitlab-URL, das Token und die Ausführung der Aufgabe an (Executoren). Da sich mein Test und mein Gitlab auf verschiedenen Servern befinden, wähle ich ssh executor aus. Sie müssen die Serveradresse und das Login / Passwort für die Verbindung über ssh angeben.

Runner kann an ein oder mehrere Projekte angehängt werden. Da meine Arbeitslogik überall gleich ist, wurde ein gemeinsamer Läufer erstellt (für alle Projekte gleich).
Der letzte Schliff ist das Erstellen einer CI-Konfigurationsdatei

.gitlab-ci.yml
 stages: - build - clear #  develop build_develop: stage: build #   build tags: #     - ssh-develop environment: # ,       -   name: review/$CI_BUILD_REF_NAME #  url: https://site$CI_PIPELINE_ID.test #url     on_stop: clear when: manual script: - cd ../ && cp -r $CI_PROJECT_NAME $CI_PIPELINE_ID && cd $CI_PIPELINE_ID #     - cp -r /home/develop/site-files/.ssh data/docker/php/.ssh #  ssh - sed -i -e "s/TEST_DOMAIN/site$CI_PIPELINE_ID.test/g" docker-compose.yml #   - docker-compose down #   - docker-compose up -d --build #  - script -q -c "docker exec -it ${CI_PIPELINE_ID}_app_1 bash -c \"cd ../ && php composer.phar install --prefer-dist \"" #   - script -q -c "docker exec -it ${CI_PIPELINE_ID}_app_1 bash -c \"cd ../ && php composer.phar first-install $CI_PIPELINE_ID\"" #     #  production build_prod: stage: build tags: - ssh-develop environment: name: review/$CI_BUILD_REF_NAME url: https://site$CI_PIPELINE_ID.test on_stop: clear when: manual script: - cd ../ && cp -r $CI_PROJECT_NAME $CI_PIPELINE_ID && cd $CI_PIPELINE_ID - cp -r /home/develop/site-files/.ssh data/docker/php/.ssh #  ssh - docker-compose down - docker-compose up -d --build - script -q -c "docker exec -it ${CI_PIPELINE_ID}_app_1 bash -c \"cd ../ && php composer.phar install --prefer-dist --no-dev\"" - script -q -c "docker exec -it ${CI_PIPELINE_ID}_app_1 bash -c \"cd ../ && php composer.phar first-install $CI_PIPELINE_ID\"" clear: stage: clear tags: - ssh-develop environment: name: review/$CI_BUILD_REF_NAME action: stop script: - cd ../ && cd $CI_PIPELINE_ID && docker-compose down && cd ../ && echo password | sudo -S rm -rf $CI_PIPELINE_ID #       when: manual 


In dieser Konfiguration werden 2 Stufen beschrieben - Erstellen und Löschen. Die Erstellungsphase hat zwei Optionen - build_develop und build_prod



Gitlab erstellt ein verständliches Prozessablaufdiagramm. In meinem Beispiel werden alle Prozesse manuell gestartet (wenn: manueller Parameter). Dies geschieht, damit der Entwickler nach der Bereitstellung der Testwebsite seine Änderungen in den Container ziehen kann, ohne den gesamten Container neu zu erstellen. Ein weiterer Grund ist der Domänenname - Site $ CI_PIPELINE_ID.test, wobei CI_PIPELINE_ID die Nummer des Prozesses ist, der die Assembly gestartet hat. Das heißt, sie haben die Site mit der Domain site123.test zur Überprüfung eingereicht, und um heiße Änderungen vorzunehmen, schüttet der Entwickler die Änderungen sofort in den Container.

Eine kleine Funktion von ssh executor. Bei Verbindung mit dem Server wird ein Ordner des Formulars erstellt.

 /home//builds/_runner/0/_/_ 

Daher wurde eine Zeile hinzugefügt

 cd ../ && cp -r $CI_PROJECT_NAME $CI_PIPELINE_ID && cd $CI_PIPELINE_ID 

Darin gehen wir zum obigen Ordner und kopieren das Projekt in den Ordner mit der Prozessnummer. Sie können also mehrere Zweige eines Projekts bereitstellen. In den Einstellungen des Handlers müssen Sie jedoch die Option Für aktuelle Projekte sperren aktivieren, damit der Handler nicht versucht, mehrere Zweige gleichzeitig zu erweitern.

Die Löschphase stoppt die Container und löscht den Ordner. Möglicherweise benötigen Sie Root-Rechte. Daher verwenden wir das Echo-Passwort | sudo -S rm wobei Passwort Ihr Passwort ist.

Müllabfuhr


Von Zeit zu Zeit müssen Sie nicht verwendete Container entfernen, um keinen Platz zu beanspruchen. Dazu hängt ein Skript mit solchen Inhalten in der Krone

 #!/bin/bash #   : docker ps --filter status=dead --filter status=exited -aq | xargs -r docker rm -v #   : yes | docker container prune #    : yes | docker image prune #    : yes | docker volume prune 

einmal am Tag durchgeführt.

Fazit


Diese Lösung hat uns geholfen, das Testen und Freigeben neuer Funktionen erheblich zu optimieren. Konstruktionskritisch wird akzeptiert, um Fragen zu beantworten.

Bonus


Um nicht jedes Mal Bilder aus der Docker-Datei zu erfassen, können Sie diese in der lokalen Docker-Registrierung speichern.

Datei docker-compose.yml
 registry: restart: always image: registry:2 ports: - 5000:5000 volumes: - /opt/docker-registry/data:/var/lib/registry #     


Diese Option verwendet keine Authentifizierung. Dies ist kein sicherer Weg (!!!), eignet sich jedoch zum Speichern nicht kritischer Bilder.

Sie können gitlab für die Anzeige konfigurieren

  gitlab_rails['registry_enabled'] = true gitlab_rails['registry_host'] = "registry.test" gitlab_rails['registry_port'] = "5000" 

Danach erscheint eine Liste von Bildern in gitlab

Source: https://habr.com/ru/post/de426319/


All Articles