Skip to content

Commit 303694d

Browse files
committed
Implement containerd and tar image import functionality
- Added `containerd.rs` for handling image pushes from containerd store, including manifest loading, layer uploads, and config handling. - Introduced `tar.rs` for extracting layers and config from docker-save tar archives, with support for concurrent uploads. - Updated `mod.rs` to include new modules for containerd and tar imports. - Refactored `main.rs` to integrate new import functionalities and adjusted command handling for containerd and tar imports. - Enhanced `push.rs` to support layer uploads and manifest pushing for tar archives, ensuring proper progress reporting and error handling.
1 parent ea2d162 commit 303694d

26 files changed

Lines changed: 704 additions & 363 deletions

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "docker-image-pusher"
3-
version = "0.5.5"
3+
version = "0.5.6"
44
edition = "2024"
55
authors = ["yorelog <yorelog@gmail.com>"]
66
description = "A memory-optimized Docker image transfer tool for handling large images efficiently"
@@ -45,13 +45,13 @@ tempfile = "3.13"
4545
sha2 = "0.10"
4646

4747
# Internal OCI library
48-
oci-core = { version = "0.1.1", path = "crates/oci-core" }
48+
oci-core = { version = "0.1", path = "crates/oci-core" }
4949

5050
# Containerd metadata/content reader
51-
containerd-store = { version = "0.1.0", path = "crates/containerd-store" }
51+
containerd-store = { version = "0.1", path = "crates/containerd-store" }
5252

5353
# Minimal Bolt reader for containerd validation
54-
bolt-lite = { version = "0.1.0", path = "crates/bolt-lite" }
54+
bolt-lite = { version = "0.1", path = "crates/bolt-lite" }
5555

5656
# CLI helpers
5757
which = "8.0"

Dockerfile

Lines changed: 0 additions & 68 deletions
This file was deleted.

README.md

Lines changed: 62 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,31 @@
11
# Docker Image Pusher
22

