Vom Outsourcing zur Entwicklung (Teil 1)

Hallo zusammen, ich bin Sergej Emeljančik. Ich bin der Leiter der Firma Audit-Telekom, der Hauptentwickler und Autor des Systems Veliam. Ich habe beschlossen, einen Artikel darüber zu schreiben, wie mein Freund und ich ein Outsourcing-Unternehmen gegründet haben, eigene Software für uns entwickelt haben und sie später allen Interessierten im SaaS-Modell zur Verfügung gestellt haben. Ich werde über meine anfängliche Skepsis berichten, dass das möglich ist. Der Artikel enthält nicht nur eine Erzählung, sondern auch technische Details zur Entstehung des Produkts Veliam, einschließlich einiger Codeabschnitte. Ich werde über die Fehler sprechen, die wir gemacht haben, und wie wir sie anschließend beheben konnten. Zunächst hatte ich Bedenken, einen solchen Artikel zu veröffentlichen. Aber ich dachte, es ist besser, dies zu tun, um Feedback zu erhalten und mich zu verbessern, als den Artikel nicht zu veröffentlichen und darüber nachzudenken, was gewesen wäre, wenn…

Hintergrund

Ich habe als IT-Mitarbeiter in einem Unternehmen gearbeitet. Die Firma war ziemlich groß und hatte eine komplexe Netzwerkstruktur. Ich werde nicht auf meine Aufgaben eingehen, nur so viel: die Entwicklung von irgendetwas gehörte definitiv nicht dazu.

Wir hatten ein Monitoring, aber aus rein akademischem Interesse wollte ich versuchen, mein einfaches eigenes zu schreiben. Die Idee war, dass es web-basiert ist, sodass man einfach ohne Installation von Clients von jedem Gerät, einschließlich Mobilgeräten über Wi-Fi, auf die Netzwerkaktivitäten zugreifen kann. Außerdem wollte ich schnell erkennen können, in welchem Raum sich das Gerät befindet, das "ausgelaufen" ist, da es sehr strenge Anforderungen an die Reaktionszeit bei solchen Problemen gab. Letztendlich entstand der Plan, eine einfache Webseite zu schreiben, auf der ein JPEG mit einem Netzwerkschema als Hintergrund dient, die Geräte mit ihren IP-Adressen aus diesem Bild auszuschneiden und dynamische Inhalte in Form von grünen oder blinkend roten IP-Adressen an den richtigen Koordinaten über das Bild zu zeigen. Die Aufgabe ist gestellt, wir fangen an.

Früher habe ich mit Delphi, PHP, JS und sehr oberflächlich mit C++ programmiert. Ich kenne mich ziemlich gut mit Netzwerken aus: VLAN, Routing (OSPF, EIGRP, BGP), NAT. Das war ausreichend, um einen Prototyp eines primitiven Monitorings selbst zu schreiben.

Ich schrieb, was ich mir in PHP vorstellte. Der Apache-Server und PHP liefen unter Windows, da Linux für mich damals etwas Unverständliches und sehr Komplexes war. Wie sich später herausstellte, lag ich damit völlig falsch – in vielen Bereichen ist Linux viel einfacher als Windows. Aber das ist ein separates Thema, und wir wissen alle, wie viele Streitigkeiten es darüber gibt. Der Windows-Taskplaner rief mit einem kurzen Intervall (ich erinnere mich nicht genau, aber es war etwa einmal alle drei Sekunden) ein PHP-Skript auf, das alle Objekte durch einfaches Pingen abfragte und den Status in einer Datei speicherte.

system("ping -n 3 -w 100 {$ip_address}"); 

Ja, die Arbeit mit der Datenbank war zu diesem Zeitpunkt auch für mich neu. Ich wusste nicht, dass man Prozesse parallelisieren kann, und das Durchlaufen aller Knoten im Netzwerk dauerte lange, da es in einem einzigen Thread ablief. Besonders Probleme traten auf, wenn mehrere Knoten nicht verfügbar waren, da jeder von ihnen das Skript um 300 ms verzögerte. Auf der Client-Seite gab es eine einfache Schleifenfunktion, die alle paar Sekunden aktualisierte Informationen vom Server über eine Ajax-Anfrage herunterlud und die Benutzeroberfläche aktualisierte. Nach drei aufeinanderfolgenden fehlgeschlagenen Pings spielte, falls auf dem Computer eine Webseite mit Monitoring geöffnet war, ein fröhliches Stück Musik.

Als ich das Ergebnis sah, war ich sehr inspiriert und dachte, dass ich noch mehr hinzufügen könnte (gemäß meinem Wissen und meinen Möglichkeiten). Aber ich mochte schon immer keine Systeme mit einer Million Diagrammen, die ich damals und auch heute noch in den meisten Fällen für unnötig halte. Ich wollte nur das integrieren, was mir tatsächlich bei meiner Arbeit helfen würde. Dieses Prinzip bleibt bis heute grundlegend für die Entwicklung von Veliam. Dann wurde mir klar, dass es großartig wäre, wenn ich das Monitoring nicht ständig offen halten und über Probleme informiert werden müsste. Wenn ein Problem auftritt, wollte ich die Seite erst dann öffnen, um zu sehen, wo der problematische Netzwerk-Knoten sitzt und was ich weiter tun sollte. Ich las damals keine E-Mails, weil ich sie einfach nicht nutzte. Im Internet stieß ich auf SMS-Gateways, die GET- oder POST-Anfragen empfangen können und mir eine SMS mit dem Text senden, den ich schreibe. Ich wusste sofort, dass ich das unbedingt wollte. Also begann ich, die Dokumentation zu studieren. Nach einiger Zeit gelang es mir, und jetzt erhielt ich SMS über Probleme im Netzwerk auf mein Handy mit dem Namen des "ausgefallenen Objekts". Obwohl das System einfach war, war es von mir selbst geschrieben, und das Wichtigste, was mich damals zu seiner Weiterentwicklung motivierte, war, dass es ein praktisches Programm war, das mir wirklich bei meiner Arbeit half.

