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/docs/.nojekyll
ADDED
|
File without changes
|
package/docs/_sidebar.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
- **Home**
|
|
2
|
+
- [Quickstart](/)
|
|
3
|
+
- [Usage Notes](/usage-notes.md)
|
|
4
|
+
- **Reference**
|
|
5
|
+
- [Network Configuration Syntax](/reference/network-configuration-syntax.md)
|
|
6
|
+
- **Guides**
|
|
7
|
+
- [Compose Scripts](/guides/compose-scripts.md)
|
|
8
|
+
- [Graphviz Rendering](/guides/graphviz-rendering.md)
|
|
9
|
+
- [Examples](/guides/examples.md)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Compose scripts
|
|
2
|
+
|
|
3
|
+
Conlink also includes scripts that make docker compose a much more
|
|
4
|
+
powerful development and testing environment:
|
|
5
|
+
|
|
6
|
+
* `mdc` - modular management of multiple compose configurations
|
|
7
|
+
* `wait.sh` - wait for network and file conditions before continuing
|
|
8
|
+
* `copy.sh` - recursively copy files with variable templating
|
|
9
|
+
|
|
10
|
+
## mdc
|
|
11
|
+
|
|
12
|
+
The `mdc` command adds flexibility and power to the builtin overlay
|
|
13
|
+
capability of docker compose. Docker compose can specify multiple
|
|
14
|
+
compose files that will be combined into a single configuration.
|
|
15
|
+
Compose files that are specified later will overlay or override
|
|
16
|
+
earlier compose files. For example, if compose files A and B are
|
|
17
|
+
loaded by docker compose, then the `image` property of a service in
|
|
18
|
+
file B will take precedence (or override) the `image` property for the
|
|
19
|
+
same service in file A. Some properties such as `volumes` and
|
|
20
|
+
`environment` will have the sub-properties merged or appended to.
|
|
21
|
+
|
|
22
|
+
There are several ways that `mdc` adds to the composition capabilities
|
|
23
|
+
of docker compose:
|
|
24
|
+
1. **Mode/module dependency resolution**. The modes or modules that
|
|
25
|
+
are combined by `mdc` are defined as directories that contain
|
|
26
|
+
mode/module specific content. A `deps` file in a mode/module
|
|
27
|
+
directory is used to specify dependencies on other modes/modules.
|
|
28
|
+
The syntax and resolution algorithm is defined by the
|
|
29
|
+
[resolve-deps](https://github.com/Viasat/resolve-deps) project.
|
|
30
|
+
2. **Environment variable file combining/overlaying**. Each `.env`
|
|
31
|
+
file that appears in a mode/module directory will be appended into
|
|
32
|
+
a single `.env` file at the top-level where the `mdc` command is
|
|
33
|
+
invoked. Later environment variables will override earlier ones
|
|
34
|
+
with the same name. Variable interpolation and some shell-style
|
|
35
|
+
variable expansion can be used to combine/append environment
|
|
36
|
+
variables. For example if FOO and BAR are defined in an earlier
|
|
37
|
+
mode/module, then BAZ could be defined like this:
|
|
38
|
+
`BAZ="${FOO:-${BAR}-SUFF"` which will set BAZ to FOO if FOO is set,
|
|
39
|
+
otherwise, it will set BAZ to BAR with a "-SUFF" suffix.
|
|
40
|
+
3. **Directory hierarchy combining/overlaying**. If the mode/module
|
|
41
|
+
directory has subdirectories that themselves contain a "files/"
|
|
42
|
+
sub-directory, then the mode subdirectories will be recursively
|
|
43
|
+
copied into the top-level ".files/" directory. For example,
|
|
44
|
+
consider if the following files exists under the modes "foo" and
|
|
45
|
+
"bar" (with a dependency of "bar" on "foo"):
|
|
46
|
+
`foo/svc1/files/etc/conf1`, `foo/svc2/files/etc/conf2`, and
|
|
47
|
+
`bar/svc1/files/etc/conf1`. When `mdc` is run this will result in
|
|
48
|
+
the following two files: `.files/svc1/etc/conf1` and
|
|
49
|
+
`.files/svc2/etc/conf2`. The content of `conf1` will come from the
|
|
50
|
+
"bar" mode because it is resolved second. The use of the `copy.sh`
|
|
51
|
+
script (described below) simplifies recursive file copying and also
|
|
52
|
+
provides variable templating of copied files.
|
|
53
|
+
4. **Set environment variables based on the selected modes/modules**.
|
|
54
|
+
When `mdc` is run it will set the following special environment
|
|
55
|
+
variables in the top-level `.env` file:
|
|
56
|
+
* `COMPOSE_FILE`: A colon separated and dependency ordered list of
|
|
57
|
+
compose file paths from each resolved mode/module directory.
|
|
58
|
+
* `COMPOSE_DIR`: The directory where the top-level `.env` is
|
|
59
|
+
created.
|
|
60
|
+
* `COMPOSE_PROFILES`: A comma separated list of each resolved
|
|
61
|
+
mode/module with a `MODE_` prefix on the name. These are docker
|
|
62
|
+
compose profiles that can be used to enable services in one
|
|
63
|
+
mode/module compose file when a different mode/module is
|
|
64
|
+
selected/resolved by `mdc`. For example, if a compose file in
|
|
65
|
+
"bar" has a service that should only be enabled when the "foo"
|
|
66
|
+
mode/module is also requested/resolved, then the service can be
|
|
67
|
+
tagged with the `MODE_foo` profile.
|
|
68
|
+
* `MDC_MODE_[mode]`: Each active mode will have an environment
|
|
69
|
+
variable set to 'enabled'. Important Note: the mode name will
|
|
70
|
+
have all non-alphanumeric characters changed to an underscore so
|
|
71
|
+
that it is usable as the environment variable suffix.
|
|
72
|
+
* `MDC_MODE_DIRS`: A comma separated list of mode/module
|
|
73
|
+
directories. This can be used by other external tools that have
|
|
74
|
+
specific mode/module behavior.
|
|
75
|
+
|
|
76
|
+
Conlink network configuration can be specified in `x-network`
|
|
77
|
+
properties within compose files. This can be a problem with the
|
|
78
|
+
builtin overlay functionality of docker compose because `x-` prefixed
|
|
79
|
+
properties are simply overriden as a whole without any special merging
|
|
80
|
+
behavior. To work around this limitation, conlink has the ability to
|
|
81
|
+
directly merge `x-network` configuration from multiple compose files
|
|
82
|
+
by passing the `COMPOSE_FILE` variable to the conlink `--compose-file`
|
|
83
|
+
parameter (which supports a colon sperated list of compose files).
|
|
84
|
+
|
|
85
|
+
## wait.sh
|
|
86
|
+
|
|
87
|
+
The dynamic event driven nature of conlink mean that interfaces may
|
|
88
|
+
appear after the container service code starts running (unlike plain
|
|
89
|
+
docker container networking). For this reason, the `wait.sh` script is
|
|
90
|
+
provided to simplify waiting for interfaces to appear (and other
|
|
91
|
+
network conditions). Here is a compose file snippit that will wait for
|
|
92
|
+
`eth0` to appear and for `eni1` to both appear and have an IP address
|
|
93
|
+
assigned before running the startup command (after the `--`):
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
services:
|
|
97
|
+
svc1:
|
|
98
|
+
volumes:
|
|
99
|
+
- ./conlink/scripts:/scripts:ro
|
|
100
|
+
command: /scripts/wait.sh -i eth0 -I eni1 -- /start-cmd.sh arg1 arg2
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
In addition to waiting for interfaces and address assignment,
|
|
104
|
+
`wait.sh` can also wait for a file to appear (`-f FILE`), a remote TCP
|
|
105
|
+
port to become accessible (`-t HOST:PORT`), or run a command until it
|
|
106
|
+
completes successfully (`-c COMMAND`).
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
## copy.sh
|
|
110
|
+
|
|
111
|
+
One of the features of the `mdc` command is to collect directory
|
|
112
|
+
hierarchies from mode/module directories into a single `.files/`
|
|
113
|
+
directory at the top-level. The intended use of the merged directory
|
|
114
|
+
hierarchy is to be merged into file-systems of running containers.
|
|
115
|
+
However, simple volume mounts will replace entire directory
|
|
116
|
+
hierarchies (and hide all prior files under the mount point). The
|
|
117
|
+
`copy.sh` script is provided for easily merging/overlaying one
|
|
118
|
+
directory hierarchy onto another one. In addition, the `-T` option
|
|
119
|
+
will also replace special `{{VAR}}` tokens in the files being copied
|
|
120
|
+
with the value of the matching environment variable.
|
|
121
|
+
|
|
122
|
+
Here is a compose file snippit that shows the use of `copy.sh` to
|
|
123
|
+
recursively copy/overlay the directory tree in `./.files/svc2` onto
|
|
124
|
+
the container root file-system. In addition, due to the use of the
|
|
125
|
+
`-T` option, the script will replace any occurence of the string
|
|
126
|
+
`{{FOO}}` with the value of the `FOO` environment variable within any
|
|
127
|
+
of the files that are copied:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
services:
|
|
131
|
+
svc2:
|
|
132
|
+
environment:
|
|
133
|
+
- FOO=123
|
|
134
|
+
volumes:
|
|
135
|
+
- ./.files/svc2:/files:ro
|
|
136
|
+
command: /scripts/copy.sh -T /files / -- /start-cmd.sh arg1 arg2
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Note that instances of `copy.sh` and `wait.sh` can be easily chained
|
|
140
|
+
together like this:
|
|
141
|
+
```
|
|
142
|
+
/scripts/copy.sh -T /files / -- /scripts/wait.sh -i eth0 -- cmd args
|
|
143
|
+
```
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
The [examples](https://github.com/LonoCloud/conlink/tree/master/examples)
|
|
4
|
+
directory contains the necessary files to follow along below.
|
|
5
|
+
|
|
6
|
+
The examples also require a conlink docker image. Build the image for both
|
|
7
|
+
docker and podman like this:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
docker build -t conlink .
|
|
11
|
+
podman build -t conlink .
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## test1: compose file with embedded network config
|
|
15
|
+
|
|
16
|
+
Start the test1 compose configuration:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
docker-compose -f examples/test1-compose.yaml up --build --force-recreate
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
From h1 ping the address of h3 (routed via the r0 container):
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
docker-compose -f examples/test1-compose.yaml exec h1 ping 10.0.0.100
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## test2: compose file with separate network config and live scaling
|
|
30
|
+
|
|
31
|
+
Start the test2 compose configuration:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
docker-compose -f examples/test2-compose.yaml up -d --build --force-recreate
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
From the first node ping the second:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
docker-compose -f examples/test2-compose.yaml exec --index 1 node ping 10.0.1.2
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
From the second node ping an address in the internet service:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
docker-compose -f examples/test2-compose.yaml exec --index 2 node ping 8.8.8.8
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Scale the nodes from 2 to 5 and then ping the fifth node from the second:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
docker-compose -f examples/test2-compose.yaml up -d --scale node=5
|
|
53
|
+
docker-compose -f examples/test2-compose.yaml exec --index 2 node ping 10.0.1.5
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
## test3: network config file only (no compose) and variable templating
|
|
58
|
+
|
|
59
|
+
### test3 with docker
|
|
60
|
+
|
|
61
|
+
Start two containers named `ZZZ_node_1` and `ZZZ_node_2`.
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
docker run --name=ZZZ_node_1 --rm -d --network none alpine sleep 864000
|
|
65
|
+
docker run --name=ZZZ_node_2 --rm -d --network none alpine sleep 864000
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Start the conlink container `ZZZ_network` that will setup a network
|
|
69
|
+
configuration that is connected to the other containers:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
./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
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
In a separate terminal, ping the node 2 from node 1.
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
docker exec -it ZZZ_node_1 ping 10.0.1.2
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### test3 with rootless podman
|
|
82
|
+
|
|
83
|
+
Same as test3 but using rootless podman instead
|
|
84
|
+
|
|
85
|
+
Start two containers named `ZZZ_node_1` and `ZZZ_node_2`.
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
podman run --name=ZZZ_node_1 --rm -d --network none alpine sleep 864000
|
|
89
|
+
podman run --name=ZZZ_node_2 --rm -d --network none alpine sleep 864000
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Start the conlink container `ZZZ_network` that will setup a network
|
|
93
|
+
configuration that is connected to the other containers:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
./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
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
In a separate terminal, ping the node 2 from node 1.
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
podman exec -it ZZZ_node_1 ping 10.0.1.2
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## test4: multiple compose files and container commands
|
|
106
|
+
|
|
107
|
+
Docker-compose has the ability to specify multiple compose files that
|
|
108
|
+
are merged together into a single runtime configuration. This test
|
|
109
|
+
has conlink configuration spread across multiple compose files and
|
|
110
|
+
a separate network config file. The network configuration appears at the
|
|
111
|
+
top-level of the compose files and also within multiple compose
|
|
112
|
+
service definitions.
|
|
113
|
+
|
|
114
|
+
Run docker-compose using two compose files. The first defines the
|
|
115
|
+
conlink/network container and a basic network configuration that
|
|
116
|
+
includes a router and switch (`s0`). The second defines a single
|
|
117
|
+
container (`node1`) and switch (`s1`) that is connected to the router
|
|
118
|
+
defined in the first compose file.
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
MODES_DIR=./examples/test4-multiple/modes ./mdc node1 up --build --force-recreate
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Ping the router host from `node1`:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
docker-compose exec node1 ping 10.0.0.100
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Restart the compose instance and add another compose file that defines
|
|
131
|
+
two node2 replicas and a switch (`s2`) that is connected to the
|
|
132
|
+
router.
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
MODES_DIR=./examples/test4-multiple/modes ./mdc node1,nodes2 up --build --force-recreate
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
From both `node2` replicas, ping `node1` across the switches and `r0` router:
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
docker-compose exec --index 1 node2 ping 10.1.0.1
|
|
142
|
+
docker-compose exec --index 2 node2 ping 10.1.0.1
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
From `node1`, ping both `node2` replicas across the switches and `r0` router:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
docker-compose exec node1 ping 10.2.0.1
|
|
149
|
+
docker-compose exec node1 ping 10.2.0.2
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
Restart the compose instance and add another compose file that starts
|
|
154
|
+
conlink using an addition network file `web-network.yaml`. The network
|
|
155
|
+
file starts up a simple web server on the router.
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
MODES_DIR=./examples/test4-multiple/modes ./mdc node1,nodes2,web up --build --force-recreate
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
From the second `node2`, perform a download from the web server running on the
|
|
162
|
+
router host:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
docker-compose exec --index 2 node2 wget -O- 10.0.0.100
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
We can simplify the above launch by using the `all` mode, which contains
|
|
169
|
+
depends on `node1`, `nodes2`, and `web`. Each of those modes depends on
|
|
170
|
+
`base`, so there's no need to specify that again (transitive deps).
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
MODES_DIR=./examples/test4-multiple/modes ./mdc all up --build --force-recreate
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Remove the `.env` file as a final cleanup step:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
rm .env
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
## test5: conlink on two hosts with overlay connectivity via geneve
|
|
184
|
+
|
|
185
|
+
Launch a compose instance on host 1 and point it at host 2:
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
echo "REMOTE=ADDRESS_OF_HOST_2" > .env
|
|
189
|
+
echo "NODE_IP=192.168.100.1" > .env \
|
|
190
|
+
docker-compose --env-file .env -f examples/test5-geneve-compose.yaml up
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Launch another compose instance on host 2 and point it at host 1:
|
|
194
|
+
On host 2 run conlink like this:
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
echo "REMOTE=ADDRESS_OF_HOST_1" > .env
|
|
198
|
+
echo "NODE_IP=192.168.100.2" >> .env \
|
|
199
|
+
docker-compose --env-file .env -f examples/test5-geneve-compose.yaml up
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
On host 1, start a tcpdump on the main interface capturing Geneve
|
|
203
|
+
(encapsulated) traffic:
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
sudo tcpdump -nli eth0 port 6081
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
On host 2, start a ping within the "node1" network namespace created
|
|
210
|
+
by conlink:
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
docker-compose -f examples/test5-geneve-compose.yaml exec node ping 192.168.100.1
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
On host 1 you should see bi-directional encapsulated ping traffic on the host.
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
## test6: conlink on two hosts deployed with CloudFormation
|
|
220
|
+
|
|
221
|
+
This test uses AWS CloudFormation to deploy two AWS EC2 instances that
|
|
222
|
+
automatically install, configure, and start conlink (and dependencies)
|
|
223
|
+
using the `test5-geneve-compose.yaml` compose file.
|
|
224
|
+
|
|
225
|
+
Authenticate with AWS and set the `MY_KEY`, `MY_VPC`, and `MY_SUBNET`
|
|
226
|
+
variables to refer to a preexisting key pair name, VPC ID, and Subnet
|
|
227
|
+
ID respectively. Then use the AWS CLI to deploy the stack:
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
export MY_KEY=... MY_VPC=... MY_SUBNET=...
|
|
231
|
+
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}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
The stack will take about 8 minutes to finish deploying. You can
|
|
235
|
+
reduce the time to under a minute if you create your own AMI with the
|
|
236
|
+
pre-signal steps in `BaseUserData` baked in and modify the template to
|
|
237
|
+
use that instead.
|
|
238
|
+
|
|
239
|
+
Once the stack is finish deploying, show the outputs of the stack
|
|
240
|
+
(including instance IP addresses) like this:
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
aws --region us-west-2 cloudformation describe-stacks --stack-name ${USER}-conlink-test6 | jq '.Stacks[0].Outputs'
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Use ssh to connect to instance 1 and 2 (as the "ubuntu" user), then
|
|
247
|
+
sudo to root and cd into `/root/conlink`. You can now run the tcpdump
|
|
248
|
+
and ping test described for test5.
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
## test7: MAC, MTU, and NetEm settings
|
|
252
|
+
|
|
253
|
+
This example demonstrates using interface MAC, MTU, and NetEm (tc
|
|
254
|
+
qdisc) settings.
|
|
255
|
+
|
|
256
|
+
Start the test7 compose configuration:
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
docker-compose -f examples/test7-compose.yaml up --build --force-recreate
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Show the links in both node containers to see that on the eth0
|
|
263
|
+
interfaces the MAC addresses are `00:0a:0b:0c:0d:0*` and the MTUs are
|
|
264
|
+
set to `4111`. The eth1 interfaces should have the command line set
|
|
265
|
+
default MTU of `5111`.
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
docker-compose -f examples/test7-compose.yaml exec --index 1 node ip link
|
|
269
|
+
docker-compose -f examples/test7-compose.yaml exec --index 2 node ip link
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Ping the second node from the first to show the the NetEm setting is
|
|
273
|
+
adding 40ms delay in both directions (80ms roundtrip).
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
docker-compose -f examples/test7-compose.yaml exec --index 1 node ping 10.0.1.2
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## test8: Connections to macvlan/vlan host interfaces
|
|
280
|
+
|
|
281
|
+
This example has two nodes with web servers bound to local addresses.
|
|
282
|
+
The first node is connected to a macvlan sub-interfaces of a host
|
|
283
|
+
physical interface. The second node is connected to a VLAN
|
|
284
|
+
sub-interface of the same host (using VLAN ID/tag 5). Static NAT
|
|
285
|
+
(SNAT+DNAT) is setup inside each container to map the external
|
|
286
|
+
address/interface to the internal address/interface (dummy) where the
|
|
287
|
+
web server is running.
|
|
288
|
+
|
|
289
|
+
Create an environment file with the name of the parent host interface
|
|
290
|
+
and the external IP addresses to assign to each container:
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
cat << EOF > .env
|
|
294
|
+
HOST_INTERFACE=enp6s0
|
|
295
|
+
NODE1_HOST_ADDRESS=192.168.0.32/24
|
|
296
|
+
NODE2_HOST_ADDRESS=192.168.0.33/24
|
|
297
|
+
EOF
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Start the test8 compose configuration using the environment file:
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
docker-compose --env-file .env -f examples/test8-compose.yaml up --build --force-recreate
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Connect to the macvlan node (NODE1_HOST_ADDRESS) from an external host
|
|
307
|
+
on your network (traffic to macvlan interfaces on the same host is
|
|
308
|
+
prevented):
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
ping -c1 192.168.0.32
|
|
312
|
+
curl 192.168.0.32
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Note: to connect to the vlan node (NODE2_HOST_ADDRESS) you will need
|
|
316
|
+
to configure your physical switch/router with routing/connectivity to
|
|
317
|
+
VLAN 5 on the same physical link to your host.
|
|
318
|
+
|
|
319
|
+
## test9: bridge modes
|
|
320
|
+
|
|
321
|
+
This example demonstrates the supported bridge modes.
|
|
322
|
+
|
|
323
|
+
Start the test9 compose configuration using different bridge modes and
|
|
324
|
+
validate connectivity using ping:
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
export BRIDGE_MODE="linux" # "ovs", "patch", "auto"
|
|
328
|
+
docker-compose -f examples/test9-compose.yaml up --build --force-recreate
|
|
329
|
+
docker-compose -f examples/test9-compose.yaml exec node1 ping 10.0.1.2
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## test10: port forwarding and routing
|
|
333
|
+
|
|
334
|
+
This example demonstrates port forwarding from the conlink container
|
|
335
|
+
to two containers running simple web servers. It also demonstrates the
|
|
336
|
+
use of a router container and multiple route rules in the other
|
|
337
|
+
containers.
|
|
338
|
+
|
|
339
|
+
Start the test10 compose configuration:
|
|
340
|
+
|
|
341
|
+
```
|
|
342
|
+
docker-compose -f examples/test10-compose.yaml up --build --force-recreate
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Ports 3080 and 8080 are both published on the host by the conlink
|
|
346
|
+
container using standard Docker port mapping. The internal mapping of
|
|
347
|
+
those ports (1080 and 1180 respectively) are both are forwarded to
|
|
348
|
+
port 80 in the node1 container using conlink's port forwarding
|
|
349
|
+
mechanism. The two paths look like this:
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
host:3080 --> 1080 (in conlink) --> node1:80
|
|
353
|
+
host:8080 --> 1180 (in conlink) --> node1:80
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Use curl on the host to query both of these paths to node1:
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
curl 0.0.0.0:3080
|
|
360
|
+
curl 0.0.0.0:8080
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Ports 80 and 81 are published on the host by the conlink container
|
|
364
|
+
using standard Docker port mapping. Then conlink forwards from ports
|
|
365
|
+
80 and 81 to the first and second replica (respectively) of node2,
|
|
366
|
+
each of which listen internally on port 80. The two paths look like
|
|
367
|
+
this:
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
host:80 -> 80 (in conlink) -> node2_1:80
|
|
371
|
+
host:81 -> 81 (in conlink) -> node2_2:80
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Use curl on the host to query both replicas of node2:
|
|
375
|
+
|
|
376
|
+
```
|
|
377
|
+
curl 0.0.0.0:80
|
|
378
|
+
curl 0.0.0.0:81
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Start a two tcpdump processes in the conlink container to watch
|
|
382
|
+
routed ICMP traffic and then ping between containers across the router
|
|
383
|
+
container:
|
|
384
|
+
|
|
385
|
+
```
|
|
386
|
+
docker compose -f examples/test10-compose.yaml exec network tcpdump -nli router_1-es1 icmp
|
|
387
|
+
docker compose -f examples/test10-compose.yaml exec network tcpdump -nli router_1-es2 icmp
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
```
|
|
391
|
+
docker-compose -f examples/test10-compose.yaml exec node1 ping 10.2.0.1
|
|
392
|
+
docker-compose -f examples/test10-compose.yaml exec node1 ping 10.2.0.2
|
|
393
|
+
docker-compose -f examples/test10-compose.yaml exec node2 ping 10.1.0.1
|
|
394
|
+
|
|
395
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# GraphViz network configuration rendering
|
|
2
|
+
|
|
3
|
+
You can use d3 and GraphViz to create a visual graph rendering of
|
|
4
|
+
a network configuration. First start a simple web server in the
|
|
5
|
+
examples directory:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
cd examples
|
|
9
|
+
python3 -m http.server 8080
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Use the `net2dot` script to transform a network
|
|
13
|
+
configuration into a GraphViz data file (dot language). To render the
|
|
14
|
+
network configuration for example test1, run the following in another
|
|
15
|
+
window:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
./conlink --show-config --compose-file examples/test1-compose.yaml | ./net2dot > examples/test1.dot
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Then load `http://localhost:8080?data=test1.dot` in your browser to see the rendered
|
|
22
|
+
image.
|
|
23
|
+
|
|
24
|
+
The file `examples/net2dot.yaml` contains a configuration that
|
|
25
|
+
combines many different configuration elements (veth links, dummy
|
|
26
|
+
interfaces, vlan type links, tunnels, etc).
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
./conlink --network-file examples/net2dot.yaml --show-config | ./net2dot > examples/net2dot.dot
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Then load `http://localhost:8080?data=net2dot.dot` in your browser.
|
package/docs/index.html
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>conlink - Declarative Low-Level Networking for Containers</title>
|
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
|
7
|
+
<meta name="description" content="Create (layer 2 and layer 3) networking between containers using a declarative configuration.">
|
|
8
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
|
9
|
+
<!-- using docsify-themeable Theme: Simple -->
|
|
10
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-simple.css">
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="app"></div>
|
|
14
|
+
<script>
|
|
15
|
+
window.$docsify = {
|
|
16
|
+
name: 'conlink',
|
|
17
|
+
repo: 'LonoCloud/conlink',
|
|
18
|
+
homepage: 'https://raw.githubusercontent.com/LonoCloud/conlink/master/README.md',
|
|
19
|
+
// Uncomment to follow a symlink to root README.md and test rendering locally
|
|
20
|
+
//homepage: '_render-local-README.md',
|
|
21
|
+
|
|
22
|
+
auto2top: true,
|
|
23
|
+
loadSidebar: true,
|
|
24
|
+
subMaxLevel: 2
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
<!-- Docsify v4 -->
|
|
28
|
+
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
|
|
29
|
+
<!-- code highlighting -->
|
|
30
|
+
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-bash.min.js"></script>
|
|
31
|
+
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-yaml.min.js"></script>
|
|
32
|
+
</body>
|
|
33
|
+
</html>
|