Vagrant. Начало работы. Часть 2 из 2

24.11.2019

Теги: CLIMySQLNginxPHPUbuntuVagrantWeb-разработкаWindowsВиртуализацияНастройкаУстановка

Установка пакетов

Для автоматической установки и настройки программного обеспечения предназначена настройка config.vm.provision. Мы будем использовать самый простой способ — shell-скрипт, но доступны также и другие варианты — Ansible, Chef, Puppet. Рассмотрим пример:

Vagrant.configure(2) do |config|
  config.vm.box = "bento/ubuntu-18.04"
  config.vm.provision "nginx", type: "shell", inline: "echo Installing Nginx; apt-get install -y nginx"
  config.vm.provision "mysql", type: "shell", inline: "echo Installing MySQL; apt-get install -y mysql-server"
  config.vm.provision "php", type: "shell", inline: "echo Installing PHP; apt-get install -y php-fpm php-mysql"
end

При установке Vagrant выдает сообщения:

$ vagrant up
..........
==> default: Running provisioner: nginx (shell)...
    default: Running: inline script
    default: Installing Nginx
    ..........
==> default: Running provisioner: mysql (shell)...
    default: Running: inline script
    default: Installing MySQL
    ..........
==> default: Running provisioner: php (shell)...
    default: Running: inline script
    default: Installing PHP
    ..........

Если команд много, их удобно объединить:

$script = <<~SCRIPT
  echo Installing Nginx
  apt-get install -y nginx
  echo Installing MySQL
  apt-get install -y mysql-server
  echo Installing PHP
  apt-get install -y php-fpm php-mysql
SCRIPT
Vagrant.configure(2) do |config|
  config.vm.box = "bento/ubuntu-18.04"
  config.vm.provision "shell", inline: $script
end
$update = <<~UPDATE
  apt-get update
  apt-get -y upgrade
UPDATE
$install = <<~INSTALL
  apt-get install -y nginx
  apt-get install -y mysql-server
  apt-get install -y php-fpm php-mysql
INSTALL
Vagrant.configure(2) do |config|
  config.vm.box = "bento/ubuntu-18.04"
  config.vm.provision "update", type: "shell", inline: $update
  config.vm.provision "install", type: "shell", inline: $install
end

Или вообще вынести в отдельный shell-файл:

Vagrant.configure(2) do |config|
  config.vm.box = "bento/ubuntu-18.04"
  config.vm.provision "shell", path: "provision.sh"
end
echo 'Installing Nginx'
apt-get install -y nginx
echo 'Installing MySQL'
apt-get install -y mysql-server
echo 'Installing PHP'
apt-get install -y php-fpm php-mysql

Поставщики (provisioners) выполняются в трех случаях:

  • при начальном vagrant up
  • по команде vagrant provision
  • по команде vagrant reload --provision
Команды vagrant up|reload могут быть запущены с ключом --no-provision, чтобы пропустить инструкции provision.

Если у каждого поставщика есть имя, то можно выполнить только его:

Vagrant.configure(2) do |config|
  config.vm.box = "bento/ubuntu-18.04"
  config.vm.provision "update", type: "shell", path: "update.sh"
  config.vm.provision "install", type: "shell", path: "install.sh"
end
$ vagrant provision --provision-with update

Несколько виртуальных машин

Допускается создание нескольких виртуальных машин в одном Vagrantfile:

Vagrant.configure(2) do |config|
  # образ системы Ubuntu 18/04 LTS (Bionic Beaver)
  config.vm.box = "bento/ubuntu-18.04"
  # не проверять репозиторий на наличие обновлений
  config.vm.box_check_update = false
  # отменить создание ssh-ключа
  config.ssh.insert_key = false

  # ПЕРВАЯ ВИРТУАЛЬНАЯ МАШИНА
  config.vm.define "web-server" do |subconfig|
    # имя виртуальной машины
    subconfig.vm.provider "virtualbox" do |vb|
      vb.name = "apache-server"
    end
    # hostname виртуальной машины
    subconfig.vm.hostname = "apache-server"
    # настройки сети
    subconfig.vm.network "private_network", ip: "192.168.53.3"
    # установка пакетов
    subconfig.vm.provision "apache", type: "shell", inline: "apt-get install -y apache2"
  end

  # ВТОРАЯ ВИРТУАЛЬНАЯ МАШИНА
  config.vm.define "sql-server" do |subconfig|
    # имя виртуальной машины
    subconfig.vm.provider "virtualbox" do |vb|
      vb.name = "mysql-server"
    end
    # hostname виртуальной машины
    subconfig.vm.hostname = "mysql-server"
    # настройки сети
    subconfig.vm.network "private_network", ip: "192.168.53.4"
    # установка пакетов
    subconfig.vm.provision "mysql", type: "shell", inline: "apt-get install -y mysql-server"
  end
  
  # обновление системы (для первой и второй)
  config.vm.provision "update", type: "shell", inline: "apt-get update && apt-get upgrade -y"
end

Запускаем виртуальные машины:

$ vagrant up
Bringing machine 'web-server' up with 'virtualbox' provider...
Bringing machine 'sql-server' up with 'virtualbox' provider...

Ход установки первой виртуальной машины:

==> web-server: Importing base box 'bento/ubuntu-18.04'...
==> web-server: Matching MAC address for NAT networking...
==> web-server: Setting the name of the VM: apache-server
==> web-server: Clearing any previously set network interfaces...
==> web-server: Preparing network interfaces based on configuration...
    web-server: Adapter 1: nat
    web-server: Adapter 2: hostonly
==> web-server: Forwarding ports...
    web-server: 22 (guest) => 2222 (host) (adapter 1)
==> web-server: Booting VM...
==> web-server: Waiting for machine to boot. This may take a few minutes...
    web-server: SSH address: 127.0.0.1:2222
    web-server: SSH username: vagrant
    web-server: SSH auth method: private key
==> web-server: Machine booted and ready!
==> web-server: Checking for guest additions in VM...
==> web-server: Setting hostname...
==> web-server: Configuring and enabling network interfaces...
==> web-server: Mounting shared folders...
    web-server: /vagrant => D:/vagrant/www
==> web-server: Running provisioner: update (shell)...
    web-server: Running: inline script
    ********** обновление системы **********
==> web-server: Running provisioner: apache (shell)...
    web-server: Running: inline script
    ********** установка Apache **********

Ход установки второй виртуальной машины:

==> sql-server: Importing base box 'bento/ubuntu-18.04'...
==> sql-server: Matching MAC address for NAT networking...
==> sql-server: Setting the name of the VM: mysql-server
==> sql-server: Fixed port collision for 22 => 2222. Now on port 2200.
==> sql-server: Clearing any previously set network interfaces...
==> sql-server: Preparing network interfaces based on configuration...
    sql-server: Adapter 1: nat
    sql-server: Adapter 2: hostonly
==> sql-server: Forwarding ports...
    sql-server: 22 (guest) => 2200 (host) (adapter 1)
==> sql-server: Booting VM...
==> sql-server: Waiting for machine to boot. This may take a few minutes...
    sql-server: SSH address: 127.0.0.1:2200
    sql-server: SSH username: vagrant
    sql-server: SSH auth method: private key
==> sql-server: Machine booted and ready!
==> sql-server: Checking for guest additions in VM...
==> sql-server: Setting hostname...
==> sql-server: Configuring and enabling network interfaces...
==> sql-server: Mounting shared folders...
    sql-server: /vagrant => D:/vagrant/www
==> sql-server: Running provisioner: update (shell)...
    sql-server: Running: inline script
    ********** обновление системы **********
==> sql-server: Running provisioner: mysql (shell)...
    sql-server: Running: inline script
    ********** установка MySQL **********

Остановить обе виртуальные машины:

