Поиск по сайту:

Как развернуть базовое приложение 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.

  1. sudo apt-add-repository ppa:ansible/ansible

После этого обновите кеш apt.

  1. sudo apt-get update

Наконец, установите Ansible.

  1. sudo apt-get install ansible

После установки Ansible мы создадим новый каталог для работы и настроим базовую конфигурацию. По умолчанию Ansible использует файл hosts, расположенный по адресу /etc/ansible/hosts, который содержит все серверы, которыми он управляет. Хотя этот файл подходит для некоторых случаев использования, он глобальный, а это не то, что нам нужно здесь.

Для этого руководства мы создадим локальный файл hosts и будем использовать его. Мы можем сделать это, создав новый файл конфигурации Ansible в нашем рабочем каталоге, который мы можем использовать, чтобы указать Ansible искать файл hosts в том же каталоге.

Создайте новый каталог (который мы будем использовать в оставшейся части этого руководства).

  1. mkdir ~/ansible-php

Перейдите в новый каталог.

  1. cd ~/ansible-php/

Создайте новый файл с именем ansible.cfg и откройте его для редактирования с помощью nano или вашего любимого текстового редактора.

  1. nano ansible.cfg

Добавьте параметр конфигурации hostfile со значением hosts в группу [defaults], скопировав следующее в ansible.cfg файл.

[defaults]
hostfile = hosts

Сохраните и закройте файл ansible.cfg. Далее мы создадим файл hosts, который будет содержать IP-адрес дроплета PHP, где мы развернём наше приложение.

  1. nano hosts

Скопируйте ниже, чтобы добавить в раздел для php, заменив your_server_ip IP-адресом вашего сервера и sammy с пользователем sudo без полномочий root, которого вы создали в предварительных условиях на своем PHP-дроплете.

[php]
your_server_ip ansible_ssh_user=sammy

Сохраните и закройте файл hosts. Давайте запустим простую проверку, чтобы убедиться, что Ansible может подключиться к хосту, как и ожидалось, вызвав модуль ping в новой группе php.

  1. 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.

  1. 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-дроплете требуется пароль.

  1. 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 для редактирования.

  1. 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.

  1. 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 для редактирования.

  1. 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

Сохраните и закройте плейбук, затем запустите его.

  1. 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 для редактирования.

  1. 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.

  1. 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 для редактирования.

  1. 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

Сохраните плейбук и запустите его:

  1. 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 для редактирования.

  1. 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

Сохраните и запустите плейбук:

  1. 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:

  1. 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:

  1. 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

Сохраните и снова запустите плейбук:

  1. 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 и запускать одну ручную команду.