This is the multi-page printable view of this section. Click here to print.
Blog
- Jeden projekt Packer, trzy szablony Proxmox
- Automatyczne zarządzanie repozytoriami
- Automatyczne zarządzanie Vault za pomocą OpenTofu
- Automatyczne zarządzanie LXC w Proxmox za pomocą OpenTofu
- Automatyczne zarządzanie RouterOS za pomocą OpenTofu
- Kontener deweloperski z z pluginem vscode devcontainers
- Przygotowanie środowiska deweloperskiego z Vagrant
- Przygotowanie środowiska LAB
Jeden projekt Packer, trzy szablony Proxmox
Na początku zawsze wygląda to niewinnie.
Jedna maszyna testowa. Potem druga. Potem dochodzi inna dystrybucja. A na końcu masz:
- kilka katalogów,
- kilka „lekko” różnych konfiguracji,
- provisioning kopiowany metodą copy–paste,
- i zero pewności, czy te maszyny naprawdę są takie same.
Ten projekt powstał dokładnie z tego powodu — żeby przestać rzeźbić każdą maszynę osobno.
Co to w ogóle robi?
W skrócie:
projekt Packer → wiele szablonów VM na Proxmox
- może budować AlmaLinux 10,
- może budować Ubuntu,
- może budować Alpine,
Jak to jest podzielone (bez bólu głowy)
Żeby nie robić jednego wielkiego potwora, projekt jest rozbity logicznie na repozytoria:
Każde repo wygląda bardzo podobnie — dzięki temu wiesz, gdzie czego szukać, niezależnie od dystrybucji.
Jak to działa – krok po kroku
1. Packer łączy się z Proxmox
Na starcie Packer:
- łączy się z API Proxmox,
- tworzy tymczasową maszynę,
- podpina ISO instalacyjne.
Dane dostępowe nie są w kodzie — są pobierane z Vaulta.
2. Automatyczna instalacja systemu
Zamiast klikać instalator ręcznie:
- AlmaLinux używa kickstarta,
- Ubuntu będzie używać autoinstall,
- Alpine używa setup-alpine.
Packer:
- uruchamia mały serwer HTTP,
- podaje instalatorowi adres pliku konfiguracyjnego,
- instalacja leci sama, bez żadnych pytań.
Efekt? Zawsze ten sam system, zainstalowany w ten sam sposób.
3. Provisioning po instalacji
Gdy system już się uruchomi, Packer:
- loguje się po SSH,
- dodaje klucz publiczny,
- ustawia sudo bez hasła,
- uruchamia jeden wspólny skrypt provisioningowy.
Ten skrypt:
- aktualizuje system,
- instaluje
qemu-guest-agent, - opcjonalnie instaluje rzeczy typu
sssd/realmd, - włącza potrzebne usługi.
To jest jedno miejsce, w którym utrzymujesz „bazową konfigurację” VM.
4. Zapis jako template
Na końcu:
- maszyna jest wyłączana,
- zapisywana jako template w Proxmox,
- gotowa do klonowania.
Bez ręcznego sprzątania. Bez „czy ja o czymś nie zapomniałem?”.
Gdzie są różnice między systemami?
I tu jest najważniejsza część.
Różnice nie są w logice, tylko w danych:
- inny plik instalacyjny,
- inny plik
pkrvars, - czasem inne domyślne zasoby.
Cała reszta:
- Vault,
- sieć,
- provisioning,
- standardy bezpieczeństwa,
pozostaje taka sama.
Jak się tego używa?
Dla pojedynczego systemu:
packer init .
packer fmt -var-file=pkrvars/alma-10.hcl .
packer validate -var-file=pkrvars/alma-10.hcl .
packer build -var-file=pkrvars/alma-10.hcl .
Albo wszystko naraz:
bash scripts/packer_build.bash
Skrypt sam przechodzi po wszystkich profilach.
Co mi to realnie daje?
Najważniejsze rzeczy w praktyce:
- koniec z ręcznym klikaniem instalatorów
- koniec z różnymi „prawie takimi samymi” VM
- jedno miejsce na zmiany
- łatwa integracja z CI/CD
- łatwe dodanie kolejnej dystrybucji
To nie jest projekt „na pokaz”. To jest narzędzie, które faktycznie upraszcza życie, gdy masz więcej niż jedną maszynę.
Automatyczne zarządzanie repozytoriami
OpenTofu coraz częściej wykorzystywany jest nie tylko do budowy infrastruktury chmurowej, lecz także do zarządzania całym ekosystemem usług.
W repozytorium iac-gitlab przygotowałem modułowy zestaw definicji, który pozwala w deklaratywny sposób tworzyć i utrzymywać grupy oraz projekty w GitLabie.
Po co IaC dla GitLaba?
- Automatyzacja: grupy i projekty tworzą się automatycznie na podstawie kodu.
- Powtarzalność: każda zmiana jest opisana w repozytorium, a
tofu planpokazuje różnice. - Rozliczalność: pełna historia zmian wraz z informacją kto, gdzie i kiedy je zlecił.
- Porządek: struktura katalogów odpowiada strukturze GitLaba, co ułatwia nawigację i odnalezienie definicji konkretnej grupy czy projektu.
Jak zbudowane jest repozytorium?
Struktura katalogów odzwierciedla hierarchię GitLaba:
iac-gitlab
├── data/ # listy do walidacji (typy projektów, avatary, etykiety)
├── pl.rachuna-net/ # główna grupa i jej podgrupy
│ ├── containers/ # definicje projektów kontenerowych
│ ├── cicd/ # ustawienia CI/CD
│ └── infrastructure/ # infrastruktura (np. opentofu)
└── _providers.tf # konfiguracja providerów (m.in. GitLab)
Architektura rozwiązania
flowchart TB
subgraph s1["opentofu module"]
n2["gitlab-group"]
n1("gitlab-project")
end
A["iac-gitlab"] --> n1
A --> n2
n2@{ shape: rounded}
Tworzenie grupy repozytoriów
Definicja grupy korzysta z modułu gitlab-group:
module "_containers" {
source = "git@gitlab.com:pl.rachuna-net/infrastructure/opentofu/modules/gitlab-group.git?ref=v1.0.0"
name = "containers"
description = "Repozytoria z obrazami kontenerowymi."
parent_group = local.parent_name
visibility = "public"
default_branch = "main"
avatar = "containers"
}
module "containers" {
source = "./containers/"
}
Pierwszy moduł tworzy grupę, a drugi ładuje definicje jej podprojektów.
W pliku _locals.tf przechowuję wspólne parametry, aby uniknąć powielania konfiguracji.
Tworzenie projektu
Moduł gitlab-project umożliwia definiowanie parametrów projektu:
module "opentofu" {
source = "git@gitlab.com:pl.rachuna-net/infrastructure/opentofu/modules/gitlab-project.git?ref=v1.0.0"
name = "opentofu"
description = "Obraz Dockerowy z narzędziem opentofu."
visibility = "public"
parent_group = local.parent_name
project_type = "container"
avatar = "opentofu"
}
Jak pracować z iac-gitlab w praktyce?
- Dodaj definicję grupy lub projektu w odpowiednim katalogu.
- Wyślij Merge Request — pipeline wykona tylko plan
- Po mergu GitLab automatycznie tworzy lub aktualizuje grupy, projekty, etykiety, avatary oraz zmienne CI.
Co jeszcze znajduje się w repozytorium?
data/allowed_*— walidacja dozwolonych typów projektów i avatarów; spina IaC z politykami organizacji.images/— katalog z avatarami dla grup i projektów.
Szybki start
Automatyczne zarządzanie Vault za pomocą OpenTofu
Są takie elementy infrastruktury, które na początku wyglądają niewinnie. Ot, postawisz Vaulta, wrzucisz kilka sekretów, wystawisz parę certyfikatów i lecisz dalej. A potem przychodzi życie: kolejna usługa, kolejny zespół, kolejny pipeline, ktoś prosi o dostęp „tylko do tego jednego patha”, a Ty orientujesz się, że Vault zaczyna przypominać szufladę z kablami — daj się w to wciągnąć na chwilę i nagle nie wiesz, co do czego prowadzi.
Właśnie w tym miejscu wjeżdża iac-vault: repozytorium, które robi z Vaulta coś, co da się normalnie utrzymać. Wszystko jest opisane w IaC, wersjonowane w Git, odtwarzalne i gotowe pod automatyzację. Bez ręcznego klikania, bez „a kto to zmieniał?”, bez tajemnej wiedzy w głowie jednej osoby.
To jest wpis o tym, jak ogarniam środowisko Vaulta przy pomocy OpenTofu — od PKI i KV, po polityki i uwierzytelnianie — i dlaczego to podejście jest po prostu… wygodne.
Dlaczego w ogóle chciałem to mieć jako IaC?
Bo Vault jest świetny, ale ręczne utrzymanie Vaulta w rosnącym środowisku to proszenie się o problemy:
- polityki „tymczasowe”, które zostają na zawsze,
- sekrety tworzone ad-hoc w różnych mountach,
- PKI, które żyje własnym życiem,
- brak jasnej odpowiedzi na pytanie: „jak to odtworzyć od zera?”
Z iac-vault mam jasny układ:
- Git jest źródłem prawdy,
- zmiany przechodzą przez Code Review,
- Rollout jest przewidywalny,
- a Vault przestaje być czarną skrzynką.
- jest rozliczalność i możliwości analizowania błędów na danych.
Co to właściwie jest iac-vault?
iac-vault to repozytorium, które pełni rolę orkiestratora konfiguracji Vault. Ono „składa” środowisko z czytelnych klocków:
pki– pełna warstwa certyfikatów (Root, Intermediate, leafy),secrets– przestrzenie KV na sekrety (KV v2),policies– polityki ACL (czytelne, modularne),auth– metody logowania i integracje (userpass + AppRole),- plus
providers.tf,variables.tfi reszta „kleju”.
W praktyce: repo mówi Vaultowi dokładnie, co ma istnieć — i możesz to odtworzyć na nowej instancji w identyczny sposób.
flowchart TB
subgraph s1["opentofu module"]
n2["vault-pki"]
end
A["iac-vault"] --> n3["auth"] & n4["pki"] & n5["secrets"] & n6["polices"]
n4 --> n2
Struktura katalogów jest prosta i „czyta się sama”:
.
├── auth # mechanizmy autoryzacji (userpass, AppRole)
├── main.tf # główny plik wykonawczy OpenTofu
├── pki # konfiguracja PKI oparta o moduł vault-pki
├── policies # polityki ACL Vault
├── providers.tf # definicje providerów
├── secrets # konfiguracja backendów KV
└── variables.tf # zmienne globalne
PKI: to tutaj robi się naprawdę fajnie
Jeżeli masz więcej niż kilka usług, to PKI potrafi być największym źródłem bólu. Wiele osób kończy z:
- jednym intermediate „do wszystkiego”,
- certyfikatami porozrzucanymi po systemach,
- rotacją robioną ręcznie,
- i tym cudownym uczuciem stresu, kiedy cert się kończy „jutro” 😉
W moim podejściu PKI jest robione przez moduł 👉 vault-pki opentofu
I to jest turbo wygodne, bo moduł automatyzuje cały, zdroworozsądkowy model:
- Root CA istnieje i jest używany wyłącznie do podpisywania intermediates,
- intermediates są podzielone logicznie (np.
infrastructureiapps), - leafy są generowane deklaratywnie z jednej mapy.
To na starcie wygląda jak „dodatkowa robota”, ale w praktyce daje ogromny spokój: PKI robi się przewidywalne i banalne do rozbudowy.
Jak wygląda hierarchia?
stateDiagram direction TB [*] --> s1 s1 --> s2 s1 --> s5 s1:Root CA s2:Infrastructure Intermediate CA s5:Apps Intermediate CA
Ja trzymam prosty mental model:
- infrastructure → Vault, Consul, GitLab, routery, load balancery, core infrastruktury,
- apps → aplikacje, serwisy, fronty, API.
W OpenTofu to jest po prostu czytelna mapa:
intermediates = {
infrastructure = {
path = "pki-infrastructure"
common_name = "rachuna-net.pl Infrastructure Intermediate CA"
role_name = "infrastructure-default"
}
apps = {
path = "pki-apps"
common_name = "rachuna-net.pl Apps Intermediate CA"
role_name = "apps-default"
}
}
Leaf: certyfikaty jako lista życzeń
Najlepsze jest to, że wystawianie certyfikatów końcowych robi się trochę jak „zamawianie” usług: wpisujesz co chcesz mieć, a reszta dzieje się sama.
leaf_requests = {
"infra-gitlab" = {
backend_key = "infrastructure"
common_name = "gitlab.rachuna-net.pl"
alt_names = ["registry.rachuna-net.pl"]
}
}
I nagle certyfikaty przestają być „operacją”, a stają się zwykłym elementem konfiguracji. Dodajesz wpis → commit → apply → gotowe.
To podejście jest genialne szczególnie wtedy, kiedy usług jest dużo i ciągle dochodzą nowe.
Certyfikaty: skąd je biorę?
W zależności od use-case:
- dla automatyzacji i narzędzi (Ansible/CI) — czytam z KV,
- dla prostych skryptów albo debugowania — biorę bezpośrednio z PKI.
Przykład pobrania bezpośrednio:
RESP=$(curl \
--header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data '{"common_name": "grafana.rachuna-net.pl"}' \
https://vault.rachuna-net.pl/v1/pki-apps/issue/apps-default)
ACME: czyli „Vault, ale jak Let’s Encrypt”
To jest ten fragment, który sprawia, że całość zaczyna błyszczeć: moduł wspiera ACME, więc możesz podpiąć np. certbota1 i robić odnowienia bardziej „cloud-native” niż „przypominajka w kalendarzu”.
acme = {
acme_enabled = true
acme_cluster_path = "https://vault.rachuna-net.pl"
allow_wildcard_certificates = true
max_ttl = "168h"
}
Efekt? Certyfikaty przestają być tematem. Po prostu się robią i odnawiają.
KV: sekrety w końcu mają swoje miejsce
KV v2 to klasyk, ale różnica robi się wtedy, gdy backendy i ich przeznaczenie masz uporządkowane, nazwane i utrzymywane w IaC.
resource "vault_mount" "kv_gitlab" {
path = "kv-gitlab"
type = "kv-v2"
description = "Storage for GitLab related secrets"
}
Dzięki temu:
- łatwiej delegować dostępy,
- łatwiej utrzymać porządek,
- łatwiej przenieść środowisko.
Polityki: bezpieczeństwo bez bólu
Polityki to miejsce, gdzie zwykle kończy się „porządek” — bo łatwo dorzucić wyjątek, trudniej go potem wyczyścić.
W iac-vault polityki są modularne: dla KV osobno, dla PKI osobno, dla admina osobno. Do tego klasyczny podział na read/write/admin.
To brzmi prosto, ale działa fenomenalnie przy rosnącej liczbie zespołów i integracji.
Auth: ludzie logują się prosto, automaty logują się bezpiecznie
Dwie metody, które pokrywają 95% potrzeb:
- userpass — dla ludzi (admin/dev),
- AppRole — dla CI/CD i automatyzacji.
AppRole jest idealny do GitLaba, bo daje kontrolę nad TTL, rolami, politykami i dostępami, bez zostawiania wszędzie tokenów „na wieczność”.
Podsumowanie: dlaczego to jest fajne?
Bo Vault przestaje być „ustawiony kiedyś” i staje się „zarządzany”.
Z iac-vault dostajesz:
- ✅ odtwarzalność środowiska,
- ✅ porządek w PKI (root -> intermediates -> leafy),
- ✅ certyfikaty jako deklaracja, nie jako operacja,
- ✅ opcję ACME i automatycznego odnawiania,
- ✅ przewidywalne, modularne polityki,
- ✅ przejrzysty model auth dla ludzi i automatyzacji,
- ✅ repozytorium, które jest dokumentacją samą w sobie.
I najważniejsze: zyskujesz spokój. A to w infrastrukturze jest walutą premium.
Automatyczne zarządzanie LXC w Proxmox za pomocą OpenTofu
Nie ma nic bardziej satysfakcjonującego niż kliknięcie tofu apply i zobaczenie, jak Proxmox sam pobiera template LXC, tworzy kontenery i konfiguruje dostęp. Poniżej opisuję, jak wygląda ten proces w moim repozytorium iac-proxmox i na co warto zwrócić uwagę, jeśli chcesz to odwzorować u siebie.
Dlaczego LXC do IaC w Proxmox
- Kontenery startują w sekundy i zużywają minimalne zasoby w porównaniu z pełnymi VM.
- Wspólny kernel i brak emulacji sprzętu sprawiają, że świetnie nadają się do mikroserwisów, proxy, workerów CI czy środowisk testowych.
- Dzięki OpenTofu cały cykl życia kontenera (tworzenie, aktualizacja, usuwanie) jest wersjonowany w Git i odtwarzalny na innym hoście.
Jak zorganizowałem repozytorium iac-proxmox
Wydzielam dwa kluczowe katalogi:
containers_templates/– zasoby odpowiedzialne za pobieranie obrazów LXC do magazynu Proxmoxa.machines/– pojedyncze plikictXXXXX.tf, każdy opisuje wygląd kontenera.
Krok 1. Pobieranie template: jeden zasób, zero ręcznych klików
Szablon Ubuntu 24.04 LTS pobieram wprost z repozytorium Proxmoxa:
resource "proxmox_virtual_environment_download_file" "ubuntu24-10" {
content_type = "vztmpl"
datastore_id = local.storage_name
node_name = local.default_node
file_name = "ubuntu-24.04.tar.zst"
url = "http://download.proxmox.com/images/system/ubuntu-24.04-standard_24.04-2_amd64.tar.zst"
checksum = "4030982618eeae70854e8f9711adbd09"
checksum_algorithm = "md5"
}
Kluczowe jest ustawienie checksum i checksum_algorithm – mam pewność, że obraz nie został uszkodzony, a plan w razie różnic przerwie się na weryfikacji.
Krok 2. Tworzenie kontenera – minimalny moduł
Każdy kontener to osobny moduł z jednoznacznym ct_id:
module "ct01011" {
source = "git@gitlab.rachuna-net.pl:pl.rachuna-net/infrastructure/opentofu/modules/proxmox-container.git?ref=v1.0.0"
hostname = "ct01011.rachuna-net.pl"
description = "example-service"
node_name = "pve-s1"
ct_id = 1011
pool_id = "web-proxy"
start_on_boot = true
tags = ["example", "ubuntu"]
cpu_cores = 2
memory = { dedicated = 2048, swap = 1024 }
disk = { storage_name = "local-lvm", disk_size = 32 }
operating_system = {
template_file = "local:vztmpl/ubuntu-24.04.tar.zst"
type = "ubuntu"
}
user_account = {
username = "techuser"
password = "change-me"
public_ssh_key = "ssh-ed25519 AAAA..."
}
}
Najważniejsze parametry, które zawsze ustawiam:
| Parametr | Co robi |
|---|---|
hostname |
Pełna nazwa DNS kontenera |
node_name |
Węzeł Proxmoxa, na którym zostanie utworzony |
ct_id |
Stałe ID kontenera – ułatwia śledzenie i logging |
pool_id |
Przynależność do puli logicznej (np. web, db, proxy) |
start_on_boot |
Autostart po restarcie noda |
cpu_cores/memory/disk |
Twarda kontrola zasobów hosta |
operating_system.template_file |
Ścieżka do wcześniej pobranego template |
user_account |
Automatycznie zakładane konto i klucz SSH |
Krok 3. Bezpieczeństwo: sekrety z Vault zamiast w pliku
Hasła i klucze trzymam poza repozytorium. Wartości w user_account mogą pochodzić z Vault:
user_account = {
username = data.vault_kv_secret_v2.ct.data["username"]
password = data.vault_kv_secret_v2.ct.data["password"]
public_ssh_key = data.vault_kv_secret_v2.ct.data["ssh_key"]
}
Zyskuję rotację haseł, brak sekretów w Git i spójny audyt dostępu.
Automatyczne zarządzanie RouterOS za pomocą OpenTofu
W tym wpisie dzielę się praktycznym podejściem do Infrastructure as Code dla routerów MikroTik (RouterOS). Projekt iac-mikrotik to zestaw modułów OpenTofu (API RouterOS), który pozwala w pełni deklaratywnie zarządzać routerem bez klikania w GUI. Całość jest wersjonowana w Git, dzięki czemu łatwo zrobić review, audyt i rollback.
Co automatyzuje iac-mikrotik
- Interfaces: Ethernet, Bonding (LACP), Bridge, VLAN – każdy typ w osobnym module i katalogu.
- Serwery DHCP: sieci, pule, instancje serwerów, statyczne leases, a całość spójnie spięta z DNS.
- Serwer DNS: centralny resolver z cache, serwerami upstream i kontrolą bezpieczeństwa.
- Rekordy DNS: statyczne wpisy A/AAAA/CNAME/TXT/MX/NS w mapie
dns_records– dla krytycznych usług.
Struktura repozytorium
router.rachuna-net.pl/
├── interfaces/ # ethernet, bonding, bridge, vlan (*.tf)
├── dhcp-servers/ # każdy serwer DHCP w osobnym pliku
├── dns-server/ # main.tf z konfiguracją resolvera
└── dns-records/ # mapa statycznych rekordów DNS
Moduły OpenTofu w użyciu
routeros-ethernet,routeros-bonding,routeros-bridge,routeros-vlan– warstwa L2/L3 interfejsów.routeros-dhcp-server– sieci, pule, serwery DHCP oraz statyczne leases.routeros-dns– resolver, cache, upstream oraz statycznedns_records.
Kolejność wdrażania (dlaczego ma znaczenie)
- Interfaces: najpierw Ethernet, potem Bonding, Bridge, VLAN – zapewnia zależności L2/L3.
- Serwery DHCP: działają na gotowych interfejsach L3, z jasno zdefiniowanymi pulami.
- Serwer DNS: centralny resolver + cache, wskazywany przez DHCP.
- Rekordy DNS: statyczne wpisy dla usług krytycznych (routery, klastry, proxy).
Przykładowy moduł VLAN
module "vlan_vms_internal" {
source = "git@gitlab.rachuna-net.pl:pl.rachuna-net/infrastructure/opentofu/modules/routeros-vlan.git?ref=v1.0.0"
name = "vlan-vms-int"
interface = "bond-storage"
vlan_id = 20
arp = "enabled"
mtu = 1500
comment = "VLAN VMs internal"
}
Dlaczego tak? Każdy element (np. VLAN) żyje w osobnym pliku – można go przetestować, zreviewować i wycofać bez dotykania reszty konfiguracji.
Integracja DHCP ↔ DNS
- Lease z
hostnameautomatycznie tworzy rekordy A i PTR w resolverze RouterOS. - Statyczne rekordy w
dns_recordszabezpieczają krytyczne hosty (routery, proxmoxy, load balancery). - DHCP zawsze wskazuje lokalny DNS, co eliminuje problemy z nazwami, TLS i monitoringiem.
Zasady projektowe, które się sprawdziły
- Zero konfiguracji w GUI – tylko IaC.
- Jeden moduł = jedna funkcja; bez „kombajnów” w jednym pliku.
- Krytyczne hosty zawsze mają statyczne rekordy DNS; DHCP dla urządzeń dynamicznych.
- Wszystko przez Git: review, audyt, rollback.
Efekt
Projekt iac-mikrotik upraszcza życie przy RouterOS: wgrywam moduły OpenTofu, a router buduje się sam – z kompletnymi interfejsami, DHCP, DNS i statycznymi rekordami. Jeśli coś pójdzie nie tak, rollback to kwestia jednego commita.
Kontener deweloperski z z pluginem vscode devcontainers
W pracy nad wieloma projektami infrastrukturalnymi (OpenTofu, Ansible, Vault, GitLab CI) szybko pojawia się ten sam problem: jak zapewnić powtarzalne, gotowe do pracy środowisko developerskie, bez ręcznego konfigurowania systemu na każdym laptopie lub VM.
Rozwiązaniem, które sprawdza się w praktyce, jest Dev Container w Visual Studio Code, uzupełniony o zewnętrzny katalog /userfiles z konfiguracją użytkownika oraz automatyczny bootstrap wykonywany przy starcie kontenera.
W tym wpisie pokażę, jak zbudować takie rozwiązanie krok po kroku.
Założenia architektoniczne
Celem jest środowisko, które:
-
działa identycznie na każdym hoście,
-
nie wymaga kopiowania kluczy SSH ani dotfiles do repozytorium,
-
automatycznie:
- instaluje zaufane CA (Vault PKI),
- konfiguruje
.zshrc, Git, SSH, - przygotowuje użytkownika do pracy od razu po otwarciu repozytorium.
Kluczowe elementy:
- Dev Container oparty o własny obraz Dockera,
- bind-mount katalogu
/userfiles, - postCreateCommand jako punkt wejścia do bootstrapu.
Struktura /userfiles
Na hoście (lub w VM) utrzymywany jest katalog:
/userfiles
├── bootstrap.bash
├── configure_user.bash
├── .zshrc
├── .gitconfig
├── .gitignore_global
└── .ssh/
├── id_ed25519
├── id_ed25519.pub
└── known_hosts
To jest źródło prawdy dla konfiguracji użytkownika – niezależne od repozytoriów i kontenerów.
Konfiguracja devcontainer.json
Minimalna i stabilna konfiguracja wygląda następująco:
{
"name": "Devcontainer",
"image": "registry.rachuna-net.pl/pl.rachuna-net/containers/devcontainer:1.0.0",
"remoteUser": "ubuntu",
"postCreateCommand": "bash -lc '/userfiles/bootstrap.bash'",
"mounts": [
"source=/userfiles,target=/userfiles,type=bind"
]
}
Najważniejsze decyzje:
/userfiles–ln -s .devcontainer/userfilesw repozytorium kodu,postCreateCommanduruchamiany jawnie przezbash -lc,- brak logiki konfiguracyjnej w samym repozytorium.
Bootstrap – jeden punkt wejścia
Plik bootstrap.bash odpowiada za konfigurację systemową.
#!/usr/bin/env bash
set -euo pipefail
echo "===> Run bootstrap script"
echo "===> Install Vault CA certificates"
sudo curl -ks https://vault.localhost/v1/pki-root/ca/pem -o /usr/local/share/ca-certificates/ca.crt
sudo update-ca-certificates
bash -lc '/userfiles/configure_user.bash'
Dlaczego tak?
-
brak interaktywnych shelli (
zsh,bashbez-c), -
jednoznaczny podział:
- bootstrap → system,
- configure_user → użytkownik.
Konfiguracja użytkownika
configure_user.bash zajmuje się wyłącznie $HOME.
#!/usr/bin/env bash
set -euo pipefail
echo "===> Configure user profile"
cp /userfiles/.zshrc "$HOME/.zshrc" || true
cp /userfiles/.gitconfig "$HOME/.gitconfig" || true
cp /userfiles/.gitignore_global "$HOME/.gitignore_global" || true
mkdir -p "$HOME/.ssh"
chmod 700 "$HOME/.ssh"
cp -a /userfiles/.ssh/. "$HOME/.ssh/" || true
chmod 600 "$HOME/.ssh"/* 2>/dev/null || true
Efekt:
- klucze SSH dostępne w kontenerze,
- Git skonfigurowany globalnie,
- brak duplikowania sekretów w repozytorium.
Efekt końcowy
Po otwarciu repozytorium w VS Code:
- kontener buduje się automatycznie,
- CA z Vaulta są zaufane,
- Git i SSH działają od razu,
- developer może od razu pracować, bez setupu lokalnego.
To podejście sprawdza się szczególnie dobrze w zespołach DevOps / Platform Engineering, gdzie:
- środowiska muszą być powtarzalne,
- bezpieczeństwo (PKI, klucze) ma znaczenie,
- repozytoria nie powinny zawierać konfiguracji użytkownika.
Przygotowanie środowiska deweloperskiego z Vagrant
W tym wpisie pokazuję, jak przygotować własny obraz Ubuntu 24.10 dla Vagranta, opublikować go w rejestrze Vagrant Cloud (lub przez alternatywny hosting) oraz jak uruchomić środowisko deweloperskie przy pomocy vagrant up.
Cały proces ilustruje poniższy diagram:
---
config:
theme: neo
layout: dagre
look: neo
---
flowchart LR
subgraph s1["Przygotowanie obrazu"]
n5["Przygotowanie maszyny<br>wirtualnej na virtualbox"]
n6@{ label: "<span style=\"padding-left:\">Utworzenie box<br></span><span style=\"padding-left:\">(vagrant package)</span>" }
n7@{ label: "Wysłanie do<br style=\"--tw-scale-x:\">Vagrant box Registry" }
end
subgraph s2["Użycie obrazu (vagrant up)"]
n8["vagrant up"]
n9["run bootstrap.bash"]
n11["bash scripts"]
end
n5 --> n6
n6 --> n7
s1 --> s2
n8 --> n9
s2 --> n10("Ready to use")
n9 --> n11
n5@{ shape: rect}
n6@{ shape: rect}
n7@{ shape: rect}
n9@{ shape: lean-r}
n11@{ shape: procs}
click n5 "#przygotowanie-maszyny-wirtualnej-na-virtualboxie"
click n6 "#utworzenie-box"
click n7 "#wys%c5%82anie-do-vagrant-box-registry"
click n8 "#użycie-obrazu-vagrant-up"
click n9 "#ręczne-uruchomienie-bootstrapbash"
Przygotowanie maszyny wirtualnej na virtualboxie
Przygotowałem maszynę wirtualną na virtualbox ubuntu 24-10
z użytkownikiem vagrant hasłem vagrant
echo "vagrant ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/vagrant
sudo apt-get update
sudo apt-get dist-upgrade -y
sudo apt install -y openssh-server curl wget sudo
sudo apt install -y build-essential dkms linux-headers-$(uname -r)
mkdir -p /home/vagrant/.ssh
curl -fsSL https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant.pub -o /home/vagrant/.ssh/authorized_keys
chown -R vagrant:vagrant /home/vagrant/.ssh
chmod 700 /home/vagrant/.ssh
chmod 600 /home/vagrant/.ssh/authorized_keys
sudo apt-get autoremove -y
sudo apt-get clean
sudo rm -rf /var/lib/apt/lists/*
sudo timedatectl set-timezone UTC
sudo locale-gen en_US.UTF-8
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
Utworzenie box
vagrant package --base ubuntu-24-10 --output ubuntu-24.10.box
m@nbo-001-mr ~ vagrant package --base ubuntu-24-10 --output ubuntu-24.10.box
==> ubuntu-24-10: Exporting VM...
==> ubuntu-24-10: Compressing package to: /home/maciej-rachuna/ubuntu-24.10.box
m@nbo-001-mr ~ ls -l |grep ubuntu-24
-rw-rw-r-- 1 m m 1871476745 lip 23 08:49 ubuntu-24.10.box
Wysłanie do Vagrant box Registry
U mnie z jakiegoś powodu opcja nie działa, więc wrzuciłem obraz przez UI
vagrant cloud auth login
Użycie obrazu (vagrant up)
Pobranie repozytorium z vagrantem
git clone https://gitlab.com/pl.rachuna-net/tools/vagrant.git
Uruchomienie maszyny developerskiej
chmod +x start_vm.bash
./start_vm.bash
bootstrap.bash
vagrant up automatycznie uruchomi bootstrap.bashm@nbo-001-mr /repo/pl.rachuna-net/tools/vagrant (main) vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Checking if box 'rachuna-net.pl/ubuntu-24-10' version '1.0.0' is up to date...
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: flag to force provisioning. Provisioners marked to run always will still run.
==> default: Running provisioner: shell...
default: Running: /tmp/vagrant-shell20250723-96391-b06anr.bash
default: ===> 🚀 Run bootstrap script
default: ===> 📁 Copy userfiles to /root
default: ===> 🚀 Running script: /vagrant/provisioning/upgrade-ubuntu.bash
default: ===> Upgrade system packages and distribution
default: ===> 🚀 Running script: /vagrant/provisioning/install-packages.bash
default: ===> Install packages
default: ===> 🚀 Running script: /vagrant/provisioning/bootstrap-certs.bash
default: ===> Pobieranie CA certyfikatu dla rachuna-net.pl
default: ===> 🚀 Running script: /vagrant/provisioning/install-hashicorp.bash
default: ===> 🚀 Running script: /vagrant/provisioning/install-zsh.bash
default: ===> 🚀 Running script: /vagrant/provisioning/install-hugo.bash
Dostęp do maszyny wirtualnej
- SSH jest dostępne na porcie
2222na hoście, przekierowanym do portu22w VM. - Włączone jest przekazywanie agenta SSH oraz X11.
- Połączenie można nawiązać poleceniem:
ssh -p 2222 vagrant@localhost
Edytuj plik
~/.ssh/config, dodając wpis:Host dev-station HostName 127.0.0.1 Port 2222 User vagrant IdentityFile /repo/pl.rachuna-net/tools/vagrant/.vagrant/machines/default/virtualbox/private_key ForwardX11 yesDzięki temu możesz łatwo łączyć się z maszyną wirtualną za pomocą polecenia:
ssh dev-station
Ręczne uruchomienie bootstrap.bash
vagrant@dev-station:/vagrant$ cd /vagrant/
vagrant@dev-station:/vagrant$ chmod +x bootstrap.bash
vagrant@dev-station:/vagrant$ ./bootstrap.bash
===> 🚀 Run bootstrap script
===> 📁 Copy userfiles to /home/vagrant
===> 🚀 Running script: /vagrant/provisioning/upgrade-ubuntu.bash
===> Upgrade system packages and distribution
===> 🚀 Running script: /vagrant/provisioning/install-packages.bash
===> Install packages
===> 🚀 Running script: /vagrant/provisioning/bootstrap-certs.bash
===> Pobieranie CA certyfikatu dla rachuna-net.pl
===> 🚀 Running script: /vagrant/provisioning/install-hashicorp.bash
===> 🚀 Running script: /vagrant/provisioning/install-zsh.bash
===> 🚀 Running script: /vagrant/provisioning/install-hugo.bash
Przygotowanie środowiska LAB
W ostatnim czasie postanowiłem zrealizować długo odkładaną wizję – stworzyć własne laboratorium IT w domu, które pozwoli mi ćwiczyć i testować technologie DevOps w praktyce. Pomysł powstał z potrzeby eksperymentowania w środowisku zbliżonym do produkcyjnego, ale przy minimalnych kosztach i maksymalnej elastyczności.
Wybór sprzętu: Mini PC jako fundament laboratorium
Do budowy mojego LAB-a wybrałem trzy kompaktowe Mini PC. Powody są proste: niski pobór energii, cicha praca i wystarczająca moc obliczeniowa do uruchamiania wielu maszyn wirtualnych. Każda z maszyn będzie pełnić rolę węzła wirtualizacyjnego, na którym zainstaluję Proxmox VE – sprawdzone narzędzie do zarządzania wirtualizacją i kontenerami LXC/VM. Dzięki temu będę miał pełną kontrolę nad maszynami wirtualnymi, snapshotami i klastrami HA, co jest kluczowe przy testach infrastruktury.
Storage na Synology
Kluczowym elementem mojego LAB-a będzie centralny storage. Postawiłem na NAS Synology, który zapewnia nie tylko przestrzeń dyskową, ale również funkcje zaawansowanego zarządzania danymi, backupu i dostępności przez sieć. Wszystkie Mini PC będą korzystać z Synology jako magazynu dla maszyn wirtualnych i obrazów systemów, co pozwoli mi w prosty sposób tworzyć i przenosić VM-y pomiędzy węzłami. Dodatkowo, Synology umożliwia implementację iSCSI czy NFS, co idealnie integruje się z Proxmoxem.
Sieć zarządzana przez Mikrotika
Żeby móc testować złożone scenariusze sieciowe i DevOpsowe, potrzebowałem elastycznego rozwiązania do zarządzania siecią. W tym celu wybrałem router MikroTik. Dzięki niemu mogę tworzyć VLAN-y, testować routing, firewall, VPN-y i QoS. To pozwoli mi symulować środowiska produkcyjne, gdzie różne usługi i zespoły korzystają z odseparowanych segmentów sieci. MikroTik zapewnia też świetny interfejs do monitorowania ruchu i diagnostyki problemów w sieci.
Plany rozwoju: Kubernetes i DevOps
Budowa laboratorium to dopiero początek. Moim celem jest stopniowe wdrażanie technologii kontenerowych i DevOpsowych. W najbliższym czasie planuję postawić Kubernetes na trzech węzłach Mini PC, co pozwoli mi testować skalowanie aplikacji, zarządzanie konfiguracją, automatyczne deploymenty i monitoring usług.
Dalej chcę zintegrować narzędzia typowe dla DevOps, takie jak:
- CI/CD – Jenkins, GitLab CI/CD lub ArgoCD,
- Monitoring i logowanie – Prometheus, Grafana, Loki,
- Kontenery i obrazowanie – Docker i Harbor,
- Zarządzanie konfiguracją – Ansible, Terraform, Helm.
Dzięki temu będę mógł ćwiczyć całe cykle DevOpsowe – od budowy aplikacji, przez automatyzację wdrożeń, aż po monitoring i optymalizację wydajności.
Zalety własnego LAB-a
Posiadanie własnego środowiska testowego daje nieocenione możliwości:
- Eksperymentowanie bez ryzyka – mogę testować konfiguracje produkcyjne bez obawy o wpływ na rzeczywiste systemy.
- Praktyczna nauka – od wirtualizacji, przez sieci, po Kubernetes i CI/CD.
- Elastyczność – możliwość szybkiego tworzenia i usuwania maszyn wirtualnych, wdrażania usług i testowania scenariuszy awaryjnych.
- Nauka DevOps od A do Z – zrozumienie, jak wszystkie warstwy infrastruktury współpracują ze sobą.
Podsumowanie
Budowa domowego laboratorium DevOps na Mini PC, z Proxmoxem, Synology jako centralnym storage’em i siecią zarządzaną przez MikroTika, to nie tylko świetna zabawa, ale też praktyczna inwestycja w rozwój umiejętności IT. W przyszłości planuję rozbudować LAB o Kubernetes, narzędzia CI/CD i monitoring, co pozwoli mi w pełni odtworzyć środowisko zbliżone do rzeczywistego centrum danych. To idealne miejsce do nauki, testowania i eksperymentowania z nowoczesnymi technologiami DevOps.