Compare commits

...

45 Commits

Author SHA1 Message Date
4709d4c0e7 update readme 2024-11-17 19:56:50 +03:00
220b967809 fix warngins2 2024-11-17 19:36:22 +03:00
d8759bfa8c add colors 2024-11-17 19:29:04 +03:00
65ade98e04 fix warnings 2024-11-17 19:26:44 +03:00
52192b4d24 update job run 2024-11-17 19:19:57 +03:00
55ffb7055c fix job run 2024-11-17 19:10:08 +03:00
2f21245787 test new run job 2024-11-17 19:02:14 +03:00
74f04d975c fix failpage 2024-11-17 18:51:39 +03:00
ef8ba84ebc add failsites 2024-11-17 18:46:24 +03:00
54582d0f1d fix readme2 2024-11-13 00:29:07 +03:00
29a9f07dbc fix readme 2024-11-13 00:27:29 +03:00
2e6f7cc2f0 readmefix 2024-11-13 00:25:04 +03:00
3a1c5d02e8 add readme&microfix 2024-11-13 00:23:36 +03:00
4110aa63c1 fix jenkinsfile&proxyconf 2024-11-13 00:10:18 +03:00
5c2eb4a087 check new proxyconf2 2024-11-13 00:05:56 +03:00
258f88eedd check new proxyconf 2024-11-13 00:04:32 +03:00
764f1b5792 fix jenkinsfile 2024-11-13 00:01:20 +03:00
50feda89b3 delete vars dir 2024-11-12 23:54:09 +03:00
1738030bf9 fix proxyconf 2024-11-12 23:51:47 +03:00
b6f55f1186 fix bugs jenkinsjob 2024-11-12 23:43:48 +03:00
8fe1bebb4b fix directory 2024-11-12 23:22:02 +03:00
f803c5c74b fix all 2024-11-12 23:14:17 +03:00
df19e70c88 jenkinsfile 2024-11-11 23:17:27 +03:00
c273781043 fix all 2024-11-11 23:16:26 +03:00
ac4bad6936 fix playbook&cfg 2024-11-11 23:04:45 +03:00
83ec1528ca fix ansiblecfg 2024-11-11 23:02:35 +03:00
2f86815728 fix ansiblecfg 2024-11-11 23:00:56 +03:00
349e64b54e fix playbook 2024-11-11 14:01:45 +03:00
e6e5b55f65 fix playbook 2024-11-11 13:52:37 +03:00
cbbc6f3ae4 fix jenkinsfile 2024-11-11 13:49:52 +03:00
8ba4e824fc rework all 2024-11-11 13:48:06 +03:00
cc7cb56aa3 lftaver1.0 add nginx and proxy 2024-11-05 00:14:05 +03:00
2eca300dd0 fix playbook 2024-11-04 21:40:35 +03:00
48742d8a6f fix playbook 2024-11-04 21:38:26 +03:00
18d2f05e28 fix ssl generate 2024-11-04 21:34:45 +03:00
5e13584e7c fix ssl generate 2024-11-04 21:32:52 +03:00
ba86f05f5e fix ssl generate 2024-11-04 21:29:57 +03:00
03ebc12ac3 fix playbook ssl 2024-11-04 21:21:53 +03:00
91445e4c60 add ssl 2024-11-04 21:18:43 +03:00
bfad48fff1 remove hosts, change run without shell cmd 2024-11-04 20:28:19 +03:00
f32cc1b6a0 fix docker&jenkinsfile+legacyjen 2024-11-04 19:49:57 +03:00
589b269ae3 fix jenkinsfile 2024-11-04 19:45:06 +03:00
a2811c81ad fix jenkinsfile 2024-11-04 19:06:24 +03:00
aa6fa836ae fix jenkinsfile 2024-11-04 19:04:39 +03:00
d5a41badcf start 2024-11-04 18:53:55 +03:00
22 changed files with 620 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
gitea-data
jenkins-data
nginx

104
README.md
View File

@ -0,0 +1,104 @@
# Ansible Jenkins Deployment Pipeline
## Обзор
Этот репозиторий содержит проект Ansible, интегрированный с Jenkins, для автоматизации развёртывания двух веб-сайтов (`SiteA` и `SiteB`) и прокси-сервера (`Proxy`). Настройка обеспечивает балансировку нагрузки, автоматические проверки состояния (health checks) и динамическое обновление контента без ручного вмешательства.
## Описание Структуры
- **group_vars/**: Содержит файлы с переменными групп хостов. В данном случае `all.yml` содержит общие переменные для всех ролей и хостов.
- **roles/**: Основная директория с ролями Ansible.
- **firewall/**: Роль для настройки и конфигурирования файрвола (`firewalld`), открытия необходимых портов.
- **tasks/**: Задачи для установки и настройки `firewalld`.
- **vars/**: Переменные, используемые в роли `firewall`.
- **nginx_proxy/**: Роль для установки и настройки Nginx как прокси-сервера с балансировкой нагрузки и проверкой состояния.
- **tasks/**: Задачи для установки Nginx и деплоя конфигурации прокси.
- **templates/**: Шаблоны конфигурационных файлов Nginx для прокси-сервера.
- **nginx_site/**: Роль для установки и настройки Nginx на целевых сайтах (`SiteA` и `SiteB`), а также деплоя HTML контента.
- **tasks/**: Задачи для установки Nginx, создания корневых директорий сайтов, деплоя конфигураций и HTML файлов.
- **templates/**: Шаблоны конфигурационных файлов Nginx и HTML страниц для сайтов.
- **ssl_certificate/**: Роль для генерации самоподписанных SSL сертификатов для прокси-сервера.
- **tasks/**: Задачи для установки OpenSSL, создания директории для сертификатов и генерации самоподписанных сертификатов.
- **vars/**: Переменные, используемые в роли `ssl_certificate`.
- **playbook.yml**: Основной Ansible playbook, который связывает все роли и определяет порядок их выполнения на соответствующих хостах.
- **inventory.yml**: Файл инвентаризации, содержащий информацию о целевых хостах и группах (`SiteA`, `SiteB`, `proxy`).
- **ansible.cfg**: Конфигурационный файл Ansible, определяющий пути к ролям и другие настройки.
- **Jenkinsfile**: Скрипт для Jenkins Pipeline, который управляет процессом деплоя, включая расшифровку SSH ключей, передачу переменных и запуск Ansible playbook.
## Параметры и Их Назначение
### В `group_vars/all.yml`
- **siteA**:
- `site_title`: Заголовок страницы SiteA.
- `site_h1`: Основной заголовок `<h1>` на странице SiteA.
- `site_h2`: Дополнительный заголовок `<h2>` для SiteA.
- `site_p`: Параграф `<p>` контента для SiteA.
- `site_domain`: Доменное имя SiteA.
- `site_ip`: IP-адрес сервера SiteA.
- **siteB**:
- `site_title`: Заголовок страницы SiteB.
- `site_h1`: Основной заголовок `<h1>` на странице SiteB.
- `site_h2`: Дополнительный заголовок `<h2>` для SiteB.
- `site_p`: Параграф `<p>` контента для SiteB.
- `site_domain`: Доменное имя SiteB.
- `site_ip`: IP-адрес сервера SiteB.
- **proxy**:
- `proxy_domain`: Доменное имя прокси-сервера.
- `proxy_ip`: IP-адрес прокси-сервера.
- **ansible_python_interpreter**: Явное указание пути к Python-интерпретатору на всех хостах.
### В `Jenkinsfile`
- **DEPLOY_TARGET**: Выбор цели развертывания (`SiteA`, `SiteB`, `All`).
- **ADDITIONAL_CONTENT_SITEA_H2**: Дополнительный контент для заголовка `<h2>` на SiteA.
- **ADDITIONAL_CONTENT_SITEA_P**: Дополнительный параграф `<p>` для SiteA.
- **ADDITIONAL_CONTENT_SITEB_H2**: Дополнительный контент для заголовка `<h2>` на SiteB.
- **ADDITIONAL_CONTENT_SITEB_P**: Дополнительный параграф `<p>` для SiteB.
### В Ролях
- **firewall/vars/main.yml**:
- `firewall_ports`: Список портов и протоколов, которые необходимо открыть в файрволе (например, SSH, HTTP, HTTPS).
- **nginx_proxy/vars/main.yml**:
- `ssl_cert_path`: Путь к директории, где будут храниться SSL сертификаты.
- `ssl_cert_file`: Имя SSL сертификата.
- `ssl_key_file`: Имя ключа SSL сертификата.
- `ssl_subject`: Параметры для генерации самоподписанного SSL сертификата.
## Как Использовать
### Настройка Инвентаря
Отредактируйте `inventory.yml`, указав правильные IP-адреса и пользователя для каждого хоста:
```yaml
all:
children:
SiteA:
hosts:
192.168.0.61:
ansible_user: ansible
ansible_python_interpreter: /usr/bin/python3.6
SiteB:
hosts:
192.168.0.62:
ansible_user: ansible
ansible_python_interpreter: /usr/bin/python3.6
proxy:
hosts:
192.168.0.63:
ansible_user: ansible
ansible_python_interpreter: /usr/bin/python3.6

105
ansible/Jenkinsfile vendored Normal file
View File

@ -0,0 +1,105 @@
pipeline {
agent any
options {
ansiColor('xterm')
}
environment {
ANSIBLE_HOST_KEY_CHECKING = 'false'
VAULT_PASSWORD = credentials('vault_password')
}
parameters {
choice(
name: 'DEPLOY_TARGET',
choices: ['SiteA', 'SiteB', 'All'],
description: 'Выберите сайты для развертывания'
)
string(name: 'ADDITIONAL_CONTENT_SITEA_H2', defaultValue: 'Новое сообщение для SiteA', description: 'Дополнительный <h2> контент для SiteA')
string(name: 'ADDITIONAL_CONTENT_SITEA_P', defaultValue: 'Дополнительный параграф для SiteA', description: 'Дополнительный <p> контент для SiteA')
string(name: 'ADDITIONAL_CONTENT_SITEB_H2', defaultValue: 'Новое сообщение для SiteB', description: 'Дополнительный <h2> контент для SiteB')
string(name: 'ADDITIONAL_CONTENT_SITEB_P', defaultValue: 'Дополнительный параграф для SiteB', description: 'Дополнительный <p> контент для SiteB')
}
stages {
stage('Decrypt SSH Key') {
steps {
script {
def tempDir = '/tmp/' + UUID.randomUUID().toString()
env.TEMP_DIR = tempDir
sh "mkdir -p ${tempDir}"
def decryptedKeyFile = "${tempDir}/id_ed25519"
def vaultPassFile = "${tempDir}/vault_pass"
writeFile file: vaultPassFile, text: VAULT_PASSWORD
sh """
ansible-vault decrypt ./ansible/id_ed25519_vault --output=${decryptedKeyFile} --vault-password-file=${vaultPassFile}
"""
env.DECYPTED_KEY_FILE = decryptedKeyFile
}
}
}
stage('Deploy Site') {
steps {
script {
def selectedHosts
def extraVars = [
ansible_ssh_private_key_file: env.DECYPTED_KEY_FILE
]
switch(params.DEPLOY_TARGET) {
case 'SiteA':
selectedHosts = 'SiteA,proxy'
extraVars.siteA_h2 = params.ADDITIONAL_CONTENT_SITEA_H2
extraVars.siteA_p = params.ADDITIONAL_CONTENT_SITEA_P
break
case 'SiteB':
selectedHosts = 'SiteB,proxy'
extraVars.siteB_h2 = params.ADDITIONAL_CONTENT_SITEB_H2
extraVars.siteB_p = params.ADDITIONAL_CONTENT_SITEB_P
break
case 'All':
selectedHosts = 'SiteA,SiteB,proxy'
extraVars.siteA_h2 = params.ADDITIONAL_CONTENT_SITEA_H2
extraVars.siteA_p = params.ADDITIONAL_CONTENT_SITEA_P
extraVars.siteB_h2 = params.ADDITIONAL_CONTENT_SITEB_H2
extraVars.siteB_p = params.ADDITIONAL_CONTENT_SITEB_P
break
default:
error "Неизвестный DEPLOY_TARGET: ${params.DEPLOY_TARGET}"
}
ansiblePlaybook(
playbook: 'ansible/playbook.yml',
inventory: "ansible/inventory.yml",
extraVars: extraVars,
limit: selectedHosts
)
}
}
}
}
post {
always {
script {
if (env.TEMP_DIR) {
sh "rm -rf ${env.TEMP_DIR}"
}
}
}
success {
echo 'Deployment completed successfully.'
}
failure {
echo 'Deployment failed. Please check the logs for more details.'
}
}
}

6
ansible/ansible.cfg Normal file
View File

@ -0,0 +1,6 @@
[defaults]
inventory = inventory.yml
roles_path = ./roles
host_key_checking = False
interpreter_python = /usr/bin/python3
force_color = true

View File

@ -0,0 +1,26 @@
ansible_python_interpreter: /usr/bin/python3.6
siteA_h2: "Дефолтный заголовок H2 для SiteA"
siteA_p: "Дефолтный параграф для SiteA"
siteB_h2: "Дефолтный заголовок H2 для SiteB"
siteB_p: "Дефолтный параграф для SiteB"
siteA:
site_title: "SiteA - Добро пожаловать"
site_h1: "Добро пожаловать на SiteA"
site_h2: "{{ siteA_h2 }}"
site_p: "{{ siteA_p }}"
site_domain: "siteA.example.com"
site_ip: "192.168.0.61"
siteB:
site_title: "SiteB - Добро пожаловать"
site_h1: "Добро пожаловать на SiteB"
site_h2: "{{ siteB_h2 }}"
site_p: "{{ siteB_p }}"
site_domain: "siteB.example.com"
site_ip: "192.168.0.62"
proxy:
proxy_domain: "proxy.example.com"
proxy_ip: "192.168.0.63"

26
ansible/id_ed25519_vault Normal file
View File

@ -0,0 +1,26 @@
$ANSIBLE_VAULT;1.1;AES256
63306262646434323632386463373239336566633737636235653430333132386537366564666234
6461393163343265306366313736313961373630313234340a323534616566666137616431386461
65373333643664633833613431666531353935646562396661623163343464663262396264643537
6261363038363062640a616431336162386465316639376662333066396535623735383032316538
36613839386139363661636536306361373231623432663331623766346262366230353432373538
34353032303461323533396438306561386332396266316565393930653038623361333163323736
63663734333034336337373632333565333633306361633335663365336161636439386563393736
33613262623862626161653466626339623861353566323864363231343365333666326163396538
30353265613330626261363038633762373531623864333937366361616465313961363536636430
37333739333661303865376137343931363563656362316339383033326539343135663936393931
36653363656535656334613264653932666231663930353931306662333833366534343365386136
61336538356164653433613930343137373534653732613830366439343061313166656533323230
65353938383563646162373232613632313332643765313135653730383864643539333732623739
32393239373735616463633830333136616438316361613336613336613766356538313534303939
64646262323164643336653761663338613036376365613565373561626366643765396564383665
38303135356639373762303139633862313833313063373737633336363939336438376239613536
65636539653335396464653363613339383862653862336630353364636162663237383163666134
30643865383533623461303630356631396135663265376264663637326136663161656638616332
32626636613138313232396636343032343666343039353533626131663235393235343966303662
30336364363361356339303466633165316330376336306130336536656134336130376137613663
34333136306638306332356363616165343536666239366532333630306535626532656438613030
37626535316532623134633238313733353566373630333834616132353061656530373763303531
33366536363333303966663663353865613532353164623762636531366535393465623239643765
39626662633164623734626433313132633532336161363036633434393432393934396663633531
6333

17
ansible/inventory.yml Normal file
View File

@ -0,0 +1,17 @@
all:
children:
SiteA:
hosts:
192.168.0.61:
ansible_user: ansible
ansible_python_interpreter: /usr/bin/python3.6
SiteB:
hosts:
192.168.0.62:
ansible_user: ansible
ansible_python_interpreter: /usr/bin/python3.6
proxy:
hosts:
192.168.0.63:
ansible_user: ansible
ansible_python_interpreter: /usr/bin/python3.6

15
ansible/playbook.yml Normal file
View File

@ -0,0 +1,15 @@
- hosts: all
become: true
roles:
- firewall
- hosts: SiteA,SiteB
become: true
roles:
- nginx_site
- hosts: proxy
become: true
roles:
- ssl_certificate
- nginx_proxy

View File

@ -0,0 +1,18 @@
- name: Install firewalld
zypper:
name: firewalld
state: present
- name: Ensure firewalld is enabled and started
systemd:
name: firewalld
enabled: yes
state: started
- name: Open specified firewall ports
firewalld:
port: "{{ item.port }}/{{ item.protocol }}"
permanent: yes
state: enabled
immediate: yes
loop: "{{ firewall_ports }}"

View File

@ -0,0 +1,4 @@
firewall_ports:
- { port: 22, protocol: tcp }
- { port: 80, protocol: tcp }
- { port: 443, protocol: tcp }

View File

@ -0,0 +1,34 @@
- name: Install Nginx
zypper:
name: nginx
state: present
- name: Ensure Nginx is enabled and started
systemd:
name: nginx
enabled: yes
state: started
- name: Create directory for error pages
file:
path: /var/www/errors
state: directory
owner: nginx
group: nginx
mode: '0755'
- name: Deploy custom error page
template:
src: site_down.html.j2
dest: /var/www/errors/site_down.html
mode: '0644'
- name: Deploy Proxy Configuration
template:
src: proxy.conf.j2
dest: /etc/nginx/conf.d/proxy.conf
- name: Reload Nginx
systemd:
name: nginx
state: reloaded

View File

@ -0,0 +1,40 @@
upstream backend {
{% if siteA.site_ip %}
server {{ siteA.site_ip }} max_fails=1 fail_timeout=10s;
{% endif %}
{% if siteB.site_ip %}
server {{ siteB.site_ip }} max_fails=1 fail_timeout=10s;
{% endif %}
}
server {
listen 80;
listen 443 ssl;
server_name {{ proxy.proxy_domain }};
ssl_certificate /etc/nginx/ssl/{{ ssl_cert_file }};
ssl_certificate_key /etc/nginx/ssl/{{ ssl_key_file }};
error_page 502 503 504 /site_down.html;
location = /site_down.html {
root /var/www/errors;
internal;
}
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_intercept_errors on;
}
location /health {
proxy_pass http://backend/health;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Сайт не работает</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f8d7da;
color: #721c24;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.message {
text-align: center;
}
h1 {
font-size: 48px;
margin-bottom: 20px;
}
p {
font-size: 18px;
}
</style>
</head>
<body>
<div class="message">
<h1>Сайт не работает</h1>
<p>Просьба обратиться в техподдержку или на сервере в данный момент техработы.</p>
</div>
</body>
</html>

View File

@ -0,0 +1,3 @@
upstream_servers:
- "{{ siteA.site_ip }}"
- "{{ siteB.site_ip }}"

View File

@ -0,0 +1,67 @@
- name: Install Nginx
zypper:
name: nginx
state: present
- name: Ensure Nginx is enabled and started
systemd:
name: nginx
enabled: yes
state: started
- name: Create web root for SiteA
file:
path: /var/www/siteA
state: directory
owner: nginx
group: nginx
mode: '0755'
when: "'SiteA' in group_names"
- name: Create web root for SiteB
file:
path: /var/www/siteB
state: directory
owner: nginx
group: nginx
mode: '0755'
when: "'SiteB' in group_names"
- name: Deploy SiteA Configuration
template:
src: siteA.conf.j2
dest: /etc/nginx/conf.d/siteA.conf
when: "'SiteA' in group_names"
- name: Deploy SiteB Configuration
template:
src: siteB.conf.j2
dest: /etc/nginx/conf.d/siteB.conf
when: "'SiteB' in group_names"
- name: Deploy SiteA HTML
template:
src: index.html.j2
dest: /var/www/siteA/index.html
vars:
site_title: "{{ siteA.site_title }}"
site_h1: "{{ siteA.site_h1 }}"
site_h2: "{{ siteA.site_h2 }}"
site_p: "{{ siteA.site_p }}"
when: "'SiteA' in group_names"
- name: Deploy SiteB HTML
template:
src: index.html.j2
dest: /var/www/siteB/index.html
vars:
site_title: "{{ siteB.site_title }}"
site_h1: "{{ siteB.site_h1 }}"
site_h2: "{{ siteB.site_h2 }}"
site_p: "{{ siteB.site_p }}"
when: "'SiteB' in group_names"
- name: Reload Nginx
systemd:
name: nginx
state: reloaded

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>{{ site_title }}</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
color: #333;
text-align: center;
padding-top: 50px;
}
h1 { color: #ff5722; }
h2 { color: #ff9800; }
p { font-size: 18px; }
</style>
</head>
<body>
<h1>{{ site_h1 }}</h1>
<h2>{{ site_h2 }}</h2>
<p>{{ site_p }}</p>
</body>
</html>

View File

@ -0,0 +1,16 @@
server {
listen 80;
server_name {{ siteA.site_domain }};
root /var/www/siteA;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location /health {
return 200 'SiteA is up';
add_header Content-Type text/plain;
}
}

View File

@ -0,0 +1,16 @@
server {
listen 80;
server_name {{ siteB.site_domain }};
root /var/www/siteB;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location /health {
return 200 'SiteB is up';
add_header Content-Type text/plain;
}
}

View File

@ -0,0 +1,4 @@
siteA_h2: "Дефолтный заголовок H2 для SiteA"
siteA_p: "Дефолтный параграф для SiteA"
siteB_h2: "Дефолтный заголовок H2 для SiteB"
siteB_p: "Дефолтный параграф для SiteB"

View File

@ -0,0 +1,22 @@
- name: Install OpenSSL
zypper:
name: openssl
state: present
- name: Create SSL directory
file:
path: "{{ ssl_cert_path }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Generate Self-Signed SSL Certificate
command: >
openssl req -x509 -nodes -days 365
-newkey rsa:2048
-keyout {{ ssl_cert_path }}/{{ ssl_key_file }}
-out {{ ssl_cert_path }}/{{ ssl_cert_file }}
-subj "{{ ssl_subject }}"
args:
creates: "{{ ssl_cert_path }}/{{ ssl_cert_file }}"

View File

@ -0,0 +1,4 @@
ssl_cert_path: "/etc/nginx/ssl"
ssl_cert_file: "proxy.crt"
ssl_key_file: "proxy.key"
ssl_subject: "/C=RU/ST=Some-State/L=Some-City/O=Your Company/CN={{ proxy.proxy_domain }}"

31
docker-compose.yml Normal file
View File

@ -0,0 +1,31 @@
services:
nginx:
image: nginx:latest
container_name: nginx
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/ssl:/etc/nginx/ssl
- ./nginx/html:/usr/share/nginx/html
- /coursework/nginx/ssl:/coursework/nginx/ssl
ports:
- "80:80"
- "443:443"
depends_on:
- gitea
restart: always
gitea:
image: gitea/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
volumes:
- ./gitea-data:/data
ports:
- "3000:3000"
- "222:22"
restart: always
volumes:
gitea-data: