目錄
推送映像檔到 Docker Hub 與私有 Registry
在自己電腦上建好的映像檔,要放到伺服器上執行或分享給團隊,就需要推送到 Registry。最常用的是 Docker Hub,其次是 GitHub Container Registry(ghcr.io)以及各雲端平台的 Registry。
映像檔名稱決定推送到哪裡
推送時,Docker 依照映像檔名稱決定送到哪個 Registry、哪個帳號(命名規則見 映像檔):
| 名稱 | 推送到 |
|---|---|
yourname/mysite:1.0.0 | Docker Hub 的 yourname 帳號 |
ghcr.io/yourname/mysite:1.0.0 | GitHub Container Registry |
localhost:5000/mysite:1.0.0 | 本機 5000 連接埠上的私有 Registry |
所以推送前要先用 docker tag 把映像檔取成對應的名稱。
沒有登入就推送會怎樣
先看看沒有登入、直接推送到 Docker Hub 的結果:
$ docker tag nginx:1.30 yourname/mysite:1.0.0
$ docker push yourname/mysite:1.0.0
The push refers to repository [docker.io/yourname/mysite]
f4616bb1be1c: Unavailable
f1a6a629b824: Unavailable
3d774efa34e3: Unavailable
ecc510c1e359: Unavailable
push access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
push access denied ... authorization failed:Docker Hub 拒絕了,因為沒有登入,而且 yourname 也不是你的帳號。下面依序完成註冊、登入與推送。
推送到 Docker Hub
1. 註冊帳號
到 Docker 官網註冊帳號(可以用 Email,或直接用 Google、GitHub 帳號)。Username 就是之後映像檔名稱前面的命名空間:

2. 建立存取權杖並登入
建議到 Docker Hub 的帳號設定中建立 Personal Access Token,用它代替密碼登入,並可以限制權限(例如只能讀寫,不能刪除)。
docker login -u yourname
依提示貼上存取權杖。登入成功會顯示 Login Succeeded。
3. 建立儲存庫(可選)
第一次推送時 Docker Hub 會自動建立儲存庫。想事先設定說明或設為私人,可以在 Docker Hub 網站上點選 Create repository:

Docker Hub 上的儲存庫預設是公開的。免費方案的私人儲存庫數量有限制,詳見 Docker Hub 的方案說明。
4. 標記並推送
docker build -t yourname/mysite:1.0.0 -t yourname/mysite:latest .
docker push yourname/mysite:1.0.0
docker push yourname/mysite:latest
-t 可以用多次,一次取好多個名稱。也可以用 docker push --all-tags yourname/mysite 一次推送所有 tag。推送的輸出格式和下面「自架私有 Registry」中的實際範例相同。
推送後,在 Docker Hub 儲存庫的 Tags 分頁可以看到每個 tag,以及其他人下載用的指令:

