ข้ามไปยังเนื้อหา

Tag, Push & Pull

Docker image ทุกตัวมีชื่อแบบ fully-qualified ประกอบด้วยสี่ส่วน:

registry/namespace/repository:tag
ส่วนตัวอย่างค่าเริ่มต้น
registrydocker.iodocker.io
namespaceacmelibrary (สำหรับ official image)
repositoryapi-server
tag2.1.0latest

ดังนั้น nginx เป็นชื่อย่อของ docker.io/library/nginx:latest และ acme/api-server:2.1.0 หมายถึง docker.io/acme/api-server:2.1.0

สำหรับ GHCR (GitHub Container Registry) รูปแบบคือ:

ghcr.io/<github-owner>/<repository>:<tag>

docker tag ไม่ได้คัดลอก image แต่เพิ่ม pointer ใหม่ที่ชี้ไปยัง layer ชุดเดิม:

Terminal window
# Build image ใน local
docker build -t api-server:2.1.0 .
# เพิ่มชื่อแบบ registry-qualified พร้อม push
docker tag api-server:2.1.0 acme/api-server:2.1.0
# tag เป็น latest ด้วย (optional)
docker tag api-server:2.1.0 acme/api-server:latest

ทั้ง acme/api-server:2.1.0 และ acme/api-server:latest ชี้ไปยัง image ID เดียวกัน — ไม่ใช้พื้นที่เพิ่ม

การ push ต้องผ่านการ authenticate (ดูบทเรียน Docker Hub) หลัง docker login:

Terminal window
docker push acme/api-server:2.1.0
docker push acme/api-server:latest

แต่ละ layer จะถูกอัปโหลดครั้งเดียวและ deduplicate บน registry หาก image อื่นมี layer เดียวกันอยู่แล้ว Docker จะข้าม layer นั้นไป

ตัวอย่าง output:

The push refers to repository [docker.io/acme/api-server]
abc123def456: Pushed
789ghijkl012: Layer already exists
2.1.0: digest: sha256:deadbeef... size: 1234
Terminal window
# Pull version ที่ระบุ
docker pull acme/api-server:2.1.0
# Pull จาก GHCR
docker pull ghcr.io/acme/api-server:2.1.0

หาก image มีอยู่ใน local แล้ว Docker จะตรวจสอบว่า digest ของ remote เปลี่ยนไปหรือไม่ และดาวน์โหลดเฉพาะ layer ที่อัปเดต

กลยุทธ์การ tag ที่ดีใช้ หลาย tag สำหรับ image เดียวกัน:

Terminal window
docker tag api-server:2.1.0 acme/api-server:2.1.0 # version แน่นอน
docker tag api-server:2.1.0 acme/api-server:2.1 # minor stream
docker tag api-server:2.1.0 acme/api-server:2 # major stream
docker tag api-server:2.1.0 acme/api-server:latest # latest (optional)

ผู้ใช้สามารถ pin ที่ 2.1.0 เพื่อความเสถียร หรือติดตาม 2 สำหรับ update ที่ไม่ทำลาย backward compatibility latest เป็นแค่ alias สะดวก ไม่มี semantic อัตโนมัติ

เมื่อ tag ถูก push และระบบอื่นเริ่ม pull แล้ว ห้าม overwrite การ push 2.1.0 ซ้ำด้วย content ที่ต่างออกไปจะทำลาย reproducibility — ทีมอื่นอาจ pull image ที่ต่างจากของคุณแม้ชื่อ tag จะเหมือนกัน

แทนที่นั้น ให้สร้าง tag ใหม่เสมอ (2.1.1, 2.2.0) สำหรับ content ที่เปลี่ยนแปลง

ไม่สามารถ push ไป Docker Hub จาก Play with Docker ได้ (ไม่มี credentials) แต่สามารถฝึก docker pull, docker tag, และ docker run กับ public image ได้

# Pull a specific nginx version
docker pull nginx:1.27-alpine

# Add a local alias tag
docker tag nginx:1.27-alpine my-nginx:stable

# Check both tags point to the same image ID
docker images nginx
docker images my-nginx

# Run it to verify it works
docker run --rm -d --name test-nginx -p 8080:80 my-nginx:stable
curl http://localhost:8080
docker stop test-nginx
ตัวเลือกBenefitCost
SHA digest tag (sha256:...)Exact และ unambiguous บอกได้แน่นอนว่าเป็น content เดิม reproducible 100%อ่านไม่รู้เรื่อง (ไม่ human-readable) สื่อสารหรือจำเวอร์ชันได้ยาก
Semver tag (เช่น v1.2.3)อ่านง่าย สื่อความหมายเวอร์ชันและ intent ชัดเจนMutable — ใครก็ push ทับ tag เดิมด้วย content ใหม่ได้ถ้าไม่มีการป้องกัน
  • Push และ deploy เฉพาะ latest tag ทำให้ไม่มี version ที่ pin ไว้ให้ rollback กลับไปได้เมื่อเกิดปัญหา
  • Overwrite semver tag เดิมด้วย content ใหม่ แทนที่จะสร้าง tag ใหม่เสมอ
  • ไม่ pin ด้วย SHA digest คู่กับ semver ทำให้ตรวจสอบไม่ได้ว่า tag ที่ deploy จริงยังเป็น content เดิมหรือถูกสลับไปแล้ว

💡 ตัวอย่างจากของจริง

หลายทีมที่ใช้ GitOps (เช่น Argo CD, Flux) จะ pin deployment manifest ด้วย SHA digest แทน semver tag เพื่อรับประกันว่า cluster รัน content เดียวกันทุกครั้ง แม้ tag เดิมจะถูก overwrite ในภายหลังก็ตาม

`docker tag acme/app:1.0 acme/app:latest` ทำอะไรกับ storage จริง ๆ?
Registry เริ่มต้นเมื่อไม่ระบุที่อยู่ใน image name คืออะไร?
เหตุใดจึงควรถือว่า pushed version tag เป็น immutable?
คำสั่งใดอัปโหลด image ที่ build ใน local ไปยัง registry?