How to set Architecture for docker build to arm64? - docker

I have a Dockerfile that I run on amd64 but want to run on arm64. Since go build tool takes GOARCH=arm64 as argument I don't need any other cross compilation tool to make the binary.
# Run the build
FROM mojlighetsministeriet/go-polymer-faster-build
ENV WORKDIR /go/src/github.com/mojlighetsministeriet/email
COPY . $WORKDIR
WORKDIR $WORKDIR
RUN go get -t -v ./...
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build
# Create the final docker image
FROM scratch
COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=0 /go/src/github.com/mojlighetsministeriet/email/email /
ENTRYPOINT ["/email"]
The problem is that the resulting image gets marked with the wrong Architecture amd64 instead of arm64. How can I pass an argument to docker build so that it sets Architecture to arm64?
$ docker image inspect mojlighetsministeriet/email-arm64
[
{
"Id": "sha256:33bcd7da8631c7a0829d61cc53479a26ab7f31fab1cb039105de415ddc6178f3",
"RepoTags": [
"mojlighetsministeriet/email-arm64:latest"
],
"RepoDigests": [
"mojlighetsministeriet/email-arm64#sha256:ab3f05d5597c3a304953b5c14f795179aa75bdfd458af3dc3cfb8b8d8eb87bc3"
],
"Parent": "sha256:e5888262d93ea0946b5fd8146cf1c19ec3a7bac4d36eb51848ef0aefa75cf8e7",
"Comment": "",
"Created": "2017-12-05T18:36:36.273648787Z",
"Container": "7a226edb3b52aaeeefec9e0fb4dd1da50d84992fb6cc374aeda9d82eec1bb2c8",
"ContainerConfig": {
"Hostname": "7a226edb3b52",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"ENTRYPOINT [\"/email\"]"
],
"Image": "sha256:e5888262d93ea0946b5fd8146cf1c19ec3a7bac4d36eb51848ef0aefa75cf8e7",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/email"
],
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "17.10.0-ce",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": null,
"Image": "sha256:e5888262d93ea0946b5fd8146cf1c19ec3a7bac4d36eb51848ef0aefa75cf8e7",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/email"
],
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 7861466,
"VirtualSize": 7861466,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/03cb0162bf922636e4e0ec90123b81565a447c6cd511741103551d2f0e7f09f9/diff",
"MergedDir": "/var/lib/docker/overlay2/091f74815a0caf457df7e57ade43b41c4dd8551388beca44815a7038501742ee/merged",
"UpperDir": "/var/lib/docker/overlay2/091f74815a0caf457df7e57ade43b41c4dd8551388beca44815a7038501742ee/diff",
"WorkDir": "/var/lib/docker/overlay2/091f74815a0caf457df7e57ade43b41c4dd8551388beca44815a7038501742ee/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:66f615d03920919b0fa8bc9fed45515bb95636be1837fdd10a82b2c183e2ad5b",
"sha256:bd6a01b885eb6e3eec38a3fe3a2899646509633730b210cf6987456fd40b8a1c"
]
},
"Metadata": {
"LastTagTime": "2017-12-14T10:24:10.796813522+01:00"
}
}
]

https://docs.docker.com/desktop/multi-arch/
# Shows builders installed
docker buildx ls
# Use builder that supports platform
docker buildx use default
docker buildx build --platform linux/arm64 -t <image_name>:<image_tag> --push .

For building single docker images: Set your environment variable using the command line or modifying your .bashrc or .zshenv file. (introduced in v19.03.0 in 03/2019)
export DOCKER_DEFAULT_PLATFORM=linux/arm64
Alternatively, in the Dockerfile, include the following flag in the FROM command (for a multi-stage Dockerfile build, the flag is only needed for the first stage):
FROM --platform=linux/arm64 python:3.7-alpine
For building images as part of a docker-compose build, include the platform: linux/arm64 for each service. For example:
services:
frontend:
platform: linux/arm64
build: frontend
ports:
- 80:80
depends_on:
- backend
backend:
platform: linux/arm64
build: backend
This also works the other way around, for instance if you have an Apple M1 Chip and want to deploy images to a Linux or Windows based AMD64 environment. Simply swap 'linux/arm64' for 'linux/amd64'

