Immitable Linux CoreOS как среда для бегущего в Gitlab тест контейнера
Привет, netrunner. Мегасити никогда не спит. Мегасити майнит все, что может переварить машина. Последний звонок по работе пыльным облаком упал тебе на плечо и отразилось болью в мышце спины.
Ты думаешь, что можешь справиться с этим? Ну-ну. Посмотрим, как ты справишься с миром, где неизменность — это не просто концепция, а жестокая минималистичная реальность.
Когда наступает ночь, ты обнаруживаешь, что пишешь веб-бук про эффективное программирование. Ты собираешь свое домашнее облако, как будто это твой личный кибернетический рай, и экспериментируешь с железяками, linux дистрибутивами и devOps инструментами. Надежный удобочитаемый код — это твоя мания, твоя одержимость.
Ты готовишь Gitlab Runner для запуска тест контейнеров на отдельной машине и решаешь взглянуть на неизменность (Immutable) в срезе программирования и администрирования. Immutable Linux и immutable классы в объектно-ориентированном программировании — это твои новые игрушки, твои инструменты для пыток.
Тебе не хочется писать ansible скрипты, нет. Ты хочешь исследовать неизменяемые дистрибутивы Fedora CoreOs и openSUSE MicroOS. Один файл для конфигурации, и флешка для “прожига” машин — вот твоя цель. Простая документация? Она не имеет значения. Да кому она нужна! Файл в гите отныне твоя документация.
Ты хочешь понять, как быстро ты сможешь разобраться с примером. Уже полночь. Кофе остыл. Слышна тихая песня машины у тебя под боком. Тоже мне чертов электрокот.
Ты наслаждаешься экспериментом с Immutable Linux, гарантируешь автономную накатку инструментом самого дистрибутива и изготавливаешь gitlab runner для test containers. Всё получается быстро, слишком быстро. Пять часов — и всё работает. По пути ты пишешь о важных темах.
Ты пишешь эссенцию, чтобы не забыть и не свихнуться:
- об Immutable Linux, особенно о Fedora CoreOS
- о неизменяемых классах и преимуществах жизни в мире immutable null safety
- пример конфигурационного файла CoreOS для рабочей машины типа Gitlab Runner
Ты думаешь, что получилось интересно? Надеюсь, ты прав.
Запуск Gitlab Runners на отдельной ВМ или хосте — это наилучшая практика. Ты знаешь это и готов к этому вызову.
Основные преимущества immutable Linux:
Инфраструктура описана файлами конфигурации и, как правило, хранится в гите. Это значит, можно восстановить кибер-ландшафт из кода.
Ты чувствуешь, как адреналин пульсирует в венах, когда в серверной начинают мигать сетевые интерфейсы, словно неоновые вывески в ночи? Это мир, где каждый клик — это выстрел, а каждый баг — это враг, который хочет тебя уничтожить. Здесь нет места слабости, только жесткая логика и холодный расчет.
- Постоянство и надежность:
Поскольку серверы заменяются, а не изменяются, инфраструктура остается в известном, стабильном состоянии. Это исключает риск возникновения непредвиденных проблем, возникающих из-за изменений или несоответствий в среде. Поверь, нет ничего страшнее, чем обновлять сервак, на котором может отвалиться критически важный софт для бизнеса. Это кошмар для админа. Обновить ХОСТ в свое время было чертовски страшным дерьмом. Вот почему ты все еще работаешь на кластере mongo 5-ти летней давности. Обновить кластер — это пипец страшно. - Повышенная безопасность:
Поскольку серверы не изменяются после развертывания, поверхность атаки остается постоянной и предсказуемой. С одной стороны, ты ничего не меняешь в настройках безопасности хоста и постоянно работаешь с консистентным объектом под атакой. Это упрощает защиту инфраструктуры и обнаружение любых аномалий или нарушений. В случае инцидента безопасности новый, чистый экземпляр может быть быстро и легко развернут, что минимизирует последствия. - Упрощенная отладка и менеджмент:
Поскольку инфраструктура остается в известном состоянии, устранение неполадок становится проще и понятнее. Ошибки можно изолировать и устранять более эффективно, сокращая время простоя и повышая доступность услуг. Систему легко восстановить до исходного состояния в случае проблем. - Масштабируемость и производительность: Поскольку новые экземпляры можно быстро и легко развернуть, можно масштабировать систему в соответствии с требованиями. Кроме того, устраняя непредсказуемость, связанную с изменениями и обновлениями, можно оптимизировать производительность и поддерживать ее на постоянном уровне.
В этом новом мире неизменности каждое изменение — это как шаг по лезвию ножа. Ты либо адаптируешься, либо исчезаешь. Но кто сказал, что в цифровой пустоши не может быть своего рода красоты?
Преимущества неизменяемых объектов в программировании
В мире программирования, где каждый байт и каждый бит имеют значение, неизменяемый объект — это как надежный стаб в неоновом свете ночи. Он не изменит своего состояния, как только будет создан, и это дарит уверенность, что он не выстрелит тебе в ногу, когда ты меньше всего этого ожидаешь.
Изменяемое состояние — это как джокер в колоде, непредсказуемый и опасный. Админы знают это чувство, когда конфигурация хоста начинает вести себя странно, словно оживший кошмар.
Преимущества иммутабельности:
- Многопоточная безопасность (thread safety):
В мире, где время течет нелинейно, неизменяемый объект гарантирует, что синхронизация не станет твоей головной болью. Каждый поток видит объект в его первозданном состоянии, как будто замороженном во времени. Если одному из потоков потребуется новая версия, он создаст её, не нарушая стабильности остальных. - Всегда валидное состояние:
Объект, который не может быть изменен, всегда находится в ясном и предсказуемом состоянии.
Марк Симан, оставил киберслед о сути инкапсуляции:«Инкапсуляция - одна из наиболее неправильно понимаемых концепций ООП. Многие программисты считают, что это запрет на прямое раскрытие полей классов поля классов должны быть «инкапсулированы» за геттерами и сеттерами. Наиболее важно то, что объект должен гарантировать, что никогда не окажется в невалидном состоянии»
- Простота тестирования:
Код, основанный на неизменяемых объектах, становится предсказуемым и легко тестируемым. Это как строить софт из кирпичиков, которые уже прошли проверку на прочность. - Легкость чтения и поддержки:
Код, использующий иммутабельные объекты, не влияет негативно на другие его части. Он чище, понятнее и менее подвержен ошибкам.
Состояние — это сложная материя, и каждый разработчик знает это.
Новички, знайте: состояние = сложно.
Здесь возникают дополнительные паттерны, защита при многопоточности, проверка состояния — всё это создаёт сложность и порождает супер-босса сложности.
На этом лезвии рождаются доклады про сложность, про то как мы ее создаем, да. А потом боремся с ней.
Когнитивная нагрузка возрастает, мы можем выдержать и больше, но нужно ли?
Мы часто забываем, что главная задача инженера — упрощать.
Развивайте свой СложноДар, чтобы распознавать сложность и избегать её, фиксить на уровне идеи.
Иммутабельная вселенная — это мир, где нет места лишним шагам. Это вселенная DC, без марвеловского тепла. Здесь инженеры стремятся к эффективности и прагматичному минимализму и теряют эмпатию по пути.
Пример неизменяемого объекта
В эпоху, когда код становится искусством, а объекты — живыми существами, неизменяемость гарантирована с момента их создания. Это и есть инкапсуляция, как я уже отмечал ранее.
Проведём параллель с “Неизменяемой конфигурацией ОС” и “Неизменным Объектом значением” (Value Object), который “гарантирует свою консистентность” благодаря фабричному методу или хитроумному конструктору.
Взгляните, как можно описать неизменяемый класс на Kotlin. Мы исключаем возможность невалидного состояния, объявляя приватный конструктор и создавая класс через фабричный метод Emerge.
Пример на kotlin:
data class Email private constructor(
val email: String
) {
companion object {
fun emerge(email: String): Result<Email> =
if (EMAIL_ADDRESS
.matches(email)
)
Result.success(Email(email))
else
Result.failure(IllegalArgumentException("Invalid email: $email"))
}
}
Если интересен сам паттерн:
val EMAIL_ADDRESS = Regex(
"[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
"\\@" +
"[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
"(" +
"\\." +
"[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
")+"
)
Тест этого класса гарантирует истинность реализации и демонстрирует, как можно с ним взаимодействовать во вселенной приложения.
Test:
package team.codemonsters.refactoringexample.valueObject
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
internal class EmailTest {
@Test
fun `should not create email with invalid email`() {
// arrange
val invalidEmail = "invalidEmail"
// act
val result = Email.emerge(invalidEmail)
// assert
assertThat(result.isFailure).isTrue
}
@Test
fun `should create valid email`() {
// arrange
val validEmail = "hPbqJ@example.com"
// act
val result = Email.emerge(validEmail)
// assert
assertThat(result.isSuccess).isTrue
}
}
Вывод номер Ноль:
В царстве кода, где инфраструктура и классы становятся живыми и дышащими сущностями, используйте неизменяемые объекты как основу своей тактики.
В мире, где программы пишут сами себя, а данные обретают форму, эти объекты становятся краеугольными камнями вашей архитектуры.
Используйте неизменяемые объекты инфраструктуры, неизменяемые классы в программировании, и ваш код станет частью этой новой цифровой реальности, где стабильность и консистентность — ключевые элементы выживания.
Осталось набрать на клавиатуре файл зажигания машины.
Суть неизменяемости в Fedora CoreOS
Одним из краеугольных камней философии Fedora CoreOS является неизменность. В то время как традиционные операционные системы обновляют отдельные пакеты, Fedora CoreOS применяет обновления атомарно, заменяя всю ОС целиком. Этот подход гарантирует согласованность и надежность во всех развертываниях, устраняя потенциальные проблемы, связанные с дрейфом конфигурации или неполадками, вызванными инкрементальными апдейтами.
Конфигурационный дрифт — это явление, при котором рабочие среды отклоняются от базовой или стандартной конфигурации с течением времени. Такое отклонение может возникнуть по множеству причин: ручное вмешательство, обновления программного обеспечения и внешние факторы.
Вот несколько интересных неизменяемых дистрибутивов, которые стоит отметить:
- NixOS
- openSUSE MicroOS
- Fedora CoreOs
- Talos Linux
Эти системы воплощают идею неизменности, обеспечивая стабильность и безопасность в мире, где код и железо становятся единым целым.
Зажигаем сердце машины средствами CoreOS
В этом разделе я описываю процесс развертывания настроенного Linux-образа на “голом железе” (Bare Metal), используя механику Fedora CoreOS для оживления машины типа Gitlab Runner.
Для этого мне понадобятся следующие входные данные:
- Docker
- Человеко-читаемый конфигурационный файл в формате yaml, известный как бутан, для заливки во вселенной Fedora CoreOS.
- Эксперимент с конфигурацией Gitlab Runner для запуска тестов с тестовыми контейнерами (testContainer).
- Экспериментальная конфигурация заливки дистрибутива.
Чтобы обеспечить простой и повторяемый опыт, мне потребуется:
- Docker
- USB-накопитель
- комп или виртуальная машина.
Выбрать подходящий вариант из списка на сайте CoreOS ты сможешь для себя сам.
Шаги для развертывания:
- Скачивание человеко-читаемого файла конфигурации бутан.
- Загрузка актуальной версии ISO дистрибутива.
- Прожиг флешки с дистрибутивом.
- Генерация Файла Зажигания для компьютера с помощью утилиты от CoreOS.
- Загрузка компьютера с флешки.
- Прошивка диска с файлом зажигания, и раннер готов к работе.
Этот процесс гарантирует, что машина будет настроена и готова к выполнению задач, будь то в физической или виртуальной среде.
пишу человеко-читаемый файл конфигурации бутан
Файл описывает одну функцию - gitlab runner для Fedora Core OS для Bare Metal
Fedora Core OS Gitlab runner butane example:
variant: fcos
version: 1.6.0
passwd:
users:
- name: core
ssh_authorized_keys:
- ssh-ed25519 AAAA.... gardener@gitlab-micro-runner
storage:
# Setting the time zone via Ignition https://docs.fedoraproject.org/en-US/fedora-coreos/time-zone/
links:
- path: /etc/localtime
target: ../usr/share/zoneinfo/Europe/Moscow
files:
# Setting a Hostname
- path: /etc/hostname
mode: 0644
contents:
inline: micro-runner-0
# https://java.testcontainers.org/supported_docker_environment/continuous_integration/gitlab_ci/
- path: /opt/config.toml
overwrite: true
contents:
inline: |
[[runners]]
name = "micro-runner-0"
url = "{url-gitlab}"
token = "{token-gitlab}"
limit = 4
executor = "docker"
[runners.docker]
tls_verify = false
image = "docker:latest"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
shm_size = 0
# https://docs.fedoraproject.org/en-US/quick-docs/selinux-changing-states-and-modes/
- path: /etc/selinux/config
overwrite: true
contents:
inline: |
SELINUX=*permissive*
SELINUXTYPE=targeted
# https://docs.fedoraproject.org/en-US/fedora-coreos/running-containers/
systemd:
units:
- name: docker.service
enabled: true
- name: gitlab-runner.service
enabled: true
contents: |
[Unit]
Description=Gitlab Runner in container
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/bin/docker run --name gitlab-runner --rm -v /opt/config.toml:/etc/gitlab-runner/config.toml:Z -v /var/run/docker.sock:/var/run/docker.sock:Z docker.io/gitlab/gitlab-runner
ExecStop=/usr/bin/docker stop gitlab-runner
[Install]
WantedBy=multi-user.target
Обрати внимание:
Далее шаги в идеально демонстрируют Container Driven Approach.
Загружаю актуальную версию ISO образа дистро из сети
docker run --security-opt label=disable --pull=always --rm -v .:/data -w /data \
quay.io/coreos/coreos-installer:release download -s stable -p metal -f iso
Прожигаю usb drive ISO образом
sudo dd if=fedora-coreos-41.20241215.3.0-live.x86_64.iso of=/dev/sdc bs=1024 status=progress && sync
тулзой от CoreOS я генерю машино-читаемый (json) файл зажигания компа из понятного человеку бутана (ямл)
docker run --interactive --rm quay.io/coreos/butane:release \
--pretty --strict < runner-core.bu.yaml > runner-core.ign
Загружаю комп с флешки
Прошиваю диск компа linux в соответствии с конфигом, зажигаем машину
Подробная инфа про разновидности снабжения машин
Две строчки. Заливка на диск nvme заняла чуть больше минуты и машина ожила.
И сообщения на экране зеленым цветом.
Machine Gitlab Runner up and running.
Тестирование
TBD
Заключиние
Дистрибутив выполняет свою функцию. Автономно прожигает диск компьютера стабильным ядром и сервисом, который исполняет свое предназначение в контейнере, и все это описано в одном файле. На мой взгляд, это отличный подход к автономности дистрибутива.
Функция проста:
f(файл_с_конфигом)=сервис_на_хосте_функционирует
Надеюсь, мне удалось провести аналогии о пользе и простоте неизменяемых объектов конфигурации и объектов в кодовой базе. Неизменяемость — это просто, а простота всегда напрямую влияет на надежность. Надежность мы получаем, в том числе, благодаря простоте тестирования.
Благодарю, что прочитал до конца. Пиши мне в моем телеграм канале
Полезные ссылки
- Immutable Linux
- Understanding Immutable Linux OS
- Unlocking the power of Fedora CoreOS - Fedora Magazine
- 5 Benefits of a Container-First Approach to Software Development
Обрати внимание, что документация, примеры - все хранится в гите
Лаконичной документацией с рабочими примерами мне нравится вселенная Fedora.
Также хочу отметить прекрасную документацию Gentoo и посоветовать тем, кто хочет понять как работает linux установить и разобраться с этим милым пингвином
- https://fedoraproject.org/
- https://www.gentoo.org/