рдореА рдЕрдзрд┐рдХреГрддрддрд╛ рдЖрдгрд┐ S3 рд╕рд╣ рдорд╛рдЭреЗ рд╕реНрд╡рддрдГрдЪреЗ PyPI рднрд╛рдВрдбрд╛рд░ рдмрдирд╡рд▓реЗ. Nginx рд╡рд░

рдпрд╛ рд▓реЗрдЦрд╛рдд рдореА NJS рд╕рд╣ рдорд╛рдЭрд╛ рдЕрдиреБрднрд╡ рд╕рд╛рдорд╛рдпрд┐рдХ рдХрд░реВ рдЗрдЪреНрдЫрд┐рддреЛ, Nginx Inc рдиреЗ рд╡рд┐рдХрд╕рд┐рдд рдХреЗрд▓реЗрд▓реНрдпрд╛ Nginx рд╕рд╛рдареА JavaScript рджреБрднрд╛рд╖реА, рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЙрджрд╛рд╣рд░рдг рд╡рд╛рдкрд░реВрди рддреНрдпрд╛рдЪреНрдпрд╛ рдореБрдЦреНрдп рдХреНрд╖рдорддрд╛рдВрдЪреЗ рд╡рд░реНрдгрди рдХрд░рддреЛ. NJS рд╣рд╛ JavaScript рдЪрд╛ рдЙрдкрд╕рдВрдЪ рдЖрд╣реЗ рдЬреЛ рддреБрдореНрд╣рд╛рд▓рд╛ Nginx рдЪреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рд╡рд╛рдврд╡рдгреНрдпрд╛рдЪреА рдкрд░рд╡рд╛рдирдЧреА рджреЗрддреЛ. рдкреНрд░рд╢реНрдирд╛рд▓рд╛ рддреБрдордЪрд╛ рд╕реНрд╡рддрдГрдЪрд╛ рджреБрднрд╛рд╖реА рдХрд╛??? рджрд┐рдорд┐рддреНрд░реА рд╡реНрд╣реЙрд▓рд┐рдиреНрддреНрд╕реЗрд╡реНрд╣ рдпрд╛рдВрдиреА рддрдкрд╢реАрд▓рд╡рд╛рд░ рдЙрддреНрддрд░ рджрд┐рд▓реЗ. рдереЛрдбрдХреНрдпрд╛рдд: NJS рд╣реЗ nginx-рд╡реЗ рдЖрд╣реЗ, рдЖрдгрд┐ JavaScript рдЕрдзрд┐рдХ рдкреНрд░рдЧрддреАрд╢реАрд▓, "рдиреЗрдЯрд┐рд╡реНрд╣" рдЖрдгрд┐ GC рд╢рд┐рд╡рд╛рдп, Lua рдЪреНрдпрд╛ рд╡рд┐рдкрд░реАрдд рдЖрд╣реЗ.

рдлрд╛рд░ рдкреВрд░реНрд╡реАтАж

