CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-spotify--docker-client

A comprehensive Docker client library for Java applications providing programmatic Docker API access with container lifecycle management, image operations, and Docker Swarm support.

Pending
Overview
Eval results
Files

swarm.mddocs/

Docker Swarm Operations

This document covers comprehensive Docker Swarm orchestration including swarm management, services, tasks, nodes, secrets, configs, and production deployment patterns.

Swarm Initialization and Management

Swarm Initialization

import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.messages.swarm.*;

// Initialize new swarm cluster
SwarmInit swarmInit = SwarmInit.builder()
    .listenAddr("0.0.0.0:2377")
    .advertiseAddr("192.168.1.100:2377")
    .build();

String nodeId = docker.initSwarm(swarmInit);
System.out.println("Swarm initialized. Node ID: " + nodeId);

Advanced Swarm Initialization

// Initialize swarm with custom specification
SwarmSpec swarmSpec = SwarmSpec.builder()
    .name("production-swarm")
    .labels(Map.of(
        "environment", "production",
        "datacenter", "us-east-1"
    ))
    
    // Orchestration settings
    .orchestration(OrchestrationConfig.builder()
        .taskHistoryRetentionLimit(10)
        .build())
    
    // Raft consensus configuration
    .raft(RaftConfig.builder()
        .snapshotInterval(10000L)
        .keepOldSnapshots(5L)
        .logEntriesForSlowFollowers(500L)
        .electionTick(10L)
        .heartbeatTick(1L)
        .build())
    
    // Dispatcher configuration
    .dispatcher(DispatcherConfig.builder()
        .heartbeatPeriod(Duration.ofSeconds(5))
        .build())
    
    // Certificate authority configuration
    .caConfig(CaConfig.builder()
        .nodeCertExpiry(Duration.ofDays(90))
        .build())
    
    // Encryption configuration
    .encryptionConfig(EncryptionConfig.builder()
        .autoLockManagers(true)
        .build())
    
    .build();

SwarmInit advancedInit = SwarmInit.builder()
    .listenAddr("0.0.0.0:2377")
    .advertiseAddr("192.168.1.100:2377")
    .forceNewCluster(false)
    .spec(swarmSpec)
    .build();

String nodeId = docker.initSwarm(advancedInit);

Swarm Inspection

// Get swarm information
Swarm swarm = docker.inspectSwarm();

System.out.println("Swarm ID: " + swarm.id());
System.out.println("Created At: " + swarm.createdAt());
System.out.println("Updated At: " + swarm.updatedAt());

// Swarm specification
SwarmSpec spec = swarm.spec();
System.out.println("Swarm Name: " + spec.name());
System.out.println("Labels: " + spec.labels());

// Join tokens for workers and managers
JoinTokens joinTokens = swarm.joinTokens();
System.out.println("Worker Join Token: " + joinTokens.worker());
System.out.println("Manager Join Token: " + joinTokens.manager());

// Remote managers
List<RemoteManager> managers = swarm.remoteManagers();
for (RemoteManager manager : managers) {
    System.out.println("Manager: " + manager.nodeId() + " @ " + manager.addr());
}

Joining and Leaving Swarm

// Join swarm as worker
SwarmJoin workerJoin = SwarmJoin.builder()
    .listenAddr("0.0.0.0:2377")
    .advertiseAddr("192.168.1.101:2377")
    .remoteAddrs("192.168.1.100:2377")
    .joinToken("worker-token-here")
    .build();

docker.joinSwarm(workerJoin);

// Join swarm as manager
SwarmJoin managerJoin = SwarmJoin.builder()
    .listenAddr("0.0.0.0:2377")
    .advertiseAddr("192.168.1.102:2377")
    .remoteAddrs("192.168.1.100:2377")
    .joinToken("manager-token-here")
    .build();

docker.joinSwarm(managerJoin);

// Leave swarm
docker.leaveSwarm();

// Force leave (for managers)
docker.leaveSwarm(true);

Swarm Updates

// Update swarm configuration
Swarm currentSwarm = docker.inspectSwarm();
Long version = currentSwarm.version().index();

SwarmSpec updatedSpec = currentSwarm.spec().toBuilder()
    .name("updated-production-swarm")
    .labels(Map.of(
        "environment", "production",
        "region", "us-east",
        "updated", "true"
    ))
    .build();

// Update swarm
docker.updateSwarm(version, updatedSpec);

// Update with token rotation
docker.updateSwarm(version, true, false, updatedSpec);  // Rotate worker token
docker.updateSwarm(version, false, true, updatedSpec);  // Rotate manager token

Swarm Unlock

// Get unlock key (for auto-lock enabled swarms)
UnlockKey unlockKey = docker.unlockKey();
System.out.println("Unlock Key: " + unlockKey.unlockKey());

