Commit 0bd8ec95 authored by Nils Goroll's avatar Nils Goroll

Merge branch 'shard_param' into 'master'

Optionally support a parameter object to control internal service shards

See merge request uplex/varnish/k8s-ingress!8
parents 20f31575 7564d2d8
......@@ -191,6 +191,7 @@ example:backend-config:
script:
- cd ../examples/backend-config
- make deploy verify undeploy
- make EXAMPLE=param deploy verify undeploy
example:custom-vcl:
extends: .integration-tests
......
......@@ -134,6 +134,9 @@ spec:
rampup:
type: string
pattern: '^\d+(\.\d+)?(ms|[smhdwy])$'
shard_param:
type: string
pattern: '^([a-uw-zA-UW-Z]|v[-abd-jl-zABD-J-ZABD-JL-Z0-9_]|vc[-a-km-zA-KM-Z0-9_]|vk[-a-zA-Z0-79_]|vk8[-a-rt-zA-Rt-z0-9_])[-a-zA-Z0-9_]*$'
tls:
type: object
properties:
......
......@@ -237,6 +237,10 @@ All of the properties of ``spec.director`` are optional:
[``rampup`` parameter](https://varnish-cache.org/docs/6.3/reference/vmod_directors.generated.html#void-xshard-set-rampup-duration-duration-0)
of the ``shard`` director. Ignored for the other directors.
* ``shard_param`` (string): Name of a
[shard_param](https://varnish-cache.org/docs/7.3/reference/vmod_directors.html#directors-shard-param)
object to control the shard director. Ignored for other directors.
With ``type`` you can choose the
[round-robin](https://varnish-cache.org/docs/6.3/reference/vmod_directors.generated.html#obj-round-robin),
[random](https://varnish-cache.org/docs/6.3/reference/vmod_directors.generated.html#obj-random)
......@@ -267,6 +271,17 @@ rather than the new Endpoint for a request, with a probability that is
end of the rampup interval. This mitigates the "thundering herd" of
requests for a newly added Endpoint.
With ``shard_param`` set, the ingress controller creates a vcl object
by the given name and associates it with the director. It can then be
used from custom VCL to control the behaviour of the
director. Multiple directors can share the same ``shard_param``
object.
The ``shard_param`` name can not start with ``vcl`` or ``vk8s`` and
otherwise must only contain characters valid for vcl synbols: It must
start with an alphabetical character and only contain alphanumerical
characters plus ``-`` and ``_``.
For example:
```
......@@ -277,6 +292,7 @@ spec:
type: shard
warmup: 50
rampup: 5m
shard_param: param
```
For the Ingress implementation, a director is always configured,
......
......@@ -34,18 +34,25 @@ TESTDIR=$(mkdir)/../../test
all: deploy
deploy-helm:
deploy-bcfg-helm:
@helm install viking-ingress-backend-cfg $(CHARTDIR)/viking-test-app \
--values values.yaml
deploy-param-helm:
@helm install viking-ingress-shard-param $(CHARTDIR)/viking-test-app \
--values values-param.yaml
deploy-kubectl:
@kubectl apply -f $(mkdir)/../hello/cafe-ingress.yaml
@kubectl apply -f backend-cfg.yaml
@kubectl apply -f $(mkdir)/../hello/cafe.yaml
# TESTOPTS are passed to varnishtest, e.g.: make TESTOPTS=-v verify
verify:
$(mkdir)/verify.sh
verify-bcfg:
$(mkdir)/verify.sh cafe.vtc
verify-param:
$(mkdir)/verify.sh cafe-param.vtc
wait:
$(TESTDIR)/wait.sh app=varnish-ingress
......@@ -55,19 +62,37 @@ uninstall-kubectl:
@kubectl delete -f $(mkdir)/../hello/cafe-ingress.yaml
@kubectl delete -f $(mkdir)/../hello/cafe.yaml
uninstall-helm:
uninstall-bcfg-helm:
@helm uninstall viking-ingress-backend-cfg
uninstall-param-helm:
@helm uninstall viking-ingress-shard-param
undeploy-kubectl: uninstall-kubectl wait
undeploy-helm: uninstall-helm wait
undeploy-bcfg-helm: uninstall-bcfg-helm wait
undeploy-param-helm: uninstall-param-helm wait
ifeq ($(DEPLOY),kubectl)
deploy: deploy-kubectl
undeploy: undeploy-kubectl
verify: verify-bcfg
else
deploy-bcfg: deploy-bcfg-helm
undeploy-bcfg: undeploy-bcfg-helm
deploy-param: deploy-param-helm
undeploy-param: undeploy-param-helm
endif
ifeq ($(EXAMPLE),param)
deploy: deploy-param
undeploy: undeploy-param
verify: verify-param
else
deploy: deploy-helm
undeploy: undeploy-helm
deploy: deploy-bcfg
undeploy: undeploy-bcfg
verify: verify-bcfg
endif
.PHONY: all $(MAKECMDGOALS)
# looks like -*- vcl -*-
varnishtest "cafe example using shard_param objects"
client c1 -connect "${localhost} ${localport}" {
txreq -url /coffee/foo/bar -hdr "Host: cafe.example.com"
rxresp
expect resp.status == 200
expect resp.http.X-Caffeine-Warmup == "0.250"
expect resp.http.X-Caffeine-Rampup == "true"
} -run
client c1 -connect "${localhost} ${localport}" {
txreq -url /tea/baz/quux -hdr "Host: cafe.example.com"
rxresp
expect resp.status == 200
expect resp.http.X-Theobromine-Warmup == "0.750"
expect resp.http.X-Theobromine-Rampup == "false"
} -run
apps:
coffee:
image: uplex/http-echo
replicas: 2
servicePort: 80
containerPort: 7357
targetPort: 7357
config:
director:
type: shard
shard_param: caffeine
tea:
image: uplex/http-echo
replicas: 3
servicePort: 80
containerPort: 7357
targetPort: 7357
config:
director:
type: shard
shard_param: theobromine
ingress:
name: cafe-ingress
rules:
- host: cafe.example.com
paths:
- path: /tea
type: Prefix
app: tea
- path: /coffee
type: Prefix
app: coffee
vikingAdmSvc: varnish-ingress-admin
vcl: |
sub vcl_backend_fetch {
caffeine.set(warmup=0.25, rampup=true);
theobromine.set(warmup=0.75, rampup=false);
set bereq.http.X-Caffeine-Warmup = caffeine.get_warmup();
set bereq.http.X-Caffeine-Rampup = caffeine.get_rampup();
set bereq.http.X-Theobromine-Warmup = theobromine.get_warmup();
set bereq.http.X-Theobromine-Rampup = theobromine.get_rampup();
}
sub vcl_backend_response {
set beresp.http.X-Caffeine-Warmup = bereq.http.X-Caffeine-Warmup;
set beresp.http.X-Caffeine-Rampup = bereq.http.X-Caffeine-Rampup;
set beresp.http.X-Theobromine-Warmup = bereq.http.X-Theobromine-Warmup;
set beresp.http.X-Theobromine-Rampup = bereq.http.X-Theobromine-Rampup;
}
#! /bin/bash -ex
MYDIR=$(dirname ${BASH_SOURCE[0]})
VTC=$1
source ${MYDIR}/../../test/utils.sh
LOCALPORT=${LOCALPORT:-8888}
......@@ -15,4 +16,4 @@ kubectl port-forward svc/varnish-ingress ${LOCALPORT}:80 >/dev/null &
trap 'kill $(jobs -p)' EXIT
wait_for_port ${LOCALPORT}
varnishtest ${TESTOPTS} -Dlocalport=${LOCALPORT} cafe.vtc
varnishtest ${TESTOPTS} -Dlocalport=${LOCALPORT} ${VTC}
......@@ -502,9 +502,10 @@ const (
// DirectorSpec corresponds to spec.director in a BackendConfig, and
// allows for a choice of directors, and some parameters.
type DirectorSpec struct {
Type DirectorType `json:"type,omitempty"`
Warmup *int32 `json:"warmup,omitempty"`
Rampup string `json:"rampup,omitempty"`
Type DirectorType `json:"type,omitempty"`
Warmup *int32 `json:"warmup,omitempty"`
Rampup string `json:"rampup,omitempty"`
ShardParam string `json:"shard_param,omitempty"`
}
// TLSSpec corresponds to spec.tls in a BackendConfig, to configure
......
......@@ -400,7 +400,8 @@ BCfgs:
vclSvc.Director = &vcl.Director{
Type: vcl.GetDirectorType(
string(bcfg.Spec.Director.Type)),
Rampup: bcfg.Spec.Director.Rampup,
Rampup: bcfg.Spec.Director.Rampup,
ShardParam: bcfg.Spec.Director.ShardParam,
}
if bcfg.Spec.Director.Warmup != nil {
vclSvc.Director.Warmup =
......
......@@ -132,9 +132,10 @@ func GetDirectorType(dirStr string) DirectorType {
// Director is derived from spec.director in a BackendConfig, and allows
// for some choice of the director, and sets some parameters.
type Director struct {
Rampup string
Warmup float64
Type DirectorType
Rampup string
Warmup float64
Type DirectorType
ShardParam string
}
func (dir Director) hash(hash hash.Hash) {
......@@ -144,6 +145,7 @@ func (dir Director) hash(hash hash.Hash) {
binary.BigEndian.PutUint64(wBytes, w64)
hash.Write(wBytes)
hash.Write([]byte{byte(dir.Type)})
hash.Write([]byte(dir.ShardParam))
}
// NameTTLFrom is a enumeration of the ways that the name TTL that was
......
......@@ -108,6 +108,7 @@ backend vk8s_tea-svc_192_0_2_3_80 {
sub vcl_init {
new caffeine = directors.shard_param();
new vk8s_coffee-svc_director = directors.random();
vk8s_coffee-svc_director.add_backend(vk8s_coffee-svc_192_0_2_4_80
, 1.0
......@@ -131,6 +132,7 @@ sub vcl_init {
);
vk8s_tea-svc_director.set_warmup(0.5);
vk8s_tea-svc_director.set_rampup(5m);
vk8s_tea-svc_director.associate(caffeine.use());
vk8s_tea-svc_director.reconfigure();
new vk8s_cafe_example_com_exactMatcher = selector.set();
......
......@@ -54,6 +54,7 @@ backend vk8s_tea-svc_192_0_2_3_80 {
sub vcl_init {
new caffeine = directors.shard_param();
new vk8s_tea-svc_director = directors.shard();
vk8s_tea-svc_director.add_backend(vk8s_tea-svc_192_0_2_1_80
);
......@@ -63,6 +64,7 @@ sub vcl_init {
);
vk8s_tea-svc_director.set_warmup(0.5);
vk8s_tea-svc_director.set_rampup(5m);
vk8s_tea-svc_director.associate(caffeine.use());
vk8s_tea-svc_director.reconfigure();
}
......
......@@ -131,6 +131,7 @@ backend vk8s_tea-svc_192_0_2_3_80 {
sub vcl_init {
new caffeine = directors.shard_param();
new vk8s_coffee-svc_director = directors.random();
vk8s_coffee-svc_director.add_backend(vk8s_coffee-svc_192_0_2_4_80
, 1.0
......@@ -154,6 +155,7 @@ sub vcl_init {
);
vk8s_tea-svc_director.set_warmup(0.5);
vk8s_tea-svc_director.set_rampup(5m);
vk8s_tea-svc_director.associate(caffeine.use());
vk8s_tea-svc_director.reconfigure();
new vk8s_metaxa-svc_resolver = dynamic.resolver();
......
......@@ -526,9 +526,10 @@ var teaSvcProbeDir = Service{
Threshold: "3",
},
Director: &Director{
Type: Shard,
Rampup: "5m",
Warmup: 0.5,
Type: Shard,
Rampup: "5m",
Warmup: 0.5,
ShardParam: "caffeine",
},
}
......
......@@ -126,7 +126,9 @@ backend {{backendName $svc $addr}} {
{{end}}
sub vcl_init {
{{- range $param := shardParams .IntSvcs}}
new {{$param}} = directors.shard_param();
{{- end}}
{{- range $name, $svc := .IntSvcs}}
{{- $dirType := dirType $svc}}
new {{dirName $svc}} = directors.{{$dirType}}();
......@@ -144,6 +146,10 @@ sub vcl_init {
{{- if $svc.Director.Rampup}}
{{dirName $svc}}.set_rampup({{$svc.Director.Rampup}});
{{- end}}
{{- $param := $svc.Director.ShardParam}}
{{- if $param }}
{{dirName $svc}}.associate({{$param}}.use());
{{- end }}
{{dirName $svc}}.reconfigure();
{{- end}}
{{end}}
......@@ -422,6 +428,22 @@ func needsVia(intSvcs, extSvcs map[string]Service) bool {
return false
}
func shardParams(intSvcs map[string]Service) []string {
params := []string{}
seen := make(map[string]bool)
for _, svc := range intSvcs {
if svc.Director == nil ||
svc.Director.ShardParam == "" ||
seen[svc.Director.ShardParam] {
continue
}
seen[svc.Director.ShardParam] = true
params = append(params, svc.Director.ShardParam)
}
return params
}
var vclFuncs = template.FuncMap{
"plusOne": func(i int) int { return i + 1 },
"dirType": func(svc Service) string { return dirType(svc) },
......@@ -429,6 +451,7 @@ var vclFuncs = template.FuncMap{
"backendName": backendName,
"hostMangle": hostMangle,
"needsVia": needsVia,
"shardParams": shardParams,
"pfxPattern": pfxPattern,
"pfxSorted": pfxSorted,
"pfxSvc": pfxSvc,
......
......@@ -142,6 +142,7 @@ make EXAMPLE=purge deploy verify undeploy
echo BackendConfig example
cd ${MYPATH}/../examples/backend-config/
make deploy verify undeploy
make EXAMPLE=param deploy verify undeploy
echo -sfile cache storage with StatefulSet example
cd ${MYPATH}/../examples/file-cache/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment