4 điểm bởi GN⁺ 2025-06-19 | 1 bình luận | Chia sẻ qua WhatsApp
  • Unregistry là một container image registry gọn nhẹ lưu trữ và phục vụ image trực tiếp từ kho của Docker daemon, đồng thời với lệnh docker pussh có thể truyền image thẳng tới máy chủ Docker từ xa qua SSH
  • Các lựa chọn trước đây gồm Docker Hub/GitHub Container Registry, registry tự host, docker save | ssh... docker load, hoặc rebuild từ xa, nhưng mỗi cách đều có vấn đề như kho công khai hoặc mất phí, gánh nặng vận hành, phải truyền toàn bộ image, hoặc lãng phí tài nguyên máy chủ
  • docker pussh myapp:latest user@server tạo SSH tunnel, khởi chạy một container unregistry tạm thời trên máy chủ từ xa, rồi thực hiện docker push qua cổng localhost được forward để chỉ truyền các layer chưa có ở phía từ xa
  • Máy chủ từ xa cần có môi trường chạy Docker, quyền thực thi lệnh docker, và ở lần chạy đầu tiên phải truy cập được ghcr.io/psviderski/unregistry:latest; container unregistry chạy bằng root do cần truy cập /run/containerd/containerd.sock
  • Nếu bật containerd image store của Docker thì image đã truyền sẽ dùng được ngay trong Docker và tránh lưu trùng lặp, nhưng các image và container được tạo bằng classic storage driver có thể tạm thời không hiển thị

Vấn đề triển khai mà Unregistry giải quyết

  • Unregistry là một container image registry gọn nhẹ để chuyển Docker image sang máy chủ từ xa mà không cần registry bên ngoài
  • Lệnh plugin Docker CLI đi kèm là docker pussh, trong đó chữ s thêm vào là viết tắt của SSH
  • Khi chuyển Docker image được build cục bộ lên máy chủ, các lựa chọn phổ biến thường có những hạn chế sau
    • Docker Hub / GitHub Container Registry: phải công khai mã nguồn hoặc trả phí cho kho private
    • Self-hosted registry: phát sinh một dịch vụ riêng cần bảo trì, bảo mật và chi phí lưu trữ
    • Save/Load: docker save | ssh <remote server> docker load sẽ truyền toàn bộ image dù máy chủ đã có sẵn 90%
    • Remote rebuild: tốn thời gian và tài nguyên máy chủ, đồng thời có thể phải debug lỗi build ngay trên production

Cách docker pussh hoạt động

  • Cách dùng cơ bản chỉ là một dòng sau
docker pussh myapp:latest user@server
  • Lệnh này truyền trực tiếp chỉ các layer còn thiếu qua SSH mà không cần cấu hình registry, đăng ký dịch vụ, kho trung gian hay mở cổng public
  • Trình tự hoạt động nội bộ như sau
    • Tạo SSH tunnel tới máy chủ từ xa
    • Khởi chạy một container unregistry tạm thời trên máy chủ
    • Forward một cổng localhost ngẫu nhiên qua tunnel tới cổng của unregistry
    • Thực hiện docker push qua cổng đã forward để chỉ truyền các layer chưa có ở máy từ xa
    • Image đã truyền có thể dùng ngay trên Docker daemon từ xa
    • Dừng container unregistry và đóng SSH tunnel
  • Dự án hướng tới cơ chế truyền đơn giản và hiệu quả, giống rsync cho Docker image
  • Unregistry được tạo ra cho Uncloud, một công cụ gọn nhẹ để triển khai container lên nhiều Docker host, vì cần một cách đơn giản hơn full registry và hiệu quả hơn save/load

