Erstellung einer CI/CD-Pipeline und Automatisierung von Arbeiten mit Docker

Ich habe meine ersten Webseiten Ende der 90er Jahre erstellt. Damals war es sehr einfach, sie in einen funktionsfähigen Zustand zu versetzen. Es gab einen Apache-Server auf einem beliebigen Shared Hosting, auf diesen Server konnte man per FTP zugreifen, indem man in die Adresszeile des Browsers etwas wie ftp://ftp.example.comeingab. Dann musste man den Benutzernamen und das Passwort eingeben und die Dateien auf den Server hochladen. Es waren andere Zeiten, damals war alles einfacher als heute.

Erstellung einer CI/CD-Pipeline und Automatisierung von Arbeiten mit Docker

In den zwei Jahrzehnten, die seitdem vergangen sind, hat sich jedoch viel verändert. Die Webseiten sind komplexer geworden, sie müssen vor der Veröffentlichung in die Produktion zusammengebaut werden. Ein einziger Server ist zu vielen Servern geworden, die hinter Lastenausgleichern arbeiten, und die Verwendung von Versionskontrollsystemen ist zur Norm geworden.

Für mein persönliches Projekt hatte ich eine spezielle Konfiguration. Und ich wusste, dass ich die Möglichkeit brauchte, die Website in der Produktion zu betreiben, indem ich nur eine Aktion ausführe: den Code in den Branch master auf GitHub zu schreiben. Zudem wusste ich, dass ich mich um die Verwaltung eines riesigen Kubernetes-Clusters oder die Nutzung der Docker Swarm-Technologie oder die Betreuung eines Serverparks mit Pods, Agenten und anderen Komplexitäten nicht kümmern wollte, um mein kleines Webanwendungsprojekt am Laufen zu halten. Um mein Ziel, die Arbeit maximal zu vereinfachen, zu erreichen, musste ich mich mit CI/CD vertraut machen.

Wenn Sie ein kleines Projekt haben (in unserem Fall handelt es sich um ein Node.js-Projekt) und wissen möchten, wie Sie die Bereitstellung dieses Projekts automatisieren können, sodass das, was im Repository gespeichert ist, genau dem entspricht, was in der Produktion läuft, dann könnte Sie dieser Artikel interessieren.

Voraussetzungen

Es wird erwartet, dass der Leser dieses Artikels grundlegende Kenntnisse im Umgang mit der Kommandozeile und im Schreiben von Bash-Skripten hat. Darüber hinaus benötigt er Konten Travis CI und Docker Hub.

Ziele

Ich würde nicht sagen, dass dieser Artikel uneingeschränkt als "Leitfaden" bezeichnet werden kann. Es ist eher ein Dokument, in dem ich teile, was ich gelernt habe, und den Prozess beschreibe, der mir beim Testen und Bereitstellen von Code in der Produktion gefällt, und zwar über einen einzigen automatisierten Durchlauf.

So sieht letztendlich mein Arbeitsprozess aus.

Für Code, der in einen beliebigen Branch des Repositories geschickt wird, außer master, werden folgende Schritte durchgeführt:

  • Ein Build des Projekts wird auf Travis CI gestartet.
  • Es werden alle Unit-, Integrations- und End-to-End-Tests durchgeführt.

Nur für den Code, der in master, erfolgt Folgendes:

  • Alles, was oben gesagt wurde, plus...
  • Erstellung eines Docker-Images basierend auf dem aktuellen Code, den Einstellungen und der Umgebung.
  • Bereitstellung des Images auf Docker Hub.
  • Verbindung zum Produktionsserver.
  • Herunterladen des Images von Docker Hub auf den Server.
  • Anhalten des aktuellen Containers und Start eines neuen, basierend auf dem neuen Image.

Wenn Sie absolut nichts über Docker, über Images und Container wissen – keine Sorge. Ich werde Ihnen alles darüber erzählen.

Was ist CI/CD?

Die Abkürzung CI/CD steht für „Continuous Integration/Continuous Deployment“ – „kontinuierliche Integration/kontinuierliches Deployment“.

▍Kontinuierliche Integration

