Հե՜յ Հաբր։ Ահա գրառման թարգմանությունը.
Envoy-ը բարձր արդյունավետությամբ բաշխված պրոքսի սերվեր է (գրված է C++-ով), որը նախատեսված է առանձին ծառայությունների և հավելվածների համար, այն նաև կապի ավտոբուս է և «համընդհանուր տվյալների հարթություն», որը նախատեսված է խոշոր «ծառայողական ցանց» միկրոսերվիսային ճարտարապետությունների համար: Երբ այն ստեղծվեց, հաշվի են առնվել այն խնդիրների լուծումները, որոնք առաջացել են այնպիսի սերվերների մշակման ընթացքում, ինչպիսիք են NGINX-ը, HAProxy-ը, ապարատային բեռների հավասարակշռողները և ամպային բեռի հավասարակշռողները: Envoy-ն աշխատում է յուրաքանչյուր հավելվածի հետ և վերացում է ցանցը՝ անկախ հարթակից ընդհանուր ֆունկցիոնալություն ապահովելու համար: Երբ ենթակառուցվածքում սպասարկման ողջ երթևեկությունն անցնում է Envoy ցանցով, հեշտ է դառնում պատկերացնել խնդրահարույց տարածքները՝ հետևողական դիտարկման, ընդհանուր կատարողականությունը կարգավորելու և կոնկրետ վայրում հիմնական գործառույթների ավելացման միջոցով:
· ¶ R'RѕR RјRѕR RЅRѕSЃS, Fe
- Գործընթացից դուրս ճարտարապետություն. envoy-ը ինքնուրույն, բարձր արդյունավետությամբ սերվեր է, որը խլում է քիչ RAM: Այն աշխատում է ցանկացած հավելվածի լեզվի կամ շրջանակի հետ համատեղ:
- http/2 և grpc աջակցություն. envoy-ն ունի բարձրակարգ http/2 և grpc աջակցություն ինչպես մուտքային, այնպես էլ ելքային կապերի համար: Այն թափանցիկ պրոքսի է http/1.1-ից մինչև http/2:
- Ընդլայնված ծանրաբեռնվածության հավասարակշռում. բանագնացը աջակցում է բեռների հավասարակշռման առաջադեմ գործառույթներ, ներառյալ ավտոմատ կրկնվող փորձերը, շղթայի դադարեցումը, գլոբալ տոկոսադրույքի սահմանափակումը, հարցումների ստվերումը, գոտիների տեղական բեռների հավասարակշռումը և այլն:
- Կազմաձևման կառավարման API. envoy-ն ապահովում է հզոր API՝ իր կազմաձևումը դինամիկ կառավարելու համար:
- Դիտորդականություն. L7 տրաֆիկի խորը դիտելիություն, բաշխված հետագծման բնիկ աջակցություն և mongodb, dynamodb և շատ այլ հավելվածների դիտելիություն:
Քայլ 1 — Օրինակ NGINX Config
Այս սցենարը օգտագործում է հատուկ մշակված ֆայլ nginx.conf, հիմնվելով ամբողջական օրինակի վրա
Նախնական nginx կոնֆիգուրացիա
user www www;
pid /var/run/nginx.pid;
worker_processes 2;
events {
worker_connections 2000;
}
http {
gzip on;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types text/plain;
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
log_format download '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$http_range" "$sent_http_content_range"';
upstream targetCluster {
172.18.0.3:80;
172.18.0.4:80;
}
server {
listen 8080;
server_name one.example.com www.one.example.com;
access_log /var/log/nginx.access_log main;
error_log /var/log/nginx.error_log info;
location / {
proxy_pass http://targetCluster/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
NGINX կոնֆիգուրացիաները սովորաբար ունեն երեք հիմնական տարր.
- NGINX սերվերի, գրանցման կառուցվածքի և Gzip գործառույթի կարգավորում: Սա սահմանվում է գլոբալ բոլոր դեպքերում:
- NGINX-ի կարգավորում՝ հոսթին հարցումներ ընդունելու համար one.example.com 8080 նավահանգստում:
- Թիրախային տեղադրության կարգավորում, ինչպես վարվել URL-ի տարբեր մասերի համար տրաֆիկի հետ:
Ոչ բոլոր կոնֆիգուրացիան կկիրառվի Envoy Proxy-ի վրա, և ձեզ հարկավոր չէ կարգավորել որոշ կարգավորումներ: Բանագնաց վստահված անձը ունի չորս հիմնական տեսակներ, որոնք աջակցում են NGINX-ի կողմից առաջարկվող հիմքում ընկած ենթակառուցվածքին: Միջուկը հետևյալն է.
- Լսողներ. Նրանք սահմանում են, թե ինչպես է Envoy Proxy-ն ընդունում մուտքային հարցումները: Envoy Proxy-ը ներկայումս աջակցում է միայն TCP-ի վրա հիմնված լսողներին: Կապ հաստատվելուց հետո այն փոխանցվում է զտիչին` մշակման համար:
- Զտիչներ: Դրանք խողովակաշարի ճարտարապետության մի մասն են, որը կարող է մշակել մուտքային և ելքային տվյալները: Այս ֆունկցիոնալությունը ներառում է այնպիսի զտիչներ, ինչպիսին է Gzip-ը, որը սեղմում է տվյալները նախքան դրանք հաճախորդին ուղարկելը:
- Ուղղորդիչներ: Նրանք երթևեկությունը վերահղում են դեպի ցանկալի նպատակակետ, որը սահմանվում է որպես կլաստեր:
- Կլաստերներ: Նրանք սահմանում են երթևեկության և կազմաձևման ընտրանքների վերջնակետը:
Մենք կօգտագործենք այս չորս բաղադրիչները՝ Envoy Proxy-ի կոնֆիգուրացիա ստեղծելու համար, որը կհամապատասխանի կոնկրետ NGINX կոնֆիգուրացիան: Envoy-ի նպատակը API-ի աշխատանքն է և դինամիկ կոնֆիգուրացիան: Այս դեպքում բազային կոնֆիգուրացիան կօգտագործի NGINX-ի ստատիկ, կոշտ կոդավորված տարբերակները:
Քայլ 2 — NGINX կոնֆիգուրացիա
Առաջին մասը nginx.conf սահմանում է որոշ NGINX ներքին տարրեր, որոնք պետք է կազմաձևվեն:
Աշխատողների կապեր
Ստորև բերված կոնֆիգուրացիան որոշում է աշխատողների գործընթացների և կապերի քանակը: Սա ցույց է տալիս, թե ինչպես է NGINX-ը մասշտաբավորվելու պահանջարկը բավարարելու համար:
worker_processes 2;
events {
worker_connections 2000;
}
Envoy Proxy-ն կառավարում է աշխատանքային հոսքերը և կապերը տարբեր ձևերով:
Envoy-ը ստեղծում է աշխատանքային շարանը համակարգի յուրաքանչյուր ապարատային թելի համար: Յուրաքանչյուր աշխատանքային շարանը կատարում է ոչ արգելափակող իրադարձությունների հանգույց, որը պատասխանատու է
- Լսելով յուրաքանչյուր լսողի (լսողի)
- Նոր կապերի ընդունում
- Ստեղծեք ֆիլտրի հավաքածու միացման համար
- Միացման ողջ ընթացքում I/O բոլոր գործողությունների մշակում:
Կապի հետագա ողջ մշակումն ամբողջությամբ իրականացվում է աշխատանքային շղթայում, ներառյալ փոխանցման ցանկացած վարքագիծ:
Էնվոյում աշխատող յուրաքանչյուր թելի համար լողավազանում միացում կա: Այսպիսով, HTTP/2 կապի լողավազանները միաժամանակ հաստատում են միայն մեկ կապ յուրաքանչյուր արտաքին հոսթի համար, չորս աշխատանքային թելերով, յուրաքանչյուր արտաքին հոսթի համար կլինի չորս HTTP/2 կապ կայուն վիճակում: Ամեն ինչ պահելով մեկ աշխատանքային շղթայի վրա, գրեթե բոլոր ծածկագրերը կարող են գրվել առանց բլոկների, կարծես այն մեկ շղթայված է: Եթե ավելի շատ աշխատանքային թելեր հատկացվեն, քան անհրաժեշտ է, դա կարող է հանգեցնել հիշողության վատթարացման, ստեղծելով մեծ թվով անգործուն միացումներ և նվազեցնելով կապի վերադարձի քանակը դեպի լողավազան:
Լրացուցիչ տեղեկությունների համար այցելեք
HTTP կոնֆիգուրացիա
Հետևյալ NGINX կազմաձևման բլոկը սահմանում է HTTP պարամետրեր, ինչպիսիք են.
- Մնջախաղի որ տեսակներն են աջակցվում
- Կանխադրված ժամանակամիջոցներ
- Gzip կոնֆիգուրացիա
Դուք կարող եք հարմարեցնել այս ասպեկտները Envoy Proxy-ի զտիչներով, որոնք մենք կքննարկենք ավելի ուշ:
Քայլ 3 - Սերվերի կազմաձևում
HTTP կազմաձևման բլոկում NGINX կոնֆիգուրացիան սահմանում է լսել 8080 նավահանգիստը և պատասխանել տիրույթների մուտքային հարցումներին: one.example.com и www.one.example.com.
server {
listen 8080;
server_name one.example.com www.one.example.com;
Inside Envoy, Listeners-ը դա կառավարում է:
Պատգամավոր ունկնդիրներ
Envoy Proxy-ի հետ սկսելու ամենակարևոր ասպեկտը ունկնդիրների սահմանումն է: Դուք պետք է ստեղծեք կազմաձևման ֆայլ, որը նկարագրում է, թե ինչպես եք ցանկանում գործարկել Envoy օրինակը:
Ստորև բերված հատվածը կստեղծի նոր լսող և կկապի այն 8080 պորտին: Կազմաձևը ցույց է տալիս Envoy Proxy-ին, թե որ նավահանգիստներին պետք է միացված լինի մուտքային հարցումների համար:
Envoy Proxy-ն իր կազմաձևման համար օգտագործում է YAML նշում: Այս նշագրման ներածության համար տե՛ս այստեղ
Copy to Editorstatic_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
Սահմանելու կարիք չկա server_name, քանի որ Envoy Proxy ֆիլտրերը կկարգավորեն դա:
Քայլ 4 — Տեղադրության կարգավորում
Երբ հարցումը հասնում է NGINX-ին, տեղորոշման բլոկը որոշում է, թե ինչպես վարվել և որտեղ ուղղորդել երթևեկությունը: Հետևյալ հատվածում ամբողջ տրաֆիկը դեպի կայք փոխանցվում է վերին հոսանքին (թարգմանչի նշում. վերին հոսանքը սովորաբար հավելվածի սերվեր է) անունով կլաստերին: targetCluster. Վերին հոսքի կլաստերը սահմանում է այն հանգույցները, որոնք պետք է մշակեն հարցումը: Սա կքննարկենք հաջորդ քայլում։
location / {
proxy_pass http://targetCluster/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
Envoy-ում սա այն է, ինչ անում է Filters-ը:
Բանագնաց զտիչներ
Ստատիկ կազմաձևման համար զտիչները որոշում են, թե ինչպես են մշակվում մուտքային հարցումները: Այս դեպքում մենք սահմանում ենք համապատասխան զտիչներ սերվերի_անուններ նախորդ քայլում. Երբ մուտքային հարցումները գալիս են, որոնք համընկնում են որոշակի տիրույթների և երթուղիների հետ, երթևեկությունը ուղղորդվում է դեպի կլաստեր: Սա NGINX վերին հոսքի կոնֆիգուրացիայի համարժեքն է:
Copy to Editor filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains:
- "one.example.com"
- "www.one.example.com"
routes:
- match:
prefix: "/"
route:
cluster: targetCluster
http_filters:
- name: envoy.router
անուն բանագնաց.http_connection_manager Envoy Proxy-ում ներկառուցված զտիչ է: Այլ զտիչներ ներառում են Redis, Մոնո, TCP. Ամբողջական ցանկը կարող եք գտնել այստեղ
Բեռի հավասարակշռման այլ քաղաքականության մասին լրացուցիչ տեղեկությունների համար այցելեք
Քայլ 5 - վստահված անձի և վերին հոսքի կոնֆիգուրացիա
NGINX-ում վերին հոսքի կոնֆիգուրացիան սահմանում է թիրախային սերվերների մի շարք, որոնք կմշակեն տրաֆիկը: Այս դեպքում նշանակվել է երկու կլաստեր։
upstream targetCluster {
172.18.0.3:80;
172.18.0.4:80;
}
Envoy-ում դա կառավարվում է կլաստերների կողմից:
Բանագնաց Կլաստերներ
Վերին հոսքի համարժեքը սահմանվում է որպես կլաստերներ: Այս դեպքում սահմանվել են այն հոսթները, որոնք կսպասարկեն երթեւեկությունը։ Այն, թե ինչպես են հոսթինգները մուտք գործելու, օրինակ՝ ժամանակի ավարտը, սահմանվում է որպես կլաստերի կազմաձևում: Սա թույլ է տալիս ավելի լավ վերահսկել այնպիսի ասպեկտների հատիկությունը, ինչպիսիք են ուշացումը և բեռի հավասարակշռումը:
Copy to Editor clusters:
- name: targetCluster
connect_timeout: 0.25s
type: STRICT_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
hosts: [
{ socket_address: { address: 172.18.0.3, port_value: 80 }},
{ socket_address: { address: 172.18.0.4, port_value: 80 }}
]
Ծառայությունների հայտնաբերումն օգտագործելիս STRICT_DNS Բանագնացը շարունակաբար և ասինխրոն կերպով կլուծի նշված DNS թիրախները: DNS արդյունքից յուրաքանչյուր վերադարձված IP հասցե կհամարվի բացահայտ հոսթ վերընթաց կլաստերի մեջ: Սա նշանակում է, որ եթե հարցումը վերադարձնի երկու IP հասցե, Envoy-ը կենթադրի, որ կլաստերում երկու հոսթ կա, և երկուսն էլ պետք է հավասարակշռված լինեն: Եթե հոսթինգը հեռացվի արդյունքից, Envoy-ը ենթադրում է, որ այն այլևս գոյություն չունի և կհանի երթևեկությունը գոյություն ունեցող կապի լողավազաններից:
Լրացուցիչ տեղեկությունների համար տե՛ս
Քայլ 6. Մատյան մուտք և սխալներ
Վերջնական կոնֆիգուրացիան գրանցումն է: Սխալների մատյանները սկավառակի վրա մղելու փոխարեն, Envoy Proxy-ն ընդունում է ամպի վրա հիմնված մոտեցում: Բոլոր հավելվածների տեղեկամատյանները թողարկվում են stdout и stderr.
Երբ օգտվողները հարցում են կատարում, մուտքի մատյանները կամընտիր են և անջատված են լռելյայնորեն: HTTP հարցումների համար մուտքի մատյանները միացնելու համար միացրեք կազմաձևը access_log HTTP կապի կառավարչի համար: Ուղին կարող է լինել կամ այնպիսի սարք, ինչպիսին է stdout, կամ ֆայլ սկավառակի վրա՝ կախված ձեր պահանջներից:
Հետևյալ կոնֆիգուրացիան կվերահղորդի մուտքի բոլոր մատյանները դեպի stdout (Թարգմանչի նշում. stdout-ը պահանջվում է դոկերի ներսում envoy օգտագործելու համար: Եթե օգտագործվում է առանց docker-ի, ապա փոխարինեք /dev/stdout-ը սովորական log ֆայլի ուղով): Պատճենեք հատվածը կապի կառավարչի կազմաձևման բաժնում.
Copy to Clipboardaccess_log:
- name: envoy.file_access_log
config:
path: "/dev/stdout"
Արդյունքները պետք է նման լինեն հետևյալին.
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
access_log:
- name: envoy.file_access_log
config:
path: "/dev/stdout"
route_config:
Լռելյայնորեն, Envoy-ն ունի ձևաչափի տող, որը ներառում է HTTP հարցումի մանրամասները.
[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"n
Այս ձևաչափի տողի արդյունքը հետևյալն է.
[2018-11-23T04:51:00.281Z] "GET / HTTP/1.1" 200 - 0 58 4 1 "-" "curl/7.47.0" "f21ebd42-6770-4aa5-88d4-e56118165a7d" "one.example.com" "172.18.0.4:80"
Ելքային բովանդակությունը կարող է հարմարեցվել՝ սահմանելով ձևաչափի դաշտը: Օրինակ:
access_log:
- name: envoy.file_access_log
config:
path: "/dev/stdout"
format: "[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"n"
Մատյան գիծը կարող է նաև դուրս գալ JSON ձևաչափով՝ դաշտը դնելով json_format. Օրինակ `
access_log:
- name: envoy.file_access_log
config:
path: "/dev/stdout"
json_format: {"protocol": "%PROTOCOL%", "duration": "%DURATION%", "request_method": "%REQ(:METHOD)%"}
Բանագնաց գրանցման մեթոդաբանության մասին լրացուցիչ տեղեկությունների համար այցելեք
Մուտքագրումը միակ միջոցը չէ Envoy Proxy-ի հետ աշխատելու զգացում ստանալու համար: Այն ունի ներկառուցված առաջադեմ հետագծում և չափումներ: Դուք կարող եք ավելին իմանալ այստեղ
Քայլ 7 - Գործարկում
Այժմ դուք կոնֆիգուրացիան տեղափոխել եք NGINX-ից Envoy Proxy: Վերջին քայլը Envoy Proxy-ի օրինակ գործարկելն է՝ այն փորձարկելու համար:
Գործարկել որպես օգտվող
NGINX կազմաձևման գծի վերևում օգտվող www www; ցույց է տալիս, որ NGINX-ը աշխատում է որպես ցածր արտոնություններ ունեցող օգտվող՝ բարելավելու անվտանգությունը:
Envoy Proxy-ն օգտագործում է ամպի վրա հիմնված մոտեցում՝ կառավարելու, թե ով է տիրապետում գործընթացին: Երբ մենք գործարկում ենք Envoy Proxy-ը կոնտեյներով, մենք կարող ենք նշել ցածր արտոնություններ ունեցող օգտվող:
Գործարկեք Envoy Proxy-ը
Ստորև բերված հրամանը կգործարկի Envoy Proxy-ը հյուրընկալողի Docker կոնտեյների միջոցով: Այս հրամանը Envoy-ին հնարավորություն է տալիս լսել մուտքային հարցումները 80-րդ նավահանգստում: Այնուամենայնիվ, ինչպես նշված է լսողի կազմաձևում, Envoy Proxy-ը լսում է մուտքային տրաֆիկը 8080 նավահանգստում: Սա թույլ է տալիս գործընթացը գործարկել որպես ցածր արտոնություններ ունեցող օգտվող:
docker run --name proxy1 -p 80:8080 --user 1000:1000 -v /root/envoy.yaml:/etc/envoy/envoy.yaml envoyproxy/envoy
Փորձարկում
Գործող վստահված անձի դեպքում թեստերն այժմ կարող են կատարվել և մշակվել: Հետևյալ cURL հրամանը հարցում է ուղարկում վստահված անձի կազմաձևում սահմանված հյուրընկալող վերնագրի հետ:
curl -H "Host: one.example.com" localhost -i
HTTP հարցումը կհանգեցնի սխալի 503. Դա պայմանավորված է նրանով, որ հոսանքին հակառակ միացումները չեն աշխատում և հասանելի չեն: Այսպիսով, Envoy Proxy-ն չունի հասանելի թիրախային ուղղություններ հարցումների համար: Հետևյալ հրամանը կսկսի HTTP ծառայությունների մի շարք, որոնք համապատասխանում են Envoy-ի համար սահմանված կազմաձևերին:
docker run -d katacoda/docker-http-server; docker run -d katacoda/docker-http-server;
Հասանելի ծառայությունների միջոցով Envoy-ը կարող է հաջողությամբ ապահովել վստահված երթևեկությունը դեպի իր նպատակակետը:
curl -H "Host: one.example.com" localhost -i
Դուք պետք է տեսնեք պատասխան, որը ցույց է տալիս, թե որ Docker կոնտեյներն է մշակել հարցումը: Envoy Proxy-ի տեղեկամատյաններում դուք պետք է տեսնեք նաև մուտքի տողը տպված:
Լրացուցիչ HTTP արձագանքման վերնագրեր (HTTP պատասխան)
Դուք կտեսնեք լրացուցիչ HTTP վերնագրեր վավեր հարցման պատասխանների վերնագրերում: Վերնագիրը ցույց է տալիս այն ժամանակը, որ հոսանքի հոսանքը ծախսել է հարցումը մշակելու համար: Արտահայտված միլիվայրկյաններով: Սա օգտակար է, եթե հաճախորդը ցանկանում է որոշել ծառայության ժամանակը ցանցի հետաձգման համեմատ:
x-envoy-upstream-service-time: 0
server: envoy
Վերջնական կազմաձևում
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains:
- "one.example.com"
- "www.one.example.com"
routes:
- match:
prefix: "/"
route:
cluster: targetCluster
http_filters:
- name: envoy.router
clusters:
- name: targetCluster
connect_timeout: 0.25s
type: STRICT_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
hosts: [
{ socket_address: { address: 172.18.0.3, port_value: 80 }},
{ socket_address: { address: 172.18.0.4, port_value: 80 }}
]
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9090 }
Լրացուցիչ տեղեկություններ թարգմանչից
Envoy Proxy-ի տեղադրման հրահանգները կարելի է գտնել կայքում
Լռելյայնորեն պտույտ/րոպեում systemd ծառայության կոնֆիգուրացիա չկա:
Ավելացնել systemd ծառայության կոնֆիգուրացիա /etc/systemd/system/envoy.service:
[Unit]
Description=Envoy Proxy
Documentation=https://www.envoyproxy.io/
After=network-online.target
Requires=envoy-auth-server.service
Wants=nginx.service
[Service]
User=root
Restart=on-failure
ExecStart=/usr/bin/envoy --config-path /etc/envoy/config.yaml
[Install]
WantedBy=multi-user.target
Դուք պետք է ստեղծեք /etc/envoy/ գրացուցակը և տեղադրեք config.yaml config-ը։
Բանագնաց վստահված անձի համար հեռագրային զրույց կա.
Envoy Proxy-ը չի աջակցում ստատիկ բովանդակության սպասարկում: Այսպիսով, ով կարող է քվեարկել մի հատկանիշի օգտին.
Հարցմանը կարող են մասնակցել միայն գրանցված օգտվողները։
Արդյո՞ք այս գրառումը խրախուսեց ձեզ տեղադրել և փորձարկել դեսպանորդի վստահված անձը:
-
այո
-
ոչ
Քվեարկել է 75 օգտատեր։ 18 օգտատեր ձեռնպահ է մնացել։
Source: www.habr.com