BREAKING CHANGE(DockerHost): Rename DockerHost constructor option dockerSockPath to socketPath and update internal socket path handling

This commit is contained in:
2025-11-18 13:34:09 +00:00
parent e9975ba7b8
commit e6432b4ea9
4 changed files with 406 additions and 212 deletions

View File

@@ -1,5 +1,12 @@
# Changelog # Changelog
## 2025-11-18 - 2.0.0 - BREAKING CHANGE(DockerHost)
Rename DockerHost constructor option 'dockerSockPath' to 'socketPath' and update internal socket path handling
- Breaking: constructor option renamed from 'dockerSockPath' to 'socketPath' — callers must update their code.
- Constructor now reads the provided 'socketPath' option first, then falls back to DOCKER_HOST, CI, and finally the default unix socket.
- README examples and documentation updated to use 'socketPath'.
## 2025-11-17 - 1.3.6 - fix(streaming) ## 2025-11-17 - 1.3.6 - fix(streaming)
Convert smartrequest v5 web ReadableStreams to Node.js streams and update deps for streaming compatibility Convert smartrequest v5 web ReadableStreams to Node.js streams and update deps for streaming compatibility

603
readme.md
View File

@@ -1,29 +1,30 @@
# @apiclient.xyz/docker 🐳 # @apiclient.xyz/docker 🐳
> **Powerful TypeScript client for Docker Remote API** - Build, manage, and orchestrate Docker containers, images, networks, and more with type-safe elegance. > **Powerful TypeScript client for Docker Remote API** - Build, manage, and orchestrate Docker containers, images, networks, and swarm services with type-safe elegance.
## 🚀 Features ## 🚀 Features
- 🎯 **Full TypeScript Support** - Complete type definitions for Docker API entities - 🎯 **Full TypeScript Support** - Complete type definitions for all Docker API entities
- 🔄 **Async/Await Ready** - Modern promise-based architecture for seamless async operations - 🔄 **Async/Await Ready** - Modern promise-based architecture for seamless async operations
- 📦 **Container Management** - Create, list, inspect, and remove containers effortlessly - 📦 **Container Management** - Create, list, inspect, and manage containers effortlessly
- 🖼️ **Image Handling** - Pull from registries, build from tarballs, export, and manage tags - 🖼️ **Image Handling** - Pull from registries, build from tarballs, export, and manage tags
- 🌐 **Network Operations** - Create and manage Docker networks with full IPAM support - 🌐 **Network Operations** - Create and manage Docker networks with full IPAM support
- 🔐 **Secrets Management** - Handle Docker secrets securely in swarm mode - 🔐 **Secrets Management** - Handle Docker secrets securely in swarm mode
- 🎭 **Service Orchestration** - Deploy and manage services in Docker Swarm - 🎭 **Service Orchestration** - Deploy and manage services in Docker Swarm
- 💾 **S3 Image Storage** - Built-in support for storing/retrieving images from S3 - 💾 **S3 Image Storage** - Built-in support for storing/retrieving images from S3-compatible storage
- 📊 **Event Streaming** - Real-time Docker event monitoring with RxJS observables - 📊 **Event Streaming** - Real-time Docker event monitoring with RxJS observables
- 🔧 **Registry Authentication** - Seamless authentication with Docker registries - 🔧 **Registry Authentication** - Seamless authentication with Docker registries including private registries
- 🐝 **Swarm Mode** - Full support for Docker Swarm initialization and management
## 📦 Installation ## 📦 Installation
```bash ```bash
# Using npm
npm install @apiclient.xyz/docker --save
# Using pnpm (recommended) # Using pnpm (recommended)
pnpm add @apiclient.xyz/docker pnpm add @apiclient.xyz/docker
# Using npm
npm install @apiclient.xyz/docker --save
# Using yarn # Using yarn
yarn add @apiclient.xyz/docker yarn add @apiclient.xyz/docker
``` ```
@@ -33,12 +34,45 @@ yarn add @apiclient.xyz/docker
```typescript ```typescript
import { DockerHost } from '@apiclient.xyz/docker'; import { DockerHost } from '@apiclient.xyz/docker';
// Connect to local Docker daemon // Connect to local Docker daemon (default: /var/run/docker.sock)
const docker = new DockerHost(); const docker = new DockerHost({});
await docker.start();
// Or connect to remote Docker host // Or connect to remote Docker host via TCP
const remoteDocker = new DockerHost({ const remoteDocker = new DockerHost({
socketPath: 'tcp://remote-docker-host:2375', socketPath: 'tcp://192.168.1.100:2375',
});
await remoteDocker.start();
// List all containers
const containers = await docker.getContainers();
console.log(`Found ${containers.length} containers`);
// Don't forget to clean up
await docker.stop();
```
## 🔌 Socket Path Configuration
The library determines which Docker socket to use in the following priority order:
1. **Constructor option** - `socketPath` parameter (highest priority)
2. **Environment variable** - `DOCKER_HOST` environment variable
3. **CI environment** - If `CI` env var is set, uses `http://docker:2375/`
4. **Default** - Falls back to `http://unix:/var/run/docker.sock:`
```typescript
// Explicit socket path (highest priority)
const docker1 = new DockerHost({
socketPath: 'tcp://remote-host:2375',
});
// Uses DOCKER_HOST environment variable if set
const docker2 = new DockerHost({});
// Custom image store directory
const docker3 = new DockerHost({
imageStoreDir: '/custom/path/to/image-store',
}); });
``` ```
@@ -51,19 +85,18 @@ The `DockerHost` class is your primary interface to interact with the Docker dae
```typescript ```typescript
import { DockerHost } from '@apiclient.xyz/docker'; import { DockerHost } from '@apiclient.xyz/docker';
// Initialize with default local socket // Initialize with options
const docker = new DockerHost(); const docker = new DockerHost({
socketPath: '/var/run/docker.sock', // Optional: custom socket path
// Custom initialization options imageStoreDir: './docker-images', // Optional: custom image store location
const customDocker = new DockerHost({
socketPath: '/var/run/docker.sock', // Unix socket path
// or
socketPath: 'tcp://192.168.1.100:2375', // TCP connection
}); });
// Start and stop (for lifecycle management) // Start the docker host (initializes image store)
await docker.start(); await docker.start();
// ... do your work
// ... perform operations ...
// Stop and clean up
await docker.stop(); await docker.stop();
``` ```
@@ -72,11 +105,10 @@ await docker.stop();
#### List All Containers #### List All Containers
```typescript ```typescript
// Get all containers (including stopped ones) // Get all containers (running and stopped)
const allContainers = await docker.getContainers(); const containers = await docker.getContainers();
// Each container includes detailed information containers.forEach((container) => {
allContainers.forEach((container) => {
console.log(`Container: ${container.Names[0]}`); console.log(`Container: ${container.Names[0]}`);
console.log(` ID: ${container.Id}`); console.log(` ID: ${container.Id}`);
console.log(` Status: ${container.Status}`); console.log(` Status: ${container.Status}`);
@@ -85,48 +117,15 @@ allContainers.forEach((container) => {
}); });
``` ```
#### Create and Manage Containers #### Get Container by ID
```typescript ```typescript
import { DockerContainer } from '@apiclient.xyz/docker'; import { DockerContainer } from '@apiclient.xyz/docker';
// Create a container with detailed configuration const container = await DockerContainer.getContainerById(docker, 'abc123');
const container = await DockerContainer.create(docker, {
Image: 'nginx:latest',
name: 'my-nginx-server',
HostConfig: {
PortBindings: {
'80/tcp': [{ HostPort: '8080' }],
},
RestartPolicy: {
Name: 'unless-stopped',
},
Memory: 512 * 1024 * 1024, // 512MB memory limit
},
Env: ['NODE_ENV=production', 'LOG_LEVEL=info'],
Labels: {
app: 'web-server',
environment: 'production',
},
});
console.log(`Container created: ${container.Id}`);
// Container operations (these would need to be implemented)
// await container.start();
// await container.stop();
// await container.remove();
```
#### Get Container by ID
```typescript
const container = await DockerContainer.getContainerById(
docker,
'container-id-here',
);
if (container) { if (container) {
console.log(`Found container: ${container.Names[0]}`); console.log(`Found: ${container.Names[0]}`);
console.log(`Running: ${container.State === 'running'}`);
} }
``` ```
@@ -137,54 +136,86 @@ if (container) {
```typescript ```typescript
import { DockerImage } from '@apiclient.xyz/docker'; import { DockerImage } from '@apiclient.xyz/docker';
// Pull an image from Docker Hub // Pull from Docker Hub
const image = await DockerImage.createFromRegistry(docker, { const image = await DockerImage.createFromRegistry(docker, {
imageName: 'node', creationObject: {
imageTag: '18-alpine', imageUrl: 'nginx',
// Optional: provide registry authentication imageTag: 'alpine', // Optional, defaults to 'latest'
authToken: 'your-registry-auth-token', },
}); });
console.log(`Image pulled: ${image.RepoTags[0]}`); console.log(`Image pulled: ${image.RepoTags[0]}`);
console.log(`Size: ${(image.Size / 1024 / 1024).toFixed(2)} MB`); console.log(`Size: ${(image.Size / 1024 / 1024).toFixed(2)} MB`);
```
#### Import Images from Tar // Pull from private registry
const privateImage = await DockerImage.createFromRegistry(docker, {
```typescript creationObject: {
import * as fs from 'fs'; imageUrl: 'registry.example.com/my-app',
imageTag: 'v2.0.0',
// Import from a tar stream },
const tarStream = fs.createReadStream('./my-image.tar');
const importedImage = await DockerImage.createFromTarStream(docker, {
tarStream,
imageUrl: 'file://./my-image.tar',
imageTag: 'my-app:v1.0.0',
}); });
``` ```
#### Export Images to Tar #### Import Images from Tar Stream
```typescript ```typescript
// Export an image to a tar stream import * as fs from 'fs';
const image = await DockerImage.getImageByName(docker, 'nginx:latest'); import { DockerImage } from '@apiclient.xyz/docker';
// Import from a tar file
const tarStream = fs.createReadStream('./my-image.tar');
const importedImage = await DockerImage.createFromTarStream(docker, {
tarStream,
creationObject: {
imageUrl: 'my-app',
imageTag: 'v1.0.0',
},
});
console.log(`Imported: ${importedImage.RepoTags[0]}`);
```
#### Export Images to Tar Stream
```typescript
// Get image by name
const image = await DockerImage.getImageByName(docker, 'nginx:alpine');
// Export to tar stream
const exportStream = await image.exportToTarStream(); const exportStream = await image.exportToTarStream();
// Save to file // Save to file
const writeStream = fs.createWriteStream('./nginx-export.tar'); const writeStream = fs.createWriteStream('./nginx-export.tar');
exportStream.pipe(writeStream); exportStream.pipe(writeStream);
writeStream.on('finish', () => {
console.log('Image exported successfully');
});
``` ```
#### Tag Images #### Tag Images
```typescript ```typescript
// Tag an existing image // Tag an existing image
await DockerImage.tagImageByIdOrName(docker, 'node:18-alpine', { await DockerImage.tagImageByIdOrName(docker, 'nginx:alpine', {
registry: 'myregistry.com', registry: 'myregistry.com',
imageName: 'my-node-app', imageName: 'web-server',
imageTag: 'v2.0.0', imageTag: 'v1.0.0',
});
// Result: myregistry.com/web-server:v1.0.0
```
#### List All Images
```typescript
const images = await docker.getImages();
images.forEach((img) => {
console.log(`Image: ${img.RepoTags ? img.RepoTags.join(', ') : '<none>'}`);
console.log(` ID: ${img.Id}`);
console.log(` Size: ${(img.Size / 1024 / 1024).toFixed(2)} MB`);
console.log(` Created: ${new Date(img.Created * 1000).toISOString()}`);
}); });
// Result: myregistry.com/my-node-app:v2.0.0
``` ```
### 🌐 Network Management ### 🌐 Network Management
@@ -214,7 +245,7 @@ const network = await DockerNetwork.createNetwork(docker, {
}, },
}); });
console.log(`Network created: ${network.Id}`); console.log(`Network created: ${network.Name} (${network.Id})`);
``` ```
#### List and Inspect Networks #### List and Inspect Networks
@@ -222,75 +253,96 @@ console.log(`Network created: ${network.Id}`);
```typescript ```typescript
// Get all networks // Get all networks
const networks = await docker.getNetworks(); const networks = await docker.getNetworks();
networks.forEach((net) => { networks.forEach((net) => {
console.log(`Network: ${net.Name} (${net.Driver})`); console.log(`Network: ${net.Name} (${net.Driver})`);
console.log(` Scope: ${net.Scope}`); console.log(` Scope: ${net.Scope}`);
console.log(` Internal: ${net.Internal}`); console.log(` Internal: ${net.Internal}`);
}); });
// Get specific network // Get specific network by name
const appNetwork = await DockerNetwork.getNetworkByName( const appNetwork = await DockerNetwork.getNetworkByName(docker, 'my-app-network');
docker,
'my-app-network',
);
// Get containers on network // Get containers connected to this network
const containers = await appNetwork.getContainersOnNetwork(); const containers = await appNetwork.getContainersOnNetwork();
console.log(`Containers on network: ${containers.length}`); console.log(`Containers on network: ${containers.length}`);
``` ```
#### Remove a Network
```typescript
const network = await DockerNetwork.getNetworkByName(docker, 'my-app-network');
await network.remove();
console.log('Network removed');
```
### 🎭 Service Management (Swarm Mode) ### 🎭 Service Management (Swarm Mode)
#### Activate Swarm Mode
```typescript
// Initialize swarm mode first
await docker.activateSwarm('192.168.1.100'); // Optional: advertisement IP
console.log('Swarm mode activated');
```
#### Deploy Services #### Deploy Services
```typescript ```typescript
import { DockerService } from '@apiclient.xyz/docker'; import { DockerService, DockerImage, DockerNetwork, DockerSecret } from '@apiclient.xyz/docker';
// Create a replicated service // Create prerequisites
const network = await DockerNetwork.createNetwork(docker, {
Name: 'app-network',
Driver: 'overlay', // Use overlay for swarm
});
const image = await DockerImage.createFromRegistry(docker, {
creationObject: {
imageUrl: 'nginx',
imageTag: 'latest',
},
});
const secret = await DockerSecret.createSecret(docker, {
name: 'api-key',
version: '1.0.0',
contentArg: 'super-secret-key',
labels: { app: 'my-app' },
});
// Create a service
const service = await DockerService.createService(docker, { const service = await DockerService.createService(docker, {
name: 'web-api', name: 'web-api',
image: 'my-api:latest', image: image,
replicas: 3,
ports: [
{
Protocol: 'tcp',
PublishedPort: 80,
TargetPort: 3000,
},
],
networks: ['my-app-network'],
labels: { labels: {
app: 'api', app: 'api',
version: '2.0.0', version: '1.0.0',
}, },
networks: [network],
networkAlias: 'api',
secrets: [secret],
ports: ['80:3000'], // host:container
resources: { resources: {
limits: { memorySizeMB: 512,
Memory: 256 * 1024 * 1024, // 256MB
CPUs: 0.5,
},
}, },
secrets: ['api-key', 'db-password'],
mounts: [
{
Target: '/data',
Source: 'app-data',
Type: 'volume',
},
],
}); });
console.log(`Service deployed: ${service.ID}`); console.log(`Service deployed: ${service.ID}`);
``` ```
#### Manage Services #### List and Manage Services
```typescript ```typescript
// List all services // List all services
const services = await docker.getServices(); const services = await docker.getServices();
services.forEach((service) => { services.forEach((service) => {
console.log(`Service: ${service.Spec.Name}`); console.log(`Service: ${service.Spec.Name}`);
console.log(` Replicas: ${service.Spec.Mode.Replicated.Replicas}`);
console.log(` Image: ${service.Spec.TaskTemplate.ContainerSpec.Image}`); console.log(` Image: ${service.Spec.TaskTemplate.ContainerSpec.Image}`);
if (service.Spec.Mode.Replicated) {
console.log(` Replicas: ${service.Spec.Mode.Replicated.Replicas}`);
}
}); });
// Get service by name // Get service by name
@@ -299,46 +351,50 @@ const myService = await DockerService.getServiceByName(docker, 'web-api');
// Check if service needs update // Check if service needs update
const needsUpdate = await myService.needsUpdate(); const needsUpdate = await myService.needsUpdate();
if (needsUpdate) { if (needsUpdate) {
console.log('Service configuration has changed, update needed'); console.log('⚠️ Service configuration has changed, update needed');
} }
// Remove service // Remove service
await myService.remove(); await myService.remove();
console.log('Service removed');
``` ```
### 🔐 Secrets Management ### 🔐 Secrets Management
Secrets are only available in Docker Swarm mode.
```typescript ```typescript
import { DockerSecret } from '@apiclient.xyz/docker'; import { DockerSecret } from '@apiclient.xyz/docker';
// Create a secret // Create a secret
const secret = await DockerSecret.createSecret(docker, { const secret = await DockerSecret.createSecret(docker, {
name: 'api-key', name: 'database-password',
data: Buffer.from('super-secret-key-123').toString('base64'), version: '1.0.0',
contentArg: 'my-super-secret-password',
labels: { labels: {
app: 'my-app', app: 'my-app',
type: 'api-key', type: 'credential',
}, },
}); });
console.log(`Secret created: ${secret.ID}`); console.log(`Secret created: ${secret.ID}`);
// List secrets // List all secrets
const secrets = await DockerSecret.getSecrets(docker); const secrets = await DockerSecret.getSecrets(docker);
secrets.forEach((secret) => { secrets.forEach((s) => {
console.log(`Secret: ${secret.Spec.Name}`); console.log(`Secret: ${s.Spec.Name}`);
console.log(` Labels:`, s.Spec.Labels);
}); });
// Get secret by name // Get secret by name
const apiKeySecret = await DockerSecret.getSecretByName(docker, 'api-key'); const dbSecret = await DockerSecret.getSecretByName(docker, 'database-password');
// Update secret // Update secret content
await apiKeySecret.update({ await dbSecret.update('new-password-value');
data: Buffer.from('new-secret-key-456').toString('base64'),
});
// Remove secret // Remove secret
await apiKeySecret.remove(); await dbSecret.remove();
console.log('Secret removed');
``` ```
### 💾 S3 Image Storage ### 💾 S3 Image Storage
@@ -346,20 +402,19 @@ await apiKeySecret.remove();
Store and retrieve Docker images from S3-compatible storage: Store and retrieve Docker images from S3-compatible storage:
```typescript ```typescript
// Configure S3 storage // Configure S3 storage for the image store
await docker.addS3Storage({ await docker.addS3Storage({
endpoint: 's3.amazonaws.com', endpoint: 's3.amazonaws.com',
accessKeyId: 'your-access-key', accessKey: 'AKIAIOSFODNN7EXAMPLE',
secretAccessKey: 'your-secret-key', accessSecret: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
bucket: 'docker-images', bucketName: 'my-docker-images',
}); });
// Store an image to S3 // Store an image to S3
const imageStore = docker.imageStore; const imageStream = fs.createReadStream('./my-app.tar');
await imageStore.storeImage('my-app:v1.0.0'); await docker.imageStore.storeImage('my-app-v1', imageStream);
// Retrieve an image from S3 console.log('Image stored to S3');
const retrievedImage = await imageStore.getImage('my-app:v1.0.0');
``` ```
### 📊 Event Monitoring ### 📊 Event Monitoring
@@ -368,137 +423,269 @@ Monitor Docker events in real-time using RxJS observables:
```typescript ```typescript
// Subscribe to Docker events // Subscribe to Docker events
const eventStream = docker.getEventObservable(); const eventObservable = await docker.getEventObservable();
const subscription = eventStream.subscribe({ const subscription = eventObservable.subscribe({
next: (event) => { next: (event) => {
console.log(`Event: ${event.Type} - ${event.Action}`); console.log(`📡 Event: ${event.Type} - ${event.Action}`);
console.log(`Actor: ${event.Actor.ID}`); console.log(` Actor: ${event.Actor.ID}`);
console.log(`Time: ${new Date(event.time * 1000).toISOString()}`); console.log(` Time: ${new Date(event.time * 1000).toISOString()}`);
if (event.Type === 'container') {
console.log(` Container: ${event.Actor.Attributes.name}`);
}
}, },
error: (err) => console.error('Event stream error:', err), error: (err) => console.error('Event stream error:', err),
complete: () => console.log('Event stream completed'), complete: () => console.log('Event stream completed'),
}); });
// Unsubscribe when done // Unsubscribe when done
subscription.unsubscribe(); // subscription.unsubscribe();
``` ```
### 🔧 Registry Authentication ### 🔧 Registry Authentication
Authenticate with Docker registries for private images: Authenticate with Docker registries to pull private images:
```typescript ```typescript
// Authenticate with Docker Hub // Authenticate with a registry
await docker.auth({ await docker.auth({
username: 'your-username', username: 'your-username',
password: 'your-password', password: 'your-password',
serveraddress: 'https://index.docker.io/v1/', serveraddress: 'https://index.docker.io/v1/', // Docker Hub
}); });
// Or use existing Docker config console.log('✅ Authenticated with registry');
const authToken = await docker.getAuthTokenFromDockerConfig('myregistry.com');
// Use auth token when pulling images // Or read credentials from Docker config file
const authToken = await docker.getAuthTokenFromDockerConfig('registry.example.com');
// Now you can pull private images
const privateImage = await DockerImage.createFromRegistry(docker, { const privateImage = await DockerImage.createFromRegistry(docker, {
imageName: 'myregistry.com/private/image', creationObject: {
imageTag: 'latest', imageUrl: 'registry.example.com/private/app',
authToken, imageTag: 'latest',
}); },
```
### 🔄 Swarm Mode
Initialize and manage Docker Swarm:
```typescript
// Initialize swarm mode
await docker.activateSwarm({
ListenAddr: '0.0.0.0:2377',
AdvertiseAddr: '192.168.1.100:2377',
ForceNewCluster: false,
});
// Now you can create services, secrets, and use swarm features
const service = await DockerService.createService(docker, {
name: 'my-swarm-service',
image: 'nginx:latest',
replicas: 5,
// ... more service config
}); });
``` ```
## 🏗️ Advanced Examples ## 🏗️ Advanced Examples
### Complete Application Stack ### Complete Application Stack with Swarm
Deploy a complete multi-service application stack:
```typescript ```typescript
async function deployStack() { import { DockerHost, DockerNetwork, DockerSecret, DockerService, DockerImage } from '@apiclient.xyz/docker';
const docker = new DockerHost();
// Create network async function deployStack() {
const docker = new DockerHost({});
await docker.start();
// Initialize swarm
await docker.activateSwarm();
console.log('✅ Swarm initialized');
// Create overlay network for service communication
const network = await DockerNetwork.createNetwork(docker, { const network = await DockerNetwork.createNetwork(docker, {
Name: 'app-network', Name: 'app-network',
Driver: 'overlay', // for swarm mode Driver: 'overlay',
Attachable: true,
}); });
console.log('✅ Network created');
// Create secrets // Create secrets
const dbPassword = await DockerSecret.createSecret(docker, { const dbPassword = await DockerSecret.createSecret(docker, {
name: 'db-password', name: 'db-password',
data: Buffer.from('strong-password').toString('base64'), version: '1.0.0',
contentArg: 'strong-database-password',
labels: { app: 'stack' },
}); });
console.log('✅ Secrets created');
// Pull images
const postgresImage = await DockerImage.createFromRegistry(docker, {
creationObject: {
imageUrl: 'postgres',
imageTag: '14-alpine',
},
});
const appImage = await DockerImage.createFromRegistry(docker, {
creationObject: {
imageUrl: 'my-app',
imageTag: 'latest',
},
});
console.log('✅ Images pulled');
// Deploy database service // Deploy database service
const dbService = await DockerService.createService(docker, { const dbService = await DockerService.createService(docker, {
name: 'postgres', name: 'postgres-db',
image: 'postgres:14', image: postgresImage,
networks: ['app-network'], labels: { tier: 'database' },
secrets: ['db-password'], networks: [network],
env: ['POSTGRES_PASSWORD_FILE=/run/secrets/db-password'], networkAlias: 'postgres',
secrets: [dbPassword],
ports: [],
resources: {
memorySizeMB: 1024,
},
}); });
console.log('✅ Database service deployed');
// Deploy application service // Deploy application service
const appService = await DockerService.createService(docker, { const appService = await DockerService.createService(docker, {
name: 'web-app', name: 'web-app',
image: 'my-app:latest', image: appImage,
replicas: 3, labels: { tier: 'application' },
networks: ['app-network'], networks: [network],
ports: [{ Protocol: 'tcp', PublishedPort: 80, TargetPort: 3000 }], networkAlias: 'app',
secrets: [dbPassword],
ports: ['80:3000'],
resources: {
memorySizeMB: 512,
},
}); });
console.log('✅ Application service deployed');
console.log('Stack deployed successfully!'); console.log('🚀 Stack deployment complete!');
}
deployStack().catch(console.error);
```
### Image Pipeline: Pull, Tag, Export
```typescript
async function imagePipeline() {
const docker = new DockerHost({});
await docker.start();
// Pull latest image
const image = await DockerImage.createFromRegistry(docker, {
creationObject: {
imageUrl: 'node',
imageTag: '18-alpine',
},
});
console.log('✅ Image pulled');
// Tag for private registry
await DockerImage.tagImageByIdOrName(docker, 'node:18-alpine', {
registry: 'registry.company.com',
imageName: 'base/node',
imageTag: 'v18-alpine',
});
console.log('✅ Image tagged');
// Export to tar
const exportStream = await image.exportToTarStream();
const writeStream = fs.createWriteStream('./node-18-alpine.tar');
exportStream.pipe(writeStream);
await new Promise((resolve, reject) => {
writeStream.on('finish', resolve);
writeStream.on('error', reject);
});
console.log('✅ Image exported to tar');
await docker.stop();
} }
``` ```
## 🔍 TypeScript Support ## 🔍 TypeScript Support
This package provides comprehensive TypeScript definitions for all Docker API entities: Full TypeScript definitions for all Docker API entities:
```typescript ```typescript
import type { import type {
IContainerCreationDescriptor, IDockerHostConstructorOptions,
IServiceCreationDescriptor,
INetworkCreationDescriptor,
IImageCreationDescriptor, IImageCreationDescriptor,
IServiceCreationDescriptor,
ISecretCreationDescriptor, ISecretCreationDescriptor,
TLabels,
} from '@apiclient.xyz/docker'; } from '@apiclient.xyz/docker';
// Full IntelliSense support for all configuration options // Full IntelliSense support
const containerConfig: IContainerCreationDescriptor = { const options: IDockerHostConstructorOptions = {
Image: 'node:18', socketPath: '/var/run/docker.sock',
// Your IDE will provide full autocomplete here imageStoreDir: '/tmp/docker-images',
};
const imageConfig: IImageCreationDescriptor = {
imageUrl: 'nginx',
imageTag: 'alpine',
};
const labels: TLabels = {
app: 'my-app',
environment: 'production',
}; };
``` ```
## 🤝 Contributing ## 🎯 Real-World Use Cases
We welcome contributions! Please feel free to submit issues and pull requests. ### CI/CD Pipeline Integration
```typescript
// In your CI/CD pipeline
const docker = new DockerHost({
socketPath: process.env.DOCKER_HOST || '/var/run/docker.sock',
});
await docker.start();
// Build and push process
const image = await DockerImage.createFromTarStream(docker, {
tarStream: buildArtifactStream,
creationObject: {
imageUrl: 'my-app',
imageTag: process.env.CI_COMMIT_SHA,
},
});
await DockerImage.tagImageByIdOrName(docker, `my-app:${process.env.CI_COMMIT_SHA}`, {
registry: 'registry.company.com',
imageName: 'production/my-app',
imageTag: 'latest',
});
// Push to registry (authentication required)
// Note: Pushing requires proper registry authentication
```
### Dynamic Service Scaling
```typescript
// Monitor and scale services based on load
const services = await docker.getServices();
const webService = services.find(s => s.Spec.Name === 'web-app');
if (webService && webService.Spec.Mode.Replicated) {
const currentReplicas = webService.Spec.Mode.Replicated.Replicas;
console.log(`Current replicas: ${currentReplicas}`);
// Scale based on your metrics
// (Scaling API would need to be implemented)
}
```
## 📖 API Documentation ## 📖 API Documentation
For complete API documentation, visit [https://apiclient.xyz/docker](https://apiclient.xyz/docker) - **Package Repository**: [https://code.foss.global/apiclient.xyz/docker](https://code.foss.global/apiclient.xyz/docker)
- **Docker Engine API Reference**: [https://docs.docker.com/engine/api/latest/](https://docs.docker.com/engine/api/latest/)
- **Issues & Bug Reports**: [https://code.foss.global/apiclient.xyz/docker/issues](https://code.foss.global/apiclient.xyz/docker/issues)
For Docker Remote API reference, see [Docker Engine API Documentation](https://docs.docker.com/engine/api/latest/) ## 🔑 Key Concepts
- **DockerHost**: Main entry point for Docker API communication
- **Socket Path Priority**: Constructor option → `DOCKER_HOST` env → CI mode → default socket
- **Swarm Mode Required**: Services and secrets require Docker Swarm to be activated
- **Type Safety**: Full TypeScript support with comprehensive interfaces
- **Streaming Support**: Real-time event monitoring and tar stream operations
- **S3 Integration**: Built-in image storage/retrieval from S3-compatible storage
## License and Legal Information ## License and Legal Information
@@ -512,7 +699,7 @@ This project is owned and maintained by Task Venture Capital GmbH. The names and
### Company Information ### Company Information
Task Venture Capital GmbH Task Venture Capital GmbH
Registered at District court Bremen HRB 35230 HB, Germany Registered at District court Bremen HRB 35230 HB, Germany
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc. For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@apiclient.xyz/docker', name: '@apiclient.xyz/docker',
version: '1.3.6', version: '2.0.0',
description: 'Provides easy communication with Docker remote API from Node.js, with TypeScript support.' description: 'Provides easy communication with Docker remote API from Node.js, with TypeScript support.'
} }

View File

@@ -14,7 +14,7 @@ export interface IAuthData {
} }
export interface IDockerHostConstructorOptions { export interface IDockerHostConstructorOptions {
dockerSockPath?: string; socketPath?: string;
imageStoreDir?: string; imageStoreDir?: string;
} }
@@ -44,8 +44,8 @@ export class DockerHost {
...optionsArg, ...optionsArg,
}; };
let pathToUse: string; let pathToUse: string;
if (optionsArg.dockerSockPath) { if (optionsArg.socketPath) {
pathToUse = optionsArg.dockerSockPath; pathToUse = optionsArg.socketPath;
} else if (process.env.DOCKER_HOST) { } else if (process.env.DOCKER_HOST) {
pathToUse = process.env.DOCKER_HOST; pathToUse = process.env.DOCKER_HOST;
} else if (process.env.CI) { } else if (process.env.CI) {