Ejecución de un comando Ansible en varios contenedores Docker

Necesito ejecutar un comando en varios contenedores en ejecución. Por ejemplo, supongamos que mi aplicación necesita ejecutar una actualización de la estructura de datos en una base de datos después de recibir actualizaciones de código. Para hacer esto, queremos correr docker build <project_dir> -t latest, entonces docker stop; docker rm; docker run. En esta etapa, podemos suponer que hemos actualizado el código central del contenedor, pero aún necesitamos ejecutar esa actualización de la base de datos utilizando las herramientas propias de la aplicación.

Esencialmente, necesito alguna forma de obtener una lista de contenedores en ejecución, filtrados por algunos criterios, y registrar esos ID de contenedor con Ansible. Luego, para cada contenedor, ejecutamos el comando.

Como esto:

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

Esta tarea almacenaría la lista de contenedores en ejecución que utilizan my-image:latest a container_ids. Luego ejecutamos el comando:

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

Como realmente no queremos usar contenedores activos para este tipo de operación, una mejor opción sería iniciar un nuevo contenedor de un solo uso que actúe sobre los mismos datos:

- 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

Lo anterior es solo un pseudocódigo , en realidad no se ejecutará. ¿Cómo realizo la tarea de almacenar una lista de contenedores docker en ejecución que cumplen con ciertos criterios, de modo que luego pueda aplicar un comando a cada contenedor de la lista usando docker exec o docker run?

Sorprendentemente, hay poco sobre esto en línea.

Dado el siguiente resultado de ejemplo de 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

Este libro de jugadas le dará una idea de cómo capturar los datos que necesita y cómo ejecutar acciones iterando en la lista proporcionada. Es un ejemplo muy sencillo, y tendrás que adaptarlo a tus necesidades. Eso es a propósito:

---- 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

Las partes interesantes son:

  1. Reúna la lista de contenedores en un host determinado (localhost en mi ejemplo).He usado una llanura shell invocación para poder usar awk para filtrar la salida. El resultado se almacena en un registro. Dado que la entrada es una lista, esto tendrá una consecuencia directa sobre cómo recuperar los datos, más adelante. Descomente el comentario debug tarea para comparar los datos almacenados en el registro con y sin una lista.

  2. Itere sobre los resultados del registro (ID del contenedor) y use el docker_container módulo para ejecutar una acción (command parámetro). Puedes usar links y volumes_from en tu docker_container invocación. Consulte la documentación en línea de el módulo para los detalles.

@thrig, esto debe aplicarse a los contenedores que se ejecutan en un sistema, no en varios. Si necesitara aplicar el comando a varios sistemas, simplemente usaría un inventario para lograrlo.

@techraf edited he editado la pregunta. Ahora incluye un signo de interrogación.

Entonces, en realidad, está solicitando una sintaxis de una tubería similar a`docker ps | grep my-image: latest | cut-f 1’?

No @techraf, es más eficiente usar docker ps filter filter en esa instancia. La pregunta es sobre la idempotencia y las mejores prácticas, ya que ejecutar lo anterior como comandos de shell no es idempotente. Habrías pensado que tendría más sentido usar la propia API de docker de Ansible para lograr esto, si es posible.

¿Qué tiene que ver la idempotencia con la consulta? Cualquier consulta. Por favor explique.

La idempotencia es un concepto importante con ansible, @techraf. Al ejecutar comandos de shell de forma ingenua utilizando ansible, perdemos la capacidad de evaluar si el sistema ha cumplido con los requisitos del libro de jugadas (y omitir la tarea) o no. Es por eso que siempre es recomendable ejecutar módulos API nativos de ansible en lugar de shell. El manual de Ansible indica, wrt to stdout_lines, no usarlo a menudo en esta cuenta.