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

WIP: Adds Traffic Splitting doc #285

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions docs/TrafficSplitting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Traffic Splitting

The purpose of this section of the kn documentation is to describe the command verbs for traffic splitting operations and present some examples.

`kn` client can work with following properties of a traffic target defined in traffic block of a service spec.
- **RevisionName**: RevisionName of a specific revision to which to send a portion of traffic.
Copy link
Contributor

@maximilien maximilien Aug 1, 2019

Choose a reason for hiding this comment

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

Nit.. Do we need to repeat the word when it's already bolded and delimits the paragraph :) ? Same for below.

Copy link
Contributor

Choose a reason for hiding this comment

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

Would also rephrase to 'RevisionName: Name of a specific revision ...'

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sure, we'll have this incorporated in a different PR.

- **Tag**: Tag is optionally used to expose a dedicated url for referencing this target exclusively.
- **Percent**: Percent specifies percent of the traffic to this Revision.
Copy link
Contributor

@duglin duglin Jul 23, 2019

Choose a reason for hiding this comment

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

Just wanted to point out some key things in case people are unaware:

  • The tag property on a traffic block is optional. This means that we CAN NOT identify a traffic block by this value, since not all blocks will have one.
  • The revisionName property on a traffic block may not be unique. More than one traffic block can refer to the same revisionName. This means that we CAN NOT identify a traffic block by this value.
  • Additionally, since people can use latestRevision: true, there is no consistent revisionName to search on for this block (it'll change each time a new revision is created) - which requires the user to query the service each time they want to modify this traffic block to see if the value changed. Otherwise, per this PR, a new block will be create w/o them realizing it (I think).

IMO this means any operation that tries to modify an existing traffic block probably can't because there's no guaranteed way to find what you're looking for (in some cases) and in others it requires extra work, which is also racey.

Copy link
Contributor

Choose a reason for hiding this comment

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

  • The tag property on a traffic block is optional. This means that we CAN NOT identify a traffic block by this value, since not all blocks will have one.

True, therefore a user can use revision or tag (or both in case of multiple revisions being present). As mentioned above we might need to add a special name to target the "latestRevision" traffic block.

  • The revisionName property on a traffic block may not be unique. More than one traffic block can refer to the same revisionName. This means that we CAN NOT identify a traffic block by this value.

But the combination tag:revision is unique. That's how you would need to address such a block.

Copy link
Contributor

Choose a reason for hiding this comment

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

only if tag is present - which it may not be because it's optional. I think having a different traffic-block-picking syntax based on the data in the traffic sections will be a bit confusing.
We need a cmd that works consistently.

Copy link
Collaborator Author

@navidshaikh navidshaikh Jul 24, 2019

Choose a reason for hiding this comment

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

only if tag is present - which it may not be because it's optional.

Yes, and which gives us opportunity to design UX to remove the ambiguities.

I think having a different traffic-block-picking syntax based on the data in the traffic sections will be a bit confusing.

Yes, and this is why we need to give users a way to not confuse them. We should ask users to create unique identity for ambiguous targets, which is Tag. We ask users to create Tag for a revision if it has to present more than once in traffic block, so that sub-subsequent operations can be performed without ambiguity. Tag is optional, I agree, but we can leverage it for identifying a target uniquely.

There are a bunch of combinations, given that serving traffic block allows fields as optional and aliases, and I think we should work towards making the client UX easy to understand and execute for users, defining the path to reach to a desired state.


## Operations

Operations required to perform traffic splitting use cases, for example: blue/green deployment, etc can be summarized as below:
- Tag targets
Copy link
Contributor

Choose a reason for hiding this comment

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

I would have proposed names for these and small explanation if possible. Since one goal here is to see what other operations people reading this spec can come up with...

- Split traffic

### Tag Targets

User can tag traffic targets (revisions) to
- Create custom URLs
- Create a human-friendly reference to refer to a traffic target
- Create static routes and change the underlying revisions as needed
- Remove the custom URLs OR remove the tags of targets
- Remove a target from traffic block altogether


#### Tagging commands

#### 1. `kn service tag-target serviceName [RevisionName1:Tag1] [RevisionName2:Tag2]`

- Takes the first argument as service name to operate on
- Tags given revision with specified tag thereby creating a custom URL
- Does not change the traffic percent of the target
- Multiple `RevisionName:Tag` combination can be specified
- Multiple tags for same revision can be specified
- `kn service tag-target svc echo-v1:stable echo-v1:current`
- If the target doesn't exist in deployed service, it creates a target entry with 0% traffic portion
- For updating tags of existing traffic targets, use `kn service untag-target` followed by `kn service tag-target`, because
- The deployed service might have multiple tags referring to a `RevisionName`
- The specified `RevisionName:Tag` combination on CLI might request to have different tags for same revision

#### 2. `kn service untag-target serviceName [Tag] [RevisionName:Tag] [RevisionName [--all]]`

- Takes the first argument as service name to operate on
- Takes single reference of a traffic target
- Does not change the traffic percent of the target
- Can be specified either via
- `Tag`, removes the specified tag from traffic targets
- `RevisionName`, removes the tag for target where `RevisionName` matches, errors if multiple tags for a revision exists
- `RevisionName:Tag` removes `Tag` for `RevisionName`, useful for case where a single revision is tagged with multiple tags
- `--all` flag can be optionally specified along with `RevisionName` to remove all tags for given revision
- If a target has 0% traffic portion and it is untagged, target is removed from traffic block altogether


## Split Traffic

A user can
- Specify the traffic percent portion to route to a particular target
- Adjust the traffic percent of existing traffic targets
- Reference a traffic target either by `RevisionName` or `Tag`
Copy link
Contributor

Choose a reason for hiding this comment

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

We should mention that in the future people may be able to specify something other than "percent" as the criteria, so we need to design a syntax that doesn't preclude us from supporting that later on.

Since right now I believe all of our proposals have done something of the form ...:% - then as long as the % specification is at the end of the syntax then I think we might be ok. We can then assume that whatever string is after the : is the criteria - even if it's a complex expression. We may need to allow for it to be of the form type:expression (e.g. path:/foo or header:user=john) but I think that's workable. So, nothing needs to be changed w.r.t. any proposal (except the comment above to mention it) - I just wanted to bring this up so people are thinking about it.


### Traffic splitting command

#### `kn service set-traffic serviceName [revisionName1=Percent] [Tag2=Percent] [Tag3=*]`

- Takes the first argument as service name to operate on
- Subsequent arguments specifies the traffic targets
- Traffic target can be referenced either via `RevisionName` or `Tag`
Copy link
Contributor

Choose a reason for hiding this comment

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

This does not guarantee a unique look-up of the block in question

Copy link
Contributor

Choose a reason for hiding this comment

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

wdym ? Because a tag can be named like a revision ? I consider this case super seldom and we should verify this and throw an error, if then the tag and revision differs (as said (a) its very unlikely that a revision and tag will ever have the same name and (b) if this should be the case its very likely that it specifies the same block).

If you mean that when the user specifies a tag or revision which is not present, then of course again an error should be thrown.

So IMO it does guarantee a unique lookup (to 99.99999%) and simplifies the UI considerably.

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean, since the revisionName is not unique, [revisionName1=Percent] is indeterminate.

Copy link
Contributor

@rhuss rhuss Jul 24, 2019

Choose a reason for hiding this comment

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

  • If the revisionName appears once, the operation is performed
  • If the revisionName appears 0 times, an error is thrown it is checked if a revision of this name exists for the given service and the traffic block is created automatically if so. If not, an error is thrown.
  • If the revisionName appears more than once, an error is thrown and the user is hinted that she has to use a tag (multiple revisions without tags doesn't make any sense, or ?)

Copy link
Contributor

Choose a reason for hiding this comment

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

(just updated my comment above which overlooked a case)

- Traffic portion to allocate is specified after `=`
- Wildcard character `*` can be specified to allocate portion remaining after, summing specified portions and substracting it from 100
- Specified traffic allocations replace existing traffic block of deployed service

#### Referencing `latestRevision:true` (`$`) target
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a huge fan of the $ here... Maybe there is a precedence in other CLIs or reasoning. Can you elucidate this choice @navidshaikh? Thanks.

Not a huge concern if there is precedence. If not, then *latestRevision or &latestRevision could be perhaps more descriptive?

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 take on regexps where it means 'the end of a line' I guess (like in 'the end of a line of revisions') ;-). A bit made up, we could definitely use something different. However we should choose best something which does not has a meaning for a shell. E.g '*latestRevision' would expand to a filename if in the current directory is a file like 'mylatestRevision' before it's handed over to kn. & will put the process in the background if unescaped. $ alone is safe but when combined with another character it specifies a variable.

I'm afraid regardless of what we chose we won't find something so intuitive that it's obvious without reading the documentation.

I think $ is ok-ish but maybe we find something better ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

one of the suggestion Naomi mentioned during WG meeting is to use flag --traffic-latest which should refer the latestRevision field in traffic block.

We'll need an identifier for (a) traffic (b) tag operations, we can use
--traffic-latest and --tag-latest flags, for eg:

  1. --traffic-latest 2
  2. --tag-latest current

- Serving allows having `latestRevision:true` field in traffic block as traffic target
- This field indicates that the latest ready Revision of the Configuration should be used for this traffic target
- We can refer this as placeholder to point to the latest Revision which will be generated for the Service
- To reference this special target in traffic block, we can use character `$`, which can not be a Revision name to avoid conflicts
- Referencing `$` to tag a target or set traffic percent will update target in traffic block with Revision reference to `latestRevision: true`

```
kn service tag-target svc $:current
```
will form the traffic block as below before updating service
```
targets:
- latestRevision: true
tag: current
percent: xx
```

and,
```
kn service set-traffic svc $:100 #OR 'kn service set-traffic svc current:100'
```
will form the traffic block
```
targets:
- latestRevision: true
tag: current
percent: 100
```


## Examples:

1. Tag revisions `echo-v1` and `echo-v2` as `stable` and `staging`
```
kn service tag-target svc echo-v1:stable echo-v2:staging
```

2. Ramp up/down revision echo-v3 to 20%, adjusting other traffic to accommodate:
```
kn service set-traffic svc echo-v3=20 echo-v2=*
```

3. Give revision echo-v3 the tag candidate, without otherwise changing any traffic split:
```
kn service tag-target svc echo-v3:candidate
```

4. Give echo-v3 the tag candidate, and 2% of traffic adjusting other traffic to go to revision echo-v2:
```
kn service tag-target svc echo-v3:candidate
kn service set-traffic svc candidate=2 echo-v2=*
```

5. Give whatever revision has the tag candidate 10% of the traffic, adjusting the traffic on whatever revision has the tag current to accommodate:
```
kn service set-traffic svc candidate=10 current=*
```

6. Update the tag for echo-v3 from candidate to current:
```
kn service untag-target svc echo-v3:candidate
kn service tag-target svc echo-v3 current
```

7. Remove the tag current from echo-v3:
```
kn service untag-target svc echo-v3:current
```

8. Remove echo-v3 from the traffic assignments entirely, adjusting echo-v2 to fill up:
```
kn service set-traffic svc echo-v3=0 echo-v2=* #echo-v2 gets 100% traffic portion here
kn service untag-target svc echo-v3:current
```

9. Tag revision echo-v1 as stable and current with 50-50% traffic split
```
kn service tag-target svc echo-v1:stable echo-v1:current
kn service set-traffic svc stable=50 current=50
```

10. Revert all the traffic to latest revision of service
```
kn service set-traffic svc $=100
```