Skip to content

Foreign Services - followup #307

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

Merged
merged 22 commits into from
Jan 18, 2018
Merged

Foreign Services - followup #307

merged 22 commits into from
Jan 18, 2018

Conversation

rshriram
Copy link
Member

This is mostly addressing nits to the previous PR #273 .. Fixing docs, and making the endpoint ports plural.

@googlebot googlebot added the cla: yes Set by the Google CLA bot to indicate the author of a PR has signed the Google CLA. label Jan 12, 2018
@rshriram
Copy link
Member Author

@frankbu PTAL. I have folded the entire thing into one single atomic foreign services. I think the namespace issue can be tackled across all three resources uniformly

// that services in the mesh are allowed to access.
// Foreign service describes the endpoints, ports and protocols of a
// white-listed set of mesh-external domains and IP blocks that services in
// the mesh are allowed to access.
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't seem to be a description of a "service", so the resource name "ForeignService" seems odd.

@frankbu
Copy link
Contributor

frankbu commented Jan 12, 2018

I'm not following the new idea. Can there now be multiple ForeignService resources, i.e., one for foo.com and another for bar.com? What is the relationship between a ForeignService and entries in the service registry? If there are service registry entries for all the hosts, then the ForeignService is still defining multiple services, or am I missing the difference?

// the mesh are allowed to access.
//
// NOTE: If a foreign service has the same name as a service in the
// service registry, the foreign service's declaration will be given
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the name of a foreign service? The metadata.name (i.e. foreign-svc in your example) doesn't seem to be the name of any service

@rshriram
Copy link
Member Author

@frankbu you can now have multiple foreign service resources, just like egress rules. Removed the confusing wording around the registry overwrite.

message PortMap {
// REQUIRED: A valid non-negative integer port number on which
// connections to the external service would be received.
uint32 in_port = 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we sure we always have a port number here? Should we reuse the Port message?

Copy link
Member Author

Choose a reason for hiding this comment

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

Tried and dumped.. the port message in foreign service has to accomodate the tls upgrade, internal and external ports (when app wants to do http://google and wants sidecar to do https://google). The generic port message in gateway does not accomodate this. Because the port in the routing rule serves as a way in the gateway to route to a particular upstream on specific port.

Copy link
Contributor

Choose a reason for hiding this comment

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

Given that we've agreed to haev port declarations in dest-rule I think this mapping should be declared there.

Also I think it might be more readable to have something like this in dest-rule....

port :
  - number : 80
    name: http
    forwardTo: https   #forward reference by port name
  - number : 443
    name: https

Can also then use circuit-breaking to shut-down direct access to 443 when Envoy not originating traffic. Seems like something which belongs in traffic-policy

Copy link
Member Author

Choose a reason for hiding this comment

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

Destination rule does not declare ports.. It has port specific policies. Especially, with teh wildcard and other stuff, we cannot declare ports. The above format straddles route and cluster.. pushign that into destination rule is going to add complexity. Besides, routing already has this port rerouting thing.

// PortMap describes the properties of a specific port of the external
// service, the port by which the service will be accessed inside the
// mesh and TLS upgrade options if any.
message PortMap {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be part ofSubset's TrafficPolicy:

message TrafficPolicy {
// Settings controlling the load balancer algorithms.
LoadBalancerSettings load_balancer = 1;
// Settings controlling the volume of connections to an upstream service
ConnectionPoolSettings connection_pool = 2;
// Settings controlling eviction of unhealthy hosts from the load balancing pool
OutlierDetection outlier_detection = 3;
// TLS related settings for connections to the upstream service.
TLSSettings tls = 4;
}

Then we can do similar things inside of the mesh too.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah I toyed with it..The problem is the dang inheritance. DestinationRules support inheritance. It is not exactly clear where the port will fit in, as it becomes a problem of multiple inheritance.

Also, why push the port into just the subset? why not push it into the main destination rule as well ?

Copy link
Member Author

Choose a reason for hiding this comment

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

and I couldn't do that, because there is also a port in the routing rule. The existing flow is gatewayPort->routeRule(decidePort)->destinationRule(no port business here)->out.

Adding a new inbound path (foreign services) is causing this dilemma.

// mesh and TLS upgrade options if any.
message PortMap {
// REQUIRED: A valid non-negative integer port number on which
// connections to the external service would be received.
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems a little unclear to me, what about:

The port number on which the application in the mesh will call the external service.

I don't think we need to say "valid non-negative integer."

// service must be made over a different port (e.g., https over port
// 443).
//
// NOTE: outPort cannot be specified when the discovery mode is set to
Copy link
Contributor

Choose a reason for hiding this comment

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

Why? Even with static addresses, seems reasonable to want offload TLS to mesh and upgrade to a different port w/ TLS when egressing.

Copy link
Member Author

Choose a reason for hiding this comment

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

outPort applies only with static and DNS. but not with "none" which is the equivalent of original_dst_cluster.. The reason (and its a temporary restriction) is that you cannot rewrite ports in original_dst_clusters.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, it wasn't clear to me if this was an artifact of Envoy or not.

// HTTP|HTTPS|GRPC|HTTP2|MONGO|TCP. When protocol is set to HTTPS, the
// traffic will be treated as opaque TCP traffic, and TCP level
// constraints will apply.
string protocol = 3;
Copy link
Contributor

Choose a reason for hiding this comment

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

We really need to make this an enum, we're reusing the same thing all over the place.

Copy link
Contributor

@kyessenov kyessenov Jan 12, 2018

Choose a reason for hiding this comment

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

Yes, let's upstream model service from istio to here. If the intention is to define egress as
an external service, then we should start from an internal service definition.

Copy link
Contributor

Choose a reason for hiding this comment

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

hard to make this an enum when we'll have 3rd-party protocol support :/

}

// REQUIRED: The Ports associated with the external services.
repeated PortMap ports = 2;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is a PortMap really required? Can't we just blindly forward the app's request if we have no PortMap configured? Service discovery ensures that in the mesh requests to the egress proxies implementing this behavior will hit the port its listening on, and if the side-car is the egress proxy then there's no problem there either.

Copy link
Member Author

Choose a reason for hiding this comment

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

You need some set of ports for the service right? Otherwise, we would have to assume that default port is 80, which seems wonky. PortMap may be badly named, but essentially, it is the equivalent of ports, with some extra sauce to forward to a different outbound port.

@frankbu
Copy link
Contributor

frankbu commented Jan 15, 2018

I still think naming is causing confusion and making this harder to understand than necessary.

ForeignService is not a service. What seems instinctively to be the case is that it's similar to a Gateway just on the outgoing side.

@rshriram It sounds like you've already considered, but discarded, the idea of using Gateway for both. It might still make sense to use common naming though. Here's a suggestion:

  1. rename Gateway -> IngressGateway
  2. rename ForeignService -> EgressGateway

@rshriram
Copy link
Member Author

I was actually pro using the Gateway. But @louiscryan is of the opinion that this is overloading the functionality in the wrong manner.

This is essentially adding some more entries to the service discovery system, when its a simple matter of *.foo.com -> foo.bar.com.. But when we have something like foo.bar.com -> 1.1.1.1, 2.2.2.2, 3.3.3.3, then we are describing a pseudo service reg spec. Either way, the gateway is a good place to stick these in.
The problem is when we want these egress gateways to materialize in the local sidecar. One proposal I had was to use the "mesh" gateway, and add these foreign services to it. That would essentially materialize the external service in every sidecar.
This would allow you to materialize the foreign service on an external gateway as well (its upto the application to ensure traffic arrives at this external gateway though ip tables, http proxy, etc.).

@frankbu
Copy link
Contributor

frankbu commented Jan 16, 2018

I think that the naming confusion/disagreement stems from the fact that ForeignService is both a service AND a gateway definition. From the documentation:

Gateway: describes a load balancer operating at the edge of the mesh ... describes a set of ports that should be exposed, the type of protocol to use, SNI configuration for the load balancer, etc.

ForeignService: describes the endpoints, ports and protocols of a white-listed set of mesh-external domains and IP blocks that services in the mesh are allowed to access.

So both are describing some of the same kinds of things: ports, protocols, etc., of services that cross the mesh internal/external boundry. What's different between the two is that Gateway is defining them as "additional gateway details" for existing mesh services, while ForeignService is defining the service itself (for the registry) in addition to the "additional gateway details". So the latter is both a "service" definition and a "gateway" definition. By "gateway" I mean a config for calls into or out of the mesh.

The way I see it, there are 3 kinds of requests that need to be considered in traffic routing:

  1. mesh internal
  2. external requests from outside the mesh
  3. requests from internal mesh services to outside services

#1 is handled by the RouteRules and DestinationRules. #2 and #3 require some additional config.

Standing back and looking at this from a high level I think a typical user with little or no implementation knowledge would think of #2 and #3 as gateway config, not a gateway and a (foreign) service. That would argue for using Gateway for both purposes, however, I can see @louiscryan's point about overloading the same config resource for both, given the difference mentioned above. That said, I do think that both of these "gateway" config resources should be called gateways, and they should share common internal data stuctures (Port, Protocol) as much as possible.

If we don't want to use the names I suggested above IngressGateway and EgressGateway (bad association with K8s Ingress :-) ), how about EntryGateway and ExitGateway instead? As long as Gateway is in the name I think it will be much easier for people to understand what it's for. Maybe ExitGateway could have a list of ForeignService inside it (similar to the previous InternalServices version of this spec. If that is possible, it would cleanly separate the gateway and service definition parts of the exit gateway.

The bottom line is that this new v1alpha2 spec solves a lot of problems but IMO a few bad names are preventing this from being something that could be relatively simple to understand.

@rshriram
Copy link
Member Author

Per discussion today, gateway is just a proxy. Internal/external/in-between. ForeignServices is a way to add more entries to the service registry (kube's external services wont suffice, because we have wildcard destinations).

By default, foreign services will be exposed via sidecars directly. But you can implement a dedicated egress proxy using the gateway. When you do the latter, you declare foreign services as exposable only at gateway (this is missing today), then you write a route rule that will forward traffic from sidecar to the gateway host.
You can also funnel all traffic through third party gateways, by specifying the endpoint IP in the foreign services. The recipe for third party gateways is different from the recipe for egress gateways.


// Endpoint defines a network address (IP or hostname) associated with
// the foreign service.
message Endpoint {
Copy link
Contributor

Choose a reason for hiding this comment

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

Still doesn't seem to cover port variation per endpoint instance. Would have expected to see

map<string, int> ports = 3; // Mapping of port names to physical port numbers by endpoint instance

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah yes.. That was an intentional omit. The problem was it made no sense with inport and outport. It also made no sense when there was port remapping happening at the route level.

Shriram Rajagopalan added 2 commits January 17, 2018 17:57
@rshriram
Copy link
Member Author

Updates: I removed the portMap thing completely. Its back to good old Ports. Its also back to the good old http://google.com:443 model, so that we can make some progress on the foreign services while we sort out the saner way of doing 80 to 443.

People might most likely use https from the start, and not bother to use Istio for monitoring external APIs. As that ensures that the application works with and without Istio. So, in lieu of that, it seems its not that important to cater to this TLS upgrade use case.

Other than that, the other nits are per previous PR.

@wora
Copy link
Contributor

wora commented Jan 18, 2018

LGTM

Envoy uses an Address proto to capture the concept of host and port. I wonder if we should do something similar. Just an idea for future consideration.

@rshriram
Copy link
Member Author

@wora will do, in next iteration (just wanted to get this out of the door by 22nd) for initial feedback. After @kyessenov refactors the envoy apis, I hope it would make it easier to import/download these protos separately, reuse data structures. I wanted to import the TLS stuff as well, but it was too buried into the entire API, and I couldn't import easily. Hopefully, with the refactoring, I should be able to import all the envoy TLS things

Copy link
Contributor

@ZackButcher ZackButcher left a comment

Choose a reason for hiding this comment

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

LGTM, though I prefer ExternalService to ForeignService (even with the unfortunate naming collision with the k8s resource).

@rshriram
Copy link
Member Author

Okay, @ZackButcher @frankbu and @kyessenov prefer the term ExternalService. I have no preference. Don't mind renaming.. @louiscryan if you have any concern, now would be a good time to speak before I rename the files..

@louiscryan
Copy link
Contributor

LGTM and fine with rename to ExternalService

@rshriram rshriram merged commit 2351810 into master Jan 18, 2018
@rshriram rshriram deleted the passthrough branch February 13, 2018 19:41
@johnzheng1975
Copy link
Member

Is this related with defect: upstream connect error or disconnect/reset before headers?
istio/istio#4999

Is this fix merged in istio0.7.1? We still find istio/istio#4999 raise in istio0.7.1

incfly pushed a commit to incfly/api that referenced this pull request Jun 13, 2018
nacx pushed a commit to nacx/api that referenced this pull request Feb 23, 2022
Signed-off-by: Liam White <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes Set by the Google CLA bot to indicate the author of a PR has signed the Google CLA.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants