Skip to content

Instantly share code, notes, and snippets.

@efrecon
Last active April 19, 2026 21:27
Show Gist options
  • Select an option

  • Save efrecon/8ce9c75d518b6eb863f667442d7bc679 to your computer and use it in GitHub Desktop.

Select an option

Save efrecon/8ce9c75d518b6eb863f667442d7bc679 to your computer and use it in GitHub Desktop.
`docker inspect` template to regenerate the `docker run` command that created a container
docker run \
--name {{printf "%q" .Name}} \
{{- with .HostConfig}}
{{- if .Privileged}}
--privileged \
{{- end}}
{{- if .AutoRemove}}
--rm \
{{- end}}
{{- if .Runtime}}
--runtime {{printf "%q" .Runtime}} \
{{- end}}
{{- range $b := .Binds}}
--volume {{printf "%q" $b}} \
{{- end}}
{{- range $v := .VolumesFrom}}
--volumes-from {{printf "%q" $v}} \
{{- end}}
{{- range $l := .Links}}
--link {{printf "%q" $l}} \
{{- end}}
{{- if index . "Mounts"}}
{{- range $m := .Mounts}}
--mount type={{.Type}}
{{- if $s := index $m "Source"}},source={{$s}}{{- end}}
{{- if $t := index $m "Target"}},destination={{$t}}{{- end}}
{{- if index $m "ReadOnly"}},readonly{{- end}}
{{- if $vo := index $m "VolumeOptions"}}
{{- range $i, $v := $vo.Labels}}
{{- printf ",volume-label=%s=%s" $i $v}}
{{- end}}
{{- if $dc := index $vo "DriverConfig" }}
{{- if $n := index $dc "Name" }}
{{- printf ",volume-driver=%s" $n}}
{{- end}}
{{- range $i, $v := $dc.Options}}
{{- printf ",volume-opt=%s=%s" $i $v}}
{{- end}}
{{- end}}
{{- end}}
{{- if $bo := index $m "BindOptions"}}
{{- if $p := index $bo "Propagation" }}
{{- printf ",bind-propagation=%s" $p}}
{{- end}}
{{- end}} \
{{- end}}
{{- end}}
{{- if .PublishAllPorts}}
--publish-all \
{{- end}}
{{- if .UTSMode}}
--uts {{printf "%q" .UTSMode}} \
{{- end}}
{{- with .LogConfig}}
--log-driver {{printf "%q" .Type}} \
{{- range $o, $v := .Config}}
--log-opt {{$o}}={{printf "%q" $v}} \
{{- end}}
{{- end}}
{{- with .RestartPolicy}}
--restart "{{.Name -}}
{{- if eq .Name "on-failure"}}:{{.MaximumRetryCount}}
{{- end}}" \
{{- end}}
{{- range $e := .ExtraHosts}}
--add-host {{printf "%q" $e}} \
{{- end}}
{{- range $v := .CapAdd}}
--cap-add {{printf "%q" $v}} \
{{- end}}
{{- range $v := .CapDrop}}
--cap-drop {{printf "%q" $v}} \
{{- end}}
{{- range $d := .Devices}}
--device {{printf "%q" (index $d).PathOnHost}}:{{printf "%q" (index $d).PathInContainer}}:{{(index $d).CgroupPermissions}} \
{{- end}}
{{- end}}
{{- with .NetworkSettings -}}
{{- range $p, $conf := .Ports}}
{{- with $conf}}
--publish "
{{- if $h := (index $conf 0).HostIp}}{{$h}}:
{{- end}}
{{- (index $conf 0).HostPort}}:{{$p}}" \
{{- end}}
{{- end}}
{{- range $n, $conf := .Networks}}
{{- with $conf}}
--network {{printf "%q" $n}} \
{{- range $a := $conf.Aliases}}
--network-alias {{printf "%q" $a}} \
{{- end}}
{{- end}}
{{- end}}
{{- end}}
{{- with .Config}}
{{- if .Hostname}}
--hostname {{printf "%q" .Hostname}} \
{{- end}}
{{- if .Domainname}}
--domainname {{printf "%q" .Domainname}} \
{{- end}}
{{- if index . "ExposedPorts"}}
{{- range $p, $conf := .ExposedPorts}}
--expose {{printf "%q" $p}} \
{{- end}}
{{- end}}
{{- if .User}}
--user {{printf "%q" .User}} \
{{- end}}
{{- range $e := .Env}}
--env {{printf "%q" $e}} \
{{- end}}
{{- range $l, $v := .Labels}}
--label {{printf "%q" $l}}={{printf "%q" $v}} \
{{- end}}
{{- if not (or .AttachStdin (or .AttachStdout .AttachStderr))}}
--detach \
{{- end}}
{{- if .AttachStdin}}
--attach stdin \
{{- end}}
{{- if .AttachStdout}}
--attach stdout \
{{- end}}
{{- if .AttachStderr}}
--attach stderr \
{{- end}}
{{- if .Tty}}
--tty \
{{- end}}
{{- if .OpenStdin}}
--interactive \
{{- end}}
{{- if .Entrypoint}}
{{- /* Since the entry point cannot be overridden from the command line with an array of size over 1,
we are fine assuming the default value in such a case. */ -}}
{{- if eq (len .Entrypoint) 1 }}
--entrypoint "
{{- range $i, $v := .Entrypoint}}
{{- if $i}} {{end}}
{{- $v}}
{{- end}}" \
{{- end}}
{{- end}}
{{printf "%q" .Image}} \
{{range .Cmd}}{{printf "%q " .}}{{- end}}
{{- end}}
@bulletcomes

