Comment générer un Dockerfile à partir d'une image?

241

Est-il possible de générer un Dockerfile à partir d'une image? Je veux savoir pour deux raisons:

  1. Je peux télécharger des images à partir du référentiel mais j'aimerais voir la recette qui les a générées.

  2. J'aime l'idée de sauvegarder des instantanés, mais une fois que j'aurai terminé, ce serait bien d'avoir un format structuré pour revoir ce qui a été fait.

user1026169
la source
Vous pouvez utiliser Portainer.io portainer.io Il s'agit d'une application Web qui s'exécute à l'intérieur d'un conteneur Docker utilisé pour gérer toutes (presque) les informations concernant vos conteneurs. Même les images sont reçues.
Vincent

Réponses:

98

Comment générer ou inverser un Dockerfile à partir d'une image?

Vous pouvez.

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

Il tirera automatiquement l'image de docker cible et l'exportera Dockerfile. Le paramètre -sV=1.36n'est pas toujours requis.

Référence: https://hub.docker.com/repository/docker/alpine/dfimage

ci-dessous est l'ancienne réponse, cela ne fonctionne plus.

$ 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
la source
3
Il s'agit de la méthode Docker et doit être marquée comme réponse choisie.
kytwb
2
@jenson ce n'est pas exactement pareil, peut couvrir 95%. Mais ne fonctionne pas avec une image écrasée.
BMW
5
@BMW Pourriez-vous s'il vous plaît aider à résoudre ce problème en exécutant l'image à partir de votre exemple? /usr/lib/ruby/gems/2.2.0/gems/excon-0.45.4/lib/excon/unix_socket.rb:14:in `connect_nonblock ': connexion refusée - connect (2) pour / var / run / docker .sock (Errno :: ECONNREFUSED) (Excon :: Errors :: SocketError)
long
8
centurylink / dockerfile-from-image ne fonctionne pas avec la nouvelle version docker. Celui-ci fonctionne pour moi: hub.docker.com/r/chenzj/dfimage
aleung
6
imagelayers.io semble être cassé. Il ne trouve aucune image, y compris ses images de démonstration
Robert Lugg
165

Pour comprendre comment une image docker a été créée, utilisez la docker history --no-trunccommande.

Vous pouvez créer un fichier Docker à partir d'une image, mais il ne contiendra pas tout ce que vous souhaitez pour comprendre pleinement comment l'image a été générée. Vous pouvez raisonnablement extraire les parties MAINTAINER, ENV, EXPOSE, VOLUME, WORKDIR, ENTRYPOINT, CMD et ONBUILD du dockerfile.

Le script suivant devrait fonctionner pour vous:

#!/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"

J'utilise cela dans le cadre d'un script pour reconstruire des conteneurs en cours d'exécution sous forme d'images: https://github.com/docbill/docker-scripts/blob/master/docker-rebase

Le Dockerfile est principalement utile si vous souhaitez pouvoir reconditionner une image.

La chose à garder à l'esprit est qu'une image de docker peut en fait être la sauvegarde tar d'une machine réelle ou virtuelle. J'ai fait plusieurs images de docker de cette façon. Même l'historique de construction me montre l'importation d'un énorme fichier tar comme première étape dans la création de l'image ...

user6856
la source
1
Il m'obtient: json: impossible de démêler le tableau dans la valeur Go des types de types.ContainerJSON
Mohsen
Pouvez-vous décrire votre dernier commentaire plus en détail? Tout est-il / juste taré comme d'habitude? Ou existe-t-il des cas particuliers?
Robert Lugg
Je pense que c'est une réponse de 6 ans, mais je reçoisError response from daemon: page not found
João Ciocca
53

D'une manière ou d'une autre, j'ai absolument manqué la commande réelle dans la réponse acceptée, alors la voici encore, un peu plus visible dans son propre paragraphe, pour voir combien de personnes sont comme moi

$ docker history --no-trunc <IMAGE_ID>
user7610
la source
1
Alors pourquoi avons-nous besoin ub.docker.com/r/chenzj/dfimage? C'est même une réponse plus récente.
lucid_dreamer
3
Je suppose que car docker historyimprime les lignes Dockerfile dans un ordre inverse et laisse tomber les RUNinstructions (vous obtenez uniquement la commande elle-même, pas le RUNkeyworkd en face d'elle) et d'autres choses, vous devez donc le modifier manuellement pour accéder à un Dockerfile à construire. Cet autre outil peut effectuer cette modification automatiquement pour vous (je ne l'ai pas essayé, donc je ne sais pas.)
user7610
@ user7610 votre commande affiche simplement l'historique de l'image extraite du hub. Comment puis-je voir mes commandes sur les images Docker?
BarzanHayati
@BarzanHayati Pouvez-vous la poser comme une nouvelle question et la lier ici? Soyez très précis lorsque vous demandez. Affichez la commande pour démarrer l'image, puis exécutez certaines commandes que vous souhaitez voir ultérieurement, à titre d'exemple, puis arrêtez le conteneur (si c'est ce que vous faites réellement), puis demandez comment récupérer les commandes émises. Merci.
user7610
1
@ user7610 Je pourrais la poser, mais dès que je la pose, je dois la supprimer car les autres utilisateurs me donnent moins de points pour les questions répétées.
BarzanHayati
35

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

Explications étape par étape:

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)

Exemple:

 ~  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
la source
1
La solution la plus simple. Je vous remercie!
user3576508
Cela n'ajoute pas de barre oblique inversée de fin lorsqu'elle décompose des instructions RUN multilignes. J'ai ajouté ma propre réponse inspirée de cela.
Scott Centoni
tac n'est pas disponible sur mac, vous pouvez donc opter pour awk comme ci-dessous: | awk '{print NR, $ 0}' | sort -nr | sed 's / ^ [0-9] * //' |
phulei
11

Ce n'est pas possible à ce stade (sauf si l'auteur de l'image a explicitement inclus le Dockerfile).

Cependant, c'est définitivement quelque chose d'utile! Il y a deux choses qui aideront à obtenir cette fonctionnalité.

  1. Constructions approuvées (détaillées dans cette discussion docker-dev
  2. Des métadonnées plus détaillées dans les images successives produites par le processus de construction. À long terme, les métadonnées devraient indiquer quelle commande de génération a produit l'image, ce qui signifie qu'il sera possible de reconstruire le Dockerfile à partir d'une séquence d'images.
jpetazzo
la source
8

Mise à jour de décembre 2018 à la réponse 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
la source
6

Ceci est dérivé de la réponse de @ fallino, avec quelques ajustements et simplifications en utilisant l'option de format de sortie pour l' historique du docker . Étant donné que macOS et Gnu / Linux ont des utilitaires de ligne de commande différents, une version différente est nécessaire pour Mac. Si vous n'avez besoin que de l'un ou de l'autre, vous pouvez simplement utiliser ces lignes.

#!/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
la source
5

docker pull chenzj/dfimage


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

dfimage image_id

ci-dessous est sortie de la commande dfimage: -

$ dfimage 0f1947a021ce

DU NŒUD: 8 WORKDIR / usr / src / app

Fichier COPY: e76d2e84545dedbe901b7b7b0c8d2c9733baa07cc821054efec48f623e29218c in ./

Installation de RUN / bin / sh -c npm

COPY dir: a89a4894689a38cbf3895fdc0870878272bb9e09268149a87a6974a274b2184a in.

EXPOSE 8080

CMD ["npm" "start"]

user128364
la source