Docker私有仓库镜像上传

3
我正在尝试使用HTTP API将图像上传到我的私有docker注册表,但不幸的是没有成功。
显然,我还没有完全理解上传过程,并希望询问是否有人可以详细解释一下或指导我正确的方向。
到目前为止,我已经尝试了以下curl命令。 为了进行实验,我只使用空的alpine镜像。 为此,我使用docker pull alpine将其下载到我的工作站,然后使用docker save -o alpine.tar alpine创建tar归档文件。
然后,我将此存档文件解压缩到一个名为alpine的目录中。 这是它的内容: ls -R alpine
alpine:
    39cb81dcd06e3d4e2b813f56b72da567696fa9a59b652bd477615b31af969239
    e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a.json
    manifest.json

alpine/39cb81dcd06e3d4e2b813f56b72da567696fa9a59b652bd477615b31af969239:
    json
    layer.tar
    VERSION

根据文档,我应该首先通过向 /v2//blobs/uploads/ URL 发送 POST 请求来初始化上传。为此,我执行以下命令: curl -X POST -L -D headers $DOCKER_HOST/v2/alpine/blobs/uploads 答案如下: cat headers
HTTP/1.1 301 Moved Permanently
Docker distribution api version: registry/2.0
location: /v2/alpine/blobs/uploads/
Date: Tu, 21 Jan 2020 12:42:55 GMT
content length: 0

HTTP/1.1 202 Accepted
content length: 0
Docker distribution api version: registry/2.0
Docker upload guide: ed595b3c-1236-46c8-a759-14187fc60e7d
Location: http://<IPADDRESS>/v2/alpine/blobs/uploads/ed595b3c-1236-46c8-a759-14187fc60e7d?_state=GjzU_y-YDQherf4xXO57KyEonSSSwNEM8FiF8rmNfuN7Ik5hbWUiOiJhbHBpbmUiLCJVVUlEIjoiZWQ1OTViM2MtMTIzNi00NmM4LWE3NTktMTQxODdmYzYwZTdkIiwiT2Zmc2V0IjowLCJTdGFydGVkQXQiOiIyMDIwLTAxLTIxVDEyOjQyOjU1LjMxNDYzNTg0NVoifQ%3D%3D
Range: 0-0
X Content Type Options: nosniff
Date: Tu, 21 Jan 2020 12:42:55 GMT

现在我想进行一个单块上传,如docker-registry文档中所述。

为此,我发出以下curl请求:

url=http://<IPADDRESS>/v2/alpine/blobs/uploads/ed595b3c-1236-46c8-a759-14187fc60e7d?_state=GjzU_y-YDQherf4xXO57KyEonSSSwNEM8FiF8rmNfuN7Ik5hbWUiOiJhbHBpbmUiLCJVVUlEIjoiZWQ1OTViM2MtMTIzNi00NmM4LWE3NTktMTQxODdmYzYwZTdkIiwiT2Zmc2V0IjowLCJTdGFydGVkQXQiOiIyMDIwLTAxLTIxVDEyOjQyOjU1LjMxNDYzNTg0NVoifQ%3D%3D?digest=sha256:39cb81dcd06e3d4e2b813f56b72da567696fa9a59b652bd477615b31af969239 

layerpath=/home/user/alpine/39cb81dcd06e3d4e2b813f56b72da567696fa9a59b652bd477615b31af969239/layer.tar

curl -X PUT -H "Content-Type=application/octet-stream" --data-binary @"$layerpath"  $url

针对这个问题,我收到了一个对我毫无意义的答案:

 {"errors":[{"code": "BLOB_UPLOAD_INVALID", "message": "blob upload invalid", "detail":212}]}

我不知道我做错了什么。非常感谢任何帮助。


