---
slug: "docker-29-ecr-push-403-forbidden-containerd-image-store"
title: "Docker 29 で GitHub Actions から ECR への docker push が 403 Forbidden になる問題と対処法"
description: "GitHub Actions の ubuntu-latest ランナーが Docker 29 に更新され、containerd image store がデフォルトになったことで ECR への push が 403 Forbidden で失敗する問題の解説と対処法。"
url: "https://www.ytyng.com/blog/docker-29-ecr-push-403-forbidden-containerd-image-store"
publish_date: "2026-02-13T02:34:24Z"
created: "2026-02-13T02:34:24.794Z"
updated: "2026-03-01T23:36:57.769Z"
categories: []
keywords: ""
featured_image_url: "https://media.ytyng.com/resize/20260213/e7451e22c74a424881f66136b3857bd7.png.webp?width=768"
has_video: true
has_music: true
video_urls: ["https://media.ytyng.net/ytyng-blog/334/featured-video-1.mp4", "https://media.ytyng.net/ytyng-blog/334/featured-video-2.mp4", "https://media.ytyng.net/ytyng-blog/334/featured-video-3.mp4"]
music_urls: ["https://media.ytyng.net/ytyng-blog/334/featured-music-334-3.mp3", "https://media.ytyng.net/ytyng-blog/334/featured-music-334-4.mp3"]
lang: "ja"
---

# Docker 29 で GitHub Actions から ECR への docker push が 403 Forbidden になる問題と対処法

## AIコーディングエージェント用修正プロンプト

```
Github ワークフローでの docker push が失敗している。
 https://www.ytyng.com/blog/docker-29-ecr-push-403-forbidden-containerd-image-store に解決方法が書いてあるので、見て対応して
```

## 概要

2026年2月9日、GitHub Actions の `ubuntu-latest` ランナーイメージが更新され、Docker が **28 → 29** にアップデートされた。

これにより、それまで正常に動作していた ECR (Amazon Elastic Container Registry) への `docker push` が突然 **403 Forbidden** エラーで失敗するようになった。

## エラーの内容

```
unknown: unexpected status from HEAD request to
https://***.dkr.ecr.ap-northeast-1.amazonaws.com/v2/repo-name/manifests/0.1.99:
403 Forbidden
```

特徴的なのは、**Docker イメージのレイヤーは全て正常に push される**にも関わらず、最後の **manifest の push だけが 403 で失敗する**という点。

## 原因: Docker 29 の containerd image store

Docker 29 では、**containerd image store** がデフォルトで有効になった。

従来の Docker (28以前) では、`docker build` で作成されたイメージは Docker 独自の image store に保存され、`docker push` は Docker Image Manifest V2 形式で push していた。

Docker 29 では、ビルドされたイメージが containerd の image store に保存される。この場合、`docker push` 時に生成される manifest の形式が変わり、ECR がこれを受け付けずに 403 Forbidden を返す。

ビルドログで確認できる兆候として、Docker 28 では見られなかった **`unpacking to ...`** という行が `docker build` の出力に現れる。これが containerd image store が使われている証拠。

```
# Docker 29 (containerd image store が有効な場合)
#20 naming to ***.dkr.ecr.../image:0.1.99 done
#20 unpacking to ***.dkr.../image:0.1.99          ← これが出る
#20 unpacking to ***.dkr.../image:0.1.99 3.2s done
```

```
# Docker 28 (従来の image store)
#20 naming to ***.dkr.ecr.../image:0.1.95 done
                                                    ← unpacking は出ない
```

## 対処法: containerd snapshotter を無効化する

GitHub Actions の workflow ファイルで、Docker daemon の設定を変更して containerd snapshotter を無効化する。

```yaml
steps:
  - uses: actions/checkout@v3

  - name: Disable containerd image store
    run: |
      DAEMON_JSON="/etc/docker/daemon.json"
      if [ -f "$DAEMON_JSON" ]; then
        sudo jq '. + {"features": {"containerd-snapshotter": false}}' "$DAEMON_JSON" \
          | sudo tee "${DAEMON_JSON}.tmp" > /dev/null
        sudo mv "${DAEMON_JSON}.tmp" "$DAEMON_JSON"
      else
        echo '{"features": {"containerd-snapshotter": false}}' \
          | sudo tee "$DAEMON_JSON" > /dev/null
      fi
      sudo systemctl restart docker
```

### ポイント

- `ubuntu-latest` ランナーには **`/etc/docker/daemon.json` が存在しない場合がある**ため、ファイルの存在確認が必要。存在しない場合は新規作成する。
- 設定変更後に `sudo systemctl restart docker` で Docker daemon を再起動する必要がある。
- 既存の `daemon.json` がある場合は `jq` でマージすることで、他の設定を壊さないようにする。

## 環境情報

| 項目 | 成功時 (2025-12) | 失敗時 (2026-02) |
|---|---|---|
| ランナーイメージ | ubuntu24/20251215 | ubuntu24/20260209 |
| Docker | 28.0.4 | 29.1.5 |
| Docker Buildx | 0.30.1 | 0.31.1 |
| containerd image store | 無効 (デフォルト) | **有効 (デフォルト)** |

## 参考リンク

- [docker/build-push-action #826 - Possible incompatibility with AWS ECR](https://github.com/docker/build-push-action/issues/826)
- [docker/build-push-action #983 - Push to ECR registry fails with 403 Forbidden](https://github.com/docker/build-push-action/discussions/983)
- [Docker Docs - Exporters](https://docs.docker.com/build/exporters/)