3+
[English](README.md) | [简体中文](README.zh-CN.md)
4+
35
[![Build Status](https://github.com/yorelog/docker-image-pusher/workflows/Build/badge.svg)](https://github.com/yorelog/docker-image-pusher/actions)
46
[![Crates.io](https://img.shields.io/crates/v/docker-image-pusher.svg)](https://crates.io/crates/docker-image-pusher)
57
[![Downloads](https://img.shields.io/crates/d/docker-image-pusher.svg)](https://crates.io/crates/docker-image-pusher)
68
[![License](https://img.shields.io/github/license/yorelog/docker-image-pusher)](https://github.com/yorelog/docker-image-pusher)
79

8-
A memory-optimized Docker image transfer tool designed to handle large Docker images without excessive memory usage. This tool addresses the common problem of memory exhaustion when pulling or pushing multi-gigabyte Docker images.
9-
10-
## 🎯 Problem Statement
11-
12-
Traditional Docker image tools often load entire layers into memory, which can cause:
13-
- **Memory exhaustion** with large images (>1GB)
14-
- **System instability** when processing multiple large layers
15-
- **Failed transfers** due to insufficient RAM
16-
- **Poor performance** on resource-constrained systems
17-
18-
## 🚀 Solution
19-
20-
This tool implements **streaming-based layer processing** using the OCI client library:
21-
22-
-**Streaming Downloads**: Layers are streamed directly to disk without loading into memory
23-
-**Sequential Processing**: Processes one layer at a time to minimize memory footprint
24-
-**Chunked Uploads**: Layers ≥500MB stream in ~5MB chunks (auto-expands when registries demand larger slices)
25-
-**Local Caching**: Efficient caching system for faster subsequent operations
26-
-**Progress Monitoring**: Real-time feedback on transfer progress and layer sizes
27-
28-
## 🆕 What's New in 0.5.4
29-
30-
- **Pipeline lives in `oci-core`** – The concurrent extraction/upload queue, blob-existence checks, rate limiting, and telemetry now ship inside the reusable `oci-core::blobs` module. Other projects can embed the exact same uploader without copy/paste.
31-
- **Prefetch-aware chunk uploads** – Large layers read an initial chunk into memory before network I/O begins, giving registries a steady stream immediately and honoring any server-provided chunk size hints mid-flight.
32-
- **Tar importer emits shared `LocalLayer` structs**`tar_import.rs` now returns the exact structs consumed by `LayerUploadPool`, eliminating adapter code and reducing memory copies during extraction.
33-
- **Cleaner push workflow**`src/push.rs` delegates scheduling to `LayerUploadPool`, so the CLI only worries about plan setup, manifest publishing, and user prompts. The parallelism cap and chunk sizing still respect the same CLI flags as before.
34-
- **Docs caught up** – This README now documents the pipeline-focused architecture, the new reusable uploader, and the 0.5.4 feature set.
35-
36-
## OCI Core Library
37-
38-
The OCI functionality now lives inside `crates/oci-core`, an MIT-licensed library crate that
39-
can be embedded in other tools. It exposes:
10+
A tiny, memory‑friendly Docker/OCI image pusher for large images and constrained hosts.
4011

41-
- `reference` – a no-dependency reference parser with rich `OciError` signals
42-
- `auth` – helpers for anonymous/basic auth negotiation
43-
- `client` – an async `reqwest` uploader/downloader that understands chunked blobs,
44-
real-time telemetry, and registry-provided chunk hints
12+
Highlights:
13+
- Streaming layer uploads with bounded memory
14+
- Chunked uploads for large layers (auto‑adapts to registry hints)
15+
- Clear progress reporting; resumable upload sessions
16+
- Works with tar archives or directly from containerd
17+
- Simple override: `docker.io/nginx:v1` + `--target gitea.corp.com/proj` -> `gitea.corp.com/proj/nginx:v1`
4518

46-
`docker-image-pusher` consumes `oci-core` through a normal Cargo path dependency, mirroring how
47-
Rust itself treats the `core` crate. This keeps the CLI boundary clean while enabling other
48-
projects to reuse the same stable OCI primitives without pulling in the rest of the binary.
49-
50-
## 🛠️ Installation
51-
52-
### Download Pre-built Binaries (Recommended)
53-
54-
Download the latest compiled binaries from [GitHub Releases](https://github.com/yorelog/docker-image-pusher/releases):
55-
56-
**Available Platforms:**
57-
- `docker-image-pusher-linux-x86_64` - Linux 64-bit
58-
- `docker-image-pusher-macos-x86_64` - macOS Intel
59-
- `docker-image-pusher-macos-aarch64` - macOS Apple Silicon (M1/M2)
60-
- `docker-image-pusher-windows-x86_64.exe` - Windows 64-bit
61-
62-
**Installation Steps:**
63-
64-
1. Visit the [Releases page](https://github.com/yorelog/docker-image-pusher/releases)
65-
2. Download the binary for your platform from the latest release
66-
3. Make it executable and add to PATH:
67-
68-
```bash
69-
# Linux/macOS
70-
chmod +x docker-image-pusher-*
71-
sudo mv docker-image-pusher-* /usr/local/bin/docker-image-pusher
72-
73-
# Windows
74-
# Move docker-image-pusher-windows-x86_64.exe to a directory in your PATH
75-
# Rename to docker-image-pusher.exe if desired
76-
```
19+
## 📦 Install
7720

78-
### Install from Crates.io
79-
80-
Install directly using Cargo from the official Rust package registry:
81-
82-
```bash
83-
cargo install docker-image-pusher
84-
```
85-
86-
This will compile and install the latest published version from [crates.io](https://crates.io/crates/docker-image-pusher).
87-
88-
### From Source
89-
90-
For development or customization:
91-
92-
```bash
93-
git clone https://github.com/yorelog/docker-image-pusher
94-
cd docker-image-pusher
95-
cargo build --release
96-
```
21+
- Releases: download binaries from [GitHub Releases](https://github.com/yorelog/docker-image-pusher/releases)
22+
- Crates.io: `cargo install docker-image-pusher`
23+
- From source:
24+
```bash
25+
git clone https://github.com/yorelog/docker-image-pusher
26+
cd docker-image-pusher && cargo build --release
27+
```
9728

98-
The compiled binary will be available at `target/release/docker-image-pusher` (or `.exe` on Windows)
9929

10030
## 📖 Usage
10131

@@ -107,83 +37,78 @@ The compiled binary will be available at `target/release/docker-image-pusher` (o
10737
```
10838
Credentials are saved under `.docker-image-pusher/credentials.json` and reused automatically.
10939

110-
2. **Save a local image to a tarball**
40+
2. **Save a local image to a tarball (optional)**
11141
```bash
112-
docker-image-pusher save nginx:latest
42+
docker-image-pusher save nginx:latest --out ./
43+
# produces ./nginx_latest.tar
11344
```
114-
- Detects Docker/nerdctl/Podman automatically (or pass `--runtime`).
115-
- Prompts for image selection if you omit arguments.
116-
- Produces a sanitized tar such as `./nginx_latest.tar`.
11745

11846
3. **Push the tar archive**
11947
```bash
120-
docker-image-pusher push ./nginx_latest.tar
48+
docker-image-pusher push --tar ./nginx_latest.tar
12149
```
122-
- The RepoTag embedded in the tar is combined with the most recent registry you authenticated against (or `--target/--registry` overrides).
123-
- If the destination image was confirmed previously, we auto-continue after a short pause; otherwise we prompt before uploading.
50+
- Use `--target` to set the exact destination. If omitted, we infer from tar metadata and (optionally) `--registry`.
51+
- If the destination was confirmed previously, we auto-continue after a short pause; otherwise we prompt once.
12452

12553
### Command Reference
12654

12755
| Command | When to use | Key flags |
12856
|---------|-------------|-----------|
129-
| `save [IMAGE ...]` | Export one or more local images to tar archives | `--runtime`, `--output-dir`, `--force` |
130-
| `push <tar>` | Upload a docker-save tar archive directly to a registry | `-t/--target`, `--registry`, `--username/--password`, `--blob-chunk` |
57+
| `save [IMAGE ...]` | Export local images to tar/portable folder | `--out`, `--root`, `--namespace`, `--digest` |
58+
| `push --tar <TAR>` | Upload a docker-save tar directly to a registry | `-t/--target`, `--registry`, `--username/--password`, `--blob-chunk` |
59+
| `push --image <IMAGE>` | Push directly from containerd (no tar) | `--root`, `--namespace`, `-t/--target`, `--username/--password`, `--blob-chunk` |
13160
| `login <registry>` | Persist credentials for future pushes | `--username`, `--password` |
13261

133-
The `push` command now handles most of the bookkeeping automatically:
134-
135-
- infers a sensible destination from tar metadata, the last five targets, or stored credentials
136-
- prompts once when switching registries (or auto-confirms if you accepted it before)
137-
- imports `docker save` archives on the fly before uploading
138-
- reuses saved logins unless you pass explicit `--username/--password`
62+
### Destination overrides
13963

64+
- If the tar contains `docker.io/nginx:v1` and you pass `--target gitea.corp.com/project1`,
65+
the final destination resolves to `gitea.corp.com/project1/nginx:v1` (repo/tag taken from tar).
66+
- If you pass a full target like `--target gitea.corp.com/project1/nginx:custom`, it is used as-is.
67+
- `--registry` only affects inference when `--target` is not provided; it forces the registry host while keeping repo/tag from tar metadata.
14068

141-
## 🏗️ Architecture
69+
## 🧭 Scenarios
14270

143-
### Memory Optimization Strategy
71+
### 1) Push a docker-save tar to a private registry
14472

145-
```
146-
Traditional Approach (High Memory):
147-
[Registry] → [Full Image in Memory] → [Local Storage]
148-
149-
❌ Memory usage scales with image size
150-
❌ Can exceed available RAM with large images
151-
152-
Optimized Approach (Low Memory):
153-
[Registry] → [Stream Layer by Layer] → [Local Storage]
154-
155-
✅ Constant memory usage regardless of image size
156-
✅ Handles multi-GB images efficiently
73+
```bash
74+
docker-image-pusher login harbor.xxx.com --username USER --password PASS
75+
docker-image-pusher push --tar ./app_1.0.0.tar \
76+
--target harbor.xxx.com/org/app:1.0.0
15777
```
15878

159-
### State Directory
79+
Notes:
80+
- Use `--target` to specify the destination (registry/org/repo:tag)
81+
- Use `--registry harbor.xxx.com` only if a host override is needed
82+
- `--blob-chunk` sets chunk size (MiB) for large layers
16083

161-
Credential material and push history are stored under `.docker-image-pusher/`:
84+
### 2) Push directly from containerd (no tar)
16285

163-
```
164-
.docker-image-pusher/
165-
├── credentials.json # registry → username/password pairs from `login`
166-
└── push_history.json # most recent destinations (used for inference/prompts)
86+
```bash
87+
docker-image-pusher push \
88+
--root ~/.local/share/containerd \
89+
--namespace default \
90+
--image org/app:1.0.0 \
91+
--target harbor.xxx.com/org/app:1.0.0
16792
```
16893

169-
Tar archives produced by `save` live wherever you choose to write them (current directory by default). They remain ordinary `docker save` outputs, so you can transfer them, scan them, or delete them independently of the CLI state.
94+
Optional: export for offline delivery/audit, then push when needed:
17095

171-
### Processing Flow
96+
```bash
97+
docker-image-pusher save \
98+
--root ~/.local/share/containerd \
99+
--namespace default \
100+
--out ./export \
101+
org/app:1.0.0
102+
```
172103

173-
#### Save Operation (runtime → tar):
174-
1. **Runtime detection** – locate Docker, nerdctl, or Podman (or honor `--runtime`).
175-
2. **Image selection** – parse JSON output from `images --format '{{json .}}'` and optionally prompt.
176-
3. **Tar export** – call `<runtime> save image -o file.tar`, sanitizing filenames and warning before overwrites.
104+
Tip: First push to a new target may ask for a one‑time confirmation based on history/metadata; subsequent pushes auto‑continue.
177105

178-
#### Push Operation (tar → registry):
179-
1. **Authenticate** – load stored credentials or prompt for overrides.
180-
2. **Tar analysis** – extract RepoTags + manifest to infer the final destination.
181-
3. **Layer extraction** – stream each layer from the tar into temporary files while hashing and reporting progress.
182-
4. **Layer/config upload** – reuse existing blobs when present, otherwise stream in fixed-size chunks with telemetry.
183-
5. **Manifest publish** – rebuild the OCI manifest and push it once all blobs are present.
184106

107+
## 📚 More
185108

186-
## 🤝 Welcome Contributing
109+
- Advanced architecture: see ARCHITECTURE.md
110+
- Reusable OCI library: crates/oci-core/README.md
187111

112+
## 🤝 Contributing
188113

189-
**Happy Docker image transferring! 🐳**
114+
PRs and issues welcome. Happy pushing! 🐳

0 commit comments

Comments
 (0)