99 lines
5.1 KiB
YAML
99 lines
5.1 KiB
YAML
---
|
||
# tasks file for app_image
|
||
#
|
||
# Роль-инициатор сборки. Гоняет команду сборки приложения на control-хосте и
|
||
# доставляет получившийся образ на сервер через docker save/load. Тулчейн сборки
|
||
# (Go, node, …) на сервере не нужен — туда едет готовый образ.
|
||
#
|
||
# Контракт приложения (app_image_command): команда в app_image_src_dir получает
|
||
# BUILD_ID из окружения и собирает полный образ <app_image_name>:$BUILD_ID.
|
||
#
|
||
# Тег образа = случайный BUILD_ID (роль его генерит). Дедупликации по содержимому
|
||
# нет — каждый деплой везёт образ и пересоздаёт контейнер. Для ручного нечастого
|
||
# деплоя это осознанный выбор: простота важнее экономии рестарта. Старые образы
|
||
# на сервере чистит `docker image prune -af` по крону (см. playbook-system.yml).
|
||
#
|
||
# Рассчитана на один целевой хост за прогон: сборка делегируется на control-хост,
|
||
# при нескольких хостах в play повторится на каждый (мы деплоим последовательно).
|
||
#
|
||
# Выход: факт app_image_tag (= BUILD_ID) + образ <app_image_name>:<app_image_tag>
|
||
# на сервере. Тег забирает следующий кирпичик (рендер compose).
|
||
|
||
- name: "Validate role input"
|
||
ansible.builtin.assert:
|
||
that:
|
||
# Формат имени docker-образа: он же идёт в имя tar-файла (vars/main.yml),
|
||
# поэтому '/' и прочее ломало бы путь и docker-референс.
|
||
- app_image_name is string and app_image_name is match('^[a-z0-9][a-z0-9._-]*$')
|
||
- app_image_src_dir is string and app_image_src_dir | length > 0
|
||
- app_image_command is string and app_image_command | length > 0
|
||
fail_msg: >-
|
||
app_image_name — валидное имя docker-образа (^[a-z0-9][a-z0-9._-]*$);
|
||
app_image_src_dir и app_image_command — непустые строки
|
||
quiet: true
|
||
|
||
- name: "Generate build id (image tag)"
|
||
ansible.builtin.set_fact:
|
||
app_image_tag: "{{ lookup('ansible.builtin.password', '/dev/null chars=ascii_lowercase,digits length=16') }}"
|
||
|
||
- name: "Build image and deliver it to server"
|
||
# В --check command-таски пропускаются, tar не создаётся и copy упал бы «нет
|
||
# файла на контроллере». Пропускаем всю доставку — факт app_image_tag уже
|
||
# выставлен, поэтому рендер compose ниже честно покажет diff со своим тегом.
|
||
when: "not ansible_check_mode"
|
||
block:
|
||
- name: "Build image locally via app contract"
|
||
delegate_to: localhost
|
||
# Сборка идёт от локального юзера. Инвентарь включает become глобально, но
|
||
# локальная сборка под root не нужна — фиксируем инвариант явно.
|
||
become: false
|
||
ansible.builtin.command:
|
||
cmd: "{{ app_image_command }}"
|
||
chdir: "{{ app_image_src_dir }}"
|
||
environment:
|
||
BUILD_ID: "{{ app_image_tag }}"
|
||
# Локальная сборка — средство доставки; факт изменения системы (сервера)
|
||
# отражает загрузка образа ниже.
|
||
changed_when: false
|
||
|
||
- name: "Save image to tar locally"
|
||
delegate_to: localhost
|
||
become: false
|
||
ansible.builtin.command:
|
||
cmd: "docker save --output {{ app_image_local_tar }} {{ app_image_name }}:{{ app_image_tag }}"
|
||
changed_when: false
|
||
|
||
- name: "Copy image tar to server"
|
||
ansible.builtin.copy:
|
||
src: "{{ app_image_local_tar }}"
|
||
dest: "{{ app_image_remote_tar }}"
|
||
mode: "0644"
|
||
|
||
- name: "Load image on server"
|
||
ansible.builtin.command:
|
||
cmd: "docker load --input {{ app_image_remote_tar }}"
|
||
changed_when: true
|
||
|
||
always:
|
||
- name: "Remove local image tar"
|
||
delegate_to: localhost
|
||
become: false
|
||
ansible.builtin.file:
|
||
path: "{{ app_image_local_tar }}"
|
||
state: absent
|
||
|
||
- name: "Remove remote image tar"
|
||
ansible.builtin.file:
|
||
path: "{{ app_image_remote_tar }}"
|
||
state: absent
|
||
|
||
# Локальный тег — временная ручка (на сервер образ уехал через save/load).
|
||
# Снимаем, чтобы control-хост не копил <app>:<random> от каждого прогона.
|
||
- name: "Remove transient local image tag"
|
||
delegate_to: localhost
|
||
become: false
|
||
ansible.builtin.command:
|
||
cmd: "docker image rm {{ app_image_name }}:{{ app_image_tag }}"
|
||
changed_when: false
|
||
failed_when: false
|