// Unlock swarm
docker.unlock(unlockKey);

Service Management

Service Creation

import com.spotify.docker.client.messages.swarm.*;

// Basic service creation
ServiceSpec serviceSpec = ServiceSpec.builder()
    .name("web-service")
    .taskTemplate(TaskSpec.builder()
        .containerSpec(ContainerSpec.builder()
            .image("nginx:latest")
            .build())
        .build())
    .build();

ServiceCreateResponse response = docker.createService(serviceSpec);
System.out.println("Created service ID: " + response.id());

Advanced Service Configuration

// Comprehensive service configuration
ServiceSpec advancedService = ServiceSpec.builder()
    .name("production-api")
    .labels(Map.of(
        "environment", "production",
        "tier", "backend",
        "version", "1.0.0"
    ))
    
    // Task template
    .taskTemplate(TaskSpec.builder()
        .containerSpec(ContainerSpec.builder()
            .image("myapp:latest")
            .hostname("api-server")
            .env("ENV=production", "PORT=8080")
            .args("--config", "/app/config.yml")
            .user("appuser")
            .dir("/app")
            
            // Resource limits
            .resources(ResourceRequirements.builder()
                .limits(Resources.builder()
                    .memoryBytes(512L * 1024 * 1024)  // 512MB
                    .nanoCpus(500_000_000L)           // 0.5 CPU
                    .build())
                .reservations(Resources.builder()
                    .memoryBytes(256L * 1024 * 1024)  // 256MB reserved
                    .nanoCpus(250_000_000L)           // 0.25 CPU reserved
                    .build())
                .build())
            
            // Health check
            .healthcheck(HealthConfig.builder()
                .test("CMD curl -f http://localhost:8080/health || exit 1")
                .interval(Duration.ofSeconds(30))
                .timeout(Duration.ofSeconds(10))
                .retries(3)
                .startPeriod(Duration.ofSeconds(60))
                .build())
            
            // Secrets and configs
            .secrets(SecretBind.builder()
                .secretId("app-secret-id")
                .secretName("database-password")
                .file(SecretFile.builder()
                    .name("db-password")
                    .uid(1000L)
                    .gid(1000L)
                    .mode(0400L)
                    .build())
                .build())
            
            .configs(ConfigBind.builder()
                .configId("app-config-id")
                .configName("application-config")
                .file(ConfigFile.builder()
                    .name("app-config.yml")
                    .uid(1000L)
                    .gid(1000L)
                    .mode(0644L)
                    .build())
                .build())
            
            .build())
        
        // Placement constraints
        .placement(Placement.builder()
            .constraints("node.role==worker", "engine.labels.type==compute")
            .preferences(PlacementPreference.builder()
                .spread(SpreadDescriptor.builder()
                    .spreadDescriptor("node.labels.zone")
                    .build())
                .build())
            .maxReplicas(2L)  // Max replicas per node
            .build())
        
        // Restart policy
        .restartPolicy(RestartPolicy.builder()
            .condition("on-failure")
            .delay(Duration.ofSeconds(5))
            .maxAttempts(3L)
            .window(Duration.ofSeconds(120))
            .build())
        
        // Networks
        .networks(NetworkAttachmentConfig.builder()
            .target("production-network")
            .aliases("api", "backend")
            .build())
        
        .build())
    
    // Service mode (replicated vs global)
    .mode(ServiceMode.builder()
        .replicated(ReplicatedService.builder()
            .replicas(3L)
            .build())
        .build())
    
    // Update configuration
    .updateConfig(UpdateConfig.builder()
        .parallelism(1L)
        .delay(Duration.ofSeconds(10))
        .failureAction("rollback")
        .monitor(Duration.ofSeconds(60))
        .maxFailureRatio(0.1f)
        .order("start-first")
        .build())
    
    // Rollback configuration
    .rollbackConfig(UpdateConfig.builder()
        .parallelism(1L)
        .delay(Duration.ofSeconds(5))
        .failureAction("pause")
        .monitor(Duration.ofSeconds(30))
        .maxFailureRatio(0.0f)
        .build())
    
    // Endpoint specification (for published ports)
    .endpointSpec(EndpointSpec.builder()
        .mode("vip")
        .ports(PortConfig.builder()
            .name("http")
            .protocol("tcp")
            .targetPort(8080L)
            .publishedPort(80L)
            .publishMode("ingress")
            .build())
        .build())
    
    .build();

ServiceCreateResponse response = docker.createService(advancedService);

Service with Authentication

// Create service that requires registry authentication
RegistryAuth auth = RegistryAuth.builder()
    .username("myuser")
    .password("mypass")
    .serverAddress("https://my-registry.com")
    .build();

ServiceSpec serviceSpec = ServiceSpec.builder()
    .name("private-service")
    .taskTemplate(TaskSpec.builder()
        .containerSpec(ContainerSpec.builder()
            .image("my-registry.com/myapp:latest")
            .build())
        .build())
    .build();

ServiceCreateResponse response = docker.createService(serviceSpec, auth);

Service Inspection and Updates

// Inspect service
Service service = docker.inspectService("service-name-or-id");

System.out.println("Service ID: " + service.id());
System.out.println("Version: " + service.version().index());
System.out.println("Created: " + service.createdAt());
System.out.println("Updated: " + service.updatedAt());

// Service endpoint
Endpoint endpoint = service.endpoint();
if (endpoint != null) {
    System.out.println("Endpoint Mode: " + endpoint.spec().mode());
    for (PortConfig port : endpoint.spec().ports()) {
        System.out.println("Port: " + port.publishedPort() + " -> " + port.targetPort());
    }
    
    // Virtual IPs
    for (EndpointVirtualIp vip : endpoint.virtualIps()) {
        System.out.println("VIP: " + vip.addr() + " (Network: " + vip.networkId() + ")");
    }
}

// Update service
ServiceSpec updatedSpec = service.spec().toBuilder()
    .taskTemplate(service.spec().taskTemplate().toBuilder()
        .containerSpec(service.spec().taskTemplate().containerSpec().toBuilder()
            .image("myapp:v2.0")
            .env("VERSION=2.0", "UPDATED=true")
            .build())
        .build())
    .build();

docker.updateService(service.id(), service.version().index(), updatedSpec);

Service Listing and Filtering

// List all services
List<Service> allServices = docker.listServices();

// List with criteria
Service.Criteria criteria = Service.Criteria.builder()
    .serviceName("web-service")
    .serviceId("service-id")
    .serviceLabel("environment", "production")
    .build();

List<Service> filteredServices = docker.listServices(criteria);

for (Service service : filteredServices) {
    System.out.println("Service: " + service.spec().name());
    System.out.println("Replicas: " + service.spec().mode().replicated().replicas());
    System.out.println("Image: " + service.spec().taskTemplate().containerSpec().image());
}

Service Removal

// Remove service
docker.removeService("service-name-or-id");

// Safe service removal with scaling down first
public void safeRemoveService(DockerClient docker, String serviceId) 
        throws DockerException, InterruptedException {
    
    try {
        // First scale service to 0
        Service service = docker.inspectService(serviceId);
        ServiceSpec scaledSpec = service.spec().toBuilder()
            .mode(ServiceMode.builder()
                .replicated(ReplicatedService.builder()
                    .replicas(0L)
                    .build())
                .build())
            .build();
        
        docker.updateService(serviceId, service.version().index(), scaledSpec);
        System.out.println("Scaled service to 0 replicas");
        
        // Wait for tasks to stop
        Thread.sleep(10000);
        
        // Remove service
        docker.removeService(serviceId);
        System.out.println("Removed service: " + serviceId);
        
    } catch (DockerException e) {
        System.err.println("Error removing service: " + e.getMessage());
    }
}

Service Logs

// Get service logs
try (LogStream logs = docker.serviceLogs("service-name",
    DockerClient.LogsParam.stdout(),
    DockerClient.LogsParam.stderr(),
    DockerClient.LogsParam.follow(),
    DockerClient.LogsParam.timestamps(true))) {
    
    logs.forEachRemaining(logMessage -> {
        System.out.println("Service Log: " + logMessage.content().toStringUtf8());
    });
}

Task Management

Task Listing and Inspection

// List all tasks
List<Task> allTasks = docker.listTasks();

// List with criteria
Task.Criteria taskCriteria = Task.Criteria.builder()
    .serviceName("web-service")
    .nodeId("node-id")
    .taskName("web-service.1")
    .taskState("running")
    .build();

List<Task> filteredTasks = docker.listTasks(taskCriteria);

for (Task task : filteredTasks) {
    System.out.println("Task ID: " + task.id());
    System.out.println("Service ID: " + task.serviceId());
    System.out.println("Node ID: " + task.nodeId());
    System.out.println("Slot: " + task.slot());
    
    TaskStatus status = task.status();
    System.out.println("State: " + status.state());
    System.out.println("Message: " + status.message());
    
    if (status.containerStatus() != null) {
        System.out.println("Container ID: " + status.containerStatus().containerId());
        System.out.println("PID: " + status.containerStatus().pid());
    }
}

Task Inspection

// Inspect specific task
Task task = docker.inspectTask("task-id");

System.out.println("Task Details:");
System.out.println("  ID: " + task.id());
System.out.println("  Version: " + task.version().index());
System.out.println("  Created: " + task.createdAt());
System.out.println("  Updated: " + task.updatedAt());
System.out.println("  Service: " + task.serviceId());
System.out.println("  Node: " + task.nodeId());
System.out.println("  Slot: " + task.slot());

