¿Cómo generar un Dockerfile a partir de una imagen?

241

¿Es posible generar un Dockerfile a partir de una imagen? Quiero saber por dos razones:

  1. Puedo descargar imágenes del repositorio pero me gustaría ver la receta que las generó.

  2. Me gusta la idea de guardar instantáneas, pero una vez que haya terminado, sería bueno tener un formato estructurado para revisar lo que se hizo.

usuario1026169
fuente
Puede usar Portainer.io portainer.io Es una aplicación web que se ejecuta dentro de un contenedor acoplable utilizado para administrar todas (casi) cosas sobre sus contenedores. Incluso imágenes recepciones.
Vincent

Respuestas:

98

¿Cómo generar o revertir un Dockerfile desde una imagen?

Usted puede.

alias dfimage="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm alpine/dfimage"
dfimage -sV=1.36 nginx:latest

Extraerá automáticamente la imagen del acoplador de destino y la exportará Dockerfile. El parámetro -sV=1.36no siempre es obligatorio.

Referencia: https://hub.docker.com/repository/docker/alpine/dfimage

a continuación se muestra la respuesta anterior, ya no funciona.

$ docker pull centurylink/dockerfile-from-image
$ alias dfimage="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm centurylink/dockerfile-from-image"
$ dfimage --help
Usage: dockerfile-from-image.rb [options] <image_id>
    -f, --full-tree                  Generate Dockerfile for all parent layers
    -h, --help                       Show this message
BMW
fuente
3
Esta es la forma Docker y debe marcarse como respuesta elegida.
kytwb
2
@jenson no es exactamente lo mismo, puede cubrir el 95%. Pero no funciona con la imagen aplastada.
BMW
55
@BMW ¿Podría ayudarme a resolver este problema al ejecutar la imagen de su ejemplo? /usr/lib/ruby/gems/2.2.0/gems/excon-0.45.4/lib/excon/unix_socket.rb:14:in `connect_nonblock ': conexión rechazada - connect (2) para / var / run / docker .sock (Errno :: ECONNREFUSED) (Excon :: Errores :: SocketError)
largo
8
centurylink / dockerfile-from-image no funciona con la nueva versión docker. Este funciona para mí: hub.docker.com/r/chenzj/dfimage
aleung
66
imagelayers.io parece estar roto. No puede encontrar ninguna imagen, incluidas las de demostración
Robert Lugg
165

Para comprender cómo se creó una imagen acoplable, use el docker history --no-trunccomando

Puede crear un archivo acoplable a partir de una imagen, pero no contendrá todo lo que desee para comprender completamente cómo se generó la imagen. Razonablemente, lo que puede extraer son las partes MAINTAINER, ENV, EXPOSE, VOLUME, WORKDIR, ENTRYPOINT, CMD y ONBUILD del dockerfile.

El siguiente script debería funcionar para usted:

#!/bin/bash
docker history --no-trunc "$1" | \
sed -n -e 's,.*/bin/sh -c #(nop) \(MAINTAINER .*[^ ]\) *0 B,\1,p' | \
head -1
docker inspect --format='{{range $e := .Config.Env}}
ENV {{$e}}
{{end}}{{range $e,$v := .Config.ExposedPorts}}
EXPOSE {{$e}}
{{end}}{{range $e,$v := .Config.Volumes}}
VOLUME {{$e}}
{{end}}{{with .Config.User}}USER {{.}}{{end}}
{{with .Config.WorkingDir}}WORKDIR {{.}}{{end}}
{{with .Config.Entrypoint}}ENTRYPOINT {{json .}}{{end}}
{{with .Config.Cmd}}CMD {{json .}}{{end}}
{{with .Config.OnBuild}}ONBUILD {{json .}}{{end}}' "$1"

Lo uso como parte de un script para reconstruir contenedores en ejecución como imágenes: https://github.com/docbill/docker-scripts/blob/master/docker-rebase

El Dockerfile es principalmente útil si desea poder reempaquetar una imagen.

Lo que hay que tener en cuenta es que una imagen acoplable en realidad puede ser solo el respaldo de alquitrán de una máquina real o virtual. He hecho varias imágenes de docker de esta manera. Incluso el historial de compilación me muestra la importación de un gran archivo tar como primer paso para crear la imagen ...

usuario6856
fuente
1
Me consigue: json: no se puede desarmar la matriz en el valor Go de los tipos de tipos.ContainerJSON
Mohsen
¿Puedes describir tu último comentario con mayor detalle? ¿Está todo en / simplemente alquitranado como de costumbre? ¿O hay casos especiales?
Robert Lugg
Creo que esta es una respuesta de 6 años, pero estoy obteniendoError response from daemon: page not found
João Ciocca
53

De alguna manera me perdí absolutamente el comando real en la respuesta aceptada, así que aquí está de nuevo, un poco más visible en su propio párrafo, para ver cuántas personas son como yo

$ docker history --no-trunc <IMAGE_ID>
user7610
fuente
1
Entonces, ¿por qué necesitamos ub.docker.com/r/chenzj/dfimage? Es incluso una respuesta más reciente.
lucid_dreamer
3
Supongo que porque docker historyimprime las líneas de Dockerfile en orden inverso y deja caer las RUNinstrucciones (solo obtienes el comando en sí, no el RUNteclado delante) y otras cosas, por lo que debes editarlo manualmente para llegar a un Dockerfile edificable. Esa otra herramienta puede hacer esto editando de forma automática para usted (yo no lo probamos, así que no sé.)
user7610
@ user7610 su comando solo muestra el historial de la imagen extraída del concentrador. ¿Cómo podría ver mis comandos en las imágenes de la ventana acoplable?
BarzanHayati
@BarzanHayati ¿Puedes hacer una nueva pregunta y vincularla aquí? Sé muy específico cuando preguntes. Muestre el comando para iniciar la imagen, luego emita algunos comandos que desee ver más adelante, como ejemplo, luego detenga el contenedor (si eso es lo que realmente hace en realidad) y luego pregunte cómo recuperar los comandos emitidos. Gracias.
usuario7610
1
@ user7610 Podría preguntarlo, pero tan pronto como lo solicite, debo eliminarlo porque otros usuarios me dan puntos negativos por preguntas repetidas.
BarzanHayati
35

Una solución bash:

docker history --no-trunc $argv  | tac | tr -s ' ' | cut -d " " -f 5- | sed 's,^/bin/sh -c #(nop) ,,g' | sed 's,^/bin/sh -c,RUN,g' | sed 's, && ,\n  & ,g' | sed 's,\s*[0-9]*[\.]*[0-9]*\s*[kMG]*B\s*$,,g' | head -n -1

Explicaciones paso a paso:

tac : reverse the file
tr -s ' '                                       trim multiple whitespaces into 1
cut -d " " -f 5-                                remove the first fields (until X months/years ago)
sed 's,^/bin/sh -c #(nop) ,,g'                  remove /bin/sh calls for ENV,LABEL...
sed 's,^/bin/sh -c,RUN,g'                       remove /bin/sh calls for RUN
sed 's, && ,\n  & ,g'                           pretty print multi command lines following Docker best practices
sed 's,\s*[0-9]*[\.]*[0-9]*\s*[kMG]*B\s*$,,g'      remove layer size information
head -n -1                                      remove last line ("SIZE COMMENT" in this case)

Ejemplo:

 ~  dih ubuntu:18.04
ADD file:28c0771e44ff530dba3f237024acc38e8ec9293d60f0e44c8c78536c12f13a0b in /
RUN set -xe
   &&  echo '#!/bin/sh' > /usr/sbin/policy-rc.d
   &&  echo 'exit 101' >> /usr/sbin/policy-rc.d
   &&  chmod +x /usr/sbin/policy-rc.d
   &&  dpkg-divert --local --rename --add /sbin/initctl
   &&  cp -a /usr/sbin/policy-rc.d /sbin/initctl
   &&  sed -i 's/^exit.*/exit 0/' /sbin/initctl
   &&  echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup
   &&  echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean
   &&  echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean
   &&  echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean
   &&  echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages
   &&  echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes
   &&  echo 'Apt::AutoRemove::SuggestsImportant "false";' > /etc/apt/apt.conf.d/docker-autoremove-suggests
RUN rm -rf /var/lib/apt/lists/*
RUN sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list
RUN mkdir -p /run/systemd
   &&  echo 'docker' > /run/systemd/container
CMD ["/bin/bash"]
fallino
fuente
1
La solución más sencilla. ¡Gracias!
user3576508
Esto no agrega una barra invertida final cuando divide las instrucciones RUN multilínea. He añadido mi propia respuesta inspirada por esto.
Scott Centoni
tac no está disponible en mac, por lo que puede ir a awk como a continuación: | awk '{print NR, $ 0}' | sort -nr | sed 's / ^ [0-9] * //' |
Phulei
11

No es posible en este momento (a menos que el autor de la imagen incluya explícitamente el Dockerfile).

Sin embargo, definitivamente es algo útil. Hay dos cosas que ayudarán a obtener esta función.

  1. Compilaciones de confianza (detalladas en esta discusión de docker-dev
  2. Metadatos más detallados en las sucesivas imágenes producidas por el proceso de construcción. A la larga, los metadatos deberían indicar qué comando de compilación produjo la imagen, lo que significa que será posible reconstruir el Dockerfile a partir de una secuencia de imágenes.
jpetazzo
fuente
8

Actualización de diciembre de 2018 a la respuesta de BMW

docker pull chenzj/dfimage
alias dfimage="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm chenzj/dfimage"
dfimage IMAGE_ID > Dockerfile
AndrewD
fuente
6

Esto se deriva de la respuesta de @ fallino, con algunos ajustes y simplificaciones mediante el uso de la opción de formato de salida para el historial del acoplador . Como macOS y Gnu / Linux tienen diferentes utilidades de línea de comandos, es necesaria una versión diferente para Mac. Si solo necesita uno u otro, puede usar esas líneas.

#!/bin/bash
case "$OSTYPE" in
    linux*)
        docker history --no-trunc --format "{{.CreatedBy}}" $1 | # extract information from layers
        tac                                                    | # reverse the file
        sed 's,^\(|3.*\)\?/bin/\(ba\)\?sh -c,RUN,'             | # change /bin/(ba)?sh calls to RUN
        sed 's,^RUN #(nop) *,,'                                | # remove RUN #(nop) calls for ENV,LABEL...
        sed 's,  *&&  *, \\\n \&\& ,g'                           # pretty print multi command lines following Docker best practices
    ;;
    darwin*)
        docker history --no-trunc --format "{{.CreatedBy}}" $1 | # extract information from layers
        tail -r                                                | # reverse the file
        sed -E 's,^(\|3.*)?/bin/(ba)?sh -c,RUN,'               | # change /bin/(ba)?sh calls to RUN
        sed 's,^RUN #(nop) *,,'                                | # remove RUN #(nop) calls for ENV,LABEL...
        sed $'s,  *&&  *, \\\ \\\n \&\& ,g'                      # pretty print multi command lines following Docker best practices
    ;;
    *)
        echo "unknown OSTYPE: $OSTYPE"
    ;;
esac
Scott Centoni
fuente
5

docker pull chenzj/dfimage


alias dfimage="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm chenzj/dfimage"

dfimage image_id

a continuación se muestra la salida del comando dfimage: -

$ dfimage 0f1947a021ce

DESDE nodo: 8 WORKDIR / usr / src / app

COPIAR archivo: e76d2e84545dedbe901b7b7b0c8d2c9733baa07cc821054efec48f623e29218c in ./

RUN / bin / sh -c npm install

COPY dir: a89a4894689a38cbf3895fdc0870878272bb9e09268149a87a6974a274b2184a in.

EXPOSE 8080

CMD ["npm" "inicio"]

usuario128364
fuente