Kontinuierliche Integration ist der Prozess, bei dem Entwickler Commits ins Hauptrepository des Projekts (gewöhnlich in den Branch master). Dabei wird die Qualität des Codes durch automatisierte Tests sichergestellt.

▍Kontinuierliches Deployment

Kontinuierliches Deployment ist die häufige automatisierte Bereitstellung von Code in der Produktion. Der zweite Teil der Abkürzung CI/CD wird manchmal als „Continuous Delivery“ („kontinuierliche Lieferung“) erklärt. Das ist im Grunde dasselbe wie „kontinuierliches Deployment“, jedoch impliziert „kontinuierliche Lieferung“ die Notwendigkeit einer manuellen Bestätigung von Änderungen vor dem Start des Deployment-Prozesses des Projekts.

Erste Schritte

Die Anwendung, mit der ich das alles gelernt habe, heißt TakeNote. Es handelt sich um ein Webprojekt, an dem ich arbeite, das dazu dient, Notizen zu machen. Zuerst versuchte ich, ein JAMStack-Projekt oder nur eine Frontend-Anwendung ohne Server zu erstellen, um die standardmäßigen Hosting- und Deploymentmöglichkeiten zu nutzen, die Netlifyanbietet. Im Laufe des Wachstums der Komplexität der Anwendung musste ich auch einen Server-Teil erstellen, was bedeutete, dass ich eine eigene Strategie für die automatisierte Integration und das automatisierte Deployment des Projekts entwickeln musste.

In meinem Fall stellt die Anwendung einen Express-Server dar, der in der Node.js-Umgebung läuft, eine Single-Page-React-Anwendung bedient und eine gesicherte serverseitige API unterstützt. Diese Architektur folgt einer Strategie, die in diesem Leitfaden für Full-Stack-Authentifizierung zu finden ist.

Ich habe mich mit einem Freund beraten, der Experte für Automatisierung ist, und fragte ihn, was ich tun muss, damit all das so funktioniert, wie ich es brauche. Er gab mir die Idee, wie der automatisierte Arbeitsablauf aussehen sollte, der im Abschnitt „Ziele“ dieses Artikels dargelegt ist. Dass ich mir solche Ziele gesetzt habe, bedeutete, dass ich verstehen musste, wie man Docker benutzt.

Docker

Docker ist ein Tool, das durch Containerisierungstechnologie das einfache Verbreiten von Anwendungen sowie deren Bereitstellung und Ausführung in derselben Umgebung ermöglicht, selbst wenn die Docker-Plattform in verschiedenen Umgebungen läuft. Zuerst musste ich die Docker-Befehlszeilenwerkzeuge (CLI) zur Verfügung haben. Die Anleitung zur Installation von Docker kann nicht als sehr klar und verständlich bezeichnet werden, aber man kann erfahren, dass man, um den ersten Schritt zur Installation zu machen, Docker Desktop (für Mac oder Windows) herunterladen muss.

Docker Hub ist etwa das gleiche wie GitHub für Git-Repositories oder ein Registry npm für JavaScript-Pakete. Es ist ein Online-Repository für Docker-Images. Es ist die Verbindung, mit der Docker Desktop arbeitet.

Um mit Docker zu arbeiten, müssen also zwei Dinge erledigt werden:

Danach können Sie die Funktionsfähigkeit der Docker CLI überprüfen, indem Sie den folgenden Befehl zur Versionsüberprüfung von Docker eingeben:

docker -v

Geben Sie dann bei der Aufforderung Ihren Benutzernamen und Ihr Passwort für Docker Hub ein:

docker login

Um Docker zu verwenden, müssen Sie die Konzepte von Images und Containern verstehen.

▍Images

Ein Image ist eine Art Plan, der Anweisungen zum Erstellen eines Containers enthält. Es ist ein unveränderlicher Schnappschuss des Dateisystems und der Anwendungseinstellungen. Entwickler können Images einfach austauschen.

# Вывод сведений обо всех образах
docker images

Dieser Befehl gibt eine Tabelle mit der folgenden Überschrift aus:

