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

В этом материале мы будем практиковаться писать Ansible role для автоматического поднятия web-сервера.

Итак, как я ��же упоминал в первой части, любое написание ansible-роли сопровождается планом. В этот план нужно включить все, что будет необходимо установить и настроить.

Если рассматривать все пункты в одной статье, то материал получается слишком объемным, - собственно, поэтому и было принято решение разделить его на две части. Вот наш план, в котором зачеркнуты первые три пункта, которые мы выполнили в первой части:

  1. Пункт 1. Первоначальная настройка сервера.

  2. Пункт 2. Установка LEMP.

  3. Пункт 3. Права и пользователь.

  4. Пункт 4. Настройка LEMP.

  5. Пункт 5. Перенос кода площадки и БД.

  6. Пункт 6. Тестирование.

  7. Пункт 7. Итог.

В этой статье выполним оставшиеся четыре этапа. Итак, на данный момент в директории /var/ansible находится:

.

├── hosts.txt

├── LEMP

│   ├── defaults

│   │   └── main.yml

│   ├── files

│   ├── handlers

│   │   └── main.yml

│   ├── meta

│   │   └── main.yml

│   ├── README.md

│   ├── tasks

│   │   ├── apache2_install.yml

│   │   ├── default_settings.yml

│   │   ├── default_user_settings.yml

│   │   ├── exim4_install.yml

│   │   ├── main.yml

│   │   ├── mysql_install.yml

│   │   └── nginx_install.yml

│   ├── templates

│   ├── tests

│   │   ├── inventory

│   │   └── test.yml

│   └── vars

│       └── main.yml

└── playbook.yml

Пункт 4. Первоначальная настройка сервера.

На этом этапе мы произведем настройку следующих сервисов:

  1. php

  2. nginx

  3. mysql

  4. apache2

  5. exim4

Настройка php.

Первым делом необходимо установить php на удаленный сервер. Для этого создаем пустой файл в /var/ansible/LEMP/tasks с названием php.yml. Используем модуль apt.

cd /var/ansible/LEMP/tasks
touch php.yml

Добавляем:

- name: install php
  apt: name={{ item }} update_cache=yes state=latest
  with_items:
  - git
  - php
  - php-curl
  - php-gd
  - php-mbstring
  - php-xml
  - php-xmlrpc
  - php-soap
  - php-intl
  - php-zip
  1. with_items: - создаем массив переменных из необходимых нам пакетов.

  2. name={{ item }} - здесь мы используем массив item для установки php модулей. apt будет выполняться до тех пор, пока не установит все пакеты из массива item.

Не забываем подключать новый yml-файл в main.yml.

В main.yml добавляем.

#####install php
  - include_tasks: php.yml

Для php нам необходимо будет передать php.ini файл.

Создаем директорию php и файл php-ansible.ini в /var/ansible/LEMP/files/.

cd /var/ansible/LEMP/files/
mkdir php
touch php/php.ini

Вставляем в файл php-ansible.ini, после [PHP], любую необходимую вам конфигурацию:

[PHP]

Далее необходимо передать этот файл в /etc/php/7.3/apache2/. Он автоматически загрузится и применится после перезагрузки интерпретатора php. В данном случае это apache2.

Открываем файл php.yml в заданиях (/var/ansible/LEMP/tasks/php.yml) и добавляем копирование файлов и перезагрузку apache2.

Добавляем:

- name: copy config
  copy:
    src: php/php-ansible.ini
    dest: /etc/php/7.3/apache2

- name: restart apache2
  service:
    name: apache2
    state: restarted

Настройка nginx.

  1. Для настройки нам необходимо перенести конфигурационные файлы nginx:

    1. nginx.conf;

    2. конфигурацию площадки. domain_name.conf.

  2. Включить площадку.

  3. Перезагрузить nginx.

Переходим в директорию /var/ansible/LEMP/files.

Создаем директорию nginx.

mkdir nginx
cd nginx/

В директории nginx необходимо создать 2 файла: nginx.conf и domain_name.conf.

touch nginx.conf domain_name.conf
  1. nginx.conf необходимо передать в корневую директорию nginx

  2. domain_name.conf необходимо передать в sites-available.

В nginx.conf вставляем конфигурацию из нашей предыдущей статьи.

В domain_name.conf конфигурацию из нашей предыдущей статьи.

После добавления конфигурации переходим в ./tasks/nginx_install.yml.

Передаем конфигурацию на удаленный сервер с помощью модуля copy и file.

