Kontener deweloperski z z pluginem vscode devcontainers
2 minute read
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.