Monthly Archives: October 2018

Ansible par la pratique – Deuxième partie: Premiers playbooks avec les rôles

Premiers playbooks utilisant les rôles

Ce tutoriel est la suite de la première partie consacrée à ansible.

On va partir de l’hypothèse que l’on veut un blog sur notre VPS CentOS 7, en l’occurrence wordpress. Le nom d’hôte pleinement qualifié sera blog.example.com.

Pour ce faire il nous faudra donc un LAMP. Nous n’allons pas parler sécurité, tout du moins pas encore, c’est notre premier jet. On n’utilisera pas le coffre comme vu précédemment et ce sera l’utilisateur root qui fera l’installation. C’est vraiment pas fait pour de la production en l’état. Dans la partie production, il faudra ajouter un utilisateur pouvant utiliser sudo, configurer finement SSH pour ne pas accepter les connexions avec le super-utilisateur root, etc… Ce sera pour plus tard.

Afin de ne pas s’exposer inutilement sur internet, on va faire l’installation d’une machine virtuelle sur notre poste de travail, qui lui a Fedora d’installé (mais ce n’est pas obligatoire). Je ne vais pas détailler l’installation de la machine,  ce serai hors sujet et alourdirai encore ce tutoriel, mais on va partir d’une installation toute neuve:

  • L’adresse de cette machine est 192.168.122.10.
  • Le partitionnement est déjà effectué à l’installation, on n’y touchera pas.
  • Le nom d’hôte a été renseigné ou pas, on le remettra de toute façon en jouant notre playbook.
  • Le mot de passe root est déjà mis à l’installation.
  • Le réseau a été activé et la machine est joignable en SSH par l’utilisateur root.

L’intégralité des fichiers est versionné sur gitlab, en prenant le tag tuto-ansible-2. En effet la branche master va évoluer avec l’avancement de ce tutoriel en plusieurs parties.

git clone https://gitlab.com/tartare-tutorial/ansible.git
cd ansible
git checkout tags/tuto-ansible-2

Mise en place de l’arborescence

Les environnements

On va créer nos deux répertoires d’environnement :

  • production
  • staging

On ne va pas s’occuper de l’environnement de production pour l’instant, ce répertoire restera vide, pour l’instant. Dans celui destiné aux tests, on placera un fichier hosts (fichier au format INI), et deux répertoires pouvant accueillir chacun un fichier de définition de variables

  • pour les hôtes: host_vars
  • pour les groupes d’hôtes: group_vars

En résumé, sur notre station de travail, dans un répertoire dédié, ça se résume à ça:

mkdir -p production staging/{group,host}_vars
touch staging/hosts staging/group_vars/vps.yml staging/host_vars/192.168.122.10.yml

On édite nos fichiers:

Fichier staging/hosts
[vps]
192.168.122.10

Les variables définies dans ce fichier seront prioritaires à celle définies dans le rôle, et même à celle définies dans le fichier de groupe (
staging/group_vars/vps.yml). La doc officielle en parle mieux que moi.

Fichier staging/host_vars/192.168.122.10.yml
hostname:
  short: blog
  domain: example.com

Le fichier staging/group_vars/vps.yml est juste un fichier vide il ne nous sert pas pour l’instant.

Les Roles

On va créer nos trois rôles, c’est à dire un fichier YAML à la racine du projet, plus un autre, site.yml, qui inclura tous nos rôles et quatre répertoires d’accueil pour nos rôles :

  • common: un pseudo rôle qui sera inclus dans tous les autres rôles. C’est ici que l’on va mettre tous ce qui peut servir dans plusieurs rôle. Par exemple une fonction déclenchée pour redémarrer le service apache
  • system: un rôle qui sera chargé de la post-installation de notre serveur:
    • Installation du dépôt additionnel EPEL.
    • Gérer les paquets: Installation, suppression ou remplacement de paquets RPM.
    • Activer SELinux s’il n’est pas encore activé.
    • Installer et configurer etckeeper pour versionner le répertoire /etc.
    • Définir le nom d’hôte.
    • Activer le pare-feu.
    • Configurer la mise à l’heure (avec des serveurs géographiquement proches).
    • Rendre la journalisation système permanente.
    • Gérer l’activation/désactivation, le démarrage ou l’arrêt de services.
  • lamp: un rôle qui sera chargé de l’installation de notre LAMP (Linux-Apache-Mariadb-PHP):
    • Installation du serveur web.
    • Installation du gestionnaire de base de données et de son initialisation.
    • Installation du module apache PHP et modification du fichier /etc/php.ini.
    • Ouverture du port HTTP sur le pare-feu.
  • blog: un rôle qui sera chargé de l’installation de wordpress:
    • Mise en place de la base de données pour wordpress.
    • Initialisation de wordpress.

