feat: Выполнил практическое задание по DevOps
This commit is contained in:
@@ -0,0 +1,159 @@
|
|||||||
|
|
||||||
|
# Тестовое задание SimbirSoft DevOps
|
||||||
|
|
||||||
|
>[!NOTE]
|
||||||
|
>Соловьев Руслан
|
||||||
|
>
|
||||||
|
>Резюме - [HH](https://krasnodar.hh.ru/resume/b105319cff0f77ed050039ed1f5a4a4a733148)
|
||||||
|
>
|
||||||
|
>Узнать поднобнее - https://ruslansoloviev.ru
|
||||||
|
|
||||||
|
|
||||||
|
## Почему хочу девопсить
|
||||||
|
|
||||||
|
Мне нравится DevOps за сочетание разработки и системного администрирования. Мне интересно не только написать приложение, но и разобраться, как оно будет развёрнуто, как автоматизировать этот процесс, обеспечить его стабильную работу и понять, что происходит с сервисом после его запуска.
|
||||||
|
|
||||||
|
Именно поэтому со временем я стал больше заниматься инфраструктурной частью своих проектов: Docker, CI/CD, Kubernetes, мониторингом, сетями и автоматизацией. Особенно нравится автоматизировать повторяющиеся процессы и превращать ручную настройку в воспроизводимую конфигурацию.
|
||||||
|
|
||||||
|
В дальнейшем я хочу развиваться именно как DevOps-инженер, работать с более крупной инфраструктурой и задачами, где требования к надёжности, автоматизации и наблюдаемости значительно выше, чем в моих текущих проектах.
|
||||||
|
|
||||||
|
## Теоретическая часть
|
||||||
|
|
||||||
|
1) Нужно обеспечить высокую доступность сервиса, как бы ее реализовал?
|
||||||
|
<br>
|
||||||
|
- Так как у нас технически в данном задании nginx раздает только статику я бы вообще убрал сервер как точку отказа и вынес статическую страницу в объектное хранилище S3 и подключил CDN, таким образом высокая доступность будет обеспечена силами облачного провайдера, а CDN ускорит доставку контента до пользователей и сократит затраты на GET операции в хранилище.
|
||||||
|
- Если же необходимо реализовать высокую доступность именно посредством серверов, то я бы поднял как минимум 2 экземпляра на разных ВМ в разных зонах доступности и повесил на них балансировщик с хелс чеками доступности каждой из ВМ что бы не слать трафик на заведомо мертвую ВМ, 2 AZ поскольку этого будет достаточно в большинстве случаем да и самому nginx не нужен кворум для работы
|
||||||
|
<br>
|
||||||
|
|
||||||
|
2) Тебе надо создать и настроить 5 таких серверов, как бы это реализовал?
|
||||||
|
<br>
|
||||||
|
|
||||||
|
- Так как я описал необходимое состояние ВМ в ansible плейбук то для настройки будет достаточно указать все ВМ в инвентаре плейбука, а для заказа смотря как управляется текущая инфраструктура - если там терраформ или что то похожее то в конфигурации описал бы необходимые 5 экземпляров, если ручками то заказываю в гипервизоре или панели клауд провайдера
|
||||||
|
|
||||||
|
## Практическая часть
|
||||||
|
|
||||||
|
В данном тестовом задании я использовал Ansible и для его воспроизводимости понадобятся сам Ansible и некоторые его коллекции, установить которые можно следующими командами:
|
||||||
|
<br>
|
||||||
|
|
||||||
|
**Debian/Ubuntu**
|
||||||
|
```sh
|
||||||
|
sudo apt update && sudo apt install -y ansible
|
||||||
|
```
|
||||||
|
|
||||||
|
**macOS**
|
||||||
|
```sh
|
||||||
|
brew install ansible
|
||||||
|
```
|
||||||
|
|
||||||
|
**Через pip**
|
||||||
|
```sh
|
||||||
|
python3 -m pip install ansible
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ansible-galaxy collection install community.general
|
||||||
|
ansible-galaxy collection install community.crypto
|
||||||
|
ansible-galaxy collection install community.docker
|
||||||
|
```
|
||||||
|
|
||||||
|
В файле *hosts.yaml* необходимо указать адрес ВМ и пользователя, например
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
all:
|
||||||
|
hosts:
|
||||||
|
nginx:
|
||||||
|
ansible_host: 192.168.20.217
|
||||||
|
ansible_user: rouxinol
|
||||||
|
```
|
||||||
|
|
||||||
|
Далее в файле *secrets.yaml* необходимо указать пароль для указаного ранее пользователя, а так же пароль для *sudo* для указаного пользователя, например:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
ansible_password: "superpass123"
|
||||||
|
ansible_become_password: "superpass123"
|
||||||
|
```
|
||||||
|
|
||||||
|
Далее можно зашифровать этот файл:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ansible-vault encrypt secrets.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
После всех действий можно запустить плейбук:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ansible-playbook -i hosts.yaml playbook.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Если был зашифрован secrets.yaml то необходимо так же добавить флаг ```--ask-vault-pass```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
В качестве лабораторной работы я заказал ВМ с Ubuntu Server 24.04 с пользователем *rouxinol* в Proxmox VE, IP ВМ в локальной сети - 192.168.20.217
|
||||||
|
|
||||||
|
Логи выполнения плейбука можно посмотреть в [логе выполнения Ansible](./ansible-playbook.log)
|
||||||
|
|
||||||
|
Логи повторного выполнения плейбука можно посмотреть в [логе повторного выполнения Ansible](./ansible-playbook-repeat.log)
|
||||||
|
|
||||||
|
## Ремарки к практическим заданиям
|
||||||
|
|
||||||
|
3) Продемонстрировать блокировку портов
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
**Конечная конфирукция ufw с ВМ**
|
||||||
|
```log
|
||||||
|
rouxinol@rouxinol-testserver:/opt/nginx$ sudo ufw status verbose
|
||||||
|
Status: active
|
||||||
|
Logging: on (low)
|
||||||
|
Default: deny (incoming), allow (outgoing), deny (routed)
|
||||||
|
New profiles: skip
|
||||||
|
|
||||||
|
To Action From
|
||||||
|
-- ------ ----
|
||||||
|
22/tcp (OpenSSH) ALLOW IN Anywhere
|
||||||
|
80/tcp ALLOW IN Anywhere
|
||||||
|
443/tcp ALLOW IN Anywhere
|
||||||
|
22/tcp (OpenSSH (v6)) ALLOW IN Anywhere (v6)
|
||||||
|
80/tcp (v6) ALLOW IN Anywhere (v6)
|
||||||
|
443/tcp (v6) ALLOW IN Anywhere (v6)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Nmap по привелигированным портам**
|
||||||
|
|
||||||
|
```log
|
||||||
|
❯ nmap 192.168.20.217
|
||||||
|
Starting Nmap 7.98 ( https://nmap.org ) at 2026-08-17 01:54 +0300
|
||||||
|
Nmap scan report for 192.168.20.217
|
||||||
|
Host is up (0.0029s latency).
|
||||||
|
Not shown: 997 filtered tcp ports (no-response)
|
||||||
|
PORT STATE SERVICE
|
||||||
|
22/tcp open ssh
|
||||||
|
80/tcp open http
|
||||||
|
443/tcp open https
|
||||||
|
|
||||||
|
Nmap done: 1 IP address (1 host up) scanned in 43.31 seconds
|
||||||
|
```
|
||||||
|
|
||||||
|
6) Бекап каждый понедельник
|
||||||
|
|
||||||
|
```log
|
||||||
|
root@rouxinol-testserver:/opt/nginx# crontab -l
|
||||||
|
CRON_TZ="UTC"
|
||||||
|
#Ansible: nginx configuration backup
|
||||||
|
0 1 * * 1 /opt/nginx/backup.sh
|
||||||
|
root@rouxinol-testserver:/opt/nginx# ./backup.sh
|
||||||
|
Successfully copied 25.1kB to /tmp/tmp.9hPGthi4R2/nginx
|
||||||
|
root@rouxinol-testserver:/opt/nginx# ls backups/
|
||||||
|
nginx_2026-08-16_23-01-36.tar.gz nginx_2026-08-16_23-02-10.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
7) В Dockerfile указано запускать master-процесс от пользователя nginx, а так же в nginx,conf указано запускать worker-процессы так же от nginx, однако для этого были выбраны непривелигированные порты 8080 и 8443, однако можно было использовать образ nginxinc/nginx-unprivileged и не указывать ничего из этого и в Dockerfile есть закомментированный FROM этого образа - однако он не был выбран так как в Docker Hub нет нужной 1.29.6 версии - я подобрал ближайшую
|
||||||
|
|
||||||
|
8) При запуске плейбука в его корне автоматически создается ssh ed25519 ключ без фразы пароля, для подключения к ВМ будет достаточно именно для моего тестового окружения следующей команды:
|
||||||
|
```sh
|
||||||
|
ssh -i ./id_ed25519_simbirkey rouxinol@192.168.20.217
|
||||||
|
```
|
||||||
|
|
||||||
|
9) [Dockerfile тут](./roles/nginx/files/Dockerfile)
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
❯ ansible-playbook -i hosts.yaml playbook.yaml --ask-vault-pass
|
||||||
|
Vault password:
|
||||||
|
|
||||||
|
PLAY [Настройка VM для раздачи статического файла через nginx] *************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
|
||||||
|
TASK [Получение SSH отпечатка] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx -> localhost]
|
||||||
|
|
||||||
|
TASK [Добавление SSH отпечатка в known_hosts] ******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx -> localhost]
|
||||||
|
|
||||||
|
TASK [Сбор фактов] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
[WARNING]: Host 'nginx' is using the discovered Python interpreter at '/usr/bin/python3.12', but future installation of another Python interpreter could cause a different interpreter to be discovered. See https://docs.ansible.com/ansible-core/2.20/reference_appendices/interpreter_discovery.html for more information.
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-key : Генерация SSH ключа] ***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx -> localhost]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Добавление SSH ключа] ***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
[WARNING]: Deprecation warnings can be disabled by setting `deprecation_warnings=False` in ansible.cfg.
|
||||||
|
[DEPRECATION WARNING]: Importing 'to_native' from 'ansible.module_utils._text' is deprecated. This feature will be removed from ansible-core version 2.24. Use ansible.module_utils.common.text.converters instead.
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Установка необходимых пакетов] **************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Разрешить SSH] ******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Разрешить HTTP и HTTPS] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx] => (item=80)
|
||||||
|
ok: [nginx] => (item=443)
|
||||||
|
|
||||||
|
TASK [prepare-vm : Включение и запуск файрволла] ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Перезагрузка файрволла] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Включение и запуск SSH] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Включение и запуск cron] ********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Установка UTC для cron] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-docker : Проверка наличия докера] ****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-docker : Скачивание скрипта установки докера] ****************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
skipping: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-docker : Установка докера] ***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
skipping: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-docker : Активация докер сервиса] ****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Подготовка директории] ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Проверка наличия сертификата] ********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Проверка наличия приватного ключа] ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Создание директории для сертификатов] ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
skipping: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Генерация приватного ключа] **********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
skipping: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Генерация CSR] ***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
skipping: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Генерация самоподписанного сертификата] **********************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
skipping: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Копирование файлов конфигурации] *****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx] => (item=nginx.conf)
|
||||||
|
ok: [nginx] => (item=Dockerfile)
|
||||||
|
ok: [nginx] => (item=index.html)
|
||||||
|
ok: [nginx] => (item=docker-compose.yaml)
|
||||||
|
ok: [nginx] => (item=backup.sh)
|
||||||
|
|
||||||
|
TASK [nginx : Подготовка директории бекапов] *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Настройка еженедельного резервного копирования Nginx] ********************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Сборка и запуск Docker Compose] ******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
PLAY RECAP *****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
nginx : ok=22 changed=3 unreachable=0 failed=0 skipped=6 rescued=0 ignored=0
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
❯ ansible-playbook -i hosts.yaml playbook.yaml --ask-vault-pass
|
||||||
|
Vault password:
|
||||||
|
|
||||||
|
PLAY [Настройка VM для раздачи статического файла через nginx] *************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
|
||||||
|
TASK [Получение SSH отпечатка] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx -> localhost]
|
||||||
|
|
||||||
|
TASK [Добавление SSH отпечатка в known_hosts] ******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx -> localhost]
|
||||||
|
|
||||||
|
TASK [Сбор фактов] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
[WARNING]: Host 'nginx' is using the discovered Python interpreter at '/usr/bin/python3.12', but future installation of another Python interpreter could cause a different interpreter to be discovered. See https://docs.ansible.com/ansible-core/2.20/reference_appendices/interpreter_discovery.html for more information.
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-key : Генерация SSH ключа] ***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx -> localhost]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Добавление SSH ключа] ***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
[WARNING]: Deprecation warnings can be disabled by setting `deprecation_warnings=False` in ansible.cfg.
|
||||||
|
[DEPRECATION WARNING]: Importing 'to_native' from 'ansible.module_utils._text' is deprecated. This feature will be removed from ansible-core version 2.24. Use ansible.module_utils.common.text.converters instead.
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Установка необходимых пакетов] **************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Разрешить SSH] ******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Разрешить HTTP и HTTPS] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx] => (item=80)
|
||||||
|
changed: [nginx] => (item=443)
|
||||||
|
|
||||||
|
TASK [prepare-vm : Включение и запуск файрволла] ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Перезагрузка файрволла] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Включение и запуск SSH] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Включение и запуск cron] ********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-vm : Установка UTC для cron] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-docker : Проверка наличия докера] ****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-docker : Скачивание скрипта установки докера] ****************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-docker : Установка докера] ***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [prepare-docker : Активация докер сервиса] ****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Подготовка директории] ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Проверка наличия сертификата] ********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Проверка наличия приватного ключа] ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
ok: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Создание директории для сертификатов] ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Генерация приватного ключа] **********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Генерация CSR] ***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Генерация самоподписанного сертификата] **********************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Копирование файлов конфигурации] *****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx] => (item=nginx.conf)
|
||||||
|
changed: [nginx] => (item=Dockerfile)
|
||||||
|
changed: [nginx] => (item=index.html)
|
||||||
|
changed: [nginx] => (item=docker-compose.yaml)
|
||||||
|
changed: [nginx] => (item=backup.sh)
|
||||||
|
|
||||||
|
TASK [nginx : Подготовка директории бекапов] *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Настройка еженедельного резервного копирования Nginx] ********************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
TASK [nginx : Сборка и запуск Docker Compose] ******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
changed: [nginx]
|
||||||
|
|
||||||
|
PLAY RECAP *****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
||||||
|
nginx : ok=28 changed=20 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
all:
|
||||||
|
hosts:
|
||||||
|
nginx:
|
||||||
|
ansible_host: 192.168.20.217
|
||||||
|
ansible_user: rouxinol
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
- name: "Настройка VM для раздачи статического файла через nginx"
|
||||||
|
hosts: all
|
||||||
|
gather_facts: false
|
||||||
|
vars_files:
|
||||||
|
- secrets.yaml
|
||||||
|
pre_tasks:
|
||||||
|
- name: Получение SSH отпечатка
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "ssh-keyscan -H {{ ansible_host }}"
|
||||||
|
register: ssh_host_key
|
||||||
|
changed_when: false
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Добавление SSH отпечатка в known_hosts
|
||||||
|
ansible.builtin.known_hosts:
|
||||||
|
name: "{{ ansible_host }}"
|
||||||
|
key: "{{ ssh_host_key.stdout }}"
|
||||||
|
path: "{{ lookup('env', 'HOME') }}/.ssh/known_hosts"
|
||||||
|
state: present
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Сбор фактов
|
||||||
|
ansible.builtin.setup:
|
||||||
|
roles:
|
||||||
|
- prepare-key
|
||||||
|
- prepare-vm
|
||||||
|
- prepare-docker
|
||||||
|
- nginx
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
backup.sh
|
||||||
|
docker-compose.yaml
|
||||||
|
ssl/
|
||||||
|
*.key
|
||||||
|
*.pem
|
||||||
|
*.crt
|
||||||
|
backups/
|
||||||
|
*.tar
|
||||||
|
*.tar.gz
|
||||||
|
*.tgz
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# FROM nginxinc/nginx-unprivileged:1.29.8-alpine3.23-slim@sha256:59678856b05324b7f6371f26eb1520be7fcd8bdc8ab380fc4913db8503e5a842
|
||||||
|
FROM nginx:1.29.6-alpine3.23-slim@sha256:c8eb3bb3009bb98c04480e11405f5b4d38adbd0bf6df5f5e6ff552b236576331
|
||||||
|
|
||||||
|
COPY --chown=nginx:nginx nginx.conf /etc/nginx/nginx.conf
|
||||||
|
COPY --chown=nginx:nginx index.html /usr/share/nginx/html/index.html
|
||||||
|
|
||||||
|
EXPOSE 80 443
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
|
CMD wget -q --spider http://127.0.0.1:8080 || exit 1
|
||||||
|
|
||||||
|
USER nginx
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
BACKUP_DIR="/opt/nginx/backups"
|
||||||
|
CONTAINER="nginx"
|
||||||
|
DATE=$(date -u +"%Y-%m-%d_%H-%M-%S")
|
||||||
|
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
|
||||||
|
docker cp "${CONTAINER}:/etc/nginx" "$TMP_DIR/nginx"
|
||||||
|
|
||||||
|
tar -czf "${BACKUP_DIR}/nginx_${DATE}.tar.gz" \
|
||||||
|
-C "$TMP_DIR" nginx
|
||||||
|
|
||||||
|
rm -rf "$TMP_DIR"
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: simbir-nginx:1.29.6
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "80:8080"
|
||||||
|
- "443:8443"
|
||||||
|
restart: "unless-stopped"
|
||||||
|
container_name: nginx
|
||||||
|
volumes:
|
||||||
|
- /opt/nginx/ssl:/etc/nginx/ssl:ro
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>
|
||||||
|
Hello DevOps world!
|
||||||
|
</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>Hello DevOps world!</h2><br>
|
||||||
|
<h3 id="time"></h3>
|
||||||
|
<script>
|
||||||
|
setInterval(() => {
|
||||||
|
document.getElementById("time").textContent =
|
||||||
|
new Date().toLocaleTimeString("ru-RU", {
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit"
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
</script>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
pid /tmp/nginx.pid;
|
||||||
|
user nginx;
|
||||||
|
events {}
|
||||||
|
|
||||||
|
http {
|
||||||
|
client_body_temp_path /tmp/client_temp;
|
||||||
|
proxy_temp_path /tmp/proxy_temp;
|
||||||
|
fastcgi_temp_path /tmp/fastcgi_temp;
|
||||||
|
uwsgi_temp_path /tmp/uwsgi_temp;
|
||||||
|
scgi_temp_path /tmp/scgi_temp;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 8080;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 8443 ssl;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
|
||||||
|
ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
- name: Подготовка директории
|
||||||
|
become: true
|
||||||
|
ansible.builtin.file:
|
||||||
|
state: directory
|
||||||
|
path: /opt/nginx
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Проверка наличия сертификата
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /opt/nginx/ssl/cert.pem
|
||||||
|
register: cert_file
|
||||||
|
|
||||||
|
- name: Проверка наличия приватного ключа
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /opt/nginx/ssl/key.pem
|
||||||
|
register: key_file
|
||||||
|
|
||||||
|
- name: Создание директории для сертификатов
|
||||||
|
become: true
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /opt/nginx/ssl
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0755'
|
||||||
|
when: not cert_file.stat.exists or not key_file.stat.exists
|
||||||
|
|
||||||
|
- name: Генерация приватного ключа
|
||||||
|
become: true
|
||||||
|
community.crypto.openssl_privatekey:
|
||||||
|
path: /opt/nginx/ssl/key.pem
|
||||||
|
size: 2048
|
||||||
|
owner: root
|
||||||
|
group: 101
|
||||||
|
mode: '0640'
|
||||||
|
when: not cert_file.stat.exists or not key_file.stat.exists
|
||||||
|
|
||||||
|
- name: Генерация CSR
|
||||||
|
become: true
|
||||||
|
community.crypto.openssl_csr:
|
||||||
|
path: /opt/nginx/ssl/nginx.csr
|
||||||
|
privatekey_path: /opt/nginx/ssl/key.pem
|
||||||
|
common_name: nginx.local
|
||||||
|
subject_alt_name:
|
||||||
|
- "DNS:nginx.local"
|
||||||
|
- "DNS:localhost"
|
||||||
|
- "IP:{{ansible_facts['default_ipv4']['address']}}"
|
||||||
|
when: not cert_file.stat.exists or not key_file.stat.exists
|
||||||
|
|
||||||
|
- name: Генерация самоподписанного сертификата
|
||||||
|
become: true
|
||||||
|
community.crypto.x509_certificate:
|
||||||
|
path: /opt/nginx/ssl/cert.pem
|
||||||
|
privatekey_path: /opt/nginx/ssl/key.pem
|
||||||
|
csr_path: /opt/nginx/ssl/nginx.csr
|
||||||
|
provider: selfsigned
|
||||||
|
selfsigned_not_after: "+3650d"
|
||||||
|
when: not cert_file.stat.exists or not key_file.stat.exists
|
||||||
|
|
||||||
|
- name: Изменение прав на сертификат
|
||||||
|
become: true
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /opt/nginx/ssl/cert.pem
|
||||||
|
owner: root
|
||||||
|
group: "101"
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Копирование файлов конфигурации
|
||||||
|
become: true
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{item}}"
|
||||||
|
dest: "/opt/nginx/{{item}}"
|
||||||
|
mode: "0755"
|
||||||
|
loop:
|
||||||
|
- nginx.conf
|
||||||
|
- Dockerfile
|
||||||
|
- index.html
|
||||||
|
- docker-compose.yaml
|
||||||
|
- backup.sh
|
||||||
|
|
||||||
|
- name: Подготовка директории бекапов
|
||||||
|
become: true
|
||||||
|
ansible.builtin.file:
|
||||||
|
state: directory
|
||||||
|
path: /opt/nginx/backups
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Настройка еженедельного резервного копирования Nginx
|
||||||
|
become: true
|
||||||
|
ansible.builtin.cron:
|
||||||
|
name: "nginx configuration backup"
|
||||||
|
minute: "0"
|
||||||
|
hour: "1"
|
||||||
|
weekday: "1"
|
||||||
|
job: "/opt/nginx/backup.sh"
|
||||||
|
env: false
|
||||||
|
|
||||||
|
- name: Сборка и запуск Docker Compose
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: /opt/nginx
|
||||||
|
state: present
|
||||||
|
build: always
|
||||||
|
become: true
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
- name: Проверка наличия докера
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: docker --version
|
||||||
|
register: docker_version
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Скачивание скрипта установки докера
|
||||||
|
become: true
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: https://get.docker.com
|
||||||
|
dest: /tmp/get-docker.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
when: docker_version.rc != 0
|
||||||
|
|
||||||
|
- name: Установка докера
|
||||||
|
become: true
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: sh /tmp/get-docker.sh
|
||||||
|
creates: /usr/bin/docker
|
||||||
|
when: docker_version.rc != 0
|
||||||
|
|
||||||
|
- name: Активация докер сервиса
|
||||||
|
become: true
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: docker
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- name: Генерация SSH ключа
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "ssh-keygen -t ed25519 -f {{playbook_dir}}/id_ed25519_simbirkey -N '' -C ''"
|
||||||
|
creates: "{{playbook_dir}}/id_ed25519_simbirkey"
|
||||||
|
delegate_to: localhost
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
- name: Добавление SSH ключа
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: "{{ansible_user}}"
|
||||||
|
key: "{{ lookup('file', playbook_dir + '/id_ed25519_simbirkey.pub') }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Установка необходимых пакетов
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- ufw
|
||||||
|
- openssl
|
||||||
|
- openssh-server
|
||||||
|
- tar
|
||||||
|
- cron
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Разрешить SSH
|
||||||
|
community.general.ufw:
|
||||||
|
rule: allow
|
||||||
|
name: openssh
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Разрешить HTTP и HTTPS
|
||||||
|
community.general.ufw:
|
||||||
|
rule: allow
|
||||||
|
port: "{{ item }}"
|
||||||
|
proto: tcp
|
||||||
|
become: true
|
||||||
|
loop:
|
||||||
|
- "80"
|
||||||
|
- "443"
|
||||||
|
|
||||||
|
- name: Включение и запуск файрволла
|
||||||
|
community.general.ufw:
|
||||||
|
state: enabled
|
||||||
|
default: deny
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Перезагрузка файрволла
|
||||||
|
ansible.builtin.command: ufw reload
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Включение и запуск SSH
|
||||||
|
ansible.builtin.systemd_service:
|
||||||
|
name: ssh
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Включение и запуск cron
|
||||||
|
ansible.builtin.systemd_service:
|
||||||
|
name: cron
|
||||||
|
state: started
|
||||||
|
enabled: true
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Установка UTC для cron
|
||||||
|
ansible.builtin.cron:
|
||||||
|
name: CRON_TZ
|
||||||
|
env: true
|
||||||
|
job: UTC
|
||||||
|
become: true
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ansible_password: "superpass123"
|
||||||
|
ansible_become_password: "superpass123"
|
||||||
Reference in New Issue
Block a user