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:
238
readme.md
238
readme.md
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user