¿Cómo ejecutar un script de shell en el host desde el contenedor de Docker?

94

¿Cómo controlar el host desde el contenedor Docker?

Por ejemplo, ¿cómo ejecutar el script de bash copiado en el host?

Alex Ushakov
fuente
8
¿No sería exactamente lo contrario de aislar el host de la ventana acoplable?
Marcus Müller
31
Si. Pero a veces es necesario.
Alex Ushakov
No estoy seguro sobre el "host de control", pero recientemente estuve en una charla de científicos de datos que están usando Docker para ejecutar scripts para procesar cargas de trabajo enormes (usando GPU montadas en AWS) y enviar el resultado al host. Un caso de uso muy interesante. Esencialmente scripts empaquetados con un entorno de ejecución confiable gracias a Docker
KCD
@KCD ¿Y por qué prefieren la contenedorización de aplicaciones a través de Docker en lugar de utilizar contenedores a nivel de sistema (LXC)?
Alex Ushakov

Respuestas:

28

¡Eso REALMENTE depende de lo que necesites que haga ese script bash!

Por ejemplo, si el script bash solo hace eco de alguna salida, puede hacer

docker run --rm -v $(pwd)/mybashscript.sh:/mybashscript.sh ubuntu bash /mybashscript.sh

Otra posibilidad es que desee que el script bash instale algún software, por ejemplo, el script para instalar docker-compose. podrías hacer algo como

docker run --rm -v /usr/bin:/usr/bin --privileged -v $(pwd)/mybashscript.sh:/mybashscript.sh ubuntu bash /mybashscript.sh

Pero en este punto, realmente está empezando a tener que saber íntimamente qué está haciendo el script para permitir los permisos específicos que necesita en su host desde el interior del contenedor.

Paul Becotte
fuente
1
Tuve la idea de hacer un contenedor que se conecta al host y crea nuevos contenedores.
Alex Ushakov
1
A Docker no parece gustarle tu montura relativa. Esto debería funcionardocker run --rm -v $(pwd)/mybashscript.sh:/work/mybashscript.sh ubuntu /work/mybashscript.sh
KCD
5
La primera línea inicia un nuevo contenedor de ubuntu y monta el script donde se puede leer. No permite que el contenedor acceda al sistema de archivos del host, por ejemplo. La segunda línea expone al anfitrión /usr/binal contenedor. En ningún caso, el contenedor tiene acceso completo al sistema host. Tal vez me equivoque, pero parece una mala respuesta a una mala pregunta.
Paul
3
Muy bien, la pregunta era bastante vaga. La pregunta no pedía "acceso completo al sistema host". Como se describió, si el script bash solo tiene la intención de hacer eco de alguna salida, no NECESITA ningún acceso al sistema de archivos del host. Para mi segundo ejemplo, que fue instalar docker-compose, el único permiso que necesita es acceder al directorio bin donde se almacena el binario. Como dije al principio, para hacer esto, tendría que tener ideas muy específicas sobre lo que está haciendo el script para permitir los permisos correctos.
Paul Becotte
1
Intenté esto, el script se ejecuta en el contenedor, no en el host
All2Pie
60

La solución que uso es conectarme al host SSHy ejecutar el comando de esta manera:

ssh -l ${USERNAME} ${HOSTNAME} "${SCRIPT}"

ACTUALIZAR

Como esta respuesta sigue recibiendo votos, me gustaría recordar (y lo recomiendo encarecidamente) que la cuenta que se está utilizando para invocar el script debe ser una cuenta sin ningún permiso, pero solo ejecutando ese script como sudo(eso puede ser hecho desde sudoersarchivo).

Mohammed Noureldin
fuente
Como otra solución, el contenedor podría generar un conjunto de comandos y el host podría ejecutarlos después de que el contenedor salga: eval $ (docker run --rm -it container_name_to_output script)
parity3
Necesito ejecutar una línea de comando en el Host desde dentro de un contenedor Docker, pero cuando entro al contenedor, sshno se encuentra. ¿Tiene alguna otra sugerencia?
Ron Rosenfeld
@RonRosenfeld, ¿qué imagen de Docker estás usando? en el caso de Debian / Ubuntu, ejecute lo siguiente: apt update && apt install openssh-client.
Mohammed Noureldin
Sería lo que esté instalado en mi Synology NAS. ¿Cómo puedo decir?
Ron Rosenfeld
@RonRosenfeld, lo siento, no entiendo lo que quieres decir
Mohammed Noureldin
52

Usó una tubería con nombre. En el sistema operativo host, cree un script para ejecutar y leer comandos, y luego llame a eval en eso.

Haga que el contenedor de la ventana acoplable lea en esa tubería con nombre.

Para poder acceder a la tubería, debe montarla a través de un volumen.

Esto es similar al mecanismo SSH (o un método basado en socket similar), pero lo restringe adecuadamente al dispositivo host, que probablemente sea mejor. Además, no tiene que pasar información de autenticación.

Mi única advertencia es que tenga cuidado con la razón por la que está haciendo esto. Es algo que debe hacer si desea crear un método para autoactualizarse con la entrada del usuario o lo que sea, pero probablemente no desee llamar a un comando para obtener algunos datos de configuración, ya que la forma correcta sería pasar eso como argumentos. / volume en la ventana acoplable. También tenga cuidado con el hecho de que está evaluando, así que solo piense en el modelo de permisos.

Algunas de las otras respuestas, como ejecutar un script. Bajo un volumen, no funcionarán de forma genérica ya que no tendrán acceso a todos los recursos del sistema, pero podría ser más apropiado según su uso.

Bradford Medeiros
fuente
14
ATENCIÓN: Esta es la respuesta correcta / mejor, y necesita un poco más de elogio. Todas las demás respuestas son jugar con preguntar "qué estás tratando de hacer" y hacer excepciones para algunas cosas. Tengo un caso de uso muy específico que requiere que pueda hacer esto, y esta es la única buena respuesta en mi humilde opinión. SSH anterior requeriría reducir los estándares de seguridad / firewall, y la función de ejecución de la ventana acoplable es simplemente incorrecta. Gracias por esto. Supongo que esto no recibe tantos votos positivos porque no es una respuesta simple de copiar / pegar, pero esta es la respuesta. +100 puntos míos si pudiera
Farley
3
Para aquellos que buscan más información, pueden usar el siguiente script que se ejecuta en la máquina host: unix.stackexchange.com/a/369465 Por supuesto, tendrá que ejecutarlo con 'nohup' y crear algún tipo de envoltorio supervisor para mantenerlo vivo (tal vez use un trabajo cron: P)
sucotronic
7
Esta puede ser una buena respuesta. Sin embargo, sería mucho mejor si proporcionara más detalles y una explicación más detallada de la línea de comandos. ¿Es posible elaborar?
Mohammed Noureldin
5
Upvoted, esto funciona! Cree una tubería con nombre usando 'mkfifo host_executor_queue' donde se monta el volumen. Luego, para agregar un consumidor que ejecute comandos que se colocan en la cola como shell del host, use 'tail -f host_executor_queue | sh & '. El & al final hace que se ejecute en segundo plano. Finalmente, para enviar comandos a la cola, use 'echo touch foo> host_executor_queue'; esta prueba crea un archivo temporal foo en el directorio de inicio. Si desea que el consumidor se inicie al iniciar el sistema, coloque '@reboot tail -f host_executor_queue | sh & 'en crontab. Simplemente agregue la ruta relativa a host_executor_queue.
Skybunk
1
¿Alguien podría editar la respuesta con un código de ejemplo?
Lucas Pottersky
6

Si no le preocupa la seguridad y simplemente está buscando iniciar un contenedor de la ventana acoplable en el host desde dentro de otro contenedor de la ventana acoplable como el OP, puede compartir el servidor de la ventana acoplable que se ejecuta en el host con el contenedor de la ventana acoplable compartiendo su socket de escucha.

Consulte https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface y vea si su tolerancia al riesgo personal lo permite para esta aplicación en particular.

Puede hacer esto agregando los siguientes argumentos de volumen a su comando de inicio

docker run -v /var/run/docker.sock:/var/run/docker.sock ...

o compartiendo /var/run/docker.sock dentro de su docker componga un archivo como este:

version: '3'

services:
   ci:
      command: ...
      image: ...
      volumes
         - /var/run/docker.sock:/var/run/docker.sock

Cuando ejecuta el comando de inicio de docker dentro de su contenedor de docker, el servidor de docker que se ejecuta en su host verá la solicitud y aprovisionará el contenedor hermano.

crédito: http://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/

