{"id":308944,"date":"2020-08-24T21:00:30","date_gmt":"2020-08-24T21:00:30","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=308944"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=308944","title":{"rendered":"Blue-Green Deployment \u043d\u0430 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u043a\u0430\u0445"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/516230\/\">\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bash_(Unix_shell)\" rel=\"nofollow\">bash<\/a>, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Secure_Shell\" rel=\"nofollow\">ssh<\/a>, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Docker_(software)\" rel=\"nofollow\">docker<\/a> \u0438 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Nginx\" rel=\"nofollow\">nginx<\/a> \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u043c \u0431\u0435\u0441\u0448\u043e\u0432\u043d\u0443\u044e \u0432\u044b\u043a\u043b\u0430\u0434\u043a\u0443 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. <a href=\"https:\/\/martinfowler.com\/bliki\/BlueGreenDeployment.html\" rel=\"nofollow\">Blue-green deployment<\/a> \u2014 \u044d\u0442\u043e \u0442\u0435\u0445\u043d\u0438\u043a\u0430, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0430\u044f \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043d\u0435 \u043e\u0442\u043a\u043b\u043e\u043d\u044f\u044f \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u041e\u043d\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0439 zero downtime deployment \u0438 \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441 \u043e\u0434\u043d\u0438\u043c \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u043c, \u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0440\u044f\u0434\u043e\u043c \u0432\u0442\u043e\u0440\u043e\u0439, \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043a \u0440\u0430\u0431\u043e\u0442\u0435 \u0438\u043d\u0441\u0442\u0430\u043d\u0441.<\/p>\n<p>  <\/p>\n<p>\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u0443 \u0412\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432, \u0438 \u0435\u043c\u0443 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u0438\u043a\u0430\u043a \u043d\u0435\u043b\u044c\u0437\u044f \u043d\u0430 \u043f\u0430\u0440\u0443 \u0441\u0435\u043a\u0443\u043d\u0434 \u043f\u0440\u0438\u043b\u0435\u0447\u044c. \u0410 \u0412\u0430\u043c \u043e\u0447\u0435\u043d\u044c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043a\u0430\u0442\u0438\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0444\u0438\u043a\u0441 \u0431\u0430\u0433\u0430 \u0438\u043b\u0438 \u043d\u043e\u0432\u0443\u044e \u043a\u0440\u0443\u0442\u0443\u044e \u0444\u0438\u0447\u0443. \u0412 \u043e\u0431\u044b\u0447\u043d\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0435\u0433\u043e \u0438 \u0441\u043d\u043e\u0432\u0430 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0434\u043e\u043a\u0435\u0440\u0430, \u043c\u043e\u0436\u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c, \u043f\u043e\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c, \u043d\u043e \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0438\u043e\u0434, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u043d\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442\u0441\u044f, \u0432\u0435\u0434\u044c \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0443\u044e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443. \u0410 \u0435\u0441\u043b\u0438 \u043e\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f, \u043d\u043e \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0435\u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b\u043c? \u0412\u043e\u0442 \u0442\u0430\u043a\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0435\u0451 \u0440\u0435\u0448\u0430\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 \u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u043e.<\/p>\n<p>  <\/p>\n<p>DISCLAIMER: \u0411\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u2014 \u0432 \u0432\u0438\u0434\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u043e\u0439 \u0441\u0435\u0441\u0441\u0438\u0438. \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0441\u043b\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c, \u0438 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0441\u0430\u043c \u0441\u0435\u0431\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u0432 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e\u043c \u043e\u0431\u044a\u0451\u043c\u0435. \u0414\u043b\u044f \u0430\u0442\u043c\u043e\u0441\u0444\u0435\u0440\u043d\u043e\u0441\u0442\u0438, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u044c\u0442\u0435, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043a\u043e\u0434\u0441\u043d\u0438\u043f\u043f\u0435\u0442\u044b, \u0430 \u0431\u0443\u043c\u0430\u0433\u0430 \u0438\u0437 &quot;\u0436\u0435\u043b\u0435\u0437\u043d\u043e\u0433\u043e&quot; \u0442\u0435\u043b\u0435\u0442\u0430\u0439\u043f\u0430.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/youtu.be\/2XLZ4Z8LpEE\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/an\/av\/tg\/anavtgfhojyh9rjqi7cvvtxe8z0.jpeg\"><\/a><\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0442\u0435\u0445\u043d\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043b\u043e\u0436\u043d\u043e \u043d\u0430\u0433\u0443\u0433\u043b\u0438\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e \u0447\u0438\u0442\u0430\u044f \u043a\u043e\u0434 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430. \u0415\u0441\u043b\u0438 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0447\u0442\u043e-\u0442\u043e \u0435\u0449\u0451 \u2014 \u0433\u0443\u0433\u043b\u0438\u0442\u0435 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0439\u0442\u0435 \u0432 <a href=\"https:\/\/explainshell.com\/\" rel=\"nofollow\">explainshell<\/a> (\u0431\u043b\u0430\u0433\u043e, \u043e\u043d \u0441\u043d\u043e\u0432\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0432 \u0441\u0432\u044f\u0437\u0438 \u0441 \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u043e\u0439 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u0430). \u0427\u0442\u043e \u043d\u0435 \u0433\u0443\u0433\u043b\u0438\u0442\u0441\u044f \u2014 \u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0439\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0445. \u0421 \u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432\u0438\u0435\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u044e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0440\u0430\u0437\u0434\u0435\u043b &quot;\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0442\u0435\u0445\u043d\u0438\u043a\u0438&quot;.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c.<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ mkdir blue-green-deployment &amp;&amp; cd $_<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"servis\">\u0421\u0435\u0440\u0432\u0438\u0441<\/h2>\n<p>  <\/p>\n<p>\u0421\u0434\u0435\u043b\u0430\u0435\u043c \u043f\u043e\u0434\u043e\u043f\u044b\u0442\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0438 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u043c \u0435\u0433\u043e \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440.<\/p>\n<p>  <\/p>\n<h3 id=\"interesnye-tehniki\">\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0442\u0435\u0445\u043d\u0438\u043a\u0438<\/h3>\n<p>  <\/p>\n<ul>\n<li><code>cat &lt;&lt; EOF &gt; file-name<\/code> (<a href=\"https:\/\/tldp.org\/LDP\/abs\/html\/here-docs.html\" rel=\"nofollow\">Here Document<\/a> + <a href=\"https:\/\/www.tldp.org\/LDP\/abs\/html\/io-redirection.html\" rel=\"nofollow\">I\/O Redirection<\/a>) \u2014 \u0441\u043f\u043e\u0441\u043e\u0431 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043c\u043d\u043e\u0433\u043e\u0441\u0442\u0440\u043e\u0447\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439.<\/li>\n<li><code>wget -qO- URL<\/code> (<a href=\"https:\/\/explainshell.com\/explain?cmd=wget+-qO-+URL\" rel=\"nofollow\">explainshell<\/a>) \u2014 \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043f\u043e HTTP \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u0432 <code>\/dev\/stdout<\/code> (\u0430\u043d\u0430\u043b\u043e\u0433 <code>curl URL<\/code>).<\/li>\n<\/ul>\n<p>  <\/p>\n<h3 id=\"raspechatka\">\u0420\u0430\u0441\u043f\u0435\u0447\u0430\u0442\u043a\u0430<\/h3>\n<p>  <\/p>\n<blockquote><p>\u042f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u0440\u044b\u0432\u0430\u044e \u0441\u043d\u0438\u043f\u043f\u0435\u0442, \u0447\u0442\u043e\u0431\u044b \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a\u0443 \u0434\u043b\u044f Python. \u0412 \u043a\u043e\u043d\u0446\u0435 \u0431\u0443\u0434\u0435\u0442 \u0435\u0449\u0451 \u043e\u0434\u0438\u043d \u0442\u0430\u043a\u043e\u0439 \u043a\u0443\u0441\u043e\u043a. \u0421\u0447\u0438\u0442\u0430\u0439\u0442\u0435, \u0447\u0442\u043e \u0432 \u044d\u0442\u0438\u0445 \u043c\u0435\u0441\u0442\u0430\u0445 \u0431\u0443\u043c\u0430\u0433\u0430 \u043f\u043e\u0440\u0432\u0430\u043b\u0430\u0441\u044c \u0438 \u0431\u044b\u043b\u0430 \u0441\u043a\u043b\u0435\u0435\u043d\u0430.<\/p><\/blockquote>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ cat &lt;&lt; EOF &gt; uptimer.py<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"python\">from http.server import BaseHTTPRequestHandler, HTTPServer from time import monotonic  app_version = 1 app_name = f'Uptimer v{app_version}.0' loading_seconds = 15 - app_version * 5  class Handler(BaseHTTPRequestHandler):     def do_GET(self):         if self.path == '\/':             try:                 t = monotonic() - server_start                 if t &lt; loading_seconds:                     self.send_error(503)                 else:                     self.send_response(200)                     self.send_header('Content-Type', 'text\/html')                     self.end_headers()                     response = f'&lt;h2&gt;{app_name} is running for {t:3.1f} seconds.&lt;\/h2&gt;\\n'                     self.wfile.write(response.encode('utf-8'))             except Exception:                 self.send_error(500)         else:             self.send_error(404)  httpd = HTTPServer(('', 8080), Handler) server_start = monotonic() print(f'{app_name} (loads in {loading_seconds} sec.) started.') httpd.serve_forever()<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"plaintext\">EOF  $ cat &lt;&lt; EOF &gt; Dockerfile FROM python:alpine EXPOSE 8080 COPY uptimer.py app.py CMD [ &quot;python&quot;, &quot;-u&quot;, &quot;.\/app.py&quot; ] EOF  $ docker build --tag uptimer . Sending build context to Docker daemon  39.42kB Step 1\/4 : FROM python:alpine  ---&gt; 8ecf5a48c789 Step 2\/4 : EXPOSE 8080  ---&gt; Using cache  ---&gt; cf92d174c9d3 Step 3\/4 : COPY uptimer.py app.py  ---&gt; a7fbb33d6b7e Step 4\/4 : CMD [ &quot;python&quot;, &quot;-u&quot;, &quot;.\/app.py&quot; ]  ---&gt; Running in 1906b4bd9fdf Removing intermediate container 1906b4bd9fdf  ---&gt; c1655b996fe8 Successfully built c1655b996fe8 Successfully tagged uptimer:latest  $ docker run --rm --detach --name uptimer --publish 8080:8080 uptimer 8f88c944b8bf78974a5727070a94c76aa0b9bb2b3ecf6324b784e782614b2fbf  $ docker ps CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                    NAMES 8f88c944b8bf        uptimer             &quot;python -u .\/app.py&quot;   3 seconds ago       Up 5 seconds        0.0.0.0:8080-&gt;8080\/tcp   uptimer  $ docker logs uptimer Uptimer v1.0 (loads in 10 sec.) started.  $ wget -qSO- http:\/\/localhost:8080   HTTP\/1.0 503 Service Unavailable   Server: BaseHTTP\/0.6 Python\/3.8.3   Date: Sat, 22 Aug 2020 19:52:40 GMT   Connection: close   Content-Type: text\/html;charset=utf-8   Content-Length: 484  $ wget -qSO- http:\/\/localhost:8080   HTTP\/1.0 200 OK   Server: BaseHTTP\/0.6 Python\/3.8.3   Date: Sat, 22 Aug 2020 19:52:45 GMT   Content-Type: text\/html &lt;h2&gt;Uptimer v1.0 is running for 15.4 seconds.&lt;\/h2&gt;  $ docker rm --force uptimer uptimer<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"revers-proksi\">\u0420\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438<\/h2>\n<p>  <\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u043c\u0435\u043b\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0435\u0437\u0430\u043c\u0435\u0442\u043d\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0434 \u043d\u0438\u043c \u0431\u044b\u043b\u0430 \u0435\u0449\u0451 \u043a\u0430\u043a\u0430\u044f-\u0442\u043e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043a\u0440\u043e\u0435\u0442 \u0435\u0433\u043e \u043f\u043e\u0434\u043c\u0435\u043d\u0443. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440 <a href=\"https:\/\/nginx.org\/\" rel=\"nofollow\">nginx<\/a> \u0432 <a href=\"https:\/\/docs.nginx.com\/nginx\/admin-guide\/web-server\/reverse-proxy\/\" rel=\"nofollow\">\u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438<\/a>. \u0420\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c. \u041e\u043d \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0438 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0445 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0430 \u043e\u0442\u0432\u0435\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u0438 \u0434\u043e\u043a\u0435\u0440\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/docs.docker.com\/network\/\" rel=\"nofollow\">docker network<\/a>. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0443 \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043c\u043e\u0436\u043d\u043e \u0434\u0430\u0436\u0435 \u043d\u0435 \u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u0440\u0442 \u0432 \u0445\u043e\u0441\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0435, \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442 \u0443\u0433\u0440\u043e\u0437 \u0438\u0437 \u0432\u043d\u0435\u0448\u043a\u0438.<\/p>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u0431\u0443\u0434\u0435\u0442 \u0436\u0438\u0442\u044c \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u043c \u0445\u043e\u0441\u0442\u0435, \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043e\u0442\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043e\u0442 docker network \u0438 \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u0447\u0435\u0440\u0435\u0437 \u0441\u0435\u0442\u044c \u0445\u043e\u0441\u0442\u0430, \u043f\u0440\u043e\u0431\u0440\u043e\u0441\u0438\u0432 \u043f\u043e\u0440\u0442 <strong>\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/strong> \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c <code>--publish<\/code>, \u043a\u0430\u043a \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0438 \u043a\u0430\u043a \u0443 \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438.<\/p>\n<p>  <\/p>\n<p>\u0420\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 80, \u0438\u0431\u043e \u044d\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0441\u043b\u0443\u0448\u0430\u0442\u044c \u0432\u043d\u0435\u0448\u043a\u0443. \u0415\u0441\u043b\u0438 80-\u0439 \u043f\u043e\u0440\u0442 \u0443 \u0412\u0430\u0441 \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u0445\u043e\u0441\u0442\u0435 \u0437\u0430\u043d\u044f\u0442, \u043f\u043e\u043c\u0435\u043d\u044f\u0439\u0442\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>--publish 80:80<\/code> \u043d\u0430 <code>--publish ANY_FREE_PORT:80<\/code>.<\/p>\n<p>  <\/p>\n<h3 id=\"interesnye-tehniki-1\">\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0442\u0435\u0445\u043d\u0438\u043a\u0438<\/h3>\n<p>  <\/p>\n<ul>\n<li>&quot;\u0412 docker-\u0441\u0435\u0442\u044f\u0445, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c, \u0441 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u043c\u0438 \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e IP \u0430\u0434\u0440\u0435\u0441\u0443. \u0418\u043c\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0442\u0430\u043a\u0436\u0435 \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u0442\u0441\u044f \u0432 \u0435\u0433\u043e \u0430\u0439\u043f\u0438\u0448\u043d\u0438\u043a&quot; (<a href=\"https:\/\/docs.docker.com\/network\/network-tutorial-standalone\/#use-user-defined-bridge-networks\" rel=\"nofollow\">\u0441\u0442\u0430\u0442\u044c\u044f &quot;Networking with standalone containers&quot;, \u0447\u0430\u0441\u0442\u044c &quot;Use user-defined bridge networks&quot;<\/a>, \u043f\u0443\u043d\u043a\u0442 5 \u0434\u043e\u043a\u0435\u0440-\u043a\u043e\u0434\u0435\u043a\u0441\u0430).<\/li>\n<\/ul>\n<p>  <\/p>\n<h3 id=\"raspechatka-1\">\u0420\u0430\u0441\u043f\u0435\u0447\u0430\u0442\u043a\u0430<\/h3>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ docker network create web-gateway 5dba128fb3b255b02ac012ded1906b7b4970b728fb7db3dbbeccc9a77a5dd7bd  $ docker run --detach --rm --name uptimer --network web-gateway uptimer a1105f1b583dead9415e99864718cc807cc1db1c763870f40ea38bc026e2d67f  $ docker run --rm --network web-gateway alpine wget -qO- http:\/\/uptimer:8080 &lt;h2&gt;Uptimer v1.0 is running for 11.5 seconds.&lt;\/h2&gt;  $ docker run --detach --publish 80:80 --network web-gateway --name reverse-proxy nginx:alpine 80695a822c19051260c66bf60605dcb4ea66802c754037704968bc42527bf120  $ docker ps CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                NAMES 80695a822c19        nginx:alpine        &quot;\/docker-entrypoint.\u2026&quot;   27 seconds ago       Up 25 seconds       0.0.0.0:80-&gt;80\/tcp   reverse-proxy a1105f1b583d        uptimer             &quot;python -u .\/app.py&quot;     About a minute ago   Up About a minute   8080\/tcp             uptimer  $ cat &lt;&lt; EOF &gt; uptimer.conf server {     listen 80;     location \/ {         proxy_pass http:\/\/uptimer:8080;     } } EOF  $ docker cp .\/uptimer.conf reverse-proxy:\/etc\/nginx\/conf.d\/default.conf  $ docker exec reverse-proxy nginx -s reload 2020\/06\/23 20:51:03 [notice] 31#31: signal process started  $ wget -qSO- http:\/\/localhost   HTTP\/1.1 200 OK   Server: nginx\/1.19.0   Date: Sat, 22 Aug 2020 19:56:24 GMT   Content-Type: text\/html   Transfer-Encoding: chunked   Connection: keep-alive &lt;h2&gt;Uptimer v1.0 is running for 104.1 seconds.&lt;\/h2&gt;<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"besshovnyy-deployment\">\u0411\u0435\u0441\u0448\u043e\u0432\u043d\u044b\u0439 \u0434\u0435\u043f\u043b\u043e\u0439\u043c\u0435\u043d\u0442<\/h2>\n<p>  <\/p>\n<p>\u0412\u044b\u043a\u0430\u0442\u0438\u043c \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u0441 \u0434\u0432\u0443\u0445\u043a\u0440\u0430\u0442\u043d\u044b\u043c \u0431\u0443\u0441\u0442\u043e\u043c startup performance) \u0438 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0431\u0435\u0441\u0448\u043e\u0432\u043d\u043e \u0435\u0451 \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c.<\/p>\n<p>  <\/p>\n<h3 id=\"interesnye-tehniki-2\">\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0442\u0435\u0445\u043d\u0438\u043a\u0438<\/h3>\n<p>  <\/p>\n<ul>\n<li><code>echo 'my text' | docker exec -i my-container sh -c 'cat &gt; \/my-file.txt'<\/code> \u2014 \u0417\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442 <code>my text<\/code> \u0432 \u0444\u0430\u0439\u043b <code>\/my-file.txt<\/code> \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 <code>my-container<\/code>.<\/li>\n<li><code>cat &gt; \/my-file.txt<\/code> \u2014 \u0417\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0444\u0430\u0439\u043b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u0432\u0445\u043e\u0434\u0430 <code>\/dev\/stdin<\/code>.<\/li>\n<\/ul>\n<p>  <\/p>\n<h3 id=\"raspechatka-2\">\u0420\u0430\u0441\u043f\u0435\u0447\u0430\u0442\u043a\u0430<\/h3>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ sed -i &quot;s\/app_version = 1\/app_version = 2\/&quot; uptimer.py  $ docker build --tag uptimer . Sending build context to Docker daemon  39.94kB Step 1\/4 : FROM python:alpine  ---&gt; 8ecf5a48c789 Step 2\/4 : EXPOSE 8080  ---&gt; Using cache  ---&gt; cf92d174c9d3 Step 3\/4 : COPY uptimer.py app.py  ---&gt; 3eca6a51cb2d Step 4\/4 : CMD [ &quot;python&quot;, &quot;-u&quot;, &quot;.\/app.py&quot; ]  ---&gt; Running in 8f13c6d3d9e7 Removing intermediate container 8f13c6d3d9e7  ---&gt; 1d56897841ec Successfully built 1d56897841ec Successfully tagged uptimer:latest  $ docker run --detach --rm --name uptimer_BLUE --network web-gateway uptimer 96932d4ca97a25b1b42d1b5f0ede993b43f95fac3c064262c5c527e16c119e02  $ docker logs uptimer_BLUE Uptimer v2.0 (loads in 5 sec.) started.  $ docker run --rm --network web-gateway alpine wget -qO- http:\/\/uptimer_BLUE:8080 &lt;h2&gt;Uptimer v2.0 is running for 23.9 seconds.&lt;\/h2&gt;  $ sed s\/uptimer\/uptimer_BLUE\/ uptimer.conf | docker exec --interactive reverse-proxy sh -c 'cat &gt; \/etc\/nginx\/conf.d\/default.conf'  $ docker exec reverse-proxy cat \/etc\/nginx\/conf.d\/default.conf server {     listen 80;     location \/ {         proxy_pass http:\/\/uptimer_BLUE:8080;     } }  $ docker exec reverse-proxy nginx -s reload 2020\/06\/25 21:22:23 [notice] 68#68: signal process started  $ wget -qO- http:\/\/localhost &lt;h2&gt;Uptimer v2.0 is running for 63.4 seconds.&lt;\/h2&gt;  $ docker rm -f uptimer uptimer  $ wget -qO- http:\/\/localhost &lt;h2&gt;Uptimer v2.0 is running for 84.8 seconds.&lt;\/h2&gt;  $ docker ps CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                NAMES 96932d4ca97a        uptimer             &quot;python -u .\/app.py&quot;     About a minute ago   Up About a minute   8080\/tcp             uptimer_BLUE 80695a822c19        nginx:alpine        &quot;\/docker-entrypoint.\u2026&quot;   8 minutes ago        Up 8 minutes        0.0.0.0:80-&gt;80\/tcp   reverse-proxy<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043e\u0431\u0440\u0430\u0437 \u0431\u0438\u043b\u0434\u0438\u0442\u0441\u044f \u043f\u0440\u044f\u043c\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0447\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u0442\u0430\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u043b\u0438\u0448\u043d\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u043e\u0439. \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0448\u0430\u0433\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 \u043e\u0431\u0440\u0430\u0437\u0430 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 CI-\u0441\u0438\u0441\u0442\u0435\u043c\u0443) \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u0435\u0433\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440.<\/p>\n<p>  <\/p>\n<h2 id=\"perekachka-obrazov\">\u041f\u0435\u0440\u0435\u043a\u0430\u0447\u043a\u0430 \u043e\u0431\u0440\u0430\u0437\u043e\u0432<\/h2>\n<p>  <\/p>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u043f\u0435\u0440\u0435\u043a\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0437\u0430 \u0441 localhost \u043d\u0430 localhost \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430, \u0442\u0430\u043a \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u0440\u0430\u0437\u0434\u0435\u043b \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0449\u0443\u043f\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u043c\u0435\u044f \u043f\u043e\u0434 \u0440\u0443\u043a\u043e\u0439 \u0434\u0432\u0430 \u0445\u043e\u0441\u0442\u0430 \u0441 \u0434\u043e\u043a\u0435\u0440\u043e\u043c. \u041d\u0430 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u043a\u0430\u0445 \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ ssh production-server docker image ls REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE  $ docker image save uptimer | ssh production-server 'docker image load' Loaded image: uptimer:latest  $ ssh production-server docker image ls REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE uptimer             latest              1d56897841ec        5 minutes ago       78.9MB<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u043e\u043c\u0430\u043d\u0434\u0430 <code>docker save<\/code> \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0431\u0440\u0430\u0437\u0430 \u0432 .tar \u0430\u0440\u0445\u0438\u0432, \u0442\u043e \u0435\u0441\u0442\u044c \u043e\u043d \u0432\u0435\u0441\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0432 1.5 \u0440\u0430\u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u0435, \u0447\u0435\u043c \u043c\u043e\u0433 \u0431\u044b \u0432\u0435\u0441\u0438\u0442\u044c \u0432 \u0441\u0436\u0430\u0442\u043e\u043c \u0432\u0438\u0434\u0435. \u0422\u0430\u043a \u043f\u043e\u0436\u043c\u0451\u043c \u0436\u0435 \u0435\u0433\u043e \u0432\u043e \u0438\u043c\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438 \u0442\u0440\u0430\u0444\u0438\u043a\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ docker image save uptimer | gzip | ssh production-server 'zcat | docker image load' Loaded image: uptimer:latest<\/code><\/pre>\n<p>  <\/p>\n<p>\u0410 \u0435\u0449\u0451, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0437\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c \u043f\u0435\u0440\u0435\u043a\u0430\u0447\u043a\u0438 (\u043f\u0440\u0430\u0432\u0434\u0430, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u044f\u044f \u0443\u0442\u0438\u043b\u0438\u0442\u0430):<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ docker image save uptimer | gzip | pv | ssh production-server 'zcat | docker image load' 25,7MiB 0:01:01 [ 425KiB\/s] [                   &lt;=&gt;    ] Loaded image: uptimer:latest<\/code><\/pre>\n<p>  <\/p>\n<blockquote><p>\u0421\u043e\u0432\u0435\u0442: \u0415\u0441\u043b\u0438 \u0412\u0430\u043c \u0434\u043b\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043f\u043e SSH \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043a\u0443\u0447\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0432\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u0444\u0430\u0439\u043b <code>~\/.ssh\/config<\/code>.<\/p><\/blockquote>\n<p>\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043e\u0431\u0440\u0430\u0437\u0430 \u0447\u0435\u0440\u0435\u0437 <code>docker image save\/load<\/code> \u2014 \u044d\u0442\u043e \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434, \u043d\u043e \u043d\u0435 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439. \u0415\u0441\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435:<\/p>\n<p>  <\/p>\n<ol>\n<li>Container Registry (\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u043e\u0442\u0440\u0430\u0441\u043b\u0438).<\/li>\n<li>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a docker daemon \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0445\u043e\u0441\u0442\u0430:<br \/> \n<ol>\n<li>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0441\u0440\u0435\u0434\u044b <code>DOCKER_HOST<\/code>.<\/li>\n<li>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 <code>-H<\/code> \u0438\u043b\u0438 <code>--host<\/code> \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 <code>docker-compose<\/code>.<\/li>\n<li><code>docker context<\/code><\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p>  <\/p>\n<p>\u0412\u0442\u043e\u0440\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 (\u0441 \u0442\u0440\u0435\u043c\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u043c\u0438 \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438) \u0445\u043e\u0440\u043e\u0448\u043e \u043e\u043f\u0438\u0441\u0430\u043d \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 <a href=\"https:\/\/www.docker.com\/blog\/how-to-deploy-on-remote-docker-hosts-with-docker-compose\/\" rel=\"nofollow\">How to deploy on remote Docker hosts with docker-compose<\/a>.<\/p>\n<p>  <\/p>\n<h2 id=\"deploysh\"><code>deploy.sh<\/code><\/h2>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0431\u0435\u0440\u0451\u043c \u0432\u0441\u0451, \u0447\u0442\u043e \u043c\u044b \u0434\u0435\u043b\u0430\u043b\u0438 \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0432 \u043e\u0434\u0438\u043d \u0441\u043a\u0440\u0438\u043f\u0442. \u041d\u0430\u0447\u043d\u0451\u043c \u0441 top-level \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0430 \u043f\u043e\u0442\u043e\u043c \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0432 \u043d\u0435\u0439.<\/p>\n<p>  <\/p>\n<h3 id=\"interesnye-tehniki-3\">\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0442\u0435\u0445\u043d\u0438\u043a\u0438<\/h3>\n<p>  <\/p>\n<ul>\n<li><code>${parameter?err_msg}<\/code> \u2014 \u043e\u0434\u043d\u043e \u0438\u0437 \u0437\u0430\u043a\u043b\u0438\u043d\u0430\u043d\u0438\u0439 bash-\u043c\u0430\u0433\u0438\u0438 (aka <a href=\"https:\/\/www.tldp.org\/LDP\/abs\/html\/parameter-substitution.html\" rel=\"nofollow\">parameter substitution<\/a>). \u0415\u0441\u043b\u0438 <code>parameter<\/code> \u043d\u0435 \u0437\u0430\u0434\u0430\u043d, \u0432\u044b\u0432\u0435\u0441\u0442\u0438 <code>err_msg<\/code> \u0438 \u0432\u044b\u0439\u0442\u0438 \u0441 \u043a\u043e\u0434\u043e\u043c 1.<\/li>\n<li><code>docker --log-driver journald<\/code> \u2014 \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u043e\u043c \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u043a\u0435\u0440\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u0431\u0435\u0437 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u0440\u043e\u0442\u0430\u0446\u0438\u0438. \u0421 \u0442\u0430\u043a\u0438\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c \u043b\u043e\u0433\u0438 \u0431\u044b\u0441\u0442\u0440\u043e \u0437\u0430\u0431\u0438\u0432\u0430\u044e\u0442 \u0432\u0435\u0441\u044c \u0434\u0438\u0441\u043a, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f production-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u0443\u043c\u043d\u044b\u0439.<\/li>\n<\/ul>\n<p>  <\/p>\n<h3 id=\"skript-deploymenta\">\u0421\u043a\u0440\u0438\u043f\u0442 \u0434\u0435\u043f\u043b\u043e\u0439\u043c\u0435\u043d\u0442\u0430<\/h3>\n<p>  <\/p>\n<pre><code class=\"bash\">deploy() {     local usage_msg=&quot;Usage: ${FUNCNAME[0]} image_name&quot;     local image_name=${1?$usage_msg}      ensure-reverse-proxy || return 2     if get-active-slot $image_name     then         local OLD=${image_name}_BLUE         local new_slot=GREEN     else         local OLD=${image_name}_GREEN         local new_slot=BLUE     fi     local NEW=${image_name}_${new_slot}     echo &quot;Deploying '$NEW' in place of '$OLD'...&quot;     docker run \\         --detach \\         --restart always \\         --log-driver journald \\         --name $NEW \\         --network web-gateway \\         $image_name || return 3     echo &quot;Container started. Checking health...&quot;     for i in {1..20}     do         sleep 1         if get-service-status $image_name $new_slot         then             echo &quot;New '$NEW' service seems OK. Switching heads...&quot;             sleep 2  # Ensure service is ready             set-active-slot $image_name $new_slot || return 4             echo &quot;'$NEW' service is live!&quot;             sleep 2  # Ensure all requests were processed             echo &quot;Killing '$OLD'...&quot;             docker rm -f $OLD             docker image prune -f             echo &quot;Deployment successful!&quot;             return 0         fi         echo &quot;New '$NEW' service is not ready yet. Waiting ($i)...&quot;     done     echo &quot;New '$NEW' service did not raise, killing it. Failed to deploy T_T&quot;     docker rm -f $NEW     return 5 }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>ensure-reverse-proxy<\/code> \u2014 \u0423\u0431\u0435\u0436\u0434\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 (\u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0434\u043b\u044f \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0434\u0435\u043f\u043b\u043e\u044f)<\/li>\n<li><code>get-active-slot service_name<\/code> \u2014 \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043a\u0430\u043a\u043e\u0439 \u0441\u0435\u0439\u0447\u0430\u0441 \u0441\u043b\u043e\u0442 \u0430\u043a\u0442\u0438\u0432\u0435\u043d \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 (<code>BLUE<\/code> \u0438\u043b\u0438 <code>GREEN<\/code>)<\/li>\n<li><code>get-service-status service_name deployment_slot<\/code> \u2014 \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0433\u043e\u0442\u043e\u0432 \u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441 \u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/li>\n<li><code>set-active-slot service_name deployment_slot<\/code> \u2014 \u041c\u0435\u043d\u044f\u0435\u0442 \u043a\u043e\u043d\u0444\u0438\u0433 nginx \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">ensure-reverse-proxy() {     is-container-up reverse-proxy &amp;&amp; return 0     echo &quot;Deploying reverse-proxy...&quot;     docker network create web-gateway     docker run \\         --detach \\         --restart always \\         --log-driver journald \\         --name reverse-proxy \\         --network web-gateway \\         --publish 80:80 \\         nginx:alpine || return 1     docker exec --interactive reverse-proxy sh -c &quot;&gt; \/etc\/nginx\/conf.d\/default.conf&quot;     docker exec reverse-proxy nginx -s reload }  is-container-up() {     local container=${1?&quot;Usage: ${FUNCNAME[0]} container_name&quot;}      [ -n &quot;$(docker ps -f name=${container} -q)&quot; ]     return $? }  get-active-slot() {     local service=${1?&quot;Usage: ${FUNCNAME[0]} service_name&quot;}      if is-container-up ${service}_BLUE &amp;&amp; is-container-up ${service}_GREEN; then         echo &quot;Collision detected! Stopping ${service}_GREEN...&quot;         docker rm -f ${service}_GREEN         return 0  # BLUE     fi     if is-container-up ${service}_BLUE &amp;&amp; ! is-container-up ${service}_GREEN; then         return 0  # BLUE     fi     if ! is-container-up ${service}_BLUE; then         return 1  # GREEN     fi }  get-service-status() {     local usage_msg=&quot;Usage: ${FUNCNAME[0]} service_name deployment_slot&quot;     local service=${1?usage_msg}     local slot=${2?$usage_msg}      case $service in         # Add specific healthcheck paths for your services here         *) local health_check_port_path=&quot;:8080\/&quot; ;;     esac     local health_check_address=&quot;http:\/\/${service}_${slot}${health_check_port_path}&quot;     echo &quot;Requesting '$health_check_address' within the 'web-gateway' docker network:&quot;     docker run --rm --network web-gateway alpine \\         wget --timeout=1 --quiet --server-response $health_check_address     return $? }  set-active-slot() {     local usage_msg=&quot;Usage: ${FUNCNAME[0]} service_name deployment_slot&quot;     local service=${1?$usage_msg}     local slot=${2?$usage_msg}     [ &quot;$slot&quot; == BLUE ] || [ &quot;$slot&quot; == GREEN ] || return 1      get-nginx-config $service $slot | docker exec --interactive reverse-proxy sh -c &quot;cat &gt; \/etc\/nginx\/conf.d\/$service.conf&quot;     docker exec reverse-proxy nginx -t || return 2     docker exec reverse-proxy nginx -s reload }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f <code>get-active-slot<\/code> \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u0439:<\/p>\n<p>  <\/p>\n<blockquote><p>\u041f\u043e\u0447\u0435\u043c\u0443 \u043e\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0447\u0438\u0441\u043b\u043e, \u0430 \u043d\u0435 \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0441\u0442\u0440\u043e\u043a\u0443?<\/p><\/blockquote>\n<p>\u0412\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u0432 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0435\u0451 \u0440\u0430\u0431\u043e\u0442\u044b, \u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c exit code \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 bash \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0449\u0435, \u0447\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0443. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435, \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u043d\u0435\u0451 \u0441\u0442\u0440\u043e\u043a\u0443 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e:<br \/>  <code>get-active-slot service &amp;&amp; echo BLUE || echo GREEN<\/code>.<\/p>\n<p>  <\/p>\n<blockquote><p>\u0410 \u0442\u0440\u0451\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u0442\u043e\u0447\u043d\u043e \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f?<\/p><\/blockquote>\n<p><a href=\"https:\/\/viewer.diagrams.net\/?highlight=0000ff&amp;nav=1&amp;title=get-active-slot.drawio#Uhttps%3A%2F%2Fdrive.google.com%2Fuc%3Fid%3D1XUeTRTGc-1TcIUwvNABmii_-D2grg8uH%26export%3Ddownload\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ko\/xc\/xk\/koxcxkowoq-lwpuczszmhcwsvya.png\"><\/a><\/p>\n<p>  <\/p>\n<p>\u0414\u0430\u0436\u0435 \u0434\u0432\u0443\u0445 \u0445\u0432\u0430\u0442\u0438\u0442, \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0442\u0443\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0442\u044b, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c <code>else<\/code>.<\/p>\n<p>  <\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u0430\u0441\u044c \u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0439 \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0438 nginx: <code>get-nginx-config service_name deployment_slot<\/code>. \u041f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 \u0445\u0435\u043b\u0441\u0447\u0435\u043a\u043e\u043c, \u0442\u0443\u0442 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433 \u0434\u043b\u044f \u043b\u044e\u0431\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0418\u0437 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0433\u043e \u2014 \u0442\u043e\u043b\u044c\u043a\u043e <code>cat &lt;&lt;- EOF<\/code>, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u0442\u0430\u0431\u044b \u0432 \u043d\u0430\u0447\u0430\u043b\u0435. \u041f\u0440\u0430\u0432\u0434\u0430, \u0446\u0435\u043d\u0430 \u0431\u043b\u0430\u0433\u043e\u0432\u0438\u0434\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u2014 \u0441\u043c\u0435\u0448\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u044b \u0441 \u043f\u0440\u043e\u0431\u0435\u043b\u0430\u043c\u0438, \u0447\u0442\u043e \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u0434\u0443\u0440\u043d\u044b\u043c \u0442\u043e\u043d\u043e\u043c. \u041d\u043e bash \u0444\u043e\u0440\u0441\u0438\u0442 \u0442\u0430\u0431\u044b, \u0430 \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0435 nginx \u0442\u043e\u0436\u0435 \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u0438\u043c\u0435\u0442\u044c \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435. \u041a\u043e\u0440\u043e\u0447\u0435, \u0442\u0443\u0442 \u0441\u043c\u0435\u0448\u0435\u043d\u0438\u0435 \u0442\u0430\u0431\u043e\u0432 \u0441 \u043f\u0440\u043e\u0431\u0435\u043b\u0430\u043c\u0438 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043b\u0443\u0447\u0448\u0438\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0438\u0437 \u0445\u0443\u0434\u0448\u0438\u0445. \u041e\u0434\u043d\u0430\u043a\u043e, \u0432 \u0441\u043d\u0438\u043f\u043f\u0435\u0442\u0435 \u043d\u0438\u0436\u0435 \u0412\u044b \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0443\u0432\u0438\u0434\u0438\u0442\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0445\u0430\u0431\u0440 &quot;\u0434\u0435\u043b\u0430\u0435\u0442 \u0445\u043e\u0440\u043e\u0448\u043e&quot;, \u043c\u0435\u043d\u044f\u044f \u0432\u0441\u0435 \u0442\u0430\u0431\u044b \u043d\u0430 4 \u043f\u0440\u043e\u0431\u0435\u043b\u0430 \u0438 \u0434\u0435\u043b\u0430\u044f \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c EOF. <a href=\"https:\/\/gist.github.com\/Himura2la\/21d6054eb9af69438946928387b76360#file-deploy-sh-L142\" rel=\"nofollow\">\u0410 \u0432\u043e\u0442 \u0442\u0443\u0442 \u0437\u0430\u043c\u0435\u0442\u043d\u043e<\/a>.<\/p>\n<p>  <\/p>\n<blockquote><p>\u0427\u0442\u043e\u0431 \u0434\u0432\u0430 \u0440\u0430\u0437\u0430 \u043d\u0435 \u0432\u0441\u0442\u0430\u0432\u0430\u0442\u044c, \u0441\u0440\u0430\u0437\u0443 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e <code>cat &lt;&lt; 'EOF'<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0435\u0449\u0451 \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442\u0441\u044f \u0434\u0430\u043b\u0435\u0435. \u0415\u0441\u043b\u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e <code>cat &lt;&lt; EOF<\/code>, \u0442\u043e \u0432\u043d\u0443\u0442\u0440\u0438 heredoc \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u044f \u0441\u0442\u0440\u043e\u043a\u0438 (\u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 (<code>$foo<\/code>), \u0432\u044b\u0437\u043e\u0432\u044b \u043a\u043e\u043c\u0430\u043d\u0434 (<code>$(bar)<\/code>) \u0438 \u0442.\u0434.), \u0430 \u0435\u0441\u043b\u0438 \u0437\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u0440\u0438\u0437\u043d\u0430\u043a \u043a\u043e\u043d\u0446\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 \u0432 \u043e\u0434\u0438\u043d\u0430\u0440\u043d\u044b\u0435 \u043a\u043e\u0432\u044b\u0447\u043a\u0438, \u0442\u043e \u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u044f \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0438 \u0441\u0438\u043c\u0432\u043e\u043b <code>$<\/code> \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a\u0430\u043a \u0435\u0441\u0442\u044c. \u0422\u043e \u0447\u0442\u043e \u043d\u0430\u0434\u043e \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0432\u043d\u0443\u0442\u0440\u044c \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430.<\/p><\/blockquote>\n<p>  <\/p>\n<pre><code class=\"bash\">get-nginx-config() {     local usage_msg=&quot;Usage: ${FUNCNAME[0]} service_name deployment_slot&quot;     local service=${1?$usage_msg}     local slot=${2?$usage_msg}     [ &quot;$slot&quot; == BLUE ] || [ &quot;$slot&quot; == GREEN ] || return 1      local container_name=${service}_${slot}     case $service in         # Add specific nginx configs for your services here         *) nginx-config-simple-service $container_name:8080 ;;     esac }  nginx-config-simple-service() {     local usage_msg=&quot;Usage: ${FUNCNAME[0]} proxy_pass&quot;     local proxy_pass=${1?$usage_msg}  cat &lt;&lt; EOF server {     listen 80;     location \/ {         proxy_pass http:\/\/$proxy_pass;     } } EOF }<\/code><\/pre>\n<p>  <\/p>\n<p>\u042d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u0432\u0435\u0441\u044c \u0441\u043a\u0440\u0438\u043f\u0442. \u0418 \u0432\u043e\u0442 <a href=\"https:\/\/gist.github.com\/Himura2la\/21d6054eb9af69438946928387b76360\" rel=\"nofollow\">\u0433\u0438\u0441\u0442 \u0441 \u044d\u0442\u0438\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c<\/a> \u0434\u043b\u044f \u0441\u043a\u0430\u0447\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 wget \u0438\u043b\u0438 curl.<\/p>\n<p>  <\/p>\n<h2 id=\"vypolnenie-parametrizirovannyh-skriptov-na-udalyonnom-servere\">\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u043d\u0430 \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435<\/h2>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u0442\u0443\u0447\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0446\u0435\u043b\u0435\u0432\u043e\u0439 \u0441\u0435\u0440\u0432\u0435\u0440. \u0412 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 <code>localhost<\/code> \u0432\u043f\u043e\u043b\u043d\u0435 \u043f\u043e\u0434\u043e\u0439\u0434\u0451\u0442:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ ssh-copy-id localhost \/usr\/bin\/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed \/usr\/bin\/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys himura@localhost's password:   Number of key(s) added: 1  Now try logging into the machine, with:   &quot;ssh 'localhost'&quot; and check to make sure that only the key(s) you wanted were added.<\/code><\/pre>\n<p>  <\/p>\n<p>\u041c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u0435\u043f\u043b\u043e\u0439\u043c\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u043d\u0430 \u0446\u0435\u043b\u0435\u0432\u043e\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u0431\u0435\u0441\u0448\u043e\u0432\u043d\u043e \u043f\u043e\u0434\u043c\u0435\u043d\u044f\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u043d\u043e \u043a\u0430\u043a \u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0430 \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435? \u0423 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0435\u0441\u0442\u044c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u0435\u043d \u0438 \u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c \u0441\u0440\u0430\u0437\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043f\u043e\u0434 \u043e\u0434\u0438\u043d \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 (\u043a\u043e\u043d\u0444\u0438\u0433\u0430\u043c\u0438 nginx \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0440\u0443\u043b\u0438\u0442\u044c \u043f\u043e \u043a\u0430\u043a\u043e\u043c\u0443 url \u043a\u0430\u043a\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u0435\u0440\u0432\u0438\u0441). \u0421\u043a\u0440\u0438\u043f\u0442 \u043d\u0435\u043b\u044c\u0437\u044f \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u0435\u0433\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c (\u0441 \u0446\u0435\u043b\u044c\u044e \u0431\u0430\u0433\u0444\u0438\u043a\u0441\u043e\u0432 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u044b), \u0434\u0430 \u0438 \u0432\u043e\u043e\u0431\u0449\u0435, \u0441\u0442\u044d\u0439\u0442 = \u0437\u043b\u043e.<\/p>\n<p>  <\/p>\n<p>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 1: \u0422\u0430\u043a\u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u043d\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u0447\u0435\u0440\u0435\u0437 <code>scp<\/code>. \u0417\u0430\u0442\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043f\u043e <code>ssh<\/code> \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0441 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c\u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438.<\/p>\n<p>  <\/p>\n<p>\u041c\u0438\u043d\u0443\u0441\u044b:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0414\u0432\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0432\u043c\u0435\u0441\u0442\u043e \u043e\u0434\u043d\u043e\u0433\u043e<\/li>\n<li>\u041c\u0435\u0441\u0442\u0430 \u043a\u0443\u0434\u0430 \u0432\u044b \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u0442\u0435 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0431\u044b\u0442\u044c, \u0438\u043b\u0438 \u043d\u0435 \u0431\u044b\u0442\u044c \u043a \u043d\u0435\u043c\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u0430, \u0438\u043b\u0438 \u0441\u043a\u0440\u0438\u043f\u0442 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u043e\u0434\u043c\u0435\u043d\u044b.<\/li>\n<li>\u0416\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u0431\u0440\u0430\u0442\u044c \u0437\u0430 \u0441\u043e\u0431\u043e\u0439 (\u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442).<\/li>\n<li>\u0423\u0436\u0435 \u0442\u0440\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 2: <\/p>\n<p>  <\/p>\n<ul>\n<li>\u0412 \u0441\u043a\u0440\u0438\u043f\u0442\u0435 \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c<\/li>\n<li>\u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>sed<\/code> \u0434\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432 \u043a\u043e\u043d\u0435\u0446 \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/li>\n<li>\u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u0441\u0451 \u044d\u0442\u043e \u043f\u0440\u044f\u043c\u043e \u0432 shh \u0447\u0435\u0440\u0435\u0437 pipe (<code>|<\/code>)<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041f\u043b\u044e\u0441\u044b:<\/p>\n<p>  <\/p>\n<ul>\n<li>Truely stateless<\/li>\n<li>No boilerplate entities<\/li>\n<li>Feeling cool<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0412\u043e\u0442 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0435\u0437 Ansible. \u0414\u0430, \u0432\u0441\u0451 \u0443\u0436\u0435 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u043d\u043e. \u0414\u0430, \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434. \u0421\u043c\u043e\u0442\u0440\u0438\u0442\u0435, \u043a\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439, \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u044b\u0439 \u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ cat &lt;&lt; 'EOF' &gt; deploy.sh<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"bash\">#!\/bin\/bash  usage_msg=&quot;Usage: $0 ssh_address local_image_tag&quot; ssh_address=${1?$usage_msg} image_name=${2?$usage_msg}  echo &quot;Connecting to '$ssh_address' via ssh to seamlessly deploy '$image_name'...&quot; ( sed &quot;\\$a deploy $image_name&quot; | ssh -T $ssh_address ) &lt;&lt; 'END_OF_SCRIPT' deploy() {     echo &quot;Yay! The '${FUNCNAME[0]}' function is executing on '$(hostname)' with argument '$1'&quot; } END_OF_SCRIPT<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"plaintext\">EOF  $ chmod +x deploy.sh  $ .\/deploy.sh localhost magic-porridge-pot Connecting to localhost... Yay! The 'deploy' function is executing on 'hut' with argument 'magic-porridge-pot'<\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e, \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0431\u044b\u0442\u044c \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u043d\u0430 \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u043c \u0445\u043e\u0441\u0442\u0435 \u0435\u0441\u0442\u044c \u0430\u0434\u0435\u043a\u0432\u0430\u0442\u043d\u044b\u0439 bash, \u0442\u0430\u043a \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0430\u0447\u0430\u043b\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u0447\u043a\u0443 (\u044d\u0442\u043e \u0432\u043c\u0435\u0441\u0442\u043e <a href=\"https:\/\/en.wikipedia.org\/wiki\/Shebang_(Unix)\" rel=\"nofollow\">shellbang<\/a>):<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">if [ &quot;$SHELL&quot; != &quot;\/bin\/bash&quot; ] then     echo &quot;The '$SHELL' shell is not supported by 'deploy.sh'. Set a '\/bin\/bash' shell for '$USER@$HOSTNAME'.&quot;     exit 1 fi<\/code><\/pre>\n<p>  <\/p>\n<p>\u0410 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0451 \u043f\u043e-\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u043c\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ docker exec reverse-proxy rm \/etc\/nginx\/conf.d\/default.conf  $ wget -qO deploy.sh https:\/\/git.io\/JUJml  $ chmod +x deploy.sh  $ .\/deploy.sh localhost uptimer Sending gzipped image 'uptimer' to 'localhost' via ssh... Loaded image: uptimer:latest Connecting to 'localhost' via ssh to seamlessly deploy 'uptimer'... Deploying 'uptimer_GREEN' in place of 'uptimer_BLUE'... 06f5bc70e9c4f930e7b1f826ae2ca2f536023cc01e82c2b97b2c84d68048b18a Container started. Checking health... Requesting 'http:\/\/uptimer_GREEN:8080\/' within the 'web-gateway' docker network:   HTTP\/1.0 503 Service Unavailable wget: server returned error: HTTP\/1.0 503 Service Unavailable New 'uptimer_GREEN' service is not ready yet. Waiting (1)... Requesting 'http:\/\/uptimer_GREEN:8080\/' within the 'web-gateway' docker network:   HTTP\/1.0 503 Service Unavailable wget: server returned error: HTTP\/1.0 503 Service Unavailable New 'uptimer_GREEN' service is not ready yet. Waiting (2)... Requesting 'http:\/\/uptimer_GREEN:8080\/' within the 'web-gateway' docker network:   HTTP\/1.0 200 OK   Server: BaseHTTP\/0.6 Python\/3.8.3   Date: Sat, 22 Aug 2020 20:15:50 GMT   Content-Type: text\/html  New 'uptimer_GREEN' service seems OK. Switching heads... nginx: the configuration file \/etc\/nginx\/nginx.conf syntax is ok nginx: configuration file \/etc\/nginx\/nginx.conf test is successful 2020\/08\/22 20:15:54 [notice] 97#97: signal process started 'uptimer_GREEN' service is live! Killing 'uptimer_BLUE'... uptimer_BLUE Total reclaimed space: 0B Deployment successful!<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c <a href=\"http:\/\/localhost\/\" rel=\"nofollow\">http:\/\/localhost\/<\/a> \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0434\u0435\u043f\u043b\u043e\u0439\u043c\u0435\u043d\u0442 \u0435\u0449\u0451 \u0440\u0430\u0437 \u0438 \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043e\u043d \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0431\u0435\u0441\u0448\u043e\u0432\u043d\u043e \u043f\u0443\u0442\u0451\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043f\u043e \u041a\u0414 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u044b\u043a\u043b\u0430\u0434\u043a\u0438.<\/p>\n<p>  <\/p>\n<h2 id=\"ne-zabyvaem-ubiratsya-posle-raboty-3\">\u041d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u0443\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0440\u0430\u0431\u043e\u0442\u044b :3<\/h2>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ docker rm -f uptimer_GREEN reverse-proxy  uptimer_GREEN reverse-proxy  $ docker network rm web-gateway  web-gateway  $ cd ..  $ rm -r blue-green-deployment<\/code><\/pre>\n<\/div>\n<p> \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\/post\/516230\/\"> https:\/\/habr.com\/ru\/post\/516230\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/516230\/\">\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bash_(Unix_shell)\" rel=\"nofollow\">bash<\/a>, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Secure_Shell\" rel=\"nofollow\">ssh<\/a>, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Docker_(software)\" rel=\"nofollow\">docker<\/a> \u0438 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Nginx\" rel=\"nofollow\">nginx<\/a> \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u043c \u0431\u0435\u0441\u0448\u043e\u0432\u043d\u0443\u044e \u0432\u044b\u043a\u043b\u0430\u0434\u043a\u0443 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. <a href=\"https:\/\/martinfowler.com\/bliki\/BlueGreenDeployment.html\" rel=\"nofollow\">Blue-green deployment<\/a> \u2014 \u044d\u0442\u043e \u0442\u0435\u0445\u043d\u0438\u043a\u0430, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0430\u044f \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043d\u0435 \u043e\u0442\u043a\u043b\u043e\u043d\u044f\u044f \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u041e\u043d\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0439 zero downtime deployment \u0438 \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441 \u043e\u0434\u043d\u0438\u043c \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u043c, \u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0440\u044f\u0434\u043e\u043c \u0432\u0442\u043e\u0440\u043e\u0439, \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043a \u0440\u0430\u0431\u043e\u0442\u0435 \u0438\u043d\u0441\u0442\u0430\u043d\u0441.<\/p>\n<p>  <\/p>\n<p>\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u0443 \u0412\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432, \u0438 \u0435\u043c\u0443 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u0438\u043a\u0430\u043a \u043d\u0435\u043b\u044c\u0437\u044f \u043d\u0430 \u043f\u0430\u0440\u0443 \u0441\u0435\u043a\u0443\u043d\u0434 \u043f\u0440\u0438\u043b\u0435\u0447\u044c. \u0410 \u0412\u0430\u043c \u043e\u0447\u0435\u043d\u044c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043a\u0430\u0442\u0438\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0444\u0438\u043a\u0441 \u0431\u0430\u0433\u0430 \u0438\u043b\u0438 \u043d\u043e\u0432\u0443\u044e \u043a\u0440\u0443\u0442\u0443\u044e \u0444\u0438\u0447\u0443. \u0412 \u043e\u0431\u044b\u0447\u043d\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0435\u0433\u043e \u0438 \u0441\u043d\u043e\u0432\u0430 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0434\u043e\u043a\u0435\u0440\u0430, \u043c\u043e\u0436\u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c, \u043f\u043e\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c, \u043d\u043e \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0438\u043e\u0434, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u043d\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442\u0441\u044f, \u0432\u0435\u0434\u044c \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0443\u044e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443. \u0410 \u0435\u0441\u043b\u0438 \u043e\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f, \u043d\u043e \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0435\u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b\u043c? \u0412\u043e\u0442 \u0442\u0430\u043a\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0435\u0451 \u0440\u0435\u0448\u0430\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 \u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u043e.<\/p>\n<p>  <\/p>\n<p>DISCLAIMER: \u0411\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u2014 \u0432 \u0432\u0438\u0434\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u043e\u0439 \u0441\u0435\u0441\u0441\u0438\u0438. \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0441\u043b\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c, \u0438 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0441\u0430\u043c \u0441\u0435\u0431\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u0432 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e\u043c \u043e\u0431\u044a\u0451\u043c\u0435. \u0414\u043b\u044f \u0430\u0442\u043c\u043e\u0441\u0444\u0435\u0440\u043d\u043e\u0441\u0442\u0438, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u044c\u0442\u0435, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043a\u043e\u0434\u0441\u043d\u0438\u043f\u043f\u0435\u0442\u044b, \u0430 \u0431\u0443\u043c\u0430\u0433\u0430 \u0438\u0437 &quot;\u0436\u0435\u043b\u0435\u0437\u043d\u043e\u0433\u043e&quot; \u0442\u0435\u043b\u0435\u0442\u0430\u0439\u043f\u0430.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/youtu.be\/2XLZ4Z8LpEE\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/an\/av\/tg\/anavtgfhojyh9rjqi7cvvtxe8z0.jpeg\"><\/a><\/p>\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-308944","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/308944","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=308944"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/308944\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=308944"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=308944"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=308944"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}