--- # --- Каталоги и файлы ---------------------------------------------------- - name: Создать каталог развёртывания ansible.builtin.file: path: "{{ deploy_dir }}" state: directory owner: root group: root mode: "0750" tags: [env] - name: Скопировать docker-compose.yaml ansible.builtin.copy: src: "{{ deploy_src_root }}/docker-compose.yaml" dest: "{{ deploy_dir }}/docker-compose.yaml" mode: "0640" # nginx монтирует ./nginx/templates и ./nginx/certs — без шаблонов nginx не # стартует, поэтому копируем конфигурацию рядом с compose. - name: Скопировать шаблоны nginx ansible.builtin.copy: src: "{{ deploy_src_root }}/nginx/templates/" dest: "{{ deploy_dir }}/nginx/templates/" mode: "0644" # backend монтирует ./backend/uwsgi.ini (http-socket + 4 воркера) - name: Скопировать конфиг uwsgi для backend ansible.builtin.copy: src: "{{ deploy_src_root }}/backend/uwsgi.ini" dest: "{{ deploy_dir }}/backend/uwsgi.ini" mode: "0644" # --- Секреты: генерация с персистом на control-node (идемпотентно) -------- - name: Сгенерировать/загрузить пароли (persist в secrets_store, gitignored) ansible.builtin.set_fact: sarex_secrets: >- {{ sarex_secrets | default({}) | combine({ item: lookup('password', secrets_store ~ '/' ~ inventory_hostname ~ '/' ~ item ~ ' length=' ~ secret_length ~ ' chars=ascii_letters,digits') }) }} loop: "{{ sarex_secret_vars }}" no_log: true tags: [env] - name: Собрать словарь переопределений для .env (пароли + домены) ansible.builtin.set_fact: env_overrides: >- {{ sarex_secrets | combine({ 'PLATFORM_DOMAIN': platform_domain, 'ADMIN_DOMAIN': admin_domain, 'MINIO_DOMAIN': minio_domain, 'SAREX_MINIO_CONSOLE_URL': 'https://' ~ minio_domain, }) }} no_log: true tags: [env] - name: Отрендерить .env из .env.example с переопределениями ansible.builtin.template: src: env.j2 dest: "{{ deploy_dir }}/.env" owner: root group: root mode: "0600" no_log: true tags: [env] # --- Самоподписанный TLS-сертификат для трёх доменов ---------------------- - name: Создать каталог для сертификатов ansible.builtin.file: path: "{{ cert_dir }}" state: directory mode: "0750" - name: Сгенерировать самоподписанный сертификат (SAN на все домены) ansible.builtin.shell: # umask 077 → приватный ключ создаётся сразу с правами 0600 cmd: >- umask 077 && openssl req -x509 -nodes -newkey rsa:2048 -days {{ cert_days }} -keyout {{ cert_dir }}/selfsigned.key -out {{ cert_dir }}/selfsigned.crt -subj "/CN={{ platform_domain }}" -addext "subjectAltName=DNS:{{ platform_domain }},DNS:{{ admin_domain }},DNS:{{ minio_domain }}" creates: "{{ cert_dir }}/selfsigned.crt" # --- Логин в приватный реестр образов (json_key) -------------------------- - name: Проверить, выполнен ли вход в реестр ansible.builtin.command: grep -q "{{ registry_host }}" /root/.docker/config.json register: registry_login_state changed_when: false failed_when: false tags: [login] - name: Скопировать ключ реестра на хост (временно) ansible.builtin.copy: src: "{{ registry_key_src }}" dest: /root/.registry-key.json mode: "0600" when: registry_login_state.rc != 0 no_log: true tags: [login] - name: docker login в приватный реестр ansible.builtin.shell: >- set -o pipefail && cat /root/.registry-key.json | docker login --username {{ registry_username }} --password-stdin {{ registry_host }} args: executable: /bin/bash when: registry_login_state.rc != 0 register: registry_login_result changed_when: "'Login Succeeded' in registry_login_result.stdout" no_log: true tags: [login] - name: Удалить временный ключ реестра с хоста ansible.builtin.file: path: /root/.registry-key.json state: absent tags: [login] # --- Опционально: поднять стек ------------------------------------------- - name: Поднять стек (docker compose up -d) ansible.builtin.command: cmd: "{{ compose_cmd }} up -d" chdir: "{{ deploy_dir }}" when: sarex_compose_up | bool changed_when: true # --- Django-суперпользователь: генерация логина+пароля, создание ----------- # Логин и пароль генерируются один раз и персистятся в secrets_store # (переиспользуются при повторе — идемпотентно). - name: Сгенерировать логин суперпользователя ansible.builtin.set_fact: superuser_name: "{{ lookup('password', secrets_store ~ '/' ~ inventory_hostname ~ '/SAREX_SUPERUSER_NAME chars=ascii_lowercase,digits length=10') }}" no_log: true tags: [superuser] - name: Сгенерировать пароль суперпользователя ansible.builtin.set_fact: superuser_password: "{{ lookup('password', secrets_store ~ '/' ~ inventory_hostname ~ '/SAREX_SUPERUSER_PASSWORD chars=ascii_letters,digits length=' ~ secret_length) }}" no_log: true tags: [superuser] - name: Создать/обновить Django-суперпользователя в backend ansible.builtin.command: argv: - "{{ compose_cmd.split()[0] }}" - exec - -e - "SU_NAME={{ superuser_name }}" - -e - "SU_PASS={{ superuser_password }}" - -e - "SU_EMAIL={{ superuser_name }}@{{ platform_domain }}" - sarex-backend - python - manage.py - shell - -c - >- import os; from django.contrib.auth import get_user_model; U = get_user_model(); u, c = U.objects.get_or_create(username=os.environ['SU_NAME'], defaults={'email': os.environ['SU_EMAIL']}); u.is_staff = True; u.is_superuser = True; u.set_password(os.environ['SU_PASS']); u.save(); print('created' if c else 'updated') register: superuser_result changed_when: true no_log: true tags: [superuser] - name: Показать учётные данные суперпользователя ansible.builtin.debug: msg: "Django superuser → login: {{ superuser_name }} password: {{ superuser_password }}" tags: [superuser]