Добавляем:

  - name: Copy config.
    copy:
      src: nginx/nginx.conf
      dest: /etc/nginx/nginx.conf

  - name: Copy domain_name  config
    copy:
      src: nginx/domain_name.conf
      dest: /etc/nginx/sites-available/domain_name.conf

  - name: enable site domain_name
    file:
      src: /etc/nginx/sites-available/domain_name.conf
      dest: /etc/nginx/sites-enabled/domain_name.conf
      state: link

  - name: restart nginx
    service:
      name: nginx
      state: restarted
  1. src - файл в директории ./files;

  2. dest - адрес сохранения файла на удаленном сервере.

Запускаем и провер��ем:

TASK [LEMP : include_tasks] *************************************************************************************************************************************************************************************
included: /var/ansible/LEMP/tasks/nginx_install.yml for ansible2
TASK [LEMP : Install nginx] *************************************************************************************************************************************************************************************
ok: [ansible2]
TASK [LEMP : Copy config.] **************************************************************************************************************************************************************************************
changed: [ansible2]
TASK [LEMP : Copy domain_name  config] **************************************************************************************************************************************************************************
changed: [ansible2]
TASK [LEMP : enable site domain_name] ***************************************************************************************************************************************************************************
changed: [ansible2]
PLAY RECAP ******************************************************************************************************************************************************************************************************
ansible2                   : ok=4    changed=3    unreachable=0    failed=0

Конфигурация для nginx добавлена. 

Итог:

  1. Передается конфигурация nginx и domain_name.

  2. Создается символьная ссылка в sites-enabled.

  3. Перезагружается сервис.

Настройка mysql.

Необходимо создать конфигурационный файл mysql.cnf, после чего передать его на удаленный сервер.

Создаем директорию mysql в /var/ansible/LEMP/files.

cd /var/ansible/LEMP/files
mkdir mysql
cd mysql/
touch mysql.cnf

Вставляем после [mysqld] необходимую вам конфигурацию.

[mysqld]

Открываем файл конфигурации ansible mysql /var/ansible/LEMP/tasks/mysql_install.yml

Передаем файл конфигурации на удаленный сервер и перезагружаем mysql.

Добавляем:

  - name: Copy config
    copy:
      src: mysql/mysql.cnf
      dest: /etc/mysql/mysql.conf.d/mysql.cnf

  - name: restart mysql
    service:
      name: mysql
      state: restarted

Итог:

  1. Перезагружаем сервис mysql.

  2. Настройка mysql завершена.

Настройка apache2.

Делаем аналогичные действия как и у nginx

Необходимо передать

  1. apache2.conf

  2. domain_name.conf

  3. ports.conf

Создаем директорию и выше перечисленные файлы в директории /var/ansible/LEMP/files.

Конфигурации для apache2 и domain_name можно взять из следующих статей:

  1. Конфигурация apache2.conf

  2. Конфигурация domain_name.conf.

Настраиваем работу apache2 на 81 порту. Добавляем конфигурацию для ports.conf:

Listen 81
<IfModule ssl_module>
         Listen 443
</IfModule>

<IfModule mod_gnutls.c>
         Listen 443
</IfModule>

Далее идем в /var/ansible/LEMP/tasks/apache2_install.yml

Добавляем:

 - name: copy config
    copy:
      src: apache2/apache2.conf
      dest: /etc/apache2/apache2.conf

  - name: copy domain_name config
    copy:
      src: apache2/domain_name.conf
      dest: /etc/apache2/sites-available/domain_name.conf

  - name: enable site domain_name
    file:
      src: /etc/apache2/sites-available/domain_name.conf
      dest: /etc/apache2/sites-enabled/domain_name.conf
      state: link

  - name: copy ports
    copy:
      src: apache2/ports.conf
      dest: /etc/apache2/ports.conf

  - name: restart apache2
    service:
      name: apache2
      state: restarted

Итог:

  1. Передаются файлы конфигурации;

  2. Перезагружаем сервис apache2.

Настройка exim4.

Необходимо:

  1. Передать файл конфигурации /etc/exim4/update-exim4.conf.conf;

  2. Перезагрузить exim4.

Создаем директорию exim4 и файл update-exim4.conf.conf в /var/ansible/LEMP/files.

Добавляем в файл конфигурации exim4:

