构建多架构镜像
构建多架构镜像
构建多架构镜像
harbor目前不支持,harbor说2.0支持此功能
测试环境:
本机:
Linux HT061 4.13.0-36-generic #40~16.04.1-Ubuntu SMP Fri Feb 16 23:25:58 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
docker :
docker version
Client: Docker Engine - Community
Version: 19.03.8
API version: 1.40
Go version: go1.12.17
Git commit: afacb8b7f0
Built: Wed Mar 11 01:25:46 2020
OS/Arch: linux/amd64
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 19.03.8
API version: 1.40 (minimum version 1.12)
Go version: go1.12.17
Git commit: afacb8b7f0
Built: Wed Mar 11 01:24:19 2020
OS/Arch: linux/amd64
Experimental: true
containerd:
Version: 1.2.6
GitCommit: 894b81a4b802e4eb2a91d1ce216b8817763c29fb
runc:
Version: 1.0.0-rc8
GitCommit: 425e105d5a03fabd737a126ad93d62a9eeede87f
docker-init:
Version: 0.18.0
GitCommit: fec3683
服务器:
Linux storage 4.4.13-20170224.kylin.5.YUN+ #51 SMP Mon Apr 10 14:11:02 CST 2017 aarch64 aarch64 aarch64 GNU/Linux
docker:
docker version
Client:
Version: 17.03.2-ce-rc1
API version: 1.27
Go version: go1.9.2
Git commit: eef6495
Built: Wed Nov 15 13:33:44 2017
OS/Arch: linux/arm64
Server:
Version: 17.03.2-ce-rc1
API version: 1.27 (minimum version 1.12)
Go version: go1.9.2
Git commit: eef6495
Built: Wed Nov 15 13:33:44 2017
OS/Arch: linux/arm64
Experimental: false
开始
1. docker version要求
Docker 版本不低于 19.03 且开启buildx
export DOCKER_CLI_EXPERIMENTAL=enabled
或者
cat /etc/docker/daemon.json
{
"experimental": true
}
docker buildx --help
Usage: docker buildx COMMAND
Build with BuildKit
Management Commands:
imagetools Commands to work on images in registry
Commands:
bake Build from a file
build Start a build
create Create a new builder instance
inspect Inspect current builder instance
ls List builder instances
rm Remove a builder instance
stop Stop builder instance
use Set the current builder instance
version Show buildx version information
Run 'docker buildx COMMAND --help' for more information on a command.
2. 启用 binfmt_misc
docker run --rm --privileged docker/binfmt:a7996909642ee92942dcd6cff44b9b95f08dad64
验证是 binfmt_misc 否开启:
root@HT061:/ ls -al /proc/sys/fs/binfmt_misc/
总用量 0
drwxr-xr-x 2 root root 0 4月 7 09:06 .
dr-xr-xr-x 1 root root 0 4月 7 09:05 ..
-rw-r--r-- 1 root root 0 4月 7 09:06 ksh
-rw-r--r-- 1 root root 0 4月 7 09:06 llvm-6.0-runtime.binfmt
-rw-r--r-- 1 root root 0 4月 7 09:06 python2.7
-rw-r--r-- 1 root root 0 4月 7 09:06 python3.5
-rw-r--r-- 1 root root 0 4月 7 09:06 python3.6
-rw-r--r-- 1 root root 0 4月 9 08:49 qemu-aarch64
-rw-r--r-- 1 root root 0 4月 9 08:49 qemu-arm
-rw-r--r-- 1 root root 0 4月 9 08:49 qemu-ppc64le
-rw-r--r-- 1 root root 0 4月 9 08:49 qemu-riscv64
-rw-r--r-- 1 root root 0 4月 9 08:49 qemu-s390x
--w------- 1 root root 0 4月 7 09:06 register
-rw-r--r-- 1 root root 0 4月 7 09:06 status
验证是否启用了相应的处理器:
root@HT061:/ cat /proc/sys/fs/binfmt_misc/qemu-aarch64
enabled
interpreter /usr/bin/qemu-aarch64
flags: OCF
offset 0
magic 7f454c460201010000000000000000000200b7
mask ffffffffffffff00fffffffffffffffffeffff
3. 从默认的构建器切换到多平台构建器
root@HT061:~# docker buildx create --use --name mybuilder
mybuilder
启动构建器:
root@HT061:~# docker buildx inspect mybuilder --bootstrap
查看当前使用的构建器及构建器支持的 CPU 架构,可以看到支持很多 CPU 架构:
root@HT061:~# docker buildx ls
4. 准备代码和Dockerfile
root@HT061:/home/ht061/桌面/mutiarch# cat hello.go
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Printf("Hello, %s!\n", runtime.GOARCH)
}
root@HT061:/home/ht061/桌面/mutiarch# cat Dockerfile
FROM golang:alpine AS builder
RUN mkdir /app
ADD . /app/
WORKDIR /app
RUN go build -o hello .
FROM alpine
RUN mkdir /app
WORKDIR /app
COPY --from=builder /app/hello .
CMD ["./hello"]
golang和alpine都是支持多架构的 golang:alpine镜像: alpine镜像:
5. build/push
build镜像并push到dockerhub
root@HT061:/home/ht061/桌面/mutiarch# docker buildx build -t lurenjia/hello-arch --platform=linux/arm64,linux/amd64 . --push
查看不同架构信息:
root@HT061:/home/ht061/桌面/mutiarch# docker manifest inspect lurenjia/hello-arch
6. pull / 测试
由于之前已经启用了 binfmt_misc,现在我们就可以运行任何 CPU 架构的 Docker 镜像了,因此可以在本地系统上测试之前生成的 2个镜像是否有问题。 现在就可以通过 docker pull lurenjia/hello-arch 拉取刚刚创建的镜像了,Docker 将会根据你的 CPU 架构拉取匹配的镜像
root@HT061:/home/ht061/桌面/mutiarch# docker buildx imagetools inspect lurenjia/hello-arch
root@HT061:/home/ht061/桌面/mutiarch# docker run --rm docker.io/lurenjia/hello-arch:latest@sha256:cccc0329458f6a4a6a689080a8631b3634feeda5792ed0f6d00bc3fc86c02961
root@HT061:/home/ht061/桌面/mutiarch# docker run --rm docker.io/lurenjia/hello-arch:latest@sha256:5a99f4cd5f90b03e63a77e6646e6eda8daa297f492d22b5a3e061181da966bfd
docker pull / docker run 测试
在arm64上:
原生仓库支持此功能
root@HT061:/home/ht061/桌面/registry# ./test-registry.sh 192.168.17.187:5000/arch
Warning: some commands will fail if you are not authenticated to 192.168.17.187:5000/arch
>> 1: Pulling required images from DockerHub
>> 2: Tagging and pushing images to registry 192.168.17.187:5000/arch
docker tag s390x/alpine:latest 192.168.17.187:5000/arch/s390x_alpine:latest
The push refers to repository [192.168.17.187:5000/arch/s390x_alpine]
b0f4d46f0129: Mounted from s390x_alpine
latest: digest: sha256:842db5c820b72e078691118de1791c9baa15ba09c87235e70990186ac0f825de size: 528
docker tag ppc64le/alpine:latest 192.168.17.187:5000/arch/ppc64le_alpine:latest
The push refers to repository [192.168.17.187:5000/arch/ppc64le_alpine]
d80722399fe1: Mounted from ppc64le_alpine
latest: digest: sha256:04d04970e33c492fa411b508455d02a85978492db0403b8a714f365432c04f1c size: 528
docker tag aarch64/alpine:latest 192.168.17.187:5000/arch/aarch64_alpine:latest
The push refers to repository [192.168.17.187:5000/arch/aarch64_alpine]
6b5c485d13f0: Mounted from aarch64_alpine
latest: digest: sha256:6ace9a4351a3f02894c273cee7adc519318d6186f0d364fa37e418394576c5ef size: 528
docker tag alpine:latest 192.168.17.187:5000/arch/amd64_alpine:latest
The push refers to repository [192.168.17.187:5000/arch/amd64_alpine]
beee9f30bc1f: Mounted from amd64_alpine
latest: digest: sha256:cb8a924afdf0229ef7515d9e5b3024e23b3eb03ddbba287f4a19c6ac90b8d221 size: 528
>> 4: Attempt creating manifest list on registry 192.168.17.187:5000/arch
DEBU[0000] endpoints: [{false https://192.168.17.187:5000 v2 false true 0xc420062a80} {false http://192.168.17.187:5000 v2 false true 0xc420062a80} {false https://192.168.17.187:5000 v1 false true 0xc420062c00} {false http://192.168.17.187:5000 v1 false true 0xc420062c00}]
DEBU[0000] repoName: arch/alpine
INFO[0000] Retrieving digests of images...
DEBU[0000] authConfig for 192.168.17.187:5000:
DEBU[0000] endpoints: [{false https://192.168.17.187:5000 v2 false true 0xc420062f00} {false http://192.168.17.187:5000 v2 false true 0xc420062f00}]
DEBU[0000] Trying to fetch image manifest of 192.168.17.187:5000/arch/ppc64le_alpine repository from https://192.168.17.187:5000 v2
INFO[0000] Image "192.168.17.187:5000/arch/ppc64le_alpine:latest" is digest sha256:04d04970e33c492fa411b508455d02a85978492db0403b8a714f365432c04f1c; size: 528
DEBU[0000] Adding manifest references of "192.168.17.187:5000/arch/ppc64le_alpine:latest" to blob mount requests
DEBU[0000] Adding manifest "arch/ppc64le_alpine" -> to be pushed to "arch/alpine" as a manifest reference
DEBU[0000] authConfig for 192.168.17.187:5000:
DEBU[0000] endpoints: [{false https://192.168.17.187:5000 v2 false true 0xc4204d0600} {false http://192.168.17.187:5000 v2 false true 0xc4204d0600}]
DEBU[0000] Trying to fetch image manifest of 192.168.17.187:5000/arch/amd64_alpine repository from https://192.168.17.187:5000 v2
INFO[0000] Image "192.168.17.187:5000/arch/amd64_alpine:latest" is digest sha256:cb8a924afdf0229ef7515d9e5b3024e23b3eb03ddbba287f4a19c6ac90b8d221; size: 528
DEBU[0000] Adding manifest references of "192.168.17.187:5000/arch/amd64_alpine:latest" to blob mount requests
DEBU[0000] Adding manifest "arch/amd64_alpine" -> to be pushed to "arch/alpine" as a manifest reference
DEBU[0000] authConfig for 192.168.17.187:5000:
DEBU[0000] endpoints: [{false https://192.168.17.187:5000 v2 false true 0xc420349080} {false http://192.168.17.187:5000 v2 false true 0xc420349080}]
DEBU[0000] Trying to fetch image manifest of 192.168.17.187:5000/arch/s390x_alpine repository from https://192.168.17.187:5000 v2
INFO[0000] Image "192.168.17.187:5000/arch/s390x_alpine:latest" is digest sha256:842db5c820b72e078691118de1791c9baa15ba09c87235e70990186ac0f825de; size: 528
DEBU[0000] Adding manifest references of "192.168.17.187:5000/arch/s390x_alpine:latest" to blob mount requests
DEBU[0000] Adding manifest "arch/s390x_alpine" -> to be pushed to "arch/alpine" as a manifest reference
DEBU[0000] authConfig for 192.168.17.187:5000:
DEBU[0000] endpoints: [{false https://192.168.17.187:5000 v2 false true 0xc420063c80} {false http://192.168.17.187:5000 v2 false true 0xc420063c80}]
DEBU[0000] Trying to fetch image manifest of 192.168.17.187:5000/arch/aarch64_alpine repository from https://192.168.17.187:5000 v2
INFO[0000] Image "192.168.17.187:5000/arch/aarch64_alpine:latest" is digest sha256:6ace9a4351a3f02894c273cee7adc519318d6186f0d364fa37e418394576c5ef; size: 528
DEBU[0000] Adding manifest references of "192.168.17.187:5000/arch/aarch64_alpine:latest" to blob mount requests
DEBU[0000] Adding manifest "arch/aarch64_alpine" -> to be pushed to "arch/alpine" as a manifest reference
DEBU[0000] Manifest list push url: https://192.168.17.187:5000/v2/arch/alpine/manifests/latest
DEBU[0000] mediaType of manifestList: application/vnd.docker.distribution.manifest.list.v2+json
DEBU[0000] authConfig for 192.168.17.187:5000:
DEBU[0000] Mount of blob sha256:597c87082c114f1e78cf07db96e69306d6771ce8fe5f72cecb82a5c724c1bd9f succeeded, location: "https://192.168.17.187:5000/v2/arch/alpine/blobs/sha256:597c87082c114f1e78cf07db96e69306d6771ce8fe5f72cecb82a5c724c1bd9f"
DEBU[0000] Mount of blob sha256:bc1c99f4ba60de0d3ca52dc6855483e24c91884e33df71f502bbff6eb909d9b9 succeeded, location: "https://192.168.17.187:5000/v2/arch/alpine/blobs/sha256:bc1c99f4ba60de0d3ca52dc6855483e24c91884e33df71f502bbff6eb909d9b9"
DEBU[0000] Mount of blob sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72 succeeded, location: "https://192.168.17.187:5000/v2/arch/alpine/blobs/sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72"
DEBU[0000] Mount of blob sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819 succeeded, location: "https://192.168.17.187:5000/v2/arch/alpine/blobs/sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819"
DEBU[0000] Mount of blob sha256:452f204f05aae9837957231219a5d48e346220f0ac71874632109c1f8be49b9e succeeded, location: "https://192.168.17.187:5000/v2/arch/alpine/blobs/sha256:452f204f05aae9837957231219a5d48e346220f0ac71874632109c1f8be49b9e"
DEBU[0000] Mount of blob sha256:ca1c6795bfb97df28a926fd646127ba4944b69beb1cea7b00d62787b8b3c0108 succeeded, location: "https://192.168.17.187:5000/v2/arch/alpine/blobs/sha256:ca1c6795bfb97df28a926fd646127ba4944b69beb1cea7b00d62787b8b3c0108"
DEBU[0000] Mount of blob sha256:8e8812ba3b2d44c581d76fa0ad56a60e346c10cb1a778b10089d3d385502e0a4 succeeded, location: "https://192.168.17.187:5000/v2/arch/alpine/blobs/sha256:8e8812ba3b2d44c581d76fa0ad56a60e346c10cb1a778b10089d3d385502e0a4"
DEBU[0000] Mount of blob sha256:bc1d962af60541fd028aaa6f21d62a662d718b3571577acf3fb65c04a61b1150 succeeded, location: "https://192.168.17.187:5000/v2/arch/alpine/blobs/sha256:bc1d962af60541fd028aaa6f21d62a662d718b3571577acf3fb65c04a61b1150"
DEBU[0000] manifest reference push URL: https://192.168.17.187:5000/v2/arch/alpine/manifests/sha256:04d04970e33c492fa411b508455d02a85978492db0403b8a714f365432c04f1c
DEBU[0000] referenced manifest "arch/ppc64le_alpine" pushed; digest matches: sha256:04d04970e33c492fa411b508455d02a85978492db0403b8a714f365432c04f1c
DEBU[0000] manifest reference push URL: https://192.168.17.187:5000/v2/arch/alpine/manifests/sha256:cb8a924afdf0229ef7515d9e5b3024e23b3eb03ddbba287f4a19c6ac90b8d221
DEBU[0000] referenced manifest "arch/amd64_alpine" pushed; digest matches: sha256:cb8a924afdf0229ef7515d9e5b3024e23b3eb03ddbba287f4a19c6ac90b8d221
DEBU[0000] manifest reference push URL: https://192.168.17.187:5000/v2/arch/alpine/manifests/sha256:842db5c820b72e078691118de1791c9baa15ba09c87235e70990186ac0f825de
DEBU[0000] referenced manifest "arch/s390x_alpine" pushed; digest matches: sha256:842db5c820b72e078691118de1791c9baa15ba09c87235e70990186ac0f825de
DEBU[0000] manifest reference push URL: https://192.168.17.187:5000/v2/arch/alpine/manifests/sha256:6ace9a4351a3f02894c273cee7adc519318d6186f0d364fa37e418394576c5ef
DEBU[0000] referenced manifest "arch/aarch64_alpine" pushed; digest matches: sha256:6ace9a4351a3f02894c273cee7adc519318d6186f0d364fa37e418394576c5ef
Digest: sha256:1825baa9aeac87267c3132a89d87a10e8292d5e5042d25aded65923200c82bec 1388
root@HT061:/home/ht061/桌面/registry# cat test-registry.yml
image: __REGISTRY__/alpine:latest
manifests:
-
image: __REGISTRY__/ppc64le_alpine:latest
platform:
architecture: ppc64le
os: linux
-
image: __REGISTRY__/amd64_alpine:latest
platform:
architecture: amd64
os: linux
-
image: __REGISTRY__/s390x_alpine:latest
platform:
architecture: s390x
os: linux
-
image: __REGISTRY__/aarch64_alpine:latest
platform:
architecture: arm64
os: linux
variant: v8
root@HT061:/home/ht061/桌面/registry# cat test-registry.sh
#!/bin/bash
## This script will test creating a manifest list against a specified registry
## that claims to support the Docker v2 distribution API and the v2.2 image
## specification.
## It expects `manifest-tool` to be in the $PATH as well as the docker client.
## You must be authenticated via `docker login` to the registry provided or
## whatever method that registry provides for inserting docker authentication.
## It will pull 4 images from DockerHub (alpine for 4 architectures)
## and tag them against the provided registry; push them as images to that
## registry/repo and then use the `manifest-tool` to assemble them into a
## manifest list and push using the V2 API and V2 features (like cross-repository
## push and references to blobs already existing)
_REGISTRY="${1}"
_IMAGELIST="s390x/alpine
ppc64le/alpine
aarch64/alpine
alpine"
[ -z "${_REGISTRY}" ] && {
echo "Please provide a registry URL + namespace/repo name as the first parameter"
exit 1
}
echo "Warning: some commands will fail if you are not authenticated to ${_REGISTRY}"
echo ">> 1: Pulling required images from DockerHub"
for i in $_IMAGELIST; do
docker pull ${i}:latest
done
echo ">> 2: Tagging and pushing images to registry ${_REGISTRY}"
for i in $_IMAGELIST; do
target="${i/\//_}"
[ "${target}" == "${i}" ] && {
# special case for no arch prefix on amd64 (x86_64 Linux) images
target="amd64_${i}"
}
echo docker tag ${i}:latest ${_REGISTRY}/${target}:latest
docker tag ${i}:latest ${_REGISTRY}/${target}:latest
docker push ${_REGISTRY}/${target}:latest
done
echo ">> 4: Attempt creating manifest list on registry ${_REGISTRY}"
sed s,__REGISTRY__,${_REGISTRY}, test-registry.yml >test-registry.yaml
manifest-tool --debug push from-spec test-registry.yaml
harbor-2.0.0 测试
支持此功能:
手动上传manifest:
root@HT061:/opt/harbor-2.0.0/harbor/timi# docker images | grep alpine | grep ygt.h | grep 0.0.1
ygt.harbor.csse/timi/s390x_alpine 0.0.1 452f204f05aa 8 weeks ago 5.65MB
ygt.harbor.csse/timi/ppc64le_alpine 0.0.1 597c87082c11 8 weeks ago 6.63MB
ygt.harbor.csse/timi/amd64_alpine 0.0.1 a187dde48cd2 8 weeks ago 5.6MB
ygt.harbor.csse/timi/aarch64_alpine 0.0.1 8e8812ba3b2d 3 years ago 3.83MB
root@HT061:/opt/harbor-2.0.0/harbor/timi#
#上传
root@HT061:/opt/harbor-2.0.0/harbor/timi# docker push ygt.harbor.csse/timi/s390x_alpine:0.0.1
The push refers to repository [ygt.harbor.csse/timi/s390x_alpine]
b0f4d46f0129: Layer already exists
0.0.1: digest: sha256:842db5c820b72e078691118de1791c9baa15ba09c87235e70990186ac0f825de size: 528
root@HT061:/opt/harbor-2.0.0/harbor/timi# docker push ygt.harbor.csse/timi/ppc64le_alpine:0.0.1
The push refers to repository [ygt.harbor.csse/timi/ppc64le_alpine]
d80722399fe1: Layer already exists
0.0.1: digest: sha256:04d04970e33c492fa411b508455d02a85978492db0403b8a714f365432c04f1c size: 528
root@HT061:/opt/harbor-2.0.0/harbor/timi# docker push ygt.harbor.csse/timi/amd64_alpine:0.0.1
The push refers to repository [ygt.harbor.csse/timi/amd64_alpine]
beee9f30bc1f: Layer already exists
0.0.1: digest: sha256:cb8a924afdf0229ef7515d9e5b3024e23b3eb03ddbba287f4a19c6ac90b8d221 size: 528
root@HT061:/opt/harbor-2.0.0/harbor/timi# docker push ygt.harbor.csse/timi/aarch64_alpine:0.0.1
The push refers to repository [ygt.harbor.csse/timi/aarch64_alpine]
6b5c485d13f0: Layer already exists
0.0.1: digest: sha256:6ace9a4351a3f02894c273cee7adc519318d6186f0d364fa37e418394576c5ef size: 528
root@HT061:/opt/harbor-2.0.0/harbor/timi#
#创建manifest
root@HT061:/opt/harbor-2.0.0/harbor/timi# docker manifest create ygt.harbor.csse/timi/alpine:0.0.1 ygt.harbor.csse/timi/s390x_alpine:0.0.1 ygt.harbor.csse/timi/ppc64le_alpine:0.0.1 ygt.harbor.csse/timi/amd64_alpine:0.0.1 ygt.harbor.csse/timi/aarch64_alpine:0.0.1
Created manifest list ygt.harbor.csse/timi/alpine:0.0.1
#push manifest
root@HT061:/opt/harbor-2.0.0/harbor/timi# docker manifest push ygt.harbor.csse/timi/alpine:0.0.1
Pushed ref ygt.harbor.csse/timi/alpine@sha256:6ace9a4351a3f02894c273cee7adc519318d6186f0d364fa37e418394576c5ef with digest: sha256:6ace9a4351a3f02894c273cee7adc519318d6186f0d364fa37e418394576c5ef
Pushed ref ygt.harbor.csse/timi/alpine@sha256:cb8a924afdf0229ef7515d9e5b3024e23b3eb03ddbba287f4a19c6ac90b8d221 with digest: sha256:cb8a924afdf0229ef7515d9e5b3024e23b3eb03ddbba287f4a19c6ac90b8d221
Pushed ref ygt.harbor.csse/timi/alpine@sha256:04d04970e33c492fa411b508455d02a85978492db0403b8a714f365432c04f1c with digest: sha256:04d04970e33c492fa411b508455d02a85978492db0403b8a714f365432c04f1c
Pushed ref ygt.harbor.csse/timi/alpine@sha256:842db5c820b72e078691118de1791c9baa15ba09c87235e70990186ac0f825de with digest: sha256:842db5c820b72e078691118de1791c9baa15ba09c87235e70990186ac0f825de
sha256:e959c02d88f4d4fceabba95f2136a1932d56d3ab438adc581403f8ae65655ea5
root@HT061:/opt/harbor-2.0.0/harbor/timi#
#查看manifest
root@HT061:/opt/harbor-2.0.0/harbor/timi# docker manifest inspect ygt.harbor.csse/timi/alpine:0.0.1
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 528,
"digest": "sha256:6ace9a4351a3f02894c273cee7adc519318d6186f0d364fa37e418394576c5ef",
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 528,
"digest": "sha256:cb8a924afdf0229ef7515d9e5b3024e23b3eb03ddbba287f4a19c6ac90b8d221",
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 528,
"digest": "sha256:04d04970e33c492fa411b508455d02a85978492db0403b8a714f365432c04f1c",
"platform": {
"architecture": "ppc64le",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 528,
"digest": "sha256:842db5c820b72e078691118de1791c9baa15ba09c87235e70990186ac0f825de",
"platform": {
"architecture": "s390x",
"os": "linux"
}
}
]
}
root@HT061:/opt/harbor-2.0.0/harbor/timi#