// Task specification
TaskSpec spec = task.spec();
ContainerSpec containerSpec = spec.containerSpec();
System.out.println("  Image: " + containerSpec.image());
System.out.println("  Command: " + containerSpec.command());
System.out.println("  Args: " + containerSpec.args());

// Task status and history
TaskStatus status = task.status();
System.out.println("  Current State: " + status.state());
System.out.println("  Message: " + status.message());
System.out.println("  Timestamp: " + status.timestamp());

// Container status (if running)
if (status.containerStatus() != null) {
    ContainerStatus containerStatus = status.containerStatus();
    System.out.println("  Container ID: " + containerStatus.containerId());
    System.out.println("  PID: " + containerStatus.pid());
    System.out.println("  Exit Code: " + containerStatus.exitCode());
}

Node Management

Node Listing and Inspection

// List all nodes
List<Node> allNodes = docker.listNodes();

// List with criteria
Node.Criteria nodeCriteria = Node.Criteria.builder()
    .nodeName("worker-1")
    .nodeRole("worker")
    .membershipAccepted()
    .build();

List<Node> filteredNodes = docker.listNodes(nodeCriteria);

for (Node node : filteredNodes) {
    System.out.println("Node ID: " + node.id());
    System.out.println("Hostname: " + node.description().hostname());
    System.out.println("Role: " + node.spec().role());
    System.out.println("Availability: " + node.spec().availability());
    System.out.println("State: " + node.status().state());
    System.out.println("Address: " + node.status().addr());
    
    // Manager status (if applicable)
    ManagerStatus managerStatus = node.managerStatus();
    if (managerStatus != null) {
        System.out.println("Leader: " + managerStatus.leader());
        System.out.println("Reachability: " + managerStatus.reachability());
        System.out.println("Address: " + managerStatus.addr());
    }
    
    // Node resources
    NodeDescription desc = node.description();
    Resources resources = desc.resources();
    System.out.println("Memory: " + resources.memoryBytes() + " bytes");
    System.out.println("CPUs: " + resources.nanoCpus() / 1_000_000_000.0);
}

Node Inspection

// Inspect specific node (returns NodeInfo which is alias for Node)
NodeInfo nodeInfo = docker.inspectNode("node-id-or-hostname");

System.out.println("Node Information:");
System.out.println("  ID: " + nodeInfo.id());
System.out.println("  Version: " + nodeInfo.version().index());
System.out.println("  Created: " + nodeInfo.createdAt());
System.out.println("  Updated: " + nodeInfo.updatedAt());

// Node specification
NodeSpec spec = nodeInfo.spec();
System.out.println("  Name: " + spec.name());
System.out.println("  Labels: " + spec.labels());
System.out.println("  Role: " + spec.role());
System.out.println("  Availability: " + spec.availability());

// Node description (hardware/software info)
NodeDescription desc = nodeInfo.description();
System.out.println("  Hostname: " + desc.hostname());
Platform platform = desc.platform();
System.out.println("  Architecture: " + platform.architecture());
System.out.println("  OS: " + platform.os());

// Engine info
EngineDescription engine = desc.engine();
System.out.println("  Engine Version: " + engine.engineVersion());
System.out.println("  Plugins: " + engine.plugins());
System.out.println("  Labels: " + engine.labels());

// TLS info
TlsInfo tlsInfo = desc.tlsInfo();
System.out.println("  Certificate Subject: " + tlsInfo.certIssuerSubject());
System.out.println("  Certificate Issuer: " + tlsInfo.certIssuerPublicKey());

Node Updates

// Update node configuration
Node node = docker.listNodes().get(0);  // Get first node
Long version = node.version().index();

NodeSpec updatedSpec = node.spec().toBuilder()
    .availability("drain")  // Drain node for maintenance
    .labels(Map.of(
        "maintenance", "true",
        "type", "compute",
        "zone", "us-east-1a"
    ))
    .build();

docker.updateNode(node.id(), version, updatedSpec);

// Common node operations
public void drainNode(DockerClient docker, String nodeId) 
        throws DockerException, InterruptedException {
    
    Node node = docker.inspectNode(nodeId);
    NodeSpec drainSpec = node.spec().toBuilder()
        .availability("drain")
        .build();
    
    docker.updateNode(nodeId, node.version().index(), drainSpec);
    System.out.println("Node " + nodeId + " drained");
}

public void activateNode(DockerClient docker, String nodeId) 
        throws DockerException, InterruptedException {
    
    Node node = docker.inspectNode(nodeId);
    NodeSpec activeSpec = node.spec().toBuilder()
        .availability("active")
        .build();
    
    docker.updateNode(nodeId, node.version().index(), activeSpec);
    System.out.println("Node " + nodeId + " activated");
}

