ãã®èšäºã§ã¯ãNginx Inc ã«ãã£ãŠéçºããã Nginx çšã® JavaScript ã€ã³ã¿ãŒããªã¿ãŒã§ãã NJS ã«ã€ããŠã®ç§ã®çµéšãå
±æããå®éã®äŸã䜿çšããŠãã®äž»ãªæ©èœã«ã€ããŠèª¬æããããšæããŸãã NJS ã¯ãNginx ã®æ©èœãæ¡åŒµã§ãã JavaScript ã®ãµãã»ããã§ãã 質åã«å¯ŸããŠ
æâŠ
åã®ä»äºã§ãdocker-composeãdindããã®ä»ã®æ©èœãåããå€æ°ã®éå€ãª CI/CD ãã€ãã©ã€ã³ãå«ã gitlab ãç¶æ¿ããããã㯠kaniko Rails ã«è»¢éãããŸããã 以åCIã§äœ¿çšããŠããç»åããã®ãŸãŸç§»åããŸããã ãããã¯ãgitlab IP ãå€æŽãããCI ãã«ããã£ã«å€ããæ¥ãŸã§ãæ£åžžã«åäœããŠããŸããã åé¡ã¯ãCI ã«åå ãã Docker ã€ã¡ãŒãžã® XNUMX ã€ããssh çµç±ã§ Python ã¢ãžã¥ãŒã«ããã«ãã git ãæã£ãŠããããšã§ããã SSH ã®å Žåã¯ç§å¯ããŒãå¿
èŠã§ããããã㯠known_hosts ãšãšãã«ã€ã¡ãŒãžå
ã«ãããŸããã ãŸããå®éã® IP ãš known_hosts ã§æå®ããã IP ã®éã®äžäžèŽã«ãããCI ã¯ããŒæ€èšŒãšã©ãŒã§å€±æããŸããã æ°ããã€ã¡ãŒãžãæ¢åã® Dockfile ããããã«çµã¿ç«ãŠããããªãã·ã§ã³ãè¿œå ãããŸãã StrictHostKeyChecking no
ã ããããåŸå³ã®æªãã¯äŸç¶ãšããŠæ®ã£ãŠãããã©ã€ãã©ãªããã©ã€ããŒã PyPI ãªããžããªã«ç§»åããããšããèŠæããããŸããã ãã©ã€ããŒã PyPI ã«åãæ¿ããåŸã®è¿œå ã®ããŒãã¹ã¯ãããåçŽãªãã€ãã©ã€ã³ãšãrequirements.txt ã®éåžžã®èšè¿°ã§ããã
éžæã¯æ±ºãŸããŸãããè«žåïŒ
ç§ãã¡ã¯ãã¹ãŠãã¯ã©ãŠããš Kubernetes ã§å®è¡ããŠãããæçµçã«ã¯å€éšã¹ãã¬ãŒãžãåããã¹ããŒãã¬ã¹ ã³ã³ãããŒã§ããå°èŠæš¡ãªãµãŒãã¹ãååŸããããšèããŠããŸããã ãŸããS3ã䜿ã£ãŠããã®ã§ãããåªå ããŸããã ãããŠãå¯èœã§ããã°ãgitlab ã§ã®èªèšŒã䜿çšããŸã (å¿ èŠã«å¿ããŠèªåã§è¿œå ã§ããŸã)ã
ç°¡åã«æ€çŽ¢ãããšãs3pypiãpypicloudãããã³ã«ãçšã® HTML ãã¡ã€ã«ããæåãã§äœæãããªãã·ã§ã³ãªã©ãããã€ãã®çµæãåŸãããŸããã æåŸã®ãªãã·ã§ã³ã¯èªç¶ã«æ¶ããŠããŸããŸããã
s3pypi: ããã¯ãS3 ãã¹ãã£ã³ã°ã䜿çšããããã® CLI ã§ãã ãã¡ã€ã«ãã¢ããããŒãããHTML ãçæããŠãåããã±ããã«ã¢ããããŒãããŸãã 家åºã§ã®äœ¿çšã«é©ããŠããŸãã
pypicloud: èå³æ·±ããããžã§ã¯ãã®ããã«æããŸããããããã¥ã¡ã³ããèªãã åŸã¯ãã£ããããŸããã åªããããã¥ã¡ã³ããšããŒãºã«åãããŠæ¡åŒµã§ããã«ãããããããå®éã«ã¯åé·ã§æ§æãé£ããããšãå€æããŸããã åœæã®èŠç©ããã«ããã°ãã¿ã¹ã¯ã«åãããŠã³ãŒããä¿®æ£ããã«ã¯ 3 ïœ 5 æ¥ããã£ãã§ãããã ãã®ãµãŒãã¹ã«ã¯ããŒã¿ããŒã¹ãå¿ èŠã§ãã ä»ã«äœãèŠã€ãããªãã£ãå Žåã«åããŠããã®ãŸãŸã«ããŠãããŸããã
ããã«è©³ããæ€çŽ¢ãããšãNginx ã®ã¢ãžã¥ãŒã« ngx_aws_auth ãèŠã€ãããŸããã 圌ã®ãã¹ãã®çµæã¯ãS3 ãã±ããã®å 容ã瀺ã XML ããã©ãŠã¶ã«è¡šç€ºãããŸããã æ€çŽ¢æã®æåŸã®ã³ããã㯠XNUMX 幎åã§ããã ãªããžããªã¯æŸæ£ãããããã«èŠããŸããã
ãœãŒã¹ã«ã¢ã¯ã»ã¹ããŠèªãããšã§ã
ãã®äŸãããŒã¹ã«ãããšãXNUMX æéåŸã« ngx_aws_auth ã¢ãžã¥ãŒã«ã䜿çšãããšããšåã XML ããã©ãŠã¶ã«è¡šç€ºãããŸãããããã¹ãŠããã§ã« JS ã§èšè¿°ãããŠããŸããã
nginx ãœãªã¥ãŒã·ã§ã³ããšãŠãæ°ã«å ¥ããŸããã 第äžã«ãåªããããã¥ã¡ã³ããšå€ãã®äŸãããã第äºã«ããã¡ã€ã«ãæäœããããã® Nginx ã®åªããæ©èœããã¹ãŠ (ããã«äœ¿ãã) åŸããã第äžã«ãNginx ã®æ§æã®æžãæ¹ãç¥ã£ãŠãã人ãªã誰ã§ããäœãäœã§ããããç解ã§ããã§ãããã Nexus ã¯èšããŸã§ããªããPython ã Go (ãŒãããäœæããå Žå) ãšæ¯èŒããŠããããããªãºã ã¯ç§ã«ãšã£ãŠãã©ã¹ã§ãã
TL;DR 2 æ¥åŸãPyPi ã®ãã¹ã ããŒãžã§ã³ã¯ãã§ã« CI ã§äœ¿çšãããŠããŸããã
ããã¯ã©ã®ããã«åäœããŸããïŒ
ã¢ãžã¥ãŒã«ãNginxã«ããŒãããã ngx_http_js_module
ãå
¬åŒã® docker ã€ã¡ãŒãžã«å«ãŸããŠããŸãã ãã£ã¬ã¯ãã£ãã䜿çšããŠã¹ã¯ãªãããã€ã³ããŒãããŸã js_import
Nginxã®èšå®ã«å€æŽããŸãã é¢æ°ã¯ãã£ã¬ã¯ãã£ãã«ãã£ãŠåŒã³åºãããŸã js_content
ã ãã£ã¬ã¯ãã£ãã¯å€æ°ãèšå®ããããã«äœ¿çšãããŸã js_set
ãã¹ã¯ãªããã«èšè¿°ãããŠããé¢æ°ã®ã¿ãåŒæ°ãšããŠåãåããŸãã ãã ããNJS ã§ãµãã¯ãšãªãå®è¡ã§ããã®ã¯ãXMLHttpRequest ã§ã¯ãªããNginx ã䜿çšããå Žåã®ã¿ã§ãã ãããè¡ãã«ã¯ã察å¿ããå Žæã Nginx æ§æã«è¿œå ããå¿
èŠããããŸãã ãŸããã¹ã¯ãªããã§ã¯ããã®å Žæãžã®ãµããªã¯ãšã¹ããèšè¿°ããå¿
èŠããããŸãã Nginx æ§æããé¢æ°ã«ã¢ã¯ã»ã¹ã§ããããã«ããã«ã¯ãã¹ã¯ãªããèªäœã§é¢æ°åããšã¯ã¹ããŒãããå¿
èŠããããŸã 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}
ãã©ãŠã¶ã§ãªã¯ãšã¹ããããå Žå http://localhost:8080/
ç§ãã¡ã¯å
¥ããŸã location /
ãã£ã¬ã¯ãã£ã js_content
é¢æ°ãåŒã³åºã request
ç§ãã¡ã®ã¹ã¯ãªããã§èª¬æãããŠãã script.js
ã 次ã«ãé¢æ°å
㧠request
ãµãã¯ãšãªãè¡ãããŸã location = /sub-query
ãåŒæ°ããååŸããã¡ãœãã (çŸåšã®äŸã§ã¯ GET) ã䜿çšããŸãã (r)
ããã®é¢æ°ãåŒã³åºããããšãã«æé»çã«æž¡ãããŸãã ãµããªã¯ãšã¹ãã®å¿çã¯é¢æ°å
ã§åŠçãããŸã call_back
.
S3ãè©ŠããŠã¿ã
ãã©ã€ããŒã S3 ã¹ãã¬ãŒãžã«ãªã¯ãšã¹ããè¡ãã«ã¯ã以äžãå¿ èŠã§ãã
ACCESS_KEY
SECRET_KEY
S3_BUCKET
䜿çšããã http ã¡ãœãããçŸåšã®æ¥ä»/æå»ãS3_NAME ããã³ URI ãããç¹å®ã®çš®é¡ã®æååãçæãããSECRET_KEY ã䜿çšããŠçœ²å (HMAC_SHA1) ãããŸãã 次ã¯æ¬¡ã®ãããªè¡ã§ã AWS $ACCESS_KEY:$HASH
ãèªå¯ããããŒã§äœ¿çšã§ããŸãã åã®æé ã§æååãçæããããã«äœ¿çšããã®ãšåãæ¥ä»/æå»ãããããŒã«è¿œå ããå¿
èŠããããŸã X-amz-date
ã ã³ãŒãã§ã¯æ¬¡ã®ããã«ãªããŸãã
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 Sign v2 èªèšŒã®äŸãéæšå¥šã¹ããŒã¿ã¹ã«å€æŽãããŸãã)
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}
ã«ã€ããŠã®ã¡ãã£ãšãã説æ _subrequest_uri
: ããã¯ãåæ URI ã«å¿ããŠãS3 ãžã®ãªã¯ãšã¹ãã圢æããå€æ°ã§ãã ãã«ãŒããã®å
容ãååŸããå¿
èŠãããå Žåã¯ãåºåãæåã瀺ã URI ãªã¯ãšã¹ããäœæããå¿
èŠããããŸãã delimiter
ããã¯ããã£ã¬ã¯ããªã«å¯Ÿå¿ãããã¹ãŠã® CommonPrefixes xml èŠçŽ ã®ãªã¹ããè¿ããŸã (PyPI ã®å Žåã¯ããã¹ãŠã®ããã±ãŒãžã®ãªã¹ã)ã ç¹å®ã®ãã£ã¬ã¯ããªå
ã®ã³ã³ãã³ãã®ãªã¹ã (ãã¹ãŠã®ããã±ãŒãž ããŒãžã§ã³ã®ãªã¹ã) ãååŸããå¿
èŠãããå Žåãuri ãªã¯ãšã¹ãã«ã¯ããã£ã¬ã¯ã㪠(ããã±ãŒãž) ã®ååãå¿
ãã¹ã©ãã·ã¥ / ã§çµãããã¬ãã£ãã¯ã¹ ãã£ãŒã«ããå«ãŸããŠããå¿
èŠããããŸãã ããããªããšãããšãã°ãã£ã¬ã¯ããªã®ã³ã³ãã³ãããªã¯ãšã¹ããããšãã«è¡çªãçºçããå¯èœæ§ããããŸãã aiohttp-request ããã³ aiohttp-requests ãã£ã¬ã¯ããªãããããªã¯ãšã¹ã㧠/?prefix=aiohttp-request
ã®å Žåãå¿çã«ã¯äž¡æ¹ã®ãã£ã¬ã¯ããªã®å
容ãå«ãŸããŸãã æ«å°Ÿã«ã¹ã©ãã·ã¥ãããå Žåã¯ã /?prefix=aiohttp-request/
ã®å Žåãå¿çã«ã¯å¿
èŠãªãã£ã¬ã¯ããªã®ã¿ãå«ãŸããŸãã ãã¡ã€ã«ããªã¯ãšã¹ãããå ŽåãçµæãšããŠåŸããã URI ã¯å
ã® URI ãšç°ãªã£ãŠããŠã¯ãªããŸããã
ä¿åã㊠Nginx ãåèµ·åããŸãã ãã©ãŠã¶ã« Nginx ã®ã¢ãã¬ã¹ãå ¥åãããšããªã¯ãšã¹ãã®çµæã¯æ¬¡ã®ãã㪠XML ã«ãªããŸãã
ãã£ã¬ã¯ããªã®ãªã¹ã
<?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>
ãã£ã¬ã¯ããªã®ãªã¹ãããå¿
èŠãªã®ã¯èŠçŽ ã®ã¿ã§ã CommonPrefixes
.
å¿ èŠãªãã£ã¬ã¯ããªããã©ãŠã¶ã®ã¢ãã¬ã¹ã«è¿œå ãããšããã®å 容ã XML 圢åŒã§åä¿¡ããŸãã
ãã£ã¬ã¯ããªå ã®ãã¡ã€ã«ã®ãªã¹ã
<?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>"00000000000000000000000000000000-1"</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>"b2d76df4aeb4493c5456366748218093"</ETag>
<Size>93183</Size>
<Owner>
<ID>02d6176db174dc93cb1b899f7c6078f08654445fe8cf1b6ce98d8855f66bdbf4</ID>
<DisplayName></DisplayName>
</Owner>
<StorageClass>STANDARD</StorageClass>
</Contents>
</ListBucketResult>
ãã¡ã€ã«ã®ãªã¹ãããèŠçŽ ã®ã¿ãååŸããŸã Key
.
æ®ã£ãŠããã®ã¯ãçµæã® XML ã解æãããŸã Content-Type ããããŒã text/html ã«çœ®ãæããŠã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="/ja/${reValue.groups.v}">${a_text}</a>`);
}
}
return '<html><body>n' + out.join('</br>n') + 'n</html></body>'
}
PyPIãè©ŠããŠã¿ã
åäœããããšãããã£ãŠããããã±ãŒãžã®ã©ãã«ãå£ããŠããªãããšã確èªããŸãã
# СПзЎаеЌ ÐŽÐ»Ñ ÑеÑÑПв МПвПе ПкÑÑжеМОе
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
ã©ã€ãã©ãªã§ãç¹°ãè¿ããŸãã
# СПзЎаеЌ ÐŽÐ»Ñ ÑеÑÑПв МПвПе ПкÑÑжеМОе
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
CI ã§ã¯ãããã±ãŒãžã®äœæãšããŒãã¯æ¬¡ã®ããã«ãªããŸãã
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}"
èªèšŒ
Gitlabã§ã¯å€éšãµãŒãã¹ã®èªèšŒã»èªå¯ã«JWTãå©çšããããšãå¯èœã§ãã Nginx ã® auth_request ãã£ã¬ã¯ãã£ãã䜿çšããŠãã¹ã¯ãªããå ã®é¢æ°åŒã³åºããå«ããµããªã¯ãšã¹ãã«èªèšŒããŒã¿ããªãã€ã¬ã¯ãããŸãã ã¹ã¯ãªãã㯠Gitlab URL ã«å¯ŸããŠå¥ã®ãµããªã¯ãšã¹ããäœæããèªèšŒããŒã¿ãæ£ããæå®ãããŠããå ŽåãGitlab ã¯ã³ãŒã 200 ãè¿ããããã±ãŒãžã®ã¢ããããŒã/ããŠã³ããŒããèš±å¯ãããŸãã XNUMX ã€ã®ãµãã¯ãšãªã䜿çšããŠãããã«ããŒã¿ã Gitlab ã«éä¿¡ããŠã¿ãŠã¯ãããã§ãããã? ãããããšãèªèšŒã«å€æŽãå ãããã³ã« Nginx èšå®ãã¡ã€ã«ãç·šéããå¿ èŠããããããã¯ããªãé¢åãªäœæ¥ã«ãªãããã§ãã ãŸããKubernetes ãèªã¿åãå°çšã®ã«ãŒã ãã¡ã€ã«ã·ã¹ãã ããªã·ãŒã䜿çšããŠããå Žåãconfigmap ãä»ã㊠nginx.conf ã眮ãæãããšãã«ããã«è€éããå¢ããŸãã ãããŠãããªã¥ãŒã (pvc) ãšèªã¿åãå°çšã®ã«ãŒã ãã¡ã€ã«ã·ã¹ãã ã®æ¥ç¶ãçŠæ¢ããããªã·ãŒãåæã«äœ¿çšããªãããconfigmap ãä»ã㊠Nginx ãæ§æããããšã¯çµ¶å¯Ÿã«äžå¯èœã«ãªããŸã (ãããçºçããŸã)ã
NJS äžéäœã䜿çšãããšãç°å¢å€æ°ã䜿çšã㊠nginx èšå®å ã®æå®ããããã©ã¡ãŒã¿ãŒãå€æŽããã¹ã¯ãªããå ã§ããã€ãã®ãã§ã㯠(ããšãã°ãééã£ãŠæå®ããã URL) ãè¡ãæ©äŒãåŸãããŸãã
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}
ããããã次ã®ãããªçåãçããŸãã - ãªãæ¢è£œã®ã¢ãžã¥ãŒã«ã䜿çšããªãã®ã§ãã? ããã§ã¯ãã¹ãŠããã§ã«è¡ãããŠããŸãïŒ ããšãã°ãvar AWS = require('aws-sdk') ãšãããšãS3 èªèšŒã䜿çšããŠãbikeããèšè¿°ããå¿ èŠã¯ãããŸããã
çæã«ç§»ããŸããã
ç§ã«ãšã£ãŠãå€éš JS ã¢ãžã¥ãŒã«ãã€ã³ããŒãã§ããªãããšã¯äžå¿«ã§ã¯ãããŸãããæåŸ
ãããŠããæ©èœã«ãªããŸããã äžèšã®äŸã§èª¬æãããŠãã require('crypto') ã¯
Nginx ã®çŸåšã®ãããžã§ã¯ãã§ãå§çž®ãç¡å¹ã«ããå¿
èŠããããŸã gzip off;
NJS ã«ã¯ gzip ã¢ãžã¥ãŒã«ããªããæ¥ç¶ã§ããªããããå§çž®ããŒã¿ãæ±ãæ¹æ³ããããŸããã 確ãã«ããã®å Žåãããã¯å®éã«ã¯ãã€ãã¹ã§ã¯ãããŸããã ããã¹ãã®éã¯ããã»ã©å€ããªãã転éããããã¡ã€ã«ã¯ãã§ã«å§çž®ãããŠãããè¿œå ã®å§çž®ã¯ããŸãå¹æããããŸããã ãŸããããã¯ã³ã³ãã³ããæ°ããªç§æ©ãé ä¿¡ããå¿ èŠãããã»ã©è² è·ã®é«ããµãŒãã¹ãéèŠãªãµãŒãã¹ã§ã¯ãããŸããã
ã¹ã¯ãªããã®ãããã°ã«ã¯é·ãæéãããããerror.log ã®ãåºåãã«ãã£ãŠã®ã¿å¯èœã§ãã èšå®ããããã°ã¬ãã«æ å ±ãèŠåãŸãã¯ãšã©ãŒã«å¿ããŠããããã r.logãr.warnãr.error ã® 3 ã€ã®ã¡ãœããã䜿çšã§ããŸãã Chrome (v8) ãŸã㯠njs ã³ã³ãœãŒã« ããŒã«ã§ããã€ãã®ã¹ã¯ãªããããããã°ããããšããŸããããããã§ãã¹ãŠã確èªã§ããããã§ã¯ãããŸããã ã³ãŒãããããã°ãããšã (å¥åæ©èœãã¹ã)ãå±¥æŽã¯æ¬¡ã®ããã«ãªããŸãã
docker-compose restart nginx
curl localhost:8080/
docker-compose logs --tail 10 nginx
ãããŠããã®ãããªã·ãŒã±ã³ã¹ã¯äœçŸãååšããå¯èœæ§ããããŸãã
ãµãã¯ãšãªãšãã®å€æ°ã䜿çšããŠã³ãŒããèšè¿°ãããšãè€éãªãã€ããçããŸãã å Žåã«ãã£ãŠã¯ãã³ãŒãã®äžé£ã®åäœãç解ããããšããŠãããŸããŸãª IDE ãŠã£ã³ããŠãå³åŸå·ŠåŸãå§ããããšããããŸãã é£ããããšã§ã¯ãããŸããããéåžžã«é¢åãªå ŽåããããŸãã
ES6 ã¯å®å šã«ã¯ãµããŒããããŠããŸããã
ä»ã«ãæ¬ ç¹ããããããããŸãããããã以å€ã«ã¯äœããããŸããã§ããã NJS ã䜿çšããŠåŠå®çãªçµéšãããå Žåã¯ãæ å ±ãå ±æããŠãã ããã
ãŸãšã
NJS ã¯ãNginx ã§ããŸããŸãª JavaScript ã¹ã¯ãªãããå®è£ ã§ãã軜éã®ãªãŒãã³ãœãŒã¹ ã€ã³ã¿ããªã¿ã§ãã éçºã«ããã£ãŠã¯ãããã©ãŒãã³ã¹ã«çŽ°å¿ã®æ³šæãæãããŸããã ãã¡ããããŸã 足ããªãéšåã¯ãããããããŸããããã®ãããžã§ã¯ãã¯å°äººæ°ã®ããŒã ã«ãã£ãŠéçºãããŠãããæ°æ©èœã®è¿œå ããã°ã®ä¿®æ£ã«ç©æ¥µçã«åãçµãã§ããŸãã ãã€ã NJS ã§å€éšã¢ãžã¥ãŒã«ãæ¥ç¶ã§ããããã«ãªããNginx ã®æ©èœãã»ãŒç¡å¶éã«ãªãããšãé¡ã£ãŠããŸãã ãã ããNGINX Plus ããããããããããæ©èœã¯ãããŸããã
åºæïŒ habr.com