diff --git a/Jenkinsfile b/Jenkinsfile index 005f009..eb554fd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -11,6 +11,7 @@ pipeline { string(name: 'DB_USER', defaultValue: 'postgres', description: 'Имя пользователя базы данных') string(name: 'DB_NAME', defaultValue: 'mydb', description: 'Имя базы данных') string(name: 'BACKUP_DIR', defaultValue: '/var/backups/postgresql', description: 'Директория для бэкапа') + string(name: 'TASKS', defaultValue: '', description: 'Список тегов задач для выполнения (setup,firewall,init,configure,database,user,backup)') } stages { stage('Clone repository') { @@ -37,19 +38,24 @@ pipeline { } } } - stage('Install PostgreSQL') { + stage('Run PostgreSQL Playbook') { steps { - ansiblePlaybook( - playbook: 'install_postgresql.yml', - inventory: "inventory.yml", - extraVars: [ - postgres_user: params.DB_USER, - postgres_password: PSQL_PASSWORD, - postgres_db: params.DB_NAME, - backup_dir: params.BACKUP_DIR, - ansible_ssh_private_key_file: env.DECRYPTED_KEY_FILE - ] - ) + script { + def tagsString = params.TASKS ? params.TASKS.split(',').join(',') : '' + + ansiblePlaybook( + playbook: 'playbooks/install_postgresql.yml', + inventory: "inventory.yml", + extraVars: [ + postgres_user: params.DB_USER, + postgres_password: PSQL_PASSWORD, + postgres_db: params.DB_NAME, + backup_dir: params.BACKUP_DIR, + ansible_ssh_private_key_file: env.DECRYPTED_KEY_FILE + ], + tags: tagsString + ) + } } } } diff --git a/README.md b/README.md index e69de29..5a756cd 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,61 @@ +# Проект по автоматизации настройки PostgreSQL + +Этот проект предназначен для автоматизации установки, настройки и управления базой данных PostgreSQL с использованием **Ansible** и **Jenkins**. Он включает пайплайн Jenkins и Ansible плейбук с ролью для управления PostgreSQL. + +## Структура проекта + +- **Jenkinsfile** — скрипт для автоматизации пайплайна Jenkins, который позволяет клонировать репозиторий, расшифровывать SSH-ключи, запускать Ansible плейбук и выполнять определенные задачи роли PostgreSQL. +- **ansible.cfg** — конфигурационный файл Ansible, где указаны настройки по умолчанию для выполнения плейбуков. +- **inventory.yml** — файл инвентаря Ansible, который определяет хосты, на которых будут выполняться плейбуки. +- **playbooks/install_postgresql.yml** — основной Ansible плейбук для установки и настройки PostgreSQL. +- **roles/postgresql** — Ansible роль для управления PostgreSQL, которая содержит: + - **tasks/** — каталог с задачами: + - `setup.yml` — установка необходимых пакетов PostgreSQL. + - `open_firewall.yml` — настройка правил брандмауэра для доступа к базе данных. + - `initialize.yml` — инициализация новой базы данных. + - `configure.yml` — настройка параметров конфигурации PostgreSQL. + - `databases.yml` — создание и управление базами данных. + - `users.yml` — создание и управление пользователями базы данных. + - `backup.yml` — резервное копирование базы данных. + - **templates/** — шаблоны конфигурационных файлов для PostgreSQL: + - `pg_hba.conf.j2` — шаблон файла для управления доступом к базе данных. + - `postgresql.conf.j2` — шаблон основного конфигурационного файла PostgreSQL. + - **vars/** — переменные, используемые в роли PostgreSQL. + +## Запуск проекта + +### Предварительные требования + +- **Jenkins** с установленным Ansible плагином +- Доступ к хостам, указанным в `inventory.yml` + +### Пайплайн Jenkins + +Файл **Jenkinsfile** определяет этапы пайплайна для автоматизированного развертывания PostgreSQL: + +1. **Клонирование репозитория** — загрузка кода проекта. +2. **Расшифровка SSH-ключа** — декодирование зашифрованного ключа с использованием Ansible Vault. +3. **Запуск плейбука PostgreSQL** — выполнение Ansible плейбука для развертывания и настройки PostgreSQL на целевых хостах. + +### Параметры запуска + +Пайплайн поддерживает следующие параметры: + +- **DB_USER** — имя пользователя PostgreSQL. +- **DB_NAME** — название базы данных. +- **BACKUP_DIR** — директория для хранения резервных копий. +- **TASKS** — список задач для выполнения, указанный через запятую (например, `setup,backup`). + +### Порядок задач + +По умолчанию задачи выполняются в следующем порядке: + +1. `setup` — установка необходимых пакетов. +2. `firewall` — настройка брандмауэра. +3. `init` — инициализация базы данных. +4. `configure` — конфигурация базы данных. +5. `database` — создание базы данных. +6. `user` — управление пользователями. +7. `backup` — резервное копирование данных. + +При указании параметра `TASKS`, можно выбрать конкретные задачи, и они будут выполнены в этом порядке. diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..6db58e7 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] +inventory = inventory.yml +roles_path = ./roles diff --git a/install_postgresql.yml b/install_postgresql.yml deleted file mode 100644 index c490c4c..0000000 --- a/install_postgresql.yml +++ /dev/null @@ -1,125 +0,0 @@ -- name: Install PostgreSQL and Backup - hosts: all - become: true - vars: - postgres_user: '{{ postgres_user }}' - postgres_password: '{{ postgres_password }}' - postgres_db: '{{ postgres_db }}' - backup_dir: '{{ backup_dir }}' - - tasks: - - name: Update zypper - command: zypper refresh - register: zypper_refresh - changed_when: "'Refreshing' in zypper_refresh.stdout" - - - name: Update System - zypper: - name: '*' - state: latest - when: zypper_refresh.changed - - - name: Update PostgreSQL package - zypper: - name: - - postgresql-server - - postgresql-contrib - state: present - - - name: PostgreSQL initdb - command: sudo -u postgres initdb -D /var/lib/pgsql/data - args: - creates: /var/lib/pgsql/data/PG_VERSION - - - name: Systemctl start and enable PostgreSQL - service: - name: postgresql - state: started - enabled: true - - - name: python3-psycopg2 install - zypper: - name: python3-psycopg2 - state: present - - - name: Change listen_addresses in postgresql.conf - lineinfile: - path: /var/lib/pgsql/data/postgresql.conf - regexp: '^#?listen_addresses\\s*=' - line: "listen_addresses = '*'" - notify: Restart PostgreSQL - - - name: Change pg_hba.conf - lineinfile: - path: /var/lib/pgsql/data/pg_hba.conf - regexp: '^host\\s+all\\s+all\\s+0\\.0\\.0\\.0/0\\s+md5' - line: 'host all all 0.0.0.0/0 md5' - notify: Restart PostgreSQL - - - name: Create User PostgreSQL - community.postgresql.postgresql_user: - name: '{{ postgres_user }}' - password: '{{ postgres_password }}' - state: present - - - name: Create Base PostgreSQL - community.postgresql.postgresql_db: - name: '{{ postgres_db }}' - owner: '{{ postgres_user }}' - encoding: UTF8 - state: present - - - name: Create a table - community.postgresql.postgresql_query: - db: '{{ postgres_db }}' - query: 'CREATE TABLE IF NOT EXISTS contacts (id SERIAL PRIMARY KEY, name VARCHAR(100), phone_number VARCHAR(15));' - login_user: '{{ postgres_user }}' - login_password: '{{ postgres_password }}' - - - name: Open firewall 5432 port - command: firewall-cmd --add-port=5432/tcp --permanent - become: true - - - name: Restart Firewall - command: firewall-cmd --reload - become: true - - - name: Create backup directory - file: - path: '{{ backup_dir }}' - state: directory - owner: postgres - group: postgres - mode: '0755' - - - name: PostgreSQL database backup - become_user: postgres - command: 'pg_dump -U {{ postgres_user }} -F c -f "{{ backup_dir }}/db_backup_{{ postgres_db }}_{{ ansible_date_time.iso8601 }}.sql" {{ postgres_db }}' - environment: - PGPASSWORD: '{{ postgres_password }}' - - - name: Create cron for daily full backup - cron: - name: 'PostgreSQL daily full backup' - user: postgres - minute: '0' - hour: '1' - job: 'pg_dump -U {{ postgres_user }} -F c {{ postgres_db }} > {{ backup_dir }}/full_db_backup_{{ postgres_db }}_$(date +\\\\%F-\\\\%H-%M).sql' - environment: - PGPASSWORD: '{{ postgres_password }}' - - - name: Create cron backup script - cron: - name: 'PostgreSQL hourly backup' - user: postgres - minute: '0' - hour: '*' - job: 'pg_dump -U {{ postgres_user }} -F c {{ postgres_db }} > {{ backup_dir }}/db_backup_{{ postgres_db }}_$(date +\\\\%F-\\\\%H-%M).sql' - environment: - PGPASSWORD: '{{ postgres_password }}' - - handlers: - - name: Restart PostgreSQL - service: - name: postgresql - state: restarted diff --git a/playbooks/install_postgresql.yml b/playbooks/install_postgresql.yml new file mode 100644 index 0000000..fec3c7f --- /dev/null +++ b/playbooks/install_postgresql.yml @@ -0,0 +1,4 @@ +- hosts: all + become: true + roles: + - postgresql diff --git a/roles/postgresql/handlers/main.yml b/roles/postgresql/handlers/main.yml new file mode 100644 index 0000000..ef04727 --- /dev/null +++ b/roles/postgresql/handlers/main.yml @@ -0,0 +1,4 @@ +- name: Restart PostgreSQL + service: + name: postgresql + state: restarted diff --git a/roles/postgresql/tasks/backup.yml b/roles/postgresql/tasks/backup.yml new file mode 100644 index 0000000..84a6fc6 --- /dev/null +++ b/roles/postgresql/tasks/backup.yml @@ -0,0 +1,41 @@ +- name: Create backup directory + file: + path: '{{ backup_dir }}' + state: directory + owner: postgres + group: postgres + mode: '0755' + tags: + - backup + +- name: Perform database backup + command: > + pg_dump -U {{ postgres_user }} -F c -f "{{ backup_dir }}/db_backup_{{ postgres_db }}_{{ ansible_date_time.iso8601 }}.sql" {{ postgres_db }} + become_user: postgres + environment: + PGPASSWORD: '{{ postgres_password }}' + tags: + - backup + +- name: Daily cron full backup + cron: + name: 'PostgreSQL daily full backup' + user: postgres + minute: '0' + hour: '1' + job: "pg_dump -U {{ postgres_user }} -F c {{ postgres_db }} > {{ backup_dir }}/full_db_backup_{{ postgres_db }}_$(date +\\%F-\\%H-%M).sql" + environment: + PGPASSWORD: '{{ postgres_password }}' + tags: + - backup + +- name: Hourly cron incremental backup + cron: + name: 'PostgreSQL hourly incremental backup' + user: postgres + minute: '0' + job: "pg_dump -U {{ postgres_user }} -F c --data-only --file=\"{{ backup_dir }}/incremental_db_backup_{{ postgres_db }}_$(date +\\%F-\\%H-%M).sql\" {{ postgres_db }}" + environment: + PGPASSWORD: '{{ postgres_password }}' + tags: + - backup \ No newline at end of file diff --git a/roles/postgresql/tasks/configure.yml b/roles/postgresql/tasks/configure.yml new file mode 100644 index 0000000..8cc7565 --- /dev/null +++ b/roles/postgresql/tasks/configure.yml @@ -0,0 +1,21 @@ +- name: Configure postgresql.conf with template + template: + src: postgresql.conf.j2 + dest: /var/lib/pgsql/data/postgresql.conf + owner: postgres + group: postgres + mode: '0644' + notify: Restart PostgreSQL + tags: + - configure + +- name: Configure pg_hba.conf with template + template: + src: pg_hba.conf.j2 + dest: /var/lib/pgsql/data/pg_hba.conf + owner: postgres + group: postgres + mode: '0644' + notify: Restart PostgreSQL + tags: + - configure diff --git a/roles/postgresql/tasks/databases.yml b/roles/postgresql/tasks/databases.yml new file mode 100644 index 0000000..999b203 --- /dev/null +++ b/roles/postgresql/tasks/databases.yml @@ -0,0 +1,17 @@ +- name: Create PostgreSQL database + community.postgresql.postgresql_db: + name: '{{ postgres_db }}' + owner: '{{ postgres_user }}' + encoding: UTF8 + state: present + tags: + - database + +- name: Create contacts table in PostgreSQL + community.postgresql.postgresql_query: + db: '{{ postgres_db }}' + query: 'CREATE TABLE IF NOT EXISTS contacts (id SERIAL PRIMARY KEY, name VARCHAR(100), phone_number VARCHAR(15));' + login_user: '{{ postgres_user }}' + login_password: '{{ postgres_password }}' + tags: + - database diff --git a/roles/postgresql/tasks/initialize.yml b/roles/postgresql/tasks/initialize.yml new file mode 100644 index 0000000..c9de0f8 --- /dev/null +++ b/roles/postgresql/tasks/initialize.yml @@ -0,0 +1,14 @@ +- name: PostgreSQL initdb + command: sudo -u postgres initdb -D /var/lib/pgsql/data + args: + creates: /var/lib/pgsql/data/PG_VERSION + tags: + - init + +- name: Systemctl start and enable PostgreSQL + service: + name: postgresql + state: started + enabled: true + tags: + - init diff --git a/roles/postgresql/tasks/main.yml b/roles/postgresql/tasks/main.yml new file mode 100644 index 0000000..ee7f31a --- /dev/null +++ b/roles/postgresql/tasks/main.yml @@ -0,0 +1,7 @@ +- import_tasks: setup.yml +- import_tasks: initialize.yml +- import_tasks: configure.yml +- import_tasks: users.yml +- import_tasks: databases.yml +- import_tasks: open_firewall.yml +- import_tasks: backup.yml \ No newline at end of file diff --git a/roles/postgresql/tasks/open_firewall.yml b/roles/postgresql/tasks/open_firewall.yml new file mode 100644 index 0000000..1d984a2 --- /dev/null +++ b/roles/postgresql/tasks/open_firewall.yml @@ -0,0 +1,14 @@ +- name: Open PostgreSQL port in firewall + firewalld: + port: 5432/tcp + permanent: true + state: enabled + become: true + tags: + - firewall + +- name: Reload firewall using command + command: firewall-cmd --reload + become: true + tags: + - firewall diff --git a/roles/postgresql/tasks/setup.yml b/roles/postgresql/tasks/setup.yml new file mode 100644 index 0000000..1a378e6 --- /dev/null +++ b/roles/postgresql/tasks/setup.yml @@ -0,0 +1,15 @@ +- name: Install PostgreSQL packages + zypper: + name: + - postgresql-server + - postgresql-contrib + state: present + tags: + - setup + +- name: Install python3-psycopg2 + zypper: + name: python3-psycopg2 + state: present + tags: + - setup diff --git a/roles/postgresql/tasks/users.yml b/roles/postgresql/tasks/users.yml new file mode 100644 index 0000000..efa300d --- /dev/null +++ b/roles/postgresql/tasks/users.yml @@ -0,0 +1,7 @@ +- name: Create PostgreSQL user + community.postgresql.postgresql_user: + name: '{{ postgres_user }}' + password: '{{ postgres_password }}' + state: present + tags: + - users diff --git a/roles/postgresql/templates/pg_hba.conf.j2 b/roles/postgresql/templates/pg_hba.conf.j2 new file mode 100644 index 0000000..fe82a0b --- /dev/null +++ b/roles/postgresql/templates/pg_hba.conf.j2 @@ -0,0 +1,3 @@ +{% for entry in postgres_hba_entries %} +{{ entry.type }} {{ entry.database }} {{ entry.user }} {{ entry.address }} {{ entry.method }} +{% endfor %} diff --git a/roles/postgresql/templates/postgresql.conf.j2 b/roles/postgresql/templates/postgresql.conf.j2 new file mode 100644 index 0000000..7013fde --- /dev/null +++ b/roles/postgresql/templates/postgresql.conf.j2 @@ -0,0 +1,12 @@ +listen_addresses = '{{ postgres_listen_addresses | default("*") }}' + +port = {{ postgres_port | default(5432) }} + + +max_connections = {{ postgres_max_connections | default(100) }} +shared_buffers = {{ postgres_shared_buffers | default("128MB") }} +effective_cache_size = {{ postgres_effective_cache_size | default("4GB") }} +maintenance_work_mem = {{ postgres_maintenance_work_mem | default("64MB") }} +checkpoint_completion_target = {{ postgres_checkpoint_completion_target | default(0.7) }} +wal_buffers = {{ postgres_wal_buffers | default("16MB") }} +default_statistics_target = {{ postgres_default_statistics_target | default(100) }} \ No newline at end of file diff --git a/roles/postgresql/vars/main.yml b/roles/postgresql/vars/main.yml new file mode 100644 index 0000000..d86ab40 --- /dev/null +++ b/roles/postgresql/vars/main.yml @@ -0,0 +1,11 @@ +postgres_listen_addresses: '*' +postgres_port: 5432 + +postgres_hba_entries: + - { type: 'host', database: 'all', user: 'all', address: '0.0.0.0/0', method: 'md5' } + - { type: 'local', database: 'all', user: 'all', address: '', method: 'trust' } + +backup_dir: "/var/lib/pgsql/backups" +postgres_user: "postgres" +postgres_password: "your_password" +postgres_db: "your_database"