Marcin Lewandowski
Marcin Lewandowski
Programista PHP ( Symfony ), blogger, trener oraz miłośnik kawy. Na co dzień pracuję z Symfony, RabbitMQ, ElasticSearch, Node.js, Redis, Docker, MySQL.

Instalacja i konfiguracja Mysql-a przez Puppet-a

Instalacja i konfiguracja Mysql-a przez Puppet-a

Ostatnim elementem serwera LAMP, który konfigurujemy jest baza danych MySQL lub MariaDB. W związku z czym, wzbogacimy konfigurację z poprzednich wpisów o instalację i konfigurację bazy danych. Co pod koniec wpisu da nam w pełni działający serwer LAMP pod nasze przyszłe projekty.

Poprawki

Zanim jednak przejdziemy do samego procesu instalacji i konfiguracji bazy danych dokonamy kilku modyfikacji już istniejącego rozwiązania.

Vagrantfile

Zaczniemy od pliku Vagrantfile, gdzie przed procesem instalacji Puppet-a dodamy aktualizacją repozytoriów co powinno wyeliminować poniższy błąd z którym możemy się spotkać.

Polecenie aktualizacji listy pakietów z repozytoriów dodajemy przed poleceniem instalacji Puppet-a:

sudo apt-get -y update

Kolejną modyfikacją jest wyłączenie automatycznego sprawdzania, czy jest zainstalowana najnowsza wersja VirtualBox Guest Additions. Potrafi to znacznie spowolnić proces budowania maszyny więc wyłączymy tę opcję. Do konfiguracji dodajemy:

if Vagrant.has_plugin?('vagrant-vbguest')
    config.vbguest.auto_update = false
end

Wyłączenie jak widzicie jest warunkowe i uzależnione od zainstalowanego plugin-u Vagrant-a. Jeśli takowego nie macie w systemie to bardzo prosto możecie go zainstalować poleceniem:

vagrant gem install vagrant-vbguest

Po wprowadzonych modyfikacjach plik Vagrantfile powinien wyglądać następująco:

Vagrant.configure("2") do |config|
 
  config.vm.box = "ubuntu/xenial64"
 
  config.vm.network :private_network, ip: "192.168.33.10"
 
  if Vagrant.has_plugin?('vagrant-vbguest')
      config.vbguest.auto_update = false
  end
 
  config.vm.provider "virtualbox" do |vb|
 
      vb.name = "WebServerPuppet"
      vb.cpus = 1
      vb.memory = 1024
      vb.gui = false
 
  end
 
$provision_script= <<SCRIPT if [[ $(which puppet) != '/usr/bin/puppet' ]]; then sudo apt-get -y update sudo apt-get install -y puppet fi SCRIPT config.vm.provision :shell, :inline => $provision_script
 
  config.vm.provision "puppet" do |puppet|
    puppet.manifests_path = "manifests"
    puppet.manifest_file = "default.pp"
    puppet.module_path = "modules"
  end
 
end

Zmiany w recepturze Puppet-a

Tutaj zmiany będą bardziej kosmetyczne jednak warto wiedzieć że mamy więcej możliwości jeśli chodzi o instalację pakietów. W poprzednich wpisach posługiwaliśmy się zapisem ensure => installed, który nie jest jedyną możliwością instalacji pakietów. Do dyspozycji mamy jeszcze opcje:

  • present – alternatywa dla opcji installed, która jest bardziej spójna z innymi modułami Puppet-a,
  • latest – instaluje ostatnią wersję pakietu, zapewniając najaktualniejszą jego wersję,
  • numer_wersji – dzięki zdefiniowaniu numeru wersji możemy zainstalować pakiet w wybranej wersji o ile będzie ona dostępna, jeśli nie będzie to konieczne będzie podanie źródła w parametrze source z którego będzie możliwa instalacja,

Tak więc po zmianach plik manifests/default.pp będzie wyglądał następująco:

package { 'nginx':
  ensure => present
}
 
package { 'php7.0':
  ensure  => present,
  require => Package['nginx']
}
 
package { 'apache2.2-common':
  ensure => absent
}
 
service { 'nginx':
  ensure  => running,
  require => Package['nginx']
}
 
file { '/etc/nginx/sites-enabled/default':
  source => 'puppet:///modules/nginx/site.conf',
  notify => Service['nginx']
}
 
file { '/var/www/html/index.html':
  source  => 'puppet:///modules/nginx/index.html',
  require => File['/etc/nginx/sites-enabled/default']
}
 
file { '/var/www/html/index.php':
  source  => 'puppet:///modules/nginx/index.php',
  require => File['/etc/nginx/sites-enabled/default']
}

Poza zmianą installed na present dokonałem poprawy formatowania kodu, wyrównując => w ramach poszczególnych sekcji.

Instalacja bazy danych

Jako że poprawki mamy naniesione czas zainstalować ostatni składnik serwera LAMP czyli serwer bazodanowy. Do wyboru mamy wiele baz danych przy czym najpopularniejsza w tego typu konfiguracjach jest MySQL lub jej fork, czyli MariaDB. Oczywiście nic nie stoi na przeszkodzie, aby zainstalować Postgres-a czy inną bazę jaka będzie wam potrzebna.

MySQL / MariaDB

W zależności o dystrybucji pod nazwą pakietu mysql-server będzie się kryła baza MySQL lub MariaDB. Na potrzeby tego opisu przyjmiemy, że nie robi nam to różnicy, gdyż proces samej instalacji i konfiguracji nie będzie się różnił.

Zaczynamy oczywiście od instalacji odpowiedniego pakietu dodając wpis w pliku manifests/default.pp

package { 'mysql-server':
  ensure => present
}

Zapis powinien odwołuje się do pakietu o nazwie mysql-server i wymaga, aby ów pakiet był zainstalowany w systemie. Następnie musimy się upewnić, że pakiet będzie uruchomiony w związku z czym tworzymy wpis serwisu.

service { 'mysql':
  ensure  => true,
  enable  => true,
  require => Package['mysql-server'],
}

Kiedy mamy te dwa wpisy dodane do naszej receptury pozostaje jedynie zbudować maszynę z jej uwzględnieniem i cieszyć się serwerem LAMP. Niestety nie do końca 😉 Otóż jest mały haczyk, mianowicie nie posiadamy użytkownika i hasła na którego mogli byśmy się logować. Tu z pomocą przyjedzie nam aplikacja mysqladmin, dzięki której możemy ustawić nowe hasło dla użytkownika root.

Dodajemy wpis do receptury:

exec { "set-mysql-password":
  unless => "mysqladmin -uroot -p$mysql_password status",
  path => ["/bin", "/usr/bin"],
  command => "mysqladmin -uroot password $mysql_password",
  require => Service["mysql"],
}

Jako że mamy do czynienia z zasobem typu exec, którego wcześniej nie omawiałem to przyjrzymy się temu fragmentowi nieco dokładniej. Zapewne po samej nazwie typu wywnioskowaliście, że typ ten służy do uruchamiania zewnętrznych aplikacji. Zatem zapoznajmy się z parametrami jakie zostały tutaj zdefiniowane:

  • unless – chcąc uruchomić jakąś aplikację możemy uruchamiać ją zawsze lub nałożyć pewne ograniczenia. W tym przypadku takim ograniczeniem będzie uruchomienie aplikacji mysqladmin, gdy użytkownik root ma ustawione inne hasło niż to znajdujące się w zmiennej $mysql_password, czyli unless daje nam możliwość uruchomienia aplikacji, gdy warunek jest nie spełniony. Innymi parametrami tożsamymi z unless są parametry onlyif oraz creates.
  • path – lista ścieżek jakie mają zostać przeszukane w celu znalezienia aplikacji, jeśli aplikacja jest zainstalowana w systemie prawdopodobnie parametr ten nie będzie potrzebny,
  • command – polecenie jakie ma zostać uruchomione. My chcemy, aby aplikacja mysqladmin zmieniła hasło użytkownika root
  • require – wymagania jakie mają zostać spełnione, aby polecenie zostało uruchomione. Naszym jedynym wymaganiem jest działający serwis mysql,

Ostatni niezbędny element, czyli dodanie zmiennej wraz z hasłem do naszego serwera:

$mysql_password status = 'tajne_haslo'

Na chwilę pominę kwestię, że rozwiązanie to jest słabe. Ponieważ przechowywanie haseł w plikach, które wyślemy do repozytorium jest wyjątkowo złym pomysłem i może się zemścić w przyszłości. Jednak na potrzeby tego przykładu zostawimy to rozwiązanie, które później zmienimy na coś lepszego 😉

Testujemy bazę danych

Po instalacji bazy danych należało by się upewnić, że baza działa i można z nią się połączyć używając użytkownika i hasła. Najprostszym sposobem będzie oczywiście zalogowanie się do maszyny wirtualnej poleceniem:

vagrant ssh

Następnie przelogowujemy się na root-a poleceniem:

sudo su

I teraz możemy sprawdzić czy serwer żyje poleceniem z receptury:

mysqladmin -uroot -ptajne_haslo status

Jeśli podaliście użyliście inne hasło niż te z przykładu to po fladze -p musicie wpisać swoje hasło. Po wywołaniu tego polecenia powinniście otrzymać komunikat podobny do tego poniżej.

Początek nas ostrzega przed podawaniem hasła bezpośrednio w linii komend co możemy w tym momencie zignorować. Nas interesuje dalsza część, gdzie mamy Uptime mówiący o czasie działania serwera. Jeśli serwer działa to super, jeśli nie to musicie poszukać błędu czy to w recepturze czy też w systemie.

PHP połączenie z bazą danych

Powyższy sposób wymaga naszej interakcji, a my dążymy do pełnej automatyzacji więc lepszym rozwiązaniem będzie sprawdzenie tego z poziomu PHP. W tym celu tworzymy prosty skrypt php łączący się z bazą danych. Dodajemy plik mysql.php w katalogu modules/nginx/files z zawartością:

<?php 

$dbname = 'test'; 
$dsn = 'mysql:host=localhost;dbname='.$dbname; 
$username = 'test'; 
$password = 'test123'; 
$options = array( 
    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
);
 
try
{
    $dbh = new PDO($dsn, $username, $password, $options);
    echo 'Connected';
}
catch(Exception $e)
{
    echo 'Error: ' . $e->getMessage();
}

Plik ten odpowiada za połączenie z bazą danych o nazwie test, chce dokonać połączenia wykorzystując nazwę użytkownika test oraz hasło test123. Oczywiście w systemie takiej bazy danych nie mamy, a także takiego użytkownika z takim hasłem w związku z czym przechodzimy do receptury manifest/default.pp i dodajemy dodatkowe wpisy. Zaczniemy od dodania bazy i użytkownika.

$dbname = 'test'
$dbuser = 'test'
$dbpassword = 'test123'
 
exec { "create-db":
  unless => "/usr/bin/mysql -u${dbuser} -p${dbpassword} ${dbname}",
  command => "/usr/bin/mysql -uroot -p$mysql_password -e \"create database ${dbname}; grant all on ${dbname}.* to ${dbuser}@localhost identified by '$dbpassword';\"",
  require => Service["mysql"],
}

Następnie dodajemy wpis instalujący dodatkowy pakiet umożliwiający php łączenie się z bazą MySQL:

package { 'php7.0-mysql':
  ensure  => present,
  require => Package['php7.0']
}

Kolejny wpis to przekopiowanie przygotowanego pliku php do odpowiedniego katalogu na maszynie wirtualnej.

file { '/var/www/html/mysql.php':
  source  => 'puppet:///modules/nginx/mysql.php',
  require => File['/etc/nginx/sites-enabled/default']
}

Teraz po zbudowaniu maszyny wirtualnej pod adresem: http://192.168.33.10/mysql.php powinniśmy zobaczyć komunikat:

Podsumowanie

Po zainstalowaniu bazy danych i sprawdzeniu, że proces ten jest wykonany prawidłowo mamy recepturę, która buduje nam serwer LAMP. Dodatkowo w tym wpisie poznaliśmy nowy typ zasobu exec, który pozwala uruchamiać zewnętrzne aplikacje co może nam się niejednokrotnie przydać. Cały przedstawiony tutaj kod jak zwykle znajdziecie na GitHub-ie.