Matt Bucci
fuente
1
Tenga en cuenta que la ventana acoplable debe estar instalada en el contenedor; de lo contrario, también deberá montar un volumen para el binario de la ventana acoplable (p /usr/bin/docker:/usr/bin/docker. Ej .).
Gerry
1
Tenga cuidado al montar el conector de la ventana acoplable en su contenedor, esto podría ser un problema de seguridad grave: docs.docker.com/engine/security/security/…
DatGuyKaj
@DatGuyKaj gracias, he editado mi respuesta para reflejar los problemas descritos en su recurso.
Matt Bucci
Esto no responde a la pregunta, que se trata de ejecutar un script en el host, no en un contenedor
Brandon
5

Esta respuesta es solo una versión más detallada de la solución de Bradford Medeiros , que para mí también resultó ser la mejor respuesta, por lo que el mérito es de él.

En su respuesta, explica QUÉ hacer ( tuberías con nombre ) pero no exactamente CÓMO hacerlo.

Tengo que admitir que no sabía qué se llaman tuberías en el momento en que leí su solución. Así que luché para implementarlo (aunque en realidad es realmente simple), pero tuve éxito, así que estoy feliz de ayudar explicando cómo lo hice. Entonces, el punto de mi respuesta es solo detallar los comandos que necesita ejecutar para que funcione, pero nuevamente, el crédito es para él.

PARTE 1: Prueba del concepto de tubería con nombre sin Docker

En el host principal, elija la carpeta donde desea colocar su archivo de /path/to/pipe/tubería con nombre, por ejemplo mypipe, y un nombre de tubería, por ejemplo , y luego ejecute:

mkfifo /path/to/pipe/mypipe

Se crea la tubería. Tipo

ls -l /path/to/pipe/mypipe 

Y compruebe que los derechos de acceso comienzan con "p", como

prw-r--r-- 1 root root 0 mypipe

Ahora ejecuta:

tail -f /path/to/pipe/mypipe

El terminal ahora está esperando que se envíen datos a esta tubería

Ahora abra otra ventana de terminal.

Y luego ejecuta:

echo "hello world" > /path/to/pipe/mypipe

Verifique la primera terminal (la que tiene tail -f), debería mostrar "hola mundo"

PARTE 2 - Ejecutar comandos a través de la tubería

En el contenedor del host, en lugar de ejecutar, tail -fque solo genera lo que se envía como entrada, ejecute este comando que lo ejecutará como comandos:

eval "$(cat /path/to/pipe/mypipe)"

Luego, desde la otra terminal, intente ejecutar:

echo "ls -l" > /path/to/pipe/mypipe

Regrese a la primera terminal y debería ver el resultado del ls -lcomando.

PARTE 3 - Haz que escuche para siempre

Es posible que haya notado que en la parte anterior, justo después de ls -lque se muestra la salida, deja de escuchar los comandos.

En lugar de eval "$(cat /path/to/pipe/mypipe)", ejecuta:

while true; do eval "$(cat /path/to/pipe/mypipe)"; done

(no puedes hacer eso)

Ahora puede enviar un número ilimitado de comandos uno tras otro, todos se ejecutarán, no solo el primero.

PARTE 4: haz que funcione incluso cuando se reinicia

La única advertencia es que si el host tiene que reiniciarse, el ciclo "while" dejará de funcionar.

Para manejar el reinicio, esto es lo que hice:

Ponlo while true; do eval "$(cat /path/to/pipe/mypipe)"; doneen un archivo llamado execpipe.shcon #!/bin/bashencabezado

No se olvide de chmod +xella

Agréguelo a crontab ejecutando

crontab -e

Y luego agregando

@reboot /path/to/execpipe.sh

En este punto, pruébelo: reinicie su servidor, y cuando esté respaldado, repita algunos comandos en la tubería y verifique si están ejecutados. Por supuesto, no puede ver el resultado de los comandos, por ls -llo que no ayudará, perotouch somefile ayudará.

Otra opción es modificar el script para colocar la salida en un archivo, como por ejemplo:

while true; do eval "$(cat /path/to/pipe/mypipe)" &> /somepath/output.txt; done

Ahora puede ejecutar ls -ly la salida (stdout y stderr usando&> en bash) debería estar en output.txt.

PARTE 5 - Haz que funcione con Docker

Si está utilizando docker compose y dockerfile como yo, esto es lo que hice:

Supongamos que desea montar la carpeta principal de mypipe como /hostpipeen su contenedor

Agrega esto:

VOLUME /hostpipe

en su dockerfile para crear un punto de montaje

Luego agrega esto:

volumes:
   - /path/to/pipe:/hostpipe

en su docker, componga el archivo para montar / ruta / a / tubería como / hostpipe

Reinicie sus contenedores Docker.

PARTE 6 - Prueba

Ejecutar en su contenedor Docker:

docker exec -it <container> bash

Vaya a la carpeta de montaje y compruebe que puede ver la tubería:

cd /hostpipe && ls -l

Ahora intente ejecutar un comando desde dentro del contenedor:

echo "touch this_file_was_created_on_main_host_from_a_container.txt" > /hostpipe/mypipe

¡Y debería funcionar!

ADVERTENCIA: Si tiene un host OSX (Mac OS) y un contenedor de Linux, no funcionará (explicación aquí https://stackoverflow.com/a/43474708/10018801 y problema aquí https://github.com/docker / for-mac / issues / 483 ) porque la implementación de la tubería no es la misma, por lo que lo que escribe en la tubería desde Linux solo puede ser leído por Linux y lo que escribe en la tubería desde Mac OS solo puede ser leído por un Mac OS (esta frase puede no ser muy precisa, pero tenga en cuenta que existe un problema multiplataforma).

Por ejemplo, cuando ejecuto la configuración de mi ventana acoplable en DEV desde mi computadora Mac OS, la tubería nombrada como se explicó anteriormente no funciona. Pero en la puesta en escena y la producción, tengo un host Linux y contenedores Linux, y funciona perfectamente.

PARTE 7 - Ejemplo del contenedor Node.JS

Así es como envío un comando desde mi contenedor node js al host principal y recupero el resultado:

const pipePath = "/hostpipe/mypipe"
const outputPath = "/hostpipe/output.txt"
const commandToRun = "pwd && ls-l"

console.log("delete previous output")
if (fs.existsSync(outputPath)) fs.unlinkSync(outputPath)

console.log("writing to pipe...")
const wstream = fs.createWriteStream(pipePath)
wstream.write(commandToRun)
wstream.close()

console.log("waiting for output.txt...") //there are better ways to do that than setInterval
let timeout = 10000 //stop waiting after 10 seconds (something might be wrong)
const timeoutStart = Date.now()
const myLoop = setInterval(function () {
    if (Date.now() - timeoutStart > timeout) {
        clearInterval(myLoop);
        console.log("timed out")
    } else {
        //if output.txt exists, read it
        if (fs.existsSync(outputPath)) {
            clearInterval(myLoop);
            const data = fs.readFileSync(outputPath).toString()
            if (fs.existsSync(outputPath)) fs.unlinkSync(outputPath) //delete the output file
            console.log(data) //log the output of the command
        }
    }
}, 300);
Vincent
fuente
Esto funciona muy bien. ¿Y la seguridad? ¿Quiero usar esto para iniciar / detener contenedores Docker desde dentro de un contenedor en ejecución? ¿Simplemente hago un dockeruser sin ningún privilegio, excepto para ejecutar comandos de docker?
Kristof van Woensel
4

Escriba un servidor python simple escuchando en un puerto (digamos 8080), vincule el puerto -p 8080: 8080 con el contenedor, haga una solicitud HTTP a localhost: 8080 para pedirle al servidor Python que ejecute scripts de shell con popen, ejecute un curl o escribiendo código para hacer una solicitud HTTP curl -d '{"foo": "bar"}' localhost: 8080

#!/usr/bin/python
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
import subprocess
import json

PORT_NUMBER = 8080

# This class will handles any incoming request from
# the browser 
class myHandler(BaseHTTPRequestHandler):
        def do_POST(self):
                content_len = int(self.headers.getheader('content-length'))
                post_body = self.rfile.read(content_len)
                self.send_response(200)
                self.end_headers()
                data = json.loads(post_body)

                # Use the post data
                cmd = "your shell cmd"
                p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
                p_status = p.wait()
                (output, err) = p.communicate()
                print "Command output : ", output
                print "Command exit status/return code : ", p_status

                self.wfile.write(cmd + "\n")
                return
try:
        # Create a web server and define the handler to manage the
        # incoming request
        server = HTTPServer(('', PORT_NUMBER), myHandler)
        print 'Started httpserver on port ' , PORT_NUMBER

        # Wait forever for incoming http requests
        server.serve_forever()

except KeyboardInterrupt:
        print '^C received, shutting down the web server'
        server.socket.close()
Frank Chang
fuente
En mi opinión, esta es la mejor respuesta. La ejecución de comandos arbitrarios en la máquina host DEBE realizarse a través de algún tipo de API (por ejemplo, REST). Esta es la única forma en que se puede aplicar la seguridad y los procesos en ejecución pueden controlarse adecuadamente (por ejemplo, matar, manejar stdin, stdout, código de salida, etc.). Por supuesto, sería bonito si esta API pudiera ejecutarse dentro de Docker, pero personalmente no me importa ejecutarla directamente en el host.
barney765
2

Mi pereza me llevó a encontrar la solución más fácil que no se publicó como respuesta aquí.

Está basado en el gran artículo de luc juggery .

Todo lo que necesita hacer para obtener un shell completo para su host Linux desde dentro de su contenedor Docker es:

docker run --privileged --pid=host -it alpine:3.8 \
nsenter -t 1 -m -u -n -i sh

Explicación:

--privileged: otorga permisos adicionales al contenedor, permite que el contenedor obtenga acceso a los dispositivos del host (/ dev)

--pid = host: permite que los contenedores usen el árbol de procesos del host de Docker (la máquina virtual en la que se ejecuta el demonio de Docker) Utilidad nsenter: permite ejecutar un proceso en espacios de nombres existentes (los bloques de construcción que proporcionan aislamiento a los contenedores)

nsenter (-t 1 -m -u -n -i sh) permite ejecutar el proceso sh en el mismo contexto de aislamiento que el proceso con PID 1. Todo el comando proporcionará un shell sh interactivo en la VM

Esta configuración tiene importantes implicaciones de seguridad y debe usarse con precauciones (si corresponde).

Shmulik ahituv
fuente
1
docker run --detach-keys="ctrl-p" -it -v /:/mnt/rootdir --name testing busybox
# chroot /mnt/rootdir
# 
Zibri
fuente
3
Si bien esta respuesta podría resolver la pregunta del OP, se sugiere que explique cómo funciona y por qué resuelve el problema. Esto ayuda a los nuevos desarrolladores a comprender lo que está sucediendo y cómo solucionar este y otros problemas similares por sí mismos. ¡Gracias por contribuir!
Caleb Kleveter
1

Tengo un enfoque simple.

Paso 1: Monte /var/run/docker.sock:/var/run/docker.sock (para que pueda ejecutar comandos de docker dentro de su contenedor)

Paso 2: Ejecute esto a continuación dentro de su contenedor. La parte clave aquí es ( - host de red, ya que se ejecutará desde el contexto del host)

docker ejecutar -i --rm --network host -v /opt/test.sh:/test.sh alpine: 3.7 sh /test.sh

test.sh debe contener algunos comandos (ifconfig, netstat, etc.) lo que necesite. Ahora podrá obtener la salida del contexto del host.

Bala
fuente
2
Según la documentación oficial de Docker sobre redes que utilizan la red de host, "Sin embargo, en todas las demás formas, como el almacenamiento, el espacio de nombres de procesos y el espacio de nombres de usuarios, el proceso está aislado del host". Salida - docs.docker.com/network/network-tutorial-host
Peter Mutisya
0

Como recuerda Marcus, la ventana acoplable es básicamente un proceso de aislamiento. A partir de la ventana acoplable 1.8, puede copiar archivos en ambos sentidos entre el host y el contenedor, consulte el documento dedocker cp

https://docs.docker.com/reference/commandline/cp/

Una vez que se copia un archivo, puede ejecutarlo localmente

usuario2915097
fuente
1
Lo sé. ¿Cómo ejecutar este script desde, en otras palabras, dentro del contenedor docker?
Alex Ushakov
1
duplicado de stackoverflow.com/questions/31720935/… ?
user2915097
2
@AlexUshakov: de ninguna manera. Hacer eso rompería muchas de las ventajas de Docker. No lo hagas. No lo intentes. Reconsidere lo que necesita hacer.
Marcus Müller
Ver también el truco de Vlad foros.docker.com/t/…
user2915097
1
siempre puede, en el host, obtener el valor de alguna variable en su contenedor, algo así como myvalue=$(docker run -it ubuntu echo $PATH)y probarlo regularmente en un shell de script (por supuesto, usará algo más que $ PATH, solo es un ejemplo), cuando es un valor específico,
inicia
0

Puede usar el concepto de tubería, pero use un archivo en el host y fswatch para lograr el objetivo de ejecutar un script en la máquina host desde un contenedor docker. Así (use bajo su propio riesgo):

#! /bin/bash

touch .command_pipe
chmod +x .command_pipe

# Use fswatch to execute a command on the host machine and log result
fswatch -o --event Updated .command_pipe | \
            xargs -n1 -I "{}"  .command_pipe >> .command_pipe_log  &

 docker run -it --rm  \
   --name alpine  \
   -w /home/test \
   -v $PWD/.command_pipe:/dev/command_pipe \
   alpine:3.7 sh

rm -rf .command_pipe
kill %1

En este ejemplo, dentro del contenedor, envíe comandos a / dev / command_pipe, así:

/home/test # echo 'docker network create test2.network.com' > /dev/command_pipe

En el host, puede verificar si se creó la red:

$ docker network ls | grep test2
8e029ec83afe        test2.network.com                            bridge              local
Fábio Silva
fuente
-7

Para ampliar la respuesta del usuario 2915097 :

La idea del aislamiento es poder restringir lo que una aplicación / proceso / contenedor (cualquiera que sea su ángulo en esto) puede hacer al sistema host de manera muy clara. Por lo tanto, poder copiar y ejecutar un archivo realmente rompería todo el concepto.

Si. Pero a veces es necesario.

No. Ese no es el caso, o Docker no es lo correcto para usar. Lo que debe hacer es declarar una interfaz clara para lo que desea hacer (por ejemplo, actualizar una configuración de host) y escribir un cliente / servidor mínimo para hacer exactamente eso y nada más. Generalmente, sin embargo, esto no parece ser muy deseable. En muchos casos, simplemente debe repensar su enfoque y erradicar esa necesidad. Docker nació cuando básicamente todo era un servicio al que se podía acceder mediante algún protocolo. No puedo pensar en ningún caso de uso adecuado de un contenedor Docker que obtenga los derechos para ejecutar cosas arbitrarias en el host.

Marcus Müller
fuente
Tengo un caso de uso: tengo un servicio dockerizado A(src en github). En el Arepositorio, creo los ganchos adecuados que, después del comando 'git pull', crean una nueva imagen de la ventana acoplable y los ejecutan (y eliminan el contenedor antiguo, por supuesto). Siguiente: github tiene web-hooks que permiten crear una solicitud POST a un enlace de punto final arbitrario después de presionar el maestro. Por lo tanto, no crearé el servicio B acoplado, que será ese punto final y que solo ejecutará 'git pull' en el repositorio A en la máquina HOST (importante: el comando 'git pull' debe ejecutarse en el entorno HOST, no en el entorno B porque B no se puede ejecutar un nuevo contenedor A dentro de B ...)
Kamil Kiełczewski
1
El problema: no quiero tener nada en HOST excepto linux, git y docker. Y quiero tener el servicio A y el servicio B de dockerizet (que de hecho es un controlador de git-push que ejecuta git pull en el repositorio A después de que alguien haga git push en el maestro). Así que la implementación automática de git es un caso de uso problemático
Kamil Kiełczewski
@ KamilKiełczewski Estoy tratando de hacer exactamente lo mismo, ¿has encontrado una solución?
user871784
1
Decir "No, ese no es el caso" es una actitud estrecha y supone que conoce todos los casos de uso del mundo. Nuestro caso de uso está ejecutando pruebas. Deben ejecutarse en contenedores para probar correctamente el entorno, pero dada la naturaleza de las pruebas, también deben ejecutar scripts en el host.
Senica Gonzalez
1
Solo para aquellos que se preguntan por qué dejo una respuesta de -7: a) está bien ser falible. Estaba equivocado. Está bien que esto esté documentado aquí. b) Los comentarios realmente aportan valor; eliminar la respuesta los eliminaría también. c) Aún aporta un punto de vista que sería prudente considerar (no rompa su aislamiento si no es necesario. Sin embargo, a veces es necesario).
Marcus Müller