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:
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?
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:
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.
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.
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.
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.