Node Removal

// Remove node from swarm
docker.deleteNode("node-id");

// Force remove (even if node is manager)
docker.deleteNode("node-id", true);

// Safe node removal process
public void safeRemoveNode(DockerClient docker, String nodeId) 
        throws DockerException, InterruptedException {
    
    try {
        // First drain the node
        drainNode(docker, nodeId);
        
        // Wait for tasks to migrate
        System.out.println("Waiting for tasks to migrate...");
        Thread.sleep(30000);
        
        // Verify no tasks are running on the node
        List<Task> nodeTasks = docker.listTasks(
            Task.Criteria.builder()
                .nodeId(nodeId)
                .taskState("running")
                .build()
        );
        
        if (!nodeTasks.isEmpty()) {
            System.out.println("Warning: " + nodeTasks.size() + " tasks still running on node");
        }
        
        // Remove node
        docker.deleteNode(nodeId);
        System.out.println("Node " + nodeId + " removed successfully");
        
    } catch (DockerException e) {
        System.err.println("Error removing node: " + e.getMessage());
    }
}

Secrets Management

Secret Creation

import com.spotify.docker.client.messages.swarm.*;
import java.util.Base64;

// Create secret from string data
String secretData = "my-secret-password";
String encodedData = Base64.getEncoder().encodeToString(secretData.getBytes());

SecretSpec secretSpec = SecretSpec.builder()
    .name("database-password")
    .data(encodedData)
    .labels(Map.of(
        "environment", "production",
        "type", "password"
    ))
    .build();

SecretCreateResponse response = docker.createSecret(secretSpec);
System.out.println("Created secret ID: " + response.id());

Advanced Secret Configuration

// Create secret with external driver
SecretSpec externalSecret = SecretSpec.builder()
    .name("external-secret")
    .labels(Map.of("provider", "vault"))
    .driver(Driver.builder()
        .name("vault")
        .options(Map.of(
            "path", "secret/myapp/db",
            "key", "password"
        ))
        .build())
    .build();

// Create secret from file
byte[] fileContent = Files.readAllBytes(Paths.get("/path/to/secret/file"));
String fileData = Base64.getEncoder().encodeToString(fileContent);

SecretSpec fileSecret = SecretSpec.builder()
    .name("ssl-certificate")
    .data(fileData)
    .labels(Map.of("type", "certificate"))
    .build();

docker.createSecret(externalSecret);
docker.createSecret(fileSecret);

Secret Listing and Inspection

// List all secrets
List<Secret> secrets = docker.listSecrets();

for (Secret secret : secrets) {
    System.out.println("Secret ID: " + secret.id());
    System.out.println("Name: " + secret.spec().name());
    System.out.println("Created: " + secret.createdAt());
    System.out.println("Updated: " + secret.updatedAt());
    System.out.println("Labels: " + secret.spec().labels());
    
    // Driver information
    Driver driver = secret.spec().driver();
    if (driver != null) {
        System.out.println("Driver: " + driver.name());
        System.out.println("Driver Options: " + driver.options());
    }
}

// Inspect specific secret
Secret secret = docker.inspectSecret("secret-name-or-id");
System.out.println("Secret Details:");
System.out.println("  ID: " + secret.id());
System.out.println("  Version: " + secret.version().index());
System.out.println("  Name: " + secret.spec().name());
// Note: Secret data is not returned for security reasons

Using Secrets in Services

// Service with secret bindings
ServiceSpec serviceWithSecrets = ServiceSpec.builder()
    .name("secure-web-service")
    .taskTemplate(TaskSpec.builder()
        .containerSpec(ContainerSpec.builder()
            .image("nginx:latest")
            
            // Bind secrets as files
            .secrets(
                SecretBind.builder()
                    .secretId("database-password-id")
                    .secretName("database-password")
                    .file(SecretFile.builder()
                        .name("db_password")
                        .uid(33L)      // www-data user
                        .gid(33L)      // www-data group
                        .mode(0400L)   // Read-only for owner
                        .build())
                    .build(),
                
                SecretBind.builder()
                    .secretId("ssl-cert-id")
                    .secretName("ssl-certificate")
                    .file(SecretFile.builder()
                        .name("server.crt")
                        .uid(0L)       // root
                        .gid(0L)       // root
                        .mode(0444L)   // Read-only for all
                        .build())
                    .build()
            )
            
            .build())
        .build())
    .build();

docker.createService(serviceWithSecrets);

Secret Removal

// Remove secret
docker.deleteSecret("secret-name-or-id");

