Erstellen einer CI/CD-Kette und Automatisierung der Arbeit mit Docker

Meine ersten Websites habe ich Ende der 90er Jahre geschrieben. Dann war es sehr einfach, sie in einen betriebsbereiten Zustand zu versetzen. Auf einem Shared-Hosting gab es einen Apache-Server. Auf diesen Server konnte über FTP zugegriffen werden, indem man in die Browserzeile etwas wie folgt eingab ftp://ftp.example.com. Anschließend galt es, einen Namen und ein Passwort einzugeben und die Dateien auf den Server hochzuladen. Es gab andere Zeiten, da war alles einfacher als heute.

Erstellen einer CI/CD-Kette und Automatisierung der Arbeit mit Docker

In den letzten zwei Jahrzehnten hat sich viel verändert. Websites sind komplexer geworden und müssen vor der Freigabe für die Produktion zusammengestellt werden. Aus einem einzelnen Server sind viele Server geworden, die hinter Load Balancern laufen, und der Einsatz von Versionskontrollsystemen ist alltäglich geworden.

Für mein persönliches Projekt hatte ich eine spezielle Konfiguration. Und ich wusste, dass ich die Möglichkeit brauchte, eine Site in der Produktion bereitzustellen, indem ich nur eine Aktion ausführte: Code in einen Zweig schreiben master auf GitHub. Ich wusste auch, dass ich keinen riesigen Kubernetes-Cluster verwalten, keine Docker-Swarm-Technologie verwenden oder einen Serverpark mit Pods, Agenten und allen möglichen anderen Komplexitäten unterhalten wollte, um meine kleine Webanwendung auszuführen. Um das Ziel zu erreichen, die Arbeit so einfach wie möglich zu machen, musste ich mich mit CI/CD vertraut machen.

Wenn Sie ein kleines Projekt haben (in unserem Fall ein Node.js-Projekt) und lernen möchten, wie Sie die Bereitstellung dieses Projekts automatisieren und gleichzeitig sicherstellen möchten, dass das, was im Repository gespeichert ist, genau mit dem übereinstimmt, was in der Produktion funktioniert, denke ich Dieser Artikel könnte Sie interessieren.

Voraussetzungen

Vom Leser dieses Artikels wird erwartet, dass er über grundlegende Befehlszeilen- und Bash-Skriptkenntnisse verfügt. Darüber hinaus benötigt er Konten Travis CI и Docker-Hub.

Tore

Ich werde nicht sagen, dass dieser Artikel bedingungslos als „Trainingsleitfaden“ bezeichnet werden kann. Dies ist eher ein Dokument, in dem ich über das, was ich gelernt habe, spreche und den für mich geeigneten Prozess zum Testen und Bereitstellen von Code in der Produktion beschreibe, der in einem automatisierten Durchgang durchgeführt wird.

So sah mein Workflow letztendlich aus.

Für Code, der in einen anderen Zweig des Repositorys als verschoben wird masterwerden folgende Aktionen ausgeführt:

  • Der Projektaufbau auf Travis CI beginnt.
  • Es werden alle Unit-, Integrations- und End-to-End-Tests durchgeführt.

Nur für Code, der in landet master, wird Folgendes durchgeführt:

  • Alles oben Genannte, plus...
  • Erstellen eines Docker-Images basierend auf dem aktuellen Code, den Einstellungen und der Umgebung.
  • Hosten des Images auf Docker Hub.
  • Verbindung zum Produktionsserver.
  • Hochladen eines Bildes vom Docker Hub auf den Server.
  • Stoppen Sie den aktuellen Container und starten Sie einen neuen basierend auf dem neuen Image.

Wenn Sie absolut nichts über Docker, Images und Container wissen, machen Sie sich keine Sorgen. Ich werde dir alles darüber erzählen.

Was ist CI/CD?

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

▍Kontinuierliche Integration

Kontinuierliche Integration ist der Prozess, bei dem Entwickler Commits für das Hauptquellcode-Repository eines Projekts (normalerweise einen Zweig) vornehmen master). Gleichzeitig wird die Qualität des Codes durch automatisierte Tests sichergestellt.

▍Kontinuierliche Bereitstellung

Unter Continuous Deployment versteht man die häufige automatisierte Bereitstellung von Code in der Produktion. Der zweite Teil der Abkürzung CI/CD wird manchmal als „Continuous Delivery“ („Continuous Delivery“) bezeichnet. Dies ist im Grunde dasselbe wie „kontinuierliche Bereitstellung“, aber „kontinuierliche Bereitstellung“ impliziert, dass Änderungen manuell bestätigt werden müssen, bevor der Projektbereitstellungsprozess gestartet wird.

Erste Schritte

Die Anwendung, auf der ich das alles gemeistert habe, heißt Etwas beachten. Dies ist ein Webprojekt, an dem ich arbeite, um Notizen zu machen. Zuerst habe ich es versucht JAMStack-Projekt oder nur eine Front-End-Anwendung ohne Server, um die standardmäßigen Hosting- und Projektbereitstellungsoptionen zu nutzen, die es bietet Netlify. Da die Komplexität der Anwendung zunahm, musste ich ihr Back-End erstellen, was bedeutete, dass ich meine eigene Strategie für die automatisierte Integration und automatisierte Bereitstellung des Projekts entwickeln musste.

In meinem Fall handelt es sich bei der Anwendung um einen Express-Server, der in einer Node.js-Umgebung ausgeführt wird, eine Single-Page-React-Anwendung bereitstellt und eine sichere serverseitige API unterstützt. Diese Architektur folgt einer Strategie, die in zu finden ist diese Leitfaden zur vollständigen Stack-Authentifizierung.

Ich habe mich beraten другом, ein Automatisierungsexperte, fragte ihn, was ich tun muss, damit alles so funktioniert, wie ich es möchte. Er gab mir eine Vorstellung davon, wie der im Abschnitt „Ziele“ dieses Artikels beschriebene automatisierte Workflow aussehen sollte. Um solche Ziele zu setzen, musste ich herausfinden, wie man Docker nutzt.

Docker

Docker ist ein Tool, das dank der Containerisierungstechnologie die einfache Verteilung von Anwendungen sowie deren Bereitstellung und Ausführung in derselben Umgebung ermöglicht, selbst wenn die Docker-Plattform selbst in verschiedenen Umgebungen ausgeführt wird. Zuerst musste ich mir die Docker-Befehlszeilentools (CLI) aneignen. Anweisung Die Installationsanleitung für Docker ist nicht ganz klar, aber Sie können daraus lernen, dass Sie für den ersten Schritt der Installation Docker Desktop (für Mac oder Windows) herunterladen müssen.

Docker Hub ist ungefähr das Gleiche wie GitHub für Git-Repositorys oder Registry npm für JavaScript-Pakete. Dies ist ein Online-Repository für Docker-Images. Hier stellt Docker Desktop eine Verbindung her.

Um mit Docker zu beginnen, müssen Sie also zwei Dinge tun:

Anschließend können Sie überprüfen, ob die Docker-CLI funktioniert, indem Sie den folgenden Befehl ausführen, um die Docker-Version zu überprüfen:

docker -v

Melden Sie sich als Nächstes bei Docker Hub an, indem Sie Ihren Benutzernamen und Ihr Passwort eingeben, wenn Sie dazu aufgefordert werden:

docker login

Um Docker verwenden zu können, müssen Sie die Konzepte von Bildern und Containern verstehen.

▍Bilder

Ein Bild ist eine Art Bauplan, der Anweisungen zum Bau eines Containers enthält. Dies ist eine unveränderliche Momentaufnahme des Dateisystems und der Anwendungseinstellungen. Entwickler können Bilder problemlos teilen.

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

Dieser Befehl gibt eine Tabelle mit folgendem Titel aus:

REPOSITORY     TAG     IMAGE ID     CREATED     SIZE
---

Als nächstes betrachten wir einige Beispiele für Befehle im gleichen Format – zuerst gibt es einen 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 zum Ausführen einer Anwendung erforderlich ist. Eine Anwendung mit diesem Ansatz funktioniert unabhängig von der Infrastruktur immer gleich: in einer isolierten Umgebung und in derselben Umgebung. Wir sprechen über die Tatsache, dass Instanzen desselben Bildes in unterschiedlichen Umgebungen gestartet werden.

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

▍Tags

Ein Tag ist ein Hinweis auf eine bestimmte Version eines Bildes.

▍Kurzreferenz für Docker-Befehle

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

Team

Kontext

Aktion

Docker-Build

Bild

Erstellen eines Images aus einer Docker-Datei

Docker-Tag

Bild

Bild-Tagging

Andockbilder

Bild

Eine Liste von Bildern anzeigen

Andocklauf

Behälter

Ausführen eines bildbasierten Containers

Docker schieben

Bild

Senden eines Bildes an die Registry

Docker ziehen

Bild

Laden eines Bildes aus der Registry

Docker ps

Behälter

Container auflisten

Docker-System bereinigen

Bild/Container

Entfernen nicht verwendeter Container und Bilder

▍Docker-Datei

Ich weiß, wie man eine Produktionsanwendung lokal ausführt. Ich habe eine Webpack-Konfiguration, um eine fertige React-App zu erstellen. Als nächstes habe ich einen Befehl, der einen Node.js-basierten Server auf dem Port startet 5000. Es sieht aus wie das:

npm i         # установка зависимостей
npm run build # сборка React-приложения
npm run start # запуск Node-сервера

Bitte beachten Sie, dass ich für dieses Material keine Beispielanwendung habe. Aber für Experimente reicht hier jede einfache Node-Anwendung aus.

Um den Container verwenden zu können, müssen Sie Docker Anweisungen geben. Dies geschieht über eine Datei namens Dockerfilebefindet sich im Stammverzeichnis des Projekts. Diese Akte erscheint zunächst eher unverständlich.

Der darin enthaltene Inhalt beschreibt aber in speziellen Befehlen lediglich so etwas wie das Einrichten einer Arbeitsumgebung. Hier sind einige dieser Befehle:

  • AB — Dieser Befehl startet eine Datei. Es gibt das Basis-Image an, aus dem der Container erstellt wird.
  • COPY - Kopieren von Dateien von einer lokalen Quelle in einen Container.
  • ARBEITSVERZEICHNIS - Festlegen des Arbeitsverzeichnisses für die folgenden Befehle.
  • RENNE - Befehle ausführen.
  • ENTLARVEN - Porteinstellung.
  • EINSTIEGSPUNKT – Eine Angabe des auszuführenden Befehls.

Dockerfile könnte etwa so 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

Abhängig vom ausgewählten Basis-Image müssen Sie möglicherweise zusätzliche Abhängigkeiten installieren. Tatsache ist, dass einige Basis-Images (wie Node Alpine Linux) so kompakt wie möglich konzipiert sind. Daher enthalten sie möglicherweise nicht die erwarteten Programme.

▍Erstellen, Markieren und Ausführen eines Containers

Die örtliche Montage und Inbetriebnahme des Containers erfolgt, nachdem wir dies getan haben DockerfileDie Aufgaben sind recht einfach. Bevor ein Image an Docker Hub übertragen wird, muss es lokal getestet werden.

▍Montage

Zuerst müssen Sie sammeln Bild, unter Angabe eines Namens und optional eines Tags (wenn kein Tag angegeben ist, weist das System dem Bild automatisch ein Tag zu latest).

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

Nachdem Sie diesen Befehl ausgeführt haben, können Sie zusehen, wie Docker das Image erstellt.

Sending build context to Docker daemon   2.88MB
Step 1/9 : FROM node:12-alpine
 ---> ...выполнение этапов сборки...
Successfully built 123456789123
Successfully tagged <image>:<tag>

Der Aufbau kann ein paar Minuten dauern – es hängt alles davon ab, wie viele Abhängigkeiten Sie haben. Nachdem der Build abgeschlossen ist, können Sie den Befehl ausführen docker images und werfen Sie einen Blick auf die Beschreibung Ihres neuen Bildes.

REPOSITORY          TAG               IMAGE ID            CREATED              SIZE
<image>             latest            123456789123        About a minute ago   x.xxGB

▍Starten

Das Bild wurde erstellt. Und das bedeutet, dass Sie auf dieser Basis einen Container betreiben können. Da ich auf die im Container laufende Anwendung zugreifen möchte localhost:5000, i, auf der linken Seite des Paares 5000:5000 im folgenden Befehlssatz 5000. Auf der rechten Seite befindet sich der Containerhafen.

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

Nachdem der Container nun erstellt wurde und ausgeführt wird, können Sie den Befehl verwenden docker ps um Informationen zu diesem Container anzuzeigen (oder Sie können den Befehl verwenden docker ps -a, das Informationen zu allen Containern anzeigt, nicht nur zu den laufenden).

CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                      PORTS                    NAMES
987654321234        <image>             "/bin/sh -c 'npm run…"   6 seconds ago        Up 6 seconds                0.0.0.0:5000->5000/tcp   stoic_darwin

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

▍Tag-Zuweisung und Veröffentlichung

Um eines der erstellten Images auf dem Produktionsserver verwenden zu können, müssen wir dieses Image vom Docker Hub herunterladen können. Das bedeutet, dass Sie zunächst ein Repository für das Projekt auf Docker Hub erstellen müssen. Danach haben wir einen Ort, an den wir das Bild senden können. Das Image muss umbenannt werden, sodass sein Name mit unserem Docker Hub-Benutzernamen beginnt. Darauf sollte der Name des Repositorys folgen. Am Ende des Namens kann ein beliebiges Tag platziert werden. Nachfolgend finden Sie ein Beispiel für die Benennung von Bildern nach diesem Schema.

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

docker build -t <username>/<repository>:<tag> .
docker tag <username>/<repository>:<tag> <username>/<repository>:latest
docker push <username>/<repository>:<tag>

# На практике это может выглядеть, например, так:
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 geht, ist das Image auf Docker Hub verfügbar und kann einfach auf den Server hochgeladen oder mit anderen Entwicklern geteilt werden.

Nächste Schritte

Mittlerweile haben wir überprüft, dass die Anwendung in Form eines Docker-Containers lokal läuft. Wir haben den Container auf Docker Hub hochgeladen. All dies bedeutet, dass wir unserem Ziel bereits sehr gute Fortschritte gemacht haben. Jetzt müssen wir zwei weitere Fragen lösen:

  • Einrichten eines CI-Tools zum Testen und Bereitstellen von Code.
  • Einrichten 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 zu beachten, dass Sie hier eine andere Kombination von Diensten nutzen können. Anstelle von Travis CI können Sie beispielsweise CircleCI oder Github Actions verwenden. Und statt DigitalOcean – AWS oder Linode.

Wir haben uns entschieden, mit Travis CI zusammenzuarbeiten, und ich habe bereits etwas in diesem Dienst eingerichtet. Deshalb werde ich jetzt kurz darüber sprechen, wie man es für die Arbeit vorbereitet.

Travis CI

Travis CI ist ein Tool zum Testen und Bereitstellen von Code. Ich möchte nicht näher auf die Einrichtung von Travis CI eingehen, da jedes Projekt einzigartig ist und nicht viel bringt. Aber ich werde die Grundlagen behandeln, um Ihnen den Einstieg zu erleichtern, wenn Sie sich für die Verwendung von Travis CI entscheiden. Was auch immer Sie wählen – Travis CI, CircleCI, Jenkins oder etwas anderes – ähnliche Konfigurationsmethoden gelten überall.

Um mit Travis CI zu beginnen, gehen Sie zu Projektseite und ein Konto erstellen. Dann integrieren Sie Travis CI in Ihr GitHub-Konto. Beim Einrichten des Systems müssen Sie das Repository angeben, das Sie automatisieren möchten, und den Zugriff darauf ermöglichen. (Ich verwende GitHub, bin mir aber sicher, dass Travis CI in BitBucket, GitLab und andere ähnliche Dienste integriert werden kann.)

Bei jedem Start von Travis CI wird ein Server gestartet, der die in der Konfigurationsdatei angegebenen Befehle ausführt, einschließlich der Bereitstellung der entsprechenden Zweige des Repositorys.

▍Joblebenszyklus

Travis CI-Konfigurationsdatei aufgerufen .travis.yml und im Projektstammverzeichnis gespeichert, unterstützt das Konzept von Ereignissen Lebenszyklus Aufgaben. Hier sind die Ereignisse, aufgelistet in der Reihenfolge ihres Auftretens:

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

▍Testen

In der Konfigurationsdatei werde ich einen lokalen Travis CI-Server einrichten. Ich habe Node 12 als Sprache ausgewählt und das System angewiesen, die für die Verwendung von Docker erforderlichen Abhängigkeiten zu installieren.

Alles aufgeführt in .travis.yml, wird bei allen Pull-Requests an alle Zweige des Repositorys ausgeführt, sofern nicht anders angegeben. Dies ist eine nützliche Funktion, da wir damit den gesamten Code testen können, der in das Repository gelangt. Dadurch können Sie feststellen, ob der Code bereit ist, in den Zweig geschrieben zu werden. masterund ob dadurch der Erstellungsprozess des Projekts unterbrochen wird. In dieser globalen Konfiguration installiere ich alles lokal, führe den Webpack-Entwicklungsserver im Hintergrund aus (dies ist eine Funktion meines Workflows) und führe die Tests durch.

Wenn Sie möchten, dass in Ihrem Repository Codeabdeckungssymbole angezeigt werden, hier Hier finden Sie eine kurze Anleitung zur Verwendung von Jest, Travis CI und Coveralls zum Sammeln und Anzeigen dieser Informationen.

Hier 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 Zweige des Repositorys und für Pull-Requests ausgeführt werden.

▍Bereitstellung

Basierend auf der Annahme, dass alle automatisierten Tests erfolgreich abgeschlossen wurden, können wir den Code optional auf dem Produktionsserver bereitstellen. Da wir dies nur für den Zweigcode tun möchten master, geben wir dem System in den Bereitstellungseinstellungen die entsprechenden Anweisungen. Bevor Sie versuchen, den Code, den wir uns als Nächstes ansehen, in Ihrem Projekt zu verwenden, möchte ich Sie warnen, dass Sie über ein tatsächliches Skript verfügen müssen, das für die Bereitstellung aufgerufen wird.

deploy:
  # Собрать Docker-контейнер и отправить его на Docker Hub
  provider: script
  script: bash deploy.sh
  on:
    branch: master

Das Bereitstellungsskript führt zwei Dinge aus:

  • Erstellen, Markieren und Senden des Bildes an Docker Hub mithilfe eines CI-Tools (in unserem Fall Travis CI).
  • Laden des Bildes auf den Server, Stoppen des alten Containers und Starten eines neuen (in unserem Fall läuft der Server auf der DigitalOcean-Plattform).

Zunächst müssen Sie einen automatischen Prozess zum Erstellen, Markieren und Übertragen des Images an Docker Hub einrichten. All dies ist dem, was wir bereits manuell gemacht haben, sehr ähnlich, mit der Ausnahme, dass wir hier eine Strategie zum Zuweisen eindeutiger Tags zu Bildern und zum Automatisieren der Anmeldung benötigen. Ich hatte Schwierigkeiten mit einigen Details des Bereitstellungsskripts, z. B. der Tagging-Strategie, der Anmeldung, der Kodierung von SSH-Schlüsseln und dem Aufbau einer SSH-Verbindung. Aber zum Glück ist mein Freund sehr gut im Bash und in vielen anderen Dingen. Er hat mir geholfen, dieses Drehbuch zu schreiben.

