-- Views
November 12, 26
スライド概要
本資料では、まずDockerとレジストリの基本概念を説明し、CloudShellでGHCR(GitHub Container Registry)からECR(Amazon Elastic Container Registry)へイメージをコピーする手順を示します。Docker pull による取得時にルート領域の容量が枯渇し、"no space left on device" エラーが発生した原因と対処法を詳細に分析します。その上で、Docker の展開工程を省き容量負荷を抑える "crane" ツールの導入方法と使用例を紹介し、認証・認可の手順(IAM権限取得、ECR ログイン、push 許可確認)も解説します。さらに、コピー時のダイジェスト照合やタグ管理のポイント、CloudShell の利用上の注意点(VPC エンドポイント、プライベートリンク)についても触れ、実務で安全にイメージを移行できるようまとめています。
CloudShellで GHCRからECRへコピー 2026/11/13 品川会#10 ムカイヤマ ※個人の見解であり、所属組織とは無関係です。
自己紹介 ムカイヤマ ・所属:SIer(AWS中心のインフラ設計・構築) - オンプレからAWSの移行 - 脆弱性対応 ・好きなAWSサービス・ツール: AWS CLI、Systems Manager、AWSサポート ・2026 Japan AWS Jr. Champions ▲過去の登壇資料 ※資料の内容は 個人の見解であり、 所属組織とは無関係です。
本日お話しすること • Docker・レジストリの前提知識 • CloudShellを使ったGHCR → ECRのコピー • コピー中に起きた問題と対処 今回は扱わないこと • コンテナの実行・アプリのデプロイ
GHCRからECRへコピーする GHCR・ECRはイメージを保管するレジストリ GHCR(コピー元) GitHub Container Registry コピー ECR(コピー先) Amazon Elastic Container Registry 今回はCloudShellでコピー操作を実行 docs.github.com/…/working-with-the-container-registry
pullは取得、runは起動 同じイメージから複数のコンテナを実行できる。 pull レジストリ ghcr.io owner/app:v1 docker run イメージ アプリ・ライブラリ 実行に必要な設定 読み取り専用 docs.docker.com/…/what-is-an-image/ docs.docker.com/…/what-is-a-container/ コンテナA 隔離された実行環境 コンテナB 隔離された実行環境
ECRで外部イメージを使う レジストリ:イメージを保管・配布するサービス リポジトリ:レジストリ内のイメージの保管単位 GHCR 取得 Docker Hub Amazon ECR Public Amazon ECR
公開GHCRは認証なしで取得 GitHub Container Registry(ghcr.io) 公開イメージは匿名でpull可能 非公開イメージは別途認証・権限が必要 docs.github.com/…/working-with-the-container-registry
ECRは認証と権限が必要 今回はAmazon ECR Privateを使う IAM権限で認証トークンを取得 ログインに加え、リポジトリとpush権限が必要 docs.aws.amazon.com/AmazonECR/…/registry_auth.html docs.aws.amazon.com/AmazonECR/…/image-push-iam.html
コピー方法を比較して選ぶ 比較軸 ローカル 用途 単発・手元で作業 ECRプルスルー キャッシュ pull時の自動取得 取得方法 pull・tag・push ECRが上流から取得 シェルでコピー実行 Docker等の導入 ECRへの認証 push権限の確認 環境・ツールの版 認証情報の管理 実行中断への対応 ルール作成 上流の認証情報 IAM権限の確認 対応上流・更新条件 認証情報の管理 初回pullの外部通信※ 必要ツールの確認 ECRへの認証 push権限の確認 外部接続の確認 セッション管理 保存方式の確認 準備 注意点 CloudShell 単発・AWS上で作業 ※PrivateLink利用時、初回pullにはNAT経由のインターネット経路が必要。 キャッシュ後のpullには不要。 docs.aws.amazon.com/…/pull-through-… docs.aws.amazon.com/…/vpc-endpoints…
CloudShellでdockerコマンド実行 GHCRのイメージをECRへ。 手元のPCにツールやイメージを置かない。 DockerはCloudShellにプリインストール済み GHCR コピー元 CloudShell コマンド実行 Amazon ECR コピー先 CloudShellから両レジストリへ通信する。
まずDockerで取得を試す SOURCE="ghcr.io/<owner>/<image>@sha256:<digest>" docker pull --platform "<os>/<arch>" "$SOURCE" <owner>・<image>・<digest> は実値に置換。 <os>/<arch> はコピー対象と実行先に合わせる。
pull中に容量不足が発生 failed to register layer: no space left on device 実測から、今回はルート領域の容量枯渇と判明。
エラーが発生した際の状況 実行環境 東京リージョン(ap-northeast-1) 新規に作成したCloudShell pull対象 ghcr.io/danny-avila/librechat-dev:latest プラットフォーム:linux/amd64 保存先 vfs / /var/lib/docker ルート(/)と同じoverlay領域:約16 GiB 開始時 イメージ・コンテナ・ビルドキャッシュは空 ルート使用量5.14 GiB / 利用可能量9.62 GiB
枯渇したのはルート領域 ルート容量 利用可能量が0になり、pullが容量不足で失敗 failed to register layer: no space left on device inode 失敗直前も約38万個残存 今回の直接原因はinode不足ではない ホーム領域 約1 GiBの別領域。Dockerの保存先ではない 今回枯渇したのはホームの1 GBではない 既存データ 開始時のイメージ・コンテナ・キャッシュは空 今回の再現では蓄積が主因ではない
vfsは親の内容も複製する vfsは新しい層を作る際に、親の内容も複製する。 同一イメージの比較では、20層累積がoverlay2の約3.83倍。 A+B+C 差分 C A+B 差分 B A 親A 今回の保存方式:vfs 比較した保存方式:overlay2 docs.docker.com/engine/storage/drivers/vfs-driver/ docs.docker.com/engine/storage/drivers/overlayfs-driver/
(参考)vfsとoverlay2の比較 比較:Docker 27.5.1/独立デーモン/linux/amd64 同一ローカル環境・同一固定digest・20層のID一致 vfs累積(GiB) overlay2累積(GiB) 12 9 6 3 0 0層 5層 10層 15層 20層:vfs 11.816 GiB / overlay2 3.088 GiB(差8.728 GiB) 測定:pull後の各レイヤー保存領域をduで測定・層順に積算 一時ファイル・メタデータは除外。CloudShellとは別測定。 20層
Dockerへの展開を省く Docker:取得 → 展開 → 転送 GHCR (コピー元) CloudShell内の Dockerストア ECR (コピー先) crane:Dockerストアへの展開を省略 GHCR (コピー元) ECR (コピー先) データはCloudShellのcraneが中継する。 レジストリ同士が直接転送するわけではない。 github.com/google/go-containerregistry/…/crane_copy.md
Dockerとcraneの違い 比較軸 docker pull / push crane copy ローカル展開 Dockerストアへ展開 Docker展開なし 容量への影響 展開・保存方式に依存 展開分の容量を回避 残る制約 通信・認証・保存容量 通信・認証・メモリ Dockerデーモンは不要。ただし転送経路は必要。 github.com/google/go-containerregistry/…/crane_copy.md
通信はCloudShell経由 AWS Cloud crane copy GHCR コピー元 CloudShell Amazon ECR crane実行 コピー先 Docker展開は省略。通信はCloudShell経由。 github.com/google/go-containerregistry/…/crane_copy.md
craneの導入方法 mkdir -p "$HOME/bin" # 公式Releaseから固定版を取得 # checksum照合後に展開 tar -xzf crane.tar.gz -C "$HOME/bin" crane export PATH="$HOME/bin:$PATH" crane version ダウンロード・checksum照合後のコマンド抜粋。 採用するRelease・CPU・実行時の版を記録する。 github.com/google/go-containerregistry/releases
ECRにログインする
REGION=ap-northeast-1
ACCOUNT_ID="<12-digit-account-id>"
REGISTRY="$ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com"
LOGIN=(--username AWS --password-stdin)
aws ecr get-login-password --region "$REGION" |
crane auth login "$REGISTRY" "${LOGIN[@]}"
前提:正しいアカウント・IAM権限。
リポジトリを事前作成。コピーは次の手順で実行。
docs.aws.amazon.com/AmazonECR/…/registry_auth.html
ログイン成功とpush許可は別 1. 認証:ログイン 2. 認可:push時 Docker/craneがECRへ トークンを使ってログイン トークンは12時間有効 IAMユーザー/ロールに 対象リポジトリへの push権限があるか確認 ログイン成功でも、push権限がなければ拒否される 設定:Docker設定の参照先を揃える。helperは実行環境にも用意。 保護:Base64は暗号化ではない。認証情報を共有せず、不要時はlogout。 docs.aws.amazon.com/AmazonECR/…/registry_auth.html docs.aws.amazon.com/AmazonECR/…/image-push-iam.html docs.docker.com/reference /cli/docker/login/
コピー元とコピー先を指定する
コピー元:SOURCE
@sha256:<digest>
digestで対象を固定。
値は事前に確認する。
コピー先:DEST
:<tag>
タグはコピー先の識別名。
上書き可否も確認する。
DEST="${REGISTRY}/<repository>:<tag>"
crane copy --platform "<os>/<arch>" "$SOURCE" "$DEST"
認証済みのSOURCE・REGISTRYを使用
github.com/google/go-containerregistry/…/crane_copy.md
docs.aws.amazon.com/AmazonECR/…/image-tag-mutability.html
同じ形式のdigestを照合 crane digest --platform "<os>/<arch>" "$SOURCE" crane digest --platform "<os>/<arch>" "$DEST" コピー時と同じplatformのmanifest同士で比較。 元indexとの違いを、転送失敗と混同しない。 不一致なら形式・タグ・転送結果を確認。 digest一致は転送内容の確認。 アプリの動作や安全性は別に検証する。 github.com/google/go-containerregistry/…/crane_digest.md
まとめ CloudShellでもDockerコマンドは使える 今回もルート領域の容量枯渇を再現。 大きなイメージや長時間の作業には注意。 通常はECRプルスルーキャッシュや ローカル環境の利用を優先して検討する docs.aws.amazon.com/cloudshell/…/limits.html docs.aws.amazon.com/AmazonECR/…/pull-through-cache.html
参考文献(1/3) [1] https://docs.docker.com/get-started/docker-concepts/ the-basics/what-is-an-image/ [2] https://docs.docker.com/get-started/docker-concepts/ the-basics/what-is-a-container/ [3] https://docs.github.com/en/packages/working-with-a-githubpackages-registry/working-with-the-container-registry [4] https://docs.aws.amazon.com/cloudshell/latest/userguide/ vm-specs.html [5] https://docs.aws.amazon.com/cloudshell/latest/userguide/ using-cshell-in-vpc.html [6] https://docs.docker.com/engine/storage/drivers/vfs-driver/
参考文献(2/3) [7] https://docs.docker.com/engine/storage/drivers/ overlayfs-driver/ [8] https://github.com/google/go-containerregistry/blob/main/ cmd/crane/doc/crane_copy.md [9] https://github.com/google/go-containerregistry/blob/main/ cmd/crane/doc/crane_digest.md [10] https://github.com/google/go-containerregistry/releases [11] https://docs.aws.amazon.com/AmazonECR/latest/userguide/ registry_auth.html [12] https://docs.aws.amazon.com/AmazonECR/latest/userguide/ image-push-iam.html
参考文献(3/3) [13] https://docs.aws.amazon.com/AmazonECR/latest/userguide/ pull-through-cache.html [14] https://docs.docker.com/reference/cli/docker/login/ [15] https://docs.aws.amazon.com/AmazonECR/latest/userguide/ image-tag-mutability.html [16] https://www.gnu.org/software/coreutils/manual/html_node/ df-invocation.html [17] https://github.com/google/go-containerregistry/blob/main/ cmd/crane/doc/crane_auth.md [18] https://docs.aws.amazon.com/cloudshell/latest/userguide/ limits.html
ご清聴ありがとうございました。 資料は下記に公開しています。 https://www.docswell.com/user/mkymdk ※本スライドの内容は個人の見解であり、 所属組織とは無関係です。