Skip to content

api: additions for host-level port publishing#1645

Merged
stevvooe merged 1 commit intomoby:masterfrom
stevvooe:port-exposition
Oct 21, 2016
Merged

api: additions for host-level port publishing#1645
stevvooe merged 1 commit intomoby:masterfrom
stevvooe:port-exposition

Conversation

@stevvooe
Copy link
Contributor

@stevvooe stevvooe commented Oct 14, 2016

To allow exposing ports on the host to which a task is scheduled, we
have introduced the concept of an publish mode parameter to the
PortConfig. The default, ingress, works as it does today. The new mode,
host, will bind the port to the host's port space, optimistically
deferring allocation to the target node.

Signed-off-by: Stephen J Day stephen.day@docker.com

cc @mrjana @aluzzardi @mavenugo

@aluzzardi
Copy link
Member

FYI
#550
#571

@aluzzardi
Copy link
Member

And #543

@stevvooe
Copy link
Contributor Author

@aluzzardi I'll work that in when we've decided whether we like this model. The alternative is to define a new host_port field that, if defined, binds a host_port for the target_port. If the host_port is less than zero, an ephemeral will be allocated (we could also use 0 + ephemeral).

@stevvooe
Copy link
Contributor Author

Also #1077

api/types.proto Outdated

// PortConfigExpositionHost exposes the port on just the target host.
// If the published port is undefined, an ephemeral port will be
// allocated. If the published port is defined, the node will attempt
Copy link
Contributor

Choose a reason for hiding this comment

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

Question :
is this task-specific publish-port ?
If it is service-wide publish-port, how can we support multiple tasks on the same host ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mavenugo If the user defines a publish port in host mode, only one instance of the task can run per node. If the user leaves this undefined, each instance will take a new ephemeral port.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, this is the part we kind of discussed in the meeting and it was felt that the major use case is to have ephemeral port mapping capability as long as it is query-able at the task level from docker api. Later on not sure if these can be tied to a scheduler constraint since the manager would effectively know about all the ports that swarm tasks bind to on any node if some service wants to use a specific port.

@mrjana
Copy link
Contributor

mrjana commented Oct 15, 2016

@stevvooe I think one overall problem with this is that at a port level it is mutually exclusive i.e for a given TargetPort/Protocol it can either be Ingress or Host. This is not going to satisfy the use case where the app generally listens on http/https but it want all of the endpoints to be exposed in Ingress fashion while a /metrics endpoint to be exposed in Host fashion.

@mavenugo
Copy link
Contributor

@stevvooe instead of making it mutually exclusive, can we model it in such a way that we provide the user an option to enable both or either. That will satisfy the requirement that @mrjana suggested above.

@mavenugo
Copy link
Contributor

@mrjana question on mutual exclusion. What is your suggestion for the user to configure a static published-port:exposed-port for the routing-mesh and a ephmeral-port for host-port ? Should this be 2 different configuration option ?

@stevvooe
Copy link
Contributor Author

@mavenugo I think this data model separates the "endpoint mode" from how the port is exposed. A port can be declared twice under the same endpoint, both under host and ingress.

Let's look at valid configuration where we want to expose the port 8080 under several

$ docker service create --replicas 2
--publish-ingress 8080:8080
--publish-ingress 8080
--publish-host 8080
--publish-host 8090:8080 ...  

The above would do the following, by order of flag:

  1. Bind 8080 across all nodes in the cluster, forwarding to 8080 for the service using the endpoint mode.
  2. Bind an ephemeral port across the cluster, forwarding to 8080 for the service, use the endpoint mode.
  3. Bind an ephemeral port to the host, forwarding to 8080. Endpoint mode has no effect.
  4. Bind 8090 to forward to 8080 in the container.

What do we see in docker service ls and docker service ps? First, we can see the ingress ports as part of the service ls output:

$ docker service ls
ID            NAME            REPLICAS  IMAGE  PORTS
13eqrrpt7hhw  admiring_knuth  2/2       redis  *:8080->8080/tcp,*:47895->8080/tcp

Note that these are * bound, denoting availability from any node.

So, we have two replicas running, across two nodes with ips 192.168.1.20 and 192.168.1.30. We can see the host ports exposed in docker service ps:

$ docker service ps <the service>                                                                                               
ID                         NAME              IMAGE  NODE  PORTS
5ssce40t1051k6pu4s9zz5ost  admiring_knuth.1  redis  moby  192.168.1.20:8090->8080/tcp,192.168.1.20:23458->8080/tcp
7jayfw7la2i22cw5sremrgwyc  admiring_knuth.2  redis  moby  192.168.1.30:8090->8080/tcp,192.168.1.30:56787->8080/tcp

Implications:

  1. When specifying a host port, limited to one task per service on each node.
  2. Must handle port allocation conflicts: exhaustion and collisions are same failure case.
  3. Can optimize by flowing port status back to manager to make earlier scheduling or failure reports.

What do we do for docker/docker:

  1. Let's alias --publish to --publish-ingress, retaining the short -p for the current behavior.
  2. Adopt a new option --publish-host which exposes the port on the host. It accepts both ephemeral and selected port options.

@jpetazzo @mavenugo @mrjana @aaronlehmann @aluzzardi

api/types.proto Outdated
// port is automatically assigned.
uint32 published_port = 4;

Exposition exposition = 5;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@aaronlehmann @mrjana @aluzzardi @mavenugo @mstanleyjones I really hate this terminology. Calling in the semantic adaptationists.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

PublishMode
PortMode

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah we probably need a better term than Exposition

Copy link
Contributor

Choose a reason for hiding this comment

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

PublishMode

@stevvooe
Copy link
Contributor Author

stevvooe commented Oct 19, 2016

@mavenugo @mrjana In a separate comment, I wanted to show the protobuf of repeated PortConfig ports for the above example:

# --publish-ingress 8080:8080
{
   mode: ingress
   target_port: 8080
   published_port: 8080
}
# --publish-ingress 8080
{
  mode: ingress
  target_port: 8080
}
# --publish-host 8080
{
  mode: host
  target_port: 8080
}
# --publish-host 8090:8080
{
  mode: host
  target_port: 8080
  published_port: 8090
}

This all sits under the same endpoint specification.

@mrjana
Copy link
Contributor

mrjana commented Oct 20, 2016

@stevvooe I think I like this model proposal. If we have enough consensus we can get the ball rolling.

@mrjana
Copy link
Contributor

mrjana commented Oct 20, 2016

@jpetazzo @aluzzardi @joegross @binman-docker Can you guys please chime in on the model/ui/api? Especially this: #1645 (comment)

@binman-docker
Copy link

This looks great, nothing to add re: model/ui/api. Thank you!

@stevvooe stevvooe changed the title api: additions for host-level port exposition api: additions for host-level port publishing Oct 20, 2016
@codecov-io
Copy link

codecov-io commented Oct 20, 2016

Current coverage is 57.18% (diff: 100%)

Merging #1645 into master will decrease coverage by 0.15%

@@             master      #1645   diff @@
==========================================
  Files            91         91          
  Lines         14724      14724          
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
- Hits           8443       8420    -23   
- Misses         5183       5209    +26   
+ Partials       1098       1095     -3   

Sunburst

Powered by Codecov. Last update 8b3a173...b2f4cd0

api/types.proto Outdated
option (gogoproto.goproto_enum_prefix) = false;

// PublishModeIngress exposes the port across the cluster on all nodes.
PUBLISH_INGRESS = 0 [(gogoproto.enumvalue_customname) = "PublishModeIngress"];
Copy link
Member

Choose a reason for hiding this comment

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

s/PUBLISH_//

@aluzzardi
Copy link
Member

Minor nit

LGTM

@aluzzardi
Copy link
Member

@mrjana @mavenugo re:

5ssce40t1051k6pu4s9zz5ost  [...] 192.168.1.20:8090->8080/tcp,192.168.1.20:23458->8080/tcp

@dperny is working on a PR to add an address into the Node object - you could use that information from the Docker CLI to display the address in docker service ps (so you can show things like 192.168.1.20:23458)

Also - beside this change, there's going to be a need to surface dynamically bound ports into the TaskStatus (so you can figure out which port was bound - basically the port part of 192.168.1.20:23458).

This has been spec'ed in the past and I think you can just reuse this: https://github.com/docker/swarmkit/pull/550/files

@stevvooe Still okay with that PR from May?

In the end, retrieving 192.168.1.20:23458 would actually be (pseudo template): {{ .Node.Addr }}:{ .Task.Status.ContainerStatus.Port}

@stevvooe
Copy link
Contributor Author

@aluzzardi The PR from May looks fine, but we may want to define a PortStatus structure if we need to add further information. Also, I would do this at the TaskStatus level, since networking is not container-bound. That might be more inline with the model we've followed before.

To allow exposing ports on the host to which a task is scheduled, we
have introduced the concept of an publish mode parameter to the
PortConfig. The default, ingress, works as it does today. The new mode,
host, will bind the port to the host's port space, optimistically
deferring allocation to the target node.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
@mrjana
Copy link
Contributor

mrjana commented Oct 20, 2016

@stevvooe Can we add the TaskStatus changes here as well so we would have the complete set of model changes needed?

@stevvooe
Copy link
Contributor Author

@mrjana I was leaving that as an exercise to the @mrjana. 😎

@mrjana
Copy link
Contributor

mrjana commented Oct 21, 2016

Ok then let @mrjana take care of it 😉

Copy link
Contributor

@mrjana mrjana left a comment

Choose a reason for hiding this comment

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

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants