<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Service-Mesh on DevOps Way - Практические гайды</title>
    <link>https://devopsway.ru/tags/service-mesh/</link>
    <description>Recent content in Service-Mesh on DevOps Way - Практические гайды</description>
    <image>
      <title>DevOps Way - Практические гайды</title>
      <url>https://devopsway.ru/images/devopsway-og.png</url>
      <link>https://devopsway.ru/images/devopsway-og.png</link>
    </image>
    <generator>Hugo -- 0.165.0</generator>
    <language>ru</language>
    <lastBuildDate>Sat, 15 Aug 2026 20:08:42 +0300</lastBuildDate>
    <atom:link href="https://devopsway.ru/tags/service-mesh/feed.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Networking 20/80, уровень 6: Балансировка нагрузки и сети Kubernetes</title>
      <link>https://devopsway.ru/posts/networking-06-lb-k8s/</link>
      <pubDate>Sat, 08 Aug 2026 14:30:00 +0300</pubDate>
      <guid>https://devopsway.ru/posts/networking-06-lb-k8s/</guid>
      <description>Финал мини-курса: L4 против L7 балансировки, четыре типа Service в Kubernetes, Ingress и обратный прокси (reverse proxy) на nginx, алгоритмы балансировки, обзор сервисной сетки (service mesh) и чеклист диагностики сети в K8s. Три подвоха с собеса и итог всего курса.</description>
      <content:encoded><![CDATA[<p>Седьмой, финальный уровень мини-курса &quot;Networking 20/80&quot;. Всё предыдущее сходится здесь: адреса, DNS, TCP, HTTP и межсетевые экраны складываются в то, как запрос снаружи попадает в pod и распределяется между репликами. L4 против L7, четыре типа Service, Ingress – и общая картина сети в Kubernetes целиком.</p>
<blockquote>
<p>&quot;В Kubernetes нет понятия &quot;сервер&quot;. Есть pod-ы, которые рождаются и умирают. Service – абстракция, которая превращает хаос в стабильную точку доступа (endpoint). Ingress – дверь снаружи.&quot;</p>
</blockquote>
<hr>
<h2 id="откуда-это-пошло">Откуда это пошло</h2>
<p><strong>1997 – F5 Networks</strong> выпускает аппаратный балансировщик BIG-IP. Дорого, железом. Задача: распределить HTTP-запросы между несколькими серверами.</p>
<p><strong>2001 – HAProxy</strong> (Willy Tarreau). Специализированный L4/L7 балансировщик, до сих пор стандарт.</p>
<p><strong>2004 – nginx</strong> (Игорь Сысоев). Изначально HTTP-сервер для Rambler.ru. Стал де-факто стандартом для обратного прокси (reverse proxy) и балансировки. Бесплатный, быстрый, конфигурируемый.</p>
<p><strong>2014 – Kubernetes Services.</strong> Абстракция поверх iptables/IPVS: стабильный ClusterIP, который распределяет трафик по pod-ам на L4. Свой nginx/haproxy ради этого держать больше не нужно – kube-proxy балансирует сам. (HTTP-маршрутизация снаружи – это уже L7/Ingress, о нём ниже.)</p>
<p><strong>2016 – Envoy</strong> (Lyft). Прокси-контейнер (sidecar) для сервисной сетки (service mesh). Основа Istio. Балансировка на L7 с размыканием цепи (circuit breaking), повторами, наблюдаемостью.</p>
<hr>
<h2 id="балансировка-l4-против-l7">Балансировка L4 против L7</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">L4 (Transport):
</span></span><span class="line"><span class="cl">  Решение на основе: IP + порт
</span></span><span class="line"><span class="cl">  Не знает: HTTP, URL, заголовки, cookies
</span></span><span class="line"><span class="cl">  Скорость: очень быстрая (просто перенаправляет пакеты)
</span></span><span class="line"><span class="cl">  Примеры: HAProxy (mode tcp), AWS NLB, K8s Service (ClusterIP)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">L7 (Application):
</span></span><span class="line"><span class="cl">  Решение на основе: URL path, Host header, cookies, HTTP method
</span></span><span class="line"><span class="cl">  Знает: весь HTTP-запрос
</span></span><span class="line"><span class="cl">  Скорость: медленнее (разбирает HTTP)
</span></span><span class="line"><span class="cl">  Примеры: nginx, HAProxy (mode http), AWS ALB, K8s Ingress
</span></span></code></pre></div><h3 id="когда-что-использовать">Когда что использовать</h3>
<table>
	<thead>
			<tr>
					<th>Сценарий</th>
					<th>Уровень</th>
					<th>Почему</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>TCP-балансировка (PostgreSQL, Redis)</td>
					<td>L4</td>
					<td>Не HTTP, нет URL для маршрутизации</td>
			</tr>
			<tr>
					<td>Маршрутизация по URL: <code>/api</code> → бэкенд, <code>/</code> → фронтенд</td>
					<td>L7</td>
					<td>Нужен разбор HTTP</td>
			</tr>
			<tr>
					<td>Терминация TLS (SSL termination)</td>
					<td>L7</td>
					<td>Нужно расшифровать TLS</td>
			</tr>
			<tr>
					<td>Липкие сессии (sticky sessions, по cookie)</td>
					<td>L7</td>
					<td>Нужен разбор cookies</td>
			</tr>
			<tr>
					<td>Максимальная производительность</td>
					<td>L4</td>
					<td>Минимальные накладные расходы (overhead)</td>
			</tr>
			<tr>
					<td>gRPC, WebSocket</td>
					<td>L7</td>
					<td>gRPC – поверх HTTP/2, WebSocket – через Upgrade; нужен L7-прокси, понимающий эти протоколы</td>
			</tr>
	</tbody>
</table>
<hr>
<h2 id="сеть-в-kubernetes--полная-картина">Сеть в Kubernetes – полная картина</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Интернет
</span></span><span class="line"><span class="cl">    │
</span></span><span class="line"><span class="cl">    ▼
</span></span><span class="line"><span class="cl">┌──────────────────────┐
</span></span><span class="line"><span class="cl">│  Ingress Controller  │  L7: маршрутизация по Host/Path
</span></span><span class="line"><span class="cl">│  (nginx-ingress)     │  терминация TLS
</span></span><span class="line"><span class="cl">└──────────┬───────────┘
</span></span><span class="line"><span class="cl">           │
</span></span><span class="line"><span class="cl">    ┌──────▼──────┐
</span></span><span class="line"><span class="cl">    │   Service    │  L4: ClusterIP, стабильный виртуальный IP
</span></span><span class="line"><span class="cl">    │ (ClusterIP)  │  правила iptables/IPVS для распределения
</span></span><span class="line"><span class="cl">    └──────┬──────┘
</span></span><span class="line"><span class="cl">           │
</span></span><span class="line"><span class="cl">    ┌──────┼──────┐
</span></span><span class="line"><span class="cl">    │      │      │
</span></span><span class="line"><span class="cl">  ┌─▼─┐ ┌─▼─┐ ┌─▼─┐
</span></span><span class="line"><span class="cl">  │Pod│ │Pod│ │Pod│  Реальные контейнеры
</span></span><span class="line"><span class="cl">  │ 1 │ │ 2 │ │ 3 │  Каждый с уникальным IP
</span></span><span class="line"><span class="cl">  └───┘ └───┘ └───┘
</span></span></code></pre></div><hr>
<h2 id="k8s-service--4-типа">K8s Service – 4 типа</h2>
<h3 id="1-clusterip-по-умолчанию">1. ClusterIP (по умолчанию)</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Service</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">api</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">ClusterIP             </span><span class="w"> </span><span class="c"># виртуальный IP внутри кластера</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">selector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">api</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="m">8080</span><span class="w">               </span><span class="c"># порт Service</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">targetPort</span><span class="p">:</span><span class="w"> </span><span class="m">8080</span><span class="w">         </span><span class="c"># порт Pod</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">kubectl get svc api
</span></span><span class="line"><span class="cl"><span class="c1"># NAME  TYPE        CLUSTER-IP    PORT(S)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># api   ClusterIP   10.96.45.12   8080/TCP</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Доступен ТОЛЬКО внутри кластера:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># curl http://10.96.45.12:8080  (из pod-а)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># curl http://api:8080          (DNS резолвит в ClusterIP)</span>
</span></span></code></pre></div><p><strong>Как работает:</strong> kube-proxy создаёт правила iptables/IPVS, которые перенаправляют трафик с ClusterIP на реальные IP pod-ов. Выбор pod-а: в режиме iptables – случайный с равной вероятностью, в IPVS – round-robin по умолчанию.</p>
<h3 id="2-nodeport">2. NodePort</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">NodePort</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="m">8080</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">targetPort</span><span class="p">:</span><span class="w"> </span><span class="m">8080</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">nodePort</span><span class="p">:</span><span class="w"> </span><span class="m">30080</span><span class="w">          </span><span class="c"># 30000–32767</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Снаружи: curl http://&lt;любая-нода&gt;:30080
</span></span><span class="line"><span class="cl">  → DNAT → ClusterIP → Pod
</span></span></code></pre></div><h3 id="3-loadbalancer">3. LoadBalancer</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">LoadBalancer          </span><span class="w"> </span><span class="c"># облачный LB (AWS ELB, GCP LB)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="m">80</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">targetPort</span><span class="p">:</span><span class="w"> </span><span class="m">8080</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Снаружи: curl http://&lt;cloud-lb-ip&gt;:80
</span></span><span class="line"><span class="cl">  → Cloud LB → NodePort → ClusterIP → Pod
</span></span></code></pre></div><h3 id="4-externalname-dns-алиас">4. ExternalName (DNS-алиас)</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">ExternalName</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">externalName</span><span class="p">:</span><span class="w"> </span><span class="l">rds.amazonaws.com   </span><span class="w"> </span><span class="c"># CNAME → внешний сервис</span><span class="w">
</span></span></span></code></pre></div><hr>
<h2 id="ingress--маршрутизация-на-l7">Ingress – маршрутизация на L7</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">networking.k8s.io/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Ingress</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">app-ingress</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">annotations</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">nginx.ingress.kubernetes.io/ssl-redirect</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;true&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">ingressClassName</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">tls</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">hosts</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="l">api.example.com</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">secretName</span><span class="p">:</span><span class="w"> </span><span class="l">api-tls-cert       </span><span class="w"> </span><span class="c"># TLS-сертификат в Secret</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">rules</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">host</span><span class="p">:</span><span class="w"> </span><span class="l">api.example.com</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">http</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">paths</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- <span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">/api</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">pathType</span><span class="p">:</span><span class="w"> </span><span class="l">Prefix</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">backend</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">service</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">api-service</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">port</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                  </span><span class="nt">number</span><span class="p">:</span><span class="w"> </span><span class="m">8080</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- <span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">pathType</span><span class="p">:</span><span class="w"> </span><span class="l">Prefix</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">backend</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">service</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">frontend-service</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">port</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                  </span><span class="nt">number</span><span class="p">:</span><span class="w"> </span><span class="m">3000</span><span class="w">
</span></span></span></code></pre></div><h3 id="как-это-работает">Как это работает</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">1. DNS: api.example.com → IP Ingress Controller
</span></span><span class="line"><span class="cl">2. TLS: Ingress Controller терминирует TLS (расшифровывает)
</span></span><span class="line"><span class="cl">3. HTTP: Host=api.example.com, Path=/api
</span></span><span class="line"><span class="cl">4. Routing: Ingress Controller → Service api-service:8080 → Pod
</span></span></code></pre></div><blockquote>
<p><strong>⚠️ Статус на 2026:</strong> сообщество вывело контроллер <strong>ingress-nginx</strong> в отставку
(март 2026) – репозиторий заморожен, без релизов и security-патчей. Планировавшийся
преемник InGate не взлетел. Направление развития – <strong>Gateway API</strong> (эволюция Ingress).
При этом сам nginx как reverse proxy и Ingress API как таковой живы – на пенсию
отправлен именно этот один Kubernetes-контроллер. Для новых кластеров – Gateway API
или другой ingress-контроллер (Traefik, HAProxy, облачные). Концепции ниже (L4/L7,
Service, терминация TLS, upstream) переносятся на любой из них.</p>
</blockquote>
<hr>
<h2 id="nginx-как-обратный-прокси-reverse-proxy--конфигурация-для-devops">nginx как обратный прокси (reverse proxy) – конфигурация для DevOps</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nginx" data-lang="nginx"><span class="line"><span class="cl"><span class="c1"># /etc/nginx/conf.d/api.conf
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">upstream</span> <span class="s">api_backend</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kn">server</span> <span class="n">10.0.0.10</span><span class="p">:</span><span class="mi">8080</span> <span class="s">weight=3</span><span class="p">;</span>    <span class="c1"># 3 из 4 запросов
</span></span></span><span class="line"><span class="cl">    <span class="kn">server</span> <span class="n">10.0.0.11</span><span class="p">:</span><span class="mi">8080</span> <span class="s">weight=1</span><span class="p">;</span>    <span class="c1"># 1 из 4 запросов
</span></span></span><span class="line"><span class="cl">    <span class="kn">server</span> <span class="n">10.0.0.12</span><span class="p">:</span><span class="mi">8080</span> <span class="s">backup</span><span class="p">;</span>      <span class="c1"># только если первые два упали
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Health check (nginx plus) или passive:
</span></span></span><span class="line"><span class="cl">    <span class="c1"># server 10.0.0.10:8080 max_fails=3 fail_timeout=30s;
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">server</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kn">server_name</span> <span class="s">api.example.com</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kn">ssl_certificate</span>     <span class="s">/etc/letsencrypt/live/api.example.com/fullchain.pem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kn">ssl_certificate_key</span> <span class="s">/etc/letsencrypt/live/api.example.com/privkey.pem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kn">location</span> <span class="s">/api/</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_pass</span> <span class="s">http://api_backend</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_set_header</span> <span class="s">X-Real-IP</span> <span class="nv">$remote_addr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-For</span> <span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_read_timeout</span> <span class="s">60s</span><span class="p">;</span>    <span class="c1"># + остальные timeouts и security headers в проде
</span></span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kn">location</span> <span class="s">/</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kn">proxy_pass</span> <span class="s">http://frontend:3000</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><hr>
<h2 id="алгоритмы-балансировки">Алгоритмы балансировки</h2>
<table>
	<thead>
			<tr>
					<th>Алгоритм</th>
					<th>Как работает</th>
					<th>Когда использовать</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><strong>Round Robin</strong></td>
					<td>По очереди: 1, 2, 3, 1, 2, 3&hellip;</td>
					<td>По умолчанию, одинаковые серверы</td>
			</tr>
			<tr>
					<td><strong>Weighted RR</strong></td>
					<td>С весами: 1 получает 70%, 2 – 30%</td>
					<td>Серверы разной мощности</td>
			</tr>
			<tr>
					<td><strong>Least Connections</strong></td>
					<td>К серверу с наименьшим числом соединений</td>
					<td>Запросы разной длительности</td>
			</tr>
			<tr>
					<td><strong>IP Hash</strong></td>
					<td>hash(client_ip) → сервер</td>
					<td>Липкие сессии без cookie</td>
			</tr>
			<tr>
					<td><strong>Random</strong></td>
					<td>Случайный сервер</td>
					<td>Простейший, неплохое распределение</td>
			</tr>
			<tr>
					<td><strong>Consistent Hash</strong></td>
					<td>hash(key) → кольцо серверов</td>
					<td>Кеширование (минимум перебалансировки)</td>
			</tr>
	</tbody>
</table>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nginx" data-lang="nginx"><span class="line"><span class="cl"><span class="c1"># Метод балансировки задаётся ОДНОЙ директивой на upstream
</span></span></span><span class="line"><span class="cl"><span class="c1"># (по умолчанию – Round Robin). Раскомментируй НУЖНЫЙ –
</span></span></span><span class="line"><span class="cl"><span class="c1"># методы нельзя смешивать в одном upstream:
</span></span></span><span class="line"><span class="cl"><span class="k">upstream</span> <span class="s">backend</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># least_conn;          # к серверу с наименьшим числом активных соединений
</span></span></span><span class="line"><span class="cl">    <span class="c1"># ip_hash;             # закрепить клиента по его IP (sticky без cookie)
</span></span></span><span class="line"><span class="cl">    <span class="c1"># hash $request_uri consistent;   # consistent hashing (ketama) по ключу – удобно для кеширования
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kn">server</span> <span class="n">10.0.0.1</span><span class="p">:</span><span class="mi">8080</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kn">server</span> <span class="n">10.0.0.2</span><span class="p">:</span><span class="mi">8080</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><hr>
<h2 id="сервисная-сетка--следующий-уровень-обзор">Сервисная сетка – следующий уровень (обзор)</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Без mesh:              С mesh (Istio/Linkerd):
</span></span><span class="line"><span class="cl">Pod → Pod              Pod → Sidecar → Sidecar → Pod
</span></span><span class="line"><span class="cl">                           (Envoy)    (Envoy)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Что даёт sidecar:
</span></span><span class="line"><span class="cl">- mTLS между сервисами (автоматическое шифрование)
</span></span><span class="line"><span class="cl">- Retries, timeouts, circuit breaking
</span></span><span class="line"><span class="cl">- Traffic splitting (canary: 5% → новая версия)
</span></span><span class="line"><span class="cl">- Observability (метрики, traces) без изменения кода
</span></span></code></pre></div><blockquote>
<p><strong>20/80 для джуна и выше:</strong> знать, что сервисная сетка существует и зачем. Не нужно уметь настраивать Istio – это уже сеньорский уровень.</p>
</blockquote>
<hr>
<h2 id="диагностика-сети-в-kubernetes--чеклист">Диагностика сети в Kubernetes – чеклист</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 1. Pod → Pod (в одном namespace):</span>
</span></span><span class="line"><span class="cl">kubectl <span class="nb">exec</span> pod-a -- curl http://pod-b-ip:8080
</span></span><span class="line"><span class="cl"><span class="c1"># Работает? → сеть между pod-ами ОК</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. Pod → Service:</span>
</span></span><span class="line"><span class="cl">kubectl <span class="nb">exec</span> pod-a -- curl http://service-name:8080
</span></span><span class="line"><span class="cl"><span class="c1"># Не работает? → проблема с DNS или Service selector</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 3. DNS внутри pod-а:</span>
</span></span><span class="line"><span class="cl">kubectl <span class="nb">exec</span> pod-a -- nslookup service-name
</span></span><span class="line"><span class="cl"><span class="c1"># NXDOMAIN? → Service не существует или неправильный namespace</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Timeout? → CoreDNS не отвечает</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 4. Service selector совпадает с pod labels?</span>
</span></span><span class="line"><span class="cl">kubectl get svc api -o yaml <span class="p">|</span> grep -A3 selector
</span></span><span class="line"><span class="cl">kubectl get pods -l <span class="nv">app</span><span class="o">=</span>api
</span></span><span class="line"><span class="cl"><span class="c1"># Если pod-ов нет → Endpoints пустые → Service не знает, куда слать</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 5. Endpoints:</span>
</span></span><span class="line"><span class="cl">kubectl get endpoints api
</span></span><span class="line"><span class="cl"><span class="c1"># Если пустые → selector не матчит ни один pod</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 6. Ingress → Service:</span>
</span></span><span class="line"><span class="cl">kubectl describe ingress app-ingress
</span></span><span class="line"><span class="cl"><span class="c1"># Проверить: backend service существует? Порт правильный?</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Events: &#34;error obtaining endpoints&#34; → Service/Endpoints проблема</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 7. Извне → Ingress:</span>
</span></span><span class="line"><span class="cl">curl -v https://api.example.com
</span></span><span class="line"><span class="cl"><span class="c1"># Проверить: DNS → IP Ingress Controller? TLS-сертификат валидный?</span>
</span></span></code></pre></div><hr>
<h2 id="подвохи-для-собеса">Подвохи для собеса</h2>
<h3 id="подвох-1-чем-service-clusterip-отличается-от-ingress">Подвох 1: &quot;Чем Service (ClusterIP) отличается от Ingress?&quot;</h3>
<table>
	<thead>
			<tr>
					<th></th>
					<th>Service (ClusterIP)</th>
					<th>Ingress</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><strong>Уровень</strong></td>
					<td>L4 (TCP/UDP)</td>
					<td>L7 (HTTP/HTTPS)</td>
			</tr>
			<tr>
					<td><strong>Доступность</strong></td>
					<td>Только внутри кластера</td>
					<td>Снаружи кластера</td>
			</tr>
			<tr>
					<td><strong>Маршрутизация</strong></td>
					<td>По IP + порт</td>
					<td>По заголовку Host и URL path</td>
			</tr>
			<tr>
					<td><strong>TLS</strong></td>
					<td>Нет (или через pod)</td>
					<td>Да (терминация TLS)</td>
			</tr>
			<tr>
					<td><strong>Протоколы</strong></td>
					<td>Любой TCP/UDP</td>
					<td>HTTP/HTTPS/gRPC</td>
			</tr>
	</tbody>
</table>
<p><strong>На собесе, одной фразой:</strong> &quot;Ingress – это как виртуальный хост в nginx, а Service – как upstream.&quot;</p>
<hr>
<h3 id="подвох-2-как-pod-получает-ip-адрес">Подвох 2: &quot;Как pod получает IP-адрес?&quot;</h3>
<p><strong>Ответ через CNI:</strong></p>
<ol>
<li>Kubelet создаёт pod</li>
<li>Kubelet вызывает CNI-плагин (Calico, Cilium, Flannel)</li>
<li>CNI назначает IP из pod CIDR ноды (например, <code>10.244.1.0/24</code> для node-1)</li>
<li>CNI создаёт veth pair (виртуальный кабель): один конец в pod, другой – в хостовой сети</li>
<li>CNI настраивает маршрут: <code>10.244.1.15 → veth-pod-api</code></li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Pod CIDR ноды:</span>
</span></span><span class="line"><span class="cl">kubectl get node worker-1 -o <span class="nv">jsonpath</span><span class="o">=</span><span class="s1">&#39;{.spec.podCIDR}&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 10.244.1.0/24</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Pod IP:</span>
</span></span><span class="line"><span class="cl">kubectl get pod api-xxx -o <span class="nv">jsonpath</span><span class="o">=</span><span class="s1">&#39;{.status.podIP}&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 10.244.1.15</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># На ноде – veth pair:</span>
</span></span><span class="line"><span class="cl">ip link show <span class="p">|</span> grep veth
</span></span><span class="line"><span class="cl"><span class="c1"># vethc49c832@if3: &lt;BROADCAST,MULTICAST,UP&gt;</span>
</span></span></code></pre></div><p><strong>На собесе:</strong> &quot;Pod IP назначается CNI-плагином. Каждая нода получает свой pod CIDR (подсеть). CNI создаёт veth pair – виртуальный кабель между сетевым namespace pod-а и хостовой сетью. Между нодами трафик маршрутизируется через overlay (VXLAN в Flannel) или через BGP (в Calico).&quot;</p>
<hr>
<h3 id="подвох-3-почему-kube-proxy--не-proxy">Подвох 3: &quot;Почему kube-proxy – не proxy?&quot;</h3>
<p><strong>Ответ:</strong></p>
<p>Название вводит в заблуждение. kube-proxy НЕ проксирует трафик (в текущих версиях). Он <strong>программирует правила</strong> в iptables/IPVS:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># kube-proxy создаёт правила вроде:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Если dst = 10.96.45.12:8080 (ClusterIP)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># → DNAT к одному из: 10.244.1.15:8080, 10.244.2.8:8080, 10.244.3.22:8080</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Пакет идёт НАПРЯМУЮ от pod к pod, через iptables DNAT</span>
</span></span><span class="line"><span class="cl"><span class="c1"># kube-proxy не участвует в пути данных!</span>
</span></span></code></pre></div><p><strong>На собесе:</strong> &quot;kube-proxy – это агент на каждой ноде (не control plane), который синхронизирует Endpoints с правилами iptables/IPVS. Трафик идёт через iptables DNAT, не через процесс kube-proxy. Поэтому kube-proxy можно убить, и существующие соединения продолжат работать – пока не изменятся Endpoints.&quot;</p>
<hr>
<h2 id="код-челлендж">Код-челлендж</h2>
<p><strong>Финальный проект:</strong> нарисуй (текстом) полный путь HTTP-запроса от пользователя до pod-а в K8s:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Пользователь вводит: https://api.example.com/users
</span></span></code></pre></div><p>Опиши каждый шаг: DNS, TCP, TLS, Ingress, Service, Pod. Укажи, на каком уровне OSI/TCP-IP происходит каждый шаг.</p>
<details>
<summary>Решение</summary>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">1. DNS (L7 Application):
</span></span><span class="line"><span class="cl">   Браузер → DNS resolver → &#34;api.example.com&#34; = 34.56.78.90 (IP Ingress Controller)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2. TCP Handshake (L4 Transport):
</span></span><span class="line"><span class="cl">   Браузер → SYN → 34.56.78.90:443 → SYN-ACK → ACK
</span></span><span class="line"><span class="cl">   Соединение установлено
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">3. TLS Handshake (L5-6):
</span></span><span class="line"><span class="cl">   ClientHello → ServerHello + Certificate → Key Exchange → Finished
</span></span><span class="line"><span class="cl">   Зашифрованный канал
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">4. HTTP Request (L7):
</span></span><span class="line"><span class="cl">   GET /users HTTP/1.1
</span></span><span class="line"><span class="cl">   Host: api.example.com
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">5. Ingress Controller (nginx-ingress pod):
</span></span><span class="line"><span class="cl">   - Терминирует TLS (расшифровывает)
</span></span><span class="line"><span class="cl">   - Смотрит Host: api.example.com, Path: /users
</span></span><span class="line"><span class="cl">   - Находит правило: /users → Service &#34;api-service:8080&#34;
</span></span><span class="line"><span class="cl">   - Резолвит Service → Endpoints (реальные pod IP)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">6. Service / iptables (L4):
</span></span><span class="line"><span class="cl">   - Ingress Controller отправляет запрос на ClusterIP 10.96.45.12:8080
</span></span><span class="line"><span class="cl">   - iptables DNAT: 10.96.45.12 → 10.244.1.15 (pod IP, случайный выбор)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">7. Pod Network (L3):
</span></span><span class="line"><span class="cl">   - CNI маршрутизирует пакет к ноде, где живёт pod
</span></span><span class="line"><span class="cl">   - veth pair доставляет в сетевой namespace pod-а
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">8. Application (L7):
</span></span><span class="line"><span class="cl">   - Pod (container) получает: GET /users HTTP/1.1
</span></span><span class="line"><span class="cl">   - Обрабатывает → 200 OK + JSON
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">9. Обратный путь:
</span></span><span class="line"><span class="cl">   Pod → veth → CNI → iptables (reverse DNAT) → Ingress → TLS encrypt → TCP → клиент
</span></span></code></pre></div></details>
<hr>
<h2 id="итог-курса-что-ты-теперь-знаешь">Итог курса: что ты теперь знаешь</h2>
<table>
	<thead>
			<tr>
					<th>Ур.</th>
					<th>Навык</th>
					<th>Инструмент</th>
					<th>Для собеса</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>0</td>
					<td>TCP/IP модель, инкапсуляция</td>
					<td><code>ip</code>, <code>ping</code>, <code>traceroute</code></td>
					<td>&quot;Что происходит при curl&quot;</td>
			</tr>
			<tr>
					<td>1</td>
					<td>IP-адреса, CIDR, подсети</td>
					<td><code>ip addr</code>, подсчёт</td>
					<td>&quot;Сколько хостов в /24&quot;</td>
			</tr>
			<tr>
					<td>2</td>
					<td>DNS: иерархия, записи, диагностика</td>
					<td><code>dig</code>, <code>nslookup</code></td>
					<td>&quot;Почему не резолвится&quot;</td>
			</tr>
			<tr>
					<td>3</td>
					<td>TCP/UDP, порты, состояния</td>
					<td><code>ss</code>, <code>tcpdump</code>, <code>nc</code></td>
					<td>&quot;Connection refused vs timeout&quot;</td>
			</tr>
			<tr>
					<td>4</td>
					<td>HTTP, TLS, сертификаты</td>
					<td><code>curl -v</code>, <code>openssl</code></td>
					<td>&quot;Что такое 502&quot;</td>
			</tr>
			<tr>
					<td>5</td>
					<td>Firewall: iptables, NetworkPolicy</td>
					<td><code>iptables</code>, YAML</td>
					<td>&quot;Настрой NetworkPolicy&quot;</td>
			</tr>
			<tr>
					<td>6</td>
					<td>LB, Ingress, сети K8s</td>
					<td><code>kubectl</code>, nginx</td>
					<td>&quot;Путь запроса от user до pod&quot;</td>
			</tr>
	</tbody>
</table>
<h3 id="что-дальше">Что дальше</h3>
<ul>
<li><strong>Практика:</strong> настрой полный путь на своём кластере: Ingress → Service → Pod с NetworkPolicy</li>
<li><strong>Актуальное (2026):</strong> маршрутизация в K8s смещается с Ingress на <strong>Gateway API</strong> – после отставки ingress-nginx это направление по умолчанию для новых кластеров</li>
<li><strong>Глубже:</strong> Julia Evans Zines (wizardzines.com) – DNS, HTTP, сети в картинках</li>
<li><strong>Практикум:</strong> <a href="https://github.com/kelseyhightower/kubernetes-the-hard-way">Kubernetes the Hard Way</a> – настроить K8s вручную, понять каждый сетевой компонент</li>
<li><strong>Сертификация:</strong> CKA (Certified Kubernetes Administrator) – 30% вопросов про сети</li>
</ul>
]]></content:encoded>
    </item>
  </channel>
</rss>