// Safe secret removal (check usage first)
public void safeRemoveSecret(DockerClient docker, String secretId) 
        throws DockerException, InterruptedException {
    
    try {
        // Check which services use this secret
        List<Service> services = docker.listServices();
        List<String> usingServices = new ArrayList<>();
        
        for (Service service : services) {
            TaskSpec taskSpec = service.spec().taskTemplate();
            if (taskSpec.containerSpec().secrets() != null) {
                for (SecretBind secret : taskSpec.containerSpec().secrets()) {
                    if (secretId.equals(secret.secretId()) || secretId.equals(secret.secretName())) {
                        usingServices.add(service.spec().name());
                        break;
                    }
                }
            }
        }
        
        if (usingServices.isEmpty()) {
            docker.deleteSecret(secretId);
            System.out.println("Removed secret: " + secretId);
        } else {
            System.out.println("Secret is in use by services: " + usingServices);
        }
        
    } catch (DockerException e) {
        System.err.println("Error removing secret: " + e.getMessage());
    }
}

Configs Management

Config Creation

import com.spotify.docker.client.messages.swarm.*;

// Create config from string data
String configData = "server {\n    listen 80;\n    server_name example.com;\n}";
String encodedConfig = Base64.getEncoder().encodeToString(configData.getBytes());

ConfigSpec configSpec = ConfigSpec.builder()
    .name("nginx-config")
    .data(encodedConfig)
    .labels(Map.of(
        "application", "nginx",
        "version", "1.0"
    ))
    .build();

ConfigCreateResponse response = docker.createConfig(configSpec);
System.out.println("Created config ID: " + response.id());

Advanced Config Management

// Create config from template file
String templateData = """
    upstream backend {
        server ${BACKEND_HOST}:${BACKEND_PORT};
    }
    
    server {
        listen 80;
        location / {
            proxy_pass http://backend;
        }
    }
    """;

ConfigSpec templateConfig = ConfigSpec.builder()
    .name("nginx-template")
    .data(Base64.getEncoder().encodeToString(templateData.getBytes()))
    .labels(Map.of(
        "type", "template",
        "service", "nginx"
    ))
    .build();

docker.createConfig(templateConfig);

Config Listing and Inspection

// List all configs
List<Config> configs = docker.listConfigs();

// List with criteria
Config.Criteria configCriteria = Config.Criteria.builder()
    .configName("nginx-config")
    .configLabel("application", "nginx")
    .build();

List<Config> filteredConfigs = docker.listConfigs(configCriteria);

for (Config config : filteredConfigs) {
    System.out.println("Config ID: " + config.id());
    System.out.println("Name: " + config.spec().name());
    System.out.println("Created: " + config.createdAt());
    System.out.println("Labels: " + config.spec().labels());
}

// Inspect specific config
Config config = docker.inspectConfig("config-name-or-id");
System.out.println("Config Details:");
System.out.println("  ID: " + config.id());
System.out.println("  Version: " + config.version().index());
System.out.println("  Name: " + config.spec().name());
// Config data is available (unlike secrets)
String data = new String(Base64.getDecoder().decode(config.spec().data()));
System.out.println("  Data: " + data);

Using Configs in Services

// Service with config bindings
ServiceSpec serviceWithConfigs = ServiceSpec.builder()
    .name("configured-nginx")
    .taskTemplate(TaskSpec.builder()
        .containerSpec(ContainerSpec.builder()
            .image("nginx:latest")
            
            // Bind configs as files
            .configs(
                ConfigBind.builder()
                    .configId("nginx-config-id")
                    .configName("nginx-config")
                    .file(ConfigFile.builder()
                        .name("nginx.conf")
                        .uid(0L)
                        .gid(0L)
                        .mode(0644L)
                        .build())
                    .build(),
                
                ConfigBind.builder()
                    .configId("ssl-config-id")
                    .configName("ssl-config")
                    .file(ConfigFile.builder()
                        .name("ssl.conf")
                        .uid(33L)      // www-data
                        .gid(33L)
                        .mode(0644L)
                        .build())
                    .build()
            )
            
            .build())
        .build())
    .build();

docker.createService(serviceWithConfigs);

Config Updates

// Update config (creates new version)
Config existingConfig = docker.inspectConfig("nginx-config");
String newConfigData = "server {\n    listen 443 ssl;\n    server_name example.com;\n}";

ConfigSpec updatedSpec = existingConfig.spec().toBuilder()
    .data(Base64.getEncoder().encodeToString(newConfigData.getBytes()))
    .labels(Map.of(
        "application", "nginx",
        "version", "2.0",
        "ssl", "enabled"
    ))
    .build();

docker.updateConfig(existingConfig.id(), existingConfig.version().index(), updatedSpec);

Config Removal

// Remove config
docker.deleteConfig("config-name-or-id");

