3086 lines
145 KiB
HTML
3086 lines
145 KiB
HTML
<!doctype html>
|
||
<html
|
||
lang="ru"
|
||
dir="ltr"
|
||
class="scroll-smooth"
|
||
data-default-appearance="dark"
|
||
data-auto-appearance="false"><head><script src="/livereload.js?mindelay=10&v=2&port=1313&path=livereload" data-no-instant defer></script>
|
||
<meta charset="utf-8">
|
||
|
||
<meta http-equiv="content-language" content="ru">
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||
<meta name="theme-color">
|
||
|
||
|
||
|
||
<title>Блог на Hugo в K3s: часть 2 - деплой в кластер · Олег Казанин</title>
|
||
<meta name="title" content="Блог на Hugo в K3s: часть 2 - деплой в кластер · Олег Казанин">
|
||
|
||
|
||
|
||
|
||
<meta name="description" content="NFS хранилище, Hugo Builder с webhook listener, Nginx с Prometheus exporter и автоматический SSL от Let's Encrypt. Полный деплой production окружения.">
|
||
|
||
|
||
<meta name="keywords" content="hugo,k3s,kubernetes,nfs,traefik,cert-manager,">
|
||
|
||
|
||
|
||
<link rel="canonical" href="http://localhost:1313/posts/blog-part-2-k8s-deployment/">
|
||
|
||
|
||
|
||
|
||
<meta name="author" content="Олег Казанин">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<link href="https://t.me/oa_msk" rel="me">
|
||
|
||
|
||
|
||
|
||
|
||
<link href="https://oakazanin.ru/" rel="me">
|
||
|
||
|
||
|
||
|
||
|
||
<link href="https://git.jn4.ru/astronit" rel="me">
|
||
|
||
|
||
|
||
|
||
|
||
<link href="https://obrtv.ru/a/chiefengineer" rel="me">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<meta property="og:url" content="http://localhost:1313/posts/blog-part-2-k8s-deployment/">
|
||
<meta property="og:site_name" content="Олег Казанин">
|
||
<meta property="og:title" content="Блог на Hugo в K3s: часть 2 - деплой в кластер">
|
||
<meta property="og:description" content="NFS хранилище, Hugo Builder с webhook listener, Nginx с Prometheus exporter и автоматический SSL от Let's Encrypt. Полный деплой production окружения.">
|
||
<meta property="og:locale" content="ru">
|
||
<meta property="og:type" content="article">
|
||
<meta property="article:section" content="posts">
|
||
<meta property="article:published_time" content="2026-01-08T00:00:00+00:00">
|
||
<meta property="article:modified_time" content="2026-01-08T00:00:00+00:00">
|
||
<meta property="article:tag" content="Hugo">
|
||
<meta property="article:tag" content="K3s">
|
||
<meta property="article:tag" content="Kubernetes">
|
||
<meta property="article:tag" content="Nfs">
|
||
<meta property="article:tag" content="Traefik">
|
||
<meta property="article:tag" content="Cert-Manager">
|
||
<meta property="og:image" content="http://localhost:1313/posts/blog-part-2-k8s-deployment/featured.png">
|
||
<meta property="og:see_also" content="http://localhost:1313/posts/blog-part-5-debugging/">
|
||
<meta property="og:see_also" content="http://localhost:1313/posts/blog-part-4-git-workflow/">
|
||
<meta property="og:see_also" content="http://localhost:1313/posts/blog-part-3-dev-environment/">
|
||
<meta property="og:see_also" content="http://localhost:1313/posts/blog-part-1-architecture/">
|
||
|
||
|
||
<meta name="twitter:card" content="summary_large_image">
|
||
<meta name="twitter:image" content="http://localhost:1313/posts/blog-part-2-k8s-deployment/featured.png">
|
||
<meta name="twitter:title" content="Блог на Hugo в K3s: часть 2 - деплой в кластер">
|
||
<meta name="twitter:description" content="NFS хранилище, Hugo Builder с webhook listener, Nginx с Prometheus exporter и автоматический SSL от Let's Encrypt. Полный деплой production окружения.">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<link
|
||
type="text/css"
|
||
rel="stylesheet"
|
||
href="/css/main.bundle.min.b5bc3f4587655153415b7825fd1716f97df9c99f87c23f81146f4dd4f9f49f04ad031e3b5f0ee5c0416707a1455ca2cfa8fc1f3a19ece1486b0126dcd310a63e.css"
|
||
integrity="sha512-tbw/RYdlUVNBW3gl/RcW+X35yZ+Hwj+BFG9N1Pn0nwStAx47Xw7lwEFnB6FFXKLPqPwfOhns4UhrASbc0xCmPg==">
|
||
|
||
|
||
|
||
<script
|
||
type="text/javascript"
|
||
src="/js/appearance.min.a0c4d367419d691bf95fc98ffcaf55ce81db3412c3dfbd6c4fbe968f56f77347f5a8512b0916a65a5f496dbec1ef0590dbadcf2fbd0de3c919e525f11c32d0e3.js"
|
||
integrity="sha512-oMTTZ0GdaRv5X8mP/K9VzoHbNBLD371sT76Wj1b3c0f1qFErCRamWl9Jbb7B7wWQ263PL70N48kZ5SXxHDLQ4w=="></script>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<script src="/lib/zoom/zoom.min.umd.a527109b68c082a70f3697716dd72a9d5aa8b545cf800cecbbc7399f2ca6f6e0ce3e431f2062b48bbfa47c9ea42822714060bef309be073f49b9c0e30d318d7b.js" integrity="sha512-pScQm2jAgqcPNpdxbdcqnVqotUXPgAzsu8c5nyym9uDOPkMfIGK0i7+kfJ6kKCJxQGC+8wm+Bz9JucDjDTGNew=="></script>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<script
|
||
defer
|
||
type="text/javascript"
|
||
id="script-bundle"
|
||
src="/js/main.bundle.min.858f7f82734cfae08d59fcf8d0eb186f01706a84e2f7d20d39edfd7bc8bed6166e02d5c65ecce1de82b1ac52d1e01d77bd1a82d19186fdae5fe6e12d867fcf68.js"
|
||
integrity="sha512-hY9/gnNM+uCNWfz40OsYbwFwaoTi99INOe39e8i+1hZuAtXGXszh3oKxrFLR4B13vRqC0ZGG/a5f5uEthn/PaA=="
|
||
data-copy="Копировать"
|
||
data-copied="Скопировано"></script>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<script type="module" src="/js/firebase.min.cad74e0625f72f359ec6d6fed579b87733749de70400e7614048050ed08832ee3f58983d5d139fb1ddc5f7f2f5047d45ed80ec923534a3660fc3a7965f936866.js" integrity="sha512-ytdOBiX3LzWextb+1Xm4dzN0necEAOdhQEgFDtCIMu4/WJg9XROfsd3F9/L1BH1F7YDskjU0o2YPw6eWX5NoZg=="></script>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<script id="firebase-config"
|
||
type="application/json"
|
||
data-views="views_posts/blog-part-2-k8s-deployment/index.md"
|
||
data-likes="likes_posts/blog-part-2-k8s-deployment/index.md">
|
||
{
|
||
"config": {
|
||
"apiKey": "AIzaSyBBfzADrGgnwTIyW67gfZSrAtkoybxvmdI",
|
||
"authDomain": "oakazanin-hugo-blowfish.firebaseapp.com",
|
||
"projectId": "oakazanin-hugo-blowfish",
|
||
"storageBucket": "oakazanin-hugo-blowfish.firebasestorage.app",
|
||
"messagingSenderId": "945151844512",
|
||
"appId": "1:945151844512:web:22602cc010f5b7e0cca9c5",
|
||
"measurementId": ""
|
||
}
|
||
}
|
||
</script>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||
<link rel="manifest" href="/site.webmanifest">
|
||
|
||
|
||
|
||
<script type="application/ld+json">
|
||
[{
|
||
"@context": "https://schema.org",
|
||
"@type": "Article",
|
||
"articleSection": "Posts",
|
||
"name": "Блог на Hugo в K3s: часть 2 - деплой в кластер",
|
||
"headline": "Блог на Hugo в K3s: часть 2 - деплой в кластер",
|
||
"description": "NFS хранилище, Hugo Builder с webhook listener, Nginx с Prometheus exporter и автоматический SSL от Let\u0027s Encrypt. Полный деплой production окружения.",
|
||
"inLanguage": "ru",
|
||
"url" : "http://localhost:1313/posts/blog-part-2-k8s-deployment/",
|
||
"author" : {
|
||
"@type": "Person",
|
||
"name": "Олег Казанин"
|
||
},
|
||
"copyrightYear": "2026",
|
||
"dateCreated": "2026-01-08T00:00:00\u002b00:00",
|
||
"datePublished": "2026-01-08T00:00:00\u002b00:00",
|
||
|
||
"dateModified": "2026-01-08T00:00:00\u002b00:00",
|
||
|
||
"keywords": ["hugo","k3s","kubernetes","nfs","traefik","cert-manager"],
|
||
|
||
"mainEntityOfPage": "true",
|
||
"wordCount": "1658"
|
||
}]
|
||
</script>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<script type="text/javascript">
|
||
(function(m,e,t,r,i,k,a){
|
||
m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
||
m[i].l=1*new Date();
|
||
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
|
||
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)
|
||
})(window, document,'script','https://mc.yandex.ru/metrika/tag.js?id=106929410', 'ym');
|
||
|
||
ym(106929410, 'init', {ssr:true, webvisor:true, clickmap:true, ecommerce:"dataLayer", referrer: document.referrer, url: location.href, accurateTrackBounce:true, trackLinks:true});
|
||
</script>
|
||
<noscript><div><img src="https://mc.yandex.ru/watch/106929410" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</head>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<body class="flex flex-col h-screen m-auto leading-7 max-w-7xl px-6 sm:px-14 md:px-24 lg:px-32 text-lg bg-neutral text-neutral-900 dark:bg-neutral-800 dark:text-neutral bf-scrollbar">
|
||
<div id="the-top" class="absolute flex self-center">
|
||
<a
|
||
class="px-3 py-1 text-sm -translate-y-8 rounded-b-lg bg-primary-200 focus:translate-y-0 dark:bg-neutral-600"
|
||
href="#main-content">
|
||
<span class="font-bold text-primary-600 pe-2 dark:text-primary-400">↓</span>
|
||
Перейти к основному содержимому
|
||
</a>
|
||
</div>
|
||
|
||
|
||
<div class="min-h-[148px]"></div>
|
||
<div class="fixed inset-x-0 z-100">
|
||
<div
|
||
id="menu-blur"
|
||
class="absolute opacity-0 inset-x-0 top-0 h-full single_hero_background nozoom backdrop-blur-2xl shadow-2xl bg-neutral/25 dark:bg-neutral-800/25"></div>
|
||
<div class="relative m-auto leading-7 max-w-7xl px-6 sm:px-14 md:px-24 lg:px-32">
|
||
<div class="main-menu flex items-center w-full gap-2 p-1 pl-0">
|
||
|
||
|
||
|
||
<div>
|
||
<a href="/" class="flex">
|
||
<span class="sr-only">Олег Казанин</span>
|
||
|
||
<img
|
||
src="/img/logo.png"
|
||
width="285"
|
||
height="175"
|
||
class="logo max-h-20 max-w-20 object-scale-down object-left nozoom"
|
||
alt="">
|
||
|
||
</a>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="flex items-center ms-auto">
|
||
<div class="hidden md:flex">
|
||
<nav class="flex items-center gap-x-5 h-12">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<button
|
||
id="search-button"
|
||
aria-label="Search"
|
||
class="text-base bf-icon-color-hover"
|
||
title="Поиск (/)">
|
||
<span class="relative block icon"><svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="search" class="svg-inline--fa fa-search fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>
|
||
</span>
|
||
</button>
|
||
|
||
|
||
|
||
<div class="flex items-center">
|
||
<button
|
||
id="appearance-switcher"
|
||
aria-label="Dark mode switcher"
|
||
type="button"
|
||
class="text-base bf-icon-color-hover">
|
||
<div class="flex items-center justify-center dark:hidden">
|
||
<span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M32 256c0-123.8 100.3-224 223.8-224c11.36 0 29.7 1.668 40.9 3.746c9.616 1.777 11.75 14.63 3.279 19.44C245 86.5 211.2 144.6 211.2 207.8c0 109.7 99.71 193 208.3 172.3c9.561-1.805 16.28 9.324 10.11 16.95C387.9 448.6 324.8 480 255.8 480C132.1 480 32 379.6 32 256z"/></svg>
|
||
</span>
|
||
</div>
|
||
<div class="items-center justify-center hidden dark:flex">
|
||
<span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 159.1c-53.02 0-95.1 42.98-95.1 95.1S202.1 351.1 256 351.1s95.1-42.98 95.1-95.1S309 159.1 256 159.1zM509.3 347L446.1 255.1l63.15-91.01c6.332-9.125 1.104-21.74-9.826-23.72l-109-19.7l-19.7-109c-1.975-10.93-14.59-16.16-23.72-9.824L256 65.89L164.1 2.736c-9.125-6.332-21.74-1.107-23.72 9.824L121.6 121.6L12.56 141.3C1.633 143.2-3.596 155.9 2.736 164.1L65.89 256l-63.15 91.01c-6.332 9.125-1.105 21.74 9.824 23.72l109 19.7l19.7 109c1.975 10.93 14.59 16.16 23.72 9.824L256 446.1l91.01 63.15c9.127 6.334 21.75 1.107 23.72-9.822l19.7-109l109-19.7C510.4 368.8 515.6 356.1 509.3 347zM256 383.1c-70.69 0-127.1-57.31-127.1-127.1c0-70.69 57.31-127.1 127.1-127.1s127.1 57.3 127.1 127.1C383.1 326.7 326.7 383.1 256 383.1z"/></svg>
|
||
</span>
|
||
</div>
|
||
</button>
|
||
</div>
|
||
|
||
</nav>
|
||
|
||
|
||
|
||
</div>
|
||
<div class="flex md:hidden">
|
||
<div class="flex items-center h-14 gap-4">
|
||
|
||
<button
|
||
id="search-button-mobile"
|
||
aria-label="Search"
|
||
class="flex items-center justify-center bf-icon-color-hover"
|
||
title="Поиск (/)">
|
||
<span class="relative block icon"><svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="search" class="svg-inline--fa fa-search fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>
|
||
</span>
|
||
</button>
|
||
|
||
|
||
|
||
<button
|
||
id="appearance-switcher-mobile"
|
||
type="button"
|
||
aria-label="Dark mode switcher"
|
||
class="flex items-center justify-center text-neutral-900 hover:text-primary-600 dark:text-neutral-200 dark:hover:text-primary-400">
|
||
<div class="dark:hidden">
|
||
<span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M32 256c0-123.8 100.3-224 223.8-224c11.36 0 29.7 1.668 40.9 3.746c9.616 1.777 11.75 14.63 3.279 19.44C245 86.5 211.2 144.6 211.2 207.8c0 109.7 99.71 193 208.3 172.3c9.561-1.805 16.28 9.324 10.11 16.95C387.9 448.6 324.8 480 255.8 480C132.1 480 32 379.6 32 256z"/></svg>
|
||
</span>
|
||
</div>
|
||
<div class="hidden dark:block">
|
||
<span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 159.1c-53.02 0-95.1 42.98-95.1 95.1S202.1 351.1 256 351.1s95.1-42.98 95.1-95.1S309 159.1 256 159.1zM509.3 347L446.1 255.1l63.15-91.01c6.332-9.125 1.104-21.74-9.826-23.72l-109-19.7l-19.7-109c-1.975-10.93-14.59-16.16-23.72-9.824L256 65.89L164.1 2.736c-9.125-6.332-21.74-1.107-23.72 9.824L121.6 121.6L12.56 141.3C1.633 143.2-3.596 155.9 2.736 164.1L65.89 256l-63.15 91.01c-6.332 9.125-1.105 21.74 9.824 23.72l109 19.7l19.7 109c1.975 10.93 14.59 16.16 23.72 9.824L256 446.1l91.01 63.15c9.127 6.334 21.75 1.107 23.72-9.822l19.7-109l109-19.7C510.4 368.8 515.6 356.1 509.3 347zM256 383.1c-70.69 0-127.1-57.31-127.1-127.1c0-70.69 57.31-127.1 127.1-127.1s127.1 57.3 127.1 127.1C383.1 326.7 326.7 383.1 256 383.1z"/></svg>
|
||
</span>
|
||
</div>
|
||
</button>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<script
|
||
type="text/javascript"
|
||
src="/js/background-blur.min.605b3b942818f0ab5a717ae446135ec46b8ee5a2ad12ae56fb90dc2a76ce30c388f9fec8bcc18db15bd47e3fa8a09d779fa12aa9c184cf614a315bc72c6c163d.js"
|
||
integrity="sha512-YFs7lCgY8KtacXrkRhNexGuO5aKtEq5W+5DcKnbOMMOI+f7IvMGNsVvUfj+ooJ13n6EqqcGEz2FKMVvHLGwWPQ=="
|
||
data-blur-id="menu-blur"></script>
|
||
|
||
|
||
<div class="relative flex flex-col grow">
|
||
<main id="main-content" class="grow">
|
||
|
||
|
||
<article>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div id="hero" class="h-[150px] md:h-[200px]"></div>
|
||
|
||
<div class="fixed inset-x-0 top-0 h-[800px] single_hero_background nozoom">
|
||
|
||
|
||
|
||
<img
|
||
id="background-image"
|
||
src="/posts/blog-part-2-k8s-deployment/featured_hu_9f1cc8edeee3b333.png"
|
||
role="presentation"
|
||
loading="eager"
|
||
decoding="async"
|
||
fetchpriority="high"
|
||
class="absolute inset-0 w-full h-full object-cover"
|
||
>
|
||
<div
|
||
class="absolute inset-0 bg-gradient-to-t from-neutral dark:from-neutral-800 to-transparent mix-blend-normal"></div>
|
||
<div
|
||
class="absolute inset-0 opacity-60 bg-gradient-to-t from-neutral dark:from-neutral-800 to-neutral-100 dark:to-neutral-800 mix-blend-normal"></div>
|
||
</div>
|
||
|
||
|
||
<div
|
||
id="background-blur"
|
||
class="fixed opacity-0 inset-x-0 top-0 h-full single_hero_background nozoom backdrop-blur-xl bg-neutral-100/75 dark:bg-neutral-800/60"></div>
|
||
|
||
|
||
<script
|
||
type="text/javascript"
|
||
src="/js/background-blur.min.605b3b942818f0ab5a717ae446135ec46b8ee5a2ad12ae56fb90dc2a76ce30c388f9fec8bcc18db15bd47e3fa8a09d779fa12aa9c184cf614a315bc72c6c163d.js"
|
||
integrity="sha512-YFs7lCgY8KtacXrkRhNexGuO5aKtEq5W+5DcKnbOMMOI+f7IvMGNsVvUfj+ooJ13n6EqqcGEz2FKMVvHLGwWPQ=="
|
||
data-blur-id="background-blur"
|
||
data-image-id="background-image"
|
||
data-image-url="/posts/blog-part-2-k8s-deployment/featured_hu_9f1cc8edeee3b333.png"></script>
|
||
|
||
|
||
|
||
|
||
|
||
<header id="single_header" class="mt-5 max-w-prose">
|
||
|
||
<h1 class="mt-0 text-4xl font-extrabold text-neutral-900 dark:text-neutral">
|
||
Блог на Hugo в K3s: часть 2 - деплой в кластер
|
||
</h1>
|
||
<div class="mt-1 mb-6 text-base text-neutral-500 dark:text-neutral-400 print:hidden">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div class="flex flex-row flex-wrap items-center">
|
||
|
||
|
||
<time datetime="2026-01-08T00:00:00+00:00">8 января 2026</time><span class="px-2 text-primary-500">·</span><span title="Время чтения">8 минут</span><span class="px-2 text-primary-500">·</span><span>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<span
|
||
id="views_posts/blog-part-2-k8s-deployment/index.md"
|
||
class="animate-pulse inline-block text-transparent max-h-3 rounded-full -mt-[2px] align-middle bg-neutral-300 dark:bg-neutral-400"
|
||
title="views"
|
||
>loading</span
|
||
>
|
||
<span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||
<path fill="currentColor" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></span>
|
||
</span>
|
||
<span class="px-2 text-primary-500">·</span><span>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<span
|
||
id="likes_posts/blog-part-2-k8s-deployment/index.md"
|
||
class="animate-pulse inline-block text-transparent max-h-3 rounded-full -mt-[2px] align-middle bg-neutral-300 dark:bg-neutral-400"
|
||
title="likes"
|
||
>loading</span
|
||
>
|
||
<span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||
<path fill="currentColor" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></svg></span></span>
|
||
</span>
|
||
<span class="px-2 text-primary-500">·</span><span>
|
||
<button
|
||
id="button_likes"
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
<span id="button_likes_heart" class="inline-block align-text-bottom hidden"
|
||
><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||
<path fill="currentColor" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></svg></span>
|
||
</span>
|
||
<span id="button_likes_emtpty_heart" class="inline-block align-text-bottom"
|
||
><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||
<path fill="currentColor" d="M244 84L255.1 96L267.1 84.02C300.6 51.37 347 36.51 392.6 44.1C461.5 55.58 512 115.2 512 185.1V190.9C512 232.4 494.8 272.1 464.4 300.4L283.7 469.1C276.2 476.1 266.3 480 256 480C245.7 480 235.8 476.1 228.3 469.1L47.59 300.4C17.23 272.1 0 232.4 0 190.9V185.1C0 115.2 50.52 55.58 119.4 44.1C164.1 36.51 211.4 51.37 244 84C243.1 84 244 84.01 244 84L244 84zM255.1 163.9L210.1 117.1C188.4 96.28 157.6 86.4 127.3 91.44C81.55 99.07 48 138.7 48 185.1V190.9C48 219.1 59.71 246.1 80.34 265.3L256 429.3L431.7 265.3C452.3 246.1 464 219.1 464 190.9V185.1C464 138.7 430.4 99.07 384.7 91.44C354.4 86.4 323.6 96.28 301.9 117.1L255.1 163.9z"/></svg></span></span
|
||
>
|
||
<span id="button_likes_text"> Like</span>
|
||
</button>
|
||
</span>
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
<div class="flex flex-row flex-wrap items-center">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/categories/infrastructure/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Infrastructure
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/hugo/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Hugo
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/k3s/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
K3s
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/kubernetes/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Kubernetes
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/nfs/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Nfs
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/traefik/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Traefik
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/cert-manager/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Cert-Manager
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div class="flex author">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<img
|
||
class="!mt-0 !mb-0 h-24 w-24 rounded-full me-4"
|
||
width="96"
|
||
height="96"
|
||
alt="Олег Казанин"
|
||
src="/img/profile_hu_9cb3a1ec5563cd7f.png"
|
||
data-zoom-src="/img/profile_hu_1a9fbd8177a94ed5.png">
|
||
|
||
|
||
<div class="place-self-center">
|
||
|
||
<div class="text-[0.6rem] uppercase leading-3 text-neutral-500 dark:text-neutral-400">
|
||
Автор
|
||
</div>
|
||
<div class="font-semibold leading-6 text-neutral-800 dark:text-neutral-300">
|
||
Олег Казанин
|
||
</div>
|
||
|
||
|
||
<div class="text-sm text-neutral-700 dark:text-neutral-400">Строю полезную инфраструктуру на Open Source стеке. Документирую грабли, чтобы вы на них не наступали.</div>
|
||
|
||
<div class="text-2xl sm:text-lg">
|
||
<div class="flex flex-wrap text-neutral-400 dark:text-neutral-500">
|
||
|
||
|
||
<a
|
||
class="px-1 hover:text-primary-700 dark:hover:text-primary-400"
|
||
href="mailto:oakazanin@ya.ru"
|
||
target="_blank"
|
||
aria-label="Email"
|
||
title="Email"
|
||
rel="me noopener noreferrer"
|
||
><span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M207.8 20.73c-93.45 18.32-168.7 93.66-187 187.1c-27.64 140.9 68.65 266.2 199.1 285.1c19.01 2.888 36.17-12.26 36.17-31.49l.0001-.6631c0-15.74-11.44-28.88-26.84-31.24c-84.35-12.98-149.2-86.13-149.2-174.2c0-102.9 88.61-185.5 193.4-175.4c91.54 8.869 158.6 91.25 158.6 183.2l0 16.16c0 22.09-17.94 40.05-40 40.05s-40.01-17.96-40.01-40.05v-120.1c0-8.847-7.161-16.02-16.01-16.02l-31.98 .0036c-7.299 0-13.2 4.992-15.12 11.68c-24.85-12.15-54.24-16.38-86.06-5.106c-38.75 13.73-68.12 48.91-73.72 89.64c-9.483 69.01 43.81 128 110.9 128c26.44 0 50.43-9.544 69.59-24.88c24 31.3 65.23 48.69 109.4 37.49C465.2 369.3 496 324.1 495.1 277.2V256.3C495.1 107.1 361.2-9.332 207.8 20.73zM239.1 304.3c-26.47 0-48-21.56-48-48.05s21.53-48.05 48-48.05s48 21.56 48 48.05S266.5 304.3 239.1 304.3z"/></svg>
|
||
</span></span></a
|
||
>
|
||
|
||
|
||
|
||
<a
|
||
class="px-1 hover:text-primary-700 dark:hover:text-primary-400"
|
||
href="https://t.me/oa_msk"
|
||
target="_blank"
|
||
aria-label="Telegram"
|
||
title="Telegram"
|
||
rel="me noopener noreferrer"
|
||
><span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><path fill="currentColor" d="M248,8C111.033,8,0,119.033,0,256S111.033,504,248,504,496,392.967,496,256,384.967,8,248,8ZM362.952,176.66c-3.732,39.215-19.881,134.378-28.1,178.3-3.476,18.584-10.322,24.816-16.948,25.425-14.4,1.326-25.338-9.517-39.287-18.661-21.827-14.308-34.158-23.215-55.346-37.177-24.485-16.135-8.612-25,5.342-39.5,3.652-3.793,67.107-61.51,68.335-66.746.153-.655.3-3.1-1.154-4.384s-3.59-.849-5.135-.5q-3.283.746-104.608,69.142-14.845,10.194-26.894,9.934c-8.855-.191-25.888-5.006-38.551-9.123-15.531-5.048-27.875-7.717-26.8-16.291q.84-6.7,18.45-13.7,108.446-47.248,144.628-62.3c68.872-28.647,83.183-33.623,92.511-33.789,2.052-.034,6.639.474,9.61,2.885a10.452,10.452,0,0,1,3.53,6.716A43.765,43.765,0,0,1,362.952,176.66Z"/></svg>
|
||
</span></span></a
|
||
>
|
||
|
||
|
||
|
||
<a
|
||
class="px-1 hover:text-primary-700 dark:hover:text-primary-400"
|
||
href="https://oakazanin.ru/"
|
||
target="_blank"
|
||
aria-label="Link"
|
||
title="Link"
|
||
rel="me noopener noreferrer"
|
||
><span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M172.5 131.1C228.1 75.51 320.5 75.51 376.1 131.1C426.1 181.1 433.5 260.8 392.4 318.3L391.3 319.9C381 334.2 361 337.6 346.7 327.3C332.3 317 328.9 297 339.2 282.7L340.3 281.1C363.2 249 359.6 205.1 331.7 177.2C300.3 145.8 249.2 145.8 217.7 177.2L105.5 289.5C73.99 320.1 73.99 372 105.5 403.5C133.3 431.4 177.3 435 209.3 412.1L210.9 410.1C225.3 400.7 245.3 404 255.5 418.4C265.8 432.8 262.5 452.8 248.1 463.1L246.5 464.2C188.1 505.3 110.2 498.7 60.21 448.8C3.741 392.3 3.741 300.7 60.21 244.3L172.5 131.1zM467.5 380C411 436.5 319.5 436.5 263 380C213 330 206.5 251.2 247.6 193.7L248.7 192.1C258.1 177.8 278.1 174.4 293.3 184.7C307.7 194.1 311.1 214.1 300.8 229.3L299.7 230.9C276.8 262.1 280.4 306.9 308.3 334.8C339.7 366.2 390.8 366.2 422.3 334.8L534.5 222.5C566 191 566 139.1 534.5 108.5C506.7 80.63 462.7 76.99 430.7 99.9L429.1 101C414.7 111.3 394.7 107.1 384.5 93.58C374.2 79.2 377.5 59.21 391.9 48.94L393.5 47.82C451 6.731 529.8 13.25 579.8 63.24C636.3 119.7 636.3 211.3 579.8 267.7L467.5 380z"/></svg>
|
||
</span></span></a
|
||
>
|
||
|
||
|
||
|
||
<a
|
||
class="px-1 hover:text-primary-700 dark:hover:text-primary-400"
|
||
href="https://git.jn4.ru/astronit"
|
||
target="_blank"
|
||
aria-label="Gitea"
|
||
title="Gitea"
|
||
rel="me noopener noreferrer"
|
||
><span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="5.67 143.05 628.65 387.55"><path fill="currentColor" d="M115.912 143.075c-6.462 0-13.762.525-22.012 2.325-8.7 1.8-33.5 7.4-53.8 26.9C-4.9 212.4 6.6 276.2 8 285.8c1.7 11.7 6.9 44.2 31.7 72.5 45.8 56.1 144.4 54.8 144.4 54.8s12.1 28.9 30.6 55.5c25 33.1 50.7 58.9 75.7 62 63 0 188.9-.1 188.9-.1s12 .1 28.3-10.3c14-8.5 26.5-23.4 26.5-23.4S547 483 565 451.5c5.5-9.7 10.1-19.1 14.1-28 0 0 55.2-117.1 55.2-231.1-1.1-34.5-9.6-40.6-11.6-42.6-4.1-4.1-9.6-4-9.6-4s-117.2 6.6-177.9 8c-13.267.3-26.433.597-39.5.697l.1 117.002s57.4 24.202 83.1 40.102c3.7 2.3 10.2 6.798 12.9 14.398 2.1 6.1 2 13.101-1 19.301l-61 126.9c-6.2 12.7-21.4 18.1-33.9 12l-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5 21.2-17.9 33.8-11.8a5290.322 5290.322 0 0 0 27 12.954c0-36.449-.1-109.053-.1-109.053-29 .4-89.2-2.201-89.2-2.201s-141.4-7.1-156.8-8.5c-4.9-.3-10.525-.825-16.988-.825zm12.188 48.026s7.1 59.399 15.7 94.199c7.2 29.2 24.8 77.7 24.8 77.7s-26.1-3.1-43-9.1c-25.9-8.5-36.9-18.7-36.9-18.7S69.6 321.8 60 295.4c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5 38.5-30c13.8-3.7 31-3.1 31-3.1z"/><path fill="currentColor" d="M326.8 380.1c-8.2.1-15.4 5.8-17.3 13.8-1.9 8 2 16.3 9.1 20 7.7 4 17.5 1.8 22.7-5.4 5.1-7.1 4.3-16.9-1.8-23.1l24-49.1c1.5.1 3.7.2 6.2-.5 4.1-.9 7.1-3.6 7.1-3.6 4.2 1.8 8.6 3.8 13.2 6.1 4.8 2.4 9.3 4.9 13.4 7.3.9.5 1.8 1.1 2.8 1.9 1.6 1.3 3.4 3.1 4.7 5.5 1.9 5.5-1.9 14.9-1.9 14.9-2.3 7.6-18.4 40.6-18.4 40.6-8.1-.2-15.3 5-17.7 12.5-2.6 8.1 1.1 17.3 8.9 21.3 7.8 4 17.4 1.7 22.5-5.3 5-6.8 4.6-16.3-1.1-22.6 1.9-3.7 3.7-7.4 5.6-11.3 5-10.4 13.5-30.4 13.5-30.4.9-1.7 5.7-10.3 2.7-21.3-2.5-11.4-12.6-16.7-12.6-16.7-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3 4.7-9.7 9.4-19.3 14.1-29-4.1-2-8.1-4-12.2-6.1-4.8 9.8-9.7 19.7-14.5 29.5-6.7-.1-12.9 3.5-16.1 9.4-3.4 6.3-2.7 14.1 1.9 19.8l-24.6 50.4z"/></svg></span></span></a
|
||
>
|
||
|
||
|
||
|
||
<a
|
||
class="px-1 hover:text-primary-700 dark:hover:text-primary-400"
|
||
href="https://obrtv.ru/a/chiefengineer"
|
||
target="_blank"
|
||
aria-label="Peertube"
|
||
title="Peertube"
|
||
rel="me noopener noreferrer"
|
||
><span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 365 486.53"><path fill="currentColor" d="M0,243.26V0l182.5,121.63L0,243.26Z"/><path fill="currentColor" d="M0,486.53v-243.26l182.5,121.63L0,486.53Z"/><path fill="currentColor" d="M182.5,364.9V121.63l182.5,121.63-182.5,121.63Z"/></svg></span></span></a
|
||
>
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div class="mb-5"></div>
|
||
|
||
|
||
|
||
</header>
|
||
|
||
|
||
<section class="flex flex-col max-w-full mt-0 prose dark:prose-invert lg:flex-row">
|
||
|
||
|
||
|
||
|
||
|
||
<div class="order-first lg:ms-auto px-0 lg:order-last lg:ps-8 lg:max-w-2xs">
|
||
<div class="toc ps-5 print:hidden lg:sticky lg:top-[140px]">
|
||
<details
|
||
open
|
||
id="TOCView"
|
||
class="toc-right mt-0 overflow-y-auto overscroll-contain bf-scrollbar rounded-lg -ms-5 ps-5 pe-2 hidden lg:block">
|
||
<summary
|
||
class="block py-1 text-lg font-semibold cursor-pointer bg-neutral-100 text-neutral-800 -ms-5 ps-5 dark:bg-neutral-700 dark:text-neutral-100 lg:hidden">
|
||
Оглавление
|
||
</summary>
|
||
<div
|
||
class="min-w-[220px] py-2 border-dotted border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||
<nav id="TableOfContents">
|
||
<ul>
|
||
<li><a href="#архитектура-деплоя">Архитектура деплоя</a></li>
|
||
<li><a href="#шаг-1-nfs-хранилище">Шаг 1: NFS хранилище</a>
|
||
<ul>
|
||
<li><a href="#создаём-директории-на-nas">Создаём директории на NAS</a></li>
|
||
<li><a href="#настраиваем-nfs-через-omv-web-ui">Настраиваем NFS через OMV Web UI</a></li>
|
||
<li><a href="#проверяем-экспорт">Проверяем экспорт</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#шаг-2-persistentvolumes-в-k3s">Шаг 2: PersistentVolumes в K3s</a></li>
|
||
<li><a href="#шаг-3-hugo-builder">Шаг 3: Hugo Builder</a>
|
||
<ul>
|
||
<li><a href="#зачем-нужен-hugo-builder">Зачем нужен Hugo Builder?</a></li>
|
||
<li><a href="#dockerfile">Dockerfile</a></li>
|
||
<li><a href="#buildsh---скрипт-сборки-hugo">build.sh - скрипт сборки Hugo</a></li>
|
||
<li><a href="#webhook-listenersh---слушатель-webhook">webhook-listener.sh - слушатель webhook</a></li>
|
||
<li><a href="#сборка-и-деплой-образа">Сборка и деплой образа</a></li>
|
||
<li><a href="#deployment-и-service">Deployment и Service</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#шаг-4-nginx-с-prometheus-exporter">Шаг 4: Nginx с Prometheus exporter</a></li>
|
||
<li><a href="#шаг-5-ssl-сертификаты">Шаг 5: SSL сертификаты</a></li>
|
||
<li><a href="#шаг-6-ingressroute-через-traefik">Шаг 6: IngressRoute через Traefik</a></li>
|
||
<li><a href="#шаг-7-webhook-в-gitea">Шаг 7: Webhook в Gitea</a></li>
|
||
<li><a href="#проверка-работы">Проверка работы</a></li>
|
||
<li><a href="#что-дальше">Что дальше</a></li>
|
||
</ul>
|
||
</nav>
|
||
</div>
|
||
</details>
|
||
<details class="toc-inside mt-0 overflow-hidden rounded-lg -ms-5 ps-5 lg:hidden">
|
||
<summary
|
||
class="py-1 text-lg font-semibold cursor-pointer bg-neutral-100 text-neutral-800 -ms-5 ps-5 dark:bg-neutral-700 dark:text-neutral-100 lg:hidden">
|
||
Оглавление
|
||
</summary>
|
||
<div
|
||
class="py-2 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||
<nav id="TableOfContents">
|
||
<ul>
|
||
<li><a href="#архитектура-деплоя">Архитектура деплоя</a></li>
|
||
<li><a href="#шаг-1-nfs-хранилище">Шаг 1: NFS хранилище</a>
|
||
<ul>
|
||
<li><a href="#создаём-директории-на-nas">Создаём директории на NAS</a></li>
|
||
<li><a href="#настраиваем-nfs-через-omv-web-ui">Настраиваем NFS через OMV Web UI</a></li>
|
||
<li><a href="#проверяем-экспорт">Проверяем экспорт</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#шаг-2-persistentvolumes-в-k3s">Шаг 2: PersistentVolumes в K3s</a></li>
|
||
<li><a href="#шаг-3-hugo-builder">Шаг 3: Hugo Builder</a>
|
||
<ul>
|
||
<li><a href="#зачем-нужен-hugo-builder">Зачем нужен Hugo Builder?</a></li>
|
||
<li><a href="#dockerfile">Dockerfile</a></li>
|
||
<li><a href="#buildsh---скрипт-сборки-hugo">build.sh - скрипт сборки Hugo</a></li>
|
||
<li><a href="#webhook-listenersh---слушатель-webhook">webhook-listener.sh - слушатель webhook</a></li>
|
||
<li><a href="#сборка-и-деплой-образа">Сборка и деплой образа</a></li>
|
||
<li><a href="#deployment-и-service">Deployment и Service</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#шаг-4-nginx-с-prometheus-exporter">Шаг 4: Nginx с Prometheus exporter</a></li>
|
||
<li><a href="#шаг-5-ssl-сертификаты">Шаг 5: SSL сертификаты</a></li>
|
||
<li><a href="#шаг-6-ingressroute-через-traefik">Шаг 6: IngressRoute через Traefik</a></li>
|
||
<li><a href="#шаг-7-webhook-в-gitea">Шаг 7: Webhook в Gitea</a></li>
|
||
<li><a href="#проверка-работы">Проверка работы</a></li>
|
||
<li><a href="#что-дальше">Что дальше</a></li>
|
||
</ul>
|
||
</nav>
|
||
</div>
|
||
</details>
|
||
|
||
|
||
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="min-w-0 min-h-0 max-w-fit">
|
||
|
||
<details
|
||
class="mt-2 mb-5 overflow-hidden rounded-lg ms-0 ps-5"
|
||
open>
|
||
|
||
<summary
|
||
class="py-1 text-lg font-semibold cursor-pointer bg-primary-200 text-neutral-800 -ms-5 ps-5 dark:bg-primary-800 dark:text-neutral-100">
|
||
Блог на Hugo в K3s -
|
||
Эта статья — часть серии.
|
||
</summary>
|
||
|
||
|
||
|
||
<div
|
||
class="py-1 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||
<a href="/posts/blog-part-1-architecture/">
|
||
Часть 1:
|
||
Блог на Hugo в K3s: часть 1 - архитектура и первый запуск
|
||
</a>
|
||
</div>
|
||
|
||
|
||
|
||
<div
|
||
class="py-1 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||
Часть 2:
|
||
Ты уже здесь
|
||
</div>
|
||
|
||
|
||
|
||
<div
|
||
class="py-1 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||
<a href="/posts/blog-part-3-dev-environment/">
|
||
Часть 3:
|
||
Блог на Hugo в K3s: часть 3 - development окружение
|
||
</a>
|
||
</div>
|
||
|
||
|
||
|
||
<div
|
||
class="py-1 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||
<a href="/posts/blog-part-4-git-workflow/">
|
||
Часть 4:
|
||
Блог на Hugo в K3s: часть 4 - выбор Git workflow
|
||
</a>
|
||
</div>
|
||
|
||
|
||
|
||
<div
|
||
class="py-1 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||
<a href="/posts/blog-part-5-debugging/">
|
||
Часть 5:
|
||
Блог на Hugo в K3s: часть 5 - что делать когда всё внезапно сломалось
|
||
</a>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
</details>
|
||
|
||
|
||
<div class="article-content max-w-prose mb-20">
|
||
<p>В первой части мы запустили Hugo локально. Сайт работает пока открыт терминал. Закрыл терминал - сайт умер.</p>
|
||
<p>Пора переносить это в K3s.</p>
|
||
<hr>
|
||
|
||
<h2 class="relative group">Архитектура деплоя
|
||
<div id="архитектура-деплоя" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d0%b0%d1%80%d1%85%d0%b8%d1%82%d0%b5%d0%ba%d1%82%d1%83%d1%80%d0%b0-%d0%b4%d0%b5%d0%bf%d0%bb%d0%be%d1%8f" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h2>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Git Push
|
||
</span></span><span class="line"><span class="cl"> ↓
|
||
</span></span><span class="line"><span class="cl">Gitea (внутренний)
|
||
</span></span><span class="line"><span class="cl"> ↓ webhook POST
|
||
</span></span><span class="line"><span class="cl">Hugo Builder
|
||
</span></span><span class="line"><span class="cl"> ├→ git clone + submodule
|
||
</span></span><span class="line"><span class="cl"> ├→ hugo --minify
|
||
</span></span><span class="line"><span class="cl"> └→ output → NFS
|
||
</span></span><span class="line"><span class="cl"> ↓
|
||
</span></span><span class="line"><span class="cl"> /export/blog-public/
|
||
</span></span><span class="line"><span class="cl"> ↓
|
||
</span></span><span class="line"><span class="cl"> Nginx (x2 реплики)
|
||
</span></span><span class="line"><span class="cl"> ↓
|
||
</span></span><span class="line"><span class="cl"> Traefik Ingress
|
||
</span></span><span class="line"><span class="cl"> ↓
|
||
</span></span><span class="line"><span class="cl"> your-blog.ru (SSL)</span></span></code></pre></div></div>
|
||
<p>Пять компонентов:</p>
|
||
<ol>
|
||
<li><strong>NFS</strong> - хранилище для статики (OpenMediaVault)</li>
|
||
<li><strong>Hugo Builder</strong> - пересобирает сайт при каждом пуше</li>
|
||
<li><strong>Nginx</strong> - раздаёт статику с NFS</li>
|
||
<li><strong>cert-manager</strong> - автоматический SSL от Let’s Encrypt</li>
|
||
<li><strong>Traefik IngressRoute</strong> - маршрутизация с SSL терминацией</li>
|
||
</ol>
|
||
<hr>
|
||
|
||
<h2 class="relative group">Шаг 1: NFS хранилище
|
||
<div id="шаг-1-nfs-хранилище" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d1%88%d0%b0%d0%b3-1-nfs-%d1%85%d1%80%d0%b0%d0%bd%d0%b8%d0%bb%d0%b8%d1%89%d0%b5" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h2>
|
||
<p>Hugo собирает статику в HTML/CSS/JS файлы. Nginx раздаёт эти файлы. Значит нужно общее хранилище куда Hugo пишет, а Nginx читает.</p>
|
||
<p>NFS - самый простой вариант для homelab. У меня OpenMediaVault на отдельной машине.</p>
|
||
|
||
<h3 class="relative group">Создаём директории на NAS
|
||
<div id="создаём-директории-на-nas" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d1%91%d0%bc-%d0%b4%d0%b8%d1%80%d0%b5%d0%ba%d1%82%d0%be%d1%80%d0%b8%d0%b8-%d0%bd%d0%b0-nas" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h3>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Подключаемся к NAS (SSH на нестандартном порту для безопасности)</span>
|
||
</span></span><span class="line"><span class="cl">ssh -p <span class="m">33322</span> nasadmin@192.168.11.30
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Создаём папки для production и development окружений</span>
|
||
</span></span><span class="line"><span class="cl">sudo mkdir -p /srv/storage/blog/blog-public
|
||
</span></span><span class="line"><span class="cl">sudo mkdir -p /srv/storage/blog/blog-public-dev
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Выдаём права на запись (контейнеры пишут от root)</span>
|
||
</span></span><span class="line"><span class="cl">sudo chmod -R <span class="m">775</span> /srv/storage/blog/</span></span></code></pre></div></div>
|
||
<p><strong>Почему SSH на порту 33322?</strong> Стандартный порт 22 - первая цель сканеров и ботов. Нестандартный порт снижает шум в логах и количество brute-force попыток до нуля. Безопасность через скрытность работает для домашних серверов.</p>
|
||
|
||
<h3 class="relative group">Настраиваем NFS через OMV Web UI
|
||
<div id="настраиваем-nfs-через-omv-web-ui" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d0%bd%d0%b0%d1%81%d1%82%d1%80%d0%b0%d0%b8%d0%b2%d0%b0%d0%b5%d0%bc-nfs-%d1%87%d0%b5%d1%80%d0%b5%d0%b7-omv-web-ui" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h3>
|
||
<p>Storage → Shared Folders → Create:</p>
|
||
<ul>
|
||
<li>Name: <code>blog-public</code></li>
|
||
<li>Device: основной диск</li>
|
||
<li>Path: <code>/blog/blog-public</code></li>
|
||
</ul>
|
||
<p>Services → NFS → Shares → Create:</p>
|
||
<ul>
|
||
<li>Shared folder: <code>blog-public</code></li>
|
||
<li>Client: <code>192.168.11.0/24</code></li>
|
||
<li>Privilege: Read/Write</li>
|
||
<li>Extra options: <code>rw,sync,no_subtree_check,no_root_squash</code></li>
|
||
</ul>
|
||
<p>То же для <code>blog-public-dev</code>.</p>
|
||
<p><strong>Критично:</strong> <code>no_root_squash</code> - без этого контейнеры не смогут записывать файлы (они пишут от root внутри контейнера).</p>
|
||
|
||
<h3 class="relative group">Проверяем экспорт
|
||
<div id="проверяем-экспорт" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d0%bf%d1%80%d0%be%d0%b2%d0%b5%d1%80%d1%8f%d0%b5%d0%bc-%d1%8d%d0%ba%d1%81%d0%bf%d0%be%d1%80%d1%82" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h3>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Заходим на NAS</span>
|
||
</span></span><span class="line"><span class="cl">ssh -p <span class="m">33322</span> nasadmin@192.168.11.30
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Проверяем что NFS экспортирует наши шары</span>
|
||
</span></span><span class="line"><span class="cl">sudo exportfs -v <span class="p">|</span> grep blog
|
||
</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"># /export/blog-public 192.168.11.0/24(rw,sync,no_root_squash,...)</span>
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># /export/blog-public-dev 192.168.11.0/24(rw,sync,no_root_squash,...)</span></span></span></code></pre></div></div>
|
||
<hr>
|
||
|
||
<h2 class="relative group">Шаг 2: PersistentVolumes в K3s
|
||
<div id="шаг-2-persistentvolumes-в-k3s" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d1%88%d0%b0%d0%b3-2-persistentvolumes-%d0%b2-k3s" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h2>
|
||
<p>K3s нужно сказать где лежат NFS шары. Создаём манифест с PersistentVolume ресурсами.</p>
|
||
<p><strong>Файл:</strong> <code>02-pv.yaml</code></p>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
|
||
</span></span></span><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">PersistentVolume</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">blog-public-pv</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">capacity</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">storage</span><span class="p">:</span><span class="w"> </span><span class="l">5Gi</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">accessModes</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">ReadWriteMany</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">nfs</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">server</span><span class="p">:</span><span class="w"> </span><span class="m">192.168.11.30</span><span class="w"> </span><span class="c"># IP вашего NAS</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">/export/blog-public</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">mountOptions</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">nfsvers=3</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">hard</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
|
||
</span></span></span><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">PersistentVolume</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">blog-public-dev-pv</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">capacity</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">storage</span><span class="p">:</span><span class="w"> </span><span class="l">5Gi</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">accessModes</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">ReadWriteMany</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">nfs</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">server</span><span class="p">:</span><span class="w"> </span><span class="m">192.168.11.30</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">/export/blog-public-dev</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">mountOptions</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">nfsvers=3</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">hard</span></span></span></code></pre></div></div>
|
||
<p><strong>Почему NFSv3, а не NFSv4?</strong> Потому что NFSv4.2 в K3s не работал - поды виснут в <code>ContainerCreating</code> с ошибкой <code>mount.nfs: No such file or directory</code>. NFSv3 работает стабильно. Не надо усложнять то что работает.</p>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Применяем манифест</span>
|
||
</span></span><span class="line"><span class="cl">kubectl apply -f 02-pv.yaml
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Проверяем что PV создались и привязались</span>
|
||
</span></span><span class="line"><span class="cl">kubectl get pv <span class="p">|</span> grep blog
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># blog-public-pv 5Gi RWX Bound blog/blog-public-pvc</span></span></span></code></pre></div></div>
|
||
<hr>
|
||
|
||
<h2 class="relative group">Шаг 3: Hugo Builder
|
||
<div id="шаг-3-hugo-builder" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d1%88%d0%b0%d0%b3-3-hugo-builder" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h2>
|
||
<p>Нужен контейнер который слушает webhook от Gitea, клонирует репозиторий и собирает Hugo.</p>
|
||
|
||
<h3 class="relative group">Зачем нужен Hugo Builder?
|
||
<div id="зачем-нужен-hugo-builder" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d0%b7%d0%b0%d1%87%d0%b5%d0%bc-%d0%bd%d1%83%d0%b6%d0%b5%d0%bd-hugo-builder" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h3>
|
||
<p><strong>Проблема:</strong> Hugo генерирует статику командой <code>hugo</code>. Где её запускать? На локальной машине? Тогда нужно вручную заливать файлы на сервер после каждого изменения. Неудобно и ломает автоматизацию.</p>
|
||
<p><strong>Решение:</strong> Контейнер который живёт в K3s, слушает webhook от Gitea и автоматически пересобирает сайт при каждом <code>git push</code>.</p>
|
||
|
||
<h3 class="relative group">Dockerfile
|
||
<div id="dockerfile" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#dockerfile" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h3>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">FROM</span><span class="w"> </span><span class="s">alpine:3.19</span><span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="c"># Устанавливаем всё что нужно Hugo и Git</span><span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="k">RUN</span> apk add --no-cache <span class="se">\
|
||
</span></span></span><span class="line"><span class="cl"> git nodejs npm bash curl wget <span class="se">\
|
||
</span></span></span><span class="line"><span class="cl"> libc6-compat libstdc++ ca-certificates<span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="c"># Скачиваем Hugo Extended v0.155.3</span><span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="k">WORKDIR</span><span class="w"> </span><span class="s">/tmp</span><span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="k">RUN</span> wget https://github.com/gohugoio/hugo/releases/download/v0.155.3/hugo_extended_0.155.3_linux-amd64.tar.gz <span class="o">&&</span> <span class="se">\
|
||
</span></span></span><span class="line"><span class="cl"> tar -xzf hugo_extended_0.155.3_linux-amd64.tar.gz <span class="o">&&</span> <span class="se">\
|
||
</span></span></span><span class="line"><span class="cl"> cp hugo /usr/bin/hugo <span class="o">&&</span> <span class="se">\
|
||
</span></span></span><span class="line"><span class="cl"> chmod +x /usr/bin/hugo <span class="o">&&</span> <span class="se">\
|
||
</span></span></span><span class="line"><span class="cl"> rm -rf /tmp/*<span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="k">WORKDIR</span><span class="w"> </span><span class="s">/workspace</span><span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="c"># Копируем скрипты</span><span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="k">COPY</span> webhook-listener.sh /usr/local/bin/<span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="k">COPY</span> build.sh /usr/local/bin/<span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="k">RUN</span> chmod +x /usr/local/bin/*.sh<span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="k">EXPOSE</span><span class="w"> </span><span class="s">8080</span><span class="err">
|
||
</span></span></span><span class="line"><span class="cl"><span class="k">CMD</span> <span class="p">[</span><span class="s2">"/usr/local/bin/webhook-listener.sh"</span><span class="p">]</span></span></span></code></pre></div></div>
|
||
|
||
<h3 class="relative group">build.sh - скрипт сборки Hugo
|
||
<div id="buildsh---скрипт-сборки-hugo" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#buildsh---%d1%81%d0%ba%d1%80%d0%b8%d0%bf%d1%82-%d1%81%d0%b1%d0%be%d1%80%d0%ba%d0%b8-hugo" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h3>
|
||
<p><strong>Зачем:</strong> Отдельный скрипт сборки нужен чтобы его можно было запускать не только из webhook listener, но и вручную для тестирования. Один скрипт - одна ответственность.</p>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
|
||
</span></span></span><span class="line"><span class="cl"><span class="nb">set</span> -e <span class="c1"># Остановиться при первой ошибке</span>
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">GIT_TERMINAL_PROMPT</span><span class="o">=</span><span class="m">0</span> <span class="c1"># Не запрашивать пароли интерактивно</span>
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="nv">REPO_URL</span><span class="o">=</span><span class="s2">"https://git.example.com/user/blog.git"</span> <span class="c1"># URL вашего Gitea репозитория</span>
|
||
</span></span><span class="line"><span class="cl"><span class="nv">BRANCH</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">BRANCH</span><span class="k">:-</span><span class="nv">main</span><span class="si">}</span><span class="s2">"</span> <span class="c1"># Ветка (передаётся через env)</span>
|
||
</span></span><span class="line"><span class="cl"><span class="nv">OUTPUT_DIR</span><span class="o">=</span><span class="s2">"/mnt/blog-public"</span> <span class="c1"># Куда складывать собранную статику (NFS)</span>
|
||
</span></span><span class="line"><span class="cl"><span class="nv">WORK_DIR</span><span class="o">=</span><span class="s2">"/tmp/build"</span> <span class="c1"># Временная папка для клонирования</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">rm -rf <span class="si">${</span><span class="nv">WORK_DIR</span><span class="si">}</span>
|
||
</span></span><span class="line"><span class="cl">mkdir -p <span class="si">${</span><span class="nv">WORK_DIR</span><span class="si">}</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="nb">cd</span> <span class="si">${</span><span class="nv">WORK_DIR</span><span class="si">}</span>
|
||
</span></span><span class="line"><span class="cl">git clone --branch <span class="si">${</span><span class="nv">BRANCH</span><span class="si">}</span> --depth <span class="m">1</span> <span class="si">${</span><span class="nv">REPO_URL</span><span class="si">}</span> site 2><span class="p">&</span><span class="m">1</span>
|
||
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> site
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Подтягиваем тему Blowfish как Git submodule</span>
|
||
</span></span><span class="line"><span class="cl">git submodule update --init --recursive --depth <span class="m">1</span> 2><span class="p">&</span><span class="m">1</span>
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Собираем сайт (минифицируем CSS/JS/HTML)</span>
|
||
</span></span><span class="line"><span class="cl">hugo --minify --destination <span class="si">${</span><span class="nv">OUTPUT_DIR</span><span class="si">}</span> 2><span class="p">&</span><span class="m">1</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="k">if</span> <span class="o">[</span> -f <span class="s2">"</span><span class="si">${</span><span class="nv">OUTPUT_DIR</span><span class="si">}</span><span class="s2">/index.html"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
|
||
</span></span><span class="line"><span class="cl"> <span class="nb">echo</span> <span class="s2">"Build successful!"</span>
|
||
</span></span><span class="line"><span class="cl"><span class="k">else</span>
|
||
</span></span><span class="line"><span class="cl"> <span class="nb">echo</span> <span class="s2">"Build failed - index.html not found"</span>
|
||
</span></span><span class="line"><span class="cl"> <span class="nb">exit</span> <span class="m">1</span>
|
||
</span></span><span class="line"><span class="cl"><span class="k">fi</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">rm -rf <span class="si">${</span><span class="nv">WORK_DIR</span><span class="si">}</span></span></span></code></pre></div></div>
|
||
|
||
<h3 class="relative group">webhook-listener.sh - слушатель webhook
|
||
<div id="webhook-listenersh---слушатель-webhook" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#webhook-listenersh---%d1%81%d0%bb%d1%83%d1%88%d0%b0%d1%82%d0%b5%d0%bb%d1%8c-webhook" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h3>
|
||
<p><strong>Зачем:</strong> Gitea отправляет HTTP POST запрос при каждом <code>git push</code>. Нужен простой HTTP сервер который принимает этот запрос и запускает сборку. netcat - самый простой способ поднять HTTP listener без зависимостей.</p>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
|
||
</span></span></span><span class="line"><span class="cl"><span class="nb">set</span> -e
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">"Starting webhook listener on port 8080..."</span>
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="k">while</span> true<span class="p">;</span> <span class="k">do</span>
|
||
</span></span><span class="line"><span class="cl"> <span class="c1"># Принимаем HTTP запрос через netcat и сразу отвечаем 200 OK</span>
|
||
</span></span><span class="line"><span class="cl"> <span class="nb">echo</span> -e <span class="s2">"HTTP/1.1 200 OK\r\n\r\nWebhook received"</span> <span class="p">|</span> nc -l -p <span class="m">8080</span>
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"> <span class="c1"># Запускаем сборку синхронно (чтобы видеть логи в kubectl logs)</span>
|
||
</span></span><span class="line"><span class="cl"> <span class="nb">echo</span> <span class="s2">"</span><span class="k">$(</span>date<span class="k">)</span><span class="s2">: Webhook triggered, starting build..."</span>
|
||
</span></span><span class="line"><span class="cl"> /usr/local/bin/build.sh
|
||
</span></span><span class="line"><span class="cl"> <span class="nb">echo</span> <span class="s2">"</span><span class="k">$(</span>date<span class="k">)</span><span class="s2">: Build completed, waiting for next webhook..."</span>
|
||
</span></span><span class="line"><span class="cl"><span class="k">done</span></span></span></code></pre></div></div>
|
||
|
||
<h3 class="relative group">Сборка и деплой образа
|
||
<div id="сборка-и-деплой-образа" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d1%81%d0%b1%d0%be%d1%80%d0%ba%d0%b0-%d0%b8-%d0%b4%d0%b5%d0%bf%d0%bb%d0%be%d0%b9-%d0%be%d0%b1%d1%80%d0%b0%d0%b7%d0%b0" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h3>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Собираем Docker образ</span>
|
||
</span></span><span class="line"><span class="cl">docker build -t hugo-builder:latest .
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Сохраняем в tar файл</span>
|
||
</span></span><span class="line"><span class="cl">docker save hugo-builder:latest -o /tmp/hugo-builder.tar
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Копируем на все K3s worker ноды</span>
|
||
</span></span><span class="line"><span class="cl"><span class="k">for</span> ip in <span class="m">210</span> 211<span class="p">;</span> <span class="k">do</span>
|
||
</span></span><span class="line"><span class="cl"> scp /tmp/hugo-builder.tar k3s@192.168.11.<span class="nv">$ip</span>:/tmp/
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"> <span class="c1"># Импортируем образ в containerd K3s</span>
|
||
</span></span><span class="line"><span class="cl"> ssh k3s@192.168.11.<span class="nv">$ip</span> <span class="s2">"sudo k3s ctr images import /tmp/hugo-builder.tar && rm /tmp/hugo-builder.tar"</span>
|
||
</span></span><span class="line"><span class="cl"><span class="k">done</span></span></span></code></pre></div></div>
|
||
|
||
<h3 class="relative group">Deployment и Service
|
||
<div id="deployment-и-service" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#deployment-%d0%b8-service" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h3>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">apps/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">Deployment</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">hugo-builder-prod</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">blog</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">replicas</span><span class="p">:</span><span class="w"> </span><span class="m">1</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">matchLabels</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">hugo-builder-prod</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">template</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><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">labels</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">hugo-builder-prod</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><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">containers</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">hugo-builder</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">hugo-builder:latest</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">imagePullPolicy</span><span class="p">:</span><span class="w"> </span><span class="l">Never </span><span class="w"> </span><span class="c"># Образ локальный, не тянуть из registry</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">env</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">BRANCH</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">value</span><span class="p">:</span><span class="w"> </span><span class="s2">"main"</span><span class="w"> </span><span class="c"># Для prod используем main ветку</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">volumeMounts</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">public</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l">/mnt/blog-public </span><span class="w"> </span><span class="c"># NFS хранилище</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">resources</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">requests</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">cpu</span><span class="p">:</span><span class="w"> </span><span class="l">200m</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">memory</span><span class="p">:</span><span class="w"> </span><span class="l">256Mi</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">limits</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">cpu</span><span class="p">:</span><span class="w"> </span><span class="l">500m</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">memory</span><span class="p">:</span><span class="w"> </span><span class="l">512Mi</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">volumes</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">public</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">persistentVolumeClaim</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">claimName</span><span class="p">:</span><span class="w"> </span><span class="l">blog-public-pvc</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
|
||
</span></span></span><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">hugo-builder-prod</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">blog</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">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">hugo-builder-prod</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">name</span><span class="p">:</span><span class="w"> </span><span class="l">webhook</span></span></span></code></pre></div></div>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Применяем манифест</span>
|
||
</span></span><span class="line"><span class="cl">kubectl apply -f 01-hugo-builder-prod.yaml
|
||
</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">kubectl get pods -n blog <span class="p">|</span> grep hugo-builder
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Смотрим логи - должна быть строка "Starting webhook listener"</span>
|
||
</span></span><span class="line"><span class="cl">kubectl logs -n blog deployment/hugo-builder-prod</span></span></code></pre></div></div>
|
||
<hr>
|
||
|
||
<h2 class="relative group">Шаг 4: Nginx с Prometheus exporter
|
||
<div id="шаг-4-nginx-с-prometheus-exporter" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d1%88%d0%b0%d0%b3-4-nginx-%d1%81-prometheus-exporter" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h2>
|
||
<p>Nginx раздаёт статику с того же NFS где Hugo её собрал. Две реплики для минимальной доступности при обновлениях.</p>
|
||
<p>Бонус: sidecar контейнер с nginx-prometheus-exporter для мониторинга через Grafana.</p>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">apps/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">Deployment</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">nginx</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">blog</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">replicas</span><span class="p">:</span><span class="w"> </span><span class="m">2</span><span class="w"> </span><span class="c"># Две реплики для доступности</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">matchLabels</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">nginx</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">template</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><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">labels</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">nginx</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><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">containers</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c"># Основной контейнер - Nginx</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">nginx</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">nginx:1.25-alpine</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">containerPort</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">volumeMounts</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">html</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l">/usr/share/nginx/html</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">readOnly</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w"> </span><span class="c"># Nginx только читает, не пишет</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">config</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l">/etc/nginx/nginx.conf</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">subPath</span><span class="p">:</span><span class="w"> </span><span class="l">nginx.conf</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">resources</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">requests</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">cpu</span><span class="p">:</span><span class="w"> </span><span class="l">50m</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">memory</span><span class="p">:</span><span class="w"> </span><span class="l">64Mi</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c"># Sidecar - экспортер метрик для Prometheus</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">nginx-exporter</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">nginx/nginx-prometheus-exporter:1.1.0</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">args</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- -<span class="l">nginx.scrape-uri=http://localhost/nginx_status</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">containerPort</span><span class="p">:</span><span class="w"> </span><span class="m">9113</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">metrics</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">resources</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">requests</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">cpu</span><span class="p">:</span><span class="w"> </span><span class="l">10m</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">memory</span><span class="p">:</span><span class="w"> </span><span class="l">16Mi</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">volumes</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">html</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">persistentVolumeClaim</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">claimName</span><span class="p">:</span><span class="w"> </span><span class="l">blog-public-pvc </span><span class="w"> </span><span class="c"># NFS хранилище</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">config</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">configMap</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">nginx-config</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
|
||
</span></span></span><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">nginx</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">blog</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">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">nginx</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">80</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">http</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">9113</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">9113</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">metrics </span><span class="w"> </span><span class="c"># Для Prometheus</span></span></span></code></pre></div></div>
|
||
<hr>
|
||
|
||
<h2 class="relative group">Шаг 5: SSL сертификаты
|
||
<div id="шаг-5-ssl-сертификаты" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d1%88%d0%b0%d0%b3-5-ssl-%d1%81%d0%b5%d1%80%d1%82%d0%b8%d1%84%d0%b8%d0%ba%d0%b0%d1%82%d1%8b" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h2>
|
||
<p>cert-manager автоматически получает сертификаты от Let’s Encrypt через HTTP-01 challenge.</p>
|
||
<p><strong>Важно:</strong> Сначала настрой A-запись у DNS провайдера:</p>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">your-blog.ru A 77.37.XXX.XXX (ваш внешний IP)
|
||
</span></span><span class="line"><span class="cl">www.your-blog.ru A 77.37.XXX.XXX</span></span></code></pre></div></div>
|
||
<p>Без этого Let’s Encrypt не сможет проверить что домен принадлежит вам.</p>
|
||
<div class="highlight-wrapper"><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">cert-manager.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">Certificate</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">blog-tls</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">blog</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">secretName</span><span class="p">:</span><span class="w"> </span><span class="l">blog-tls</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">issuerRef</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">letsencrypt-prod</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">ClusterIssuer</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">dnsNames</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">your-blog.ru</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">www.your-blog.ru</span></span></span></code></pre></div></div>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Применяем манифест</span>
|
||
</span></span><span class="line"><span class="cl">kubectl apply -f 04-certificate.yaml
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Ждём 30-60 секунд пока cert-manager получит сертификат</span>
|
||
</span></span><span class="line"><span class="cl">kubectl get certificate -n blog
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Должно быть READY=True</span>
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># NAME READY SECRET AGE</span>
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># blog-tls True blog-tls 45s</span></span></span></code></pre></div></div>
|
||
<hr>
|
||
|
||
<h2 class="relative group">Шаг 6: IngressRoute через Traefik
|
||
<div id="шаг-6-ingressroute-через-traefik" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d1%88%d0%b0%d0%b3-6-ingressroute-%d1%87%d0%b5%d1%80%d0%b5%d0%b7-traefik" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h2>
|
||
<p>Traefik маршрутизирует трафик на Nginx и делает SSL терминацию.</p>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="c"># HTTP → HTTPS редирект (опционально)</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">traefik.io/v1alpha1</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">IngressRoute</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">blog-http</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">blog</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">entryPoints</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">web </span><span class="w"> </span><span class="c"># Порт 80</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">routes</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">match</span><span class="p">:</span><span class="w"> </span><span class="l">Host(`your-blog.ru`) || Host(`www.your-blog.ru`)</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Rule</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">services</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">nginx</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></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="c"># HTTPS с SSL</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">traefik.io/v1alpha1</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">IngressRoute</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">blog-https</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">blog</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">entryPoints</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">websecure </span><span class="w"> </span><span class="c"># Порт 443</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">routes</span><span class="p">:</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">match</span><span class="p">:</span><span class="w"> </span><span class="l">Host(`your-blog.ru`) || Host(`www.your-blog.ru`)</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Rule</span><span class="w">
|
||
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">services</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">nginx</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">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">secretName</span><span class="p">:</span><span class="w"> </span><span class="l">blog-tls </span><span class="w"> </span><span class="c"># Сертификат от cert-manager</span></span></span></code></pre></div></div>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Применяем манифест</span>
|
||
</span></span><span class="line"><span class="cl">kubectl apply -f 05-ingressroute.yaml
|
||
</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">curl -I https://your-blog.ru
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># HTTP/2 200</span></span></span></code></pre></div></div>
|
||
<hr>
|
||
|
||
<h2 class="relative group">Шаг 7: Webhook в Gitea
|
||
<div id="шаг-7-webhook-в-gitea" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d1%88%d0%b0%d0%b3-7-webhook-%d0%b2-gitea" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h2>
|
||
<p>Последний шаг - связать Gitea с Hugo Builder.</p>
|
||
<p>Gitea → ваш репозиторий → Settings → Webhooks → Add Webhook → Gitea</p>
|
||
<ul>
|
||
<li><strong>URL:</strong> <code>http://hugo-builder-prod.blog.svc.cluster.local:8080</code></li>
|
||
<li><strong>HTTP Method:</strong> POST</li>
|
||
<li><strong>Content Type:</strong> application/json</li>
|
||
<li><strong>Trigger On:</strong> Push events</li>
|
||
<li><strong>Branch filter:</strong> <code>main</code></li>
|
||
</ul>
|
||
<p>Нажимаем “Test Delivery” - должен вернуть <code>200 OK</code>.</p>
|
||
<p>Проверяем логи Hugo Builder:</p>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Следим за логами в реальном времени</span>
|
||
</span></span><span class="line"><span class="cl">kubectl logs -n blog deployment/hugo-builder-prod -f
|
||
</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"># Webhook triggered, starting build...</span>
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Cloning repository...</span>
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Initializing submodules...</span>
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Building Hugo site...</span>
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Build successful!</span></span></span></code></pre></div></div>
|
||
<hr>
|
||
|
||
<h2 class="relative group">Проверка работы
|
||
<div id="проверка-работы" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d0%bf%d1%80%d0%be%d0%b2%d0%b5%d1%80%d0%ba%d0%b0-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%8b" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h2>
|
||
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Меняем статью</span>
|
||
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> ~/hugo-projects/blog
|
||
</span></span><span class="line"><span class="cl">git checkout main
|
||
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">"## Тестовая правка"</span> >> content/posts/hello-world/index.md
|
||
</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">git add .
|
||
</span></span><span class="line"><span class="cl">git commit -m <span class="s2">"test: проверка автосборки"</span>
|
||
</span></span><span class="line"><span class="cl">git push origin main
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Следим за логами Hugo Builder</span>
|
||
</span></span><span class="line"><span class="cl">kubectl logs -n blog deployment/hugo-builder-prod -f
|
||
</span></span><span class="line"><span class="cl">
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Через 5-7 секунд сборка завершится</span>
|
||
</span></span><span class="line"><span class="cl"><span class="c1"># Проверяем что изменение попало на сайт</span>
|
||
</span></span><span class="line"><span class="cl">curl -s https://your-blog.ru/posts/hello-world/ <span class="p">|</span> grep <span class="s2">"Тестовая правка"</span></span></span></code></pre></div></div>
|
||
<p>Если видите “Тестовая правка” - всё работает. Каждый <code>git push</code> автоматически обновляет сайт.</p>
|
||
<hr>
|
||
|
||
<h2 class="relative group">Что дальше
|
||
<div id="что-дальше" class="anchor"></div>
|
||
|
||
<span
|
||
class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
|
||
<a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%d1%87%d1%82%d0%be-%d0%b4%d0%b0%d0%bb%d1%8c%d1%88%d0%b5" aria-label="Якорь">#</a>
|
||
</span>
|
||
|
||
</h2>
|
||
<p>Production окружение развёрнуто. Но пока только для ветки <code>main</code>.</p>
|
||
<p>В следующей части добавим development окружение с отдельным Hugo Builder, Nginx и защитой через Basic Auth. Два независимых пайплайна в одном namespace.</p>
|
||
<hr>
|
||
<p><strong>Стек этой части:</strong></p>
|
||
<ul>
|
||
<li>K3s 1.30</li>
|
||
<li>NFS на OpenMediaVault</li>
|
||
<li>Hugo Builder (Alpine + Hugo v0.155.3)</li>
|
||
<li>Nginx 1.25 + Prometheus exporter</li>
|
||
<li>cert-manager + Let’s Encrypt</li>
|
||
<li>Traefik IngressRoute</li>
|
||
</ul>
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
<details class="mt-2 mb-5 overflow-hidden rounded-lg ms-0 ps-5">
|
||
|
||
<summary
|
||
class="py-1 text-lg font-semibold cursor-pointer bg-primary-200 text-neutral-800 -ms-5 ps-5 dark:bg-primary-800 dark:text-neutral-100">
|
||
Блог на Hugo в K3s -
|
||
Эта статья — часть серии.
|
||
</summary>
|
||
|
||
|
||
|
||
<div
|
||
class="py-1 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||
<a href="/posts/blog-part-1-architecture/">
|
||
Часть 1:
|
||
Блог на Hugo в K3s: часть 1 - архитектура и первый запуск
|
||
</a>
|
||
</div>
|
||
|
||
|
||
|
||
<div
|
||
class="py-1 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||
Часть 2:
|
||
Ты уже здесь
|
||
</div>
|
||
|
||
|
||
|
||
<div
|
||
class="py-1 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||
<a href="/posts/blog-part-3-dev-environment/">
|
||
Часть 3:
|
||
Блог на Hugo в K3s: часть 3 - development окружение
|
||
</a>
|
||
</div>
|
||
|
||
|
||
|
||
<div
|
||
class="py-1 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||
<a href="/posts/blog-part-4-git-workflow/">
|
||
Часть 4:
|
||
Блог на Hugo в K3s: часть 4 - выбор Git workflow
|
||
</a>
|
||
</div>
|
||
|
||
|
||
|
||
<div
|
||
class="py-1 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||
<a href="/posts/blog-part-5-debugging/">
|
||
Часть 5:
|
||
Блог на Hugo в K3s: часть 5 - что делать когда всё внезапно сломалось
|
||
</a>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
</details>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<h2 class="mt-8 text-2xl font-extrabold mb-10">Статьи по теме</h2>
|
||
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<article
|
||
class="article-link--related relative min-h-full min-w-full overflow-hidden rounded-lg border border-neutral-300 dark:border-neutral-600">
|
||
|
||
<div class="flex-none relative overflow-hidden thumbnail_card_related">
|
||
<img
|
||
src="/posts/blog-part-1-architecture/featured_hu_fbc572dfd73ed162.png"
|
||
role="presentation"
|
||
loading="lazy"
|
||
decoding="async"
|
||
fetchpriority="low"
|
||
class="not-prose absolute inset-0 w-full h-full object-cover">
|
||
</div>
|
||
|
||
|
||
<div class="p-4">
|
||
<header>
|
||
<a
|
||
|
||
href="/posts/blog-part-1-architecture/"
|
||
|
||
class="not-prose before:absolute before:inset-0 decoration-primary-500 dark:text-neutral text-xl font-bold text-neutral-800 hover:underline hover:underline-offset-2">
|
||
<h2>
|
||
Блог на Hugo в K3s: часть 1 - архитектура и первый запуск
|
||
|
||
</h2>
|
||
</a>
|
||
</header>
|
||
<div class="text-sm text-neutral-500 dark:text-neutral-400">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div class="flex flex-row flex-wrap items-center">
|
||
|
||
|
||
<time datetime="2026-01-03T00:00:00+00:00">3 января 2026</time><span class="px-2 text-primary-500">·</span><span title="Время чтения">5 минут</span><span class="px-2 text-primary-500">·</span><span>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<span
|
||
id="views_posts/blog-part-1-architecture/index.md"
|
||
class="animate-pulse inline-block text-transparent max-h-3 rounded-full -mt-[2px] align-middle bg-neutral-300 dark:bg-neutral-400"
|
||
title="views"
|
||
>loading</span
|
||
>
|
||
<span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||
<path fill="currentColor" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></span>
|
||
</span>
|
||
<span class="px-2 text-primary-500">·</span><span>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<span
|
||
id="likes_posts/blog-part-1-architecture/index.md"
|
||
class="animate-pulse inline-block text-transparent max-h-3 rounded-full -mt-[2px] align-middle bg-neutral-300 dark:bg-neutral-400"
|
||
title="likes"
|
||
>loading</span
|
||
>
|
||
<span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||
<path fill="currentColor" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></svg></span></span>
|
||
</span>
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
<div class="flex flex-row flex-wrap items-center">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/categories/infrastructure/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Infrastructure
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/hugo/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Hugo
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/blowfish/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Blowfish
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/gitea/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Gitea
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/homelab/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Homelab
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/devops/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Devops
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
<div class="px-6 pt-4 pb-2"></div>
|
||
</article>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<article
|
||
class="article-link--related relative min-h-full min-w-full overflow-hidden rounded-lg border border-neutral-300 dark:border-neutral-600">
|
||
|
||
<div class="flex-none relative overflow-hidden thumbnail_card_related">
|
||
<img
|
||
src="/posts/k3s-part3-installation/featured_hu_cb63b79224e99ddd.png"
|
||
role="presentation"
|
||
loading="lazy"
|
||
decoding="async"
|
||
fetchpriority="low"
|
||
class="not-prose absolute inset-0 w-full h-full object-cover">
|
||
</div>
|
||
|
||
|
||
<div class="p-4">
|
||
<header>
|
||
<a
|
||
|
||
href="/posts/k3s-part3-installation/"
|
||
|
||
class="not-prose before:absolute before:inset-0 decoration-primary-500 dark:text-neutral text-xl font-bold text-neutral-800 hover:underline hover:underline-offset-2">
|
||
<h2>
|
||
K3s HA для homelab: Ставим K3s HA кластер
|
||
|
||
</h2>
|
||
</a>
|
||
</header>
|
||
<div class="text-sm text-neutral-500 dark:text-neutral-400">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div class="flex flex-row flex-wrap items-center">
|
||
|
||
|
||
<time datetime="2025-11-02T00:00:00+00:00">2 ноября 2025</time><span class="px-2 text-primary-500">·</span><span title="Время чтения">10 минут</span><span class="px-2 text-primary-500">·</span><span>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<span
|
||
id="views_posts/k3s-part3-installation/index.md"
|
||
class="animate-pulse inline-block text-transparent max-h-3 rounded-full -mt-[2px] align-middle bg-neutral-300 dark:bg-neutral-400"
|
||
title="views"
|
||
>loading</span
|
||
>
|
||
<span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||
<path fill="currentColor" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></span>
|
||
</span>
|
||
<span class="px-2 text-primary-500">·</span><span>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<span
|
||
id="likes_posts/k3s-part3-installation/index.md"
|
||
class="animate-pulse inline-block text-transparent max-h-3 rounded-full -mt-[2px] align-middle bg-neutral-300 dark:bg-neutral-400"
|
||
title="likes"
|
||
>loading</span
|
||
>
|
||
<span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||
<path fill="currentColor" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></svg></span></span>
|
||
</span>
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
<div class="flex flex-row flex-wrap items-center">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/kubernetes/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Kubernetes
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/k3s/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
K3s
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/homelab/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Homelab
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/installation/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Installation
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/ha/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Ha
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/etcd/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Etcd
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/devops/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Devops
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
<div class="px-6 pt-4 pb-2"></div>
|
||
</article>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<article
|
||
class="article-link--related relative min-h-full min-w-full overflow-hidden rounded-lg border border-neutral-300 dark:border-neutral-600">
|
||
|
||
<div class="flex-none relative overflow-hidden thumbnail_card_related">
|
||
<img
|
||
src="/posts/k3s-part1-architecture/featured_hu_93e9342ed126d912.png"
|
||
role="presentation"
|
||
loading="lazy"
|
||
decoding="async"
|
||
fetchpriority="low"
|
||
class="not-prose absolute inset-0 w-full h-full object-cover">
|
||
</div>
|
||
|
||
|
||
<div class="p-4">
|
||
<header>
|
||
<a
|
||
|
||
href="/posts/k3s-part1-architecture/"
|
||
|
||
class="not-prose before:absolute before:inset-0 decoration-primary-500 dark:text-neutral text-xl font-bold text-neutral-800 hover:underline hover:underline-offset-2">
|
||
<h2>
|
||
K3s HA для homelab: архитектура без боли
|
||
|
||
</h2>
|
||
</a>
|
||
</header>
|
||
<div class="text-sm text-neutral-500 dark:text-neutral-400">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div class="flex flex-row flex-wrap items-center">
|
||
|
||
|
||
<time datetime="2025-10-14T00:00:00+00:00">14 октября 2025</time><span class="px-2 text-primary-500">·</span><span title="Время чтения">8 минут</span><span class="px-2 text-primary-500">·</span><span>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<span
|
||
id="views_posts/k3s-part1-architecture/index.md"
|
||
class="animate-pulse inline-block text-transparent max-h-3 rounded-full -mt-[2px] align-middle bg-neutral-300 dark:bg-neutral-400"
|
||
title="views"
|
||
>loading</span
|
||
>
|
||
<span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||
<path fill="currentColor" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></span>
|
||
</span>
|
||
<span class="px-2 text-primary-500">·</span><span>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<span
|
||
id="likes_posts/k3s-part1-architecture/index.md"
|
||
class="animate-pulse inline-block text-transparent max-h-3 rounded-full -mt-[2px] align-middle bg-neutral-300 dark:bg-neutral-400"
|
||
title="likes"
|
||
>loading</span
|
||
>
|
||
<span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||
<path fill="currentColor" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></svg></span></span>
|
||
</span>
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
<div class="flex flex-row flex-wrap items-center">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/kubernetes/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Kubernetes
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/k3s/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
K3s
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/homelab/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Homelab
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/proxmox/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Proxmox
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/architecture/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Architecture
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/ha/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Ha
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/devops/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Devops
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
<div class="px-6 pt-4 pb-2"></div>
|
||
</article>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<article
|
||
class="article-link--related relative min-h-full min-w-full overflow-hidden rounded-lg border border-neutral-300 dark:border-neutral-600">
|
||
|
||
<div class="flex-none relative overflow-hidden thumbnail_card_related">
|
||
<img
|
||
src="/posts/k3s-part2-infrastructure/featured_hu_fa55fce8dafb1970.png"
|
||
role="presentation"
|
||
loading="lazy"
|
||
decoding="async"
|
||
fetchpriority="low"
|
||
class="not-prose absolute inset-0 w-full h-full object-cover">
|
||
</div>
|
||
|
||
|
||
<div class="p-4">
|
||
<header>
|
||
<a
|
||
|
||
href="/posts/k3s-part2-infrastructure/"
|
||
|
||
class="not-prose before:absolute before:inset-0 decoration-primary-500 dark:text-neutral text-xl font-bold text-neutral-800 hover:underline hover:underline-offset-2">
|
||
<h2>
|
||
K3s HA для homelab: Готовим инфраструктуру в Proxmox
|
||
|
||
</h2>
|
||
</a>
|
||
</header>
|
||
<div class="text-sm text-neutral-500 dark:text-neutral-400">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div class="flex flex-row flex-wrap items-center">
|
||
|
||
|
||
<time datetime="2025-10-21T00:00:00+00:00">21 октября 2025</time><span class="px-2 text-primary-500">·</span><span title="Время чтения">10 минут</span><span class="px-2 text-primary-500">·</span><span>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<span
|
||
id="views_posts/k3s-part2-infrastructure/index.md"
|
||
class="animate-pulse inline-block text-transparent max-h-3 rounded-full -mt-[2px] align-middle bg-neutral-300 dark:bg-neutral-400"
|
||
title="views"
|
||
>loading</span
|
||
>
|
||
<span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||
<path fill="currentColor" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></span>
|
||
</span>
|
||
<span class="px-2 text-primary-500">·</span><span>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<span
|
||
id="likes_posts/k3s-part2-infrastructure/index.md"
|
||
class="animate-pulse inline-block text-transparent max-h-3 rounded-full -mt-[2px] align-middle bg-neutral-300 dark:bg-neutral-400"
|
||
title="likes"
|
||
>loading</span
|
||
>
|
||
<span class="inline-block align-text-bottom"><span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||
<path fill="currentColor" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></svg></span></span>
|
||
</span>
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
<div class="flex flex-row flex-wrap items-center">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/kubernetes/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Kubernetes
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/k3s/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
K3s
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/homelab/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Homelab
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/proxmox/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Proxmox
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/infrastructure/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Infrastructure
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/debian/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Debian
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
<a class="relative mt-[0.5rem] me-2" href="/tags/devops/">
|
||
<span class="flex cursor-pointer">
|
||
<span
|
||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||
Devops
|
||
</span>
|
||
</span>
|
||
|
||
</a>
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
<div class="px-6 pt-4 pb-2"></div>
|
||
</article>
|
||
|
||
|
||
</section>
|
||
|
||
|
||
|
||
</div>
|
||
</section>
|
||
|
||
|
||
<footer class="pt-8 max-w-prose print:hidden">
|
||
|
||
|
||
|
||
|
||
|
||
<div class="pt-8">
|
||
<hr class="border-dotted border-neutral-300 dark:border-neutral-600">
|
||
<div class="flex justify-between pt-3">
|
||
<span class="flex flex-col">
|
||
|
||
<a
|
||
class="flex text-neutral-700 hover:text-primary-600 dark:text-neutral dark:hover:text-primary-400"
|
||
href="/posts/blog-part-1-architecture/">
|
||
<span class="leading-6">
|
||
<span class="inline-block rtl:rotate-180">←</span> Блог на Hugo в K3s: часть 1 - архитектура и первый запуск
|
||
</span>
|
||
</a>
|
||
|
||
<span class="ms-6 mt-1 text-xs text-neutral-500 dark:text-neutral-400">
|
||
<time datetime="2026-01-03T00:00:00+00:00">3 января 2026</time>
|
||
</span>
|
||
|
||
|
||
</span>
|
||
<span class="flex flex-col items-end">
|
||
|
||
<a
|
||
class="flex text-right text-neutral-700 hover:text-primary-600 dark:text-neutral dark:hover:text-primary-400"
|
||
href="/posts/blog-part-3-dev-environment/">
|
||
<span class="leading-6">
|
||
Блог на Hugo в K3s: часть 3 - development окружение <span class="inline-block rtl:rotate-180">→</span>
|
||
</span>
|
||
</a>
|
||
|
||
<span class="me-6 mt-1 text-xs text-neutral-500 dark:text-neutral-400">
|
||
<time datetime="2026-01-15T00:00:00+00:00">15 января 2026</time>
|
||
</span>
|
||
|
||
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
</footer>
|
||
</article>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div
|
||
id="scroll-to-top"
|
||
class="fixed bottom-6 end-6 z-50 transform translate-y-4 opacity-0 duration-200">
|
||
<a
|
||
href="#the-top"
|
||
class="pointer-events-auto flex h-12 w-12 items-center justify-center rounded-full bg-neutral/50 text-xl text-neutral-700 hover:text-primary-600 dark:bg-neutral-800/50 dark:text-neutral dark:hover:text-primary-400"
|
||
aria-label="Пролистать наверх"
|
||
title="Пролистать наверх">
|
||
↑
|
||
</a>
|
||
</div>
|
||
|
||
</main><footer id="site-footer" class="py-10 print:hidden">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<nav class="flex flex-row pb-4 text-base font-medium text-neutral-500 dark:text-neutral-400 ">
|
||
<ul class="flex list-none flex-col sm:flex-row">
|
||
|
||
<li class=" flex mb-1 text-end sm:mb-0 sm:me-7 sm:last:me-0 ">
|
||
<a
|
||
class="decoration-primary-500 hover:underline hover:decoration-2 hover:underline-offset-2 flex items-center"
|
||
href="/tags/"
|
||
title="Tags">
|
||
|
||
Теги
|
||
</a>
|
||
</li>
|
||
|
||
<li class=" flex mb-1 text-end sm:mb-0 sm:me-7 sm:last:me-0 ">
|
||
<a
|
||
class="decoration-primary-500 hover:underline hover:decoration-2 hover:underline-offset-2 flex items-center"
|
||
href="/categories/"
|
||
title="Categories">
|
||
|
||
Категории
|
||
</a>
|
||
</li>
|
||
|
||
<li class=" flex mb-1 text-end sm:mb-0 sm:me-7 sm:last:me-0 ">
|
||
<a
|
||
class="decoration-primary-500 hover:underline hover:decoration-2 hover:underline-offset-2 flex items-center"
|
||
href="/authors/"
|
||
title="Authors">
|
||
|
||
Авторы
|
||
</a>
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
|
||
<div class="flex items-center justify-between">
|
||
|
||
|
||
<p class="text-sm text-neutral-500 dark:text-neutral-400">
|
||
©
|
||
2026
|
||
Олег Казанин
|
||
</p>
|
||
|
||
|
||
|
||
|
||
<p class="text-xs text-neutral-500 dark:text-neutral-400">
|
||
|
||
|
||
Работает на <a class="hover:underline hover:decoration-primary-400 hover:text-primary-500"
|
||
href="https://gohugo.io/" target="_blank" rel="noopener noreferrer">Hugo</a> & <a class="hover:underline hover:decoration-primary-400 hover:text-primary-500"
|
||
href="https://blowfish.page/" target="_blank" rel="noopener noreferrer">Blowfish</a>
|
||
</p>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
mediumZoom(document.querySelectorAll("img:not(.nozoom)"), {
|
||
margin: 24,
|
||
background: "rgba(0,0,0,0.5)",
|
||
scrollOffset: 0,
|
||
});
|
||
</script>
|
||
|
||
|
||
|
||
</footer>
|
||
<div
|
||
id="search-wrapper"
|
||
class="invisible fixed inset-0 flex h-screen w-screen cursor-default flex-col bg-neutral-500/50 p-4 backdrop-blur-sm dark:bg-neutral-900/50 sm:p-6 md:p-[10vh] lg:p-[12vh] z-500"
|
||
data-url="http://localhost:1313/">
|
||
<div
|
||
id="search-modal"
|
||
class="flex flex-col w-full max-w-3xl min-h-0 mx-auto border rounded-md shadow-lg top-20 border-neutral-200 bg-neutral dark:border-neutral-700 dark:bg-neutral-800">
|
||
<header class="relative z-10 flex items-center justify-between flex-none px-2">
|
||
<form class="flex items-center flex-auto min-w-0">
|
||
<div class="flex items-center justify-center w-8 h-8 text-neutral-400">
|
||
<span class="relative block icon"><svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="search" class="svg-inline--fa fa-search fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>
|
||
</span>
|
||
</div>
|
||
<input
|
||
type="search"
|
||
id="search-query"
|
||
class="flex flex-auto h-12 mx-1 bg-transparent appearance-none focus:outline-dotted focus:outline-2 focus:outline-transparent"
|
||
placeholder="Поиск"
|
||
tabindex="0">
|
||
</form>
|
||
<button
|
||
id="close-search-button"
|
||
class="flex items-center justify-center w-8 h-8 text-neutral-700 hover:text-primary-600 dark:text-neutral dark:hover:text-primary-400"
|
||
title="Закрыть (Esc)">
|
||
<span class="relative block icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M310.6 361.4c12.5 12.5 12.5 32.75 0 45.25C304.4 412.9 296.2 416 288 416s-16.38-3.125-22.62-9.375L160 301.3L54.63 406.6C48.38 412.9 40.19 416 32 416S15.63 412.9 9.375 406.6c-12.5-12.5-12.5-32.75 0-45.25l105.4-105.4L9.375 150.6c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L160 210.8l105.4-105.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-105.4 105.4L310.6 361.4z"/></svg>
|
||
</span>
|
||
</button>
|
||
</header>
|
||
<section class="flex-auto px-2 overflow-auto">
|
||
<ul id="search-results">
|
||
|
||
</ul>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</body>
|
||
|
||
</html>
|