Yêu cầu chạy và các giới hạn

  • Máy cục bộ cần hỗ trợ Docker CLI plugin, Docker 19.03 trở lên và OpenSSH client
  • Máy chủ từ xa phải cài Docker và đang chạy
  • Người dùng SSH phải có quyền chạy lệnh docker
    • Người dùng đó phải là root hoặc là người dùng non-root thuộc nhóm docker
    • Xem tài liệu Docker Manage Docker as a non-root user
    • Nếu cần sudo thì phải chạy được sudo docker mà không bị hỏi mật khẩu
  • Ở lần chạy docker pussh đầu tiên, máy chủ từ xa phải kéo được image ghcr.io/psviderski/unregistry:latest từ ghcr.io
    • Với máy chủ cần proxy, phải cấu hình theo hướng dẫn Docker Daemon proxy configuration
    • Trong môi trường air-gapped hoặc bị hạn chế truy cập ghcr.io, có thể kiểm tra phiên bản unregistry image cần thiết rồi preload thủ công
  • Container unregistry chạy bằng root vì cần truy cập /run/containerd/containerd.sock để có đủ quyền

Cài đặt và nền tảng hỗ trợ

  • Trên macOS/Linux có thể cài docker-pussh bằng Homebrew
brew install psviderski/tap/docker-pussh
  • Sau khi cài bằng Homebrew, để dùng docker pussh như Docker CLI plugin cần tạo symbolic link ~/.docker/cli-plugins/docker-pussh
  • Trên macOS/Linux cũng có cách tải trực tiếp
    • Ví dụ phiên bản hiện tại là tải script docker-pussh của v0.4.3 vào thư mục Docker plugin rồi cấp quyền thực thi
    • Cũng có thể tải script mới nhất từ nhánh main
  • Debian có thể cài qua kho gói không chính thức unregistry-debian do @dariogriffo tạo và duy trì
  • Windows hiện chưa được hỗ trợ, nhưng có thể thử WSL 2 và quy trình cài đặt trên Linux
  • Có thể kiểm tra cài đặt bằng lệnh sau
docker pussh --help

Thiết lập containerd image store

  • Unregistry lưu image trực tiếp vào image store của containerd, runtime container cấp thấp mà Docker sử dụng
  • Ở hành vi mặc định của Docker, Docker duy trì một lớp lưu trữ riêng và không dùng trực tiếp image của containerd
  • Nếu bật containerd image store trong Docker, Docker có thể dùng trực tiếp image mà unregistry đã lưu, nhờ đó loại bỏ trùng lặp
  • Khi bật containerd image store

    • Image được push bằng unregistry có thể dùng ngay trong Docker
    • Image chỉ được lưu một lần trong containerd nên không tốn thêm dung lượng
    • Không cần bước pull thêm từ unregistry sang classic Docker image store nên thao tác pussh nhanh hơn
  • Khi giữ hành vi mặc định của Docker

    • Sau khi push, pussh sẽ chạy thêm docker pull trên host từ xa để Docker có thể sử dụng image
    • Image sẽ được lưu cả trong containerd lẫn classic Docker image store, tức là lưu hai lần
    • Các unmanaged image trong containerd có thể dần chiếm đầy dung lượng đĩa theo thời gian
    • Có thể quản lý thủ công bằng các lệnh sau
    sudo ctr -n moby images ls
    sudo ctr -n moby images rm <image>
    
  • Lưu ý khi cấu hình

    • Cách bật containerd image store trong Docker Engine tuân theo tài liệu Docker chính thức
    • Khi chuyển sang containerd image store, các image và container được tạo bằng classic storage driver có thể tạm thời không hiển thị
    • Các tài nguyên đó vẫn còn trên filesystem và có thể lấy lại khi tắt tính năng containerd image store

Ví dụ sử dụng

  • Cách truyền cơ bản chỉ cần chỉ định tên image và đích SSH từ xa
docker pussh myapp:latest user@server.example.com
  • Nếu private key chưa được thêm vào SSH agent, có thể chỉ định key bằng -i
docker pussh myapp:latest ubuntu@192.168.1.100 -i ~/.ssh/id_rsa
  • Có thể chỉ định cổng SSH tùy chỉnh bằng cách thêm cổng sau địa chỉ đích
docker pussh myapp:latest user@server:2222
  • Có thể chỉ định file SSH config tùy chỉnh bằng -F
docker pussh myapp:latest prod-server -F ~/.ssh/config.prod
  • Để chỉ push một nền tảng cụ thể trong image đa nền tảng, dùng --platform
docker pussh myapp:latest user@server --platform linux/amd64
  • Để dùng một phiên bản unregistry image cụ thể trên host từ xa, đặt biến môi trường UNREGISTRY_IMAGE
UNREGISTRY_IMAGE=ghcr.io/psviderski/unregistry:A.B.C docker pussh myapp:latest user@server.example.com

Trường hợp sử dụng tiêu biểu

  • Khi triển khai lên máy chủ production, có thể push trực tiếp image build cục bộ lên máy chủ và chạy mà không cần registry trung gian
docker build --platform linux/amd64 -t myapp:1.2.3 .
docker pussh myapp:1.2.3 deploy@prod-server
ssh deploy@prod-server docker run -d myapp:1.2.3
  • Trong pipeline CI/CD, có thể gửi image trực tiếp tới đích triển khai mà bỏ qua độ phức tạp của registry
- name: Build and deploy
  run: |
    docker build -t myapp:${{ github.sha }} .
    docker pussh myapp:${{ github.sha }} deploy@staging-server
  • Trong homelab và môi trường air-gapped, có thể triển khai image trong mạng cô lập không có truy cập Internet tới registry công cộng

Cách dùng nâng cao và các dự án liên quan

  • Unregistry cũng có thể dùng như một local registry chạy độc lập
    • Mount /run/containerd/containerd.sock rồi chạy container ghcr.io/psviderski/unregistry
    • Sau đó có thể dùng localhost:5000 như một registry thông thường với docker tagdocker push
  • Thiết lập SSH có thể dùng file SSH config chuẩn hoặc truyền file config riêng bằng -F
  • Có các dự án bên thứ ba liên quan
  • Phần triển khai có nhắc tới SpegelDocker Distribution
    • Spegel là P2P container image registry đã truyền cảm hứng cho cách triển khai registry dùng containerd image store làm backend
    • Docker Distribution là triển khai Docker registry làm nền tảng cho unregistry

1 bình luận

 
GN⁺ 2025-06-19
Ý kiến trên Hacker News
  • Với tư cách là người tạo ra Docker, tôi thích điều này. Có lẽ thiết kế lý tưởng nên là một máy chủ duy nhất không tách biệt Docker engine và registry
    Nếu có thể lưu trữ, truyền và chạy container khi cần thì nó đã trở thành một thành phần vững chắc hơn nhiều, đồng thời cũng tránh được hướng đi đáng tiếc là engine và registry lưu image theo những cách không đồng nhất
    Tôi cũng cho rằng mọi cụm production nên có kho lưu trữ image phân tán, và việc push image vào kho đó phải là thứ kích hoạt triển khai. Cách làm hiện nay là push lên registry, cấu hình cụm, rồi từng node tự kéo từ registry về thì vừa mong manh vừa kém hiệu quả. Tôi đã cố lập luận cho một thiết kế tốt hơn, nhưng quán tính khi đó đã quá lớn, và cộng đồng Kubernetes thời kỳ đầu lại thù địch với những ý tưởng xuất phát từ Docker

    • Việc có ít nhất ba cách bố trí hệ thống tệp cho image, và thậm chí hai kiểu kho image ngay trong engine, quả thật khá lộn xộn. Dù vậy, tôi nghĩ Docker vẫn chưa quá muộn để đạt được hướng đó mà không phá vỡ mô hình hiện tại. Chỉ là không rõ Docker có còn quan tâm đến chuyện ấy không, và có vẻ dạo này họ đang trải qua thời kỳ khó khăn
      Triển khai bằng cách push vào cụm nghe rất thông minh. Tôi cũng đang nghĩ đến một kho image phân tán kiểu cài unregistry trên mọi node để chúng tự lấy và chia sẻ image với nhau, nhưng cách để push trở thành thứ kích hoạt triển khai thì tôi cần suy nghĩ thêm
  • Hay đấy. Lệnh pussh thực sự xứng đáng được công nhận là một cách chơi chữ rất thanh lịch. Dễ nhớ, ý nghĩa hiện ra ngay, và chỉ khác một chữ cái so với lệnh chuẩn cùng họ

    • Không tệ, nhưng sẽ tốt hơn nếu có thêm một bí danh chính thống hơn như docker push-over-ssh
      Trong tự động hóa được phát triển theo nhóm, pussh có thể trông như lỗi gõ với những người không biết chức năng này, và gây ra sự bối rối không cần thiết. Ngược lại, push-over-ssh cho thấy rõ đây là một cái tên có chủ đích. Cứ xem như tùy chọn ngắn và tùy chọn dài vậy
    • Chữ s thêm vào là chữ s của sssh
      “Cái extra s đó là gì vậy?”
      “Lỗi gõ đấy”
    • Cũng rất dễ đụng độ tên
  • Năm 2015 tôi đã ngây thơ gửi một PR[1] để đưa tính năng này vào dòng chính Docker, nhưng nhanh chóng bị hướng sang chuyện hỗ trợ một lĩnh vực khác. Có lẽ việc làm cho registry trở nên không còn cần thiết đã đụng chạm quá mạnh đến mô hình kinh doanh của Docker
    [1]: https://github.com/richardcrichardc/docker2docker

    • Vậy ra bạn là người khởi xướng. Thật tiếc là Docker vẫn chưa có API để duyệt các layer của image
      Rốt cuộc tôi đoán kế hoạch là chuyển mặc định sang kho image của containerd. Khi cả local lẫn remote đều dùng kho image của containerd, có vẻ sẽ làm được điều ban đầu bạn từng triển khai mà không cần wrapper registry nữa
  • Đây có vẻ là một ý tưởng hay, rất hợp với những hệ thống đã dùng công cụ triển khai kiểu push như Ansible. Với các công ty không có hỗ trợ 24/7 cho Docker registry, nó cũng có vẻ là một cơ chế triển khai hotfix tốt
    Tôi tò mò không biết nó có tích hợp gọn gàng với các công cụ OCI như buildah không, hay là bắt buộc phải có cài đặt Docker đầy đủ ở cả hai đầu. Tôi chưa xem kỹ, nhưng trong kiểu cấu hình này, có vẻ mảnh ghép còn thiếu để skopeo hoạt động là phải bootstrap một mini registry trên máy chủ từ xa

    • Phía remote cần containerd. Docker và Kubernetes cũng dùng containerd. Phía client thì chỉ cần bất kỳ công cụ nào nói được registry API, tức đặc tả OCI Distribution (https://github.com/opencontainers/distribution-spec)
      Unregistry tái sử dụng mã Docker registry chính thức ở lớp API, nên nó trông và hoạt động tương tự https://hub.docker.com/_/registry
      Ở phía client, có thể dùng các công cụ nói chuyện với OCI registry như skopeo, crane, regclient, BuildKit. Tuy nhiên để dùng chúng, bạn phải tự chạy unregistry trên host từ xa. Lệnh docker pussh chỉ đơn giản là dùng Docker cục bộ để tự động hóa luồng đó
      Cứ coi nó là một script Bash: https://github.com/psviderski/unregistry/blob/main/docker-pu...
      Bạn có thể dễ dàng chỉnh lại theo cách mình muốn
    • Đồng ý. Ở nhiều dịch vụ tôi quản lý, chúng tôi build image cục bộ rồi lưu lại, upload archive bằng Ansible, sau đó khôi phục image, và thường mất lâu hơn rất nhiều so với mức mong muốn
    • Cần có Docker daemon ở cả hai đầu. Đây là một cách khéo léo để chia sẻ layer giữa hai daemon qua SSH
  • Lẽ ra từ đầu nó phải như thế này mới đúng. Quá tuyệt
    Docker registry vẫn có chỗ để dùng, nhưng nhìn chung nó bị thiết kế quá mức và đứng ở phía đối lập với tinh thần hacker

    • Vì là một công ty nhận vốn đầu tư mạo hiểm nên Docker cũng phải kiếm tiền bằng cách nào đó
    • Tôi khuyến nghị dùng ghcr.io, registry của GitHub, cùng với GitHub Actions
      Tôi mất khoảng 20 phút để thiết lập workflow .yaml build và push image lên registry ghcr.io riêng tư, và khoảng 5 phút để cho phép máy chủ kéo image từ đó. Cấu hình này khá thực dụng
    • Có vẻ sự phức tạp nằm ở quy trình push blob vào registry. Trước đây tôi từng làm một registry chỉ đọc tương thích OCI, và nó không phức tạp đến thế
  • Tôi đang nhìn thấy một pipeline kiểu: build image trong GitLab rồi push lên Artifactory, sau đó triển khai được kích hoạt để kéo từ Artifactory và push lại sang AWS ECR, rồi cập nhật template triển khai của EKS để kéo từ ECR xuống node và khởi chạy container Pod
    Tôi cần điều này trong đời mình

    • Hỏi vì tò mò thôi, tại sao lại dùng cả Artifactory lẫn ECR? Bên tôi đang cân nhắc chuyển từ Artifactory sang ECR để giảm chi phí
    • Ở dự án gần nhất, pipeline còn mất nhiều thời gian kéo và đẩy container hơn cả build ứng dụng thật. Mà ngay cả toàn bộ thời gian đó cũng vẫn nhỏ so với thời gian chờ kiểm tra trạng thái; trong khi thực tế chỉ chưa đến 1 giây sau khi khởi động là đã biết nó có ổn hay không rồi
  • Nhờ xem cái này mà tôi biết đến uncloud. Tôi đang tìm một thứ giống dokku nhưng mạnh hơn một chút để dựng server cho side project, và nó đúng kiểu như vậy

    • Cũng có https://skateco.github.io/. Nhìn lướt qua thì có vẻ tương tự
    • Nếu chưa dùng hoặc chưa cân nhắc Portainer thì tôi khuyên nên thử. Tôi đang chạy Portainer Community Edition và Portainer Agent trên hai EC2 instance của AWS, và nó hoạt động tốt
      Tính năng stack cũng rất hay, về cơ bản chính là Docker Compose. Trên một EC2 instance, Portainer Agent chạy Caddy bên trong container, còn Caddy đóng vai trò load balancer và reverse proxy
    • Mừng vì ý tưởng của uncloud đã tạo được sự đồng cảm. Nếu có câu hỏi hoặc cần trợ giúp thì cứ vào Discord
  • Khá lạ khi Docker ngay từ đầu lại không hoạt động theo cách này. Trông rất hay

    • Bạn đã có thể làm điều tương tự bằng cách đóng image thành archive, đẩy nó lên server, rồi chạy từ archive đó trên server
      Việc lưu archive là kiểu docker save -o may-app.tar my-app:latest, còn load là kiểu docker load -i /path/to/my-app.tar
      Nếu dùng công cụ như Ansible thì có thể dễ dàng đạt được điều mà “Unregistry” tự động hóa. Theo kho lưu trữ GitHub, nhược điểm của cách save/load là truyền toàn bộ image qua mạng, và điều đó thực sự có thể thành vấn đề. Có vẻ việc quản lý trực tiếp image thay vì file archive cũng tiện hơn
  • Dự án và cách tiếp cận rất gọn gàng. Tôi đã quá chán các registry đắt đỏ nên cuối cùng tự host Zot[1], nhưng với một số trường hợp thì cách này có vẻ dễ hơn nhiều
    Tôi tự hỏi có ai khác cũng thấy sẽ rất tuyệt nếu có một dịch vụ private registry dễ cấu hình, giá rẻ và tính phí theo mức sử dụng hay không
    [1]: https://zotregistry.dev

    • Nếu bạn chưa biết thì chứng chỉ SSL của zothub.io đã hết hạn
  • Ý tưởng ổn đấy. Tuy vậy, có thể có nhược điểm là việc triển khai bị gắn chặt với dịch vụ. Ví dụ, tôi không rõ sẽ xử lý scale-out hay triển khai red/green thế nào, và có vẻ phía làm việc đó sẽ phải biết về push
    Chỉnh sửa: hóa ra thứ làm việc đó là uncloud. Tôi vừa mới nhận ra
    Dù vậy thì đây vẫn là một đánh đổi. Nếu quy mô nhỏ, dùng một Hetzner VM và hài lòng với sự đơn giản, đồng thời cũng không ngại build image ở local, thì đây là một lựa chọn tuyệt vời

    • Chắc chắn lúc nào cũng là đánh đổi. Thật tốt khi có các lựa chọn để có thể chọn công cụ phù hợp nhất cho từng công việc