Salt States by Example | Part 3 | Install MySQL, PHP and PHP-FPM using Saltstack

By: rahul On: Sun 01 October 2017
In: Devops
Tags: #devops #configuration-management #linux #saltstack

Greetings Wanderer!

This is a continuation on our attempt to write a complete Salt State. Before proceeding, if you haven't already, please check the links/articles listed below:

> Saltstack By Example | Part 1 | Installation
> Saltstack By Example | Part 2 | Configuration
> Saltstack By Example | Part 3 | Basic Commands
> Saltstack By Example | Part 4 | Salt State Examples

> Salt States by Example | Part 1 | Install a Salt Minion on CentOS or Debian
> Salt States by Example | Part 2 | Install Nginx using Saltstack
>> Salt States by Example | Part 3 | Install MySQL, PHP and PHP-FPM using Saltstack (<== We are here)

In the previous article, we saw how to install a few software packages and Nginx on a Salt Minion. In this post, we'll see how to go about installing MySQL/MariaDB and PHP on the Salt Minion.

Prerequisites
  • A Salt Master
  • A Salt Minion that runs a Debian minimal install or a CentOS minimal install - the installation is outlined in Part 1
  • This is what our directory structure looks like:
.
|-- common    <=== COMPLETED
|-- nginx     <=== COMPLETED
|   `-- repofiles
|-- mysql
|-- php
|   `-- files
|-- wordpress 
|   `-- files
|-- wpcli
|   `-- files
`-- wp_user
    `-- files
        |-- templates
        `-- wptest
            |-- logs
            `-- public_html

1. MySQL Installation - How to install MySQL using Saltstack (or install MariaDB using Saltstack)

1a. First, we'll begin by declaring a few variables, using the map.jinja file (mysql/map.jinja):

{%  set mysql = salt['grains.filter_by']({
    'Debian': {
        'pkgs': ['mysql-server', 'python-mysqldb', 'libmysqld-dev'],
        'service': 'mysql',
        'configfile': '/etc/mysql/my.cnf',
    },
    'RedHat': {
        'pkgs': ['mariadb', 'mariadb-server', 'MySQL-python', 'mariadb-devel'],
        'service': 'mariadb',
        'configfile': '/etc/my.cnf',
    }
}) %}

1b. The next step would be to install MySQL, for which, we'll create a file called packages.sls(mysql/packages.sls) and add the following code:

{%- from "wordpresser/mysql/map.jinja" import mysql %}

install_mysql:
  pkg.installed:
    - names: {{ mysql.pkgs }}

reload-mysql:
  service.running:
    - name: {{ mysql.service }}
    - enable: True
    - reload: True

1c. We also need to open the port 3306 in the firewall, which we'll do with firewalld - create a file called firewalld.sls(mysql/firewalld.sls) and add the following code:

open_mysql_port:
  firewalld.present:
    - name: public
    - ports:
      - 22/tcp
      - 80/tcp
      - 443/tcp
      - 3306/tcp

1d. One last step in this process is to set a MySQL root password, remove the empty test DBs and the anonymous MySQL users, and disable remote login for the MySQL root user. Usually, this is done using the script mysql_secure_installation, whose behaviour we'll replicate using a file called mysql_secure.sls(mysql/mysql_secure.sls). Add the following code:

{% from "wordpresser/mysql/map.jinja" import mysql %}
{% set mysql_root_pass = salt['pillar.get']('mysql:server:root_password', salt['grains.get']('server_id')) %}

root_user:
  mysql_user.present:
    - name: 'root'
    - password: {{ mysql_root_pass }}

mysql remove anonymous users:
  mysql_user.absent:
    - name: ''
    - host: 'localhost'
    - connection_user: 'root'
    - connection_pass: '{{ mysql_root_pass }}'
    - connection_charset: utf8

mysql remove test database:
  mysql_database.absent:
    - name: test
    - host: 'localhost'
    - connection_user: 'root'
    - connection_pass: '{{ mysql_root_pass }}'
    - connection_charset: utf8

disable remote login for root:
  mysql_query.run:
    - database: 'mysql'
    - query: "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');"
    - output: "/tmp/removehostroot.txt"
    - host: 'localhost'
    - connection_user: 'root'
    - connection_pass: '{{ mysql_root_pass }}'
    - connection_charset: utf8

mysql_restart:
  module.wait:
    - name: service.restart
    - m_name: {{ mysql.service }}

Here's what the completed mysql directory structure should look like:

mysql/
|-- firewalld.sls
|-- map.jinja
|-- mysql_secure.sls
`-- packages.sls

2. PHP Installation - Install PHP using Saltstack

2a. Again, we'll begin by decalring a few variables using a new map.jinja file (php/map.jinja):

{%  set php = salt['grains.filter_by']({
    'Debian': {
        'pkgs': ['php5', 'php5-mysql', 'php-pear', 'php5-cli', 'php5-common', 'php5-dev', 'libapache2-mod-php5', 'php5-fpm', 'php5-gd'],
        'service': 'php5-fpm',
        'docroot': '/var/www/html/',
    'phpini': '/etc/php5/fpm/php.ini',
    'phpwww': '/etc/php5/fpm/pool.d/www.conf',
    },
    'RedHat': {
        'pkgs': [ 'php', 'php-cli', 'php-common', 'php-devel', 'php-mbstring', 'php-pdo', 'php-pear', 'php-mysql', 'php-gd', 'php-fpm', 'php-xml'],
        'service': 'php-fpm',
        'docroot': '/var/www/html/',
    'phpini': '/etc/php.ini',
    'phpwww': '/etc/php-fpm.d/www.conf',
    }
}) %}

2b. There're a couple of PHP files and a couple of configuration files that we'll save/store on the Salt master and copy it over to the respective Minion, during the Salt run. These are stored under a new directory called files (php/files):

php/files/
|-- default.conf
|-- info.php
|-- www.conf_centos
`-- www.conf_deb

The contents of the files can be read and accessed from this link - wordpresser/php/files - the default.conf is Nginx's default configuration file, info.php is a basic PHP info file, and the www.conf_centos and www.conf_deb files are the OS-specific www.conf files required by PHP-FPM.

2c. Now, onto the PHP installation section. We'll create a file called packages.sls (php/packages.sls) and add the following code:

{%- from "wordpresser/php/map.jinja" import php %}

install_php:
  pkg.installed:
    - names: {{ php.pkgs }}

php-fpm-service:
  service.running:
    - name: {{ php.service }}
    - enable: True
    - watch:
      - pkg: {{ php.service }}
    - require:
      - pkg: {{ php.service }}

copy_info_file:
  file.managed:
    - name: /usr/share/nginx/html/info.php
    - source: salt://wordpresser/php/files/info.php
    - makedirs: True

php.ini-conf:
  file.replace:
    - name: {{ php.phpini }}
    - pattern: ";cgi.fix_pathinfo=1"
    - repl: "cgi.fix_pathinfo=0"

www.conf-listen.mode:
  file.managed:
    - name: {{ php.phpwww }}
    {% if grains['os_family'] == 'Debian' %}
    - source: salt://wordpresser/php/files/www.conf_deb
    {% elif grains['os_family'] == 'RedHat' %}
    - source: salt://wordpresser/php/files/www.conf_centos
    {% endif %}

{% if grains['os_family'] == 'Debian' %}
add-nginx-to-wwwdata:
  group.present:
    - name: www-data
    - addusers:
      - nginx

copy_default_conf:
  file.managed:
    - name: /etc/nginx/conf.d/default.conf
    - source: salt://wordpresser/php/files/default.conf
    - backup: minion
{% endif %}

{% if grains['os_family'] == 'RedHat' %}
selinux-state-temp:
  cmd.run:
    - name: setenforce 0

selinux-state-perm:
  file.replace:
    - name: /etc/selinux/config
    - pattern: "SELINUX=enforcing"
    - repl: "SELINUX=permissive"
{% endif %}

php-fpm-restart:
  cmd.run:
    - name: systemctl restart {{ php.service }}

nginx-restart:
  cmd.run:
    - name: systemctl restart nginx

Here's what the completed php directory structure should look like:

php/
|-- files
|   |-- default.conf
|   |-- info.php
|   |-- www.conf_centos
|   `-- www.conf_deb
|-- map.jinja
`-- packages.sls

2d. Edit the init.sls file to include the mysql and php state files:

include:
  - wordpresser.common.packages
  - wordpresser.nginx.repo
  - wordpresser.nginx.packages
  - wordpresser.nginx.firewalld
  - wordpresser.mysql.packages
  - wordpresser.mysql.firewalld
  - wordpresser.mysql.mysql_secure
  - wordpresser.php.packages

2e. Run salt command - salt '*' state.apply

If all goes well, MySQL and PHP (and php-fpm) will be installed on the Minions. To recap this post, we saw how to install MySQL and install PHP using Salt. This concludes a basic LEMP installation with Salt. In the next post, we'll discuss how to go about Installing Wordpress with Salt.

A complete version of the code is available at this GitHub repository: Wordpresser

EOF.


If you found the article helpful, please share or cite the article, and spread the word:


For any feedback or corrections, please write in to: rahul [at] muchbits [dot] com