{"id":410605,"date":"2024-06-29T21:29:02","date_gmt":"2024-06-29T21:29:02","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=410605"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=410605","title":{"rendered":"<span>Serverless\u00a0\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u00a0\u0444\u0430\u0439\u043b\u043e\u0432\u00a0\u0441\u00a0AWS\u00a0lambda<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0414\u043e\u0431\u0440\u044b\u0439 \u0434\u0435\u043d\u044c, \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c serverless \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043d\u0430 \u0431\u0430\u0437\u0435 AWS lambda \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 (\u0438\u043b\u0438 \u043b\u044e\u0431\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432) \u0441 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c \u0432 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u043c AWS S3 bucket. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u044b \u0431\u0443\u0434\u0435\u043c terraform \u0441\u043a\u0440\u0438\u043f\u0442\u044b, \u0437\u0430\u043b\u0438\u0442\u044b\u0435 \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0432 \u043c\u043e\u0435\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 <a href=\"https:\/\/github.com\/kompotkot\/hatchery\/tree\/main\/files_distributor\" rel=\"noopener noreferrer nofollow\">kompotkot\/hatchery<\/a> \u043d\u0430 GitHub.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/25e\/284\/acb\/25e284acbf3ff78a34d1e587145c3e2a.png\" width=\"1160\" height=\"580\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/25e\/284\/acb\/25e284acbf3ff78a34d1e587145c3e2a.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0423\u00a0\u0438\u0437\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435\u00a0\u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430:<\/p>\n<ul>\n<li>\n<p>lambda \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443 \u0438 \u0435\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0434\u043b\u044f \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/p>\n<\/li>\n<li>\n<p>\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 lambda \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0440\u0435\u0434\u0430 \u0440\u0430\u0431\u043e\u0442\u044b, \u0447\u0442\u043e \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0447 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432\u0440\u0435\u0434\u043e\u043d\u043e\u0441\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0438\u0439 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0439\u0442\u0438 \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044b \u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u044b, \u0441\u0435\u0441\u0441\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0439, \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0441\u043f\u0443\u0441\u0442\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f<\/p>\n<\/li>\n<li>\n<p>\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 \u043d\u0430 S3 bucket \u043a\u0440\u0430\u0439\u043d\u0435 \u0434\u0435\u0448\u0435\u0432\u043e\u0435 \u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432\u0438\u0435<\/p>\n<\/li>\n<\/ul>\n<h2>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0437\u0430\u043c\u0435\u0442\u043e\u043a \u0441 API. \u0412 \u043a\u0430\u0436\u0434\u0443\u044e \u0437\u0430\u043c\u0435\u0442\u043a\u0443 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443, \u0430 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438:<\/p>\n<pre><code class=\"json\">- journal_1   - entry_1     - image_1   - entry_2     - image_1     - image_n   - entry_n - journal_n<\/code><\/pre>\n<p>\u0423 \u043d\u0430\u0448\u0435\u0433\u043e \u0433\u0438\u043f\u043e\u0442\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e API \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u043c\u0435\u0442\u043a\u0438 (entry) \u0432 \u0436\u0443\u0440\u043d\u0430\u043b\u0435 (journal):<\/p>\n<pre><code class=\"bash\">curl \\   --request GET \\   --url 'https:\/\/api.example.com\/journals\/{journal_id}\/entries\/{entries_id}'   --header 'Authorization: {token_id}'<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0432 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u044d\u0442\u043e\u0442 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 <code>status_code<\/code> \u0440\u0430\u0432\u0435\u043d 200, \u0437\u043d\u0430\u0447\u0438\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d \u0438 \u0438\u043c\u0435\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0436\u0443\u0440\u043d\u0430\u043b\u0443. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u044b \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043c \u0435\u043c\u0443 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u0437\u0430\u043c\u0435\u0442\u043a\u0438. <\/p>\n<h2>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Bugout.dev<\/h2>\n<p>\u0412\u043e \u0438\u0437\u0431\u0435\u0436\u0430\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 \u0411\u0414, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0430\u043c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a\u043e\u0439 \u0437\u0430\u043c\u0435\u0442\u043a\u0435, \u043a\u0430\u043a\u0430\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442, \u043c\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f <code>resources<\/code> \u043e\u0442 <a href=\"https:\/\/bugout.dev\/\" rel=\"noopener noreferrer nofollow\">Bugout.dev<\/a>.<\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u0432 \u0446\u0435\u043b\u044f\u0445 \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f \u043d\u0430\u0448\u0435\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b, \u043d\u043e \u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0439 \u0448\u0430\u0433 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 \u0432\u0430\u0448\u0435\u0439 \u0411\u0414 \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 API \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c\u044b\u0445 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430\u0445. \u041a\u043e\u0434 Bugout.dev \u043e\u0442\u043a\u0440\u044b\u0442 \u0438 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439 API \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0432 <span>\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/span> \u043d\u0430 GitHub.<\/p>\n<p>\u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0438 \u0433\u0440\u0443\u043f\u043f\u0430 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <code>myapp<\/code> (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u044b\u043c \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430) \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 <a href=\"https:\/\/bugout.dev\/account\/teams\" rel=\"noopener noreferrer nofollow\">Bugout.dev Teams <\/a>\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c ID \u044d\u0442\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u044b \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0448\u0430\u0433\u0430 (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u044d\u0442\u043e <code>e6006d97-0551-4ec9-aabd-da51ee437909<\/code>):<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9c9\/59d\/20b\/9c959d20b98b481b974f4f72c10590b3.png\" width=\"1257\" height=\"250\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9c9\/59d\/20b\/9c959d20b98b481b974f4f72c10590b3.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c Bugout.dev Application \u043f\u043e\u0434 \u043d\u0430\u0448\u0443 \u0433\u0440\u0443\u043f\u043f\u0443 <code>myapp<\/code>\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e curl \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0442\u043e\u043a\u0435\u043d \u043c\u043e\u0436\u043d\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 <a href=\"https:\/\/bugout.dev\/account\/tokens\" rel=\"noopener noreferrer nofollow\">Bugout.dev Tokens<\/a>, \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u0435\u0433\u043e \u043f\u043e\u0434 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <code>BUGOUT_ACCESS_TOKEN<\/code>:<\/p>\n<pre><code class=\"bash\">curl \\ --request POST \\   --url 'https:\/\/auth.bugout.dev\/applications' \\   --header \"Authorization: Bearer $BUGOUT_ACCESS_TOKEN\" \\   --form 'group_id=e6006d97-0551-4ec9-aabd-da51ee437909' \\   --form 'name=myapp-images' \\   --form 'description=Image uploader for myapp notes' \\   | jq .<\/code><\/pre>\n<p>\u0412 \u043e\u0442\u0432\u0435\u0442 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435, \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438:<\/p>\n<pre><code class=\"json\">{ \"id\": \"f0a1672d-4659-49f6-bc51-8a0aad17e979\", \"group_id\": \"e6006d97-0551-4ec9-aabd-da51ee437909\", \"name\": \"myapp-images\", \"description\": \"Image uploader for myapp notes\" }<\/code><\/pre>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 ID <code>f0a1672d-4659-49f6-bc51-8a0aad17e979<\/code> \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f <code>resources<\/code>, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0435\u0441\u0443\u0440\u0441 &#8212; \u044d\u0442\u043e \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0437\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0435 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u043a\u043b\u044e\u0447\u0435\u0439, \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"json\">{ \"id\": \"a6423cd1-317b-4f71-a756-dc92eead185c\", \"application_id\": \"f0a1672d-4659-49f6-bc51-8a0aad17e979\", \"resource_data\": { \"id\": \"d573fab2-beb1-4915-91ce-c356236768a4\", \"name\": \"random-image-name\", \"entry_id\": \"51113e7d-39eb-4f68-bf99-54de5892314b\", \"extension\": \"png\", \"created_at\": \"2021-09-19 15:15:00.437163\", \"journal_id\": \"2821951d-70a4-419b-a968-14e056b49b71\" }, \"created_at\": \"2021-09-19T15:15:00.957809+00:00\", \"updated_at\": \"2021-09-19T15:15:00.957809+00:00\" }<\/code><\/pre>\n<p>\u0418\u0442\u043e\u0433\u043e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0432\u043e\u0435\u0433\u043e \u0440\u043e\u0434\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u0443\u044e \u0411\u0414, \u0433\u0434\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0432 S3 bucket \u043e \u0442\u043e\u043c \u0432 \u043a\u0430\u043a\u043e\u0439 \u0436\u0443\u0440\u043d\u0430\u043b (<code>journal_id<\/code>) \u0438 \u0432 \u043a\u0430\u043a\u0443\u044e \u0437\u0430\u043c\u0435\u0442\u043a\u0443 (<code>entry_id<\/code>) \u0431\u044b\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430 \u0441 \u043a\u0430\u043a\u0438\u043c ID, \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c.<\/p>\n<h2>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 AWS<\/h2>\n<p>\u041d\u0430 AWS \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0432 S3 bucket \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 lambda \u0434\u043b\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439 \u0441 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430\u043c\u0438. \u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0430\u043a\u043a\u0430\u0443\u043d\u0442 AWS \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 IAM \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u043b\u044f terraform. \u042d\u0442\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0442\u0438\u043f\u0430 <code>Programmatic access<\/code> \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a\u043e \u0432\u0441\u0435\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c \u0431\u0435\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0432\u0435\u0431 \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u044e:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/df1\/d19\/19a\/df1d1919aa2e2aefcdb64606ed67dfa9.png\" width=\"993\" height=\"220\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/df1\/d19\/19a\/df1d1919aa2e2aefcdb64606ed67dfa9.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0438, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u0441\u0432\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435:<\/p>\n<pre><code class=\"bash\">export AWS_ACCESS_KEY_ID=&lt;your_aws_terraform_account_access_key> export AWS_SECRET_ACCESS_KEY=&lt;your_aws_terraform_account_secret_key><\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c \u0441\u0432\u043e\u044e VPC \u0441 \u043f\u043e\u0434\u0441\u0435\u0442\u044f\u043c\u0438:<\/p>\n<ul>\n<li>\n<p>2 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430<\/p>\n<\/li>\n<li>\n<p>2 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u043d\u0438 \u043f\u0440\u0438\u0433\u043e\u0434\u044f\u0442\u0441\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 AWS Load Balancer. \u041a\u043e\u0434 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 <a href=\"https:\/\/github.com\/kompotkot\/hatchery\/tree\/main\/files_distributor\/network\" rel=\"noopener noreferrer nofollow\">files_distributor\/network<\/a>, \u043e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>variables.tf<\/code> \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<pre><code class=\"bash\">terraform apply<\/code><\/pre>\n<p>\u0418\u0437 \u0432\u044b\u0432\u043e\u0434\u0430 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043b\u044f <code>AWS_HATCHERY_VPC_ID<\/code>, <code>AWS_HATCHERY_SUBNET_PUBLIC_A_ID<\/code> \u0438 <code>AWS_HATCHERY_SUBNET_PUBLIC_B_ID<\/code>.<\/p>\n<h2>\u041a\u043e\u0434 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/h2>\n<p>\u0412 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0443\u044e AWS lambda \u0444\u0443\u043d\u043a\u0446\u0438\u044e. \u041f\u043e \u043e\u043f\u044b\u0442\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u044f \u0437\u0430\u043c\u0435\u0442\u0438\u043b, \u0447\u0442\u043e \u043f\u0440\u0438 \u043f\u0440\u0435\u0432\u044b\u0448\u0435\u043d\u0438\u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u043f\u0430\u043a\u0435\u0442\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c \u0441\u0432\u044b\u0448\u0435 10\u041c\u0411, \u0440\u0435\u0437\u043a\u043e \u043f\u0430\u0434\u0430\u0435\u0442 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043a\u043e\u0434\u0430 \u043d\u0430 AWS. \u0414\u0430\u0436\u0435 \u043f\u0440\u0438 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u043b\u0438\u0432\u043a\u0435 \u043d\u0430 S3 bucket \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 lambda \u0438\u0437 \u043d\u0435\u0433\u043e, AWS \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0434\u0432\u0438\u0441\u0442\u0443\u0442\u044c \u043d\u0430 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0440\u043e\u043a. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0442\u043e \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f lambda layers. \u0422\u0430\u043a \u0436\u0435, \u0435\u0441\u043b\u0438 \u0432\u044b \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0435 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0431\u0435\u0437 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0441 \u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u0432 \u0441\u0432\u044f\u0437\u043a\u0435 \u0441 CloudFront, \u0442\u043e \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u043f\u0440\u0438\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c\u0441\u044f \u043a lambda@edge.<\/p>\n<p>\u041f\u043e\u043b\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u043a\u043e\u0434\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 \u0444\u0430\u0439\u043b\u0435 <a href=\"https:\/\/github.com\/kompotkot\/hatchery\/blob\/main\/files_distributor\/bucket\/modules\/s3_bucket\/files\/lambda_function.py\" rel=\"noopener noreferrer nofollow\">lambda_function.py<\/a> \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u041d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430 nodejs, \u043d\u043e \u0434\u043b\u044f \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u043c\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f python. \u041a\u043e\u0434 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0431\u043b\u043e\u043a\u043e\u0432:<\/p>\n<pre><code class=\"python\">MY_APP_JOURNALS_URL = \"https:\/\/api.example.com\"     # API \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0441 \u0437\u0430\u043c\u0435\u0442\u043a\u0430\u043c\u0438 BUGOUT_AUTH_URL = \"https:\/\/auth.bugout.dev\"         # Bugout.dev \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 (\u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a) FILES_S3_BUCKET_NAME = \"hatchery-files\"      # \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 S3 bucket, \u0433\u0434\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 FILES_S3_BUCKET_PREFIX = \"dev\"               # \u041f\u0440\u0435\u0444\u0438\u043a\u0441 S3 bucket, \u0433\u0434\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 BUGOUT_APPLICATION_ID = os.environ.get(\"BUGOUT_FILES_APPLICATION_ID\")   # Bugout.dev application ID \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u043d\u0435\u0435<\/code><\/pre>\n<p>\u0420\u0430\u0441\u0448\u0438\u0440\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 Bugout.dev Resources. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442, \u0442\u043e \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430, \u043d\u0430\u043c \u0432\u0435\u0440\u043d\u0435\u0442\u0441\u044f 404 \u043e\u0448\u0438\u0431\u043a\u0430, \u0447\u0442\u043e \u043c\u044b \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0438 \u0432\u0435\u0440\u043d\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0443, \u043a\u0430\u043a \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u043e \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0435.<\/p>\n<pre><code class=\"python\">class BugoutResponseException(Exception):     def __init__(self, message, status_code, detail=None) -> None:         super().__init__(message)         self.status_code = status_code         if detail is not None:             self.detail = detail<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0432 S3 bucket \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 <code>cgi<\/code>, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0435\u0439 \u043d\u0430\u043c \u0440\u0430\u0441\u043f\u0430\u0440\u0441\u0438\u0442\u044c \u0442\u0435\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u0435 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <code>multipart\/&lt;image_type><\/code>. \u0418 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0431\u0443\u0434\u0435\u043c \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c \u043f\u0443\u0442\u0438 <code>{journal_id}\/entries\/{entry_id}\/images\/{image_id}<\/code> \u0431\u0435\u0437 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430.<\/p>\n<pre><code class=\"python\">def put_image_to_bucket(     journal_id: str,     entry_id: str,     image_id: UUID,     content_type: str,     content_length: int,     decoded_body: bytes, ) -> None:     _, c_data = parse_header(content_type)     c_data[\"boundary\"] = bytes(c_data[\"boundary\"], \"utf-8\")     c_data[\"CONTENT-LENGTH\"] = content_length      form_data = parse_multipart(BytesIO(decoded_body), c_data)      for image_str in form_data[\"file\"]:         image_path = f\"{FILES_S3_BUCKET_PREFIX}\/{journal_id}\/entries\/{entry_id}\/images\/{str(image_id)}\"         s3.put_object(             Body=image_str, Bucket=FILES_S3_BUCKET_NAME, Key=image_path         )<\/code><\/pre>\n<p>\u0412\u043e \u0432\u0440\u0435\u043c\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0438\u0437 S3 bucket \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0437\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 base64 \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438.<\/p>\n<pre><code class=\"python\">def get_image_from_bucket(journal_id: str, entry_id: str, image_id: str) -> bytes:     image_path = f\"{FILES_S3_BUCKET_PREFIX}\/{journal_id}\/entries\/{entry_id}\/images\/{image_id}\"     response = s3.get_object(Bucket=FILES_S3_BUCKET_NAME, Key=image_path)     image = response[\"Body\"].read()     encoded_image = base64.b64encode(image)     return encoded_image<\/code><\/pre>\n<p>\u041a\u043e\u0434 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>lambda_handler(event,context)<\/code> \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 GitHub \u043f\u043e<a href=\"https:\/\/github.com\/kompotkot\/hatchery\/blob\/main\/files_distributor\/bucket\/modules\/s3_bucket\/files\/lambda_function.py\" rel=\"noopener noreferrer nofollow\"> \u0441\u0441\u044b\u043b\u043a\u0435<\/a>, \u0433\u0434\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ul>\n<li>\n<p>\u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 <code>journal_id<\/code> \u0438 <code>entry_id<\/code><\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u043a API \u043d\u0430\u0448\u0435\u0433\u043e \u0433\u0438\u043f\u043e\u0442\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f <code>https:\/\/api.example.com\/journals\/{journal_id}\/entries\/{entry_id}<\/code> \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 <code>headers={\"authorization\": auth_bearer_header}<\/code><\/p>\n<\/li>\n<li>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043c\u0435\u0442\u043e\u0434\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430: <code>GET<\/code>, <code>POST<\/code> \u0438\u043b\u0438 <code>DELETE<\/code> \u043c\u044b \u0447\u0438\u0442\u0430\u0435\u043c, \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0438\u043b\u0438 \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443 \u0434\u043b\u044f \u0437\u0430\u043c\u0435\u0442\u043a\u0438 \u0432 \u0436\u0443\u0440\u043d\u0430\u043b\u0435<\/p>\n<\/li>\n<li>\n<p>\u0412\u043e \u0432\u0440\u0435\u043c\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430 \u0432 S3 bucket, \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0438 \u0440\u0430\u0437\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430. \u0414\u0430\u043d\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439 \u0445\u044d\u0448\u0430, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u0442\u0434.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u0442\u044c \u0432 lambda \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <code>requests<\/code>, \u043a \u0441\u0447\u0430\u0441\u0442\u044c\u044e <code>boto3<\/code> \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 AWS \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 lambda \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0443\u0441\u0442\u043e\u0435 python \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0438 \u0443\u043f\u0430\u043a\u0443\u0435\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 <code>site-packages<\/code>:<\/p>\n<pre><code class=\"bash\">python3 -m venv .venv source .venv\/bin\/activate pip install requests cd .venv\/lib\/python3.8\/site-packages zip -r9 \"lambda_function.zip\" .<\/code><\/pre>\n<p>\u041f\u043e\u043c\u0435\u0441\u0442\u0438\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0430\u0440\u0445\u0438\u0432 <code>lambda_function.zip<\/code> \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>files_distributor\/bucket\/modules\/s3_bucket\/files<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u0434 \u0441\u0430\u043c\u043e\u0439 lambda \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<pre><code class=\"bash\">zip -g lambda_function.zip -r lambda_function.py<\/code><\/pre>\n<p>\u041d\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440 \u0433\u043e\u0442\u043e\u0432, \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 AWS \u0438 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c lambda \u0441\u0435\u0440\u0432\u0435\u0440, \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c \u0432 <code>files_distributor\/bucket<\/code>:<\/p>\n<pre><code class=\"bash\">terraform apply<\/code><\/pre>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c:<\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 AWS S3 bucket <code>hatchery-sources<\/code>, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043a\u043e\u0434 \u0434\u043b\u044f lambda \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 AWS S3 bucket <code>hatchery-files<\/code> \u043a\u0443\u0434\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043d\u0430\u0448\u0438 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c <code>dev<\/code><\/p>\n<\/li>\n<li>\n<p>AWS lambda \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441 \u0440\u0430\u0431\u043e\u0447\u0438\u043c \u043a\u043e\u0434\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/p>\n<\/li>\n<li>\n<p>IAM \u0440\u043e\u043b\u044c \u0434\u043b\u044f lambda, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 S3 bucket \u0438 \u043b\u043e\u0433\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u0434\u043b\u044f IAM \u0440\u043e\u043b\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 <code>files_distributor\/bucket\/modules\/iam\/files\/iam_role_lambda_inline_policy.json<\/code>. \u0414\u0440\u0443\u0433\u043e\u0439 \u0444\u0430\u0439\u043b <code>iam_role_lambda_policy.json<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f lambda \u0444\u0443\u043d\u043a\u0446\u0438\u0438. <\/p>\n<p>\u0414\u043b\u044f \u0434\u0435\u0431\u0430\u0433\u0430 lambda \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c <code>print<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0438\u043b\u0438 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u043f\u0430\u043a\u0435\u0442\u043e\u043c <code>logging<\/code> \u0432 python. \u0412\u044b\u0432\u043e\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 AWS CloudWatch:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/723\/1fe\/731\/7231fe73149dedaa4e884dac0558b38a.png\" width=\"1576\" height=\"135\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/723\/1fe\/731\/7231fe73149dedaa4e884dac0558b38a.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>BUGOUT_FILES_APPLICATION_ID<\/code> \u0438\u0437 \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043e\u0434\u0430 \u0432 lambda \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 <code>Configuration\/Environment variables<\/code>.<\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0448\u0430\u0433\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u0435 AWS lambda arn \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>AWS_HATCHERY_LAMBDA_ARN<\/code>.<\/p>\n<h2>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 AWS Load Balancer \u0438 \u0432\u044b\u0445\u043e\u0434 \u0432 \u043c\u0438\u0440<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0441\u0442\u0430\u043b\u0441\u044f \u043e\u0434\u0438\u043d \u0448\u0430\u0433, \u0441\u043e\u0437\u0434\u0430\u0442\u044c AWS Security Group, \u0433\u0434\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u043e\u0440\u0442 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0443\u0448\u0430\u0442\u044c AWS Load Balancer \u0434\u043b\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 lambda \u0444\u0443\u043d\u043a\u0446\u0438\u044e (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e 80 \u0438 443).<\/p>\n<pre><code class=\"bash\">terraform apply \\     -var hatchery_vpc_id=$AWS_HATCHERY_VPC_ID \\     -var hatchery_sbn_public_a_id=$AWS_HATCHERY_SUBNET_PUBLIC_A_ID \\     -var hatchery_sbn_public_b_id=$AWS_HATCHERY_SUBNET_PUBLIC_B_ID \\     -var hatchery_lambda_arn=$AWS_HATCHERY_LAMBDA_ARN<\/code><\/pre>\n<p>\u041f\u043e\u0437\u0434\u0440\u0430\u0432\u043b\u044f\u044e, \u043d\u0430\u0448\u0430 AWS lambda \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u0430 \u043c\u0438\u0440\u0443 \u0438 \u0433\u043e\u0442\u043e\u0432\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0438 \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0437\u0430\u043c\u0435\u0442\u043a\u0430\u043c\u0438!<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/578974\/\"> https:\/\/habr.com\/ru\/articles\/578974\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0414\u043e\u0431\u0440\u044b\u0439 \u0434\u0435\u043d\u044c, \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c serverless \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043d\u0430 \u0431\u0430\u0437\u0435 AWS lambda \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 (\u0438\u043b\u0438 \u043b\u044e\u0431\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432) \u0441 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c \u0432 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u043c AWS S3 bucket. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u044b \u0431\u0443\u0434\u0435\u043c terraform \u0441\u043a\u0440\u0438\u043f\u0442\u044b, \u0437\u0430\u043b\u0438\u0442\u044b\u0435 \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0432 \u043c\u043e\u0435\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 <a href=\"https:\/\/github.com\/kompotkot\/hatchery\/tree\/main\/files_distributor\" rel=\"noopener noreferrer nofollow\">kompotkot\/hatchery<\/a> \u043d\u0430 GitHub.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0423\u00a0\u0438\u0437\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435\u00a0\u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430:<\/p>\n<ul>\n<li>\n<p>lambda \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443 \u0438 \u0435\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0434\u043b\u044f \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/p>\n<\/li>\n<li>\n<p>\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 lambda \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0440\u0435\u0434\u0430 \u0440\u0430\u0431\u043e\u0442\u044b, \u0447\u0442\u043e \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0447 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432\u0440\u0435\u0434\u043e\u043d\u043e\u0441\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0438\u0439 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0439\u0442\u0438 \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044b \u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u044b, \u0441\u0435\u0441\u0441\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0439, \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0441\u043f\u0443\u0441\u0442\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f<\/p>\n<\/li>\n<li>\n<p>\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 \u043d\u0430 S3 bucket \u043a\u0440\u0430\u0439\u043d\u0435 \u0434\u0435\u0448\u0435\u0432\u043e\u0435 \u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432\u0438\u0435<\/p>\n<\/li>\n<\/ul>\n<h2>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0437\u0430\u043c\u0435\u0442\u043e\u043a \u0441 API. \u0412 \u043a\u0430\u0436\u0434\u0443\u044e \u0437\u0430\u043c\u0435\u0442\u043a\u0443 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443, \u0430 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438:<\/p>\n<pre><code class=\"json\">- journal_1   - entry_1     - image_1   - entry_2     - image_1     - image_n   - entry_n - journal_n<\/code><\/pre>\n<p>\u0423 \u043d\u0430\u0448\u0435\u0433\u043e \u0433\u0438\u043f\u043e\u0442\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e API \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u043c\u0435\u0442\u043a\u0438 (entry) \u0432 \u0436\u0443\u0440\u043d\u0430\u043b\u0435 (journal):<\/p>\n<pre><code class=\"bash\">curl \\   --request GET \\   --url 'https:\/\/api.example.com\/journals\/{journal_id}\/entries\/{entries_id}'   --header 'Authorization: {token_id}'<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0432 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u044d\u0442\u043e\u0442 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 <code>status_code<\/code> \u0440\u0430\u0432\u0435\u043d 200, \u0437\u043d\u0430\u0447\u0438\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d \u0438 \u0438\u043c\u0435\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0436\u0443\u0440\u043d\u0430\u043b\u0443. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u044b \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043c \u0435\u043c\u0443 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u0437\u0430\u043c\u0435\u0442\u043a\u0438. <\/p>\n<h2>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Bugout.dev<\/h2>\n<p>\u0412\u043e \u0438\u0437\u0431\u0435\u0436\u0430\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 \u0411\u0414, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0430\u043c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a\u043e\u0439 \u0437\u0430\u043c\u0435\u0442\u043a\u0435, \u043a\u0430\u043a\u0430\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442, \u043c\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f <code>resources<\/code> \u043e\u0442 <a href=\"https:\/\/bugout.dev\/\" rel=\"noopener noreferrer nofollow\">Bugout.dev<\/a>.<\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u0432 \u0446\u0435\u043b\u044f\u0445 \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f \u043d\u0430\u0448\u0435\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b, \u043d\u043e \u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0439 \u0448\u0430\u0433 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 \u0432\u0430\u0448\u0435\u0439 \u0411\u0414 \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 API \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c\u044b\u0445 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430\u0445. \u041a\u043e\u0434 Bugout.dev \u043e\u0442\u043a\u0440\u044b\u0442 \u0438 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439 API \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0432 <span>\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/span> \u043d\u0430 GitHub.<\/p>\n<p>\u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0438 \u0433\u0440\u0443\u043f\u043f\u0430 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <code>myapp<\/code> (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u044b\u043c \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430) \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 <a href=\"https:\/\/bugout.dev\/account\/teams\" rel=\"noopener noreferrer nofollow\">Bugout.dev Teams <\/a>\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c ID \u044d\u0442\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u044b \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0448\u0430\u0433\u0430 (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u044d\u0442\u043e <code>e6006d97-0551-4ec9-aabd-da51ee437909<\/code>):<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c Bugout.dev Application \u043f\u043e\u0434 \u043d\u0430\u0448\u0443 \u0433\u0440\u0443\u043f\u043f\u0443 <code>myapp<\/code>\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e curl \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0442\u043e\u043a\u0435\u043d \u043c\u043e\u0436\u043d\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 <a href=\"https:\/\/bugout.dev\/account\/tokens\" rel=\"noopener noreferrer nofollow\">Bugout.dev Tokens<\/a>, \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u0435\u0433\u043e \u043f\u043e\u0434 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <code>BUGOUT_ACCESS_TOKEN<\/code>:<\/p>\n<pre><code class=\"bash\">curl \\ --request POST \\   --url 'https:\/\/auth.bugout.dev\/applications' \\   --header \"Authorization: Bearer $BUGOUT_ACCESS_TOKEN\" \\   --form 'group_id=e6006d97-0551-4ec9-aabd-da51ee437909' \\   --form 'name=myapp-images' \\   --form 'description=Image uploader for myapp notes' \\   | jq .<\/code><\/pre>\n<p>\u0412 \u043e\u0442\u0432\u0435\u0442 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435, \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438:<\/p>\n<pre><code class=\"json\">{ \"id\": \"f0a1672d-4659-49f6-bc51-8a0aad17e979\", \"group_id\": \"e6006d97-0551-4ec9-aabd-da51ee437909\", \"name\": \"myapp-images\", \"description\": \"Image uploader for myapp notes\" }<\/code><\/pre>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 ID <code>f0a1672d-4659-49f6-bc51-8a0aad17e979<\/code> \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f <code>resources<\/code>, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0435\u0441\u0443\u0440\u0441 &#8212; \u044d\u0442\u043e \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0437\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0435 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u043a\u043b\u044e\u0447\u0435\u0439, \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"json\">{ \"id\": \"a6423cd1-317b-4f71-a756-dc92eead185c\", \"application_id\": \"f0a1672d-4659-49f6-bc51-8a0aad17e979\", \"resource_data\": { \"id\": \"d573fab2-beb1-4915-91ce-c356236768a4\", \"name\": \"random-image-name\", \"entry_id\": \"51113e7d-39eb-4f68-bf99-54de5892314b\", \"extension\": \"png\", \"created_at\": \"2021-09-19 15:15:00.437163\", \"journal_id\": \"2821951d-70a4-419b-a968-14e056b49b71\" }, \"created_at\": \"2021-09-19T15:15:00.957809+00:00\", \"updated_at\": \"2021-09-19T15:15:00.957809+00:00\" }<\/code><\/pre>\n<p>\u0418\u0442\u043e\u0433\u043e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0432\u043e\u0435\u0433\u043e \u0440\u043e\u0434\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u0443\u044e \u0411\u0414, \u0433\u0434\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0432 S3 bucket \u043e \u0442\u043e\u043c \u0432 \u043a\u0430\u043a\u043e\u0439 \u0436\u0443\u0440\u043d\u0430\u043b (<code>journal_id<\/code>) \u0438 \u0432 \u043a\u0430\u043a\u0443\u044e \u0437\u0430\u043c\u0435\u0442\u043a\u0443 (<code>entry_id<\/code>) \u0431\u044b\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430 \u0441 \u043a\u0430\u043a\u0438\u043c ID, \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c.<\/p>\n<h2>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 AWS<\/h2>\n<p>\u041d\u0430 AWS \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0432 S3 bucket \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 lambda \u0434\u043b\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439 \u0441 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430\u043c\u0438. \u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0430\u043a\u043a\u0430\u0443\u043d\u0442 AWS \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 IAM \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u043b\u044f terraform. \u042d\u0442\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0442\u0438\u043f\u0430 <code>Programmatic access<\/code> \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a\u043e \u0432\u0441\u0435\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c \u0431\u0435\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0432\u0435\u0431 \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u044e:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0438, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u0441\u0432\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435:<\/p>\n<pre><code class=\"bash\">export AWS_ACCESS_KEY_ID=&lt;your_aws_terraform_account_access_key> export AWS_SECRET_ACCESS_KEY=&lt;your_aws_terraform_account_secret_key><\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c \u0441\u0432\u043e\u044e VPC \u0441 \u043f\u043e\u0434\u0441\u0435\u0442\u044f\u043c\u0438:<\/p>\n<ul>\n<li>\n<p>2 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430<\/p>\n<\/li>\n<li>\n<p>2 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u043d\u0438 \u043f\u0440\u0438\u0433\u043e\u0434\u044f\u0442\u0441\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 AWS Load Balancer. \u041a\u043e\u0434 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 <a href=\"https:\/\/github.com\/kompotkot\/hatchery\/tree\/main\/files_distributor\/network\" rel=\"noopener noreferrer nofollow\">files_distributor\/network<\/a>, \u043e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>variables.tf<\/code> \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<pre><code class=\"bash\">terraform apply<\/code><\/pre>\n<p>\u0418\u0437 \u0432\u044b\u0432\u043e\u0434\u0430 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043b\u044f <code>AWS_HATCHERY_VPC_ID<\/code>, <code>AWS_HATCHERY_SUBNET_PUBLIC_A_ID<\/code> \u0438 <code>AWS_HATCHERY_SUBNET_PUBLIC_B_ID<\/code>.<\/p>\n<h2>\u041a\u043e\u0434 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/h2>\n<p>\u0412 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0443\u044e AWS lambda \u0444\u0443\u043d\u043a\u0446\u0438\u044e. \u041f\u043e \u043e\u043f\u044b\u0442\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u044f \u0437\u0430\u043c\u0435\u0442\u0438\u043b, \u0447\u0442\u043e \u043f\u0440\u0438 \u043f\u0440\u0435\u0432\u044b\u0448\u0435\u043d\u0438\u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u043f\u0430\u043a\u0435\u0442\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c \u0441\u0432\u044b\u0448\u0435 10\u041c\u0411, \u0440\u0435\u0437\u043a\u043e \u043f\u0430\u0434\u0430\u0435\u0442 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043a\u043e\u0434\u0430 \u043d\u0430 AWS. \u0414\u0430\u0436\u0435 \u043f\u0440\u0438 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u043b\u0438\u0432\u043a\u0435 \u043d\u0430 S3 bucket \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 lambda \u0438\u0437 \u043d\u0435\u0433\u043e, AWS \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0434\u0432\u0438\u0441\u0442\u0443\u0442\u044c \u043d\u0430 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0440\u043e\u043a. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0442\u043e \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f lambda layers. \u0422\u0430\u043a \u0436\u0435, \u0435\u0441\u043b\u0438 \u0432\u044b \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0435 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0431\u0435\u0437 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0441 \u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u0432 \u0441\u0432\u044f\u0437\u043a\u0435 \u0441 CloudFront, \u0442\u043e \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u043f\u0440\u0438\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c\u0441\u044f \u043a lambda@edge.<\/p>\n<p>\u041f\u043e\u043b\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u043a\u043e\u0434\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 \u0444\u0430\u0439\u043b\u0435 <a href=\"https:\/\/github.com\/kompotkot\/hatchery\/blob\/main\/files_distributor\/bucket\/modules\/s3_bucket\/files\/lambda_function.py\" rel=\"noopener noreferrer nofollow\">lambda_function.py<\/a> \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u041d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430 nodejs, \u043d\u043e \u0434\u043b\u044f \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u043c\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f python. \u041a\u043e\u0434 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0431\u043b\u043e\u043a\u043e\u0432:<\/p>\n<pre><code class=\"python\">MY_APP_JOURNALS_URL = \"https:\/\/api.example.com\"     # API \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0441 \u0437\u0430\u043c\u0435\u0442\u043a\u0430\u043c\u0438 BUGOUT_AUTH_URL = \"https:\/\/auth.bugout.dev\"         # Bugout.dev \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 (\u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a) FILES_S3_BUCKET_NAME = \"hatchery-files\"      # \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 S3 bucket, \u0433\u0434\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 FILES_S3_BUCKET_PREFIX = \"dev\"               # \u041f\u0440\u0435\u0444\u0438\u043a\u0441 S3 bucket, \u0433\u0434\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 BUGOUT_APPLICATION_ID = os.environ.get(\"BUGOUT_FILES_APPLICATION_ID\")   # Bugout.dev application ID \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u043d\u0435\u0435<\/code><\/pre>\n<p>\u0420\u0430\u0441\u0448\u0438\u0440\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 Bugout.dev Resources. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442, \u0442\u043e \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430, \u043d\u0430\u043c \u0432\u0435\u0440\u043d\u0435\u0442\u0441\u044f 404 \u043e\u0448\u0438\u0431\u043a\u0430, \u0447\u0442\u043e \u043c\u044b \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0438 \u0432\u0435\u0440\u043d\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0443, \u043a\u0430\u043a \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u043e \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0435.<\/p>\n<pre><code class=\"python\">class BugoutResponseException(Exception):     def __init__(self, message, status_code, detail=None) -> None:         super().__init__(message)         self.status_code = status_code         if detail is not None:             self.detail = detail<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0432 S3 bucket \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 <code>cgi<\/code>, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0435\u0439 \u043d\u0430\u043c \u0440\u0430\u0441\u043f\u0430\u0440\u0441\u0438\u0442\u044c \u0442\u0435\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u0435 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <code>multipart\/&lt;image_type><\/code>. \u0418 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0431\u0443\u0434\u0435\u043c \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c \u043f\u0443\u0442\u0438 <code>{journal_id}\/entries\/{entry_id}\/images\/{image_id}<\/code> \u0431\u0435\u0437 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430.<\/p>\n<pre><code class=\"python\">def put_image_to_bucket(     journal_id: str,     entry_id: str,     image_id: UUID,     content_type: str,     content_length: int,     decoded_body: bytes, ) -> None:     _, c_data = parse_header(content_type)     c_data[\"boundary\"] = bytes(c_data[\"boundary\"], \"utf-8\")     c_data[\"CONTENT-LENGTH\"] = content_length      form_data = parse_multipart(BytesIO(decoded_body), c_data)      for image_str in form_data[\"file\"]:         image_path = f\"{FILES_S3_BUCKET_PREFIX}\/{journal_id}\/entries\/{entry_id}\/images\/{str(image_id)}\"         s3.put_object(             Body=image_str, Bucket=FILES_S3_BUCKET_NAME, Key=image_path         )<\/code><\/pre>\n<p>\u0412\u043e \u0432\u0440\u0435\u043c\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0438\u0437 S3 bucket \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0437\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 base64 \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438.<\/p>\n<pre><code class=\"python\">def get_image_from_bucket(journal_id: str, entry_id: str, image_id: str) -> bytes:     image_path = f\"{FILES_S3_BUCKET_PREFIX}\/{journal_id}\/entries\/{entry_id}\/images\/{image_id}\"     response = s3.get_object(Bucket=FILES_S3_BUCKET_NAME, Key=image_path)     image = response[\"Body\"].read()     encoded_image = base64.b64encode(image)     return encoded_image<\/code><\/pre>\n<p>\u041a\u043e\u0434 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>lambda_handler(event,context)<\/code> \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 GitHub \u043f\u043e<a href=\"https:\/\/github.com\/kompotkot\/hatchery\/blob\/main\/files_distributor\/bucket\/modules\/s3_bucket\/files\/lambda_function.py\" rel=\"noopener noreferrer nofollow\"> \u0441\u0441\u044b\u043b\u043a\u0435<\/a>, \u0433\u0434\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ul>\n<li>\n<p>\u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 <code>journal_id<\/code> \u0438 <code>entry_id<\/code><\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u043a API \u043d\u0430\u0448\u0435\u0433\u043e \u0433\u0438\u043f\u043e\u0442\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f <code>https:\/\/api.example.com\/journals\/{journal_id}\/entries\/{entry_id}<\/code> \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 <code>headers={\"authorization\": auth_bearer_header}<\/code><\/p>\n<\/li>\n<li>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043c\u0435\u0442\u043e\u0434\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430: <code>GET<\/code>, <code>POST<\/code> \u0438\u043b\u0438 <code>DELETE<\/code> \u043c\u044b \u0447\u0438\u0442\u0430\u0435\u043c, \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0438\u043b\u0438 \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443 \u0434\u043b\u044f \u0437\u0430\u043c\u0435\u0442\u043a\u0438 \u0432 \u0436\u0443\u0440\u043d\u0430\u043b\u0435<\/p>\n<\/li>\n<li>\n<p>\u0412\u043e \u0432\u0440\u0435\u043c\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430 \u0432 S3 bucket, \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0438 \u0440\u0430\u0437\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430. \u0414\u0430\u043d\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439 \u0445\u044d\u0448\u0430, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u0442\u0434.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u0442\u044c \u0432 lambda \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <code>requests<\/code>, \u043a \u0441\u0447\u0430\u0441\u0442\u044c\u044e <code>boto3<\/code> \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 AWS \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 lambda \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0443\u0441\u0442\u043e\u0435 python \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0438 \u0443\u043f\u0430\u043a\u0443\u0435\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 <code>site-packages<\/code>:<\/p>\n<pre><code class=\"bash\">python3 -m venv .venv source .venv\/bin\/activate pip install requests cd .venv\/lib\/python3.8\/site-packages zip -r9 \"lambda_function.zip\" .<\/code><\/pre>\n<p>\u041f\u043e\u043c\u0435\u0441\u0442\u0438\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0430\u0440\u0445\u0438\u0432 <code>lambda_function.zip<\/code> \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>files_distributor\/bucket\/modules\/s3_bucket\/files<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u0434 \u0441\u0430\u043c\u043e\u0439 lambda \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<pre><code class=\"bash\">zip -g lambda_function.zip -r lambda_function.py<\/code><\/pre>\n<p>\u041d\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440 \u0433\u043e\u0442\u043e\u0432, \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 AWS \u0438 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c lambda \u0441\u0435\u0440\u0432\u0435\u0440, \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c \u0432 <code>files_distributor\/bucket<\/code>:<\/p>\n<pre><code class=\"bash\">terraform apply<\/code><\/pre>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c:<\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 AWS S3 bucket <code>hatchery-sources<\/code>, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043a\u043e\u0434 \u0434\u043b\u044f lambda \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 AWS S3 bucket <code>hatchery-files<\/code> \u043a\u0443\u0434\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043d\u0430\u0448\u0438 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c <code>dev<\/code><\/p>\n<\/li>\n<li>\n<p>AWS lambda \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441 \u0440\u0430\u0431\u043e\u0447\u0438\u043c \u043a\u043e\u0434\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/p>\n<\/li>\n<li>\n<p>IAM \u0440\u043e\u043b\u044c \u0434\u043b\u044f lambda, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 S3 bucket \u0438 \u043b\u043e\u0433\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u0434\u043b\u044f IAM \u0440\u043e\u043b\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 <code>files_distributor\/bucket\/modules\/iam\/files\/iam_role_lambda_in<\/code><\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-410605","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/410605","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=410605"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/410605\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=410605"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=410605"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=410605"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}