REPOSITORY     TAG     IMAGE ID     CREATED     SIZE
---

Anschließend werden wir einige Beispiele für Befehle im gleichen Format betrachten – zuerst kommt der Befehl mit einem Kommentar und dann ein Beispiel dafür, was er ausgeben kann.

▍Container

Ein Container ist ein ausführbares Paket, das alles enthält, was zur Ausführung einer Anwendung erforderlich ist. Bei diesem Ansatz wird die Anwendung immer gleich funktionieren, unabhängig von der Infrastruktur: in einer isolierten Umgebung und in derselben Umgebung. Es geht darum, dass in unterschiedlichen Umgebungen Instanzen desselben Images ausgeführt werden.

# Перечисление всех контейнеров
docker ps -a
CONTAINER ID     IMAGE     COMMAND     CREATED     STATUS     PORTS     NAMES
---

▍Tags

Ein Tag ist ein Verweis auf eine bestimmte Version des Images.

▍Kurzübersicht über Docker-Befehle

Hier ist eine Übersicht über einige häufig verwendete Docker-Befehle.

Team

Kontext

Aktion

docker build

Image

Image aus Dockerfile erstellen

docker tag

Image

Image taggen

docker images

Image

Ausgabe der Liste der Images

docker run

Container

Container basierend auf einem Image starten

docker push

Image

Image ins Repository übertragen

docker pull

Image

Image aus dem Repository herunterladen

docker ps

Container

Ausgabe der Liste der Container

docker system prune

Image/Container

Unbenutzte Container und Images entfernen

▍Dockerfile

Ich weiß, wie man eine Anwendung lokal für die Produktion startet. Ich habe eine Webpack-Konfiguration, die zum Erstellen einer fertigen React-Anwendung gedacht ist. Außerdem habe ich einen Befehl, der einen auf Node.js basierenden Server auf Port 5000startet. So sieht das aus:

npm i         # Abhängigkeiten installieren
npm run build # React-Anwendung bauen
npm run start # Node-Server starten

Es ist anzumerken, dass ich keine Beispielanwendung für dieses Material habe. Aber hier eignet sich jede einfache Node-Anwendung für Experimente.

Um den Container zu nutzen, müssen Sie Docker Anweisungen geben. Dies geschieht über eine Datei, die nennt sich Dockerfile, die sich im Stammverzeichnis des Projekts befindet. Diese Datei scheint zunächst recht komplex.

Aber der Inhalt beschreibt lediglich, mit speziellen Befehlen, etwas Ähnliches wie die Konfiguration einer Arbeitsumgebung. Hier sind einige dieser Befehle:

  • FROM — Dieser Befehl beginnt die Datei. Er gibt das Basis-Image an, auf dem der Container aufgebaut wird.
  • COPY — Kopieren von Dateien aus einer lokalen Quelle in den Container.
  • WORKDIR — Festlegen des Arbeitsverzeichnisses für die folgenden Befehle.
  • RUN — Ausführen von Befehlen.
  • EXPOSE — Einrichten des Ports.
  • ENTRYPOINT — Angabe des auszuführenden Befehls.

Dockerfile kann folgendermaßen aussehen:

# Загрузить базовый образ
FROM node:12-alpine

# Скопировать файлы из текущей директории в директорию app/
COPY . app/

# Использовать app/ в роли рабочей директории
WORKDIR app/

# Установить зависимости (команда npm ci похожа npm i, но используется для автоматизированных сборок)
RUN npm ci --only-production

# Собрать клиентское React-приложение для продакшна
RUN npm run build

# Прослушивать указанный порт
EXPOSE 5000

# Запустить Node-сервер
ENTRYPOINT npm run start

Je nach dem gewählten Basis-Image müssen möglicherweise zusätzliche Abhängigkeiten installiert werden. Das liegt daran, dass einige Basis-Images (wie Node Alpine Linux) so konzipiert sind, dass sie so kompakt wie möglich sind. Infolgedessen können sie einige Programme fehlen, auf die Sie angewiesen sind.

▍Bauen, Taggen und Starten des Containers

Der lokale Aufbau und das Starten des Containers ist, nachdem wir haben, Dockerfile, ziemlich einfach. Bevor das Image auf Docker Hub hochgeladen wird, muss es lokal getestet werden.

▍Bauen

Zuerst muss gebaut werden, Image, indem der Name angegeben wird, und, was optional ist, ein Tag (wenn kein Tag angegeben wird, wird das System dem Image automatisch einen Tag zuweisen. latest).

# Сборка образа
docker build -t <image>:<tag> .

Nach Ausführung dieses Befehls kann man beobachten, wie Docker das Image baut.

Den Build-Kontext an das Docker-Daemon senden   2.88MB
Schritt 1/9 : VON node:12-alpine
 ---> ...Bauphasen werden ausgeführt...
Erfolgreich gebaut 123456789123
Erfolgreich getaggt :

Der Build kann einige Minuten dauern – das hängt davon ab, wie viele Abhängigkeiten Sie haben. Nach Abschluss des Builds kann man den Befehl ausführen, docker images und sich die Beschreibung seines neuen Images ansehen.

REPOSITORY          TAG               IMAGE ID            ERSTELLT              GRÖSSE
             latest            123456789123        Vor etwa einer Minute   x.xxGB

▍Start

Das Image wurde erstellt. Das bedeutet, dass nun ein Container basierend auf diesem Image gestartet werden kann. Da ich möchte, dass ich auf die Anwendung, die im Container läuft, unter der Adresse zugreifen kann, localhost:5000, habe ich auf der linken Seite des Paares 5000:5000 in dem folgenden Befehl festgelegt. Auf der rechten Seite befindet sich der Port des Containers. 5000.

# Запуск с использованием локального порта 5000 и порта контейнера 5000
docker run -p 5000:5000 <image>:<tag>

Jetzt, da der Container erstellt und gestartet wurde, kann man den Befehl verwenden, docker ps um die Informationen zu diesem Container anzusehen (oder man kann den Befehl docker ps -a, verwenden, der Informationen über alle Container anzeigt, nicht nur über die laufenden).

CONTAINER ID        IMAGE               BEFEHL                  CREATOR              STATUS                      PORTS                    NAMES
987654321234                     "\/bin\/sh -c 'npm run…"   Vor 6 Sekunden        Hoch 6 Sekunden                0.0.0.0:5000->5000\/tcp   stoic_darwin

Wenn Sie jetzt die Adresse aufrufen, localhost:5000 – können Sie die Seite der laufenden Anwendung sehen, die genauso aussieht wie die Seite der Anwendung, die in der Produktionsumgebung läuft.

▍Tag zuweisen und veröffentlichen

Um eines der erstellten Images auf dem Produktionsserver zu verwenden, müssen wir die Möglichkeit haben, dieses Image von Docker Hub herunterzuladen. Das bedeutet, dass wir zunächst ein Repository für das Projekt auf Docker Hub erstellen müssen. Danach steht uns ein Speicherplatz zur Verfügung, an den wir das Image senden können. Das Image muss so umbenannt werden, dass sein Name mit unserem Benutzernamen auf Docker Hub beginnt. Danach folgt der Name des Repositories. Am Ende des Namens kann ein beliebiges Tag stehen. Im Folgenden wird ein Beispiel für die Benennung von Images gemäß diesem Schema gezeigt.

Jetzt können wir das Image unter einem neuen Namen erstellen und den Befehl ausführen docker push um es in das Docker Hub-Repository zu senden.

docker build -t /: .
docker tag /: /:latest
docker push /:

# In der Praxis könnte das zum Beispiel so aussehen:
docker build -t user/app:v1.0.0 .
docker tag user/app:v1.0.0 user/app:latest
docker push user/app:v1.0.0

Wenn alles gut läuft, wird das Image auf Docker Hub verfügbar sein und kann einfach auf den Server geladen oder an andere Entwickler weitergegeben werden.

Nächste Schritte

