# @apiclient.xyz/docker 🐳 > **Powerful TypeScript client for Docker Remote API** - Build, manage, and orchestrate Docker containers, images, networks, and swarm services with type-safe elegance. ## Issue Reporting and Security For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly. ## 🚀 Features - 🎯 **Full TypeScript Support** - Complete type definitions for all Docker API entities - 🔄 **Async/Await Ready** - Modern promise-based architecture for seamless async operations - 📦 **Container Management** - Full lifecycle control: create, start, stop, remove, inspect containers - 🔌 **Interactive Containers** - Stream logs, attach to processes, execute commands in real-time - 🖼️ **Image Handling** - Pull from registries, build from tarballs, export, and manage tags - 🌐 **Network Operations** - Create and manage Docker networks with full IPAM support - 🔐 **Secrets Management** - Handle Docker secrets securely in swarm mode - 🎭 **Service Orchestration** - Deploy and manage services in Docker Swarm - 💾 **S3 Image Storage** - Built-in support for storing/retrieving images from S3-compatible storage - 📊 **Event Streaming** - Real-time Docker event monitoring with RxJS observables - 🔧 **Registry Authentication** - Seamless authentication with Docker registries including private registries - 🐝 **Swarm Mode** - Full support for Docker Swarm initialization and management ## 📦 Installation ```bash # Using pnpm (recommended) pnpm add @apiclient.xyz/docker # Using npm npm install @apiclient.xyz/docker # Using yarn yarn add @apiclient.xyz/docker ``` ## 🎯 Quick Start ```typescript import { DockerHost } from '@apiclient.xyz/docker'; // Connect to local Docker daemon (default: /var/run/docker.sock) const docker = new DockerHost({}); await docker.start(); // Check if Docker is accessible await docker.ping(); console.log('✅ Docker is running'); // List all containers const containers = await docker.getContainers(); console.log(`Found ${containers.length} containers`); // Get a specific container and interact with it const container = await docker.getContainerById('abc123'); await container.start(); // Stream logs in real-time const logStream = await container.streamLogs({ follow: true }); logStream.on('data', (chunk) => console.log(chunk.toString())); // Don't forget to clean up await docker.stop(); ``` ## 🏗️ Clean Architecture The module follows a **Facade pattern** with `DockerHost` as the single entry point: ```typescript const docker = new DockerHost({}); // All operations go through DockerHost const containers = await docker.getContainers(); // List containers const container = await docker.getContainerById('id'); // Get specific container const network = await docker.createNetwork({ Name: 'my-net' }); // Create network const service = await docker.createService(descriptor); // Deploy service const image = await docker.createImageFromRegistry({ imageUrl: 'nginx' }); // Resources support both strings and instances await docker.createService({ image: 'nginx:latest', // String works! networks: ['my-network'], // String array works! secrets: [secretInstance] // Or use actual instances }); ``` ## 🔌 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', }); ``` ## 📚 Complete API Guide ### 🐳 DockerHost - Your Gateway to Docker The `DockerHost` class is your primary interface to interact with the Docker daemon. ```typescript import { DockerHost } from '@apiclient.xyz/docker'; // Initialize with options const docker = new DockerHost({ socketPath: '/var/run/docker.sock', // Optional: custom socket path imageStoreDir: './docker-images', // Optional: custom image store location }); // Start the docker host (initializes image store) await docker.start(); // ... perform operations ... // Stop and clean up await docker.stop(); ``` #### Health Check / Ping Docker Check if the Docker daemon is running and accessible: ```typescript // Ping Docker daemon try { await docker.ping(); console.log('✅ Docker is running and accessible'); } catch (error) { console.error('❌ Docker is not accessible:', error.message); } // Use in health check function async function isDockerHealthy(): Promise { try { await docker.ping(); return true; } catch (error) { return false; } } // Example: Wait for Docker to be ready async function waitForDocker(timeoutMs = 10000): Promise { const startTime = Date.now(); while (Date.now() - startTime < timeoutMs) { try { await docker.ping(); console.log('✅ Docker is ready'); return; } catch (error) { console.log('⏳ Waiting for Docker...'); await new Promise(resolve => setTimeout(resolve, 1000)); } } throw new Error('Docker did not become available within timeout'); } ``` ### 📦 Container Management #### List All Containers ```typescript // Get all containers (running and stopped) const containers = await docker.getContainers(); containers.forEach((container) => { console.log(`Container: ${container.Names[0]}`); console.log(` ID: ${container.Id}`); console.log(` Status: ${container.Status}`); console.log(` Image: ${container.Image}`); console.log(` State: ${container.State}`); }); ``` #### Get Container by ID ```typescript const container = await docker.getContainerById('abc123'); if (container) { console.log(`Found: ${container.Names[0]}`); console.log(`Running: ${container.State === 'running'}`); } ``` #### Container Lifecycle Operations ```typescript // Get a container const container = await docker.getContainerById('abc123'); // Start the container await container.start(); console.log('Container started'); // Stop the container (with optional timeout) await container.stop({ t: 10 }); // 10 seconds graceful stop console.log('Container stopped'); // Restart by starting again await container.start(); // Remove the container await container.remove({ force: true, v: true }); // force + remove volumes console.log('Container removed'); ``` #### Inspect Container Details ```typescript const container = await docker.getContainerById('abc123'); // Get detailed information const details = await container.inspect(); console.log('Container details:', details); // Or just refresh the container state await container.refresh(); console.log('Updated state:', container.State); ``` #### Get Container Logs ```typescript // Get logs as a string (one-shot) const logs = await container.logs({ stdout: true, stderr: true, timestamps: true, tail: 100, // Last 100 lines }); console.log(logs); ``` #### Stream Logs in Real-Time 🔥 ```typescript // Stream logs continuously (follow mode) const logStream = await container.streamLogs({ stdout: true, stderr: true, timestamps: true, tail: 50, // Start with last 50 lines, then follow }); logStream.on('data', (chunk) => { console.log(chunk.toString()); }); logStream.on('error', (err) => { console.error('Stream error:', err); }); // Stop streaming when done // logStream.destroy(); ``` #### Attach to Container Process 🔥 Attach to the container's main process (PID 1) for interactive session: ```typescript const { stream, close } = await container.attach({ stdin: true, stdout: true, stderr: true, logs: true, // Include previous logs }); // Pipe to/from process streams process.stdin.pipe(stream); stream.pipe(process.stdout); // Handle stream events stream.on('end', () => { console.log('Attachment ended'); }); // Later: detach cleanly await close(); ``` #### Execute Commands in Container 🔥 Run commands inside a running container: ```typescript // Execute a command const { stream, close } = await container.exec('ls -la /app', { tty: true, user: 'root', workingDir: '/app', env: ['DEBUG=true'], }); // Handle output stream.on('data', (chunk) => { console.log(chunk.toString()); }); stream.on('end', async () => { console.log('Command finished'); await close(); }); // Execute with array of arguments const { stream: stream2, close: close2 } = await container.exec( ['bash', '-c', 'echo "Hello from container"'], { tty: true } ); ``` #### Get Container Stats ```typescript // Get stats (one-shot) const stats = await container.stats({ stream: false }); console.log('CPU Usage:', stats.cpu_stats); console.log('Memory Usage:', stats.memory_stats); ``` #### Create Containers ```typescript const newContainer = await docker.createContainer({ Hostname: 'my-app', Domainname: 'local', networks: ['my-network'], // Can use string or DockerNetwork instance }); console.log(`Container created: ${newContainer.Id}`); ``` ### 🖼️ Image Management #### Pull Images from Registry ```typescript // Pull from Docker Hub const image = await docker.createImageFromRegistry({ imageUrl: 'nginx', imageTag: 'alpine', // Optional, defaults to 'latest' }); console.log(`Image pulled: ${image.RepoTags[0]}`); console.log(`Size: ${(image.Size / 1024 / 1024).toFixed(2)} MB`); // Pull from private registry const privateImage = await docker.createImageFromRegistry({ imageUrl: 'registry.example.com/my-app', imageTag: 'v2.0.0', }); ``` #### Import Images from Tar Stream ```typescript import * as fs from 'fs'; // Import from a tar file const tarStream = fs.createReadStream('./my-image.tar'); const importedImage = await docker.createImageFromTarStream(tarStream, { 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 docker.getImageByName('nginx:alpine'); // Export to tar stream const exportStream = await image.exportToTarStream(); // Save to file const writeStream = fs.createWriteStream('./nginx-export.tar'); exportStream.pipe(writeStream); writeStream.on('finish', () => { console.log('Image exported successfully'); }); ``` #### List All Images ```typescript const images = await docker.getImages(); images.forEach((img) => { console.log(`Image: ${img.RepoTags ? img.RepoTags.join(', ') : ''}`); console.log(` ID: ${img.Id}`); console.log(` Size: ${(img.Size / 1024 / 1024).toFixed(2)} MB`); console.log(` Created: ${new Date(img.Created * 1000).toISOString()}`); }); ``` #### Remove Images ```typescript const image = await docker.getImageByName('nginx:alpine'); await image.remove({ force: true }); console.log('Image removed'); ``` ### 🌐 Network Management #### Create Custom Networks ```typescript // Create an overlay network (for swarm) const network = await docker.createNetwork({ Name: 'my-app-network', Driver: 'overlay', EnableIPv6: false, Attachable: true, }); console.log(`Network created: ${network.Name} (${network.Id})`); ``` #### List and Inspect Networks ```typescript // Get all networks const networks = await docker.getNetworks(); networks.forEach((net) => { console.log(`Network: ${net.Name} (${net.Driver})`); console.log(` Scope: ${net.Scope}`); console.log(` Internal: ${net.Internal}`); }); // Get specific network by name const appNetwork = await docker.getNetworkByName('my-app-network'); // Get containers connected to this network const containers = await appNetwork.getContainersOnNetwork(); console.log(`Containers on network: ${containers.length}`); ``` #### Remove a Network ```typescript const network = await docker.getNetworkByName('my-app-network'); await network.remove(); console.log('Network removed'); ``` ### 🎭 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 ```typescript // Create prerequisites const network = await docker.createNetwork({ Name: 'app-network', Driver: 'overlay', // Use overlay for swarm }); const image = await docker.createImageFromRegistry({ imageUrl: 'nginx', imageTag: 'latest', }); const secret = await docker.createSecret({ name: 'api-key', version: '1.0.0', contentArg: 'super-secret-key', labels: { app: 'my-app' }, }); // Create a service (supports both strings and instances!) const service = await docker.createService({ name: 'web-api', image: image, // Or use string: 'nginx:latest' labels: { app: 'api', version: '1.0.0', }, networks: [network], // Or use strings: ['app-network'] networkAlias: 'api', secrets: [secret], // Or use strings: ['api-key'] ports: ['80:3000'], // host:container resources: { memorySizeMB: 512, }, }); console.log(`Service deployed: ${service.ID}`); ``` #### List and Manage Services ```typescript // List all services const services = await docker.getServices(); services.forEach((service) => { console.log(`Service: ${service.Spec.Name}`); console.log(` Image: ${service.Spec.TaskTemplate.ContainerSpec.Image}`); }); // Get service by name const myService = await docker.getServiceByName('web-api'); // Refresh service state await myService.refresh(); // Check if service needs update const needsUpdate = await myService.needsUpdate(); if (needsUpdate) { console.log('⚠️ Service configuration has changed, update needed'); } // Remove service await myService.remove(); console.log('Service removed'); ``` ### 🔐 Secrets Management Secrets are only available in Docker Swarm mode. ```typescript // Create a secret const secret = await docker.createSecret({ name: 'database-password', version: '1.0.0', contentArg: 'my-super-secret-password', labels: { app: 'my-app', type: 'credential', }, }); console.log(`Secret created: ${secret.ID}`); // List all secrets const secrets = await docker.getSecrets(); secrets.forEach((s) => { console.log(`Secret: ${s.Spec.Name}`); console.log(` Labels:`, s.Spec.Labels); }); // Get secret by name const dbSecret = await docker.getSecretByName('database-password'); // Update secret content await dbSecret.update('new-password-value'); // Remove secret await dbSecret.remove(); console.log('Secret removed'); ``` ### 💾 Image Storage Store and retrieve Docker images from local storage or S3: ```typescript // Store image to local storage const imageStream = fs.createReadStream('./my-app.tar'); await docker.storeImage('my-app-v1', imageStream); console.log('Image stored locally'); // Retrieve image from storage const storedImageStream = await docker.retrieveImage('my-app-v1'); storedImageStream.pipe(fs.createWriteStream('./restored-image.tar')); // Configure S3 storage (optional) await docker.addS3Storage({ endpoint: 's3.amazonaws.com', accessKey: 'AKIAIOSFODNN7EXAMPLE', accessSecret: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', bucketName: 'my-docker-images', }); ``` ### 📊 Event Monitoring Monitor Docker events in real-time using RxJS observables: ```typescript // Subscribe to Docker events const eventObservable = await docker.getEventObservable(); const subscription = eventObservable.subscribe({ next: (event) => { console.log(`📡 Event: ${event.Type} - ${event.Action}`); console.log(` Actor: ${event.Actor.ID}`); 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), complete: () => console.log('Event stream completed'), }); // Unsubscribe when done // subscription.unsubscribe(); ``` ### 🔧 Registry Authentication Authenticate with Docker registries to pull private images: ```typescript // Authenticate with a registry await docker.auth({ username: 'your-username', password: 'your-password', serveraddress: 'https://index.docker.io/v1/', // Docker Hub }); console.log('✅ Authenticated with registry'); // Or read credentials from Docker config file await docker.getAuthTokenFromDockerConfig('registry.example.com'); // Now you can pull private images const privateImage = await docker.createImageFromRegistry({ imageUrl: 'registry.example.com/private/app', imageTag: 'latest', }); ``` ## 🏗️ Advanced Examples ### Complete Application Stack with Swarm Deploy a complete multi-service application stack: ```typescript import { DockerHost } from '@apiclient.xyz/docker'; 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 docker.createNetwork({ Name: 'app-network', Driver: 'overlay', Attachable: true, }); console.log('✅ Network created'); // Create secrets const dbPassword = await docker.createSecret({ name: 'db-password', version: '1.0.0', contentArg: 'strong-database-password', labels: { app: 'stack' }, }); console.log('✅ Secrets created'); // Deploy database service const dbService = await docker.createService({ name: 'postgres-db', image: 'postgres:14-alpine', // Using string for convenience labels: { tier: 'database' }, networks: ['app-network'], // Using string array networkAlias: 'postgres', secrets: ['db-password'], // Using string array ports: [], resources: { memorySizeMB: 1024, }, }); console.log('✅ Database service deployed'); // Deploy application service const appService = await docker.createService({ name: 'web-app', image: 'my-app:latest', labels: { tier: 'application' }, networks: ['app-network'], networkAlias: 'app', secrets: ['db-password'], ports: ['80:3000'], resources: { memorySizeMB: 512, }, }); console.log('✅ Application service deployed'); console.log('🚀 Stack deployment complete!'); } deployStack().catch(console.error); ``` ### Container Debugging Session Interactive debugging session with a running container: ```typescript async function debugContainer(containerId: string) { const docker = new DockerHost({}); await docker.start(); const container = await docker.getContainerById(containerId); // First, check container state await container.inspect(); console.log(`Container: ${container.Names[0]}`); console.log(`State: ${container.State}`); // Get recent logs const logs = await container.logs({ tail: 50 }); console.log('Recent logs:', logs); // Stream live logs in one terminal console.log('\n--- Live Logs ---'); const logStream = await container.streamLogs({ timestamps: true }); logStream.on('data', (chunk) => { process.stdout.write(chunk); }); // Execute diagnostic commands console.log('\n--- Running Diagnostics ---'); const { stream, close } = await container.exec('ps aux', { tty: true }); stream.on('data', (chunk) => { console.log(chunk.toString()); }); stream.on('end', async () => { console.log('\nDiagnostics complete'); await close(); await docker.stop(); }); } ``` ### Image Pipeline: Pull, Tag, Export ```typescript async function imagePipeline() { const docker = new DockerHost({}); await docker.start(); // Pull latest image const image = await docker.createImageFromRegistry({ imageUrl: 'node', imageTag: '18-alpine', }); console.log('✅ Image pulled'); // Export to tar for backup/transfer 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'); // Store in image store (with S3 backup if configured) const tarStream = fs.createReadStream('./node-18-alpine.tar'); await docker.storeImage('node-18-alpine-backup', tarStream); console.log('✅ Image stored in image store'); await docker.stop(); } ``` ## 🔍 TypeScript Support Full TypeScript definitions for all Docker API entities: ```typescript import type { IDockerHostConstructorOptions, IImageCreationDescriptor, IServiceCreationDescriptor, ISecretCreationDescriptor, IContainerCreationDescriptor, INetworkCreationDescriptor, TLabels, TPorts, DockerResource, } from '@apiclient.xyz/docker'; // Full IntelliSense support const options: IDockerHostConstructorOptions = { socketPath: '/var/run/docker.sock', imageStoreDir: '/tmp/docker-images', }; const imageConfig: IImageCreationDescriptor = { imageUrl: 'nginx', imageTag: 'alpine', }; const labels: TLabels = { app: 'my-app', environment: 'production', }; ``` ## 🎯 Real-World Use Cases ### 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 buildStream = fs.createReadStream('./build-artifact.tar'); const image = await docker.createImageFromTarStream(buildStream, { imageUrl: 'my-app', imageTag: process.env.CI_COMMIT_SHA, }); console.log(`✅ Image built: my-app:${process.env.CI_COMMIT_SHA}`); ``` ### Health Check Service ```typescript async function healthCheckService() { const docker = new DockerHost({}); try { await docker.ping(); const containers = await docker.getContainers(); const unhealthy = containers.filter(c => c.State !== 'running'); if (unhealthy.length > 0) { console.warn(`⚠️ ${unhealthy.length} containers not running`); // Send alerts, restart services, etc. } return { healthy: true, containers: containers.length }; } catch (error) { console.error('❌ Docker health check failed:', error); return { healthy: false, error: error.message }; } } ``` ## 📖 API Documentation - **Package Repository**: [https://code.foss.global/apiclient.xyz/docker](https://code.foss.global/apiclient.xyz/docker) - **npm Package**: [https://www.npmjs.com/package/@apiclient.xyz/docker](https://www.npmjs.com/package/@apiclient.xyz/docker) - **Docker Engine API Reference**: [https://docs.docker.com/engine/api/latest/](https://docs.docker.com/engine/api/latest/) ## 🔑 Key Concepts - **DockerHost**: Main entry point - all operations flow through this facade - **Flexible Descriptors**: Accept both string references and class instances - **Health Checks**: Use `ping()` method to verify Docker daemon accessibility - **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 log streaming, event monitoring, and container attachment - **Interactive Containers**: Attach to processes, execute commands, stream logs - **Clean Architecture**: Facade pattern with internal delegation for maintainability ## 🆕 Recent Updates ### Version 3.0.0+ - Architecture & Stability - ✨ **Clean OOP Architecture**: Refactored to Facade pattern with DockerHost as single entry point - ✨ **Container Streaming**: Real-time `streamLogs()`, `attach()`, and `exec()` methods for interactive containers - ✨ **Flexible Descriptors**: Support both string references and class instances in all creation methods - ✨ **Complete Container API**: Full lifecycle methods (start, stop, remove, logs, inspect, stats) - ✨ **DockerResource Base Class**: Consistent patterns and type safety across all resources - ✨ **Health Check Support**: New `ping()` method to verify Docker daemon availability - 🐛 **Fixed Circular Dependencies**: Resolved Node.js module loading issues with type-only imports - 🔧 **Improved Type Safety**: Better TypeScript definitions and interfaces throughout - 📚 **Enhanced Documentation**: Comprehensive examples, migration guides, and real-world use cases ## License and Legal Information This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. **Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file. ### Trademarks This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH. ### Company Information Task Venture Capital GmbH 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. By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.