In diesem Artikel möchte ich darĂŒber sprechen, wie wir Puppet und Hiera verwenden , um Eisen- und virtuelle Server zu konfigurieren. GrundsĂ€tzlich geht es um die Architektur und die von uns erfundene Hierarchie, die die Konfiguration von Servern erleichtert und systematisiert.
Ich wurde aufgefordert, diesen Artikel zu schreiben, weil ich im Internet keine besonders guten, wirklich funktionierenden Beispiele dafĂŒr gefunden habe, wie man mit Hiera arbeiten kann und wofĂŒr es ist. GrundsĂ€tzlich handelt es sich hierbei um Tutorials mit Beispielen, um in das Thema einzutreten. Aber die wirkliche praktische Anwendung von Hiera ist dort nicht geschrieben. Vielleicht habe ich nicht gut ausgesehen, aber hier ist ein echtes Beispiel, das Ihnen wahrscheinlich helfen wird, alle Punkte ĂŒber i zu setzen, wie ich es einmal getan habe.
FĂŒr wen wĂ€re dieser Artikel nĂŒtzlich
Wenn:
- Sie wissen, was Puppet und Hiera sind, aber Sie verwenden sie nicht wirklich zusammen, da nicht klar ist, wie und warum
- Sie haben viele Teams in Ihrem Unternehmen und mĂŒssen die Serverkonfiguration auf Befehlsebene irgendwie differenzieren
- Sie verwenden ein Pappet und die Knotendateien sind unglaublich groĂ geworden
- Lesen Sie gerne die Serverkonfiguration im göttlichen Yaml-Format :)
- Sie interessieren sich grundsĂ€tzlich fĂŒr das Thema Konfigurationsmanagement und Systemadministration.
Dieser Artikel ist fĂŒr Sie.
Bevor Sie anfangen
Ich werde Sie sofort warnen, der Artikel hat sich als lang herausgestellt, aber ich hoffe, er ist nĂŒtzlich. AuĂerdem wird davon ausgegangen, dass Sie Hiera bereits mit Puppe verbunden haben und zumindest irgendwie mit Puppe vertraut sind. Wenn hiera nicht verbunden ist, ist es nicht schwierig zu tun.
Daten eingeben
- Wir haben ungefÀhr 30 Entwicklungsteams bei SEMrush, von denen jedes seine eigenen Server hat
- Jedes Team arbeitet mit seinen eigenen Technologien (PL, DBMS usw.)
- Teams können und sollten (idealerweise) eine gemeinsame Konfiguration fĂŒr bestimmte Projekte verwenden (Wiederverwendung von Code)
- Die Teams selbst verwalten die Bereitstellung von Anwendungen auf ihren Servern (dies erfolgt nicht ĂŒber das Pappet).
Ein bisschen Geschichte
Anfangs hatten wir alles im Pappet der Version 3, dann entschieden wir uns, das 4. Pappet zu implementieren, und wir begannen, alle neuen Server darin zu platzieren und die alten langsam auf das 4. zu portieren.
Im dritten Teil verwendeten wir das klassische System von Knotendateien und -modulen. Die Module wurden in einer speziellen Gruppe von Projekten in Gitlab erstellt, auf einen Pappet-Server (mit r10k ) geklont , dann kamen die Pappet-Agenten zum Assistenten und erhielten ein Verzeichnis, um es auf den Server anzuwenden.
Dann versuchten sie, dies nicht zu tun und keine lokalen Module zu verwenden, sondern stellten Links zu den erforderlichen Modulen und ihren Repositorys in das Puppetfile. Warum? Weil diese Module von der Community und den Entwicklern stĂ€ndig unterstĂŒtzt und verbessert werden (im Idealfall), und unsere lokalen Module nicht. SpĂ€ter fĂŒhrten sie hiera ein und wechselten vollstĂ€ndig dazu, und Knotendateien (wie node.pp) sind in Vergessenheit geraten.
Im vierten Teil haben wir versucht, lokale Module vollstĂ€ndig aufzugeben und nur Remote-Module zu verwenden. Leider sollte hier wieder eine Reservierung eingefĂŒgt werden, da es ânicht ganz geklappt hatâ, manchmal muss man noch etwas selbst neigen und fertigstellen. NatĂŒrlich gibt es nur Hiera und keine Knotendateien.
Wenn Sie 30 Teams mit einem Technologiezoo haben, wird das Problem, wie diese Menagerie mit> 1000 Servern gehalten werden kann, besonders akut. Weiter werde ich erzÀhlen, wie uns hiera dabei hilft.
Hierarchie
Hiera (von der es seinen Namen hat) richtet eine Hierarchie ein. Bei uns sieht es so aus:
--- :hierarchy: - "nodes/%{::fqdn}" - "teams/%{::team}_team/nodes/%{::fqdn}" - "teams/%{::team}_team/projects/%{::project}/tiers/%{::tier}" - "teams/%{::team}_team/projects/%{::project}/%{::role}" - "teams/%{::team}_team/projects/%{::project}" - "teams/%{::team}_team/roles/%{::role}" - "teams/%{::team}_team/%{::team}" - "projects/%{::project}/tiers/%{::tier}/%{::role}" - "projects/%{::project}/tiers/%{::tier}" - "projects/%{::project}/%{::role}" - "projects/%{::project}" - "tiers/%{::tier}" - "virtual/%{::virtual}" - "os/%{::operatingsystem}/%{::operatingsystemmajrelease}" - "os/%{::operatingsystem}" - users - common
Lassen Sie uns zunÀchst obskure Variablen (Fakten) behandeln.
Jeder Server in SEMrush sollte idealerweise 4 exponierte, spezielle Fakten haben, die seine Zugehörigkeit beschreiben:
team
Tatsache - zu welchem ââTeam gehört es?- Faktenprojekt - auf welches Projekt bezieht es sich?
- Rollentatsache - welche Rolle spielt dieses Projekt?
tier
Fact - Welche Art von Inszenierung hat es (Prod, Test, Dev)?
Wie funktioniert es Der Pappet-Agent kommt zum Pappet-Master und sucht anhand dieser Fakten nach Dateien fĂŒr sich selbst, wobei er die Ordner gemÀà unserer Hierarchie durchsucht. Es muss nicht angegeben werden, dass die Konfigurationsdateien zu den Servern gehören. Stattdessen wissen die Server selbst, welche Dateien ihnen gehören, und betrachten nur ihren Pfad und ihre Fakten.
WÀhrend des Server-Setups kommunizieren Administratoren mit Entwicklern und geben diese Parameter an (hÀufig wenden sich sachkundige Personen hÀufig selbst an Administratoren), um in Zukunft eine Hierarchie in Hiera zu erstellen, auf deren Grundlage dann die Serverkonfiguration beschrieben wird. Ein solches System hilft, Code wiederzuverwenden und hinsichtlich der Serverkonfiguration flexibler zu sein.
Zum Beispiel haben wir ein spezielles Projekt. In diesem Projekt gibt es möglicherweise einen Frontend-Server mit Nginx, einen Backend-Server mit Python, einen Datenbankcluster mit MySQL und einen Redis-Server fĂŒr das Caching. Alle diese Server sollten in einem Projekt namens " Special" platziert werden und dann den Servern Rollen zuweisen.
In der Projektdatei beschreiben wir die Parameter, die dem gesamten Projekt gemeinsam sind. Das erste, was mir in den Sinn kommt, ist die Erstellung auf allen Servern des Benutzers fĂŒr die Bereitstellung mit der Ausgabe der erforderlichen Rechte fĂŒr ihn und der EinfĂŒhrung seiner SSH-SchlĂŒssel.
In der Rolle fĂŒr jeden Server wird der Dienst normalerweise beschrieben und angepasst - fĂŒr das, was dieser Server beabsichtigt (Nginx, Python, MySQL usw.). In diesem Fall benötigen wir definitiv eine Stufe, wenn wir auch eine Kopie der Produktionsumgebung auf der Entwicklungsplattform bereitstellen mĂŒssen. aber Ă€ndern Sie etwas darin (Passwörter zum Beispiel). In diesem Fall unterscheiden sich der Dev-Server und der Prod-Server nur darin, dass die Ebene auf die gewĂŒnschte âPositionâ (Prod oder Dev) eingestellt ist. Und dann reicht ein bisschen Magie und Hiera.
Wenn wir zwei identische Server in derselben Rolle bereitstellen mĂŒssen, sich jedoch etwas darin unterscheiden sollte, z. B. einige Zeilen in der Konfiguration, wird ein anderer Teil der Hierarchie Abhilfe schaffen. Wir platzieren die Dateien mit dem Namen des Formats {fqdn }.yaml
an der richtigen Stelle (z. B. nodes/myserver.domain.net
), legen die erforderlichen Werte fĂŒr Variablen auf der Ebene eines bestimmten Servers fest, und das Pappet wendet fĂŒr beide Server fĂŒr die Rolle dieselbe Konfiguration an und ist fĂŒr jeden Server eindeutig von Servern.
Beispiel: Zwei Backends mit PHP-Code haben dieselbe Rolle und sind völlig identisch. Es ist klar, dass wir nicht beide Server sichern wollen - es macht keinen Sinn. Wir können eine Rolle erstellen, in der dieselbe Konfiguration fĂŒr beide Server beschrieben wird, und dann eine weitere Datei nodes/backend1.semrush.net
erstellen, in der die Konfiguration fĂŒr die Sicherung nodes/backend1.semrush.net
werden soll.
Die Batch-Datei teams/team-name.yaml
gibt die Konfiguration fĂŒr alle Server an, die zum Team gehören. In den meisten FĂ€llen werden die Benutzer beschrieben, die mit diesen Servern interagieren können, sowie ihre Zugriffsrechte.
Basierend auf diesen Variablen haben wir diese Hierarchie aufgebaut . Je höher die gefundene Datei in der Hierarchie ist, desto höher ist die PrioritÀt der darin angegebenen Konfiguration.
Daraus folgt, dass Variablen basierend auf dieser Hierarchie ĂŒberschrieben werden können. Das heiĂt, die Variable in der Rollendatei " projects/%{::project}/%{::role}
" hat Vorrang vor der Variablen in der Projektdatei " projects/%{::project}
". Variablen können auch auf allen Hierarchieebenen zusammengefĂŒhrt werden, wenn Sie ein Modul und / oder Profil / eine Rolle so geschrieben haben, dass Sie dies tun können. Durch Angabe des gemeinsamen Teils der MySQL-Konfiguration fĂŒr alle Projektserver können Sie derselben Variablen auf anderen Hierarchieebenen spezielle Teile hinzufĂŒgen, die fĂŒr diese Rolle Gewicht haben (in der Konfiguration fĂŒr den Slave wird ein zusĂ€tzlicher Abschnitt angezeigt).
Es stellt sich heraus, dass die Datei des spezifischen Knotens entlang des Pfads â hieradata/nodes/%{::fqdn}
â die höchste PrioritĂ€t hat. Als nĂ€chstes kommt die Knotendatei, aber bereits auf Befehlsebene. Unten ist der Block, der andere, allgemeinere Fakten beschreibt:
- "virtual/%{::virtual}" - "os/%{::operatingsystem}/%{::operatingsystemmajrelease}" - "os/%{::operatingsystem}" - users - common
Dementsprechend haben wir in der Datei common.yaml
eine Konfiguration, die definitiv fĂŒr alle Server gelten sollte. In der Datei users.yaml
alle Benutzer in os/%{::operatingsystem}
beschrieben (aber users.yaml
werden nicht alle auf Servern erstellt). Allgemeine Konfiguration, typisch fĂŒr Server mit einem bestimmten Betriebssystem (fact ::operatingsystem
) und so weiter.
Ich denke, wenn man diese Hierarchie betrachtet, wird alles klar. Im Folgenden werde ich ein Beispiel fĂŒr die Verwendung einer solchen Hierarchie betrachten. Aber zuerst mĂŒssen Sie ĂŒber Profile sprechen.
Profile
Ein wichtiger Punkt bei der Konfiguration von Servern mithilfe von Modulen ist die Verwendung von Profilen. Sie befinden sich auf der Pfadwebsite site/profiles
und sind die Einstiegspunkte zu den Modulen. Dank ihnen können Sie die hÀngenden Module auf dem Server genauer konfigurieren und die erforderlichen Ressourcen erstellen.
Betrachten Sie ein einfaches Beispiel. Es gibt ein Modul , das Redis installiert und konfiguriert. Und wir möchten auch den sysctl-Parameter vm.overcommit_memory
beim AnschlieĂen dieses Moduls auf 1 setzen, weil hier . Dann schreiben wir ein kleines Profil, das diese FunktionalitĂ€t bietet:
# standalone redis server class profiles::db::redis ( Hash $config = {}, String $output_buffer_limit_slave = '256mb 64mb 60', ) { # https://redis.io/topics/faq#background-saving-fails-with-a-fork-error-under-linux-even-if-i-have-a-lot-of-free-ram sysctl { 'vm.overcommit_memory': ensure => present, value => '1', } class { '::redis': * => $config, } }
Wie oben erwĂ€hnt, sind Profile ein Werkzeug, mit dem Sie das Verhalten des Moduls Ă€ndern / verbessern sowie die Anzahl der Konfigurationen in Hiera reduzieren können. Wenn Sie Remote-Module verwenden, kann hĂ€ufig das Problem auftreten, dass âgenehmigteâ Module hĂ€ufig nicht ĂŒber die von Ihnen benötigte FunktionalitĂ€t verfĂŒgen oder Fehler aufweisen. Im Prinzip können Sie dieses Modul dann klonen und Funktionen korrigieren / hinzufĂŒgen. Die richtige Entscheidung wĂ€re jedoch, wenn möglich, ein gutes Profil zu erstellen, das das Modul so âvorbereitenâ kann, wie Sie es benötigen. Im Folgenden finden Sie einige Beispiele fĂŒr Profile, mit denen Sie besser verstehen können, warum sie benötigt werden.
Geheimnisse in Hiera verstecken
Einer der wichtigen Vorteile von hiera gegenĂŒber dem nackten Pappet ist seine FĂ€higkeit, vertrauliche Daten in Konfigurationsdateien in verschlĂŒsselter Form im Repository zu speichern. Ihre Passwörter sind sicher.
Kurz gesagt, Sie verwenden den öffentlichen SchlĂŒssel, um die benötigten Informationen zu verschlĂŒsseln und mit einer solchen Zeile in die Hiera-Datei einzufĂŒgen. Der private Teil des SchlĂŒssels wird auf dem Pappet-Master gespeichert, sodass Sie diese Daten entschlĂŒsseln können. Weitere Details finden Sie auf der Projektseite .
Auf dem Client (funktionierender Computer) wird das Tool einfach mithilfe von gem install hiera-eyaml
. Mit einem Befehl der Form eyaml encrypt --pkcs7-public-key=/path/to/public_key.pkcs7.pem -s 'hello'
Sie Daten verschlĂŒsseln und in eine Datei mit der Erweiterung eyaml oder einfach yaml einfĂŒgen, je nachdem, wie Sie konfigurieren, und dann wird das Pappet es herausfinden. Sie erhalten so etwas wie:
roles::postrgresql::password: 'ENC[PKCS7,MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAbIz1ihQlThMWa9T+Lq194Y6QdElMD1XTev5y+VPSHtkPTu6Al6TJaSrXF+7phJIjue+NF4ZVtJCLkHxUR6nJJqks0fcGS1vF2+6mmM9cy69sIU1A3HqpOHZLuqHAc7jUqljYxpwWSIGOK6I2FygdAp5FfOTewqfcVVmXj97EJdcv3DKrbAlSrIMO2iZRYwQvyv+qnptnZ7pilR2veOCPW2UMm6zagDLutX9Ft5vERbdaiCiEfTOpVa9Qx0GqveNRVJLV/5lfcL5ajdNBJXkvKqDbx8d3ZBtEVAAqeKlw0LqzScgmCbWQx2kUzukX5LSxbTpT0Th984Vp1sl7iPk7UTA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCp5GcwidcEMA+0wjAMblkKgBCR/f9KGXUgLh3/Ok60OIT5]'
Oder eine mehrzeilige Zeichenfolge:
roles::postgresql::password: > ENC[PKCS7,MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEw DQYJKoZIhvcNAQEBBQAEggEAbIz1ihQlThMWa9T+Lq194Y6QdElMD1XTev5y +VPSHtkPTu6Al6TJaSrXF+7phJIjue+NF4ZVtJCLkHxUR6nJJqks0fcGS1vF 2+6mmM9cy69sIU1A3HqpOHZLuqHAc7jUqljYxpwWSIGOK6I2FygdAp5FfOTe wqfcVVmXj97EJdcv3DKrbAlSrIMO2iZRYwQvyv+qnptnZ7pilR2veOCPW2UM m6zagDLutX9Ft5vERbdaiCiEfTOpVa9Qx0GqveNRVJLV/5lfcL5ajdNBJXkv KqDbx8d3ZBtEVAAqeKlw0LqzScgmCbWQx2kUzukX5LSxbTpT0Th984Vp1sl7 iPk7UTA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCp5GcwidcEMA+0wjAM blkKgBCR/f9KGXUgLh3/Ok60OIT5]
Es scheint, dass wir mit der Vorbereitung fertig sind, jetzt können wir ein Beispiel betrachten.
Finger Beispiel
Spoiler : Es wird viel mehr Konfigurationen geben, sodass diejenigen, die sich fĂŒr diesen Artikel von rein theoretischem Interesse interessieren, diesen Abschnitt ĂŒberspringen und bis zum Ende gehen können.
Schauen wir uns nun ein Beispiel an, wie ein Server mithilfe von Hiera in Puppet4 konfiguriert wird. Ich werde den Code nicht fĂŒr alle Profile veröffentlichen, da sich der Beitrag sonst als ziemlich groĂ herausstellen wird. Ich werde mich auf die Hierarchie und Konfiguration von Hiera konzentrieren.
Die Aufgabe ist folgende: Wir mĂŒssen Folgendes bereitstellen:
- Zwei identische Datenbankserver, auf denen postgresql bereitgestellt wird
- Zwei weitere Server - Frontend mit Nginx
- FĂŒnfter und sechster Server - Python-Backends im Docker
- In der Entwicklungsumgebung ist bis auf einige Serverkonfigurationen alles gleich
Wir werden unsere Hierarchie der Reihe nach erstellen und mit der Projektdatei beginnen.
Projekt
Erstellen Sie die Projektdatei projects/kicker.yaml
. Wir fĂŒgen ein, was allen Servern gemeinsam ist: Wir benötigen einige Repositorys und Ordner fĂŒr die Bereitstellung sowie den Bereitstellungsbenutzer selbst.
--- classes: - apt::debian::semrush files: "/srv/data": ensure: 'directory' owner: 'deploy' group: 'www-data' mode: '0755' '/srv/data/shared_temp': ensure: 'directory' owner: 'deploy' group: 'www-data' mode: '0775' user_management::present: - deploy
Db Rolle
Erstellen Sie eine projects/kicker/db.yaml
Datenbankserver projects/kicker/db.yaml
. Bisher mĂŒssen wir die Server nicht in Umgebungen unterteilen:
--- classes: - profiles::db::postgresql profiles::db::postgresql::globals: manage_package_repo: true version: '10' profiles::db::postgresql::db_configs: 'listen_addresses': value: '*' profiles::db::postgresql::databases: kicker: {} profiles::db::postgresql::hba_rules: 'local connect to kicker': type: 'local' database: 'kicker' user: 'kicker' auth_method: 'md5' order: '001' 'allow connect from 192.168.1.100': type: 'host' database: 'kicker' user: 'kicker' auth_method: 'md5' address: '192.168.1.100/32' order: '002'
Hier verbinden wir ein Profil, das fĂŒr den allgemeinen Gebrauch von allen geschrieben wurde, die Postgres auf ihrem Server installieren möchten. Das Profil ist konfigurierbar und ermöglicht es Ihnen, das Modul flexibel zu konfigurieren, bevor Sie es anwenden.
FĂŒr die Neugierigsten unter dem Katzencode fĂŒr dieses Profil:
Profil :: db :: postgresql class profiles::db::postgresql ( Hash $globals = {}, Hash $params = {}, Hash $recovery = {}, Hash[String, Hash[String, Variant[String, Boolean, Integer]]] $roles = {}, Hash[String, Hash[String, Variant[String, Boolean]]] $db_configs = {}, Hash[String, Hash[String, Variant[String, Boolean]]] $databases = {}, Hash[String, String] $db_grants = {}, Hash[String, Hash[String, String]] $extensions = {}, Hash[String, String] $table_grants = {}, Hash[String, Hash[String, String]] $hba_rules = {}, Hash[String, String] $indent_rules = {}, Optional[String] $role = undef, # 'master', 'slave' Optional[String] $master_host = undef, Optional[String] $replication_password = undef, Integer $master_port = 5432, String $replication_user = 'repl', String $trigger_file = '/tmp/pg_trigger.file', ){ case $role { 'slave': { $_params = { manage_recovery_conf => true, } if $globals['datadir'] { file { "${globals['datadir']}/recovery.done": ensure => absent, } } $_recovery = { 'recovery config' => { standby_mode => 'on', primary_conninfo => "host=${master_host} port=${master_port} user=${replication_user} password=${replication_password}", trigger_file => $trigger_file, } } $_conf = { 'hot_standby' => { value => 'on', }, } file { $trigger_file: ensure => absent, } } 'master': { $_conf = { 'wal_level' => { value => 'replica', }, 'max_wal_senders' => { value => 5, }, 'wal_keep_segments' => { value => 32, }, } file { $trigger_file: ensure => present, } } default: { $_params = {} $_recovery = {} $_conf = {} } } class { '::postgresql::globals': * => $globals, } class { '::postgresql::server': * => deep_merge($_params, $params), } create_resources('::postgresql::server::config_entry', deep_merge($_conf, $db_configs)) create_resources('::postgresql::server::role', $roles) create_resources('::postgresql::server::database', $databases) create_resources('::postgresql::server::database_grant', $db_grants) create_resources('::postgresql::server::extension', $extensions) create_resources('::postgresql::server::table_grant', $table_grants) create_resources('::postgresql::server::pg_hba_rule', $hba_rules) create_resources('::postgresql::server::pg_indent_rule', $indent_rules) create_resources('::postgresql::server::recovery', deep_merge($_recovery, $recovery)) }
Daher installieren wir Postgresql 10
einen Schlag, konfigurieren die Konfiguration ( listen
), erstellen die kicker
Datenbank und schreiben zwei Regeln fĂŒr den Zugriff auf diese Datenbank in pg_hba.conf
. Cool!
Frontend-Rolle
Wir nehmen das frontend
. Erstellen Sie die Datei projects/kicker/frontend.yaml
mit den folgenden Inhalten:
--- classes: - profiles::webserver::nginx profiles::webserver::nginx::servers: 'kicker.semrush.com': use_default_location: false listen_port: 80 server_name: - 'kicker.semrush.com' profiles::webserver::nginx::locations: 'kicker-root': location: '/' server: 'kicker.semrush.com' proxy: 'http://kicker-backend.semrush.com:8080' proxy_set_header: - 'X-Real-IP $remote_addr' - 'X-Forwarded-for $remote_addr' - 'Host kicker.semrush.com' location_cfg_append: 'proxy_next_upstream': 'error timeout invalid_header http_500 http_502 http_503 http_504' proxy_connect_timeout: '5'
Hier ist alles einfach. Wir verbinden das profiles::webserver::nginx
, das den Eintrag in das nginx-Modul vorbereitet, und definieren auch die Variablen, insbesondere den server
und den location
fĂŒr diese Site.
Ein aufmerksamer Leser wird feststellen, dass es angemessener wÀre, die Beschreibung der Site höher in der Hierarchie zu platzieren, da wir weiterhin eine Entwicklungsumgebung haben und andere Variablen ( server_name
, proxy
) dort verwendet werden, dies ist jedoch nicht zu wichtig. Wenn wir die Rolle auf diese Weise beschreiben, können wir sehen, wie diese Variablen nur durch Hierarchie neu definiert werden.
Docker-Rolle
Die Rolle von docker
projects/kicker/docker.yaml
:
--- classes: - profiles::docker profiles::docker::params: version: '17.05.0~ce-0~debian-stretch' packages: 'python3-pip': provider: apt 'Fabric3': provider: pip3 ensure: 1.12.post1 user_management::users: deploy: groups: - docker
Das profiles/docker.pp
sehr einfach und elegant. Ich werde seinen Code geben:
Profil :: Docker class profiles::docker ( Hash $params = {}, Boolean $install_kernel = false, ){ class { 'docker': * => $params, } if ($install_kernel) { include profiles::docker::kernel } }
Alles ist fertig. Dies reicht bereits aus, um das benötigte Produkt auf vielen Servern bereitzustellen und ihnen einfach ein bestimmtes Projekt und eine bestimmte Rolle zuzuweisen (z. B. die Datei im gewĂŒnschten Format im Verzeichnis facts.d abzulegen, dessen Speicherort von der Installationsmethode von Puppet abhĂ€ngt).
Jetzt haben wir folgende Dateistruktur:
. âââ kicker â âââ db.yaml â âââ docker.yaml â âââ frontend.yaml âââ kicker.yaml 1 directory, 4 files
Jetzt beschĂ€ftigen wir uns mit Umgebungen und der Definition einer Konfiguration, die fĂŒr eine Rolle an einem bestimmten Standort eindeutig ist.
Umgebung und Override
Lassen Sie uns die allgemeine Konfiguration fĂŒr alle VerkĂ€ufe erstellen. Die Datei projects/kicker/tiers/prod.yaml
enthÀlt einen Hinweis darauf, dass eine Klasse mit einer Firewall mit dieser Umgebung verbunden werden muss ( projects/kicker/tiers/prod.yaml
prod) sowie eine bestimmte Klasse, die ein höheres Maà an Sicherheit bietet:
Wenn wir in einer Entwicklungsumgebung etwas Bestimmtes beschreiben mĂŒssen, wird dieselbe Datei erstellt und die erforderliche Konfiguration eingegeben.
Als NĂ€chstes mĂŒssen Sie die Variablen fĂŒr die Nginx-Konfiguration der frontend
Rolle in der Entwicklungsumgebung noch neu definieren. Dazu mĂŒssen Sie die Datei projects/kicker/tiers/dev/frontend.yaml
erstellen. Achten Sie auf eine neue Hierarchieebene.
--- profiles::webserver::nginx::servers: 'kicker-dev.semrush.com': use_default_location: false listen_port: 80 server_name: - 'kicker-dev.semrush.com' profiles::webserver::nginx::locations: 'kicker-root': location: '/' server: 'kicker-dev.semrush.com' proxy: 'http://kicker-backend-dev.semrush.com:8080' proxy_set_header: - 'X-Real-IP $remote_addr' - 'X-Forwarded-for $remote_addr' - 'Host kicker-dev.semrush.com' location_cfg_append: 'proxy_next_upstream': 'error timeout invalid_header http_500 http_502 http_503 http_504' proxy_connect_timeout: '5'
Sie mĂŒssen keine Klasse mehr angeben, sie wird von frĂŒheren Hierarchieebenen geerbt. Hier haben wir proxy_pass
und proxy_pass
geÀndert. Ein Server mit den Fakten role = frontend und tier = dev findet zuerst die Datei projects/kicker/frontend.yaml
fĂŒr sich selbst. AnschlieĂend werden die Variablen aus dieser Datei von der Datei projects/kicker/tiers/dev/frontend.yaml
mit höherer PrioritĂ€t ĂŒberschrieben .
Passwort fĂŒr PostgreSQL versteckt
Und so haben wir den letzten Punkt auf der Tagesordnung - Passwörter fĂŒr PostgreSQL festlegen.
Passwörter sollten in Umgebungen variieren. Wir werden eyaml verwenden, um Passwörter sicher zu speichern. Passwörter erstellen:
eyaml encrypt -s 'verysecretpassword' eyaml encrypt -s 'testpassword'
Wir fĂŒgen die resultierenden Zeilen in die Dateien **projects/kicker/tiers/prod/db.yaml**
und **projects/kicker/tiers/dev/db.yaml**
(oder Sie können die eyaml-Erweiterung verwenden, dies ist anpassbar). Hier ist ein Beispiel:
--- profiles::db::postgresql::roles: 'kicker': password_hash: > 'ENC[PKCS7,MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAsdpb2P0axUJzyWr2duRKAjh0WooGYUmoQ5gw0nO9Ym5ftv6uZXv25DRMKh7vsbzrrOR5/lLesx/pAVmcs2qbhd/y0Vr1oc2ohHlZBBKtCSEYwem5VN+kTMhWPvlt93x/S9ERoBp8LrrsIvicSYZByNfpS2DXCFbogSXCfEPxTTmCOtlOnxdjidIc9Q1vfAXv7FRQanYIspr2UytScm56H/ueeAc/8RYK51/nXDMtdPOiAP5VARioUKyTDSk8FqNvdUZRqA3cl+hA+xD5PiBHn5T09pnH8HyE/39q09gE0pXRe5+mOnU/4qfqFPc/EvAgAq5mVawlCR6c/cCKln5wJTA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBDNKijGHBLPCth0sfwAjfl/gBAaPsfvzZQ/Umgjy1n+im0s]'
Als nĂ€chstes wird das Passwort fĂŒr die kicker
Rolle kommen, entschlĂŒsselt und auf den Datenbankserver in PostgreSQL angewendet.
Das ist in der Tat alles. Ja, das Beispiel erwies sich als massiv, aber ich hoffe, es funktioniert, ohne Fragen zu stellen, klar und nĂŒtzlich. Die resultierende Hierarchie in Hiera lautet wie folgt:
. âââ db.yaml âââ docker.yaml âââ frontend.yaml âââ tiers âââ dev â âââ db.yaml â âââ frontend.yaml âââ prod â âââ db.yaml âââ prod.yaml 3 directories, 7 files
Sie können diese Dateien live verfolgen, indem Sie ein speziell erstelltes Repository klonen
Fazit
Puppe ist gut und einfach mit Hiera zu verwenden. Ich wĂŒrde es nicht als ideales Konfigurationswerkzeug in der modernen Welt bezeichnen, ĂŒberhaupt nicht, aber es verdient Aufmerksamkeit. Er bewĂ€ltigt einige Aufgaben sehr gut, und seine âPhilosophieâ, einen stĂ€ndig identischen Zustand von Ressourcen und Konfiguration beizubehalten, kann eine wichtige Rolle bei der GewĂ€hrleistung der Sicherheit und Einheitlichkeit von Konfigurationen spielen.
Die moderne Welt entwickelt sich allmĂ€hlich zu Synergien und entwickelt sich weiter. Nur wenige Leute verwenden nur noch ein Konfigurationssystem, oft gibt es im Arsenal der Entwickler und Administratoren mehrere Systeme gleichzeitig. Und das ist gut so, denn es gibt eine groĂe Auswahl. Die Hauptsache ist, dass alles logisch und verstĂ€ndlich sein sollte, wie und wo es konfiguriert werden kann.
Daher ist es unser Ziel als Administratoren, nichts selbst zu konfigurieren. All dies sollte idealerweise von den Teams selbst durchgefĂŒhrt werden. Und wir mĂŒssen ihnen ein Werkzeug oder Produkt geben, mit dem wir dies sicher, einfach und vor allem mit einem genauen Ergebnis tun können. Nun, und helfen Sie bei der Lösung architektonischer und schwerwiegenderer Probleme als "Sie mĂŒssen PostgreSQL auf dem Server installieren und einen Benutzer erstellen." Camon, 2018 ist auf dem Hof! Also werfen Sie Marionette und Ansible und bewegen Sie sich in die Zukunft ohne Server.
Mit der Entwicklung von Cloud-, Containerisierungs- und Container-Orchestrierungssystemen treten Konfigurationsmanagementsysteme fĂŒr Benutzer und Kunden langsam in den Hintergrund. Sie können auch einen ausfallsicheren Cluster von Containern in der Cloud erstellen und Ihre Anwendungen in Containern mit Auto-Skelling, Backup, Replikation, Auto-Discovery usw. aufbewahren, ohne eine einzige Zeile fĂŒr Ansible, Puppet, Chef usw. zu schreiben. Sie mĂŒssen sich um nichts kĂŒmmern (na ja, fast). Auf der anderen Seite gibt es aufgrund von Wolken weniger Eisenserver. Sie mĂŒssen sie nur nicht mehr konfigurieren. Diese Aktion liegt in der Verantwortung des Cloud-Anbieters. Es ist jedoch unwahrscheinlich, dass sie dieselben Systeme wie gewöhnliche Sterbliche verwenden.
Credits
Vielen Dank:
- Dmitry Tupitsin, Dmitry Loginov, Stepan Fedorov und das gesamte Team von Systemadministratoren fĂŒr ihre Hilfe bei der Vorbereitung dieses Artikels
- Vladimir Legkostupov fĂŒr das Bild
- Yana Tabakova, die all dies organisiert und dabei hilft, alle Phasen vor der Veröffentlichung zu durchlaufen
- Nikita Zakharov fĂŒr UnterstĂŒtzung bei Lizenzfragen