Эта статья представляет собой обучающий материал, который предназначен для начинающих системных администраторов, поэтому опытным специалистам можно смело его пропустить. Публикация является продолжением цикла обучающих статей вот, вот.
В этом материале мы будем практиковаться писать Ansible role для автоматического поднятия web-сервера.
Итак, как я уже упоминал в первой части, любое написание ansible-роли сопровождается планом. В этот план нужно включить все, что будет необходимо установить и настроить.
Если рассматривать все пункты в одной статье, то материал получается слишком объемным, - собственно, поэтому и было принято решение разделить его на две части. Вот наш план, в котором зачеркнуты первые три пункта, которые мы выполнили в первой части:
Пункт 1. Первоначальная настройка сервера.Пункт 2. Установка LEMP.Пункт 3. Права и пользователь.Пункт 4. Настройка LEMP.
Пункт 5. Перенос кода площадки и БД.
Пункт 6. Тестирование.
Пункт 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. Первоначальная настройка сервера.
На этом этапе мы произведем настройку следующих сервисов:
php
nginx
mysql
apache2
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
with_items: - создаем массив переменных из необходимых нам пакетов.
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.
-
Для настройки нам необходимо перенести конфигурационные файлы nginx:
nginx.conf;
конфигурацию площадки. domain_name.conf.
Включить площадку.
Перезагрузить nginx.
Переходим в директорию /var/ansible/LEMP/files
.
Создаем директорию nginx.
mkdir nginx
cd nginx/
В директории nginx необходимо создать 2 файла: nginx.conf и domain_name.conf.
touch nginx.conf domain_name.conf
nginx.conf необходимо передать в корневую директорию nginx
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
src - файл в директории ./files;
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 добавлена.
Итог:
Передается конфигурация nginx и domain_name.
Создается символьная ссылка в sites-enabled.
Перезагружается сервис.
Настройка 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
Итог:
Перезагружаем сервис mysql.
Настройка mysql завершена.
Настройка apache2.
Делаем аналогичные действия как и у nginx
Необходимо передать
apache2.conf
domain_name.conf
ports.conf
Создаем директорию и выше перечисленные файлы в директории /var/ansible/LEMP/files
.
Конфигурации для apache2 и domain_name можно взять из следующих статей:
Конфигурация apache2.conf
Конфигурация 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
Итог:
Передаются файлы конфигурации;
Перезагружаем сервис apache2.
Настройка exim4.
Необходимо:
Передать файл конфигурации
/etc/exim4/update-exim4.conf.conf
;Перезагрузить 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.
Это:
mysql_dump - директория с дампом площадки;
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.
Рекомендации для чтения:
Комментарии (15)
NAI
30.06.2022 16:54+2- name: Copy domain_name config copy: src: nginx/domain_name.conf dest: /etc/nginx/sites-available/domain_name.conf
Файл с переменными /var/ansible/LEMP/vars/main.yml: DOMAIN_NAME: domain_name
Т.е. не смотря на наличие файла с переменными, в которых указан domain_name, во всех конфигах вы домены прибиваете гвоздями и копируете? Т.е. на следующий проект надо вносить изменения в 4 файла?... не надо так.
Лучше сразу объяснить про temlpates.
А еще не понятно, почему нет разбиения по ролям, хотя LEMP как бы намекает на 4 независимых роли 8)
P.s. после ребута сервер превратится в тыкву т.к. у сервисов нет enabled: yes
thisprogame Автор
01.07.2022 17:08-1Добрый день.
Да действительно можно не прибивать гвоздями, а использовать переменную.
Постараюсь исправить данный момент в статье. Спасибо!
andreymal
30.06.2022 16:55+1PHP 7.3, использование with_items, неиспользование FQCN… Такое чувство, будто статья валялась в песочнице несколько лет и её выпустили только сейчас
Использование files вместо templates тоже смущает, уж хотя бы domain_name стоит читать из переменной, чтобы можно было как минимум разделить staging и production, наверное?
thisprogame Автор
01.07.2022 17:14Да, можно так делать. Не был учтен данный момент при написании. Исправлю. Спасибо!
DenTs
01.07.2022 10:19+1Мне кажется, что для новичков это полезный материал, помогает наглядно понять основные возможности ansible.
В качестве следующего шага, мне кажется, что стоит добавить переменные и templates, чтобы показать возможности параметризации в ansible.
Также возможно под эту задачу (или под компоненты) уже есть готовая роль, которую можно переиспользовать.
DarkHost
01.07.2022 10:31Было бы интересно увидеть продолжение(чужие варианты реализации) того же плэйбука, но когда, например, нужно забиндить виртуалхост только на внешнем IP. Ну и другие варианты использования "фактов".
nikweter
В целом неплохо. Гораздо лучше чем в прошлой статье. Но…
Я примерно такое года 3 назад писал, и без захардкоженых путей вроде dest: /etc/php/7.3/apache2
Версия php выносится в переменную {{ php_version }} и ставится любая нужная примерно как — php{{ php_version }}-curl и файлы также раскладываются.
mysql я какой-то ролью с гэлакси настраивал — базы создавал с пользователями и дампы раскатывал. Не помню чем мне встроенный модуль не угодил.
Учитывая то, что вы меня на работу лет 5 назад не взяли из-за недостатка квалификации, средний уровень статей по ansible немного… э-э-э-… удручает.
thisprogame Автор
В начале своего пути очень много информации, которую трудно переварить моментально.
Данные статьи написана простыми словами для обучения новичков. Она не является идеальной. Так, что просим не судить строго)