Erstellen von Container-nativen Node.js-Anwendungen mit Red Hat OpenShift Application Runtimes und Istio

Entwickler, die an einer Kubernetes-basierten Anwendungsumgebung wie Red Hat OpenShift arbeiten, müssen eine Reihe von Dingen berücksichtigen, um die erheblichen Vorteile dieser Technologien voll auszuschöpfen, darunter:

  • Wie kommuniziere ich mit der Orchestrierungsebene, um anzuzeigen, dass die Anwendung ordnungsgemäß funktioniert und für den Empfang von Datenverkehr verfügbar ist?
  • Was passiert, wenn die Anwendung einen Systemfehler erkennt, und wie leitet die Anwendung diesen an die Orchestrierungsebene weiter?
  • Wie kann ich den Verkehrsfluss zwischen meinen Anwendungen genau nachverfolgen, um potenzielle Engpässe zu identifizieren?
  • Welche Tools kann ich verwenden, um meine aktualisierte Anwendung einfach als Teil meiner Standard-Toolchain bereitzustellen?
  • Was passiert, wenn ich einen Netzwerkfehler zwischen meinen Diensten einführe, und wie teste ich dieses Szenario?

Diese Fragen sind von zentraler Bedeutung für die Entwicklung containernativer Lösungen. Bei Red Hat definieren wir containernativ als Anwendungen, die den folgenden Grundprinzipien entsprechen:

  • DevOps-Automatisierung
  • Single-Concern-Prinzip
  • Diensterkennung
  • Hohe Beobachtbarkeit
  • Lebenszykluskonformität
  • Laufzeitbeschränkung
  • Verfügbarkeit verarbeiten
  • Bildunveränderlichkeit

Dies mag neben der Kernanwendungslogik wie eine Menge Overhead erscheinen. Red Hat OpenShift Application Runtimes (RHOAR) und Istio stellen Entwicklern Tools zur Verfügung, mit denen sie diese Prinzipien mit minimalem Overhead in Bezug auf Codierung und Implementierung einhalten können.

In diesem Blogbeitrag konzentrieren wir uns speziell darauf, wie RHOAR und Istio kombiniert werden, um Tools für DevOps-Automatisierung, Lebenszykluskonformität, hohe Beobachtbarkeit und Laufzeitbeschränkung bereitzustellen.

Hinweis:Dieser Artikel basiert auf Version 0.7 von Istio, die zum Zeitpunkt der Erstellung dieses Artikels die neueste Version war. Wir empfehlen, diese Version von Istio nicht für Produktionsbereitstellungen zu verwenden, da sich einige Schlüsselfunktionen noch im Alpha-/Betastatus befinden. Obwohl sich Istio schnell weiterentwickelt, halten wir es für wichtig, dass Entwickler die Fähigkeiten erlernen und verstehen, um diese Technologie voll auszuschöpfen, sobald sie zu einem tragfähigen Produktionsangebot wird.

Voraussetzungen

  • Red Hat Openshift Container Platform 3.9 (RHOCP) oder Minishift Istio-Build:https://github.com/openshift-istio/origin/releases
  • oc Befehlszeilenzugriff auf RHOCP mit Cluster-Administratorrechten
  • Node.js-Version 8.6.0

Hinweis:Aufgrund der erforderlichen Administratorrechte während der Installationsphase ist Istio auf Red Hat OpenShift Online nicht verfügbar.

Ein RHOAR-Projekt einrichten

Wir beginnen mit dem RHOAR Health Check Booster Repo:
https://github.com/bucharest-gold/nodejs-health-check-redhat.
Klonen Sie dieses Repo mit dem folgenden Befehl :

$ git clone https://github.com/bucharest-gold/nodejs-health-check-redhat

Wechseln Sie zu nodejs-health-check-redhat Ordner:

$ cd nodejs-health-check-redhat

Installieren Sie npm Abhängigkeiten:

$ npm install

Erstellen Sie in OpenShift ein neues Projekt mit dem Namen rhoar-istio :

$ oc new-project rhoar-istio

Stellen Sie die RHOAR-Booster-Anwendung bereit:

$ npm run openshift

