[アップデート] ECR リポジトリ間でレイヤーを共有できる Blob マウント機能を利用できるようになりました
概要
ECR リポジトリ間でレイヤーを共有できる Blob マウント機能が利用できるようになりました。
ECR へのイメージプッシュ時、他リポジトリに同等のレイヤーが存在する場合は再プッシュが不要になり、下記メリットがあります。
- ECR のストレージコストが削減される
- イメージプッシュ時間が短くなる
- GitHub Actions などでイメージをビルドしてプッシュしていた際、そちらの利用時間が短くなる
コスト面でのメリットを考えると有効化しない理由が無いと言えます。
Blob マウンティングの仕組み
ECR のようなコンテナレジストリの標準仕様として、OCI Distribution Specification が定義されています。
Blob マウンティングは ECR 独自のものでは無く、OCI Distribution Specification でも定義されている一般的な機能になります。
If a necessary blob exists already in another repository, it can be mounted into a different repository via a POST request in the following format:
/v2/<name>/blobs/uploads/?mount=<digest>&from=<other_name>
https://github.com/opencontainers/distribution-spec/blob/v1.0.0/spec.md#mounting-a-blob-from-another-repository
OCI Client 側は元々対応しており、Blob ファイルが存在するかどうかを ECR 側が返却するようになったと考えれば良さそうです。
以前から Blob マウンティングを利用できる Docker Hub のドキュメントも参考になります。
Get a bearer token for the repository
Check if the blob exists using a HEAD request for each blob digest.
If the blob does not exist, upload the blob using a monolithic PUT request:
・First, initiate the upload with POST.
・Then upload and complete with PUT.
https://docs.docker.com/reference/api/registry/latest/#tag/push
ECR での具体的な実装までは確認できていないですが、下図のようなイメージで既存レイヤーを利用できます。

ECR で Blob マウンティングを利用する際の制約について
アカウントとリージョンが同じで、暗号化設定が同じであれば Blob マウンティングが利用できます。
Blob mounting only works within the same registry (same account and region).
Repositories must use identical encryption type and keys.
https://docs.aws.amazon.com/AmazonECR/latest/userguide/blob-mounting.html
また、現状プライベートレジストリ専用の機能になるようです。
検証してみる
ECR のサービスページに移動して、「プライベートレジストリ > 機能と設定 > ブロブマウンティング」でトグルを有効にするだけです。

今回、クライアント側は Container Engine に dockerd (moby) を指定した Rancher Desktop を利用します。
% docker version --format '{{json .Client}}' | jq
{
"Version": "29.1.4-rd",
"ApiVersion": "1.52",
"DefaultAPIVersion": "1.52",
"GitCommit": "3c6914c",
"GoVersion": "go1.25.5",
"Os": "darwin",
"Arch": "arm64",
"BuildTime": "Fri Jan 9 20:45:44 2026",
"Context": "rancher-desktop"
}
利用する Dockerfile は下記で、ベースイメージは node:22-bookworm を利用しています。
FROM node:22-bookworm
WORKDIR /app
RUN corepack enable
COPY . .
RUN pnpm install
RUN pnpm run build
EXPOSE 80
CMD ["pnpm", "run", "start"]
イメージをビルドします。
% docker build \
--platform=linux/x86_64 \
-t sample-ecs-app1:v1 \
-f Dockerfile .
[+] Building 60.4s (12/12) FINISHED docker:rancher-desktop
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 183B 0.0s
=> [internal] load metadata for docker.io/library/node:22-bookworm 2.5s
=> [auth] library/node:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/6] FROM docker.io/library/node:22-bookworm@sha256:cd7bcd2e7a1e6f72052feb023c7f6b722205d3fcab7bbcbd2d1bfdab10b1e935 22.3s
=> => resolve docker.io/library/node:22-bookworm@sha256:cd7bcd2e7a1e6f72052feb023c7f6b722205d3fcab7bbcbd2d1bfdab10b1e935 0.0s
=> => sha256:fd1872fa12cc6b1145803f1a0679ca26cc65fa1b4e0ee389bfb30267594736b6 64.40MB / 64.40MB 5.7s
=> => sha256:cd7bcd2e7a1e6f72052feb023c7f6b722205d3fcab7bbcbd2d1bfdab10b1e935 6.41kB / 6.41kB 0.0s
=> => sha256:58b82c7153457434610289a1f61c4326cc9ea77b996a8e9b3cdd92c9814bd7e6 2.49kB / 2.49kB 0.0s
=> => sha256:a08c488a9779570021138dacddb3138542f6632362b21bb14a7e5d5621e34258 6.74kB / 6.74kB 0.0s
=> => sha256:c1be109a62df95316ceac87ea501079f32e17f36b636865a860841b7db06100c 48.48MB / 48.48MB 3.0s
=> => sha256:64538a062a61add8dc8b290fa69475e8902eb839c497a5f5dcd5a950422e493c 24.04MB / 24.04MB 1.8s
=> => sha256:4925cf9d8be888d2b942e0479d921815942727632813c006bad6a067e6363663 211.49MB / 211.49MB 9.6s
=> => extracting sha256:c1be109a62df95316ceac87ea501079f32e17f36b636865a860841b7db06100c 2.8s
=> => sha256:357cb6974fa00f5868ed182a039825412fca969c0988eb54c7114136aba26f0b 3.32kB / 3.32kB 3.5s
=> => sha256:a6174c95fe7408545d8621aba806a8dce153306ae7f114bf6cfc66854efa5494 58.30MB / 58.30MB 7.5s
=> => sha256:737aff54b15787f7e024f1e1a146d3d7677be2f217565c88152937be519722ec 1.25MB / 1.25MB 6.2s
=> => extracting sha256:64538a062a61add8dc8b290fa69475e8902eb839c497a5f5dcd5a950422e493c 0.9s
=> => sha256:5e9e90c62a56b42994131b60a9afcd3851a32cabafa66d482444ab1dcbdbc620 446B / 446B 6.7s
=> => extracting sha256:fd1872fa12cc6b1145803f1a0679ca26cc65fa1b4e0ee389bfb30267594736b6 3.3s
=> => extracting sha256:4925cf9d8be888d2b942e0479d921815942727632813c006bad6a067e6363663 8.1s
=> => extracting sha256:357cb6974fa00f5868ed182a039825412fca969c0988eb54c7114136aba26f0b 0.0s
=> => extracting sha256:a6174c95fe7408545d8621aba806a8dce153306ae7f114bf6cfc66854efa5494 3.0s
=> => extracting sha256:737aff54b15787f7e024f1e1a146d3d7677be2f217565c88152937be519722ec 0.0s
=> => extracting sha256:5e9e90c62a56b42994131b60a9afcd3851a32cabafa66d482444ab1dcbdbc620 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 13.80kB 0.0s
=> [2/6] WORKDIR /app 0.5s
=> [3/6] RUN corepack enable 1.1s
=> [4/6] COPY . . 0.0s
=> [5/6] RUN pnpm install 11.1s
=> [6/6] RUN pnpm run build 22.6s
=> exporting to image 0.3s
=> => exporting layers 0.3s
=> => writing image sha256:aa88b4b4ec32eaef2a7d9e1f0da7dc39a80060ef5e48ab50ea4cb0ea43472429 0.0s
=> => naming to docker.io/library/sample-ecs-app1:v1
inspect コマンドで確認すると 13 レイヤー存在します。
% docker image inspect sample-ecs-app1:v1
[
{
"Id": "sha256:aa88b4b4ec32eaef2a7d9e1f0da7dc39a80060ef5e48ab50ea4cb0ea43472429",
"RepoTags": [
"sample-ecs-app1:v1"
],
"RepoDigests": [],
"Comment": "buildkit.dockerfile.v0",
"Created": "2026-01-26T18:31:39.840563389+09:00",
"Config": {
"ExposedPorts": {
"80/tcp": {}
},
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NODE_VERSION=22.22.0",
"YARN_VERSION=1.22.22"
],
"Entrypoint": [
"docker-entrypoint.sh"
],
"Cmd": [
"pnpm",
"run",
"start"
],
"WorkingDir": "/app",
"ArgsEscaped": true
},
"Architecture": "amd64",
"Os": "linux",
"Size": 1196643713,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/od3lv162f61lq4tlkq9qv4v8d/diff:/var/lib/docker/overlay2/0wa8akz0t29y9e9ips4z9jxo1/diff:/var/lib/docker/overlay2/k9g6vkzu2hz22g0g6kvc9xbya/diff:/var/lib/docker/overlay2/loz6ohzdl5h0n05y54hxpbeps/diff:/var/lib/docker/overlay2/f6817fd0f4b5ecee53865ecf7b19628faa479b9951608ec5e69a511d928c1d31/diff:/var/lib/docker/overlay2/5def0c3cb1982576bc2ebc0a10e5e77bc2868d576eecbb9d11b1e9840fc3e3c2/diff:/var/lib/docker/overlay2/42cca240b8c949ce69764e0531d5267051178ae497b765eafc80b9ea23427454/diff:/var/lib/docker/overlay2/02a7e17bd7519e51368549ea1301c398b2c5f78c10cb4c96bc5b9ea7e109fe54/diff:/var/lib/docker/overlay2/221773ffaf3d84d3ab5d95961091e487509d0253c0adbd75e4f225a05bb22337/diff:/var/lib/docker/overlay2/2cb00f7b3e0473dc8bfe8d83cc22d043a931a985d60c1956944ba5eb89f3dd4b/diff:/var/lib/docker/overlay2/27a301181c4a696e8161337240305baa11eb01556e2da91aeccdab37e0a42662/diff:/var/lib/docker/overlay2/bb67cd6cf2876bdac251044f5345f6c4bbca212c11fc7bc96736da4814c9b786/diff",
"MergedDir": "/var/lib/docker/overlay2/w3h78x2si7k56xo2k5y0hl9yr/merged",
"UpperDir": "/var/lib/docker/overlay2/w3h78x2si7k56xo2k5y0hl9yr/diff",
"WorkDir": "/var/lib/docker/overlay2/w3h78x2si7k56xo2k5y0hl9yr/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:f77cd126bcdfedb7ff4e195153ee4ee6ac48cbd420cdb5a74595148f70839557",
"sha256:881e9a2631bef0498cf356a846f379e423cbfbf4dc18cc33d403952fdb8485d4",
"sha256:7c3c6c0e7920cd95ff3cd4b1c27f16f2cc95ce1476526b243cda0ab17ce621e7",
"sha256:615dfee08a6cb44800f56db6a24db3816c61b661af488693c90c47465ae2fb69",
"sha256:44fe76e92c267903c4a3f383d18e65efbf667f1f70578a6ffe2c828d991ba5e1",
"sha256:505dc992a4c97ed295cdbbe8d9fcebc16065e39b9131999e3074b68eb66e1e38",
"sha256:9a2d436e19b36e8aba13dd24fa8318bd975092d95ee0a9b52fbd8486414e6f71",
"sha256:5f24a50d908d76e9a43a2ac37e60a95863677ca6a94d7ede16a4e6f1eef77c39",
"sha256:e8e2b9946fdbbbe24354f52616720492dae7a1faf713d9f7d0a0ae54f8508797",
"sha256:72900796864fb69a6e9be3d50067c582d115db4893fd95a6682d315aa1afaf95",
"sha256:6a723e07a2760f1cbedb361cbeb7c5aab4141dff503fea0d52955a47e1a92a88",
"sha256:5b63f81449ea223a9e392c6ef9e9f1e5fa04ebf5895885e2eb6959b95e54b45a",
"sha256:adceef049edf4799370f05fdda04024f440800309456c0e7611a757ce96a44c9"
]
},
"Metadata": {
"LastTagTime": "2026-01-26T18:31:40.126390222+09:00"
}
}
]
history は下記のようになりました。
% docker image history sample-ecs-app1:v1
IMAGE CREATED CREATED BY SIZE COMMENT
aa88b4b4ec32 50 seconds ago CMD ["pnpm" "run" "start"] 0B buildkit.dockerfile.v0
<missing> 50 seconds ago EXPOSE [80/tcp] 0B buildkit.dockerfile.v0
<missing> 50 seconds ago RUN /bin/sh -c pnpm run build # buildkit 1.33MB buildkit.dockerfile.v0
<missing> About a minute ago RUN /bin/sh -c pnpm install # buildkit 62.2MB buildkit.dockerfile.v0
<missing> About a minute ago COPY . . # buildkit 12.7kB buildkit.dockerfile.v0
<missing> About a minute ago RUN /bin/sh -c corepack enable # buildkit 137kB buildkit.dockerfile.v0
<missing> About a minute ago WORKDIR /app 0B buildkit.dockerfile.v0
<missing> 11 days ago CMD ["node"] 0B buildkit.dockerfile.v0
<missing> 11 days ago ENTRYPOINT ["docker-entrypoint.sh"] 0B buildkit.dockerfile.v0
<missing> 11 days ago COPY docker-entrypoint.sh /usr/local/bin/ # … 388B buildkit.dockerfile.v0
<missing> 11 days ago RUN /bin/sh -c set -ex && export GNUPGHOME… 5.34MB buildkit.dockerfile.v0
<missing> 11 days ago ENV YARN_VERSION=1.22.22 0B buildkit.dockerfile.v0
<missing> 11 days ago RUN /bin/sh -c ARCH= && dpkgArch="$(dpkg --p… 198MB buildkit.dockerfile.v0
<missing> 11 days ago ENV NODE_VERSION=22.22.0 0B buildkit.dockerfile.v0
<missing> 11 days ago RUN /bin/sh -c groupadd --gid 1000 node &&… 8.94kB buildkit.dockerfile.v0
<missing> 13 days ago RUN /bin/sh -c set -ex; apt-get update; ap… 588MB buildkit.dockerfile.v0
<missing> 13 days ago RUN /bin/sh -c set -eux; apt-get update; a… 177MB buildkit.dockerfile.v0
<missing> 13 days ago RUN /bin/sh -c set -eux; apt-get update; a… 48.4MB buildkit.dockerfile.v0
<missing> 2 weeks ago # debian.sh --arch 'amd64' out/ 'bookworm' '… 117MB debuerreotype 0.17
SIZE が表記されている部分 (RUN、COPY、最初のレイヤー)と WORKDIR で 13 レイヤーになります。
タグを付け替えて ECR にプッシュすると、すべてのレイヤーが Pushed になりました。
% docker push xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-ecs-app1:v1
The push refers to repository [xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-ecs-app1]
adceef049edf: Pushed
5b63f81449ea: Pushed
6a723e07a276: Pushed
72900796864f: Pushed
e8e2b9946fdb: Pushed
5f24a50d908d: Pushed
9a2d436e19b3: Pushed
505dc992a4c9: Pushed
44fe76e92c26: Pushed
615dfee08a6c: Pushed
7c3c6c0e7920: Pushed
881e9a2631be: Pushed
f77cd126bcdf: Pushed
v1: digest: sha256:0244053ce7d04c7e374e47836351495c832afaf1dab5a73496e8de5222f7ae62 size: 3049
アプリケーションを少し改変して再度ビルドします。
最後の 3 レイヤー (COPY . .、RUN pnpm install、RUN pnpm run build) が作り直されました。
% docker build \
--platform=linux/x86_64 \
-t sample-ecs-app2:v1 \
-f Dockerfile .
[+] Building 36.0s (11/11) FINISHED docker:rancher-desktop
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 183B 0.0s
=> [internal] load metadata for docker.io/library/node:22-bookworm 0.8s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/6] FROM docker.io/library/node:22-bookworm@sha256:cd7bcd2e7a1e6f72052feb023c7f6b722205d3fcab7bbcbd2d1bfdab10b1e935 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 2.29kB 0.0s
=> CACHED [2/6] WORKDIR /app 0.0s
=> CACHED [3/6] RUN corepack enable 0.0s
=> [4/6] COPY . . 0.0s
=> [5/6] RUN pnpm install 11.0s
=> [6/6] RUN pnpm run build 23.9s
=> exporting to image 0.3s
=> => exporting layers 0.3s
=> => writing image sha256:c8f88161c31598862f7933439d46da1be4801bf386b99bdb4953a9b0ef0f519d 0.0s
=> => naming to docker.io/library/sample-ecs-app2:v1
inspect コマンドでも最後の 3 レイヤーが変わっていることがわかります。
% docker image inspect sample-ecs-app2:v1
[
{
"Id": "sha256:c8f88161c31598862f7933439d46da1be4801bf386b99bdb4953a9b0ef0f519d",
"RepoTags": [
"sample-ecs-app2:v1"
],
"RepoDigests": [],
"Comment": "buildkit.dockerfile.v0",
"Created": "2026-01-26T18:35:19.600101702+09:00",
"Config": {
"ExposedPorts": {
"80/tcp": {}
},
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NODE_VERSION=22.22.0",
"YARN_VERSION=1.22.22"
],
"Entrypoint": [
"docker-entrypoint.sh"
],
"Cmd": [
"pnpm",
"run",
"start"
],
"WorkingDir": "/app",
"ArgsEscaped": true
},
"Architecture": "amd64",
"Os": "linux",
"Size": 1196643759,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/j0gok9x8dchxogdp3klxens6h/diff:/var/lib/docker/overlay2/cajqxldlkn6biwiqegsjnglkb/diff:/var/lib/docker/overlay2/k9g6vkzu2hz22g0g6kvc9xbya/diff:/var/lib/docker/overlay2/loz6ohzdl5h0n05y54hxpbeps/diff:/var/lib/docker/overlay2/f6817fd0f4b5ecee53865ecf7b19628faa479b9951608ec5e69a511d928c1d31/diff:/var/lib/docker/overlay2/5def0c3cb1982576bc2ebc0a10e5e77bc2868d576eecbb9d11b1e9840fc3e3c2/diff:/var/lib/docker/overlay2/42cca240b8c949ce69764e0531d5267051178ae497b765eafc80b9ea23427454/diff:/var/lib/docker/overlay2/02a7e17bd7519e51368549ea1301c398b2c5f78c10cb4c96bc5b9ea7e109fe54/diff:/var/lib/docker/overlay2/221773ffaf3d84d3ab5d95961091e487509d0253c0adbd75e4f225a05bb22337/diff:/var/lib/docker/overlay2/2cb00f7b3e0473dc8bfe8d83cc22d043a931a985d60c1956944ba5eb89f3dd4b/diff:/var/lib/docker/overlay2/27a301181c4a696e8161337240305baa11eb01556e2da91aeccdab37e0a42662/diff:/var/lib/docker/overlay2/bb67cd6cf2876bdac251044f5345f6c4bbca212c11fc7bc96736da4814c9b786/diff",
"MergedDir": "/var/lib/docker/overlay2/56ytvmxawcvc8g11k1cm91o8c/merged",
"UpperDir": "/var/lib/docker/overlay2/56ytvmxawcvc8g11k1cm91o8c/diff",
"WorkDir": "/var/lib/docker/overlay2/56ytvmxawcvc8g11k1cm91o8c/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:f77cd126bcdfedb7ff4e195153ee4ee6ac48cbd420cdb5a74595148f70839557",
"sha256:881e9a2631bef0498cf356a846f379e423cbfbf4dc18cc33d403952fdb8485d4",
"sha256:7c3c6c0e7920cd95ff3cd4b1c27f16f2cc95ce1476526b243cda0ab17ce621e7",
"sha256:615dfee08a6cb44800f56db6a24db3816c61b661af488693c90c47465ae2fb69",
"sha256:44fe76e92c267903c4a3f383d18e65efbf667f1f70578a6ffe2c828d991ba5e1",
"sha256:505dc992a4c97ed295cdbbe8d9fcebc16065e39b9131999e3074b68eb66e1e38",
"sha256:9a2d436e19b36e8aba13dd24fa8318bd975092d95ee0a9b52fbd8486414e6f71",
"sha256:5f24a50d908d76e9a43a2ac37e60a95863677ca6a94d7ede16a4e6f1eef77c39",
"sha256:e8e2b9946fdbbbe24354f52616720492dae7a1faf713d9f7d0a0ae54f8508797",
"sha256:72900796864fb69a6e9be3d50067c582d115db4893fd95a6682d315aa1afaf95",
"sha256:9882b30132cc30785447ede43545e7594f09c460e90ee892859f860c0f4a30f9",
"sha256:6c9361d512425a1ad40a6a16e6c4be9881cdf4ada779a729cf06edc08e5d087d",
"sha256:e3a6a2c6232418aafed8cfb1b1872d852eeebcc8ae7ff785186cd6bf2f0b516a"
]
},
"Metadata": {
"LastTagTime": "2026-01-26T18:35:19.90009216+09:00"
}
}
]
タグを変えてプッシュすると 3 つ以外は Mounted from sample-ecs-app1 となりました。
% docker push xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-ecs-app2:v1
The push refers to repository [xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-ecs-app2]
e3a6a2c62324: Pushed
6c9361d51242: Pushed
9882b30132cc: Pushed
72900796864f: Mounted from sample-ecs-app1
e8e2b9946fdb: Mounted from sample-ecs-app1
5f24a50d908d: Mounted from sample-ecs-app1
9a2d436e19b3: Mounted from sample-ecs-app1
505dc992a4c9: Mounted from sample-ecs-app1
44fe76e92c26: Mounted from sample-ecs-app1
615dfee08a6c: Mounted from sample-ecs-app1
7c3c6c0e7920: Mounted from sample-ecs-app1
881e9a2631be: Mounted from sample-ecs-app1
f77cd126bcdf: Mounted from sample-ecs-app1
v1: digest: sha256:50fbdd305d1cdb3e12169d8c5a14d3efa78f3a5ecc91073aed715b781e546439 size: 3049
無事 Blob マウントを利用できてそうですね!
後から Blob マウント無効化した場合
Blob マウントを OFF にした場合、次のイメージプッシュから Blob マウントされなくなりました(即時反映されるようです)。
ただし、昔の Blob マウントを利用したイメージが使えなくなるわけでは無いです。
If you decide to disable blob mounting, existing images that were pushed with blob mounting configured will continue to work and layers will remain mounted.
https://docs.aws.amazon.com/AmazonECR/latest/userguide/blob-mounting.html#blob_mounting_concepts
実際、Blob マウントを無効化した状態で sample-ecs-app2 にプッシュしたイメージを利用できました。
Blob マウントを無効化するケースは無い気がしますが、この点でも安心ですね。
最後に
大きくコストメリットが出るかは環境次第ですが、有効化しない理由は無いくらいの機能だと思います。
設定も簡単なので是非試してみて下さい!






