<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Yandex-Cloud on Igor Plotnikov</title><link>https://iplotnikov.com/tags/yandex-cloud/</link><description>Recent content in Yandex-Cloud on Igor Plotnikov</description><generator>Hugo -- gohugo.io</generator><language>ru-RU</language><atom:link href="https://iplotnikov.com/tags/yandex-cloud/index.xml" rel="self" type="application/rss+xml"/><item><title>Как устроен этот сайт</title><link>https://iplotnikov.com/p/%D0%BA%D0%B0%D0%BA-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD-%D1%8D%D1%82%D0%BE%D1%82-%D1%81%D0%B0%D0%B9%D1%82/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://iplotnikov.com/p/%D0%BA%D0%B0%D0%BA-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD-%D1%8D%D1%82%D0%BE%D1%82-%D1%81%D0%B0%D0%B9%D1%82/</guid><description>&lt;img src="https://iplotnikov.com/p/%D0%BA%D0%B0%D0%BA-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD-%D1%8D%D1%82%D0%BE%D1%82-%D1%81%D0%B0%D0%B9%D1%82/cover.jpg" alt="Featured image of post Как устроен этот сайт" /&gt;&lt;p&gt;Небольшая статья о том как устроен этот блог под капотом. Есть приватный git-репозиторий с текстовыми файлами и бакет в Яндекс облаке. Сайт статический, то есть каждая страница лежит в хранилище готовым HTML-файлом, и когда читатель её открывает, хранилище просто отдаёт то, что там уже есть.&lt;/p&gt;&#10;&lt;p&gt;Собирает страницы &lt;a class="link" href="https://github.com/gohugoio/hugo" target="_blank" rel="noopener"&#10; &gt;Hugo&lt;/a&gt;, генератор статических сайтов на Go.&lt;/p&gt;&#10;&lt;h2 id="что-происходит-по-шагам"&gt;Что происходит по шагам&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Шаг 1. Я пишу статью.&lt;/strong&gt; Создаю папку в &lt;code&gt;content/post&lt;/code&gt;, кладу туда &lt;code&gt;index.md&lt;/code&gt; и картинки.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Шаг 2. Смотрю, что получилось.&lt;/strong&gt; Команда &lt;code&gt;hugo server -D&lt;/code&gt; поднимает копию сайта на localhost с горячей перезагрузкой.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Шаг 3. Делаю коммит и пуш в &lt;code&gt;main&lt;/code&gt;.&lt;/strong&gt; На этом моё ручное участие заканчивается.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Шаг 4. GitHub Actions поднимает чистую виртуалку&lt;/strong&gt; и выкачивает на неё репозиторий вместе с темой.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Шаг 5. Ставится Hugo и собирается сайт.&lt;/strong&gt; Команда &lt;code&gt;hugo --minify&lt;/code&gt; превращает markdown в HTML и по дороге сжимает разметку, результат складывается в папку &lt;code&gt;public&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Шаг 6. Результат синхронизируется с бакетом.&lt;/strong&gt; Заливаются только изменившиеся файлы, а флаг &lt;code&gt;--delete&lt;/code&gt; подчищает в хранилище то, чего больше нет в сборке, иначе удалённая статья продолжала бы открываться по старому адресу.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Шаг 7. Статья размещена на сайте.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h2 id="пайплайн"&gt;Пайплайн&#10;&lt;/h2&gt;&lt;p&gt;Всё описано в одном файле &lt;code&gt;.github/workflows/deploy.yaml&lt;/code&gt;, триггером служит любой пуш в ветку &lt;code&gt;main&lt;/code&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Deploy&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;main]&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/checkout@v4&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;submodules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;recursive&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fetch-depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;peaceiris/actions-hugo@v3&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;hugo-version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;latest&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;hugo --minify&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;AWS_DEFAULT_REGION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ru-central1&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; aws s3 sync ./public s3://iplotnikov.com \&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --endpoint-url=https://storage.yandexcloud.net --delete&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img alt="Прогон пайплайна в GitHub Actions" class="gallery-image" data-flex-basis="302px" data-flex-grow="126" height="319" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://iplotnikov.com/p/%D0%BA%D0%B0%D0%BA-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD-%D1%8D%D1%82%D0%BE%D1%82-%D1%81%D0%B0%D0%B9%D1%82/pipe.png" width="402"&gt;&lt;/p&gt;&#10;&lt;p&gt;Весь прогон занимает около десяти секунд, ключи доступа лежат в секретах GitHub и принадлежат в Яндекс облаке сервисному аккаунту с ролью &lt;code&gt;storage.editor&lt;/code&gt;, который умеет только читать и писать объекты в этом хранилище и больше ничего, так что при утечке ключа ущерб ограничен содержимым одного бакета.&lt;/p&gt;&#10;&lt;h2 id="домен-и-сертификат"&gt;Домен и сертификат&#10;&lt;/h2&gt;&lt;p&gt;Доменом управляет Yandex Cloud DNS, то есть зона &lt;code&gt;iplotnikov.com&lt;/code&gt; целиком живёт в облаке и обслуживается серверами &lt;code&gt;ns1.yandexcloud.net&lt;/code&gt; и &lt;code&gt;ns2.yandexcloud.net&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;HTTPS обеспечивает сертификат от Let&amp;rsquo;s Encrypt, выпущенный через Yandex Certificate Manager и привязанный к бакету. Сертификаты Let&amp;rsquo;s Encrypt живут 90 дней, Certificate Manager запрашивает обновление за 30 дней до истечения и раскатывает новую версию на все привязанные ресурсы.&lt;/p&gt;&#10;&lt;h2 id="из-чего-складывается-счёт"&gt;Из чего складывается счёт&#10;&lt;/h2&gt;&lt;p&gt;В Object Storage никакой абонентской платы за сам факт существования бакета нет, счётчик крутится только тогда, когда данные лежат или их кто-то читает. Хранение считается пропорционально времени, вплоть до часов и мегабайт, операции делятся на типы по методам S3 API (загрузка объекта PUT, скачивание GET, получение метаданных HEAD), и оплачивается фактическое их количество, а удаление объектов не тарифицируется вообще. Входящий трафик тоже бесплатен, так что деплой ничего не стоит сам по себе.&lt;/p&gt;&#10;&lt;p&gt;Поверх этого работает бесплатный лимит, не тарифицируются первый гигабайт хранения, первые десять тысяч операций записи и сто тысяч операций чтения, а также первые сто гигабайт исходящего трафика в месяц. Блог с несколькими десятками мегабайт статики и парой тысяч посещений в такие рамки укладывается целиком, поэтому в детализации напротив всех строк Object Storage стоит ноль: и хранение, и одиннадцать тысяч операций GET, и сто двадцать операций PUT от последних деплоев, и весь исходящий трафик.&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="Детализация потребления за месяц" class="gallery-image" data-flex-basis="463px" data-flex-grow="193" height="658" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://iplotnikov.com/p/%D0%BA%D0%B0%D0%BA-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD-%D1%8D%D1%82%D0%BE%D1%82-%D1%81%D0%B0%D0%B9%D1%82/detail.png" srcset="https://iplotnikov.com/p/%D0%BA%D0%B0%D0%BA-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD-%D1%8D%D1%82%D0%BE%D1%82-%D1%81%D0%B0%D0%B9%D1%82/detail_hu_6e619aaeaafd855e.png 800w, https://iplotnikov.com/p/%D0%BA%D0%B0%D0%BA-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD-%D1%8D%D1%82%D0%BE%D1%82-%D1%81%D0%B0%D0%B9%D1%82/detail.png 1270w" width="1270"&gt;&lt;/p&gt;&#10;&lt;p&gt;И получается что хостинг сайта раскатанный таким образом не стоит ничего. Все 44 рубля в счёте это Cloud DNS, где 41,95 рубля приходится на саму DNS-зону, которая тарифицируется по часам её существования, и ещё 82 копейки на публичные запросы к ней. Сертификат от Let&amp;rsquo;s Encrypt в Certificate Manager отдельных денег тоже не стоит.&lt;/p&gt;&#10;&lt;p&gt;Интересно посмотреть, что будет при росте. Ставки в стандартном хранилище такие: примерно 2,4 рубля за гигабайт хранения в месяц, 46 копеек за десять тысяч операций GET и около 1,7 рубля за гигабайт исходящего трафика сверх бесплатных ста. Если читателей станет в десять раз больше, операции вылезут за лимит на одиннадцать тысяч штук, и счёт вырастет на пятьдесят копеек. При стократном росте, то есть больше миллиона запросов в месяц, добавится сорок шесть рублей.&lt;/p&gt;&#10;&lt;h2 id="сколько-стоила-бы-виртуалка"&gt;Сколько стоила бы виртуалка&#10;&lt;/h2&gt;&lt;p&gt;Для сравнения я собрал в калькуляторе Yandex Cloud самую минимальную конфигурацию, два ядра с гарантированной долей 5%, 0.5 гб памяти, 5 гб диска и публичный IP-адрес. Вышло 612 рублей в месяц, и это сверх тех же 42 рублей за DNS, которые никуда не денутся. Почти 200 рублей из этой суммы приходится не на вычислительные ресурсы, а на публичный IP-адрес, ещё 17 на диск. Если довести машину до вменяемого состояния, скажем до 20% доли ядра и двух гигабайт памяти, счёт уходит в район полутора тысяч.&lt;/p&gt;&#10;&lt;p&gt;Разница тут не в том, что виртуалки у Яндекса такие дорогие, а в модели оплаты, в случае с Compute Cloud придётся платить за зарезервированные ресурсы. Ядра, память, диск и адрес будут капать в счёт круглые сутки независимо от того, зашёл на сайт хоть кто-нибудь или нет. Больше того, диск и IP тарифицируются даже когда машина выключена, так что 200 рублей в месяц набегают на полностью простаивающем сервере. Блог, который читают полтора человека в день, простаивает практически всё время, но платить приходится за все двадцать четыре часа.&lt;/p&gt;&#10;&lt;p&gt;Пришёл читатель и скачал 100 файлов, значит в счёт попали 100 операций GET и несколько сотен килобайт трафика. Не пришёл никто, значит и потребления нет. А поскольку блог такого размера целиком помещается в бесплатный лимит, фактический счёт за хостинг равен нулю, тогда как виртуалка выставляла бы свои шестьсот рублей каждый месяц независимо ни от чего.&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="Расчёт минимальной виртуальной машины в калькуляторе Yandex Cloud" class="gallery-image" data-flex-basis="350px" data-flex-grow="145" height="733" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://iplotnikov.com/p/%D0%BA%D0%B0%D0%BA-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD-%D1%8D%D1%82%D0%BE%D1%82-%D1%81%D0%B0%D0%B9%D1%82/calc.png" srcset="https://iplotnikov.com/p/%D0%BA%D0%B0%D0%BA-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD-%D1%8D%D1%82%D0%BE%D1%82-%D1%81%D0%B0%D0%B9%D1%82/calc_hu_389a3f9b6607e041.png 800w, https://iplotnikov.com/p/%D0%BA%D0%B0%D0%BA-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD-%D1%8D%D1%82%D0%BE%D1%82-%D1%81%D0%B0%D0%B9%D1%82/calc.png 1069w" width="1069"&gt;&lt;/p&gt;&#10;&lt;p&gt;Плюс к деньгам сюда добавляется всё, за что не приходится платить временем: не надо накатывать обновления безопасности, следить за сертификатами, чинить упавший nginx и держать в голове, что на машине вообще-то крутится веб-сервер, который по всем законам подлости обязательно рано или поздно отвалится.&lt;/p&gt;&#10;</description></item></channel></rss>