feat(host): Add DockerHost version & image-prune APIs, extend network creation options, return exec inspect info, and improve image import/store and streaming

This commit is contained in:
2025-11-25 05:18:48 +00:00
parent 889b017d4f
commit b86601c939
10 changed files with 670 additions and 18 deletions

238
readme.md
View File

@@ -175,6 +175,37 @@ async function waitForDocker(timeoutMs = 10000): Promise<void> {
}
```
#### Get Docker Version Information 🆕
Get detailed version information about the Docker daemon:
```typescript
// Get Docker daemon version
const version = await docker.getVersion();
console.log(`Docker Version: ${version.Version}`);
console.log(`API Version: ${version.ApiVersion}`);
console.log(`Platform: ${version.Os}/${version.Arch}`);
console.log(`Go Version: ${version.GoVersion}`);
console.log(`Git Commit: ${version.GitCommit}`);
console.log(`Kernel Version: ${version.KernelVersion}`);
// Check API compatibility
if (version.MinAPIVersion) {
console.log(`Minimum API Version: ${version.MinAPIVersion}`);
}
// Example: Verify API compatibility
async function checkApiCompatibility(requiredVersion: string): Promise<boolean> {
const version = await docker.getVersion();
// Compare version strings (simplified)
return version.ApiVersion >= requiredVersion;
}
const isCompatible = await checkApiCompatibility('1.40');
console.log(`API compatible: ${isCompatible}`);
```
### 📦 Container Management
#### List All Containers
@@ -305,7 +336,7 @@ Run commands inside a running container:
```typescript
// Execute a command
const { stream, close } = await container.exec('ls -la /app', {
const { stream, close, inspect } = await container.exec('ls -la /app', {
tty: true,
user: 'root',
workingDir: '/app',
@@ -323,12 +354,84 @@ stream.on('end', async () => {
});
// Execute with array of arguments
const { stream: stream2, close: close2 } = await container.exec(
const { stream: stream2, close: close2, inspect: inspect2 } = await container.exec(
['bash', '-c', 'echo "Hello from container"'],
{ tty: true }
);
```
#### Check Exec Command Exit Codes 🆕
Get the exit code and execution state of commands - essential for health checks and automation:
```typescript
// Execute a command and check its exit code
const { stream, close, inspect } = await container.exec('pg_isready -U postgres', {
tty: false,
attachStdout: true,
attachStderr: true,
});
let output = '';
stream.on('data', (chunk) => {
output += chunk.toString();
});
stream.on('end', async () => {
// Get execution information
const info = await inspect();
console.log(`Exit Code: ${info.ExitCode}`); // 0 = success, non-zero = failure
console.log(`Still Running: ${info.Running}`);
console.log(`Process ID: ${info.Pid}`);
console.log(`Container ID: ${info.ContainerID}`);
if (info.ExitCode === 0) {
console.log('✅ Command succeeded');
} else {
console.log(`❌ Command failed with exit code ${info.ExitCode}`);
}
await close();
});
// Example: Health check function
async function healthCheck(container: DockerContainer): Promise<boolean> {
const { stream, close, inspect } = await container.exec('curl -f http://localhost:3000/health');
return new Promise((resolve) => {
stream.on('end', async () => {
const info = await inspect();
await close();
resolve(info.ExitCode === 0);
});
});
}
// Example: Run tests in container and get result
async function runTests(container: DockerContainer): Promise<{ passed: boolean; output: string }> {
const { stream, close, inspect } = await container.exec('npm test', {
workingDir: '/app',
});
let output = '';
stream.on('data', (chunk) => {
output += chunk.toString();
});
return new Promise((resolve) => {
stream.on('end', async () => {
const info = await inspect();
await close();
resolve({
passed: info.ExitCode === 0,
output: output,
});
});
});
}
```
#### Get Container Stats
```typescript
@@ -424,6 +527,58 @@ await image.remove({ force: true });
console.log('Image removed');
```
#### Prune Unused Images 🆕
Clean up unused images to free disk space:
```typescript
// Prune all dangling images (untagged images)
const result = await docker.pruneImages({ dangling: true });
console.log(`Images deleted: ${result.ImagesDeleted.length}`);
console.log(`Space reclaimed: ${(result.SpaceReclaimed / 1024 / 1024).toFixed(2)} MB`);
// Display what was deleted
result.ImagesDeleted.forEach((deleted) => {
if (deleted.Untagged) {
console.log(` Untagged: ${deleted.Untagged}`);
}
if (deleted.Deleted) {
console.log(` Deleted: ${deleted.Deleted}`);
}
});
// Prune with custom filters
const resultWithFilters = await docker.pruneImages({
filters: {
// Remove images older than 24 hours
until: ['24h'],
// Only remove images with specific label
label: ['temporary=true'],
},
});
// Example: Scheduled cleanup function
async function cleanupOldImages() {
console.log('🧹 Starting image cleanup...');
// Remove dangling images
const danglingResult = await docker.pruneImages({ dangling: true });
console.log(`Removed ${danglingResult.ImagesDeleted.length} dangling images`);
// Remove old images (older than 7 days)
const oldResult = await docker.pruneImages({
filters: {
until: ['168h'], // 7 days
},
});
console.log(`Removed ${oldResult.ImagesDeleted.length} old images`);
const totalSpace = danglingResult.SpaceReclaimed + oldResult.SpaceReclaimed;
console.log(`✅ Total space reclaimed: ${(totalSpace / 1024 / 1024 / 1024).toFixed(2)} GB`);
}
```
### 🌐 Network Management
#### Create Custom Networks
@@ -432,7 +587,7 @@ console.log('Image removed');
// Create an overlay network (for swarm)
const network = await docker.createNetwork({
Name: 'my-app-network',
Driver: 'overlay',
Driver: 'overlay', // 'bridge', 'overlay', 'host', 'none', 'macvlan'
EnableIPv6: false,
Attachable: true,
});
@@ -440,6 +595,83 @@ const network = await docker.createNetwork({
console.log(`Network created: ${network.Name} (${network.Id})`);
```
#### Advanced Network Configuration 🆕
Create networks with custom drivers, IPAM configuration, and labels:
```typescript
// Create a bridge network with custom IPAM (IP Address Management)
const bridgeNetwork = await docker.createNetwork({
Name: 'custom-bridge',
Driver: 'bridge', // Use bridge driver for single-host networking
IPAM: {
Driver: 'default',
Config: [{
Subnet: '172.20.0.0/16',
Gateway: '172.20.0.1',
IPRange: '172.20.10.0/24', // Allocate IPs from this range
}]
},
Labels: {
environment: 'production',
team: 'backend',
},
});
console.log(`Bridge network created: ${bridgeNetwork.Name}`);
console.log(` Driver: ${bridgeNetwork.Driver}`);
console.log(` Subnet: ${bridgeNetwork.IPAM.Config[0].Subnet}`);
// Create an internal network (isolated from external networks)
const internalNetwork = await docker.createNetwork({
Name: 'internal-db',
Driver: 'bridge',
Internal: true, // No external access
Attachable: true,
Labels: {
purpose: 'database',
},
});
// Create a network with IPv6 support
const ipv6Network = await docker.createNetwork({
Name: 'ipv6-network',
Driver: 'bridge',
EnableIPv6: true,
IPAM: {
Config: [
{
Subnet: '172.28.0.0/16',
Gateway: '172.28.0.1',
},
{
Subnet: 'fd00:dead:beef::/48',
Gateway: 'fd00:dead:beef::1',
}
]
},
});
// Example: Create network for microservices
async function createMicroserviceNetwork() {
return await docker.createNetwork({
Name: 'microservices',
Driver: 'overlay', // For swarm mode
Attachable: true, // Allow standalone containers to attach
IPAM: {
Config: [{
Subnet: '10.0.0.0/24',
Gateway: '10.0.0.1',
}]
},
Labels: {
'com.docker.stack.namespace': 'production',
'version': '2.0',
},
});
}
```
#### List and Inspect Networks
```typescript