<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>David Kistauri</title><generator>teletype.in</generator><description><![CDATA[David Kistauri]]></description><image><url>https://img2.teletype.in/files/91/48/9148d914-114c-43bc-9a38-acd64f1b311f.jpeg</url><title>David Kistauri</title><link>https://teletype.in/@dtroode</link></image><link>https://teletype.in/@dtroode?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dtroode</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/dtroode?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/dtroode?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Mon, 06 Apr 2026 10:14:43 GMT</pubDate><lastBuildDate>Mon, 06 Apr 2026 10:14:43 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@dtroode/y-combinator</guid><link>https://teletype.in/@dtroode/y-combinator?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dtroode</link><comments>https://teletype.in/@dtroode/y-combinator?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dtroode#comments</comments><dc:creator>dtroode</dc:creator><title>Y-комбинатор</title><pubDate>Fri, 11 Mar 2022 18:50:02 GMT</pubDate><category>функциональное программирование</category><description><![CDATA[Y-комбинатор — один из комбинаторов неподвижной точки — ключ к пониманию рекурсии и подсказка к тому, зачем вообще нужно функциональное программирование и в чем его особенность. В книгах объясняется сложно, поэтому я много раз перечитал, записал каждый шаг и прокоментировал его, чтоб самому понять. А потом отредактировал текст и делюсь со всеми.]]></description><content:encoded><![CDATA[
  <p id="PvyW">Y-комбинатор — один из <a href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80_%D0%BD%D0%B5%D0%BF%D0%BE%D0%B4%D0%B2%D0%B8%D0%B6%D0%BD%D0%BE%D0%B9_%D1%82%D0%BE%D1%87%D0%BA%D0%B8" target="_blank">комбинаторов неподвижной точки</a> — ключ к пониманию рекурсии и подсказка к тому, зачем вообще нужно функциональное программирование и в чем его особенность. В книгах объясняется сложно, поэтому я много раз перечитал, записал каждый шаг и прокоментировал его, чтоб самому понять. А потом отредактировал текст и делюсь со всеми.</p>
  <p id="l2S2">Рассмотрим Y-комбинатор на примере Scheme — диалекта Lisp. Тестовой функцией будет <code>length</code>, которая измеряет длину списка. Для начала объясню как рабоатет сама функция.</p>
  <pre id="ZxeM">(define length
    (lambda (l)
        (cond
            ((null? l) 0)
            (else (add1 (length (cdr l)))))))</pre>
  <p id="1Ia8">С каждым блоком кода открываются скобки, а потом они закрываются. Почти как <code>{}</code> в JavaScript. Разберем по строкам.</p>
  <ol id="nIs3">
    <li id="Mkv5"><code>define length</code> — <code>define</code> определяет называние функции, как если бы мы написали <code>function length</code> в JavaScript или <code>def length</code> в Python.</li>
    <li id="zrsC"><code>lambda (l)</code> — определяет безымянную функцию и её аргументы. В данном случаи аргумент один — <code>l</code> — в функцию мы передадим список. Передавая безымянную функцию в первую строку, мы определяем для нее имя. Первые две строки — аналог <code>function length(l)</code> в JavaScript и <code>def length(l)</code> в Python.</li>
    <li id="aN4K"><code>cond</code> — начало условия. Это как <code>if</code>, только туда передается много строк условий и действий подряд и в конце <code>else</code>.</li>
    <li id="voSv">В каждой следующей строке после <code>cond</code> идет блок кода с условием и действием. Как <code>((null? l) 0)</code>. Читается так: <code>((если это) то это)</code>. А <code>null?</code> — это функция, которая проверяет список, который мы ей передаём, на пустоту.</li>
    <li id="VCHt"><code>add1</code> — функция, которая добавляет 1; её надо писать самостоятельно. <code>cdr</code> — функция, которая возвращает список, который мы передаём, но без первого элемента.</li>
  </ol>
  <p id="r9Pw">В общем виде функция работает так:</p>
  <ol id="sthc">
    <li id="1Qma">проверяем список на пустоту,</li>
    <li id="uOb2">если пустой — возвращаем 0, если нет, идем дальше,</li>
    <li id="2CPK">добавляем 1 к рекурсивному запуску фукнции,</li>
    <li id="FNH5">запускаем функцию со списком, который меньше на один элемент,</li>
  </ol>
  <p id="gGMS">Пока список не будет пуст, мы будем добавлять единицу, когда он останется пуст, вернётся 0 из <code>((null? l) 0)</code> и шаг за шагом в обратном направлении добавится по единице.</p>
  <p id="5Ob3">Если непонятно, то лучше пропустить какой-нибудь список через фукнцию. Например <code>(lisp is great)</code>. Функция будет запускаться рекурсивно, удаляя по одному элементу из начала: <code>(lisp is great)</code>, <code>(is great)</code>, <code>(great)</code>, <code>()</code>. Теперь можно приступать к комбинатору неподвижной точки.</p>
  <p id="eeJt">Сперва попробуем избавиться от <code>define</code>. Функция будет безымянной. В Lisp есть синтаксис мгновенного объявления и вызова функции, как и в JavaScript. В скобки передается безымянная лямба-функция и следом аргумент:</p>
  <pre id="KKeO">((lambda (length)
     (lambda (l)
         (cond
             ((null? l) 0)
             (else (add1 (length (cdr l))))))) eternity)</pre>
  <p id="uIcU">Две лямбды означают, что мы создаём функцию, которая возвращает функцию, готовую принять другой аргумент. <code>eternity</code> просто пустышка, которая подставляется вместо аргумента. Такая функция будет очень похожа на length, но рекурсивного вызова не будет, потому что у функции нет имени и мы не знаем, как ее вызвать. Но если передать туда пустой список, то сработает первое условие — <code>(null? l)</code> и функция вернёт 0. То есть для пустого списка всё ок.</p>
  <pre id="6DMn">((lambda (f)
     (lambda (l)
         (cond
             ((null? l) 0)
             (else (add1 (f (cdr l))))))) ; здесь будет вторая фукнция
 ((lambda (g)
      (lambda (l) ; здесь будет cdr l
          (cond
              ((null? l) 0)
              (else (add1 (g (cdr l))))))) ; здесь будет eternity
 eternity))</pre>
  <p id="8CK5">Теперь передадим вместо <code>eternity</code> другую функцию. В первую функцию передается вторая, а в неё — <code>eternity</code>. Теперь мы можем передать список с одним элементом. Выполнится <code>else</code>, вызовется вторая функция, которая такая же, как и первая, и там мы уже остановимся. А можно так добавлять бесконечно. Но код будет не универсальным, а писать так много неудобно. Перейдем к другому определению функции.</p>
  <pre id="fPQ3">((lambda (mk-length) ; (1)
     (mk-length eternity))
 (lambda (length) ; (2)
     (lambda (l)
         (cond
             ((null? l) 0)
             (else (add1 (length (cdr l))))))))</pre>
  <p id="LZnE">Теперь у нас есть отдельная функция (первая), которая возвращает похожую на <code>length</code>функцию. Функция (2) попадет в лямбду (1) как аругмент <code>mk-length</code>. Внутри происходит опять объявление с вызовом. В функцию (2) подставляется <code>eternity</code> вместо <code>length</code>.</p>
  <p id="xTGQ">Теперь повторим прошлый код с новым синтаксисом подстановки, передадим в функцию (2) вместо <code>eternity</code> саму функцию.</p>
  <pre id="2RSA">((lambda (mk-length) ; (1)
     (mk-length
         (mk-length eternity)))
 (lambda (length) ; (2)
     (lambda (l)
         (cond
             ((null? l) 0)
             (else (add1 (length (cdr l))))))))</pre>
  <p id="gBzR">Здесь мы передаем <code>eternity</code> в функцию, как и в прошлый раз, и всю эту конструкцию снова передаем в функцию. Уберем <code>eternity</code>.</p>
  <pre id="q6Sn">((lambda (mk-length) ; (1)
     (mk-length mk-length))
 (lambda (length) ; (2)
     (lambda (l)
         (cond
             ((null? l) 0)
             (else (add1 (length (cdr l))))))))</pre>
  <p id="je9b">Функция (2) передается в функцию (1) и получает там имя <code>mk-length</code>, а потом передается в себя в строке <code>(mk-length mk-length)</code>. Вернем <code>eternity</code>, но теперь в другое место, положим его прямо внутрь функции.</p>
  <pre id="LZEQ">((lambda (mk-length) ; (1)
     (mk-length mk-length))
 (lambda (length) ; (2)
     (lambda (l)
         (cond
             ((null? l) 0)
             (else (add1 ((length eternity) (cdr l))))))))</pre>
  <p id="L2CT">Теперь опять заменим <code>eternity</code> на функцию, мы уже делали так.</p>
  <pre id="9tKj">((lambda (mk-length) ; (1)
     (mk-length mk-length))
 (lambda (length) ; (2)
     (lambda (l)
         (cond
             ((null? l) 0)
             (else (add1 ((length length) (cdr l))))))))</pre>
  <p id="wFKo">В функциональном программировании используется прием eta-reduction. Он позволяет заменить <code>(lambda (x) (function x))</code> на <code>function</code>, потому что в первом варианте мы передаем аргумент в функцию, которая находится в ожидании, во втором варианте функция также ждет аргумент, который можно ей передать. Если мы передадим любое число в оба варианта, то функция получит число и там, и там.</p>
  <p id="bpaO">Сделаем обратную замену: подставим вместо <code>(length length)</code> функцию <code>(lambda (x) ((length length) x))</code>. Здесь <code>(length length)</code> просто функция.</p>
  <pre id="yYG7">((lambda (mk-length) ; (1)
     (mk-length mk-length))
 (lambda (length) ; (2)
     (lambda (l)
         (cond
             ((null? l) 0)
             (else (add1 ((lambda (x) ((length length) x))                    (cdr l))))))))</pre>
  <p id="g82A">Вытащим новую конструкцию за функцию.</p>
  <pre id="fBjZ">((lambda (mk-length)
     (mk-length mk-length))
 (lambda (mk-length) ; новая функция-обертка
     ((lambda (length) ; подстановка аргумента
          (lambda (l)
              (cond
                  ((null? l) 0)
                  (else (add1 (length (cdr l)))))))
      (lambda (x) ; аргумент
          ((mk-length mk-length) x)))))</pre>
  <p id="QZnp">На 4 строке появились двойные скобки: это значит, что мы в функцию передаем аргумент. Выделенный фрагмент — прошлая функция, куда мы передаем последние две строки. Если подставить <code>(lambda (x) ((length length) x))</code> вместо <code>length</code> в четвертой строке, то получим функцию из предыдущего блока. Всю эту конструкцию мы обернули в новую фукнцию.</p>
  <p id="7Ms7">Вытащим выделенный фрагмент в отдельный аргумент.</p>
  <pre id="eSlh">((lambda (le)
     ((lambda (mk-length)
          (mk-length mk-length))
      (lambda (mk-length)
          (le (lambda (x)
              ((mk-length mk-length) x))))))
 (lambda (length)
     (lambda (l)
         (cond
             ((null? l) 0)
             (else (add1 (length (cdr l))))))))</pre>
  <p id="O2KT">Выделенный фрагмент — функция, похожая на изначальный <code>length</code>. Она передается в первую функцию как <code>le</code>. Остальное — часть, которая выполняет рекурсию. Её можно определить с помощью <code>define</code>.</p>
  <pre id="38ZT">(define Y
    (lambda (le)
        ((lambda (f) (f f))
         (lambda (f)
             (le (lambda (x) ((f f) x)))))))</pre>
  <p id="JtK6">Здесь <code>le</code> — функция, которую мы хотим вызывать рекурсивно, <code>x</code> — ее аргумент, а <code>f</code> — внутреннее имя функция для применения функции к себе. Эта часть называется Y-комбинатор. Их существует несколько видов, но этот основной. Более сложное, но не менее интересное, объяснение есть в книге The Little Schemer, а еще один вид комбинатора есть во второй части — The Seasoned Schemer. Это интересные и веселые книги по функциональному программированию, которые стоит прочитать навичкам в этом разделе.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@dtroode/choose-right-tools</guid><link>https://teletype.in/@dtroode/choose-right-tools?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dtroode</link><comments>https://teletype.in/@dtroode/choose-right-tools?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dtroode#comments</comments><dc:creator>dtroode</dc:creator><title>Выбирайте правильные инструменты</title><pubDate>Fri, 11 Mar 2022 18:33:40 GMT</pubDate><category>веб</category><description><![CDATA[Разработчики, которые имели медленный сайт или не имели его, с популярностью React переводят сайты на Gatsby, а потом радостно пишут в Твиттер о 90-100 в Lighthouse и рекомендуют перенести старый WordPress-блог на новый JS-фреймворк. И даже те, кто имел статический сайт на HTML с 70 в Lighthouse, переписывают его на Gatsby, который оптимизирует сайт за них и выдает хорошие цифры в тестах.]]></description><content:encoded><![CDATA[
  <p id="2xll">Разработчики, которые имели медленный сайт или не имели его, с популярностью React переводят сайты на Gatsby, а потом радостно пишут в Твиттер о 90-100 в Lighthouse и рекомендуют перенести старый WordPress-блог на новый JS-фреймворк. И даже те, кто имел статический сайт на HTML с 70 в Lighthouse, переписывают его на Gatsby, который оптимизирует сайт за них и выдает хорошие цифры в тестах.</p>
  <p id="ckR7">Проблема в том, что вам скорее всего не нужен JavaScript для личного блога. Gatsby крут плагинами, но всё, что нужно от него, — генерация страниц из Markdown. Клиент не хочет видеть JS-бандл. Gatsby нужен для сложных сайтов с анимациями и интерактивом, например, <a href="https://joshwcomeau.com/" target="_blank">для этого блога</a> — он издает звуки, персонажи двигаются, а примеры кода запускаются на месте. React с его JSX, где интерактив легко встраивается в текст, идеально здесь подходит, а еще у Gatsby хорошая поддержка MDX, чтоб делать такое же с Markdown.</p>
  <p id="cwzF">Ситуация описывается так:</p>
  <blockquote id="pxpT"><a href="https://twitter.com/twanttobealighi/status/1225769570335698944" target="_blank">@twanttobealighi</a>: реакт делает сложное простым, а простое невозможным</blockquote>
  <p id="pD8F">Разработчикам кажется, что Gatsby помогает, раз повышает результаты в тестах, но это не предел: вам дают конфетку и вы не хотите больше, а можно. Gatsby оптимизирует картинки — генерирует несколько размеров, — сжимает код и делает ту работу, которая некоторым кажется магией. Вы не делали ничего раньше и вас ругал Google, а теперь не ругает.</p>
  <p id="s1Vx">Возьмите полную статику: <a href="https://11ty.dev/" target="_blank">Eleventy</a>, — используйте плагины для сжатия кода и картинок или напишите свой код в десять строк и дайте клиенту минималистичный набор HTML + CSS. Это тоже даст 100 в Lighthouse, но ниже буду написаны цифры, более глубоко описывающие скорость загрузки: первая отрисовка, время до взаимодействия с сайтом, самый крупный элемент сайта, — которые будут в разы меньше, а в сложных тестах вы наберете лучший результат.</p>
  <p id="6Uvm">А пишу я это потому, что у меня тоже сперва была полная статика с Jekyll, а потом я поддался количеству плагинов в Gatsby и автоматической оптимизации изображений. Но недавно я переписал сайт на Eleventy за три дня. <em>Выбирайте правильные инструменты.</em></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@dtroode/google-cloud-ssh-sftp</guid><link>https://teletype.in/@dtroode/google-cloud-ssh-sftp?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dtroode</link><comments>https://teletype.in/@dtroode/google-cloud-ssh-sftp?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dtroode#comments</comments><dc:creator>dtroode</dc:creator><title>SSH и SFTP для виртуальных машин на Google Cloud</title><pubDate>Thu, 25 Nov 2021 18:27:27 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/67/19/6719f740-70a0-4b3e-bf1b-027b7a53df54.png"></media:content><category>eve-ng</category><description><![CDATA[<img src="https://img2.teletype.in/files/12/85/12852f9e-20f4-4212-9fc1-532202d08173.png"></img>На гугл-сервере есть отличная поддержка SSH, который нужен как сам по себе, так и для SFTP-подключения. Но иногда этих возможностей не хватает, поэтому можно настроить сервер под себя.]]></description><content:encoded><![CDATA[
  <p id="Znvr">На гугл-сервере есть отличная поддержка SSH, который нужен как сам по себе, так и для SFTP-подключения. Но иногда этих возможностей не хватает, поэтому можно настроить сервер под себя.</p>
  <p id="syVq">Сперва расскажу, как подключаться по SSH от разных пользователей, потом покажу как на основе этого получить SFTP-доступ.</p>
  <p id="cYHr">Самый простой способ работать с SSH – установить терминальное приложение <a href="https://cloud.google.com/sdk/docs/install" target="_blank">gcloud</a>. Теперь командой <code>gcloud compute ssh --project=АЙДИ_ПРОЕКТА --zone=ЗОНА ИМЯ_МАШИНКИ</code> подключаемся к машинке. Если не заходили до этого в свой гугл-аккаунт, в терминале появится просьба и инструкция ко входу. gcloud сам создаст пользователя и SSH-ключи в первый раз. Теперь от этого пользователя можно <a href="#7ZNn">заходить и по SFTP</a>.</p>
  <p id="Onne">А теперь дополнительные настройки, без которых и так всё работает.</p>
  <h2 id="mofy">Свой SSH</h2>
  <p id="futx">После первого входа гугл создал вам ключи. Они лежат там, где и любая другая программа их положила, можно нагуглить эту папку. У меня – стандартная для мака <code>~/.ssh</code>. Перейдёте в свою папку и увидите ключ. Его можно использовать для подключения к стандартному пользователю.</p>
  <p id="x7jm">Для большего контроля можно вручную добавить ключи для других пользователей. Следующие действия проделываем на своём компьютере.</p>
  <p id="gnxj">Генерируем ключи для пользователя student, приватный ключ будет в файле <code>~/.ssh/test</code>, публичный в таком же файле с расширением <code>.pub</code>.</p>
  <pre id="l8jx">ssh-keygen -f ~/.ssh/test -C student</pre>
  <p id="Wh60">Passphrase – дополнительный, но необязательный пароль, который у вас попросит генератор. Этот пользователь будет использовать в виртуальной машинке, имя можно дать любое, как и название файла. </p>
  <figure id="tGye" class="m_retina">
    <img src="https://img2.teletype.in/files/12/85/12852f9e-20f4-4212-9fc1-532202d08173.png" width="836" />
  </figure>
  <p id="Zvwd">Выведем содержимое публичного ключа командой <code>cat ~/.ssh/test.pub</code>, вручную скопируем, оно нам сейчас понадобится. Ключ начинается словом ssh-rsa и заканчивается именем пользователя, для которого создан ключ, всё это копируем.</p>
  <figure id="UDkl" class="m_retina">
    <img src="https://img1.teletype.in/files/43/74/43742997-4a56-4cd2-9afe-f9af7b911cfe.png" width="836" />
  </figure>
  <p id="kphZ">Переходим в раздел Metadata на гугл-сервере. Можно через меню поиска внутри сервера. Открываем вкладку SSH Keys, нажимаем Edit, Add item и вставляем в поле скопированный ключ. Получится так:</p>
  <figure id="YTX7" class="m_original">
    <img src="https://img3.teletype.in/files/af/18/af18d22e-839c-48af-87d4-9e9b69571243.png" width="1670" />
  </figure>
  <p id="1o2d">Сохраняем и ждём, пока появится надпись, что ключи сохранены. Машинку всё это время можно держать включённой.</p>
  <p id="hNHP">После сохранения ключей со своего компьютера логинимся:</p>
  <pre id="fep5">ssh -i ~/.ssh/test student@34.88.135.152</pre>
  <p id="Sw7g">Здесь я указал путь к <em>приватному</em> ключу, пользователя@айпишник.машинки.</p>
  <figure id="ixpb" class="m_retina">
    <img src="https://img3.teletype.in/files/65/1b/651b93df-a309-4b94-bc35-b6610d11ef37.png" width="836" />
    <figcaption>Получилось! Для выхода <code>exit</code> или <code>Ctrl + D</code></figcaption>
  </figure>
  <blockquote id="jRxX">Вообще тут я подключился к своему дебиану, но ссылку на эту инструкцию я буду указывать как инструкцию для EVE-NG. Чтоб никто не смущался, вывод в консоли после подключения будет отличаться, это ок :-)</blockquote>
  <h2 id="7ZNn">SFTP</h2>
  <p id="F8O9">На основе существующих пользователей можно подключаться по SFTP. Для этого в разделе Metadata на сервере должен быть ключ на имя пользователя, его пара должна быть на вашем компьютере.</p>
  <p id="YBjf">В любой программе нам понадобится тип подключения (sftp), айпи (нашей машинки), порт (если не меняли, то 22), имя пользователя, пароль (если есть), приватный ссш-ключ. Практически те же данные, что и при обычном ssh-подключении. Вот пример:</p>
  <figure id="Po37" class="m_retina">
    <img src="https://img2.teletype.in/files/56/42/56426a3b-47c7-4854-a022-ce1ad1684969.png" width="713" />
    <figcaption>Это Cyberduck – FTP-клиент для мака. Чтоб появилось такое окно, я нажал Open Connection</figcaption>
  </figure>
  <p id="tapB">После этого мы имеем полный доступ к данным, как будто они у нас на компьютере. Можно добавлять файлы и качать их.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@dtroode/eve-ng-addons</guid><link>https://teletype.in/@dtroode/eve-ng-addons?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dtroode</link><comments>https://teletype.in/@dtroode/eve-ng-addons?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dtroode#comments</comments><dc:creator>dtroode</dc:creator><title>Добавляем образы в EVE-NG на Google Cloud</title><pubDate>Tue, 09 Nov 2021 11:15:27 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/e0/82/e082b4a1-7286-478a-a486-0e50cfe43d00.png"></media:content><description><![CDATA[<img src="https://img4.teletype.in/files/b7/7f/b77fc3b1-3fd0-41ce-b1fb-01c55a457ce2.png"></img>Чтоб работать с устройствами в EVE-NG, надо добавить образы этих устройств. Теоретически там ничего сложного, только вот с цисками надо немного повозиться, сейчас покажу как это делается практически.]]></description><content:encoded><![CDATA[
  <p id="5UVx">Чтоб работать с устройствами в EVE-NG, надо добавить образы этих устройств. Теоретически там ничего сложного, только вот с цисками надо немного повозиться, сейчас покажу как это делается практически.</p>
  <h2 id="iG86">Откуда брать образы</h2>
  <p id="AJgS">Образы можно легко нагуглить, либо скачать с официальных сайтов. Вот те, с которыми мы будем работать (zip разархивировать):</p>
  <ul id="B0cn">
    <li id="19It"><a href="https://networkhunt.com/download/download-cisco-iou-iol-images/" target="_blank">Циски (последние два образа)</a>,</li>
    <li id="KRVZ"><a href="https://mikrotik.com/download" target="_blank">Микротик</a>,</li>
    <li id="pZRv"><a href="https://www.eve-ng.net/index.php/documentation/howtos/howto-create-own-linux-host-image/" target="_blank">Линукс</a>.</li>
  </ul>
  <p id="AMR4">В примере я использую образ микротика, который отмечен на картинке и образ линукс <code>linux-ubuntu-desktop-16.04.4.tar.gz</code>.</p>
  <figure id="uwlt" class="m_custom">
    <img src="https://img4.teletype.in/files/b7/7f/b77fc3b1-3fd0-41ce-b1fb-01c55a457ce2.png" width="700" />
  </figure>
  <h2 id="ToUr">Закидываем файлы</h2>
  <p id="9gxr">Закинуть файлы в Еву можно по FTP, это даже будет удобнее, для этого надо разобраться, как подключиться в виртуальной машинке через FTP-клиент. <a href="https://teletype.in/@dtroode/google-cloud-ssh-sftp" target="_blank">Я так и сделал</a>, но тут расскажу про способ, не предполагающий дополнительных знаний.</p>
  <p id="zeaw">Заходим по SSH в консоль Евы.</p>
  <p id="jTjg">Образы хранятся в папке <code>/opt/unetlab/addons/</code>, туда и будем добавлять. Сперва надо загрузить их в саму машинку. Нажимаем на шестерёнку, выбираем пункт Upload file, выбираем образ на компьютере, он загружается в отдельную папку. </p>
  <figure id="4fxc" class="m_custom">
    <img src="https://img3.teletype.in/files/a0/e1/a0e12311-d4ca-4b9f-b16b-a32d36b2dce2.png" width="397" />
  </figure>
  <p id="2KTe">Папка, в которой появится файл будет указана после загрузки файла.</p>
  <figure id="lY7n" class="m_custom">
    <img src="https://img1.teletype.in/files/42/7f/427f2f44-92df-46af-8d3c-2a079722c61e.png" width="516" />
    <figcaption>Вот тут папка /home/davidkis113_gmail_com</figcaption>
  </figure>
  <p id="qYBn">Теперь файл из это папки надо переместить в нашу папку с образами. Переходим туда, где сейчас лежит файл: <code>cd /home/davidkis113_gmail_com</code>. Теперь надо перенести образ в нужную папку.</p>
  <p id="3Qc3">Для микротика:</p>
  <p id="nOyx">Создаём папку в соответствии с версией образа командой.</p>
  <pre id="oHhm">sudo mkdir /opt/unetlab/addons/qemu/mikrotik-6.49/</pre>
  <p id="H5Y4">Выполняем команду для переноса и изменения имени и расширения файла:</p>
  <pre id="HG6M">sudo mv НАЗВАНИЕ_ФАЙЛА /opt/unetlab/addons/qemu/mikrotik-6.49/hda.qcow2</pre>
  <p id="CkGp">Для линукса:</p>
  <p id="Xk5O">В папке, где находится файл <code>cd /home/davidkis113_gmail_com</code>:</p>
  <pre id="RBv1">sudo mv НАЗВАНИЕ_ФАЙЛА /opt/unetlab/addons/qemu/НАЗВАНИЕ_ФАЙЛА
cd /opt/unetlab/addons/qemu
sudo tar xzvf НАЗВАНИЕ_ФАЙЛА
rm -f НАЗВАНИЕ_ФАЙЛА</pre>
  <p id="c1IW">Первая команда для переноса файла, вторая для перехода в ту папку, где теперь лежит файл, третья для разархивирования, четвёртая, чтоб удалить архив.</p>
  <p id="2ouu">У меня в примере название файла <code>linux-ubuntu-desktop-16.04.4.tar.gz</code>.</p>
  <p id="pBw5">Общая часть:</p>
  <p id="NSHA">Выполняем команду <code>/opt/unetlab/wrappers/unl_wrapper -a fixpermissions</code>, чтоб Ева увидела образ. Теперь образ должен отобразиться в списке в лабораторной работе. Если не отобразился обновляем страницу или перезагружаем машинку.</p>
  <h2 id="qLsi">Но с образами Cisco IOL не так просто</h2>
  <p id="N24N">Образы Cisco IOL находятся в папке <code>/opt/unetlab/addons/iol/bin</code>. Но просто так они работать не будут, нужна лицензия. Это несложно:</p>
  <ul id="WXsI">
    <li id="Dmpw">Переносим образы по одному в папку так же командой mv но в другую папку:  <code>sudo mv НАЗВАНИЕ_ФАЙЛА /opt/unetlab/addons/iol/bin/НАЗВАНИЕ_ФАЙЛА</code>.</li>
    <li id="lKxe">После переноса всех образов выполняем команду <code>/opt/unetlab/wrappers/unl_wrapper -a fixpermissions</code> – чтоб Ева заметила образы.</li>
    <li id="MDJY">Создаём файл script.py в той же директории, где лежат образы, – название не принципиально – командой <code>sudo nano script.py</code> и записываем в него код, сохраняем как обычно <code>Ctrl + o</code>, <code>Enter</code>, <code>Ctrl + x</code>:</li>
  </ul>
  <pre id="SE7t" data-lang="python">#! /usr/bin/python
print &quot;\n*********************************************************************&quot;
print &quot;Cisco IOU License Generator - Kal 2011, python port of 2006 C version&quot;
import os
import socket
import hashlib
import struct
# get the host id and host name to calculate the hostkey
hostid=os.popen(&quot;hostid&quot;).read().strip()
hostname = socket.gethostname()
ioukey=int(hostid,16)
for x in hostname:
 ioukey = ioukey + ord(x)
print &quot;hostid=&quot; + hostid +&quot;, hostname=&quot;+ hostname + &quot;, ioukey=&quot; + hex(ioukey)[2:]
# create the license using md5sum
iouPad1=&#x27;\x4B\x58\x21\x81\x56\x7B\x0D\xF3\x21\x43\x9B\x7E\xAC\x1D\xE6\x8A&#x27;
iouPad2=&#x27;\x80&#x27; + 39*&#x27;\0&#x27;
md5input=iouPad1 + iouPad2 + struct.pack(&#x27;!L&#x27;, ioukey) + iouPad1
iouLicense=hashlib.md5(md5input).hexdigest()[:16]
# add license info to $HOME/.iourc
print &quot;\n*********************************************************************&quot;
print &quot;Create the license file $HOME/.iourc with this command:&quot;
print &quot; echo -e &#x27;[license]\\n&quot; + hostname + &quot; = &quot; + iouLicense + &quot;;&#x27;&quot; + &quot; | tee $HOME/.iourc &quot;
print &quot;\nThe command adds the following text to $HOME/.iourc:&quot;
print &quot;[license]\n&quot; + hostname + &quot; = &quot; + iouLicense + &quot;;&quot;
# disable phone home feature
print &quot;\n*********************************************************************&quot;
print &quot;Disable the phone home feature with this command:&quot;
print &quot; grep -q -F &#x27;127.0.0.1 xml.cisco.com&#x27; /etc/hosts || echo &#x27;127.0.0.1 xml.cisco.com&#x27; | sudo tee -a /etc/hosts&quot;
print &quot;\nThe command adds the following text to /etc/hosts:&quot;
print &quot;127.0.0.1 xml.cisco.com&quot;
print &quot;\n*********************************************************************&quot;</pre>
  <ul id="da1E">
    <li id="a4nO">Запускаем скрипт командой <code>python script.py</code>, увидим следующие две строки в выводе:</li>
  </ul>
  <pre id="e7sg">[license]
название-машинки = НАБОР_ЦИФР_И_БУКВ;</pre>
  <ul id="HhdJ">
    <li id="7QeZ">Копируем эти две строки, создаём файл iourc снова в той же директории с образами командой <code>sudo nano iourc</code>, записываем в него эти две строчки – они будут разными у каждого – и сохраняем как обычно.</li>
  </ul>
  <p id="ILBD">Теперь образы цисок должны отображаться в Еве и работать. Если что – как всегда перезагрузка.</p>
  <p id="Q1y3">Для остальных образов процедура почти та же, нюансы гуглятся.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@dtroode/eve-ng-google-cloud</guid><link>https://teletype.in/@dtroode/eve-ng-google-cloud?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dtroode</link><comments>https://teletype.in/@dtroode/eve-ng-google-cloud?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dtroode#comments</comments><dc:creator>dtroode</dc:creator><title>Установка EVE-NG на Google Cloud</title><pubDate>Mon, 25 Oct 2021 13:38:44 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/44/65/4465cb01-0857-4375-9e7a-3c1258cbd9ff.png"></media:content><category>eve-ng</category><description><![CDATA[<img src="https://img4.teletype.in/files/32/32/3232527a-f8d8-4103-aa66-b1c33bfb6852.jpeg"></img>Google Cloud подойдёт для студентов, он предоставляет бесплатные 300 долларов на 90 дней. Деньги тратятся на обслуживание сервера, затраты зависят от мощности сервера и частоты использования. Поэтому лучше выключать виртуальную машинку каждый раз, когда не используете её.]]></description><content:encoded><![CDATA[
  <p id="z4d3">Google Cloud подойдёт для студентов, он предоставляет бесплатные 300 долларов на 90 дней. Деньги тратятся на обслуживание сервера, затраты зависят от мощности сервера и частоты использования. Поэтому лучше выключать виртуальную машинку каждый раз, когда не используете её.</p>
  <p id="rIqa">Плюсы Google Cloud в том, что не используются мощности вашего компьютера и получить полноценный доступ к Еве можно из любой точки с любого компьютера по айпи.</p>
  <p id="Qo8a">На главной странице выбираем список проектов и создаём новый проект.</p>
  <figure id="Zoai" class="m_original">
    <img src="https://img4.teletype.in/files/32/32/3232527a-f8d8-4103-aa66-b1c33bfb6852.jpeg" width="2880" />
    <figcaption>Нажимаем New Project</figcaption>
  </figure>
  <h2 id="tjNq">Готовим изображение</h2>
  <p id="Omi7">Ева обычно настраивается на Убунте, поэтому нужно подготовить подходящее изображение Убунты.</p>
  <p id="hfj9">Есть две версии Евы: Community и Pro. Вторая просит лицензионный ключ, первая бесплатная, обновляеся реже и в целом попроще. Для них нужны разные образы.</p>
  <p id="WreE">Для Community:</p>
  <p id="GCfP">Переходим по ссылке <a href="https://console.cloud.google.com/marketplace/product/ubuntu-os-pro-cloud/ubuntu-pro-xenial?project=fiery-odyssey-325912" target="_blank">Ubuntu Pro</a>, нажимаем Launch и переходим к следующему разделу про виртуалку.</p>
  <p id="N5uK">Для Pro:</p>
  <p id="Bk3M">Можно тоже установить через Ubuntu Pro, но она более финансово затратная, поэтому переходим в консоль проекта: </p>
  <figure id="zcJb" class="m_original">
    <img src="https://img1.teletype.in/files/0f/16/0f16bae6-1b17-4306-9aeb-9b0fd60fce9c.jpeg" width="2374" />
  </figure>
  <p id="sNs5">И вставляем эту команду. Если просит авторизовать, разрешаем.</p>
  <pre id="eCXA">gcloud compute images create nested-ubuntu-bionic --source-image-family=ubuntu-1804-lts --source-image-project=ubuntu-os-cloud --licenses https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx</pre>
  <h2 id="BLxp">Виртуалка</h2>
  <p id="wNSH">Находясь в новом проекте, в поиске – находится наверху на любой странице – вбиваем VM Instances и переходим в раздел с виртуальными машинами. Создаём новую машину.</p>
  <ol id="eRVl">
    <li id="w0T3">Выбираем имя.</li>
    <li id="4mxV">Выбираем регион и зону. Нужен тот регион, который ближе к нам. Эта зона будет дальше часто использоваться, но запоминать её не надо, всегда можно посмотреть.</li>
    <li id="3LB7">Настраиваем железо. Нам подойдёт процессор типа N1 или N2, характеристики процессора и оперативной памяти на своё усмотрение в заивисмости от проекта. <em>Справа можно увидеть цену, которая уйдёт на обслуживание, но если не держать сервер включённым всё время, то она будет значительно меньше.</em></li>
    <li id="VPwn">Выбирам загрузочный диск. Нажимаем изменить. Для Community Евы меняем размер диска на своё усмотрение, обычно 50-60 хватает. Для Pro Евы переходим в Custom images, выбираем свой проект, выбираем то изображение, которое создали, так же меняем размер диска.</li>
    <li id="XxZm">Ниже разрешаем HTTP траффик, потому что будем использовать Еву без SSL-сертификата. Настройка HTTPS – отдельная тема.</li>
  </ol>
  <p id="TSPI">Машинка создастся и скоро станет доступна.</p>
  <h2 id="tTRc">Установка самой Евы</h2>
  <p id="yGBi">Если машинка не включилась, включаем её.</p>
  <figure id="M6I0" class="m_original">
    <img src="https://img3.teletype.in/files/29/0f/290f7216-a7aa-4056-8704-9a2159cd6b7d.jpeg" width="2118" />
    <figcaption>Выбираем Start</figcaption>
  </figure>
  <p id="Rofk">Переходим в консоль Евы по SSH:</p>
  <figure id="zXkU" class="m_original">
    <img src="https://img2.teletype.in/files/18/cd/18cddcf2-20fb-4617-a53d-7c3a156af061.jpeg" width="2044" />
    <figcaption>Google Cloud попытается открыть ещё одно окно браузера, браузер может заблокировать это действие и сообщить об этом. В каждом браузере по-разному разрешается доступ, решение легко найти</figcaption>
  </figure>
  <p id="NtQ5">Заходим от рута <code>sudo -i</code>, выполняем команды для установки евы и обновления:</p>
  <pre id="Zd1w">wget -O - http://www.eve-ng.net/repo/install-eve.sh | bash -i
apt update
apt upgrade</pre>
  <p id="8SfM">Перезапускаем машинку через меню с тремя точками. Снова заходим по SSH, появится синий экран. <strong>Нажимаем Ctrl + c</strong>, вводим <code>sudo -i</code> и настраиваем Еву.</p>
  <figure id="DgLV" class="m_custom">
    <img src="https://img2.teletype.in/files/9d/70/9d70b4a0-77b7-4dbb-a7e9-a32978630af7.png" width="696" />
    <figcaption>Синий экран, на этом моменте нельзя вводить пароль, сперва Ctrl + c</figcaption>
  </figure>
  <p id="kssN">На моменте с настройкой айпи адреса выбираем DHCP, дальше direct connection.</p>
  <figure id="FgUz" class="m_custom">
    <img src="https://img3.teletype.in/files/6c/e4/6ce40e75-7b36-4161-8c55-b6c8b523d118.jpeg" width="697" />
  </figure>
  <p id="nVkm">Перезапускаем машинку.</p>
  <h2 id="AKWs">Вложенная виртуализация</h2>
  <p id="CrJ7">Вложенная виртуализация нужна, чтоб можно было запускать виртуальные машинки внутри Евы (которая тоже является виртуальной машинкой). По умолчанию она не настроена.</p>
  <p id="VGDW">Открываем внутреннюю консоль проекта. Прописываем три команды, где меняем EVE_NAME на имя своей виртуальной машинки, ZONE – на указанную зону этой машинки, её можно увидеть рядом с названием машинки, а PROJECT_ID – айди, которое можно узнать, нажав на имя проекта в левом верхнем углу страницы </p>
  <p id="m5Lb">Эта команда копирует конфиг машинки в файл YAML_FILE_PATH. Название файла можно изменить.</p>
  <pre id="Ut3E">gcloud compute instances export EVE-NAME \
  --project=PROJECT_ID \
  --destination=YAML_FILE_PATH \
  --zone=ZONE</pre>
  <p id="O2D1">Эта команда добавляет в скопированный конфиг две строки, которые включают вложенную виртуализацию.</p>
  <pre id="QyQA">cat &lt;&lt;EOT &gt;&gt; YAML_FILE_PATH
advancedMachineFeatures:
  enableNestedVirtualization: true
EOT</pre>
  <p id="QfQc">Эта команда заменяет конфиг Евы на отредактированный нами, который хранится в файле.</p>
  <pre id="VX7u">gcloud compute instances update-from-file EVE-NAME \
  --project=PROJECT_ID \
  --source=YAML_FILE_PATH \
  --most-disruptive-allowed-action=RESTART \
  --zone=ZONE</pre>
  <p id="8FZN">Файл YAML_FILE_PATH можно удалять.</p>
  <h2 id="tNX9">Фаервол</h2>
  <p id="m9D4">По умолчанию многие порты блокируются виртуальной машинкой для внешнего доступа. Проблема в том, что доступ ко всем устройствам внутри лабораторных работ предоставляется по айпи Евы и порту устройства.</p>
  <p id="fdQb">В поиске вбиваем Firewall, создаём правило для фаервола, придумываем ему имя. Разрешаем доступ по любому айпи к портам с 0 по 65535. Вот так:</p>
  <figure id="71dv" class="m_custom">
    <img src="https://img1.teletype.in/files/86/cb/86cb3b63-6975-45fe-80d2-ab59c3ca2b16.jpeg" width="700.9999999999999" />
    <figcaption>Остальное не меняем</figcaption>
  </figure>
  <p id="bvNd">И создаём ещё одно такое же правило, где вместо Ingress ставим Egress. Теперь трафик может ходить в обе стороны. Надо понимать, что теперь любой человек сможет подключиться к устройствам внутри вашей лабораторки, зная внешний айпи Евы и порт устройства.</p>
  <h2 id="WmRU">Настройка интерфейсов</h2>
  <p id="f4Ip">Машинка работает, но выхода в интернет у неё нет. Будем настраивать виртуальные интерфейсы таким образом, чтоб они передавали трафик на реальный интерфейс. Покажу на примере одного интерфейса. Всё делаем внутри Евы, чтоб зайти туда, используем кнопку SSH.</p>
  <ul id="HoAo">
    <li id="ogH3">Сразу заходим в рут <code>sudo -i</code> Переходим к файлу с конфигами интерфейсов редактором nano: <code>nano /etc/network/interfaces</code>, здесь видим заголовок Cloud devices. Это всё интерфейсы. Настраиваем первый, чтоб он выглядел так:</li>
  </ul>
  <pre id="TNee">iface eth1 inet manual
auto pnet1
iface pnet1 inet static
    bridge_ports eth1
    bridge_stp off
    address 10.199.199.1
    netmask 255.255.255.0</pre>
  <p id="PlMF">Можно указать другой адрес, он станет адресом для Cloud 1 внутри лабораторки. Чтоб сохранить файл и выйти Ctrl + o, Enter, Ctrl + x.</p>
  <ul id="LZ8C">
    <li id="5IuO">Перезагружаем сетевой сервис <code>systemctl restart networking</code>. Теперь проверим, после ввода команды <code>ip a</code> у pnet1 должен появится айпи, который мы указали.</li>
    <li id="Imuo">Переходим к системному файлу: <code>nano /etc/sysctl.conf</code>, убираем решётку в строке <code>net.ipv4.ip_forward=1</code>, чтоб пакеты перенаправлялись. Так же сохраняем и выходим. Вводим команду <code>sysctl -p /etc/sysctl.conf</code>, чтоб применить настройки.</li>
    <li id="JsID">Настриваем правила для исходящего трафика командой <code>iptables -t nat -A POSTROUTING -s 10.199.199.0/24 -o pnet0 -j MASQUERADE</code>. Здесь айпишник – сеть, которая должна соответствовать айпишнику интерфейса (указывали ранее).</li>
    <li id="YtD0">Командой <code>iptables -L -nv -t nat</code> можно проверить последнюю настройку, должны увидеть строку со знакомыми из прошлой команды словами. Чтоб сохранить изменения вводим несколько команд:</li>
  </ul>
  <pre id="fjKg">iptables-save &gt; /etc/iptables.rules
nano /etc/network/if-pre-up.d/iptables</pre>
  <ul id="rF6T">
    <li id="9vi4">Вставляем этот кусок кода, чтоб каждый раз правила сами применялись:</li>
  </ul>
  <pre id="5J1I">#!/bin/sh
iptables-restore &lt; /etc/iptables.rules
exit 0</pre>
  <p id="3bST"> – и сохраняем Ctrl + o, Enter, Ctrl + x.</p>
  <ul id="RVXT">
    <li id="NFsQ">Вводим команду: <code>nano /etc/network/if-post-down.d/iptables</code>. Вставляем этот код, чтоб каждый раз правила сами сохранялись:</li>
  </ul>
  <pre id="Fask">#!/bin/sh
iptables-save -c &gt; /etc/iptables.rules
if [ -f /etc/iptables.rules ]; then
    iptables-restore &lt; /etc/iptables.rules
fi
exit 0</pre>
  <p id="I42F">– так же сохраняем.</p>
  <ul id="15m8">
    <li id="9gm3">Вводим две команды, чтоб сделать файлы доступными для запуска:</li>
  </ul>
  <pre id="28Qi">sudo chmod +x /etc/network/if-post-down.d/iptables
sudo chmod +x /etc/network/if-pre-up.d/iptables</pre>
  <p id="vM3A">Теперь сеть должна работать.</p>
  <h2 id="LydC">Работа с Евой</h2>
  <p id="6H8A">В списке виртуальных машинок, нажав на имя машинки, можно увидеть и отредактировать её характеристики. Справа кнопка с тремя точками, чтоб запускать и выключать машинку.</p>
  <p id="jNE7">External IP – адрес, по которому можно зайти в лабораторки Евы, Internal IP нужен для внутреннего использования, по нему тоже можно зайти в Еву, если натсроен SSH туннель, или из другой машинки.</p>
  <h2 id="4M3h"><a href="https://teletype.in/@dtroode/eve-ng-addons" target="_blank">Добавление образов в Еву</a></h2>
  <p id="Pycn">В машинке пока почти нет образов, например Cisco, Mikrotik и разных операционок. Как их добавить рассказываю по ссылке в заголовке.</p>

]]></content:encoded></item></channel></rss>