<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Ихрь постит в уютный бложик: заметки с тегом devops</title>
<link>https://ifedyukin.ru/blog/tags/devops/</link>
<description>Фрирайтинг, заметки, шитпостинг и все подряд</description>
<author></author>
<language>ru</language>
<generator>Aegea 11.1 (v4098)</generator>

<itunes:subtitle>Фрирайтинг, заметки, шитпостинг и все подряд</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit></itunes:explicit>

<item>
<title>Change SSH port on Ubuntu 22 using Ansible</title>
<guid isPermaLink="false">74</guid>
<link>https://ifedyukin.ru/blog/all/change-ssh-port-on-ubuntu-22-using-ansible/</link>
<pubDate>Wed, 29 Mar 2023 18:46:00 +0300</pubDate>
<author></author>
<comments>https://ifedyukin.ru/blog/all/change-ssh-port-on-ubuntu-22-using-ansible/</comments>
<description>
&lt;p&gt;After updating Ubuntu 22.10 SSHd uses socket-based activation.&lt;br /&gt;
As a result, the sshd configuration port does not affect the listening port.&lt;br /&gt;
To change the port, we need to perform the following tasks:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;- name: Create config folder
  file:
    path: /etc/systemd/system/ssh.socket.d
    state: directory
    recurse: true

- name: Create config file
  copy:
    dest: /etc/systemd/system/ssh.socket.d/listen.conf
    content: |
      [Socket]
      ListenStream={{ custom_ssh_port }}

- name: Reload systemd manager
  systemd:
    daemon_reload: yes

- name: restart ssh
  service:
    name: &amp;quot;ssh&amp;quot;
    state: restarted

- name: Update connection port
  set_fact:
    ansible_ssh_port: &amp;quot;{{ custom_ssh_port }}&amp;quot;&lt;/code&gt;&lt;/pre&gt;</description>
</item>

<item>
<title>Как хостить MySQL на маленьких VPS</title>
<guid isPermaLink="false">62</guid>
<link>https://ifedyukin.ru/blog/all/kak-hostit-mysql-na-malenkih-vps/</link>
<pubDate>Tue, 22 Mar 2022 17:20:29 +0300</pubDate>
<author></author>
<comments>https://ifedyukin.ru/blog/all/kak-hostit-mysql-na-malenkih-vps/</comments>
<description>
&lt;p&gt;Недавно я начал хостить бложик (apache + mysql + nginx + пара сервисов на nodejs) на самом дешевом дроплете от Digital Ocean (надо ж кредитные токены DO куда-то потратить).&lt;/p&gt;
&lt;p&gt;Внезапно столкнулся с проблемой, что контейнер MySQL периодически умирает от OOM киллера, MySQL с небольшим количеством данных съедала ну очень много памяти в простое.&lt;/p&gt;
&lt;p&gt;Платить больше я не хотел, а воспоминания, что когда-то MySQL крутилась у меня на прямо маленьких VPS никак не давала покоя.&lt;/p&gt;
&lt;p&gt;Оказалось, что есть такая штука, как &lt;tt&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/performance-schema.html#:~:text=The%20MySQL%20Performance%20Schema%20is,of%20the%20server%20at%20runtime."&gt;Performance Schema&lt;/a&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The MySQL Performance Schema is a feature for monitoring MySQL Server execution at a low level.&lt;br /&gt;
The Performance Schema provides a way to inspect internal execution of the server at runtime.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Дальше я не особо читал, конечно, погуглил чуть, решил поэкспериментировать.&lt;br /&gt;
Добавляем в конфиг в секцию &lt;tt&gt;[mysqld]&lt;/tt&gt;  строчку, чтобы отключить эту фичу (я просто примонтировал новый конфиг), перезагрузил сервис и бах — случилась магия и теперь MySQL кушает гораздо меньше ресурсов. А мониторить мне пока не к чему.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://ifedyukin.ru/blog/pictures/Screenshot-2022-03-22-at-17.08.52.png" width="1966" height="616" alt="" /&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>Обходим блокировку аналитики AD блокерами</title>
<guid isPermaLink="false">53</guid>
<link>https://ifedyukin.ru/blog/all/ad-blockers-workaround/</link>
<pubDate>Mon, 22 Feb 2021 13:14:12 +0300</pubDate>
<author></author>
<comments>https://ifedyukin.ru/blog/all/ad-blockers-workaround/</comments>
<description>
&lt;p&gt;AD-блокеры — несомненно крутая штука, тем не менее, они блокируют скрипты аналитики, которые не всегда являются злом.&lt;/p&gt;
&lt;p&gt;Например, &lt;a href="https://www.cloudflare.com/web-analytics/"&gt;аналитика&lt;/a&gt; от Cloudflare — про приватность и легкость, данных лишних не собирает, на сторону их не продает. Потому обойти ее блокировку различными расширениями не так уже и подло.&lt;/p&gt;
&lt;p&gt;Блокировщики работают в несколько этапов: блокируют подгрузку файла скрипта аналитики и блокируют запросы к серверам аналитики, к которым эти скрипты и обращаются.&lt;/p&gt;
&lt;p&gt;Для обхода блокировки нам понадобится одна вещь — прокся с возможностью замены части контента в ответе, например, nginx.&lt;/p&gt;
&lt;p&gt;Добавляем два локейшена в конфиг:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# сам скрипт аналитики
location /analytics-script.js {
  # очень важно, чтоб отрабатывал sub_filter, т.к. если сервер отдаст gzip, то замена не сработает
  proxy_set_header Accept-Encoding &amp;quot;&amp;quot;;

  # заменяем в скрипте оригинальный адрес на наш, проксированный
  sub_filter 'https://cloudflareinsights.com/cdn-cgi/rum'  'https://домен/analytics-api';
  sub_filter_types *;
  sub_filter_once off;

  proxy_hide_header Content-Security-Policy;
  proxy_pass https://static.cloudflareinsights.com/beacon.min.js;
}

# проксируем вызовы к оригинальному api аналитики
location /analytics-api {
  proxy_pass https://cloudflareinsights.com/cdn-cgi/rum;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Подключаем аналитику не с домена Cloudflare, а со своего домена.&lt;/p&gt;
&lt;p&gt;Таким образом мы загружаем и скрипт аналитики со своего домена, и аналитику он отправляет на наш домен, а внутри уже все проксируется в Cloudflare.&lt;/p&gt;
&lt;p&gt;AD блокеры ничего не блокируют, мы получаем аналитику. Запросы куда-то еще уходят неявно.&lt;/p&gt;
&lt;div class="hr"&gt;&lt;/div&gt;&lt;p&gt;Есть одна небольшая проблема — у всех запросов один IP, IP прокси, почему-то аналитика Cloudflare не учитвает заголовки и не имеет задокументированных способов переопределить IP юзера, как это сделано в Google аналитике.&lt;/p&gt;
&lt;p&gt;Закинул в коммьюнити &lt;a href="https://community.cloudflare.com/t/web-analytics-ip-override/246614"&gt;топик&lt;/a&gt; на эту тему, посмотрим, как решится.&lt;/p&gt;
</description>
</item>

<item>
<title>Docker’изация JavaScript-приложений</title>
<guid isPermaLink="false">29</guid>
<link>https://ifedyukin.ru/blog/all/dockerize-js/</link>
<pubDate>Fri, 30 Nov 2018 18:03:02 +0300</pubDate>
<author></author>
<comments>https://ifedyukin.ru/blog/all/dockerize-js/</comments>
<description>
&lt;p&gt;Поучаствовал в IT-Субботнике, рассказал о Docker’изации JavaScript-приложений.&lt;/p&gt;
&lt;div class="e2-text-video"&gt;
&lt;iframe src="https://www.youtube.com/embed/xC7-HCPEn6k?enablejsapi=1" allow="autoplay" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>Docker + Nginx + Env</title>
<guid isPermaLink="false">28</guid>
<link>https://ifedyukin.ru/blog/all/docker-nginx-env/</link>
<pubDate>Thu, 06 Sep 2018 18:01:56 +0300</pubDate>
<author></author>
<comments>https://ifedyukin.ru/blog/all/docker-nginx-env/</comments>
<description>
&lt;p&gt;Иногда бывают ситуации, когда внутри nginx-конфига надо сделать что-то в зависимости от переменной окружения, которая прокинется откуда-то извне (или не прокинется), так помимо этого это всё ещё и в Docker крутится, в который окружение прокидывается от compose или k8s.&lt;/p&gt;
&lt;p&gt;С выше изложенными условиями выполнить эту задачу по-простому не получится (ну или я не нашёл как). Решение, представленное ниже, не особо-то и сложное, но, на мой взгляд, несколько нетривиально, ну и, если б я нашёл другой способ, то такой огород городить точно не стал бы.&lt;/p&gt;
&lt;p&gt;Итак, ближе к делу, берём и переписываем наш Dockerfile следующим образом.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;FROM # какой-то образ

WORKDIR /usr/src/app
COPY . /usr/src/app

ENTRYPOINT [&amp;quot;/usr/src/app/start.sh&amp;quot;]

EXPOSE 80&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ключевой момент здесь — ENTRYPOINT, им является какой-то sh-файл (не забудьте ему права на выполнение дать). Этот файл будет преобразовывать наш nginx-конфиг и запускать nginx.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;#!/bin/sh

export SEARCH=&amp;quot;${SEARCH_FROM_ENV:-google}&amp;quot;

envsubst '${SEARCH}' &amp;lt; /etc/nginx/nginx.conf &amp;gt; /etc/nginx/nginx.conf

nginx -g 'daemon off;'&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;В строчке экспорта мы “отдаём” переменную SEARCH, которую читаем из переменной окружения “SEARCHFROMENV”.&lt;br /&gt;
В случае, если переменная окружения не задана, присваиваем стандартное значение “google”.&lt;br /&gt;
После чего обращаемся к системной утилите envsubst, которой конкретно указываем, какие переменные менять, передаём в неё наш конфиг, а результат выполнения пишем в этот же конфиг.&lt;br /&gt;
Наконец, запускаем nginx.&lt;br /&gt;
В конфиге nginx изначально указываем где-то выражение следующего вида.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;if (${SEARCH} = &amp;quot;google&amp;quot;) {
  # что-то делаем
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;После обработки envsubst без передачи каких-либо переменных окружения переменная SEARCH заменится на “google”.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;if (&amp;quot;google&amp;quot; = &amp;quot;google&amp;quot;) {
  # что-то делаем
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Таким образом мы прокидываем какую-то env-переменную в nginx-конфиг, а так же, в случае неопределённого окружения, имеем значение по-умолчанию.&lt;/p&gt;
</description>
</item>

<item>
<title>GitLab CI &amp; Telegram</title>
<guid isPermaLink="false">18</guid>
<link>https://ifedyukin.ru/blog/all/gitlab-ci-telegram/</link>
<pubDate>Fri, 05 Jan 2018 17:22:20 +0300</pubDate>
<author></author>
<comments>https://ifedyukin.ru/blog/all/gitlab-ci-telegram/</comments>
<description>
&lt;p&gt;Последнее время стал замечать, что всё больше людей юзают GitLab, отмечая, что у него клёвый CI/CD. Не знаю, как правильно всё это оценивать, но попробовать я решил однозначно.&lt;/p&gt;
&lt;p&gt;Во-первых, переместил статические сайтики с GitHub Pages на GitLab Pages. Во-вторых, сделал небольшое ExpressJS-приложение и разместил на GitLab, а так же настроил деплой на Heroku, что, &lt;a href="https://ifedyukin.ru/blog/all/bachelor-work-1/"&gt;оказалось, очень просто&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;GitLab CI, конечно, крут, много полезных примеров и доков, из коробки поддерживается множество интеграций и фич, но мне была нужна интеграция с Telegram, т. к. он всегда включен.&lt;/p&gt;
&lt;p&gt;Ну, раз нет интеграции из коробки, то сделаем сами, причем на данном этапе нужно всего лишь уведомление о статусе деплоя.&lt;/p&gt;
&lt;p&gt;Задача поставлена, сложностей никаких (на самом деле они возникали, но это я доки невнимательно читал). Делаем.&lt;/p&gt;
&lt;p&gt;Чтобы взаимодействовать с Telegram создадим бота: пишем &lt;a href="https://t.me/BotFather"&gt;@BotFather&lt;/a&gt;, создаём обычного бота, загружаем аватарку и т. п. Всё это делается максимально просто. После создания бота в чатик прилетит token для работы с API.&lt;/p&gt;
&lt;p&gt;Бот будет слать уведомления пользователю с нужным ID, но просто так Telegram не позволяет рассылать сообщения от бота любому пользователю, поэтому новосозданному боту нужно отправить хотя бы какое-то сообщение от пользователя, которому должны приходить уведомления.&lt;/p&gt;
&lt;p&gt;Сохраняем нужные значения в GitLab:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Settings нужного репозитория;&lt;/li&gt;
&lt;li&gt;Пункт CI/CD;&lt;/li&gt;
&lt;li&gt;Secret variables;&lt;/li&gt;
&lt;li&gt;Сохранить в переменную TELEGRAM_BOT_TOKEN token, присланный после создания бота через BotFather;&lt;/li&gt;
&lt;li&gt;В TELEGRAM_USER_ID сохраняем ID пользователя, которому будут отправляться уведомления.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Для удобной отправки уведомлений создадим скрипт в `ci-notify.sh`, в котором будем обращаться к API Telegram и отправлять сообщение нужному пользователю через созданного бота:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;#!/bin/bash

TIME=&amp;quot;10&amp;quot;
URL=&amp;quot;https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage&amp;quot;
TEXT=&amp;quot;Deploy status: $1%0A%0AProject:+$CI_PROJECT_NAME%0AURL:+$CI_PROJECT_URL/pipelines/$CI_PIPELINE_ID/%0ABranch:+$CI_COMMIT_REF_SLUG&amp;quot;

curl -s --max-time $TIME -d &amp;quot;chat_id=$TELEGRAM_USER_ID&amp;amp;disable_web_page_preview=1&amp;amp;text=$TEXT&amp;quot; $URL &amp;gt; /dev/null&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;В качестве первого параметра для этого скрипта должен передаваться статус деплоя. В .gitlab-ci.yml описываем вызов этого скрипта в нужное время с нужными параметрами:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;stages:
- deploy
- notify

deploy:
  image: node:4.2.2
  stage: deploy

  script:
  #deploy success
  - sh .ci-notify.sh ✅

  artifacts:
    paths:
    - public
  only:
  - master

notify_error:
  stage: notify
  script:
  - sh .ci-notify.sh ❌
  when: on_failure #deploy fail&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Для обозначения статуса деплоя я использовал Emoji. В случае успешного выполнения деплоя просто вызывается скрипт с нужны параметром. В случае неудачного деплоя “управление переходит” в следующий stage, в котором происходит уведомление о неудачном деплое.&lt;/p&gt;
&lt;p&gt;Таким образом, где-то за 10 минут можно настроить простые уведомления в Telegram из GitLab CI и хоть чуть-чуть почувствовать себя DevOps’ом. Если подзаморочиться, то можно расширить возможности всего этого, но мне как-то лень.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://ifedyukin.ru/blog/pictures/tg-ci.png" width="492" height="612" alt="" /&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>Запуск Karma в Chrome — Travis-CI</title>
<guid isPermaLink="false">13</guid>
<link>https://ifedyukin.ru/blog/all/travis-ci-chrome/</link>
<pubDate>Mon, 27 Mar 2017 17:05:37 +0300</pubDate>
<author></author>
<comments>https://ifedyukin.ru/blog/all/travis-ci-chrome/</comments>
<description>
&lt;p&gt;Если вы тестируете свой код и используете GitHub, то скорее всего вы уже используете Travis, однако, при тестировании JavaScript в Travis может возникнуть проблема — Travis не умеет запускать тесты в Chrome, но преодолеть её можно всего несколькими строчками config-файлов.&lt;/p&gt;
&lt;p&gt;Для начала нам нужно настроить сам travis, в моём случае `.travis.yml` выглядит следующим образом:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;language: node_js
node_js:
- '6.2'
before_install:
- export CHROME_BIN=chromium-browser
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- sudo apt-get update
- sudo apt-get install -y libappindicator1 fonts-liberation
- wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- sudo dpkg -i google-chrome*.deb
script:
- npm install
- npm test&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Внимание здесь стоит обратить на блок `before_install`.&lt;/p&gt;
&lt;p&gt;Для Karma тоже нужно несколько изменить файл настроек — создадим лаунчер, который будет использоваться только в окружении Travis:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;module.exports = function (config) {
    var configuration = {
        // configs
        
        browsers: ['Chrome'],
        customLaunchers: {
            Chrome_travis_ci: {
                base: 'Chrome',
                flags: ['--no-sandbox']
            }
        },
      
        // configs
    };

    if (process.env.TRAVIS) {
        configuration.browsers = ['Chrome_travis_ci'];
    }

    config.set(configuration);
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;На этом процедура настройки закончена — пушим изменения на Github и можем наблюдать процесс тестирования в “консоли” Travis соответствующего репозитория.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://ifedyukin.ru/blog/pictures/travisLog.png" width="800" height="367" alt="" /&gt;
&lt;/div&gt;
</description>
</item>


</channel>
</rss>