0
# Docker Swarm Operations
1
2
This document covers comprehensive Docker Swarm orchestration including swarm management, services, tasks, nodes, secrets, configs, and production deployment patterns.
3
4
## Swarm Initialization and Management
5
6
### Swarm Initialization
7
8
```java { .api }
9
import com.spotify.docker.client.DockerClient;
10
import com.spotify.docker.client.messages.swarm.*;
11
12
// Initialize new swarm cluster
13
SwarmInit swarmInit = SwarmInit.builder()
14
.listenAddr("0.0.0.0:2377")
15
.advertiseAddr("192.168.1.100:2377")
16
.build();
17
18
String nodeId = docker.initSwarm(swarmInit);
19
System.out.println("Swarm initialized. Node ID: " + nodeId);
20
```
21
22
### Advanced Swarm Initialization
23
24
```java { .api }
25
// Initialize swarm with custom specification
26
SwarmSpec swarmSpec = SwarmSpec.builder()
27
.name("production-swarm")
28
.labels(Map.of(
29
"environment", "production",
30
"datacenter", "us-east-1"
31
))
32
33
// Orchestration settings
34
.orchestration(OrchestrationConfig.builder()
35
.taskHistoryRetentionLimit(10)
36
.build())
37
38
// Raft consensus configuration
39
.raft(RaftConfig.builder()
40
.snapshotInterval(10000L)
41
.keepOldSnapshots(5L)
42
.logEntriesForSlowFollowers(500L)
43
.electionTick(10L)
44
.heartbeatTick(1L)
45
.build())
46
47
// Dispatcher configuration
48
.dispatcher(DispatcherConfig.builder()
49
.heartbeatPeriod(Duration.ofSeconds(5))
50
.build())
51
52
// Certificate authority configuration
53
.caConfig(CaConfig.builder()
54
.nodeCertExpiry(Duration.ofDays(90))
55
.build())
56
57
// Encryption configuration
58
.encryptionConfig(EncryptionConfig.builder()
59
.autoLockManagers(true)
60
.build())
61
62
.build();
63
64
SwarmInit advancedInit = SwarmInit.builder()
65
.listenAddr("0.0.0.0:2377")
66
.advertiseAddr("192.168.1.100:2377")
67
.forceNewCluster(false)
68
.spec(swarmSpec)
69
.build();
70
71
String nodeId = docker.initSwarm(advancedInit);
72
```
73
74
### Swarm Inspection
75
76
```java { .api }
77
// Get swarm information
78
Swarm swarm = docker.inspectSwarm();
79
80
System.out.println("Swarm ID: " + swarm.id());
81
System.out.println("Created At: " + swarm.createdAt());
82
System.out.println("Updated At: " + swarm.updatedAt());
83
84
// Swarm specification
85
SwarmSpec spec = swarm.spec();
86
System.out.println("Swarm Name: " + spec.name());
87
System.out.println("Labels: " + spec.labels());
88
89
// Join tokens for workers and managers
90
JoinTokens joinTokens = swarm.joinTokens();
91
System.out.println("Worker Join Token: " + joinTokens.worker());
92
System.out.println("Manager Join Token: " + joinTokens.manager());
93
94
// Remote managers
95
List<RemoteManager> managers = swarm.remoteManagers();
96
for (RemoteManager manager : managers) {
97
System.out.println("Manager: " + manager.nodeId() + " @ " + manager.addr());
98
}
99
```
100
101
### Joining and Leaving Swarm
102
103
```java { .api }
104
// Join swarm as worker
105
SwarmJoin workerJoin = SwarmJoin.builder()
106
.listenAddr("0.0.0.0:2377")
107
.advertiseAddr("192.168.1.101:2377")
108
.remoteAddrs("192.168.1.100:2377")
109
.joinToken("worker-token-here")
110
.build();
111
112
docker.joinSwarm(workerJoin);
113
114
// Join swarm as manager
115
SwarmJoin managerJoin = SwarmJoin.builder()
116
.listenAddr("0.0.0.0:2377")
117
.advertiseAddr("192.168.1.102:2377")
118
.remoteAddrs("192.168.1.100:2377")
119
.joinToken("manager-token-here")
120
.build();
121
122
docker.joinSwarm(managerJoin);
123
124
// Leave swarm
125
docker.leaveSwarm();
126
127
// Force leave (for managers)
128
docker.leaveSwarm(true);
129
```
130
131
### Swarm Updates
132
133
```java { .api }
134
// Update swarm configuration
135
Swarm currentSwarm = docker.inspectSwarm();
136
Long version = currentSwarm.version().index();
137
138
SwarmSpec updatedSpec = currentSwarm.spec().toBuilder()
139
.name("updated-production-swarm")
140
.labels(Map.of(
141
"environment", "production",
142
"region", "us-east",
143
"updated", "true"
144
))
145
.build();
146
147
// Update swarm
148
docker.updateSwarm(version, updatedSpec);
149
150
// Update with token rotation
151
docker.updateSwarm(version, true, false, updatedSpec); // Rotate worker token
152
docker.updateSwarm(version, false, true, updatedSpec); // Rotate manager token
153
```
154
155
### Swarm Unlock
156
157
```java { .api }
158
// Get unlock key (for auto-lock enabled swarms)
159
UnlockKey unlockKey = docker.unlockKey();
160
System.out.println("Unlock Key: " + unlockKey.unlockKey());
161
162
// Unlock swarm
163
docker.unlock(unlockKey);
164
```
165
166
## Service Management
167
168
### Service Creation
169
170
```java { .api }
171
import com.spotify.docker.client.messages.swarm.*;
172
173
// Basic service creation
174
ServiceSpec serviceSpec = ServiceSpec.builder()
175
.name("web-service")
176
.taskTemplate(TaskSpec.builder()
177
.containerSpec(ContainerSpec.builder()
178
.image("nginx:latest")
179
.build())
180
.build())
181
.build();
182
183
ServiceCreateResponse response = docker.createService(serviceSpec);
184
System.out.println("Created service ID: " + response.id());
185
```
186
187
### Advanced Service Configuration
188
189
```java { .api }
190
// Comprehensive service configuration
191
ServiceSpec advancedService = ServiceSpec.builder()
192
.name("production-api")
193
.labels(Map.of(
194
"environment", "production",
195
"tier", "backend",
196
"version", "1.0.0"
197
))
198
199
// Task template
200
.taskTemplate(TaskSpec.builder()
201
.containerSpec(ContainerSpec.builder()
202
.image("myapp:latest")
203
.hostname("api-server")
204
.env("ENV=production", "PORT=8080")
205
.args("--config", "/app/config.yml")
206
.user("appuser")
207
.dir("/app")
208
209
// Resource limits
210
.resources(ResourceRequirements.builder()
211
.limits(Resources.builder()
212
.memoryBytes(512L * 1024 * 1024) // 512MB
213
.nanoCpus(500_000_000L) // 0.5 CPU
214
.build())
215
.reservations(Resources.builder()
216
.memoryBytes(256L * 1024 * 1024) // 256MB reserved
217
.nanoCpus(250_000_000L) // 0.25 CPU reserved
218
.build())
219
.build())
220
221
// Health check
222
.healthcheck(HealthConfig.builder()
223
.test("CMD curl -f http://localhost:8080/health || exit 1")
224
.interval(Duration.ofSeconds(30))
225
.timeout(Duration.ofSeconds(10))
226
.retries(3)
227
.startPeriod(Duration.ofSeconds(60))
228
.build())
229
230
// Secrets and configs
231
.secrets(SecretBind.builder()
232
.secretId("app-secret-id")
233
.secretName("database-password")
234
.file(SecretFile.builder()
235
.name("db-password")
236
.uid(1000L)
237
.gid(1000L)
238
.mode(0400L)
239
.build())
240
.build())
241
242
.configs(ConfigBind.builder()
243
.configId("app-config-id")
244
.configName("application-config")
245
.file(ConfigFile.builder()
246
.name("app-config.yml")
247
.uid(1000L)
248
.gid(1000L)
249
.mode(0644L)
250
.build())
251
.build())
252
253
.build())
254
255
// Placement constraints
256
.placement(Placement.builder()
257
.constraints("node.role==worker", "engine.labels.type==compute")
258
.preferences(PlacementPreference.builder()
259
.spread(SpreadDescriptor.builder()
260
.spreadDescriptor("node.labels.zone")
261
.build())
262
.build())
263
.maxReplicas(2L) // Max replicas per node
264
.build())
265
266
// Restart policy
267
.restartPolicy(RestartPolicy.builder()
268
.condition("on-failure")
269
.delay(Duration.ofSeconds(5))
270
.maxAttempts(3L)
271
.window(Duration.ofSeconds(120))
272
.build())
273
274
// Networks
275
.networks(NetworkAttachmentConfig.builder()
276
.target("production-network")
277
.aliases("api", "backend")
278
.build())
279
280
.build())
281
282
// Service mode (replicated vs global)
283
.mode(ServiceMode.builder()
284
.replicated(ReplicatedService.builder()
285
.replicas(3L)
286
.build())
287
.build())
288
289
// Update configuration
290
.updateConfig(UpdateConfig.builder()
291
.parallelism(1L)
292
.delay(Duration.ofSeconds(10))
293
.failureAction("rollback")
294
.monitor(Duration.ofSeconds(60))
295
.maxFailureRatio(0.1f)
296
.order("start-first")
297
.build())
298
299
// Rollback configuration
300
.rollbackConfig(UpdateConfig.builder()
301
.parallelism(1L)
302
.delay(Duration.ofSeconds(5))
303
.failureAction("pause")
304
.monitor(Duration.ofSeconds(30))
305
.maxFailureRatio(0.0f)
306
.build())
307
308
// Endpoint specification (for published ports)
309
.endpointSpec(EndpointSpec.builder()
310
.mode("vip")
311
.ports(PortConfig.builder()
312
.name("http")
313
.protocol("tcp")
314
.targetPort(8080L)
315
.publishedPort(80L)
316
.publishMode("ingress")
317
.build())
318
.build())
319
320
.build();
321
322
ServiceCreateResponse response = docker.createService(advancedService);
323
```
324
325
### Service with Authentication
326
327
```java { .api }
328
// Create service that requires registry authentication
329
RegistryAuth auth = RegistryAuth.builder()
330
.username("myuser")
331
.password("mypass")
332
.serverAddress("https://my-registry.com")
333
.build();
334
335
ServiceSpec serviceSpec = ServiceSpec.builder()
336
.name("private-service")
337
.taskTemplate(TaskSpec.builder()
338
.containerSpec(ContainerSpec.builder()
339
.image("my-registry.com/myapp:latest")
340
.build())
341
.build())
342
.build();
343
344
ServiceCreateResponse response = docker.createService(serviceSpec, auth);
345
```
346
347
### Service Inspection and Updates
348
349
```java { .api }
350
// Inspect service
351
Service service = docker.inspectService("service-name-or-id");
352
353
System.out.println("Service ID: " + service.id());
354
System.out.println("Version: " + service.version().index());
355
System.out.println("Created: " + service.createdAt());
356
System.out.println("Updated: " + service.updatedAt());
357
358
// Service endpoint
359
Endpoint endpoint = service.endpoint();
360
if (endpoint != null) {
361
System.out.println("Endpoint Mode: " + endpoint.spec().mode());
362
for (PortConfig port : endpoint.spec().ports()) {
363
System.out.println("Port: " + port.publishedPort() + " -> " + port.targetPort());
364
}
365
366
// Virtual IPs
367
for (EndpointVirtualIp vip : endpoint.virtualIps()) {
368
System.out.println("VIP: " + vip.addr() + " (Network: " + vip.networkId() + ")");
369
}
370
}
371
372
// Update service
373
ServiceSpec updatedSpec = service.spec().toBuilder()
374
.taskTemplate(service.spec().taskTemplate().toBuilder()
375
.containerSpec(service.spec().taskTemplate().containerSpec().toBuilder()
376
.image("myapp:v2.0")
377
.env("VERSION=2.0", "UPDATED=true")
378
.build())
379
.build())
380
.build();
381
382
docker.updateService(service.id(), service.version().index(), updatedSpec);
383
```
384
385
### Service Listing and Filtering
386
387
```java { .api }
388
// List all services
389
List<Service> allServices = docker.listServices();
390
391
// List with criteria
392
Service.Criteria criteria = Service.Criteria.builder()
393
.serviceName("web-service")
394
.serviceId("service-id")
395
.serviceLabel("environment", "production")
396
.build();
397
398
List<Service> filteredServices = docker.listServices(criteria);
399
400
for (Service service : filteredServices) {
401
System.out.println("Service: " + service.spec().name());
402
System.out.println("Replicas: " + service.spec().mode().replicated().replicas());
403
System.out.println("Image: " + service.spec().taskTemplate().containerSpec().image());
404
}
405
```
406
407
### Service Removal
408
409
```java { .api }
410
// Remove service
411
docker.removeService("service-name-or-id");
412
413
// Safe service removal with scaling down first
414
public void safeRemoveService(DockerClient docker, String serviceId)
415
throws DockerException, InterruptedException {
416
417
try {
418
// First scale service to 0
419
Service service = docker.inspectService(serviceId);
420
ServiceSpec scaledSpec = service.spec().toBuilder()
421
.mode(ServiceMode.builder()
422
.replicated(ReplicatedService.builder()
423
.replicas(0L)
424
.build())
425
.build())
426
.build();
427
428
docker.updateService(serviceId, service.version().index(), scaledSpec);
429
System.out.println("Scaled service to 0 replicas");
430
431
// Wait for tasks to stop
432
Thread.sleep(10000);
433
434
// Remove service
435
docker.removeService(serviceId);
436
System.out.println("Removed service: " + serviceId);
437
438
} catch (DockerException e) {
439
System.err.println("Error removing service: " + e.getMessage());
440
}
441
}
442
```
443
444
### Service Logs
445
446
```java { .api }
447
// Get service logs
448
try (LogStream logs = docker.serviceLogs("service-name",
449
DockerClient.LogsParam.stdout(),
450
DockerClient.LogsParam.stderr(),
451
DockerClient.LogsParam.follow(),
452
DockerClient.LogsParam.timestamps(true))) {
453
454
logs.forEachRemaining(logMessage -> {
455
System.out.println("Service Log: " + logMessage.content().toStringUtf8());
456
});
457
}
458
```
459
460
## Task Management
461
462
### Task Listing and Inspection
463
464
```java { .api }
465
// List all tasks
466
List<Task> allTasks = docker.listTasks();
467
468
// List with criteria
469
Task.Criteria taskCriteria = Task.Criteria.builder()
470
.serviceName("web-service")
471
.nodeId("node-id")
472
.taskName("web-service.1")
473
.taskState("running")
474
.build();
475
476
List<Task> filteredTasks = docker.listTasks(taskCriteria);
477
478
for (Task task : filteredTasks) {
479
System.out.println("Task ID: " + task.id());
480
System.out.println("Service ID: " + task.serviceId());
481
System.out.println("Node ID: " + task.nodeId());
482
System.out.println("Slot: " + task.slot());
483
484
TaskStatus status = task.status();
485
System.out.println("State: " + status.state());
486
System.out.println("Message: " + status.message());
487
488
if (status.containerStatus() != null) {
489
System.out.println("Container ID: " + status.containerStatus().containerId());
490
System.out.println("PID: " + status.containerStatus().pid());
491
}
492
}
493
```
494
495
### Task Inspection
496
497
```java { .api }
498
// Inspect specific task
499
Task task = docker.inspectTask("task-id");
500
501
System.out.println("Task Details:");
502
System.out.println(" ID: " + task.id());
503
System.out.println(" Version: " + task.version().index());
504
System.out.println(" Created: " + task.createdAt());
505
System.out.println(" Updated: " + task.updatedAt());
506
System.out.println(" Service: " + task.serviceId());
507
System.out.println(" Node: " + task.nodeId());
508
System.out.println(" Slot: " + task.slot());
509
510
// Task specification
511
TaskSpec spec = task.spec();
512
ContainerSpec containerSpec = spec.containerSpec();
513
System.out.println(" Image: " + containerSpec.image());
514
System.out.println(" Command: " + containerSpec.command());
515
System.out.println(" Args: " + containerSpec.args());
516
517
// Task status and history
518
TaskStatus status = task.status();
519
System.out.println(" Current State: " + status.state());
520
System.out.println(" Message: " + status.message());
521
System.out.println(" Timestamp: " + status.timestamp());
522
523
// Container status (if running)
524
if (status.containerStatus() != null) {
525
ContainerStatus containerStatus = status.containerStatus();
526
System.out.println(" Container ID: " + containerStatus.containerId());
527
System.out.println(" PID: " + containerStatus.pid());
528
System.out.println(" Exit Code: " + containerStatus.exitCode());
529
}
530
```
531
532
## Node Management
533
534
### Node Listing and Inspection
535
536
```java { .api }
537
// List all nodes
538
List<Node> allNodes = docker.listNodes();
539
540
// List with criteria
541
Node.Criteria nodeCriteria = Node.Criteria.builder()
542
.nodeName("worker-1")
543
.nodeRole("worker")
544
.membershipAccepted()
545
.build();
546
547
List<Node> filteredNodes = docker.listNodes(nodeCriteria);
548
549
for (Node node : filteredNodes) {
550
System.out.println("Node ID: " + node.id());
551
System.out.println("Hostname: " + node.description().hostname());
552
System.out.println("Role: " + node.spec().role());
553
System.out.println("Availability: " + node.spec().availability());
554
System.out.println("State: " + node.status().state());
555
System.out.println("Address: " + node.status().addr());
556
557
// Manager status (if applicable)
558
ManagerStatus managerStatus = node.managerStatus();
559
if (managerStatus != null) {
560
System.out.println("Leader: " + managerStatus.leader());
561
System.out.println("Reachability: " + managerStatus.reachability());
562
System.out.println("Address: " + managerStatus.addr());
563
}
564
565
// Node resources
566
NodeDescription desc = node.description();
567
Resources resources = desc.resources();
568
System.out.println("Memory: " + resources.memoryBytes() + " bytes");
569
System.out.println("CPUs: " + resources.nanoCpus() / 1_000_000_000.0);
570
}
571
```
572
573
### Node Inspection
574
575
```java { .api }
576
// Inspect specific node (returns NodeInfo which is alias for Node)
577
NodeInfo nodeInfo = docker.inspectNode("node-id-or-hostname");
578
579
System.out.println("Node Information:");
580
System.out.println(" ID: " + nodeInfo.id());
581
System.out.println(" Version: " + nodeInfo.version().index());
582
System.out.println(" Created: " + nodeInfo.createdAt());
583
System.out.println(" Updated: " + nodeInfo.updatedAt());
584
585
// Node specification
586
NodeSpec spec = nodeInfo.spec();
587
System.out.println(" Name: " + spec.name());
588
System.out.println(" Labels: " + spec.labels());
589
System.out.println(" Role: " + spec.role());
590
System.out.println(" Availability: " + spec.availability());
591
592
// Node description (hardware/software info)
593
NodeDescription desc = nodeInfo.description();
594
System.out.println(" Hostname: " + desc.hostname());
595
Platform platform = desc.platform();
596
System.out.println(" Architecture: " + platform.architecture());
597
System.out.println(" OS: " + platform.os());
598
599
// Engine info
600
EngineDescription engine = desc.engine();
601
System.out.println(" Engine Version: " + engine.engineVersion());
602
System.out.println(" Plugins: " + engine.plugins());
603
System.out.println(" Labels: " + engine.labels());
604
605
// TLS info
606
TlsInfo tlsInfo = desc.tlsInfo();
607
System.out.println(" Certificate Subject: " + tlsInfo.certIssuerSubject());
608
System.out.println(" Certificate Issuer: " + tlsInfo.certIssuerPublicKey());
609
```
610
611
### Node Updates
612
613
```java { .api }
614
// Update node configuration
615
Node node = docker.listNodes().get(0); // Get first node
616
Long version = node.version().index();
617
618
NodeSpec updatedSpec = node.spec().toBuilder()
619
.availability("drain") // Drain node for maintenance
620
.labels(Map.of(
621
"maintenance", "true",
622
"type", "compute",
623
"zone", "us-east-1a"
624
))
625
.build();
626
627
docker.updateNode(node.id(), version, updatedSpec);
628
629
// Common node operations
630
public void drainNode(DockerClient docker, String nodeId)
631
throws DockerException, InterruptedException {
632
633
Node node = docker.inspectNode(nodeId);
634
NodeSpec drainSpec = node.spec().toBuilder()
635
.availability("drain")
636
.build();
637
638
docker.updateNode(nodeId, node.version().index(), drainSpec);
639
System.out.println("Node " + nodeId + " drained");
640
}
641
642
public void activateNode(DockerClient docker, String nodeId)
643
throws DockerException, InterruptedException {
644
645
Node node = docker.inspectNode(nodeId);
646
NodeSpec activeSpec = node.spec().toBuilder()
647
.availability("active")
648
.build();
649
650
docker.updateNode(nodeId, node.version().index(), activeSpec);
651
System.out.println("Node " + nodeId + " activated");
652
}
653
```
654
655
### Node Removal
656
657
```java { .api }
658
// Remove node from swarm
659
docker.deleteNode("node-id");
660
661
// Force remove (even if node is manager)
662
docker.deleteNode("node-id", true);
663
664
// Safe node removal process
665
public void safeRemoveNode(DockerClient docker, String nodeId)
666
throws DockerException, InterruptedException {
667
668
try {
669
// First drain the node
670
drainNode(docker, nodeId);
671
672
// Wait for tasks to migrate
673
System.out.println("Waiting for tasks to migrate...");
674
Thread.sleep(30000);
675
676
// Verify no tasks are running on the node
677
List<Task> nodeTasks = docker.listTasks(
678
Task.Criteria.builder()
679
.nodeId(nodeId)
680
.taskState("running")
681
.build()
682
);
683
684
if (!nodeTasks.isEmpty()) {
685
System.out.println("Warning: " + nodeTasks.size() + " tasks still running on node");
686
}
687
688
// Remove node
689
docker.deleteNode(nodeId);
690
System.out.println("Node " + nodeId + " removed successfully");
691
692
} catch (DockerException e) {
693
System.err.println("Error removing node: " + e.getMessage());
694
}
695
}
696
```
697
698
## Secrets Management
699
700
### Secret Creation
701
702
```java { .api }
703
import com.spotify.docker.client.messages.swarm.*;
704
import java.util.Base64;
705
706
// Create secret from string data
707
String secretData = "my-secret-password";
708
String encodedData = Base64.getEncoder().encodeToString(secretData.getBytes());
709
710
SecretSpec secretSpec = SecretSpec.builder()
711
.name("database-password")
712
.data(encodedData)
713
.labels(Map.of(
714
"environment", "production",
715
"type", "password"
716
))
717
.build();
718
719
SecretCreateResponse response = docker.createSecret(secretSpec);
720
System.out.println("Created secret ID: " + response.id());
721
```
722
723
### Advanced Secret Configuration
724
725
```java { .api }
726
// Create secret with external driver
727
SecretSpec externalSecret = SecretSpec.builder()
728
.name("external-secret")
729
.labels(Map.of("provider", "vault"))
730
.driver(Driver.builder()
731
.name("vault")
732
.options(Map.of(
733
"path", "secret/myapp/db",
734
"key", "password"
735
))
736
.build())
737
.build();
738
739
// Create secret from file
740
byte[] fileContent = Files.readAllBytes(Paths.get("/path/to/secret/file"));
741
String fileData = Base64.getEncoder().encodeToString(fileContent);
742
743
SecretSpec fileSecret = SecretSpec.builder()
744
.name("ssl-certificate")
745
.data(fileData)
746
.labels(Map.of("type", "certificate"))
747
.build();
748
749
docker.createSecret(externalSecret);
750
docker.createSecret(fileSecret);
751
```
752
753
### Secret Listing and Inspection
754
755
```java { .api }
756
// List all secrets
757
List<Secret> secrets = docker.listSecrets();
758
759
for (Secret secret : secrets) {
760
System.out.println("Secret ID: " + secret.id());
761
System.out.println("Name: " + secret.spec().name());
762
System.out.println("Created: " + secret.createdAt());
763
System.out.println("Updated: " + secret.updatedAt());
764
System.out.println("Labels: " + secret.spec().labels());
765
766
// Driver information
767
Driver driver = secret.spec().driver();
768
if (driver != null) {
769
System.out.println("Driver: " + driver.name());
770
System.out.println("Driver Options: " + driver.options());
771
}
772
}
773
774
// Inspect specific secret
775
Secret secret = docker.inspectSecret("secret-name-or-id");
776
System.out.println("Secret Details:");
777
System.out.println(" ID: " + secret.id());
778
System.out.println(" Version: " + secret.version().index());
779
System.out.println(" Name: " + secret.spec().name());
780
// Note: Secret data is not returned for security reasons
781
```
782
783
### Using Secrets in Services
784
785
```java { .api }
786
// Service with secret bindings
787
ServiceSpec serviceWithSecrets = ServiceSpec.builder()
788
.name("secure-web-service")
789
.taskTemplate(TaskSpec.builder()
790
.containerSpec(ContainerSpec.builder()
791
.image("nginx:latest")
792
793
// Bind secrets as files
794
.secrets(
795
SecretBind.builder()
796
.secretId("database-password-id")
797
.secretName("database-password")
798
.file(SecretFile.builder()
799
.name("db_password")
800
.uid(33L) // www-data user
801
.gid(33L) // www-data group
802
.mode(0400L) // Read-only for owner
803
.build())
804
.build(),
805
806
SecretBind.builder()
807
.secretId("ssl-cert-id")
808
.secretName("ssl-certificate")
809
.file(SecretFile.builder()
810
.name("server.crt")
811
.uid(0L) // root
812
.gid(0L) // root
813
.mode(0444L) // Read-only for all
814
.build())
815
.build()
816
)
817
818
.build())
819
.build())
820
.build();
821
822
docker.createService(serviceWithSecrets);
823
```
824
825
### Secret Removal
826
827
```java { .api }
828
// Remove secret
829
docker.deleteSecret("secret-name-or-id");
830
831
// Safe secret removal (check usage first)
832
public void safeRemoveSecret(DockerClient docker, String secretId)
833
throws DockerException, InterruptedException {
834
835
try {
836
// Check which services use this secret
837
List<Service> services = docker.listServices();
838
List<String> usingServices = new ArrayList<>();
839
840
for (Service service : services) {
841
TaskSpec taskSpec = service.spec().taskTemplate();
842
if (taskSpec.containerSpec().secrets() != null) {
843
for (SecretBind secret : taskSpec.containerSpec().secrets()) {
844
if (secretId.equals(secret.secretId()) || secretId.equals(secret.secretName())) {
845
usingServices.add(service.spec().name());
846
break;
847
}
848
}
849
}
850
}
851
852
if (usingServices.isEmpty()) {
853
docker.deleteSecret(secretId);
854
System.out.println("Removed secret: " + secretId);
855
} else {
856
System.out.println("Secret is in use by services: " + usingServices);
857
}
858
859
} catch (DockerException e) {
860
System.err.println("Error removing secret: " + e.getMessage());
861
}
862
}
863
```
864
865
## Configs Management
866
867
### Config Creation
868
869
```java { .api }
870
import com.spotify.docker.client.messages.swarm.*;
871
872
// Create config from string data
873
String configData = "server {\n listen 80;\n server_name example.com;\n}";
874
String encodedConfig = Base64.getEncoder().encodeToString(configData.getBytes());
875
876
ConfigSpec configSpec = ConfigSpec.builder()
877
.name("nginx-config")
878
.data(encodedConfig)
879
.labels(Map.of(
880
"application", "nginx",
881
"version", "1.0"
882
))
883
.build();
884
885
ConfigCreateResponse response = docker.createConfig(configSpec);
886
System.out.println("Created config ID: " + response.id());
887
```
888
889
### Advanced Config Management
890
891
```java { .api }
892
// Create config from template file
893
String templateData = """
894
upstream backend {
895
server ${BACKEND_HOST}:${BACKEND_PORT};
896
}
897
898
server {
899
listen 80;
900
location / {
901
proxy_pass http://backend;
902
}
903
}
904
""";
905
906
ConfigSpec templateConfig = ConfigSpec.builder()
907
.name("nginx-template")
908
.data(Base64.getEncoder().encodeToString(templateData.getBytes()))
909
.labels(Map.of(
910
"type", "template",
911
"service", "nginx"
912
))
913
.build();
914
915
docker.createConfig(templateConfig);
916
```
917
918
### Config Listing and Inspection
919
920
```java { .api }
921
// List all configs
922
List<Config> configs = docker.listConfigs();
923
924
// List with criteria
925
Config.Criteria configCriteria = Config.Criteria.builder()
926
.configName("nginx-config")
927
.configLabel("application", "nginx")
928
.build();
929
930
List<Config> filteredConfigs = docker.listConfigs(configCriteria);
931
932
for (Config config : filteredConfigs) {
933
System.out.println("Config ID: " + config.id());
934
System.out.println("Name: " + config.spec().name());
935
System.out.println("Created: " + config.createdAt());
936
System.out.println("Labels: " + config.spec().labels());
937
}
938
939
// Inspect specific config
940
Config config = docker.inspectConfig("config-name-or-id");
941
System.out.println("Config Details:");
942
System.out.println(" ID: " + config.id());
943
System.out.println(" Version: " + config.version().index());
944
System.out.println(" Name: " + config.spec().name());
945
// Config data is available (unlike secrets)
946
String data = new String(Base64.getDecoder().decode(config.spec().data()));
947
System.out.println(" Data: " + data);
948
```
949
950
### Using Configs in Services
951
952
```java { .api }
953
// Service with config bindings
954
ServiceSpec serviceWithConfigs = ServiceSpec.builder()
955
.name("configured-nginx")
956
.taskTemplate(TaskSpec.builder()
957
.containerSpec(ContainerSpec.builder()
958
.image("nginx:latest")
959
960
// Bind configs as files
961
.configs(
962
ConfigBind.builder()
963
.configId("nginx-config-id")
964
.configName("nginx-config")
965
.file(ConfigFile.builder()
966
.name("nginx.conf")
967
.uid(0L)
968
.gid(0L)
969
.mode(0644L)
970
.build())
971
.build(),
972
973
ConfigBind.builder()
974
.configId("ssl-config-id")
975
.configName("ssl-config")
976
.file(ConfigFile.builder()
977
.name("ssl.conf")
978
.uid(33L) // www-data
979
.gid(33L)
980
.mode(0644L)
981
.build())
982
.build()
983
)
984
985
.build())
986
.build())
987
.build();
988
989
docker.createService(serviceWithConfigs);
990
```
991
992
### Config Updates
993
994
```java { .api }
995
// Update config (creates new version)
996
Config existingConfig = docker.inspectConfig("nginx-config");
997
String newConfigData = "server {\n listen 443 ssl;\n server_name example.com;\n}";
998
999
ConfigSpec updatedSpec = existingConfig.spec().toBuilder()
1000
.data(Base64.getEncoder().encodeToString(newConfigData.getBytes()))
1001
.labels(Map.of(
1002
"application", "nginx",
1003
"version", "2.0",
1004
"ssl", "enabled"
1005
))
1006
.build();
1007
1008
docker.updateConfig(existingConfig.id(), existingConfig.version().index(), updatedSpec);
1009
```
1010
1011
### Config Removal
1012
1013
```java { .api }
1014
// Remove config
1015
docker.deleteConfig("config-name-or-id");
1016
1017
// Bulk config cleanup
1018
public void cleanupOldConfigs(DockerClient docker, String namePrefix)
1019
throws DockerException, InterruptedException {
1020
1021
List<Config> configs = docker.listConfigs();
1022
1023
for (Config config : configs) {
1024
String configName = config.spec().name();
1025
if (configName.startsWith(namePrefix)) {
1026
1027
// Check if config is in use
1028
boolean inUse = isConfigInUse(docker, config.id());
1029
1030
if (!inUse) {
1031
try {
1032
docker.deleteConfig(config.id());
1033
System.out.println("Removed unused config: " + configName);
1034
} catch (DockerException e) {
1035
System.err.println("Failed to remove config " + configName + ": " + e.getMessage());
1036
}
1037
} else {
1038
System.out.println("Config in use, skipping: " + configName);
1039
}
1040
}
1041
}
1042
}
1043
1044
private boolean isConfigInUse(DockerClient docker, String configId)
1045
throws DockerException, InterruptedException {
1046
1047
List<Service> services = docker.listServices();
1048
for (Service service : services) {
1049
TaskSpec taskSpec = service.spec().taskTemplate();
1050
if (taskSpec.containerSpec().configs() != null) {
1051
for (ConfigBind config : taskSpec.containerSpec().configs()) {
1052
if (configId.equals(config.configId()) || configId.equals(config.configName())) {
1053
return true;
1054
}
1055
}
1056
}
1057
}
1058
return false;
1059
}
1060
```
1061
1062
## Complete Swarm Deployment Example
1063
1064
```java { .api }
1065
public class SwarmDeploymentExample {
1066
1067
public void deployCompleteApplication(DockerClient docker)
1068
throws DockerException, InterruptedException {
1069
1070
System.out.println("Deploying complete multi-service application to swarm...");
1071
1072
// 1. Initialize swarm if needed
1073
try {
1074
docker.inspectSwarm();
1075
System.out.println("Swarm already initialized");
1076
} catch (DockerException e) {
1077
initializeSwarm(docker);
1078
}
1079
1080
// 2. Create application network
1081
createApplicationNetwork(docker);
1082
1083
// 3. Create secrets and configs
1084
createSecretsAndConfigs(docker);
1085
1086
// 4. Deploy database service
1087
deployDatabaseService(docker);
1088
1089
// 5. Deploy application service
1090
deployApplicationService(docker);
1091
1092
// 6. Deploy load balancer
1093
deployLoadBalancer(docker);
1094
1095
// 7. Monitor deployment
1096
monitorDeployment(docker);
1097
1098
System.out.println("Application deployment completed");
1099
}
1100
1101
private void initializeSwarm(DockerClient docker)
1102
throws DockerException, InterruptedException {
1103
1104
SwarmInit init = SwarmInit.builder()
1105
.listenAddr("0.0.0.0:2377")
1106
.build();
1107
1108
String nodeId = docker.initSwarm(init);
1109
System.out.println("Initialized swarm with node: " + nodeId);
1110
}
1111
1112
private void createApplicationNetwork(DockerClient docker)
1113
throws DockerException, InterruptedException {
1114
1115
NetworkConfig networkConfig = NetworkConfig.builder()
1116
.name("app-network")
1117
.driver("overlay")
1118
.attachable(true)
1119
.labels(Map.of("purpose", "application"))
1120
.build();
1121
1122
try {
1123
docker.createNetwork(networkConfig);
1124
System.out.println("Created application network");
1125
} catch (DockerException e) {
1126
System.out.println("Network already exists");
1127
}
1128
}
1129
1130
private void createSecretsAndConfigs(DockerClient docker)
1131
throws DockerException, InterruptedException {
1132
1133
// Database password secret
1134
SecretSpec dbSecret = SecretSpec.builder()
1135
.name("db-password")
1136
.data(Base64.getEncoder().encodeToString("secure-password".getBytes()))
1137
.build();
1138
1139
// Application config
1140
String appConfig = """
1141
database:
1142
host: postgres
1143
port: 5432
1144
name: myapp
1145
server:
1146
port: 8080
1147
""";
1148
1149
ConfigSpec appConfigSpec = ConfigSpec.builder()
1150
.name("app-config")
1151
.data(Base64.getEncoder().encodeToString(appConfig.getBytes()))
1152
.build();
1153
1154
try {
1155
docker.createSecret(dbSecret);
1156
docker.createConfig(appConfigSpec);
1157
System.out.println("Created secrets and configs");
1158
} catch (DockerException e) {
1159
System.out.println("Secrets/configs already exist");
1160
}
1161
}
1162
1163
private void deployDatabaseService(DockerClient docker)
1164
throws DockerException, InterruptedException {
1165
1166
ServiceSpec dbService = ServiceSpec.builder()
1167
.name("postgres")
1168
.taskTemplate(TaskSpec.builder()
1169
.containerSpec(ContainerSpec.builder()
1170
.image("postgres:13")
1171
.env("POSTGRES_DB=myapp", "POSTGRES_USER=app")
1172
.secrets(SecretBind.builder()
1173
.secretName("db-password")
1174
.file(SecretFile.builder()
1175
.name("postgres_password")
1176
.uid(999L) // postgres user
1177
.gid(999L)
1178
.mode(0400L)
1179
.build())
1180
.build())
1181
.mounts(Mount.builder()
1182
.type("volume")
1183
.source("postgres-data")
1184
.target("/var/lib/postgresql/data")
1185
.build())
1186
.build())
1187
.networks(NetworkAttachmentConfig.builder()
1188
.target("app-network")
1189
.aliases("database")
1190
.build())
1191
.placement(Placement.builder()
1192
.constraints("node.role==manager") // Database on manager for persistence
1193
.build())
1194
.build())
1195
.mode(ServiceMode.builder()
1196
.replicated(ReplicatedService.builder()
1197
.replicas(1L)
1198
.build())
1199
.build())
1200
.build();
1201
1202
docker.createService(dbService);
1203
System.out.println("Deployed database service");
1204
}
1205
1206
private void deployApplicationService(DockerClient docker)
1207
throws DockerException, InterruptedException {
1208
1209
ServiceSpec appService = ServiceSpec.builder()
1210
.name("webapp")
1211
.taskTemplate(TaskSpec.builder()
1212
.containerSpec(ContainerSpec.builder()
1213
.image("myapp:latest")
1214
.configs(ConfigBind.builder()
1215
.configName("app-config")
1216
.file(ConfigFile.builder()
1217
.name("config.yml")
1218
.uid(1000L)
1219
.gid(1000L)
1220
.mode(0644L)
1221
.build())
1222
.build())
1223
.secrets(SecretBind.builder()
1224
.secretName("db-password")
1225
.file(SecretFile.builder()
1226
.name("db_password")
1227
.uid(1000L)
1228
.gid(1000L)
1229
.mode(0400L)
1230
.build())
1231
.build())
1232
.healthcheck(HealthConfig.builder()
1233
.test("CMD curl -f http://localhost:8080/health")
1234
.interval(Duration.ofSeconds(30))
1235
.timeout(Duration.ofSeconds(10))
1236
.retries(3)
1237
.build())
1238
.build())
1239
.networks(NetworkAttachmentConfig.builder()
1240
.target("app-network")
1241
.aliases("backend")
1242
.build())
1243
.placement(Placement.builder()
1244
.constraints("node.role==worker")
1245
.build())
1246
.resources(ResourceRequirements.builder()
1247
.limits(Resources.builder()
1248
.memoryBytes(512L * 1024 * 1024)
1249
.nanoCpus(500_000_000L)
1250
.build())
1251
.build())
1252
.build())
1253
.mode(ServiceMode.builder()
1254
.replicated(ReplicatedService.builder()
1255
.replicas(3L)
1256
.build())
1257
.build())
1258
.updateConfig(UpdateConfig.builder()
1259
.parallelism(1L)
1260
.delay(Duration.ofSeconds(10))
1261
.failureAction("rollback")
1262
.build())
1263
.build();
1264
1265
docker.createService(appService);
1266
System.out.println("Deployed application service");
1267
}
1268
1269
private void deployLoadBalancer(DockerClient docker)
1270
throws DockerException, InterruptedException {
1271
1272
ServiceSpec lbService = ServiceSpec.builder()
1273
.name("nginx-lb")
1274
.taskTemplate(TaskSpec.builder()
1275
.containerSpec(ContainerSpec.builder()
1276
.image("nginx:latest")
1277
.build())
1278
.networks(NetworkAttachmentConfig.builder()
1279
.target("app-network")
1280
.build())
1281
.build())
1282
.mode(ServiceMode.builder()
1283
.replicated(ReplicatedService.builder()
1284
.replicas(2L)
1285
.build())
1286
.build())
1287
.endpointSpec(EndpointSpec.builder()
1288
.ports(PortConfig.builder()
1289
.targetPort(80L)
1290
.publishedPort(80L)
1291
.protocol("tcp")
1292
.publishMode("ingress")
1293
.build())
1294
.build())
1295
.build();
1296
1297
docker.createService(lbService);
1298
System.out.println("Deployed load balancer service");
1299
}
1300
1301
private void monitorDeployment(DockerClient docker)
1302
throws DockerException, InterruptedException {
1303
1304
System.out.println("Monitoring deployment status...");
1305
1306
String[] services = {"postgres", "webapp", "nginx-lb"};
1307
1308
for (int i = 0; i < 30; i++) { // Wait up to 5 minutes
1309
boolean allReady = true;
1310
1311
for (String serviceName : services) {
1312
Service service = docker.inspectService(serviceName);
1313
1314
List<Task> tasks = docker.listTasks(Task.Criteria.builder()
1315
.serviceName(serviceName)
1316
.taskState("running")
1317
.build());
1318
1319
Long replicas = service.spec().mode().replicated().replicas();
1320
1321
System.out.printf("Service %s: %d/%d replicas running%n",
1322
serviceName, tasks.size(), replicas);
1323
1324
if (tasks.size() < replicas) {
1325
allReady = false;
1326
}
1327
}
1328
1329
if (allReady) {
1330
System.out.println("All services are ready!");
1331
return;
1332
}
1333
1334
Thread.sleep(10000); // Wait 10 seconds
1335
}
1336
1337
System.out.println("Deployment monitoring timeout");
1338
}
1339
}
1340
```
1341
1342
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.