{"id":295592,"date":"2019-12-17T16:20:44","date_gmt":"2019-12-17T16:20:44","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=295592"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=295592","title":{"rendered":"&#8216;Hello World&#8217; \u0432\u0430\u043c \u0432 \u043e\u0431\u043b\u0430\u043a\u043e"},"content":{"rendered":"\n<div class=\"post__text post__text-html js-mediator-article\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/465149\/\">\n<p>\u041c\u0438\u0440 \u0441\u0445\u043e\u0434\u0438\u0442 \u0441 \u0443\u043c\u0430, \u0437\u0430\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u044f \u043a\u0430\u043b\u044c\u043a\u0443\u043b\u044f\u0442\u043e\u0440 \u0434\u043b\u044f 2+2 \u0432 \u043e\u0431\u043b\u0430\u043a\u0430. \u0427\u0435\u043c \u043c\u044b \u0445\u0443\u0436\u0435? \u0414\u0430\u0432\u0430\u0439\u0442\u0435 Hello World \u0437\u0430\u0442\u043e\u043b\u043a\u0430\u0435\u043c \u0432 \u0442\u0440\u0438 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0430\u0440\u0443-\u0442\u0440\u043e\u0439\u043a\u0443 \u0442\u0435\u0441\u0442\u043e\u0432, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439, \u043d\u0430\u0440\u0438\u0441\u0443\u0435\u043c \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0439 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u043c \u0434\u0435\u043f\u043b\u043e\u0439 \u0432 \u0443\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0439 \u043f\u0440\u043e\u0434 \u043f\u0440\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432. \u0418\u0442\u0430\u043a, \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430 \u043e\u0442 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0434\u043e \u0434\u0435\u043f\u043b\u043e\u044f \u0432 \u043f\u0440\u043e\u0434. \u0418\u043d\u0435\u0442\u0435\u0440\u0435\u0441\u043d\u043e? \u0442\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442<a name=\"habracut\"><\/a><\/p>\n<p>  <\/p>\n<h2 id=\"s-chegoooooo-nachinaetsya-roooo--\">\u0421 \u0447\u0435\u0433\u043e\u043e\u043e\u043e\u043e\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0420\u043e\u043e\u043e\u043e\u2026 ?<\/h2>\n<p>  <\/p>\n<p>\u041d\u0435\u0442 \u043d\u0435 \u0420\u043e\u0434\u0438\u043d\u0430, \u0430 \u043f\u0440\u043e\u0434\u0443\u043a\u0442. \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f c \u0438\u0434\u0435\u0438. \u0418\u0442\u0430\u043a, \u0438\u0434\u0435\u044f \u0442\u0430\u043a\u043e\u0432\u0430: <\/p>\n<p>  <\/p>\n<ul>\n<li>\u043d\u0443\u0436\u0435\u043d \u0441\u0435\u0440\u0432\u0438\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0434\u0430\u0451\u0442 &#8216;Hello World&#8217; \u043f\u043e REST API<\/li>\n<li>c\u043b\u043e\u0432\u043e <strong>&#8216;Hello&#8217;<\/strong> \u043e\u0442\u0434\u0430\u0451\u0442 \u043e\u0434\u0438\u043d \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441, \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0439, \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0439 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439_1<\/li>\n<li>c\u043b\u043e\u0432\u043e <strong>&#8216;World&#8217;<\/strong> \u043e\u0442\u0434\u0430\u0451\u0442 \u0432\u0442\u043e\u0440\u043e\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0432\u0435\u0434\u0435\u043d\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b_2<\/li>\n<li>\u043a\u043e\u043c\u0430\u043d\u0434\u0430_3 \u043f\u0438\u0448\u0435\u0442 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u0441\u043a\u043b\u0435\u0438\u0432\u0430\u043d\u0438\u044f &#8216;Hello&#8217; \u0438 &#8216;World&#8217;<\/li>\n<\/ul>\n<p>  <\/p>\n<h3 id=\"toolset\">Toolset<\/h3>\n<p>  <\/p>\n<ul>\n<li>OS (desktop) \u2014 Debian 9 Stretch<\/li>\n<li>IDE \u2014 IntelliJ IDEA 2019.1<\/li>\n<li>Git Repo \u2014 GitHub<\/li>\n<li>CI \u2014 Concourse 5.4.0<\/li>\n<li>Maven Repo \u2014 Nexus<\/li>\n<li>OpenJDK 11<\/li>\n<li>Maven 3.6.0<\/li>\n<li>Kubernetes 1.14 (1 master + 1 worker): calico network, nginx-ingress-controller<\/li>\n<\/ul>\n<p>  <\/p>\n<blockquote><p><strong>\u0412\u0430\u0436\u043d\u0430\u044f \u0437\u0430\u043c\u0435\u0442\u043a\u0430:<\/strong> \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0435 \u043e \u043a\u0440\u0430\u0441\u0438\u0432\u043e\u043c \u043a\u043e\u0434\u0435 (codestyle, checkstyle, javadocs, SOLID \u0438 \u043f\u0440\u043e\u0447\u0438\u0435 \u0443\u043c\u043d\u044b\u0435 \u0441\u043b\u043e\u0432\u0430) \u0438 \u0432\u044b\u043b\u0438\u0437\u0430\u043d\u043d\u044b\u0445 \u0434\u043e \u0438\u0434\u0435\u0430\u043b\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u044f\u0445 (\u0445\u043e\u043b\u0438\u0432\u0430\u0440\u0438\u0442\u044c \u043f\u0440\u043e \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u044b\u0439 Hello World \u043c\u043e\u0436\u043d\u043e \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e). \u041e\u043d\u0430 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u043e\u0435\u0434\u0438\u043d\u043e \u043a\u043e\u0434, \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438\u0438, \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0432\u0441\u0435\u0433\u043e \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0432 \u043f\u0440\u043e\u0434, \u0430 \u0432\u043c\u0435\u0441\u0442\u043e HelloWorld \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0443 \u0432\u0430\u0441 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u0432\u044b\u0441\u043e\u043a\u043e\u043d\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u0441 \u043a\u0443\u0447\u0435\u0439 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0438 \u043a\u0440\u0443\u0442\u044b\u0445 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u043a \u043d\u0435\u043c\u0443.<\/p><\/blockquote>\n<p>  <\/p>\n<h3 id=\"iz-chego-sostoit-servis\">\u0418\u0437 \u0447\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0441\u0435\u0440\u0432\u0438\u0441?<\/h3>\n<p>  <\/p>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u0432 \u0432\u0438\u0434\u0435 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430 \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432 \u0441\u0435\u0431\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u0432 \u0432\u0438\u0434\u0435 yaml-\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430 OpenAPI \u0438 \u0443\u043c\u0435\u0442\u044c \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u0435\u0451 \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443 (GET \/doc)<\/li>\n<li>\u043c\u0435\u0442\u043e\u0434\u044b API \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439 \u0438\u0437 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043f\u0443\u043d\u043a\u0442\u0430<\/li>\n<li>README.md \u0441 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0411\u0443\u0434\u0435\u043c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443. \u041f\u043e\u0435\u0445\u0430\u043b\u0438!<\/p>\n<p>  <\/p>\n<h2 id=\"hello-microservice\">&#8216;Hello&#8217; microservice<\/h2>\n<p>  <\/p>\n<h3 id=\"specification\">Specification<\/h3>\n<p>  <\/p>\n<p>\u0421\u043f\u0435\u043a\u0438 \u043f\u0438\u0448\u0435\u043c \u0432 Swagger Editor&#8217;\u0435 \u0438 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0438\u043c \u0436\u0435 \u0432 OpenAPI \u0441\u043f\u0435\u043a\u0443. Swagger Editor \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432 \u0434\u043e\u043a\u0435\u0440\u0435 \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439, \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044f swagger-\u0434\u043e\u043a\u0438 \u0432 openapi-\u0434\u043e\u043a\u0443 \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u0436\u0430\u0442\u0438\u0435\u043c \u043e\u0434\u043d\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438 \u0432 UI \u044d\u0434\u0438\u0442\u043e\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0448\u043b\u0451\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 <strong>POST \/api\/convert<\/strong> \u043d\u0430 <strong><a href=\"http:\/\/converter.swagger.io\" rel=\"nofollow\">http:\/\/converter.swagger.io<\/a><\/strong>. \u0418\u0442\u043e\u0433\u043e\u0432\u0430\u044f \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f hello \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">openapi: 3.0.1 info:   title: Hello ;)   description: Hello microservice   version: 1.0.0 servers:   - url: https:\/\/demo1.bihero.io\/api\/hello tags:   - name: hello     description: Everything about saying 'Hello' paths:   \/:     x-vertx-event-bus:       address: service.hello       timeout: 1000c     get:       tags:         - hello       summary: Get 'Hello' word       operationId: getHelloWord       responses:         200:           description: OK   \/doc:     x-vertx-event-bus:       address: service.hello       timeout: 1000c     get:       tags:         - hello_doc       summary: Get 'Hello' microservice documentation       operationId: getDoc       responses:         200:           description: OK components: {}<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"implementation\">Implementation<\/h3>\n<p>  <\/p>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0434\u043e \u043f\u0438\u0441\u0430\u0442\u044c, \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 3-\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0441 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u0432 \u0441\u043f\u0435\u043a\u0435 \u043a\u0430\u043a <strong>operationId<\/strong>)<\/li>\n<li>\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430<\/li>\n<li>vertx verticle \u0434\u043b\u044f \u0431\u0438\u043d\u0434\u0438\u043d\u0433\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0441\u043e \u0441\u043f\u0435\u043a\u043e\u0439 (\u043c\u0435\u0442\u043e\u0434\u044b api -&gt; \u043c\u0435\u0442\u043e\u0434\u044b \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438\u0437 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043f\u0443\u043d\u043a\u0442\u0430) \u0438 \u0434\u043b\u044f \u0441\u0442\u0430\u0440\u0442\u0430 http-\u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 \u0432 src \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/n_\/mu\/7h\/n_mu7ht4nkqya165lkl7b44ii1w.png\"><\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pom.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt; &lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\"          xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"          xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\"&gt;     &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;      &lt;properties&gt;         &lt;main.verticle&gt;io.bihero.hello.HelloVerticle&lt;\/main.verticle&gt;         &lt;vertx.version&gt;3.8.1&lt;\/vertx.version&gt;         &lt;logback.version&gt;1.2.3&lt;\/logback.version&gt;         &lt;junit-jupiter.version&gt;5.3.1&lt;\/junit-jupiter.version&gt;         &lt;maven-surefire-plugin.version&gt;2.19.1&lt;\/maven-surefire-plugin.version&gt;         &lt;junit-platform-surefire-provider.version&gt;1.1.0&lt;\/junit-platform-surefire-provider.version&gt;         &lt;assertj-core.version&gt;3.8.0&lt;\/assertj-core.version&gt;         &lt;allure.version&gt;2.8.1&lt;\/allure.version&gt;         &lt;allure-maven.version&gt;2.10.0&lt;\/allure-maven.version&gt;         &lt;aspectj.version&gt;1.9.2&lt;\/aspectj.version&gt;         &lt;mockito.version&gt;2.21.0&lt;\/mockito.version&gt;         &lt;rest-assured.version&gt;3.0.0&lt;\/rest-assured.version&gt;     &lt;\/properties&gt;      &lt;groupId&gt;io.bihero&lt;\/groupId&gt;     &lt;artifactId&gt;hello-microservice&lt;\/artifactId&gt;     &lt;version&gt;1.0.0-SNAPSHOT&lt;\/version&gt;     &lt;build&gt;         &lt;plugins&gt;             &lt;plugin&gt;                 &lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;                 &lt;configuration&gt; ```1.8&lt;\/source&gt;                     &lt;target&gt;1.8&lt;\/target&gt;                 &lt;\/configuration&gt;                 &lt;executions&gt;                     &lt;execution&gt;                         &lt;id&gt;default-compile&lt;\/id&gt;                         &lt;configuration&gt;                             &lt;annotationProcessors&gt;                                 &lt;annotationProcessor&gt;io.vertx.codegen.CodeGenProcessor&lt;\/annotationProcessor&gt;                             &lt;\/annotationProcessors&gt;                             &lt;generatedSourcesDirectory&gt;src\/main\/generated&lt;\/generatedSourcesDirectory&gt;                             &lt;compilerArgs&gt;                                 &lt;arg&gt;-Acodegen.output=${project.basedir}\/src\/main&lt;\/arg&gt;                             &lt;\/compilerArgs&gt;                         &lt;\/configuration&gt;                     &lt;\/execution&gt;                     &lt;execution&gt;                         &lt;id&gt;default-testCompile&lt;\/id&gt;                         &lt;configuration&gt;                             &lt;annotationProcessors&gt;                                 &lt;annotationProcessor&gt;io.vertx.codegen.CodeGenProcessor&lt;\/annotationProcessor&gt;                             &lt;\/annotationProcessors&gt;                             &lt;generatedTestSourcesDirectory&gt;src\/test\/generated&lt;\/generatedTestSourcesDirectory&gt;                             &lt;compilerArgs&gt;                                 &lt;arg&gt;-Acodegen.output=${project.basedir}\/src\/test&lt;\/arg&gt;                             &lt;\/compilerArgs&gt;                         &lt;\/configuration&gt;                     &lt;\/execution&gt;                 &lt;\/executions&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-surefire-plugin&lt;\/artifactId&gt;                 &lt;version&gt;${maven-surefire-plugin.version}&lt;\/version&gt;                 &lt;configuration&gt;                     &lt;properties&gt;                         &lt;property&gt;                             &lt;name&gt;listener&lt;\/name&gt;                             &lt;value&gt;io.qameta.allure.junit5.AllureJunit5&lt;\/value&gt;                         &lt;\/property&gt;                     &lt;\/properties&gt;                     &lt;includes&gt;                         &lt;include&gt;**\/*Test*.java&lt;\/include&gt;                     &lt;\/includes&gt;                     &lt;argLine&gt;                         -javaagent:\"${settings.localRepository}\/org\/aspectj\/aspectjweaver\/${aspectj.version}\/aspectjweaver-${aspectj.version}.jar\" -Djdk.net.URLClassPath.disableClassPathURLCheck=true                     &lt;\/argLine&gt;                     &lt;systemProperties&gt;                         &lt;property&gt;                             &lt;name&gt;allure.results.directory&lt;\/name&gt;                             &lt;value&gt;${project.basedir}\/target\/allure-results&lt;\/value&gt;                         &lt;\/property&gt;                         &lt;property&gt;                             &lt;name&gt;junit.jupiter.extensions.autodetection.enabled&lt;\/name&gt;                             &lt;value&gt;true&lt;\/value&gt;                         &lt;\/property&gt;                     &lt;\/systemProperties&gt;                     &lt;reportFormat&gt;plain&lt;\/reportFormat&gt;                 &lt;\/configuration&gt;                 &lt;dependencies&gt;                     &lt;dependency&gt;                         &lt;groupId&gt;org.aspectj&lt;\/groupId&gt;                         &lt;artifactId&gt;aspectjweaver&lt;\/artifactId&gt;                         &lt;version&gt;${aspectj.version}&lt;\/version&gt;                     &lt;\/dependency&gt;                     &lt;dependency&gt;                         &lt;groupId&gt;org.junit.platform&lt;\/groupId&gt;                         &lt;artifactId&gt;junit-platform-surefire-provider&lt;\/artifactId&gt;                         &lt;version&gt;${junit-platform-surefire-provider.version}&lt;\/version&gt;                     &lt;\/dependency&gt;                     &lt;dependency&gt;                         &lt;groupId&gt;org.junit.jupiter&lt;\/groupId&gt;                         &lt;artifactId&gt;junit-jupiter-engine&lt;\/artifactId&gt;                         &lt;version&gt;${junit-jupiter.version}&lt;\/version&gt;                     &lt;\/dependency&gt;                 &lt;\/dependencies&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;io.qameta.allure&lt;\/groupId&gt;                 &lt;artifactId&gt;allure-maven&lt;\/artifactId&gt;                 &lt;version&gt;${allure-maven.version}&lt;\/version&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-site-plugin&lt;\/artifactId&gt;                 &lt;version&gt;3.7.1&lt;\/version&gt;                 &lt;dependencies&gt;                     &lt;dependency&gt;                         &lt;groupId&gt;org.apache.maven.wagon&lt;\/groupId&gt;                         &lt;artifactId&gt;wagon-webdav-jackrabbit&lt;\/artifactId&gt;                         &lt;version&gt;2.8&lt;\/version&gt;                     &lt;\/dependency&gt;                 &lt;\/dependencies&gt;             &lt;\/plugin&gt;              &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-project-info-reports-plugin&lt;\/artifactId&gt;                 &lt;version&gt;3.0.0&lt;\/version&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-shade-plugin&lt;\/artifactId&gt;                 &lt;version&gt;2.3&lt;\/version&gt;                 &lt;executions&gt;                     &lt;execution&gt;                         &lt;phase&gt;package&lt;\/phase&gt;                         &lt;goals&gt;                             &lt;goal&gt;shade&lt;\/goal&gt;                         &lt;\/goals&gt;                         &lt;configuration&gt;                             &lt;transformers&gt;                                 &lt;transformer implementation=\"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer\"&gt;                                     &lt;manifestEntries&gt;                                         &lt;Main-Class&gt;io.vertx.core.Launcher&lt;\/Main-Class&gt;                                         &lt;Main-Verticle&gt;${main.verticle}&lt;\/Main-Verticle&gt;                                     &lt;\/manifestEntries&gt;                                 &lt;\/transformer&gt;                                 &lt;transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\"&gt;                                     &lt;resource&gt;META-INF\/services\/io.vertx.core.spi.VerticleFactory&lt;\/resource&gt;                                 &lt;\/transformer&gt;                             &lt;\/transformers&gt;                             &lt;artifactSet&gt;                             &lt;\/artifactSet&gt;                             &lt;outputFile&gt;${project.build.directory}\/${project.artifactId}-fat.jar&lt;\/outputFile&gt;                         &lt;\/configuration&gt;                     &lt;\/execution&gt;                 &lt;\/executions&gt;             &lt;\/plugin&gt;         &lt;\/plugins&gt;         &lt;resources&gt;             &lt;resource&gt;                 &lt;directory&gt;src\/main\/resources&lt;\/directory&gt;                 &lt;filtering&gt;true&lt;\/filtering&gt;                 &lt;includes&gt;                     &lt;include&gt;**\/version.txt&lt;\/include&gt;                 &lt;\/includes&gt;             &lt;\/resource&gt;             &lt;resource&gt;                 &lt;directory&gt;src\/main\/resources&lt;\/directory&gt;                 &lt;filtering&gt;false&lt;\/filtering&gt;                 &lt;excludes&gt;                     &lt;exclude&gt;**\/version.txt&lt;\/exclude&gt;                 &lt;\/excludes&gt;             &lt;\/resource&gt;         &lt;\/resources&gt;     &lt;\/build&gt;     &lt;distributionManagement&gt;         &lt;site&gt;             &lt;id&gt;reports&lt;\/id&gt;             &lt;url&gt;dav:https:\/\/nexus.dev.techedge.pro:8443\/repository\/reports\/${project.artifactId}\/&lt;\/url&gt;         &lt;\/site&gt;     &lt;\/distributionManagement&gt;     &lt;reporting&gt;         &lt;excludeDefaults&gt;true&lt;\/excludeDefaults&gt;         &lt;plugins&gt;             &lt;plugin&gt;                 &lt;groupId&gt;io.qameta.allure&lt;\/groupId&gt;                 &lt;artifactId&gt;allure-maven&lt;\/artifactId&gt;                 &lt;configuration&gt;                     &lt;resultsDirectory&gt;${project.build.directory}\/allure-results&lt;\/resultsDirectory&gt;                     &lt;reportDirectory&gt;${project.reporting.outputDirectory}\/${project.version}\/allure&lt;\/reportDirectory&gt;                 &lt;\/configuration&gt;             &lt;\/plugin&gt;         &lt;\/plugins&gt;     &lt;\/reporting&gt;      &lt;dependencies&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-web-api-service&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-codegen&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;             &lt;scope&gt;provided&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;ch.qos.logback&lt;\/groupId&gt;             &lt;artifactId&gt;logback-classic&lt;\/artifactId&gt;             &lt;version&gt;${logback.version}&lt;\/version&gt;         &lt;\/dependency&gt;          &lt;!-- test &amp;ndash;&amp;gt;--&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-unit&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-junit5&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.junit.jupiter&lt;\/groupId&gt;             &lt;artifactId&gt;junit-jupiter-api&lt;\/artifactId&gt;             &lt;version&gt;${junit-jupiter.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.junit.jupiter&lt;\/groupId&gt;             &lt;artifactId&gt;junit-jupiter-engine&lt;\/artifactId&gt;             &lt;version&gt;${junit-jupiter.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.assertj&lt;\/groupId&gt;             &lt;artifactId&gt;assertj-core&lt;\/artifactId&gt;             &lt;version&gt;${assertj-core.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.mockito&lt;\/groupId&gt;             &lt;artifactId&gt;mockito-core&lt;\/artifactId&gt;             &lt;version&gt;${mockito.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.qameta.allure&lt;\/groupId&gt;             &lt;artifactId&gt;allure-junit5&lt;\/artifactId&gt;             &lt;version&gt;${allure.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-web-client&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;     &lt;\/dependencies&gt;  &lt;\/project&gt;<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">HelloService.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.hello;  import io.vertx.core.AsyncResult; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.ext.web.api.OperationRequest; import io.vertx.ext.web.api.OperationResponse; import io.vertx.ext.web.api.generator.WebApiServiceGen;  @WebApiServiceGen public interface HelloService {      static HelloService create(Vertx vertx) {         return new DefaultHelloService(vertx);     }      void getHelloWord(OperationRequest context, Handler&lt;AsyncResult&lt;OperationResponse&gt;&gt; resultHandler);      void getDoc(OperationRequest context, Handler&lt;AsyncResult&lt;OperationResponse&gt;&gt; resultHandler);  } <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">DefaultHelloService.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.hello;  import io.vertx.core.AsyncResult; import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.api.OperationRequest; import io.vertx.ext.web.api.OperationResponse;  public class DefaultHelloService implements HelloService {      private final Vertx vertx;      public DefaultHelloService(Vertx vertx) {         this.vertx = vertx;     }      @Override     public void getHelloWord(OperationRequest context, Handler&lt;AsyncResult&lt;OperationResponse&gt;&gt; resultHandler) {         resultHandler.handle(Future.succeededFuture(OperationResponse.completedWithPlainText(Buffer.buffer(\"Hello\"))));     }      @Override     public void getDoc(OperationRequest context, Handler&lt;AsyncResult&lt;OperationResponse&gt;&gt; resultHandler) {         vertx.fileSystem().readFile(\"doc.yaml\", buffResult -&gt;                 resultHandler.handle(Future.succeededFuture(                         OperationResponse.completedWithPlainText(buffResult.result()))                 ));     }  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">HelloVerticle.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.hello;  import io.vertx.core.AbstractVerticle; import io.vertx.core.Promise; import io.vertx.core.eventbus.MessageConsumer; import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerOptions; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.Router; import io.vertx.ext.web.api.contract.openapi3.OpenAPI3RouterFactory; import io.vertx.serviceproxy.ServiceBinder;  public class HelloVerticle extends AbstractVerticle {      private HttpServer server;     private MessageConsumer&lt;JsonObject&gt; consumer;      @Override     public void start(Promise&lt;Void&gt; promise) {         startHelloService();         startHttpServer().future().setHandler(promise);     }      \/**      * This method closes the http server and unregister all services loaded to Event Bus      *\/     @Override     public void stop(){         this.server.close();         consumer.unregister();     }      private void startHelloService() {         consumer = new ServiceBinder(vertx).setAddress(\"service.hello\")                 .register(HelloService.class, HelloService.create(getVertx()));     }      \/**      * This method constructs the router factory, mounts services and handlers and starts the http server      * with built router      * @return      *\/     private Promise&lt;Void&gt; startHttpServer() {         Promise&lt;Void&gt; promise = Promise.promise();         OpenAPI3RouterFactory.create(this.vertx, \"\/doc.yaml\", openAPI3RouterFactoryAsyncResult -&gt; {             if (openAPI3RouterFactoryAsyncResult.succeeded()) {                 OpenAPI3RouterFactory routerFactory = openAPI3RouterFactoryAsyncResult.result();                  \/\/ Mount services on event bus based on extensions                 routerFactory.mountServicesFromExtensions();                  \/\/ Generate the router                 Router router = routerFactory.getRouter();                  int port = config().getInteger(\"serverPort\", 8080);                 String host = config().getString(\"serverHost\", \"localhost\");                  server = vertx.createHttpServer(new HttpServerOptions().setPort(port).setHost(host));                 server.requestHandler(router).listen(ar -&gt; {                     \/\/ Error starting the HttpServer                     if (ar.succeeded()) promise.complete();                     else promise.fail(ar.cause());                 });             } else {                 \/\/ Something went wrong during router factory initialization                 promise.fail(openAPI3RouterFactoryAsyncResult.cause());             }         });         return promise;     }  } <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0412 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0438 \u0435\u0433\u043e \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043d\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435\u043e\u0431\u044b\u0447\u043d\u043e\u0433\u043e (\u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 @WebApiServiceGen, \u043d\u043e \u043f\u0440\u043e \u043d\u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432 <a href=\"https:\/\/vertx.io\/docs\/vertx-web-api-service\/java\/#_using_vert_x_api_service\" rel=\"nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a>), \u0430 \u0432\u043e\u0442 \u043a\u043e\u0434 verticle-\u043a\u043b\u0430\u0441\u0441\u0430 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435.<\/p>\n<p>  <\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b \u0434\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0430 \u0432\u0435\u0440\u0442\u0438\u043a\u043b\u0430:<\/p>\n<p>  <\/p>\n<ul>\n<li><strong>startHelloService<\/strong> \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0430\u0442\u0430\u0446\u0438\u0435\u0439 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0438 \u0431\u0438\u043d\u0434\u0438\u0442 \u0435\u0433\u043e \u043d\u0430 \u0430\u0434\u0440\u0435\u0441 \u0432 event bus (\u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <em>x-vertx-event-bus.address<\/em> \u0438\u0437 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432\u044b\u0448\u0435)<\/li>\n<li><strong>startHttpServer<\/strong> \u0441\u043e\u0437\u0434\u0430\u0451\u0442 router factory \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0441\u043e\u0437\u0434\u0430\u0451\u0442 http-\u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043f\u0440\u0438\u0446\u0435\u043f\u043b\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 router \u043a \u0445\u044d\u043d\u0434\u043b\u0435\u0440\u0443 \u0432\u0441\u0435\u0445 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 http-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (\u0435\u0441\u043b\u0438 \u0433\u0443\u0440\u0431\u043e, \u0442\u043e \u0437\u0430\u043f\u0440\u043e\u0441 <strong>GET \/<\/strong> \u0431\u0443\u0434\u0435\u0442 \u043f\u0430\u0434\u0430\u0442\u044c \u0432 event bus vertex&#8217;\u0430 \u0441 \u0430\u0434\u0440\u0435\u0441\u043e\u043c <strong>service.hello<\/strong> (\u0430 \u0442\u0443\u0434\u0430 \u043c\u044b \u0437\u0430\u0431\u0438\u043d\u0434\u0438\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 <em>io.bihero.hello.HelloService<\/em>) \u0438 \u0441 \u0438\u043c\u0435\u043d\u0435\u043c \u043c\u0435\u0442\u043e\u0434\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 <strong>getHelloWord<\/strong>)<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041f\u043e\u0440\u0430 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0434\u0436\u0430\u0440\u043d\u0438\u043a \u0438 \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">mvn clean package # \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0434\u0436\u0430\u0440\u043d\u0438\u043a java -Dlogback.configurationFile=.\/src\/conf\/logback-console.xml -jar target\/hello-microservice-fat.jar  -conf .\/src\/conf\/config.json # \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u0441\u0442\u0440\u043e\u043a\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b \u0434\u0432\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430:<\/p>\n<p>  <\/p>\n<ul>\n<li>-Dlogback.configurationFile=.\/src\/conf\/logback-console.xml \u2014 \u043f\u0443\u0442\u044c \u0434\u043e \u043a\u043e\u043d\u0444\u0438\u0433-\u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f logback (\u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c slf4j \u0438 logback \u043a\u0430\u043a \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f slf4j-api)<\/li>\n<li>-conf .\/src\/conf\/config.json \u2014 \u043a\u043e\u043d\u0444\u0438\u0433 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0442\u0430\u043c \u0434\u043b\u044f \u043d\u0430\u0441 \u0432\u0430\u0436\u0435\u043d \u043f\u043e\u0440\u0442, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442 http REST API:<br \/> \n<pre><code class=\"json\">{ \"type\": \"file\", \"format\": \"json\", \"scanPeriod\": 5000, \"config\": { \"path\": \"\/home\/slava\/JavaProjects\/hello-world-to-cloud\/hellomicroservice\/src\/conf\/config.json\" }, \"serverPort\": 8081, \"serverHost\": \"0.0.0.0\" }<\/code><\/pre>\n<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0412\u044b\u0432\u043e\u0434 maven&#8217;\u0430 \u043d\u0430\u043c \u043e\u0441\u043e\u0431\u043e \u043d\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0435\u043d, \u0430 \u0432\u043e\u0442 \u043a\u0430\u043a \u0441\u0442\u0430\u0440\u0442\u0430\u043d\u0443\u043b \u0441\u0435\u0440\u0432\u0438\u0441, \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c (\u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043b\u043e\u0433\u0433\u0435\u0440\u0430 \u0434\u043b\u044f \u043f\u0430\u043a\u0435\u0442\u0430 <strong>io.netty<\/strong> \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d <strong>level=&#187;INFO&#187;<\/strong>)<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u0430\u043a \u0441\u0442\u0430\u0440\u0442\u0430\u043d\u0443\u043b \u0441\u0435\u0440\u0432\u0438\u0441<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">2019-10-03 20:52:45,159 [vert.x-worker-thread-0] DEBUG i.s.v.p.OpenAPIV3Parser: Loaded raw data: openapi: 3.0.1 info:   title: Hello ;)   description: Hello microservice   version: 1.0.0 servers:   - url: https:\/\/demo1.bihero.io\/api\/hello tags:   - name: hello     description: Everything about saying 'Hello' paths:   \/:     x-vertx-event-bus:       address: service.hello       timeout: 1000c     get:       tags:         - hello       summary: Get 'Hello' word       operationId: getHelloWord       responses:         200:           description: OK   \/doc:     x-vertx-event-bus:       address: service.hello       timeout: 1000c     get:       tags:         - hello_doc       summary: Get 'Hello' microservice documentation       operationId: getDoc       responses:         200:           description: OK components: {} 2019-10-03 20:52:45,195 [vert.x-worker-thread-0] DEBUG i.s.v.p.OpenAPIV3Parser: Parsed rootNode: {\"openapi\":\"3.0.1\",\"info\":{\"title\":\"Hello ;)\",\"description\":\"Hello microservice\",\"version\":\"1.0.0\"},\"servers\":[{\"url\":\"https:\/\/demo1.bihero.io\/api\/hello\"}],\"tags\":[{\"name\":\"hello\",\"description\":\"Everything about saying 'Hello'\"}],\"paths\":{\"\/\":{\"x-vertx-event-bus\":{\"address\":\"service.hello\",\"timeout\":\"1000c\"},\"get\":{\"tags\":[\"hello\"],\"summary\":\"Get 'Hello' word\",\"operationId\":\"getHelloWord\",\"responses\":{\"200\":{\"description\":\"OK\"}}}},\"\/doc\":{\"x-vertx-event-bus\":{\"address\":\"service.hello\",\"timeout\":\"1000c\"},\"get\":{\"tags\":[\"hello_doc\"],\"summary\":\"Get 'Hello' microservice documentation\",\"operationId\":\"getDoc\",\"responses\":{\"200\":{\"description\":\"OK\"}}}}},\"components\":{}} Oct 03, 2019 8:52:45 PM io.vertx.core.impl.launcher.commands.VertxIsolatedDeployer INFO: Succeeded in deploying verticle <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0423\u0440\u0430! \u0421\u0435\u0440\u0432\u0438\u0441 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b, \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">curl http:\/\/127.0.0.1:8081\/ Hello curl -v http:\/\/127.0.0.1:8081\/doc openapi: 3.0.1 info:   title: Hello ;)   description: Hello microservice   version: 1.0.0 servers:   - url: https:\/\/demo1.bihero.io\/api\/hello tags:   - name: hello     description: Everything about saying 'Hello' paths:   \/:     x-vertx-event-bus:       address: service.hello       timeout: 1000c     get:       tags:         - hello       summary: Get 'Hello' word       operationId: getHelloWord       responses:         200:           description: OK   \/doc:     x-vertx-event-bus:       address: service.hello       timeout: 1000c     get:       tags:         - hello_doc       summary: Get 'Hello' microservice documentation       operationId: getDoc       responses:         200:           description: OK components: {}<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0441\u043b\u043e\u0432\u043e\u043c <strong>Hello<\/strong> \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 <strong>GET \/<\/strong>, \u0447\u0442\u043e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u0438 \u0443\u043c\u0435\u0435\u0442 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043e\u043d \u0443\u043c\u0435\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c, \u043e\u0442\u0434\u0430\u0432\u0430\u044f \u0441\u043f\u0435\u0446\u0438\u0444\u043a\u0430\u0446\u0438\u044e \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443 <strong>GET \/doc<\/strong>. \u041a\u0440\u0443\u0442\u043e, \u0438\u0434\u0451\u043c \u0432 \u043f\u0440\u043e\u0434!<\/p>\n<p>  <\/p>\n<h3 id=\"chto-to-tut-ne-tak-\">\u0427\u0442\u043e-\u0442\u043e \u0442\u0443\u0442 \u043d\u0435 \u0442\u0430\u043a &#8230;<\/h3>\n<p>  <\/p>\n<p>\u0420\u0430\u043d\u0435\u0435 \u044f \u043f\u0438\u0441\u0430\u043b, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u0432\u0430\u0436\u0435\u043d \u0432\u044b\u0432\u043e\u0434 maven&#8217;\u0430 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435. \u042f \u043d\u0430\u0432\u0440\u0430\u043b, \u0432\u044b\u0432\u043e\u0434 \u0432\u0430\u0436\u0435\u043d \u0438 \u043e\u0447\u0435\u043d\u044c. \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b maven \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b \u0442\u0435\u0441\u0442\u044b \u0438 \u043f\u0440\u0438 \u043f\u0430\u0434\u0435\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441\u0431\u043e\u0440\u043a\u0430 \u043f\u0430\u0434\u0430\u043b\u0430. \u0421\u0431\u043e\u0440\u043a\u0430 \u0432\u044b\u0448\u0435 \u043f\u0440\u043e\u0448\u043b\u0430, \u0438 \u044d\u0442\u043e \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043b\u0438\u0431\u043e \u0442\u0435\u0441\u0442\u044b \u043f\u0440\u043e\u0448\u043b\u0438, \u043b\u0438\u0431\u043e \u0438\u0445 \u043d\u0435\u0442. \u0422\u0435\u0441\u0442\u043e\u0432 \u0443 \u043d\u0430\u0441, \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435, \u043d\u0435\u0442, \u043d\u0430\u0441\u0442\u0430\u043b\u0430 \u043f\u043e\u0440\u0430 \u0438\u0445 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c (\u0442\u0443\u0442 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043f\u043e\u0440\u0438\u0442\u044c \u043e \u043c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u044f\u0445, \u043e \u0442\u043e\u043c \u043a\u043e\u0433\u0434\u0430 \u0438 \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b, \u0434\u043e \u0438\u043b\u0438 \u043f\u043e\u0441\u043b\u0435 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438, \u043d\u043e \u043c\u044b \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043c \u043f\u0440\u043e \u0432\u0430\u0436\u043d\u0443\u044e \u0437\u0430\u043c\u0435\u0442\u043a\u0443 \u0432\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0442\u0430\u0442\u044c\u0438 \u0438 \u043f\u043e\u0439\u0434\u0451\u043c \u0434\u0430\u043b\u044c\u0448\u0435 \u2014 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0430\u0440\u043e\u0447\u043a\u0443 \u0442\u0435\u0441\u0442\u043e\u0432).<br \/>  \u041f\u0435\u0440\u0432\u044b\u0439 \u0442\u0435\u0441\u0442-\u043a\u043b\u0430\u0441\u0441 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e \u0441\u0432\u043e\u0435\u0439 \u043f\u0440\u0438\u0440\u043e\u0434\u0435 \u044e\u043d\u0438\u0442-\u0442\u0435\u0441\u0442\u043e\u043c, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0449\u0438\u043c \u0434\u0432\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u0430 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">HelloServiceTest.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.hello;  import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.api.OperationRequest; import io.vertx.junit5.VertxExtension; import io.vertx.junit5.VertxTestContext; import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith;  import java.io.IOException;  import static org.assertj.core.api.Assertions.assertThat;  @ExtendWith(VertxExtension.class) public class HelloServiceTest {      private HelloService helloService = HelloService.create(Vertx.vertx());      @Test     @DisplayName(\"Test 'getHelloWord' method returns 'Hello' word\")     public void testHelloMethod(VertxTestContext testContext) {         helloService.getHelloWord(new OperationRequest(new JsonObject()), testContext.succeeding(it -&gt; {             assertThat(it.getStatusCode()).isEqualTo(200);             assertThat(it.getPayload().toString()).isEqualTo(\"Hello\");             testContext.completeNow();         }));     }      @Test     @DisplayName(\"Test 'getDoc' method returns service documentation in OpenAPI format\")     public void testDocMethod(VertxTestContext testContext) {         helloService.getDoc(new OperationRequest(new JsonObject()), testContext.succeeding(it -&gt; {             try {                 assertThat(it.getStatusCode()).isEqualTo(200);                 assertThat(it.getPayload().toString()).isEqualTo(IOUtils.toString(this.getClass()                         .getResourceAsStream(\"..\/..\/..\/doc.yaml\"), \"UTF-8\"));                 testContext.completeNow();             } catch (IOException e) {                 testContext.failNow(e);             }         }));     }  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0412\u0442\u043e\u0440\u043e\u0439 \u0442\u0435\u0441\u0442 \u2014 \u043d\u0435\u0434\u043e\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0442\u0435\u0441\u0442, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0449\u0438\u0439, \u0447\u0442\u043e \u0432\u0435\u0440\u0442\u0438\u043a\u043b \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0438 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 http \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u043c\u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u0430\u043c\u0438 \u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u043c:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">HelloVerticleTest.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.hello;  import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.codec.BodyCodec; import io.vertx.junit5.Checkpoint; import io.vertx.junit5.VertxExtension; import io.vertx.junit5.VertxTestContext; import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith;  import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy;  @ExtendWith(VertxExtension.class) public class HelloVerticleTest {      @Test     @DisplayName(\"Test that verticle is up and respond me by 'Hello' word and doc in OpenAPI format\")     public void testHelloVerticle(Vertx vertx, VertxTestContext testContext) {         WebClient webClient = WebClient.create(vertx);          Checkpoint deploymentCheckpoint = testContext.checkpoint();         Checkpoint requestCheckpoint = testContext.checkpoint(2);          HelloVerticle verticle = spy(new HelloVerticle());         JsonObject config = new JsonObject().put(\"serverPort\", 8081).put(\"serverHost\", \"0.0.0.0\");         doReturn(config).when(verticle).config();         vertx.deployVerticle(verticle, testContext.succeeding(id -&gt; {             deploymentCheckpoint.flag();             \/\/ test GET \/             webClient.get(8081, \"localhost\", \"\/\")                     .as(BodyCodec.string())                     .send(testContext.succeeding(resp -&gt; {                         assertThat(resp.body()).isEqualTo(\"Hello\");                         assertThat(resp.statusCode()).isEqualTo(200);                         requestCheckpoint.flag();                     }));             \/\/ test GET \/doc             webClient.get(8081, \"localhost\", \"\/doc\")                     .as(BodyCodec.string())                     .send(testContext.succeeding(resp -&gt; {                         try {                             assertThat(resp.body()).isEqualTo(IOUtils.toString(this.getClass()                                     .getResourceAsStream(\"..\/..\/..\/doc.yaml\"), \"UTF-8\"));                             assertThat(resp.statusCode()).isEqualTo(200);                             requestCheckpoint.flag();                         } catch (Exception e) {                             requestCheckpoint.flag();                             testContext.failNow(e);                         }                     }));         }));     }  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u041f\u043e\u0440\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">mvn clean package<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0430\u0441 \u043e\u0447\u0435\u043d\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u043b\u043e\u0433 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 surefire, \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a (\u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430 \u043a\u043b\u0438\u043a\u0430\u0431\u0435\u043b\u044c\u043d\u0430):<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/habrastorage.org\/webt\/3l\/s3\/dk\/3ls3dkohbjzzlfj1rruhtvtxjzs.png\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/3l\/s3\/dk\/3ls3dkohbjzzlfj1rruhtvtxjzs.png\"><\/a><\/p>\n<p>  <\/p>\n<p>\u0417\u0434\u043e\u0440\u043e\u0432\u043e! \u0421\u0435\u0440\u0432\u0438\u0441 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f, \u0442\u0435\u0441\u0442\u044b \u0431\u0435\u0433\u0443\u0442 \u0438 \u043d\u0435 \u043f\u0430\u0434\u0430\u044e\u0442 (\u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e \u043a\u0440\u0430\u0441\u043e\u0442\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0447\u0430\u043b\u044c\u0441\u0442\u0432\u0443), \u043f\u043e\u0440\u0430 \u0437\u0430\u0434\u0443\u043c\u0430\u0442\u044c\u0441\u044f \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0435\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 (\u0442\u043e \u0435\u0441\u0442\u044c \u0434\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432). \u041d\u0430 \u0434\u0432\u043e\u0440\u0435 \u043a\u043e\u043d\u0435\u0446 2019-\u0433\u043e, \u0438, \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435, \u0431\u0430\u043d\u0434\u043b\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432 \u0432\u0438\u0434\u0435 docker-\u043e\u0431\u0440\u0430\u0437\u0430. \u041f\u043e\u0435\u0445\u0430\u043b\u0438!<\/p>\n<p>  <\/p>\n<h2 id=\"docker-i-vse-vse-vse\">Docker \u0438 \u0432\u0441\u0435 \u0432\u0441\u0435 \u0432\u0441\u0435<\/h2>\n<p>  <\/p>\n<p>Docker image \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <code>adoptopenjdk\/openjdk11<\/code>. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043e\u0431\u0440\u0430\u0437 \u043d\u0430\u0448 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0434\u0436\u0430\u0440\u043d\u0438\u043a \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0430\u043c\u0438 \u0438 \u043f\u0440\u043e\u043f\u0438\u0448\u0435\u043c \u0432 \u0434\u043e\u043a\u0435\u0440\u0444\u0430\u0439\u043b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u0441\u0442\u0430\u0440\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435. \u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 <strong>Dockerfile<\/strong> \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">FROM adoptopenjdk\/openjdk11:alpine-jre COPY target\/hello-microservice-fat.jar app.jar COPY src\/conf\/config.json . COPY src\/conf\/logback-console.xml . COPY run.sh . RUN chmod +x run.sh CMD [\".\/run.sh\"]<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043a\u0440\u0438\u043f\u0442 <strong>run.sh<\/strong> \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">#!\/bin\/sh java ${JVM_OPTS} -Dlogback.configurationFile=.\/logback-console.xml -jar app.jar -conf config.json<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f <strong>JVM_OPTS<\/strong> \u043d\u0430\u043c \u043d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043f\u043e\u043a\u0430 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u043d\u0443\u0436\u043d\u0430, \u043d\u043e \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0435\u0451 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u0438 \u0442\u044e\u043d\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u044b \u0438 \u043d\u0430\u0448\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u041f\u043e\u0440\u0430 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0437 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">docker build -t=\"hellomicroservice\" . docker run -dit --name helloms hellomicroservice # \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432 \u043b\u043e\u0433\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, \u0447\u0442\u043e \u043e\u043d \u0442\u0430\u043c \u043d\u0430\u043c \u043f\u043e\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b docker logs -f helloms  # \u0432\u044b\u0432\u043e\u0434 docker logs 2019-10-05 14:55:46,059 [vert.x-worker-thread-0] DEBUG i.s.v.p.OpenAPIV3Parser: Loaded raw data: openapi: 3.0.1 info:   title: Hello ;)   description: Hello microservice   version: 1.0.0 servers:   - url: https:\/\/demo1.bihero.io\/api\/hello tags:   - name: hello     description: Everything about saying 'Hello' paths:   \/:     x-vertx-event-bus:       address: service.hello       timeout: 1000c     get:       tags:         - hello       summary: Get 'Hello' word       operationId: getHelloWord       responses:         200:           description: OK   \/doc:     x-vertx-event-bus:       address: service.hello       timeout: 1000c     get:       tags:         - hello_doc       summary: Get 'Hello' microservice documentation       operationId: getDoc       responses:         200:           description: OK components: {} 2019-10-05 14:55:46,098 [vert.x-worker-thread-0] DEBUG i.s.v.p.OpenAPIV3Parser: Parsed rootNode: {\"openapi\":\"3.0.1\",\"info\":{\"title\":\"Hello ;)\",\"description\":\"Hello microservice\",\"version\":\"1.0.0\"},\"servers\":[{\"url\":\"https:\/\/demo1.bihero.io\/api\/hello\"}],\"tags\":[{\"name\":\"hello\",\"description\":\"Everything about saying 'Hello'\"}],\"paths\":{\"\/\":{\"x-vertx-event-bus\":{\"address\":\"service.hello\",\"timeout\":\"1000c\"},\"get\":{\"tags\":[\"hello\"],\"summary\":\"Get 'Hello' word\",\"operationId\":\"getHelloWord\",\"responses\":{\"200\":{\"description\":\"OK\"}}}},\"\/doc\":{\"x-vertx-event-bus\":{\"address\":\"service.hello\",\"timeout\":\"1000c\"},\"get\":{\"tags\":[\"hello_doc\"],\"summary\":\"Get 'Hello' microservice documentation\",\"operationId\":\"getDoc\",\"responses\":{\"200\":{\"description\":\"OK\"}}}}},\"components\":{}} Oct 05, 2019 2:55:46 PM io.vertx.core.impl.launcher.commands.VertxIsolatedDeployer INFO: Succeeded in deploying verticle<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043e\u0441\u0442\u0430\u043d\u0435\u043c ip-\u0430\u0434\u0440\u0435\u0441 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">docker inspect helloms | grep IPAddress  \"SecondaryIPAddresses\": null,             \"IPAddress\": \"172.17.0.2\",                     \"IPAddress\": \"172.17.0.2\",<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"bash\">curl http:\/\/172.17.0.2:8081\/ # \u0442\u0443\u0442 \u043e\u0436\u0438\u0434\u0430\u0435\u043c \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0441\u043b\u043e\u0432\u043e 'Hello' \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 curl http:\/\/172.17.0.2:8081\/doc # \u0442\u0443\u0442 \u0436\u0434\u0451\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 OpenAPI<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u0442\u0430\u043a, \u0441\u0435\u0440\u0432\u0438\u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435. \u041d\u043e \u043c\u044b \u0436\u0435 \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0435\u0433\u043e \u0440\u0443\u043a\u0430\u043c\u0438 \u0432\u043e\u0442 \u0442\u0430\u043a (docker run) \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0432 production-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u044b\u0439 kubernetes. \u0427\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 kubernetes, \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u0448\u0430\u0431\u043b\u043e\u043d, yml-\u0444\u0430\u0439\u043b, \u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0442\u043e\u0433\u043e, \u043a\u0430\u043a\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b (deployment, service, ingress, etc) \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u0430\u043a\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. \u041d\u043e, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u043d\u0430\u0447\u043d\u0451\u043c \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u043f\u043b\u0435\u0439\u0442 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 k8s, \u043f\u0443\u0448\u043d\u0435\u043c \u043a\u0430 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u043d\u0435\u0435 \u043e\u0431\u0440\u0430\u0437 \u043d\u0430 \u0434\u043e\u043a\u0435\u0440\u0445\u0430\u0431:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">docker tag hello bihero\/hello docker push bihero\/hello<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0438\u0448\u0435\u043c \u0442\u0435\u043c\u043f\u043b\u0435\u0439\u0442 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 kubernetes (\u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u044b \u043d\u0435 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435 \u0441\u0432\u0430\u0440\u0449\u0438\u043a\u0438 \u0438 \u043d\u0435 \u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u0435\u043c \u043d\u0430 &#171;\u043a\u043e\u0448\u0435\u0440\u043d\u043e\u0441\u0442\u044c&#187; \u0442\u0435\u043c\u043f\u043b\u0435\u0439\u0442\u0430):<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">apiVersion: extensions\/v1beta1 kind: Deployment metadata:   labels:     io.bihero.hello.service: bihero-hello   name: bihero-hello spec:   replicas: 3   strategy:     type: RollingUpdate     rollingUpdate:       maxSurge: 1       maxUnavailable: 1   template:     metadata:       labels:         io.bihero.hello.service: bihero-hello     spec:       containers:         - image: bihero\/hello:${HELLO_SERVICE_IMAGE_VERSION}           name: bihero-hello           ports:             - containerPort: 8081           imagePullPolicy: Always           resources: {}       restartPolicy: Always --- apiVersion: v1 kind: Service metadata:   labels:     io.bihero.hello.service: bihero-hello   name: bihero-hello spec:   ports:     - name: \"8081\"       port: 8081       targetPort: 8081   selector:     io.bihero.hello.service: bihero-hello status:   loadBalancer: {} --- apiVersion: extensions\/v1beta1 kind: Ingress metadata:   name: bihero-hello   annotations:     kubernetes.io\/ingress.class: nginx     nginx.ingress.kubernetes.io\/ssl-redirect: \"true\"     nginx.ingress.kubernetes.io\/secure-backends: \"false\"     nginx.ingress.kubernetes.io\/ssl-passthrough: \"false\"     nginx.ingress.kubernetes.io\/rewrite-target: \/$2     kubernetes.io\/tls-acme: \"true\"   namespace: default spec:   tls:     - hosts:         - ${ID_DOMAIN}       secretName: bihero   rules:     - host: ${ID_DOMAIN}       http:         paths:           - path: \/api\/hello(\/|$)(.*)             backend:               serviceName: bihero-hello               servicePort: 8081<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u0440\u0430\u0442\u043a\u043e \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043c\u044b \u0432\u0438\u0434\u0438\u043c \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li><strong>Deployment<\/strong>: \u0442\u0443\u0442 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c, \u0438\u0437 \u043a\u0430\u043a\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 \u0434\u0435\u043f\u043b\u043e\u0438\u043c\u0441\u044f \u0438 \u0438\u0437 \u043a\u0430\u043a\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u0432 \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0441\u0435\u0442 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0422\u0430\u043a\u0436\u0435 \u0432\u0430\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 <em>metadata.labels<\/em> \u2014 \u043f\u043e \u043d\u0438\u043c \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c <strong>Service<\/strong> \u043a <strong>Deployment<\/strong><\/li>\n<li><strong>Service<\/strong>: \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441 \u043a \u0434\u0435\u043f\u043b\u043e\u0439\u043c\u0435\u043d\u0442\u0443\/\u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0441\u0435\u0442\u0443. \u041f\u043e \u0441\u0443\u0442\u0438 \u0441\u0435\u0440\u0432\u0438\u0441 \u0432 k8s \u2014 \u044d\u0442\u043e \u0442\u043e, \u043a \u0447\u0435\u043c\u0443 \u0443\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u043b\u0430\u0442\u044c http-\u0437\u0430\u043f\u0440\u043ec\u044b <strong>\u0432\u043d\u0443\u0442\u0440\u0438<\/strong> \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430 (\u0438 \u0434\u0430 \u2014 \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 <strong>selector<\/strong>)<\/li>\n<li><strong>Ingress<\/strong>: \u0438\u043d\u0433\u0440\u0435\u0441\u0441 \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u0435\u0440\u0432\u0438\u0441 \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0440\u0443\u0436\u0443, \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u043c\u0438\u0440. \u0412\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0441 <strong>\/api\/hello<\/strong> \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u043d\u0430 \u043d\u0430\u0448 hello-\u0441\u0435\u0440\u0432\u0438\u0441 (<a href=\"https:\/\/domain.com\/api\/hello\" rel=\"nofollow\">https:\/\/domain.com\/api\/hello<\/a> -&gt; <a href=\"http:\/\/bihero-hello.service.internal.domain.local:8081\/\" rel=\"nofollow\">http:\/\/bihero-hello.service.internal.domain.local:8081\/<\/a>)<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0435 \u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u044e\u0442 \u0434\u0432\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<ul>\n<li>${HELLO_SERVICE_IMAGE_VERSION} \u2014 \u0442\u0435\u0433 docker-\u043e\u0431\u0440\u0430\u0437\u0430 \u0441 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043d\u0430\u0448 \u043f\u0435\u0440\u0432\u044b\u0439 deployment<\/li>\n<li>${ID_DOMAIN} \u2014 \u0434\u043e\u043c\u0435\u043d, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0451\u043c \u043d\u0430\u0448\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b<\/li>\n<\/ul>\n<p>  <\/p>\n<blockquote><p><strong>\u0412\u0430\u0436\u043d\u043e\u0435 \u043f\u0440\u043e https<\/strong><br \/>  \u0412 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0435 \u0443\u0436\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f secret \u0441 \u0438\u043c\u0435\u043d\u0435\u043c <strong>bihero<\/strong>, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 wildcard-\u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430 \u043e\u0442 LetsEncrypt. \u0415\u0441\u043b\u0438 \u043a\u0440\u0430\u0442\u043a\u043e, \u0442\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a  <\/p>\n<pre><code class=\"bash\">kubectl create secret tls bihero --key keys\/privkey.pem --cert keys\/fullchain.pem<\/code><\/pre>\n<p>  \u0433\u0434\u0435 privkey.pem \u0438 fullchain.pem \u2014 \u0444\u0430\u0439\u043b\u044b, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0435 letsencrypt&#8217;\u043e\u043c<br \/>  \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 secret&#8217;\u0430 \u0434\u043b\u044f tls \u0432 k8s \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u0440\u043e\u0439\u0434\u044f \u043f\u043e <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/ingress\/#tls\" rel=\"nofollow\">\u0441\u0441\u044b\u043b\u043a\u0435<\/a> <\/p><\/blockquote>\n<p>  <\/p>\n<p>\u041d\u0430\u0441\u0442\u0430\u043b\u0430 \u043f\u043e\u0440\u0430 \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c\u0441\u044f \u0432 k8s \ud83d\ude42 \u041f\u043e\u0435\u0445\u0430\u043b\u0438!<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">export HELLO_SERVICE_IMAGE_VERSION=latest export ID_DOMAIN=demo1.bihero.io cat k8s.yaml | envsubst | kubectl apply -f -<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 stdout \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0432\u043e\u0442 \u044d\u0442\u043e:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">deployment.extensions\/bihero-hello created service\/bihero-hello created ingress.extensions\/bihero-hello created<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0443 \u0447\u0442\u043e \u0436, \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u0442\u0430\u043c \u043d\u0430\u043c kubernetes \u043d\u0430\u0432\u043e\u0440\u043e\u0442\u0438\u043b:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">kubectl get po # \u0434\u0430, \u0432\u043c\u0435\u0441\u0442\u043e pod \u043c\u043e\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c po, k8s \u0432\u0430\u0441 \u043f\u043e\u0439\u043c\u0451\u0442<\/code><\/pre>\n<p>  <\/p>\n<p><a href=\"https:\/\/habrastorage.org\/webt\/up\/uu\/mh\/upuumhgqijpejz-jgu9n8zc_ds4.png\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/up\/uu\/mh\/upuumhgqijpejz-jgu9n8zc_ds4.png\"><\/a><br \/>  \u041a\u0430\u043a \u0438 \u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f \u2014 3 \u043f\u043e\u0434\u0430<\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0430<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">kubectl describe po bihero-hello-5b4759d55b-bf4qc<\/code><\/pre>\n<p>  <\/p>\n<p><a href=\"https:\/\/habrastorage.org\/webt\/dv\/31\/8n\/dv318n2kmrvhua0bbv63togmivs.png\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/dv\/31\/8n\/dv318n2kmrvhua0bbv63togmivs.png\"><\/a><\/p>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u0442\u0430\u043c \u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u043e\u0436\u0438\u0432\u0430\u0435\u0442?<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">kubectl describe service bihero-hello<\/code><\/pre>\n<p>  <\/p>\n<p><a href=\"https:\/\/habrastorage.org\/webt\/to\/1r\/fy\/to1rfysgzpxwi3zp6jlaffswra4.png\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/to\/1r\/fy\/to1rfysgzpxwi3zp6jlaffswra4.png\"><\/a><\/p>\n<p>  <\/p>\n<p>\u0410 \u0438\u043d\u0433\u0440\u0435\u0441\u0441?<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">kubectl describe ing bihero-hello<\/code><\/pre>\n<p>  <\/p>\n<p><a href=\"https:\/\/habrastorage.org\/webt\/o2\/np\/m4\/o2npm4hdhucyueujgknmuqitfny.png\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/o2\/np\/m4\/o2npm4hdhucyueujgknmuqitfny.png\"><\/a><\/p>\n<p>  <\/p>\n<p>\u0417\u0434\u043e\u0440\u043e\u0432\u043e! \u0421\u0435\u0440\u0432\u0438\u0441 \u0431\u0435\u0433\u0430\u0435\u0442 \u0432 k8s \u0438 \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0438\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0435\u0433\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u0447\u043a\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0441\u043f\u0435\u043a\u0435.<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">curl https:\/\/demo1.bihero.io\/api\/hello Hello<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"bash\">curl https:\/\/demo1.bihero.io\/api\/hello\/doc openapi: 3.0.1 info:   title: Hello ;)   description: Hello microservice   version: 1.0.0 servers:   - url: https:\/\/demo1.bihero.io\/api\/hello tags:   - name: hello     description: Everything about saying 'Hello' paths:   \/:     x-vertx-event-bus:       address: service.hello       timeout: 1000c     get:       tags:         - hello       summary: Get 'Hello' word       operationId: getHelloWord       responses:         200:           description: OK   \/doc:     x-vertx-event-bus:       address: service.hello       timeout: 1000c     get:       tags:         - hello_doc       summary: Get 'Hello' microservice documentation       operationId: getDoc       responses:         200:           description: OK components: {}<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"a---avtomatizaciya\">\u0410 \u2014 \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f<\/h2>\n<p>  <\/p>\n<p>\u0424\u0443\u0445\u2026 \u0414\u043e\u0448\u043b\u0438 \u0434\u043e \u0441\u0430\u043c\u043e\u0433\u043e \u0432\u043a\u0443\u0441\u043d\u043e\u0433\u043e \u0438 \u0432\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e. \u0411\u044b\u043b\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u043d\u0435\u043c\u0430\u043b\u043e \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u043a\u0430\u0436\u0434\u044b\u0439 \u0448\u0430\u0433 \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u043b\u0441\u044f \u0440\u0443\u0447\u043d\u044b\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u0442\u0443\u043b\u043e\u0432, \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0441\u0432\u043e\u0438\u0445. \u041f\u043e\u0440\u0430 \u0437\u0430\u0434\u0443\u043c\u0430\u0442\u044c\u0441\u044f \u043e \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0435 \u0448\u0430\u0433\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0438\u0441\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0438\u043b\u0438 \u0441\u0432\u043e\u0438\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433 \u043f\u0430\u043f\u043b\u0430\u0439\u043d\u0430, \u0430 \u043d\u0430 \u0444\u0438\u043d\u0438\u0448\u0435 \u0431\u044b\u043b \u0440\u043e\u0432\u043d\u044b\u0439 \u0438 \u0431\u0435\u0441\u0448\u043e\u0432\u043d\u044b\u0439 \u0430\u043f\u0433\u0440\u0435\u0439\u0434 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 k8s \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0435. \u0421\u043a\u0430\u0437\u0430\u043d\u043e, \u0441\u0434\u0435\u043b\u0430\u043d\u043e!<\/p>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u0438\u043b\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044e, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u043b\u043e\u0436\u0438\u043c \u0432\u0441\u0451 \u043f\u043e \u043f\u043e\u043b\u043e\u0447\u043a\u0430\u043c \u0438 \u043d\u0430\u0440\u0438\u0441\u0443\u0435\u043c \u0441\u0445\u0435\u043c\u0443 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u043d\u0430 CI-\u0441\u0435\u0440\u0432\u0435\u0440\u0435.<\/p>\n<p>  <\/p>\n<h3 id=\"chto-bylo-sdelano-rukami\">\u0427\u0442\u043e \u0431\u044b\u043b\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0440\u0443\u043a\u0430\u043c\u0438?<\/h3>\n<p>  <\/p>\n<ol>\n<li>\u041d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u043a\u043e\u0434, \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u0442\u0435\u0441\u0442\u044b \u043a \u043a\u043e\u0434\u0443, \u043f\u0440\u043e\u0448\u043b\u0438 \u0432\u0441\u0451 \u0447\u0435\u043a\u0438 (\u043a\u043e\u0434\u0440\u0435\u0432\u044c\u044e \u0438 \u043f\u0440\u043e\u0447\u0435\u0435), \u0437\u0430\u043a\u043e\u043c\u043c\u0438\u0442\u0438\u043b\u0438 \u0432 git-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/li>\n<li>\u0417\u0430\u043f\u0443\u0441\u043a \u0441\u0431\u043e\u0440\u043a\u0438 (mvn), \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432 (surefire, allure) \u2014 \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c fat-jar \u0441 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c<\/li>\n<li>\u0421\u0431\u043e\u0440\u043a\u0430 docker-\u043e\u0431\u0440\u0430\u0437\u0430 (docker build)<\/li>\n<li>Push docker-\u043e\u0431\u0440\u0430\u0437\u0430 \u043d\u0430 \u0434\u043e\u043a\u0435\u0440\u0445\u0430\u0431 (\u0438\u043b\u0438 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 docker registry) (docker push)<\/li>\n<li>\u0414\u0435\u043f\u043b\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 k8s (kubectl apply)<\/li>\n<\/ol>\n<p>  <\/p>\n<h3 id=\"chto-budet-delat-ci-server-\">\u0427\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c CI-\u0441\u0435\u0440\u0432\u0435\u0440 ?<\/h3>\n<p>  <\/p>\n<p>\u0414\u0430 \u0432\u0441\u0451 \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0447\u0442\u043e \u0438 \u043c\u044b \u0440\u0443\u0447\u043a\u0430\u043c\u0438 \u0434\u0435\u043b\u0430\u043b\u0438 (\u043a\u0440\u043e\u043c\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u0438 \u0442\u0435\u0441\u0442\u043e\u0432), \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u043f\u0443\u0442\u0438 \u0431\u0443\u0434\u0435\u0442 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0442\u044c \u043d\u0430\u0441 \u043e \u0441\u0432\u043e\u0438\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u0445 \u0438 \u043e\u0442\u0447\u0451\u0442\u044b \u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c \u0432 \u043d\u0443\u0436\u043d\u044b\u0435 \u043c\u0435\u0441\u0442\u0430. \u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<br \/>  <a href=\"https:\/\/habrastorage.org\/webt\/fy\/kf\/kn\/fykfkndjy0qzvl79t1_s9_ka6wg.png\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/fy\/kf\/kn\/fykfkndjy0qzvl79t1_s9_ka6wg.png\"><\/a><br \/>  \u041e\u043f\u0438\u0448\u0435\u043c \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u043f\u043e \u0448\u0430\u0433\u0430\u043c:<\/p>\n<p>  <\/p>\n<ol>\n<li>\u041f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0431\u0443\u0434\u0435\u0442 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0438\u0442\u044c \u0434\u0436\u043e\u0431\u0443 \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u043e \u043a\u043e\u043c\u043c\u0438\u0442\u0443 \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0443\u044e \u0432\u0435\u0442\u043a\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043f\u0443\u0441\u0442\u044c \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u0435\u0442\u043a\u0430 <strong>master<\/strong> (\u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0432 master \u043c\u044b, \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435, \u043d\u0435 \u043a\u043e\u043c\u043c\u0438\u0442\u0438\u043c, \u0442\u0443\u0434\u0430 \u043a\u043e\u043c\u043c\u0438\u0442\u044b \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u043f\u0440\u0438 merge&#8217;\u0430\u0445 \u043f\u043e\u0441\u043b\u0435 merge request&#8217;\u043e\u0432 \u0438 \u0442\u0449\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0435\u0432\u044c\u044e)<\/li>\n<li>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430\u0447\u0430\u043b\u0430\u0441\u044c \u0441\u0431\u043e\u0440\u043a\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0438\u0437 \u0432\u044b\u0448\u0435\u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 dev-\u0432\u0435\u0442\u043a\u0438 (telegram-bot)<\/li>\n<li>\u041f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432<\/li>\n<li>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043a\u0430\u043a \u043f\u043e\u0440\u0448\u043b\u0438 \u0442\u0435\u0441\u0442\u044b<\/li>\n<li>\u0422\u0435\u0441\u0442\u044b \u043f\u0440\u043e\u0448\u043b\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u2014 \u0434\u0435\u043f\u043b\u043e\u0438\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 maven repository (\u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u043a\u0435\u0439\u0441\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <a href=\"https:\/\/help.sonatype.com\/repomanager3\/high-availability\/configuring-blob-stores\" rel=\"nofollow\">nexus blob store<\/a>)<\/li>\n<li>\u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c fat-jar (mvn package, \u043d\u043e \u0441 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u043c \u0445\u0430\u043a\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0442\u044c \u043f\u043e \u043d\u043e\u0432\u043e\u0439 \u043a\u043e\u0434 \u2014 \u043c\u044b \u044d\u0442\u043e \u0443\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432)<\/li>\n<li>\u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c docker image \u0438\u0437 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0434\u0436\u0430\u0440\u043d\u0438\u043a\u0430 \u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u043a\u043e\u043d\u0444\u0438\u0433\u043e\u0432. \u0422\u0443\u0442 \u0441\u0442\u043e\u0438\u0442\u044c \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0439 \u0448\u0430\u0433 \u0434\u0435\u043b\u0430\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0431\u043e\u0440\u043a\u0443 \u043e\u0431\u0440\u0430\u0437\u0430, \u043d\u043e \u0438 \u043f\u0443\u0448\u0438\u0442 \u0435\u0433\u043e \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u0448 \u043e\u0431\u0440\u0430\u0437 \u043a\u0430\u043a \u0440\u0435\u0441\u0443\u0440\u0441 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430 (\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u0445 \u0441\u043a\u043e\u0440\u043e \u0443\u0437\u043d\u0430\u0435\u0442\u0435). \u041f\u0443\u0448 \u043e\u0431\u0440\u0430\u0437\u0430 \u0432 registry \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0438\u0442 \u0434\u0435\u043f\u043b\u043e\u0439 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 k8s \u043a\u043b\u0430\u0441\u0442\u0435\u0440<\/li>\n<li>\u0414\u0435\u043f\u043b\u043e\u0439 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 k8s \u043a\u043b\u0430\u0441\u0442\u0435\u0440<\/li>\n<li>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0441\u0431\u043e\u0440\u043a\u0430 \u043f\u0440\u043e\u0448\u043b\u0430 \u0438 \u043d\u043e\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0443\u0448\u043b\u0430 \u0432 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0439 k8s \u043a\u043b\u0430\u0441\u0442\u0435\u0440. \u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0434\u0436\u043e\u0431\u0443 \u0441 \u043b\u043e\u0433\u0430\u043c\u0438 \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432<\/li>\n<li>\u0415\u0441\u043b\u0438 \u043d\u0430 4-\u043c \u0448\u0430\u0433\u0435 \u043c\u044b \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u043c, \u0447\u0442\u043e \u0442\u0435\u0441\u0442\u044b \u043d\u0435 \u043f\u0440\u043e\u0448\u043b\u0438, \u0442\u043e \u0434\u0435\u043f\u043b\u043e\u0438\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 maven repository<\/li>\n<li>\u0418 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0441\u0431\u043e\u0440\u043a\u0430 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0443\u043f\u0430\u043b\u0430 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c\u0438 \u0441\u0441\u044b\u043b\u043a\u0430\u043c\u0438 \u0432 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0438<\/li>\n<\/ol>\n<p>  <\/p>\n<h5 id=\"concourse-ci\">Concourse CI<\/h5>\n<p>  <\/p>\n<p>\u0412\u044b\u0448\u0435\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u043e\u0434 CI-\u0441\u0435\u0440\u0432\u0435\u0440 <a href=\"https:\/\/concourse-ci.org\/\" rel=\"nofollow\">Concourse<\/a>. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 Concourse CI:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439 UI (\u0432\u0441\u0451 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u043e\u043c \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430 \u0447\u0435\u0440\u0435\u0437 yaml-\u043a\u043e\u043d\u0444\u0438\u0433\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u0440\u044f\u0434\u043e\u043c \u0441 \u043a\u043e\u0434\u043e\u043c, \u0438 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u044b\u0439 \u0442\u0443\u043b \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 <strong>fly<\/strong>): \u044d\u0442\u043e \u0438 \u043f\u043b\u044e\u0441 \u0438 \u043c\u0438\u043d\u0443\u0441 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u2014 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e \u0438 \u0433\u0438\u0431\u043a\u043e \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0441 \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u044e (mvn, docker, fly, kubectl), \u043d\u043e \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e \u0434\u043b\u044f \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u0430\u0432\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0445\u043e\u0447\u0435\u0442 \u043f\u043e\u0442\u044b\u043a\u0430\u0442\u044c \u0432 \u043a\u043d\u043e\u043f\u043e\u0447\u043a\u0438 (\u043d\u043e \u0434\u043b\u044f \u043d\u0438\u0445 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043e\u0442\u0447\u0451\u0442\u044b \u043f\u0438\u0441\u0430\u0442\u044c \u0432 tg-\u0433\u0440\u0443\u043f\u043f\u0443 \u0441\u043e \u0441\u0441\u044b\u043b\u043a\u0430\u043c\u0438 \u043d\u0430 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u043d\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u044b)<\/li>\n<li>\u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u0442\u0435\u043f \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0432 docker container&#8217;\u0435, \u0447\u0442\u043e \u0434\u0430\u0451\u0442 \u0433\u0438\u0431\u043a\u043e\u0441\u0442\u044c \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0442\u0435\u043f\u0430 (\u043d\u0435 \u043d\u0430\u0434\u043e \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u0439 worker-\u043d\u043e\u0434\u0435 \u0448\u0430\u043c\u0430\u043d\u0438\u0442\u044c \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438, \u0435\u0441\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e environment-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0435 \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u0438 \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u0432 \u043e\u0434\u043d\u043e\u043c \u0438\u0437 \u0448\u0430\u0433\u043e\u0432 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430) \u2014 \u0441\u043e\u0431\u0440\u0430\u043b \u043e\u0431\u0440\u0430\u0437 \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u0441\u0442\u0435\u043f \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430 \u043f\u043e\u0434\u0442\u044f\u043d\u0435\u0442 \u0435\u0433\u043e \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u0442\u0430\u0440\u0442\u0430, \u0438 \u0434\u0435\u043b\u043e \u0432 \u0448\u043b\u044f\u043f\u0435.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0418\u0442\u0430\u043a, \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0439\u0442\u0435, \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0441\u0431\u0440\u043a\u0438:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pipeline.yaml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">resource_types:   - name: telegram     type: docker-image     source:       repository: vtutrinov\/concourse-telegram-resource       tag: latest   - name: kubernetes     type: docker-image     source:       repository: zlabjp\/kubernetes-resource       tag: 1.16   - name: metadata     type: docker-image     source:       repository: olhtbr\/metadata-resource       tag: 2.0.1 resources:   - name: metadata     type: metadata   - name: sources     type: git     source:       branch: master       uri: git@github.com:bihero-io\/hello-microservice.git       private_key: ((deployer-private-key))   - name: docker-image     type: docker-image     source:       repository: bihero\/hello       username: ((docker-registry-user))       password: ((docker-registry-password))   - name: telegram     type: telegram     source:       bot_token: ((telegram-ci-bot-token))       chat_id: ((telegram-group-to-report-build))       ci_url: ((ci_url))       command: \"\/build_hello_ms\"   - name: kubernetes-demo     type: kubernetes     source:       server: https:\/\/178.63.194.241:6443       namespace: default       kubeconfig: ((kubeconfig-demo)) jobs:   - name: build-hello-microservice     serial: true     public: true     plan:       - in_parallel:           - get: sources             trigger: true           - get: telegram             trigger: true           - put: metadata       - put: telegram         params:           status: Build In Progress       - task: unit-tests         config:           platform: linux           image_resource:             type: docker-image             source:               repository: ((docker-registry-uri))\/bih\/maven               tag: 3-jdk-11               username: ((docker-private-registry-user))               password: ((docker-private-registry-password))           inputs:             - name: sources           outputs:             - name: tested-workspace           run:             path: \/bin\/sh             args:               - -c               - |                 output_dir=tested-workspace                 cp -R .\/sources\/* \"${output_dir}\/\"                 mvn -f \"${output_dir}\/pom.xml\" clean test           caches:             - path: ~\/.m2\/         on_failure:           do:             - task: tests-report               config:                 platform: linux                 image_resource:                   type: docker-image                   source:                     repository: ((docker-registry-uri))\/bih\/maven                     tag: 3-jdk-11                     username: ((docker-private-registry-user))                     password: ((docker-private-registry-password))                 inputs:                   - name: tested-workspace                 outputs:                   - name: message                 run:                   path: \/bin\/sh                   args:                     - -c                     - |                       output_dir=tested-workspace                       mvn -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -f \"${output_dir}\/pom.xml\" site-deploy                       version=$(cat $output_dir\/target\/classes\/version.txt)                       cat &gt;message\/msg &lt;&lt;EOL                       &lt;a href=\"https:\/\/nexus.dev.techedge.pro:8443\/repository\/reports\/hello-microservice\/${version}\/allure\/\"&gt;Allure report&lt;\/a&gt;                       EOL                 caches:                   - path: ~\/.m2\/             - put: telegram               params:                 status: Build Failed (unit-tests)                 message_file: message\/msg       - task: tests-report         config:           platform: linux           image_resource:             type: docker-image             source:               repository: ((docker-registry-uri))\/bih\/maven               tag: 3-jdk-11               username: ((docker-private-registry-user))               password: ((docker-private-registry-password))           inputs:             - name: tested-workspace           outputs:             - name: message             - name: tested-workspace           run:             path: \/bin\/sh             args:               - -c               - |                 work_dir=tested-workspace                 mvn -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -f \"${work_dir}\/pom.xml\" site-deploy                 version=$(cat $work_dir\/target\/classes\/version.txt)                 cat &gt;message\/msg &lt;&lt;EOL                 &lt;a href=\"https:\/\/nexus.dev.techedge.pro:8443\/repository\/reports\/hello-microservice\/${version}\/allure\/\"&gt;Allure report&lt;\/a&gt;                 EOL           caches:             - path: ~\/.m2\/       - task: package         config:           platform: linux           image_resource:             type: docker-image             source:               repository: ((docker-registry-uri))\/bih\/maven               tag: 3-jdk-11               username: ((docker-private-registry-user))               password: ((docker-private-registry-password))           inputs:             - name: tested-workspace             - name: metadata           outputs:             - name: app-packaged-workspace             - name: metadata           run:             path: \/bin\/sh             args:               - -c               - |                 output_dir=app-packaged-workspace                 cp -R .\/tested-workspace\/* \"${output_dir}\/\"                 mvn -f \"${output_dir}\/pom.xml\" package -Dmaven.main.skip -DskipTests                 env                 tag=\"-\"$(cat metadata\/build_name)                 echo $tag &gt;&gt; ${output_dir}\/target\/classes\/version.txt                 cat ${output_dir}\/target\/classes\/version.txt &gt; metadata\/version           caches:             - path: ~\/.m2\/         on_failure:           do:             - put: telegram               params:                 status: Build Failed (package)       - put: docker-image         params:           build: app-packaged-workspace           tag_file: app-packaged-workspace\/target\/classes\/version.txt           tag_as_latest: true         get_params:           skip_download: true       - task: make-k8s-app-template         config:           platform: linux           image_resource:             type: docker-image             source:               repository: bhgedigital\/envsubst           inputs:             - name: sources             - name: metadata           outputs:             - name: k8s           run:             path: \/bin\/sh             args:               - -c               - |                 export DOMAIN=demo1.bihero.io                 export HELLO_SERVICE_IMAGE_VERSION=$(cat metadata\/version)                 cat sources\/k8s.yaml | envsubst &gt; k8s\/hello_app_template.yaml                 cat k8s\/hello_app_template.yaml       - put: kubernetes-demo         params:           kubectl: apply -f k8s\/hello_app_template.yaml       - put: telegram         params:           status: Build Success           message_file: message\/msg<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u0440\u0430\u0442\u043a\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430:<\/p>\n<p>  <\/p>\n<ol>\n<li>\u0421\u0435\u043a\u0446\u0438\u044f <a href=\"https:\/\/concourse-ci.org\/resource-types.html\" rel=\"nofollow\">resource_types<\/a> \u043d\u0443\u0436\u043d\u0430 \u0434\u043b\u044f \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c, \u0441\u043e\u0431\u0438\u0440\u0430\u044f \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442. \u0412 \u043d\u0430\u0448\u0435\u043c \u043a\u0435\u0439\u0441\u0435 \u044d\u0442\u043e \u0442\u0440\u0438 \u0442\u0438\u043f\u0430 (\u0438\u043c\u0435\u043d\u0430 \u0442\u0438\u043f\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u044b\u0435, \u0441\u0430\u043c\u0430 \u0441\u0443\u0442\u044c \u0442\u0438\u043f\u0430 \u0437\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 docker-\u043e\u0431\u0440\u0430\u0437\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0438\u043f): telegram \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0432 tg-\u0433\u0440\u0443\u043f\u043f\u0443 \u0438 \u0434\u043b\u044f \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0430 \u0434\u0436\u043e\u0431\u044b \u043f\u043e \u0441\u0431\u043e\u0440\u043a\u0435 \u043f\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u0435, kubernetes \u0434\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 k8s-\u043a\u043b\u0430\u0441\u0442\u0435\u0440 \u0438 metadata \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0431\u0438\u043b\u0434\u0443 (\u043d\u043e\u043c\u0435\u0440 \u0431\u0438\u043b\u0434\u0430, \u0434\u0430\u0442\u0430 \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u0442.\u0434.) \u0432 \u0442\u0430\u0441\u043a\u0430\u0445 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430<\/li>\n<li>\u0421\u0435\u043a\u0446\u0438\u044f resources \u043d\u0443\u0436\u043d\u0430 \u0434\u043b\u044f \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0431\u0438\u043b\u0434\u0430. \u042d\u0442\u043e \u0442\u043e \u0441\u0430\u043c\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u0432 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0435, \u0433\u0434\u0435 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u0441 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u043c\u0438, docker-registry \u0434\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c\u044b\u0445 docker-\u043e\u0431\u0440\u0430\u0437\u043e\u0432 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0435\u043f\u043e\u0432 \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041a\u0430\u0436\u0434\u044b\u0439 \u0440\u0435\u0441\u0443\u0440\u0441 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u0442\u0435\u043f\u0435 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430 \u043a\u0430\u043a input-\u0440\u0435\u0441\u0443\u0440\u0441 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c \u0431\u043b\u043e\u043a\u0435, \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0435\u043c \u0442\u0430\u0441\u043a \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430<\/li>\n<li>\u0421\u0435\u043a\u0446\u0438\u044f jobs \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u043d\u0430\u0431\u043e\u0440 \u0434\u0436\u043e\u0431, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0423 \u043d\u0430\u0441 \u044d\u0442\u043e \u043e\u0434\u043d\u0430 \u0434\u0436\u043e\u0431\u0430 \u0441 \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u0442\u0430\u0441\u043a\u043e\u0432 \u0438 put-\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0432 tg-\u0433\u0440\u0443\u043f\u043f\u0443. \u0418\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438 <strong> \u2014 get<\/strong> \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0435\u043c \u0432\u0445\u043e\u0434\u043d\u044b\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0434\u043b\u044f \u0431\u0438\u043b\u0434\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, git-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439), <strong> \u2014 put<\/strong> \u2014 \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b (docker image) \u0438\u043b\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0445 \u0448\u0430\u0433\u0430\u0445 \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 (metadata). \u041a\u0430\u0436\u0434\u044b\u0439 task \u0432 \u0434\u0436\u043e\u0431\u0435 \u2014 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432\u043d\u0443\u0442\u0440\u0438 docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 docker-image&#8217;\u0430, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c <strong>image_resource<\/strong> \u0442\u0430\u0441\u043a\u0438<\/li>\n<li>\u0421\u0442\u0440\u043e\u043a\u0438 \u0432\u0438\u0434\u0430 <strong>((parameter-name))<\/strong> \u2014 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435, \u043e\u0431\u044b\u0447\u043d\u043e \u0432 \u044d\u0442\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043b\u0435\u0436\u0430\u0442 \u0441\u0435\u043a\u0440\u0435\u0442\u044b, \u044f\u0432\u043a\u0438 \u043f\u0430\u0440\u043e\u043b\u0438 \u043a \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c \u0438 \u043f\u0440\u043e\u0447\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0438\u043c\u0435\u044e\u0449\u0438\u0445\u0441\u044f \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u043e\u0432 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u0441\u044b\u043b\u043a\u0430 \u0434\u043e docker-registry).<\/li>\n<\/ol>\n<p>  <\/p>\n<p>\u0414\u0435\u043f\u043b\u043e\u0439 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430 \u0441 \u0444\u0430\u0439\u043b\u043e\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">fly -t bih sp -p hello-microservice -c pipeline.yaml -l credentials.yaml # -t - target name # sp - alias to set-pipeline # -p - pipeline name # -c - pipeline config file # -l - file with parameters and credentials<\/code><\/pre>\n<p>  <\/p>\n<p>\u0424\u0430\u0439\u043b <strong>credentials.yaml<\/strong> \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">docker-registry-user: &lt;dockerhub-user&gt; docker-registry-password: &lt;dockerhub-password&gt; docker-registry-uri: &lt;private-docker-registry-url&gt; docker-private-registry-user: &lt;private-docker-registry-user&gt; docker-private-registry-password: &lt;private-docker-registry-passwordl&gt; telegram-ci-bot-token: &lt;telegram-bot-token&gt; telegram-group-to-report-build: &lt;telegram-group-id&gt; ci_url: &lt;ci-server-url&gt; deployer-private-key: |   -----BEGIN OPENSSH PRIVATE KEY-----   github-deploy-key   -----END OPENSSH PRIVATE KEY----- kubeconfig-demo: |   apiVersion: v1   clusters:   - cluster:       certificate-authority-data: &lt;kube-cert-data&gt;       server: &lt;kube-api-server-url&gt;     name: kubernetes   contexts:   - context:       cluster: kubernetes       user: kubernetes-admin     name: kubernetes-admin@kubernetes   current-context: kubernetes-admin@kubernetes   kind: Config   preferences: {}   users:   - name: kubernetes-admin     user:       client-certificate-data: &lt;kube-client-cert-data&gt;       client-key-data: &lt;kube-client-key-data&gt;<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0438\u0448\u043b\u0430 \u043f\u043e\u0440\u0430 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0430\u0448 \u043f\u0435\u0440\u0432\u044b\u0439 \u0431\u0438\u043b\u0434. \u0421\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u044b \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438:<\/p>\n<p>  <\/p>\n<ol>\n<li>\u0417\u0430\u043b\u043e\u0433\u0438\u043d\u0438\u0442\u044c\u0441\u044f \u043d\u0430 CI-\u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u043d\u0430\u043c \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0438 \u0434\u0436\u043e\u0431\u0443 \u0438 \u043d\u0430\u0436\u0430\u0442\u044c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u0441 \u043f\u043b\u044e\u0441\u0438\u043a\u043e\u043c:<\/li>\n<li>\u0421\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0441\u0451 \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 (\u0447\u0442\u043e \u0438 \u0432 \u043f\u0443\u043d\u043a\u0442\u0435 1), \u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043a\u043e\u043dc\u043e\u043b\u044c\u043d\u0443\u044e \u0443\u0442\u0438\u043b\u0438\u0442\u0443 <strong>fly<\/strong>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0441 \u0442\u043e\u0433\u043e \u0436\u0435 CI-\u0441\u0435\u0440\u0432\u0435\u0440\u0430:<br \/> \n<pre><code class=\"bash\">fly -t bih tj -j hello-microservice\/build-hello-microservice -w # tj - alias for 'trigger-job' # -j - job (&lt;piprlinr-name&gt;\/&lt;job-name-in-pipeline&gt;) # -w - watch<\/code><\/pre>\n<\/li>\n<li>\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 <strong>\/build_hello_ms<\/strong> \u0432 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0433\u0440\u0443\u043f\u043f\u0443, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 <strong>telegram-group-to-report-build<\/strong> \u0432 \u0444\u0430\u0439\u043b\u0435 <strong>credentials.yaml<\/strong><\/li>\n<li>\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043c\u043c\u0438\u0442 \u0432 master-\u0432\u0435\u0442\u043a\u0443 \u0432 \u0433\u0438\u0442 (\u043f\u043e\u043c\u043d\u0438\u043c, \u0447\u0442\u043e \u043c\u044b \u043d\u0435 \u043f\u0440\u043e \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u0443\u044e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u0435\u0439\u0447\u0430\u0441 \u0433\u043e\u0432\u043e\u0440\u0438\u043c, \u0430 \u043f\u0440\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0432 \u0446\u0435\u043b\u043e\u043c: \u043a\u043e\u043c\u043c\u0438\u0442\u0438\u0442\u044c \u0432 master \u2014 \u044d\u0442\u043e \u043f\u043b\u043e\u0445\u043e, \u2014 \u043d\u043e \u0432 \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0445 \u0446\u0435\u043b\u044f\u0445 \u043c\u043e\u0436\u043d\u043e \ud83d\ude09 )<\/li>\n<\/ol>\n<p>  <\/p>\n<p>\u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0431\u0438\u043b\u0434\u0430 (\u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0435\u0433\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f) \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0434\u0432\u0430 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u0432 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0433\u0440\u0443\u043f\u043f\u0443:<\/p>\n<p>  <\/p>\n<ol>\n<li>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e \u043d\u0430\u0447\u0430\u043b\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0436\u043e\u0431\u043e\u0439:<br \/>  <a href=\"https:\/\/habrastorage.org\/webt\/nh\/bu\/xw\/nhbuxw6mlng--ctknv2y2hh7p5q.png\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/nh\/bu\/xw\/nhbuxw6mlng--ctknv2y2hh7p5q.png\"><\/a><\/li>\n<li>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0441\u0431\u043e\u0440\u043a\u0438:<br \/>  <a href=\"https:\/\/habrastorage.org\/webt\/v9\/py\/vo\/v9pyvoi2szjw9g7h4v_57mf74ei.png\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/v9\/py\/vo\/v9pyvoi2szjw9g7h4v_57mf74ei.png\"><\/a><br \/>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0441\u0431\u043e\u0440\u043a\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432 UI CI-\u0441\u0435\u0440\u0432\u0435\u0440\u0430:<br \/> \n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.2493%;\"><iframe src=\"https:\/\/www.youtube.com\/embed\/qHG8P5fkPWc?rel=0&amp;showinfo=1&amp;hl=en-US\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen scrolling=\"no\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<\/li>\n<\/ol>\n<p>  <\/p>\n<p>\u0423\u0440\u0430! \u0421\u0431\u043e\u0440\u043a\u0430 \u043f\u0440\u043e\u0448\u043b\u0430, \u0434\u043e\u043a\u0435\u0440-\u043e\u0431\u0440\u0430\u0437 \u0441\u043e\u0431\u0440\u0430\u043d, \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 k8s \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u0438 \u043e\u0442\u0447\u0451\u0442\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b. \u041f\u043e\u0440\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0435\u043d\u043d\u043e\u0435:<\/p>\n<p>  <\/p>\n<ol>\n<li>\u041e\u0431\u0440\u0430\u0437 \u043d\u0430 docker-hub&#8217;\u0435<br \/>  <a href=\"https:\/\/habrastorage.org\/webt\/pq\/zx\/xf\/pqzxxfn_dhfqnj6cxgxlcrkb6w0.png\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/pq\/zx\/xf\/pqzxxfn_dhfqnj6cxgxlcrkb6w0.png\"><\/a><\/li>\n<li>\u0421\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u0434\u043e\u0432<br \/>  <a href=\"https:\/\/habrastorage.org\/webt\/d_\/s5\/ev\/d_s5evcbp9k24rddt1ffweipux8.png\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/d_\/s5\/ev\/d_s5evcbp9k24rddt1ffweipux8.png\"><\/a><\/li>\n<li>\u0418 \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u044e \u043e\u0431\u0440\u0430\u0437\u0430, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u0451\u0440\u043d\u0443\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0432 \u043e\u0434\u043d\u043e\u043c \u0438\u0437 \u043f\u043e\u0434\u043e\u0432 \u0438\u0437 2-\u0433\u043e \u043f\u0443\u043d\u043a\u0442\u0430<br \/>  <a href=\"https:\/\/habrastorage.org\/webt\/yb\/h-\/hr\/ybh-hrr4ommmlrsqh4inb4_nii4.png\" rel=\"nofollow\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/yb\/h-\/hr\/ybh-hrr4ommmlrsqh4inb4_nii4.png\"><\/a><\/li>\n<li>\u0414\u0435\u043b\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u043e\u0442\u0432\u0435\u0442:<\/li>\n<\/ol>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">curl https:\/\/demo1.bihero.io\/api\/hello -v<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">curl https:\/\/demo1.bihero.io\/api\/hello -v                                                                                                                          \ue0b2 \uf00c \ue0b2 5350 \ue0b2 14:59:04 \uf017  *   Trying 178.63.194.243... * TCP_NODELAY set * Connected to demo1.bihero.io (178.63.194.243) port 443 (#0) * ALPN, offering h2 * ALPN, offering http\/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: *   CAfile: \/etc\/ssl\/certs\/ca-certificates.crt   CApath: \/etc\/ssl\/certs * TLSv1.2 (OUT), TLS header, Certificate Status (22): * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Client hello (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Client hello (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 \/ ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server accepted to use h2 * Server certificate: *  subject: CN=*.bihero.io *  start date: Nov  7 13:59:46 2019 GMT *  expire date: Feb  5 13:59:46 2020 GMT *  subjectAltName: host \"demo1.bihero.io\" matched cert's \"*.bihero.io\" *  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3 *  SSL certificate verify ok. * Using HTTP2, server supports multi-use * Connection state changed (HTTP\/2 confirmed) * Copying HTTP\/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x55778f779520) &gt; GET \/api\/hello HTTP\/1.1 &gt; Host: demo1.bihero.io &gt; User-Agent: curl\/7.52.1 &gt; Accept: *\/* &gt;  * Connection state changed (MAX_CONCURRENT_STREAMS updated)! &lt; HTTP\/2 200  &lt; server: nginx\/1.15.8 &lt; date: Sun, 01 Dec 2019 11:59:06 GMT &lt; content-type: text\/plain &lt; content-length: 5 &lt; strict-transport-security: max-age=15724800; includeSubDomains &lt;  * Curl_http_done: called premature == 0 * Connection #0 to host demo1.bihero.io left intact Hello<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u041c\u043d\u043e\u0433\u043e \u0432\u0441\u0435\u0433\u043e \u0431\u044b\u043b\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e, \u043d\u043e \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c, \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u043c\u044b \u0442\u0443\u0442 \u0441\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c. \u041f\u0440\u043e\u0434\u0443\u043a\u0442 \u0436\u0435 \u043f\u0438\u043b\u0438\u043c, \u0438 \u0435\u0449\u0451 \u0446\u0435\u043b\u044b\u0445 \u0434\u0432\u0430 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043d\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b. \u0414\u0430\u043b\u044c\u0448\u0435 \u043c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0437\u0436\u0451\u0432\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043e\u0441\u0442\u0430\u0432\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0442\u043e\u043b\u044c\u043a\u043e \u043b\u0438\u0448\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0438 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0441\u0431\u043e\u0440\u043a\u0438 \u0432 \u0441\u043f\u043e\u0439\u043b\u0435\u0440\u0430\u0445 (\u0440\u0430\u0437\u0432\u0435 \u0447\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0437\u0430\u043c\u0443\u0442\u0438\u043c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441 testcontainers). \u0410 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0432\u043e\u0434\u044b \u0438 \u0432\u043d\u0443\u0448\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 TODO-\u043b\u0438\u0441\u0442 (\u043a\u0443\u0434\u0430 \u0436\u0435 \u0431\u0435\u0437 \u0431\u044d\u043a\u043b\u043e\u0433\u0430). \u041f\u043e\u0435\u0445\u0430\u043b\u0438!<\/p>\n<p>  <\/p>\n<h2 id=\"world-microservice\">&#8216;World&#8217; microservice<\/h2>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Service specification<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">openapi: 3.0.1 info:   title: World ;)   description: \"'World' word microservice\"   version: 1.0.0 servers:   - url: https:\/\/demo1.bihero.io\/api\/world tags:   - name: world     description: Everything about 'World' word paths:   \/:     x-vertx-event-bus:       address: service.world       timeout: 1000     get:       tags:         - world       summary: Get 'World' word       operationId: getWorldWord       responses:         200:           description: OK           content: {}   \/doc:     x-vertx-event-bus:       address: service.world       timeout: 1000c     get:       tags:         - world       summary: Get 'World' microservice documentation       operationId: getDoc       responses:         200:           description: OK components: {}<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pom.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt; &lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\"          xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"          xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\"&gt;     &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;      &lt;properties&gt;         &lt;main.verticle&gt;io.bihero.world.WorldVerticle&lt;\/main.verticle&gt;         &lt;vertx.version&gt;3.8.1&lt;\/vertx.version&gt;         &lt;logback.version&gt;1.2.3&lt;\/logback.version&gt;         &lt;junit-jupiter.version&gt;5.3.1&lt;\/junit-jupiter.version&gt;         &lt;maven-surefire-plugin.version&gt;2.19.1&lt;\/maven-surefire-plugin.version&gt;         &lt;junit-platform-surefire-provider.version&gt;1.1.0&lt;\/junit-platform-surefire-provider.version&gt;         &lt;assertj-core.version&gt;3.8.0&lt;\/assertj-core.version&gt;         &lt;allure.version&gt;2.8.1&lt;\/allure.version&gt;         &lt;allure-maven.version&gt;2.10.0&lt;\/allure-maven.version&gt;         &lt;aspectj.version&gt;1.9.2&lt;\/aspectj.version&gt;         &lt;mockito.version&gt;2.21.0&lt;\/mockito.version&gt;         &lt;rest-assured.version&gt;3.0.0&lt;\/rest-assured.version&gt;     &lt;\/properties&gt;      &lt;groupId&gt;io.bihero&lt;\/groupId&gt;     &lt;artifactId&gt;world-microservice&lt;\/artifactId&gt;     &lt;version&gt;1.0.0-SNAPSHOT&lt;\/version&gt;     &lt;build&gt;         &lt;plugins&gt;             &lt;plugin&gt;                 &lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;                 &lt;configuration&gt; ```11&lt;\/source&gt;                     &lt;target&gt;11&lt;\/target&gt;                 &lt;\/configuration&gt;                 &lt;executions&gt;                     &lt;execution&gt;                         &lt;id&gt;default-compile&lt;\/id&gt;                         &lt;configuration&gt;                             &lt;annotationProcessors&gt;                                 &lt;annotationProcessor&gt;io.vertx.codegen.CodeGenProcessor&lt;\/annotationProcessor&gt;                             &lt;\/annotationProcessors&gt;                             &lt;generatedSourcesDirectory&gt;src\/main\/generated&lt;\/generatedSourcesDirectory&gt;                             &lt;compilerArgs&gt;                                 &lt;arg&gt;-Acodegen.output=${project.basedir}\/src\/main&lt;\/arg&gt;                             &lt;\/compilerArgs&gt;                         &lt;\/configuration&gt;                     &lt;\/execution&gt;                     &lt;execution&gt;                         &lt;id&gt;default-testCompile&lt;\/id&gt;                         &lt;configuration&gt;                             &lt;annotationProcessors&gt;                                 &lt;annotationProcessor&gt;io.vertx.codegen.CodeGenProcessor&lt;\/annotationProcessor&gt;                             &lt;\/annotationProcessors&gt;                             &lt;generatedTestSourcesDirectory&gt;src\/test\/generated&lt;\/generatedTestSourcesDirectory&gt;                             &lt;compilerArgs&gt;                                 &lt;arg&gt;-Acodegen.output=${project.basedir}\/src\/test&lt;\/arg&gt;                             &lt;\/compilerArgs&gt;                         &lt;\/configuration&gt;                     &lt;\/execution&gt;                 &lt;\/executions&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-surefire-plugin&lt;\/artifactId&gt;                 &lt;version&gt;${maven-surefire-plugin.version}&lt;\/version&gt;                 &lt;configuration&gt;                     &lt;properties&gt;                         &lt;property&gt;                             &lt;name&gt;listener&lt;\/name&gt;                             &lt;value&gt;io.qameta.allure.junit5.AllureJunit5&lt;\/value&gt;                         &lt;\/property&gt;                     &lt;\/properties&gt;                     &lt;includes&gt;                         &lt;include&gt;**\/*Test*.java&lt;\/include&gt;                     &lt;\/includes&gt;                     &lt;argLine&gt;                         -javaagent:\"${settings.localRepository}\/org\/aspectj\/aspectjweaver\/${aspectj.version}\/aspectjweaver-${aspectj.version}.jar\" -Djdk.net.URLClassPath.disableClassPathURLCheck=true                     &lt;\/argLine&gt;                     &lt;systemProperties&gt;                         &lt;property&gt;                             &lt;name&gt;allure.results.directory&lt;\/name&gt;                             &lt;value&gt;${project.basedir}\/target\/allure-results&lt;\/value&gt;                         &lt;\/property&gt;                         &lt;property&gt;                             &lt;name&gt;junit.jupiter.extensions.autodetection.enabled&lt;\/name&gt;                             &lt;value&gt;true&lt;\/value&gt;                         &lt;\/property&gt;                     &lt;\/systemProperties&gt;                     &lt;reportFormat&gt;plain&lt;\/reportFormat&gt;                 &lt;\/configuration&gt;                 &lt;dependencies&gt;                     &lt;dependency&gt;                         &lt;groupId&gt;org.aspectj&lt;\/groupId&gt;                         &lt;artifactId&gt;aspectjweaver&lt;\/artifactId&gt;                         &lt;version&gt;${aspectj.version}&lt;\/version&gt;                     &lt;\/dependency&gt;                     &lt;dependency&gt;                         &lt;groupId&gt;org.junit.platform&lt;\/groupId&gt;                         &lt;artifactId&gt;junit-platform-surefire-provider&lt;\/artifactId&gt;                         &lt;version&gt;${junit-platform-surefire-provider.version}&lt;\/version&gt;                     &lt;\/dependency&gt;                     &lt;dependency&gt;                         &lt;groupId&gt;org.junit.jupiter&lt;\/groupId&gt;                         &lt;artifactId&gt;junit-jupiter-engine&lt;\/artifactId&gt;                         &lt;version&gt;${junit-jupiter.version}&lt;\/version&gt;                     &lt;\/dependency&gt;                 &lt;\/dependencies&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;io.qameta.allure&lt;\/groupId&gt;                 &lt;artifactId&gt;allure-maven&lt;\/artifactId&gt;                 &lt;version&gt;${allure-maven.version}&lt;\/version&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-site-plugin&lt;\/artifactId&gt;                 &lt;version&gt;3.7.1&lt;\/version&gt;                 &lt;dependencies&gt;                     &lt;dependency&gt;                         &lt;groupId&gt;org.apache.maven.wagon&lt;\/groupId&gt;                         &lt;artifactId&gt;wagon-webdav-jackrabbit&lt;\/artifactId&gt;                         &lt;version&gt;2.8&lt;\/version&gt;                     &lt;\/dependency&gt;                 &lt;\/dependencies&gt;             &lt;\/plugin&gt;              &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-project-info-reports-plugin&lt;\/artifactId&gt;                 &lt;version&gt;3.0.0&lt;\/version&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-shade-plugin&lt;\/artifactId&gt;                 &lt;version&gt;2.3&lt;\/version&gt;                 &lt;executions&gt;                     &lt;execution&gt;                         &lt;phase&gt;package&lt;\/phase&gt;                         &lt;goals&gt;                             &lt;goal&gt;shade&lt;\/goal&gt;                         &lt;\/goals&gt;                         &lt;configuration&gt;                             &lt;transformers&gt;                                 &lt;transformer implementation=\"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer\"&gt;                                     &lt;manifestEntries&gt;                                         &lt;Main-Class&gt;io.vertx.core.Launcher&lt;\/Main-Class&gt;                                         &lt;Main-Verticle&gt;${main.verticle}&lt;\/Main-Verticle&gt;                                     &lt;\/manifestEntries&gt;                                 &lt;\/transformer&gt;                                 &lt;transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\"&gt;                                     &lt;resource&gt;META-INF\/services\/io.vertx.core.spi.VerticleFactory&lt;\/resource&gt;                                 &lt;\/transformer&gt;                             &lt;\/transformers&gt;                             &lt;artifactSet&gt;                             &lt;\/artifactSet&gt;                             &lt;outputFile&gt;${project.build.directory}\/${project.artifactId}-fat.jar&lt;\/outputFile&gt;                         &lt;\/configuration&gt;                     &lt;\/execution&gt;                 &lt;\/executions&gt;             &lt;\/plugin&gt;         &lt;\/plugins&gt;         &lt;resources&gt;             &lt;resource&gt;                 &lt;directory&gt;src\/main\/resources&lt;\/directory&gt;                 &lt;filtering&gt;true&lt;\/filtering&gt;                 &lt;includes&gt;                     &lt;include&gt;**\/version.txt&lt;\/include&gt;                 &lt;\/includes&gt;             &lt;\/resource&gt;             &lt;resource&gt;                 &lt;directory&gt;src\/main\/resources&lt;\/directory&gt;                 &lt;filtering&gt;false&lt;\/filtering&gt;                 &lt;excludes&gt;                     &lt;exclude&gt;**\/version.txt&lt;\/exclude&gt;                 &lt;\/excludes&gt;             &lt;\/resource&gt;         &lt;\/resources&gt;     &lt;\/build&gt;     &lt;distributionManagement&gt;         &lt;site&gt;             &lt;id&gt;reports&lt;\/id&gt;             &lt;url&gt;dav:https:\/\/nexus.dev.techedge.pro:8443\/repository\/reports\/${project.artifactId}\/&lt;\/url&gt;         &lt;\/site&gt;     &lt;\/distributionManagement&gt;     &lt;reporting&gt;         &lt;excludeDefaults&gt;true&lt;\/excludeDefaults&gt;         &lt;plugins&gt;             &lt;plugin&gt;                 &lt;groupId&gt;io.qameta.allure&lt;\/groupId&gt;                 &lt;artifactId&gt;allure-maven&lt;\/artifactId&gt;                 &lt;configuration&gt;                     &lt;resultsDirectory&gt;${project.build.directory}\/allure-results&lt;\/resultsDirectory&gt;                     &lt;reportDirectory&gt;${project.reporting.outputDirectory}\/${project.version}\/allure&lt;\/reportDirectory&gt;                 &lt;\/configuration&gt;             &lt;\/plugin&gt;         &lt;\/plugins&gt;     &lt;\/reporting&gt;      &lt;dependencies&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-web-api-service&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-codegen&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;             &lt;scope&gt;provided&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;ch.qos.logback&lt;\/groupId&gt;             &lt;artifactId&gt;logback-classic&lt;\/artifactId&gt;             &lt;version&gt;${logback.version}&lt;\/version&gt;         &lt;\/dependency&gt;          &lt;!-- test &amp;ndash;&amp;gt;--&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-unit&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-junit5&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.junit.jupiter&lt;\/groupId&gt;             &lt;artifactId&gt;junit-jupiter-api&lt;\/artifactId&gt;             &lt;version&gt;${junit-jupiter.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.junit.jupiter&lt;\/groupId&gt;             &lt;artifactId&gt;junit-jupiter-engine&lt;\/artifactId&gt;             &lt;version&gt;${junit-jupiter.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.assertj&lt;\/groupId&gt;             &lt;artifactId&gt;assertj-core&lt;\/artifactId&gt;             &lt;version&gt;${assertj-core.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.mockito&lt;\/groupId&gt;             &lt;artifactId&gt;mockito-core&lt;\/artifactId&gt;             &lt;version&gt;${mockito.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.qameta.allure&lt;\/groupId&gt;             &lt;artifactId&gt;allure-junit5&lt;\/artifactId&gt;             &lt;version&gt;${allure.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-web-client&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;     &lt;\/dependencies&gt;  &lt;\/project&gt;<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">WorldService.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.world;  import io.vertx.core.AsyncResult; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.ext.web.api.OperationRequest; import io.vertx.ext.web.api.OperationResponse; import io.vertx.ext.web.api.generator.WebApiServiceGen;  @WebApiServiceGen public interface WorldService {      static WorldService create(Vertx vertx) {         return new DefaultWorldService(vertx);     }      void getWorldWord(OperationRequest context, Handler&lt;AsyncResult&lt;OperationResponse&gt;&gt; resultHandler);      void getDoc(OperationRequest context, Handler&lt;AsyncResult&lt;OperationResponse&gt;&gt; resultHandler);  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">DefaultWorldService.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.world;  import io.vertx.core.AsyncResult; import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.api.OperationRequest; import io.vertx.ext.web.api.OperationResponse;  public class DefaultWorldService implements WorldService {      private final Vertx vertx;      public DefaultWorldService(Vertx vertx) {         this.vertx = vertx;     }      public void getWorldWord(OperationRequest context, Handler&lt;AsyncResult&lt;OperationResponse&gt;&gt; resultHandler) {         resultHandler.handle(Future.succeededFuture(OperationResponse.completedWithPlainText(Buffer.buffer(\"World\"))));     }      @Override     public void getDoc(OperationRequest context, Handler&lt;AsyncResult&lt;OperationResponse&gt;&gt; resultHandler) {         vertx.fileSystem().readFile(\"doc.yaml\", buffResult -&gt;                 resultHandler.handle(Future.succeededFuture(                         OperationResponse.completedWithPlainText(buffResult.result()))                 ));     }  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">WorldVerticle.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.world;  import io.vertx.core.AbstractVerticle; import io.vertx.core.Promise; import io.vertx.core.eventbus.MessageConsumer; import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerOptions; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.Router; import io.vertx.ext.web.api.contract.openapi3.OpenAPI3RouterFactory; import io.vertx.serviceproxy.ServiceBinder;  public class WorldVerticle extends AbstractVerticle {      HttpServer server;     MessageConsumer&lt;JsonObject&gt; consumer;      public void startWorldService() {         consumer = new ServiceBinder(vertx).setAddress(\"service.world\")                 .register(WorldService.class, WorldService.create(getVertx()));     }      \/**      * This method constructs the router factory, mounts services and handlers and starts the http server      * with built router      * @return      *\/     private Promise&lt;Void&gt; startHttpServer() {         Promise&lt;Void&gt; promise = Promise.promise();         OpenAPI3RouterFactory.create(this.vertx, \"\/doc.yaml\", openAPI3RouterFactoryAsyncResult -&gt; {             if (openAPI3RouterFactoryAsyncResult.succeeded()) {                 OpenAPI3RouterFactory routerFactory = openAPI3RouterFactoryAsyncResult.result();                  \/\/ Mount services on event bus based on extensions                 routerFactory.mountServicesFromExtensions();                  \/\/ Generate the router                 Router router = routerFactory.getRouter();                  int port = config().getInteger(\"serverPort\", 8080);                 String host = config().getString(\"serverHost\", \"localhost\");                  server = vertx.createHttpServer(new HttpServerOptions().setPort(port).setHost(host));                 server.requestHandler(router).listen(ar -&gt; {                     \/\/ Error starting the HttpServer                     if (ar.succeeded()) promise.complete();                     else promise.fail(ar.cause());                 });             } else {                 \/\/ Something went wrong during router factory initialization                 promise.fail(openAPI3RouterFactoryAsyncResult.cause());             }         });         return promise;     }      @Override     public void start(Promise&lt;Void&gt; promise) {         startWorldService();         startHttpServer().future().setHandler(promise);     }      \/**      * This method closes the http server and unregister all services loaded to Event Bus      *\/     @Override     public void stop(){         this.server.close();         consumer.unregister();     }  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">WorldServiceTest.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.world;  import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.api.OperationRequest; import io.vertx.junit5.VertxExtension; import io.vertx.junit5.VertxTestContext; import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith;  import java.io.IOException;  import static org.assertj.core.api.Assertions.assertThat;  @ExtendWith(VertxExtension.class) public class WorldServiceTest {      private WorldService worldService = WorldService.create(Vertx.vertx());      @Test     @DisplayName(\"Test 'getWorldWord' method returns 'World' word\")     public void testHelloMethod(VertxTestContext testContext) {         worldService.getWorldWord(new OperationRequest(new JsonObject()), testContext.succeeding(it -&gt; {             assertThat(it.getStatusCode()).isEqualTo(200);             assertThat(it.getPayload().toString()).isEqualTo(\"World\");             testContext.completeNow();         }));     }      @Test     @DisplayName(\"Test 'getDoc' method returns service documentation in OpenAPI format\")     public void testDocMethod(VertxTestContext testContext) {         worldService.getDoc(new OperationRequest(new JsonObject()), testContext.succeeding(it -&gt; {             try {                 assertThat(it.getStatusCode()).isEqualTo(200);                 assertThat(it.getPayload().toString()).isEqualTo(IOUtils.toString(this.getClass()                         .getResourceAsStream(\"..\/..\/..\/doc.yaml\"), \"UTF-8\"));                 testContext.completeNow();             } catch (IOException e) {                 testContext.failNow(e);             }         }));     }  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">WorldVerticleTest.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.world;  import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.codec.BodyCodec; import io.vertx.junit5.Checkpoint; import io.vertx.junit5.VertxExtension; import io.vertx.junit5.VertxTestContext; import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith;  import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy;  @ExtendWith(VertxExtension.class) public class WorldVerticleTest {      @Test     @DisplayName(\"Test that verticle is up and respond me by 'World' word and doc in OpenAPI format\")     public void testHelloVerticle(Vertx vertx, VertxTestContext testContext) {         WebClient webClient = WebClient.create(vertx);          Checkpoint deploymentCheckpoint = testContext.checkpoint();         Checkpoint requestCheckpoint = testContext.checkpoint(2);          WorldVerticle verticle = spy(new WorldVerticle());         JsonObject config = new JsonObject().put(\"serverPort\", 8082).put(\"serverHost\", \"0.0.0.0\");         doReturn(config).when(verticle).config();         vertx.deployVerticle(verticle, testContext.succeeding(id -&gt; {             deploymentCheckpoint.flag();             \/\/ test GET \/             webClient.get(8082, \"localhost\", \"\/\")                     .as(BodyCodec.string())                     .send(testContext.succeeding(resp -&gt; {                         assertThat(resp.body()).isEqualTo(\"World\");                         assertThat(resp.statusCode()).isEqualTo(200);                         requestCheckpoint.flag();                     }));             \/\/ test GET \/doc             webClient.get(8082, \"localhost\", \"\/doc\")                     .as(BodyCodec.string())                     .send(testContext.succeeding(resp -&gt; {                         try {                             assertThat(resp.body()).isEqualTo(IOUtils.toString(this.getClass()                                     .getResourceAsStream(\"..\/..\/..\/doc.yaml\"), \"UTF-8\"));                             assertThat(resp.statusCode()).isEqualTo(200);                             requestCheckpoint.flag();                         } catch (Exception e) {                             requestCheckpoint.flag();                             testContext.failNow(e);                         }                     }));         }));     }  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Dockerfile<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">FROM adoptopenjdk\/openjdk11:alpine-jre COPY target\/world-microservice-fat.jar app.jar COPY src\/conf\/config.json . COPY src\/conf\/logback-console.xml . COPY run.sh . RUN chmod +x run.sh CMD [\".\/run.sh\"]<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">run.sh<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">#!\/bin\/sh java ${JVM_OPTS} -Dlogback.configurationFile=.\/logback-console.xml -jar app.jar -conf config.json<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pipeline.yaml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">resource_types:   - name: telegram     type: docker-image     source:       repository: vtutrinov\/concourse-telegram-resource       tag: latest   - name: kubernetes     type: docker-image     source:       repository: zlabjp\/kubernetes-resource       tag: 1.16   - name: metadata     type: docker-image     source:       repository: olhtbr\/metadata-resource       tag: 2.0.1 resources:   - name: metadata     type: metadata   - name: sources     type: git     source:       branch: master       uri: git@github.com:bihero-io\/worldmicroservice.git       private_key: ((deployer-private-key))   - name: docker-image     type: docker-image     source:       repository: bihero\/world       username: ((docker-registry-user))       password: ((docker-registry-password))   - name: telegram     type: telegram     source:       bot_token: ((telegram-ci-bot-token))       chat_id: ((telegram-group-to-report-build))       ci_url: ((ci_url))       command: \"\/build_world_ms\"   - name: kubernetes-demo     type: kubernetes     source:       server: ((k8s-api-server))       namespace: default       kubeconfig: ((kubeconfig-demo)) jobs:   - name: build-world-microservice     serial: true     public: true     plan:       - in_parallel:           - get: sources             trigger: true           - get: telegram             trigger: true           - put: metadata       - put: telegram         params:           status: Build In Progress       - task: unit-tests         config:           platform: linux           image_resource:             type: docker-image             source:               repository: ((docker-registry-uri))\/bih\/maven-dind               tag: 3-jdk-11               username: ((docker-private-registry-user))               password: ((docker-private-registry-password))           inputs:             - name: sources           outputs:             - name: tested-workspace           run:             path: \/bin\/sh             args:               - -c               - |                 output_dir=tested-workspace                 cp -R .\/sources\/* \"${output_dir}\/\"                 mvn -f \"${output_dir}\/pom.xml\" clean test           caches:             - path: ~\/.m2\/         on_failure:           do:             - task: tests-report               config:                 platform: linux                 image_resource:                   type: docker-image                   source:                     repository: ((docker-registry-uri))\/bih\/maven-dind                     tag: 3-jdk-11                     username: ((docker-private-registry-user))                     password: ((docker-private-registry-password))                 inputs:                   - name: tested-workspace                 outputs:                   - name: message                 run:                   path: \/bin\/sh                   args:                     - -c                     - |                       output_dir=tested-workspace                       mvn -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -f \"${output_dir}\/pom.xml\" site-deploy                       version=$(cat $output_dir\/target\/classes\/version.txt)                       cat &gt;message\/msg &lt;&lt;EOL                       &lt;a href=\"https:\/\/nexus.dev.techedge.pro:8443\/repository\/reports\/hello-microservice\/${version}\/allure\/\"&gt;Allure report&lt;\/a&gt;                       EOL                 caches:                   - path: ~\/.m2\/             - put: telegram               params:                 status: Build Failed (unit-tests)                 message_file: message\/msg       - task: tests-report         config:           platform: linux           image_resource:             type: docker-image             source:               repository: ((docker-registry-uri))\/bih\/maven-dind               tag: 3-jdk-11               username: ((docker-private-registry-user))               password: ((docker-private-registry-password))           inputs:             - name: tested-workspace           outputs:             - name: message             - name: tested-workspace           run:             path: \/bin\/sh             args:               - -c               - |                 work_dir=tested-workspace                 mvn -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -f \"${work_dir}\/pom.xml\" site-deploy                 version=$(cat $work_dir\/target\/classes\/version.txt)                 cat &gt;message\/msg &lt;&lt;EOL                 &lt;a href=\"https:\/\/nexus.dev.techedge.pro:8443\/repository\/reports\/world-microservice\/${version}\/allure\/\"&gt;Allure report&lt;\/a&gt;                 EOL           caches:             - path: ~\/.m2\/       - task: package         config:           platform: linux           image_resource:             type: docker-image             source:               repository: ((docker-registry-uri))\/bih\/maven-dind               tag: 3-jdk-11               username: ((docker-private-registry-user))               password: ((docker-private-registry-password))           inputs:             - name: tested-workspace             - name: metadata           outputs:             - name: app-packaged-workspace             - name: metadata           run:             path: \/bin\/sh             args:               - -c               - |                 output_dir=app-packaged-workspace                 cp -R .\/tested-workspace\/* \"${output_dir}\/\"                 mvn -f \"${output_dir}\/pom.xml\" package -Dmaven.main.skip -DskipTests                 tag=\"-\"$(cat metadata\/build_name)                 echo $tag &gt;&gt; ${output_dir}\/target\/classes\/version.txt                 cat ${output_dir}\/target\/classes\/version.txt &gt; metadata\/version           caches:             - path: ~\/.m2\/         on_failure:           do:             - put: telegram               params:                 status: Build Failed (package)       - put: docker-image         params:           build: app-packaged-workspace           tag_file: app-packaged-workspace\/target\/classes\/version.txt           tag_as_latest: true         get_params:           skip_download: true       - task: make-k8s-app-template         config:           platform: linux           image_resource:             type: docker-image             source:               repository: bhgedigital\/envsubst           inputs:             - name: sources             - name: metadata           outputs:             - name: k8s           run:             path: \/bin\/sh             args:               - -c               - |                 export DOMAIN=demo1.bihero.io                 export WORLD_SERVICE_IMAGE_VERSION=$(cat metadata\/version)                 cat sources\/k8s.yaml | envsubst &gt; k8s\/world_app_template.yaml                 cat k8s\/world_app_template.yaml       - put: kubernetes-demo         params:           kubectl: apply -f k8s\/world_app_template.yaml       - put: telegram         params:           status: Build Success           message_file: message\/msg<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">k8s app template<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">apiVersion: extensions\/v1beta1 kind: Deployment metadata:   labels:     io.bihero.hello.service: bihero-world   name: bihero-world spec:   replicas: 3   strategy:     type: RollingUpdate     rollingUpdate:       maxSurge: 1       maxUnavailable: 1   template:     metadata:       labels:         io.bihero.hello.service: bihero-world     spec:       containers:         - image: bihero\/world:${WORLD_SERVICE_IMAGE_VERSION}           name: bihero-world           ports:             - containerPort: 8082           imagePullPolicy: Always           resources: {}       restartPolicy: Always --- apiVersion: v1 kind: Service metadata:   labels:     io.bihero.hello.service: bihero-world   name: bihero-world spec:   ports:     - name: \"8082\"       port: 8082       targetPort: 8082   selector:     io.bihero.hello.service: bihero-world status:   loadBalancer: {} --- apiVersion: extensions\/v1beta1 kind: Ingress metadata:   name: bihero-world   annotations:     kubernetes.io\/ingress.class: nginx     nginx.ingress.kubernetes.io\/ssl-redirect: \"true\"     nginx.ingress.kubernetes.io\/secure-backends: \"false\"     nginx.ingress.kubernetes.io\/ssl-passthrough: \"false\"     nginx.ingress.kubernetes.io\/rewrite-target: \/$2     kubernetes.io\/tls-acme: \"true\"   namespace: default spec:   tls:     - hosts:         - ${DOMAIN}       secretName: bihero   rules:     - host: ${DOMAIN}       http:         paths:           - path: \/api\/world(\/|$)(.*)             backend:               serviceName: bihero-world               servicePort: 8082<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<h2 id=\"helloworld-microservice\">&#8216;HelloWorld&#8217; microservice<\/h2>\n<p>  <\/p>\n<p>\u042d\u0442\u043e\u0442 \u043e\u0440\u0435\u0448\u0435\u043a \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u043a\u0440\u0435\u043f\u0447\u0435, \u0447\u0435\u043c \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e. \u041d\u0443, \u0434\u0430 \u043b\u0430\u0434\u043d\u043e, \u043c\u044b \u0438 \u0435\u0433\u043e \u0440\u0430\u0441\u043a\u043e\u043b\u043e\u043b\u0438. \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0438 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441 testcontainers, \u043d\u043e \u043e\u0431\u043e \u0432\u0441\u0451 \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Service specification<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">openapi: 3.0.1 info:   title: Hello World ;)   description: \"Hello World microservice. Aggregate 'Hello World' by hellomicroservice and worldmicroservice\"   version: 1.0.0 servers:   - url: https:\/\/demo1.bihero.io\/api\/helloworld tags:   - name: helloworld     description: Everything about 'Hello World' paths:   \/:     x-vertx-event-bus:       address: service.helloworld       timeout: 1000     get:       tags:         - helloworld       summary: Aggregate 'Hello World'       operationId: getHelloWorld       responses:         200:           description: OK           content: {}   \/doc:     x-vertx-event-bus:       address: service.helloworld       timeout: 1000c     get:       tags:         - world       summary: Get 'Hello World' microservice documentation       operationId: getDoc       responses:         200:           description: OK components: {}<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pom.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt; &lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\"          xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"          xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\"&gt;     &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;      &lt;properties&gt;         &lt;main.verticle&gt;io.bihero.helloworld.HelloWorldVerticle&lt;\/main.verticle&gt;         &lt;vertx.version&gt;3.8.1&lt;\/vertx.version&gt;         &lt;logback.version&gt;1.2.3&lt;\/logback.version&gt;         &lt;junit-jupiter.version&gt;5.3.1&lt;\/junit-jupiter.version&gt;         &lt;maven-surefire-plugin.version&gt;2.19.1&lt;\/maven-surefire-plugin.version&gt;         &lt;junit-platform-surefire-provider.version&gt;1.1.0&lt;\/junit-platform-surefire-provider.version&gt;         &lt;assertj-core.version&gt;3.8.0&lt;\/assertj-core.version&gt;         &lt;allure.version&gt;2.8.1&lt;\/allure.version&gt;         &lt;allure-maven.version&gt;2.10.0&lt;\/allure-maven.version&gt;         &lt;aspectj.version&gt;1.9.2&lt;\/aspectj.version&gt;         &lt;mockito.version&gt;2.21.0&lt;\/mockito.version&gt;         &lt;rest-assured.version&gt;3.0.0&lt;\/rest-assured.version&gt;         &lt;testcontainers.version&gt;1.12.3&lt;\/testcontainers.version&gt;     &lt;\/properties&gt;      &lt;groupId&gt;io.bihero&lt;\/groupId&gt;     &lt;artifactId&gt;hello-world-microservice&lt;\/artifactId&gt;     &lt;version&gt;1.0.0-SNAPSHOT&lt;\/version&gt;     &lt;build&gt;         &lt;plugins&gt;             &lt;plugin&gt;                 &lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;                 &lt;configuration&gt; ```11&lt;\/source&gt;                     &lt;target&gt;11&lt;\/target&gt;                 &lt;\/configuration&gt;                 &lt;executions&gt;                     &lt;execution&gt;                         &lt;id&gt;default-compile&lt;\/id&gt;                         &lt;configuration&gt;                             &lt;annotationProcessors&gt;                                 &lt;annotationProcessor&gt;io.vertx.codegen.CodeGenProcessor&lt;\/annotationProcessor&gt;                             &lt;\/annotationProcessors&gt;                             &lt;generatedSourcesDirectory&gt;src\/main\/generated&lt;\/generatedSourcesDirectory&gt;                             &lt;compilerArgs&gt;                                 &lt;arg&gt;-Acodegen.output=${project.basedir}\/src\/main&lt;\/arg&gt;                             &lt;\/compilerArgs&gt;                         &lt;\/configuration&gt;                     &lt;\/execution&gt;                     &lt;execution&gt;                         &lt;id&gt;default-testCompile&lt;\/id&gt;                         &lt;configuration&gt;                             &lt;annotationProcessors&gt;                                 &lt;annotationProcessor&gt;io.vertx.codegen.CodeGenProcessor&lt;\/annotationProcessor&gt;                             &lt;\/annotationProcessors&gt;                             &lt;generatedTestSourcesDirectory&gt;src\/test\/generated&lt;\/generatedTestSourcesDirectory&gt;                             &lt;compilerArgs&gt;                                 &lt;arg&gt;-Acodegen.output=${project.basedir}\/src\/test&lt;\/arg&gt;                             &lt;\/compilerArgs&gt;                         &lt;\/configuration&gt;                     &lt;\/execution&gt;                 &lt;\/executions&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-surefire-plugin&lt;\/artifactId&gt;                 &lt;version&gt;${maven-surefire-plugin.version}&lt;\/version&gt;                 &lt;configuration&gt;                     &lt;properties&gt;                         &lt;property&gt;                             &lt;name&gt;listener&lt;\/name&gt;                             &lt;value&gt;io.qameta.allure.junit5.AllureJunit5&lt;\/value&gt;                         &lt;\/property&gt;                     &lt;\/properties&gt;                     &lt;includes&gt;                         &lt;include&gt;**\/*Test.java&lt;\/include&gt;                     &lt;\/includes&gt;                     &lt;argLine&gt;                         -javaagent:\"${settings.localRepository}\/org\/aspectj\/aspectjweaver\/${aspectj.version}\/aspectjweaver-${aspectj.version}.jar\" -Djdk.net.URLClassPath.disableClassPathURLCheck=true                     &lt;\/argLine&gt;                     &lt;systemProperties&gt;                         &lt;property&gt;                             &lt;name&gt;allure.results.directory&lt;\/name&gt;                             &lt;value&gt;${project.basedir}\/target\/allure-results&lt;\/value&gt;                         &lt;\/property&gt;                         &lt;property&gt;                             &lt;name&gt;junit.jupiter.extensions.autodetection.enabled&lt;\/name&gt;                             &lt;value&gt;true&lt;\/value&gt;                         &lt;\/property&gt;                     &lt;\/systemProperties&gt;                     &lt;reportFormat&gt;plain&lt;\/reportFormat&gt;                 &lt;\/configuration&gt;                 &lt;dependencies&gt;                     &lt;dependency&gt;                         &lt;groupId&gt;org.aspectj&lt;\/groupId&gt;                         &lt;artifactId&gt;aspectjweaver&lt;\/artifactId&gt;                         &lt;version&gt;${aspectj.version}&lt;\/version&gt;                     &lt;\/dependency&gt;                     &lt;dependency&gt;                         &lt;groupId&gt;org.junit.platform&lt;\/groupId&gt;                         &lt;artifactId&gt;junit-platform-surefire-provider&lt;\/artifactId&gt;                         &lt;version&gt;${junit-platform-surefire-provider.version}&lt;\/version&gt;                     &lt;\/dependency&gt;                     &lt;dependency&gt;                         &lt;groupId&gt;org.junit.jupiter&lt;\/groupId&gt;                         &lt;artifactId&gt;junit-jupiter-engine&lt;\/artifactId&gt;                         &lt;version&gt;${junit-jupiter.version}&lt;\/version&gt;                     &lt;\/dependency&gt;                 &lt;\/dependencies&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;io.qameta.allure&lt;\/groupId&gt;                 &lt;artifactId&gt;allure-maven&lt;\/artifactId&gt;                 &lt;version&gt;${allure-maven.version}&lt;\/version&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-site-plugin&lt;\/artifactId&gt;                 &lt;version&gt;3.7.1&lt;\/version&gt;                 &lt;dependencies&gt;                     &lt;dependency&gt;                         &lt;groupId&gt;org.apache.maven.wagon&lt;\/groupId&gt;                         &lt;artifactId&gt;wagon-webdav-jackrabbit&lt;\/artifactId&gt;                         &lt;version&gt;2.8&lt;\/version&gt;                     &lt;\/dependency&gt;                 &lt;\/dependencies&gt;             &lt;\/plugin&gt;              &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-project-info-reports-plugin&lt;\/artifactId&gt;                 &lt;version&gt;3.0.0&lt;\/version&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-shade-plugin&lt;\/artifactId&gt;                 &lt;version&gt;2.3&lt;\/version&gt;                 &lt;executions&gt;                     &lt;execution&gt;                         &lt;phase&gt;package&lt;\/phase&gt;                         &lt;goals&gt;                             &lt;goal&gt;shade&lt;\/goal&gt;                         &lt;\/goals&gt;                         &lt;configuration&gt;                             &lt;transformers&gt;                                 &lt;transformer implementation=\"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer\"&gt;                                     &lt;manifestEntries&gt;                                         &lt;Main-Class&gt;io.vertx.core.Launcher&lt;\/Main-Class&gt;                                         &lt;Main-Verticle&gt;${main.verticle}&lt;\/Main-Verticle&gt;                                     &lt;\/manifestEntries&gt;                                 &lt;\/transformer&gt;                                 &lt;transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\"&gt;                                     &lt;resource&gt;META-INF\/services\/io.vertx.core.spi.VerticleFactory&lt;\/resource&gt;                                 &lt;\/transformer&gt;                             &lt;\/transformers&gt;                             &lt;artifactSet&gt;                             &lt;\/artifactSet&gt;                             &lt;outputFile&gt;${project.build.directory}\/${project.artifactId}-fat.jar&lt;\/outputFile&gt;                         &lt;\/configuration&gt;                     &lt;\/execution&gt;                 &lt;\/executions&gt;             &lt;\/plugin&gt;         &lt;\/plugins&gt;         &lt;resources&gt;             &lt;resource&gt;                 &lt;directory&gt;src\/main\/resources&lt;\/directory&gt;                 &lt;filtering&gt;true&lt;\/filtering&gt;                 &lt;includes&gt;                     &lt;include&gt;**\/version.txt&lt;\/include&gt;                 &lt;\/includes&gt;             &lt;\/resource&gt;             &lt;resource&gt;                 &lt;directory&gt;src\/main\/resources&lt;\/directory&gt;                 &lt;filtering&gt;false&lt;\/filtering&gt;                 &lt;excludes&gt;                     &lt;exclude&gt;**\/version.txt&lt;\/exclude&gt;                 &lt;\/excludes&gt;             &lt;\/resource&gt;         &lt;\/resources&gt;     &lt;\/build&gt;     &lt;distributionManagement&gt;         &lt;site&gt;             &lt;id&gt;reports&lt;\/id&gt;             &lt;url&gt;dav:https:\/\/nexus.dev.techedge.pro:8443\/repository\/reports\/${project.artifactId}\/&lt;\/url&gt;         &lt;\/site&gt;     &lt;\/distributionManagement&gt;     &lt;reporting&gt;         &lt;excludeDefaults&gt;true&lt;\/excludeDefaults&gt;         &lt;plugins&gt;             &lt;plugin&gt;                 &lt;groupId&gt;io.qameta.allure&lt;\/groupId&gt;                 &lt;artifactId&gt;allure-maven&lt;\/artifactId&gt;                 &lt;configuration&gt;                     &lt;resultsDirectory&gt;${project.build.directory}\/allure-results&lt;\/resultsDirectory&gt;                     &lt;reportDirectory&gt;${project.reporting.outputDirectory}\/${project.version}\/allure&lt;\/reportDirectory&gt;                 &lt;\/configuration&gt;             &lt;\/plugin&gt;         &lt;\/plugins&gt;     &lt;\/reporting&gt;      &lt;dependencies&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-web-api-service&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-web-client&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-codegen&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;             &lt;scope&gt;provided&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;ch.qos.logback&lt;\/groupId&gt;             &lt;artifactId&gt;logback-classic&lt;\/artifactId&gt;             &lt;version&gt;${logback.version}&lt;\/version&gt;         &lt;\/dependency&gt;          &lt;!-- test &amp;ndash;&amp;gt;--&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-unit&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.vertx&lt;\/groupId&gt;             &lt;artifactId&gt;vertx-junit5&lt;\/artifactId&gt;             &lt;version&gt;${vertx.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.junit.jupiter&lt;\/groupId&gt;             &lt;artifactId&gt;junit-jupiter-api&lt;\/artifactId&gt;             &lt;version&gt;${junit-jupiter.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.junit.jupiter&lt;\/groupId&gt;             &lt;artifactId&gt;junit-jupiter-engine&lt;\/artifactId&gt;             &lt;version&gt;${junit-jupiter.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.assertj&lt;\/groupId&gt;             &lt;artifactId&gt;assertj-core&lt;\/artifactId&gt;             &lt;version&gt;${assertj-core.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.mockito&lt;\/groupId&gt;             &lt;artifactId&gt;mockito-core&lt;\/artifactId&gt;             &lt;version&gt;${mockito.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;io.qameta.allure&lt;\/groupId&gt;             &lt;artifactId&gt;allure-junit5&lt;\/artifactId&gt;             &lt;version&gt;${allure.version}&lt;\/version&gt;             &lt;scope&gt;test&lt;\/scope&gt;         &lt;\/dependency&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.testcontainers&lt;\/groupId&gt;             &lt;artifactId&gt;junit-jupiter&lt;\/artifactId&gt;             &lt;version&gt;${testcontainers.version}&lt;\/version&gt;         &lt;\/dependency&gt;     &lt;\/dependencies&gt;  &lt;\/project&gt;<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">HelloWorldService.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.helloworld;  import io.vertx.core.AsyncResult; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.api.OperationRequest; import io.vertx.ext.web.api.OperationResponse; import io.vertx.ext.web.api.generator.WebApiServiceGen;  @WebApiServiceGen public interface HelloWorldService {      static HelloWorldService create(Vertx vertx, JsonObject config) {         return new DefaultHelloWorldService(vertx, config);     }      void getHelloWorld(OperationRequest context, Handler&lt;AsyncResult&lt;OperationResponse&gt;&gt; resultHandler);      void getDoc(OperationRequest context, Handler&lt;AsyncResult&lt;OperationResponse&gt;&gt; resultHandler);  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">DefaultHelloWorldService.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.helloworld;  import io.vertx.core.*; import io.vertx.core.buffer.Buffer; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.api.OperationRequest; import io.vertx.ext.web.api.OperationResponse; import io.vertx.ext.web.client.WebClient;  public class DefaultHelloWorldService implements HelloWorldService {      private final Vertx vertx;      private final JsonObject config;      private final WebClient webClient;      public DefaultHelloWorldService(Vertx vertx, JsonObject config) {         this.vertx = vertx;         this.config = config;         this.webClient = WebClient.create(this.vertx);     }      @Override     public void getHelloWorld(OperationRequest context, Handler&lt;AsyncResult&lt;OperationResponse&gt;&gt; resultHandler) {         getHelloWord().compose(this::getHelloWorld).setHandler(v -&gt;                 resultHandler.handle(                         Future.succeededFuture(OperationResponse.completedWithPlainText(Buffer.buffer(v.result())))                 ));     }      @Override     public void getDoc(OperationRequest context, Handler&lt;AsyncResult&lt;OperationResponse&gt;&gt; resultHandler) {         vertx.fileSystem().readFile(\"doc.yaml\", buffResult -&gt;                 resultHandler.handle(Future.succeededFuture(                         OperationResponse.completedWithPlainText(buffResult.result()))                 ));     }      private Future&lt;String&gt; getHelloWord() {         Future&lt;String&gt; future = Future.future();         webClient.get(config.getInteger(\"hello-service-port\"), config.getString(\"hello-service-host\"), \"\/\").send(ar -&gt;                 future.handle(Future.succeededFuture(ar.result().bodyAsString())));         return future;     }      private Future&lt;String&gt; getHelloWorld(String helloWord) {         Future&lt;String&gt; future = Future.future();         webClient.get(config.getInteger(\"world-service-port\"), config.getString(\"world-service-host\"), \"\/\").send(ar -&gt;                 future.handle(Future.succeededFuture(helloWord + \" \" + ar.result().bodyAsString())));         return future;     }  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">HelloWorldVerticle.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.helloworld;  import io.vertx.core.AbstractVerticle; import io.vertx.core.Promise; import io.vertx.core.eventbus.MessageConsumer; import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerOptions; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.Router; import io.vertx.ext.web.api.contract.openapi3.OpenAPI3RouterFactory; import io.vertx.serviceproxy.ServiceBinder;  public class HelloWorldVerticle extends AbstractVerticle {      HttpServer server;     MessageConsumer&lt;JsonObject&gt; consumer;      public void startWorldService() {         consumer = new ServiceBinder(vertx).setAddress(\"service.helloworld\")                 .register(HelloWorldService.class, HelloWorldService.create(vertx, config()));     }      \/**      * This method constructs the router factory, mounts services and handlers and starts the http server      * with built router      * @return      *\/     private Promise&lt;Void&gt; startHttpServer() {         Promise&lt;Void&gt; promise = Promise.promise();         OpenAPI3RouterFactory.create(this.vertx, \"\/doc.yaml\", openAPI3RouterFactoryAsyncResult -&gt; {             if (openAPI3RouterFactoryAsyncResult.succeeded()) {                 OpenAPI3RouterFactory routerFactory = openAPI3RouterFactoryAsyncResult.result();                  \/\/ Mount services on event bus based on extensions                 routerFactory.mountServicesFromExtensions();                  \/\/ Generate the router                 Router router = routerFactory.getRouter();                  int port = config().getInteger(\"serverPort\", 8080);                 String host = config().getString(\"serverHost\", \"localhost\");                  server = vertx.createHttpServer(new HttpServerOptions().setPort(port).setHost(host));                 server.requestHandler(router).listen(ar -&gt; {                     \/\/ Error starting the HttpServer                     if (ar.succeeded()) promise.complete();                     else promise.fail(ar.cause());                 });             } else {                 \/\/ Something went wrong during router factory initialization                 promise.fail(openAPI3RouterFactoryAsyncResult.cause());             }         });         return promise;     }      @Override     public void start(Promise&lt;Void&gt; promise) {         startWorldService();         startHttpServer().future().setHandler(promise);     }      \/**      * This method closes the http server and unregister all services loaded to Event Bus      *\/     @Override     public void stop(){         this.server.close();         consumer.unregister();     }  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">HelloWorldServiceTest.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package io.bihero.helloworld;  import io.vertx.core.DeploymentOptions; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.codec.BodyCodec; import io.vertx.junit5.Checkpoint; import io.vertx.junit5.VertxExtension; import io.vertx.junit5.VertxTestContext; import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers;  import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.spy;  @Testcontainers @ExtendWith(VertxExtension.class) public class HelloWorldServiceTest {      @Container     private static final GenericContainer helloServiceContainer = new GenericContainer(\"bihero\/hello\")             .withExposedPorts(8081);      @Container     private static final GenericContainer worldServiceContainer = new GenericContainer(\"bihero\/world\")             .withExposedPorts(8082);      @Test     @DisplayName(\"Test 'helloworld' microservice respond by 'Hello World' string and doc in OpenAPI format\")     public void testHelloWorld(Vertx vertx, VertxTestContext testContext) {         WebClient webClient = WebClient.create(vertx);          Checkpoint deploymentCheckpoint = testContext.checkpoint();         Checkpoint requestCheckpoint = testContext.checkpoint(2);          HelloWorldVerticle verticle = spy(new HelloWorldVerticle());         JsonObject config = new JsonObject().put(\"serverPort\", 8083)                                             .put(\"serverHost\", \"0.0.0.0\")                                             .put(\"hello-service-host\", helloServiceContainer.getContainerIpAddress())                                             .put(\"world-service-host\", worldServiceContainer.getContainerIpAddress())                                             .put(\"hello-service-port\", helloServiceContainer.getMappedPort(8081))                                             .put(\"world-service-port\", worldServiceContainer.getMappedPort(8082));         DeploymentOptions deploymentOptions = new DeploymentOptions().setConfig(config);         vertx.deployVerticle(verticle, deploymentOptions, testContext.succeeding(id -&gt; {             deploymentCheckpoint.flag();             \/\/ test GET \/             webClient.get(8083, \"localhost\", \"\/\")                     .as(BodyCodec.string())                     .send(testContext.succeeding(resp -&gt; {                         assertThat(resp.body()).isEqualTo(\"Hello World\");                         assertThat(resp.statusCode()).isEqualTo(200);                         requestCheckpoint.flag();                     }));             \/\/ test GET \/doc             webClient.get(8083, \"localhost\", \"\/doc\")                     .as(BodyCodec.string())                     .send(testContext.succeeding(resp -&gt; {                         try {                             assertThat(resp.body()).isEqualTo(IOUtils.toString(this.getClass()                                     .getResourceAsStream(\"..\/..\/..\/doc.yaml\"), \"UTF-8\"));                             assertThat(resp.statusCode()).isEqualTo(200);                             requestCheckpoint.flag();                         } catch (Exception e) {                             requestCheckpoint.flag();                             testContext.failNow(e);                         }                     }));         }));     }  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>Dockerfile \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043d\u0435\u043c\u043d\u043e\u0436\u0435\u0447\u043a\u043e \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0434\u0432\u0443\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0432\u044b\u0448\u0435 \u2014 \u043a\u043e\u043d\u0444\u0438\u0433 \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043c\u044b \u043a\u043b\u0430\u0434\u0451\u043c \u043d\u0435 \u0432 <strong>\/<\/strong> \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u043e, \u0430 \u0432 <strong>\/usr\/local<\/strong>, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0435\u0433\u043e ConfigMap&#8217;\u043e\u043c \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 k8s<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Dockerfile<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">FROM adoptopenjdk\/openjdk11:alpine-jre COPY target\/hello-world-microservice-fat.jar app.jar COPY src\/conf\/config.json \/usr\/local\/config.json COPY src\/conf\/logback-console.xml . COPY run.sh . RUN chmod +x run.sh CMD [\".\/run.sh\"]<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0418\u0442\u0430\u043a, \u043f\u043e\u0434\u043e\u0448\u043b\u0438 \u043a \u043f\u0430\u0439\u043f\u0430\u043b\u0439\u043d\u0443 \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u0442\u0443\u0442 \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u044f\u0441\u043d\u0438\u0442\u044c, \u043a\u0430\u043a \u0432\u043e\u043e\u0431\u0449\u0435 CI \u043a\u0440\u0443\u0442\u0438\u0442\u0441\u044f \u0438 \u043a\u0430\u043a \u0442\u0430\u043c \u0442\u0430\u0441\u043a\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f. Concourse \u0432 \u0442\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0438\u0441\u0430\u043b\u0430\u0441\u044c \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f, \u0438\u043c\u0435\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e worker-\u043d\u043e\u0434 \u0438 \u0432\u0441\u0451 \u043e\u043d\u0438 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u044b docker-compose&#8217;\u043e\u043c (\u0440\u044f\u0434\u043e\u043c \u0435\u0449\u0451 \u043a\u0440\u0443\u0442\u044f\u0442\u0441\u044f ui-\u043d\u043e\u0434\u0430 \u0438 postgresql). \u0422\u0430\u0441\u043a\u0438 \u0432 \u0434\u0436\u043e\u0431\u0430\u0445 \u2014 \u044d\u0442\u043e \u0442\u043e\u0436\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0441\u0442\u0430\u0440\u0442\u0443\u044e\u0449\u0438\u0435 docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b, \u0442\u043e \u0435\u0441\u0442\u044c \u043c\u044b \u0443\u0436\u0435 \u0438\u043c\u0435\u0435\u043c docker \u0432 docker&#8217;\u0435. \u0410 \u0435\u0449\u0451 \u043c\u044b \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0442\u0438\u043c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e testcontainers (\u0432 \u043d\u0430\u0448\u0435\u043c \u043a\u0435\u0439\u0441\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b <strong>hello<\/strong> \u0438 <strong>world<\/strong> \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u044d\u0442\u043e\u0433\u043e \u043a\u0440\u0443\u0442\u043e\u0433\u043e \u0442\u0443\u043b\u0430). \u0427\u0443\u0432\u0441\u0442\u0432\u0443\u0435\u0442\u0435 \u0447\u0435\u043c \u043f\u0430\u0445\u043d\u0435\u0442? \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043a\u043e: <strong>\u0434\u043e\u043a\u0435\u0440 \u0432 \u0434\u043e\u043a\u0435\u0440\u0435 \u0432 \u0434\u043e\u043a\u0435\u0440\u0435<\/strong>! \u0418 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043c\u043e\u0434\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u0441 docker&#8217;\u043e\u043c, maven&#8217;\u043e\u043c \u0438 11-\u043e\u0439 \u0434\u0436\u0430\u0432\u043e\u0439 \u043d\u0430 \u0431\u043e\u0440\u0442\u0443. \u0412\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u043c, Dockerfile:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">FROM alpine:3.7  ENV DOCKER_CHANNEL=stable \\     DOCKER_VERSION=17.12.1-ce \\     DOCKER_COMPOSE_VERSION=1.19.0 \\     DOCKER_SQUASH=0.2.0 # Install Docker, Docker Compose, Docker Squash RUN apk --update --no-cache add \\         bash \\         curl \\         device-mapper \\         py-pip \\         iptables \\         util-linux \\         ca-certificates \\         maven \\         openjdk11 --repository=http:\/\/dl-cdn.alpinelinux.org\/alpine\/edge\/community \\         &amp;&amp; \\     apk upgrade &amp;&amp; \\     curl -fL \"https:\/\/download.docker.com\/linux\/static\/${DOCKER_CHANNEL}\/x86_64\/docker-${DOCKER_VERSION}.tgz\" | tar zx &amp;&amp; \\     mv \/docker\/* \/bin\/ &amp;&amp; chmod +x \/bin\/docker* &amp;&amp; \\     pip install docker-compose==${DOCKER_COMPOSE_VERSION} &amp;&amp; \\     curl -fL \"https:\/\/github.com\/jwilder\/docker-squash\/releases\/download\/v${DOCKER_SQUASH}\/docker-squash-linux-amd64-v${DOCKER_SQUASH}.tar.gz\" | tar zx &amp;&amp; \\     mv \/docker-squash* \/bin\/ &amp;&amp; chmod +x \/bin\/docker-squash* &amp;&amp; \\     rm -rf \/var\/cache\/apk\/* &amp;&amp; \\     rm -rf \/root\/.cache  COPY repository \/root\/.m2\/repository # \u0442\u0443\u0442 \u043c\u044b \u043a\u043b\u0430\u0434\u0451\u043c \u0432 \u043e\u0431\u0440\u0430\u0437 \u0432\u0435\u043d\u0434\u043e\u0440-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0442\u044f\u043d\u0443\u0442\u044c \u0438 \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0431\u0438\u043b\u0434\u0435 \u0441 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0430 COPY settings.xml \/root\/.m2\/settings.xml # \u043a\u043e\u043d\u0444\u0438\u0433 \u0434\u043b\u044f maven'\u0430 \u0441 \u043a\u0440\u0435\u0434\u0430\u043c\u0438 \u043a \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u043c\u0443 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044e COPY entrypoint.sh \/bin\/entrypoint.sh # \u0432\u043e\u043b\u0448\u0435\u0431\u043d\u044b\u0439 \u0431\u0430\u0448-\u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0430\u0451\u0442 \u043d\u0430\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u043a\u0435\u0440 \u0432 \u0442\u0430\u0441\u043a\u0435 ENV JAVA_HOME=\/usr\/lib\/jvm\/java-11-openjdk\/ ENTRYPOINT [\"entrypoint.sh\"]<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 \u043d\u0430 \u0448\u0430\u0433 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u0445\u043e\u0434\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <em>entrypoint.sh<\/em>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442 \u043d\u0430\u043c \u0437\u0430\u043f\u0443\u0441\u043a \u0434\u043e\u043a\u0435\u0440\u0430 \u043f\u0435\u0440\u0435\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0441\u0430\u043c\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">entrypoint.sh<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">#!\/usr\/bin\/env bash  # Inspired by concourse\/docker-image-resource: # https:\/\/github.com\/concourse\/docker-image-resource\/blob\/master\/assets\/common.sh  set -o errexit -o pipefail -o nounset  # Waits DOCKERD_TIMEOUT seconds for startup (default: 60) DOCKERD_TIMEOUT=\"${DOCKERD_TIMEOUT:-60}\" # Accepts optional DOCKER_OPTS (default: --data-root \/scratch\/docker) DOCKER_OPTS=\"${DOCKER_OPTS:-}\"  # Constants DOCKERD_PID_FILE=\"\/tmp\/docker.pid\" DOCKERD_LOG_FILE=\"\/tmp\/docker.log\"  sanitize_cgroups() {   local cgroup=\"\/sys\/fs\/cgroup\"    mkdir -p \"${cgroup}\"   if ! mountpoint -q \"${cgroup}\"; then     if ! mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup \"${cgroup}\"; then       echo &gt;&amp;2 \"Could not make a tmpfs mount. Did you use --privileged?\"       exit 1     fi   fi   mount -o remount,rw \"${cgroup}\"    # Skip AppArmor   # See: https:\/\/github.com\/moby\/moby\/commit\/de191e86321f7d3136ff42ff75826b8107399497   export container=docker    # Mount \/sys\/kernel\/security   if [[ -d \/sys\/kernel\/security ]] &amp;&amp; ! mountpoint -q \/sys\/kernel\/security; then     if ! mount -t securityfs none \/sys\/kernel\/security; then       echo &gt;&amp;2 \"Could not mount \/sys\/kernel\/security.\"       echo &gt;&amp;2 \"AppArmor detection and --privileged mode might break.\"     fi   fi    sed -e 1d \/proc\/cgroups | while read sys hierarchy num enabled; do     if [[ \"${enabled}\" != \"1\" ]]; then       # subsystem disabled; skip       continue     fi      grouping=\"$(cat \/proc\/self\/cgroup | cut -d: -f2 | grep \"\\\\&lt;${sys}\\\\&gt;\")\"     if [[ -z \"${grouping}\" ]]; then       # subsystem not mounted anywhere; mount it on its own       grouping=\"${sys}\"     fi      mountpoint=\"${cgroup}\/${grouping}\"      mkdir -p \"${mountpoint}\"      # clear out existing mount to make sure new one is read-write     if mountpoint -q \"${mountpoint}\"; then       umount \"${mountpoint}\"     fi      mount -n -t cgroup -o \"${grouping}\" cgroup \"${mountpoint}\"      if [[ \"${grouping}\" != \"${sys}\" ]]; then       if [[ -L \"${cgroup}\/${sys}\" ]]; then         rm \"${cgroup}\/${sys}\"       fi        ln -s \"${mountpoint}\" \"${cgroup}\/${sys}\"     fi   done    # Initialize systemd cgroup if host isn't using systemd.   # Workaround for https:\/\/github.com\/docker\/for-linux\/issues\/219   if ! [[ -d \/sys\/fs\/cgroup\/systemd ]]; then     mkdir \"${cgroup}\/systemd\"     mount -t cgroup -o none,name=systemd cgroup \"${cgroup}\/systemd\"   fi }  # Setup container environment and start docker daemon in the background. start_docker() {   echo &gt;&amp;2 \"Setting up Docker environment...\"   mkdir -p \/var\/log   mkdir -p \/var\/run    sanitize_cgroups    # check for \/proc\/sys being mounted readonly, as systemd does   if grep '\/proc\/sys\\s\\+\\w\\+\\s\\+ro,' \/proc\/mounts &gt;\/dev\/null; then     mount -o remount,rw \/proc\/sys   fi    local docker_opts=\"${DOCKER_OPTS:-}\"    # Pass through `--garden-mtu` from gardian container   if [[ \"${docker_opts}\" != *'--mtu'* ]]; then     local mtu=\"$(cat \/sys\/class\/net\/$(ip route get 8.8.8.8|awk '{ print $5 }')\/mtu)\"     docker_opts+=\" --mtu ${mtu}\"   fi    # Use Concourse's scratch volume to bypass the graph filesystem by default   if [[ \"${docker_opts}\" != *'--data-root'* ]] &amp;&amp; [[ \"${docker_opts}\" != *'--graph'* ]]; then     docker_opts+=' --data-root \/scratch\/docker'   fi    rm -f \"${DOCKERD_PID_FILE}\"   touch \"${DOCKERD_LOG_FILE}\"    echo &gt;&amp;2 \"Starting Docker...\"   dockerd ${docker_opts} &amp;&gt;\"${DOCKERD_LOG_FILE}\" &amp;   echo \"$!\" &gt; \"${DOCKERD_PID_FILE}\" }  # Wait for docker daemon to be healthy # Timeout after DOCKERD_TIMEOUT seconds await_docker() {   local timeout=\"${DOCKERD_TIMEOUT}\"   echo &gt;&amp;2 \"Waiting ${timeout} seconds for Docker to be available...\"   local start=${SECONDS}   timeout=$(( timeout + start ))   until docker info &amp;&gt;\/dev\/null; do     if (( SECONDS &gt;= timeout )); then       echo &gt;&amp;2 'Timed out trying to connect to docker daemon.'       if [[ -f \"${DOCKERD_LOG_FILE}\" ]]; then         echo &gt;&amp;2 '---DOCKERD LOGS---'         cat &gt;&amp;2 \"${DOCKERD_LOG_FILE}\"       fi       exit 1     fi     if [[ -f \"${DOCKERD_PID_FILE}\" ]] &amp;&amp; ! kill -0 $(cat \"${DOCKERD_PID_FILE}\"); then       echo &gt;&amp;2 'Docker daemon failed to start.'       if [[ -f \"${DOCKERD_LOG_FILE}\" ]]; then         echo &gt;&amp;2 '---DOCKERD LOGS---'         cat &gt;&amp;2 \"${DOCKERD_LOG_FILE}\"       fi       exit 1     fi     sleep 1   done   local duration=$(( SECONDS - start ))   echo &gt;&amp;2 \"Docker available after ${duration} seconds.\" }  # Gracefully stop Docker daemon. stop_docker() {   if ! [[ -f \"${DOCKERD_PID_FILE}\" ]]; then     return 0   fi   local docker_pid=\"$(cat ${DOCKERD_PID_FILE})\"   if [[ -z \"${docker_pid}\" ]]; then     return 0   fi   echo &gt;&amp;2 \"Terminating Docker daemon.\"   kill -TERM ${docker_pid}   local start=${SECONDS}   echo &gt;&amp;2 \"Waiting for Docker daemon to exit...\"   wait ${docker_pid}   local duration=$(( SECONDS - start ))   echo &gt;&amp;2 \"Docker exited after ${duration} seconds.\" }  start_docker trap stop_docker EXIT await_docker  # do not exec, because exec disables traps if [[ \"$#\" != \"0\" ]]; then   \"$@\" else   bash --login fi<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pipeline.yaml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">resource_types:   - name: telegram     type: docker-image     source:       repository: vtutrinov\/concourse-telegram-resource       tag: latest   - name: kubernetes     type: docker-image     source:       repository: zlabjp\/kubernetes-resource       tag: 1.16   - name: metadata     type: docker-image     source:       repository: olhtbr\/metadata-resource       tag: 2.0.1 resources:   - name: metadata     type: metadata   - name: sources     type: git     source:       branch: master       uri: git@github.com:bihero-io\/helloworldmicroservice.git       private_key: ((deployer-private-key))   - name: docker-image     type: docker-image     source:       repository: bihero\/helloworld       username: ((docker-registry-user))       password: ((docker-registry-password))   - name: telegram     type: telegram     source:       bot_token: ((telegram-ci-bot-token))       chat_id: ((telegram-group-to-report-build))       ci_url: ((ci_url))       command: \"\/build_helloworld_ms\"   - name: kubernetes-demo     type: kubernetes     source:       server: ((k8s-api-server))       namespace: default       kubeconfig: ((kubeconfig-demo)) jobs:   - name: build-helloworld-microservice     serial: true     public: true     plan:       - in_parallel:           - get: sources             trigger: true           - get: telegram             trigger: true           - put: metadata       - put: telegram         params:           status: Build In Progress       - task: tests         privileged: true         config:           platform: linux           image_resource:             type: docker-image             source:               repository: ((docker-registry-uri))\/bih\/dind  # \u0442\u0443\u0442 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0437, \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0434\u043e\u043a\u0435\u0440\u0444\u0430\u0439\u043b\u0430, \u0433\u0434\u0435 \u043c\u044b \u0441\u0442\u0430\u0432\u0438\u043c \u0434\u043e\u043a\u0435\u0440, maven \u0438 11-\u044e \u0434\u0436\u0430\u0432\u0443               tag: latest               username: ((docker-private-registry-user))               password: ((docker-private-registry-password))           inputs:             - name: sources           outputs:             - name: tested-workspace           run:             path: entrypoint.sh             args:               - bash               - -ceux               - |                 # \u0432\u043e\u0442 \u0442\u0443\u0442 \u043c\u044b \u0443\u0436\u0435 \u0438\u043c\u0435\u0435\u043c \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0439 \u0434\u043e\u043a\u0435\u0440 \u0432\u043d\u0443\u0442\u0440\u0438 \u0442\u0430\u0441\u043a\u0438 \u0438 \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0441 testcontainers                 output_dir=tested-workspace                 cp -R .\/sources\/* \"${output_dir}\/\"                 mvn -f \"${output_dir}\/pom.xml\" clean test           caches:             - path: ~\/.m2\/         on_failure:           do:             - task: tests-report               config:                 platform: linux                 image_resource:                   type: docker-image                   source:                     repository: ((docker-registry-uri))\/bih\/maven-dind                     tag: 3-jdk-11                     username: ((docker-private-registry-user))                     password: ((docker-private-registry-password))                 inputs:                   - name: tested-workspace                 outputs:                   - name: message                 run:                   path: \/bin\/sh                   args:                     - -c                     - |                       output_dir=tested-workspace                       mvn -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -f \"${output_dir}\/pom.xml\" site-deploy                       version=$(cat $output_dir\/target\/classes\/version.txt)                       cat &gt;message\/msg &lt;&lt;EOL                       &lt;a href=\"https:\/\/nexus.dev.techedge.pro:8443\/repository\/reports\/hello-world-microservice\/${version}\/allure\/\"&gt;Allure report&lt;\/a&gt;                       EOL                 caches:                   - path: ~\/.m2\/             - put: telegram               params:                 status: Build Failed (unit-tests)                 message_file: message\/msg       - task: tests-report         config:           platform: linux           image_resource:             type: docker-image             source:               repository: ((docker-registry-uri))\/bih\/maven-dind               tag: 3-jdk-11               username: ((docker-private-registry-user))               password: ((docker-private-registry-password))           inputs:             - name: tested-workspace           outputs:             - name: message             - name: tested-workspace           run:             path: \/bin\/sh             args:               - -c               - |                 work_dir=tested-workspace                 mvn -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -f \"${work_dir}\/pom.xml\" site-deploy                 version=$(cat $work_dir\/target\/classes\/version.txt)                 cat &gt;message\/msg &lt;&lt;EOL                 &lt;a href=\"https:\/\/nexus.dev.techedge.pro:8443\/repository\/reports\/hello-world-microservice\/${version}\/allure\/\"&gt;Allure report&lt;\/a&gt;                 EOL           caches:             - path: ~\/.m2\/       - task: package         config:           platform: linux           image_resource:             type: docker-image             source:               repository: ((docker-registry-uri))\/bih\/maven-dind               tag: 3-jdk-11               username: ((docker-private-registry-user))               password: ((docker-private-registry-password))           inputs:             - name: tested-workspace             - name: metadata           outputs:             - name: app-packaged-workspace             - name: metadata           run:             path: \/bin\/sh             args:               - -c               - |                 output_dir=app-packaged-workspace                 cp -R .\/tested-workspace\/* \"${output_dir}\/\"                 mvn -f \"${output_dir}\/pom.xml\" package -Dmaven.main.skip -DskipTests                 tag=\"-\"$(cat metadata\/build_name)                 echo $tag &gt;&gt; ${output_dir}\/target\/classes\/version.txt                 cat ${output_dir}\/target\/classes\/version.txt &gt; metadata\/version           caches:             - path: ~\/.m2\/         on_failure:           do:             - put: telegram               params:                 status: Build Failed (package)       - put: docker-image         params:           build: app-packaged-workspace           tag_file: app-packaged-workspace\/target\/classes\/version.txt           tag_as_latest: true         get_params:           skip_download: true       - task: make-k8s-app-template         config:           platform: linux           image_resource:             type: docker-image             source:               repository: bhgedigital\/envsubst           inputs:             - name: sources             - name: metadata           outputs:             - name: k8s           run:             path: \/bin\/sh             args:               - -c               - |                 export DOMAIN=demo1.bihero.io                 export HELLO_WORLD_SERVICE_IMAGE_VERSION=$(cat metadata\/version)                 cat sources\/k8s.yaml | envsubst &gt; k8s\/helloworld_app_template.yaml                 cat k8s\/helloworld_app_template.yaml       - put: kubernetes-demo         params:           kubectl: apply -f k8s\/helloworld_app_template.yaml       - put: telegram         params:           status: Build Success           message_file: message\/msg<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u041f\u043e\u0434\u043e\u0448\u043b\u0438 \u043a \u0434\u0435\u043f\u043b\u043e\u044e \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 k8s. \u0418 \u0442\u0443\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0437\u043d\u0430\u0442\u044c \u0430\u0434\u0440\u0435\u0441\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 <strong>hello<\/strong> \u0438 <strong>world<\/strong> \u0432\u043d\u0443\u0442\u0440\u0438 k8s-\u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430. \u041f\u043e \u0434\u0435\u0444\u043e\u043b\u0442\u0443 \u0432\u0441\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0432\u043d\u0443\u0442\u0440\u0438 k8s \u0438\u043c\u0435\u0442 \u0430\u0434\u0440\u0435\u0441\u0430 \u0442\u0438\u043f\u0430 <strong>&lt;service-name&gt;..default.svc.cluster.local<\/strong>, \u0432\u043e\u0442 \u0438\u043c\u0438 \u0438 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f, \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0436\u0435 \u043c\u044b \u0445\u043e\u0434\u0438\u0442\u044c \u0434\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043a\u0440\u0443\u0442\u044f\u0442\u0441\u044f \u0440\u044f\u0434\u043e\u043c \u0447\u0435\u0440\u0435\u0437 \u0432\u043d\u0435\u0448\u043d\u0438\u0439 API. \u0421\u043a\u0430\u0437\u0430\u043d\u043e, \u0441\u0434\u0435\u043b\u0430\u043d\u043e :<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u043a\u043e\u043d\u0435\u0447\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0442\u0435\u043c\u043f\u043b\u0435\u0439\u0442\u0430 \u0434\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 k8s<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">apiVersion: v1 kind: ConfigMap metadata:   name: hello-world-config data:   config.json: |     {       \"type\": \"file\",       \"format\": \"json\",       \"scanPeriod\": 5000,       \"config\": {         \"path\": \"\/config.json\"       },       \"serverPort\": 8083,       \"serverHost\": \"0.0.0.0\",       \"hello-service-host\": \"bihero-hello.default.svc.cluster.local\",       \"hello-service-port\": 8081,       \"world-service-host\": \"bihero-world.default.svc.cluster.local\",       \"world-service-port\": 8082     } --- apiVersion: extensions\/v1beta1 kind: Deployment metadata:   labels:     io.bihero.hello.service: bihero-helloworld   name: bihero-helloworld spec:   replicas: 3   strategy:     type: RollingUpdate     rollingUpdate:       maxSurge: 1       maxUnavailable: 1   template:     metadata:       labels:         io.bihero.hello.service: bihero-helloworld     spec:       containers:         - image: bihero\/helloworld:${HELLO_WORLD_SERVICE_IMAGE_VERSION}           name: bihero-helloworld           ports:             - containerPort: 8083           imagePullPolicy: Always           resources: {}           volumeMounts: # \u0432 \/usr\/local \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0439 \u043a\u043e\u043d\u0444\u0438\u0433 \u043d\u0430 \u0437\u0430\u043d\u0447\u0435\u043d\u0438\u0435 \u0438\u0437 ConfigMap'\u0430 \u0441\u0432\u0435\u0440\u0445\u0443             - mountPath: \/usr\/local\/               name: hello-world-config       restartPolicy: Always       volumes:         - name: hello-world-config           configMap:             name: hello-world-config --- apiVersion: v1 kind: Service metadata:   labels:     io.bihero.hello.service: bihero-helloworld   name: bihero-helloworld spec:   ports:     - name: \"8083\"       port: 8083       targetPort: 8083   selector:     io.bihero.hello.service: bihero-helloworld status:   loadBalancer: {} --- apiVersion: extensions\/v1beta1 kind: Ingress metadata:   name: bihero-helloworld   annotations:     kubernetes.io\/ingress.class: nginx     nginx.ingress.kubernetes.io\/ssl-redirect: \"true\"     nginx.ingress.kubernetes.io\/secure-backends: \"false\"     nginx.ingress.kubernetes.io\/ssl-passthrough: \"false\"     nginx.ingress.kubernetes.io\/rewrite-target: \/$2     kubernetes.io\/tls-acme: \"true\"   namespace: default spec:   tls:     - hosts:         - ${DOMAIN}       secretName: bihero   rules:     - host: ${DOMAIN}       http:         paths:           - path: \/api\/helloworld(\/|$)(.*)             backend:               serviceName: bihero-helloworld               servicePort: 8083<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u041d\u0443, \u0438 \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u043e \u2014 \u043a\u043e\u043c\u043c\u0438\u0442\u0438\u043c\u0441\u044f, \u043f\u0443\u0448\u0438\u043c\u0441\u044f, \u0431\u0438\u043b\u0434\u0438\u043c\u0441\u044f, \u0434\u0435\u043f\u043b\u043e\u0438\u043c\u0441\u044f, \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u0441\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">curl https:\/\/demo1.bihero.io\/api\/helloworld Hello World<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"bash\">curl https:\/\/demo1.bihero.io\/api\/helloworld\/doc                  openapi: 3.0.1 info:   title: Hello World ;)   description: \"Hello World microservice. Aggregate 'Hello World' by hellomicroservice and worldmicroservice\"   version: 1.0.0 servers:   - url: https:\/\/demo1.bihero.io\/api\/helloworld tags:   - name: helloworld     description: Everything about 'Hello World' paths:   \/:     x-vertx-event-bus:       address: service.helloworld       timeout: 1000     get:       tags:         - helloworld       summary: Aggregate 'Hello World'       operationId: getHelloWorld       responses:         200:           description: OK           content: {}   \/doc:     x-vertx-event-bus:       address: service.helloworld       timeout: 1000c     get:       tags:         - world       summary: Get 'Hello World' microservice documentation       operationId: getDoc       responses:         200:           description: OK components: {}<\/code><\/pre>\n<p>  <\/p>\n<p>\u0423\u0440\u0430! \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442! \u041c\u043e\u0436\u0435\u043c \u0440\u0435\u043b\u0438\u0437\u0438\u0442\u044c\u0441\u044f \u0438 \u0432 \u043f\u0440\u043e\u0434, \u043d\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0442\u044b \u043a\u0430\u0440\u0442\u0438\u043d\u044b\u2026 <\/p>\n<p>  <\/p>\n<h2 id=\"todoshechki-backlog\">TODO&#8217;\u0448\u0435\u0447\u043a\u0438 (backlog)<\/h2>\n<p>  <\/p>\n<ol>\n<li>\u041c\u043d\u043e\u0433\u043e \u0431\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442\u0430 \u0432 \u043f\u043e\u043c\u043d\u0438\u043a\u0430\u0445 \u2014 \u0443\u043d\u0435\u0441\u0442\u0438 \u0432\u0441\u0451 \u043e\u0431\u0449\u0435\u0435 \u0432 parent pom \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043d\u0435\u0433\u043e.<\/li>\n<li>\u0421\u0435\u0439\u0447\u0430\u0441 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430\u0445 docker-\u043e\u0431\u0440\u0430\u0437\u044b \u0442\u0435\u0433\u0430\u044e\u0442\u0441\u044f \u0438 \u0441\u0440\u0430\u0437\u0443 \u043f\u0443\u0448\u0430\u0442\u0441\u044f \u0432 docker-hub, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0441\u043d\u044d\u043f\u0448\u043e\u0442\u043d\u044b\u0435 \u043e\u0431\u0440\u0430\u0437\u044b \u2014 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0442\u0443\u0434\u0430 \u043f\u0443\u0448\u0438\u043b\u0438\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u043b\u0438\u0437\u043d\u044b\u0435 \u043e\u0431\u0440\u0430\u0437\u044b, \u0432\u0441\u0451 \u0441\u043d\u044d\u043f\u0448\u043e\u0442\u043d\u043e\u0435 \u0432 private registry.<\/li>\n<li>\u0421\u0434\u0435\u043b\u0430\u0442\u044c &#171;\u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0435&#187; \u0432\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 (maven-release-plugin? concourse semver-resource ?), \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0435\u0440\u0441\u0438\u0438 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438, \u0438 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0438\u0442\u044c \u0440\u0435\u043b\u0438\u0437\u043d\u044b\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0435\u043c \u0437\u0430 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432\u0435\u0440\u0441\u0438\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430.<\/li>\n<li>\u0420\u0435\u0448\u0438\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0440\u0430\u0441\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 API \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438 \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 \u041d\u0415-\u043c\u043e\u043d\u043e\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0432 \u0433\u0438\u0442\u0435 (\u043a\u043e\u0433\u0434\u0430 \u044d\u0442\u043e \u0442\u0440\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0442\u0438\u043f\u0430 HelloWorld, \u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043d\u0435\u0442, \u043d\u043e \u043a\u043e\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u0435\u0441\u044f\u0442\u043a\u043e\u0432 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0442\u043e \u043d\u0430\u0441\u0442\u0443\u043f\u0438\u0442 \u0410\u0414). \u0415\u0441\u043b\u0438 \u043a\u0442\u043e-\u0442\u043e \u0437\u0430\u043d\u0435\u0442 \u0436\u0435\u043b\u0435\u0437\u043e\u0431\u0435\u0442\u043e\u043d\u043d\u044b\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u044b, \u0442\u043e \u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u2014 \u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u0443\u0437\u043d\u0430\u0442\u044c \u0438 \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \ud83d\ude42<\/li>\n<\/ol>\n<p>  <\/p>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a \u0432 \u0433\u043e\u043b\u043e\u0432\u0435 \u0431\u044b\u043b \u0431\u043e\u043b\u044c\u0448\u043e\u0439, \u043d\u043e \u0437\u0430\u0431\u044b\u043b\u0441\u044f \u043f\u043e \u043f\u0443\u0442\u0438, \u0435\u0441\u043b\u0438 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u0441\u044f, \u0442\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u044e, \u043d\u0443 \u0438\u043b\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u044f\u0439\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \ud83d\ude42<\/p>\n<p>  <\/p>\n<h3 id=\"i-ishodniki\">\u0418 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438<\/h3>\n<p>  <\/p>\n<p><a href=\"https:\/\/github.com\/bihero-io\/hello-microservice\" rel=\"nofollow\">https:\/\/github.com\/bihero-io\/hello-microservice<\/a><br \/>  <a href=\"https:\/\/github.com\/bihero-io\/worldmicroservice\" rel=\"nofollow\">https:\/\/github.com\/bihero-io\/worldmicroservice<\/a><br \/>  <a href=\"https:\/\/github.com\/bihero-io\/helloworldmicroservice\" rel=\"nofollow\">https:\/\/github.com\/bihero-io\/helloworldmicroservice<\/a><\/p>\n<p>  <\/p>\n<p><strong>[UPD] \u0432 TODO&#8217;\u0448\u0435\u0447\u043a\u0438<\/strong><\/p>\n<p>  <\/p>\n<ol>\n<li>\u0417\u0430\u043f\u0438\u043b\u0438\u0442\u044c \u0441\u0442\u0435\u043f \u0432 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0435 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 helm-\u0447\u0430\u0440\u0442\u0430, \u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c \u0432 k8s \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0447\u0430\u0440\u0442\u0430, \u0434\u0430\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u043c on-prem \u044e\u0437\u0435\u0440\u0430\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u0441 \u0442\u0435\u043c\u043f\u043b\u0435\u0439\u0442\u0430\u043c\u0438, \u0442\u0430\u043a \u0438 \u0438\u0437 \u0447\u0430\u0440\u0442\u0430<\/li>\n<\/ol>\n<\/div>\n<p>               <script class=\"js-mediator-script\">!function(e){function t(t,n){if(!(n in e)){for(var r,a=e.document,i=a.scripts,o=i.length;o--;)if(-1!==i[o].src.indexOf(t)){r=i[o];break}if(!r){r=a.createElement(\"script\"),r.type=\"text\/javascript\",r.async=!0,r.defer=!0,r.src=t,r.charset=\"UTF-8\";var d=function(){var e=a.getElementsByTagName(\"script\")[0];e.parentNode.insertBefore(r,e)};\"[object Opera]\"==e.opera?a.addEventListener?a.addEventListener(\"DOMContentLoaded\",d,!1):e.attachEvent(\"onload\",d):d() } } }t(\"\/\/mediator.mail.ru\/script\/2820404\/\",\"_mediator\")}(window);<\/script>      <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\/post\/465149\/\"> https:\/\/habr.com\/ru\/post\/465149\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html js-mediator-article\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/465149\/\">\n<p>\u041c\u0438\u0440 \u0441\u0445\u043e\u0434\u0438\u0442 \u0441 \u0443\u043c\u0430, \u0437\u0430\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u044f \u043a\u0430\u043b\u044c\u043a\u0443\u043b\u044f\u0442\u043e\u0440 \u0434\u043b\u044f 2+2 \u0432 \u043e\u0431\u043b\u0430\u043a\u0430. \u0427\u0435\u043c \u043c\u044b \u0445\u0443\u0436\u0435? \u0414\u0430\u0432\u0430\u0439\u0442\u0435 Hello World \u0437\u0430\u0442\u043e\u043b\u043a\u0430\u0435\u043c \u0432 \u0442\u0440\u0438 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0430\u0440\u0443-\u0442\u0440\u043e\u0439\u043a\u0443 \u0442\u0435\u0441\u0442\u043e\u0432, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439, \u043d\u0430\u0440\u0438\u0441\u0443\u0435\u043c \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0439 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u043c \u0434\u0435\u043f\u043b\u043e\u0439 \u0432 \u0443\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0439 \u043f\u0440\u043e\u0434 \u043f\u0440\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432. \u0418\u0442\u0430\u043a, \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430 \u043e\u0442 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0434\u043e \u0434\u0435\u043f\u043b\u043e\u044f \u0432 \u043f\u0440\u043e\u0434. \u0418\u043d\u0435\u0442\u0435\u0440\u0435\u0441\u043d\u043e? \u0442\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442<\/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-295592","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/295592","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=295592"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/295592\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=295592"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=295592"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=295592"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}