Sobald die Bereitstellung abgeschlossen ist, sollten Sie eine Ausgabe wie diese sehen:

 2018-06-01T14:06:35.037Z INFO build nodejs-health-check-redhat-s2i-1 complete
 2018-06-01T14:06:37.923Z INFO creating deployment configuration nodejs-health-check-redhat
 2018-06-01T14:06:37.927Z INFO creating new route nodejs-health-check-redhat
 2018-06-01T14:06:37.963Z INFO creating new service nodejs-health-check-redhat
 2018-06-01T14:06:38.063Z INFO route host mapping nodejs-health-check-redhat-rhoar.router.default.svc.cluster.local
 2018-06-01T14:06:38.106Z INFO complete

In OpenShift sollte die Anwendung bereitgestellt werden und Pods sollten ausgeführt werden, wie unten gezeigt.

Das Wichtigste, was hier zu beachten ist, ist die URL der Routenhostzuordnung, die in diesem Fall http://nodejs-health-checker-rhoar-istio.router.default.svc.cluster.local ist . Sobald Ihr DNS richtig konfiguriert ist, sollten Sie zu dieser URL navigieren und die folgende Seite sehen können:

Wir werden diese Benutzeroberfläche in Kürze verwenden, um den Neustart des Containers auszulösen.

Werfen wir einen Blick auf den Code, um zu sehen, was diese Booster-App demonstriert.
Blick auf app.js , können wir Folgendes sehen, was bedeutet, dass die App eine Instanz des Express-Webframeworks erstellt:

const app = express();

Die folgende Zeile bedeutet, dass die App die Variable isOnline setzt bis true beim Start:

let isOnline = true;

Und die App definiert eine benutzerdefinierte Aktivitätsprüfung, die „OK“ zurückgibt, wenn isOnline auf true gesetzt ist:

const options = {
	livenessCallback: (request, response) => {
		return isOnline ? response.send('OK') : response.sendStatus(500);
	}
};

Die App definiert eine Route, /api/stop , mit dem Benutzer den Wert von isOnline festlegen können bis false :

app.use('/api/stop', (request, response) => {
	isOnline = false;
	return response.send('Stopping HTTP server');
});

Die App verwendet den kube-probe npm-Modul zur Bereitstellung von Bereitschafts- und Lebendigkeitsprüfungen:

const probe = require('kube-probe');

Das Sondenmodul wird mit dem App-Objekt (Instanz von Express) aufgerufen:

probe(app, options);

Wenn Sie sich die Pods in der OpenShift-Konsole ansehen, sollten Sie Folgendes sehen:

Dies zeigt, dass die Bereitschaftsprüfung OpenShift korrekt darüber informiert, dass der Container bereit ist.

Über die von der Route bereitgestellte Benutzeroberfläche, wenn Sie auf Stop Service klicken klicken, sollten Sie in OpenShift einen Hinweis darauf sehen, dass OpenShift festgestellt hat, dass die Aktivitätsprüfung fehlgeschlagen ist und versucht, den Container neu zu starten.

Das ist also eine ziemlich coole „out of the box“-Funktionalität, die von RHOAR bereitgestellt wird und drei der Schlüsselprinzipien des Container-nativen Designs berührt:DevOps-Automatisierung, Lebenszykluskonformität und hohe Beobachtbarkeit.

Warum Istio verwenden?

Folgendes stammt von der Istio-Website:

Istio bietet eine Komplettlösung, um die vielfältigen Anforderungen von Microservice-Anwendungen zu erfüllen, indem es Einblicke in das Verhalten und die operative Kontrolle über das Service Mesh als Ganzes bietet. Es stellt eine Reihe von Schlüsselfunktionen einheitlich über ein Netzwerk von Diensten bereit:

Verkehrsmanagement. Kontrollieren Sie den Verkehrsfluss und API-Aufrufe zwischen Diensten, machen Sie Anrufe zuverlässiger und machen Sie das Netzwerk robuster gegenüber widrigen Bedingungen.
Dienstidentität und -sicherheit. Stellen Sie Dienste im Mesh mit einer überprüfbaren Identität bereit und bieten Sie die Möglichkeit, den Dienstdatenverkehr zu schützen, während er über Netzwerke mit unterschiedlichem Grad an Vertrauenswürdigkeit fließt.
Richtliniendurchsetzung. Wenden Sie Unternehmensrichtlinien auf die Interaktion zwischen Diensten an, stellen Sie sicher, dass Zugriffsrichtlinien durchgesetzt werden und Ressourcen gerecht unter den Verbrauchern verteilt werden. Richtlinienänderungen werden durch Konfigurieren des Netzes vorgenommen, nicht durch Ändern des Anwendungscodes.
Telemetrie. Machen Sie sich ein Bild von den Abhängigkeiten zwischen Diensten und der Art und dem Verkehrsfluss zwischen ihnen, um Probleme schnell zu erkennen.

Kurz gesagt, die Einführung von Istio in unser Projekt wird viele Tools rund um das Verkehrsmanagement, die Überwachung und die Fehlertoleranz bereitstellen, die (unter anderem) viele Vorteile für das Prinzip der hohen Beobachtbarkeit bieten.

Mit minimalen Auswirkungen auf die Implementierung seitens des Entwicklers erstellt Istio beispielsweise Ablaufverfolgungsinformationen wie diese:

Der obige Screenshot zeigt die Ablaufverfolgung einer Anfrage, die drei Microservices in einem Service Mesh trifft. Der folgende Screenshot zeigt dasselbe Netz in einem gerichteten azyklischen Diagramm, das ebenfalls aus den von Istio aufgezeichneten Informationen generiert wurde.

Installieren von Istio

Zu Beginn installieren wir Istio anhand der Anweisungen hier:https://github.com/openshift-istio/openshift-ansible/blob/istio-3.9-0.7.1/istio/Installation.md

Auf dem Master-Knoten:

Wechseln Sie in das Verzeichnis mit der Master-Konfigurationsdatei (master-config.yaml ), zum Beispiel /etc/origin/master .

Erstellen Sie eine Datei namens master-config.patch mit folgendem Inhalt:

admissionConfig:
 pluginConfig:
  MutatingAdmissionWebhook:
   configuration:
    apiVersion: v1
    disable: false
    kind: DefaultAdmissionConfig
kubernetesMasterConfig:
 controllerArguments:
  cluster-signing-cert-file:
  - ca.crt
  cluster-signing-key-file:
  - ca.key

Führen Sie die folgenden Befehle aus, um master-config.yml zu patchen Datei und starten Sie die atomaren OpenShift-Master-Dienste neu:

cp -p master-config.yaml master-config.yaml.prepatch

oc ex config patch master-config.yaml.prepatch -p "$(cat ./master-config.patch)" > master-config.yaml
systemctl restart atomic-openshift-master*

Um die Elasticsearch-Anwendung ausführen zu können, muss die Kernel-Konfiguration auf jedem Knoten geändert werden. diese Änderung wird durch sysctl gehandhabt Dienst.

Erstellen Sie eine Datei namens /etc/sysctl.d/99-elasticsearch.conf mit folgendem Inhalt:

vm.max_map_count = 262144

Führen Sie den folgenden Befehl aus:

sysctl vm.max_map_count=262144

Auf einer Maschine mit oc Benutzer, der mit Cluster-Admin-Rechten angemeldet ist, klonen Sie openshift-istio Repo lokal:

$ git clone https://github.com/openshift-istio/openshift-ansible.git

$ cd openshift-ansible/istio

Führen Sie die Vorlage für das Istio-Installationsprogramm aus:

$ oc new-app istio_installer_template.yaml --param=OPENSHIFT_ISTIO_MASTER_PUBLIC_URL=<master public url>

Überprüfen Sie die Installation:

$ oc get pods -n istio-system -w

Sie sollten eine ähnliche Liste wie diese sehen:

Sobald alle Pods erfolgreich ausgeführt werden, wird eine Reihe neuer Routen erstellt, z. B. die im folgenden Screenshot gezeigten:

Nehmen Sie sich etwas Zeit, um sich die Schnittstellen anzusehen, die durch diese Routen offengelegt werden; Zu diesem Zeitpunkt werden jedoch keine Daten vorhanden sein, bis wir beginnen, unsere App mit einem Istio-Proxy-Sidecar zu verwenden.

