Konfigurieren eines Servers zum Bereitstellen einer Rails-Anwendung mit Ansible

Vor nicht allzu langer Zeit musste ich mehrere ansible Playbooks schreiben, um den Server auf die Bereitstellung der Rails-Anwendung vorzubereiten. Und überraschenderweise fand ich kein einfaches Schritt-für-Schritt-Handbuch. Ich wollte nicht das Spielbuch eines anderen kopieren, ohne zu verstehen, was geschah, und musste daher die Dokumentation lesen und alles selbst sammeln. Vielleicht kann mir jemand helfen, diesen Prozess mit diesem Artikel zu beschleunigen.


Das erste, was Sie verstehen müssen, ist, dass ansible Ihnen eine praktische Schnittstelle bietet, über die Sie eine vordefinierte Liste von Aktionen auf den Remote-Servern über SSH ausführen können. Hier gibt es keine Magie. Sie können das Plugin nicht installieren und aus der Null-Ausfallzeit-Box eine Bereitstellung Ihrer Anwendung mit Docker, Überwachung und anderen Extras herausholen. Um ein Spielbuch zu schreiben, müssen Sie genau wissen, was Sie tun möchten und wie es geht. Daher mag ich keine vorgefertigten Spielbücher aus dem Github oder Artikel wie: "Kopieren und ausführen, es wird funktionieren."


Was brauchen wir


Wie gesagt, um ein Spielbuch zu schreiben, muss man wissen, was man machen will und wie man es macht. Lassen Sie uns entscheiden, was wir brauchen. Für eine Rails-Anwendung benötigen wir mehrere Systempakete: nginx, postgresql (redis usw.). Darüber hinaus benötigen wir Ruby einer bestimmten Version. Es ist am besten, es über rbenv (rvm, asdf ...) zu installieren. Es ist immer eine schlechte Idee, all dies vom Stammverzeichnis des Benutzers aus auszuführen. Sie müssen daher einen separaten Benutzer erstellen und die Rechte für ihn konfigurieren. Danach müssen Sie unseren Code auf den Server hochladen, die Konfigurationen für Nginx, Postgres usw. kopieren und alle diese Dienste ausführen.


Infolgedessen ist die Reihenfolge der Aktionen wie folgt:


  1. Melden Sie sich als root an
  2. Installieren Sie Systempakete
  3. Erstellen Sie einen neuen Benutzer, konfigurieren Sie die Rechte und den SSH-Schlüssel
  4. Konfigurieren Sie Systempakete (Nginx usw.) und führen Sie sie aus
  5. Erstellen Sie einen Benutzer in der Datenbank (Sie können sofort eine Datenbank erstellen)
  6. Melden Sie sich als neuer Benutzer an
  7. Installieren Sie rbenv und ruby
  8. Installieren Sie den Bundler
  9. Geben Sie den Anwendungscode ein
  10. Wir starten den Puma-Server

Darüber hinaus können die letzten Schritte mit capistrano ausgeführt werden. Zumindest kann sie den Code aus der Box in Release-Verzeichnisse kopieren, das Release bei einer erfolgreichen Bereitstellung mit einem Symlink wechseln, Konfigurationen aus dem freigegebenen Verzeichnis kopieren, Puma neu starten usw. All dies kann mit Ansible gemacht werden, aber warum?


Dateistruktur


Ansible hat eine strenge Dateistruktur für alle Dateien. Bewahren Sie diese daher am besten in einem separaten Verzeichnis auf. Und es ist nicht so wichtig, ob es in der Schienenanwendung selbst oder separat sein wird. Sie können Dateien in einem separaten Git-Repository speichern. Persönlich war es für mich am bequemsten, das ansible-Verzeichnis in / config des Rails-Verzeichnisses der Anwendung zu erstellen und alles in einem Repository zu speichern.


Einfaches Spielbuch


Playbook ist eine yml-Datei, die beschreibt, was und wie ansible mit einer speziellen Syntax tun soll. Lassen Sie uns das erste Spielbuch erstellen, das nichts tut:


--- - name: Simple playbook hosts: all 

