<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>DevOps, Productivity, Career // etogeek blog</title>
    <link>https://etogeek.dev/en/</link>
    <description>Recent content on DevOps, Productivity, Career // etogeek blog</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Mon, 27 Oct 2025 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://etogeek.dev/en/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Maintenance mode in Nginx</title>
      <link>https://etogeek.dev/en/posts/nginx-maintenance-mode/</link>
      <pubDate>Mon, 27 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://etogeek.dev/en/posts/nginx-maintenance-mode/</guid>
      <description>&#xA;  &#xA;&#xA;&#xA;&#xA;&lt;div&#xA;  &#xA;    class=&#34;flex px-4 py-3 rounded-md bg-primary-100 dark:bg-primary-900&#34;&#xA;  &gt;&#xA;&#xA;  &lt;span&#xA;    &#xA;      class=&#34;text-primary-400 ltr:pr-3 rtl:pl-3 flex items-center&#34;&#xA;    &gt;&#xA;&#xA;    &#xA;&#xA;  &lt;span class=&#34;relative block icon&#34;&gt;&#xA;    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 512 512&#34;&gt;&lt;path fill=&#34;currentColor&#34; d=&#34;M506.3 417l-213.3-364c-16.33-28-57.54-28-73.98 0l-213.2 364C-10.59 444.9 9.849 480 42.74 480h426.6C502.1 480 522.6 445 506.3 417zM232 168c0-13.25 10.75-24 24-24S280 154.8 280 168v128c0 13.25-10.75 24-23.1 24S232 309.3 232 296V168zM256 416c-17.36 0-31.44-14.08-31.44-31.44c0-17.36 14.07-31.44 31.44-31.44s31.44 14.08 31.44 31.44C287.4 401.9 273.4 416 256 416z&#34;/&gt;&lt;/svg&gt;&#xA;&#xA;  &lt;/span&gt;&#xA;&#xA;&#xA;  &lt;/span&gt;&#xA;&#xA;  &lt;span&#xA;    &#xA;      class=&#34;dark:text-neutral-300&#34;&#xA;    &gt;This post is also &lt;a href=&#34;https://etogeek.dev/posts/nginx-maintenance-mode/&#34;   target=&#34;_blank&#34;&gt;&#xA;    available in Russian&lt;/a&gt;.&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h1 class=&#34;relative group&#34;&gt;What is it? &#xA;    &lt;div id=&#34;what-is-it&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#what-is-it&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h1&gt;&#xA;&lt;p&gt;There is no built-in “mode” like this in Nginx. I just use this name for &lt;strong&gt;the ability to manually switch the site to serve a specific page instead of the normal content.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Right now we can serve a specific HTML page instead of the default error page.&lt;/p&gt;&#xA;&lt;p&gt;For example, instead of the default 504 error we can return a nice page with the company logo and a clear polite message like “The service is temporarily unavailable. We’re aware of the problem; please try again in a minute.”&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;error_page&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;500&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;501&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;503&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;502&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;504&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/static/errors/5xx.html&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What if we know there will be maintenance today from 20:00 and the service will be down? We turn on maintenance mode with information about the work and an ETA.&lt;/p&gt;&#xA;&lt;p&gt;Second case: the service crashed hard, engineers are handling the incident, and users are seeing 500s, 503s, 504s, and timeouts. Turn on maintenance mode so everyone sees a stable message.&lt;/p&gt;&#xA;&#xA;&#xA;&lt;h1 class=&#34;relative group&#34;&gt;A not-so-good attempt &#xA;    &lt;div id=&#34;a-not-so-good-attempt&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#a-not-so-good-attempt&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h1&gt;&#xA;&lt;p&gt;The first solution you’ll find online: use &lt;code&gt;if&lt;/code&gt; to check for a file on the server (for example &lt;code&gt;/etc/nginx/maintenance.flag&lt;/code&gt;). If the file exists — return the page; if not — continue with the standard Nginx config. Something like this:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &#x9;&lt;span class=&#34;kn&#34;&gt;....&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &#x9;&lt;span class=&#34;s&#34;&gt;error_page&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;503&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/maintenance.html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &#x9;&lt;span class=&#34;kn&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/maintenance.html&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &#x9;    &lt;span class=&#34;kn&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/etc/nginx/maintenance/&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &#x9;    &lt;span class=&#34;kn&#34;&gt;internal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &#x9;&lt;span class=&#34;kn&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &#x9;  &lt;span class=&#34;kn&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;(-f&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/etc/nginx/maintenance.flag)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &#x9;     &lt;span class=&#34;kn&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;503&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &#x9;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &#x9;  &lt;span class=&#34;kn&#34;&gt;proxy_pass&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;http://127.0.0.1:3000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works, but here &lt;strong&gt;the file existence is checked on EVERY request&lt;/strong&gt;. That can be wasteful. It looked fine in the dev environment, but caused slowdowns in production.&lt;/p&gt;&#xA;&#xA;&#xA;&lt;h1 class=&#34;relative group&#34;&gt;Why &lt;code&gt;return 503&lt;/code&gt;? &#xA;    &lt;div id=&#34;why-return-503&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#why-return-503&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h1&gt;&#xA;&lt;p&gt;Why should we return HTTP 503 even though we’re sending a normal, working HTML page?&lt;/p&gt;&#xA;&lt;p&gt;503 means the service is temporarily unavailable (maintenance or overload). &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/503&#34;   target=&#34;_blank&#34;&gt;&#xA;    More details&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Search engines do not index pages that return 503. Imagine Google’s crawler hits your site during downtime and stores “Under maintenance” as the page content.&lt;/p&gt;&#xA;&lt;p&gt;Also, browsers should not cache such pages, so after maintenance ends the user doesn’t keep seeing the maintenance page from cache.&lt;/p&gt;&#xA;&#xA;&#xA;&lt;h1 class=&#34;relative group&#34;&gt;How to do it with a config include? &#xA;    &lt;div id=&#34;how-to-do-it-with-a-config-include&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#how-to-do-it-with-a-config-include&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h1&gt;&#xA;&lt;p&gt;The idea:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;we have a file &lt;code&gt;maintenance_on.conf&lt;/code&gt; with a single line: &lt;code&gt;return 503;&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;when needed, include this file in the desired locations via &lt;code&gt;include maintenance_on.conf&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;gracefully restart Nginx (reload)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Implementation details:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create a directory to keep things clean: &lt;code&gt;mkdir /etc/nginx/maintenance&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Put your &lt;code&gt;maintenance.html&lt;/code&gt; page there. Vibe-code it&amp;hellip;&lt;/li&gt;&#xA;&lt;li&gt;Create the config file &lt;code&gt;maintenance_on.conf&lt;/code&gt;:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;503&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Create an empty config file &lt;code&gt;maintenance_off.conf&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Create a symlink &lt;code&gt;maintenance_current.conf&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ln -sfn /etc/nginx/maintenance/maintenance_off.conf /etc/nginx/maintenance/maintenance_current.conf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add a few lines to the Nginx &lt;code&gt;server&lt;/code&gt; block:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&#x9;&lt;span class=&#34;kn&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s&#34;&gt;error_page&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;503&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/maintenance.html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/maintenance.html&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;internal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/etc/nginx/maintenance/maintenance.html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;add_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Cache-Control&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;no-store&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;add_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Retry-After&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;3600&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/etc/nginx/maintenance/maintenance_current.conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;err&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What happens here:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;We tell Nginx to serve &lt;code&gt;/maintenance.html&lt;/code&gt; on a 503 error.&lt;/li&gt;&#xA;&lt;li&gt;We configure the &lt;code&gt;/maintenance.html&lt;/code&gt; location that serves our service page. &lt;code&gt;internal&lt;/code&gt; ensures the client cannot directly request &lt;code&gt;/maintenance.html&lt;/code&gt; or any other internal file.&lt;/li&gt;&#xA;&lt;li&gt;We add headers so the browser does not cache the page, plus &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After&#34;   target=&#34;_blank&#34;&gt;&#xA;    Retry-After&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;In the main (or any) location we &lt;code&gt;include&lt;/code&gt; our symlink.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;So to enable maintenance mode we only need to switch the symlink and gracefully reload Nginx:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ln -sfn /etc/nginx/maintenance/maintenance_on.conf /etc/nginx/maintenance/maintenance_current.conf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nginx -t &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; systemctl reload nginx&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To disable it, point the symlink back to the &lt;code&gt;_off&lt;/code&gt; file and reload Nginx again.&lt;/p&gt;&#xA;&lt;p&gt;How to automate it — up to you.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>How to Install GitLab Runner in Docker Swarm</title>
      <link>https://etogeek.dev/en/posts/gitlab-runner-swarm-cluster/</link>
      <pubDate>Sun, 18 Aug 2024 10:06:32 +0000</pubDate>
      <guid>https://etogeek.dev/en/posts/gitlab-runner-swarm-cluster/</guid>
      <description>&#xA;  &#xA;&#xA;&#xA;&#xA;&lt;div&#xA;  &#xA;    class=&#34;flex px-4 py-3 rounded-md bg-primary-100 dark:bg-primary-900&#34;&#xA;  &gt;&#xA;&#xA;  &lt;span&#xA;    &#xA;      class=&#34;text-primary-400 ltr:pr-3 rtl:pl-3 flex items-center&#34;&#xA;    &gt;&#xA;&#xA;    &#xA;&#xA;  &lt;span class=&#34;relative block icon&#34;&gt;&#xA;    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 512 512&#34;&gt;&lt;path fill=&#34;currentColor&#34; d=&#34;M506.3 417l-213.3-364c-16.33-28-57.54-28-73.98 0l-213.2 364C-10.59 444.9 9.849 480 42.74 480h426.6C502.1 480 522.6 445 506.3 417zM232 168c0-13.25 10.75-24 24-24S280 154.8 280 168v128c0 13.25-10.75 24-23.1 24S232 309.3 232 296V168zM256 416c-17.36 0-31.44-14.08-31.44-31.44c0-17.36 14.07-31.44 31.44-31.44s31.44 14.08 31.44 31.44C287.4 401.9 273.4 416 256 416z&#34;/&gt;&lt;/svg&gt;&#xA;&#xA;  &lt;/span&gt;&#xA;&#xA;&#xA;  &lt;/span&gt;&#xA;&#xA;  &lt;span&#xA;    &#xA;      class=&#34;dark:text-neutral-300&#34;&#xA;    &gt;This post is also &lt;a href=&#34;https://etogeek.dev/posts/gitlab-runner-swarm-cluster/&#34;   target=&#34;_blank&#34;&gt;&#xA;    available in Russian&lt;/a&gt;.&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;p&gt;In my project, I have a Docker Swarm cluster where Jenkins Agents are dynamically launched to execute all the jobs from Jenkins. Why not in Kubernetes? Because maintaining a Kubernetes cluster just for jobs is not optimal; Swarm is much simpler to manage.&lt;/p&gt;&#xA;&lt;p&gt;Recently, I set up a Self-Hosted GitLab, but I couldn’t find an official guide on how to launch a GitLab Runner in a Swarm cluster with autoscaling – meaning that the runner would automatically spin up additional containers on Swarm nodes. I had to gather the information bit by bit. Here’s the method I used.&lt;/p&gt;&#xA;&lt;p&gt;The guide consists of three steps:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Obtain the registration token&lt;/li&gt;&#xA;&lt;li&gt;Distribute the runner configurations to the machines&lt;/li&gt;&#xA;&lt;li&gt;Deploy the runners&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Obtaining the Runner Authentication Token &#xA;    &lt;div id=&#34;obtaining-the-runner-authentication-token&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#obtaining-the-runner-authentication-token&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Previously, a runner registration token was used to register runners, but it has now been deprecated. GitLab has started using &lt;a href=&#34;https://docs.gitlab.com/runner/register/#register-with-a-runner-authentication-token&#34;   target=&#34;_blank&#34;&gt;&#xA;    Runner Authentication Token&lt;/a&gt; for connecting runners.&lt;/p&gt;&#xA;&lt;p&gt;Go to the project, group, or instance settings to register a new Runner: Admin Settings -&amp;gt; CI/CD -&amp;gt; Runners -&amp;gt; New instance runner:&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;    &#xA;  &#xA;  &#xA;    &lt;figure&gt;&#xA;      &#xA;      &lt;img&#xA;        class=&#34;my-0 rounded-md&#34;&#xA;        loading=&#34;lazy&#34;&#xA;        src=&#34;https://etogeek.dev/posts/gitlab-runner-swarm-cluster/image.png&#34;&#xA;        alt=&#34;new instance runner&#34;&#xA;      /&gt;&#xA;      &#xA;      &#xA;    &lt;/figure&gt;&#xA;  &#xA;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;Specify the Tags. Later, we&amp;rsquo;ll use these tags in our GitLab CI pipelines to ensure they run on specific runners. For example, I use the tag &lt;code&gt;swarm&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;On the next page, copy the token and save it somewhere:&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;    &#xA;  &#xA;  &#xA;    &lt;figure&gt;&#xA;      &#xA;      &lt;img&#xA;        class=&#34;my-0 rounded-md&#34;&#xA;        loading=&#34;lazy&#34;&#xA;        src=&#34;https://etogeek.dev/posts/gitlab-runner-swarm-cluster/image-1.png&#34;&#xA;        alt=&#34;runner authentication token&#34;&#xA;      /&gt;&#xA;      &#xA;      &#xA;    &lt;/figure&gt;&#xA;  &#xA;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;Now, GitLab will be waiting for a runner to register with this token.&lt;/p&gt;&#xA;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Configuring the Runners &#xA;    &lt;div id=&#34;configuring-the-runners&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#configuring-the-runners&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;We can launch a container with the GitLab Runner, exec to it, and execute the register command. During registration, GitLab Runner will save the token and minimal settings in the &lt;code&gt;/etc/gitlab/config.toml&lt;/code&gt; file inside the container. But instead of manually executing a register command on each container on every machine, &lt;strong&gt;let’s create a configuration template and distribute it to the Swarm nodes&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Prepare the configuration file:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;concurrent&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;# Concurrent containers per node&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;check_interval&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;docker-swarm-runner&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://&amp;lt;YOUR-GITLAB-INSTANCE&amp;gt;/&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;token&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;GITLAB AUTHENTICATION TOKEN&amp;gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;executor&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;docker&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;custom_build_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;docker&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;tls_verify&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;image&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;alpine:latest&amp;#34;&lt;/span&gt;  &lt;span class=&#34;c&#34;&gt;# Default image for jobs&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;privileged&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;  &lt;span class=&#34;c&#34;&gt;# If we need Docker-in-Docker&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;disable_entrypoint_overwrite&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;oom_kill_disable&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;disable_cache&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;volumes&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/cache&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;shm_size&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;allowed_pull_policies&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;always&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;if-not-present&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;never&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;gcs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace the token with the one you obtained in the previous step. Also, specify the address of your GitLab instance.&lt;/p&gt;&#xA;&lt;p&gt;Now, on each Swarm node, you need to create a directory for the configuration and place this file there. How you do this is up to you, but I use Ansible.&lt;/p&gt;&#xA;&#xA;  &#xA;  &#xA;  &#xA;  &#xA;&#xA;&#xA;&#xA;&lt;div&#xA;  &#xA;    class=&#34;flex px-4 py-3 rounded-md&#34;&#xA;    style=&#34;background-color: #e63946&#34;&#xA;  &gt;&#xA;&#xA;  &lt;span&#xA;    &#xA;      class=&#34;ltr:pr-3 rtl:pl-3 flex items-center&#34;&#xA;      style=&#34;color: #1d3557&#34;&#xA;    &gt;&#xA;&#xA;    &#xA;&#xA;  &lt;span class=&#34;relative block icon&#34;&gt;&#xA;    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 448 512&#34;&gt;&#xA;&lt;path fill=&#34;currentColor&#34;  d=&#34;M159.3 5.4c7.8-7.3 19.9-7.2 27.7 .1c27.6 25.9 53.5 53.8 77.7 84c11-14.4 23.5-30.1 37-42.9c7.9-7.4 20.1-7.4 28 .1c34.6 33 63.9 76.6 84.5 118c20.3 40.8 33.8 82.5 33.8 111.9C448 404.2 348.2 512 224 512C98.4 512 0 404.1 0 276.5c0-38.4 17.8-85.3 45.4-131.7C73.3 97.7 112.7 48.6 159.3 5.4zM225.7 416c25.3 0 47.7-7 68.8-21c42.1-29.4 53.4-88.2 28.1-134.4c-2.8-5.6-5.6-11.2-9.8-16.8l-50.6 58.8s-81.4-103.6-87.1-110.6C133.1 243.8 112 273.2 112 306.8C112 375.4 162.6 416 225.7 416z&#34;/&gt;&lt;/svg&gt;&#xA;  &lt;/span&gt;&#xA;&#xA;&#xA;  &lt;/span&gt;&#xA;&#xA;  &lt;span&#xA;    &#xA;      style=&#34;color: #f1faee&#34;&#xA;    &gt;Remember, storing the token in a Git repository is unsafe. It’s bad practice. In the case of Ansible, you can use Ansible Vault or third-party solutions like Hashicorp Vault or Infisical.&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;Copying the Configuration File to Nodes &#xA;    &lt;div id=&#34;copying-the-configuration-file-to-nodes&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#copying-the-configuration-file-to-nodes&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Here’s an example of Ansible code to copy the configuration file:&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;templates/config.toml.j2&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-jinja&#34; data-lang=&#34;jinja&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;concurrent = 5&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;check_interval = 0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;[[runners]]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;  name = &amp;#34;docker-swarm-runner&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;  url = &amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;gitlab_instance_url&lt;/span&gt; &lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;x&#34;&gt;&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;  token = &amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;gitlab_runner_swarm_auth_token.value&lt;/span&gt; &lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;x&#34;&gt;&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;  executor = &amp;#34;docker&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;  [runners.custom_build_dir]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;  [runners.docker]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    tls_verify = false&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    image = &amp;#34;alpine:latest&amp;#34;  # Default image for jobs, can be overridden in .gitlab-ci.yml&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    privileged = true  # Enable if you need to run Docker-in-Docker or privileged containers&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    disable_entrypoint_overwrite = false&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    oom_kill_disable = false&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    disable_cache = false&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    volumes = [&amp;#34;/cache&amp;#34;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    shm_size = 0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    allowed_pull_policies = [&amp;#34;always&amp;#34;, &amp;#34;if-not-present&amp;#34;, &amp;#34;never&amp;#34;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;  [runners.cache]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    [runners.cache.s3]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    [runners.cache.gcs]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;tasks/main.yml&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Create directories&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ansible.builtin.file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;/etc/gitlab-runner/config&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;directory&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;recurse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Copy config file&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ansible.builtin.template&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;config.toml.j2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;dest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;/etc/gitlab-runner/config/config.toml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;The configuration file should be on all Swarm cluster nodes&lt;/strong&gt;.&lt;/p&gt;&#xA;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Deploying GitLab Runner in Swarm &#xA;    &lt;div id=&#34;deploying-gitlab-runner-in-swarm&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#deploying-gitlab-runner-in-swarm&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Swarm works with the familiar docker-compose files, so let’s create one. I also use Ansible for copying, so here’s an example jinja template:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-jinja&#34; data-lang=&#34;jinja&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;services:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;  gitlab-runner:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    image: gitlab/gitlab-runner:&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;{{&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;gitlab_runner_image_version&lt;/span&gt; &lt;span class=&#34;cp&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;x&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    deploy:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;      mode: global&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    volumes:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;      - /var/run/docker.sock:/var/run/docker.sock&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;      - /etc/gitlab-runner/config:/etc/gitlab-runner&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    networks:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;      - gitlab-net&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;networks:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;  gitlab-net:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;x&#34;&gt;    external: false&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;We specify deploy mode: global, so the container is launched on all cluster nodes. This is like a DaemonSet in Kubernetes.&lt;/li&gt;&#xA;&lt;li&gt;We connect the directory with the config.toml file.&lt;/li&gt;&#xA;&lt;li&gt;Additionally, we mount the Docker socket so that the GitLab runner can manage our Docker engine and create new containers (this is necessary for autoscaling).&lt;/li&gt;&#xA;&lt;li&gt;We specify the version of the GitLab Runner container; you can find available versions on &lt;a href=&#34;https://hub.docker.com/r/gitlab/gitlab-runner/tags&#34;   target=&#34;_blank&#34;&gt;&#xA;    Docker Hub&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I copy this file using Ansible:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Copy compose file&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ansible.builtin.template&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;docker-compose.yml.j2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;dest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;/etc/gitlab-runner/docker-compose.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;You need to run the Swarm stack from the manager node (the main cluster node)&lt;/strong&gt;, but the file will be on all nodes. It’s redundant, but it’s easier for me this way, so I don’t have to add conditions in Ansible.&lt;/p&gt;&#xA;&lt;p&gt;Go to the manager node and execute:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker stack deploy -c docker-compose.yml gitlab-runner&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After a minute, check:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@swarm-node01:/home/ysemyenkov# docker stack ps gitlab-runner&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ID             NAME                                                    IMAGE                                 NODE           DESIRED STATE   CURRENT STATE        ERROR     PORTS&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pnkxq7yf3wm3   gitlab-runner.1tlong-name   gitlab/gitlab-runner:ubuntu-v17.3.0   swarm-node01   Running         Running &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; days ago&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ih4822qch9ew   gitlab-runner.3tlong-name   gitlab/gitlab-runner:ubuntu-v17.3.0   swarm-node03   Running         Running &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; days ago&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xzj5yt1cv5ae   gitlab-runner.2tlong-name   gitlab/gitlab-runner:ubuntu-v17.3.0   swarm-node02   Running         Running &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; days ago&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If everything is okay, you’ll see the registered Runner in GitLab:&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;    &#xA;  &#xA;  &#xA;    &lt;figure&gt;&#xA;      &#xA;      &lt;img&#xA;        class=&#34;my-0 rounded-md&#34;&#xA;        loading=&#34;lazy&#34;&#xA;        src=&#34;https://etogeek.dev/posts/gitlab-runner-swarm-cluster/image-2.png&#34;&#xA;        alt=&#34;registered swarm gitlab runners&#34;&#xA;      /&gt;&#xA;      &#xA;      &#xA;    &lt;/figure&gt;&#xA;  &#xA;&#xA;&lt;/p&gt;&#xA;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Testing &#xA;    &lt;div id=&#34;testing&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#testing&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;We can create a test pipeline that runs a dozen jobs simultaneously:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-gitlab&#34; data-lang=&#34;gitlab&#34;&gt;stages:&#xA;  - test&#xA;&#xA;parallel-jobs:&#xA;  stage: test&#xA;  tags:&#xA;    - swarm&#xA;  script:&#xA;    - echo &amp;#34;Starting sleep for 600 seconds&amp;#34;&#xA;    - sleep 600&#xA;  parallel:&#xA;    matrix:&#xA;      - JOB_NAME: &amp;#34;job1&amp;#34;&#xA;      - JOB_NAME: &amp;#34;job2&amp;#34;&#xA;      - JOB_NAME: &amp;#34;job3&amp;#34;&#xA;      - JOB_NAME: &amp;#34;job4&amp;#34;&#xA;      - JOB_NAME: &amp;#34;job5&amp;#34;&#xA;      - JOB_NAME: &amp;#34;job6&amp;#34;&#xA;      - JOB_NAME: &amp;#34;job7&amp;#34;&#xA;      - JOB_NAME: &amp;#34;job8&amp;#34;&#xA;      - JOB_NAME: &amp;#34;job9&amp;#34;&#xA;      - JOB_NAME: &amp;#34;job10&amp;#34;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Run the pipeline and see that the containers launched in the required number and on different nodes. You can view it with &lt;code&gt;docker ps&lt;/code&gt; command on the nodes or through monitoring tools. For example, I prefer viewing cAdvisor metrics in Grafana:&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;    &#xA;  &#xA;  &#xA;    &lt;figure&gt;&#xA;      &#xA;      &lt;img&#xA;        class=&#34;my-0 rounded-md&#34;&#xA;        loading=&#34;lazy&#34;&#xA;        src=&#34;https://etogeek.dev/posts/gitlab-runner-swarm-cluster/image-3.png&#34;&#xA;        alt=&#34;containers in grafana from cadvisor metrics&#34;&#xA;      /&gt;&#xA;      &#xA;      &#xA;    &lt;/figure&gt;&#xA;  &#xA;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;You can see that the top three containers are the main GitLab Runner processes, which receive tasks and create dynamic containers for jobs. Below are our containers with sleep jobs running simultaneously on different nodes.&lt;/p&gt;&#xA;&lt;p&gt;That&amp;rsquo;s it.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Difference: Authentication and Authorization</title>
      <link>https://etogeek.dev/en/posts/auth-auth/</link>
      <pubDate>Thu, 18 Apr 2024 00:00:00 +0000</pubDate>
      <guid>https://etogeek.dev/en/posts/auth-auth/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Authentication and authorization&lt;/strong&gt; — similar words with different meanings, and they are easy to confuse. Let&amp;rsquo;s explore the differences.&lt;/p&gt;&#xA;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Authentication &#xA;    &lt;div id=&#34;authentication&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#authentication&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt; is a process that verifies you are who you claim to be. An example of authentication is entering a username and password. The system checks these credentials to confirm your identity.&lt;/p&gt;&#xA;&lt;p&gt;In &lt;strong&gt;Linux&lt;/strong&gt; systems, authentication is handled by files such as:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;/etc/passwd&lt;/code&gt; — stores user information.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;/etc/shadow&lt;/code&gt; — contains encrypted user passwords.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;/etc/nsswitch.conf&lt;/code&gt; — directs where to look for user and group information and other resources, including DNS or network file system services. It tells the system to look for data in local files or, for example, in LDAP.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Authorization &#xA;    &lt;div id=&#34;authorization&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#authorization&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Authorization&lt;/strong&gt; follows authentication and determines your access to resources or actions. It checks whether you are permitted access to certain service areas.&lt;/p&gt;&#xA;&lt;p&gt;In Linux, access rights are defined through:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;/etc/group&lt;/code&gt; — describes user groups and their members.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;/etc/sudoers&lt;/code&gt; — specifies who can execute commands with superuser privileges.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Real-life Example &#xA;    &lt;div id=&#34;real-life-example&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#real-life-example&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;When you show your passport at the border, that’s &lt;strong&gt;authentication&lt;/strong&gt; — you prove that you are John Smith. Deciding whether you can leave the country is a matter of &lt;strong&gt;authorization&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Important to remember&lt;/strong&gt;: Authentication always precedes authorization. The system first needs to know who you are and then decides what you are allowed to do.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;Прокомментировать статью, поделиться идеями, поболтать и задать вопрос можно в 👉 &lt;a href=&#34;https://t.me/etogeekchat&#34;   target=&#34;_blank&#34;&gt;&#xA;    телеграм-чате&lt;/a&gt;, а так же обязательно подписаться на 👉 &lt;a href=&#34;https://t.me/etogeek&#34;   target=&#34;_blank&#34;&gt;&#xA;    телеграм-канал&lt;/a&gt;!&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>How to commit only part of a file?</title>
      <link>https://etogeek.dev/en/posts/commit-part-of-the-file/</link>
      <pubDate>Thu, 08 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://etogeek.dev/en/posts/commit-part-of-the-file/</guid>
      <description>&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;TL;DR; &#xA;    &lt;div id=&#34;tldr&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#tldr&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;git add -p&lt;/code&gt;&lt;/p&gt;&#xA;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;A bit more detail &#xA;    &lt;div id=&#34;a-bit-more-detail&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#a-bit-more-detail&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;code&gt;git add -p&lt;/code&gt; (or &lt;code&gt;--patch&lt;/code&gt;) command goes through all files and asks about each change, what you want to do with it:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;l&#34;&gt;❯ git add -p&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;diff --git a/ansible/file.yml b/ansible/file.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;index 73f6b4d..899610f 100644&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;a/ansible/file.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;+++ b/ansible/file.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;@@&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-&lt;span class=&#34;m&#34;&gt;52&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;+52,8 @@&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;loop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;service&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;+        - &amp;#34;node_modules&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;+        - &amp;#34;systemd_templates&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;       &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;(1/1) Stage this hunk [y,n,q,a,d,e,?]?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then it&amp;rsquo;s an interactive input. Well, the most important are “&lt;code&gt;y&lt;/code&gt;” and “&lt;code&gt;n&lt;/code&gt;&amp;quot; — to add these changes to the index or skip them. There are options to skip or add &amp;ldquo;to the end of the file&amp;rdquo;. It can also be used as &lt;code&gt;git add -p filename&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Reminder, the index in git is a list of files that will be committed.&lt;/p&gt;&#xA;&lt;p&gt;Importantly, this action adds our change only to the index. It still needs to be committed.&lt;/p&gt;&#xA;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;How else can it be used? &#xA;    &lt;div id=&#34;how-else-can-it-be-used&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#how-else-can-it-be-used&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;As I wrote here, I always used either &lt;code&gt;git add .&lt;/code&gt; or &lt;code&gt;git add &amp;lt;filename&amp;gt;&lt;/code&gt;. But there&amp;rsquo;s a catch:&lt;/p&gt;&#xA;&lt;p&gt;with &lt;code&gt;git add .&lt;/code&gt;, extra files about which you might have forgotten can get into the index, and then into the commit&lt;/p&gt;&#xA;&lt;p&gt;Here, &lt;code&gt;git add -p&lt;/code&gt; allows you to more consciously (thoughtfully) go through the files before adding them to the index.&lt;/p&gt;&#xA;&lt;p&gt;Also, a reminder that to remove a file from the index, you can use the command git reset filename.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>What do I listen to when I work</title>
      <link>https://etogeek.dev/en/posts/what-i-listen/</link>
      <pubDate>Wed, 07 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://etogeek.dev/en/posts/what-i-listen/</guid>
      <description>&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;What I Listen On? &#xA;    &lt;div id=&#34;what-i-listen-on&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#what-i-listen-on&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;AirPods Pro 2&lt;/strong&gt; — powerful noise cancellation system, fit well in the ears, still hold a charge well, switches between devices correctly. They are over a year old, I use them every day. I&amp;rsquo;m deeply integrated into the Apple ecosystem and don&amp;rsquo;t think I&amp;rsquo;ll switch to another headphone brand in the foreseeable future.&lt;/p&gt;&#xA;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;What Do I Listen To? &#xA;    &lt;div id=&#34;what-do-i-listen-to&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;&#xA;        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700&#34;&#xA;            style=&#34;text-decoration-line: none !important;&#34; href=&#34;#what-do-i-listen-to&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;        &#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;It really depends on my mood, the task at hand, energy level, but here are the main playlists from my bookmarks:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Discovery of the year — hip-hop is great for work, made such a &lt;a href=&#34;https://open.spotify.com/playlist/0kXTxy3b7TKRhM63IgEi2X&#34;   target=&#34;_blank&#34;&gt;&#xA;    playlist on Spotify&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;If I want something a bit more calming, I turn on lo-fi girl. Either on &lt;a href=&#34;https://open.spotify.com/playlist/0vvXsWCC9xrXsKd4FyS8kM?si=9bda45677aa54b34&#34;   target=&#34;_blank&#34;&gt;&#xA;    Spotify&lt;/a&gt;, or &lt;a href=&#34;https://www.youtube.com/watch?v=jfKfPfyJRdk&#34;   target=&#34;_blank&#34;&gt;&#xA;    Youtube&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I always find it hilarious that the soundtrack from the game Stronghold Crusader tops my Spotify Wrapped for the second year in a row, but that doesn’t take away from the fact that it’s a really cool 40-minute playlist. &lt;a href=&#34;https://open.spotify.com/album/50F2mUOZU5YFPcFCNi13Xv?si=04a0ca19832d4e55&#34;   target=&#34;_blank&#34;&gt;&#xA;    Spotify&lt;/a&gt;, &lt;a href=&#34;https://www.youtube.com/watch?v=9foO7qWlNds&#34;   target=&#34;_blank&#34;&gt;&#xA;    Youtube&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;A very long playlist that is both relaxing and keeps you focused with an ambient remix of the &lt;a href=&#34;https://www.youtube.com/watch?v=hShxsAlJmfw&#34;   target=&#34;_blank&#34;&gt;&#xA;    soundtrack to the movie Dune&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Another long playlist, repetitive but more relaxing — music from the game Witcher 3. &lt;a href=&#34;https://www.youtube.com/watch?v=-MJi7T4lX80&#34;   target=&#34;_blank&#34;&gt;&#xA;    Youtube&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;When in a cheerier mood, I might play my retro playlist - &lt;a href=&#34;https://open.spotify.com/playlist/3jWwoZ9iSjAuZuT7raBuup?si=b76ce8f2d9ae4f3f&#34;   target=&#34;_blank&#34;&gt;&#xA;    Spotify&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Two playlists about 15-20 minutes each — two radio stations from the game GTA 3 on Youtube: &lt;a href=&#34;https://www.youtube.com/watch?v=HsU7Yi6qxe4&#34;   target=&#34;_blank&#34;&gt;&#xA;    Game Radio&lt;/a&gt;, and &lt;a href=&#34;https://www.youtube.com/watch?v=7jHUddL3xfg&#34;   target=&#34;_blank&#34;&gt;&#xA;    Head Radio&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Quite upbeat music, can be distracting, suited for less focused and routine work — 40 minutes, album by the band The Medics (NL) &lt;a href=&#34;https://open.spotify.com/album/1qZpvQGNyR2R0uqTsWQA3T?si=d94352ed343546d7&#34;   target=&#34;_blank&#34;&gt;&#xA;    Spotify&lt;/a&gt;, &lt;a href=&#34;https://youtube.com/playlist?list=OLAK5uy_lI1HuztruEJvdpOqT2Cs76tKgz1_p1I9k&amp;amp;si=W3icsd7wEBr5Fr62&#34;   target=&#34;_blank&#34;&gt;&#xA;    Youtube&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Difference between $VAR and ${VAR}?</title>
      <link>https://etogeek.dev/en/posts/shell-variables/</link>
      <pubDate>Sun, 28 Jan 2024 00:00:00 +0000</pubDate>
      <guid>https://etogeek.dev/en/posts/shell-variables/</guid>
      <description>&lt;p&gt;This is really a frequent question. I&amp;rsquo;m explaining in addition to the &lt;a href=&#34;https://t.me/etogeek/224&#34;   target=&#34;_blank&#34;&gt;&#xA;    post&lt;/a&gt;(sorry, it is not translated yet) about variable substitution in a file.&lt;/p&gt;&#xA;&lt;p&gt;There&amp;rsquo;s no rocket science here, and the difference only lies in how the command interpreter (Bash, zsh, sh, thousands of them) determines the boundaries of the variable name:&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;$VAR&lt;/code&gt; — works well when the variable name is separated from other text by unused symbols, such as a space, or a backslash. But if we insert the variable into a word, it will be interpreted incorrectly:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;VAR&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;eto&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$VAR&lt;/span&gt;      &lt;span class=&#34;c1&#34;&gt;# Will output eto&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$VARgeek&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# Will output the value of VARgeek, if it exists, otherwise — empty&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;${VAR}&lt;/code&gt; — more reliable. Helps to accurately separate the variable name from other text:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;VAR&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;eto&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;VAR&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;     &lt;span class=&#34;c1&#34;&gt;# Will output eto&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;VAR&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;geek &lt;span class=&#34;c1&#34;&gt;# Will output etogeek&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
  </channel>
</rss>