Nachdem Istio installiert ist und ausgeführt wird, müssen wir unsere Node.js-Anwendungsbereitstellung so konfigurieren, dass sie den Istio-Proxy-Sidecar enthält. Istio ist so konfiguriert, dass das Proxy-Sidecar allen Bereitstellungen hinzugefügt wird, die die Anmerkung sidecar.istio.io/inject: "true" enthalten .

Ändern Sie den Port, auf dem die Liveness-/Bereitschaftstests lauschen

Der Istio-Sidecar-Proxy funktioniert nicht ordnungsgemäß, wenn sich die Aktivitäts-/Bereitschaftstests auf demselben Port wie die App-Routen befinden. Um dieses Problem zu beheben, ändern wir den Port für die Probes in unserer Node.js-App auf 3000.

Dazu fügen wir eine zusätzliche Express-Web-Framework-Instanz hinzu, die Port 3000 überwacht, indem wir Folgendes zu app.js hinzufügen :

const health = express();

…

probe(health, options);
health.listen(3000, function(){
	console.log('App ready, probes listening on port 3000');
})

Das vollständige app.js Datei sieht nun so aus:

const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const probe = require('kube-probe');
const app = express();
const health = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.static(path.join(__dirname, 'public')));
// Expose the license.html at http[s]://[host]:[port]/licences/licenses.html
app.use('/licenses', express.static(path.join(__dirname, 'licenses')));
let isOnline = true;
//
app.use('/api/greeting', (request, response) =&gt; {
if (!isOnline) {
	response.status(503);
	return response.send('Not online');
}
const name = request.query ? request.query.name : undefined;
	return response.send({content: `Hello, ${name || 'World!'}`});
});
app.use('/api/stop', (request, response) =&gt; {
	isOnline = false;
	return response.send('Stopping HTTP server');
});
const options = {
	livenessCallback: (request, response) =&gt; {
		return isOnline ? response.send('OK') : response.sendStatus(500);
	}
};
probe(health, options);
health.listen(3000, function(){
	console.log('App ready, probes listening on port 3000');
})
module.exports = app;

Aktualisieren Sie die Datei „deployment.yml“

Wir müssen die folgenden Änderungen an .nodeshift/deployment.yml vornehmen Datei. Ergänzungen sind grün markiert.
Änderungen sind rot markiert:

spec:
 template:
  metadata:
   labels:
    app: nodejs-health-check-redhat
    name: nodejs-health-check-redhat
   annotations:
    sidecar.istio.io/inject: "true"
 spec:
  containers:
  - name: nodejs-health-check-redhat
   ports:
   - containerPort: 8080
    protocol: TCP
    name: http
   readinessProbe:
    httpGet:
     path: /api/health/readiness
     port: 3000
     scheme: HTTP
    failureThreshold: 3
    initialDelaySeconds: 10
    periodSeconds: 5
    successThreshold: 1
    timeoutSeconds: 1
   livenessProbe:
    httpGet:
     path: /api/health/liveness
     port: 3000
     scheme: HTTP
    failureThreshold: 2
    initialDelaySeconds: 60
    periodSeconds: 3
    successThreshold: 1
    timeoutSeconds: 1
   resources:
    limits:
    cpu: 200m
    memory: 400Mi
   requests:
    cpu: 100m
    memory: 200Mi

Sehen wir uns diese Änderungen einzeln an.

Damit Istio-Metriken die Anwendung korrekt identifizieren können, muss die Vorlage in metadata eine „App“-Bezeichnung haben :

metadata:
labels:
 app: nodejs-health-check-redhat
 name: nodejs-health-check-redhat

Der Sidecar-Injektor von Istio ist so konfiguriert, dass der Sidecar-Proxy zu allen Bereitstellungen hinzugefügt wird, einschließlich sidecar.istio.io/inject: "true" Anmerkung. Also fügen wir dies unter metadata hinzu :

annotations:
&nbspsidecar.istio.io/inject: "true"

Damit die Daten als HTTP protokolliert werden, muss der Container eine Portdefinition namens http haben .

- name: nodejs-health-check-redhat
 ports:
 - containerPort: 8080
  protocol: TCP
  name: http

Wie bereits erwähnt, ändern wir die Probe-Ports von 8080 auf 3000:

readinessProbe:
 httpGet:
  path: /api/health/readiness
  port: 3000
  scheme: HTTP
 failureThreshold: 3
 initialDelaySeconds: 10
 periodSeconds: 5
 successThreshold: 1
 timeoutSeconds: 1
livenessProbe:
 httpGet:
  path: /api/health/liveness
  port: 3000
  scheme: HTTP
 failureThreshold: 2
 initialDelaySeconds: 60
 periodSeconds: 3
 successThreshold: 1
 timeoutSeconds: 1

Und schließlich fügen wir auch einige Ressourcenbeschränkungen hinzu, um OpenShift die erforderliche CPU und den Arbeitsspeicher mitzuteilen, die dieser Container verbrauchen wird:

resources:
 limits:
  cpu: 200m
  memory: 400Mi
 requests:
  cpu: 100m
  memory: 200Mi

Erstellen Sie eine service.yml-Datei

Damit Istio den Datenverkehr zu unserer App als HTTP behandeln kann, müssen wir einen service.yml erstellen Datei im .nodeshift Ordner und die Datei muss Folgendes enthalten:

spec:
 ports:
 - name: http
  port: 8080
  protocol: TCP
  targetPort: 8080

Stellen Sie die Anwendung erneut bereit

Löschen Sie zunächst die vorhandene Bereitstellungskonfiguration:

$ oc delete dc/nodejs-health-check-redhat

$ oc delete service nodejs-health-check-redhat

$ oc delete route nodejs-health-check-redhat

Führen Sie npm run openshift aus um die Anwendung erneut bereitzustellen.

Sobald die Bereitstellung abgeschlossen ist, sollten Sie Folgendes in der OpenShift-Konsole sehen:

Hinweis:Der obige Screenshot zeigt, dass jetzt zwei Container bereit sind (2/2) im Pod nodejs-health-check-redhat, was darauf hinweist, dass der Istio-Sidecar-Proxy neben dem App-Container ausgeführt wird.

Wenn Sie auf den laufenden Pod klicken, sollten Sie die Liste der Container wie folgt sehen:

Navigieren Sie zur UI-Route, z. B. http://nodejs-health-check-redhat-rhoar.router.default.svc.cluster.local/ , und führen Sie eine Reihe von Anfragen aus. Es lohnt sich auch, auf Service stoppen zu klicken klicken, um zu testen, wie Istio damit umgeht, dass der Dienst nicht verfügbar ist.

Überprüfen Sie die Ergebnisse in Istio

Wenn Sie sich jetzt die grafana ansehen Route, die wir im istio-system erstellt haben project, sollten Sie so etwas wie den folgenden Screenshot sehen, der den Datenverkehr zu unserer Anwendung mit Antwortzeiten, Fehler- und Erfolgsraten deutlich zeigt.

Wenn Sie sich die Jaeger-Konsole ansehen, sollten Sie auch eine erhebliche Menge an Aktivitäten sehen, zum Beispiel:

Zusammenfassung

Das Erstellen containerbasierter Lösungen kann wie eine herausfordernde Aufgabe erscheinen, die für Anwendungsentwickler viel Overhead bedeutet. Durch die Verwendung einer Kombination aus RHOAR und Istio werden viele dieser Überlegungen erledigt, sodass sich Anwendungsentwickler auf die Implementierung der Geschäftslogik konzentrieren können.

Diese Tools machen es Entwicklern viel einfacher, die Bereitstellung ihrer Anwendung auf OpenShift zu steuern, mit dem Service-Orchestrierungs-Framework zu interagieren, die Leistung ihrer Anwendung zu überwachen, zu verstehen, wie die Anwendung mit anderen Anwendungen (Service Mesh) zusammenhängt, und auch einzuführen und Systemfehler testen. Entwickler müssen nicht lernen, wie sie ihre Anwendung containerisieren oder Metriken oder Tracing-Tools auf Anwendungsebene implementieren. dies alles wird mit minimaler Konfiguration bereitgestellt.