---
id: docker-registry
title: "Container Registry"
shortTitle: "Container Registry"
track: docker
trackTitle: "Docker"
order: 9
level: important
status: published
estimatedMinutes: 30
prerequisites:
  - docker-volume
next: docker-network
reviewedAgainst: 2026-10-12
sources:
  - title: "Docker Hub"
    url: https://docs.docker.com/docker-hub/
  - title: "GitHub Container Registry"
    url: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry
---

# Container Registry

Registry là kho image. `docker pull` tải về. `docker push` đẩy lên. Lab này chỉ gắn tag local, không đẩy image và không đăng nhập.

## Để làm gì

Đọc một tên image đủ ba phần, gắn tag, và không đưa secret vào layer.

## Gồm những gì

- Tên `registry/repo:tag`.
- `docker tag`.
- Khác nhau giữa Docker Hub, GHCR, và ACR ở tên, không ở lệnh `push`.

Không gồm tạo service principal hay token. Không `docker login` trong bài này.

## Dùng khi nào

CI build xong phải để image ở chỗ cluster kéo được. `docker build` trên máy bạn chỉ tạo image local. Máy khác không thấy, trừ khi cùng docker daemon.

Đừng push tag `latest` rồi tưởng là version. `latest` chỉ là một tag chuyển động. Deployment cần tag bất biến, thường là git sha.

## Kiến thức cốt lõi

Tên đầy đủ có host registry, đường dẫn repo, và tag. `nginx:alpine` là dạng ngắn của `docker.io/library/nginx:alpine`. `ghcr.io/org/app:1.4.0` nằm ở GitHub Container Registry. ACR có dạng `name.azurecr.io/app:1.4.0`.

`docker tag local:dev ghcr.io/org/app:1.4.0` không copy layer sang mạng. Nó thêm một tên cho cùng image id trên máy bạn. `docker push` mới gửi.

Registry riêng tư cần `docker login` trước pull trên server. Token đó là secret. Đừng để trong Dockerfile bằng `ENV`, và đừng `COPY` file `.npmrc` có token nếu bước sau không xóa layer. Multi-stage build vẫn giữ layer trung gian trong cache local. Token không được xuất hiện trong `docker history` của image bạn push.

## Lệnh và code mẫu

```bash
docker pull alpine:3
docker tag alpine:3 lab-app:1
docker image ls lab-app
```

Không push. Xóa tag local khi xong:

```bash
docker rmi lab-app:1
```

`alpine:3` có thể vẫn còn vì tag kia chỉ là tên thứ hai. Giữ `alpine:3` nếu các bài sau còn dùng.

## Thực hành

1. Gắn tag `lab-app:1`.
2. `docker image ls` và xác nhận image id của `lab-app:1` trùng `alpine:3`.
3. `docker rmi lab-app:1`.

## Kết quả mong đợi

Hai tên, một image id. Sau `rmi`, `lab-app:1` không còn trong danh sách.

## Checklist

- [ ] Tag deploy là version hoặc git sha, không chỉ `latest`.
- [ ] Không có token trong ENV hoặc file bị COPY vào image đã push.
- [ ] Cluster kéo từ registry riêng tư đã có quyền pull, không dùng docker daemon của máy dev.

## Lỗi thường gặp

**`docker push lab-app:1`.** Tên không có host registry. Docker hiểu là Docker Hub, repo `lab-app`, và từ chối nếu bạn không có quyền. Gắn tên đầy đủ trước khi push.

**Build trên máy ARM rồi chạy trên node AMD.** Image không có variant đúng thì node báo exec format error. CI phải build đúng platform của cluster, hoặc dùng manifest nhiều kiến trúc.

## Nguồn

1. [Docker Hub](https://docs.docker.com/docker-hub/) — tên image trên Docker Hub.
2. [Working with the Container registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) — `ghcr.io` và quyền package.

## Tiếp theo

[Docker network](./06-network.md)
