conlink 2.5.2 → 2.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,16 +1,59 @@
1
- # conlink: Declarative Low-Level Networking for Containers
1
+ # conlink
2
2
 
3
- Create (layer 2 and layer 3) networking between containers using
4
- a declarative configuration.
3
+ [![npm](https://img.shields.io/npm/v/conlink.svg)](https://www.npmjs.com/package/conlink)
4
+ [![docker](https://img.shields.io/docker/v/lonocloud/conlink.svg)](https://hub.docker.com/r/lonocloud/conlink)
5
+
6
+ ## Declarative Low-Level Networking for Containers
7
+
8
+ conlink replaces the standard Docker Compose networking for all or portions of
9
+ your project, providing fine-grained control over layer 2 and layer 3 networking
10
+ with a declarative configuration syntax.
11
+
12
+ ```yaml
13
+ services:
14
+ # 1. Add conlink to your Docker Compose file, and point it to your network
15
+ # config file, which can be the Docker Compose file itself!
16
+ network:
17
+ image: lonocloud/conlink:latest
18
+ pid: host
19
+ network_mode: none
20
+ cap_add: [SYS_ADMIN, NET_ADMIN, SYS_NICE, NET_BROADCAST, IPC_LOCK]
21
+ security_opt: [ 'apparmor:unconfined' ]
22
+ volumes:
23
+ - /var/run/docker.sock:/var/run/docker.sock
24
+ - /var/lib/docker:/var/lib/docker
25
+ - ./:/test
26
+ command: /app/build/conlink.js --compose-file /test/docker-compose.yaml
27
+
28
+ node:
29
+ image: alpine
30
+ # 2. Disable standard Docker Compose networking where desired
31
+ network_mode: none
32
+ command: sleep Infinity
33
+ # 3. Create links with complete control over interface naming,
34
+ # addressing, routing, and much more! Any necessary "switches"
35
+ # (bridges) are created automatically.
36
+ x-network:
37
+ links:
38
+ - {bridge: s1, ip: 10.0.1.1/24}
39
+ ```
40
+
41
+ Check out the [runnable examples](https://github.com/LonoCloud/conlink/tree/master/examples)
42
+ for more ideas on what is possible. [This guide](https://lonocloud.github.io/conlink/#/guides/examples)
43
+ walks through how to run each example.
44
+
45
+ The [reference documentation](https://lonocloud.github.io/conlink/#/reference/network-configuration-syntax)
46
+ contains the full list of configuration options. Be sure to also read [usage notes](https://lonocloud.github.io/conlink/#/usage-notes),
47
+ which highlight some unique aspects of using conlink-provided networking.
5
48
 
6
49
  Conlink also includes scripts that make docker compose a much more
7
50
  powerful development and testing environment (refer to
8
- [Compose scripts](#compose-scripts-mdc-waitsh-and-copysh) for
51
+ [Compose scripts](https://lonocloud.github.io/conlink/#/guides/compose-scripts) for
9
52
  details):
10
53
 
11
- * [mdc](#mdc): modular management of multiple compose configurations
12
- * [wait.sh](#waitsh): wait for network and file conditions before continuing
13
- * [copy.sh](#copysh): recursively copy files with variable templating
54
+ * [mdc](https://lonocloud.github.io/conlink/#/guides/compose-scripts?id=mdc): modular management of multiple compose configurations
55
+ * [wait.sh](https://lonocloud.github.io/conlink/#/guides/compose-scripts?id=waitsh): wait for network and file conditions before continuing
56
+ * [copy.sh](https://lonocloud.github.io/conlink/#/guides/compose-scripts?id=copysh): recursively copy files with variable templating
14
57
 
15
58
  ## Why conlink?
16
59
 
@@ -59,762 +102,9 @@ Other:
59
102
  * For CloudFormation deployment (e.g. `test6`), the AWS CLI is
60
103
  required.
61
104
 
62
- ## Usage Notes
63
-
64
- ### Asynchronous startup
65
-
66
- The conlink managed container links are created after the main process
67
- in the container starts executing. This is different from normal
68
- docker behavior where the interfaces are created and configured before
69
- the main process starts. This means the interfaces for those
70
- links will not be immediately present and the container process will
71
- need to account for this asynchronous interface behavior. The `node`
72
- service in `examples/test2-compose.yaml` shows a simple example of
73
- a container command that will wait for an interface to appear before
74
- continuing with another command.
75
-
76
- ### System Capabilities/Permissions
77
-
78
- The conlink container needs to have a superset of the network related
79
- system capabilities of the containers that it will connect to. At
80
- a minimum `SYS_ADMIN` and `NET_ADMIN` are required but depending on
81
- what the other containers require then those additional capabilities
82
- will also be required for the conlink container. In particular, if the
83
- container uses systemd, then it will likely use `SYS_NICE` and
84
- `NET_BROADCAST` and conlink will likewise need those capabilities.
85
-
86
- ### Bridging: Open vSwtich/OVS, Linux bridge, and patch
87
-
88
- Conlink connects container veth links together via a bridge or via a
89
- direct patch. All veth type links must have a `bridge` property that
90
- defines which links will be connected together (i.e. the same
91
- broadcast domain). The default bridge mode is defined by the
92
- `--default-bridge-mode` parameter and defaults to "auto". If a bridge
93
- is set to mode "auto" then conlink will check if the kernel has the
94
- `openvswitch` kernel module loaded and if so it will create an Open
95
- vSwitch/OVS bridge/switch for that bridge, otherwise it will create a
96
- regular Linux bridge (e.g. brctl). If any bridges are explicitly
97
- defined with an "ovs" mode and the kernel does not have support then
98
- conlink will stop/error on startup.
99
-
100
- The "patch" mode will connect two links together using tc qdisc
101
- ingress filters. This type connection is equivalent to a patch panel
102
- ("bump-in-the-wire") connection and all traffic will be passed between
103
- the two links unchanged unlike Linux and OVS bridges which typically
104
- block certain bridge control broadcast traffic). The primary downside
105
- of "patch" connections is that they limited to two links whereas "ovs"
106
- and "linux" bridge modes can support many links connected into the
107
- same bridge (broadcast domain).
108
-
109
- ## Network Configuration Syntax
110
-
111
- Network configuration can either be loaded directly from configuration
112
- files using the `--network-config` option or it can be loaded from
113
- `x-network` properties contained in docker-compose files using the
114
- `--compose-file` option. Multiple of each option may be specified and
115
- all the network configuration will be merged into a final network
116
- configuration. Both options also support colon separated lists.
117
-
118
- The network configuration can have four top level keys: `links`,
119
- `bridges`, `tunnels`, and `commands`.
120
-
121
- ### Links
122
-
123
- Each link defintion specifies an interface that will be configured in
124
- a container. Most types have some sort of connection to either the
125
- conlink/network container or the host network namespace. For example,
126
- "veth" type links always have their peer end connected to a bridge in
127
- the conlink/network container and vlan types are children of physical
128
- interfaces in the host.
129
-
130
- The following table describes the link properties:
131
-
132
- | property | link types | format | default | description |
133
- |-----------|------------|----------------|---------|--------------------------|
134
- | type | * | string 1 | veth | link/interface type |
135
- | service | * | string | 2 | compose service |
136
- | container | * | string | | container name |
137
- | bridge | veth | string | | conlink bridge / domain |
138
- | outer-dev | not dummy | string[15] | | conlink/host intf name |
139
- | dev | * | string[15] | eth0 | container intf name |
140
- | ip | * | CIDR | | IP CIDR 7 |
141
- | mac | 3 | MAC | | MAC addr 7 |
142
- | mtu | * | number 4 | 65535 | intf MTU |
143
- | route | * | strings 8 | | ip route add args |
144
- | nat | * | IP | | DNAT/SNAT to IP |
145
- | netem | * | strings 8 | | tc qdisc NetEm options |
146
- | mode | 5 | string | | virt intf mode |
147
- | vlanid | vlan | number | | VLAN ID |
148
- | forward | veth | strings 6 8 | | forward conlink ports 7 |
149
- | ethtool | veth | strings 8 | | ethtool settings |
150
-
151
- - 1 - veth, dummy, vlan, ipvlan, macvlan, ipvtap, macvtap
152
- - 2 - defaults to outer compose service
153
- - 3 - not ipvlan/ipvtap
154
- - 4 - max MTU of parent device for \*vlan, \*vtap types
155
- - 5 - macvlan, macvtap, ipvlan, ipvtap
156
- - 6 - string syntax: `conlink_port:container_port/proto`
157
- - 7 - offset by scale/replica index
158
- - 8 - either a single string or an array of strings
159
-
160
- Each link has a 'type' key that defaults to "veth" and each link
161
- definition must also have either a `service` key or a `container` key.
162
- If the link is defined in the service of a compose file then the value
163
- of `service` will default to the name of that service.
164
-
165
- The `container` key is a fully qualified container name that this link
166
- will apply to. The `service` key is the name of a docker-compose
167
- service that this link applies to. In the case of a `service` link, if
168
- more than one replica is started for that service, then the mac, and
169
- ip values in the link definition will be incremented by the service
170
- index - 1.
171
-
172
- All link definitions support the following optional properties: dev,
173
- ip, mtu, route, nat, netem. If dev is not specified then it will
174
- default to "eth0". For `*vlan` type interfaces, mtu cannot be larger
175
- than the MTU of the parent (outer-dev) device.
176
-
177
- For the `netem` property, refer to the `netem` man page. The `OPTIONS`
178
- grammar defines the valid strings for the `netem` property.
179
-
180
- The `forward` property is an array of strings that defines ports to
181
- forward from the conlink container into the container over this link.
182
- Traffic arriving on the conlink container's docker interface of type
183
- `proto` and destined for port `conlink_port` is forwarded over this
184
- link to the container IP and port `container_port` (`ip` is required).
185
- The initial port (`conlink_port`) is offset by the service
186
- replica/scale number (minus 1). So if the first replica has port 80
187
- forwarded then the second replica will have port 81 forwarded.
188
- For publicly publishing a port, the conlink container needs to be on
189
- a docker network and the `conlink_port` should match the target port
190
- of a docker published port (for the conlink container).
191
-
192
- For the `ethtool` property, refer to the `ethtool` man page. The
193
- syntax for each ethtool setting is basically the ethtool command line
194
- arguments without the "devname. So the equivalent of the ethtool
195
- command `ethtool --offload eth0 rx off` would be link configuration
196
- `{dev: eth0, ethtool: ["--offload rx off"], ...}`.
197
-
198
- ### Bridges
199
-
200
- The bridge settings currently only support the "mode" setting. If
201
- the mode is not specified in this section or the section is omitted
202
- entirely, then bridges specified in the links configuration will
203
- default to the value of the `--default-bridge-mode` parameter (which
204
- itself defaults to "auto").
205
-
206
- The following table describes the bridge properties:
207
-
208
- | property | format | description |
209
- |-----------|---------|--------------------------------|
210
- | bridge | string | conlink bridge / domain name |
211
- | mode | string | auto, ovs, or linux |
212
-
213
- ### Tunnels
214
-
215
- Tunnels links/interfaces will be created and attached to the specified
216
- bridge. Any containers with links to the same bridge will share
217
- a broadcast domain with the tunnel link.
218
-
219
- The following table describes the tunnel properties:
220
-
221
- | property | format | description |
222
- |-----------|---------|----------------------------|
223
- | type | string | geneve or vxlan |
224
- | bridge | string | conlink bridge / domain |
225
- | remote | IP | remote host addr |
226
- | vni | number | Virtual Network Identifier |
227
- | netem | string | tc qdisc NetEm options |
228
-
229
- Each tunnel definition must have the keys: type, bridge, remote, and
230
- vni. The netem optional property also applies to tunnel interfaces.
231
-
232
- ### Commands
233
-
234
- Commands will be executed in parallel within the matching container
235
- once all links are succesfully configured for that container.
236
-
237
- The following table describes the command properties:
238
-
239
- | property | format | description |
240
- |-----------|------------------|----------------------------|
241
- | service | string | compose service |
242
- | container | string | container name |
243
- | command | array or string | command or shell string |
244
-
245
- Each command defintion must have a `command` key and either
246
- a `service` or `container` key. The `service` and `container` keys are
247
- defined the same as for link properties.
248
-
249
- If the `command` value is an array then the command and arguments will
250
- be executed directly. If the `command` is a string then the string
251
- will be wrapped in `sh -c STRING` for execution.
252
-
253
-
254
- ## Examples
255
-
256
- The examples below require a conlink docker image. Build the image for
257
- both docker and podman like this:
258
-
259
- ```
260
- docker build -t conlink .
261
- podman build -t conlink .
262
- ```
263
-
264
- ### test1: compose file with embedded network config
265
-
266
- Start the test1 compose configuration:
267
-
268
- ```
269
- docker-compose -f examples/test1-compose.yaml up --build --force-recreate
270
- ```
271
-
272
- From h1 ping the address of h3 (routed via the r0 container):
273
-
274
- ```
275
- docker-compose -f examples/test1-compose.yaml exec h1 ping 10.0.0.100
276
- ```
277
-
278
-
279
- ### test2: compose file with separate network config and live scaling
280
-
281
- Start the test2 compose configuration:
282
-
283
- ```
284
- docker-compose -f examples/test2-compose.yaml up -d --build --force-recreate
285
- ```
286
-
287
- From the first node ping the second:
288
-
289
- ```
290
- docker-compose -f examples/test2-compose.yaml exec --index 1 node ping 10.0.1.2
291
- ```
292
-
293
- From the second node ping an address in the internet service:
294
-
295
- ```
296
- docker-compose -f examples/test2-compose.yaml exec --index 2 node ping 8.8.8.8
297
- ```
298
-
299
- Scale the nodes from 2 to 5 and then ping the fifth node from the second:
300
-
301
- ```
302
- docker-compose -f examples/test2-compose.yaml up -d --scale node=5
303
- docker-compose -f examples/test2-compose.yaml exec --index 2 node ping 10.0.1.5
304
- ```
305
-
306
-
307
- ### test3: network config file only (no compose) and variable templating
308
-
309
- #### test3 with docker
310
-
311
- Start two containers named `ZZZ_node_1` and `ZZZ_node_2`.
312
-
313
- ```
314
- docker run --name=ZZZ_node_1 --rm -d --network none alpine sleep 864000
315
- docker run --name=ZZZ_node_2 --rm -d --network none alpine sleep 864000
316
- ```
317
-
318
- Start the conlink container `ZZZ_network` that will setup a network
319
- configuration that is connected to the other containers:
320
-
321
- ```
322
- ./conlink-start.sh -v --mode docker --host-mode docker --network-file examples/test3-network.yaml -- --name ZZZ_network --rm -e NODE_NAME_1=ZZZ_node_1 -e NODE_NAME_2=ZZZ_node_2
323
- ```
324
-
325
- In a separate terminal, ping the node 2 from node 1.
326
-
327
- ```
328
- docker exec -it ZZZ_node_1 ping 10.0.1.2
329
- ```
330
-
331
- #### test3 with rootless podman
332
-
333
- Same as test3 but using rootless podman instead
334
-
335
- Start two containers named `ZZZ_node_1` and `ZZZ_node_2`.
336
-
337
- ```
338
- podman run --name=ZZZ_node_1 --rm -d --network none alpine sleep 864000
339
- podman run --name=ZZZ_node_2 --rm -d --network none alpine sleep 864000
340
- ```
341
-
342
- Start the conlink container `ZZZ_network` that will setup a network
343
- configuration that is connected to the other containers:
344
-
345
- ```
346
- ./conlink-start.sh -v --mode podman --host-mode podman --network-file examples/test3-network.yaml -- --name ZZZ_network --rm -e NODE_NAME_1=ZZZ_node_1 -e NODE_NAME_2=ZZZ_node_2
347
- ```
348
-
349
- In a separate terminal, ping the node 2 from node 1.
350
-
351
- ```
352
- podman exec -it ZZZ_node_1 ping 10.0.1.2
353
- ```
354
-
355
- ### test4: multiple compose files and container commands
356
-
357
- Docker-compose has the ability to specify multiple compose files that
358
- are merged together into a single runtime configuration. This test
359
- has conlink configuration spread across multiple compose files and
360
- a separate network config file. The network configuration appears at the
361
- top-level of the compose files and also within multiple compose
362
- service definitions.
363
-
364
- Run docker-compose using two compose files. The first defines the
365
- conlink/network container and a basic network configuration that
366
- includes a router and switch (`s0`). The second defines a single
367
- container (`node1`) and switch (`s1`) that is connected to the router
368
- defined in the first compose file.
369
-
370
- ```
371
- MODES_DIR=./examples/test4-multiple/modes ./mdc node1 up --build --force-recreate
372
- ```
373
-
374
- Ping the router host from `node1`:
375
-
376
- ```
377
- docker-compose exec node1 ping 10.0.0.100
378
- ```
379
-
380
- Restart the compose instance and add another compose file that defines
381
- two node2 replicas and a switch (`s2`) that is connected to the
382
- router.
383
-
384
- ```
385
- MODES_DIR=./examples/test4-multiple/modes ./mdc node1,nodes2 up --build --force-recreate
386
- ```
387
-
388
- From both `node2` replicas, ping `node1` across the switches and `r0` router:
389
-
390
- ```
391
- docker-compose exec --index 1 node2 ping 10.1.0.1
392
- docker-compose exec --index 2 node2 ping 10.1.0.1
393
- ```
394
-
395
- From `node1`, ping both `node2` replicas across the switches and `r0` router:
396
-
397
- ```
398
- docker-compose exec node1 ping 10.2.0.1
399
- docker-compose exec node1 ping 10.2.0.2
400
- ```
401
-
402
-
403
- Restart the compose instance and add another compose file that starts
404
- conlink using an addition network file `web-network.yaml`. The network
405
- file starts up a simple web server on the router.
406
-
407
- ```
408
- MODES_DIR=./examples/test4-multiple/modes ./mdc node1,nodes2,web up --build --force-recreate
409
- ```
410
-
411
- From the second `node2`, perform a download from the web server running on the
412
- router host:
413
-
414
- ```
415
- docker-compose exec --index 2 node2 wget -O- 10.0.0.100
416
- ```
417
-
418
- We can simplify the above launch by using the `all` mode, which contains
419
- depends on `node1`, `nodes2`, and `web`. Each of those modes depends on
420
- `base`, so there's no need to specify that again (transitive deps).
421
-
422
- ```
423
- MODES_DIR=./examples/test4-multiple/modes ./mdc all up --build --force-recreate
424
- ```
425
-
426
- Remove the `.env` file as a final cleanup step:
427
-
428
- ```
429
- rm .env
430
- ```
431
-
432
-
433
- ### test5: conlink on two hosts with overlay connectivity via geneve
434
-
435
- Launch a compose instance on host 1 and point it at host 2:
436
-
437
- ```
438
- echo "REMOTE=ADDRESS_OF_HOST_2" > .env
439
- echo "NODE_IP=192.168.100.1" > .env \
440
- docker-compose --env-file .env -f examples/test5-geneve-compose.yaml up
441
- ```
442
-
443
- Launch another compose instance on host 2 and point it at host 1:
444
- On host 2 run conlink like this:
445
-
446
- ```
447
- echo "REMOTE=ADDRESS_OF_HOST_1" > .env
448
- echo "NODE_IP=192.168.100.2" >> .env \
449
- docker-compose --env-file .env -f examples/test5-geneve-compose.yaml up
450
- ```
451
-
452
- On host 1, start a tcpdump on the main interface capturing Geneve
453
- (encapsulated) traffic:
454
-
455
- ```
456
- sudo tcpdump -nli eth0 port 6081
457
- ```
458
-
459
- On host 2, start a ping within the "node1" network namespace created
460
- by conlink:
461
-
462
- ```
463
- docker-compose -f examples/test5-geneve-compose.yaml exec node ping 192.168.100.1
464
- ```
465
-
466
- On host 1 you should see bi-directional encapsulated ping traffic on the host.
467
-
468
-
469
- ### test6: conlink on two hosts deployed with CloudFormation
470
-
471
- This test uses AWS CloudFormation to deploy two AWS EC2 instances that
472
- automatically install, configure, and start conlink (and dependencies)
473
- using the `test5-geneve-compose.yaml` compose file.
474
-
475
- Authenticate with AWS and set the `MY_KEY`, `MY_VPC`, and `MY_SUBNET`
476
- variables to refer to a preexisting key pair name, VPC ID, and Subnet
477
- ID respectively. Then use the AWS CLI to deploy the stack:
478
-
479
- ```
480
- export MY_KEY=... MY_VPC=... MY_SUBNET=...
481
- aws --region us-west-2 cloudformation deploy --stack-name ${USER}-conlink-test6 --template-file examples/test6-cfn.yaml --parameter-overrides KeyPairName=${MY_KEY} VpcId=${MY_VPC} SubnetId=${MY_SUBNET}
482
- ```
483
-
484
- The stack will take about 8 minutes to finish deploying. You can
485
- reduce the time to under a minute if you create your own AMI with the
486
- pre-signal steps in `BaseUserData` baked in and modify the template to
487
- use that instead.
488
-
489
- Once the stack is finish deploying, show the outputs of the stack
490
- (including instance IP addresses) like this:
491
-
492
- ```
493
- aws --region us-west-2 cloudformation describe-stacks --stack-name ${USER}-conlink-test6 | jq '.Stacks[0].Outputs'
494
- ```
495
-
496
- Use ssh to connect to instance 1 and 2 (as the "ubuntu" user), then
497
- sudo to root and cd into `/root/conlink`. You can now run the tcpdump
498
- and ping test described for test5.
499
-
500
-
501
- ### test7: MAC, MTU, and NetEm settings
502
-
503
- This example demonstrates using interface MAC, MTU, and NetEm (tc
504
- qdisc) settings.
505
-
506
- Start the test7 compose configuration:
507
-
508
- ```
509
- docker-compose -f examples/test7-compose.yaml up --build --force-recreate
510
- ```
511
-
512
- Show the links in both node containers to see that on the eth0
513
- interfaces the MAC addresses are `00:0a:0b:0c:0d:0*` and the MTUs are
514
- set to `4111`. The eth1 interfaces should have the command line set
515
- default MTU of `5111`.
516
-
517
- ```
518
- docker-compose -f examples/test7-compose.yaml exec --index 1 node ip link
519
- docker-compose -f examples/test7-compose.yaml exec --index 2 node ip link
520
- ```
521
-
522
- Ping the second node from the first to show the the NetEm setting is
523
- adding 40ms delay in both directions (80ms roundtrip).
524
-
525
- ```
526
- docker-compose -f examples/test7-compose.yaml exec --index 1 node ping 10.0.1.2
527
- ```
528
-
529
- ### test8: Connections to macvlan/vlan host interfaces
530
-
531
- This example has two nodes with web servers bound to local addresses.
532
- The first node is connected to a macvlan sub-interfaces of a host
533
- physical interface. The second node is connected to a VLAN
534
- sub-interface of the same host (using VLAN ID/tag 5). Static NAT
535
- (SNAT+DNAT) is setup inside each container to map the external
536
- address/interface to the internal address/interface (dummy) where the
537
- web server is running.
538
-
539
- Create an environment file with the name of the parent host interface
540
- and the external IP addresses to assign to each container:
541
-
542
- ```
543
- cat << EOF > .env
544
- HOST_INTERFACE=enp6s0
545
- NODE1_HOST_ADDRESS=192.168.0.32/24
546
- NODE2_HOST_ADDRESS=192.168.0.33/24
547
- EOF
548
- ```
549
-
550
- Start the test8 compose configuration using the environment file:
551
-
552
- ```
553
- docker-compose --env-file .env -f examples/test8-compose.yaml up --build --force-recreate
554
- ```
555
-
556
- Connect to the macvlan node (NODE1_HOST_ADDRESS) from an external host
557
- on your network (traffic to macvlan interfaces on the same host is
558
- prevented):
559
-
560
- ```
561
- ping -c1 192.168.0.32
562
- curl 192.168.0.32
563
- ```
564
-
565
- Note: to connect to the vlan node (NODE2_HOST_ADDRESS) you will need
566
- to configure your physical switch/router with routing/connectivity to
567
- VLAN 5 on the same physical link to your host.
568
-
569
- ### test9: bridge modes
570
-
571
- This example demonstrates the supported bridge modes.
572
-
573
- Start the test9 compose configuration using different bridge modes and
574
- validate connectivity using ping:
575
-
576
- ```
577
- export BRIDGE_MODE="linux" # "ovs", "patch", "auto"
578
- docker-compose -f examples/test9-compose.yaml up --build --force-recreate
579
- docker-compose -f examples/test9-compose.yaml exec node1 ping 10.0.1.2
580
- ```
581
-
582
- ### test10: port forwarding and routing
583
-
584
- This example demonstrates port forwarding from the conlink container
585
- to two containers running simple web servers. It also demonstrates the
586
- use of a router container and multiple route rules in the other
587
- containers.
588
-
589
- Start the test10 compose configuration:
590
-
591
- ```
592
- docker-compose -f examples/test10-compose.yaml up --build --force-recreate
593
- ```
594
-
595
- Ports 3080 and 8080 are both published on the host by the conlink
596
- container using standard Docker port mapping. The internal mapping of
597
- those ports (1080 and 1180 respectively) are both are forwarded to
598
- port 80 in the node1 container using conlink's port forwarding
599
- mechanism. The two paths look like this:
600
-
601
- ```
602
- host:3080 --> 1080 (in conlink) --> node1:80
603
- host:8080 --> 1180 (in conlink) --> node1:80
604
- ```
605
-
606
- Use curl on the host to query both of these paths to node1:
607
-
608
- ```
609
- curl 0.0.0.0:3080
610
- curl 0.0.0.0:8080
611
- ```
612
-
613
- Ports 80 and 81 are published on the host by the conlink container
614
- using standard Docker port mapping. Then conlink forwards from ports
615
- 80 and 81 to the first and second replica (respectively) of node2,
616
- each of which listen internally on port 80. The two paths look like
617
- this:
618
-
619
- ```
620
- host:80 -> 80 (in conlink) -> node2_1:80
621
- host:81 -> 81 (in conlink) -> node2_2:80
622
- ```
623
-
624
- Use curl on the host to query both replicas of node2:
625
-
626
- ```
627
- curl 0.0.0.0:80
628
- curl 0.0.0.0:81
629
- ```
630
-
631
- Start a two tcpdump processes in the conlink container to watch
632
- routed ICMP traffic and then ping between containers across the router
633
- container:
634
-
635
- ```
636
- docker compose -f examples/test10-compose.yaml exec network tcpdump -nli router_1-es1 icmp
637
- docker compose -f examples/test10-compose.yaml exec network tcpdump -nli router_1-es2 icmp
638
- ```
639
-
640
- ```
641
- docker-compose -f examples/test10-compose.yaml exec node1 ping 10.2.0.1
642
- docker-compose -f examples/test10-compose.yaml exec node1 ping 10.2.0.2
643
- docker-compose -f examples/test10-compose.yaml exec node2 ping 10.1.0.1
644
-
645
- ```
646
-
647
- ## Compose scripts: mdc, wait.sh, and copy.sh
648
-
649
- ### mdc
650
-
651
- The `mdc` command adds flexibility and power to the builtin overlay
652
- capability of docker compose. Docker compose can specify multiple
653
- compose files that will be combined into a single configuration.
654
- Compose files that are specified later will overlay or override
655
- earlier compose files. For example, if compose files A and B are
656
- loaded by docker compose, then the `image` property of a service in
657
- file B will take precedence (or override) the `image` property for the
658
- same service in file A. Some properties such as `volumes` and
659
- `environment` will have the sub-properties merged or appended to.
660
-
661
- There are several ways that `mdc` adds to the composition capabilities
662
- of docker compose:
663
- 1. **Mode/module dependency resolution**. The modes or modules that
664
- are combined by `mdc` are defined as directories that contain
665
- mode/module specific content. A `deps` file in a mode/module
666
- directory is used to specify dependencies on other modes/modules.
667
- The syntax and resolution algorithm is defined by the
668
- [resolve-deps](https://github.com/Viasat/resolve-deps) project.
669
- 2. **Environment variable file combining/overlaying**. Each `.env`
670
- file that appears in a mode/module directory will be appended into
671
- a single `.env` file at the top-level where the `mdc` command is
672
- invoked. Later environment variables will override earlier ones
673
- with the same name. Variable interpolation and some shell-style
674
- variable expansion can be used to combine/append environment
675
- variables. For example if FOO and BAR are defined in an earlier
676
- mode/module, then BAZ could be defined like this:
677
- `BAZ="${FOO:-${BAR}-SUFF"` which will set BAZ to FOO if FOO is set,
678
- otherwise, it will set BAZ to BAR with a "-SUFF" suffix.
679
- 3. **Directory hierarchy combining/overlaying**. If the mode/module
680
- directory has subdirectories that themselves contain a "files/"
681
- sub-directory, then the mode subdirectories will be recursively
682
- copied into the top-level ".files/" directory. For example,
683
- consider if the following files exists under the modes "foo" and
684
- "bar" (with a dependency of "bar" on "foo"):
685
- `foo/svc1/files/etc/conf1`, `foo/svc2/files/etc/conf2`, and
686
- `bar/svc1/files/etc/conf1`. When `mdc` is run this will result in
687
- the following two files: `.files/svc1/etc/conf1` and
688
- `.files/svc2/etc/conf2`. The content of `conf1` will come from the
689
- "bar" mode because it is resolved second. The use of the `copy.sh`
690
- script (described below) simplifies recursive file copying and also
691
- provides variable templating of copied files.
692
- 4. **Set environment variables based on the selected modes/modules**.
693
- When `mdc` is run it will set the following special environment
694
- variables in the top-level `.env` file:
695
- * `COMPOSE_FILE`: A colon separated and dependency ordered list of
696
- compose file paths from each resolved mode/module directory.
697
- * `COMPOSE_DIR`: The directory where the top-level `.env` is
698
- created.
699
- * `COMPOSE_PRPOFILES`: A comma separated list of each resolved
700
- mode/module with a `MODE_` prefix on the name. These are docker
701
- compose profiles that can be used to enable services in one
702
- mode/module compose file when a different mode/module is
703
- selected/resolved by `mdc`. For example, if a compose file in
704
- "bar" has a service that should only be enabled when the "foo"
705
- mode/module is also requested/resolved, then the service can be
706
- tagged with the `MODE_foo` profile.
707
- * `MDC_MODE_DIRS`: A comma separated list of mode/module
708
- directories. This can be used by other external tools that have
709
- specific mode/module behavior.
710
-
711
- Conlink network configuration can be specified in `x-network`
712
- properties within compose files. This can be a problem with the
713
- builtin overlay functionality of docker compose because `x-` prefixed
714
- properties are simply overriden as a whole without any special merging
715
- behavior. To work around this limitation, conlink has the ability to
716
- directly merge `x-network` configuration from multiple compose files
717
- by passing the `COMPOSE_FILE` variable to the conlink `--compose-file`
718
- parameter (which supports a colon sperated list of compose files).
719
-
720
- ### wait.sh
721
-
722
- The dynamic event driven nature of conlink mean that interfaces may
723
- appear after the container service code starts running (unlike plain
724
- docker container networking). For this reason, the `wait.sh` script is
725
- provided to simplify waiting for interfaces to appear (and other
726
- network conditions). Here is a compose file snippit that will wait for
727
- `eth0` to appear and for `eni1` to both appear and have an IP address
728
- assigned before running the startup command (after the `--`):
729
-
730
- ```
731
- services:
732
- svc1:
733
- volumes:
734
- - ./conlink/scripts:/scripts:ro
735
- command: /scripts/wait.sh -i eth0 -I eni1 -- /start-cmd.sh arg1 arg2
736
- ```
737
-
738
- In addition to waiting for interfaces and address assignment,
739
- `wait.sh` can also wait for a file to appear (`-f FILE`), a remote TCP
740
- port to become accessible (`-t HOST:PORT`), or run a command until it
741
- completes successfully (`-c COMMAND`).
742
-
743
-
744
- ### copy.sh
745
-
746
- One of the features of the `mdc` command is to collect directory
747
- hierarchies from mode/module directories into a single `.files/`
748
- directory at the top-level. The intended use of the merged directory
749
- hierarchy is to be merged into file-systems of running containers.
750
- However, simple volume mounts will replace entire directory
751
- hierarchies (and hide all prior files under the mount point). The
752
- `copy.sh` script is provided for easily merging/overlaying one
753
- directory hierarchy onto another one. In addition, the `-T` option
754
- will also replace special `{{VAR}}` tokens in the files being copied
755
- with the value of the matching environment variable.
756
-
757
- Here is a compose file snippit that shows the use of `copy.sh` to
758
- recursively copy/overlay the directory tree in `./.files/svc2` onto
759
- the container root file-system. In addition, due to the use of the
760
- `-T` option, the script will replace any occurence of the string
761
- `{{FOO}}` with the value of the `FOO` environment variable within any
762
- of the files that are copied:
763
-
764
- ```
765
- services:
766
- svc2:
767
- environment:
768
- - FOO=123
769
- volumes:
770
- - ./.files/svc2:/files:ro
771
- command: /scripts/copy.sh -T /files / -- /start-cmd.sh arg1 arg2
772
- ```
773
-
774
- Note that instances of `copy.sh` and `wait.sh` can be easily chained
775
- together like this:
776
- ```
777
- /scripts/copy.sh -T /files / -- /scripts/wait.sh -i eth0 -- cmd args
778
- ```
779
-
780
- ## GraphViz network configuration rendering
781
-
782
- You can use d3 and GraphViz to create a visual graph rendering of
783
- a network configuration. First start a simple web server in the
784
- examples directory:
785
-
786
- ```
787
- cd examples
788
- python3 -m http.server 8080
789
- ```
790
-
791
- Use the `net2dot` script to transform a network
792
- configuration into a GraphViz data file (dot language). To render the
793
- network configuration for example test1, run the following in another
794
- window:
795
-
796
- ```
797
- ./conlink --show-config --compose-file examples/test1-compose.yaml | ./net2dot > examples/test1.dot
798
- ```
799
-
800
- Then load `http://localhost:8080?data=test1.dot` in your browser to see the rendered
801
- image.
802
-
803
- The file `examples/net2dot.yaml` contains a configuration that
804
- combines many different configuration elements (veth links, dummy
805
- interfaces, vlan type links, tunnels, etc).
806
-
807
- ```
808
- ./conlink --network-file examples/net2dot.yaml --show-config | ./net2dot > examples/net2dot.dot
809
- ```
810
-
811
- Then load `http://localhost:8080?data=net2dot.dot` in your browser.
812
-
813
-
814
105
  ## Copyright & License
815
106
 
816
107
  This software is copyright Viasat and subject to the terms of the
817
108
  Mozilla Public License version 2.0 (MPL.20). A copy of the license is
818
109
  located in the LICENSE file at the top of the repository or available
819
110
  at https://mozilla.org/MPL/2.0/.
820
-