Продолжение сетапа из AWS: создание стека в AWS – bash-скрипт и CloudFormation шаблон.
Далее потребуется добавить Ansible playbook и роли для настройки хоста.
В принципе — ничего особенно отличного от того, что описано в постах серии RTFM migration, например — Ansible: миграция RTFM 2.9 – монтирование EBS и настройка NGINX на Bastion.
Что надо будет выполнить:
- добавить роль
common, в которой будет выполняться:- монтирование data-диска (EBS)
- установка набора утилит —
mailutils,curl,dnsutils,telnet,unzip - установка
hostname - копирование
.bashrcи.vimrcна хост - настройка таймзоны
- настройка почтового ящика
root
- роль
eximдля настройки отправки уведомлений - роль
nginx, понятно для чего (пока без SSL) - роль
manala.logrotate - роль
jnv.unattended-upgrades
А далее можно будет приступить к созданию ролей для самого стека Prometheus.
Содержание
hosts
Начинаем с создания файла hosts.
Имени для сервера пока нет, поэтому используем IP:
[all:vars] data_volume_mount_path="/data" [btrm-mon-dev] 52.***.***.233 [btrm-mon-dev:vars] data_volume_id="/dev/xvdb" set_hostname="btrm-mon-dev"
Тут:
data_volume_mount_path, которая будет указывать на точку монтирования подключаемого EBSdata_volume_id— сам диск EBS, который подключается к системе CloudFormationset_hostname— будет задано в качестве имени хоста
playbook
Теперь создадим файл плейбука — btrm-monitoring-ansible-provision.yml, пока только с одной ролью common:
- hosts: all
become:
true
roles:
- role: common
роль common
Создаём роль common — добавляем каталоги:
[simterm]
$ mkdir -p roles/common/{tasks,files}
[/simterm]
В roles/common/tasks создаём файл main.yml с одной задачей — вызывать модуль ping:
- name: Execute ping ping:
Время тестить!
Вызываем ansible-playbook:
[simterm]
$ ansible-playbook -i hosts --limit=btrm-mon-dev --private-key=../../aws-credentials/btrm-mon.pem btrm-monitoring-ansible-provision.yml
PLAY [all] ****
TASK [Gathering Facts] ****
fatal: [52.***.***.233]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: Permission denied (publickey).\r\n", "unreachable": true}
to retry, use: --limit @/home/username/Work/btrm-monitoring/ansible/btrm-monitoring-ansible-provision.retry
PLAY RECAP ****
52.***.***.233 : ok=0 changed=0 unreachable=1 failed=0
[/simterm]
ОК, отлично.
Имя пользователя. На хосте запущен AWS AMI с Debian, добавляем admin как ansible_ssh_user в hosts:
[all:vars] data_volume_mount_path="/data" ansible_ssh_user=admin ...
Повторяем:
[simterm]
$ ansible-playbook -i hosts --limit=btrm-mon-dev --private-key=../../aws-credentials/btrm-mon.pem btrm-monitoring-ansible-provision.yml PLAY [all] **** TASK [Gathering Facts] **** ok: [52.***.***.233] TASK [common : Execute ping] **** ok: [52.***.***.233] PLAY RECAP **** 52.***.***.233 : ok=2 changed=0 unreachable=0 failed=0
[/simterm]
Работает.
Хорошо, поехали дальше — добавляем задачи для роли common.
parted
Первой задачей будет создать раздел на диске /dev/xvdb, если его ещё нет.
Для этого надо будет установить саму утилиту parted, а раз так — то установим сразу всё необходимое.
Обновляем roles/common/tasks/main.yml, убираем ping, добавляем задачи — обновить кеш apt, потом обновить все установленные пакеты, потом установить набор дефолтных утилит:
- name: Upgrade all packages to the latest version
apt:
update_cache: yes
upgrade: yes
- name: Install common packages
package:
name: "{{ item }}"
state: present
with_items:
- mailutils
- curl
- dnsutils
- telnet
- unzip
- parted
Третьей задачей вызываем parted и создаём раздел номер 1 на диске из переменной data_volume_id:
...
- name: Create partiniom on {{ data_volume_id }}
parted:
device: "{{ data_volume_id }}"
number: 1
state: present
Проверяем разделы на хосте сейчас:
[simterm]
$ ansible -i hosts btrm-mon-dev --private-key=../../aws-credentials/btrm-mon.pem -a lsblk 52.***.***.233 | SUCCESS | rc=0 >> NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT xvda 202:0 0 8G 0 disk └─xvda1 202:1 0 8G 0 part / xvdb 202:16 0 8G 0 disk
[/simterm]
Проверяем синтаксис плейбука:
[simterm]
$ ansible-playbook -i hosts --syntax-check --limit=btrm-mon-dev btrm-monitoring-ansible-provision.yml playbook: btrm-monitoring-ansible-provision.yml
[/simterm]
И запускаем применение common:
[simterm]
$ ansible-playbook -i hosts --limit=btrm-mon-dev --private-key=../../aws-credentials/btrm-mon.pem btrm-monitoring-ansible-provision.yml PLAY [all] **** TASK [Gathering Facts] **** ok: [52.***.***.233] TASK [common : Upgrade all packages to the latest version] **** [WARNING]: Could not find aptitude. Using apt-get instead. ok: [52.***.***.233] TASK [common : Install common packages] **** changed: [52.***.***.233] => (item=mailutils) ok: [52.***.***.233] => (item=curl) changed: [52.***.***.233] => (item=dnsutils) changed: [52.***.***.233] => (item=telnet) changed: [52.***.***.233] => (item=unzip) changed: [52.***.***.233] => (item=parted) TASK [common : Create partition on /dev/xvdb] **** changed: [52.***.***.233] PLAY RECAP **** 52.***.***.233 : ok=4 changed=2 unreachable=0 failed=0
[/simterm]
Проверяем разделы теперь:
[simterm]
$ ansible -i hosts btrm-mon-dev --private-key=../../aws-credentials/btrm-mon.pem -a lsblk 52.***.***.233 | SUCCESS | rc=0 >> NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT xvda 202:0 0 8G 0 disk └─xvda1 202:1 0 8G 0 part / xvdb 202:16 0 8G 0 disk └─xvdb1 202:17 0 8G 0 part
[/simterm]
Раздел 1 на диске xvdb создан — /dev/xvdb1.
filesystem
Далее — создаём файловую систему на /dev/xvdb1, используем модуль filesystem:
...
- name: Create a ext4 filesystem on /dev/{{ data_volume_id }}1
filesystem:
fstype: ext4
dev: "{{ data_volume_id }}1"
Запускаем, проверяем:
[simterm]
$ ansible-playbook -i hosts --limit=btrm-mon-dev --private-key=../../aws-credentials/btrm-mon.pem btrm-monitoring-ansible-provision.yml ... TASK [common : Create partition on /dev/xvdb] **** ok: [52.***.***.233] TASK [common : Create a ext4 filesystem on /dev/xvdb1] **** changed: [52.***.***.233] PLAY RECAP **** 52.***.***.233 : ok=5 changed=1 unreachable=0 failed=0
[/simterm]
mount
Следующим шагом — надо создать каталог /data, и смонтировать в него раздел /dev/xvdb1.
Используем file для создания каталога и mount — для монтирования диска:
...
- name: Create {{ data_volume_mount_path }} directory
file:
path: "{{ data_volume_mount_path }}"
state: directory
mode: 0755
recurse: yes
- name: Mount data-volume {{ data_volume_id }}1 to {{ data_volume_mount_path }}
mount:
path: "{{ data_volume_mount_path }}"
src: "{{ data_volume_id }}1"
state: mounted
fstype: ext4
Запускаем:
[simterm]
$ ansible-playbook -i hosts --limit=btrm-mon-dev --private-key=../../aws-credentials/btrm-mon.pem btrm-monitoring-ansible-provision.yml ... TASK [common : Create /data directory] **** changed: [52.***.***.233] TASK [common : Mount data-volume /dev/xvdb1 to /data] **** changed: [52.***.***.233] PLAY RECAP **** 52.***.***.233 : ok=7 changed=2 unreachable=0 failed=0
[/simterm]
Проверяем:
[simterm]
$ ansible -i hosts btrm-mon-dev --private-key=../../aws-credentials/btrm-mon.pem -a "ls -l /data" 52.***.***.233 | SUCCESS | rc=0 >> total 16 drwx------ 2 root root 16384 тра 10 15:29 lost+found
[/simterm]
hostname
hostnameСледующим шагом надо поменять имя хоста на значение, указанное в переменной set_hostname нашего файла hosts.
Кроме того, что бы задать имя хоста — надо отредактировать /etc/hosts, но т.к. это AWS EC2 — то /etc/hosts будет перезаписано, ибо при перезагрузке задаётся стартап-скриптами (см. Update Etc Hosts). Что бы отключить это — надо изменить файл /etc/cloud/cloud.cfg.d/01_debian_cloud.cfg и значение manage_etc_hosts в нём с True на False.
Добавляем ещё три задачи — задать имя хоста, добавить его в /etc/hosts для резолва на 127.0.0.1, и отключить обновление /etc/hosts:
...
- name: Set hostname
hostname:
name: "{{ set_hostname }}"
- name: Add hostname to /etc/hosts
lineinfile:
dest: /etc/hosts
regexp: '^127\.0\.0\.1[ \t]+localhost'
line: "127.0.0.1 localhost {{ set_hostname }}"
state: present
- name: Update /etc/cloud/cloud.cfg.d/01_debian_cloud.cfg
lineinfile:
dest: /etc/cloud/cloud.cfg.d/01_debian_cloud.cfg
regexp: '^manage_etc_hosts: true'
line: "manage_etc_hosts: false"
state: present
Проверяем имя сейчас:
[simterm]
$ ansible -i hosts btrm-mon-dev --private-key=../../aws-credentials/btrm-mon.pem -a hostname 52.***.***.233 | SUCCESS | rc=0 >> ip-10-0-1-82
[/simterm]
Запускаем:
[simterm]
$ ansible-playbook -i hosts --limit=btrm-mon-dev --private-key=../../aws-credentials/btrm-mon.pem btrm-monitoring-ansible-provision.yml ... TASK [common : Set hostname] **** changed: [52.***.***.233] TASK [common : Add hostname to /etc/hosts] **** changed: [52.***.***.233] TASK [common : Update /etc/cloud/cloud.cfg.d/01_debian_cloud.cfg] **** changed: [52.***.***.233] PLAY RECAP **** 52.***.***.233 : ok=10 changed=4 unreachable=0 failed=0
[/simterm]
Проверяем сейчас:
[simterm]
$ ansible -i hosts btrm-mon-dev --private-key=../../aws-credentials/btrm-mon.pem -a hostname 52.***.***.233 | SUCCESS | rc=0 >> btrm-mon-dev
[/simterm]
Отлично.
timezone
Время выставляем с помощью модуля timezone:
...
- name: Set timezone to Europe/Kiev
timezone:
name: Europe/Kiev
root mail
Настраиваем почту для root.
В файл плейбука btrm-monitoring-ansible-provision.yml добавляем блок переменных и переменную notify_email:
- hosts: all vars: notify_email: [email protected] ...
В roles/common/tasks/main.yml добавляем обновление /etc/aliases и вызов newaliases:
...
- name: Change root mailbox
lineinfile:
dest: /etc/aliases
regexp: '^root: '
line: "root: {{ notify_email }}"
state: present
- name: Update mail aliases
shell:
newaliases
Прочее
Последним для этой роли осталось скопировать .bashrc и .vimrc.
В roles/common/files/ добавляем файл bashrc:
PS1='\t \[[\e[0;COLORm\]\u\[\e[m\]@\e[0;37m\]\h\[\e[m\] \[\e[1;34m\]\w\[\e[m\]]\[\e[0;31m\] \$\[\e[m\]\[\e[0;37m\] ' export EDITOR=vim # aliases alias osupgrade="sudo apt-get update && sudo apt-get upgrade"
И vimrc:
set tabstop=4 set shiftwidth=4 set softtabstop=4 set expandtab set paste set smartindent syntax on
Добавляем их копирование:
...
- name: Copy .bashrc to root
copy:
src: files/bashrc
dest: /root/.bashrc
- name: Set username color in /root/.bashrc
replace:
path: /root/.bashrc
regexp: 'COLOR'
replace: '31'
- name: Copy .bashrc to admin
copy:
src: files/bashrc
dest: /home/admin/.bashrc
- name: Set username color in /home/admin/.bashrc
replace:
path: /home/admin/.bashrc
regexp: 'COLOR'
replace: '32'
- name: Copy .vimrc to root
copy:
src: files/vimrc
dest: /root/.vimrc
- name: Copy .vimrc to admin
copy:
src: files/vimrc
dest: /home/admin/.vimrc
Запускаем все последние изменения:
[simterm]
$ !416 ansible-playbook -i hosts --limit=btrm-mon-dev --private-key=../../aws-credentials/btrm-mon.pem btrm-monitoring-ansible-provision.yml ... TASK [common : Update /etc/cloud/cloud.cfg.d/01_debian_cloud.cfg] **** changed: [52.***.***.233] TASK [common : Change root mailbox] **** changed: [52.***.***.233] TASK [common : Update mail aliases] **** changed: [52.***.***.233] TASK [common : Set timezone to Europe/Kiev] **** changed: [52.***.***.233] TASK [common : Copy .bashrc to root] **** changed: [52.***.***.233] TASK [common : Set username color in /root/.bashrc] **** changed: [52.***.***.233] TASK [common : Copy .bashrc to admin] **** changed: [52.***.***.233] TASK [common : Set username color in /home/admin/.bashrc] **** changed: [52.***.***.233] TASK [common : Copy .vimrc to root] **** changed: [52.***.***.233] TASK [common : Copy .vimrc to admin] **** changed: [52.***.***.233] PLAY RECAP **** 52.***.***.233 : ok=19 changed=10 unreachable=0 failed=0
[/simterm]
ОК.
В целом с ролью common на этом закончили.
роль exim
Ещё одной ролью будет роль для настройки exim на отправку почты с хоста (учитывая, что это хост мониторинга — весьма актуальная задача).
Создаём каталоги:
[simterm]
$ mkdir -p roles/exim/{tasks,templates}
[/simterm]
Создаём два шаблона — mailname.j2 с указанием имени хоста, которое будет использоваться MTA при отправке писем, и update-exim4.conf.conf.j2, в котором указываются настройки для Exim, что бы он мог отправлять почту «в мир (см. Exim: Mailing to remote domains not supported и Ansible: миграция RTFM 2.10 – Let’s Encrypt, NGINX SSL, hostname и exim).
Файл roles/exim/templates/mailname.j2 содержит одну строку:
{{ inventory_hostname }}
Файл update-exim4.conf.conf.j2 немного побольше:
dc_eximconfig_configtype='internet'
dc_other_hostnames='"{{ inventory_hostname }}"'
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'
В файл roles/exim/tasks/main.yml добавляем их добавление на сервер:
- name: Update Exim4 settings
template:
src=templates/update-exim4.conf.conf.j2
dest=/etc/exim4/update-exim4.conf.conf
- name: Update mailname
template:
src=templates/mailname.j2
dest=/etc/mailname
И туда же добавляем ещё три задачи — смена FROM для root, перезапуск exim для применения новго файла настроек, и отправку тестового письма:
...
- name: Change root FROM address
lineinfile:
dest: /etc/email-addresses
regexp: '^root: '
line: "root: root@{{ inventory_hostname }}"
state: present
- name: Exim4 restart
service:
name=exim4
state=restarted
- name: Send test email
shell:
echo "Eximt4 config complete" | mailx -s "{{ inventory_hostname }} Exim4 test" "{{ notify_email }}"
Добавляем роль exim в плейбук:
- hosts: all
vars:
notify_email: [email protected]
become:
true
roles:
- role: common
- role: exim
Запускаем, проверяем тестовое письмо:
роль nginx
В этой роли выполним установку NGINX и копирование файла настроек самого NGINX и файла виртуалхоста.
Для сервера уже добавлен домен, который будем использовать в NGINX — dev.monitor.domain.tld, он же добавлен в hosts.
Создаём каталоги:
[simterm]
$ mkdir -p roles/nginx/{tasks,templates}
[/simterm]
В roles/nginx/templates/ добавляем nginx.conf.j2:
user www-data;
worker_processes auto;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH !RC4";
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1h;
ssl_stapling on;
ssl_stapling_verify on;
ssl_dhparam /etc/nginx/dhparams.pem;
server_tokens off;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
log_format proxy '[$time_local] $remote_addr - $server_name to: '
'$upstream_addr: $request upstream_response_time '
'$upstream_response_time msec $msec request_time $request_time';
gzip on;
gzip_disable "msie6";
include /etc/nginx/conf.d/*.conf;
}
Он нам нужен для настроек SSL и добавления ssl_dhparam.
Сюда же добавляем шаблон для виртуахоста — roles/nginx/templates/dev.monitor.domain.tld.conf.j2:
server {
listen 80;
server_name {{ inventory_hostname }};
access_log /var/log/nginx/{{ inventory_hostname }}-access.log proxy;
error_log /var/log/nginx/{{ inventory_hostname }}-error.log warn;
location / {
root html;
index index.html index.htm;
}
}
Он пока минимальный, SSL и upstream добавим позже.
Добавляем задачи — в файле roles/nginx/tasks/main.yml выполняем установку NGINX, замену его конфига, генерацию ключа Diffie Hellman, копирование конфига виртуалхоста и перезагрузку конфигов NGINX:
- name: Install Nginx
package:
name: nginx
state: latest
- name: Replace NGINX config
template:
src=templates/nginx.conf.j2
dest=/etc/nginx/nginx.conf
- name: Generate dhparams
shell: openssl dhparam -out /etc/nginx/dhparams.pem 2048
args:
creates: /etc/nginx/dhparams.pem
- name: Add NGINX {{ inventory_hostname }} virtualhost config
template:
src=templates/{{ inventory_hostname }}.conf.j2
dest=/etc/nginx/conf.d/{{ inventory_hostname }}.conf
- name: Service NGINX reload
service:
name=nginx
state=restarted
В btrm-monitoring-ansible-provision.yml добавляем роль nginx:
...
roles:
- role: common
- role: exim
- role: nginx
Запускаем, проверяем:
[simterm]
$ curl -I dev.monitor.domain.com HTTP/1.1 200 OK Server: nginx Date: Mon, 14 May 2018 11:39:34 GMT ...
[/simterm]
Отлично.
роль logrotate
Тут всё просто — используем готовую роль из Ansible Galaxy — manala.logrotate.
В btrm-monitoring-ansible-provision.yml добавляем:
...
...
- role: manala.logrotate
manala_logrotate_configs:
- file: nginx
config:
- /var/log/nginx/*.log:
- size: 100M
- missingok
- rotate: 5
- compress
- delaycompress:
- notifempty
- create: 0640 www-data adm
- sharedscripts
- daily
- postrotate
systemctl reload nginx.service
- endscript
Создаём файл requirements.yml, добавляем зависимость:
- src: manala.logrotate
роль unattended-upgrades
Аналогично с ролью unattended-upgrades — используем jnv.unattended-upgrades, добавляем её в requirements.yml:
- src: manala.logrotate - src: jnv.unattended-upgrades
И в btrm-monitoring-ansible-provision.yml, с настройками:
...
- role: jnv.unattended-upgrades
unattended_mail: "{{ notify_email }}"
unattended_automatic_reboot: true
unattended_automatic_reboot_time: 05:00
unattended_clean_interval: 10
Загружаем роли:
[simterm]
$ ansible-galaxy install —ignore-certs -r requirements.yml
[/simterm]
И запускаем выполнение плейбука с последними обновлениями:
[simterm]
$ ansible-playbook -i hosts —limit=btrm-mon-dev —private-key=../../aws-credentials/btrm-mon.pem btrm-monitoring-ansible-provision.yml
[/simterm]
Проверяем:
[simterm]
root@btrm-mon-dev:/home/admin# cat /etc/apt/apt.conf.d/50unattended-upgrades | grep Upgr
// Unattended-Upgrade::Origins-Pattern controls which packages are
Unattended-Upgrade::Origins-Pattern {
Unattended-Upgrade::Package-Blacklist {
Unattended-Upgrade::Mail "[email protected]";
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "05:00";
[/simterm]
Готово.
В следующей части добавим роли для запуска самого Prometheus, Alertmanager и Grafana, потом к ним добавим екпортёры и настроим первые алерты.
