Il n'y a pas si longtemps, j'avais besoin d'Ă©crire plusieurs playbooks Ansible pour prĂ©parer un serveur au dĂ©ploiement d'une application Rails. Ă ma surprise, je n'ai trouvĂ© aucun manuel simple Ă©tape par Ă©tape. Copier le playbook de quelqu'un d'autre sans comprendre ce qui se passe n'Ă©tait pas ma volontĂ©, et j'ai finalement dĂ» lire la documentation, assemblant tout moi-mĂȘme. Peut-ĂȘtre que je pourrai aider certains Ă accĂ©lĂ©rer ce processus grĂące Ă cet article.
Tout d'abord, il est important de comprendre qu'Ansible vous offre une interface pratique pour exĂ©cuter une liste d'actions prĂ©dĂ©finies sur un ou plusieurs serveurs distants via SSH. Il n'y a pas de magie ici, vous ne pouvez pas simplement installer un plugin et obtenir un dĂ©ploiement sans temps d'arrĂȘt de votre application avec Docker, un monitoring, et d'autres avantages prĂȘts Ă l'emploi. Pour Ă©crire un playbook, vous devez savoir ce que vous voulez faire et comment le faire. C'est pourquoi je ne suis pas satisfait des playbooks prĂȘts Ă l'emploi sur GitHub, ou des articles du type : "Copiez et exĂ©cutez, ça fonctionnera".
De quoi avons-nous besoin ?
Comme je l'ai dĂ©jĂ mentionnĂ©, pour Ă©crire un playbook, il faut savoir ce que vous voulez faire et comment le faire. DĂ©finissons ce dont nous avons besoin. Pour une application Rails, nous aurons besoin de plusieurs paquets systĂšme : nginx, postgresql (redis, etc.). De plus, nous avons besoin de Ruby dans une version spĂ©cifique. Il est prĂ©fĂ©rable de l'installer via rbenv (rvm, asdfâŠ). ExĂ©cuter tout cela sous l'utilisateur root n'est jamais une bonne idĂ©e, donc il faut crĂ©er un utilisateur sĂ©parĂ© et lui attribuer des droits. AprĂšs cela, il est nĂ©cessaire de transfĂ©rer notre code sur le serveur, de copier les configurations pour nginx, postgres, etc., et de dĂ©marrer tous ces services.
Ainsi, l'ordre des opérations est le suivant :
- Nous nous connectons en tant que root
- nous installons les paquets systĂšme
- nous créons un nouvel utilisateur, configurons les droits, la clé ssh
- nous configurons les paquets systÚme (nginx, etc.) et les démarrons
- Nous crĂ©ons un utilisateur dans la base de donnĂ©es (nous pouvons aussi crĂ©er la base en mĂȘme temps)
- Nous nous connectons avec le nouvel utilisateur
- Nous installons rbenv et Ruby
- Nous installons Bundler
- Nous déployons le code de l'application
- Nous lançons le serveur Puma
D'ailleurs, les derniĂšres Ă©tapes peuvent ĂȘtre effectuĂ©es avec Capistrano, car au moins elle sait par dĂ©faut copier le code dans les rĂ©pertoires de publication, changer le lien symbolique de la publication lors d'un dĂ©ploiement rĂ©ussi, copier les configurations Ă partir du rĂ©pertoire partagĂ©, redĂ©marrer Puma, etc. Tout cela peut Ă©galement ĂȘtre fait avec Ansible, mais pourquoi faire ?
Structure des fichiers
Ansible a une structure de fichiers stricte Playbook simple
Un playbook est un fichier yml qui dĂ©crit, Ă l'aide d'une syntaxe spĂ©ciale, ce qu'Ansible doit faire et comment cela doit ĂȘtre fait. CrĂ©ons notre premier playbook qui ne fait rien :
--- - name: Playbook simple hosts: all
Ici, nous disons simplement que notre playbook s'appelleet que son contenu doit ĂȘtre exĂ©cutĂ© pour tous les hĂŽtes. Nous pouvons l'enregistrer dans le rĂ©pertoire /ansible sous le nom Un playbook est un fichier yml qui dĂ©crit, Ă l'aide d'une syntaxe spĂ©ciale, ce qu'Ansible doit faire et comment cela doit ĂȘtre fait. CrĂ©ons notre premier playbook qui ne fait rien : playbook.yml playbook.yml et essayer de l'exĂ©cuter :
ansible-playbook ./playbook.yml
PLAY [Playbook simple] ************************************************************************************************************************************
skipping: aucun hĂŽte correspondantAnsible dit qu'il ne connaĂźt pas d'hĂŽtes correspondant Ă la liste all. Ils doivent ĂȘtre Ă©numĂ©rĂ©s dans un fichier .
CrĂ©ons-le dans le mĂȘme rĂ©pertoire ansible :
123.123.123.123Ici, nous indiquons simplement un hÎte (idéalement l'hÎte de votre VPS pour les tests, ou vous pouvez spécifier localhost) et l'enregistrer sous le nom inventory.
Vous pouvez essayer d'exécuter Ansible avec le fichier d'inventaire :
ansible-playbook ./playbook.yml -i inventory
PLAY [Playbook simple] ************************************************************************************************************************************
TASK [Collecte de faits] ************************************************************************************************************************************
PLAY RECAP ************************************************************************************************************************************Si vous avez accÚs par ssh à l'hÎte spécifié, Ansible se connectera et collectera des informations sur le systÚme distant. (la tùche par défaut [Collecte de faits]) puis fournira un rapport succinct sur l'exécution (PLAY RECAP).
Par dĂ©faut, le nom d'utilisateur utilisĂ© pour la connexion est celui avec lequel vous ĂȘtes connectĂ© au systĂšme. Il n'existe probablement pas sur l'hĂŽte. Dans le fichier de playbook, vous pouvez indiquer quel utilisateur utiliser pour la connexion Ă l'aide de la directive remote_user. Les informations sur le systĂšme distant peuvent Ă©galement souvent ne pas vous intĂ©resser, et il n'est pas nĂ©cessaire de perdre du temps Ă les collecter. Cette tĂąche peut Ă©galement ĂȘtre dĂ©sactivĂ©e :
---
- name: Playbook simple
hosts: all
remote_user: root
become: true
gather_facts: noEssayez de redĂ©marrer le playbook et assurez-vous que la connexion fonctionne. (Si vous avez spĂ©cifiĂ© l'utilisateur root, vous devez Ă©galement indiquer la directive become: true pour obtenir des droits d'administrateur. Comme indiquĂ© dans la documentation : become dĂ©fini sur âtrueâ/âyesâ pour activer l'escalade des privilĂšges. bien que ce ne soit pas tout Ă fait clair pourquoi).
Vous pourriez rencontrer une erreur due au fait qu'Ansible ne peut pas déterminer l'interpréteur Python, alors vous pouvez le spécifier manuellement :
ansible_python_interpreter: /usr/bin/python3 oĂč se trouve votre Python peut ĂȘtre vĂ©rifiĂ© avec la commande whereis python.
Installation de paquets systĂšme
La distribution standard d'Ansible comprend de nombreux modules pour travailler avec divers paquets systĂšme, ce qui Ă©vite d'avoir Ă Ă©crire des scripts bash pour chaque situation. Nous allons maintenant utiliser l'un de ces modules pour mettre Ă jour le systĂšme et installer des paquets systĂšme. Sur mon VPS, j'ai Ubuntu Linux, donc pour installer des paquets, j'utilise apt-get et Si vous utilisez un autre systĂšme d'exploitation, un autre module sera peut-ĂȘtre nĂ©cessaire (rappelez-vous que j'ai mentionnĂ© au dĂ©but qu'il fallait savoir Ă l'avance ce que nous allons faire). Cependant, la syntaxe sera probablement similaire.
Ajoutons les premiĂšres tĂąches Ă notre playbook :
---
- name: Playbook simple
hosts: all
remote_user: root
become: true
gather_facts: no
tasks:
- name: Mettre Ă jour le systĂšme
apt: update_cache=yes
- name: Installer les dépendances systÚme
apt:
name: git,nginx,redis,postgresql,postgresql-contrib
state: presentUne tĂąche â c'est exactement ce que Ansible va exĂ©cuter sur les serveurs distants. Nous donnons un nom Ă la tĂąche afin de suivre son exĂ©cution dans les logs. Et nous dĂ©crivons, Ă l'aide de la syntaxe du module spĂ©cifique, ce qu'il doit faire. Dans ce cas apt: update_cache=yes â indique de mettre Ă jour les paquets systĂšme Ă l'aide du module apt. La deuxiĂšme commande est un peu plus complexe. Nous passons une liste de paquets au module apt et lui disons que leur state doit devenir prĂ©sent, c'est-Ă -dire que nous demandons d'installer ces paquets. De la mĂȘme maniĂšre, nous pouvons indiquer de les supprimer ou de les mettre Ă jour, simplement en changeant state. Notez que pour que Rails fonctionne avec PostgreSQL, nous avons besoin du paquet postgresql-contrib, que nous installons actuellement. Encore une fois, il faut le savoir et le faire, Ansible ne le fera pas de lui-mĂȘme.
Essayez de relancer le playbook et vérifiez que les paquets s'installent.
Création de nouveaux utilisateurs.
Pour interagir avec les utilisateurs, Ansible dispose également d'un module : user. Ajoutons une tùche supplémentaire (j'ai masqué les parties déjà connues du playbook par des commentaires, afin de ne pas avoir à le copier entiÚrement à chaque fois) :
---
- name: Playbook simple
# ...
tasks:
# ...
- name: Ajouter un nouvel utilisateur
user:
name: my_user
shell: /bin/bash
password: "{{ 123qweasd | password_hash('sha512') }}"Nous crĂ©ons un nouvel utilisateur, lui attribuons un shell et un mot de passe. Et nous rencontrons immĂ©diatement plusieurs problĂšmes. Que faire si les noms d'utilisateur doivent ĂȘtre diffĂ©rents pour diffĂ©rents hĂŽtes ? De plus, stocker le mot de passe en clair dans le playbook est une trĂšs mauvaise idĂ©e. Commençons par dĂ©placer le nom d'utilisateur et le mot de passe dans des variables, et plus loin dans l'article, je vous montrerai comment chiffrer le mot de passe.
---
- name: Playbook simple
# ...
tasks:
# ...
- name: Ajouter un nouvel utilisateur
user:
name: "{{ user }}"
shell: /bin/bash
password: "{{ user_password | password_hash('sha512') }}"Les variables sont définies dans les playbooks à l'aide de doubles accolades.
Nous indiquerons les valeurs des variables dans le fichier d'inventaire :
123.123.123.123
[all:vars]
user=my_user
user_password=123qweasdNotez la directive [all:vars] â elle indique que le bloc de texte suivant est constituĂ© de variables (vars) et qu'elles s'appliquent Ă tous les hĂŽtes (all).
La construction est également intéressante "{{ user_password | password_hash('sha512') }}". En effet, Ansible n'ajoute pas l'utilisateur via user_add comme vous le feriez manuellement. Il enregistre directement toutes les données, c'est pourquoi nous devons également préalablement transformer le mot de passe en hachage, ce que fait cette commande.
Ajoutons notre utilisateur au groupe sudo. Cependant, avant cela, il est nécessaire de s'assurer qu'un tel groupe existe car personne ne fera cela pour nous :
---
- name: Playbook simple
# ...
tasks:
# ...
- name: Assurer l'existence d'un groupe 'sudo'
group:
name: sudo
state: present
- name: Ajouter un nouvel utilisateur
user:
name: "{{ user }}"
shell: /bin/bash
password: "{{ user_password | password_hash('sha512') }}"
groups: "sudo"Tout est assez simple, nous avons également un module group pour créer des groupes, avec une syntaxe trÚs similaire à apt. Ensuite, il suffit d'attribuer ce groupe à l'utilisateur (groups: "sudo").
Il est également utile d'ajouter une clé SSH à cet utilisateur, afin que nous puissions nous connecter sous son compte sans mot de passe :
---
- name: Playbook simple
# ...
tasks:
# ...
- name: Assurer un groupe 'sudo'
group:
name: sudo
state: present
- name: Ajouter un nouvel utilisateur
user:
name: "{{ user }}"
shell: /bin/bash
password: "{{ user_password | password_hash('sha512') }}"
groups: "sudo"
- name: Déployer la clé SSH
authorized_key:
user: "{{ user }}"
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
state: presentDans ce cas, la construction est intĂ©ressante "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" â elle copie le contenu du fichier id_rsa.pub (vous pouvez avoir un nom diffĂ©rent), c'est-Ă -dire la partie publique de la clĂ© SSH et l'ajoute Ă la liste des clĂ©s autorisĂ©es pour l'utilisateur sur le serveur.
RĂŽles
Les trois tĂąches pour la crĂ©ation d'utilisateurs peuvent facilement ĂȘtre regroupĂ©es en une seule catĂ©gorie de tĂąches, et il serait bon de garder ce groupe sĂ©parĂ© du playbook principal pour qu'il ne devienne pas trop encombrĂ©. Pour cela, Ansible propose des .
ConformĂ©ment Ă la structure de fichiers indiquĂ©e au dĂ©but, les rĂŽles doivent ĂȘtre placĂ©s dans un rĂ©pertoire sĂ©parĂ© roles, chaque rĂŽle ayant un rĂ©pertoire distinct avec le mĂȘme nom, Ă l'intĂ©rieur du rĂ©pertoire tasks, files, templates, etc.
CrĂ©ons la structure de fichiers : ./ansible/roles/user/tasks/main.yml (main est le fichier principal qui sera chargĂ© et exĂ©cutĂ© lors de la connexion du rĂŽle au playbook, oĂč l'on peut inclure d'autres fichiers du rĂŽle). Nous pouvons maintenant transfĂ©rer dans ce fichier toutes les tĂąches relatives Ă l'utilisateur :
# 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: presentDans le playbook principal, il est nécessaire d'indiquer d'utiliser le rÎle user :
---
- name: Playbook simple
hosts: all
remote_user: root
gather_facts: no
tasks:
- name: Mettre Ă jour le systĂšme
apt: update_cache=yes
- name: Installer les dépendances systÚme
apt:
name: git,nginx,redis,postgresql,postgresql-contrib
state: present
roles:
- userIl se peut également qu'il soit judicieux d'exécuter la mise à jour du systÚme avant toutes les autres tùches, on peut alors renommer le bloc tasks dans lequel elles sont définies en pre_tasks.
Configuration de nginx
Nginx doit dĂ©jĂ ĂȘtre installĂ©, il faut le configurer et le lancer. Faisons cela directement dans le rĂŽle. CrĂ©ons la structure de fichiers :
- ansible
- roles
- nginx
- files
- tasks
- main.yml
- templatesNous aurons maintenant besoin de fichiers et de modĂšles. La diffĂ©rence entre eux est que les fichiers sont copiĂ©s tels quels par Ansible, tandis que les modĂšles doivent avoir l'extension j2 et peuvent utiliser des valeurs de variables avec les mĂȘmes accolades doubles.
Intégrons nginx dans main.yml fichier. Pour cela, nous avons le module systemd :
# Copy nginx configs and start it
- name: enable service nginx and start
systemd:
name: nginx
state: started
enabled: yesIci, non seulement nous disons que nginx doit ĂȘtre dĂ©marrĂ© (c'est-Ă -dire que nous le lançons), mais nous indiquons aussi qu'il doit ĂȘtre activĂ©.
Nous allons maintenant copier les fichiers de configuration :
# 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'Nous crĂ©ons le fichier de configuration principal de nginx (vous pouvez le prendre directement depuis le serveur, ou l'Ă©crire vous-mĂȘme). Ainsi qu'un fichier de configuration pour notre application dans le rĂ©pertoire sites_available (ce n'est pas obligatoire mais utile). Dans le premier cas, nous utilisons le module copy pour copier les fichiers (le fichier doit se trouver dans /ansible/roles/nginx/files/nginx.conf). Dans le second, nous copions le modĂšle en remplaçant les valeurs des variables. Le modĂšle doit se trouver dans /ansible/roles/nginx/templates/my_app.j2). Et il peut ressembler approximativement Ă ceci :
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 }};
....
}Faites attention aux insertions {{ app_name }}, {{ app_path }}, {{ server_name }}, {{ inventory_hostname }} â ce sont toutes des variables, dont les valeurs seront remplacĂ©es par ansible dans le modĂšle avant la copie. Cela est utile si vous utilisez un playbook pour diffĂ©rents groupes d'hĂŽtes. Par exemple, nous pouvons complĂ©ter notre fichier d'inventaire :
[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_appSi nous lançons maintenant notre playbook, il exĂ©cutera les tĂąches spĂ©cifiĂ©es pour les deux hĂŽtes. Mais pour l'hĂŽte de staging, les variables seront diffĂ©rentes de celles de production, et pas seulement dans les rĂŽles et les playbooks, mais aussi dans les configs de nginx. {{ inventory_hostname }} il n'est pas nĂ©cessaire de spĂ©cifier dans le fichier d'inventaire â c'est et elle contient l'hĂŽte pour lequel le playbook est actuellement exĂ©cutĂ©.
Si vous souhaitez avoir un fichier d'inventaire pour plusieurs hÎtes, et exécuter uniquement pour un seul groupe, vous pouvez le faire avec la commande suivante :
ansible-playbook -i inventory .\/playbook.yml -l "staging"une autre option consiste à avoir des fichiers d'inventaire séparés pour différents groupes. Ou vous pouvez combiner les deux approches si vous avez beaucoup d'hÎtes différents.
Revenons à la configuration de nginx. AprÚs avoir copié les fichiers de configuration, nous devons créer un lien symbolique dans sites_enabled pour my_app.conf à partir de sites_available. Et redémarrer nginx.
... # ancien code dans mail.yml
- name: Créer un lien symbolique vers sites-enabled
file:
src: \/etc\/nginx\/sites-available\/my_app.conf
dest: \/etc\/nginx\/sites-enabled\/my_app.conf
state: link
- name: redémarrer nginx
service:
name: nginx
state: restartedTout est assez simple ici - encore des modules Ansible avec une syntaxe plutĂŽt standard. Mais il y a un point important. RedĂ©marrer Nginx Ă chaque fois n'a pas de sens. Vous avez remarquĂ© que nous n'Ă©crivons pas des commandes du type : « faites cela ainsi », la syntaxe ressemble plutĂŽt à « cet Ă©lĂ©ment doit avoir tel Ă©tat ». C'est gĂ©nĂ©ralement ainsi qu'Ansible fonctionne. Si le groupe existe dĂ©jĂ , ou si le paquet systĂšme est dĂ©jĂ installĂ©, Ansible le vĂ©rifiera et passera la tĂąche. De mĂȘme, les fichiers ne seront pas copiĂ©s s'ils correspondent exactement Ă ce qui est dĂ©jĂ sur le serveur. Nous pouvons en profiter et redĂ©marrer Nginx uniquement si les fichiers de configuration ont Ă©tĂ© modifiĂ©s. Pour cela, il existe la directive register :
# 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.changedSi l'un des fichiers de configuration change, le fichier sera copié et une variable sera enregistrée restart_nginx. Et ce n'est que si cette variable a été enregistrée que le redémarrage du service sera effectué.
Bien sûr, il faut également ajouter le rÎle Nginx au playbook principal.
Configuration de PostgreSQL
Nous devons activer PostgreSQL avec systemd exactement comme nous l'avons fait avec Nginx, et crĂ©er un utilisateur que nous allons utiliser pour accĂ©der Ă la base de donnĂ©es ainsi que la base de donnĂ©es elle-mĂȘme.
Créons un rÎle /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 }}"Je ne dĂ©taillerai pas comment ajouter des variables dans l'inventaire, cela a dĂ©jĂ Ă©tĂ© fait de nombreuses fois, de mĂȘme que la syntaxe des modules postgresql_db et postgresql_user. Des informations supplĂ©mentaires peuvent ĂȘtre trouvĂ©es dans la documentation. Ici, la directive la plus intĂ©ressante est become_user: postgres. En fait, par dĂ©faut, l'accĂšs Ă la base de donnĂ©es PostgreSQL se fait uniquement par l'utilisateur postgres et seulement localement. Cette directive nous permet d'exĂ©cuter des commandes au nom de cet utilisateur (si bien sĂ»r nous avons accĂšs).
De plus, il se peut que vous deviez ajouter une ligne dans pg_hba.conf pour ouvrir l'accĂšs au nouveau utilisateur Ă la base. Cela peut ĂȘtre rĂ©alisĂ© de la mĂȘme maniĂšre que nous avons modifiĂ© la configuration de Nginx.
Et bien sûr, il faut ajouter le rÎle PostgreSQL au playbook principal.
Installation de Ruby via rbenv
Ansible n'a pas de modules pour travailler avec rbenv, et il s'installe en clonant le dépÎt Git. Par conséquent, cette tùche devient la plus non standard. Créons un rÎle pour cela /ansible/roles/ruby_rbenv/main.yml et commençons à le remplir :
# Install rbenv and ruby
- name: Install rbenv
become_user: "{{ user }}"
git: repo=https://github.com/rbenv/rbenv.git dest=~/.rbenvNous utilisons à nouveau la directive become_user pour travailler sous l'utilisateur que nous avons créé à cet effet. Comme rbenv est installé dans son répertoire personnel et non de maniÚre globale. Nous utilisons également le module git pour cloner le dépÎt, en indiquant repo et dest.
Ensuite, nous devons ajouter rbenv init dans bashrc et y ajouter rbenv dans PATH. Pour cela, nous avons le module lineinfile :
- name: Ajouter rbenv au PATH
become_user: "{{ user }}"
lineinfile:
path: ~/.bashrc
state: present
line: 'export PATH="${HOME}/.rbenv/bin:${PATH}"'
- name: Ajouter rbenv init Ă bashrc
become_user: "{{ user }}"
lineinfile:
path: ~/.bashrc
state: present
line: 'eval "$(rbenv init -)"'AprĂšs cela, il faut installer ruby_build :
- name: Installer ruby-build
become_user: "{{ user }}"
git: repo=https://github.com/rbenv/ruby-build.git dest=~/.rbenv/plugins/ruby-buildEt enfin, installer ruby. Cela se fait via rbenv, c'est-Ă -dire simplement avec une commande bash :
- name: Installer ruby
become_user: "{{ user }}"
shell: |
export PATH="${HOME}/.rbenv/bin:${PATH}"
eval "$(rbenv init -)"
rbenv install {{ ruby_version }}
args:
executable: /bin/bashNous indiquons quelle commande exĂ©cuter et avec quoi. Cependant, ici nous ferons face Ă un problĂšme, car ansible ne lance pas le code contenu dans bashrc avant d'exĂ©cuter les commandes. Ainsi, rbenv devra ĂȘtre dĂ©fini directement dans ce mĂȘme script.
Le problĂšme suivant est liĂ© au fait que la commande shell n'a pas d'Ă©tat du point de vue d'ansible. Il n'y aura donc pas de vĂ©rification automatique pour savoir si cette version de ruby est installĂ©e ou non â nous devons le faire nous-mĂȘmes :
- name: Installer 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/bashIl reste Ă installer bundler :
- name: Installer bundler
become_user: "{{ user }}"
shell: |
export PATH="${HOME}/.rbenv/bin:${PATH}"
eval "$(rbenv init -)"
gem install bundlerEt encore une fois, ajouter notre rĂŽle ruby_rbenv au playbook principal.
Fichiers partagés.
En gĂ©nĂ©ral, Ă ce stade, la configuration pourrait ĂȘtre terminĂ©e. Ensuite, il suffit d'exĂ©cuter capistrano et il copiera automatiquement le code, crĂ©era les rĂ©pertoires nĂ©cessaires et lancera l'application (si tout est configurĂ© correctement). Cependant, capistrano nĂ©cessite souvent des fichiers de configuration supplĂ©mentaires, tels que database.yml ou .env Ils peuvent ĂȘtre copiĂ©s de la mĂȘme maniĂšre que les fichiers et modĂšles pour nginx. Il y a juste un petit dĂ©tail. Avant de copier les fichiers, il faut crĂ©er leur structure de rĂ©pertoires, quelque chose comme cela :
# Copy shared files for deploy
- name: Ensure shared dir
become_user: "{{ user }}"
file:
path: "{{ app_path }}/shared/config"
state: directorynous indiquons seulement un répertoire et ansible créera automatiquement les parents, si besoin.
Ansible Vault
Nous avons déjà rencontré le fait que des données sensibles telles que le mot de passe utilisateur peuvent se retrouver dans les variables. Si vous avez créé .env un fichier pour l'application, et database.yml il devrait y avoir encore plus de ces données critiques. Il serait préférable de les cacher des yeux indiscrets. Pour cela, nous utilisons .
Créons un fichier pour les variables /ansible/vars/all.yml (vous pouvez créer différents fichiers pour différents groupes d'hÎtes, tout comme dans le fichier d'inventaire : production.yml, staging.yml, etc.).
Ce fichier doit contenir toutes les variables qui doivent ĂȘtre encryptĂ©es, en utilisant la syntaxe yml standard :
# 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_baseAprĂšs quoi ce fichier peut ĂȘtre encryptĂ© avec la commande :
ansible-vault encrypt ./vars/all.ymlĂvidemment, lors de l'encryptage, vous devrez dĂ©finir un mot de passe pour le dĂ©cryptage. Vous pouvez voir ce qu'il y a Ă l'intĂ©rieur du fichier aprĂšs avoir exĂ©cutĂ© cette commande.
à l'aide de ansible-vault decrypt vous pouvez déchiffrer le fichier, le modifier et le chiffrer à nouveau.
Pour travailler, il n'est pas nécessaire de déchiffrer le fichier. Vous le conservez sous forme chiffrée et exécutez le playbook avec l'argument --ask-vault-pass. Ansible demandera le mot de passe, récupérera les variables et exécutera les tùches. Toutes les données resteront chiffrées.
La commande complĂšte pour plusieurs groupes d'hĂŽtes et ansible vault ressemblera Ă quelque chose comme ceci :
ansible-playbook -i inventory ./playbook.yml -l "staging" --ask-vault-passEt je ne vous donnerai pas le texte complet des playbooks et des rĂŽles, Ă©crivez vous-mĂȘme. Parce qu'ansible est une chose comme ça - si vous ne comprenez pas ce qu'il faut faire, il ne le fera pas non plus.
Source : habr.com