Und so kam der Tag, an dem einer der Internetkanäle bei der Arbeit ausfiel, während mein Monitoring mir darüber keinerlei Hinweis gab. Denn die Google-DNS waren nach wie vor hervorragend erreichbar. Es war an der Zeit, darüber nachzudenken, wie man überwachen kann, ob die Verbindung aktiv ist. Es gab verschiedene Ideen, wie man das umsetzen könnte. Bei einigen Geräten hatte ich jedoch keinen Zugang. Ich musste mir überlegen, wie ich herausfinden kann, welcher der Kanäle aktiv ist, ohne die Möglichkeit zu haben, dies direkt im Netzwerkgerät zu überprüfen. Dann hatte ein Kollege die Idee, dass die Traceroute zu öffentlichen Servern möglicherweise unterschiedlich sein könnte, je nachdem, über welchen Kanal die Internetverbindung derzeit läuft. Ich habe es überprüft und tatsächlich war es so. Bei der Traceroute gab es unterschiedliche Routen.

system(“tracert -d -w 500 8.8.8.8”);

So entstand ein weiteres Skript, genauer gesagt wurde die Tracing-Funktion zum Schluss desselben Skripts hinzugefügt, das alle Geräte im Netzwerk pingte. Schließlich war das ein weiterer langwieriger Prozess, der im selben Thread ausgeführt wurde und die gesamte Skriptleistung verlangsamte. Doch damals war das nicht so offensichtlich. Dennoch erfüllte es seinen Zweck, da im Code festgelegt war, welche Tracing-Informationen für jeden der Kanäle erforderlich waren. So begann ein System zu arbeiten, das bereits Netzwerkinstrumente (Router, Switches, WLAN usw.) und Kommunikationskanäle mit der Außenwelt überwachte (auch wenn man das laut sagen kann, da keine Metriken gesammelt wurden, sondern einfach nur gepingt wurde). SMS kamen zuverlässig an und auf dem Diagramm war immer gut sichtbar, wo das Problem lag.

In der täglichen Arbeit musste ich mich oft mit Cross-Referenzierung beschäftigen. Es wurde mühsam, ständig auf die Cisco-Switches zu gehen, um zu sehen, welchen Schnittstelle ich nutzen sollte. Wie großartig wäre es, einfach auf das Monitoring zu klicken und eine Liste der Schnittstellen mit Beschreibungen zu sehen? Das würde mir Zeit sparen. Außerdem müsste ich in diesem Szenario nicht Putty oder SecureCRT starten, um Benutzerinformationen und Befehle einzugeben. Ich könnte einfach im Monitoring klicken, sehen, was ich brauche, und mit meiner Arbeit fortfahren. Ich begann zu suchen, wie man mit den Switches interagieren kann. Sofort fielen mir zwei Optionen ein: SNMP oder über SSH auf den Switch zugreifen, die benötigten Befehle eingeben und das Ergebnis parsen. SNMP habe ich wegen der komplexen Umsetzung verworfen; ich wollte schnell ein Ergebnis haben. Mit SNMP müsste man lange in MIB herumgraben und auf dieser Grundlage die Schnittstellendaten erstellen. Es gibt einen wunderbaren Befehl in CISCO.

show interface status

Es zeigt genau das, was ich für Cross-Referenzen benötige. Warum sich mit SNMP quälen, wenn ich einfach die Ausgabe dieses Befehls sehen möchte, dachte ich. Nach einiger Zeit habe ich diese Möglichkeit umgesetzt. Ich klickte auf das Objekt auf der Webseite. Ein Ereignis wurde ausgelöst, woraufhin der Client via AJAX den Server ansprach, der sich dann per SSH mit dem benötigten Switch verband (die Zugangsdaten waren im Code festgelegt, ich wollte keine separate Menüführung erstellen, um die Anmeldeinformationen über die Benutzeroberfläche zu ändern, ich brauchte schnell Ergebnisse) und den oben genannten Befehl eingab, um die Daten an den Browser zurückzugeben. So konnte ich mit einem Klick die Informationen zu den Schnittstellen sehen. Das war äußerst praktisch, besonders wenn ich diese Informationen gleichzeitig auf mehreren Switches einsehen musste.

Die Überwachung der Kanäle basierend auf Tracings erwies sich letztendlich nicht als die beste Idee, da manchmal Wartungsarbeiten am Netzwerk durchgeführt wurden und sich das Tracing ändern konnte, wodurch die Überwachung mich alarmierte, dass es Probleme mit dem Kanal gibt. Nach viel Zeit, die ich mit der Analyse verbrachte, stellte ich fest, dass alle Kanäle funktionierten, während meine Überwachung mir einen Streich spielte. Letztendlich bat ich Kollegen, die für die kanalbildenden Switches verantwortlich waren, mir einfach die Syslogs zu schicken, wenn sich der Zustand der Nachbarn (Neighbor) änderte. Das war entsprechend viel einfacher, schneller und wahrheitsgemäßer als das Tracing. Wenn eine Benachrichtigung wie 'Neighbor lost' eintraf, konnte ich sofort eine Warnung über den Ausfall des Kanals auslösen.

Darüber hinaus wurden Klick-Reports für die Objekte hinzugefügt sowie SNMP zur Sammlung einiger Metriken integriert, und damit war es im Großen und Ganzen auch schon alles. Die Systementwicklung ging nicht weiter. Es hat alles getan, was ich brauchte, es war ein nützliches Werkzeug. Viele Leser werden mir wahrscheinlich sagen, dass es dafür bereits eine Menge Software im Internet gibt. Aber tatsächlich konnte ich damals keine kostenlosen Produkte finden, und ich wollte unbedingt meine Programmierfähigkeiten weiterentwickeln. Was könnte da besser dazu anregen als eine konkrete praktische Aufgabe? So wurde die erste Version des Monitorings abgeschlossen und nicht weiter modifiziert.

Gründung des Unternehmens Audit-Telekom

Im Laufe der Zeit begann ich, parallel in anderen Unternehmen zu arbeiten, da mir mein Arbeitszeitplan dies erlaubte. Wenn man in verschiedenen Firmen arbeitet, entwickelt sich das Wissen in verschiedenen Bereichen sehr schnell und der Horizont erweitert sich. Es gibt Unternehmen, in denen man, um es mit einem Sprichwort zu sagen, sowohl Schneider, als auch Erntearbeiter und Spieler ist. Einerseits ist das herausfordernd, andererseits kann man, wenn man sich anstrengt, ein vielseitiger Spezialist werden, was es einem ermöglicht, Aufgaben schneller und effektiver zu lösen, da man versteht, wie angrenzende Bereiche funktionieren.

Mein Freund Pawel (auch ein IT-Spezialist) hat ständig versucht, mich zu ermutigen, ein eigenes Unternehmen zu gründen. Es gab unzählige Ideen mit verschiedenen Ansätzen für eigene Geschäfte. Das wurde über viele Jahre diskutiert. Letztendlich sollte es jedoch zu nichts führen, da ich skeptisch bin und Pawel ein Träumer. Jedes Mal, wenn er eine Idee vorschlug, glaubte ich nicht daran und lehnte eine Teilnahme ab. Aber wir hatten so sehr den Wunsch, unser eigenes Geschäft zu eröffnen.

Endlich konnten wir eine Lösung finden, die uns beide zufriedenstellt, und uns auf das konzentrieren, was wir am besten können. Im Jahr 2016 haben wir beschlossen, ein IT-Unternehmen zu gründen, das Unternehmen bei der Lösung von IT-Herausforderungen unterstützt. Dazu gehören die Implementierung von IT-Systemen (1C, Terminalserver, Mailserver usw.), deren Wartung, klassischer Helpdesk für Benutzer und Netzwerkadministration.

Offen gesagt, als ich das Unternehmen gründete, hatte ich nicht an den Erfolg geglaubt – ich war mir zu 99,9 % sicher. Aber irgendwie schaffte es Pavel, mich dazu zu bringen, es auszuprobieren, und um es vorwegzunehmen, er hatte recht. Pavel und ich haben jeweils 300.000 Rubel beigesteuert, ein neues Unternehmen, "Audit-Telekom", gegründet, ein kleines Büro gemietet, coole Visitenkarten gemacht – kurz gesagt, wie wahrscheinlich die meisten unerfahrenen, neu gegründeten Unternehmer, und begannen, nach Kunden zu suchen. Die Suche nach Kunden ist an sich schon eine eigene Geschichte. Möglicherweise werden wir einen separaten Artikel in unserem Unternehmensblog darüber schreiben, wenn es jemanden interessiert. Kaltakquise, Flyer und so weiter. Das brachte keine Ergebnisse. Wie ich jetzt aus vielen Businessgeschichten lese, hängt vieles irgendwie vom Glück ab. Wir hatten Glück, und nur wenige Wochen nach der Gründung der Firma wandte sich mein Bruder Vladimir an uns und brachte unseren ersten Kunden. Ich möchte nicht mit Details über die Arbeit mit Kunden langweilen; der Artikel handelt nicht davon. Ich will nur sagen, dass wir zur Prüfung fuhren, kritische Punkte identifizierten, und diese Punkte brachen zusammen, während die Entscheidung getroffen wurde, ob wir als Outsourcing-Partner auf längere Sicht zusammenarbeiten wollten. Daraufhin wurde sofort eine positive Entscheidung getroffen.

Im Zuge des persönlichen Netzwerks und durch Empfehlungen tauchten zunehmend andere Unternehmen im Servicebereich auf. Der Helpdesk war in einem System. Die Verbindungen zu Netzwerkgeräten und Servern waren in einem anderen, je nachdem wer wie arbeitete. Manche speicherten Verknüpfungen, andere nutzten RDP-Adressbücher. Das Monitoring war ein weiteres separates System. Es ist sehr unpraktisch für das Team, in verschiedenen Systemen zu arbeiten. Wichtige Informationen gehen dabei verloren. Zum Beispiel, wenn der Terminalserver eines Kunden nicht mehr verfügbar ist. Sofort kommen Anfragen von den Nutzern dieses Kunden. Der Supportmitarbeiter erstellt ein Ticket (es kam per Telefon). Wären Vorfälle und Anfragen in einem einzigen System registriert, könnte der Supportmitarbeiter sofort sehen, wo das Problem beim Nutzer liegt und ihm darüber informieren, während er gleichzeitig die Verbindung zum betroffenen System herstellt, um die Situation zu klären. Alle sind über die taktische Lage informiert und arbeiten reibungslos zusammen. Wir haben kein System gefunden, das all dies vereint. Es wurde klar, dass es an der Zeit war, unser eigenes Produkt zu entwickeln.

Fortsetzung der Arbeit an unserem Überwachungssystem

Es war offensichtlich, dass das zuvor entwickelte System überhaupt nicht für die aktuellen Aufgaben geeignet war. Weder in Bezug auf Funktionalität noch auf Qualität. Daher wurde entschieden, das System von Grund auf neu zu entwickeln. Grafisch sollte es ganz anders aussehen. Es sollte ein hierarchisches System sein, damit man die benötigten Objekte für den jeweiligen Kunden schnell und bequem öffnen konnte. Das Schema der ersten Version war in diesem Fall absolut nicht gerechtfertigt, da die Kunden unterschiedlich sind und es keine Rolle spielte, in welchen Räumen die Geräte stehen. Dies war bereits in die Dokumentation überführt worden.

Die Aufgaben sind:

  1. Hierarchische Struktur;
  2. Eine Art Serverkomponente, die beim Kunden in Form einer virtuellen Maschine platziert werden kann, um die benötigten Metriken zu sammeln und an einen zentralen Server zu senden, der alles aggregiert und uns anzeigt;
  3. Benachrichtigungen. Solche, die man nicht übersehen kann, da es zu diesem Zeitpunkt keine Möglichkeit gab, dass jemand nur auf den Monitor schaut;
  4. Ein Ticketsystem. Es begannen Kunden aufzutauchen, bei denen wir nicht nur Server- und Netzwerkausrüstung, sondern auch Arbeitsstationen betreuten;
  5. Die Möglichkeit, sich schnell mit Servern und Hardware aus dem System zu verbinden;

Die Aufgaben wurden festgelegt, wir beginnen mit dem Schreiben. Gleichzeitig bearbeiten wir Anfragen von Kunden. Zu diesem Zeitpunkt waren wir bereits zu viert. Wir fingen an, beide Teile und den zentralen Server sowie den Server für die Installation beim Kunden sofort zu schreiben. Zu diesem Zeitpunkt war Linux uns bereits vertraut, und wir hatten entschieden, dass die virtuellen Maschinen, die bei den Kunden stehen würden, auf Debian basieren würden. Es wird keine Installer geben, wir werden einfach das Projekt der Serverkomponente auf einer bestimmten virtuellen Maschine erstellen und dann einfach an den jeweiligen Kunden klonen. Das war ein weiterer Fehler. Später wurde klar, dass in solch einem Schema der Mechanismus für Updates überhaupt nicht durchdacht war. D.h., wir fügten eine neue Funktion hinzu, und dann gab es ein großes Problem, diese auf alle Kundenserver zu verbreiten, aber dazu später mehr, alles der Reihe nach.

Wir haben den ersten Prototyp erstellt. Dieser konnte die benötigten Netzgeräte der Kunden und Server anpingen und diese Daten an unseren zentralen Server senden. Dieser aktualisierte wiederum diese Daten in der Gesamtheit auf dem zentralen Server. Ich werde hier nicht nur die Geschichte erzählen, wie und was gelungen ist, sondern auch welche dilettantischen Fehler gemacht wurden und wie viel Zeit wir später dafür aufwenden mussten. Also, der gesamte Objektbaum wurde in einer einzigen Datei als serialisiertes Objekt gespeichert. Solange wir der System einige Kunden angeschlossen hatten, lief alles mehr oder weniger normal, auch wenn manchmal unerklärliche Artefakte auftraten. Doch als wir ein Dutzend Server an das System anschlossen, geschahen Wunder. Manchmal verschwanden alle Objekte im System einfach, ohne dass der Grund klar war. Es ist wichtig zu beachten, dass die Server, die bei den Kunden waren, alle paar Sekunden Daten an den zentralen Server über POST-Anfragen schickten. Aufmerksame Leser und erfahrene Programmierer werden bereits erraten haben, dass es ein Problem mit dem gleichzeitigen Zugriff auf die Datei gab, in der das serialisierte Objekt aus verschiedenen Threads gespeichert war. Und genau dann traten die Wunder mit dem Verschwinden der Objekte auf. Die Datei wurde einfach leer. Doch dies wurde nicht sofort erkannt, sondern erst im Verlauf des Betriebs mit mehreren Servern. In dieser Zeit wurde ein Funktionalität zum Scannen der Ports hinzugefügt (die Server schickten an den Zentralen nicht nur Informationen über die Erreichbarkeit der Geräte, sondern auch über die offenen Ports). Dies geschah durch den Aufruf des Befehls:

$connection = @fsockopen($ip, $port, $errno, $errstr, 0.5);

Die Ergebnisse waren oft ungenau und das Scannen dauerte sehr lange. Ganz zu schweigen vom Ping, der über fping lief:

system("fping -r 3 -t 100 {$this->ip}");

Dies war ebenfalls nicht parallelisiert, sodass der Prozess sehr lange dauerte. Später wurde bei fping die gesamte Liste der zu überprüfenden IP-Adressen auf einmal übergeben, und wir erhielten zurück eine fertige Liste derer, die geantwortet haben. Im Gegensatz zu uns konnte fping Prozesse parallelisieren.

Eine weitere häufige Routineaufgabe war die Konfiguration von Diensten über das WEB. Zum Beispiel das ECP von MS Exchange. Im Grunde genommen ist das nur ein Link. Wir haben daher beschlossen, dass wir solche Links direkt im System hinzufügen sollten, um nicht in der Dokumentation oder irgendwo in Lesezeichen nach dem Zugang zu ECP eines bestimmten Kunden suchen zu müssen. So entstand das Konzept der RessourcenkLinks für das System, deren Funktionalität bis heute verfügbar ist und fast keine Änderungen erfahren hat.

Die Funktionsweise der RessourcenkLinks in Veliam
Vom Outsourcing zur Entwicklung (Teil 1)

Remote-Verbindungen

So sieht es in der aktuellen Version von Veliam in der Praxis aus
Vom Outsourcing zur Entwicklung (Teil 1)

Eine der Herausforderungen war die schnelle und bequeme Verbindung zu den bereits zahlreichen Servern (es sind bereits mehrere hundert), wobei es äußerst unpraktisch war, Millionen vorab gespeicherter RDP-Verknüpfungen durchzusehen. Ein Werkzeug war erforderlich. Im Internet gibt es Software, die so etwas wie ein Adressbuch für solche RDP-Verbindungen darstellt, aber diese sind nicht in das Überwachungssystem integriert, und Konten können nicht gespeichert werden. Jedes Mal die Kontodaten für verschiedene Kunden einzugeben, ist ein wahrer Albtraum, wenn man täglich Dutzende von Verbindungen zu unterschiedlichen Servern herstellt. Bei SSH sieht es etwas besser aus; es gibt viele gute Programme, die die Möglichkeit bieten, solche Verbindungen in Ordnern zu organisieren und die Zugangsdaten zu speichern. Doch es gibt zwei Probleme. Erstens: Für RDP- und SSH-Verbindungen haben wir kein einheitliches Programm gefunden. Zweitens: Wenn ich zu einem bestimmten Zeitpunkt nicht an meinem Computer bin und schnell eine Verbindung herstellen muss oder einfach das System neu installiert habe, muss ich in die Dokumentation gehen, um die Kontodaten dieses Kunden zu überprüfen. Das ist unpraktisch und eine reine Zeitverschwendung.

Die benötigte hierarchische Struktur für die Server unserer Kunden war bereits in unserem internen Produkt vorhanden. Es musste nur überlegt werden, wie man schnelle Verbindungen zur benötigten Hardware herstellen kann. Für den Anfang wenigstens innerhalb des eigenen Netzwerks.

Da der Client in unserem System ein Browser war, der keinen Zugriff auf lokale Ressourcen des Computers hatte, um einfach eine Anwendung mit einem bestimmten Befehl zu starten, wurde die Idee entwickelt, alles über das „Windows custom url scheme“ zu realisieren. So entstand eine Art „Plugin“ für unser System, das einfach Putty und Remote Desktop Plus beinhaltete und bei der Installation die URI-Schemata in Windows registrierte. Jetzt, wenn wir uns mit einem Objekt über RDP oder SSH verbinden wollten, klickten wir diese Aktion in unserem System an, und das Custom URI funktionierte. Es wurde der Standard mstsc.exe, der in Windows integriert ist, oder putty gestartet, das Teil des „Plugins“ war. Ich setze das Wort Plugin in Anführungszeichen, da es sich nicht um ein klassisches Browser-Plugin handelt.

Das war zumindest etwas. Ein nützliches Adressbuch. Im Fall von Putty war alles sogar sehr gut, da man als Eingabeparameter sowohl die IP-Adresse als auch den Benutzernamen und das Passwort angeben konnte. Das heißt, zu den Linux-Servern in unserem Netzwerk konnten wir uns mit nur einem Klick ohne Eingabe von Passwörtern verbinden. Aber mit RDP ist es nicht so einfach. In das Standard-mstsc können keine Anmeldedaten als Parameter eingegeben werden. Da kam Remote Desktop Plus zur Hilfe. Es ermöglichte dies. Momentan kommen wir ohne es aus, aber lange Zeit war es ein treuer Helfer in unserem System. Bei HTTP(S)-Webseiten war alles einfach, solche Objekte öffneten sich einfach im Browser und das war's. Praktisch und bequem. Aber das war nur Glück in unserem internen Netzwerk.

Da die überwiegende Mehrheit der Probleme remote aus dem Büro gelöst wurde, war es am einfachsten, VPNs zu den Kunden einzurichten. So konnte man sich auch aus unserem System zu ihnen verbinden. Dennoch war es etwas unpraktisch. Für jeden Kunden musste man auf jedem Computer eine Menge gespeicherter Verbindungen haben. VPN Verbindungen und bevor man sich mit irgendetwas verbindet, musste man das entsprechende VPN aktivieren. Mit dieser Lösung haben wir eine lange Zeit gearbeitet. Doch die Anzahl der Kunden steigt, die Anzahl der VPNs ebenfalls und das alles begann, problematisch zu werden, sodass wir etwas unternehmen mussten. Besonders tränt es einem die Augen nach der Neuinstallation des Systems, wenn man Dutzende von VPN-Verbindungen in ein neues Windows-Profil erneut eingeben muss. Das kann ich nicht länger ertragen, sagte ich, und begann darüber nachzudenken, was wir dagegen tun können.

Es hat sich so ergeben, dass alle Kunden als Router Geräte einer bekannten Marke, Mikrotik, verwendeten. Sie sind sehr funktional und praktisch für nahezu jede Aufgabe. Ein Nachteil ist, dass sie „entführt“ werden. Dieses Problem haben wir einfach gelöst, indem wir allen externen Zugriff gesperrt haben. Aber wir mussten irgendwie Zugang zu ihnen haben, ohne zum Kunden fahren zu müssen, da das zeitaufwendig ist. Wir haben einfach zu jedem solchen Mikrotik Tunnel eingerichtet und sie in einen separaten Pool zusammengefasst, ohne irgendeine Routing, um eine Verbindung unserer eigenen Netzwerke mit den Netzwerken der Kunden und deren Netzwerken untereinander zu vermeiden.

Die Idee entstand, ein System zu entwickeln, bei dem der zentrale Überwachungsserver, nachdem ich auf das gewünschte Objekt geklickt habe, mit den SSH-Zugangsdaten aller Client-Mikrotiks zu den entsprechenden Geräten verbindet und eine Portweiterleitung zu einem bestimmten Host mit dem benötigten Port einrichtet. Hier gibt es jedoch mehrere Punkte zu beachten. Diese Lösung ist nicht universell – sie funktioniert nur für Mikrotik, da die Befehlsyntax bei allen Routern unterschiedlich ist. Außerdem mussten solche Weiterleitungen später irgendwie wieder gelöscht werden, und der serverseitige Teil unseres Systems konnte im Grunde nicht nachverfolgen, ob ich meine RDP-Session beendet hatte. Zudem stellt eine solche Weiterleitung ein Sicherheitsrisiko für den Kunden dar. Außerdem waren wir nicht auf Universallösungen aus, da das Produkt nur innerhalb unseres Unternehmens verwendet wurde und es keinerlei Überlegungen gab, es öffentlich zugänglich zu machen.

Jedes der Probleme wurde auf seine eigene Weise gelöst. Als die Regel erstellt wurde, war diese Portweiterleitung nur für eine bestimmte externe IP-Adresse verfügbar (von der die Verbindung initiiert wurde). So konnten Sicherheitslücken vermieden werden. Bei jeder solchen Verbindung wurde jedoch eine Regel im MikroTik zur NAT-Seite hinzugefügt und nicht entfernt. Jeder weiß, dass je mehr Regeln dort sind, desto stärker die CPU des Routers belastet wird. Außerdem konnte ich es nicht akzeptieren, dass ich einmal auf einen MikroTik zugreife und dort Hunderte von überflüssigen, nicht benötigten Regeln finde.

Wenn unser Server den Verbindungsstatus nicht überprüfen kann, soll MikroTik dies selbst tun. Und ich habe ein Skript geschrieben, das ständig alle Portweiterleitungsregeln mit einer bestimmten Beschreibung überwacht und prüft, ob es eine passende TCP-Verbindung gibt. Wenn eine solche Regel längere Zeit nicht mehr vorhanden war, war die Verbindung wahrscheinlich bereits beendet und die Portweiterleitung konnte entfernt werden. Es hat alles gut funktioniert, das Skript lief einwandfrei.

Übrigens, hier ist es:

global atmonrulecounter {"dontDelete"="dontDelete"}
:foreach i in=[/ip firewall nat find comment~"atmon_script_main"] do={ 
	local dstport [/ip firewall nat get value-name="dst-port" $i]
	local dstaddress [/ip firewall nat get value-name="dst-address" $i]
	local dstaddrport "$dstaddress:$dstport"
	#log warning message=$dstaddrport
	local thereIsCon [/ip firewall connection find dst-address~"$dstaddrport"]
	if ($thereIsCon = "") do={
		set ($atmonrulecounter->$dstport) ($atmonrulecounter->$dstport + 1)
		#:log warning message=($atmonrulecounter->$dstport)
		if (($atmonrulecounter->$dstport) > 5) do={
			#log warning message="Removing nat rules added automaticaly by atmon_script"
			/ip firewall nat remove [/ip firewall nat find comment~"atmon_script_main_$dstport"]
			/ip firewall nat remove [/ip firewall nat find comment~"atmon_script_sub_$dstport"]
			set ($atmonrulecounter->$dstport) 0
		}
	} else {
		set ($atmonrulecounter->$dstport) 0
	}
}

Es wäre sicherlich möglich gewesen, es schöner, schneller etc. zu gestalten, aber es funktionierte, belastete die Mikrotiks nicht und erfüllte seinen Zweck hervorragend. Wir konnten endlich mit nur einem Mausklick auf die Server und Netzwerkausrüstung der Kunden zugreifen, ohne ein VPN aufzubauen oder Passwörter einzugeben. Mit diesem System war die Arbeit wirklich sehr bequem. Die Wartungszeit wurde verkürzt, und wir konnten unsere Zeit mit der Arbeit verbringen, anstatt uns mit dem Zugang zu den benötigten Objekten zu beschäftigen.

Mikrotik-Backup

Wir hatten ein Backup aller Mikrotiks auf FTP eingerichtet. Insgesamt lief alles gut. Aber als es nötig war, das Backup abzurufen, musste ich diesen FTP öffnen und dort suchen. Das System, in dem alle Router verwaltet werden, haben wir, und wir können mit den Geräten über SSH kommunizieren. Warum sollten wir nicht so vorgehen, dass das System täglich automatisch von allen Mikrotiks Backups abholt, dachte ich. Und ich begann mit der Umsetzung. Wir haben uns verbunden, ein Backup erstellt und es in den Speicher übernommen.

PHP-Skript zum Erstellen eines Backups von Mikrotik:

<?php

	$IP = '0.0.0.0';
	$LOGIN = 'admin';
	$PASSWORD = '';
	$BACKUP_NAME = 'test';

    $connection = ssh2_connect($IP, 22);

    if (!ssh2_auth_password($connection, $LOGIN, $PASSWORD)) exit;

    ssh2_exec($connection, '/system backup save name="atmon" password="atmon"');
    stream_get_contents($connection);
    ssh2_exec($connection, '/export file="atmon.rsc"');
    stream_get_contents($connection);
    sleep(40); // Waiting backup makes

    $sftp = ssh2_sftp($connection);

    // Download backup file
    $size = filesize("ssh2.sftp://$sftp/atmon.backup");
    $stream = fopen("ssh2.sftp://$sftp/atmon.backup", 'r');
    $contents = '';
    $read = 0;
    $len = $size;
    while ($read < $len && ($buf = fread($stream, $len - $read))) {
        $read += strlen($buf);
        $contents .= $buf;
    }
    file_put_contents ($BACKUP_NAME . '.backup',$contents);
    @fclose($stream);

    sleep(3);
    // Download RSC file
    $size = filesize("ssh2.sftp://$sftp/atmon.rsc");
    $stream = fopen("ssh2.sftp://$sftp/atmon.rsc", 'r');
    $contents = '';
    $read = 0;
    $len = $size;
    while ($read

Backups are created in two forms — binary and text configuration. The binary version helps to quickly restore the required configuration, while the text version allows for understanding what needs to be done in case of an forced equipment replacement when the binary cannot be uploaded. As a result, we have gained another convenient functionality in the system. Moreover, when adding new MikroTik devices, no setup was required; you simply add the object to the system and specify the SSH credentials. The system then automatically handled the backup process. This functionality is not available in the current version of SaaS Veliam, but we will port it soon.

Screenshots of how it looked in the internal system
Vom Outsourcing zur Entwicklung (Teil 1)

Transition to proper storage in the database

Ich habe bereits erwähnt, dass Artefakte auftraten. Manchmal verschwand die gesamte Objektliste im System, manchmal wurde beim Bearbeiten eines Objekts die Information nicht gespeichert, und ich musste das Objekt dreimal umbenennen. Das hat alle schrecklich genervt. Das Verschwinden von Objekten geschah selten und ließ sich leicht durch die Wiederherstellung der Datei beheben, aber die Fehler beim Bearbeiten von Objekten passierten häufig. Wahrscheinlich habe ich das ursprünglich nicht über die Datenbank gemacht, weil ich mir nicht vorstellen konnte, wie man einen Baum mit all seinen Verbindungen in einer flachen Tabelle hält. Die Tabelle ist flach, der Baum ist hierarchisch. Aber eine gute Lösung für den gleichzeitigen Zugriff und später (bei der Komplexität des Systems) für Transaktionen ist eine Datenbank. Ich bin sicherlich nicht der erste, der auf dieses Problem gestoßen ist. Ich habe gegoogelt. Es stellte sich heraus, dass alles bereits vor mir erdacht wurde, und es gibt mehrere Algorithmen, die einen Baum aus einer flachen Tabelle erstellen. Nachdem ich mir jeden angesehen hatte, habe ich einen von ihnen implementiert. Aber das war bereits die neue Version des Systems, da ich im Grunde wegen dieses Problems viel neu programmieren musste. Das Ergebnis war eindeutig, die Probleme mit dem zufälligen Verhalten des Systems verschwanden. Manche mögen sagen, die Fehler seien ziemlich amateurhaft (einzelne Skripte, Speicherung von Informationen, auf die mehrfacher gleichzeitiger Zugriff aus verschiedenen Threads bestand, in einer Datei usw.) im Bereich der Softwareentwicklung. Vielleicht stimmt das, aber meine Hauptaufgabe war die Administration, und Programmieren war ein Hobby, und ich hatte einfach keine Erfahrung in der Zusammenarbeit mit Programmierern, wo mir solche elementaren Dinge sofort von erfahreneren Kollegen erklärt worden wären. Deshalb habe ich all diese Fehler selbst gemacht, aber ich habe das Material sehr gut verstanden. Außerdem umfasst mein Tätigkeitsbereich auch Treffen mit Kunden, Aktivitäten zur Förderung des Unternehmens und eine Menge administrativer Fragen innerhalb des Unternehmens und vieles mehr. Aber wie dem auch sei, das, was da war, war gefragt. Die Jungs und ich selbst haben das Produkt im Alltag verwendet. Es gab sowohl offensichtlich gescheiterte Ideen als auch Lösungen, für die Zeit aufgewendet wurde, und schließlich wurde klar, dass es sich um ein nicht funktionsfähiges Werkzeug handelte, das niemand benutzte und das nicht in Veliam implementiert wurde.

Kundendienst — HelpDesk

Es ist erwähnenswert, wie HelpDesk entstand. Das ist überhaupt eine eigene Geschichte, denn bei Veliam handelt es sich bereits um die dritte völlig neue Version, die sich von allen vorherigen unterscheidet. Jetzt ist es ein einfaches, intuitives System ohne überflüssige Spielereien und mit der Möglichkeit, sich mit der Domain zu integrieren. Außerdem besteht die Möglichkeit, auf dasselbe Benutzerprofil von überall aus über den Link in der E-Mail zuzugreifen. Und das Wichtigste ist, dass man sich von jedem Ort (ob zu Hause oder im Büro) direkt über VNC mit dem Antragssteller verbinden kann, ohne VPN oder Portweiterleitungen. Ich werde erzählen, wie wir dazu gekommen sind, was zuvor war und welche katastrophalen Lösungen es gab.

Wir haben uns über das bekannte TeamViewer mit den Nutzern verbunden. Auf allen Computern der Benutzer, die wir betreuen, war TV installiert. Das erste, was wir falsch gemacht haben und später entfernt haben, war die Hardwarebindung jedes Kunden-HWID. Wie kam der Benutzer in das HWID-System, um eine Anfrage zu stellen? Neben TV wurde auf den Computern eine spezielle, in Lazarus geschriebene Utility installiert (hier werden viele die Augen rund machen und vielleicht sogar googeln, was das ist, aber von allen kompilierbaren Sprachen kannte ich Delphi am besten, und Lazarus ist fast das gleiche, nur kostenlos). Also startete der Benutzer ein spezielles Batch-Skript, das diese Utility öffnete, welche die HWID des Systems las und daraufhin der Browser gestartet wurde, um die Authentifizierung durchzuführen. Warum wurde das gemacht? In einigen Firmen wird die Anzahl der betreuten Nutzer einzeln gezählt, und der Preis für die Betreuung wird anhand der Anzahl der Personen pro Monat festgelegt. Das versteht ihr, aber warum die Hardwarebindung? Ganz einfach: Einige Personen kamen nach Hause und stellten von ihrem Laptop aus eine Anfrage mit dem Stil „Macht mir alles schön hier“. Neben der HWID-Auslesung zog die Utility auch die aktuelle TeamViewer-ID aus der Registry und übermittelte sie uns. TeamViewer hat eine API zur Integration. Und wir haben diese Integration umgesetzt. Aber es gab einen Haken. Über diese APIs kann man sich nicht mit dem Computer des Benutzers verbinden, wenn er die Sitzung nicht eindeutig selbst initiiert, und nach dem Versuch, sich mit ihm zu verbinden, muss er auch noch „bestätigen“. Zu diesem Zeitpunkt schien es uns logisch, dass sich niemand ohne Erlaubnis des Benutzers verbinden sollte, und wenn eine Person am Computer ist, initiiert sie die Sitzung und antwortet positiv auf die Anfrage zur Remote-Verbindung. Es stellte sich jedoch als ganz anders heraus. Antragsteller vergaßen, die Sitzung zu initiieren, und wir mussten ihnen in Telefonaten sagen, dass sie das tun sollten. Das kostete Zeit und nervte beide Parteien. Außerdem war es keineswegs selten, dass eine Person eine Anfrage hinterlässt, aber die Verbindung nur dann erlaubt, wenn sie zum Mittagessen geht. Denn das Problem ist nicht kritisch und sie möchte nicht, dass ihr Arbeitsablauf unterbrochen wird. Dementsprechend wird sie keinen Knopf drücken, um die Verbindung zu erlauben. So entstand eine zusätzliche Funktion bei der Authentifizierung im HelpDesk — das Auslesen der TeamViewer-ID. Wir kannten das permanente Passwort, das bei der Installation von TeamViewer verwendet wurde. Genauer gesagt, das wusste nur das System, da es im Installer und in unserem System eingebettet war. Daher gab es einen Verbindungsknopf in der Anfrage, auf den man drücken konnte, ohne warten zu müssen, und direkt TeamViewer öffnete und die Verbindung hergestellt wurde. Schlussendlich gab es zwei Arten der möglichen Verbindungen. Über die offizielle TeamViewer-API und unsere Eigenlösung. Zu meinem Erstaunen hörten die Leute fast sofort auf, die erste zu benutzen, obwohl es einen Hinweis gab, diese nur in besonderen Fällen und wenn der Benutzer selbst dafür sein Einverständnis gibt, zu verwenden. Sicherheit war schließlich ein großes Thema. Aber es stellte sich heraus, dass die Antragsteller das nicht brauchten. Sie hatten absolut kein Problem damit, dass sich jemand ohne Bestätigungsschaltfläche mit ihnen verbindet. Und da es so war, wurde die Funktionalität der Verbindung über die API aus Gründen der Unnötigkeit eingestellt.

Wechsel zu Multithreading in Linux

Die Frage nach der Beschleunigung des Netzwerk-Scans hinsichtlich der Offenheit einer im Voraus bestimmten Liste von Ports sowie einfachem Ping von Netzwerkobjekten drängte sich schon lange auf. Die erste Idee, die dabei in den Sinn kommt, ist Multithreading. Die meiste Zeit, die für das Pingen aufgebracht wird, besteht im Warten auf die Rückkehr des Pakets, und der nächste Ping kann nicht beginnen, bis das vorherige Paket zurückgekehrt ist. In Unternehmen mit über 20 Servern plus Netzwerkgeräten kann sich dies bereits als ziemlich langsam herausstellen. Das Problem ist, dass ein Paket möglicherweise verloren gehen kann, und der Systemadministrator sollte darüber nicht sofort informiert werden. Er wird einfach solchen Spam sehr schnell ignorieren. Das bedeutet, dass jeder Gegenstand mindestens mehrmals geprüft werden muss, bevor man zu dem Schluss kommt, dass er nicht erreichbar ist. Um es nicht zu sehr ins Detail zu vertiefen, muss parallelisiert werden, denn wenn dies nicht geschieht, wird der Systemadministrator wahrscheinlich von einem Kunden über das Problem erfahren, anstatt von dem Überwachungssystem.

PHP selbst unterstützt von Haus aus keine Multithreading. Es ermöglicht allerdings Multiprocessing, man kann forken. Ich hatte bereits einen Mechanismus zur Abfrage geschrieben und wollte es so gestalten, dass ich einmal alle benötigten Knoten aus der Datenbank lese, alle gleichzeitig pinge, auf die Antwort von jedem warte und erst danach die Daten schreibe. Das spart bei der Anzahl der Leseanfragen. In diese Idee passte das Multithreading hervorragend. Für PHP gibt es das Modul PThreads, das echtes Multithreading ermöglicht. Ich musste jedoch ziemlich viel Zeit investieren, um es für PHP 7.2 einzurichten, aber die Aufgabe wurde erledigt. Das Scannen von Ports und das Pingen wurden schnell. Anstelle von beispielsweise 15 Sekunden für einen Durchlauf benötigte dieser Prozess nur noch 2 Sekunden. Das war ein gutes Ergebnis.

Schnelles Audit neuer Unternehmen

Wie ist die Funktionalität zur Sammlung verschiedener Metriken und Hardwaremerkmale entstanden? Ganz einfach. Manchmal werden wir einfach mit einer Auditerstellung der aktuellen IT-Infrastruktur beauftragt. Und das Gleiche ist notwendig, um die Überprüfung eines neuen Kunden zu beschleunigen. Es musste etwas entwickelt werden, das uns ermöglicht, in ein mittelständisches oder großes Unternehmen zu gehen und schnell zu erkennen, was überhaupt vorhanden ist. Ping in internen Netzwerken wird meiner Meinung nach nur von denen blockiert, die sich das Leben selbst erschweren wollen, und nach unserer Erfahrung gibt es nur wenige von ihnen. Aber es gibt sie. Dementsprechend kann man die Netzwerke schnell auf vorhan-dene Geräte mit einem einfachen Ping scannen. Danach kann man sie hinzufügen und auf offene Ports scannen, die uns interessieren. Im Grunde genommen war diese Funktionalität bereits vorhanden, es musste nur ein Befehl vom zentralen Server an den untergeordneten Server hinzugefügt werden, damit dieser die angegebenen Netzwerke scannt und alles, was er findet, zur Liste hinzufügt. Ich habe vergessen zu erwähnen, dass davon ausgegangen wurde, dass wir bereits ein fertiges Image mit einem konfigurierten System (untergeordneter Überwachungsserver) haben, das wir einfach beim Kunden während des Audits bereitstellen und an unsere Cloud anschließen konnten.

Das Ergebnis eines Audits umfasst in der Regel eine Vielzahl unterschiedlicher Informationen, und eine davon ist – welche Geräte sich im Netzwerk befinden. Zunächst interessierten uns Windows-Server und Windows-Workstations innerhalb der Domäne. In mittelständischen und großen Unternehmen ist das Fehlen einer Domäne wahrscheinlich die Ausnahme. Um eine gemeinsame Sprache zu sprechen, betrachte ich Unternehmen mit durchschnittlich 100+ Mitarbeitern. Es musste eine Möglichkeit gefunden werden, Daten von allen Windows-Maschinen und -Servern zu sammeln, indem man ihre IP-Adressen und das Konto des Domänenadministrators kennt, ohne dabei Software auf jedem einzelnen Rechner zu installieren. Hier kommt die WMI-Schnittstelle ins Spiel. Windows Management Instrumentation (WMI) ist wörtlich übersetzt das Instrument zur Verwaltung von Windows. WMI ist eine der grundlegenden Technologien für das zentrale Management und die Überwachung verschiedener Komponenten der Computerinfrastruktur, die unter Windows betrieben wird. Dies stammt aus Wikipedia. Anschließend musste ich erneut basteln, um das wmic (den WMI-Client) für Debian zu sammeln. Nachdem alles bereit war, musste man einfach die relevanten Nodes über wmic abfragen, um die benötigten Informationen zu erhalten. Über WMI kann man fast jede Information von einem Windows-Computer abrufen, und darüber hinaus kann man den Computer auch steuern, beispielsweise ihn neu starten. So entstand die Sammlung von Informationen über Windows-Stationen und -Server in unserem System. Zusätzlich haben wir aktuelle Informationen über die Systemauslastung. Diese fragen wir häufiger ab, während die Informationen über die Hardware seltener angefordert werden. Danach wurde das Durchführen eines Audits ein wenig angenehmer.

Entscheidung über die Verbreitung von Software

Wir nutzen das System täglich selbst, und es ist für jeden technischen Mitarbeiter zugänglich. Wir dachten, dass wir das, was bereits existiert, auch mit anderen teilen könnten. Das System war jedoch noch lange nicht bereit für die Verbreitung. Es war notwendig, viele Aspekte zu überarbeiten, damit die lokale Version zu einem SaaS wird. Dazu gehören Änderungen verschiedener technischer Aspekte in der Systemarbeit (Fernzugriffe, Kundenservice), die Analyse der Module hinsichtlich der Lizenzierung, das Sharding von Kundendatenbanken, die Skalierung jedes Dienstes und die Entwicklung von Auto-Update-Systemen für alle Teile. Aber dazu wird es einen zweiten Teil des Artikels geben.

Update

Der zweite Teil

Quelle: habr.com

Erwerben Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster