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/.github/workflows/push.yml +9 -1
- package/README.md +50 -760
- package/docs/.nojekyll +0 -0
- package/docs/_sidebar.md +9 -0
- package/docs/guides/compose-scripts.md +143 -0
- package/docs/guides/examples.md +395 -0
- package/docs/guides/graphviz-rendering.md +32 -0
- package/docs/index.html +33 -0
- package/docs/reference/network-configuration-syntax.md +143 -0
- package/docs/usage-notes.md +50 -0
- package/mdc +5 -2
- package/net2dot.cljs +4 -3
- package/package.json +6 -2
- package/src/conlink/core.cljs +7 -13
package/README.md
CHANGED
|
@@ -1,16 +1,59 @@
|
|
|
1
|
-
# conlink
|
|
1
|
+
# conlink
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/conlink)
|
|
4
|
+
[](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](
|
|
51
|
+
[Compose scripts](https://lonocloud.github.io/conlink/#/guides/compose-scripts) for
|
|
9
52
|
details):
|
|
10
53
|
|
|
11
|
-
* [mdc](
|
|
12
|
-
* [wait.sh](
|
|
13
|
-
* [copy.sh](
|
|
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
|
-
|