$ vagrant halt
==> sql-server: Attempting graceful shutdown of VM...
==> web-server: Attempting graceful shutdown of VM...

Запустить обе виртуальные машины:

$ vagrant up

Подключение по ssh к первой машине:

$ vagrant ssh web-server

Остановить вторую виртуальную машину:

$ vagrant halt sql-server

Установка Nginx, MySQL и PHP

Во время создания виртуальной машины Vagrant запустит скрипт provision.sh, который установит Nginx, MySQL, PHP + создаст два виртуальных хоста.

Vagrant.configure(2) do |config|
  # образ системы Ubuntu 18/04 LTS (Bionic Beaver)
  config.vm.box = "bento/ubuntu-18.04"
  # не проверять репозиторий на наличие обновлений
  config.vm.box_check_update = false
  # отменить создание ssh-ключа
  config.ssh.insert_key = false

  config.vm.provider "virtualbox" do |vb|
    # имя виртуальной машины
    vb.name = "ubuntu-1804-test"
    # объем оперативной памяти
    vb.memory = 2048
    # количество ядер процессора
    vb.cpus = 1
  end
  
  # hostname виртуальной машины
  config.vm.hostname = "ubuntu-1804-test"
  # настройки сети
  config.vm.network "public_network"
  # синхронизация директорий
  config.vm.synced_folder ".", "/var/www"
  # установка пакетов
  config.vm.provision "shell", path: "provision.sh"
end
apt-get update
apt-get -y upgrade

apt-get install -y nginx
apt-get install -y mysql-server
apt-get install -y php-fpm php-mysql

# создаем две директории для двух виртуальных хостов
mkdir /var/www/site1.loc
mkdir /var/www/site2.loc
# создаем в каждой из этих директорий php-файл
echo '<?php phpinfo(); ?>' > /var/www/site1.loc/index.php
echo '<?php phpinfo(); ?>' > /var/www/site2.loc/index.php

# создаем два виртуальных хоста
cat > /etc/nginx/sites-available/site1.loc <<EOF
server {
    # слушать порт 80
    listen 80;
    # директория сайта
    root /var/www/site1.loc;
    # индексные файлы
    index index.php index.html;
    # домен сайта
    server_name site1.loc www.site1.loc;

    location / {
        try_files \$uri \$uri/ =404;
    }

    # PHP скрипты передаются на выполнение FastCGI серверу
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        # With php-fpm (or other unix sockets):
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
    }
}
EOF

cat > /etc/nginx/sites-available/site2.loc <<EOF
server {
    # слушать порт 80
    listen 80;
    # директория сайта
    root /var/www/site2.loc;
    # индексные файлы
    index index.php index.html;
    # домен сайта
    server_name site2.loc www.site2.loc;

    location / {
        try_files \$uri \$uri/ =404;
    }

    # PHP скрипты передаются на выполнение FastCGI серверу
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        # With php-fpm (or other unix sockets):
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
    }
}
EOF

ln -s /etc/nginx/sites-available/site1.loc /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/site2.loc /etc/nginx/sites-enabled/

echo '' >> '/etc/hosts'
echo '127.0.0.1   site1.loc www.site1.loc' >> '/etc/hosts'
echo '127.0.0.1   site2.loc www.site2.loc' >> '/etc/hosts'

systemctl reload nginx

Синхронизация директорий

По умолчанию синхронизируется директория, где расположен Vagrantfile на хост-системе с директорией /vagrant виртуальной машины. Это можно изменить с помощью настройки config.vm.synced_folder: указывается абсолютный или относительный путь для хост-системы и абсолютный — для виртуальной машины.

В нашем случае синхронизируется директория d:/vagrant/www с директорией /var/www. Таким образом, будут синхронизированы и вложенные директории виртуальных хостов:

d:/vagrant/www/site1.loc <=> /var/www/site1.loc  # первый виртуальный хост
d:/vagrant/www/site2.loc <=> /var/www/site2.loc  # второй виртуальный хост