5. 在其他機器上使用
docker pull yourname/mysite:1.0.0
docker run -d -p 8080:80 yourname/mysite:1.0.0
自架私有 Registry:實際示範推送與下載
Docker 官方提供 registry 映像檔,可以快速架一個私有 Registry。這也是最容易親手體驗「推送」的方法,不需要任何帳號:
$ docker run -d -p 5000:5000 --restart unless-stopped -v registry-data:/var/lib/registry --name registry registry:3
Unable to find image 'registry:3' locally
3: Pulling from library/registry
e2de96513ba9: Already exists
90764beeca7f: Pull complete
8dc2188d2a74: Pull complete
783ed5b12fca: Pull complete
2aef3a8beb68: Pull complete
Digest: sha256:ddf754342cfc8acc51a56d5d0ab6af06826461864460636d8bd5c546dab2a7b8
Status: Downloaded newer image for registry:3
c5d02febbf0fd6d8c17e6818990adb28fd0a97c380a0d4c0a58ec793f685e4a0
標記並推送:
$ docker tag nginx:1.30 localhost:5000/mysite:1.0.0
$ docker tag nginx:1.30 localhost:5000/mysite:latest
$ docker push localhost:5000/mysite:1.0.0
The push refers to repository [localhost:5000/mysite]
3d774efa34e3: Pushed
ecc510c1e359: Pushed
f4616bb1be1c: Pushed
f1a6a629b824: Pushed
cb44c3fe542b: Pushed
121907e00c1c: Pushed
220a6ac36368: Pushed
1.0.0: digest: sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02 size: 2288
i Info → Not all multiplatform-content is present and only the available single-platform image was pushed
sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb -> sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02
$ docker push --all-tags localhost:5000/mysite
The push refers to repository [localhost:5000/mysite]
220a6ac36368: Layer already exists
3d774efa34e3: Layer already exists
ecc510c1e359: Layer already exists
f4616bb1be1c: Layer already exists
f1a6a629b824: Layer already exists
cb44c3fe542b: Layer already exists
121907e00c1c: Layer already exists
1.0.0: digest: sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02 size: 2288
220a6ac36368: Layer already exists
3d774efa34e3: Layer already exists
ecc510c1e359: Layer already exists
f4616bb1be1c: Layer already exists
f1a6a629b824: Layer already exists
cb44c3fe542b: Layer already exists
121907e00c1c: Layer already exists
latest: digest: sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02 size: 2288
i Info → Not all multiplatform-content is present and only the available single-platform image was pushed
sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb -> sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02
i Info → Not all multiplatform-content is present and only the available single-platform image was pushed
sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb -> sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02
- 第一次推送時,每一層都顯示 Pushed(上傳)。
- 用
--all-tags推送latest時,所有層都顯示 Layer already exists:1.0.0和latest是同一個映像檔,Registry 裡已經有這些層,不用重新上傳。 - 最後的
Info是 Docker 29 的提示:本機只下載了linux/amd64這一個平台的 nginx,所以推送的也只有這個平台。要推送多平台映像檔見 多平台映像檔。
用 Registry 的 API 確認內容:
$ curl -s http://localhost:5000/v2/_catalog
{"repositories":["mysite"]}
$ curl -s http://localhost:5000/v2/mysite/tags/list
{"name":"mysite","tags":["1.0.0","latest"]}
刪掉本機的版本,再從自己的 Registry 下載回來:
$ docker rmi localhost:5000/mysite:1.0.0 localhost:5000/mysite:latest
Untagged: localhost:5000/mysite:1.0.0
Untagged: localhost:5000/mysite:latest
$ docker pull localhost:5000/mysite:1.0.0
1.0.0: Pulling from mysite
Digest: sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02
Status: Downloaded newer image for localhost:5000/mysite:1.0.0
localhost:5000/mysite:1.0.0
這樣架設的 Registry 沒有帳號驗證也沒有 HTTPS,只適合在本機或內部網路測試。
localhost的 Registry 可以直接使用;其他位址的 HTTP Registry 會被 Docker 拒絕,需要另外設定insecure-registries。正式使用請加上 TLS 與驗證,或使用雲端平台提供的 Registry(例如 AWS ECR、Google Artifact Registry、Azure Container Registry)。
推送到 GitHub Container Registry(ghcr.io)
適合程式碼放在 GitHub 的專案。先在 GitHub 建立一個具有 write:packages 權限的 Personal Access Token,然後:
echo $GITHUB_TOKEN | docker login ghcr.io -u 你的GitHub帳號 --password-stdin
docker tag mysite ghcr.io/你的帳號/mysite:1.0.0
docker push ghcr.io/你的帳號/mysite:1.0.0
--password-stdin 從標準輸入讀取密碼,避免密碼出現在指令歷史記錄裡。
tag 命名建議
| 做法 | 範例 | 說明 |
|---|---|---|
| 語意化版本 | 1.4.2、1.4、1 | 同時推送多個層級,讓使用者自行選擇更新幅度 |
| Git commit | sha-3f2a1c9 | 每個映像檔都能對應到確切的程式碼 |
| 環境 | staging、production | 可變動的標籤,指向目前部署的版本 |
latest | latest | 方便試用,但正式環境不要依賴它 |
正式部署時請使用固定的版本號,這樣才知道伺服器上跑的是哪個版本,也能快速退回上一版(見 部署到雲端主機)。
登出與憑證
docker logout
docker logout ghcr.io
登入資訊預設存在 ~/.docker/config.json。Docker Desktop 會改用作業系統的憑證管理員(Windows 認證管理員、macOS 鑰匙圈)保存,比較安全。
重點回顧
- 映像檔名稱的前綴決定推送到哪個 Registry。
- 用存取權杖(Access Token)登入,不要用帳號密碼。
docker tag加上目的地名稱,再docker push。- 正式環境使用固定的版本號 tag,不要依賴
latest。
動手練習
練習 1:用本章的方法啟動本機 Registry(registry:3,對應 5000 埠),把 alpine:3.23 推送上去,刪除本機的副本後再下載回來。
答案
docker run -d -p 5000:5000 --name registry registry:3
docker tag alpine:3.23 localhost:5000/alpine:3.23
docker push localhost:5000/alpine:3.23
docker rmi localhost:5000/alpine:3.23
docker pull localhost:5000/alpine:3.23
常見問題
推送時出現 denied: requested access to the resource is denied?
通常是沒有登入,或映像檔名稱的帳號部分不是你的帳號。名稱要寫成 你的帳號/儲存庫:tag,並先 docker login。
Docker Hub 的私有儲存庫要付費嗎?
免費帳號可以建立少量私有儲存庫,數量與限制以 Docker Hub 官方方案說明為準。也可以改用 GitHub Container Registry。
可以自動推送嗎?
可以用 GitHub Actions 在每次推送程式碼或打版本 tag 時自動建置並推送,見 [GitHub Actions 自動建置](/zh-tw/docker/ci-cd/)。
更新於 2026年10月14日