рдХреЕрдирд░реА рдбрд┐рдкреНрд▓реЙрдпрдореЗрдВрдЯ рд▓рд╛рдБрдЪ рдЖрдгрд┐ рд╡реНрд╣рд┐рдЬреНрдпреБрдЕрд▓рд╛рдЗрдЬ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА Istio+Kiali рд╡рд╛рдкрд░рдгреЗ
рдпрд╛ рдорд╛рд▓рд┐рдХреЗрддреАрд▓ рд▓реЗрдЦ
рдХреБрдмрд░реНрдиреЗрдЯреНрд╕ #1 рдордзреНрдпреЗ рдХреЕрдирд░реА рддреИрдирд╛рддреА: рдЧрд┐рдЯрд▓реЕрдм рд╕реАрдЖрдп рдХреБрдмрд░реНрдиреЗрдЯреНрд╕ #2 рдордзреНрдпреЗ рдХреЕрдирд░реА рддреИрдирд╛рддреА: рдЕрд░реНрдЧреЛ рд░реЛрд▓рдЖрдЙрдЯреНрд╕ - (рд╣рд╛ рд▓реЗрдЦ)
- рдЬреЗрдирдХрд┐рдиреНрд╕-рдПрдХреНрд╕ рдЗрд╕реНрдЯрд┐рдУ рдлреНрд▓реЕрдЧрд░ рд╡рд╛рдкрд░реВрди рдХреЕрдирд░реА рдЙрдкрдпреЛрдЬрди
рдХреЕрдирд░реА рдЙрдкрдпреЛрдЬрди
рдЖрдореНрд╣рд╛рд▓рд╛ рдЖрд╢рд╛ рдЖрд╣реЗ рдХреА рддреБрдореНрд╣реА рд╡рд╛рдЪрд╛рд▓
рдЗрд╕реНрдЯрд┐рдУ
рдЖрдгрд┐ рдЖрдореНрд╣реА рдЕрд╕реЗ рдЧреГрд╣реАрдд рдзрд░рддреЛ рдХреА рд╣рд╛ рд▓реЗрдЦ рд╡рд╛рдЪреВрди рддреБрдореНрд╣рд╛рд▓рд╛ рдЖрдзреАрдЪ рдорд╛рд╣рд┐рдд рдЖрд╣реЗ рдХреА Istio рдХрд╛рдп рдЖрд╣реЗ. рдирд╕рд▓реНрдпрд╛рд╕, рдЖрдкрдг рдпрд╛рдмрджреНрджрд▓ рд╡рд╛рдЪреВ рд╢рдХрддрд╛
рдЪрд╛рдЪрдгреНрдпрд╛рдВрд╕рд╛рдареА рдЕрд░реНрдЬ
рдкреНрд░рддреНрдпреЗрдХ рдкреЙрдбрдордзреНрдпреЗ рджреЛрди рдХрдВрдЯреЗрдирд░ рдЕрд╕рддрд╛рдд: рдЖрдордЪрд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдЖрдгрд┐ istio-proxy.
рдЖрдореНрд╣реА рдлреНрд░рдВрдЯрдПрдВрдб-nginx рдЖрдгрд┐ рдмреЕрдХрдПрдВрдб рдкрд╛рдпрдерди рдкреЙрдбрд╕рд╣ рдПрдХ рд╕рд╛рдзрд╛ рдЪрд╛рдЪрдгреА рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд╛рдкрд░реВ. nginx рдкреЙрдб рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рдирдВрддреАрд▓рд╛ рдмреЕрдХрдПрдВрдб рдкреЙрдбрд╡рд░ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░реЗрд▓ рдЖрдгрд┐ рдкреНрд░реЙрдХреНрд╕реА рдореНрд╣рдгреВрди рдХрд╛рд░реНрдп рдХрд░реЗрд▓. рддрдкрд╢реАрд▓ рдЦрд╛рд▓реАрд▓ рдпрдорд▓реНрд╕рдордзреНрдпреЗ рдЖрдврд│реВ рд╢рдХрддрд╛рдд:
рдЪрд╛рдЪрдгреА рдЕрд░реНрдЬ рд╕реНрд╡рддрдГ рдЪрд╛рд▓рд╡рдгреЗ
рдЬрд░ рддреБрдореНрд╣рд╛рд▓рд╛ рдорд╛рдЭреНрдпрд╛ рдЙрджрд╛рд╣рд░рдгрд╛рдЪреЗ рдЕрдиреБрд╕рд░рдг рдХрд░рд╛рдпрдЪреЗ рдЕрд╕реЗрд▓ рдЖрдгрд┐ рд╣рд╛ рдЪрд╛рдЪрдгреА рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╕реНрд╡рддрдГ рд╡рд╛рдкрд░рд╛рдпрдЪрд╛ рдЕрд╕реЗрд▓ рддрд░ рдкрд╣рд╛
рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдЙрдкрдпреЛрдЬрди
рдЬреЗрд╡реНрд╣рд╛ рдЖрдореНрд╣реА рдкрд╣рд┐рд▓реА рддреИрдирд╛рддреА рд▓рд╛рдБрдЪ рдХрд░рддреЛ, рддреЗрд╡реНрд╣рд╛ рдЖрдореНрд╣реА рдкрд╛рд╣рддреЛ рдХреА рдЖрдордЪреНрдпрд╛ рдНрдкреНрд▓рд┐рдХреЗрд╢рдирдЪреНрдпрд╛ рдкреЙрдбреНрд╕рдордзреНрдпреЗ рдлрдХреНрдд 2 рдХрдВрдЯреЗрдирд░ рдЖрд╣реЗрдд, рдореНрд╣рдгрдЬреЗ, Istio sidecar рдиреБрдХрддреЗрдЪ рд▓рд╛рдЧреВ рдХреЗрд▓реЗ рдЬрд╛рдд рдЖрд╣реЗ:
рдЖрдгрд┐ рдЖрдкрдг рдиреЗрдорд╕реНрдкреЗрд╕рдордзреНрдпреЗ Istio Gateway Loadbalancer рджреЗрдЦреАрд▓ рдкрд╛рд╣рддреЛ istio-system
:
рд╡рд╛рд╣рддреВрдХ рдирд┐рд░реНрдорд┐рддреА
рдЖрдореНрд╣реА рдкреБрдвреАрд▓ рдЖрдпрдкреА рдЯреНрд░реЕрдлрд┐рдХ рд╡реНрдпреБрддреНрдкрдиреНрди рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рд╡рд╛рдкрд░реВ рдЬреЗ рдлреНрд░рдВрдЯрдПрдВрдб рдкреЙрдбреНрд╕рджреНрд╡рд╛рд░реЗ рдкреНрд░рд╛рдкреНрдд рдХреЗрд▓реЗ рдЬрд╛рдИрд▓ рдЖрдгрд┐ рдмреЕрдХрдПрдВрдб рдкреЙрдбреНрд╕рд╡рд░ рдлреЙрд░рд╡рд░реНрдб рдХреЗрд▓реЗ рдЬрд╛рдИрд▓:
while true; do curl -s --resolve 'frontend.istio-test:80:35.242.202.152' frontend.istio-test; sleep 0.1; done
рдЖрдореНрд╣реА рджреЗрдЦреАрд▓ рдЬреЛрдбреВ frontend.istio-test
рдЖрдордЪреНрдпрд╛ рд╣реЛрд╕реНрдЯ рдлрд╛рдЗрд▓рд╡рд░.
Kiali рдорд╛рд░реНрдЧреЗ рдЬрд╛рд│реА рдкрд╣рд╛
рдЖрдореНрд╣реА Tracing, Grafana, Prometheus рдЖрдгрд┐ Kiali рд╕реЛрдмрдд рдЪрд╛рдЪрдгреА рдНрдкреНрд▓рд┐рдХреЗрд╢рди рдЖрдгрд┐ Istio рдЗрдВрд╕реНрдЯреЙрд▓ рдХреЗрд▓реЗ (рддрдкрд╢реАрд▓рд╛рдВрд╕рд╛рдареА рдЦрд╛рд▓реА рдкрд╣рд╛).
istioctl dashboard kiali # admin:admin
Kiali рдЬрд╛рд│реАрджреНрд╡рд╛рд░реЗ рд╡рд░реНрддрдорд╛рди рд░рд╣рджрд╛рд░реАрдЪреЗ рджреГрд╢реНрдпрдорд╛рди рдХрд░рддреЗ
рдЬрд╕реЗ рдЖрдкрдг рдкрд╛рд╣реВ рд╢рдХрддреЛ, резрежреж% рд░рд╣рджрд╛рд░реА рдлреНрд░рдВрдЯрдПрдВрдб рд╕реЗрд╡реЗрдХрдбреЗ рдЬрд╛рддреЗ, рдирдВрддрд░ v100 рд▓реЗрдмрд▓ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рдлреНрд░рдВрдЯрдПрдВрдб рдкреЙрдбреНрд╕рдХрдбреЗ рдЬрд╛рддреЗ, рдХрд╛рд░рдг рдЖрдореНрд╣реА рдПрдХ рд╕рд╛рдзрд╛ nginx рдкреНрд░реЙрдХреНрд╕реА рд╡рд╛рдкрд░рдд рдЖрд╣реЛрдд рдЬреЛ рдмреЕрдХрдПрдВрдб рд╕реЗрд╡реЗрдХрдбреЗ рд╡рд┐рдирдВрддреНрдпрд╛ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░рддреЛ, рдЬреНрдпрд╛рдореБрд│реЗ рддреНрдпрд╛рдВрдирд╛ рдмреЕрдХрдПрдВрдб рдкреЙрдбреНрд╕рд╡рд░ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХреЗрд▓реЗ рдЬрд╛рддреЗ. рд▓реЗрдмрд▓ v1 рд╕рд╣.
Kiali Istio рд╕рд╣ рдЙрддреНрддрдо рдХрд╛рд░реНрдп рдХрд░рддреЗ рдЖрдгрд┐ рдмреЙрдХреНрд╕реНрдб рдореЗрд╢ рд░реЗрдВрдбрд░рд┐рдВрдЧ рд╕реЛрд▓реНрдпреВрд╢рди рдкреНрд░рджрд╛рди рдХрд░рддреЗ. рдЕрддрд┐ рдЙрддреНрддрдо.
рдХреЕрдирд░реА рдЙрдкрдпреЛрдЬрди
рдЖрдордЪреНрдпрд╛ рдмреЕрдХрдПрдВрдбрдордзреНрдпреЗ рдЖрдзреАрдкрд╛рд╕реВрдирдЪ рджреЛрди k8s рдЙрдкрдпреЛрдЬрди рдЖрд╣реЗрдд, рдПрдХ v1 рд╕рд╛рдареА рдЖрдгрд┐ рдПрдХ v2 рд╕рд╛рдареА. рдЖрддрд╛ рдЖрдореНтАНрд╣рд╛рд▓рд╛ рдЗрд╕реНтАНрдЯрд┐рдУрд▓рд╛ рдард░рд╛рд╡рд┐рдХ рдЯрдХреНрдХреЗ рд╡рд┐рдирдВрддреНтАНрдпрд╛рдВрдирд╛ v2 рд╡рд░ рдлреЙрд░рд╡рд░реНрдб рдХрд░рдгреНтАНрдпрд╛рд╕рд╛рдареА рд╕рд╛рдВрдЧрд╛рд╡реЗ рд▓рд╛рдЧреЗрд▓.
рдкрд╛рдпрд░реА 1: 10%
рдЖрдгрд┐ рдЖрдореНрд╣рд╛рд▓рд╛ рдлрдХреНрдд рд╡реНрд╣рд░реНрдЪреНрдпреБрдЕрд▓ рд╕рд░реНрд╡реНрд╣рд┐рд╕рдЪреЗ рд╡рдЬрди рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░рдгреНрдпрд╛рдЪреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдЖрд╣реЗ
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: backend
namespace: default
spec:
gateways: []
hosts:
- "backend.default.svc.cluster.local"
http:
- match:
- {}
route:
- destination:
host: backend.default.svc.cluster.local
subset: v1
port:
number: 80
weight: 90
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 10
рдЖрдореНрд╣реА рдкрд╛рд╣рддреЛ рдХреА 10% рд╡рд┐рдирдВрддреНрдпрд╛ v2 рд╡рд░ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХреЗрд▓реНрдпрд╛ рдЬрд╛рддрд╛рдд.
рдкрд╛рдпрд░реА 2: 50%
рдЖрдгрд┐ рдЖрддрд╛ рддреЗ 50% рдкрд░реНрдпрдВрдд рд╡рд╛рдврд╡рдгреЗ рдкреБрд░реЗрд╕реЗ рдЖрд╣реЗ:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: backend
namespace: default
spec:
...
- destination:
host: backend.default.svc.cluster.local
subset: v1
port:
number: 80
weight: 50
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 50
рдкрд╛рдпрд░реА 3: 100%
рдЖрддрд╛ рдХреЕрдирд░реА рдЙрдкрдпреЛрдЬрди рдкреВрд░реНрдг рдорд╛рдирд▓реЗ рдЬрд╛рдК рд╢рдХрддреЗ рдЖрдгрд┐ рд╕рд░реНрд╡ рд░рд╣рджрд╛рд░реА v2 рд╡рд░ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХреЗрд▓реА рдЬрд╛рддреЗ:
рдХреЕрдирд░реА рдореЕрдиреНрдпреБрдЕрд▓реА рдЪрд╛рдЪрдгреА
рд╕рдордЬрд╛ рдЖрдореНрд╣реА рдЖрддрд╛ рд╕рд░реНрд╡ рд╡рд┐рдирдВрддреНрдпрд╛рдВрдкреИрдХреА резреж% v2 рдмреЕрдХрдПрдВрдбрд▓рд╛ рдкрд╛рдард╡рддреЛ. рд╕рд░реНрд╡рдХрд╛рд╣реА рдЖрдордЪреНрдпрд╛ рдЕрдкреЗрдХреНрд╖реЗрдкреНрд░рдорд╛рдгреЗ рдЪрд╛рд▓рддреЗ рдпрд╛рдЪреА рдЦрд╛рддреНрд░реА рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдЖрдореНрд╣реА рд╡реНрдпрдХреНрддрд┐рдЪрд▓рд┐рддрдкрдгреЗ v10 рдЪрд╛рдЪрдгреА рдХрд░реВ рдЗрдЪреНрдЫрд┐рдд рдЕрд╕рд▓реНрдпрд╛рд╕ рдХрд╛рдп?
рдЖрдореНрд╣реА HTTP рд╢реАрд░реНрд╖рд▓реЗрдЦрд╛рдВрд╡рд░ рдЖрдзрд╛рд░рд┐рдд рдПрдХ рд╡рд┐рд╢реЗрд╖ рдЬреБрд│рдгрд╛рд░реЗ рдирд┐рдпрдо рдЬреЛрдбреВ рд╢рдХрддреЛ:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: backend
namespace: default
spec:
gateways: []
hosts:
- "backend.default.svc.cluster.local"
http:
- match:
- headers:
canary:
exact: "canary-tester"
route:
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 100
- match:
- {}
route:
- destination:
host: backend.default.svc.cluster.local
subset: v1
port:
number: 80
weight: 90
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 10
рдЖрддрд╛ рдХрд░реНрд▓ рд╡рд╛рдкрд░реВрди рдЖрдореНрд╣реА рд╣реЗрдбрд░ рдкрд╛рдард╡реВрди v2 рд╡рд┐рдирдВрддреА рд╕рдХреНрддреА рдХрд░реВ рд╢рдХрддреЛ:
рд╢реАрд░реНрд╖рд▓реЗрдЦ рдирд╕рд▓реЗрд▓реНрдпрд╛ рд╡рд┐рдирдВрддреНрдпрд╛ рдЕрдЬреВрдирд╣реА 1/10 рдЧреБрдгреЛрддреНрддрд░рд╛рдиреЗ рдЪрд╛рд▓рд╡рд┐рд▓реНрдпрд╛ рдЬрд╛рддреАрд▓:
рджреЛрди рдЖрд╢реНрд░рд┐рдд рдЖрд╡реГрддреНрддреНрдпрд╛рдВрд╕рд╛рдареА рдХреЕрдирд░реА
рдЖрддрд╛ рдЖрдкрдг рддреНрдпрд╛ рдкрд░реНрдпрд╛рдпрд╛рдЪрд╛ рд╡рд┐рдЪрд╛рд░ рдХрд░реВ рдЬрд┐рдереЗ рдЖрдкрд▓реНрдпрд╛рдХрдбреЗ рдлреНрд░рдВрдЯрдПрдВрдб рдЖрдгрд┐ рдмреЕрдХрдПрдВрдб рджреЛрдиреНрд╣реАрд╕рд╛рдареА v2 рдЖрд╡реГрддреНрддреА рдЖрд╣реЗ. рджреЛрдиреНрд╣реАрд╕рд╛рдареА, рдЖрдореНрд╣реА рдирдореВрдж рдХреЗрд▓реЗ рдЖрд╣реЗ рдХреА 10% рд░рд╣рджрд╛рд░реА v2 рд╡рд░ рдЬрд╛рд╡реА:
рдЖрдореНрд╣реА рдкрд╛рд╣рддреЛ рдХреА рдлреНрд░рдВрдЯрдПрдВрдб v1 рдЖрдгрд┐ v2 рджреЛрдиреНрд╣реА рдлреЙрд░рд╡рд░реНрдб рдЯреНрд░реЕрдлрд┐рдХ 1/10 рдЖрдгрд┐ рдмреЕрдХрдПрдВрдб v1 рдЖрдгрд┐ v2 рдЪреНрдпрд╛ рдкреНрд░рдорд╛рдгрд╛рдд.
рдЬрд░ рдЖрдореНрд╣рд╛рд▓рд╛ рдлреНрд░рдВрдЯрдПрдВрдб-v2 рд╡рд░реВрди рдлрдХреНрдд рдмреЕрдХрдПрдВрдб-v2 рд╡рд░ рд░рд╣рджрд╛рд░реА рдлреЙрд░рд╡рд░реНрдб рдХрд░рд╛рдпрдЪреА рдЕрд╕реЗрд▓ рдХрд╛рд░рдг рддреА v1 рд╢реА рд╕реБрд╕рдВрдЧрдд рдирд╛рд╣реА? рд╣реЗ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА, рдЖрдореНрд╣реА рдлреНрд░рдВрдЯрдПрдВрдбрд╕рд╛рдареА 1/10 рдЧреБрдгреЛрддреНрддрд░ рд╕реЗрдЯ рдХрд░реВ, рдЬреЗ рдирд┐рдЧреЛрд╢рд┐рдПрд╢рди рд╡рд╛рдкрд░реВрди рдмреЕрдХрдПрдВрдб-v2 рд╡рд░ рдХрд╛рдп рд░рд╣рджрд╛рд░реА рдпреЗрддреЗ рд╣реЗ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рддреЗ. sourceLabels
:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: backend
namespace: default
spec:
gateways: []
hosts:
- "backend.default.svc.cluster.local"
http:
...
- match:
- sourceLabels:
app: frontend
version: v2
route:
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 100
рдкрд░рд┐рдгрд╛рдореА, рдЖрдореНрд╣рд╛рд▓рд╛ рдЖрд╡рд╢реНрдпрдХ рддреЗ рдорд┐рд│рддреЗ:
рдореЕрдиреНрдпреБрдЕрд▓ рдХреЕрдирд░реА рджреГрд╖реНрдЯрд┐рдХреЛрдирд╛рддреВрди рдлрд░рдХ
╨Т рдкрд╣рд┐рд▓рд╛ рднрд╛рдЧ рдЖрдореНрд╣реА рджреЛрди k8s рдЙрдкрдпреЛрдЬрди рд╡рд╛рдкрд░реВрди рдХреЕрдирд░реА рдЙрдкрдпреЛрдЬрди рд╡реНрдпрдХреНрддрд┐рдЪрд▓рд┐рддрдкрдгреЗ рдХреЗрд▓реЗ. рддреЗрдереЗ рдЖрдореНрд╣реА рдкреНрд░рддрд┐рдХреГрддреАрдВрдЪреА рд╕рдВрдЦреНрдпрд╛ рдмрджрд▓реВрди рд╡рд┐рдирдВрддреАрдЪреЗ рдкреНрд░рдорд╛рдг рдирд┐рдпрдВрддреНрд░рд┐рдд рдХреЗрд▓реЗ. рд╣рд╛ рджреГрд╖реНрдЯрд┐рдХреЛрди рдХрд╛рд░реНрдп рдХрд░рддреЛ, рдкрд░рдВрддреБ рддреНрдпрд╛рдд рдЧрдВрднреАрд░ рдХрдорддрд░рддрд╛ рдЖрд╣реЗрдд.
Istio рдкреНрд░рддрд┐рдХреГрддреАрдВрдЪреА рд╕рдВрдЦреНрдпрд╛ рд╡рд┐рдЪрд╛рд░рд╛рдд рди рдШреЗрддрд╛ рд╡рд┐рдирдВрддреНрдпрд╛рдВрдЪреЗ рдкреНрд░рдорд╛рдг рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдгреЗ рд╢рдХреНрдп рдХрд░рддреЗ. рдпрд╛рдЪрд╛ рдЕрд░реНрде, рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде, рдЖрдореНрд╣реА HPAs (Horizontal Pod Autoscalers) рд╡рд╛рдкрд░реВ рд╢рдХрддреЛ рдЖрдгрд┐ рдХреЕрдирд░реА рддреИрдирд╛рддреАрдЪреНрдпрд╛ рд╕рдзреНрдпрд╛рдЪреНрдпрд╛ рд╕реНрдерд┐рддреАрдиреБрд╕рд╛рд░ рдХреЙрдиреНрдлрд┐рдЧрд░ рдХрд░рдгреНрдпрд╛рдЪреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╛рд╣реА.
рдкрд░рд┐рдгрд╛рдо
Istio рдЙрддреНрдХреГрд╖реНрдЯ рдХрд╛рд░реНрдп рдХрд░рддреЗ рдЖрдгрд┐ рддреЗ Kiali рд╕реЛрдмрдд рд╡рд╛рдкрд░рдгреЗ рдЦреВрдк рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рд╕рдВрдпреЛрдЬрди рдмрдирд╡рддреЗ. рдСрдЯреЛрдореЗрд╢рди рдЖрдгрд┐ рдХреЕрдирд░реА рд╡рд┐рд╢реНрд▓реЗрд╖рдгрд╛рд╕рд╛рдареА Istio рд╕рд╣ Spinnaker рдПрдХрддреНрд░ рдХрд░рдгреЗ рд╣реЗ рдорд╛рдЭреНрдпрд╛ рд╕реНрд╡рд╛рд░рд╕реНрдпрд╛рдЪреНрдпрд╛ рдпрд╛рджреАрдд рдкреБрдвреЗ рдЖрд╣реЗ.
рд╕реНрддреНрд░реЛрдд: www.habr.com