Der erste Teil des Skripts besteht also darin, das Bild an Docker Hub zu senden. Das geht ganz einfach. Das von mir verwendete Tagging-Schema umfasst die Kombination des Git-Hashs und des Git-Tags, sofern vorhanden. Dadurch wird sichergestellt, dass das Tag eindeutig ist und die Baugruppe, auf der es basiert, leichter identifiziert werden kann. DOCKER_USERNAME и DOCKER_PASSWORD sind benutzerdefinierte Umgebungsvariablen, die über die Travis CI-Schnittstelle festgelegt werden können. Travis CI verarbeitet sensible Daten automatisch, damit diese 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 ganz davon ab, welchen Host Sie verwenden und wie die Verbindung zu ihm organisiert ist. In meinem Fall werden die Befehle verwendet, um eine Verbindung zum Server herzustellen, da ich Digital Ocean verwende doctl. Bei der Arbeit mit Aws wird das Dienstprogramm verwendet aws, usw.

Das Einrichten des Servers war nicht besonders schwierig. Also habe ich ein Droplet basierend auf dem Basisbild erstellt. Zu beachten ist, dass das von mir gewählte System eine einmalige manuelle Installation von Docker und einen einmaligen manuellen Start von Docker erfordert. Ich habe Ubuntu 18.04 verwendet, um Docker zu installieren. Wenn Sie also auch Ubuntu verwenden, können Sie einfach folgen dies einfache Anleitung.

Ich spreche hier nicht von spezifischen Befehlen für den Dienst, da dieser Aspekt in verschiedenen Fällen sehr unterschiedlich sein kann. Ich gebe nur einen allgemeinen Aktionsplan, der nach der Verbindung über SSH mit dem Server, auf dem das Projekt bereitgestellt wird, durchgeführt werden soll:

  • Sie müssen den Container finden, der gerade ausgeführt wird, und ihn stoppen.
  • Dann müssen Sie einen neuen Container im Hintergrund starten.
  • Sie müssen den lokalen Port des Servers auf einstellen 80 - Dadurch können Sie die Website unter der Adresse des Formulars betreten example.com, ohne einen Port anzugeben, anstatt eine Adresse wie zu verwenden example.com:5000.
  • Und schließlich müssen Sie alle alten Container und Bilder entfernen.

Hier ist die Fortsetzung des Drehbuchs.

# Найти 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 Dinge, auf die Sie achten sollten

Wenn Sie über SSH von Travis CI aus eine Verbindung zum Server herstellen, wird möglicherweise eine Warnung angezeigt, die es Ihnen nicht erlaubt, mit der Installation fortzufahren, da das System auf die Antwort des Benutzers wartet.

The authenticity of host '<hostname> (<IP address>)' can't be established.
RSA key fingerprint is <key fingerprint>.
Are you sure you want to continue connecting (yes/no)?

Ich habe gelernt, dass ein String-Schlüssel in Base64 codiert werden kann, um ihn in einer Form zu speichern, in der bequem und zuverlässig damit gearbeitet werden kann. In der Installationsphase können Sie den öffentlichen Schlüssel entschlüsseln und in eine Datei schreiben known_hosts um den oben genannten Fehler zu beheben.

echo <public key> | base64 # выводит <публичный ключ, закодированный в base64>

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== [email protected]" | base64

Und hier ist, was es ausgibt – eine Base64-codierte Zeichenfolge:

MTIzLjQ1LjY3Ljg5IHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQUJJd0FBQVFFQWtsT1Vwa0RIcmZIWTE3U2JybVRJcE5MVEdLOVRqb20vQldEU1UKR1BsK25hZnpsSERUWVc3aGRJNHlaNWV3MThKSDRKVzlqYmhVRnJ2aVF6TTd4bEVMRVZmNGg5bEZYNVFWa2JQcHBTd2cwY2RhMwpQYnY3a09kSi9NVHlCbFdYRkNSK0hBbzNGWFJpdEJxeGlYMW5LaFhwSEFac01jaUxxOFY2UmpzTkFRd2RzZE1GdlNsVksvN1hBCnQzRmFvSm9Bc25jTTFROXg1KzNWMFd3NjgvZUlGbWIxenVVRmxqUUpLcHJyWDg4WHlwTkR2allOYnk2dncvUGIwcndlcnQvRW4KbVorQVc0T1pQblRQSTg5WlBtVk1MdWF5ckQyY0U4NlovaWw4YitndzNyMysxbkthdG1Ja2puMnNvMWQwMVFyYVRsTXFWU3NieApOclJGaTl3cmYrTTdRPT0geW91QGV4YW1wbGUuY29tCg==