# /etc/exim4/update-exim4.conf.conf
#
# Edit this file and /etc/mailname by hand and execute update-exim4.conf
# yourself or use 'dpkg-reconfigure exim4-config'
#
# Please note that this is _not_ a dpkg-conffile and that automatic changes
# to this file might happen. The code handling this will honor your local
# changes, so this is usually fine, but will break local schemes that mess
# around with multiple versions of the file.
#
# update-exim4.conf uses this file to determine variable values to generate
# exim configuration macros for the configuration file.
#
# Most settings found in here do have corresponding questions in the
# Debconf configuration, but not all of them.
#
# This is a Debian specific file
dc_eximconfig_configtype='local'
dc_other_hostnames='domain_name'
dc_local_interfaces='127.0.0.1 ; ::1'
dc_readhost=''
dc_relay_domains=''
dc_minimaldns='false'
dc_relay_nets=''
dc_smarthost=''
CFILEMODE='644'
dc_use_split_config='false'
dc_hide_mailname=''
dc_mailname_in_oh='true'
dc_localdelivery='mail_spool'

В данный файл добавляете нужную вам конфигурацию.

В файл конфигурации (/var/ansible/LEMP/tasks/exim4_install.yml) добавляем "копирование файла" и "перезагрузка exim4".

  - name: copy config
    copy:
      src: exim4/update-exim4.conf.conf
      dest: /etc/exim4/update-exim4.conf.conf

  - name: restart exim4
    service:
      name: exim4
      state: restarted

Конфигурация для exim4 готова.

Структура директории files с конфигурацией:

├── files

│   ├── apache2

│   │   ├── apache2.conf

│   │   ├── domain_name.conf

│   │   └── ports.conf

│   ├── exim4

│   │   └── update-exim4.conf.conf

│   ├── mysql

│   │   └── mysql.cnf

│   ├── nginx

│   │   ├── domain_name.conf

│   │   └── nginx.conf

│   └── php

│       └── php-ansible.ini

На данный момент настройка сервисов завершена. Если необходимо прокидывать или менять дополнительные файлы, вы также их можете добавить и изменить по выше указанному методу.

Пункт 5. Перенос кода площадки и БД.

В данном пункте необходимо переместить dump площадки для загрузки в БД и перенести код площадки.

Нам понадобится 2 директории в директории files.

Это:

  1. mysql_dump - директория с дампом площадки;

  2. data - директория с кодом.

Для начала добавляем код площадки в директорию /data.

В нашем случае кодом площадки будет выступать установщик wordpress.

Далее переносим дамп вашей БД в директорию /mysql_dump.

Создаем новый yml-файл с названием file.yml по адресу /var/ansible/LEMP/tasks/.

Включаем его в main.yml

  ####add_site_file
  - include_tasks: file.yml

Добавляем в него задание:

  - name: copy file domain_name
    copy:
      src: data/
      dest: /var/www/domain_name/data/
      owner: domain_name
      group: domain_name

  - name: copy dump
    copy:
      src: mysql_dump/dump.sql
      dest: /tmp/dump.sql

  - name: mysql_dump
    mysql_db:
      name: domain_name_db
      state: import
      target: /tmp/dump.sql
      login_user: root
      login_password: "{{ mysql_root_password }}"

Для того, чтоб загрузить дамп в БД, используется модуль mysql_db.

Файлы площадки и дамп переместили на сервер.

Пункт 6. Тестирование.

На данный момент структура директорий выгляди�� следующим образом:
.
├── hosts.txt
├── LEMP
│   ├── defaults
│   │   └── main.yml
│   ├── files
│   │   ├── apache2
│   │   │   ├── apache2.conf
│   │   │   ├── domain_name.conf
│   │   │   └── ports.conf
│   │   ├── data
│   │   ├── exim4
│   │   │   └── update-exim4.conf.conf
│   │   ├── mysql
│   │   │   └── mysql.cnf
│   │   ├── mysql_dump
│   │   │   └── dump.sql
│   │   ├── nginx
│   │   │   ├── domain_name.conf
│   │   │   └── nginx.conf
│   │   └── php
│   │       └── php-ansible.ini
│   ├── handlers
│   │   └── main.yml
│   ├── meta
│   │   └── main.yml
│   ├── README.md
│   ├── tasks
│   │   ├── apache2_install.yml
│   │   ├── default_settings.yml
│   │   ├── default_user_settings.yml
│   │   ├── exim4_install.yml
│   │   ├── file.yml
│   │   ├── main.yml
│   │   ├── mysql_install.yml
│   │   ├── nginx_install.yml
│   │   └── php.yml
│   ├── templates
│   ├── tests
│   │   ├── inventory
│   │   └── test.yml
│   └── vars
│       └── main.yml
├── php.ini
├── playbook.retry
└── playbook.yml

Конфигурация заданий в директории .tasks:

apache2_install.yml:

  - name: Install apache2
    apt:
      name: apache2
      state: latest

  - name: copy config
    copy:
      src: apache2/apache2.conf
      dest: /etc/apache2/apache2.conf

  - name: copy domain_name config
    copy:
      src: apache2/domain_name.conf
      dest: /etc/apache2/sites-available/domain_name.conf

  - name: copy ports
    copy:
      src: apache2/ports.conf
      dest: /etc/apache2/ports.conf

  - name: restart apache2
    service:
      name: apache2
      state: restarted

default_settings.yml:

  - name: update repo.
    shell: apt update

  - name: install default app.
    shell:
      cmd: "apt install -y dirmngr mc iotop htop telnet tcpdump nmap curl hexedit sudo zip unzip patch pwgen vim less parted subversion ntp bzip2 lsof strace mutt s-nail ncdu smartmontools tree dnsutils logrotate rsyslog"

  - name: time
    shell:
      cmd: "timedatectl set-timezone {{time_zone}}"

  - name: locale settings
    shell:
      cmd: 'locale-gen {{locale1}} && update-locale LANG={{locale2}} LC_TIME="{{locale1}}"'

  - name: hostname
    shell:
      cmd: "hostnamectl set-hostname {{DOMAIN_NAME}}"

default_user_settings.yml:

  - name: add group
    group:
      name: "{{ DOMAIN_NAME }}"
      state: present
      gid: "{{ Group_GID }}"

  - name: add user
    user:
      name: "{{ DOMAIN_NAME }}"
      password: "{{ user_password | password_hash('sha512') }}"
      uid: "{{ User_uid }}"
      group: "{{ DOMAIN_NAME }}"
      state: present
      update_password: on_create
      home: "/var/www/{{ DOMAIN_NAME }}"
      shell: /bin/bash

  - name: create home directory
    file:
      path: "/var/www/{{ DOMAIN_NAME }}"
      owner: "{{ DOMAIN_NAME }}"
      group: "{{ DOMAIN_NAME }}"
      mode: 0751
      state: directory

  - name: create other directory
    file:
      path: "/var/www/{{ DOMAIN_NAME }}/data"
      owner: "{{ DOMAIN_NAME }}"
      group: "{{ DOMAIN_NAME }}"
      mode: 0755
      state: directory

  - name: create other directory
    file:
      path: "/var/www/{{ DOMAIN_NAME }}/log"
      owner: "{{ DOMAIN_NAME }}"
      group: "{{ DOMAIN_NAME }}"
      mode: 0755
      state: directory

  - name: create other directory
    file:
      path: "/var/www/{{ DOMAIN_NAME }}/sess"
      owner: "{{ DOMAIN_NAME }}"
      group: "{{ DOMAIN_NAME }}"
      mode: 0755
      state: directory

  - name: create other directory
    file:
      path: "/var/www/{{ DOMAIN_NAME }}/tmp"
      owner: "{{ DOMAIN_NAME }}"
      group: "{{ DOMAIN_NAME }}"
      mode: 0755
      state: directory

  - name: create other directory
    file:
      path: "/var/www/{{ DOMAIN_NAME }}/upload"
      owner: "{{ DOMAIN_NAME }}"
      group: "{{ DOMAIN_NAME }}"
      mode: 0755
      state: directory

  - name: create other directory
    file:
      path: "/var/www/{{ DOMAIN_NAME }}/log/apache2"
      owner: "{{ DOMAIN_NAME }}"
      group: "{{ DOMAIN_NAME }}"
      mode: 0755
      state: directory

  - name: create other directory
    file:
      path: "/var/www/{{ DOMAIN_NAME }}/log/nginx"
      owner: "{{ DOMAIN_NAME }}"
      group: "{{ DOMAIN_NAME }}"
      mode: 0755
      state: directory

exim4_install.yml:

  - name: Install exim4
    apt:
      name: exim4
      state: latest

  - name: copy config
    copy:
      src: exim4/update-exim4.conf.conf
      dest: /etc/exim4/update-exim4.conf.conf

  - name: restart exim4
    service:
      name: exim4
      state: restarted

main.yml:

#  - include_tasks: default_settings.yml
  #####install mysql
#  - include_tasks: mysql_install.yml
  #####install nginx
#  - include_tasks: nginx_install.yml
  #####install apache2
#  - include_tasks: apache2_install.yml
  #####install exim4
#  - include_tasks: exim4_install.yml
  #####default user settings
#  - include_tasks: default_user_settings.yml
  #####install php
#  - include_tasks: php.yml
  #####copy file domain_name
  - include_tasks: file.yml