рдорд╛рдЭреНрдпрд╛ рд╢реЗрд╡рдЯрдЪреНрдпрд╛ рдиреЛрдХрд░реАрд╡рд░, рдорд▓рд╛ рдбреЙрдХрд░-рдХрдВрдкреЛрдЬ, рдбрд┐рдВрдб рдЖрдгрд┐ рдЗрддрд░ рдЖрдирдВрджрд╛рдВрд╕рд╣ рдЕрдиреЗрдХ рдореЛрдЯрд▓реА рд╕реАрдЖрдп/рд╕реАрдбреА рдкрд╛рдЗрдкрд▓рд╛рдЗрдирд╕рд╣ рдЧрд┐рдЯрд▓реЕрдмрдЪрд╛ рд╡рд╛рд░рд╕рд╛ рдорд┐рд│рд╛рд▓рд╛, рдЬреНрдпрд╛ рдХрд╛рдирд┐рдХреЛ рд░реЗрд▓рдордзреНрдпреЗ рд╣рд╕реНрддрд╛рдВрддрд░рд┐рдд рдХреЗрд▓реНрдпрд╛ рдЧреЗрд▓реНрдпрд╛. рдкреВрд░реНрд╡реА CI рдордзреНрдпреЗ рд╡рд╛рдкрд░рд▓реЗрд▓реНрдпрд╛ рдкреНрд░рддрд┐рдорд╛ рддреНрдпрд╛рдВрдЪреНрдпрд╛ рдореВрд│ рд╕реНрд╡рд░реВрдкрд╛рдд рд╣рд▓рд╡рд┐рдгреНрдпрд╛рдд рдЖрд▓реНрдпрд╛ рд╣реЛрддреНрдпрд╛. рдЖрдордЪрд╛ рдЧрд┐рдЯрд▓реЕрдм рдЖрдпрдкреА рдмрджрд▓рд▓рд╛ рдЖрдгрд┐ рд╕реАрдЖрдп рднреЛрдкрд│реНрдпрд╛рдд рдмрджрд▓рд▓рд╛ рддреНрдпрд╛ рджрд┐рд╡рд╕рд╛рдкрд░реНрдпрдВрдд рддреНрдпрд╛рдВрдиреА рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд╛рдо рдХреЗрд▓реЗ. рд╕рдорд╕реНрдпрд╛ рдЕрд╢реА рд╣реЛрддреА рдХреА рд╕реАрдЖрдпрдордзреНрдпреЗ рд╕рд╣рднрд╛рдЧреА рдЭрд╛рд▓реЗрд▓реНрдпрд╛ рдбреЙрдХрд░ рдкреНрд░рддрд┐рдорд╛рдВрдкреИрдХреА рдПрдХ рдЧрд┐рдЯ рд╣реЛрддреА, рдЬреА ssh рджреНрд╡рд╛рд░реЗ рдкрд╛рдпрдерди рдореЙрдбреНрдпреВрд▓реНрд╕ рдЦреЗрдЪрддреЗ. ssh рд╕рд╛рдареА рддреБрдореНрд╣рд╛рд▓рд╛ рдЦрд╛рдЬрдЧреА рдХреА рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ рдЖрдгрд┐... рддреА рдЬреНрдЮрд╛рдд_рд╣реЛрд╕реНрдЯреНрд╕рд╕рд╣ рдЗрдореЗрдЬрдордзреНрдпреЗ рд╣реЛрддреА. рдЖрдгрд┐ рд╡рд╛рд╕реНрддрд╡рд┐рдХ IP рдЖрдгрд┐ рдЬреНрдЮрд╛рдд_рд╣реЛрд╕реНрдЯреНрд╕рдордзреНрдпреЗ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХреЗрд▓реЗрд▓реНрдпрд╛ рдПрдХрд╛рдордзреНрдпреЗ рдЬреБрд│рдд рдирд╕рд▓реНрдпрд╛рдореБрд│реЗ рдХреЛрдгрддреЗрд╣реА CI рдореБрдЦреНрдп рд╕рддреНрдпрд╛рдкрди рддреНрд░реБрдЯреАрд╕рд╣ рдЕрдпрд╢рд╕реНрд╡реА рдЭрд╛рд▓реЗ. рд╡рд┐рджреНрдпрдорд╛рди рдбреЙрдХрдлрд╛рдИрд▓реНрд╕рдордзреВрди рдПрдХ рдирд╡реАрди рдкреНрд░рддрд┐рдорд╛ рджреНрд░реБрддрдкрдгреЗ рдПрдХрддреНрд░ рдХреЗрд▓реА рдЧреЗрд▓реА рдЖрдгрд┐ рдкрд░реНрдпрд╛рдп рдЬреЛрдбрд▓рд╛ рдЧреЗрд▓рд╛ StrictHostKeyChecking no. рдкрдг рд╡рд╛рдИрдЯ рдЪрд╡ рдХрд╛рдпрдо рд░рд╛рд╣рд┐рд▓реА рдЖрдгрд┐ libs рдЦрд╛рдЬрдЧреА PyPI рднрд╛рдВрдбрд╛рд░рд╛рдд рд╣рд▓рд╡рдгреНрдпрд╛рдЪреА рдЗрдЪреНрдЫрд╛ рд╣реЛрддреА. рдЦрд╛рдЬрдЧреА PyPI рд╡рд░ рд╕реНрд╡рд┐рдЪ рдХреЗрд▓реНрдпрд╛рдирдВрддрд░ рдЕрддрд┐рд░рд┐рдХреНрдд рдмреЛрдирд╕, рдПрдХ рд╕реЛрдкреА рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдЖрдгрд┐ рдЖрд╡рд╢реНрдпрдХрддрд╛рдВрдЪреЗ рд╕рд╛рдорд╛рдиреНрдп рд╡рд░реНрдгрди рд╣реЛрддреЗ.txt

рдирд┐рд╡рдб рдЭрд╛рд▓реА рдЖрд╣реЗ, рд╕рдЬреНрдЬрдирд╛рдВрдиреЛ!

рдЖрдореНрд╣реА рдХреНрд▓рд╛рдЙрдбреНрд╕ рдЖрдгрд┐ рдХреБрдмрд░реНрдиреЗрдЯреНрд╕рдордзреНрдпреЗ рд╕рд░реНрд╡рдХрд╛рд╣реА рдЪрд╛рд▓рд╡рддреЛ рдЖрдгрд┐ рд╢реЗрд╡рдЯреА рдЖрдореНрд╣рд╛рд▓рд╛ рдПрдХ рдЫреЛрдЯреА рд╕реЗрд╡рд╛ рдорд┐рд│рд╡рд╛рдпрдЪреА рд╣реЛрддреА рдЬреА рдмрд╛рд╣реНрдп рд╕реНрдЯреЛрд░реЗрдЬрд╕рд╣ рд╕реНрдЯреЗрдЯрд▓реЗрд╕ рдХрдВрдЯреЗрдирд░ рд╣реЛрддреА. рдмрд░рдВ, рдЖрдореНрд╣реА S3 рд╡рд╛рдкрд░рдд рдЕрд╕рд▓реНрдпрд╛рдиреЗ, рддреНрдпрд╛рд▓рд╛ рдкреНрд░рд╛рдзрд╛рдиреНрдп рджрд┐рд▓реЗ рдЧреЗрд▓реЗ. рдЖрдгрд┐, рд╢рдХреНрдп рдЕрд╕рд▓реНрдпрд╛рд╕, gitlab рдордзреНрдпреЗ рдкреНрд░рдорд╛рдгреАрдХрд░рдгрд╛рд╕рд╣ (рдЖрд╡рд╢реНрдпрдХ рдЕрд╕рд▓реНрдпрд╛рд╕ рдЖрдкрдг рддреЗ рд╕реНрд╡рддрдГ рдЬреЛрдбреВ рд╢рдХрддрд╛).

рджреНрд░реБрдд рд╢реЛрдзрд╛рдореБрд│реЗ рдЕрдиреЗрдХ рдкрд░рд┐рдгрд╛рдо рдорд┐рд│рд╛рд▓реЗ: s3pypi, pypicloud рдЖрдгрд┐ рд╕рд▓рдЧрдорд╕рд╛рдареА html рдлрд╛рдЗрд▓реНрд╕рдЪреНрдпрд╛ "рдореЕрдиреНрдпреБрдЕрд▓" рдирд┐рд░реНрдорд┐рддреАрд╕рд╣ рдкрд░реНрдпрд╛рдп. рд╢реЗрд╡рдЯрдЪрд╛ рдкрд░реНрдпрд╛рдп рд╕реНрд╡рддрдГрдЪ рдЧрд╛рдпрдм рдЭрд╛рд▓рд╛.

s3pypi: S3 рд╣реЛрд╕реНрдЯрд┐рдВрдЧ рд╡рд╛рдкрд░рдгреНрдпрд╛рд╕рд╛рдареА рд╣реА рдХреНрд▓реА рдЖрд╣реЗ. рдЖрдореНрд╣реА рдлрд╛рдЗрд▓реНрд╕ рдЕрдкрд▓реЛрдб рдХрд░рддреЛ, html рдЬрдирд░реЗрдЯ рдХрд░рддреЛ рдЖрдгрд┐ рддреНрдпрд╛рдЪ рдмрдХреЗрдЯрдордзреНрдпреЗ рдЕрдкрд▓реЛрдб рдХрд░рддреЛ. рдШрд░рдЧреБрддреА рд╡рд╛рдкрд░рд╛рд╕рд╛рдареА рдпреЛрдЧреНрдп.

pypicloud: рд╣рд╛ рдПрдХ рдордиреЛрд░рдВрдЬрдХ рдкреНрд░рдХрд▓реНрдк рдЕрд╕рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ рд╡рд╛рдЯрд▓реЗ, рдкрд░рдВрддреБ рджрд╕реНрддрдРрд╡рдЬреАрдХрд░рдг рд╡рд╛рдЪрд▓реНрдпрд╛рдирдВрддрд░ рдореА рдирд┐рд░рд╛рд╢ рдЭрд╛рд▓реЛ. рдЪрд╛рдВрдЧрд▓реЗ рджрд╕реНрддрдРрд╡рдЬреАрдХрд░рдг рдЖрдгрд┐ рдЖрдкрд▓реНрдпрд╛ рдЧрд░рдЬреЗрдиреБрд╕рд╛рд░ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░рдгреНрдпрд╛рдЪреА рдХреНрд╖рдорддрд╛ рдЕрд╕реВрдирд╣реА, рдкреНрд░рддреНрдпрдХреНрд╖рд╛рдд рддреЗ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдЖрдгрд┐ рдХреЙрдиреНрдлрд┐рдЧрд░ рдХрд░рдгреЗ рдХрдареАрдг рдЕрд╕рд▓реНрдпрд╛рдЪреЗ рджрд┐рд╕реВрди рдЖрд▓реЗ. рддреНрдпрд╛рд╡реЗрд│рдЪреНрдпрд╛ рдЕрдВрджрд╛рдЬрд╛рдиреБрд╕рд╛рд░, рддреБрдордЪреНрдпрд╛ рдХрд╛рд░реНрдпрд╛рдВрд╕рд╛рдареА рдХреЛрдб рджреБрд░реБрд╕реНрдд рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рей-рел рджрд┐рд╡рд╕ рд▓рд╛рдЧрд▓реЗ рдЕрд╕рддреЗ. рд╕реЗрд╡реЗрд▓рд╛ рдбреЗрдЯрд╛рдмреЗрд╕ рджреЗрдЦреАрд▓ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ. рдЖрдореНрд╣рд╛рд▓рд╛ рджреБрд╕рд░реЗ рдХрд╛рд╣реА рд╕рд╛рдкрдбрд▓реЗ рдирд╛рд╣реА рддрд░ рдЖрдореНрд╣реА рддреЗ рд╕реЛрдбрд▓реЗ.

рдЕрдзрд┐рдХ рд╕рдЦреЛрд▓ рд╢реЛрдзрд╛рдореБрд│реЗ Nginx, ngx_aws_auth рд╕рд╛рдареА рдореЙрдбреНрдпреВрд▓ рдорд┐рд│рд╛рд▓реЗ. рддреНрдпрд╛рдЪреНрдпрд╛ рдЪрд╛рдЪрдгреАрдЪрд╛ рдкрд░рд┐рдгрд╛рдо рдмреНрд░рд╛рдЙрдЭрд░рдордзреНрдпреЗ XML рдкреНрд░рджрд░реНрд╢рд┐рдд рдЭрд╛рд▓рд╛, рдЬреНрдпрд╛рдиреЗ S3 рдмрдХреЗрдЯрдордзреАрд▓ рд╕рд╛рдордЧреНрд░реА рджрд░реНрд╢рд╡рд┐рд▓реА. рд╢реЛрдзрд╛рдЪреНрдпрд╛ рд╡реЗрд│реА рд╢реЗрд╡рдЯрдЪреА рдХрдорд┐рдЯ рдПрдХ рд╡рд░реНрд╖рд╛рдкреВрд░реНрд╡реАрдЪреА рд╣реЛрддреА. рднрд╛рдВрдбрд╛рд░ рднрдиреНрдирд╛рдЯ рджрд┐рд╕рдд рд╣реЛрддреЗ.

рд╕реНрд░реЛрддрд╛рд╡рд░ рдЬрд╛рдКрди рд╡рд╛рдЪреВрди рдкреАрдИрдкреА -503 рдорд╛рдЭреНрдпрд╛ рд▓рдХреНрд╖рд╛рдд рдЖрд▓реЗ рдХреА рдПрдХреНрд╕рдПрдордПрд▓ рдлреНрд▓рд╛рдпрд╡рд░ рдПрдЪрдЯреАрдПрдордПрд▓рдордзреНрдпреЗ рд░реВрдкрд╛рдВрддрд░рд┐рдд рдХреЗрд▓реЗ рдЬрд╛рдК рд╢рдХрддреЗ рдЖрдгрд┐ рдкрд┐рдкрд▓рд╛ рджрд┐рд▓реЗ рдЬрд╛рдК рд╢рдХрддреЗ. Nginx рдЖрдгрд┐ S3 рдмрджреНрджрд▓ рдереЛрдбреЗ рдЕрдзрд┐рдХ рдЧреБрдЧрд▓ рдХреЗрд▓реНрдпрд╛рдирдВрддрд░, Nginx рд╕рд╛рдареА JS рдордзреНрдпреЗ рд▓рд┐рд╣рд┐рд▓реЗрд▓реНрдпрд╛ S3 рдордзреАрд▓ рдкреНрд░рдорд╛рдгреАрдХрд░рдгрд╛рдЪреЗ рдЙрджрд╛рд╣рд░рдг рдорд▓рд╛ рдорд┐рд│рд╛рд▓реЗ. рдЕрд╢рд╛рддрдЪ рдореА NJS рд▓рд╛ рднреЗрдЯрд▓реЛ.

рд╣реЗ рдЙрджрд╛рд╣рд░рдг рдЖрдзрд╛рд░ рдореНрд╣рдгреВрди рдШреЗрддрд▓реНрдпрд╛рд╕, рдПрдХрд╛ рддрд╛рд╕рд╛рдирдВрддрд░ рдореА рдорд╛рдЭреНрдпрд╛ рдмреНрд░рд╛рдЙрдЭрд░рдордзреНрдпреЗ ngx_aws_auth рдореЙрдбреНрдпреВрд▓ рд╡рд╛рдкрд░рддрд╛рдирд╛ рд╕рдорд╛рди XML рдкрд╛рд╣рд┐рд▓реЗ, рдкрд░рдВрддреБ рд╕рд░реНрд╡рдХрд╛рд╣реА рдЬреЗрдПрд╕рдордзреНрдпреЗ рдЖрдзреАрдЪ рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ рд╣реЛрддреЗ.

рдорд▓рд╛ nginx рд╕реЛрд▓реНрдпреВрд╢рди рдЦрд░реЛрдЦрд░ рдЖрд╡рдбрд▓реЗ. рдкреНрд░рдердо, рдЪрд╛рдВрдЧрд▓реЗ рджрд╕реНрддрдРрд╡рдЬреАрдХрд░рдг рдЖрдгрд┐ рдмрд░реАрдЪ рдЙрджрд╛рд╣рд░рдгреЗ, рджреБрд╕рд░реЗ рдореНрд╣рдгрдЬреЗ, рдЖрдореНрд╣рд╛рд▓рд╛ рдлрд╛рдпрд▓реАрдВрд╕рд╣ (рдмреЙрдХреНрд╕рдЪреНрдпрд╛ рдмрд╛рд╣реЗрд░) рдХрд╛рдо рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА Nginx рдЪреНрдпрд╛ рд╕рд░реНрд╡ рд╡рд╕реНрддреВ рдорд┐рд│рддрд╛рдд, рддрд┐рд╕рд░реЗ рдореНрд╣рдгрдЬреЗ, Nginx рд╕рд╛рдареА рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рди рдХрд╕реЗ рд▓рд┐рд╣рд╛рдпрдЪреЗ рд╣реЗ рдорд╛рд╣рд┐рдд рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рдХреЛрдгрд╛рд▓рд╛рд╣реА рдХрд╛рдп рдЖрд╣реЗ рддреЗ рд╕рдордЬрдгреНрдпрд╛рд╕ рд╕рдХреНрд╖рдо рдЕрд╕реЗрд▓. рдорд┐рдирд┐рдорд▓рд┐рдЭрдо рджреЗрдЦреАрд▓ рдорд╛рдЭреНрдпрд╛рд╕рд╛рдареА рдПрдХ рдкреНрд▓рд╕ рдЖрд╣реЗ, рдкрд╛рдпрдерди рдХрд┐рдВрд╡рд╛ рдЧреЛ (рдЬрд░ рд╕реБрд░рд╡рд╛рддреАрдкрд╛рд╕реВрди рд▓рд┐рд╣рд┐рд▓реЗ рдЕрд╕рд▓реНрдпрд╛рд╕), рдиреЗрдХреНрд╕рд╕рдЪрд╛ рдЙрд▓реНрд▓реЗрдЦ рдХрд░реВ рдирдХрд╛.

TL;DR 2 рджрд┐рд╡рд╕рд╛рдВрдирдВрддрд░, PyPi рдЪреА рдЪрд╛рдЪрдгреА рдЖрд╡реГрддреНрддреА рдЖрдзреАрдЪ CI рдордзреНрдпреЗ рд╡рд╛рдкрд░рд▓реА рдЧреЗрд▓реА рд╣реЛрддреА.

рддреЗ рдХрд╕реЗ рдХрд╛рд░реНрдп рдХрд░рддреЗ?

рдореЙрдбреНрдпреВрд▓ Nginx рдордзреНрдпреЗ рд▓реЛрдб рдХреЗрд▓реЗ рдЖрд╣реЗ ngx_http_js_module, рдЕрдзрд┐рдХреГрдд рдбреЙрдХрд░ рдкреНрд░рддрд┐рдореЗрдордзреНрдпреЗ рд╕рдорд╛рд╡рд┐рд╖реНрдЯ рдЖрд╣реЗ. рдЖрдореНрд╣реА рдирд┐рд░реНрджреЗрд╢ рд╡рд╛рдкрд░реВрди рдЖрдордЪреА рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЖрдпрд╛рдд рдХрд░рддреЛ js_importNginx рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рдирдордзреНрдпреЗ. рдлрдВрдХреНрд╢рдирд▓рд╛ рдирд┐рд░реНрджреЗрд╢рд╛рджреНрд╡рд╛рд░реЗ рдХреЙрд▓ рдХреЗрд▓реЗ рдЬрд╛рддреЗ js_content. рдбрд╛рдпрд░реЗрдХреНрдЯрд┐рд╡реНрд╣рдЪрд╛ рд╡рд╛рдкрд░ рд╡реНрд╣реЗрд░рд┐рдПрдмрд▓реНрд╕ рд╕реЗрдЯ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдХреЗрд▓рд╛ рдЬрд╛рддреЛ js_set, рдЬреЗ рдлрдХреНрдд рд╕реНрдХреНрд░рд┐рдкреНрдЯрдордзреНрдпреЗ рд╡рд░реНрдгрди рдХреЗрд▓реЗрд▓реЗ рдлрдВрдХреНрд╢рди рдПрдХ рдпреБрдХреНрддрд┐рд╡рд╛рдж рдореНрд╣рдгреВрди рдШреЗрддреЗ. рдкрд░рдВрддреБ рдЖрдореНрд╣реА NJS рдордзреНрдпреЗ рдлрдХреНрдд Nginx рд╡рд╛рдкрд░реВрди рд╕рдмрдХреНрд╡реЗрд░реА рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд░реВ рд╢рдХрддреЛ, рдХреЛрдгрддреНрдпрд╛рд╣реА XMLHttpRequest рдирд╛рд╣реА. рд╣реЗ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА, 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 рд╕рд╛рдЗрди 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 рдореВрд│рдкреЗрдХреНрд╖рд╛ рд╡реЗрдЧрд│реА рдирд╕рд╛рд╡реА.

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>&#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>

рдлрд╛рдпрд▓реАрдВрдЪреНрдпрд╛ рд╕реВрдЪреАрдордзреВрди рдЖрдореНрд╣реА рдлрдХреНрдд рдШрдЯрдХ рдШреЗрдК Key.

рдЬреЗ рдЙрд░рддреЗ рддреЗ рдореНрд╣рдгрдЬреЗ рдкрд░рд┐рдгрд╛рдореА XML рдкрд╛рд░реНрд╕ рдХрд░рдгреЗ рдЖрдгрд┐ рддреЗ 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="/mr/${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

рдЖрдореНрд╣реА рдЖрдордЪреНрдпрд╛ libs рд╕рд╣ рдкреБрдирд░рд╛рд╡реГрддреНрддреА.

# ╨б╨╛╨╖╨┤╨░╨╡╨╝ ╨┤╨╗╤П ╤В╨╡╤Б╤В╨╛╨▓ ╨╜╨╛╨▓╨╛╨╡ ╨╛╨║╤А╤Г╨╢╨╡╨╜╨╕╨╡
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 рдирд┐рд░реНрджреЗрд╢ рд╡рд╛рдкрд░реВрди, рдЖрдореНрд╣реА рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдбреЗрдЯрд╛ рд╕реНрдХреНрд░рд┐рдкреНрдЯрдордзреАрд▓ рдлрдВрдХреНрд╢рди рдХреЙрд▓ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рд╕рдмрд░рд┐рдХреНрд╡реЗрд╕реНрдЯрд╡рд░ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░реВ. рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЧрд┐рдЯрд▓реЕрдм url рд▓рд╛ рдЖрдгрдЦреА рдПрдХ рд╕рдмрд░рд┐рдХреНрд╡реЗрд╕реНрдЯ рдХрд░реЗрд▓ рдЖрдгрд┐ рдЬрд░ рдСрдереЗрдВрдЯрд┐рдХреЗрд╢рди рдбреЗрдЯрд╛ рдпреЛрдЧреНрдпрд░рд┐рддреНрдпрд╛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХреЗрд▓рд╛ рдЕрд╕реЗрд▓, рддрд░ Gitlab рдХреЛрдб 200 рдкрд░рдд рдХрд░реЗрд▓ рдЖрдгрд┐ рдкреЕрдХреЗрдЬ рдЕрдкрд▓реЛрдб/рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдгреНрдпрд╛рдЪреА рдкрд░рд╡рд╛рдирдЧреА рдЕрд╕реЗрд▓. рдПрдХ рд╕рдмрдХреНрд╡реЗрд░реА рдХрд╛ рд╡рд╛рдкрд░рдд рдирд╛рд╣реА рдЖрдгрд┐ рд▓рдЧреЗрдЪ рдбреЗрдЯрд╛ Gitlab рд▓рд╛ рдкрд╛рдард╡рд╛рдпрдЪрд╛? рдХрд╛рд░рдг рдордЧ рдкреНрд░рддреНрдпреЗрдХ рд╡реЗрд│реА рдЖрдореНрд╣реА рдЕрдзрд┐рдХреГрддрддреЗрдордзреНрдпреЗ рдХреЛрдгрддреЗрд╣реА рдмрджрд▓ рдХреЗрд▓реНрдпрд╛рд╡рд░ рдЖрдореНрд╣рд╛рд▓рд╛ Nginx рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рди рдлрд╛рдЗрд▓ рд╕рдВрдкрд╛рджрд┐рдд рдХрд░рд╛рд╡реА рд▓рд╛рдЧреЗрд▓ рдЖрдгрд┐ рд╣реЗ рдЦреВрдк рддреНрд░рд╛рд╕рджрд╛рдпрдХ рдХрд╛рдо рдЖрд╣реЗ. рддрд╕реЗрдЪ, рдЬрд░ Kubernetes рдХреЗрд╡рд│-рд╡рд╛рдЪрдиреАрдп рд░реВрдЯ рдлрд╛рдЗрд▓рд╕рд┐рд╕реНрдЯрдо рдзреЛрд░рдг рд╡рд╛рдкрд░рдд рдЕрд╕реЗрд▓, рддрд░ configmap рджреНрд╡рд╛рд░реЗ nginx.conf рдмрджрд▓рддрд╛рдирд╛ рд╣реЗ рдЖрдгрдЦреА рдЬрдЯрд┐рд▓рддрд╛ рдЬреЛрдбрддреЗ. рдЖрдгрд┐ рдПрдХрд╛рдЪ рд╡реЗрд│реА рд╡реНрд╣реЙрд▓реНрдпреВрдо (рдкреАрд╡реНрд╣реАрд╕реА) рдЖрдгрд┐ рдХреЗрд╡рд│-рд╡рд╛рдЪрдиреАрдп рд░реВрдЯ рдлрд╛рдЗрд▓рд╕рд┐рд╕реНрдЯрдо (рд╣реЗ рджреЗрдЦреАрд▓ рдШрдбрддреЗ) рдХрдиреЗрдХреНрд╢рди рдкреНрд░рддрд┐рдмрдВрдзрд┐рдд рдзреЛрд░рдгреЗ рд╡рд╛рдкрд░рдд рдЕрд╕рддрд╛рдирд╛ рдХреЙрдиреНрдлрд┐рдЧрд░рдореЕрдкрджреНрд╡рд╛рд░реЗ Nginx рдХреЙрдиреНрдлрд┐рдЧрд░ рдХрд░рдгреЗ рдкреВрд░реНрдгрдкрдгреЗ рдЕрд╢рдХреНрдп рд╣реЛрддреЗ.

NJS рдЗрдВрдЯрд░рдореАрдбрд┐рдПрдЯ рд╡рд╛рдкрд░реВрди, рдЖрдореНрд╣рд╛рд▓рд╛ рдПрдирдЬрд┐рдирдХреНрд╕ рдХреЙрдиреНрдлрд┐рдЧрд░реЗрд╢рдирдордзреАрд▓ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдкреЕрд░рд╛рдореАрдЯрд░реНрд╕ рдкрд░реНрдпрд╛рд╡рд░рдг рд╡реНрд╣реЗрд░рд┐рдПрдмрд▓реНрд╕ рд╡рд╛рдкрд░реВрди рдмрджрд▓рдгреНрдпрд╛рдЪреА рдЖрдгрд┐ рд╕реНрдХреНрд░рд┐рдкреНрдЯрдордзреНрдпреЗ рдХрд╛рд╣реА рддрдкрд╛рд╕рдгреА рдХрд░рдгреНрдпрд╛рдЪреА рд╕рдВрдзреА рдорд┐рд│рддреЗ (рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде, рдЪреБрдХреАрдЪреА рдирд┐рд░реНрджрд┐рд╖реНрдЯ 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 рдореЙрдбреНрдпреВрд▓реНрд╕ рдЖрдпрд╛рдд рдХрд░рдгреНрдпрд╛рд╕ рдЕрд╕рдорд░реНрдерддрд╛ рдПрдХ рдЕрдкреНрд░рд┐рдп, рдкрд░рдВрддреБ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╡реИрд╢рд┐рд╖реНрдЯреНрдп рдмрдирд▓реЗ. рд╡рд░рдЪреНрдпрд╛ рдЙрджрд╛рд╣рд░рдгрд╛рдордзреНрдпреЗ рдЖрд╡рд╢реНрдпрдХ ('рдХреНрд░рд┐рдкреНрдЯреЛ') рд╡рд░реНрдгрди рдХреЗрд▓реЗ рдЖрд╣реЗ рдмрд┐рд▓реНрдб-рдЗрди рдореЙрдбреНрдпреВрд▓реНрд╕ рдЖрдгрд┐ рддреНрдпрд╛рдВрдЪреНрдпрд╛рд╕рд╛рдареА рдлрдХреНрдд рдХрд╛рдорд╛рдВрдЪреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдЖрд╣реЗ. рд╕реНрдХреНрд░рд┐рдкреНрдЯрдордзреВрди рдХреЛрдб рдкреБрдиреНрд╣рд╛ рд╡рд╛рдкрд░рдгреНрдпрд╛рдЪрд╛ рдХреЛрдгрддрд╛рд╣реА рдорд╛рд░реНрдЧ рдирд╛рд╣реА рдЖрдгрд┐ рддреБрдореНрд╣рд╛рд▓рд╛ рддреЛ рд╡реЗрдЧрд╡реЗрдЧрд│реНрдпрд╛ рдлрд╛рдЗрд▓реНрд╕рдордзреНрдпреЗ рдХреЙрдкреА рдЖрдгрд┐ рдкреЗрд╕реНрдЯ рдХрд░рд╛рд╡рд╛ рд▓рд╛рдЧреЗрд▓. рдорд▓рд╛ рдЖрд╢рд╛ рдЖрд╣реЗ рдХреА рдПрдЦрд╛рджреНрдпрд╛ рджрд┐рд╡рд╢реА рд╣реА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рд▓рд╛рдЧреВ рд╣реЛрдИрд▓.

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 рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдЬрд╡рд│рдЬрд╡рд│ рдЕрдорд░реНрдпрд╛рджрд┐рдд рд╣реЛрдИрд▓. рдкрдг рдПрдирдЬреАрдЖрдпрдПрдирдПрдХреНрд╕ рдкреНрд▓рд╕ рдЖрд╣реЗ рдЖрдгрд┐ рдмрд╣реБрдзрд╛ рдХреЛрдгрддреАрд╣реА рд╡реИрд╢рд┐рд╖реНрдЯреНрдпреЗ рдирд╕рддреАрд▓!

рд▓реЗрдЦрд╛рд╕рд╛рдареА рд╕рдВрдкреВрд░реНрдг рдХреЛрдбрд╕рд╣ рднрд╛рдВрдбрд╛рд░

AWS рд╕рд╛рдЗрди v4 рд╕рдорд░реНрдердирд╛рд╕рд╣ njs-pypi

ngx_http_js_module рдореЙрдбреНрдпреВрд▓рдЪреНрдпрд╛ рдирд┐рд░реНрджреЗрд╢рд╛рдВрдЪреЗ рд╡рд░реНрдгрди

рдЕрдзрд┐рдХреГрдд NJS рднрд╛рдВрдбрд╛рд░ ╨╕ рджрд╕реНрддрдРрд╡рдЬреАрдХрд░рдг

рджрд┐рдорд┐рддреНрд░реА рд╡реНрд╣реЙрд▓рд┐рдиреНрдЯрд╕реЗрд╡реНрд╣ рдХрдбреВрди рдПрдирдЬреЗрдПрд╕ рд╡рд╛рдкрд░рдгреНрдпрд╛рдЪреА рдЙрджрд╛рд╣рд░рдгреЗ

njs - nginx рдордзреНрдпреЗ рдореВрд│ JavaScript рд╕реНрдХреНрд░рд┐рдкреНрдЯрд┐рдВрдЧ / рд╕реЗрдВрдЯ рд╣рд╛рдпрд▓реЛрдб++ 2019 рдпреЗрдереЗ рджрд┐рдорд┐рддреНрд░реА рд╡реНрд╣реЛрд▓реНрдиреАрд╡реНрд╣ рдпрд╛рдВрдЪреЗ рднрд╛рд╖рдг

рдЙрддреНрдкрд╛рджрдирд╛рдд NJS / HighLoad++ 2019 рд╡рд░ рд╡рд╕рд┐рд▓реА рд╕реЛрд╢реНрдирд┐рдХреЛрд╡реНрд╣ рдпрд╛рдВрдЪреЗ рднрд╛рд╖рдг

AWS рдордзреНрдпреЗ REST рд╡рд┐рдирдВрддреНрдпрд╛рдВрд╡рд░ рд╕реНрд╡рд╛рдХреНрд╖рд░реА рдХрд░рдгреЗ рдЖрдгрд┐ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХрд░рдгреЗ

рд╕реНрддреНрд░реЛрдд: www.habr.com