Ansible을 이용한 데이터베이스 자동화
증상
목표: Ansible로 데이터베이스 설치, 구성, 사용자, 백업 작업을 반복 가능하고 멱등적으로(같은 playbook을 다시 실행해도 시스템이 깨지지 않음) 만든다.
1. 인벤토리와 그룹을 정의한다
인벤토리에서 서버를 데이터베이스 역할별로 그룹화한다. primary, replica, 백업 서버를 별도 그룹에 둔다. 정적 INI/YAML 인벤토리 또는 클라우드용 동적 인벤토리(aws_ec2, gcp_compute)를 사용한다. 그룹 변수는 group_vars/ 아래에, 호스트별 변수는 host_vars/ 아래에 둔다.
PostgreSQL
[pg_primary]
db1.example.local
[pg_replica]
db2.example.local
[postgres:children]
pg_primary
pg_replica2. 올바른 collection을 설치한다(community.postgresql / community.mysql / community.mongodb)
현재 Ansible core는 데이터베이스 모듈을 별도 collection으로 제공한다. requirements.yml로 사용하는 엔진의 collection을 설치한다. PostgreSQL에는 community.postgresql(postgresql_db, postgresql_user, postgresql_privs), MySQL/MariaDB에는 community.mysql(mysql_db, mysql_user), MongoDB에는 community.mongodb를 사용한다. 대상 호스트에는 해당 Python 클라이언트(psycopg2, PyMySQL, pymongo)가 설치되어 있어야 한다.
PostgreSQL
# requirements.yml
collections:
- name: community.postgresql
# install:
ansible-galaxy collection install -r requirements.ymlMySQL
collections:
- name: community.mysqlMongoDB
collections:
- name: community.mongodb3. Ansible Vault로 비밀 정보를 암호화한다
데이터베이스 비밀번호, 복제 비밀, superuser 자격 증명을 평문으로 두지 않고 ansible-vault로 암호화된 변수 파일에 보관한다. 실행 시 --ask-vault-pass 또는 --vault-password-file로 복호화한다. 이렇게 하면 비밀 정보를 Git에 안전하게 저장할 수 있고 playbook은 멱등성을 유지한다.
PostgreSQL
ansible-vault create group_vars/postgres/vault.yml
# contents:
vault_pg_admin_password: "S3cret!"
# run:
ansible-playbook site.yml --ask-vault-pass4. role 구조를 구성한다(roles/postgres, roles/mysql)
엔진별로 role을 하나씩 만들고 로직을 tasks/, defaults/, templates/, handlers/ 하위 폴더로 나눈다. 이 구조는 재사용성을 높인다: 기본값은 defaults/main.yml, jinja2 구성 템플릿은 templates/, '변경이 있을 때만 재시작' 로직은 handlers/. ansible-galaxy init roles/postgres로 role 골격을 만들 수 있다.
PostgreSQL
ansible-galaxy init roles/postgres
# roles/postgres/
# defaults/main.yml
# tasks/main.yml
# templates/postgresql.conf.j2
# handlers/main.yml5. 설치 및 구성 task를 멱등적으로 작성한다
패키지를 설치하고, 데이터 디렉터리를 초기화하며, 템플릿으로 postgresql.conf/my.cnf를 렌더링한다. 구성이 바뀌면 handler로 서비스를 재시작한다. 모듈은 멱등적이다: 이미 설치된 패키지는 재설치되지 않고, 파일이 바뀌지 않으면 handler가 트리거되지 않는다. template 모듈로 구성 템플릿을 렌더링하고 'notify'로 handler에 연결한다.
PostgreSQL
- name: postgresql.conf template
ansible.builtin.template:
src: postgresql.conf.j2
dest: /etc/postgresql/16/main/postgresql.conf
notify: restart postgresql
# handlers/main.yml
- name: restart postgresql
ansible.builtin.service:
name: postgresql
state: restartedMySQL
- name: my.cnf template
ansible.builtin.template:
src: my.cnf.j2
dest: /etc/mysql/my.cnf
notify: restart mysql6. 데이터베이스 및 사용자 task를 정의한다
모듈로 데이터베이스, 사용자, 권한을 생성하고 비밀번호는 Vault 변수에서 가져온다. community.postgresql 모듈은 멱등적이다: 사용자/DB가 존재하면 다시 만들지 않고 차이만 적용한다. 권한은 postgresql_privs로 별도 부여하며, MySQL에서는 mysql_user의 priv 필드를 사용한다.
PostgreSQL
- name: application database
community.postgresql.postgresql_db:
name: appdb
state: present
- name: application user
community.postgresql.postgresql_user:
name: app_user
password: "{{ vault_app_password }}"
db: appdb
state: presentMySQL
- name: application user
community.mysql.mysql_user:
name: app_user
password: "{{ vault_app_password }}"
priv: 'appdb.*:ALL'
state: present7. 백업 task와 스케줄을 추가한다
템플릿으로 백업 스크립트를 배포하고 ansible.builtin.cron으로 스케줄링한다. 그러면 백업 작업도 코드로 관리된다. 백업 대상 디렉터리, 보관 기간, 스케줄을 변수로 만든다. cron 모듈은 멱등적이며 'name'으로 항목을 식별하므로 재실행해도 중복되지 않는다.
PostgreSQL
- name: nightly backup (cron)
ansible.builtin.cron:
name: "pg dump nightly"
minute: "0"
hour: "2"
job: "pg_dump -Fc appdb > /backup/appdb_$(date +\\%F).dump"