{"id":475574,"date":"2026-04-12T06:15:41","date_gmt":"2026-04-12T06:15:41","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=475574"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=475574","title":{"rendered":"GitLab CI + MAX Messenger: \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e \u0434\u0435\u043f\u043b\u043e\u0435 \u043d\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u043b\u0438\u0441\u044c, \u0438 \u044d\u0442\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u043d\u0435 JSON"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041c\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0432\u0435\u0449\u044c: \u043f\u043e\u0441\u043b\u0435 \u0434\u0435\u043f\u043b\u043e\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0432 \u0447\u0430\u0442 <strong>MAX<\/strong> \u0438\u0437 <strong>GitLab CI<\/strong>.<\/p>\n<p>\u041d\u0430 \u0431\u0443\u043c\u0430\u0433\u0435 \u0437\u0430\u0434\u0430\u0447\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0430 \u043f\u043e\u0447\u0442\u0438 \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e:<\/p>\n<ul>\n<li>\n<p>\u0435\u0441\u0442\u044c <code>MAX_BOT_TOKEN<\/code><\/p>\n<\/li>\n<li>\n<p>\u0435\u0441\u0442\u044c <code>MAX_NOTIFY_CHAT_ID<\/code><\/p>\n<\/li>\n<li>\n<p>\u0435\u0441\u0442\u044c <code>curl<\/code><\/p>\n<\/li>\n<li>\n<p>\u0435\u0441\u0442\u044c <code>POST https:\/\/platform-api.max.ru\/messages?chat_id=...<\/code><\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043d\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u043d\u0435\u0439. \u041c\u044b \u043c\u0435\u043d\u044f\u043b\u0438 \u043e\u0431\u0440\u0430\u0437\u044b, \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043b\u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u044b, \u0443\u043f\u0440\u043e\u0449\u0430\u043b\u0438 payload, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b\u0438 \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0443. \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0431\u044b\u043b \u043e\u0434\u0438\u043d: \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0435 \u0434\u043e\u0445\u043e\u0434\u0438\u043b\u043e.<\/p>\n<p>\u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u0442\u0430\u043c, \u0433\u0434\u0435 \u043c\u044b \u0435\u0451 \u0438\u0441\u043a\u0430\u043b\u0438.<\/p>\n<hr\/>\n<h3>\u0421\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b<\/h3>\n<ul>\n<li>\n<p><code>annotation.md<\/code> \u2014 \u043a\u043e\u0440\u043e\u0442\u043a\u0430\u044f \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f \u0438 \u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u043a\u0438 \u0434\u043b\u044f \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u0441\u0442\u0430\u0442\u044c\u0438<\/p>\n<\/li>\n<li>\n<p><code>intro.md<\/code> \u2014 \u0431\u043e\u043b\u0435\u0435 \u043e\u0442\u043f\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0432\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p><code>code-snippets.md<\/code> \u2014 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u043a\u043e\u0434\u0430 \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0432 \u0441\u0442\u0430\u0442\u044c\u044e<\/p>\n<\/li>\n<\/ul>\n<hr\/>\n<h3>\u041f\u0435\u0440\u0432\u044b\u0435 \u0441\u0438\u043c\u043f\u0442\u043e\u043c\u044b<\/h3>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u043b\u043e\u0433 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b \u0442\u0430\u043a:<\/p>\n<pre><code>DEBUG: Response: {\"code\":\"proto.payload\",\"message\":\"Can't deserialize body\"}ERROR: \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c. Response: {\"code\":\"proto.payload\",\"message\":\"Can't deserialize body\"}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u0434\u0430\u0432\u0430\u043b\u043e \u043b\u043e\u0436\u043d\u043e\u0435 \u043e\u0449\u0443\u0449\u0435\u043d\u0438\u0435, \u0447\u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 JSON. \u0412\u0435\u0434\u044c MAX API \u044f\u0432\u043d\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u2014 \u0437\u043d\u0430\u0447\u0438\u0442, \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043e\u0445\u043e\u0434\u0438\u0442. \u0417\u043d\u0430\u0447\u0438\u0442, \u0441\u0435\u0442\u044c \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435. \u0417\u043d\u0430\u0447\u0438\u0442, \u043d\u0430\u0434\u043e \u0447\u0438\u043d\u0438\u0442\u044c payload.<\/p>\n<p>\u041c\u044b \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 \u044d\u0442\u043e.<\/p>\n<hr\/>\n<h3>\u0427\u0442\u043e \u043c\u044b \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b\u0438 (\u0438 \u0447\u0442\u043e \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e)<\/h3>\n<h4>\u041f\u043e\u043f\u044b\u0442\u043a\u0430 1: printf + \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b<\/h4>\n<pre><code class=\"bash\">printf '{\"text\":\"%s\"}' \"$MSG\" &gt; \/tmp\/payload.jsoncurl ... -d @\/tmp\/payload.json<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0442\u0432\u0435\u0442: <code>Can't deserialize body<\/code><\/p>\n<h4>\u041f\u043e\u043f\u044b\u0442\u043a\u0430 2: jq + \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b<\/h4>\n<p>\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u043b\u0438\u0441\u044c \u043d\u0430 <code>alpine:3.20<\/code>, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 <code>jq<\/code>:<\/p>\n<pre><code class=\"bash\">jq -nc --arg t \"$MSG\" '{text:$t}' &gt; \/tmp\/payload.jsoncurl ... -d @\/tmp\/payload.json<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0442\u0432\u0435\u0442: \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e <code>Can't deserialize body<\/code><\/p>\n<h4>\u041f\u043e\u043f\u044b\u0442\u043a\u0430 3: \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0432\u043c\u0435\u0441\u0442\u043e \u0444\u0430\u0439\u043b\u0430<\/h4>\n<pre><code class=\"bash\">PAYLOAD=$(jq -nc --arg t \"$MSG\" '{text:$t}')curl ... --data \"${PAYLOAD}\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0442\u0432\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f: <code>Empty request body<\/code><\/p>\n<p>\u042d\u0442\u043e \u0431\u044b\u043b \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441 \u2014 \u0442\u0435\u043f\u0435\u0440\u044c \u0442\u0435\u043b\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0434\u043e\u0445\u043e\u0434\u0438\u043b\u043e. \u041d\u043e <code>apk add<\/code> \u043d\u0430\u0447\u0430\u043b \u043f\u0430\u0434\u0430\u0442\u044c \u0441 exit code 2: \u0440\u0430\u043d\u043d\u0435\u0440 \u043d\u0435 \u043c\u043e\u0433 \u0442\u044f\u043d\u0443\u0442\u044c \u043f\u0430\u043a\u0435\u0442\u044b \u0438\u0437 Alpine \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432.<\/p>\n<h4>\u041f\u043e\u043f\u044b\u0442\u043a\u0430 4: \u0441\u0442\u0430\u0442\u0438\u0447\u043d\u044b\u0439 \u0445\u0430\u0440\u0434\u043a\u043e\u0434<\/h4>\n<p>\u0423\u0431\u0440\u0430\u043b\u0438 \u0432\u0441\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435. \u041f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u0442\u0430\u0442\u0438\u0447\u043d\u044b\u0439 JSON \u0432 \u043e\u0434\u0438\u043d\u0430\u0440\u043d\u044b\u0445 \u043a\u0430\u0432\u044b\u0447\u043a\u0430\u0445:<\/p>\n<pre><code class=\"bash\">curl ... -d '{\"text\":\"test ok\"}'<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0442\u0432\u0435\u0442: <code>Empty request body<\/code><\/p>\n<hr\/>\n<h3>\u041a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442<\/h3>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0441\u0442\u0430\u043b\u043e \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e: \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043d\u0435 \u0432 JSON. \u0424\u043e\u0440\u043c\u0430\u0442 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u044b\u0439, \u043f\u0440\u043e\u0449\u0435 \u043d\u0435\u043a\u0443\u0434\u0430. \u041d\u043e \u0442\u0435\u043b\u043e \u043d\u0435 \u0434\u043e\u0445\u043e\u0434\u0438\u0442.<\/p>\n<p>\u0422\u043e\u0433\u0434\u0430 \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043b\u0438 \u0434\u0432\u0430 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f \u0441 \u043e\u0434\u043d\u043e\u0433\u043e \u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430:<\/p>\n<p><strong>\u0421 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e:<\/strong><\/p>\n<pre><code class=\"bash\">ssh -p 666 kurganskii.a@tverdasoft.ru \\  \"curl -s -X POST 'https:\/\/platform-api.max.ru\/messages?chat_id=...' \\   -H 'Authorization: ...' \\   -H 'Content-Type: application\/json' \\   -d '{\\\"text\\\":\\\"test from server\\\"}'\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442: \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0448\u043b\u043e, <code>HTTP 200<\/code>, <code>message_id<\/code> \u0432 \u043e\u0442\u0432\u0435\u0442\u0435.<\/p>\n<p><strong>\u0418\u0437 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043d\u0430 \u0442\u043e\u043c \u0436\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0435:<\/strong><\/p>\n<pre><code class=\"bash\">ssh -p 666 kurganskii.a@tverdasoft.ru  \\  \"docker run --rm curlimages\/curl:8.7.1 curl -s \\   -X POST 'https:\/\/platform-api.max.ru\/messages?chat_id=...' \\   -H 'Authorization: ...' \\   -d '{\\\"text\\\":\\\"test from docker\\\"}'\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442: <strong>exit code 6<\/strong> \u2014 <code>curl: (6) Could not resolve host: platform-api.max.ru<\/code><\/p>\n<p>\u0412\u043e\u0442 \u043e\u043d\u0430, \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u043f\u0440\u0438\u0447\u0438\u043d\u0430.<\/p>\n<hr\/>\n<h3>\u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430: Docker DNS<\/h3>\n<p>Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u043d\u0430 \u044d\u0442\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043d\u0435 \u043c\u043e\u0433\u043b\u0438 \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u0442\u044c \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0445\u043e\u0441\u0442\u044b. \u0425\u043e\u0441\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e, \u0430 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u2014 \u043d\u0435\u0442.<\/p>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441 \u044f\u0432\u043d\u044b\u043c DNS \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043b\u0430 \u0434\u0438\u0430\u0433\u043d\u043e\u0437:<\/p>\n<pre><code class=\"bash\">docker run --rm --dns 8.8.8.8 curlimages\/curl:8.7.1 curl -s \\  -X POST 'https:\/\/platform-api.max.ru\/messages?chat_id=...' \\  -H 'Authorization: ...' \\  -d '{\"text\":\"test from docker dns8\"}'<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442: \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0448\u043b\u043e \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e.<\/p>\n<hr\/>\n<h3>\u041f\u043e\u0447\u0435\u043c\u0443 \u043c\u044b \u0442\u0430\u043a \u0434\u043e\u043b\u0433\u043e \u043d\u0435 \u0432\u0438\u0434\u0435\u043b\u0438 DNS<\/h3>\n<p>\u042d\u0442\u043e \u0432\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u041c\u044b \u0432\u0438\u0434\u0435\u043b\u0438 <code>Can't deserialize body<\/code>, \u0430 \u043d\u0435 <code>Could not resolve host<\/code>.<\/p>\n<p>\u041e\u0448\u0438\u0431\u043a\u0430 DNS \u0432\u0435\u0440\u043d\u0443\u043b\u0430 \u0431\u044b <code>curl exit code 6<\/code> \u0438 \u043f\u043e\u043b\u043d\u043e\u0435 \u043c\u043e\u043b\u0447\u0430\u043d\u0438\u0435. \u041d\u043e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u0438 HTTP-\u043e\u0442\u0432\u0435\u0442 \u043e\u0442 MAX \u0441 \u043e\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u044b\u043c JSON. \u0417\u043d\u0430\u0447\u0438\u0442, \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u043b\u043e\u0441\u044c.<\/p>\n<p>\u0421\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, <strong>GitLab runner<\/strong> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e DNS-\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 \u0434\u0436\u043e\u0431\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e <code>docker run<\/code>. \u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u043e \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u0443\u044e \u0440\u0435\u0437\u043e\u043b\u0432\u0430\u0446\u0438\u044e: \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0438\u043d\u043e\u0433\u0434\u0430 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u043b\u043e\u0441\u044c, \u043d\u043e \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e, \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043b\u043e \u043a \u0431\u0438\u0442\u044b\u043c \u0438\u043b\u0438 \u043f\u0443\u0441\u0442\u044b\u043c \u0442\u0435\u043b\u0430\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<p>\u041e\u0448\u0438\u0431\u043a\u0430 <code>proto.payload<\/code> \u043e\u0442 MAX \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2014 \u044d\u0442\u043e \u0441\u0438\u043c\u043f\u0442\u043e\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u0443\u0441\u0442\u043e\u0433\u043e \u0438\u043b\u0438 \u043e\u0431\u0440\u0435\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u043b\u0430, \u0430 \u043d\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0441 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u043c JSON.<\/p>\n<hr\/>\n<h3>\u0418\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435: DNS \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0435 \u0440\u0430\u043d\u043d\u0435\u0440\u0430<\/h3>\n<p>\u0424\u0438\u043a\u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0440\u043d\u044b\u0439 \u2014 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c DNS \u0432 <code>config.toml<\/code> GitLab \u0440\u0430\u043d\u043d\u0435\u0440\u0430:<\/p>\n<pre><code># \/etc\/gitlab-runner\/config.toml[[runners]]  ...  [runners.docker]    dns = [\"8.8.8.8\", \"8.8.4.4\"]   # \u2190 \u044d\u0442\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 \u0440\u0435\u0448\u0438\u043b\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e:<\/p>\n<pre><code class=\"bash\">sudo gitlab-runner restart<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u2014 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c DNS \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 Docker daemon:<\/p>\n<pre><code class=\"json\">\/\/ \/etc\/docker\/daemon.json{  \"dns\": [\"8.8.8.8\", \"8.8.4.4\"]}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"bash\">sudo systemctl restart docker<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0430 \u0440\u0430\u043d\u043d\u0435\u0440\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0436\u0435 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u0445\u0430\u0440\u0434\u043a\u043e\u0436\u0435\u043d\u044b\u043c <code>{\"text\":\"test ok\"}<\/code> \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0441 <code>HTTP 200<\/code>.<\/p>\n<hr\/>\n<h3>\u0427\u0442\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0440\u0430\u0431\u043e\u0447\u0438\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u043c<\/h3>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a DNS \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b, \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u0434\u043b\u044f GitLab CI \u0441\u0442\u0430\u043b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"bash\">if [ -z \"$MAX_BOT_TOKEN\" ] || [ -z \"$MAX_NOTIFY_CHAT_ID\" ]; then  echo \"WARN: MAX_BOT_TOKEN \u0438\u043b\u0438 MAX_NOTIFY_CHAT_ID \u043d\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u044b\"  exit 0fiTOKEN=\"$(printf '%s' \"$MAX_BOT_TOKEN\" | tr -d '\\r\\n')\"CHAT_ID=\"$(printf '%s' \"$MAX_NOTIFY_CHAT_ID\" | tr -d '\\r\\n[:space:]')\"BODY_FILE=\"$(mktemp)\"RESPONSE_FILE=\"$(mktemp)\"printf '{\"text\":\"%s\"}' \"${MSG}\" &gt; \"${BODY_FILE}\"BODY_SIZE=\"$(wc -c &lt; \"${BODY_FILE}\" | tr -d '[:space:]')\"echo \"DEBUG: CHAT_ID=${CHAT_ID}\"echo \"DEBUG: BODY_SIZE=${BODY_SIZE}\"echo \"DEBUG: BODY_TEXT=$(cat \"${BODY_FILE}\")\"CURL_STATUS=0HTTP_CODE=$(curl -sS --max-time 15 \\  -o \"${RESPONSE_FILE}\" \\  -w \"%{http_code}\" \\  -X POST \"https:\/\/platform-api.max.ru\/messages?chat_id=${CHAT_ID}\" \\  -H \"Authorization: ${TOKEN}\" \\  -H \"Content-Type: application\/json\" \\  --data @\"${BODY_FILE}\") || CURL_STATUS=$?RESPONSE=\"$(cat \"${RESPONSE_FILE}\" 2&gt;\/dev\/null || true)\"rm -f \"${BODY_FILE}\" \"${RESPONSE_FILE}\"echo \"DEBUG: HTTP_CODE=${HTTP_CODE} CURL_STATUS=${CURL_STATUS}\"echo \"DEBUG: Response: ${RESPONSE}\"if [ \"${CURL_STATUS}\" -ne 0 ] || [ \"${HTTP_CODE}\" != \"200\" ]; then  echo \"ERROR: \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c. Response: ${RESPONSE}\"  exit 1fi<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<hr\/>\n<h3>\u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u0438\u0434 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f<\/h3>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e, \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442. \u0412\u043e\u0442 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435:<\/p>\n<pre><code>\u2705 \u0423\u0441\u043f\u0435\u0448\u043d\u044b\u0439 \u0434\u0435\u043f\u043b\u043e\u0439 \u043d\u0430 DEV\ud83d\udce6 \u041f\u0440\u043e\u0435\u043a\u0442: u.clinic\ud83c\udf0d \u041e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435: DEV\ud83c\udf3f \u0412\u0435\u0442\u043a\u0430: dev\ud83d\udd16 \u0412\u0435\u0440\u0441\u0438\u044f: f7a249d0 (https:\/\/git.tverdasoft.ru\/...\/commit\/f7a249d0...)\ud83d\udcac Commit: fix(ci): \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 MAX\ud83d\udc64 \u0410\u0432\u0442\u043e\u0440: Anton Kurganskii\u23f0 \u0412\u0440\u0435\u043c\u044f (\u041c\u0421\u041a): 2026-04-08 21:29:07\u23f1\ufe0f \u0414\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c pipeline: 9 \u043c\u0438\u043d 52 \u0441\u0435\u043a\ud83d\udd17 Pipeline: https:\/\/git.tverdasoft.ru\/...\/pipelines\/809\u2713 \u0414\u0435\u043f\u043b\u043e\u0439 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d \u0443\u0441\u043f\u0435\u0448\u043d\u043e<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u0441\u0435 \u043f\u043e\u043b\u044f \u0431\u0435\u0440\u0443\u0442\u0441\u044f \u0438\u0437 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 GitLab CI: <code>CI_PROJECT_NAME<\/code>, <code>CI_COMMIT_BRANCH<\/code>, <code>CI_COMMIT_SHORT_SHA<\/code>, <code>CI_COMMIT_SHA<\/code>, <code>CI_PROJECT_URL<\/code>, <code>CI_COMMIT_TITLE<\/code>, <code>CI_COMMIT_AUTHOR<\/code>, <code>CI_PIPELINE_CREATED_AT<\/code>, <code>CI_PIPELINE_URL<\/code>.<\/p>\n<p>\u0412\u0440\u0435\u043c\u044f \u041c\u0421\u041a \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435 UTC+3 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 BusyBox <code>date<\/code>. \u0410\u0432\u0442\u043e\u0440 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442\u0441\u044f \u0438\u0437 <code>CI_COMMIT_AUTHOR<\/code> \u0441 \u043e\u0442\u0440\u0435\u0437\u0430\u043d\u0438\u0435\u043c email \u0447\u0435\u0440\u0435\u0437 <code>sed<\/code>.<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u0441\u043d\u0438\u043f\u043f\u0435\u0442 \u2014 \u0432 <code>code-snippets.md<\/code>.<\/p>\n<hr\/>\n<h3>\u041f\u043e\u0447\u0435\u043c\u0443 curlimages\/curl, \u0430 \u043d\u0435 Alpine \u0441 jq<\/h3>\n<p>\u041c\u044b \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u043b\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0441 <code>alpine:3.20<\/code> + <code>apk add curl jq<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c JSON \u0447\u0435\u0440\u0435\u0437 <code>jq<\/code>. \u041d\u043e \u0440\u0430\u043d\u043d\u0435\u0440 \u043d\u0435 \u0438\u043c\u0435\u043b \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a Alpine \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\u043c \u2014 <code>apk add<\/code> \u043f\u0430\u0434\u0430\u043b \u0441 exit code 2.<\/p>\n<p><code>curlimages\/curl<\/code> \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u0435\u0448\u0430 (<code>pull_policy: if-not-present<\/code>) \u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u0435\u0442\u0438 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u043e\u0431\u0440\u0430\u0437\u0430. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0441\u0442\u0430\u0432\u0438\u043b\u0438 \u0435\u0433\u043e.<\/p>\n<p>\u0414\u043b\u044f \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043f\u0435\u0446\u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u0432 commit message \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e <code>sed<\/code>:<\/p>\n<pre><code class=\"bash\">SAFE_TITLE=\"$(printf '%s' \"${CI_COMMIT_TITLE}\" | sed 's\/\\\\\/\\\\\\\\\/g; s\/\"\/\\\\\"\/g')\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<hr\/>\n<h3>\u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438<\/h3>\n<p>\u0415\u0441\u043b\u0438 MAX Messenger \u043d\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438\u0437 GitLab CI:<\/p>\n<ol>\n<li>\n<p><strong>\u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 DNS \u0432 Docker<\/strong> \u2014 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 <code>docker run --rm curlimages\/curl curl ... platform-api.max.ru<\/code> \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0440\u0430\u043d\u043d\u0435\u0440\u0430. \u0415\u0441\u043b\u0438 exit code 6 \u2014 \u0432\u0441\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0430\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0430 payload \u0431\u0435\u0441\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u0430<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e<\/strong> \u2014 \u0435\u0441\u043b\u0438 \u0441 \u0445\u043e\u0441\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0430 \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043d\u0435\u0442, \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Docker<\/p>\n<\/li>\n<li>\n<p><strong>\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 DNS \u0432 config.toml<\/strong> \u2014 <code>dns = [\"8.8.8.8\", \"8.8.4.4\"]<\/code> \u0432 <code>[runners.docker]<\/code><\/p>\n<\/li>\n<li>\n<p><strong>\u0422\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0439\u0442\u0435\u0441\u044c \u0441 payload<\/strong> \u2014 <code>BODY_SIZE<\/code>, <code>BODY_TEXT<\/code>, <code>HTTP_CODE<\/code>, \u043f\u043e\u043b\u043d\u044b\u0439 Response<\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0447\u0438\u043d\u0430\u0439\u0442\u0435 \u0441 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e ASCII payload<\/strong> \u2014 <code>{\"text\":\"test ok\"}<\/code>, \u0431\u0435\u0437 \u043a\u0438\u0440\u0438\u043b\u043b\u0438\u0446\u044b \u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0447\u0438\u0449\u0430\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435<\/strong> \u043e\u0442 <code>\\r\\n<\/code> \u0447\u0435\u0440\u0435\u0437 <code>tr -d '\\r\\n'<\/code><\/p>\n<\/li>\n<li>\n<p><strong>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 <\/strong><code><strong>chat_id<\/strong><\/code><strong> \u0434\u043b\u044f \u0433\u0440\u0443\u043f\u043f, <\/strong><code><strong>user_id<\/strong><\/code><strong> \u0434\u043b\u044f \u043b\u0438\u0447\u043d\u044b\u0445<\/strong> \u2014 \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0439 ID \u0432\u0441\u0435\u0433\u0434\u0430 <code>chat_id<\/code><\/p>\n<\/li>\n<\/ol>\n<hr\/>\n<h3>\u0412\u044b\u0432\u043e\u0434<\/h3>\n<p>\u0421\u043d\u0430\u0440\u0443\u0436\u0438 \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u043e \u043a\u0430\u043a \u201c\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0438\u0437 GitLab CI\u201d. \u041f\u043e \u043e\u0449\u0443\u0449\u0435\u043d\u0438\u044f\u043c \u0432\u0441\u0451 \u0432\u0440\u0435\u043c\u044f \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043e\u0437\u0440\u0435\u0432\u0430\u0442\u044c JSON, \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0443 \u0438\u043b\u0438 API.<\/p>\n<p>\u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435:<\/p>\n<ul>\n<li>\n<p>\u0445\u043e\u0441\u0442 \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u043b <code>platform-api.max.ru<\/code> \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e<\/p>\n<\/li>\n<li>\n<p>Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u2014 \u043d\u0435\u0442<\/p>\n<\/li>\n<li>\n<p>GitLab runner \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b notify-\u0434\u0436\u043e\u0431\u044b \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445<\/p>\n<\/li>\n<li>\n<p><code>proto.payload<\/code> \u2014 \u044d\u0442\u043e \u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435, \u043d\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u0430<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u0434\u0438\u043d \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0432 <code>config.toml<\/code> \u0440\u0430\u043d\u043d\u0435\u0440\u0430 (<code>dns = [\"8.8.8.8\"]<\/code>) \u0440\u0435\u0448\u0438\u043b \u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443.<\/p>\n<p>\u0421\u0430\u043c\u044b\u0439 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434: \u0435\u0441\u043b\u0438 <code>curl exit code 6<\/code> \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0439 \u0441\u0435\u0442\u0438 \u043d\u0430 \u0445\u043e\u0441\u0442\u0435 \u2014 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 DNS, \u043f\u043e\u0442\u043e\u043c \u0432\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435.<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1022420\/\">https:\/\/habr.com\/ru\/articles\/1022420\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041c\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0432\u0435\u0449\u044c: \u043f\u043e\u0441\u043b\u0435 \u0434\u0435\u043f\u043b\u043e\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0432 \u0447\u0430\u0442 MAX \u0438\u0437 GitLab CI.\u041d\u0430 \u0431\u0443\u043c\u0430\u0433\u0435 \u0437\u0430\u0434\u0430\u0447\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0430 \u043f\u043e\u0447\u0442\u0438 \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e:\u0435\u0441\u0442\u044c MAX_BOT_TOKEN\u0435\u0441\u0442\u044c MAX_NOTIFY_CHAT_ID\u0435\u0441\u0442\u044c curl\u0435\u0441\u0442\u044c POST https:\/\/platform-api.max.ru\/messages?chat_id=&#8230;\u041d\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043d\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u043d\u0435\u0439. \u041c\u044b \u043c\u0435\u043d\u044f\u043b\u0438 \u043e\u0431\u0440\u0430\u0437\u044b, \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043b\u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u044b, \u0443\u043f\u0440\u043e\u0449\u0430\u043b\u0438 payload, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b\u0438 \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0443. \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0431\u044b\u043b \u043e\u0434\u0438\u043d: \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0435 \u0434\u043e\u0445\u043e\u0434\u0438\u043b\u043e.\u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u0442\u0430\u043c, \u0433\u0434\u0435 \u043c\u044b \u0435\u0451 \u0438\u0441\u043a\u0430\u043b\u0438.\u0421\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044bannotation.md \u2014 \u043a\u043e\u0440\u043e\u0442\u043a\u0430\u044f \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f \u0438 \u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u043a\u0438 \u0434\u043b\u044f \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u0441\u0442\u0430\u0442\u044c\u0438intro.md \u2014 \u0431\u043e\u043b\u0435\u0435 \u043e\u0442\u043f\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0432\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438code-snippets.md \u2014 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u043a\u043e\u0434\u0430 \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0432 \u0441\u0442\u0430\u0442\u044c\u044e\u041f\u0435\u0440\u0432\u044b\u0435 \u0441\u0438\u043c\u043f\u0442\u043e\u043c\u044b\u041f\u0435\u0440\u0432\u044b\u0439 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u043b\u043e\u0433 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b \u0442\u0430\u043a:DEBUG: Response: {&#171;code&#187;:&#187;proto.payload&#187;,&#187;message&#187;:&#187;Can&#8217;t deserialize body&#187;}ERROR: \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c. Response: {&#171;code&#187;:&#187;proto.payload&#187;,&#187;message&#187;:&#187;Can&#8217;t deserialize body&#187;}\u042d\u0442\u043e \u0434\u0430\u0432\u0430\u043b\u043e \u043b\u043e\u0436\u043d\u043e\u0435 \u043e\u0449\u0443\u0449\u0435\u043d\u0438\u0435, \u0447\u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 JSON. \u0412\u0435\u0434\u044c MAX API \u044f\u0432\u043d\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u2014 \u0437\u043d\u0430\u0447\u0438\u0442, \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043e\u0445\u043e\u0434\u0438\u0442. \u0417\u043d\u0430\u0447\u0438\u0442, \u0441\u0435\u0442\u044c \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435. \u0417\u043d\u0430\u0447\u0438\u0442, \u043d\u0430\u0434\u043e \u0447\u0438\u043d\u0438\u0442\u044c payload.\u041c\u044b \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 \u044d\u0442\u043e.\u0427\u0442\u043e \u043c\u044b \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b\u0438 (\u0438 \u0447\u0442\u043e \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e)\u041f\u043e\u043f\u044b\u0442\u043a\u0430 1: printf + \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043bprintf &#8216;{&#171;text&#187;:&#187;%s&#187;}&#8217; &#171;$MSG&#187; &gt; \/tmp\/payload.jsoncurl &#8230; -d @\/tmp\/payload.json\u041e\u0442\u0432\u0435\u0442: Can&#8217;t deserialize body\u041f\u043e\u043f\u044b\u0442\u043a\u0430 2: jq + \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u043b\u0438\u0441\u044c \u043d\u0430 alpine:3.20, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 jq:jq -nc &#8212;arg t &#171;$MSG&#187; &#8216;{text:$t}&#8217; &gt; \/tmp\/payload.jsoncurl &#8230; -d @\/tmp\/payload.json\u041e\u0442\u0432\u0435\u0442: \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e Can&#8217;t deserialize body\u041f\u043e\u043f\u044b\u0442\u043a\u0430 3: \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0432\u043c\u0435\u0441\u0442\u043e \u0444\u0430\u0439\u043b\u0430PAYLOAD=$(jq -nc &#8212;arg t &#171;$MSG&#187; &#8216;{text:$t}&#8217;)curl &#8230; &#8212;data &#171;${PAYLOAD}&#187;\u041e\u0442\u0432\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f: Empty request body\u042d\u0442\u043e \u0431\u044b\u043b \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441 \u2014 \u0442\u0435\u043f\u0435\u0440\u044c \u0442\u0435\u043b\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0434\u043e\u0445\u043e\u0434\u0438\u043b\u043e. \u041d\u043e apk add \u043d\u0430\u0447\u0430\u043b \u043f\u0430\u0434\u0430\u0442\u044c \u0441 exit code 2: \u0440\u0430\u043d\u043d\u0435\u0440 \u043d\u0435 \u043c\u043e\u0433 \u0442\u044f\u043d\u0443\u0442\u044c \u043f\u0430\u043a\u0435\u0442\u044b \u0438\u0437 Alpine \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432.\u041f\u043e\u043f\u044b\u0442\u043a\u0430 4: \u0441\u0442\u0430\u0442\u0438\u0447\u043d\u044b\u0439 \u0445\u0430\u0440\u0434\u043a\u043e\u0434\u0423\u0431\u0440\u0430\u043b\u0438 \u0432\u0441\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435. \u041f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u0442\u0430\u0442\u0438\u0447\u043d\u044b\u0439 JSON \u0432 \u043e\u0434\u0438\u043d\u0430\u0440\u043d\u044b\u0445 \u043a\u0430\u0432\u044b\u0447\u043a\u0430\u0445:curl &#8230; -d &#8216;{&#171;text&#187;:&#187;test ok&#187;}&#8217;\u041e\u0442\u0432\u0435\u0442: Empty request body\u041a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u041d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0441\u0442\u0430\u043b\u043e \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e: \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043d\u0435 \u0432 JSON. \u0424\u043e\u0440\u043c\u0430\u0442 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u044b\u0439, \u043f\u0440\u043e\u0449\u0435 \u043d\u0435\u043a\u0443\u0434\u0430. \u041d\u043e \u0442\u0435\u043b\u043e \u043d\u0435 \u0434\u043e\u0445\u043e\u0434\u0438\u0442.\u0422\u043e\u0433\u0434\u0430 \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043b\u0438 \u0434\u0432\u0430 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f \u0441 \u043e\u0434\u043d\u043e\u0433\u043e \u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430:\u0421 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e:ssh -p 666 kurganskii.a@tverdasoft.ru \\  &#171;curl -s -X POST &#8216;https:\/\/platform-api.max.ru\/messages?chat_id=&#8230;&#8217; \\   -H &#8216;Authorization: &#8230;&#8217; \\   -H &#8216;Content-Type: application\/json&#8217; \\   -d &#8216;{\\&#187;text\\&#187;:\\&#187;test from server\\&#187;}'&#187;\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442: \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0448\u043b\u043e, HTTP 200, message_id \u0432 \u043e\u0442\u0432\u0435\u0442\u0435.\u0418\u0437 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043d\u0430 \u0442\u043e\u043c \u0436\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0435:ssh -p 666 kurganskii.a@tverdasoft.ru  \\  &#171;docker run &#8212;rm curlimages\/curl:8.7.1 curl -s \\   -X POST &#8216;https:\/\/platform-api.max.ru\/messages?chat_id=&#8230;&#8217; \\   -H &#8216;Authorization: &#8230;&#8217; \\   -d &#8216;{\\&#187;text\\&#187;:\\&#187;test from docker\\&#187;}'&#187;\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442: exit code 6 \u2014 curl: (6) Could not resolve host: platform-api.max.ru\u0412\u043e\u0442 \u043e\u043d\u0430, \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u043f\u0440\u0438\u0447\u0438\u043d\u0430.\u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430: Docker DNSDocker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u043d\u0430 \u044d\u0442\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043d\u0435 \u043c\u043e\u0433\u043b\u0438 \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u0442\u044c \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0445\u043e\u0441\u0442\u044b. \u0425\u043e\u0441\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e, \u0430 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u2014 \u043d\u0435\u0442.\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441 \u044f\u0432\u043d\u044b\u043c DNS \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043b\u0430 \u0434\u0438\u0430\u0433\u043d\u043e\u0437:docker run &#8212;rm &#8212;dns 8.8.8.8 curlimages\/curl:8.7.1 curl -s \\  -X POST &#8216;https:\/\/platform-api.max.ru\/messages?chat_id=&#8230;&#8217; \\  -H &#8216;Authorization: &#8230;&#8217; \\  -d &#8216;{&#171;text&#187;:&#187;test from docker dns8&#8243;}&#8217;\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442: \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0448\u043b\u043e \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e.\u041f\u043e\u0447\u0435\u043c\u0443 \u043c\u044b \u0442\u0430\u043a \u0434\u043e\u043b\u0433\u043e \u043d\u0435 \u0432\u0438\u0434\u0435\u043b\u0438 DNS\u042d\u0442\u043e \u0432\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u041c\u044b \u0432\u0438\u0434\u0435\u043b\u0438 Can&#8217;t deserialize body, \u0430 \u043d\u0435 Could not resolve host.\u041e\u0448\u0438\u0431\u043a\u0430 DNS \u0432\u0435\u0440\u043d\u0443\u043b\u0430 \u0431\u044b curl exit code 6 \u0438 \u043f\u043e\u043b\u043d\u043e\u0435 \u043c\u043e\u043b\u0447\u0430\u043d\u0438\u0435. \u041d\u043e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u0438 HTTP-\u043e\u0442\u0432\u0435\u0442 \u043e\u0442 MAX \u0441 \u043e\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u044b\u043c JSON. \u0417\u043d\u0430\u0447\u0438\u0442, \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u043b\u043e\u0441\u044c.\u0421\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, GitLab runner \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e DNS-\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 \u0434\u0436\u043e\u0431\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e docker run. \u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u043e \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u0443\u044e \u0440\u0435\u0437\u043e\u043b\u0432\u0430\u0446\u0438\u044e: \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0438\u043d\u043e\u0433\u0434\u0430 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u043b\u043e\u0441\u044c, \u043d\u043e \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e, \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043b\u043e \u043a \u0431\u0438\u0442\u044b\u043c \u0438\u043b\u0438 \u043f\u0443\u0441\u0442\u044b\u043c \u0442\u0435\u043b\u0430\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.\u041e\u0448\u0438\u0431\u043a\u0430 proto.payload \u043e\u0442 MAX \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2014 \u044d\u0442\u043e \u0441\u0438\u043c\u043f\u0442\u043e\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u0443\u0441\u0442\u043e\u0433\u043e \u0438\u043b\u0438 \u043e\u0431\u0440\u0435\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u043b\u0430, \u0430 \u043d\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0441 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u043c JSON.\u0418\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435: DNS \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0435 \u0440\u0430\u043d\u043d\u0435\u0440\u0430\u0424\u0438\u043a\u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0440\u043d\u044b\u0439 \u2014 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c DNS \u0432 config.toml GitLab \u0440\u0430\u043d\u043d\u0435\u0440\u0430:# \/etc\/gitlab-runner\/config.toml[[runners]]  &#8230;  [runners.docker]    dns = [&#171;8.8.8.8&#187;, &#171;8.8.4.4&#187;]   # \u2190 \u044d\u0442\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 \u0440\u0435\u0448\u0438\u043b\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e:sudo gitlab-runner restart\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u2014 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c DNS \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 Docker daemon:\/\/ \/etc\/docker\/daemon.json{  &#171;dns&#187;: [&#171;8.8.8.8&#187;, &#171;8.8.4.4&#187;]}sudo systemctl restart docker\u041f\u043e\u0441\u043b\u0435 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0430 \u0440\u0430\u043d\u043d\u0435\u0440\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0436\u0435 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u0445\u0430\u0440\u0434\u043a\u043e\u0436\u0435\u043d\u044b\u043c {&#171;text&#187;:&#187;test ok&#187;} \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0441 HTTP 200.\u0427\u0442\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0440\u0430\u0431\u043e\u0447\u0438\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u043c\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a DNS \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b, \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u0434\u043b\u044f GitLab CI \u0441\u0442\u0430\u043b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:if [ -z &#171;$MAX_BOT_TOKEN&#187; ] || [ -z &#171;$MAX_NOTIFY_CHAT_ID&#187; ]; then  echo &#171;WARN: MAX_BOT_TOKEN \u0438\u043b\u0438 MAX_NOTIFY_CHAT_ID \u043d\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u044b&#187;  exit 0fiTOKEN=&#187;$(printf &#8216;%s&#8217; &#171;$MAX_BOT_TOKEN&#187; | tr -d &#8216;\\r\\n&#8217;)&#187;CHAT_ID=&#187;$(printf &#8216;%s&#8217; &#171;$MAX_NOTIFY_CHAT_ID&#187; | tr -d &#8216;\\r\\n[:space:]&#8217;)&#187;BODY_FILE=&#187;$(mktemp)&#187;RESPONSE_FILE=&#187;$(mktemp)&#187;printf &#8216;{&#171;text&#187;:&#187;%s&#187;}&#8217; &#171;${MSG}&#187; &gt; &#171;${BODY_FILE}&#187;BODY_SIZE=&#187;$(wc -c &lt; &#171;${BODY_FILE}&#187; | tr -d &#8216;[:space:]&#8217;)&#187;echo &#171;DEBUG: CHAT_ID=${CHAT_ID}&#187;echo &#171;DEBUG: BODY_SIZE=${BODY_SIZE}&#187;echo &#171;DEBUG: BODY_TEXT=$(cat &#171;${BODY_FILE}&#187;)&#187;CURL_STATUS=0HTTP_CODE=$(curl -sS &#8212;max-time 15 \\  -o &#171;${RESPONSE_FILE}&#187; \\  -w &#171;%{http_code}&#187; \\  -X POST &#171;https:\/\/platform-api.max.ru\/messages?chat_id=${CHAT_ID}&#187; \\  -H &#171;Authorization: ${TOKEN}&#187; \\  -H &#171;Content-Type: application\/json&#187; \\  &#8212;data @&#187;${BODY_FILE}&#187;) || CURL_STATUS=$?RESPONSE=&#187;$(cat &#171;${RESPONSE_FILE}&#187; 2&gt;\/dev\/null || true)&#187;rm -f &#171;${BODY_FILE}&#187; &#171;${RESPONSE_FILE}&#187;echo &#171;DEBUG: HTTP_CODE=${HTTP_CODE} CURL_STATUS=${CURL_STATUS}&#187;echo &#171;DEBUG: Response: ${RESPONSE}&#187;if [ &#171;${CURL_STATUS}&#187; -ne 0 ] || [ &#171;${HTTP_CODE}&#187; != &#171;200&#187; ]; then  echo &#171;ERROR: \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c. Response: ${RESPONSE}&#187;  exit 1fi\u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u0438\u0434 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e, \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442. \u0412\u043e\u0442 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435:\u2705 \u0423\u0441\u043f\u0435\u0448\u043d\u044b\u0439 \u0434\u0435\u043f\u043b\u043e\u0439 \u043d\u0430 DEV\ud83d\udce6 \u041f\u0440\u043e\u0435\u043a\u0442: u.clinic\ud83c\udf0d \u041e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435: DEV\ud83c\udf3f \u0412\u0435\u0442\u043a\u0430: dev\ud83d\udd16 \u0412\u0435\u0440\u0441\u0438\u044f: f7a249d0 (https:\/\/git.tverdasoft.ru\/&#8230;\/commit\/f7a249d0&#8230;)\ud83d\udcac Commit: fix(ci): \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 MAX\ud83d\udc64 \u0410\u0432\u0442\u043e\u0440: Anton Kurganskii\u23f0 \u0412\u0440\u0435\u043c\u044f (\u041c\u0421\u041a): 2026-04-08 21:29:07\u23f1\ufe0f \u0414\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c pipeline: 9 \u043c\u0438\u043d 52 \u0441\u0435\u043a\ud83d\udd17 Pipeline: https:\/\/git.tverdasoft.ru\/&#8230;\/pipelines\/809\u2713 \u0414\u0435\u043f\u043b\u043e\u0439 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0412\u0441\u0435 \u043f\u043e\u043b\u044f \u0431\u0435\u0440\u0443\u0442\u0441\u044f \u0438\u0437 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 GitLab CI: CI_PROJECT_NAME, CI_COMMIT_BRANCH, CI_COMMIT_SHORT_SHA, CI_COMMIT_SHA, CI_PROJECT_URL, CI_COMMIT_TITLE, CI_COMMIT_AUTHOR, CI_PIPELINE_CREATED_AT, CI_PIPELINE_URL.\u0412\u0440\u0435\u043c\u044f \u041c\u0421\u041a \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435 UTC+3 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 BusyBox date. \u0410\u0432\u0442\u043e\u0440 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442\u0441\u044f \u0438\u0437 CI_COMMIT_AUTHOR \u0441 \u043e\u0442\u0440\u0435\u0437\u0430\u043d\u0438\u0435\u043c email \u0447\u0435\u0440\u0435\u0437 sed.\u041f\u043e\u043b\u043d\u044b\u0439 \u0441\u043d\u0438\u043f\u043f\u0435\u0442 \u2014 \u0432 code-snippets.md.\u041f\u043e\u0447\u0435\u043c\u0443 curlimages\/curl, \u0430 \u043d\u0435 Alpine \u0441 jq\u041c\u044b \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u043b\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0441 alpine:3.20 + apk add curl jq, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c JSON \u0447\u0435\u0440\u0435\u0437 jq. \u041d\u043e \u0440\u0430\u043d\u043d\u0435\u0440 \u043d\u0435 \u0438\u043c\u0435\u043b \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a Alpine \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\u043c \u2014 apk add \u043f\u0430\u0434\u0430\u043b \u0441 exit code 2.curlimages\/curl \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u0435\u0448\u0430 (pull_policy: if-not-present) \u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u0435\u0442\u0438 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u043e\u0431\u0440\u0430\u0437\u0430. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0441\u0442\u0430\u0432\u0438\u043b\u0438 \u0435\u0433\u043e.\u0414\u043b\u044f \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043f\u0435\u0446\u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u0432 commit message \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e sed:SAFE_TITLE=&#187;$(printf &#8216;%s&#8217; &#171;${CI_COMMIT_TITLE}&#187; | sed &#8216;s\/\\\\\/\\\\\\\\\/g; s\/&#187;\/\\\\&#187;\/g&#8217;)&#187;\u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438\u0415\u0441\u043b\u0438 MAX Messenger \u043d\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438\u0437 GitLab CI:\u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 DNS \u0432 Docker \u2014 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 docker run &#8212;rm curlimages\/curl curl &#8230; platform-api.max.ru \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0440\u0430\u043d\u043d\u0435\u0440\u0430. \u0415\u0441\u043b\u0438 exit code 6 \u2014 \u0432\u0441\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0430\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0430 payload \u0431\u0435\u0441\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u0430\u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u2014 \u0435\u0441\u043b\u0438 \u0441 \u0445\u043e\u0441\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0430 \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043d\u0435\u0442, \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Docker\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 DNS \u0432 config.toml \u2014 dns = [&#171;8.8.8.8&#187;, &#171;8.8.4.4&#187;] \u0432 [runners.docker]\u0422\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0439\u0442\u0435\u0441\u044c \u0441 payload \u2014 BODY_SIZE, BODY_TEXT, HTTP_CODE, \u043f\u043e\u043b\u043d\u044b\u0439 Response\u041d\u0430\u0447\u0438\u043d\u0430\u0439\u0442\u0435 \u0441 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e ASCII payload \u2014 {&#171;text&#187;:&#187;test ok&#187;}, \u0431\u0435\u0437 \u043a\u0438\u0440\u0438\u043b\u043b\u0438\u0446\u044b \u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f\u041e\u0447\u0438\u0449\u0430\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u0442 \\r\\n \u0447\u0435\u0440\u0435\u0437 tr -d &#8216;\\r\\n&#8217;\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 chat_id \u0434\u043b\u044f \u0433\u0440\u0443\u043f\u043f, user_id \u0434\u043b\u044f \u043b\u0438\u0447\u043d\u044b\u0445 \u2014 \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0439 ID \u0432\u0441\u0435\u0433\u0434\u0430 chat_id\u0412\u044b\u0432\u043e\u0434\u0421\u043d\u0430\u0440\u0443\u0436\u0438 \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u043e \u043a\u0430\u043a \u201c\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0438\u0437 GitLab CI\u201d. \u041f\u043e \u043e\u0449\u0443\u0449\u0435\u043d\u0438\u044f\u043c \u0432\u0441\u0451 \u0432\u0440\u0435\u043c\u044f \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043e\u0437\u0440\u0435\u0432\u0430\u0442\u044c JSON, \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0443 \u0438\u043b\u0438 API.\u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435:\u0445\u043e\u0441\u0442 \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u043b platform-api.max.ru \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043eDocker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u2014 \u043d\u0435\u0442GitLab runner \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b notify-\u0434\u0436\u043e\u0431\u044b \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445proto.payload \u2014 \u044d\u0442\u043e \u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435, \u043d\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u041e\u0434\u0438\u043d \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0432 config.toml \u0440\u0430\u043d\u043d\u0435\u0440\u0430 (dns = [&#171;8.8.8.8&#187;]) \u0440\u0435\u0448\u0438\u043b \u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443.\u0421\u0430\u043c\u044b\u0439 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434: \u0435\u0441\u043b\u0438 curl exit code 6 \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0439 \u0441\u0435\u0442\u0438 \u043d\u0430 \u0445\u043e\u0441\u0442\u0435 \u2014 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 DNS, \u043f\u043e\u0442\u043e\u043c \u0432\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435.\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 https:\/\/habr.com\/ru\/articles\/1022420\/<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-475574","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/475574","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=475574"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/475574\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=475574"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=475574"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=475574"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}