Ejecutar comandos dentro de un contenedor Docker es más fácil de lo que piensa.

Un contenedor docker es un entorno aislado que suele contener una única aplicación con todas las dependencias necesarias. Muchas veces necesitamos ejecutar algunos comandos dentro de un contenedor docker. Hay varias maneras en las que podemos ejecutar un comando dentro de un contenedor y obtener la salida requerida.

Veamos cómo podemos hacerlo.

Usando el shell interactivo

Podemos acceder directamente al shell de un contenedor y ejecutar nuestros comandos como con un terminal Linux normal. Para obtener un shell interactivo de un contenedor detenido (no en estado de ejecución), puede utilizar:

$ docker run -it ubuntu bash
root@c520631f652d:/#

Como puede ver, aterrizamos directamente dentro de un nuevo contenedor Ubuntu donde podemos ejecutar nuestros comandos. Si un contenedor ya se está ejecutando, puede utilizar el comando exec como se indica a continuación.

Primero, averigüemos el ID del contenedor.

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c2d969adde7a nginx "/docker-entrypoint...." hace 2 horas Arriba 2 horas 127.0.0.1:80->80/tcp nginx
0960560bc24b mariadb "docker-entrypoint.s..." hace 2 horas Arriba 2 horas 127.0.0.1:3306->3306/tcp mariadb

Y, a continuación, entrar en el contenedor ID c2d969adde7a

$ docker exec -it c2d969adde7a bash 
root@c2d969adde7a:/#

En la salida anterior, puede observar que iniciamos una sesión bash del contenedor nginx que estaba en estado de ejecución. Aquí podemos ejecutar cualquier comando soportado y obtener la salida.

Nota – su contenedor puede no tener bash y si es así, puede utilizar sh.

Ej:

docker exec -it c2d969adde7a sh

Salida directa

A menudo sólo necesitamos la salida de uno o dos comandos y no necesitamos una sesión interactiva completa para nuestra tarea. Puede ejecutar el comando requerido dentro de un contenedor y obtener su salida directamente sin abrir una nueva sesión de shell utilizando el comando exec sin la bandera -it. Su sintaxis sería

$ docker exec <id o nombre del contenedor> <comando>

He aquí un ejemplo:

$ docker ps
ID CONTENEDOR IMAGEN COMANDO CREADO ESTADO PUERTOS NOMBRES
c2d969adde7a nginx "/docker-entrypoint...." hace 2 horas Arriba 2 horas 127.0.0.1:80->80/tcp nginx
0960560bc24b mariadb "docker-entrypoint.s..." hace 2 horas Arriba 2 horas 127.0.0.1:3306->3306/tcp mariadb

$ docker exec 0960560bc24b ps -ef | grep mysql
mysql 1 0 0 13:35 ?        00:00:02 mysqld
$

Ejecutamos el comando ps -ef | grep mysql dentro del contenedor MariaDB en ejecución y obtenemos la salida directamente.

Manera Dockerfile

Esta no es la forma exacta en que puede ejecutar comandos dentro de un contenedor docker, aunque puede ser útil en situaciones de desarrollo o para la depuración de despliegue inicial, etc. Podemos utilizar el comando RUN dentro de un Dockerfile. Aquí está nuestro Dockerfile de ejemplo:

FROM nginx:latest
EJECUTAR nginx -V

Simplemente extrae la última imagen de nginx del registro y luego ejecuta el comando nginx - V para mostrar la versión de Nginx al construir la imagen.

$ docker build -t nginx-test .
Envío del contexto de compilación al demonio Docker 2.048kB
Paso 1/2 : FROM nginx:latest
 --->
 7ce4f91ef623
Paso 2/2 : EJECUTAR nginx -V
 --->
 Ejecutando en 43918bbbeaa5
versión de nginx: nginx/1.19.9
construido con gcc 8.3.0 (Debian 8.3.0-6)
construido con OpenSSL 1.1.1d 10 Sep 2019
Soporte TLS SNI habilitado
configurar argumentos: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fdebug-prefix-map=/data/builder/debuild/nginx-1.19.9/debian/debuild-base/nginx-1.19.9=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie'
Eliminando el contenedor intermedio 43918bbbeaa5
 --->
 d682277f2e50
Construido con éxito d682277f2e50
Etiquetado con éxito nginx-test:latest
$

Observe la salida del comando RUN en el fragmento anterior. El fragmento anterior sólo se mostrará en la primera compilación y las compilaciones consecutivas no repetirán la salida del comando RUN. Como solución alternativa, puede probar la bandera --no-cache:

$ docker build -t nginx-test . --no-cache

El último método no es la mejor manera, pero a veces puede ser útil para la depuración, etc.

Resumen

Ejecutar un comando dentro de un contenedor Docker es simple y hay algunos métodos disponibles para hacerlo. Es una tarea habitual de un administrador Docker, por lo que conocer estos comandos es útil.

More on Docker