// Bulk config cleanup
public void cleanupOldConfigs(DockerClient docker, String namePrefix) 
        throws DockerException, InterruptedException {
    
    List<Config> configs = docker.listConfigs();
    
    for (Config config : configs) {
        String configName = config.spec().name();
        if (configName.startsWith(namePrefix)) {
            
            // Check if config is in use
            boolean inUse = isConfigInUse(docker, config.id());
            
            if (!inUse) {
                try {
                    docker.deleteConfig(config.id());
                    System.out.println("Removed unused config: " + configName);
                } catch (DockerException e) {
                    System.err.println("Failed to remove config " + configName + ": " + e.getMessage());
                }
            } else {
                System.out.println("Config in use, skipping: " + configName);
            }
        }
    }
}

private boolean isConfigInUse(DockerClient docker, String configId) 
        throws DockerException, InterruptedException {
    
    List<Service> services = docker.listServices();
    for (Service service : services) {
        TaskSpec taskSpec = service.spec().taskTemplate();
        if (taskSpec.containerSpec().configs() != null) {
            for (ConfigBind config : taskSpec.containerSpec().configs()) {
                if (configId.equals(config.configId()) || configId.equals(config.configName())) {
                    return true;
                }
            }
        }
    }
    return false;
}

Complete Swarm Deployment Example

public class SwarmDeploymentExample {
    
    public void deployCompleteApplication(DockerClient docker) 
            throws DockerException, InterruptedException {
        
        System.out.println("Deploying complete multi-service application to swarm...");
        
        // 1. Initialize swarm if needed
        try {
            docker.inspectSwarm();
            System.out.println("Swarm already initialized");
        } catch (DockerException e) {
            initializeSwarm(docker);
        }
        
        // 2. Create application network
        createApplicationNetwork(docker);
        
        // 3. Create secrets and configs
        createSecretsAndConfigs(docker);
        
        // 4. Deploy database service
        deployDatabaseService(docker);
        
        // 5. Deploy application service
        deployApplicationService(docker);
        
        // 6. Deploy load balancer
        deployLoadBalancer(docker);
        
        // 7. Monitor deployment
        monitorDeployment(docker);
        
        System.out.println("Application deployment completed");
    }
    
    private void initializeSwarm(DockerClient docker) 
            throws DockerException, InterruptedException {
        
        SwarmInit init = SwarmInit.builder()
            .listenAddr("0.0.0.0:2377")
            .build();
        
        String nodeId = docker.initSwarm(init);
        System.out.println("Initialized swarm with node: " + nodeId);
    }
    
    private void createApplicationNetwork(DockerClient docker) 
            throws DockerException, InterruptedException {
        
        NetworkConfig networkConfig = NetworkConfig.builder()
            .name("app-network")
            .driver("overlay")
            .attachable(true)
            .labels(Map.of("purpose", "application"))
            .build();
        
        try {
            docker.createNetwork(networkConfig);
            System.out.println("Created application network");
        } catch (DockerException e) {
            System.out.println("Network already exists");
        }
    }
    
    private void createSecretsAndConfigs(DockerClient docker) 
            throws DockerException, InterruptedException {
        
        // Database password secret
        SecretSpec dbSecret = SecretSpec.builder()
            .name("db-password")
            .data(Base64.getEncoder().encodeToString("secure-password".getBytes()))
            .build();
        
        // Application config
        String appConfig = """
            database:
              host: postgres
              port: 5432
              name: myapp
            server:
              port: 8080
            """;
        
        ConfigSpec appConfigSpec = ConfigSpec.builder()
            .name("app-config")
            .data(Base64.getEncoder().encodeToString(appConfig.getBytes()))
            .build();
        
        try {
            docker.createSecret(dbSecret);
            docker.createConfig(appConfigSpec);
            System.out.println("Created secrets and configs");
        } catch (DockerException e) {
            System.out.println("Secrets/configs already exist");
        }
    }
    
    private void deployDatabaseService(DockerClient docker) 
            throws DockerException, InterruptedException {
        
        ServiceSpec dbService = ServiceSpec.builder()
            .name("postgres")
            .taskTemplate(TaskSpec.builder()
                .containerSpec(ContainerSpec.builder()
                    .image("postgres:13")
                    .env("POSTGRES_DB=myapp", "POSTGRES_USER=app")
                    .secrets(SecretBind.builder()
                        .secretName("db-password")
                        .file(SecretFile.builder()
                            .name("postgres_password")
                            .uid(999L)  // postgres user
                            .gid(999L)
                            .mode(0400L)
                            .build())
                        .build())
                    .mounts(Mount.builder()
                        .type("volume")
                        .source("postgres-data")
                        .target("/var/lib/postgresql/data")
                        .build())
                    .build())
                .networks(NetworkAttachmentConfig.builder()
                    .target("app-network")
                    .aliases("database")
                    .build())
                .placement(Placement.builder()
                    .constraints("node.role==manager")  // Database on manager for persistence
                    .build())
                .build())
            .mode(ServiceMode.builder()
                .replicated(ReplicatedService.builder()
                    .replicas(1L)
                    .build())
                .build())
            .build();
        
        docker.createService(dbService);
        System.out.println("Deployed database service");
    }
    