Hier ist der oben erwähnte Befehl

install:
  - echo < публичный ключ, закодированный в base64> | base64 -d >> $HOME/.ssh/known_hosts

Der gleiche Ansatz lässt sich auch mit einem privaten Schlüssel beim Verbindungsaufbau nutzen, da man durchaus einen privaten Schlüssel für den Zugriff auf den Server benötigen kann. Wenn Sie mit einem Schlüssel arbeiten, müssen Sie lediglich sicherstellen, dass dieser sicher in einer Travis CI-Umgebungsvariablen gespeichert ist und nirgendwo angezeigt wird.

Beachten Sie außerdem, dass Sie möglicherweise das gesamte Bereitstellungsskript in einer einzigen Zeile ausführen müssen, beispielsweise mit doctl. Dies kann einen zusätzlichen Aufwand erfordern.

doctl compute ssh <droplet> --ssh-command "все команды будут здесь && здесь"

TLS/SSL und Lastausgleich

Nachdem ich alle oben genannten Schritte ausgeführt hatte, bestand das letzte Problem darin, dass der Server nicht über SSL verfügte. Da ich einen Node.js-Server verwende, um zu erzwingen arbeiten Reverse-Proxy Nginx und Let's Encrypt müssen Sie einiges basteln.

Ich wollte wirklich nicht alle SSL-Einstellungen manuell vornehmen, also habe ich einfach einen Load Balancer erstellt und Informationen darüber im DNS aufgezeichnet. Im Fall von DigitalOcean ist beispielsweise die Erstellung eines sich automatisch erneuernden, selbstsignierten Zertifikats auf dem Load Balancer ein einfaches, kostenloses und schnelles Verfahren. Dieser Ansatz hat den zusätzlichen Vorteil, dass er es bei Bedarf sehr einfach macht, SSL auf mehreren Servern einzurichten, die hinter einem Load Balancer laufen. Dies ermöglicht es den Servern selbst, überhaupt nicht an SSL zu „denken“, sondern gleichzeitig wie gewohnt den Port zu nutzen 80. Daher ist die Konfiguration von SSL auf einem Load Balancer viel einfacher und bequemer als alternative SSL-Konfigurationsmethoden.

Jetzt können Sie alle Ports auf dem Server schließen, die eingehende Verbindungen akzeptieren – bis auf den Port 80, wird für die Kommunikation mit dem Load Balancer und dem Port verwendet 22 für SSH. Daher schlägt der Versuch fehl, den Server über andere als diese beiden Ports direkt zu kontaktieren.

Ergebnisse

Nachdem ich alles getan hatte, worüber ich in diesem Artikel gesprochen habe, machten mir weder die Docker-Plattform noch das Konzept automatisierter CI/CD-Ketten mehr Angst. Ich konnte eine kontinuierliche Integrationskette einrichten, in der der Code getestet wird, bevor er in die Produktion geht, und der Code automatisch auf dem Server bereitgestellt wird. Für mich ist das alles noch relativ neu und ich bin mir sicher, dass es Möglichkeiten gibt, meinen automatisierten Arbeitsablauf zu verbessern und effizienter zu gestalten. Wenn Sie also irgendwelche Ideen dazu haben – geben Sie sie me wissen. Ich hoffe, dieser Artikel hat Ihnen bei Ihren Bemühungen geholfen. Ich möchte glauben, dass Sie durch die Lektüre genauso viel gelernt haben, wie ich gelernt habe, als ich mich mit allem befasst habe, worüber ich darin erzählt habe.

PS In unserem Marktplatz es gibt ein Bild Docker, das mit einem Klick installiert wird. Sie können überprüfen, an welchen Containern gearbeitet wird VPS. Alle Neukunden erhalten 3 Testtage kostenlos.

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

Erstellen einer CI/CD-Kette und Automatisierung der Arbeit mit Docker

Source: habr.com

Kommentar hinzufügen