你是不是要走一条艰难的路来学习和理解?否则,你可以简单地执行以下命令:docker login my_server && docker tag random_image:tag my_server/path/to/myrandom_image:tag && docker push my_server//path/to/myrandom_image:tag - Zeitounator
2
困难在于环境中没有安装docker,也不会安装。作为交付物,我得到了一些镜像的tar归档文件,应该上传到docker-registry。作为一种解决方法,我想使用HTTP-API来实现这个目标。 - H4x9r
为什么你不想在上传过程中使用Docker CLI呢?因为无论如何,构建/导出镜像都需要使用Docker,所以你可以使用docker push而不是docker save。否则,将注册表切换到非SSL模式(普通HTTP),并捕获来自标准docker push的请求。你可能在API访问方面做错了一些事情。 - Gabor Garami
我很想这样做,但这不由我决定。我只使用docker save来构建一个示例镜像,以便我可以进行实验。具体过程如下:我将镜像作为tar归档文件获取,然后需要将它们加载到Docker注册表中,以便生产机器可以通过docker pull命令加载这些镜像。 - H4x9r
1个回答

5
好的,我明白了。对于那些与此问题打交道的人,以下是一个小脚本,应该能够澄清HTTP-API的处理方式:
#!/bin/bash


# Global Variables

MANIFEST="./Manifest.json"

DOCKER_HOST=$1
REPOSITORY=$2
LAYERPATH=$3
CONFIGPATH=$4

SIZE=
DIGEST=

LOCATION=


CONFIGSIZE=
CONFIGDIGEST=
LAYERSIZE=
LAYERDIGEST=

# Functions

function initiateUpload(){
   LOCATION=$(curl -X POST -siL -v  -H "Connection: close" $DOCKER_HOST/v2/$REPOSITORY/blobs/uploads | grep Location | sed '2q;d' | cut -d: -f2- | tr -d ' ' | tr -d '\r')
}


function patchLayer(){
    layersize=$(stat -c%s "$1")
    LOCATION=$(curl -X PATCH -v -H "Content-Type: application/octet-stream" \
        -H "Content-Length: $layersize" -H "Connection: close" --data-binary @"$1" \
        $LOCATION 2>&1 | grep 'Location' | cut -d: -f2- | tr -d ' ' | tr -d '\r')
    SIZE=$layersize
}

function putLayer(){
    DIGEST=sha256:$(sha256sum $1 | cut -d ' ' -f1)
    url="$LOCATION&digest=$DIGEST"
    curl -X PUT -v -H "Content-Length: 0" -H "Connection: close" $url

}

function uploadManifest(){
    ((size=$(stat -c%s "$MANIFEST")-1))
    curl -X PUT -vvv -H "Content-Type:   application/vnd.docker.distribution.manifest.v2+json"\
    -H "Content-Length: $size" -H "Connection: close" \
    -d "$(cat "$MANIFEST")" $DOCKER_HOST/v2/$REPOSITORY/manifests/latest
}

# Check Parameters

if [ $# -lt 4 ] 
    then
        echo "Error: No arguments supplied."
        echo "Usage: upload.sh <DOCKER_HOST> <REPOSITORY> <LAYER> <CONFIG>"
       exit 1
fi

#upload Layer
initiateUpload 
patchLayer $LAYERPATH
LAYERSIZE=$SIZE
putLayer $LAYERPATH
LAYERDIGEST=$DIGEST

#upload Config

initiateUpload
patchLayer $CONFIGPATH
CONFIGSIZE=$SIZE
putLayer $CONFIGPATH
CONFIGDIGEST=$DIGEST


cat > $MANIFEST << EOF
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   "config": {
       "mediaType": "application/vnd.docker.container.image.v1+json",
       "size": $CONFIGSIZE,
       "digest": "$CONFIGDIGEST"
   },
   "layers": [
        {
            "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
            "size":$LAYERSIZE,
            "digest": "$LAYERDIGEST"
        }
    ]
 }
 EOF

 uploadManifest

虽然不太美观,但它可以胜任那个工作。

如果您需要更多信息,我很乐意扩展这个答案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接