Hier sagen wir einfach, dass unser Playbook Simple Playbook und dass sein Inhalt für alle Hosts ausgeführt werden sollte. Wir können es im Verzeichnis / ansible unter dem Namen playbook.yml speichern und versuchen, Folgendes auszuführen:


 ansible-playbook ./playbook.yml PLAY [Simple Playbook] ************************************************************************************************************************************ skipping: no hosts matched 

Ansible sagt, dass es keine Hosts kennt, die mit der Liste aller übereinstimmen. Sie müssen in einer speziellen Inventardatei aufgeführt sein .


Lassen Sie es uns im selben ansible Verzeichnis erstellen:


 123.123.123.123 

Geben Sie einfach den Host an (idealerweise den Host Ihres VPS für Tests, oder Sie können localhost registrieren) und speichern Sie ihn unter dem inventory .
Sie können versuchen, ansible mit einer Invetory-Datei auszuführen:


 ansible-playbook ./playbook.yml -i inventory PLAY [Simple Playbook] ************************************************************************************************************************************ TASK [Gathering Facts] ************************************************************************************************************************************ PLAY RECAP ************************************************************************************************************************************ 

Wenn Sie SSH-Zugriff auf den angegebenen Host haben, stellt ansible eine Verbindung her und sammelt Informationen über das Remote-System. (Standardaufgabe [Sammeln von Fakten]) Danach wird ein kurzer Fortschrittsbericht (PLAY RECAP) angezeigt.


Standardmäßig wird für die Verbindung der Benutzername verwendet, unter dem Sie am System angemeldet sind. Es wird höchstwahrscheinlich nicht auf dem Host sein. In der Playbook-Datei können Sie mithilfe der Anweisung remote_user angeben, mit welchem ​​Benutzer eine Verbindung hergestellt werden soll. Außerdem sind Informationen zu einem Remote-System für Sie häufig nicht erforderlich, und Sie sollten keine Zeit damit verschwenden, sie zu sammeln. Sie können diese Aufgabe auch deaktivieren:


 --- - name: Simple playbook hosts: all remote_user: root become: true gather_facts: no 

Versuchen Sie erneut, das Playbook auszuführen, und stellen Sie sicher, dass die Verbindung funktioniert. (Wenn Sie das Stammverzeichnis des Benutzers angegeben haben, müssen Sie auch die Anweisung get: true angeben, um erhöhte Rechte zu erhalten. Wie in der Dokumentation angegeben: become set to 'true'/'yes' to activate privilege escalation. Es ist jedoch nicht klar, warum) .


Möglicherweise erhalten Sie einen Fehler, der durch den Ansible verursacht wird, den der Python-Interpreter nicht ermitteln kann. Anschließend können Sie ihn manuell angeben:


 ansible_python_interpreter: /usr/bin/python3 

Wo Sie Python haben, können Sie mit dem Befehl whereis python .


Installieren Sie Systempakete


Ansible enthält viele Module für die Arbeit mit verschiedenen Systempaketen, sodass wir aus keinem Grund Bash-Skripte schreiben müssen. Jetzt benötigen wir eines dieser Module, um das System zu aktualisieren und Systempakete zu installieren. Ich habe Ubuntu Linux auf VPS, um Pakete zu installieren, benutze ich apt-get und ein Modul dafür . Wenn Sie ein anderes Betriebssystem verwenden, benötigen Sie möglicherweise ein anderes Modul (denken Sie daran, ich habe zu Beginn gesagt, dass wir im Voraus wissen müssen, was und wie wir tun werden). Die Syntax ist jedoch wahrscheinlich ähnlich.


Wir ergänzen unser Spielbuch mit den ersten Aufgaben:


 --- - name: Simple playbook hosts: all remote_user: root become: true gather_facts: no tasks: - name: Update system apt: update_cache=yes - name: Install system dependencies apt: name: git,nginx,redis,postgresql,postgresql-contrib state: present 

