Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos-container: support bridge and port forwarding for imperative nixos-container #20869

Merged
merged 7 commits into from
Feb 15, 2017

Conversation

wavewave
Copy link
Contributor

@wavewave wavewave commented Dec 2, 2016

Motivation for this change

systemd-nspawn supports network bridge and port forwarding via --network-bridge and --port option. Declarative container already supports network bridge but does not support port yet. Imperative container does not support both.

This PR introduces two options --bridge and --port to nixos-container commands and implements corresponding --port option in nixos/modules/virtualisation/containers.nix.

Things done
  • Tested using sandboxing
    (nix.useSandbox on NixOS,
    or option build-use-sandbox in nix.conf
    on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • Linux
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nox --run "nox-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Fits CONTRIBUTING.md.

@mention-bot
Copy link

@wavewave, thanks for your PR! By analyzing the history of the files in this pull request, we identified @ericbmerritt, @edolstra and @kampfschlaefer to be potential reviewers.

@wavewave
Copy link
Contributor Author

wavewave commented Dec 3, 2016

I made a corresponding change for nixops in the this branch.

Copy link
Member

@aszlig aszlig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you run the containers-* tests?

@@ -318,6 +319,16 @@ let
'';
};

hostPort = mkOption {
type = types.nullOr types.string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First of all, types.string is deprecated. And second, this seems to be accepting only an integer, am I correct? If yes, why not use types.int instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--port of systemd-nspawn can take a more general form such astcp:443:80 (see the following excerpt from systemd-nspawn man page) so for the time being, it's good to be a string than an integer. As for types.string, what is the most modern way now?

-p, --port=
           If private networking is enabled, maps an IP port on the host onto an IP port on
           the container. Takes a protocol specifier (either "tcp" or "udp"), separated by a
           colon from a host port number in the range 1 to 65535, separated by a colon from
           a container port number in the range from 1 to 65535. The protocol specifier and
           its separating colon may be omitted, in which case "tcp" is assumed. The
           container port number and its colon may be omitted, in which case the same port
           as the host port is implied. This option is only supported if private networking
           is used, such as with --network-veth, --network-zone= --network-bridge=.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, then I think the example and description attributes are clearly misleading, because Allow port forwarding... sounds like if it is a boolean option. I'd flesh this out as a submodule to avoid future need of deprecation once we want to remove the stringly typed one.

Also, doesn't this make more sense to be a list? What if you want to forward several ports (which I think is not uncommon)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, now I found that types.str is the correct way, thanks for pointing this out.
The description is misleading. I will change it.
I have to check whether systemd-nspawn can take multiple --port parameters. If so, it's much desirable to be a list. It would be better to be a list of key/values where key = protocol,hostPort,containerPort. Thanks for suggestion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd make it a submodule, like this (with missing example/description attrs):

{
  type = types.listOf (types.submodule {
    options = {
      protocol = mkOption {
        type = types.str;
        default = "tcp";
      };
      hostPort = mkOption {
        type = types.int;
      };
      containerPort = mkOption {
        type = types.nullOr types.int;
        default = null;
      };
    };
  });
}

Copy link
Contributor

@kampfschlaefer kampfschlaefer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No test -> no security this feature doesn't get broken next week. (And also no prove your feature is working.)

Please not only execute the existing tests to check that you didn't break anything, but also add tests for your new cool features.

@wavewave
Copy link
Contributor Author

wavewave commented Dec 4, 2016

@aszlig As you suggested, I change the configuration set to a list of submodule of (protocol,hostPort,containerPort). Now I changed the config name from hostPort to forwardPorts, which is well matched with the option with the same name in services/networking/nat.nix module.

I've tested this with my local machine:
With the following declarative container definition:

{
  containers = {
    foo = {
      privateNetwork = true;
      hostAddress = "192.168.100.10";
      localAddress = "192.168.100.11";
      forwardPorts = [ { hostPort = 10011; containerPort = 30011;}
                       { protocol = "tcp"; hostPort = 10012; }
                       { protocol = "udp"; hostPort = 10013; containerPort = 50013; }
                     ];
      autoStart = true;

      config = { config, pkgs, nodes, ... }: {
        networking.firewall.enable = false;
        environment.systemPackages = [ pkgs.traceroute pkgs.telnet ];
      };
    };
    bar = {
      privateNetwork = true;
      hostAddress = "192.168.200.10";
      localAddress = "192.168.200.11";
      forwardPorts = [ { hostPort = 20011; containerPort = 40011; }
                       { hostPort = 20012; containerPort = 40012; } ];
      autoStart = true;

      config = { config, pkgs, nodes, ... }: {
        networking.firewall.enable = false;
        environment.systemPackages = [ pkgs.traceroute pkgs.telnet ];
      };
    };

  };
}

I obtain the following port forwarding automatically done with systemd-nspawn.

$ sudo iptables -vnL -t nat 
Chain PREROUTING (policy ACCEPT 4 packets, 1327 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:10011 ADDRTYPE match dst-type LOCAL to:192.168.100.11:30011
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:10012 ADDRTYPE match dst-type LOCAL to:192.168.100.11:10012
    0     0 DNAT       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:10013 ADDRTYPE match dst-type LOCAL to:192.168.100.11:50013
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:20011 ADDRTYPE match dst-type LOCAL to:192.168.200.11:40011
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:20012 ADDRTYPE match dst-type LOCAL to:192.168.200.11:40012
 3199  894K nixos-nat-pre  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain INPUT (policy ACCEPT 4 packets, 1327 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 127 packets, 11825 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0           !127.0.0.0/8          tcp dpt:10011 ADDRTYPE match dst-type LOCAL to:192.168.100.11:30011
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0           !127.0.0.0/8          tcp dpt:10012 ADDRTYPE match dst-type LOCAL to:192.168.100.11:10012
    0     0 DNAT       udp  --  *      *       0.0.0.0/0           !127.0.0.0/8          udp dpt:10013 ADDRTYPE match dst-type LOCAL to:192.168.100.11:50013
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0           !127.0.0.0/8          tcp dpt:20011 ADDRTYPE match dst-type LOCAL to:192.168.200.11:40011
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0           !127.0.0.0/8          tcp dpt:20012 ADDRTYPE match dst-type LOCAL to:192.168.200.11:40012
...

(I am showing only relevant parts)

For imperative container, to give multiple port forwarding options, one should give port forwarding option encoded as systemd-nspawn convention separated by commas. For example,

nixos-container create foo --port 10000,10001,tcp:10002:20002

I am going to run other pre-existing tests and make a test dedicated to this new feature.

@wavewave
Copy link
Contributor Author

wavewave commented Dec 6, 2016

@aszlig I've checked that all containers-*.nix test passed!
@kampfschlaefer I will make a test for this new feature,

description = ''
Allow port forwarding from the host to the container.
List of forwarded ports from host to container. Each forwarded port is specified by protocol, hostPort and containerPort. By default, protocol is tcp and hostPort and containerPort are assumed to be the same if containerPort is not explicitly given.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: I'd break this long line as it's a bit tedious to read, especially on larger resolutions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aszlig I broke the long line now. :-)

@wavewave
Copy link
Contributor Author

wavewave commented Feb 3, 2017

@kampfschlaefer I've created a port forwarding test (nixos/tests/containers-portforward.nix).

Copy link
Contributor

@kampfschlaefer kampfschlaefer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the test.

(Although there is still the need for the "sleep 2" to wait on the networking of the host side…)

@globin globin merged commit b7a24e0 into NixOS:master Feb 15, 2017
@wavewave wavewave deleted the nixos-container branch March 25, 2017 17:47
@basvandijk
Copy link
Member

I made a corresponding change for nixops in the this branch.

@wavewave would you mind turning your nixops commits in a PR so that we can get bridge support in nixops? I would also be happy to create a PR based on your commits if you don't have time.

@basvandijk
Copy link
Member

Also see: NixOS/nixops#744 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants