Waxaan sameeyay kayd PyPI ii gaar ah oo aan haysto oggolaansho iyo S3. On Nginx

Maqaalkan waxaan jeclaan lahaa inaan khibradayda la wadaago NJS, turjumaan JavaScript u ah Nginx oo ay soo saartay Nginx Inc, oo qeexaya awoodaheeda ugu weyn aniga oo isticmaalaya tusaale dhab ah. NJS waa qayb ka mid ah JavaScript oo kuu ogolaanaysa inaad kordhiso shaqaynta Nginx. Su'aasha maxaad turjumaan adiga kuu gaar ah??? Dmitry Volyntsev ayaa si faahfaahsan uga jawaabay. Marka la soo koobo: NJS waa nginx-way, JavaScript-na waa horumar badan, "dhalad" iyo GC la'aan, si ka duwan Lua.

Waqti dheer ka hor…

Shaqadii iigu dambaysay, waxaan dhaxlay gitlab tiro badan oo dhuumaha motley CI/CD ah oo leh docker-compose, dind iyo waxyaabo kale oo lagu farxo, kuwaas oo lagu wareejiyay tareenada kaniko. Sawirada hore loogu isticmaalay CI waxaa loo raray qaabkoodii asalka ahaa. Si sax ah ayey u shaqeeyeen ilaa maalintii uu gitlab IP is beddelay oo CI isu beddelay bocorka. Dhibaatadu waxay ahayd in mid ka mid ah sawirada docker-ka ee ka qaybqaatay CI uu lahaa git, kaas oo jiiday modules Python iyada oo loo marayo ssh. ssh waxaad u baahan tahay fure gaar ah oo... waxay ku jirtay sawirka oo ay weheliyaan martigaliyayaasha la yaqaan. Iyo CI kasta oo ku guul darreystay khalad xaqiijinta muhiimka ah sababtoo ah is-waafajinta udhaxeysa IP-ga dhabta ah iyo kan lagu qeexay caan_hosts. Sawir cusub ayaa si deg deg ah looga soo ururiyay Dockfiles-ka jira waxaana lagu daray ikhtiyaarka StrictHostKeyChecking no. Laakiin dhadhanka xun ayaa hadhay waxaana jiray rabitaan ah in libyada loo raro kayd PyPI gaar ah. Gunno dheeri ah, ka dib markii loo beddelay PyPI gaar ah, waxay ahayd dhuumo fudud iyo sharraxaad caadi ah oo shuruudaha.txt

Doorashadii waa la sameeyay, mudane!

Waxaan ku wadnaa wax kasta oo ku jira daruuraha iyo Kubernetes, ugu dambeyntii waxaan rabnay inaan helno adeeg yar oo ahaa weel bilaa dawlad ah oo kaydinta dibadda ah. Hagaag, maadaama aan isticmaalno S3, mudnaanta ayaa la siiyay. Iyo, haddii ay suurtagal tahay, oo leh aqoonsiga gitlab (waxaad ku dari kartaa naftaada haddii loo baahdo).

Baaritaan degdeg ah oo la sameeyay ayaa keenay natiijooyin dhowr ah: s3pypi, pypicloud iyo ikhtiyaar leh "manual" abuurista faylasha html ee bagalka. Doorashadii u dambaysay lafteeda ayaa la waayay.

s3pypi: Tani waa cli loogu talagalay isticmaalka S3 martigelinta. Waxaan soo rarnaa faylasha, soo saarnaa html oo ku dhejinnaa baaldi isku mid ah. Ku habboon isticmaalka guriga.

pypicloud: Waxay u muuqatay mashruuc xiiso leh, laakiin ka dib markii aan akhriyay dukumentiyada waan niyad jabay. Inkasta oo dukumeenti wanaagsan iyo awoodda aad ku ballaarin karto si ay ugu habboonaato baahiyahaaga, dhab ahaantii waxay u soo baxday inay noqoto mid aan loo baahnayn oo ay adagtahay in la habeeyo. Sixitaanka koodka si uu ugu habboonaado hawlahaaga, marka loo eego qiyaasaha wakhtigaas, waxay qaadan lahayd 3-5 maalmood. Adeeggu sidoo kale wuxuu u baahan yahay xog-ururin. Waanu uga tagnay haddii ay dhacdo inaan wax kale helin.

Raadin qoto dheer oo dheeraad ah ayaa soo saartay cutubka Nginx, ngx_aws_auth. Natiijadii tijaabadiisu waxay ahayd XML lagu soo bandhigay browser-ka, kaas oo muujiyay waxa ku jira baaldiga S3. Ballanqaadkii ugu dambeeyay ee waqtiga baaritaanka wuxuu ahaa sanad ka hor. Kaydka ayaa u ekaa mid laga tagay.

Adigoo aadaya isha iyo akhrinta PEP-503 Waxaan xaqiiqsaday in XML loo rogi karo HTML duullimaad oo la siiyo pip. Ka dib markii aan wax yar ka gooyay Nginx iyo S3, waxaan la kulmay tusaale xaqiijinta S3 oo ku qoran JS ee Nginx. Taasi waa sida aan ula kulmay NJS.

Qaadashada tusaalahan sal ahaan, saacad ka dib waxaan ku arkay browserkaygii XML la mid ah markii la isticmaalayo ngx_aws_auth moduleka, laakiin wax walba waxay ku qornaayeen JS.

Runtii waan ka helay xalka nginx. Marka hore, dukumeenti wanaagsan iyo tusaalooyin badan, marka labaad, waxaan helnaa dhammaan wanaagga Nginx ee la shaqeynta faylalka (ka baxsan sanduuqa), marka saddexaad, qof kasta oo yaqaan sida loo qoro qaabeynta Nginx wuxuu awoodi doonaa inuu ogaado waxa ay tahay. Minimalism sidoo kale waa ii dheeri, marka la barbar dhigo Python ama Go (haddii laga soo qoro xoq), ma aha in la xuso xidhiidhka.

TL;DR 2 maalmood ka dib, nooca tijaabada ee PyPi ayaa horay loogu isticmaalay CI.

Sidee u shaqeeyaan?

Moduleka waxa lagu shubay Nginx ngx_http_js_module, oo lagu daray sawirka docker-ka rasmiga ah. Waxaan soo dejinaa qoraalkayaga anagoo adeegsanayna dardaaranka js_importqaabeynta Nginx. Shaqada waxaa lagu magacaabaa dardaaran js_content. Dardaaranka waxaa loo isticmaalaa in lagu dejiyo doorsoomayaasha js_set, taas oo u qaadanaysa dood ahaan kaliya shaqada lagu tilmaamay qoraalka. Laakiin waxaan ku fulin karnaa su'aalo hoose oo NJS ah annagoo adeegsanayna Nginx, ma aha wax XMLHttpCodsi ah. Si tan loo sameeyo, goobta u dhiganta waa in lagu daraa qaabeynta Nginx. Qoraalkuna waa inuu qeexaa codsi hoosaadka goobtan. Si aad awood ugu yeelatid inaad ka heshid shaqada Nginx config, magaca shaqada waa in lagu dhoofiyaa qoraalka laftiisa export default.

nginx.conf

load_module modules/ngx_http_js_module.so;
http {
  js_import   imported_name  from script.js;

server {
  listen 8080;
  ...
  location = /sub-query {
    internal;

    proxy_pass http://upstream;
  }

  location / {
    js_content imported_name.request;
  }
}

script.js

function request(r) {
  function call_back(resp) {
    // handler's code
    r.return(resp.status, resp.responseBody);
  }

  r.subrequest('/sub-query', { method: r.method }, call_back);
}

export default {request}

Marka laga codsado browserka http://localhost:8080/ waanu galnaa location /kaas oo dardaaranka js_content wuxuu ku baaqayaa shaqo request lagu tilmaamay qoraalkayaga script.js. Dhanka kale, shaqada request subquery ayaa la sameeyaa location = /sub-query, oo leh hab (tusaale hadda GET) laga helay doodda (r), u gudbay si aan toos ahayn marka shaqadan la yiraahdo. Jawaabta codsi-hoosaadku waxa lagu habayn doonaa shaqada dhexdeeda call_back.

Isku dayga S3

Si aan codsi u samayno kaydinta gaarka ah ee S3, waxaan u baahanahay:

ACCESS_KEY

SECRET_KEY

S3_BUCKET

Laga soo bilaabo habka http ee la isticmaalay, taariikhda/waqtiga hadda, S3_NAME iyo URI, nooc gaar ah oo xadhig ah ayaa la soo saarayaa, kaas oo la saxeexay (HMAC_SHA1) addoo isticmaalaya SECRET_KEY. Xiga waa xariiq sida AWS $ACCESS_KEY:$HASH, waxaa loo isticmaali karaa madaxa oggolaanshaha. Isla taariikhda/wakhtiga la isticmaalay si loo soo saaro xadhigga tallaabadii hore waa in lagu daraa madaxa X-amz-date. Codku wuxuu u eg yahay sidan:

nginx.conf

load_module modules/ngx_http_js_module.so;
http {
  js_import   s3      from     s3.js;

  js_set      $s3_datetime     s3.date_now;
  js_set      $s3_auth         s3.s3_sign;

server {
  listen 8080;
  ...
  location ~* /s3-query/(?<s3_path>.*) {
    internal;

    proxy_set_header    X-amz-date     $s3_datetime;
    proxy_set_header    Authorization  $s3_auth;

    proxy_pass          $s3_endpoint/$s3_path;
  }

  location ~ "^/(?<prefix>[w-]*)[/]?(?<postfix>[w-.]*)$" {
    js_content s3.request;
  }
}

s3.js(AWS Saxiix tusaalaha oggolaanshaha v2, oo loo beddelay heerka hoos u dhaca)

var crypt = require('crypto');

var s3_bucket = process.env.S3_BUCKET;
var s3_access_key = process.env.S3_ACCESS_KEY;
var s3_secret_key = process.env.S3_SECRET_KEY;
var _datetime = new Date().toISOString().replace(/[:-]|.d{3}/g, '');

function date_now() {
  return _datetime
}

function s3_sign(r) {
  var s2s = r.method + 'nnnn';

  s2s += `x-amz-date:${date_now()}n`;
  s2s += '/' + s3_bucket;
  s2s += r.uri.endsWith('/') ? '/' : r.variables.s3_path;

  return `AWS ${s3_access_key}:${crypt.createHmac('sha1', s3_secret_key).update(s2s).digest('base64')}`;
}

function request(r) {
  var v = r.variables;

  function call_back(resp) {
    r.return(resp.status, resp.responseBody);
  }

  var _subrequest_uri = r.uri;
  if (r.uri === '/') {
    // root
    _subrequest_uri = '/?delimiter=/';

  } else if (v.prefix !== '' && v.postfix === '') {
    // directory
    var slash = v.prefix.endsWith('/') ? '' : '/';
    _subrequest_uri = '/?prefix=' + v.prefix + slash;
  }

  r.subrequest(`/s3-query${_subrequest_uri}`, { method: r.method }, call_back);
}

export default {request, s3_sign, date_now}

Sharax yar oo ku saabsan _subrequest_uri: kani waa doorsoome kaas oo ku xidhan uri hore, samaynaysa codsi ku wajahan S3. Haddii aad u baahan tahay inaad hesho waxa ku jira "xididka", markaa waxaad u baahan tahay inaad abuurto codsi uri ah oo muujinaya xadeeyaha delimiter, kaas oo soo celin doona liiska dhammaan CommonPrefixes xml walxaha, u dhiganta hagayaasha (haddii PyPI, liiska dhammaan baakadaha). Haddii aad u baahan tahay inaad liis ka kooban ka hesho hage gaar ah (liiska dhammaan noocyada xirmada), markaas codsiga uri waa inuu ka kooban yahay goob horgale ah oo leh magaca tusaha (xirmo) oo ay qasab ku dhamaato slash /. Haddii kale, shilalku waa suurtogal marka la codsado waxa ku jira buug-tusaale, tusaale ahaan. Waxaa jira hagayaal aiohttp-request iyo aiohttp-requests iyo haddii codsigu caddeeyo /?prefix=aiohttp-request, markaas jawaabtu waxay ka koobnaan doontaa nuxurka labada buug. Haddi ay jirto dharbaaxo dhamaadka, /?prefix=aiohttp-request/, markaas jawaabtu waxay ka koobnaan doontaa oo kaliya hagaha loo baahan yahay. Oo haddii aan codsano fayl, markaa uri natiijada kama duwana midka asalka ah.

Keydi oo dib u bilow Nginx. browserka waxaanu galnaa ciwaanka Nginx-kayaga, natiijada codsigu waxay noqon doontaa XML, tusaale ahaan:

Liiska hagaha

<?xml version="1.0" encoding="UTF-8"?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <Name>myback-space</Name>
  <Prefix></Prefix>
  <Marker></Marker>
  <MaxKeys>10000</MaxKeys>
  <Delimiter>/</Delimiter>
  <IsTruncated>false</IsTruncated>
  <CommonPrefixes>
    <Prefix>new/</Prefix>
  </CommonPrefixes>
  <CommonPrefixes>
    <Prefix>old/</Prefix>
  </CommonPrefixes>
</ListBucketResult>

Laga soo bilaabo liiska hagayaasha waxaad u baahan doontaa oo kaliya walxaha CommonPrefixes.

Marka lagu daro tusaha aan uga baahanahay ciwaanka browserka, waxa aanu sidoo kale ku heli doonaa waxa ku jira foomka XML:

Liiska faylasha ku jira hagaha

<?xml version="1.0" encoding="UTF-8"?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <Name> myback-space</Name>
  <Prefix>old/</Prefix>
  <Marker></Marker>
  <MaxKeys>10000</MaxKeys>
  <Delimiter></Delimiter>
  <IsTruncated>false</IsTruncated>
  <Contents>
    <Key>old/giphy.mp4</Key>
    <LastModified>2020-08-21T20:27:46.000Z</LastModified>
    <ETag>&#34;00000000000000000000000000000000-1&#34;</ETag>
    <Size>1350084</Size>
    <Owner>
      <ID>02d6176db174dc93cb1b899f7c6078f08654445fe8cf1b6ce98d8855f66bdbf4</ID>
      <DisplayName></DisplayName>
    </Owner>
    <StorageClass>STANDARD</StorageClass>
  </Contents>
  <Contents>
    <Key>old/hsd-k8s.jpg</Key>
    <LastModified>2020-08-31T16:40:01.000Z</LastModified>
    <ETag>&#34;b2d76df4aeb4493c5456366748218093&#34;</ETag>
    <Size>93183</Size>
    <Owner>
      <ID>02d6176db174dc93cb1b899f7c6078f08654445fe8cf1b6ce98d8855f66bdbf4</ID>
      <DisplayName></DisplayName>
    </Owner>
    <StorageClass>STANDARD</StorageClass>
  </Contents>
</ListBucketResult>

Laga soo bilaabo liiska faylalka waxaan ka qaadan doonaa oo kaliya walxaha Key.

Waxa hadhay oo dhan waa in la kala saaro XML-ka soo baxay oo loo diro HTML ahaan, iyadoo marka hore lagu beddelay madaxa Nooca-Content-ka qoraal/html.

function request(r) {
  var v = r.variables;

  function call_back(resp) {
    var body = resp.responseBody;

    if (r.method !== 'PUT' && resp.status < 400 && v.postfix === '') {
      r.headersOut['Content-Type'] = "text/html; charset=utf-8";
      body = toHTML(body);
    }

    r.return(resp.status, body);
  }
  
  var _subrequest_uri = r.uri;
  ...
}

function toHTML(xml_str) {
  var keysMap = {
    'CommonPrefixes': 'Prefix',
    'Contents': 'Key',
  };

  var pattern = `<k>(?<v>.*?)</k>`;
  var out = [];

  for(var group_key in keysMap) {
    var reS;
    var reGroup = new RegExp(pattern.replace(/k/g, group_key), 'g');

    while(reS = reGroup.exec(xml_str)) {
      var data = new RegExp(pattern.replace(/k/g, keysMap[group_key]), 'g');
      var reValue = data.exec(reS);
      var a_text = '';

      if (group_key === 'CommonPrefixes') {
        a_text = reValue.groups.v.replace(///g, '');
      } else {
        a_text = reValue.groups.v.split('/').slice(-1);
      }

      out.push(`<a href="/so/${reValue.groups.v}">${a_text}</a>`);
    }
  }

  return '<html><body>n' + out.join('</br>n') + 'n</html></body>'
}

Isku day PyPI

Waxaan hubineynaa in aysan waxba ku jabin meel kasta xirmooyinka la yaqaan inay shaqeeyaan.

# Создаем для тестов новое окружение
python3 -m venv venv
. ./venv/bin/activate

# Скачиваем рабочие пакеты.
pip download aiohttp

# Загружаем в приватную репу
for wheel in *.whl; do curl -T $wheel http://localhost:8080/${wheel%%-*}/$wheel; done

rm -f *.whl

# Устанавливаем из приватной репы
pip install aiohttp -i http://localhost:8080

Waxaan ku celineynaa libyadayada.

# Создаем для тестов новое окружение
python3 -m venv venv
. ./venv/bin/activate

pip install setuptools wheel
python setup.py bdist_wheel
for wheel in dist/*.whl; do curl -T $wheel http://localhost:8080/${wheel%%-*}/$wheel; done

pip install our_pkg --extra-index-url http://localhost:8080

Gudaha CI, abuurista iyo rarista xirmo waxay u egtahay sidan:

pip install setuptools wheel
python setup.py bdist_wheel

curl -sSfT dist/*.whl -u "gitlab-ci-token:${CI_JOB_TOKEN}" "https://pypi.our-domain.com/${CI_PROJECT_NAME}"

Xaqiijinta

Gitlab gudaheeda waxaa suurtagal ah in loo isticmaalo JWT xaqiijinta/oggolaanshaha adeegyada dibadda. Adigoo isticmaalaya dardaaranka auth_request ee Nginx, waxaanu u wareejin doonaa xogta xaqiijinta codsi hoose oo ka kooban wicitaan shaqo oo ku jira qoraalka. Qoraalku wuxuu samayn doonaa codsi-hoosaad kale Gitlab url iyo haddii xogta xaqiijinta si sax ah loo cayimay, markaa Gitlab wuxuu soo celin doonaa lambarka 200 oo soo dejinta / soo dejinta xirmada waa la oggolaan doonaa. Waa maxay sababta aadan u isticmaalin hal su'aalood oo isla markaaba xogta ugu dir Gitlab? Sababtoo ah markaa waa inaan tafatirnaa faylka qaabeynta Nginx mar kasta oo aan samayno isbeddelo oggolaansho ah, tanina waa hawl aad u adag. Sidoo kale, haddii Kubernetes uu isticmaalo siyaasadda faylalka xididka-akhriska-kaliya, markaa tani waxay ku daraysaa xitaa kakanaanta marka la beddelayo nginx.conf iyada oo loo marayo configmap. Oo waxay noqotaa wax aan macquul ahayn in lagu habeeyo Nginx iyada oo loo marayo configmap isla mar ahaantaana la isticmaalayo siyaasadaha mamnuucaya isku xirka mugga (pvc) iyo nidaamka faylalka xididka-kaliya (tani sidoo kale way dhacdaa).

Isticmaalka dhexdhexaadiyaha NJS, waxaan helnaa fursad aan ku bedelno xuduudaha la cayimay ee qaabeynta nginx iyadoo la adeegsanayo doorsoomayaasha deegaanka oo aan ku sameyno xoogaa jeegag ah qoraalka (tusaale, URL si khaldan loo cayimay).

nginx.conf

location = /auth-provider {
  internal;

  proxy_pass $auth_url;
}

location = /auth {
  internal;

  proxy_set_header Content-Length "";
  proxy_pass_request_body off;
  js_content auth.auth;
}

location ~ "^/(?<prefix>[w-]*)[/]?(?<postfix>[w-.]*)$" {
  auth_request /auth;

  js_content s3.request;
}

s3.js

var env = process.env;
var env_bool = new RegExp(/[Tt]rue|[Yy]es|[Oo]n|[TtYy]|1/);
var auth_disabled  = env_bool.test(env.DISABLE_AUTH);
var gitlab_url = env.AUTH_URL;

function url() {
  return `${gitlab_url}/jwt/auth?service=container_registry`
}

function auth(r) {
  if (auth_disabled) {
    r.return(202, '{"auth": "disabled"}');
    return null
  }

  r.subrequest('/auth-provider',
                {method: 'GET', body: ''},
                function(res) {
                  r.return(res.status, "");
                });
}

export default {auth, url}

Waxay u badan tahay in su'aashu tahay breing: -Maxaa diidaya in la isticmaalo qaybo diyaarsan? Wax walba horay ayaa loo sameeyay! Tusaale ahaan, var AWS = baahan ('aws-sdk') oo looma baahna in la qoro "baaskiil" oo leh aqoonsiga S3!

Aan u gudubno qasaaraha

Aniga ahaan, awood la'aanta soo dejinta modules-ka JS dibadda waxay noqotay wax aan fiicneyn, laakiin sifo la filayo. Lagu sifeeyay tusaalaha sare wuxuu u baahan yahay ('crypto') waa modules-ku-dhis waxayna u baahan yihiin oo kaliya inay u shaqeeyaan. Sidoo kale ma jirto qaab dib loogu isticmaali karo koodka qoraallada waana in aad nuqul ka sameysaa oo aad ku dhejisaa faylal kala duwan. Waxaan rajeynayaa in maalin maalmaha ka mid ah shaqeyntan la hirgelin doono.

Cadaadisku sidoo kale waa in lagu naafo mashruuca hadda Nginx gzip off;

Sababtoo ah ma jiro module gzip gudaha NJS oo suurtagal maaha in lagu xidho; Sidaa darteed, ma jirto hab lagu shaqeeyo xogta la cufan. Run, tani run ahaantii maaha mid laga jaray kiiskan. Ma jiro wax badan oo qoraal ah, iyo faylalka la wareejiyay mar horeba waa la isku dhejiyay oo cadaadis dheeraad ah kama caawin doono iyaga wax badan. Sidoo kale, kani maaha adeeg la raran yahay ama muhiim ah oo ay tahay inaad ku dhibto gudbinta macluumaadka dhawr millise seconds si degdeg ah.

Dejinta qoraalka waxay qaadanaysaa wakhti dheer waxayna ku suurtogashaa "daabacadaha" ee error.log. Iyada oo ku xidhan xogta heerka goynta la dejiyay, digniin ama khalad, waxa suurtogal ah in la isticmaalo 3 hab r.log, r.warn, r.error siday u kala horreeyaan. Waxaan isku dayaa inaan khalad ka saaro qoraallada qaar Chrome (v8) ama aaladda njs console, laakiin wax walba laguma hubin karo halkaas. Marka qaladka koodka, aka tijaabinta functional, taariikhdu waxay u egtahay sidan:

docker-compose restart nginx
curl localhost:8080/
docker-compose logs --tail 10 nginx

waxaana jiri kara boqolaal taxane ah.

Qoritaanka koodka iyadoo la adeegsanayo su'aalo-hoosaadyo iyo doorsoomayaasha iyaga waxay isu beddeshaa qalloocan. Mararka qaarkood waxaad bilowdaa inaad ku degdegto daaqadaha IDE-ga ee kala duwan adigoo isku dayaya inaad ogaatid sida ay u socdaan tallaabooyinka code-kaga. Ma aha wax adag, laakiin mararka qaarkood aad ayay u dhibsadaan.

Ma jirto taageero buuxda oo loogu talagalay ES6.

Waxaa laga yaabaa inay jiraan cillado kale, laakiin wax kale lama kulmin. La wadaag macluumaadka haddii aad khibrad xun u leedahay isticmaalka NJS.

gunaanad

NJS waa turjumaan il furan oo fufud kaas oo kuu ogolaanaya inaad ka hirgeliso qoraalo JavaScript kala duwan Nginx. Intii lagu jiray horumarinteeda, fiiro gaar ah ayaa la siiyay waxqabadka. Dabcan, weli wax badan ayaa maqan, laakiin mashruuca waxaa soo saaray koox yar waxayna si firfircoon u soo kordhinayaan sifooyin cusub iyo hagaajinta cayayaanka. Waxaan rajeynayaa in maalin maalmaha ka mid ah NJS ay kuu ogolaan doonto inaad ku xirto qaybaha dibadda, taas oo ka dhigi doonta shaqeynta Nginx ku dhawaad ​​aan xadidneyn. Laakiin waxaa jira NGINX Plus waxayna u badan tahay inaysan jiri doonin astaamo!

Kaydka oo leh kood buuxa ee maqaalka

njs-pypi oo leh taageerada AWS Saxiixa v4

Sharaxaada awaamiirta moduleka ngx_http_js_module

Kaydka rasmiga ah ee NJS и dukumiintiyada

Tusaalooyinka isticmaalka NJS ee Dmitry Volintsev

njs - qoraalka JavaScript ee asalka ah ee nginx / Hadalka Dmitry Volnyev ee Saint HighLoad++ 2019

NJS ee wax soo saarka / Hadalka Vasily Soshnikov ee HighLoad++ 2019

Saxeexa iyo Xaqiijinta Codsiyada REST ee AWS

Source: www.habr.com

U soo iibso martigelin lagu kalsoonaan karo oo loogu talagalay bogagga leh ilaalinta DDoS, VPS VDS servers 🔥 Iibso martigelin degel oo lagu kalsoonaan karo oo leh ilaalinta DDoS, VPS VDS servers | ProHoster