Aufgabe ist nur die Aufgabe, die ansible auf Remote-Servern ausführt. Wir geben der Aufgabe einen Namen, um ihren Fortschritt im Protokoll zu verfolgen. Und wir beschreiben anhand der Syntax eines bestimmten Moduls, was es tun muss. In diesem Fall apt: update_cache=yes - Aktualisierung der Systempakete mithilfe des apt-Moduls. Das zweite Team ist etwas komplizierter. Wir übergeben die Liste der Pakete an das apt-Modul und sagen, dass ihr Status present soll, dh wir sagen, dass diese Pakete installiert werden sollen. Ebenso können wir ihnen mitteilen, dass sie einfach durch Ändern des state gelöscht oder aktualisiert werden sollen. Bitte beachten Sie, dass für die Verwendung von Rails mit Postgresql das derzeit installierte Postgresql-Contrib-Paket erforderlich ist. Dies muss wieder bekannt und getan werden, ansible allein wird dies nicht tun.


Versuchen Sie erneut, das Playbook auszuführen und überprüfen Sie, ob die Pakete installiert sind.


Erstellung neuer Benutzer.


Um mit Benutzern arbeiten zu können, verfügt Ansible auch über ein Modul - Benutzer. Fügen Sie eine weitere Aufgabe hinzu (ich habe die bereits bekannten Teile des Spielbuchs hinter den Kommentaren versteckt, um sie nicht jedes Mal vollständig zu kopieren):


 --- - name: Simple playbook # ... tasks: # ... - name: Add a new user user: name: my_user shell: /bin/bash password: "{{ 123qweasd | password_hash('sha512') }}" 

Wir erstellen einen neuen Benutzer, setzen ihm eine Schell und ein Passwort. Und dann stehen wir vor mehreren Problemen. Was ist, wenn Benutzernamen für verschiedene Hosts unterschiedlich sein müssen? Ja, und das Passwort im Playbook offen zu halten, ist eine sehr schlechte Idee. Zuerst werden wir den Benutzernamen und das Passwort in Variablen eingeben und gegen Ende des Artikels werde ich zeigen, wie das Passwort verschlüsselt wird.


 --- - name: Simple playbook # ... tasks: # ... - name: Add a new user user: name: "{{ user }}" shell: /bin/bash password: "{{ user_password | password_hash('sha512') }}" 

Variablen werden in Playbooks in doppelten geschweiften Klammern gesetzt.


Wir werden die Werte der Variablen in der Inventardatei angeben:


 123.123.123.123 [all:vars] user=my_user user_password=123qweasd 

Beachten Sie die Direktive [all:vars] - sie besagt, dass der nächste Textblock Variablen (vars) sind und für alle Hosts (all) gelten.


Interessant "{{ user_password | password_hash('sha512') }}" auch die Konstruktion von "{{ user_password | password_hash('sha512') }}" . Tatsache ist, dass ansible den Benutzer user_add wie manuell über user_add . Und es speichert alle Daten direkt, weshalb wir das Passwort auch im Voraus in einen Hash konvertieren müssen, was dieser Befehl tut.


Fügen wir unseren Benutzer der Sudo-Gruppe hinzu. Vorher müssen Sie jedoch sicherstellen, dass eine solche Gruppe existiert, da dies niemand für uns tun wird:


 --- - name: Simple playbook # ... tasks: # ... - name: Ensure a 'sudo' group group: name: sudo state: present - name: Add a new user user: name: "{{ user }}" shell: /bin/bash password: "{{ user_password | password_hash('sha512') }}" groups: "sudo" 

Es ist einfach genug, wir haben auch ein Gruppenmodul zum Erstellen von Gruppen mit einer Syntax, die apt sehr ähnlich ist. Dann reicht es aus, diese Gruppe beim Benutzer zu registrieren ( groups: "sudo" ).
Es ist auch nützlich, diesem Benutzer einen SSH-Schlüssel hinzuzufügen, damit wir uns ohne Kennwort darunter anmelden können:


 --- - name: Simple playbook # ... tasks: # ... - name: Ensure a 'sudo' group group: name: sudo state: present - name: Add a new user user: name: "{{ user }}" shell: /bin/bash password: "{{ user_password | password_hash('sha512') }}" groups: "sudo" - name: Deploy SSH Key authorized_key: user: "{{ user }}" key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" state: present 

In diesem Fall ist das Konstrukt "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" interessant - es kopiert den Inhalt der Datei id_rsa.pub (Ihr Name kann abweichen), dh den öffentlichen Teil des ssh-Schlüssels und lädt es in die Liste der autorisierten Schlüssel für den Benutzer auf dem Server hoch.