mysql_install.yml:

  - name: add mysql repo
    get_url:
      url: https://dev.mysql.com/get/mysql-apt-config_0.8.6-1_all.deb
      dest: "/tmp"
      mode: 0440

  - name: install mysql repo
    apt: "deb=/tmp/mysql-apt-config_0.8.6-1_all.deb"
    become: true

  - name: add key mysql and update repo
    shell: "apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 467B942D3A79BD29 && apt update"

  - name: install python-mysqldb
    apt:
      name: python-mysqldb
      state: present
      update_cache: yes

  - name: check latest version of mysql 5.7
    command: bash -c "apt-cache showpkg mysql-server|grep 5.7|head -1|cut -d' ' -f1"
    register: latestmysql57
  - debug: msg="{{ latestmysql57.stdout }}"

  - name: install mysql 57
    apt:
      name: mysql-server={{ latestmysql57.stdout }}
      state: present
      update_cache: yes

  - name: update mysql root password for all root accounts
    become: true
    mysql_user:
      name: root
      host: "{{ item }}"
      password: "{{ mysql_root_password }}"
      login_user: root
      login_password: 12345
      check_implicit_admin: yes
      priv: "*.*:ALL,GRANT"
      state: present
    with_items:
      - 127.0.0.1
      - ::1
      - localhost

  - name: Create a new database with name 'DOMAIN_NAME_DB'
    mysql_db:
      login_user: root
      login_password: "{{ mysql_root_password }}"
      name: "{{name_db}}"
      state: present

  - name: add user DOMAIN_NAME_USR
    mysql_user:
      login_user: root
      login_password: "{{ mysql_root_password }}"
      host: localhost
      name: "{{user_db}}"
      password: "{{password_user_db}}"
      priv: '{{name_db}}.*:ALL,GRANT'
      state: present

  - name: Copy config
    copy:
      src: mysql/mysql.cnf
      dest: /etc/mysql/mysql.conf.d/mysql.cnf

  - name: restart mysql
    service:
      name: mysql
      state: restarted

nginx_install.yml:

  - name: Install nginx
    apt:
      name: nginx
      state: latest

  - name: Copy config.
    copy:
      src: nginx/nginx.conf
      dest: /etc/nginx/nginx.conf

  - name: Copy domain_name  config
    copy:
      src: nginx/domain_name.conf
      dest: /etc/nginx/sites-available/domain_name.conf

  - name: enable site domain_name
    file:
      src: /etc/nginx/sites-available/domain_name.conf
      dest: /etc/nginx/sites-enabled/domain_name.conf
      state: link

  - name: restart nginx
    service:
      name: nginx
      state: restarted

php.yml:

- name: install php
  apt: name={{ item }} update_cache=yes state=latest
  with_items:
  - git
  - php
  - php-curl
  - php-gd
  - php-mbstring
  - php-xml
  - php-xmlrpc
  - php-soap
  - php-intl
  - php-zip

- name: copy config
  copy:
    src: php/php-ansible.ini
    dest: /etc/php/7.3/apache2

- name: restart apache2
  service:
    name: apache2
    state: restarted

Файл с переменными /var/ansible/LEMP/vars/main.yml:

DOMAIN_NAME: domain_name
locale1: ru_RU.UTF-8
locale2: en_US.UTF-8
time_zone: Europe/Moscow
User_uid: 10000
Group_GID: 10000
user_password: password
mysql_root_password: password
name_db: domain_name_db
user_db: domain_name_usr
password_user_db: password

Для тестирование переходим на удаленный сервер. Добавляем в /etc/hosts запись вида:

127.0.0.1 domain_name.com

Проверяем статусы сервисов:

systemctl status nginx apache2 mysql exim4

Если все сервисы работают, делаем запрос на сайт с помощью curl.

# curl -LI domain_name.com
HTTP/1.1 302 Found
Server: nginx
Date: Wed, 29 Jun 2022 11:32:10 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Keep-Alive: timeout=15
Location: http://domain_name.com/wp-admin/setup-config.php

HTTP/1.1 200
Server: nginx
Date: Wed, 29 Jun 2022 11:32:10 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Keep-Alive: timeout=15
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0

Все работает! Далее необходимо настраивать площадку в веб интерфейсе.

Пункт 7. Итог.

Ну вот мы с вами и познакомились с Ansible и базовыми модулями, которые чаше всего используется в его работе. Разумеется, данная роль ansible не является идеальной, и создана лишь для обучения. Этого мини-курса вполне будет достаточно, чтобы понять, как работает ansible на базовом уровне.

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

Также подписывайтесь на наш telegram-канал DevOps FM.

Рекомендации для чтения:

Зашита от dos/ddos.

Обучение docker.

10 частых ошибок в настройке nginx.

Настройка LEMP сервера с нуля.