В этом руководстве мы рассмотрим, как автоматизировать установку и удаление LAMP-стека (Linux, Apache, MySQL, PHP) с помощью Ansible. Ansible — это инструмент автоматизации с открытым исходным кодом, который позволяет вам определять инфраструктуру и управлять ею как кодом.

Введение

Стек LAMP — это популярный пакет программного обеспечения, используемый для развертывания веб-приложений. Он состоит из следующих компонентов:

  • Linux: операционная система (в данном случае мы используем инстанс Amazon Linux).

  • Apache: веб-сервер, отвечающий за обслуживание веб-контента.

  • MySQL/MariaDB: система управления реляционными базами данных для хранения данных приложений.

  • PHP: серверный язык сценариев для динамического веб-контента.

Мы будем использовать Ansible для автоматизации установки и настройки этих компонентов.

Что понадобится

Прежде чем мы начнем, убедитесь, что у вас есть:

  • Экземпляр Amazon Linux с установленным Ansible.

  • Доступ к сервису AWS Secrets Manager.

Создание Ansible Playbook

Начнем с создания плейбука Ansible, который установит стек LAMP и настроит компоненты.

---
- name: "Installing LAMP stack and configuring"
  hosts: amazon
  become: true
  vars_files:
    - httpd.vars
    - mariadb.vars
    - packages.vars
  tasks:
    # Task 1: Installing Packages
    - name: "Installing Packages"
      yum:
        name: "{{ packages }}"
        state: present
      tags:
        - lamp
        - never

    # Task 2: Enabling/Restarting services
    - name: "Enabling/Restarting services"
      service:
        name: "{{ item }}"
        state: restarted
        enabled: true
      with_items: "{{ services }}"
      tags:
        - lamp
        - never

    # Task 3: Creating httpd.conf from template
    - name: "Creating httpd.conf from httpd.conf.tmpl"
      template:
        src: httpd.conf.tmpl
        dest: /etc/httpd/conf/httpd.conf
      tags:
        - lamp
        - never

    # Task 4: Creating Virtual host
    - name: "Creating Virtual host"
      template:
        src: virtualhost.conf.tmpl
        dest: /etc/httpd/conf.d/default.conf
        owner: "{{ httpd_owner }}"
        group: "{{ httpd_group }}"
      tags:
        - lamp
        - never

    # Task 5: Creating docroot for the website
    - name: "Creating docroot for {{ hostname }}"
      file:
        path: "/var/www/html/default/"
        state: directory
        owner: "{{ httpd_owner }}"
        group: "{{ httpd_group }}"
      tags:
        - lamp
        - never

    # Task 6: Setting python3 mysql module PyMySQL
    - name: "Setting python3 mysql module PyMySQL"
      pip:
        name: PyMySQL
      tags:
        - lamp
        - mariadb
        - never

    # Task 7: Setting ROOT password for mariadb-server
    - name: "Setting ROOT password for mariadb-server"
      ignore_errors: true
      mysql_user:
        login_user: "root"
        login_password: ""
        login_unix_socket: /var/lib/mysql/mysql.sock
        name: "root"
        password: "{{ mariadb_root_password }}"
      tags:
        - lamp
        - mariadb
        - never

    # Task 8: Creating DB for the website
    - name: "Creating DB for blog - {{blog_db_name}}"
      mysql_db:
        login_user: "root"
        login_password: "{{ mariadb_root_password }}"
        login_unix_socket: /var/lib/mysql/mysql.sock
        name: "{{ blog_db_name }}"
        state: present
      tags:
        - lamp
        - mariadb
        - never

    # Task 9: Creating extra user for WordPress
    - name: "Creating extra user for WordPress - {{extra_user_name}}"
      mysql_user:
        login_user: "root"
        login_password: "{{ mariadb_root_password }}"
        login_unix_socket: /var/lib/mysql/mysql.sock
        name: "{{ extra_user_name }}"
        password: "{{ extra_user_password }}"
        host: "%"
        priv: "{{ blog_db_name }}.*:ALL"
      tags:
        - lamp
        - never
        - mariadb

    # Task 10: Downloading WordPress
    - name: "Downloading WordPress using URL"
      get_url:
        url: "{{ wp_url }}"
        dest: "/tmp/wordpress.tar.gz"
      tags:
        - lamp
        - mariadb
        - wordpress
        - never

    # Task 11: Extracting WordPress
    - name: "Extracting WordPress"
      unarchive:
        src: "/tmp/wordpress.tar.gz"
        dest: "/tmp/"
        remote_src: true
      tags:
        - lamp
        - mariadb
        - wordpress
        - never

    # Task 12: Copying WordPress files to docroot
    - name: "Copying WordPress files to docroot"
      copy:
        src: "/tmp/wordpress/"
        dest: "/var/www/html/default/"
        remote_src: true
        owner: "{{ httpd_owner }}"
        group: "{{ httpd_group }}"
      tags:
        - lamp
        - mariadb
        - wordpress
        - never

    # Task 13: Copying wp-config.php file to remote server
    - name: "Copying wp-config.php file to remote server"
      template:
        src: "./wp-config.php.tmpl"
        dest: "/var/www/html/default/wp-config.php"
        owner: "{{ httpd_owner }}"
        group: "{{ httpd_group }}"
      tags:
        - lamp
        - mariadb
        - wordpress
        - never

    # Task 14: Post Installation Cleanup
    - name: "Post Installation Cleanup"
      file:
        path: "{{ item }}"
        state: absent
      with_items:
        - "/tmp/wordpress/"
        - "/tmp/wordpress.tar.gz"
      tags:
        - wordpress

    # Task 15: Removing Packages
    - name: "Removing Packages"
      yum:
        name: "{{ packages }}"
        state: absent
      tags:
        - cleanup
        - never

    # Task 16: Removing Directories
    - name: "Removing Directories"
      file:
        path: "{{ item }}"
        state: absent
      with_items:
        - /etc/httpd/conf/httpd.conf
        - /etc/httpd/conf.d/default.conf
        - /var/www/html/default/
      tags:
        - cleanup
        - never

Плейбук состоит из нескольких задач, каждая из которых отвечает за определенное действие.

  • Задача 1: Установка пакетов: устанавливает необходимые пакеты для стека LAMP.

  • Задача 2. Включение/перезапуск служб. Обеспечивает включение и перезапуск необходимых служб.

  • Задача 3: Создание httpd.conf из шаблона: Генерирует файл конфигурации HTTP-сервера Apache из шаблона.

  • Задача 4. Создание виртуального хоста. Создает файл конфигурации виртуального хоста для веб-сайта по умолчанию.

  • Задача 5: Создание docroot для веб-сайта: Создает корневой каталог документов для веб-сайта.

  • Задача 6: Настройка модуля python3 mysql PyMySQL: Устанавливает модуль PyMySQL для Python.

  • Задача 7: Установка пароля ROOT для mariadb-server: Установка пароля root для сервера MariaDB.

  • Задача 8: Создание БД для сайта.

  • Задача 9: Создание дополнительного пользователя с привилегиями для базы данных WordPress.

  • Задача 10: Загрузка WordPress: получение исходного кода WordPress по указанному URL-адресу.

  • Задача 11: Извлечение архива WordPress.

  • Задача 12: Копирование файлов WordPress в корневой каталог документа.

  • Задача 13: Копирование файла wp-config.php на удаленный сервер: Создает файл wp-config.php для WordPress.

  • Задача 14: Очистка после установки: очищает временные файлы и каталоги.

  • Задача 15. Удаление пакетов, которые были установлены в процессе.

  • Задача 16: Удаление каталогов, которые были созданы в процессе.

Теги

Теги в Ansible позволяют выборочно запускать определенные задачи или группы задач в плейбуке. Вы можете назначать теги задачам с помощью tags атрибута, а затем указывать нужные теги при запуске плейбука.

Для запуска определенных задач с использованием тегов вы можете использовать опцию --tags с командойansible-playbook. Вот пример команды:

ansible-playbook lamp.yml --tags lamp

В приведенной выше команде будут выполняться только задачи, отмеченные lamp.

Вы также можете исключить определенные задачи, используя --skip-tags опцию. Например, чтобы пропустить задачи с тегом never, вы можете использовать следующую команду:

ansible-playbook lamp.yml --skip-tags never

В этом случае задачи с тегом never не будут выполняться.

Кроме того, вы можете перечислить все доступные теги в playbook, используя опцию --list-tags. Вот пример команды:

ansible-playbook lamp.yml --list-tags

Эта команда отобразит список всех тегов, определенных в вашем плейбуке.

Используя теги, вы можете настроить выполнение вашего плейбука в соответствии с конкретными требованиями, что обеспечивает большую гибкость и контроль.

Шифрование

Чтобы зашифровать lamp.yml плейбук с помощью Ansible Vault, вы можете использовать команду ansible-vault. Ansible Vault предоставляет безопасный способ шифрования конфиденциальных данных в ваших книгах.

Вот команда для шифрования lamp.yml файла:

ansible-vault encrypt lamp.yml

После выполнения этой команды вам будет предложено ввести и подтвердить пароль для защиты зашифрованного файла. Обязательно запомните этот пароль, так как он понадобится вам позже для расшифровки файла.

Как только lamp.yml файл будет зашифрован, его содержимое будет зашифровано и станет нечитаемым без предварительной расшифровки.

Чтобы запустить playbook с зашифрованным файлом, вы можете использовать команду ansible-playbook вместе с --ask-vault-pass опцией ввода пароля:

ansible-playbook lamp.yml --ask-vault-pass

При появлении запроса введите пароль, который вы использовали для шифрования файла.

Обратите внимание, что вы также можете указать пароль через файл или ссылку на файл паролей, используя параметр --vault-password-file, который может быть полезен при автоматизации выполнения зашифрованных книг воспроизведения.

Зашифровав playbook с помощью Ansible Vault, вы можете защитить конфиденциальную информацию, такую как пароли, ключи API или любые другие конфиденциальные данные, которые могут присутствовать в вашем playbook.

Для дополнительной безопасности я предпринял следующие шаги:

Во-первых, я создал запись Secrets Manager в AWS для безопасного хранения пароля моего хранилища. Это гарантирует, что конфиденциальная информация хранится в зашифрованном виде и недоступна для неавторизованных пользователей.

Затем я создал политику IAM, которая предоставляет доступ на чтение к диспетчеру секретов.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "SecretsManagerReadAccess",
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "arn:aws:secretsmanager:ap-south-1:939486479455:secret:vault_pass-yAAbi4"
        }
    ]
}

После создания политики я создал роль IAM, которая использует эту политику. Эта роль будет прикреплена к моей главной машине, что позволит ей безопасно получить пароль хранилища от Secrets Manager.

Чтобы получить пароль хранилища из Secrets Manager, я создал сценарий bash. Сценарий использует AWS CLI команду aws secretsmanager get-secret-value и передает секретный идентификатор в качестве аргумента (vault_pass). Затем сценарий извлекает значение пароля из ответа JSON с помощью jq и сохраняет его в secret_value переменной.

Вот пример bash-скрипта:

#!/bin/bash

secret_id="vault_pass"
secret_value=$(aws secretsmanager get-secret-value --secret-id "$secret_id" --query 'SecretString' --output text | jq -r '.vault_pass')
# Use the secret value in further operations
if [ -n "$secret_value" ]; then
    # Perform desired operations using the secret value
    echo "Retrieved the vault password: $secret_value"
else
    echo "Failed to retrieve the vault password"
fi

Запустив этот сценарий, я могу безопасно получить пароль хранилища от Secrets Manager.

Наконец, чтобы использовать пароль хранилища в моем плейбуке Ansible, я передаю сценарий в качестве аргумента командной строки вместе с командой ansible-playbook. Это гарантирует, что плейбук будет иметь доступ к паролю хранилища, когда это необходимо.

ansible-playbook -i inventory lamp.yml --vault-password-file <path/to/bash/script.sh>

Заключение

С помощью этого плейбука Ansible и скрипта AWS Secrets Manager можно автоматизировать установку и настройку LAMP-стека. Это позволяет эффективно управлять инфраструктурой и упрощает процесс развертывания.


Если вы хотите научиться устанавливать LEMP-стеки, собирать Docker-контейнеры в Ansible, самостоятельно писать плейбуки, использовать роли и модули, приходите на курс «Ansible: Infrastructure as Code». Новый поток стартует 7 августа. Посмотреть программу и записаться на курс можно на нашем сайте. Ждём на курсе!

Комментарии (3)


  1. GrimAnEye
    04.07.2023 16:58
    +1

    Этот пример плейбука только для того, чтобы вставить в конце рекламу сервиса?

    Используется vault, а в чем, например, его преимущество при автоматическом использовании - например какой смысл где-то сохранять пароль, чтобы расшифровать пароль, чтобы с ним запрашивать пароль из облака.

    А почему бы не разбить портянку playbook на роль - да, можно и так и так, но в виде роли можно выделить независимые друг от друга части и отлаживать каждую из частей станет проще. Так же использование роли позволит подробно описать, как работает их механизм, раз статья не высокого уровня сложности и поможет разобраться новичкам.

    А вообще по ansible очень хорошая и подробная официальная документация с примерами https://docs.ansible.com/


    1. AlexGluck
      04.07.2023 16:58

      Классный нерабочий плейбук, запускал на федора с 17 до 36 версии, дебиан с 7 до 12, убунту 10.04-23.04, redhat 5-9.

      Модуль yum поменять на package, pip установку делать для юзера. Такие прям супер сложные решения в 3х тасках.


  1. AnsRomanov
    04.07.2023 16:58

    Статья прилетела прямиком из 2012 года судя по всему.