Rollen


Alle drei Aufgaben für die Erstellung können problemlos als eine Aufgabengruppe verwendet werden, und es wäre schön, diese Gruppe vom Haupt-Playbook getrennt zu halten, damit sie nicht zu stark wächst. Dafür gibt es in ansible Rollen .
Entsprechend der am Anfang angegebenen Dateistruktur müssen die Rollen für jede Rolle in einem separaten Rollenverzeichnis abgelegt werden - einem separaten Verzeichnis mit demselben Namen innerhalb des Verzeichnisses für Aufgaben, Dateien, Vorlagen usw.
Erstellen wir die Dateistruktur: ./ansible/roles/user/tasks/main.yml (main ist die Hauptdatei, die geladen und ausgeführt wird, wenn die Rolle mit dem Playbook verbunden ist, andere Rollendateien können darin verbunden werden). Jetzt können Sie alle Aufgaben, die sich auf den Benutzer beziehen, in diese Datei übertragen:


 # Create user and add him to groups - name: Ensure a 'sudo' group group: name: sudo state: present - name: Add a new user user: name: "{{ user }}" shell: /bin/bash password: "{{ user_password | password_hash('sha512') }}" groups: "sudo" - name: Deploy SSH Key authorized_key: user: "{{ user }}" key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" state: present 

Im Haupt-Playbook müssen Sie angeben, um die Benutzerrolle zu verwenden:


 --- - name: Simple playbook hosts: all remote_user: root gather_facts: no tasks: - name: Update system apt: update_cache=yes - name: Install system dependencies apt: name: git,nginx,redis,postgresql,postgresql-contrib state: present roles: - user 

Es kann auch sinnvoll sein, vor allen anderen Aufgaben ein Systemupdate durchzuführen. Dazu können Sie den tasks umbenennen, in dem sie in pre_tasks definiert pre_tasks .


Nginx-Setup


Nginx sollte bereits bei uns installiert sein, Sie müssen es konfigurieren und ausführen. Machen wir es gleich in der Rolle. Erstellen Sie eine Dateistruktur:


 - ansible - roles - nginx - files - tasks - main.yml - templates 

Jetzt brauchen wir Dateien und Vorlagen. Der Unterschied zwischen den beiden besteht darin, dass ansible Dateien so wie sie sind direkt kopiert werden. Die Vorlagen sollten die Erweiterung j2 haben und können die Werte von Variablen mit denselben doppelten geschweiften Klammern verwenden.


Nehmen wir nginx in die Datei main.yml . Dafür haben wir ein systemd-Modul:


 # Copy nginx configs and start it - name: enable service nginx and start systemd: name: nginx state: started enabled: yes 

Hier sagen wir nicht nur, dass nginx gestartet werden soll (d. H. Ausführen soll), sondern sagen sofort, dass es aktiviert werden muss.
Kopieren Sie nun die Konfigurationsdateien:


 # Copy nginx configs and start it - name: enable service nginx and start systemd: name: nginx state: started enabled: yes - name: Copy the nginx.conf copy: src: nginx.conf dest: /etc/nginx/nginx.conf owner: root group: root mode: '0644' backup: yes - name: Copy template my_app.conf template: src: my_app_conf.j2 dest: /etc/nginx/sites-available/my_app.conf owner: root group: root mode: '0644' 

Wir erstellen die Haupt-Nginx-Konfigurationsdatei (Sie können sie direkt vom Server übernehmen oder selbst schreiben). Und auch die Konfigurationsdatei für unsere Anwendung im Verzeichnis sites_available (dies ist nicht erforderlich, aber nützlich). Im ersten Fall verwenden wir das /ansible/roles/nginx/files/nginx.conf zum Kopieren von Dateien (die Datei muss sich in /ansible/roles/nginx/files/nginx.conf ). Kopieren Sie im zweiten Schritt die Vorlage und ersetzen Sie die Werte der Variablen. Die Vorlage sollte sich in /ansible/roles/nginx/templates/my_app.j2 ) befinden. Und es könnte ungefähr so ​​aussehen:


 upstream {{ app_name }} { server unix:{{ app_path }}/shared/tmp/sockets/puma.sock; } server { listen 80; server_name {{ server_name }} {{ inventory_hostname }}; root {{ app_path }}/current/public; try_files $uri/index.html $uri.html $uri @{{ app_name }}; .... } 

{{ app_name }} die Einfügungen {{ app_name }} , {{ app_path }} , {{ server_name }} , {{ inventory_hostname }} - dies sind alles Variablen, deren ansible-Werte vor dem Kopieren in der Vorlage ersetzt werden. Dies ist nützlich, wenn Sie das Playbook für verschiedene Hostgruppen verwenden. Zum Beispiel können wir unsere Inventardatei ergänzen:


 [production] 123.123.123.123 [staging] 231.231.231.231 [all:vars] user=my_user user_password=123qweasd [production:vars] server_name=production app_path=/home/www/my_app app_name=my_app [staging:vars] server_name=staging app_path=/home/www/my_stage app_name=my_stage_app 

Wenn wir unser Playbook jetzt ausführen, werden die angegebenen Aufgaben für beide Hosts ausgeführt. Gleichzeitig unterscheiden sich die Variablen für den Staging-Host von der Produktion, und zwar nicht nur in Rollen und Playbooks, sondern auch in Nginx-Konfigurationen. {{ inventory_hostname }} muss nicht in der Inventardatei angegeben werden - dies ist eine spezielle Variable ansible und der Host, für den das Playbook gerade ausgeführt wird, wird dort gespeichert.
Wenn Sie eine Inventardatei für mehrere Hosts haben und nur für eine Gruppe ausführen möchten, können Sie dies mit dem folgenden Befehl ausführen:


 ansible-playbook -i inventory ./playbook.yml -l "staging" 

Eine andere Möglichkeit besteht darin, separate Inventardateien für verschiedene Gruppen zu haben. Oder Sie können zwei Ansätze kombinieren, wenn Sie viele verschiedene Hosts haben.


Kommen wir zurück zur Konfiguration von Nginx. Nach dem Kopieren der Konfigurationsdateien müssen wir in sitest_enabled auf my_app.conf einen symlink von sites_available erstellen. Und starten Sie Nginx neu.


 ... # old code in mail.yml - name: Create symlink to sites-enabled file: src: /etc/nginx/sites-available/my_app.conf dest: /etc/nginx/sites-enabled/my_app.conf state: link - name: restart nginx service: name: nginx state: restarted 

Auch hier ist alles einfach - wieder ansible Module mit ziemlich normaler Syntax. Aber es gibt einen Punkt. Ein erneuter Neustart von nginx ist nicht sinnvoll. Sie haben festgestellt, dass wir keine Befehle des Formulars schreiben: "Mach das so", die Syntax sieht eher so aus wie "Das sollte diesen Zustand haben". Und meistens funktioniert ansible so. Wenn die Gruppe bereits vorhanden ist oder das Systempaket bereits installiert ist, überprüft ansible dies und überspringt die Aufgabe. Außerdem werden Dateien nicht kopiert, wenn sie vollständig mit dem übereinstimmen, was sich bereits auf dem Server befindet. Wir können dies nutzen und nginx nur neu starten, wenn die Konfigurationsdateien geändert wurden. Hierfür gibt es eine Registerrichtlinie:


 # Copy nginx configs and start it - name: enable service nginx and start systemd: name: nginx state: started enabled: yes - name: Copy the nginx.conf copy: src: nginx.conf dest: /etc/nginx/nginx.conf owner: root group: root mode: '0644' backup: yes register: restart_nginx - name: Copy template my_app.conf template: src: my_app_conf.j2 dest: /etc/nginx/sites-available/my_app.conf owner: root group: root mode: '0644' register: restart_nginx - name: Create symlink to sites-enabled file: src: /etc/nginx/sites-available/my_app.conf dest: /etc/nginx/sites-enabled/my_app.conf state: link - name: restart nginx service: name: nginx state: restarted when: restart_nginx.changed 

Wenn sich eine der Konfigurationsdateien ändert, wird die Kopie ausgeführt und die Variable restart_nginx registriert. Und nur wenn diese Variable registriert wurde, wird der Dienst neu gestartet.


Natürlich müssen Sie die Nginx-Rolle zum Hauptspielbuch hinzufügen.


Postgresql-Setup


Wir müssen postgresql mit systemd wie mit nginx aktivieren und einen Benutzer erstellen, mit dem wir auf die Datenbank und die Datenbank selbst zugreifen können.
Erstellen Sie die Rolle /ansible/roles/postgresql/tasks/main.yml :


 # Create user in postgresql - name: enable postgresql and start systemd: name: postgresql state: started enabled: yes - name: Create database user become_user: postgres postgresql_user: name: "{{ db_user }}" password: "{{ db_password }}" role_attr_flags: SUPERUSER - name: Create database become_user: postgres postgresql_db: name: "{{ db_name }}" encoding: UTF-8 owner: "{{ db_user }}" 

Ich werde nicht beschreiben, wie Variablen zum Inventar hinzugefügt werden. Dies wurde bereits mehrfach durchgeführt, ebenso wie die Syntax der Module postgresql_db und postgresql_user. Weitere Daten finden Sie in der Dokumentation. Die Direktive become_user: postgres am interessantesten. Tatsache ist, dass standardmäßig nur Postgres-Benutzer Zugriff auf die Postgresql-Datenbank haben und nur lokal. Diese Anweisung ermöglicht es uns, Befehle im Namen dieses Benutzers auszuführen (es sei denn, wir haben natürlich Zugriff).
Möglicherweise müssen Sie auch eine Zeile zu pg_hba.conf hinzufügen, um einem neuen Benutzer den Zugriff auf die Datenbank zu ermöglichen. Dies kann auf die gleiche Weise erfolgen, wie wir die Nginx-Konfiguration geändert haben.


Und natürlich müssen Sie die Rolle von postgresql zum Hauptspielbuch hinzufügen.


Installieren Sie Ruby durch Rbenv


Ansible hat keine Module für die Arbeit mit rbenv, wird jedoch durch Klonen eines Git-Repositorys installiert. Daher wird diese Aufgabe zur ungewöhnlichsten. Erstellen wir die Rolle /ansible/roles/ruby_rbenv/main.yml für sie und füllen sie aus:


 # Install rbenv and ruby - name: Install rbenv become_user: "{{ user }}" git: repo=https://github.com/rbenv/rbenv.git dest=~/.rbenv 

Wir verwenden erneut die Direktive werden_benutzer, um unter dem Benutzer zu arbeiten, den wir für diese Zwecke erstellt haben. Da rbenv in seinem Home-Verzeichnis installiert ist, nicht global. Außerdem verwenden wir das Git-Modul, um das Repository durch Angabe von repo und dest zu klonen.


Als nächstes müssen wir rbenv init in bashrc registrieren und rbenv an derselben Stelle zu PATH hinzufügen. Dafür haben wir das Lineinfile-Modul:


 - name: Add rbenv to PATH become_user: "{{ user }}" lineinfile: path: ~/.bashrc state: present line: 'export PATH="${HOME}/.rbenv/bin:${PATH}"' - name: Add rbenv init to bashrc become_user: "{{ user }}" lineinfile: path: ~/.bashrc state: present line: 'eval "$(rbenv init -)"' 

Dann installieren Sie ruby_build:


 - name: Install ruby-build become_user: "{{ user }}" git: repo=https://github.com/rbenv/ruby-build.git dest=~/.rbenv/plugins/ruby-build 

Und schließlich Ruby installieren. Dies erfolgt über rbenv, dh nur einen Bash-Befehl:


 - name: Install ruby become_user: "{{ user }}" shell: | export PATH="${HOME}/.rbenv/bin:${PATH}" eval "$(rbenv init -)" rbenv install {{ ruby_version }} args: executable: /bin/bash 

Wir sagen, welches Team wie ausgeführt werden soll. Hier stoßen wir jedoch auf die Tatsache, dass ansible den in bashrc enthaltenen Code nicht ausführt, bevor die Befehle ausgeführt werden. Daher muss rbenv direkt im selben Skript definiert werden.


Das nächste Problem ist, dass der Shell-Befehl keinen Ansible-Status hat. Das heißt, eine automatische Überprüfung, ob diese Version von Ruby installiert ist oder nicht, wird nicht. Wir können es selbst machen:


 - name: Install ruby become_user: "{{ user }}" shell: | export PATH="${HOME}/.rbenv/bin:${PATH}" eval "$(rbenv init -)" if ! rbenv versions | grep -q {{ ruby_version }} then rbenv install {{ ruby_version }} && rbenv global {{ ruby_version }} fi args: executable: /bin/bash 

Und es bleibt Bundler zu installieren:


 - name: Install bundler become_user: "{{ user }}" shell: | export PATH="${HOME}/.rbenv/bin:${PATH}" eval "$(rbenv init -)" gem install bundler 

Fügen Sie erneut unsere ruby_rbenv-Rolle zum Hauptspielbuch hinzu.


Freigegebene Dateien.


Im Allgemeinen kann diese Einstellung abgeschlossen werden. Dann muss capistrano ausgeführt werden, und der Code selbst wird kopiert, die erforderlichen Verzeichnisse erstellt und die Anwendung gestartet (sofern alles richtig konfiguriert ist). Capistrano benötigt jedoch häufig zusätzliche Konfigurationsdateien wie database.yml oder .env können diese wie Dateien und Vorlagen für nginx kopieren. Es gibt nur eine Subtilität. Bevor Sie Dateien kopieren, müssen Sie eine Verzeichnisstruktur für diese erstellen:


 # Copy shared files for deploy - name: Ensure shared dir become_user: "{{ user }}" file: path: "{{ app_path }}/shared/config" state: directory 

Wir geben nur ein Verzeichnis an und ansible erstellt bei Bedarf automatisch das übergeordnete Verzeichnis.


Ansible Tresor


Wir sind bereits auf die Tatsache gestoßen, dass geheime Daten wie das Benutzerkennwort in Variablen vorkommen können. Wenn Sie eine .env Datei für die Anwendung und database.yml haben, sollten noch mehr solche kritischen Daten vorhanden sein. Es wäre schön, sie vor neugierigen Blicken zu verstecken. Hierfür wird Ansible Vault verwendet.


Erstellen wir eine Datei für die Variablen /ansible/vars/all.yml (hier können Sie verschiedene Dateien für verschiedene Gruppen von Hosts erstellen, genau wie in der Inventardatei: Production.yml, Staging.yml usw.).
In dieser Datei müssen Sie alle Variablen übertragen, die mit der Standard-Yml-Syntax verschlüsselt werden müssen:


 # System vars user_password: 123qweasd db_password: 123qweasd # ENV vars aws_access_key_id: xxxxx aws_secret_access_key: xxxxxx aws_bucket: bucket_name rails_secret_key_base: very_secret_key_base 

Dann kann diese Datei mit dem folgenden Befehl verschlüsselt werden:


 ansible-vault encrypt ./vars/all.yml 

Während der Verschlüsselung muss natürlich ein Passwort für die Entschlüsselung festgelegt werden. Sie können sehen, was in der Datei angezeigt wird, nachdem Sie diesen Befehl aufgerufen haben.


Mit ansible-vault decrypt Datei entschlüsselt, geändert und anschließend erneut verschlüsselt werden.


Zum Arbeiten ist das Entschlüsseln der Datei nicht erforderlich. Sie speichern es in verschlüsselter Form und führen das Playbook mit dem Argument --ask-vault-pass . Ansible fragt nach einem Passwort, ruft die Variablen ab und erledigt die Aufgaben. Alle Daten bleiben verschlüsselt.


Ein vollständiger Befehl für mehrere Hostgruppen und einen ansible Tresor würde ungefähr so ​​aussehen:


 ansible-playbook -i inventory ./playbook.yml -l "staging" --ask-vault-pass 

Und ich werde Ihnen nicht den vollständigen Text von Spielbüchern und Rollen geben, sondern selbst schreiben. Denn das Ansible ist: Wenn Sie nicht verstehen, was zu tun ist, wird er es nicht tun.

Source: https://habr.com/ru/post/de460769/


All Articles