I was able to solve the problem, not exactly as I wanted, but close enough.
Have an amd64 Linux machine with docker
Setup qemu user static for arm support https://hub.docker.com/r/multiarch/qemu-user-static/
In your docker file use base image with support for arm. E.g. ubuntu
Build your image with command similar to the following:
docker build --platform arm --pull -t your_tag .
This command will force docker to pull arm version of the base image and will also set arm architecture to your result image. But be careful, if you use tags with multiple architectures, the command above will set the tag to arm version. So to run the native amd64 version you will need to pull the tag again without --platform arg.

Related

Docker, dangling container?

I cant start my docker-compose environment, because the port is allocated by something.
ERROR: for ***** Cannot start service *****: driver failed programming external connectivity on endpoint ***** (4314ec13837d41ca8ef1b7e1d8446ab8cfa96136539a75ac763ba1cf538ffdc1): Bind for 0.0.0.0:8881 failed: port is already allocated
Encountered errors while bringing up the project.
However, there is not such a container
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
But when I inspect the docker-compose network, I can see a container in the network
$ docker network inspect *****
[
{
"Name": "*****",
"Id": "56d09f51e8fe5a9ad11dd6cdaff7e89983f519fd1ecff08116c2e48a3b34ff32",
"Created": "2018-08-01T08:17:30.704352821Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"08a5defa5ceae7a5a5ac7ec85f5ecd0924ecb4e5eacca4f5752049e32a0f190c": {
"Name": "08a5defa5cea_*****",
"EndpointID": "5d081a19b5ffe4e893965a4306668059900812532cc4995e168ce017f2765e12",
"MacAddress": "02:42:ac:12:00:06",
"IPv4Address": "172.18.0.6/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {
"com.docker.compose.network": "*****",
"com.docker.compose.project": "docker"
}
}
]
Yet it is impossible to remove this container
docker rm -f *****
Error: No such container: *****
How to proceed?
I run this script to shut down all stuck containers which sometimes linger
#!/bin/bash
# ... bring down all containers
force_it="" # normal
# force_it=" -f " # when you see "device or resource busy"
for curr_container_id in $( docker ps -q ); do
echo curr_container_id $curr_container_id
echo
echo "docker stop $curr_container_id "
docker stop $curr_container_id
echo
echo "docker rm $force_it $curr_container_id "
docker rm $force_it $curr_container_id
done
for curr_container_id in $( docker ps -q -a ); do
echo curr_container_id $curr_container_id
echo
echo "docker stop $curr_container_id "
docker stop $curr_container_id
echo
echo "docker rm $force_it $curr_container_id "
docker rm $force_it $curr_container_id
done
it works 99% of the time ... if not near the top you can toggle the force parm and re-run it ... this allows you to avoid having to bounce any docker server

Is there a way to convert a x86-only docker image to a multi-platform one?

The newest docker registry/engine have supported "manifest list" feature to allow user referencing images with different CPU architectures, OSes and other characteristics, by solo entry in registry.
So saying I have a legacy x86-only image in my repository ,and unfortunately it'd been altered during previous running as container (successive docker commits) which means no Dockerfile available. Is there a way I can convert this x86-only image to support manifest list without rebuilding it?
Docker can export the contents of a container started from the image. Then a new image can be created FROM scratch that ADDs the contents back.
Steps
docker export will create a tar file of the complete contents of a container created from the image.
$ CID=$(docker create myimage)
$ docker export -o myimage.tar $CID
$ docker rm $CID
Build a new Dockerfile FROM scratch that ADDs the exported contents tar file back.
FROM scratch
ADD myimage.tar /
Any extended meta data for Dockerfile, like ENTRYPOINT, CMD or VOLUMES, can be queried via inspect or history:
$ docker image inspect myimage -f '{{json .Config}}' | jq
{
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"27017/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.10",
"JSYAML_VERSION=3.10.0",
"GPG_KEYS=2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5",
"MONGO_PACKAGE=mongodb-org",
"MONGO_REPO=repo.mongodb.org",
"MONGO_MAJOR=3.6",
"MONGO_VERSION=3.6.3"
],
"Cmd": [
"mongod"
],
"ArgsEscaped": true,
"Image": "sha256:bac19e2cfd49108534b108c101a68a2046090d25da581ae04dc020aac93b4e31",
"Volumes": {
"/data/configdb": {},
"/data/db": {}
},
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": [],
"Labels": null
}
or
docker image history myimage --no-trunc

Permissions issues in Docker image while gradle is trying to write to an out directory

I am building a docker image which will contain gradle, and other tools used for testing the application.
So, I have created a new Dockerfile based on a corporate docker image with one of the tools I need, then strapped gradle after that, courtesy of
keeganwitt.
My run command looks like this:
docker run -it --mount source=~/app-repo/appName,target=/home/gradle/,type=bind app_unittests:gradle_sahi /bin/bash -c "whoami;pwd;chown --recursive gradle:gradle /home/gradle; gradle test --tests test.automation.tools.TestSahi --debug --stacktrace"
So this works, it starts running, and eventually I get:
Failed to create parent directory '/home/gradle/out' when creating directory '/home/gradle/out/classes/java/main
Also note that I added the chown command to my docker run command (lifted from the gradle dockerfile) - but it also runs into permission issues on everything...
I also checked docker inspect <CONTAINER_ID>:
"Mounts": [
{
"Type": "bind",
"Source": "/root/app-repo/appName",
"Destination": "/home/gradle",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
{
"Type": "volume",
"Name": "66dcb821f5687c55821ec908ea7ad041065477fa9328cd5cd47e21cf7d7a0028",
"Source": "/var/lib/docker/volumes/66dcb821f5687c55821ec908ea7ad041065477fa9328cd5cd47e21cf7d7a0028/_data",
"Destination": "/home/gradle/.gradle",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
As well as Mounts under HostConfig:
"Mounts": [
{
"Type": "bind",
"Source": "/root/app-repo/appName",
"Target": "/home/gradle/"
}
]
You can see, it IS mounted RW:true.
Please help..
You should run ls -n /root/app-repo/appName (on the source). If the ids are not 1000, you will need to chown the directory (sudo chown -R 1000:1000 /root/app-repo/appName) or run the container as root (docker run --user root or user: root in your Docker compose file).

Get list of docker tags available to pull from command line?

I want to get some basic information about the published versions/tags of a docker image, to know what image:tag's I can pull. I would also like to see the time that each tag was most recently published.
Is there a way to do this on the command line?
Docker version 1.10.2, build c3959b1
Basically looking for the equivalent of npm info {pkg} for a docker image.
Not from the command line. You have docker search but it only returns a subset of the data you want, and only for the image with the :latest tag:
> docker search sixeyed/hadoop-dotnet
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
sixeyed/hadoop-dotnet Hadoop with .NET Core installed 1 [OK]
If you want more detail, you'll need to use the registry API, but it only has a catalog endpoint for listing repositories, the issue for search is still open.
Assuming you know the repository name, you can navigate the API - first you need an auth token:
> curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:sixeyed/hadoop-dotnet:pull"
{"token":"eyJhbG...
Then you pass the token to subsequent requests, e.g. to list the tags:
> curl --header "Authorization: Bearer eyJh..." https://index.docker.io/v2/sixeyed/hadoop-dotnet/tags/list
{"name":"sixeyed/hadoop-dotnet","tags":["2.7.2","latest"]}
And then get all the information about one image by its repository name and tag:
> curl --header "Authorization: Bearer eyJh..." https://index.docker.io/v2/sixeyed/hadoop-dotnet/manifests/latest
I want to get some basic information about the published versions/tags of a docker image, to know what image:tag's I can pull.
This is from the tags/list API. Here's a small script that does it:
#!/bin/sh
ref="${1:-library/ubuntu:latest}"
repo="${ref%:*}"
tag="${ref##*:}"
token=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repo}:pull" \
| jq -r '.token')
curl -H "Authorization: Bearer $token" \
-s "https://registry-1.docker.io/v2/${repo}/tags/list" | jq .
Running that looks like:
$ ./tags-v2.sh library/ubuntu:latest
{
"name": "library/ubuntu",
"tags": [
"10.04",
"12.04",
"12.04.5",
"12.10",
"13.04",
"13.10",
"14.04",
"14.04.1",
...
I would also like to see the time that each tag was most recently published.
You likely want to pull the image config for this. First you need to pull the manifest, parse the config descriptor, then pull that blob for the config json. Here's a script that will do that for docker images:
#!/bin/sh
ref="${1:-library/ubuntu:latest}"
repo="${ref%:*}"
tag="${ref##*:}"
token=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repo}:pull" \
| jq -r '.token')
digest=$(curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
-H "Authorization: Bearer $token" \
-s "https://registry-1.docker.io/v2/${repo}/manifests/${tag}" \
| jq -r .config.digest)
curl -H "Accept: application/vnd.docker.container.image.v1+json" \
-H "Authorization: Bearer $token" \
-s -L "https://registry-1.docker.io/v2/${repo}/blobs/${digest}" | jq .
And an example of running that script:
$ ./get-config-v2.sh library/ubuntu:latest
{
"architecture": "amd64",
"config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"bash"
],
"Image": "sha256:6c18a628d47eacf574eb93da2324293a0e6c845084cca2ea13efaa3cee4d0799",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"container": "249e88be79ad9986a479c71c15a056946ae26b0c54c1f634f115be6d5f9ba1c8",
"container_config": {
"Hostname": "249e88be79ad",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"bash\"]"
],
"Image": "sha256:6c18a628d47eacf574eb93da2324293a0e6c845084cca2ea13efaa3cee4d0799",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"created": "2021-10-16T00:37:47.578710012Z",
"docker_version": "20.10.7",
"history": [
{
"created": "2021-10-16T00:37:47.226745473Z",
"created_by": "/bin/sh -c #(nop) ADD file:5d68d27cc15a80653c93d3a0b262a28112d47a46326ff5fc2dfbf7fa3b9a0ce8 in / "
},
{
"created": "2021-10-16T00:37:47.578710012Z",
"created_by": "/bin/sh -c #(nop) CMD [\"bash\"]",
"empty_layer": true
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:9f54eef412758095c8079ac465d494a2872e02e90bf1fb5f12a1641c0d1bb78b"
]
}
}
Note that this will only give you details from the build tooling, the registry itself does not track when an image was uploaded to that registry from any OCI APIs (some registries may add their own metadata, but this would be registry specific).
To handle more authentication types, different kinds of images (OCI vs Docker), and similar, I've packaged these commands and more into regctl in the regclient project. Similar projects exist from Google's container registry crane command, and RedHat's skopeo, each giving access to registries from the command line:
$ regctl tag ls ubuntu
10.04
12.04
12.04.5
12.10
13.04
13.10
14.04
14.04.1
14.04.2
14.04.3
14.04.4
14.04.5
...
$ regctl image config ubuntu
{
"created": "2021-10-16T00:37:47.578710012Z",
"architecture": "amd64",
"os": "linux",
"config": {
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"bash"
]
},
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:9f54eef412758095c8079ac465d494a2872e02e90bf1fb5f12a1641c0d1bb78b"
]
},
"history": [
{
"created": "2021-10-16T00:37:47.226745473Z",
"created_by": "/bin/sh -c #(nop) ADD file:5d68d27cc15a80653c93d3a0b262a28112d47a46326ff5fc2dfbf7fa3b9a0ce8 in / "
},
{
"created": "2021-10-16T00:37:47.578710012Z",
"created_by": "/bin/sh -c #(nop) CMD [\"bash\"]",
"empty_layer": true
}
]
}
If you don't want to use a token:
curl -L -s 'https://registry.hub.docker.com/v2/repositories/<$repo_name>/tags?page=<$page_nb>&page_size=<$page_size>' | jq '."results"[]["name"]'
Where you can get <$repo_name> with:
docker search <$expression>
For example:
$ docker search piwigo
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
linuxserver/piwigo A Piwigo container, brought to you by LinuxS… 152
mathieuruellan/piwigo Easy deployment of piwigo for my personal us… 19 [OK]
lsioarmhf/piwigo 3
hg8496/piwigo 2 [OK]
[…]
$ curl -L -s 'https://registry.hub.docker.com/v2/repositories/linuxserver/piwigo/tags?page=1&page_size=10' | jq '."results"[]["name"]'
"latest"
"12.0.0"
"version-12.0.0"
"12.0.0-ls137"
"arm64v8-12.0.0"
"arm32v7-12.0.0"
"amd64-12.0.0"
"arm64v8-version-12.0.0"
"arm32v7-version-12.0.0"
"amd64-version-12.0.0"
Source: Démarrer avec les containers Docker

How to view Docker image layers on Docker Hub?

I know that I can use this command $ docker images --tree docker history to view the layers of a Docker image, but how do I do that for images on Docker Hub without pulling it? This is so that I know what is on an image before I download it.
E.g., for the Tomcat repo, https://registry.hub.docker.com/_/tomcat/, the webpage doesn't seem to show what is on the image. I have to look at the Dockerfile on Github to find out.
Update
I see this repo https://registry.hub.docker.com/u/tutum/tomcat/ has more tabs. The "Dockerfile" tab shows how it is created, but only seems to show the latest version. Is there no choice to view the file for other tags?
Docker Hub is quite limited at the moment and does not offer the feature you asked for.
When an image is configured to build from source at Docker Hub (an Automated Build) you can see what went into it, but when it is uploaded pre-built you have no information.
This is now possible by clicking into the image tag on Docker Hub.
Use microbadger, which comes with a few badges as well, eg:
So your tomcat image on https://microbadger.com/images/tomcat would look like:
You can get this for any registry by using the registry API. Within the image manifest is a pointer to the image config, and that config is a json blob that includes the history steps. Note that this history is not authoritative, and depending on the build tooling, could report different commands than what were actually used to build the image layers.
A shell script version of this using the auth for Docker Hub looks like:
#!/bin/sh
ref="${1:-library/ubuntu:latest}"
repo="${ref%:*}"
tag="${ref##*:}"
token=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repo}:pull" \
| jq -r '.token')
digest=$(curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
-H "Authorization: Bearer $token" \
-s "https://registry-1.docker.io/v2/${repo}/manifests/${tag}" \
| jq -r .config.digest)
curl -H "Accept: application/vnd.docker.container.image.v1+json" \
-H "Authorization: Bearer $token" \
-s -L "https://registry-1.docker.io/v2/${repo}/blobs/${digest}" | jq .history
Behind the scenes, what's happening is the registry first resolves any manifest list to a single manifest for the default architecture, but you could pull any architecture manually:
$ regctl image manifest --list localhost:5000/library/alpine:latest --format '{{jsonPretty .}}'
{
"manifests": [
{
"digest": "sha256:69704ef328d05a9f806b6b8502915e6a0a4faa4d72018dc42343f511490daf8a",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "amd64",
"os": "linux"
},
"size": 528
},
{
"digest": "sha256:18c29393a090ba5cde8a5f00926e9e419f47cfcfd206cc3f7f590e91b19adfe9",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v6"
},
"size": 528
},
...
Then that platform specific manifest includes the config and layers:
$ regctl image manifest localhost:5000/library/alpine#sha256:69704ef328d05a9f806b6b8502915e6a0a4faa4d72018dc42343f511490daf8a --format '{{jsonPretty .}}'
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 1471,
"digest": "sha256:14119a10abf4669e8cdbdff324a9f9605d99697215a0d21c360fe8dfa8471bab"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 2814446,
"digest": "sha256:a0d0a0d46f8b52473982a3c466318f479767577551a53ffc9074c9fa7035982e"
}
]
}
And pulling the config blob shows all of the contents you may recognize from the history and inspect commands:
$ regctl blob get localhost:5000/library/alpine sha256:14119a10abf4669e8cdbdff324a9f9605d99697215a0d21c360fe8dfa8471bab | jq .
{
"architecture": "amd64",
"config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh"
],
"Image": "sha256:d3e0b6258ec2f725c19668f11ae5323c3b0245e197ec478424ec6a87935690eb",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"container": "330289c649db86f5fb1ae5bfef18501012b550adb0638b9193d4a3a4b65a2f9b",
"container_config": {
"Hostname": "330289c649db",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"/bin/sh\"]"
],
"Image": "sha256:d3e0b6258ec2f725c19668f11ae5323c3b0245e197ec478424ec6a87935690eb",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"created": "2021-08-27T17:19:45.758611523Z",
"docker_version": "20.10.7",
"history": [
{
"created": "2021-08-27T17:19:45.553092363Z",
"created_by": "/bin/sh -c #(nop) ADD file:aad4290d27580cc1a094ffaf98c3ca2fc5d699fe695dfb8e6e9fac20f1129450 in / "
},
{
"created": "2021-08-27T17:19:45.758611523Z",
"created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]",
"empty_layer": true
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:e2eb06d8af8218cfec8210147357a68b7e13f7c485b991c288c2d01dc228bb68"
]
}
}
The regctl commands above come from my regclient project, but I believe you can do similar commands with skopeo and crane. The advantage of these tools over curl commands is handling the authentication that varies between registries (the bearer token from Hub won't work for other registries).
Lastly, the one-line answer using regctl is a formatted image config command, which performs all the above steps without needing jq:
$ regctl image config localhost:5000/library/alpine:latest --format '{{jsonPretty .History}}'
[
{
"created": "2021-08-27T17:19:45.553092363Z",
"created_by": "/bin/sh -c #(nop) ADD file:aad4290d27580cc1a094ffaf98c3ca2fc5d699fe695dfb8e6e9fac20f1129450 in / "
},
{
"created": "2021-08-27T17:19:45.758611523Z",
"created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]",
"empty_layer": true
}
]

Resources