Copy link
Copy Markdown

Thank you soooo much for this. I am reverse enginering a docker registry a consultant setup (and he is long gone) and this helps a lot!

Good work!

@ToroNZ

ToroNZ commented Jan 31, 2022

Copy link
Copy Markdown

hell yeah

@sunds

sunds commented Aug 1, 2022

Copy link
Copy Markdown

Still very useful in mid 2022. Thanks!

@pcsmith811

Copy link
Copy Markdown

Thank you! This is really useful! To use directly the most recent version of the template:

docker inspect \
  --format "$(curl -s https://gist.githubusercontent.com/efrecon/8ce9c75d518b6eb863f667442d7bc679/raw/run.tpl)" \
  name_or_id_of_running_container

Thanks, works great and made it very simple!

@griloHBG

griloHBG commented Feb 1, 2023

Copy link
Copy Markdown

Hi @efrecon!

Thanks for this great tool!

I would like to contribute with a starting point for the --mount option of docker run.

The addition is available in my fork: https://gist.github.com/griloHBG/5c46567b813f6ec2e4bc04454837faae

Motivation: I am studying how the x11docker works and the mounts weren't showing up.

Full disclaimer: this is the first time I put my hands in this Go Text Template stuff, so I expect my addition to not be as good as it could 😛

@efrecon

efrecon commented Feb 3, 2023

Copy link
Copy Markdown
Author

I've merged your version @griloHBG . It looks fine to me and has worked for me when tested against a few containers that I had that were using the --mount option. Thanks!

@matheusyl

matheusyl commented Feb 4, 2023

Copy link
Copy Markdown

I got an error after the update:

Template parsing error: template: :19:18: executing "" at <.Mounts>: map has no entry for key "Mounts"

Could not investigate further right now since I'm in the middle of a production change.

@efrecon

efrecon commented Feb 4, 2023

Copy link
Copy Markdown
Author

hm... @matheusyl would be nice if you can reproduce this, because I haven't been able to reproduce it, event on containers that did not have any Mounts. Could it be a version thing, and could it be that you are running with an older version of docker? When I inspect without the template, the JSON returned always contains a Mounts array, albeit empty sometimes.

@oparin-alexander

Copy link
Copy Markdown

I had the same issue
Template parsing error: template: :19:18: executing "" at <.Mounts>: map has no entry for key "Mounts"
Docker version is Docker version 1.13.1, build 7d71120/1.13.1

In my version .Mounts is located in the root of docker inspect. Something like that:

[
    {
        "HostConfig": {
        ...
        },
        "Mounts": [
            {
                "Type": "bind",
                "Source": "example",
                "Destination": "example",
                "Mode": "rw",
                "RW": true,
                "Propagation": "rprivate"
            },
            ...
        ],
        ...
    }
]

So moving

          {{- range .Mounts}}
  --mount type={{.Type}},source={{.Source}},destination={{.Destination}}{{- if .Propagation}},bind-propagation={{.Propagation}}{{- end}}{{- if not .RW}},readonly{{- end}} \
        {{- end}}

out of .HostConfig scope has helped me

@wg1k

wg1k commented Feb 6, 2023

Copy link
Copy Markdown

Hi @efrecon , I'd be pleased if you'd review my just-added support for --mount: https://gist.github.com/wg1k/e28b47dc826644412629093d5c9185be .

@oparin-alexander I've seen two .Mounts, one inside the HostConfig and the other outside, as you noticed. After some play around, I've found the outer is the effective configuration. But the inner is reflecting the specified --mount options, thus, likely this is the one we want to reverse engineer to get the generating command.

@matheusyl probably in your container the --mount command was not used, so the .Mounts config was not found. In my current proposal, I consider that case and check if it exists before the loop.

@griloHBG Thank you for pushing it forward.

@efrecon

efrecon commented Feb 10, 2023

Copy link
Copy Markdown
Author

@ictus4u You are right, there are two .Mounts. The one inside HostConfig seems to reflect what you provided at the command-line (or docker compose, or ...) and is the one that we want to work with I think. For example, if you use secrets, they will also appear there (marked as read only). I have tried to fix with an extra "if" to see if that helps. @matheusyl can you check if the new version fixes your problems?

@MarcelloPercoco

Copy link
Copy Markdown

@ictus4u You are right, there are two .Mounts. The one inside HostConfig seems to reflect what you provided at the command-line (or docker compose, or ...) and is the one that we want to work with I think. For example, if you use secrets, they will also appear there (marked as read only). I have tried to fix with an extra "if" to see if that helps. @matheusyl can you check if the new version fixes your problems?

Hi.

I'm facing the exact same problem, and the last update dosen't seem to have fixed it; i see those errors and some run file are still empty

Thanks and best regards

@donny-son

Copy link
Copy Markdown

For those who are restricted to public internet access can use cat instead of curl.

docker inspect --format "$(cat /path_to_file/run.tpl)" name_or_id_of_running_container

@uvlad7

uvlad7 commented May 10, 2023

Copy link
Copy Markdown

Please add

--user {{.Config.User}}

@QGB

QGB commented May 16, 2023

Copy link
Copy Markdown

docker inspect --format "$(curl -s https://gist.githubusercontent.com/efrecon/8ce9c75d518b6eb863f667442d7bc679/raw/run.tpl)" ded0bdd038e4

Template parsing error: template: :22:15: executing "" at <.Mounts>: map has no entry for key "Mounts"

@efrecon

efrecon commented May 16, 2023

Copy link
Copy Markdown
Author

@uvlad7 --user now supported. @QGB try again, I have merged and adapted the changes from @ictus4u

@htjain

htjain commented Jun 5, 2023

Copy link
Copy Markdown

docker inspect --format "$(curl -s https://gist.githubusercontent.com/efrecon/8ce9c75d518b6eb863f667442d7bc679/raw/run.tpl)" ded0bdd038e4

Template parsing error: template: :22:15: executing "" at <.Mounts>: map has no entry for key "Mounts"

Same error

@saschabrockel

Copy link
Copy Markdown

Thank you for the great work! Unfortunately, I recognized that everything regarding health checks is missing:

  --health-cmd="redis-cli
  --raw incr ping"
  --health-interval=30s
  --health-timeout=10s
  --health-retries=3

Would it be possible to add them too?

@xuganyu96

Copy link
Copy Markdown

This is fantastically simple and effective. Thank you so much!

@snowdream

Copy link
Copy Markdown

thank you so much!

@SimonWoidig

Copy link
Copy Markdown

Starred! Simply amazing!

@yousri666

Copy link
Copy Markdown

great work! so helpful

@insinfo

insinfo commented May 6, 2024

Copy link
Copy Markdown

great work! so helpful

@spencershepard

Copy link
Copy Markdown

Thanks for this!

To create files with the run commands for all of your running containers:
docker ps -q | xargs -I % sh -c 'docker inspect --format "$(curl -s https://gist.githubusercontent.com/efrecon/8ce9c75d518b6eb863f667442d7bc679/raw/run.tpl)" % > %'

@AGou-ops

Copy link
Copy Markdown

Thanks for this!

To create files with the run commands for all of your running containers: docker ps -q | xargs -I % sh -c 'docker inspect --format "$(curl -s https://gist.githubusercontent.com/efrecon/8ce9c75d518b6eb863f667442d7bc679/raw/run.tpl)" % > %'

Good job. Slightly modify it to use the container name as the file name.

docker ps -q | xargs -I % sh -c 'docker inspect --format "$(curl -s https://gist.githubusercontent.com/efrecon/8ce9c75d518b6eb863f667442d7bc679/raw/run.tpl)" % > $(docker inspect --format "{{.Name}}" % | cut -c2-)'

@idcrook

idcrook commented Mar 5, 2025

Copy link
Copy Markdown

what a great concept! almost perfect in my use -- had to manually gather to re-assign MAC address (since used to assign IP in DHCP env)

--mac-address=aa:bb:...

@snikhil1998

Copy link
Copy Markdown

Hi @efrecon

I would like to thank you for this template.

I would like to contribute by modifying the iteration through the ports to iterate through every element rather than choosing only the first.

The change is available in my fork: https://gist.github.com/snikhil1998/9176b8583475693f1f8d1f1f5c6e76e4

Motivation: I noticed the incomplete list of port bindings when recreating docker containers with this template, so I modified it to fix the issue.

@FeedTheChunk

Copy link
Copy Markdown

Is it possible to add --mac-address to the template? thx

@martinwunderlich-celonis

Copy link
Copy Markdown

@PasaOpasen

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment