I am building a Dockerised system that will create and tear down various server types in an HTTP API, for the purposes of integration testing. I am starting the project by experimenting how to create and run multiple FTP servers simultaneously.
I want to run FTP servers on separate IP addresses, so that tests can create and tear down servers without interfering with each other. In future, that should allow tests to be parallelised if necessary.
In my Docker container, I have set up various networks, as per this Docker Compose config:
version: '2'
services:
missive-box-of-tricks:
image: missive-box-of-tricks
networks:
network-01:
aliases:
- network-01
network-02:
aliases:
- network-02
network-03:
aliases:
- network-03
network-04:
aliases:
- network-04
network-05:
aliases:
- network-05
(trimmed - there's 10 of these)
networks:
network-01:
driver: bridge
network-02:
driver: bridge
network-03:
driver: bridge
network-04:
driver: bridge
network-05:
driver: bridge
(trimmed - there's 10 of these)
This results in a set of networks inside the container (trimmed again):
~ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:14:00:02
inet addr:172.20.0.2 Bcast:172.20.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:27 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3249 (3.1 KiB) TX bytes:0 (0.0 B)
eth1 Link encap:Ethernet HWaddr 02:42:AC:16:00:02
inet addr:172.22.0.2 Bcast:172.22.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:27 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3249 (3.1 KiB) TX bytes:0 (0.0 B)
eth2 Link encap:Ethernet HWaddr 02:42:AC:15:00:02
inet addr:172.21.0.2 Bcast:172.21.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:27 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3249 (3.1 KiB) TX bytes:0 (0.0 B)
eth3 Link encap:Ethernet HWaddr 02:42:AC:17:00:02
inet addr:172.23.0.2 Bcast:172.23.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:27 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3249 (3.1 KiB) TX bytes:0 (0.0 B)
eth4 Link encap:Ethernet HWaddr 02:42:AC:18:00:02
inet addr:172.24.0.2 Bcast:172.24.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:27 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3249 (3.1 KiB) TX bytes:0 (0.0 B)
The network aliases are resolvable, so I'd expect for the FTP server to be able to listen to network-01
etc. I use this command to start up a server, from inside the container:
PUBLIC_HOST=network-01
# -P -Force the specified IP address in reply to a PASV/EPSV/SPSV command
# -S -Connections are accepted on the specified IP and port
# -l -This is the authentication type, in the form "protocol:path"
# -E -Only allow authenticated users (if you wanted anonymous only you would substitute -e).
# -j -If the user doesn't have a home directory create it at first login.
# -R -Disallow the usage of the chmod command.
# -B -Instruct the standalone server to start in the background
# -g -Custom pidfile location (defaults to /var/run/pure-ftpd.pid)
# -d Verbose logging
/usr/sbin/pure-ftpd \
-S $PUBLIC_HOST \
-p $MIN_PASV_PORT:$MAX_PASV_PORT \
-g $PID_FILE \
-l $USER_DB \
-d \
-E \
-j \
-R
I have reset the PID and user database files, so as to avoid conflict, but in fact even a single server won't start. I get this error:
Unable to start a standalone server: Address not available
I get the same if I add a PASV declaration:
-P $PUBLIC_HOST \
I also get the same if I put the IP address in explicitly, rather than using an environment variable.
So, why is this IP address not available? Is there another way I can create a range of IP addresses inside a Docker environment and then bind a PureFTP instance to listen to just one?
This is resolved. To listen to a specific IPv4 address, one cannot just use a bare IP address, and a port separator of a colon is not recognised.
The valid syntaxes use a comma, like so, for default port and specific port respectively: