Reputation: 876
I want to create a new image in a remote docker registry by providing only partial data:
According to the docs
https://docs.docker.com/registry/spec/api/#pushing-an-image
in order to push a docker image, i can:
* post a tar layer that i have.
* post a manifest
and the registry will support my new new image.
For example:
* I have locally a java app in a tar layer.
* The remote docker registry already has a java8 base image.
* I want to upload the tar layer and a manifest that references the java8 base image and have the docker registry support the new image for my app.
(The layer tar i get from a 3rd party build tool called Bazel if anyone cares)
From the docs i gather that i can take the existing java8 image manifest, download it, append (or pre-pend) my new layer to the layers section and viola.
Looking at the manifest spec https://docs.docker.com/registry/spec/manifest-v2-2/#image-manifest-field-descriptions I see there's a "config object" section with digest as reference to config file. This makes sense, i may need to redefine the entrypoint for example. So suppose i also have a docker config in a file that i guess i need to let the registry know about somehow.
Nowhere (that i can see) in the API does it state where or how to upload the config or if i need to do that at all - maybe it's included in the layer tar or something.
Do i upload the config as a layer? is it included in the tar? if not why do i give a reference to it by digest?
Best answer i can hope for would be a sequence of http calls to a docker-registry that do what i'm trying. Alternatively just explaining what the config is, and how to go about it would be very helpful.
Upvotes: 2
Views: 2289
Reputation: 876
found the solution here:
https://www.danlorenc.com/posts/containers-part-2/
very detailed, great answer, don't know who you are but i love you!
From inspecting some configs from existing images, Docker seems to require a few fields:
{
"architecture": "amd64",
"config": {
},
"history": [
{
"created_by": "Bash!"
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:69e4bd05139a843cbde4d64f8339b782f4da005e1cae56159adfc92311504719"
]
}
}
The config section can contain environment variables, the default CMD and ENTRYPOINT of your container and a few other settings. The rootfs section contains a list of layers and diff_ids that look pretty similar to our manifest. Unfortunately, the diff_ids are actually slightly different than the digests contained in our manifest, they’re actually a sha256 of the ‘uncompressed’ layers.
We can create one with this script:
cat <<EOF > config.json
{
"architecture": "amd64",
"config": {
},
"history": [
{
"created_by": "Bash!"
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:$(gunzip layer.tar.gz --to-stdout | shasum -a 256 | cut -d' ' -f1)"
]
}
}
EOF
Config Upload Configs are basically stored by the registry as normal blobs. They get referenced differently in the manifest, but they’re still uploaded by their digest and stored normally.
The same type of script we used for layers will work here:
returncode=$(curl -w "%{http_code}" -o /dev/null \
-I -H "Authorization: Bearer $(gcloud auth print-access-token)" \
https://gcr.io/v2/$PROJECT/hello/blobs/$config_digest)
if [[ $returncode -ne 200 ]]; then
# Start the upload and get the location header.
# The HTTP response seems to include carriage returns, which we need to strip
location=$(curl -i -X POST \
https://gcr.io/v2/$PROJECT/hello/blobs/uploads/ \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-d "" | grep Location | cut -d" " -f2 | tr -d '\r')
# Do the upload
curl -X PUT $location\?digest=$config_digest \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
--data-binary @config.json
fi
Upvotes: 3