У меня в настройках для второго адаптера используется сетевой мост, так что виртуальная машина является частью той же сети, что и хост-система. Через web-интерфейс роутера, который выдает ip-адреса всем устройствам локальной сети, можно закрепить за виртуальной машиной выданный ip-адрес — у меня это 192.168.110.12. А чтобы получить доступ к сайтам на виртуальной машине — добавить пару записей в host-файл основной системы.

192.168.110.12   site1.loc www.site1.loc
192.168.110.12   site2.loc www.site2.loc

Скрипт безопасности MySQL

У нас есть небольшая проблема с сервером MySQL — не задан пароль для root. Кроме того, пользователь root не может может подключаться по паролю, а только с помощью плагина auth_socket.

Чтобы это исправить, нужно выполнить скрипт безопасности. После запуска скрипт задает вопросы и нам надо на них ответить:

# mysql_secure_installation
  • Would you like to setup VALIDATE PASSWORD plugin?
  • Please set the password for root here.
  • Re-enter new password.
  • Remove anonymous users?
  • Disallow root login remotely?
  • Remove test database and access to it?
  • Reload privilege tables now?

В этом нам поможет expect — инструмент, который позволяет создать скрипт, который ответит на вопросы от скрипта безопасности MySQL. Подключимся к виртуальной машине по ssh и установим expect:

# apt install expect

Вместе с expect будет установлен и autoexpect. Он позволяет запускать скрипты, которые надо автоматизировать, после чего записывает то, что они выводят, и то, что пользователь вводит, отвечая на их вопросы. Так что запускаем и отвечаем на вопросы:

# cd /var/www  # результат работы autoexpect будет в директрии d:/vagrant/www хост-машины
# autoexpect mysql_secure_installation

После завершения работы autoexpect сообщит о том, что собранные данные записаны в файл script.exp.

#!/usr/bin/expect -f
#
# This Expect script was generated by autoexpect on Sun Nov 24 09:32:55 2019
# Expect and autoexpect were both written by Don Libes, NIST.
#
# Note that autoexpect does not guarantee a working script.  It
# necessarily has to guess about certain things.  Two reasons a script
# might fail are:
#
# 1) timing - A surprising number of programs (rn, ksh, zsh, telnet,
# etc.) and devices discard or ignore keystrokes that arrive "too
# quickly" after prompts.  If you find your new script hanging up at
# one spot, try adding a short sleep just before the previous send.
# Setting "force_conservative" to 1 (see below) makes Expect do this
# automatically - pausing briefly before sending each character.  This
# pacifies every program I know of.  The -c flag makes the script do
# this in the first place.  The -C flag allows you to define a
# character to toggle this mode off and on.

set force_conservative 0; # set to 1 to force conservative mode even if
                        ; # script was not run conservatively originally
if {$force_conservative} {
        set send_slow {1 .1}
        proc send {ignore arg} {
                sleep .1
                exp_send -s -- $arg
        }
}

#
# 2) differing output - Some programs produce different output each time
# they run.  The "date" command is an obvious example.  Another is
# ftp, if it produces throughput statistics at the end of a file
# transfer.  If this causes a problem, delete these patterns or replace
# them with wildcards.  An alternative is to use the -p flag (for
# "prompt") which makes Expect only look for the last line of output
# (i.e., the prompt).  The -P flag allows you to define a character to
# toggle this mode off and on.
#
# Read the man page for more info.
#
# -Don


set timeout -1
spawn mysql_secure_installation
match_max 100000
expect -exact "\r
Securing the MySQL server deployment.\r
\r
Connecting to MySQL using a blank password.\r
\r
VALIDATE PASSWORD PLUGIN can be used to test passwords\r
and improve security. It checks the strength of password\r
and allows the users to set only those passwords which are\r
secure enough. Would you like to setup VALIDATE PASSWORD plugin?\r
\r
Press y|Y for Yes, any other key for No: "
send -- "N\r"
expect -exact "N\r
Please set the password for root here.\r
\r
New password: "
send -- "qwerty\r"
expect -exact "\r
\r
Re-enter new password: "
send -- "qwerty\r"
expect -exact "\r
By default, a MySQL installation has an anonymous user,\r
allowing anyone to log into MySQL without having to have\r
a user account created for them. This is intended only for\r
testing, and to make the installation go a bit smoother.\r
You should remove them before moving into a production\r
environment.\r
\r
Remove anonymous users? (Press y|Y for Yes, any other key for No) : "
send -- "Y\r"
expect -exact "Y\r
Success.\r
\r
\r
Normally, root should only be allowed to connect from\r
'localhost'. This ensures that someone cannot guess at\r
the root password from the network.\r
\r
Disallow root login remotely? (Press y|Y for Yes, any other key for No) : "
send -- "Y\r"
expect -exact "Y\r
Success.\r
\r
By default, MySQL comes with a database named 'test' that\r
anyone can access. This is also intended only for testing,\r
and should be removed before moving into a production\r
environment.\r
\r
\r
Remove test database and access to it? (Press y|Y for Yes, any other key for No) : "
send -- "Y\r"
expect -exact "Y\r
 - Dropping test database...\r
Success.\r
\r
 - Removing privileges on test database...\r
Success.\r
\r
Reloading the privilege tables will ensure that all changes\r
made so far will take effect immediately.\r
\r
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : "
send -- "Y\r"
expect eof

Изменим имя скрипта (это можно сделать и в директриии d:/vagrant/www):

# mv script.exp mysql_sec.sh

Запросы, которые нужно выполнить, чтобы root мог подключаться по паролю:

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'qwerty';
FLUSH PRIVILEGES;

После этого удаляем виртуальную машину и создаем заново. Но предварительно изменяем кофигурационный файл:

Vagrant.configure(2) do |config|
  # образ системы Ubuntu 18/04 LTS (Bionic Beaver)
  config.vm.box = "bento/ubuntu-18.04"
  # не проверять репозиторий на наличие обновлений
  config.vm.box_check_update = false
  # отменить создание ssh-ключа
  config.ssh.insert_key = false

  config.vm.provider "virtualbox" do |vb|
    # имя виртуальной машины
    vb.name = "ubuntu-1804-test"
    # объем оперативной памяти
    vb.memory = 2048
    # количество ядер процессора
    vb.cpus = 1
  end
  
  # hostname виртуальной машины
  config.vm.hostname = "ubuntu-1804-test"
  # настройки сети
  config.vm.network "public_network"
  # синхронизация директорий
  config.vm.synced_folder ".", "/var/www"
  # установка пакетов
  config.vm.provision "shell", path: "provision.sh"
  config.vm.provision "shell", inline: "apt-get install -y expect"
  config.vm.provision "shell", path: "mysql_sec.sh"
  config.vm.provision "shell", inline: <<-QUERY
    mysql -uroot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'qwerty'; FLUSH PRIVILEGES;"
  QUERY
end

Основные команды

Проверить файл конфигурации Vagrantfile:

$ vagrant validate

Запустить или создать виртуальную машину:

$ vagrant up

Приостанавить работу виртуальной машины

$ vagrant suspend

Возобновить работу виртуальной машины:

$ vagrant resume 

Перезагрузить виртуальную машину:

$ vagrant reload
$ vagrant reload --provision

Подключиться к виртуальной машине по ssh:

$ vagrant ssh

Посмотреть настройки подключения по ssh:

$ vagrant ssh-config

Остановить виртуальную машину:

$ vagrant halt

Удалить виртуальную машину:

$ vagrant destroy

Проверить состояние виртуальной машины:

$ vagrant status

Проверить состояние всех виртуальных машин:

$ vagrant global-status

Посмотреть все доступные команды:

$ vagrant --help

Поиск: MySQL • Nginx • PHP • Ubuntu • Web-разработка • Виртуальная машина • Установка • Настройка • Vagrant • CLI

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.