    private void deployApplicationService(DockerClient docker) 
            throws DockerException, InterruptedException {
        
        ServiceSpec appService = ServiceSpec.builder()
            .name("webapp")
            .taskTemplate(TaskSpec.builder()
                .containerSpec(ContainerSpec.builder()
                    .image("myapp:latest")
                    .configs(ConfigBind.builder()
                        .configName("app-config")
                        .file(ConfigFile.builder()
                            .name("config.yml")
                            .uid(1000L)
                            .gid(1000L)
                            .mode(0644L)
                            .build())
                        .build())
                    .secrets(SecretBind.builder()
                        .secretName("db-password")
                        .file(SecretFile.builder()
                            .name("db_password")
                            .uid(1000L)
                            .gid(1000L)
                            .mode(0400L)
                            .build())
                        .build())
                    .healthcheck(HealthConfig.builder()
                        .test("CMD curl -f http://localhost:8080/health")
                        .interval(Duration.ofSeconds(30))
                        .timeout(Duration.ofSeconds(10))
                        .retries(3)
                        .build())
                    .build())
                .networks(NetworkAttachmentConfig.builder()
                    .target("app-network")
                    .aliases("backend")
                    .build())
                .placement(Placement.builder()
                    .constraints("node.role==worker")
                    .build())
                .resources(ResourceRequirements.builder()
                    .limits(Resources.builder()
                        .memoryBytes(512L * 1024 * 1024)
                        .nanoCpus(500_000_000L)
                        .build())
                    .build())
                .build())
            .mode(ServiceMode.builder()
                .replicated(ReplicatedService.builder()
                    .replicas(3L)
                    .build())
                .build())
            .updateConfig(UpdateConfig.builder()
                .parallelism(1L)
                .delay(Duration.ofSeconds(10))
                .failureAction("rollback")
                .build())
            .build();
        
        docker.createService(appService);
        System.out.println("Deployed application service");
    }
    
    private void deployLoadBalancer(DockerClient docker) 
            throws DockerException, InterruptedException {
        
        ServiceSpec lbService = ServiceSpec.builder()
            .name("nginx-lb")
            .taskTemplate(TaskSpec.builder()
                .containerSpec(ContainerSpec.builder()
                    .image("nginx:latest")
                    .build())
                .networks(NetworkAttachmentConfig.builder()
                    .target("app-network")
                    .build())
                .build())
            .mode(ServiceMode.builder()
                .replicated(ReplicatedService.builder()
                    .replicas(2L)
                    .build())
                .build())
            .endpointSpec(EndpointSpec.builder()
                .ports(PortConfig.builder()
                    .targetPort(80L)
                    .publishedPort(80L)
                    .protocol("tcp")
                    .publishMode("ingress")
                    .build())
                .build())
            .build();
        
        docker.createService(lbService);
        System.out.println("Deployed load balancer service");
    }
    
    private void monitorDeployment(DockerClient docker) 
            throws DockerException, InterruptedException {
        
        System.out.println("Monitoring deployment status...");
        
        String[] services = {"postgres", "webapp", "nginx-lb"};
        
        for (int i = 0; i < 30; i++) {  // Wait up to 5 minutes
            boolean allReady = true;
            
            for (String serviceName : services) {
                Service service = docker.inspectService(serviceName);
                
                List<Task> tasks = docker.listTasks(Task.Criteria.builder()
                    .serviceName(serviceName)
                    .taskState("running")
                    .build());
                
                Long replicas = service.spec().mode().replicated().replicas();
                
                System.out.printf("Service %s: %d/%d replicas running%n", 
                    serviceName, tasks.size(), replicas);
                
                if (tasks.size() < replicas) {
                    allReady = false;
                }
            }
            
            if (allReady) {
                System.out.println("All services are ready!");
                return;
            }
            
            Thread.sleep(10000);  // Wait 10 seconds
        }
        
        System.out.println("Deployment monitoring timeout");
    }
}

This comprehensive Docker Swarm system provides full orchestration capabilities with service management, security through secrets and configs, node management, and production deployment patterns for scalable containerized applications.

Install with Tessl CLI

npx tessl i tessl/maven-com-spotify--docker-client

docs

client-configuration.md

containers.md

images.md

index.md

networks.md

swarm.md

volumes.md

tile.json