Bis jetzt haben wir sichergestellt, dass die Anwendung als Docker-Container lokal funktioniert. Wir haben den Container auf Docker Hub hochgeladen. All das bedeutet, dass wir bereits recht gut auf unser Ziel hingearbeitet haben. Nun müssen wir noch zwei Fragen klären:

  • Einrichtung des CI-Tools zum Testen und Bereitstellen des Codes.
  • Einrichtung des Produktionsservers, damit er unseren Code herunterladen und ausführen kann.

In unserem Fall verwenden wir als CI/CD-Lösung Travis CI. Als Server — DigitalOcean.

Es ist erwähnenswert, dass hier auch eine andere Kombination von Diensten genutzt werden kann. Zum Beispiel kann anstelle von Travis CI auch CircleCI oder Github Actions verwendet werden. Und anstelle von DigitalOcean sind AWS oder Linode möglich.

Wir haben uns entschieden, mit Travis CI zu arbeiten, und in diesem Dienst ist bereits einiges für mich eingerichtet. Deshalb werde ich jetzt kurz erklären, wie man ihn für die Arbeit vorbereitet.

Travis CI

Travis CI ist ein Tool zum Testen und Bereitstellen von Code. Ich möchte nicht ins Detail gehen, wie man Travis CI einrichtet, da jedes Projekt einzigartig ist und dies nicht viel nützen würde. Aber ich werde die Grundlagen vorstellen, die Ihnen den Einstieg erleichtern, falls Sie sich entscheiden, Travis CI zu verwenden. Egal, ob Sie Travis CI, CircleCI, Jenkins oder etwas anderes wählen, die grundlegenden Methoden zur Einrichtung sind ähnlich.

Um mit Travis CI zu arbeiten, gehen Sie zu die Projektwebsite und erstellen Sie ein Konto. In der Folge integrieren Sie Travis CI mit Ihrem GitHub-Konto. Während der Systemkonfiguration müssen Sie das Repository angeben, das Sie automatisieren möchten, und den Zugriff darauf aktivieren. (Ich verwende GitHub, bin mir aber sicher, dass Travis CI auch mit BitBucket, GitLab und anderen ähnlichen Diensten integriert werden kann).

Jedes Mal, wenn Travis CI beginnt zu arbeiten, startet es einen Server, der die im Konfigurationsdatei angegebenen Befehle ausführt, einschließlich des Deployments der entsprechenden Branches des Repositories.

▍ Lebenszyklus eines Jobs

Die Konfigurationsdatei von Travis CI, die genannt wird .travis.yml und sich im Wurzelverzeichnis des Projekts befindet, unterstützt das Konzept von Ereignissen des Lebenszyklus des Jobs. Hier sind diese Ereignisse in der Reihenfolge, in der sie stattfinden:

  • apt addons
  • cache components
  • before_install
  • install
  • before_script
  • script
  • before_cache
  • after_success oder after_failure
  • before_deploy
  • deploy
  • after_deploy
  • after_script

▍ Testen

In der Konfigurationsdatei werde ich einen lokalen Server von Travis CI einrichten. Als Sprache habe ich Node Version 12 gewählt und der Software mitgeteilt, dass sie die für die Verwendung von Docker notwendigen Abhängigkeiten installieren soll.

Alles, was in .travis.yml, aufgeführt ist, wird bei der Ausführung aller Pull-Requests für alle Branches des Repositories ausgeführt, es sei denn, es wird etwas anderes angegeben. Dies ist eine nützliche Funktion, da sie bedeutet, dass wir den gesamten Code testen können, der in das Repository eingeht. So können wir feststellen, ob der Code bereit ist, in den Branch master, geschrieben zu werden, und ob er den Build-Prozess des Projekts nicht stört. In dieser globalen Konfiguration installiere ich alles lokal, starte den Webpack-Entwicklungsserver im Hintergrund (das ist Teil meines Workflows) und führe die Tests aus.

Wenn Sie möchten, dass in Ihrem Repository Badges mit Informationen zur Testabdeckung angezeigt werden, hier können Sie eine kurze Anleitung zur Verwendung von Jest, Travis CI und Coveralls finden, um diese Informationen zu sammeln und anzuzeigen.

Hier ist also der Inhalt der Datei .travis.yml:

