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: ...@@ -191,6 +191,7 @@ example:backend-config:
script: script:
- cd ../examples/backend-config - cd ../examples/backend-config
- make deploy verify undeploy - make deploy verify undeploy
- make EXAMPLE=param deploy verify undeploy
example:custom-vcl: example:custom-vcl:
extends: .integration-tests extends: .integration-tests
......
...@@ -134,6 +134,9 @@ spec: ...@@ -134,6 +134,9 @@ spec:
rampup: rampup:
type: string type: string
pattern: '^\d+(\.\d+)?(ms|[smhdwy])$' 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: tls:
type: object type: object
properties: properties:
......
...@@ -237,6 +237,10 @@ All of the properties of ``spec.director`` are optional: ...@@ -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) [``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. 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 With ``type`` you can choose the
[round-robin](https://varnish-cache.org/docs/6.3/reference/vmod_directors.generated.html#obj-round-robin), [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) [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 ...@@ -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 end of the rampup interval. This mitigates the "thundering herd" of
requests for a newly added Endpoint. 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: For example:
``` ```
...@@ -277,6 +292,7 @@ spec: ...@@ -277,6 +292,7 @@ spec:
type: shard type: shard
warmup: 50 warmup: 50
rampup: 5m rampup: 5m
shard_param: param
``` ```
For the Ingress implementation, a director is always configured, For the Ingress implementation, a director is always configured,
......
...@@ -34,18 +34,25 @@ TESTDIR=$(mkdir)/../../test ...@@ -34,18 +34,25 @@ TESTDIR=$(mkdir)/../../test
all: deploy all: deploy
deploy-helm: deploy-bcfg-helm:
@helm install viking-ingress-backend-cfg $(CHARTDIR)/viking-test-app \ @helm install viking-ingress-backend-cfg $(CHARTDIR)/viking-test-app \
--values values.yaml --values values.yaml
deploy-param-helm:
@helm install viking-ingress-shard-param $(CHARTDIR)/viking-test-app \
--values values-param.yaml
deploy-kubectl: deploy-kubectl:
@kubectl apply -f $(mkdir)/../hello/cafe-ingress.yaml @kubectl apply -f $(mkdir)/../hello/cafe-ingress.yaml
@kubectl apply -f backend-cfg.yaml @kubectl apply -f backend-cfg.yaml
@kubectl apply -f $(mkdir)/../hello/cafe.yaml @kubectl apply -f $(mkdir)/../hello/cafe.yaml
# TESTOPTS are passed to varnishtest, e.g.: make TESTOPTS=-v verify # TESTOPTS are passed to varnishtest, e.g.: make TESTOPTS=-v verify
verify: verify-bcfg:
$(mkdir)/verify.sh $(mkdir)/verify.sh cafe.vtc
verify-param:
$(mkdir)/verify.sh cafe-param.vtc
wait: wait:
$(TESTDIR)/wait.sh app=varnish-ingress $(TESTDIR)/wait.sh app=varnish-ingress
...@@ -55,19 +62,37 @@ uninstall-kubectl: ...@@ -55,19 +62,37 @@ uninstall-kubectl:
@kubectl delete -f $(mkdir)/../hello/cafe-ingress.yaml @kubectl delete -f $(mkdir)/../hello/cafe-ingress.yaml
@kubectl delete -f $(mkdir)/../hello/cafe.yaml @kubectl delete -f $(mkdir)/../hello/cafe.yaml
uninstall-helm: uninstall-bcfg-helm:
@helm uninstall viking-ingress-backend-cfg @helm uninstall viking-ingress-backend-cfg
uninstall-param-helm:
@helm uninstall viking-ingress-shard-param
undeploy-kubectl: uninstall-kubectl wait 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) ifeq ($(DEPLOY),kubectl)
deploy: deploy-kubectl deploy: deploy-kubectl
undeploy: undeploy-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 else
deploy: deploy-helm deploy: deploy-bcfg
undeploy: undeploy-helm undeploy: undeploy-bcfg
verify: verify-bcfg
endif endif
.PHONY: all $(MAKECMDGOALS) .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 #! /bin/bash -ex
MYDIR=$(dirname ${BASH_SOURCE[0]}) MYDIR=$(dirname ${BASH_SOURCE[0]})
VTC=$1
source ${MYDIR}/../../test/utils.sh source ${MYDIR}/../../test/utils.sh
LOCALPORT=${LOCALPORT:-8888} LOCALPORT=${LOCALPORT:-8888}
...@@ -15,4 +16,4 @@ kubectl port-forward svc/varnish-ingress ${LOCALPORT}:80 >/dev/null & ...@@ -15,4 +16,4 @@ kubectl port-forward svc/varnish-ingress ${LOCALPORT}:80 >/dev/null &
trap 'kill $(jobs -p)' EXIT trap 'kill $(jobs -p)' EXIT
wait_for_port ${LOCALPORT} wait_for_port ${LOCALPORT}
varnishtest ${TESTOPTS} -Dlocalport=${LOCALPORT} cafe.vtc varnishtest ${TESTOPTS} -Dlocalport=${LOCALPORT} ${VTC}
...@@ -502,9 +502,10 @@ const ( ...@@ -502,9 +502,10 @@ const (
// DirectorSpec corresponds to spec.director in a BackendConfig, and // DirectorSpec corresponds to spec.director in a BackendConfig, and
// allows for a choice of directors, and some parameters. // allows for a choice of directors, and some parameters.
type DirectorSpec struct { type DirectorSpec struct {
Type DirectorType `json:"type,omitempty"` Type DirectorType `json:"type,omitempty"`
Warmup *int32 `json:"warmup,omitempty"` Warmup *int32 `json:"warmup,omitempty"`
Rampup string `json:"rampup,omitempty"` Rampup string `json:"rampup,omitempty"`
ShardParam string `json:"shard_param,omitempty"`
} }
// TLSSpec corresponds to spec.tls in a BackendConfig, to configure // TLSSpec corresponds to spec.tls in a BackendConfig, to configure
......
...@@ -400,7 +400,8 @@ BCfgs: ...@@ -400,7 +400,8 @@ BCfgs:
vclSvc.Director = &vcl.Director{ vclSvc.Director = &vcl.Director{
Type: vcl.GetDirectorType( Type: vcl.GetDirectorType(
string(bcfg.Spec.Director.Type)), 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 { if bcfg.Spec.Director.Warmup != nil {
vclSvc.Director.Warmup = vclSvc.Director.Warmup =
......
...@@ -132,9 +132,10 @@ func GetDirectorType(dirStr string) DirectorType { ...@@ -132,9 +132,10 @@ func GetDirectorType(dirStr string) DirectorType {
// Director is derived from spec.director in a BackendConfig, and allows // Director is derived from spec.director in a BackendConfig, and allows
// for some choice of the director, and sets some parameters. // for some choice of the director, and sets some parameters.
type Director struct { type Director struct {
Rampup string Rampup string
Warmup float64 Warmup float64
Type DirectorType Type DirectorType
ShardParam string
} }
func (dir Director) hash(hash hash.Hash) { func (dir Director) hash(hash hash.Hash) {
...@@ -144,6 +145,7 @@ func (dir Director) hash(hash hash.Hash) { ...@@ -144,6 +145,7 @@ func (dir Director) hash(hash hash.Hash) {
binary.BigEndian.PutUint64(wBytes, w64) binary.BigEndian.PutUint64(wBytes, w64)
hash.Write(wBytes) hash.Write(wBytes)
hash.Write([]byte{byte(dir.Type)}) hash.Write([]byte{byte(dir.Type)})
hash.Write([]byte(dir.ShardParam))
} }
// NameTTLFrom is a enumeration of the ways that the name TTL that was // 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 { ...@@ -108,6 +108,7 @@ backend vk8s_tea-svc_192_0_2_3_80 {
sub vcl_init { sub vcl_init {
new caffeine = directors.shard_param();
new vk8s_coffee-svc_director = directors.random(); new vk8s_coffee-svc_director = directors.random();
vk8s_coffee-svc_director.add_backend(vk8s_coffee-svc_192_0_2_4_80 vk8s_coffee-svc_director.add_backend(vk8s_coffee-svc_192_0_2_4_80
, 1.0 , 1.0
...@@ -131,6 +132,7 @@ sub vcl_init { ...@@ -131,6 +132,7 @@ sub vcl_init {
); );
vk8s_tea-svc_director.set_warmup(0.5); vk8s_tea-svc_director.set_warmup(0.5);
vk8s_tea-svc_director.set_rampup(5m); vk8s_tea-svc_director.set_rampup(5m);
vk8s_tea-svc_director.associate(caffeine.use());
vk8s_tea-svc_director.reconfigure(); vk8s_tea-svc_director.reconfigure();
new vk8s_cafe_example_com_exactMatcher = selector.set(); new vk8s_cafe_example_com_exactMatcher = selector.set();
......
...@@ -54,6 +54,7 @@ backend vk8s_tea-svc_192_0_2_3_80 { ...@@ -54,6 +54,7 @@ backend vk8s_tea-svc_192_0_2_3_80 {
sub vcl_init { sub vcl_init {
new caffeine = directors.shard_param();
new vk8s_tea-svc_director = directors.shard(); new vk8s_tea-svc_director = directors.shard();
vk8s_tea-svc_director.add_backend(vk8s_tea-svc_192_0_2_1_80 vk8s_tea-svc_director.add_backend(vk8s_tea-svc_192_0_2_1_80
); );
...@@ -63,6 +64,7 @@ sub vcl_init { ...@@ -63,6 +64,7 @@ sub vcl_init {
); );
vk8s_tea-svc_director.set_warmup(0.5); vk8s_tea-svc_director.set_warmup(0.5);
vk8s_tea-svc_director.set_rampup(5m); vk8s_tea-svc_director.set_rampup(5m);
vk8s_tea-svc_director.associate(caffeine.use());
vk8s_tea-svc_director.reconfigure(); vk8s_tea-svc_director.reconfigure();
} }
......
...@@ -131,6 +131,7 @@ backend vk8s_tea-svc_192_0_2_3_80 { ...@@ -131,6 +131,7 @@ backend vk8s_tea-svc_192_0_2_3_80 {
sub vcl_init { sub vcl_init {
new caffeine = directors.shard_param();
new vk8s_coffee-svc_director = directors.random(); new vk8s_coffee-svc_director = directors.random();
vk8s_coffee-svc_director.add_backend(vk8s_coffee-svc_192_0_2_4_80 vk8s_coffee-svc_director.add_backend(vk8s_coffee-svc_192_0_2_4_80
, 1.0 , 1.0
...@@ -154,6 +155,7 @@ sub vcl_init { ...@@ -154,6 +155,7 @@ sub vcl_init {
); );
vk8s_tea-svc_director.set_warmup(0.5); vk8s_tea-svc_director.set_warmup(0.5);
vk8s_tea-svc_director.set_rampup(5m); vk8s_tea-svc_director.set_rampup(5m);
vk8s_tea-svc_director.associate(caffeine.use());
vk8s_tea-svc_director.reconfigure(); vk8s_tea-svc_director.reconfigure();
new vk8s_metaxa-svc_resolver = dynamic.resolver(); new vk8s_metaxa-svc_resolver = dynamic.resolver();
......
...@@ -526,9 +526,10 @@ var teaSvcProbeDir = Service{ ...@@ -526,9 +526,10 @@ var teaSvcProbeDir = Service{
Threshold: "3", Threshold: "3",
}, },
Director: &Director{ Director: &Director{
Type: Shard, Type: Shard,
Rampup: "5m", Rampup: "5m",
Warmup: 0.5, Warmup: 0.5,
ShardParam: "caffeine",
}, },
} }
......
...@@ -126,7 +126,9 @@ backend {{backendName $svc $addr}} { ...@@ -126,7 +126,9 @@ backend {{backendName $svc $addr}} {
{{end}} {{end}}
sub vcl_init { sub vcl_init {
{{- range $param := shardParams .IntSvcs}}
new {{$param}} = directors.shard_param();
{{- end}}
{{- range $name, $svc := .IntSvcs}} {{- range $name, $svc := .IntSvcs}}
{{- $dirType := dirType $svc}} {{- $dirType := dirType $svc}}
new {{dirName $svc}} = directors.{{$dirType}}(); new {{dirName $svc}} = directors.{{$dirType}}();
...@@ -144,6 +146,10 @@ sub vcl_init { ...@@ -144,6 +146,10 @@ sub vcl_init {
{{- if $svc.Director.Rampup}} {{- if $svc.Director.Rampup}}
{{dirName $svc}}.set_rampup({{$svc.Director.Rampup}}); {{dirName $svc}}.set_rampup({{$svc.Director.Rampup}});
{{- end}} {{- end}}
{{- $param := $svc.Director.ShardParam}}
{{- if $param }}
{{dirName $svc}}.associate({{$param}}.use());
{{- end }}
{{dirName $svc}}.reconfigure(); {{dirName $svc}}.reconfigure();
{{- end}} {{- end}}
{{end}} {{end}}
...@@ -422,6 +428,22 @@ func needsVia(intSvcs, extSvcs map[string]Service) bool { ...@@ -422,6 +428,22 @@ func needsVia(intSvcs, extSvcs map[string]Service) bool {
return false 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{ var vclFuncs = template.FuncMap{
"plusOne": func(i int) int { return i + 1 }, "plusOne": func(i int) int { return i + 1 },
"dirType": func(svc Service) string { return dirType(svc) }, "dirType": func(svc Service) string { return dirType(svc) },
...@@ -429,6 +451,7 @@ var vclFuncs = template.FuncMap{ ...@@ -429,6 +451,7 @@ var vclFuncs = template.FuncMap{
"backendName": backendName, "backendName": backendName,
"hostMangle": hostMangle, "hostMangle": hostMangle,
"needsVia": needsVia, "needsVia": needsVia,
"shardParams": shardParams,
"pfxPattern": pfxPattern, "pfxPattern": pfxPattern,
"pfxSorted": pfxSorted, "pfxSorted": pfxSorted,
"pfxSvc": pfxSvc, "pfxSvc": pfxSvc,
......
...@@ -142,6 +142,7 @@ make EXAMPLE=purge deploy verify undeploy ...@@ -142,6 +142,7 @@ make EXAMPLE=purge deploy verify undeploy
echo BackendConfig example echo BackendConfig example
cd ${MYPATH}/../examples/backend-config/ cd ${MYPATH}/../examples/backend-config/
make deploy verify undeploy make deploy verify undeploy
make EXAMPLE=param deploy verify undeploy
echo -sfile cache storage with StatefulSet example echo -sfile cache storage with StatefulSet example
cd ${MYPATH}/../examples/file-cache/ 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