Ce qui revient à faire

touch {system,lamp,blog,site}.yml
mkdir -p roles/{common,system,lamp,blog}

Jusqu’ici pas de mystère. Pour chaque rôle, on va créer l’arborescence préconisée par Ansible. Les répertoires vides peuvent tout à fait être omis. Seul celui commun à tous (common) aura une arborescence simplifiées dès sa création.

Je ne vous l’avais pas encore dit, mais ansible s’attend à trouver un fichier main.yml à l’intérieur des sous-répertoires du rôle (sauf pour les répertoires files et templates, qui sont respectivement dédiés aux fichiers à copier et aux fichiers modèles à interpréter par Jinja2).

Un rôle doit contenir au moins un des répertoires suivant:

  • tasks: Contient la liste des tâches devant être effectuées pour ce rôle
  • handlers: Contient les fonctions déclenchées par les tâches du rôle ou comme ici pour le rôle commun, dans n’importe quel rôle incluant ce pseudo rôle.
  • defaults: Contient  les variables par défaut pour ce rôle.
  • vars: Contient  les variables pour ce rôle. Celles-ci sont prioritaire sur celles du répertoire default.
  • files: Contient les fichiers devant être déployés par ce rôle.
  • templates: Contient les fichiers modèles devant être déployés par ce rôle (interprétés par jinja2)
  • meta: Contient les définitions des méta-données pour ce rôle, c’est à dire définir les dépendances du rôle.

Ce qui revient à faire

mkdir roles/common/{handlers,defaults} roles/{system,lamp,blog}/{tasks,handlers,defaults,vars,files,templates,meta}
touch roles/common/{handlers,defaults}/main.yml roles/{system,lamp,blog}/{tasks,handlers,defaults,vars,meta}/main.yml

Voici à quoi ressemble désormais notre arborescence: les répertoires en bleu et les fichiers en noir.

├── production
├── roles
│   |── common
│   |   └── handlers
|   |       └── main.yml
│   |── system
│   |   ├── defaults
|   |   |   └── main.yml
│   |   ├── files
│   |   ├── handlers
|   |   |   └── main.yml
│   |   ├── tasks
|   |   |   └── main.yml
│   |   ├── templates
│   |   └── vars
|   |   |   └── main.yml
│   |── lamp
│   |   ├── defaults
|   |   |   └── main.yml
│   |   ├── files
│   |   ├── handlers
|   |   |   └── main.yml
│   |   ├── tasks
|   |   |   └── main.yml
│   |   ├── templates
│   |   └── vars
|   |   |   └── main.yml
│   └── blog
│       ├── defaults
|       |   └── main.yml
│       ├── files
│       ├── handlers
|       |   └── main.yml
│       ├── tasks
|       |   └── main.yml
│       ├── templates
│       └── vars
|           └── main.yml
|── staging
|   ├── group_vars
|   ├── host_vars
|   |   └── 192.168.122.10.yml
|   └── hosts
├── blog.yml
├── lamp.yml
├── site.yml
└── system.yml

Définition des playbooks et des roles

Certes, les fichiers sont vides, mais on va maintenant les remplir.

Les playbooks

Commençons par le plus facile, celui qui sera joué pour l’installation de notre VPS. Ce n’est qu’une inclusion des autres playbooks, ceux définissant nos rôles.

Fichier site.yml
- import_playbook: system.yml
- import_playbook: lamp.yml
- import_playbook: blog.yml
Maintenant, pas plus compliqué, on définit nos rôles dans des playbooks:
  • Définition des hôtes cibles, ici on met soit un liste d’hôte, soit un groupe. Notre groupe s’appelle vps, on va l’utiliser.
  • Définition de la liste de rôles, ici notre pseudo rôle pour les fonctions déclenchées et notre rôle à proprement parler, c’est à dire le nom du sous-répertoire à utiliser dans le répertoire roles.
Fichier system.yml
- hosts: vps
  roles:
    - common
    - system
Fichier lamp.yml
- hosts: vps
  roles:
    - common
    - lamp
Fichier blog.yml
- hosts: vps
  roles:
    - common
    - blog

Les rôles

Le role commun

Le handler commun définit le redémarrage d’un service: le serveur web. En effet celui-ci sera utilisé par le rôle lamp et par le rôle blog.

Fichier roles/common/handlers/main.yml
- name: restart httpd
  service: name=httpd state=restarted

Le fichier de variable par défaut commun contient le fuseau horaire, qui sera utilisé par les rôles system et lamp.

Fichier roles/common/defaults/main.yml
localtime: "Europe/Paris"

Le rôle système

Pour le rôle system, on va se faire plaisir, on va le découper en petits morceaux, c’est plus digeste. C’est pourquoi le fichier roles/common/handlers/main.yml ne contiendra que des inclusions.

Fichier roles/system/tasks/main.yml
- include_tasks: repos.yml
- include_tasks: packages.yml
- include_tasks: selinux.yml
- include_tasks: etckeeper.yml
- include_tasks: hostname.yml
- include_tasks: firewall.yml
- include_tasks: chrony.yml
- include_tasks: journald.yml
- include_tasks: services.yml

Ce fichier de tâche va installer le dépôt additionnel EPEL.

Fichier roles/system/tasks/repos.yml
# Repositories
- name: Ensure epel repository is set
  yum:
    name: epel-release
    state: latest

Ce fichier de tâche va s’assurer que tous les paquets sont à jour, installer les paquets que l’on souhaite ajouter à notre VPS et désinstaller les paquets que l’on ne veut pas.

Concrètement, on veut que le serveur de courrier soit postfix et non sendmail ou ssmtp, comme dans le VPS livré par fistheberg.

La liste des paquets que l’on souhaite installer sera défini plus loin, dans le fichier roles/system/defaults/main.yml.

Comme vu précédemment, il pourra être surchargé dans le fichier roles/system/vars/main.yml (de manière globale, quelque soit l’environnement: staging ou production) ou même dans le fichier staging/host_vars/192.168.122.10.yml si c’est que pour l’environnement staging.

Il est à noter que pour rendre notre surcharge indépendante de l’environnement, on peut aussi définir la liste dans le fichier variable de groupe staging/group_vars/vps.yml

Fichier roles/system/tasks/packages.yml
# System update
- name: Ensure all pkgs are up-to-date
  yum:
    name: '*'
    state: latest

# Uninstall unwanted packages
- name: Ensure unwanted packages of services are absent
  yum: 
    list: "[u'ssmtp', u'sendmail']"
    state: absent

# Install packages
- name: Ensure packages are installed and up-to-date
  yum:  
    name: "{{ packages }}"
    state: latest
  vars:
    packages: "{{ rpms }}"

Ce fichier de tâche va s’assurer que les paquets nécessaires à SELinux soit présents.

Si ce n’est pas le cas, il les installe et créé le fichier /.autorelabel pour déclencher le ré-étiquetage de l’intégralité de notre système au prochain démarrage. Par contre le fichier n’est pas créer si SELinux est déjà installé.

Fichier roles/system/tasks/selinux.yml
# Install packages
- name: Ensure selinux packages are installed and up-to-date
  yum: 
    list: "[u'selinux-polic', u'selinux-policy-targeted']"
    state: latest
  register: selinux_install
  
- name: Ensure autorelabel is set if selinux was disabled
  file:
    path: "/.autorelabel"
    owner: root
    group: root
    mode: 0600
    state: touch  
  when: selinux_install is changed

Ce fichier de tâche va initialiser etckeeper.

Il a été installé par le fichier de tâches roles/system/tasks/packages.yml, donc pas la peine de faire des doublons.

Fichier roles/system/tasks/etckeeper.yml
# Manage etckeeper
- name: Ensure etc is versionned
  shell: "etckeeper init"
  args:
    executable: /bin/bash
    creates: /etc/.git
    chdir: /etc
  
- name: Ensure first commit is done for etc
  shell: "etckeeper commit 'First commit'"
  args:
    executable: /bin/bash
    creates: /etc/.git/refs/heads/master
    chdir: /etc 

Ce fichier de tâche va fixer le nom d’hôte.

Il va en plus modifier le motd pour afficher le nom d’hôte et l’adresse IP de notre système à la connexion, que se soit en direct sur une console virtuelle, ou à distance par une connexion SSH.

On est d’accord, ça sert pas à grand chose mais ça permet de montrer comment interpréter un fichier modèle avec une variable définie par nos soins dans le rôle et une autre qui est prise automatiquement par ansible dans la phase Gathering Facts.

Fichier roles/system/tasks/hostname.yml
# Set Hostname
- name: Ensure hostname is set
  hostname:
    name: "{{ hostname.short }}.{{ hostname.domain }}"

# Define banners
- name: Define banners
  template:
    src: "motd"
    dest: "/etc/motd"
    owner: root
    group: root
    mode: 0644

Ce fichier de tâche va s’assurer que le pare-feu est démarré et bien activé au démarrage.

Il va aussi ouvrir, si besoin, le pare-feu pour les connexions distantes par SSH.

Fichier roles/system/tasks/firewall.yml
# Manage firewall service
- name: Ensure firewalls is started and enabled
  systemd:
    name: firewalld
    enabled: yes
    masked: no
    state: started
    daemon_reload: yes

# Manage firewall: open ssh
- name: Ensure firewall rules are set
  firewalld: 
    service: ssh
    permanent: true
    immediate: true
    state: enabled

Ce fichier de tâche va définir notre fuseau horaire avec une variable défini dans le fichier roles/system/defaults/main.yml.

Il va en plus faire utiliser prioritairement à chrony, non pas le groupe de centos, mais un groupe encore une fois défini par nos soins dans le fichier de variables.

Fichier roles/system/tasks/chrony.yml
# Set timezone
- name: Ensure localtime is CEST
  file:
    src: "/usr/share/zoneinfo/{{ localtime }}"
    dest: "/etc/localtime"
    owner: root
    group: root
    state: link

# Configure chrony
- name: Ensure chrony use our ntp server pools before centos ones
  lineinfile: 
    path: /etc/chrony.conf
    line: 'server {{ item }}.{{ ntp_pool_domain }} iburst'
    regexp: '^server {{ item }}.{{ ntp_pool_domain }} iburst'
    insertbefore: 'server 0.centos.pool.ntp.org iburst'
  with_items: [ 0, 1, 2, 3 ]
  notify:
  - restart chronyd

Ce fichier de tâche va rendre persistant les fichiers journaux de journalctl.

En effet, par défaut, ces journaux ne survivent pas à un redémarrage. Ça consiste juste à créer le répertoire, journalctl sait quoi faire si il trouve ce répertoire.

Cette action actionne deux fonctions déclenchées qui seront renseignées et expliquées plus loin.

Fichier roles/system/tasks/journald.yml
# systemd-journald
- name: Ensure persistent storage of log messages is enabled
  file:
    path: "/var/log/journal"
    state: directory
    owner: root
    group: systemd-journal
    mode: 02755
  notify:
  - create tmpfiles journald
  - restart journald

Ce fichier de tâche va s’assurer que les services de courrier, de mise à l’heure automatique et de journalisation soient démarrés et activés.

Fichier roles/system/tasks/services.yml
# Manage all services
- name: Ensure services are started and enabled
  systemd:
    name: "{{ item }}"
    enabled: yes
    masked: no
    state: started
    daemon_reload: yes
  with_items:
  - postfix
  - chronyd
  - rsyslog

Ce fichier de variable va définir notre liste de paquets RPM que l’on souhaite installer et nos groupes de serveur de temps.

Fichier roles/system/defaults/main.yml
rpms:
  - postfix
  - chrony
  - multitail
  - mlocate
  - screen
  - vim-enhanced
  - yum-utils
  - bzip2
  - unzip
  - bind-utils
  - man-pages
  - net-tools
  - tree
  - uuid
  - etckeeper
  - wget
  - yum-utils
  - NetworkManager
  - rsyslog

ntp_pool_domain: fr.pool.ntp.org

Ce fichier décrit les fonctions déclenchées:

  • S’assurer de l’existance du répertoire volatile nécesaire au redémarrage du service de journalisation
  • Redémarrer le service systemd de journalisation
  • Redémarrer le service de mise à l’heure automatique
Fichier roles/system/handlers/main.yml
- name: create tmpfiles journald
  shell: "systemd-tmpfiles --create --prefix /var/log/journal"
  args:
    executable: /bin/bash

- name: restart journald
  service: name=systemd-journald state=restarted

- name: restart chronyd
  service: name=chronyd state=restarted

Ce fichier va remplacer le fichier /etc/motd du système après avoir été interpréter par le moteur de modèle jinja2.

Les variables hostname.short et hostname.domain sont définies par nos soins.

La variable ansible_default_ipv4.address est acquise par ansible au début de l’exécution de notre playbook, dans la partie Gathering Facts.

Fichier roles/system/templates/motd
##############################################################################

                     Hostname : {{ hostname.short }}.{{ hostname.domain }}  
                     IPv4 :     {{ ansible_default_ipv4.address }}
              
##############################################################################

Le rôle lamp

Ce fichier de définition de variables par défaut va renseigner la liste des paquets RPM à installer, définir la liste des booleans SELinux à activer et le mot de passe root pour mariadb.

Les paquets libsemanage-python et MySQL-pythonsont indispensables pour gérer les booleans SELinux et la configuration de la base de données via ansible.

Fichier roles/lamp/defaults/main.yml
rpms:
  - mariadb-server
  - httpd
  - php
  - php-mysqlnd
  - libsemanage-python
  - MySQL-python

selinux_booleans:
  - httpd_can_network_connect
  - httpd_can_sendmail
  - httpd_unified
  - httpd_enable_homedirs
  
dbrootpasswd: "monsupermotdepasse"

Ce fichier de fonctions déclenchées va définir le redémarrage du service mariadb.

Fichier roles/lamp/handlers/main.yml
- name: restart mariadb
  service: name=mariadb state=restarted

Ce fichier de tâche va:

    • Installer les paquets RPM spécifiés dans le fichier roles/lamp/defaults/main.yml.
    • Ouvrir le pare-feu pour le service HTTP (port 80).
    • Configurer un minimum PHP en mettant le fuseau horaire, ainsi que le jeu de caractères en UTF-8.
    • S’assurer que le serveur web et le SGBD sont démarrés et activés au démarrage.
    • Que le service de base de données ne soit accessible que localement.
    • Sécurise un minimum le service de base de données, aussi bien qu’avec l’exécutable mysql_secure_installation:
      • Mettre en service le mot de passe root, pour l’utilisateur root local.
      • S’assurer que l’on peut se connecter à mariadb sans mot de passe avec l’utilisateur root, en créant un fichier .my.cnf dans le HOME de l’utilisateur (ici c’est root).
      • Mettre en service le mot de passe root, pour l’utilisateur root distant.
      • Supprime les utilisateurs mariadb inutiles.
      • Supprime les bases de données inutiles.
Fichier roles/lamp/tasks/main.yml
# Install packages
- name: Ensure packages of services are installed and up-to-date
  yum: 
    name: "{{ packages }}"
    state: latest
  vars:
    packages: "{{ rpms }}"

# Manage firewall
- name: Ensure firewall rules are set
  firewalld: 
    service: http
    permanent: true
    immediate: true
    state: enabled

# Configure php
- name: Ensure php is configured
  lineinfile: 
    path: /etc/php.ini
    regexp: '^{{ item.key }}'
    line: '{{ item.key }} = {{ item.value }}'
    insertafter: '{{ item.after }}'
  with_items: 
  - key: default_charset
    value: "\"UTF-8\""
    after: ";default_charset = \"UTF-8\""
  - key: date.timezone
    value: "\"{{ localtime }}\""
    after: ";date.timezone.*"
  
- name: Ensure SELinux allow httpd to do a lot of things
  seboolean:
    name: "{{ item }}"
    state: yes
    persistent: yes
  with_items: "{{ selinux_booleans }}"

# Manage all services
- name: Ensure services are started and enabled
  systemd:
    name: "{{ item }}"
    enabled: yes
    masked: no
    state: started
    daemon_reload: yes
  with_items:
  - mariadb
  - httpd
  
# Manage mariadb service
- name: Ensure mariadb binds localhost only
  lineinfile: 
    path: /etc/my.cnf.d/server.cnf
    regexp: 'bind-address = localhost'
    line: 'bind-address = localhost'
    insertafter: '\[mysqld\]'
  notify:
  - restart mariadb
  
# Add mysql users and databases;
# Need to do this for idempotency, see
# http://ansible.cc/docs/modules.html#mysql-user
- name: Ensure mysql root password for localhost root account is updated
  mysql_user:
    name: root
    host: "localhost"
    password: "{{ dbrootpasswd }}"
    
- name: Ensure .my.cnf file with root password credentials exists
  blockinfile:
    path: /root/.my.cnf
    owner: root
    group: root
    mode: 0600
    create: yes
    marker: "# {mark} ANSIBLE MANAGED BLOCK #"
    block: |
      [client]
      user = root
      password = {{ dbrootpasswd }}

- name: Ensure mysql root password for all others root accounts is updated
  mysql_user:
    name: root
    host: "{{ item }}"
    password: "{{ dbrootpasswd }}"
  with_items:
    - "127.0.0.1"
    - "::1"

- name: Ensure default none-needed users are deleted
  mysql_user:
    name: ''
    host: "{{ item }}"
    state: absent
  with_items:
    - user: ''
      host: "localhost"
    - user: ''
      host: "{{ hostname.short }}.{{ hostname.domain }}"
    - user: "root"
      host: "{{ hostname.short }}.{{ hostname.domain }}"

- name: Remove the test database
  mysql_db:
    name: test
    state: absent

Le rôle blog

Le fichier de définition de variables par défaut var renseigner la liste des paquets à installer, les paramètres de la base de données pour wordpress: nom de la base, l’utilisateur et son mot de passe.

Ici on va montrer comment redéfinir les variables dans un tabbleau associatif (aussi appelé hash) dans un format que l’on pourra utiliser directement dans notre fichier de tâches, sans redéfinir une seconde fois le contenu des variables.

Fichier roles/blog/defaults/main.yml
rpms:
  - wordpress
  - php-pecl-imagick

databases:
  wordpress:
    user: wordpress
    passwd: wordpresspasswd
    base: wordpress

wordpress:
  settings:
    DB_NAME: "{{ databases.wordpress.base }}"
    DB_USER: "{{ databases.wordpress.user }}"
    DB_PASSWORD: "{{ databases.wordpress.passwd }}"

Le fichier de tâches va:

  • Installer les paquets RPM spécifiés dans le fichier roles/blog/defaults/main.yml.
  • Créer la base de données pour wordpress.
  • Créer l’utilisateur mariadb qui aura un accès total à cette base de données uniquement.
  • Configurer wordpress au minimum, c’est à dire renseigner dans le fichier de configuration de wordpress l’utilisateur mariadb, son mot de passe ainsi que le nom de la base.
  • Va mettre les bons droits sur certains répertoires et fichiers.
Fichier roles/blog/tasks/main.yml
# Install RPM package(s)
- name: Ensure RPM(s) are installed and up-to-date
  yum: 
    name: "{{ packages }}"
    state: latest
  vars:
    packages: "{{ rpms }}"

- name: Ensure database exists
  mysql_db:
    name: "{{ databases.wordpress.base }}"
    state: present
    encoding: utf8
  
- name: Ensure database user exists
  mysql_user: 
    name: "{{ databases.wordpress.user }}"
    host: localhost
    password: "{{ databases.wordpress.passwd }}"
    priv: '{{ databases.wordpress.base }}.*:ALL'
    
- name: Ensure wordpress config link exists
  file:
    src: "/etc/wordpress/wp-config.php"
    dest: "/usr/share/wordpress/wp-config.php"
    state: link

# Manage wordpress
- name: Ensure WordPress is configured
  lineinfile: 
    path: /etc/wordpress/wp-config.php
    regexp: "define.*'{{ item.key }}'"
    line: "define('{{ item.key }}', '{{ item.value }}' );"
  with_dict: "{{ wordpress.settings }}"
    
- name: Ensure some WordPress directories are owned by apache
  file:
    path: "/usr/share/wordpress/wp-content/{{ item }}"
    state: directory
    owner: apache
    group: ftp
    mode: 2775
  with_items:
    - gallery
    - uploads
  
- name: Ensure wordpress config files have apache group
  file:
    dest: "{{ item }}"
    owner: root
    group: apache
    mode: 0640  
  with_items:      
  - "/etc/wordpress/wp-config.php"

- name: Ensure wordpress alias is defined for httpd
  copy:
    src: "wordpress.conf"
    dest: "/etc/httpd/conf.d/wordpress.conf"
    backup: yes
  notify:
  - restart httpd

Le nouveau fichier de configuration apache pour wordpress. En effet celui fournit par le paquet restreint l’accès au système (localhost).

Fichier roles/blog/files/wordpress.conf
Alias /wordpress /usr/share/wordpress

<Directory /usr/share/wordpress>
  AllowOverride Options
  Require all granted
</Directory>

<Directory /usr/share/wordpress/wp-content/uploads>
  # Deny access to any php file in the uploads directory
  <FilesMatch "\.(php)$">
    Require all denied
  </FilesMatch>
</Directory>

<Directory /usr/share/wordpress/wp-content/plugins/akismet>
  # Deny access to any php file in the akismet directory
  <FilesMatch "\.(php|txt)$">
    Require all denied
  </FilesMatch>
</Directory>

Exécution de nos playbooks

Le lancement est maintenant bien connu, on spécifie notre environment et notre utilisateur, et on déploie le playbook général d’installation site.yml. Si on n’a pas copié notre clé publique SSH sur le serveur, il faudra aussi rajouter l’option --ask-pass.

ansible-playbook -i staging --user root site.yml

Il est possible qu’un nouveau noyau, ou un composant essentiel ai été mise à jour avec notre playbook, on redémarrera donc notre système.

On peut vérifier qu’un redémarrage est nécessaire avec la commande needs-restarting, elle a été installée avec le rôle system (paquet yum-utils).

needs-restarting -r

Et voilà, il ne reste plus que la post-installation à faire en pointant son navigateur vers la page d’administration de wordpress. Encore une fois, notre déploiement permet de mettre facilement en place un wordpress, sans chercher à le sécuriser. Mais c’est suffisant pour faire du développement wordpress.

Conclusion

Voilà, j’espère vous avoir donner envie d’adopter ce merveilleux outil de déploiement, on peut tout faire avec. La prochaine partie sera consacré à une utilisation plus avancée de nos playbooks et la dernière partie à la partie production et donc plus axée sur la sécurité, mais on va presque tout ré-utiliser, alors gardez le répertoire racine de ce déploiement bien au chaud, il resservira.

Ajouter de la SWAP sur un VPS


Les VPS sont livrés avec un disque virtuel contenant une partition unique occupant tout l’espace. Il n’est donc pas possible de modifier le schéma de partitionnement.
Heureusement pour nous, Linux accepte deux types de swap:

  • une partition dédiée
  • un fichier d’échange

Et c’est avec ce deuxième type que l’on va pouvoir ajouter de la swap.

    1. Création d’un fichier d’échange de 2Go
      dd if=/dev/zero of=/var/tmp/swapfile bs=1G count=2
    2. On force la synchronisation des disques (c’est à dire: écrire sur le disque toutes les données présentes dans les tampons en mémoire)
      sync
    3. On modifie les droits de ce fichier d’échange
      chmod 0600 /var/tmp/swapfile
    4. Initialisation du fichier d’échange, afin d’être utilisable comme extension de mémoire. Jusqu’ici le fichier avait l’étiquette SELinux user_tmp_t. La commande suivante va aussi changer l’étiquette pour swapfile_t.
      mkswap -c /var/tmp/swapfile
    5. On active notre nouvelle swap
      swapon /var/tmp/swapfile

Pour rendre l’utilisation de notre fichier swap permanent, il faut rajouter la ligne suivante dans le fichier /etc/fstab. C’est la même ligne que pour une partition d’échange, mis à part le chemin absolu du fichier, en lieu et place du chemin absolu du périphérique.

/var/tmp/swapfile swap swap defaults 0 0