# Установить язык
language: node_js

# Установить версию Node.js
node_js:
  - '12'

services:
  # Использовать командную строку Docker
  - docker

install:
  # Установить зависимости для тестов
  - npm ci

before_script:
  # Запустить сервер и клиент для тестов
  - npm run dev &

script:
  # Запустить тесты
  - npm run test

Hier enden die Aktionen, die für alle Branches des Repositories und für Pull-Requests ausgeführt werden.

▍ Deployment

Vorausgesetzt, dass alle automatisierten Tests erfolgreich abgeschlossen wurden, können wir, was nicht notwendig ist, den Code auf dem Produktionsserver bereitstellen. Da wir dies nur für den Code aus dem Branch möchten master, wir geben dem System entsprechende Anweisungen in den Bereitstellungseinstellungen. Bevor Sie versuchen, den Code, den wir im Folgenden besprechen werden, in Ihrem Projekt zu verwenden, möchte ich Sie darauf hinweisen, dass Sie ein echtes Skript haben sollten, das für die Bereitstellung aufgerufen wird.

deploy:
  # Docker-Container erstellen und an Docker Hub senden
  provider: script
  script: bash deploy.sh
  on:
    branch: master

Das Bereitstellungsskript erfüllt zwei Aufgaben:

  • Erstellung, Tagging und Senden des Images auf Docker Hub mit Hilfe von CI-Tools (in unserem Fall Travis CI).
  • Hochladen des Images auf den Server, Stoppen des alten Containers und Starten des neuen (in unserem Fall läuft der Server auf der Plattform DigitalOcean).

Zunächst muss der automatische Prozess zum Erstellen, Taggen und Senden des Images an Docker Hub eingerichtet werden. Das Ganze ähnelt sehr dem, was wir bereits manuell gemacht haben, mit der Ausnahme, dass wir hier eine Strategie zur Zuweisung einzigartiger Tags für die Images und zur Automatisierung der Anmeldung benötigen. Ich hatte Schwierigkeiten mit einigen Details des Bereitstellungsskripts, wie z.B. der Tagging-Strategie, der Anmeldung, der Kodierung der SSH-Schlüssel und der Einrichtung der SSH-Verbindung. Glücklicherweise kann mein Freund sehr gut mit bash umgehen, wie auch mit vielen anderen Dingen. Er hat mir geholfen, dieses Skript zu schreiben.

Also, der erste Teil des Skripts besteht darin, das Image zu Docker Hub zu senden. Das ist ziemlich einfach. Das von mir verwendete Tagging-Schema sieht vor, dass der Git-Hash und das Git-Tag, falls vorhanden, kombiniert werden. Dies sorgt dafür, dass ein einzigartiges Tag erstellt wird und erleichtert die Identifizierung des Builds, auf dem es basiert. DOCKER_USERNAME und DOCKER_PASSWORD — dies sind benutzerdefinierte Umgebungsvariablen, die über die Benutzeroberfläche von Travis CI festgelegt werden können. Travis CI behandelt geheime Daten automatisch so, dass sie nicht in die falschen Hände geraten.

Hier ist der erste Teil des Skripts deploy.sh.

#!/bin/sh
set -e # Остановить скрипт при наличии ошибок

IMAGE="<username>/<repository>"                             # Образ Docker
GIT_VERSION=$(git describe --always --abbrev --tags --long) # Git-хэш и теги

# Сборка и тегирование образа
docker build -t ${IMAGE}:${GIT_VERSION} .
docker tag ${IMAGE}:${GIT_VERSION} ${IMAGE}:latest

# Вход в Docker Hub и выгрузка образа
echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
docker push ${IMAGE}:${GIT_VERSION}

Wie der zweite Teil des Skripts aussehen wird, hängt vollständig davon ab, welchen Host Sie verwenden und wie die Verbindung zu ihm eingerichtet ist. In meinem Fall, da ich Digital Ocean nutze, werden die Befehle zum Verbinden mit dem Server verwendet doctl. Bei der Verwendung von AWS wird das Tool aws, und so weiter, verwendet.

Es war nicht besonders schwierig, die Serverarbeit einzurichten. So habe ich einen Droplet auf Basis eines Basis-Images eingerichtet. Ich sollte anmerken, dass das von mir gewählte System eine einmalige manuelle Installation von Docker und einen einmaligen manuellen Start von Docker erfordert. Ich habe für die Docker-Installation Ubuntu 18.04 verwendet, daher können Sie, wenn Sie ebenfalls Ubuntu benutzen, einfach folgen diesem einfachen Leitfaden.

Ich spreche hier nicht über spezifische Befehle für den Dienst, da dieser Aspekt in verschiedenen Fällen stark variieren kann. Ich werde nur einen allgemeinen Aktionsplan angeben, der nach der Verbindung per SSH mit dem Server, auf dem das Projekt bereitgestellt wird, durchgeführt wird:

  • Zuerst müssen Sie den Container finden, der derzeit läuft, und ihn stoppen.
  • Dann müssen Sie im Hintergrund einen neuen Container starten.
  • Sie müssen den lokalen Serverport auf den Wert einstellen 80 – das ermöglicht den Zugriff auf die Website unter einer Adresse wie example.com, ohne den Port anzugeben, anstatt eine Adresse wie example.com:5000.
  • Und schließlich müssen Sie alle alten Container und Images löschen.

Hier ist die Fortsetzung des Scripts.

# Найти ID работающего контейнера
CONTAINER_ID=$(docker ps | grep takenote | cut -d" " -f1)

# Остановить старый контейнер, запустить новый, очистить систему
docker stop ${CONTAINER_ID}
docker run --restart unless-stopped -d -p 80:5000 ${IMAGE}:${GIT_VERSION}
docker system prune -a -f

Einige Punkte, auf die man achten sollte

Möglicherweise sehen Sie, wenn Sie sich per SSH mit dem Server aus Travis CI verbinden, eine Warnung, die die Installation fortschreiten lässt, da das System auf eine Benutzereingabe wartet.

Die Echtheit des Hosts ' ()' kann nicht hergestellt werden.
Der RSA-Schlüsselfingerabdruck ist .
Möchten Sie die Verbindung fortsetzen (ja/nein)?

Ich habe erfahren, dass der Zeichenfolgeschlüssel in base64 kodiert werden kann, um ihn in einem Format zu speichern, mit dem man bequem und sicher arbeiten kann. Während der Installation kann der öffentliche Schlüssel dekodiert und in die Datei known_hosts geschrieben werden, um die oben beschriebene Fehlermeldung zu beseitigen.

echo  | base64 # gibt  aus

In der Praxis könnte dieser Befehl so aussehen:

echo "123.45.67.89 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
NrRFi9wrf+M7Q== you@example.com" | base64

Und so sieht die Ausgabe aus — eine Zeichenfolge in base64-Kodierung:

MTIzLjQ1LjY3Ljg5IHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQUJJd0FBQVFFQWtsT1Vwa0RIcmZIWTE3U2JybVRJcE5MVEdLOVRqb20vQldEU1UKR1BsK25hZnpsSERUWVc3aGRJNHlaNWV3MThKSDRKVzlqYmhVRnJ2aVF6TTd4bEVMRVZmNGg5bEZYNVFWa2JQcHBTd2cwY2RhMwpQYnY3a09kSi9NVHlCbFdYRkNSK0hBbzNGWFJpdEJxeGlYMW5LaFhwSEFac01jaUxxOFY2UmpzTkFRd2RzZE1GdlNsVksvN1hBCnQzRmFvSm9Bc25jTTFROXg1KzNWMFd3NjgvZUlGbWIxenVVRmxqUUpLcHJyWDg4WHlwTkR2allOYnk2dncvUGIwcndlcnQvRW4KbVorQVc0T1pQblRQSTg5WlBtVk1MdWF5ckQyY0U4NlovaWw4YitndzNyMysxbkthdG1Ja2puMnNvMWQwMVFyYVRsTXFWU3NieApOclJGaTl3cmYrTTdRPT0geW91QGV4YW1wbGUuY29tCg==

Hier ist das oben erwähnte Team

install:
  - echo  | base64 -d >> $HOME/.ssh/known_hosts

Der gleiche Ansatz kann auch mit dem privaten Schlüssel beim Herstellen einer Verbindung verwendet werden, da Sie möglicherweise einen privaten Schlüssel benötigen, um auf den Server zuzugreifen. Bei der Arbeit mit dem Schlüssel müssen Sie lediglich sicherstellen, dass er sicher in einer Umgebungsvariable von Travis CI gespeichert wird und nicht irgendwo ausgegeben wird.

Ein weiterer Punkt, den man beachten sollte, ist, dass es nötig sein kann, das gesamte Bereitstellungsskript in einer einzigen Zeile auszuführen, zum Beispiel mit Hilfe von doctl. Das kann einige zusätzliche Anstrengungen erfordern.

doctl compute ssh  --ssh-command "alle Befehle kommen hierher && hier"

TLS/SSL und Lastenverteilung

Nachdem ich alles erledigt hatte, was oben besprochen wurde, besteht mein letztes Problem darin, dass der Server kein SSL hatte. Da ich einen Node.js-Server benutze, um zu funktionieren Nginx und Let’s Encrypt Reverse Proxy zum Laufen zu bringen, ist ein gewisser Aufwand erforderlich.

Ich wollte diese SSL-Einstellungen nicht manuell vornehmen, also habe ich einfach einen Lastenausgleich erstellt und die Informationen dazu im DNS gespeichert. Bei DigitalOcean zum Beispiel ist das Erstellen eines automatisch aktualisierten selbstsignierten Zertifikats auf dem Lastenausgleich eine einfache, kostenlose und schnelle Angelegenheit. Dieser Ansatz hat den zusätzlichen Vorteil, dass er es ermöglicht, SSL sehr einfach auf vielen Servern zu konfigurieren, die hinter dem Lastenausgleich arbeiten. Das bedeutet, dass die Server selbst sich um SSL keine Gedanken machen müssen, aber weiterhin wie gewohnt den Port 80verwenden. Daher ist die Konfiguration von SSL auf dem Lastenausgleich viel einfacher und komfortabler als alternative Methoden zur SSL-Einrichtung.

Jetzt können Sie auf dem Server alle Ports, die eingehende Verbindungen annehmen, schließen, mit Ausnahme des Ports 80, der für die Kommunikation mit dem Lastenausgleich verwendet wird, und des Ports 22 für SSH. Infolgedessen wird der Versuch, direkt auf den Server über beliebige Ports, mit Ausnahme dieser beiden, scheitern.

Ergebnisse

Nachdem ich alles gemacht habe, was ich in diesem Material beschrieben habe, hatte ich keine Angst mehr vor der Docker-Plattform oder den Konzepten automatisierter CI/CD-Pipelines. Ich konnte eine kontinuierliche Integrationspipeline einrichten, in der der Code getestet wird, bevor er in die Produktion gelangt, und die automatische Bereitstellung des Codes auf dem Server erfolgt. Das alles ist für mich noch relativ neu, und ich bin sicher, dass es Möglichkeiten gibt, meinen automatisierten Arbeitsablauf zu verbessern und ihn effizienter zu gestalten. Also, wenn Sie Ideen dazu haben, lassen Sie es mich wissen. mir Ich hoffe, dieser Artikel hat Ihnen in Ihren Belangen geholfen. Ich möchte glauben, dass Sie beim Lesen genauso viel gelernt haben, wie ich, als ich alles durchging, was ich darin beschrieben habe.

P.S. wird es gewöhnliche Befehle enthalten. Marktplatz gibt es ein Image Docker, das mit einem Klick installiert wird. Sie können die Funktionalität der Container auf VPSüberprüfen. Allen neuen Kunden stehen 3 Tage zur kostenlosen Testung zur Verfügung.

Liebe Leser! Nutzen Sie CI/CD-Technologien in Ihren Projekten?

Erstellung einer CI/CD-Pipeline und Automatisierung von Arbeiten mit Docker

Quelle: habr.com

60GB SSD 8Gb DDR4