Как развернуть базовое приложение PHP с помощью Ansible в Ubuntu 14.04
Введение
В этом руководстве рассматривается процесс подготовки базового приложения PHP с использованием Ansible. Цель в конце этого руководства состоит в том, чтобы ваш новый веб-сервер обслуживал базовое приложение PHP без единого SSH-соединения или ручного запуска команды на целевом дроплете.
Мы будем использовать фреймворк Laravel в качестве примера PHP-приложения, но эти инструкции можно легко изменить для поддержки других фреймворков и приложений, если у вас уже есть свои.
Предпосылки
В этом руководстве мы будем использовать Ansible для установки и настройки Nginx, PHP и других сервисов в капле Ubuntu 14.04. Этот учебник основан на базовых знаниях Ansible, поэтому, если вы новичок в Ansible, вы можете сначала прочитать этот базовый учебник Ansible.
Чтобы следовать этому руководству, вам понадобятся:
- Одна капля Ubuntu 14.04 любого размера, которую мы будем использовать для настройки и развертывания нашего PHP-приложения. IP-адрес этого компьютера будет называться
your_server_ip
на протяжении всего руководства. - Одна капля Ubuntu 14.04, которая будет использоваться для Ansible. Это дроплет, в который вы будете входить на протяжении всего этого руководства.
- Пользователи Sudo без полномочий root, настроенные для обеих капель.
- Ключи SSH для дроплета Ansible для авторизации входа в дроплет развертывания PHP, который вы можете настроить, следуя этому руководству в своем дроплете Ansible.
Шаг 1 — Установка Ansible
Первый шаг — установить Ansible. Это легко сделать, установив PPA (Personal Package Archive) и установив пакет Ansible с помощью apt
.
Сначала добавьте PPA с помощью команды apt-add-repository
.
- sudo apt-add-repository ppa:ansible/ansible
После этого обновите кеш apt
.
- sudo apt-get update
Наконец, установите Ansible.
- sudo apt-get install ansible
После установки Ansible мы создадим новый каталог для работы и настроим базовую конфигурацию. По умолчанию Ansible использует файл hosts, расположенный по адресу /etc/ansible/hosts
, который содержит все серверы, которыми он управляет. Хотя этот файл подходит для некоторых случаев использования, он глобальный, а это не то, что нам нужно здесь.
Для этого руководства мы создадим локальный файл hosts и будем использовать его. Мы можем сделать это, создав новый файл конфигурации Ansible в нашем рабочем каталоге, который мы можем использовать, чтобы указать Ansible искать файл hosts в том же каталоге.
Создайте новый каталог (который мы будем использовать в оставшейся части этого руководства).
- mkdir ~/ansible-php
Перейдите в новый каталог.
- cd ~/ansible-php/
Создайте новый файл с именем ansible.cfg
и откройте его для редактирования с помощью nano
или вашего любимого текстового редактора.
- nano ansible.cfg
Добавьте параметр конфигурации hostfile
со значением hosts
в группу [defaults]
, скопировав следующее в ansible.cfg
файл.
[defaults]
hostfile = hosts
Сохраните и закройте файл ansible.cfg
. Далее мы создадим файл hosts
, который будет содержать IP-адрес дроплета PHP, где мы развернём наше приложение.
- nano hosts
Скопируйте ниже, чтобы добавить в раздел для php
, заменив your_server_ip
IP-адресом вашего сервера и sammy
с пользователем sudo без полномочий root, которого вы создали в предварительных условиях на своем PHP-дроплете.
[php]
your_server_ip ansible_ssh_user=sammy
Сохраните и закройте файл hosts
. Давайте запустим простую проверку, чтобы убедиться, что Ansible может подключиться к хосту, как и ожидалось, вызвав модуль ping
в новой группе php
.
- ansible php -m ping
Вы можете получить проверку аутентификации хоста SSH, в зависимости от того, заходили ли вы когда-либо на этот хост раньше. Пинг должен вернуться с успешным ответом, который выглядит примерно так:
111.111.111.111 | success >> {
"changed": false,
"ping": "pong"
}
Ansible теперь должен быть установлен и настроен; мы можем перейти к настройке нашего веб-сервера.
Шаг 2 — Установка необходимых пакетов
На этом этапе мы установим некоторые необходимые системные пакеты, используя Ansible и apt
. В частности, мы установим git
, nginx
, sqlite3
, mcrypt
и пару php5 -*
пакеты.
Прежде чем мы добавим модуль apt
для установки нужных нам пакетов, нам нужно создать базовый плейбук. Мы будем основываться на этом учебнике по мере изучения учебника. Создайте новый плейбук с именем php.yml
.
- nano php.yml
Вставьте следующую конфигурацию. Первые две строки определяют группу хостов, которую мы хотим использовать (php
), и гарантируют, что она запускает команды с sudo
по умолчанию. Остальные добавляются в модуль с нужными нам пакетами. Вы можете настроить это для своего собственного приложения или использовать приведенную ниже конфигурацию, если вы следуете примеру приложения Laravel.
---
- hosts: php
sudo: yes
tasks:
- name: install packages
apt: name={{ item }} update_cache=yes state=latest
with_items:
- git
- mcrypt
- nginx
- php5-cli
- php5-curl
- php5-fpm
- php5-intl
- php5-json
- php5-mcrypt
- php5-sqlite
- sqlite3
Сохраните файл php.yml
. Наконец, запустите ansible-playbook
, чтобы установить пакеты в Droplet. Не забудьте использовать параметр --ask-sudo-pass
, если вашему пользователю sudo на вашем PHP-дроплете требуется пароль.
- ansible-playbook php.yml --ask-sudo-pass
Шаг 3 — Изменение файлов конфигурации системы
В этом разделе мы изменим некоторые файлы конфигурации системы в дроплете PHP. Самый важный параметр конфигурации, который необходимо изменить (кроме файлов Nginx, которые будут рассмотрены на следующем шаге), — это параметр cgi.fix_pathinfo
в php5-fpm
, поскольку по умолчанию значение представляет собой угрозу безопасности.
Сначала мы объясним все разделы, которые мы собираемся добавить в этот файл, а затем включим весь файл php.yml
, который вы сможете скопировать и вставить.
Модуль lineinfile можно использовать для обеспечения того, чтобы значение конфигурации в файле было именно таким, как мы ожидаем. Это можно сделать с помощью общего регулярного выражения, чтобы Ansible мог понимать большинство форм, в которых может находиться параметр. Нам также потребуется перезапустить php5-fpm
и nginx
, чтобы Убедитесь, что изменение вступило в силу, поэтому нам также нужно добавить два обработчика в новый раздел handlers
. Обработчики идеально подходят для этого, так как они срабатывают только при изменении задачи. Они также запускаются в конце плейбука, поэтому несколько задач могут вызывать один и тот же обработчик, и он будет запущен только один раз.
Раздел для выполнения вышеуказанного будет выглядеть следующим образом:
- name: ensure php5-fpm cgi.fix_pathinfo=0
lineinfile: dest=/etc/php5/fpm/php.ini regexp='^(.*)cgi.fix_pathinfo=' line=cgi.fix_pathinfo=0
notify:
- restart php5-fpm
- restart nginx
handlers:
- name: restart php5-fpm
service: name=php5-fpm state=restarted
- name: restart nginx
service: name=nginx state=restarted
В Ansible версии 1.9.1 есть ошибка, которая не позволяет перезапустить php5-fpm
с модулем service
, как мы использовали в наших обработчиках.
Пока не будет выпущено исправление, вы можете обойти эту проблему, изменив обработчик restart php5-fpm
с использования команды service
на использование shell
. команда, например:
- name: restart php5-fpm
shell: service php5-fpm restart
Это позволит обойти проблему и корректно перезапустить php5-fpm
.
Далее нам также необходимо убедиться, что модуль php5-mcrypt
включен. Это делается путем запуска сценария php5enmod
с задачей оболочки и проверки того, что файл 20-mcrypt.ini
находится в нужном месте, когда он включен. Обратите внимание, что мы сообщаем Ansible, что задача создает определенный файл. Если этот файл существует, задача не будет запущена.
- name: enable php5 mcrypt module
shell: php5enmod mcrypt
args:
creates: /etc/php5/cli/conf.d/20-mcrypt.ini
Теперь снова откройте php.yml
для редактирования.
- nano php.yml
Добавьте вышеуказанные задачи и обработчики, чтобы файл соответствовал приведенному ниже:
---
- hosts: php
sudo: yes
tasks:
- name: install packages
apt: name={{ item }} update_cache=yes state=latest
with_items:
- git
- mcrypt
- nginx
- php5-cli
- php5-curl
- php5-fpm
- php5-intl
- php5-json
- php5-mcrypt
- php5-sqlite
- sqlite3
- name: ensure php5-fpm cgi.fix_pathinfo=0
lineinfile: dest=/etc/php5/fpm/php.ini regexp='^(.*)cgi.fix_pathinfo=' line=cgi.fix_pathinfo=0
notify:
- restart php5-fpm
- restart nginx
- name: enable php5 mcrypt module
shell: php5enmod mcrypt
args:
creates: /etc/php5/cli/conf.d/20-mcrypt.ini
handlers:
- name: restart php5-fpm
service: name=php5-fpm state=restarted
- name: restart nginx
service: name=nginx state=restarted
Наконец, запустите playbook.
- ansible-playbook php.yml --ask-sudo-pass
Теперь в Droplet установлены все необходимые пакеты, а базовая конфигурация настроена и готова к работе.
Шаг 4 — Клонирование репозитория Git
В этом разделе мы клонируем репозиторий фреймворка Laravel в нашу каплю с помощью Git. Как и в шаге 3, мы объясним все разделы, которые собираемся добавить в книгу, а затем добавим весь файл php.yml
, который вы сможете скопировать и вставить.
Прежде чем мы клонируем наш репозиторий Git, нам нужно убедиться, что /var/www
существует. Мы можем сделать это, создав задачу с файловым модулем.
- name: create /var/www/ directory
file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700
Как упоминалось выше, нам нужно использовать модуль Git для клонирования репозитория в нашу каплю. Процесс прост, потому что все, что нам обычно требуется для команды git clone
, — это исходный репозиторий. В этом случае мы также определим назначение и укажем Ansible не обновлять репозиторий, если он уже существует, установив update=no
. Поскольку мы используем Laravel, мы будем использовать URL-адрес репозитория git: https://github.com/laravel/laravel.git
.
Однако нам нужно запустить задачу от имени пользователя www-data
, чтобы убедиться в правильности разрешений. Для этого мы можем указать Ansible запустить команду от имени конкретного пользователя, используя sudo
. Окончательное задание будет выглядеть так:
- name: Clone git repository
git: >
dest=/var/www/laravel
repo=https://github.com/laravel/laravel.git
update=no
sudo: yes
sudo_user: www-data
Примечание. Для репозиториев на основе SSH вы можете добавить accept_hostkey=yes
, чтобы предотвратить зависание задачи при проверке хоста SSH.
Как и раньше, откройте файл php.yml
для редактирования.
- nano php.yml
Добавьте вышеуказанные задачи в playbook; конец файла должен соответствовать следующему:
...
- name: enable php5 mcrypt module
shell: php5enmod mcrypt
args:
creates: /etc/php5/cli/conf.d/20-mcrypt.ini
- name: create /var/www/ directory
file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700
- name: Clone git repository
git: >
dest=/var/www/laravel
repo=https://github.com/laravel/laravel.git
update=no
sudo: yes
sudo_user: www-data
handlers:
- name: restart php5-fpm
service: name=php5-fpm state=restarted
- name: restart nginx
service: name=nginx state=restarted
Сохраните и закройте плейбук, затем запустите его.
- ansible-playbook php.yml --ask-sudo-pass
Шаг 5 — Создание приложения с помощью Composer
На этом этапе мы будем использовать Composer для установки приложения PHP и его зависимостей.
В Composer есть команда create-project
, которая устанавливает все необходимые зависимости, а затем выполняет этапы создания проекта, определенные в разделе post-create-project-cmd
файла composer.json
. Это лучший способ убедиться, что приложение правильно настроено для первого использования.
Мы можем использовать следующую задачу Ansible, чтобы загрузить и установить Composer глобально как /usr/local/bin/composer
. Затем он будет доступен любому, кто использует Droplet, включая Ansible.
- name: install composer
shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
args:
creates: /usr/local/bin/composer
С установленным Composer есть модуль Composer, который мы можем использовать. В нашем случае мы хотим сообщить Composer, где находится наш проект (используя параметр working_dir
), и выполнить команду create-project
. Нам также необходимо добавить параметр optimize_autoloader=no
, так как этот флаг не поддерживается командой create-project
. Как и команду git
, мы также хотим запустить ее от имени пользователя www-data
, чтобы убедиться, что разрешения действительны. Собрав все вместе, получаем вот такую задачу:
- name: composer create-project
composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no
sudo: yes
sudo_user: www-data
Примечание. Задача create-project
может занять значительное время на новом дроплете, так как у Composer будет пустой кеш, и ему потребуется загрузить все новое.
Теперь откройте файл php.yml
для редактирования.
- nano php.yml
Добавьте указанные выше задачи в конец раздела tasks
над handlers
, чтобы конец плейбука соответствовал следующему:
...
- name: Clone git repository
git: >
dest=/var/www/laravel
repo=https://github.com/laravel/laravel.git
update=no
sudo: yes
sudo_user: www-data
- name: install composer
shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
args:
creates: /usr/local/bin/composer
- name: composer create-project
composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no
sudo: yes
sudo_user: www-data
handlers:
- name: restart php5-fpm
service: name=php5-fpm state=restarted
- name: restart nginx
service: name=nginx state=restarted
Наконец, запустите playbook.
- ansible-playbook php.yml --ask-sudo-pass
Что произойдет, если мы сейчас снова запустим Ansible? composer create-project
запустится снова, и в случае с Laravel это означает новый APP_KEY
. Вместо этого мы хотим, чтобы эта задача запускалась только после нового клонирования. Мы можем убедиться, что он запускается только один раз, зарегистрировав переменную с результатами задачи git clone
, а затем проверив эти результаты в задаче composer create-project
. Если задача git clone
была Changed, то запускаем composer create-project
, если нет, то пропускаем.
Примечание. Похоже, что в некоторых версиях модуля Ansible composer
есть ошибка, и он может выводить OK вместо Changed, так как он игнорирует что сценарии выполнялись, даже если не было установлено никаких зависимостей.
Откройте файл php.yml
для редактирования.
- nano php.yml
Найдите задачу git clone
. Добавьте параметр register
, чтобы сохранить результаты задачи в переменную cloned
, например:
- name: Clone git repository
git: >
dest=/var/www/laravel
repo=https://github.com/laravel/laravel.git
update=no
sudo: yes
sudo_user: www-data
register: cloned
Затем найдите задачу composer create-project
. Добавьте параметр when
, чтобы проверить переменную cloned
, чтобы узнать, изменилась она или нет.
- name: composer create-project
composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no
sudo: yes
sudo_user: www-data
when: cloned|changed
Сохраните плейбук и запустите его:
- ansible-playbook php.yml --ask-sudo-pass
Теперь Composer перестанет изменять APP_KEY
при каждом запуске.
Шаг 6 — Обновление переменных среды
На этом шаге мы обновим переменные среды для нашего приложения.
Laravel поставляется с файлом .env
по умолчанию, который устанавливает APP_ENV
в local
и APP_DEBUG
в true
. Мы хотим поменять их местами на production
и false
соответственно. Это можно сделать, просто используя модуль lineinfile
со следующими задачами.
- name: set APP_DEBUG=false
lineinfile: dest=/var/www/laravel/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false
- name: set APP_ENV=production
lineinfile: dest=/var/www/laravel/.env regexp='^APP_ENV=' line=APP_ENV=production
Откройте файл php.yml
для редактирования.
- nano php.yml
Добавьте эту задачу в playbook; конец файла должен соответствовать следующему:
...
- name: composer create-project
composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no
sudo: yes
sudo_user: www-data
when: cloned|changed
- name: set APP_DEBUG=false
lineinfile: dest=/var/www/laravel/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false
- name: set APP_ENV=production
lineinfile: dest=/var/www/laravel/.env regexp='^APP_ENV=' line=APP_ENV=production
handlers:
- name: restart php5-fpm
service: name=php5-fpm state=restarted
- name: restart nginx
service: name=nginx state=restarted
Сохраните и запустите плейбук:
- ansible-playbook php.yml --ask-sudo-pass
Модуль lineinfile
очень полезен для быстрой настройки любого текстового файла, и он отлично подходит для обеспечения правильной установки таких переменных среды.
Шаг 7 — Настройка Nginx
В этом разделе мы настроим Nginx для обслуживания приложения PHP.
Если вы сейчас посетите свой дроплет в своем веб-браузере (например, http://your_server_ip/
), вы увидите страницу по умолчанию Nginx вместо страницы нового проекта Laravel. Это связано с тем, что нам все еще нужно настроить наш веб-сервер Nginx для обслуживания приложения из каталога /var/www/laravel/public
. Для этого нам нужно обновить нашу конфигурацию Nginx по умолчанию с помощью этого каталога и добавить поддержку php-fpm
, чтобы он мог обрабатывать PHP-скрипты.
Создайте новый файл с именем nginx.conf
:
- nano nginx.conf
Сохраните этот блок сервера в этом файле. Вы можете проверить шаг 4 этого руководства для получения более подробной информации об этой конфигурации Nginx; приведенные ниже модификации указывают, где находится общедоступный каталог Laravel, и удостоверяются, что Nginx использует имя хоста, которое мы определили в файле hosts
, в качестве server_name
с inventory_hostname
переменная.
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /var/www/laravel/public;
index index.php index.html index.htm;
server_name {{ inventory_hostname }};
location / {
try_files $uri $uri/ =404;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/laravel/public;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Сохраните и закройте файл nginx.conf
.
Теперь мы можем использовать модуль шаблона для отправки нашего нового файла конфигурации. Модуль template
может выглядеть и звучать очень похоже на модуль copy
, но между ними есть большая разница. copy
скопирует один или несколько файлов без внесения каких-либо изменений, а template
скопирует один файл и разрешит все переменные в файле. Поскольку мы использовали {{ inventory_hostname }}
в нашем файле конфигурации, мы используем модуль template
, поэтому он преобразуется в IP-адрес, который мы использовали в hosts.
файл. Таким образом, нам не нужно жестко кодировать файлы конфигурации, которые использует Ansible.
Однако, как это обычно бывает при написании задач, нам нужно учитывать, что будет происходить на дроплете. Поскольку мы меняем конфигурацию Nginx, нам нужно перезапустить Nginx и php-fpm
. Это делается с помощью параметров notify
.
- name: Configure nginx
template: src=nginx.conf dest=/etc/nginx/sites-available/default
notify:
- restart php5-fpm
- restart nginx
Откройте файл php.yml
:
- nano php.yml
Добавьте эту задачу nginx в конец раздела задач. Весь файл php.yml
теперь должен выглядеть так:
---
- hosts: php
sudo: yes
tasks:
- name: install packages
apt: name={{ item }} update_cache=yes state=latest
with_items:
- git
- mcrypt
- nginx
- php5-cli
- php5-curl
- php5-fpm
- php5-intl
- php5-json
- php5-mcrypt
- php5-sqlite
- sqlite3
- name: ensure php5-fpm cgi.fix_pathinfo=0
lineinfile: dest=/etc/php5/fpm/php.ini regexp='^(.*)cgi.fix_pathinfo=' line=cgi.fix_pathinfo=0
notify:
- restart php5-fpm
- restart nginx
- name: enable php5 mcrypt module
shell: php5enmod mcrypt
args:
creates: /etc/php5/cli/conf.d/20-mcrypt.ini
- name: create /var/www/ directory
file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700
- name: Clone git repository
git: >
dest=/var/www/laravel
repo=https://github.com/laravel/laravel.git
update=no
sudo: yes
sudo_user: www-data
register: cloned
- name: install composer
shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
args:
creates: /usr/local/bin/composer
- name: composer create-project
composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no
sudo: yes
sudo_user: www-data
when: cloned|changed
- name: set APP_DEBUG=false
lineinfile: dest=/var/www/laravel/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false
- name: set APP_ENV=production
lineinfile: dest=/var/www/laravel/.env regexp='^APP_ENV=' line=APP_ENV=production
- name: Configure nginx
template: src=nginx.conf dest=/etc/nginx/sites-available/default
notify:
- restart php5-fpm
- restart nginx
handlers:
- name: restart php5-fpm
service: name=php5-fpm state=restarted
- name: restart nginx
service: name=nginx state=restarted
Сохраните и снова запустите плейбук:
- ansible-playbook php.yml --ask-sudo-pass
После завершения вернитесь в браузер и обновите его. Теперь вы должны увидеть страницу нового проекта Laravel!
Заключение
В этом руководстве рассматривается развертывание приложения PHP с общедоступным репозиторием. Хотя он идеально подходит для изучения того, как работает Ansible, вы не всегда будете работать над полностью открытыми проектами с открытыми репозиториями. Это означает, что вам нужно будет аутентифицировать клон git
на шаге 3 в вашем личном репозитории. Это можно очень легко сделать с помощью SSH-ключей.
Например, после того как вы создали ключи развертывания SSH и установили их в своем репозитории, вы можете использовать Ansible для их копирования и настройки на своем сервере перед задачей git clone
:
- name: create /var/www/.ssh/ directory
file: dest=/var/www/.ssh/ state=directory owner=www-data group=www-data mode=0700
- name: copy private ssh key
copy: src=deploykey_rsa dest=/var/www/.ssh/id_rsa owner=www-data group=www-data mode=0600
Это должно позволить серверу правильно аутентифицировать и развернуть ваше приложение.
Вы только что развернули базовое PHP-приложение на веб-сервере Nginx на основе Ubuntu, используя Composer для управления зависимостями! Все это было выполнено без необходимости напрямую входить в ваш PHP Droplet и запускать одну ручную команду.