Выполнение команды Ansible в нескольких контейнерах docker

Мне нужно запустить команду для нескольких запущенных контейнеров. Например, предположим, что моему приложению необходимо выполнить обновление структуры данных для базы данных после получения обновлений кода. Чтобы сделать это, мы хотим запустить docker build <project_dir> -t latest, затем docker stop; docker rm; docker run. На этом этапе мы можем предположить, что обновили основной код контейнера, но нам все равно нужно запустить это обновление базы данных с помощью собственного инструментария приложения.

По сути, мне нужен какой-то способ получить список запущенных контейнеров, отфильтрованных по некоторым критериям, и зарегистрировать эти идентификаторы контейнеров в Ansible. Затем для каждого контейнера мы запускаем команду.

Подобный этому:

- name: Get list of running containers  docker:      image: my-image:latest      state: running      register: container_ids

Эта задача сохранит список запущенных контейнеров, которые используют my-image:latest к container_ids. Затем мы выполняем команду:

- name: Exec the database update  cmd: "docker exec -it {{ item }} my-app-db-update.sh"  with: container_ids

Поскольку мы на самом деле не хотим использовать активные контейнеры для такого типа операций, лучшим вариантом было бы запустить вместо этого новый одноразовый контейнер, работающий с теми же данными:

- name: Run the database update  cmd: "docker run --rm --volumes-from {{ item }} --link:mydb:db my-app sh -c 'my-app-db-update.sh'"  with: container_ids

Приведенное выше - всего лишь псевдокод, на самом деле он не будет выполняться. Как мне выполнить задачу сохранения списка запущенных контейнеров docker, которые соответствуют определенным критериям, чтобы затем я мог применить команду к каждому контейнеру в списке, используя либо docker exec или docker run?

В Интернете на удивление мало информации об этом.

Учитывая следующий пример вывода из docker ps:

$ docker psCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES7e21761c9c44        busybox             "top"                    22 minutes ago      Up 22 minutes                           agitated_yonath7091d9c7cc56        nginx               "nginx -g 'daemon off"   23 minutes ago      Up 23 minutes       80/tcp, 443/tcp     fervent_blackwell

Этот учебник даст вам представление о том, как собирать необходимые вам данные и как выполнять действия, повторяющиеся по предоставленному списку. Это очень простой пример, и вам придется адаптировать его к вашим потребностям. Это нарочно:

---- hosts: localhost  gather_facts: no  tasks:  - name: gather list of containers    shell: docker ps | awk '/{{ item }}/{print $1}'    register: list_of_containers    with_items:      - busybox  #- name: debug  #  debug: msg="{{ list_of_containers }}"  - name: run action in container(s)    docker_container:      name: temp-container      image: busybox      command: uptime      cleanup: yes      detach: yes    register: result_of_action    with_items:      - list_of_containers.results.stdout_lines

Интересными частями являются:

  1. Соберите список контейнеров на данном хосте (localhost в моем примере).Я использовал простой shell вызов, чтобы иметь возможность использовать awk чтобы отфильтровать выходные данные. Результат сохраняется в регистре. Поскольку входные данные представляют собой список, это будет иметь прямое влияние на то, как получить данные обратно, подробнее об этом ниже. Раскомментируйте debug промежуточная задача - сравнить данные, хранящиеся в реестре, со списком и без него.

  2. Выполните итерацию по результатам регистра (идентификатор контейнера) и используйте docker_container модуль для выполнения действия (command параметр). Вы можете использовать links и volumes_from В вашем docker_container вызов. Ознакомьтесь с онлайн-документацией модуль за подробностями.

@thrig, это должно быть применено к контейнерам, работающим в * одной* системе, а не к нескольким. Если бы мне нужно было применить команду к нескольким системам, я бы просто использовал для этого инвентаризацию.

@techraf - Я отредактировал вопрос. Теперь он включает в себя вопросительный знак.

Итак, вы на самом деле запрашиваете синтаксис канала, аналогичный “docker ps | grep my-image: latest | cut -f 1”?

Нет, @techraf, в этом случае более эффективно использовать docker ps --filter. Вопрос касается идемпотентности и наилучшей практики, поскольку выполнение приведенных выше команд в качестве команд оболочки не является идемпотентным. Вы бы подумали, что было бы разумнее использовать собственный API docker от ansible для достижения этой цели, если это возможно.

Какое отношение идемпотентность имеет к запросу? Любой запрос. Пожалуйста, объясните.

Идемпотентность - важная концепция для ansible, @techraf. При наивном выполнении команд оболочки с использованием ansible мы теряем возможность оценить, соответствует ли система требованиям playbook (и пропустить задачу) или нет. Вот почему всегда желательно запускать собственные модули API ansible вместо оболочки. В руководстве ansible указано, что для stdout_lines не следует часто использовать его в этой учетной записи.