├── CNAME ├── install ├── CNAME └── index.html ├── .vscode ├── settings.json ├── launch.json └── readme.md ├── girus-logo.png ├── LINUXtips-logo.png ├── internal ├── common │ ├── init.go │ ├── i18n.go │ ├── language.go │ ├── config.go │ └── version.go ├── templates │ ├── manifests_es │ │ ├── lab_11_linux_comandos-basicos.yaml │ │ ├── lab_35_terraform_fundamentos.yaml │ │ ├── lab_04_linux_monitoramento-sistema.yaml │ │ └── lab_10_kubernetes_configmaps-secrets.yaml │ ├── templates.go │ ├── manifests_test.go │ └── manifests │ │ └── lab_04_linux_monitoramento-sistema.yaml ├── repo │ ├── example │ │ ├── index.yaml │ │ └── linux-basics │ │ │ └── lab.yaml │ ├── README.md │ └── lab.go └── helpers │ └── helpers.go ├── main.go ├── cmd ├── version.go ├── root.go ├── repo.go ├── start.go └── stop.go ├── .golangci.yml ├── .gitignore ├── .dockerignore ├── .github ├── workflows │ ├── lint.yml │ ├── badge.yml │ ├── test.yml │ ├── docker.yml │ ├── release.yml │ └── build.yml └── dependabot.yml ├── labs ├── exemplo-lab │ ├── lab.yaml │ └── lab_es.yaml ├── docker_volumes-persistencia │ ├── lab.yaml │ └── lab_es.yaml ├── kubernetes_deployments-replicasets │ ├── lab.yaml │ └── lab_es.yaml ├── docker_redes-avancadas │ ├── lab.yaml │ └── lab_es.yaml ├── kubernetes_services-networking │ ├── lab.yaml │ └── lab_es.yaml ├── linux_redes-conectividade │ ├── lab.yaml │ └── lab_es.yaml ├── linux_seguranca-criptografia │ └── lab.yaml ├── linux_automacao-agendamento │ └── lab.yaml ├── terraform_fundamentos │ ├── lab.yaml │ └── lab_es.yaml ├── aws_s3-iam │ ├── lab.yaml │ └── lab_es.yaml ├── linux_monitoramento-sistema │ ├── lab.yaml │ └── lab_es.yaml ├── docker_multi-stage-builds │ └── lab.yaml ├── kubernetes_configmaps-secrets │ ├── lab.yaml │ └── lab_es.yaml ├── aws_rds-elasticache │ ├── lab.yaml │ └── lab_es.yaml ├── terraform_estado-remoto │ ├── lab.yaml │ └── lab_es.yaml ├── aws_ec2-vpc │ ├── lab.yaml │ └── lab_es.yaml └── terraform_modulos │ ├── lab.yaml │ └── lab_es.yaml ├── Dockerfile ├── .goreleaser.yml ├── go.mod ├── Makefile └── README.es.md /CNAME: -------------------------------------------------------------------------------- 1 | girus.linuxtips.io -------------------------------------------------------------------------------- /install/CNAME: -------------------------------------------------------------------------------- 1 | girus.linuxtips.io -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "makefile.configureOnOpen": false 3 | } -------------------------------------------------------------------------------- /girus-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/badtuxx/girus-cli/HEAD/girus-logo.png -------------------------------------------------------------------------------- /LINUXtips-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/badtuxx/girus-cli/HEAD/LINUXtips-logo.png -------------------------------------------------------------------------------- /internal/common/init.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | func init() { 4 | cfg := LoadConfig() 5 | SetLanguage(cfg.Language) 6 | } 7 | -------------------------------------------------------------------------------- /internal/common/i18n.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | // T retorna a string traduzida de acordo com o idioma atual 4 | func T(pt, es string) string { 5 | if Lang() == "es" { 6 | return es 7 | } 8 | return pt 9 | } 10 | -------------------------------------------------------------------------------- /internal/common/language.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | var language = "pt" 4 | 5 | // SetLanguage define o idioma atual do CLI 6 | func SetLanguage(lang string) { 7 | if lang != "" { 8 | language = lang 9 | } 10 | } 11 | 12 | // Lang retorna o idioma atual 13 | func Lang() string { return language } 14 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/badtuxx/girus-cli/cmd" 8 | "github.com/badtuxx/girus-cli/internal/common" 9 | ) 10 | 11 | func main() { 12 | cfg := common.LoadConfig() 13 | common.SetLanguage(cfg.Language) 14 | if err := cmd.Execute(); err != nil { 15 | fmt.Fprintf(os.Stderr, "Erro ao executar o comando: %s\n", err) 16 | os.Exit(1) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/badtuxx/girus-cli/internal/common" 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | var versionCmd = &cobra.Command{ 11 | Use: "version", 12 | Short: common.T("Exibe a versão do Girus CLI", "Muestra la versión del Girus CLI"), 13 | Run: func(cmd *cobra.Command, args []string) { 14 | fmt.Print(common.GetVersion()) 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | linters: 3 | disable: 4 | - errcheck 5 | exclusions: 6 | generated: lax 7 | presets: 8 | - comments 9 | - common-false-positives 10 | - legacy 11 | - std-error-handling 12 | paths: 13 | - third_party$ 14 | - builtin$ 15 | - examples$ 16 | formatters: 17 | exclusions: 18 | generated: lax 19 | paths: 20 | - third_party$ 21 | - builtin$ 22 | - examples$ 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Go 3 | # Binários de compilação 4 | *.exe 5 | *.exe~ 6 | *.dll 7 | *.so 8 | *.dylib 9 | *.test 10 | *.out 11 | 12 | # Diretórios de build 13 | /bin/ 14 | dist/ 15 | 16 | # Cache do módulo Go 17 | vendor/ 18 | 19 | # Arquivos de saída 20 | *.log 21 | 22 | # Arquivos do sistema operacional 23 | .DS_Store 24 | .AppleDouble 25 | .LSOverride 26 | 27 | # Arquivos temporários 28 | Icon? 29 | ehthumbs.db 30 | Thumbs.db 31 | 32 | # Arquivos de IDEs e editores 33 | # Goland / JetBrains 34 | .idea/ 35 | # Vim 36 | *.swp 37 | *.swo 38 | 39 | # Cobertura de testes 40 | *.coverprofile 41 | *.coverage 42 | *.cov 43 | coverage.out 44 | 45 | # Logs de testes 46 | testdata/ 47 | 48 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # Include any files or directories that you don't want to be copied to your 2 | # container here (e.g., local build artifacts, temporary files, etc.). 3 | # 4 | # For more help, visit the .dockerignore file reference guide at 5 | # https://docs.docker.com/go/build-context-dockerignore/ 6 | 7 | **/.DS_Store 8 | **/.classpath 9 | **/.dockerignore 10 | **/.env 11 | **/.git 12 | **/.gitignore 13 | **/.project 14 | **/.settings 15 | **/.toolstarget 16 | **/.vs 17 | **/.vscode 18 | **/*.*proj.user 19 | **/*.dbmdl 20 | **/*.jfm 21 | **/bin 22 | **/charts 23 | **/docker-compose* 24 | **/compose.y*ml 25 | **/Dockerfile* 26 | **/node_modules 27 | **/npm-debug.log 28 | **/obj 29 | **/secrets.dev.yaml 30 | **/values.dev.yaml 31 | LICENSE 32 | README.md 33 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - 'main' 7 | 8 | permissions: {} 9 | 10 | jobs: 11 | golangci: 12 | name: lint 13 | runs-on: ubuntu-latest 14 | 15 | permissions: 16 | contents: read 17 | 18 | steps: 19 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 20 | with: 21 | persist-credentials: false 22 | 23 | - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 24 | with: 25 | go-version-file: './go.mod' 26 | check-latest: true 27 | 28 | - name: golangci-lint 29 | uses: golangci/golangci-lint-action@v6.1.1 30 | with: 31 | version: latest 32 | -------------------------------------------------------------------------------- /.github/workflows/badge.yml: -------------------------------------------------------------------------------- 1 | name: Build Status 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: {} 9 | 10 | jobs: 11 | badge: 12 | name: Update Build Status Badge 13 | runs-on: ubuntu-latest 14 | 15 | permissions: 16 | contents: read 17 | 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 21 | with: 22 | persist-credentials: false 23 | 24 | - name: Generate Badge 25 | uses: RubbaBoy/BYOB@24f464284c1fd32028524b59607d417a2e36fee7 # v1.3.0 26 | with: 27 | NAME: build 28 | LABEL: build 29 | STATUS: ${{ job.status }} 30 | COLOR: green 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | permissions: {} 12 | 13 | jobs: 14 | test: 15 | name: Test 16 | runs-on: ubuntu-latest 17 | 18 | permissions: 19 | contents: read 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 24 | 25 | - name: Set up Go 26 | uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 27 | with: 28 | go-version: '1.24' 29 | check-latest: true 30 | 31 | - name: Install dependencies 32 | run: go mod download 33 | 34 | - name: Run tests 35 | run: go test -v ./... 36 | -------------------------------------------------------------------------------- /internal/common/config.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | "gopkg.in/yaml.v3" 8 | ) 9 | 10 | type Config struct { 11 | Language string `yaml:"language"` 12 | } 13 | 14 | var configPath string 15 | 16 | // LoadConfig lê o arquivo de configuração padrão ~/.girus/config.yaml 17 | func LoadConfig() *Config { 18 | home, err := os.UserHomeDir() 19 | if err != nil { 20 | return &Config{Language: "pt"} 21 | } 22 | if configPath == "" { 23 | configPath = filepath.Join(home, ".girus", "config.yaml") 24 | } 25 | data, err := os.ReadFile(configPath) 26 | if err != nil { 27 | return &Config{Language: "pt"} 28 | } 29 | var cfg Config 30 | if err := yaml.Unmarshal(data, &cfg); err != nil { 31 | return &Config{Language: "pt"} 32 | } 33 | if cfg.Language == "" { 34 | cfg.Language = "pt" 35 | } 36 | return &cfg 37 | } 38 | -------------------------------------------------------------------------------- /internal/templates/manifests_es/lab_11_linux_comandos-basicos.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: linux-comandos-basicos-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: linux-comandos-basicos-es 11 | title: "Fundamentos de Linux: Navegación y Comandos Esenciales" 12 | description: "Aprende los comandos básicos y conceptos fundamentales de Linux para operar de manera eficiente en la línea de comandos." 13 | duration: 20m 14 | image: "linuxtips/girus-devops:0.1" 15 | tasks: 16 | - name: "Navegación en el Sistema de Archivos" 17 | description: "Explora la estructura de directorios de Linux y aprende a moverte con facilidad." 18 | steps: 19 | - "Usa `pwd` para mostrar el directorio actual" 20 | - "Usa `ls` para listar archivos" 21 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Launch Girus CLI", 6 | "type": "go", 7 | "request": "launch", 8 | "mode": "auto", 9 | "program": "${workspaceFolder}", 10 | "cwd": "${workspaceFolder}", 11 | "env": { 12 | "CONFIG_FILE": "manifest/config.yaml" 13 | }, 14 | "args": [ 15 | "create", 16 | "cluster" 17 | // "--verbose" 18 | ], 19 | "console": "integratedTerminal", 20 | "showLog": true 21 | }, 22 | { 23 | "type": "bashdb", 24 | "request": "launch", 25 | "name": "Debug Bash script", 26 | "program": "install.sh", 27 | "args": [], 28 | "cwd": "${workspaceFolder}" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /labs/exemplo-lab/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: girus.linuxtips.io/v1 2 | kind: Lab 3 | metadata: 4 | name: exemplo-lab 5 | version: "1.0.0" 6 | description: "Laboratório de exemplo do GIRUS CLI" 7 | author: "Seu Nome" 8 | created: "2024-06-01T10:00:00Z" 9 | spec: 10 | environment: 11 | image: ubuntu:22.04 12 | resources: 13 | cpu: "1" 14 | memory: "512Mi" 15 | volumes: 16 | - name: workspace 17 | mountPath: /workspace 18 | size: "512Mi" 19 | tasks: 20 | - name: "Primeiro Comando" 21 | description: "Aprenda a rodar comandos básicos no Linux" 22 | steps: 23 | - description: "Mostre o diretório atual" 24 | command: "pwd" 25 | expectedOutput: "/workspace" 26 | hint: "Use o comando pwd" 27 | validation: 28 | - name: "Validação Final" 29 | description: "Verifica se o usuário executou o comando pwd" 30 | checks: 31 | - command: "pwd" 32 | expectedOutput: "/workspace" 33 | errorMessage: "O diretório não está correto" 34 | -------------------------------------------------------------------------------- /internal/templates/templates.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | import ( 4 | "embed" 5 | "io/fs" 6 | "path/filepath" 7 | 8 | "github.com/badtuxx/girus-cli/internal/common" 9 | ) 10 | 11 | //go:embed manifests/*.yaml manifests_es/*.yaml 12 | var ManifestFS embed.FS 13 | 14 | func GetManifest(name string) ([]byte, error) { 15 | dir := "manifests" 16 | if common.Lang() == "es" { 17 | dir = "manifests_es" 18 | } 19 | return fs.ReadFile(ManifestFS, filepath.Join(dir, name)) 20 | } 21 | 22 | // ListManifests retorna uma lista de nomes de todos os arquivos YAML no diretório de manifests 23 | func ListManifests() ([]string, error) { 24 | dir := "manifests" 25 | if common.Lang() == "es" { 26 | dir = "manifests_es" 27 | } 28 | entries, err := fs.ReadDir(ManifestFS, dir) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | var manifests []string 34 | for _, entry := range entries { 35 | if !entry.IsDir() && filepath.Ext(entry.Name()) == ".yaml" { 36 | manifests = append(manifests, entry.Name()) 37 | } 38 | } 39 | 40 | return manifests, nil 41 | } 42 | -------------------------------------------------------------------------------- /labs/exemplo-lab/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: girus.linuxtips.io/v1 2 | kind: Lab 3 | metadata: 4 | name: ejemplo-lab-es 5 | version: "1.0.0" 6 | description: "laboratorio de ejemplo de GIRUS CLI" 7 | author: "Su Nombre" 8 | created: "2024-06-01T10:00:00Z" 9 | spec: 10 | environment: 11 | image: ubuntu:22.04 12 | resources: 13 | cpu: "1" 14 | memory: "512Mi" 15 | volumes: 16 | - name: workspace 17 | mountPath: /workspace 18 | size: "512Mi" 19 | tasks: 20 | - name: "Primer comando" 21 | description: "aprende a ejecutar comandos básicos en Linux" 22 | steps: 23 | - description: "Muestre el directorio actual" 24 | command: "pwd" 25 | expectedOutput: "/workspace" 26 | hint: "Use el comando pwd" 27 | validation: 28 | - name: "Validación Final" 29 | description: "Verifica si el usuario ejecutó el comando pwd" 30 | checks: 31 | - command: "pwd" 32 | expectedOutput: "/workspace" 33 | errorMessage: "El directorio no está correcto" 34 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.24-alpine AS builder 2 | 3 | WORKDIR /app 4 | 5 | # Copy go.mod and go.sum first to leverage Docker cache 6 | COPY go.mod go.sum ./ 7 | RUN go mod download 8 | 9 | # Copy the rest of the source code 10 | COPY . . 11 | 12 | # Build the application 13 | ARG VERSION=dev 14 | RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o girus -ldflags="-X 'github.com/badtuxx/girus-cli/internal/common.Version=${VERSION}'" ./main.go 15 | 16 | # Use a minimal alpine image for the final container 17 | FROM alpine:3.22 18 | 19 | # Install necessary packages 20 | RUN apk add --no-cache ca-certificates curl bash docker-cli 21 | 22 | # Install kind and kubectl 23 | RUN curl -Lo /usr/local/bin/kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64 && \ 24 | chmod +x /usr/local/bin/kind && \ 25 | curl -Lo /usr/local/bin/kubectl "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" && \ 26 | chmod +x /usr/local/bin/kubectl 27 | 28 | WORKDIR /app 29 | 30 | # Copy the binary from the builder stage 31 | COPY --from=builder /app/girus /usr/local/bin/girus 32 | 33 | # Create entrypoint 34 | ENTRYPOINT ["/usr/local/bin/girus"] 35 | 36 | # Default command 37 | CMD ["help"] 38 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Manter dependências do Go atualizadas 4 | - package-ecosystem: "gomod" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | day: "monday" 9 | time: "09:00" 10 | timezone: "America/Sao_Paulo" 11 | open-pull-requests-limit: 10 12 | labels: 13 | - "dependencies" 14 | - "go" 15 | commit-message: 16 | prefix: "chore(deps)" 17 | include: "scope" 18 | 19 | # Manter ações do GitHub atualizadas 20 | - package-ecosystem: "github-actions" 21 | directory: "/" 22 | schedule: 23 | interval: "weekly" 24 | day: "monday" 25 | time: "09:00" 26 | timezone: "America/Sao_Paulo" 27 | open-pull-requests-limit: 10 28 | labels: 29 | - "dependencies" 30 | - "github-actions" 31 | commit-message: 32 | prefix: "chore(deps)" 33 | include: "scope" 34 | 35 | # Manter imagens Docker atualizadas 36 | - package-ecosystem: "docker" 37 | directory: "/" 38 | schedule: 39 | interval: "weekly" 40 | day: "monday" 41 | time: "09:00" 42 | timezone: "America/Sao_Paulo" 43 | open-pull-requests-limit: 10 44 | labels: 45 | - "dependencies" 46 | - "docker" 47 | commit-message: 48 | prefix: "chore(deps)" 49 | include: "scope" 50 | -------------------------------------------------------------------------------- /internal/common/version.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | var ( 9 | Version string 10 | BuildUser string 11 | BuildDate string 12 | CommitID string 13 | GoVersion string 14 | GoOS string 15 | GoArch string 16 | ) 17 | 18 | func getDefaultIfEmpty(value, defaultValue string) string { 19 | if value == "" { 20 | return defaultValue 21 | } 22 | return value 23 | } 24 | 25 | func GetVersion() string { 26 | version := getDefaultIfEmpty(Version, "dev") 27 | buildUser := getDefaultIfEmpty(BuildUser, "unknown") 28 | buildDate := getDefaultIfEmpty(BuildDate, "unknown") 29 | commitID := getDefaultIfEmpty(CommitID, "unknown") 30 | goVersion := getDefaultIfEmpty(GoVersion, runtime.Version()) 31 | goOS := getDefaultIfEmpty(GoOS, runtime.GOOS) 32 | goArch := getDefaultIfEmpty(GoArch, runtime.GOARCH) 33 | if Lang() == "es" { 34 | return fmt.Sprintf( 35 | "versión de girus-cli: %s\n"+ 36 | "ID de commit: %s\n"+ 37 | "construido por: %s\n"+ 38 | "fecha de construcción: %s\n"+ 39 | "versión de Go: %s\n"+ 40 | "versión de GOOS: %s\n"+ 41 | "versión de GOARCH: %s\n", 42 | version, commitID, buildUser, buildDate, goVersion, goOS, goArch, 43 | ) 44 | } 45 | 46 | return fmt.Sprintf( 47 | "versão do girus-cli: %s\n"+ 48 | "commit ID: %s\n"+ 49 | "build por: %s\n"+ 50 | "data da versão: %s\n"+ 51 | "versão do Go: %s\n"+ 52 | "versão do GOOS: %s\n"+ 53 | "versão do GOARCH: %s\n", 54 | version, commitID, buildUser, buildDate, goVersion, goOS, goArch, 55 | ) 56 | } 57 | -------------------------------------------------------------------------------- /.vscode/readme.md: -------------------------------------------------------------------------------- 1 | # Depurando Bash Scripts no VS Code 2 | 3 | O VS Code não possui um depurador de Bash nativo. Para depurar arquivos `.sh`, você precisa instalar uma extensão específica. 4 | 5 | **Extensão Recomendada:** 6 | 7 | * **Nome:** Bash Debug 8 | * **ID:** `rogalmic.bash-debug` 9 | * **Link:** Bash Debug no Marketplace 10 | 11 | **Instalação:** 12 | 13 | Você pode instalar a extensão pela interface do VS Code (procurando por `rogalmic.bash-debug`) ou diretamente pelo terminal: 14 | 15 | ```bash 16 | code --install-extension rogalmic.bash-debug 17 | ``` 18 | 19 | ### Importante: 20 | 21 | Este é um depurador simples. Ele é muito útil para tarefas básicas como definir breakpoints, avançar linha por linha (step over/into/out) e inspecionar variáveis simples. 22 | Recursos mais avançados do Bash, como o comando eval ou manipulações complexas de subshells, podem não funcionar como esperado ou não ser totalmente suportados pelo depurador. Use-o como uma ferramenta auxiliar para entender o fluxo do script, mas esteja ciente de suas limitações. 23 | 24 | 25 | # Depurando Código Go 26 | 27 | A depuração de código Go no VS Code é geralmente mais direta, pois é suportada pela extensão oficial do Go. 28 | 29 | você só precisa adicionar breakpoints e iniciar a depuração. O VS Code irá compilar o código automaticamente e iniciar o depurador. 30 | 31 | Pré-requisitos: 32 | 33 | * Tenha a extensão Go para VS Code instalada. Ela geralmente é recomendada automaticamente ao abrir um projeto Go. 34 | * A extensão Go utiliza ferramentas como gopls (o language server) e dlv (o depurador Delve). 35 | -------------------------------------------------------------------------------- /internal/repo/example/index.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | generated: "2024-03-20T10:00:00Z" 3 | entries: 4 | linux-basics: 5 | - name: linux-basics 6 | version: "1.0.0" 7 | description: "Introdução aos comandos básicos do Linux" 8 | keywords: 9 | - linux 10 | - basics 11 | - terminal 12 | - commands 13 | maintainers: 14 | - "LINUXtips Team " 15 | url: "https://github.com/linuxtips/labs/raw/main/linux-basics/lab.yaml" 16 | created: "2024-03-20T10:00:00Z" 17 | digest: "sha256:1234567890abcdef" 18 | - name: linux-basics 19 | version: "1.1.0" 20 | description: "Introdução aos comandos básicos do Linux (atualizado)" 21 | keywords: 22 | - linux 23 | - basics 24 | - terminal 25 | - commands 26 | maintainers: 27 | - "LINUXtips Team " 28 | url: "https://github.com/linuxtips/labs/raw/main/linux-basics/v1.1.0/lab.yaml" 29 | created: "2024-03-21T15:30:00Z" 30 | digest: "sha256:abcdef1234567890" 31 | 32 | docker-intro: 33 | - name: docker-intro 34 | version: "1.0.0" 35 | description: "Introdução ao Docker e containers" 36 | keywords: 37 | - docker 38 | - containers 39 | - devops 40 | - virtualization 41 | maintainers: 42 | - "LINUXtips Team " 43 | url: "https://github.com/linuxtips/labs/raw/main/docker-intro/lab.yaml" 44 | created: "2024-03-20T11:00:00Z" 45 | digest: "sha256:0987654321fedcba" 46 | 47 | kubernetes-fundamentals: 48 | - name: kubernetes-fundamentals 49 | version: "1.0.0" 50 | description: "Fundamentos do Kubernetes" 51 | keywords: 52 | - kubernetes 53 | - k8s 54 | - containers 55 | - orchestration 56 | maintainers: 57 | - "LINUXtips Team " 58 | url: "https://github.com/linuxtips/labs/raw/main/kubernetes-fundamentals/lab.yaml" 59 | created: "2024-03-20T12:00:00Z" 60 | digest: "sha256:fedcba0987654321" 61 | -------------------------------------------------------------------------------- /internal/templates/manifests_test.go: -------------------------------------------------------------------------------- 1 | package templates_test 2 | 3 | import ( 4 | "embed" 5 | "path/filepath" 6 | "reflect" 7 | "testing" 8 | 9 | "io/fs" 10 | 11 | "github.com/badtuxx/girus-cli/internal/templates" 12 | "gopkg.in/yaml.v3" 13 | ) 14 | 15 | //go:embed manifests/*.yaml 16 | var manifests embed.FS 17 | 18 | func TestYAMLFilesAreValid(t *testing.T) { 19 | err := fs.WalkDir(manifests, ".", func(path string, d fs.DirEntry, err error) error { 20 | if err != nil { 21 | return err 22 | } 23 | 24 | if !d.IsDir() && filepath.Ext(path) == ".yaml" { 25 | data, err := manifests.ReadFile(path) 26 | if err != nil { 27 | t.Errorf("Erro ao ler %s: %v", path, err) 28 | return nil 29 | } 30 | 31 | var node yaml.Node 32 | if err := yaml.Unmarshal(data, &node); err != nil { 33 | t.Errorf("YAML inválido em %s: %v", path, err) 34 | } 35 | } 36 | 37 | return nil 38 | }) 39 | 40 | if err != nil { 41 | t.Fatalf("Erro ao percorrer diretório de manifests: %v", err) 42 | } 43 | } 44 | 45 | func TestListAndGetManifests(t *testing.T) { 46 | entries, err := fs.ReadDir(manifests, "manifests") 47 | if err != nil { 48 | t.Fatalf("erro ao ler diretório embed: %v", err) 49 | } 50 | 51 | var expected []string 52 | for _, entry := range entries { 53 | if !entry.IsDir() && filepath.Ext(entry.Name()) == ".yaml" { 54 | expected = append(expected, entry.Name()) 55 | } 56 | } 57 | 58 | names, err := templates.ListManifests() 59 | if err != nil { 60 | t.Fatalf("ListManifests retornou erro: %v", err) 61 | } 62 | 63 | if !reflect.DeepEqual(expected, names) { 64 | t.Errorf("nomes esperados %v, obtidos %v", expected, names) 65 | } 66 | 67 | for _, name := range names { 68 | t.Run(name, func(t *testing.T) { 69 | data, err := templates.GetManifest(name) 70 | if err != nil { 71 | t.Fatalf("erro ao obter %s: %v", name, err) 72 | } 73 | 74 | if len(data) == 0 { 75 | t.Fatalf("%s retornou dados vazios", name) 76 | } 77 | 78 | var node yaml.Node 79 | if err := yaml.Unmarshal(data, &node); err != nil { 80 | t.Errorf("YAML inválido em %s: %v", name, err) 81 | } 82 | }) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /install/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Girus CLI - LINUXtips 6 | 7 | 8 | 10 | 51 | 56 | 57 | 58 | 59 | 61 |

Girus CLI - LINUXtips

62 |
63 |

Baixando o script de instalação...

64 |

Se o download não iniciar automaticamente, execute:

65 |
66 |
67 | curl -fsSL https://girus.linuxtips.io | bash 68 |
69 |

70 | Visite o repositório no GitHub 71 |

72 | 73 | 74 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | project_name: girus-cli 2 | version: 2 3 | 4 | # Prevents parallel builds from stepping on each others toes downloading modules 5 | before: 6 | hooks: 7 | - go mod tidy 8 | - git --no-pager diff --exit-code go.mod go.sum 9 | 10 | gomod: 11 | proxy: true 12 | 13 | sboms: 14 | - artifacts: binary 15 | 16 | builds: 17 | - id: girus-cli 18 | binary: girus-cli-{{ .Os }}-{{ .Arch }} 19 | no_unique_dist_dir: true 20 | main: . 21 | flags: 22 | - -trimpath 23 | mod_timestamp: "{{ .CommitTimestamp }}" 24 | goos: 25 | - linux 26 | - darwin 27 | - windows 28 | goarch: 29 | - amd64 30 | - arm64 31 | env: 32 | - CGO_ENABLED=0 33 | ldflags: 34 | - -s -w -X github.com/badtuxx/girus-cli/internal/common.Version={{ .Version }} 35 | - -X github.com/badtuxx/girus-cli/internal/common.BuildDate={{ .Date }} 36 | - -X github.com/badtuxx/girus-cli/internal/common.CommitID={{ .ShortCommit }} 37 | - -X github.com/badtuxx/girus-cli/internal/common.BuildUser={{ .Env.GITHUB_ACTOR }} 38 | - -X github.com/badtuxx/girus-cli/internal/common.GoOS={{ .Os }} 39 | - -X github.com/badtuxx/girus-cli/internal/common.GoArch={{ .Arch }} 40 | - -X github.com/badtuxx/girus-cli/internal/common.GoVersion={{ .Env.GOVERSION }} 41 | 42 | signs: 43 | # Keyless 44 | - id: girus-cli 45 | signature: "${artifact}.sig" 46 | certificate: "${artifact}.pem" 47 | cmd: cosign 48 | args: 49 | [ 50 | "sign-blob", 51 | "--yes", 52 | "--output-signature", 53 | "${artifact}.sig", 54 | "--output-certificate", 55 | "${artifact}.pem", 56 | "${artifact}", 57 | ] 58 | artifacts: binary 59 | - id: checksum 60 | signature: "${artifact}-keyless.sig" 61 | certificate: "${artifact}.pem" 62 | cmd: cosign 63 | args: 64 | [ 65 | "sign-blob", 66 | "--yes", 67 | "--output-signature", 68 | "${artifact}-keyless.sig", 69 | "--output-certificate", 70 | "${artifact}.pem", 71 | "${artifact}", 72 | ] 73 | artifacts: checksum 74 | 75 | archives: 76 | - formats: 77 | - binary 78 | name_template: "{{ .Binary }}" 79 | allow_different_binary_count: true 80 | 81 | checksum: 82 | name_template: "{{ .ProjectName }}_checksums.txt" 83 | 84 | snapshot: 85 | version_template: SNAPSHOT-{{ .ShortCommit }} 86 | 87 | changelog: 88 | use: github-native 89 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/badtuxx/girus-cli 2 | 3 | go 1.24.0 4 | 5 | toolchain go1.24.3 6 | 7 | require ( 8 | github.com/fatih/color v1.18.0 9 | github.com/schollz/progressbar/v3 v3.18.0 10 | github.com/spf13/cobra v1.10.1 11 | gopkg.in/yaml.v3 v3.0.1 12 | k8s.io/api v0.34.1 13 | k8s.io/apimachinery v0.34.1 14 | k8s.io/client-go v0.34.1 15 | k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 16 | sigs.k8s.io/yaml v1.6.0 17 | ) 18 | 19 | require ( 20 | github.com/davecgh/go-spew v1.1.1 // indirect 21 | github.com/emicklei/go-restful/v3 v3.12.2 // indirect 22 | github.com/fxamacker/cbor/v2 v2.9.0 // indirect 23 | github.com/go-logr/logr v1.4.2 // indirect 24 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 25 | github.com/go-openapi/jsonreference v0.20.2 // indirect 26 | github.com/go-openapi/swag v0.23.0 // indirect 27 | github.com/gogo/protobuf v1.3.2 // indirect 28 | github.com/google/gnostic-models v0.7.0 // indirect 29 | github.com/google/uuid v1.6.0 // indirect 30 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 31 | github.com/josharian/intern v1.0.0 // indirect 32 | github.com/json-iterator/go v1.1.12 // indirect 33 | github.com/mailru/easyjson v0.7.7 // indirect 34 | github.com/mattn/go-colorable v0.1.13 // indirect 35 | github.com/mattn/go-isatty v0.0.20 // indirect 36 | github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect 37 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 38 | github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect 39 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 40 | github.com/pkg/errors v0.9.1 // indirect 41 | github.com/rivo/uniseg v0.4.7 // indirect 42 | github.com/spf13/pflag v1.0.9 // indirect 43 | github.com/x448/float16 v0.8.4 // indirect 44 | go.yaml.in/yaml/v2 v2.4.2 // indirect 45 | go.yaml.in/yaml/v3 v3.0.4 // indirect 46 | golang.org/x/net v0.38.0 // indirect 47 | golang.org/x/oauth2 v0.27.0 // indirect 48 | golang.org/x/sys v0.31.0 // indirect 49 | golang.org/x/term v0.30.0 // indirect 50 | golang.org/x/text v0.23.0 // indirect 51 | golang.org/x/time v0.9.0 // indirect 52 | google.golang.org/protobuf v1.36.5 // indirect 53 | gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect 54 | gopkg.in/inf.v0 v0.9.1 // indirect 55 | k8s.io/klog/v2 v2.130.1 // indirect 56 | k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect 57 | sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect 58 | sigs.k8s.io/randfill v1.0.0 // indirect 59 | sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect 60 | ) 61 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Docker 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | - 'v*' 9 | 10 | permissions: {} 11 | 12 | jobs: 13 | docker: 14 | name: Build and Push Docker Image 15 | runs-on: ubuntu-latest 16 | 17 | permissions: 18 | contents: read 19 | 20 | steps: 21 | - name: Checkout repository 22 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 23 | with: 24 | fetch-depth: 0 # Fetch all history for tags and branches 25 | 26 | - name: Determine version 27 | id: version 28 | run: | 29 | # Check if this is a tag build 30 | if [[ $GITHUB_REF == refs/tags/v* ]]; then 31 | VERSION=${GITHUB_REF#refs/tags/v} 32 | else 33 | # If not a tag, use the latest tag + commit hash 34 | LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "0.0.0") 35 | LATEST_TAG=${LATEST_TAG#v} # Remove 'v' prefix if present 36 | COMMIT_SHORT=$(git rev-parse --short HEAD) 37 | VERSION="${LATEST_TAG}-dev.${COMMIT_SHORT}" 38 | fi 39 | 40 | echo "Determined version: $VERSION" 41 | echo "VERSION=$VERSION" >> $GITHUB_ENV 42 | echo "version=$VERSION" >> $GITHUB_OUTPUT 43 | 44 | - name: Set up Docker Buildx 45 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 46 | 47 | - name: Login to Docker Hub 48 | uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 49 | with: 50 | username: linuxtips 51 | password: ${{ secrets.DOCKERHUB_TOKEN }} 52 | 53 | - name: Extract metadata for Docker 54 | id: meta 55 | uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 56 | with: 57 | images: linuxtips/girus-cli 58 | tags: | 59 | type=sha,format=short 60 | type=raw,value=latest 61 | type=raw,value=${{ env.VERSION }} 62 | type=semver,pattern={{version}},value=${{ env.VERSION }} 63 | 64 | - name: Build and push Docker image 65 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 66 | with: 67 | context: . 68 | file: ./Dockerfile 69 | push: true 70 | tags: ${{ steps.meta.outputs.tags }} 71 | labels: ${{ steps.meta.outputs.labels }} 72 | build-args: | 73 | VERSION=${{ env.VERSION }} 74 | 75 | - name: Verify Docker image 76 | run: | 77 | docker pull linuxtips/girus-cli:${{ env.VERSION }} 78 | docker run --rm linuxtips/girus-cli:${{ env.VERSION }} version 79 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Cut Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | concurrency: cut-release 9 | 10 | permissions: {} 11 | 12 | jobs: 13 | release: 14 | outputs: 15 | hashes: ${{ steps.hash.outputs.hashes }} 16 | tag_name: ${{ steps.tag.outputs.tag_name }} 17 | runs-on: ubuntu-latest 18 | 19 | permissions: 20 | contents: write # needed to write releases 21 | id-token: write # needed for keyless signing 22 | 23 | steps: 24 | - uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 25 | with: 26 | android: true 27 | dotnet: true 28 | haskell: true 29 | large-packages: true 30 | docker-images: true 31 | swap-storage: true 32 | 33 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 34 | with: 35 | fetch-depth: 0 36 | 37 | - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 38 | with: 39 | go-version-file: './go.mod' 40 | check-latest: true 41 | 42 | - uses: sigstore/cosign-installer@v3.8.1 43 | 44 | - uses: anchore/sbom-action/download-syft@v0.20.10 # v0.20.10 45 | 46 | - name: Set tag output 47 | id: tag 48 | run: | 49 | TAG_NAME=${GITHUB_REF#refs/*/} 50 | VERSION=${TAG_NAME#v} # Remove the 'v' prefix if present 51 | echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT" 52 | echo "version=${VERSION}" >> "$GITHUB_OUTPUT" 53 | echo "VERSION=${VERSION}" >> "$GITHUB_ENV" 54 | echo "Determined version: ${VERSION}" 55 | 56 | - name: Set environment variables 57 | run: | 58 | # This environment variable will be used in GoReleaser ldflags 59 | echo "GOVERSION=$(go version | cut -d' ' -f3)" >> $GITHUB_ENV 60 | 61 | - name: Run go mod tidy 62 | run: go mod tidy 63 | 64 | - name: Run GoReleaser 65 | id: run-goreleaser 66 | uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0 67 | with: 68 | version: latest 69 | args: release --clean --timeout 120m --parallelism 1 70 | env: 71 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 72 | GITHUB_ACTOR: ${{ github.actor }} 73 | VERSION: ${{ env.VERSION }} 74 | 75 | - name: Generate subject 76 | id: hash 77 | env: 78 | ARTIFACTS: "${{ steps.run-goreleaser.outputs.artifacts }}" 79 | run: | 80 | set -euo pipefail 81 | checksum_file=$(echo "$ARTIFACTS" | jq -r '.[] | select (.type=="Checksum") | .path') 82 | echo "hashes=$(cat $checksum_file | base64 -w0)" >> "$GITHUB_OUTPUT" 83 | 84 | provenance: 85 | needs: 86 | - release 87 | 88 | permissions: 89 | actions: read # To read the workflow path. 90 | id-token: write # To sign the provenance. 91 | contents: write # To add assets to a release. 92 | 93 | uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 94 | with: 95 | base64-subjects: "${{ needs.release.outputs.hashes }}" 96 | upload-assets: true # upload to a new release 97 | upload-tag-name: "${{ needs.release.outputs.tag_name }}" 98 | -------------------------------------------------------------------------------- /labs/docker_volumes-persistencia/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: docker-volumes-persistencia-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: docker-volumes-persistencia 11 | title: "Volumes e Persistência no Docker" 12 | description: "Aprenda a gerenciar dados persistentes em containers Docker usando volumes, bind mounts e tmpfs mounts. Este laboratório guiado explora diferentes técnicas de persistência de dados e suas aplicações práticas." 13 | duration: 35m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Gerenciamento de Volumes" 18 | description: "Aprenda a criar e gerenciar volumes Docker." 19 | steps: 20 | - description: "Crie um volume Docker" 21 | command: "docker volume create meu-volume" 22 | expectedOutput: "meu-volume" 23 | hint: "Use o comando docker volume create" 24 | 25 | - description: "Liste os volumes disponíveis" 26 | command: "docker volume ls" 27 | expectedOutput: "meu-volume" 28 | hint: "Use o comando docker volume ls para listar os volumes" 29 | 30 | - description: "Inspecione o volume criado" 31 | command: "docker volume inspect meu-volume" 32 | expectedOutput: "meu-volume" 33 | hint: "Use o comando docker volume inspect para ver detalhes do volume" 34 | 35 | - name: "Containers com Volumes" 36 | description: "Implemente containers usando volumes para persistência." 37 | steps: 38 | - description: "Crie um container com volume" 39 | command: "docker run -d --name container-volume -v meu-volume:/dados nginx" 40 | expectedOutput: "" 41 | hint: "Use o comando docker run com a flag -v para montar o volume" 42 | 43 | - description: "Crie um arquivo no volume" 44 | command: "docker exec container-volume sh -c 'echo \"Dados persistentes\" > /dados/teste.txt'" 45 | expectedOutput: "" 46 | hint: "Use o comando docker exec para executar comandos no container" 47 | 48 | - description: "Verifique o conteúdo do arquivo" 49 | command: "docker exec container-volume cat /dados/teste.txt" 50 | expectedOutput: "Dados persistentes" 51 | hint: "Use o comando docker exec para ler o arquivo" 52 | 53 | - name: "Bind Mounts e Tmpfs" 54 | description: "Explore diferentes tipos de montagens para persistência." 55 | steps: 56 | - description: "Crie um container com bind mount" 57 | command: "docker run -d --name container-bind -v $(pwd):/app nginx" 58 | expectedOutput: "" 59 | hint: "Use o comando docker run com bind mount para o diretório atual" 60 | 61 | - description: "Crie um container com tmpfs" 62 | command: "docker run -d --name container-tmpfs --tmpfs /tmp nginx" 63 | expectedOutput: "" 64 | hint: "Use o comando docker run com a flag --tmpfs" 65 | 66 | - description: "Verifique as montagens" 67 | command: "docker inspect container-bind | grep -A 10 Mounts" 68 | expectedOutput: "Mounts" 69 | hint: "Use o comando docker inspect para verificar as montagens" 70 | -------------------------------------------------------------------------------- /labs/kubernetes_deployments-replicasets/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: kubernetes-deployments-replicasets-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: kubernetes-deployments-replicasets 11 | title: "Deployments e ReplicaSets no Kubernetes" 12 | description: "Aprenda a gerenciar aplicações no Kubernetes usando Deployments e ReplicaSets. Este laboratório guiado explora conceitos fundamentais de orquestração de containers, escalabilidade e alta disponibilidade." 13 | duration: 40m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Criando um Deployment Básico" 18 | description: "Aprenda a criar e gerenciar Deployments no Kubernetes." 19 | steps: 20 | - description: "Crie um Deployment do nginx" 21 | command: "kubectl create deployment nginx-deployment --image=nginx:1.21" 22 | expectedOutput: "deployment.apps/nginx-deployment created" 23 | hint: "Use o comando kubectl create deployment" 24 | 25 | - description: "Verifique o status do Deployment" 26 | command: "kubectl get deployments" 27 | expectedOutput: "nginx-deployment" 28 | hint: "Use o comando kubectl get deployments" 29 | 30 | - description: "Verifique os Pods criados" 31 | command: "kubectl get pods" 32 | expectedOutput: "nginx-deployment" 33 | hint: "Use o comando kubectl get pods" 34 | 35 | - name: "Escalando Deployments" 36 | description: "Aprenda a escalar aplicações no Kubernetes." 37 | steps: 38 | - description: "Escale o Deployment para 3 réplicas" 39 | command: "kubectl scale deployment nginx-deployment --replicas=3" 40 | expectedOutput: "deployment.apps/nginx-deployment scaled" 41 | hint: "Use o comando kubectl scale deployment" 42 | 43 | - description: "Verifique as réplicas" 44 | command: "kubectl get pods" 45 | expectedOutput: "nginx-deployment" 46 | hint: "Verifique os pods em execução" 47 | 48 | - description: "Verifique o ReplicaSet" 49 | command: "kubectl get rs" 50 | expectedOutput: "nginx-deployment" 51 | hint: "Use o comando kubectl get rs para ver o ReplicaSet" 52 | 53 | - name: "Atualizações e Rollbacks" 54 | description: "Implemente estratégias de atualização e rollback." 55 | steps: 56 | - description: "Atualize a imagem do Deployment" 57 | command: "kubectl set image deployment/nginx-deployment nginx=nginx:1.22" 58 | expectedOutput: "deployment.apps/nginx-deployment image updated" 59 | hint: "Use o comando kubectl set image" 60 | 61 | - description: "Verifique o histórico de revisões" 62 | command: "kubectl rollout history deployment/nginx-deployment" 63 | expectedOutput: "deployment.apps/nginx-deployment" 64 | hint: "Use o comando kubectl rollout history" 65 | 66 | - description: "Faça rollback para a versão anterior" 67 | command: "kubectl rollout undo deployment/nginx-deployment" 68 | expectedOutput: "deployment.apps/nginx-deployment rolled back" 69 | hint: "Use o comando kubectl rollout undo" 70 | -------------------------------------------------------------------------------- /labs/kubernetes_deployments-replicasets/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: kubernetes-deployments-replicasets-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: kubernetes-deployments-replicasets-es 11 | title: "Deployments e ReplicaSets no Kubernetes" 12 | description: "aprende a administrar aplicações no Kubernetes usando Deployments e ReplicaSets. Este laboratorio guiado explora conceitos fundamentais de orquestração de containers, escalabilidade e alta disponibilidade." 13 | duration: 40m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "creando un Deployment Básico" 18 | description: "aprende a crear e administrar Deployments no Kubernetes." 19 | steps: 20 | - description: "crea un Deployment do nginx" 21 | command: "kubectl create deployment nginx-deployment --image=nginx:1.21" 22 | expectedOutput: "deployment.apps/nginx-deployment created" 23 | hint: "Use o comando kubectl create deployment" 24 | 25 | - description: "verifique o status do Deployment" 26 | command: "kubectl get deployments" 27 | expectedOutput: "nginx-deployment" 28 | hint: "Use o comando kubectl get deployments" 29 | 30 | - description: "verifique os Pods criados" 31 | command: "kubectl get pods" 32 | expectedOutput: "nginx-deployment" 33 | hint: "Use o comando kubectl get pods" 34 | 35 | - name: "Escalando Deployments" 36 | description: "aprende a escalar aplicações no Kubernetes." 37 | steps: 38 | - description: "Escale o Deployment para 3 réplicas" 39 | command: "kubectl scale deployment nginx-deployment --replicas=3" 40 | expectedOutput: "deployment.apps/nginx-deployment scaled" 41 | hint: "Use o comando kubectl scale deployment" 42 | 43 | - description: "verifique as réplicas" 44 | command: "kubectl get pods" 45 | expectedOutput: "nginx-deployment" 46 | hint: "verifique os pods em execução" 47 | 48 | - description: "verifique o ReplicaSet" 49 | command: "kubectl get rs" 50 | expectedOutput: "nginx-deployment" 51 | hint: "Use o comando kubectl get rs para ver o ReplicaSet" 52 | 53 | - name: "Atualizações e Rollbacks" 54 | description: "Implemente estratégias de actualización e rollback." 55 | steps: 56 | - description: "Atualize a imagen do Deployment" 57 | command: "kubectl set image deployment/nginx-deployment nginx=nginx:1.22" 58 | expectedOutput: "deployment.apps/nginx-deployment image updated" 59 | hint: "Use o comando kubectl set image" 60 | 61 | - description: "verifique o histórico de revisões" 62 | command: "kubectl rollout history deployment/nginx-deployment" 63 | expectedOutput: "deployment.apps/nginx-deployment" 64 | hint: "Use o comando kubectl rollout history" 65 | 66 | - description: "Faça rollback para a versão anterior" 67 | command: "kubectl rollout undo deployment/nginx-deployment" 68 | expectedOutput: "deployment.apps/nginx-deployment rolled back" 69 | hint: "Use o comando kubectl rollout undo" 70 | -------------------------------------------------------------------------------- /labs/docker_redes-avancadas/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: docker-redes-avancadas-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: docker-redes-avancadas 11 | title: "Redes Avançadas no Docker" 12 | description: "Aprenda a configurar e gerenciar redes avançadas no Docker, incluindo redes personalizadas, comunicação entre containers e isolamento de rede. Este laboratório guiado explora os conceitos avançados de networking no Docker e como implementar arquiteturas de rede complexas." 13 | duration: 35m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Criação de Redes Personalizadas" 18 | description: "Aprenda a criar e gerenciar redes Docker personalizadas." 19 | steps: 20 | - description: "Crie uma rede bridge personalizada" 21 | command: "docker network create --driver bridge minha-rede" 22 | expectedOutput: "" 23 | hint: "Use o comando docker network create para criar uma rede" 24 | 25 | - description: "Verifique as redes disponíveis" 26 | command: "docker network ls" 27 | expectedOutput: "minha-rede" 28 | hint: "Use o comando docker network ls para listar as redes" 29 | 30 | - description: "Inspecione a rede criada" 31 | command: "docker network inspect minha-rede" 32 | expectedOutput: "Name: minha-rede" 33 | hint: "Use o comando docker network inspect para ver detalhes da rede" 34 | 35 | - name: "Comunicação entre Containers" 36 | description: "Configure a comunicação entre containers em diferentes redes." 37 | steps: 38 | - description: "Crie um container na rede personalizada" 39 | command: "docker run -d --name web --network minha-rede nginx" 40 | expectedOutput: "" 41 | hint: "Use o comando docker run com --network para conectar à rede" 42 | 43 | - description: "Crie outro container na mesma rede" 44 | command: "docker run -d --name db --network minha-rede mysql:5.7" 45 | expectedOutput: "" 46 | hint: "Crie outro container na mesma rede" 47 | 48 | - description: "Teste a comunicação entre containers" 49 | command: "docker exec web ping -c 4 db" 50 | expectedOutput: "4 packets transmitted" 51 | hint: "Use o comando docker exec para testar a conectividade" 52 | 53 | - name: "Isolamento e Segurança de Rede" 54 | description: "Implemente isolamento e segurança em redes Docker." 55 | steps: 56 | - description: "Crie uma rede isolada" 57 | command: "docker network create --internal rede-isolada" 58 | expectedOutput: "" 59 | hint: "Use a opção --internal para criar uma rede isolada" 60 | 61 | - description: "Crie um container na rede isolada" 62 | command: "docker run -d --name app-isolado --network rede-isolada nginx" 63 | expectedOutput: "" 64 | hint: "Crie um container na rede isolada" 65 | 66 | - description: "Verifique o isolamento" 67 | command: "docker exec app-isolado ping -c 4 8.8.8.8" 68 | expectedOutput: "Network is unreachable" 69 | hint: "Tente acessar a internet do container isolado" 70 | -------------------------------------------------------------------------------- /labs/kubernetes_services-networking/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: kubernetes-services-networking-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: kubernetes-services-networking 11 | title: "Services e Networking no Kubernetes" 12 | description: "Aprenda a configurar e gerenciar serviços e networking no Kubernetes. Este laboratório guiado explora diferentes tipos de Services, DNS interno, e conceitos de networking no cluster." 13 | duration: 35m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Criando Services" 18 | description: "Aprenda a criar e gerenciar diferentes tipos de Services." 19 | steps: 20 | - description: "Crie um Deployment para teste" 21 | command: "kubectl create deployment web-app --image=nginx:1.21" 22 | expectedOutput: "deployment.apps/web-app created" 23 | hint: "Use o comando kubectl create deployment" 24 | 25 | - description: "Crie um Service do tipo ClusterIP" 26 | command: "kubectl expose deployment web-app --port=80 --target-port=80 --name=web-service" 27 | expectedOutput: "service/web-service exposed" 28 | hint: "Use o comando kubectl expose deployment" 29 | 30 | - description: "Verifique o Service criado" 31 | command: "kubectl get services" 32 | expectedOutput: "web-service" 33 | hint: "Use o comando kubectl get services" 34 | 35 | - name: "Service Types" 36 | description: "Explore diferentes tipos de Services no Kubernetes." 37 | steps: 38 | - description: "Crie um Service do tipo NodePort" 39 | command: "kubectl expose deployment web-app --port=80 --target-port=80 --name=web-nodeport --type=NodePort" 40 | expectedOutput: "service/web-nodeport exposed" 41 | hint: "Use o comando kubectl expose com --type=NodePort" 42 | 43 | - description: "Crie um Service do tipo LoadBalancer" 44 | command: "kubectl expose deployment web-app --port=80 --target-port=80 --name=web-lb --type=LoadBalancer" 45 | expectedOutput: "service/web-lb exposed" 46 | hint: "Use o comando kubectl expose com --type=LoadBalancer" 47 | 48 | - description: "Verifique os Services criados" 49 | command: "kubectl get services" 50 | expectedOutput: "web-nodeport" 51 | hint: "Verifique todos os services criados" 52 | 53 | - name: "DNS e Networking" 54 | description: "Implemente e teste o DNS interno do Kubernetes." 55 | steps: 56 | - description: "Crie um pod de teste" 57 | command: "kubectl run test-pod --image=busybox -- sleep 3600" 58 | expectedOutput: "pod/test-pod created" 59 | hint: "Use o comando kubectl run para criar um pod de teste" 60 | 61 | - description: "Teste o DNS interno" 62 | command: "kubectl exec test-pod -- nslookup web-service" 63 | expectedOutput: "web-service" 64 | hint: "Use o comando kubectl exec com nslookup" 65 | 66 | - description: "Teste a conectividade" 67 | command: "kubectl exec test-pod -- wget -O- web-service" 68 | expectedOutput: "nginx" 69 | hint: "Use o comando kubectl exec com wget para testar a conexão" 70 | -------------------------------------------------------------------------------- /labs/docker_volumes-persistencia/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: docker-volumes-persistencia-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: docker-volumes-persistencia-es 11 | title: "Volúmenes y Persistencia en Docker" 12 | description: "Aprende a administrar datos persistentes en contenedores Docker usando volúmenes, bind mounts y tmpfs mounts. Este laboratorio guiado explora diferentes técnicas de persistencia de datos y sus aplicaciones prácticas." 13 | duration: 35m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Administración de Volúmenes" 18 | description: "Aprende a crear y administrar volúmenes Docker." 19 | steps: 20 | - description: "Crea un volumen Docker" 21 | command: "docker volume create mi-volumen" 22 | expectedOutput: "mi-volumen" 23 | hint: "Usa el comando docker volume create" 24 | 25 | - description: "Lista los volúmenes disponibles" 26 | command: "docker volume ls" 27 | expectedOutput: "mi-volumen" 28 | hint: "Usa el comando docker volume ls para listar los volúmenes" 29 | 30 | - description: "Inspecciona el volumen creado" 31 | command: "docker volume inspect mi-volumen" 32 | expectedOutput: "mi-volumen" 33 | hint: "Usa el comando docker volume inspect para ver detalles del volumen" 34 | 35 | - name: "Contenedores con Volúmenes" 36 | description: "Implementa contenedores usando volúmenes para persistencia." 37 | steps: 38 | - description: "Crea un contenedor con volumen" 39 | command: "docker run -d --name contenedor-volumen -v mi-volumen:/datos nginx" 40 | expectedOutput: "" 41 | hint: "Usa el comando docker run con la flag -v para montar el volumen" 42 | 43 | - description: "Crea un archivo en el volumen" 44 | command: "docker exec contenedor-volumen sh -c 'echo \"Datos persistentes\" > /datos/prueba.txt'" 45 | expectedOutput: "" 46 | hint: "Usa el comando docker exec para ejecutar comandos en el contenedor" 47 | 48 | - description: "Verifica el contenido del archivo" 49 | command: "docker exec contenedor-volumen cat /datos/prueba.txt" 50 | expectedOutput: "Datos persistentes" 51 | hint: "Usa el comando docker exec para leer el archivo" 52 | 53 | - name: "Bind Mounts y Tmpfs" 54 | description: "Explora diferentes tipos de montajes para persistencia." 55 | steps: 56 | - description: "Crea un contenedor con bind mount" 57 | command: "docker run -d --name contenedor-bind -v $(pwd):/app nginx" 58 | expectedOutput: "" 59 | hint: "Usa el comando docker run con bind mount para el directorio actual" 60 | 61 | - description: "Crea un contenedor con tmpfs" 62 | command: "docker run -d --name contenedor-tmpfs --tmpfs /tmp nginx" 63 | expectedOutput: "" 64 | hint: "Usa el comando docker run con la flag --tmpfs" 65 | 66 | - description: "Verifica los montajes" 67 | command: "docker inspect contenedor-bind | grep -A 10 Mounts" 68 | expectedOutput: "Mounts" 69 | hint: "Usa el comando docker inspect para verificar los montajes" 70 | -------------------------------------------------------------------------------- /labs/linux_redes-conectividade/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: linux-redes-conectividade-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: linux-redes-conectividade 11 | title: "Redes e Conectividade no Linux" 12 | description: "Aprenda a configurar e gerenciar redes no Linux, incluindo interfaces de rede, roteamento, firewall e diagnóstico de problemas de conectividade. Este laboratório guiado explora os comandos e ferramentas essenciais para administração de redes em sistemas Linux, fornecendo uma base sólida para solução de problemas de conectividade." 13 | duration: 30m 14 | image: "linuxtips/girus-devops:0.1" 15 | tasks: 16 | - name: "Configuração de Interfaces de Rede" 17 | description: "Aprenda a configurar e gerenciar interfaces de rede no Linux, incluindo endereçamento IP, máscaras de sub-rede e gateways." 18 | steps: 19 | - description: "Verifique as interfaces de rede disponíveis" 20 | command: "ip addr show" 21 | expectedOutput: "eth0" 22 | hint: "Use o comando ip addr show para listar todas as interfaces de rede" 23 | 24 | - description: "Configure um endereço IP estático" 25 | command: "ip addr add 192.168.1.100/24 dev eth0" 26 | expectedOutput: "" 27 | hint: "Use o comando ip addr add para configurar um endereço IP" 28 | 29 | - description: "Verifique a conectividade de rede" 30 | command: "ping -c 4 8.8.8.8" 31 | expectedOutput: "4 packets transmitted" 32 | hint: "Use o comando ping para testar a conectividade" 33 | 34 | - name: "Roteamento e Firewall" 35 | description: "Explore o roteamento e configuração de firewall no Linux usando iptables e ferramentas de diagnóstico." 36 | steps: 37 | - description: "Verifique a tabela de roteamento" 38 | command: "ip route show" 39 | expectedOutput: "default via" 40 | hint: "Use o comando ip route show para ver as rotas configuradas" 41 | 42 | - description: "Configure uma regra de firewall básica" 43 | command: "iptables -A INPUT -p tcp --dport 80 -j ACCEPT" 44 | expectedOutput: "" 45 | hint: "Use o comando iptables para configurar regras de firewall" 46 | 47 | - description: "Verifique as regras de firewall" 48 | command: "iptables -L" 49 | expectedOutput: "Chain INPUT" 50 | hint: "Use o comando iptables -L para listar as regras" 51 | 52 | - name: "Diagnóstico de Problemas" 53 | description: "Aprenda a diagnosticar e resolver problemas comuns de rede no Linux." 54 | steps: 55 | - description: "Verifique o status da rede" 56 | command: "netstat -tuln" 57 | expectedOutput: "Active Internet connections" 58 | hint: "Use o comando netstat para ver conexões ativas" 59 | 60 | - description: "Teste a resolução DNS" 61 | command: "dig google.com" 62 | expectedOutput: ";; ANSWER SECTION:" 63 | hint: "Use o comando dig para testar a resolução DNS" 64 | 65 | - description: "Analise o tráfego de rede" 66 | command: "tcpdump -i eth0 -c 5" 67 | expectedOutput: "tcpdump: listening on eth0" 68 | hint: "Use o comando tcpdump para capturar pacotes de rede" 69 | -------------------------------------------------------------------------------- /labs/docker_redes-avancadas/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: docker-redes-avancadas-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: docker-redes-avancadas-es 11 | title: "Redes Avanzadas en Docker" 12 | description: "Aprende a configurar y administrar redes avanzadas en Docker, incluyendo redes personalizadas, comunicación entre contenedores y aislamiento de red. Este laboratorio guiado explora los conceptos avanzados de networking en Docker y cómo implementar arquitecturas de red complejas." 13 | duration: 35m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Creación de Redes Personalizadas" 18 | description: "Aprende a crear y administrar redes Docker personalizadas." 19 | steps: 20 | - description: "Crea una red bridge personalizada" 21 | command: "docker network create --driver bridge mi-red" 22 | expectedOutput: "" 23 | hint: "Usa el comando docker network create para crear una red" 24 | 25 | - description: "Verifica las redes disponibles" 26 | command: "docker network ls" 27 | expectedOutput: "mi-red" 28 | hint: "Usa el comando docker network ls para listar las redes" 29 | 30 | - description: "Inspecciona la red creada" 31 | command: "docker network inspect mi-red" 32 | expectedOutput: "Name: mi-red" 33 | hint: "Usa el comando docker network inspect para ver detalles de la red" 34 | 35 | - name: "Comunicación entre Contenedores" 36 | description: "Configura la comunicación entre contenedores en diferentes redes." 37 | steps: 38 | - description: "Crea un contenedor en la red personalizada" 39 | command: "docker run -d --name web --network mi-red nginx" 40 | expectedOutput: "" 41 | hint: "Usa el comando docker run con --network para conectar a la red" 42 | 43 | - description: "Crea otro contenedor en la misma red" 44 | command: "docker run -d --name db --network mi-red -e MYSQL_ROOT_PASSWORD=password mysql:5.7" 45 | expectedOutput: "" 46 | hint: "Crea otro contenedor en la misma red" 47 | 48 | - description: "Prueba la comunicación entre contenedores" 49 | command: "docker exec web ping -c 4 db" 50 | expectedOutput: "4 packets transmitted" 51 | hint: "Usa el comando docker exec para probar la conectividad" 52 | 53 | - name: "Aislamiento y Seguridad de Red" 54 | description: "Implementa aislamiento y seguridad en redes Docker." 55 | steps: 56 | - description: "Crea una red aislada" 57 | command: "docker network create --internal red-aislada" 58 | expectedOutput: "" 59 | hint: "Usa la opción --internal para crear una red aislada" 60 | 61 | - description: "Crea un contenedor en la red aislada" 62 | command: "docker run -d --name app-aislado --network red-aislada nginx" 63 | expectedOutput: "" 64 | hint: "Crea un contenedor en la red aislada" 65 | 66 | - description: "Verifica el aislamiento" 67 | command: "docker exec app-aislado ping -c 4 8.8.8.8" 68 | expectedOutput: "Network is unreachable" 69 | hint: "Intenta acceder a internet desde el contenedor aislado" 70 | -------------------------------------------------------------------------------- /labs/kubernetes_services-networking/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: kubernetes-services-networking-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: kubernetes-services-networking-es 11 | title: "Services y Networking en Kubernetes" 12 | description: "Aprende a configurar y administrar servicios y networking en Kubernetes. Este laboratorio guiado explora diferentes tipos de Services, DNS interno, y conceptos de networking en el cluster." 13 | duration: 35m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Creando Services" 18 | description: "Aprende a crear y administrar diferentes tipos de Services." 19 | steps: 20 | - description: "Crea un Deployment para prueba" 21 | command: "kubectl create deployment web-app --image=nginx:1.21" 22 | expectedOutput: "deployment.apps/web-app created" 23 | hint: "Usa el comando kubectl create deployment" 24 | 25 | - description: "Crea un Service de tipo ClusterIP" 26 | command: "kubectl expose deployment web-app --port=80 --target-port=80 --name=web-service" 27 | expectedOutput: "service/web-service exposed" 28 | hint: "Usa el comando kubectl expose deployment" 29 | 30 | - description: "Verifica el Service creado" 31 | command: "kubectl get services" 32 | expectedOutput: "web-service" 33 | hint: "Usa el comando kubectl get services" 34 | 35 | - name: "Tipos de Service" 36 | description: "Explora diferentes tipos de Services en Kubernetes." 37 | steps: 38 | - description: "Crea un Service de tipo NodePort" 39 | command: "kubectl expose deployment web-app --port=80 --target-port=80 --name=web-nodeport --type=NodePort" 40 | expectedOutput: "service/web-nodeport exposed" 41 | hint: "Usa el comando kubectl expose con --type=NodePort" 42 | 43 | - description: "Crea un Service de tipo LoadBalancer" 44 | command: "kubectl expose deployment web-app --port=80 --target-port=80 --name=web-lb --type=LoadBalancer" 45 | expectedOutput: "service/web-lb exposed" 46 | hint: "Usa el comando kubectl expose con --type=LoadBalancer" 47 | 48 | - description: "Verifica los Services creados" 49 | command: "kubectl get services" 50 | expectedOutput: "web-nodeport" 51 | hint: "Verifica todos los servicios creados" 52 | 53 | - name: "DNS y Networking" 54 | description: "Implementa y prueba el DNS interno de Kubernetes." 55 | steps: 56 | - description: "Crea un pod de prueba" 57 | command: "kubectl run test-pod --image=busybox -- sleep 3600" 58 | expectedOutput: "pod/test-pod created" 59 | hint: "Usa el comando kubectl run para crear un pod de prueba" 60 | 61 | - description: "Prueba el DNS interno" 62 | command: "kubectl exec test-pod -- nslookup web-service" 63 | expectedOutput: "web-service" 64 | hint: "Usa el comando kubectl exec con nslookup" 65 | 66 | - description: "Prueba la conectividad" 67 | command: "kubectl exec test-pod -- wget -O- web-service" 68 | expectedOutput: "nginx" 69 | hint: "Usa el comando kubectl exec con wget para probar la conexión" 70 | -------------------------------------------------------------------------------- /labs/linux_seguranca-criptografia/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: linux-seguranca-criptografia-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: linux-seguranca-criptografia 11 | title: "Segurança e Criptografia no Linux" 12 | description: "Aprenda os fundamentos de segurança e criptografia no Linux, incluindo gerenciamento de chaves SSH, criptografia de arquivos e boas práticas de segurança. Este laboratório guiado explora as ferramentas e técnicas essenciais para proteger sistemas Linux e dados sensíveis." 13 | duration: 35m 14 | image: "linuxtips/girus-devops:0.1" 15 | tasks: 16 | - name: "Gerenciamento de Chaves SSH" 17 | description: "Aprenda a criar, gerenciar e usar chaves SSH para autenticação segura." 18 | steps: 19 | - description: "Gere um par de chaves SSH" 20 | command: "ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa -N ''" 21 | expectedOutput: "Your identification has been saved" 22 | hint: "Use o comando ssh-keygen para gerar um par de chaves" 23 | 24 | - description: "Verifique as permissões das chaves" 25 | command: "ls -l ~/.ssh/id_rsa*" 26 | expectedOutput: "-rw-------" 27 | hint: "Verifique se as permissões estão corretas (600 para chave privada)" 28 | 29 | - description: "Configure o SSH para usar apenas autenticação por chave" 30 | command: "echo 'PasswordAuthentication no' | sudo tee -a /etc/ssh/sshd_config" 31 | expectedOutput: "PasswordAuthentication no" 32 | hint: "Desative a autenticação por senha no SSH" 33 | 34 | - name: "Criptografia de Arquivos" 35 | description: "Explore técnicas de criptografia de arquivos usando GPG e outras ferramentas." 36 | steps: 37 | - description: "Gere um par de chaves GPG" 38 | command: "gpg --full-generate-key" 39 | expectedOutput: "Please select what kind of key you want" 40 | hint: "Use o comando gpg para gerar um par de chaves" 41 | 42 | - description: "Crie um arquivo de teste e criptografe-o" 43 | command: "echo 'Dados sensíveis' > secreto.txt && gpg -e -r $(gpg --list-secret-keys --keyid-format LONG | grep sec | cut -d' ' -f4) secreto.txt" 44 | expectedOutput: "" 45 | hint: "Use o comando gpg -e para criptografar um arquivo" 46 | 47 | - description: "Descriptografe o arquivo" 48 | command: "gpg -d secreto.txt.gpg" 49 | expectedOutput: "Dados sensíveis" 50 | hint: "Use o comando gpg -d para descriptografar" 51 | 52 | - name: "Auditoria de Segurança" 53 | description: "Aprenda a realizar auditorias básicas de segurança no sistema." 54 | steps: 55 | - description: "Verifique portas abertas" 56 | command: "netstat -tuln" 57 | expectedOutput: "Active Internet connections" 58 | hint: "Use o comando netstat para ver portas abertas" 59 | 60 | - description: "Verifique usuários com privilégios" 61 | command: "grep -Po '^sudo.+:\K.*$' /etc/group" 62 | expectedOutput: "" 63 | hint: "Verifique os usuários no grupo sudo" 64 | 65 | - description: "Analise logs de segurança" 66 | command: "sudo tail -n 50 /var/log/auth.log" 67 | expectedOutput: "" 68 | hint: "Verifique os logs de autenticação" 69 | -------------------------------------------------------------------------------- /labs/linux_redes-conectividade/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: linux-redes-conectividade-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: linux-redes-conectividade-es 11 | title: "Redes y Conectividad en Linux" 12 | description: "Aprende a configurar y administrar redes en Linux, incluyendo interfaces de red, enrutamiento, firewall y diagnóstico de problemas de conectividad. Este laboratorio guiado explora los comandos y herramientas esenciales para administración de redes en sistemas Linux, proporcionando una base sólida para solución de problemas de conectividad." 13 | duration: 30m 14 | image: "linuxtips/girus-devops:0.1" 15 | tasks: 16 | - name: "Configuración de Interfaces de Red" 17 | description: "Aprende a configurar y administrar interfaces de red en Linux, incluyendo direccionamiento IP, máscaras de subred y gateways." 18 | steps: 19 | - description: "Verifica las interfaces de red disponibles" 20 | command: "ip addr show" 21 | expectedOutput: "eth0" 22 | hint: "Usa el comando ip addr show para listar todas las interfaces de red" 23 | 24 | - description: "Configura una dirección IP estática" 25 | command: "ip addr add 192.168.1.100/24 dev eth0" 26 | expectedOutput: "" 27 | hint: "Usa el comando ip addr add para configurar una dirección IP" 28 | 29 | - description: "Verifica la conectividad de red" 30 | command: "ping -c 4 8.8.8.8" 31 | expectedOutput: "4 packets transmitted" 32 | hint: "Usa el comando ping para probar la conectividad" 33 | 34 | - name: "Enrutamiento y Firewall" 35 | description: "Explora el enrutamiento y configuración de firewall en Linux usando iptables y herramientas de diagnóstico." 36 | steps: 37 | - description: "Verifica la tabla de enrutamiento" 38 | command: "ip route show" 39 | expectedOutput: "default via" 40 | hint: "Usa el comando ip route show para ver las rutas configuradas" 41 | 42 | - description: "Configura una regla de firewall básica" 43 | command: "iptables -A INPUT -p tcp --dport 80 -j ACCEPT" 44 | expectedOutput: "" 45 | hint: "Usa el comando iptables para configurar reglas de firewall" 46 | 47 | - description: "Verifica las reglas de firewall" 48 | command: "iptables -L" 49 | expectedOutput: "Chain INPUT" 50 | hint: "Usa el comando iptables -L para listar las reglas" 51 | 52 | - name: "Diagnóstico de Problemas" 53 | description: "Aprende a diagnosticar y resolver problemas comunes de red en Linux." 54 | steps: 55 | - description: "Verifica el estado de la red" 56 | command: "netstat -tuln" 57 | expectedOutput: "Active Internet connections" 58 | hint: "Usa el comando netstat para ver conexiones activas" 59 | 60 | - description: "Prueba la resolución DNS" 61 | command: "dig google.com" 62 | expectedOutput: ";; ANSWER SECTION:" 63 | hint: "Usa el comando dig para probar la resolución DNS" 64 | 65 | - description: "Analiza el tráfico de red" 66 | command: "tcpdump -i eth0 -c 5" 67 | expectedOutput: "tcpdump: listening on eth0" 68 | hint: "Usa el comando tcpdump para capturar paquetes de red" 69 | -------------------------------------------------------------------------------- /internal/repo/example/linux-basics/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: girus.linuxtips.io/v1 2 | kind: Lab 3 | metadata: 4 | name: linux-basics 5 | version: "1.0.0" 6 | description: "Introdução aos comandos básicos do Linux" 7 | author: "LINUXtips Team" 8 | created: "2024-03-20T10:00:00Z" 9 | spec: 10 | environment: 11 | image: ubuntu:22.04 12 | resources: 13 | cpu: "1" 14 | memory: "1Gi" 15 | volumes: 16 | - name: workspace 17 | mountPath: /workspace 18 | size: "1Gi" 19 | 20 | tasks: 21 | - name: "Navegação Básica" 22 | description: "Aprenda a navegar pelo sistema de arquivos do Linux" 23 | steps: 24 | - description: "Verifique o diretório atual" 25 | command: "pwd" 26 | expectedOutput: "/workspace" 27 | hint: "Use o comando pwd para ver o diretório atual" 28 | 29 | - description: "Liste os arquivos do diretório" 30 | command: "ls -la" 31 | expectedOutput: "total" 32 | hint: "Use o comando ls -la para listar todos os arquivos, incluindo os ocultos" 33 | 34 | - description: "Crie um diretório chamado 'test'" 35 | command: "mkdir test" 36 | expectedOutput: "" 37 | hint: "Use o comando mkdir para criar um novo diretório" 38 | 39 | - name: "Manipulação de Arquivos" 40 | description: "Aprenda a criar, editar e manipular arquivos" 41 | steps: 42 | - description: "Crie um arquivo chamado 'hello.txt'" 43 | command: "echo 'Hello, Linux!' > hello.txt" 44 | expectedOutput: "" 45 | hint: "Use o comando echo com redirecionamento para criar um arquivo" 46 | 47 | - description: "Verifique o conteúdo do arquivo" 48 | command: "cat hello.txt" 49 | expectedOutput: "Hello, Linux!" 50 | hint: "Use o comando cat para exibir o conteúdo do arquivo" 51 | 52 | - description: "Copie o arquivo para o diretório 'test'" 53 | command: "cp hello.txt test/" 54 | expectedOutput: "" 55 | hint: "Use o comando cp para copiar arquivos" 56 | 57 | - name: "Permissões de Arquivos" 58 | description: "Aprenda sobre permissões de arquivos no Linux" 59 | steps: 60 | - description: "Verifique as permissões do arquivo" 61 | command: "ls -l hello.txt" 62 | expectedOutput: "-rw-r--r--" 63 | hint: "Use o comando ls -l para ver as permissões detalhadas" 64 | 65 | - description: "Altere as permissões do arquivo" 66 | command: "chmod 755 hello.txt" 67 | expectedOutput: "" 68 | hint: "Use o comando chmod para alterar as permissões" 69 | 70 | - description: "Verifique as novas permissões" 71 | command: "ls -l hello.txt" 72 | expectedOutput: "-rwxr-xr-x" 73 | hint: "Use o comando ls -l para verificar as novas permissões" 74 | 75 | validation: 76 | - name: "Verificação Final" 77 | description: "Verifique se todas as tarefas foram concluídas corretamente" 78 | checks: 79 | - command: "test -d test" 80 | expectedOutput: "" 81 | errorMessage: "O diretório 'test' não foi criado" 82 | 83 | - command: "test -f test/hello.txt" 84 | expectedOutput: "" 85 | errorMessage: "O arquivo 'hello.txt' não foi copiado para o diretório 'test'" 86 | 87 | - command: "ls -l hello.txt | grep -q '^-rwxr-xr-x'" 88 | expectedOutput: "" 89 | errorMessage: "As permissões do arquivo 'hello.txt' não foram alteradas corretamente" 90 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # NOME DO BINÁRIO 2 | BIN=girus 3 | INSTALL_DIR=/usr/local/bin 4 | # DIRETÓRIO DE BUILD 5 | BD=dist 6 | # DIRETÓRIO ATUAL 7 | CDR=. 8 | CONFIG_PATH=manifest/config.yaml 9 | # Variáveis para versionamento 10 | VERSION := 0.4.0 11 | DATE := $(shell date -u +%Y-%m-%dT%H:%M:%SZ) 12 | BUILT_BY := $(shell whoami) 13 | COMMITID := $(shell git rev-parse --short HEAD) 14 | GO_VERSION := $(shell go version | cut -d' ' -f3) 15 | GO_OS := $(shell go env GOOS) 16 | GO_ARCH := $(shell go env GOARCH) 17 | 18 | LDFLAGS := -X github.com/badtuxx/girus-cli/internal/common.Version=$(VERSION) 19 | LDFLAGS += -X github.com/badtuxx/girus-cli/internal/common.BuildDate=$(DATE) 20 | LDFLAGS += -X github.com/badtuxx/girus-cli/internal/common.BuildUser=$(BUILT_BY) 21 | LDFLAGS += -X github.com/badtuxx/girus-cli/internal/common.CommitID=$(COMMITID) 22 | LDFLAGS += -X github.com/badtuxx/girus-cli/internal/common.GoVersion=$(GO_VERSION) 23 | LDFLAGS += -X github.com/badtuxx/girus-cli/internal/common.GoOS=$(GO_OS) 24 | LDFLAGS += -X github.com/badtuxx/girus-cli/internal/common.GoArch=$(GO_ARCH) 25 | 26 | # PLATAFORMAS SUPORTADAS 27 | PLATAFORMAS = \ 28 | linux/amd64 \ 29 | linux/arm64 \ 30 | darwin/amd64 \ 31 | darwin/arm64 \ 32 | windows/amd64 \ 33 | windows/arm64 34 | 35 | # Alvo padrão: construir o binário 36 | all: build 37 | 38 | # Constrói o binário principal 39 | build: 40 | go build -v -ldflags="$(LDFLAGS)" -o $(BD)/$(BIN) $(CDR)/main.go 41 | 42 | # Instala o binário no sistema 43 | install: build 44 | sudo mv $(BD)/$(BIN) $(INSTALL_DIR)/$(BIN) 45 | 46 | # Limpa o diretório de build 47 | clean: 48 | rm -rf $(BD) 49 | 50 | # Cria os binários para múltiplas plataformas (release) 51 | release: 52 | @echo "Construindo para múltiplas plataformas..." 53 | @mkdir -p $(BD) 54 | @for platform in $(PLATAFORMAS); do \ 55 | OS=$$(echo $$platform | cut -d/ -f1); \ 56 | ARCH=$$(echo $$platform | cut -d/ -f2); \ 57 | OUT=$(BD)/$(BIN)-$$OS-$$ARCH; \ 58 | if [ "$$OS" = "windows" ]; then \ 59 | OUT=$$OUT.exe; \ 60 | fi; \ 61 | echo "-> $$OS/$$ARCH (Saída: $$OUT)"; \ 62 | GOOS=$$OS GOARCH=$$ARCH go build -ldflags "$(LDFLAGS)" -v -o $$OUT $(CDR)/main.go || exit 1; \ 63 | done 64 | 65 | # Executa o binário localmente usando o arquivo de configuração 66 | run-local: build 67 | CONFIG_FILE=$(CONFIG_PATH) ./$(BD)/$(BIN) 68 | 69 | # Verifica se há atualizações de dependências disponíveis 70 | check-updates: 71 | @echo "Verificando atualizações disponíveis..." 72 | go list -u -m -json all | grep '"Path"\|"Version"\|"Update"' 73 | 74 | # Atualiza todas as dependências do projeto 75 | upgrade-all: 76 | @echo "Atualizando todas as dependências..." 77 | go get -u ./... 78 | go mod tidy 79 | @echo "Todas as dependências foram atualizadas." 80 | 81 | # Atualiza uma dependência específica (requer MODULE=nome/do/modulo) 82 | upgrade: 83 | ifndef MODULE 84 | $(error Você deve fornecer o nome do módulo com MODULE=exemplo.com/lib) 85 | endif 86 | @echo "Atualizando $(MODULE)..." 87 | go get -u $(MODULE) 88 | go mod tidy 89 | @echo "$(MODULE) atualizado." 90 | 91 | # Limpa dependências não utilizadas (go mod tidy) 92 | tidy: 93 | @echo "Limpando dependências não utilizadas..." 94 | go mod tidy 95 | @echo "go.mod e go.sum estão limpos." 96 | 97 | # Exibe o gráfico de dependências 98 | deps: 99 | @echo "Exibindo gráfico de dependências..." 100 | go mod graph 101 | 102 | # Declara alvos que não representam arquivos 103 | .PHONY: all build install clean release run-local check-updates upgrade-all upgrade tidy deps 104 | -------------------------------------------------------------------------------- /labs/linux_automacao-agendamento/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: linux-automacao-agendamento-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: linux-automacao-agendamento 11 | title: "Automação e Agendamento no Linux" 12 | description: "Aprenda a automatizar tarefas e agendar execuções no Linux usando cron, systemd timers e scripts de automação. Este laboratório guiado explora as ferramentas e técnicas para criar sistemas automatizados e agendar tarefas de forma eficiente." 13 | duration: 30m 14 | image: "linuxtips/girus-devops:0.1" 15 | tasks: 16 | - name: "Agendamento com Cron" 17 | description: "Aprenda a usar o cron para agendar tarefas recorrentes." 18 | steps: 19 | - description: "Verifique o status do serviço cron" 20 | command: "systemctl status cron" 21 | expectedOutput: "Active: active" 22 | hint: "Use o comando systemctl para verificar o status do serviço" 23 | 24 | - description: "Crie uma tarefa cron para backup" 25 | command: "echo '0 2 * * * tar -czf /backup/home_$(date +%Y%m%d).tar.gz /home' | crontab -" 26 | expectedOutput: "" 27 | hint: "Use o comando crontab para adicionar uma tarefa" 28 | 29 | - description: "Verifique as tarefas agendadas" 30 | command: "crontab -l" 31 | expectedOutput: "0 2 * * *" 32 | hint: "Use o comando crontab -l para listar as tarefas" 33 | 34 | - name: "Systemd Timers" 35 | description: "Explore o uso de systemd timers para agendamento de tarefas." 36 | steps: 37 | - description: "Crie um serviço systemd" 38 | command: "echo -e '[Unit]\nDescription=Backup Service\n\n[Service]\nType=oneshot\nExecStart=/usr/bin/tar -czf /backup/system_$(date +%Y%m%d).tar.gz /etc\n\n[Install]\nWantedBy=multi-user.target' | sudo tee /etc/systemd/system/backup.service" 39 | expectedOutput: "" 40 | hint: "Crie um arquivo de serviço systemd" 41 | 42 | - description: "Crie um timer para o serviço" 43 | command: "echo -e '[Unit]\nDescription=Run backup daily\n\n[Timer]\nOnCalendar=daily\nPersistent=true\n\n[Install]\nWantedBy=timers.target' | sudo tee /etc/systemd/system/backup.timer" 44 | expectedOutput: "" 45 | hint: "Crie um arquivo de timer systemd" 46 | 47 | - description: "Ative e inicie o timer" 48 | command: "sudo systemctl enable --now backup.timer" 49 | expectedOutput: "" 50 | hint: "Use systemctl para ativar o timer" 51 | 52 | - name: "Scripts de Automação" 53 | description: "Aprenda a criar e executar scripts de automação." 54 | steps: 55 | - description: "Crie um script de monitoramento" 56 | command: "echo -e '#!/bin/bash\n\necho \"Monitoramento do Sistema\"\necho \"==================\"\ndf -h\necho \"\"\nfree -h\necho \"\"\nps aux | grep -v grep' > monitor.sh && chmod +x monitor.sh" 57 | expectedOutput: "" 58 | hint: "Crie um script shell com permissões de execução" 59 | 60 | - description: "Execute o script" 61 | command: "./monitor.sh" 62 | expectedOutput: "Monitoramento do Sistema" 63 | hint: "Execute o script com ./monitor.sh" 64 | 65 | - description: "Agende o script para execução periódica" 66 | command: "echo '*/30 * * * * /workspace/monitor.sh >> /workspace/monitor.log 2>&1' | crontab -" 67 | expectedOutput: "" 68 | hint: "Use crontab para agendar a execução do script" 69 | -------------------------------------------------------------------------------- /labs/terraform_fundamentos/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: terraform-fundamentos-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: terraform-fundamentos 11 | title: "Fundamentos do Terraform" 12 | description: "Aprenda os conceitos básicos do Terraform, incluindo sintaxe HCL, providers, recursos e estados. Este laboratório guiado explora os fundamentos da infraestrutura como código." 13 | duration: 40m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Configuração Inicial" 18 | description: "Aprenda a configurar um projeto Terraform básico." 19 | steps: 20 | - description: "Crie um diretório para o projeto" 21 | command: "mkdir -p terraform-lab && cd terraform-lab" 22 | expectedOutput: "" 23 | hint: "Use o comando mkdir para criar o diretório" 24 | 25 | - description: "Crie o arquivo de configuração principal" 26 | command: "echo -e 'terraform {\n required_providers {\n aws = {\n source = \"hashicorp/aws\"\n version = \"~> 4.0\"\n }\n }\n}\n\nprovider \"aws\" {\n region = \"us-east-1\"\n}\n\nresource \"aws_instance\" \"example\" {\n ami = \"ami-0c55b159cbfafe1f0\"\n instance_type = \"t2.micro\"\n\n tags = {\n Name = \"terraform-example\"\n }\n}' > main.tf" 27 | expectedOutput: "" 28 | hint: "Crie um arquivo main.tf com a configuração básica" 29 | 30 | - description: "Inicialize o Terraform" 31 | command: "terraform init" 32 | expectedOutput: "Terraform has been successfully initialized" 33 | hint: "Use o comando terraform init" 34 | 35 | - name: "Gerenciamento de Estado" 36 | description: "Aprenda a gerenciar o estado do Terraform." 37 | steps: 38 | - description: "Crie um plano de execução" 39 | command: "terraform plan -out=tfplan" 40 | expectedOutput: "Plan: 1 to add" 41 | hint: "Use o comando terraform plan" 42 | 43 | - description: "Aplique as mudanças" 44 | command: "terraform apply tfplan" 45 | expectedOutput: "Apply complete!" 46 | hint: "Use o comando terraform apply" 47 | 48 | - description: "Verifique o estado" 49 | command: "terraform show" 50 | expectedOutput: "aws_instance.example" 51 | hint: "Use o comando terraform show" 52 | 53 | - name: "Variáveis e Outputs" 54 | description: "Aprenda a usar variáveis e outputs no Terraform." 55 | steps: 56 | - description: "Crie um arquivo de variáveis" 57 | command: "echo -e 'variable \"instance_type\" {\n description = \"Tipo da instância EC2\"\n type = string\n default = \"t2.micro\"\n}\n\nvariable \"instance_name\" {\n description = \"Nome da instância EC2\"\n type = string\n default = \"terraform-example\"\n}' > variables.tf" 58 | expectedOutput: "" 59 | hint: "Crie um arquivo variables.tf com as definições de variáveis" 60 | 61 | - description: "Crie um arquivo de outputs" 62 | command: "echo -e 'output \"instance_id\" {\n description = \"ID da instância EC2\"\n value = aws_instance.example.id\n}\n\noutput \"public_ip\" {\n description = \"IP público da instância EC2\"\n value = aws_instance.example.public_ip\n}' > outputs.tf" 63 | expectedOutput: "" 64 | hint: "Crie um arquivo outputs.tf com as definições de outputs" 65 | 66 | - description: "Atualize a configuração" 67 | command: "terraform apply -auto-approve" 68 | expectedOutput: "Apply complete!" 69 | hint: "Use o comando terraform apply com -auto-approve" 70 | -------------------------------------------------------------------------------- /internal/templates/manifests_es/lab_35_terraform_fundamentos.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: terraform-fundamentos-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: terraform-fundamentos-es 11 | title: "Fundamentos do Terraform" 12 | description: "Aprenda os conceitos básicos do Terraform, incluindo sintaxe HCL, providers, recursos e estados. Este laboratório guiado explora os fundamentos da infraestrutura como código." 13 | duration: 40m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Configuração Inicial" 18 | description: "Aprenda a configurar um projeto Terraform básico." 19 | steps: 20 | - description: "Crie um diretório para o projeto" 21 | command: "mkdir -p terraform-lab && cd terraform-lab" 22 | expectedOutput: "" 23 | hint: "Use o comando mkdir para criar o diretório" 24 | 25 | - description: "Crie o arquivo de configuração principal" 26 | command: "echo -e 'terraform {\n required_providers {\n aws = {\n source = \"hashicorp/aws\"\n version = \"~> 4.0\"\n }\n }\n}\n\nprovider \"aws\" {\n region = \"us-east-1\"\n}\n\nresource \"aws_instance\" \"example\" {\n ami = \"ami-0c55b159cbfafe1f0\"\n instance_type = \"t2.micro\"\n\n tags = {\n Name = \"terraform-example\"\n }\n}' > main.tf" 27 | expectedOutput: "" 28 | hint: "Crie um arquivo main.tf com a configuração básica" 29 | 30 | - description: "Inicialize o Terraform" 31 | command: "terraform init" 32 | expectedOutput: "Terraform has been successfully initialized" 33 | hint: "Use o comando terraform init" 34 | 35 | - name: "Gerenciamento de Estado" 36 | description: "Aprenda a gerenciar o estado do Terraform." 37 | steps: 38 | - description: "Crie um plano de execução" 39 | command: "terraform plan -out=tfplan" 40 | expectedOutput: "Plan: 1 to add" 41 | hint: "Use o comando terraform plan" 42 | 43 | - description: "Aplique as mudanças" 44 | command: "terraform apply tfplan" 45 | expectedOutput: "Apply complete!" 46 | hint: "Use o comando terraform apply" 47 | 48 | - description: "Verifique o estado" 49 | command: "terraform show" 50 | expectedOutput: "aws_instance.example" 51 | hint: "Use o comando terraform show" 52 | 53 | - name: "Variáveis e Outputs" 54 | description: "Aprenda a usar variáveis e outputs no Terraform." 55 | steps: 56 | - description: "Crie um arquivo de variáveis" 57 | command: "echo -e 'variable \"instance_type\" {\n description = \"Tipo da instância EC2\"\n type = string\n default = \"t2.micro\"\n}\n\nvariable \"instance_name\" {\n description = \"Nome da instância EC2\"\n type = string\n default = \"terraform-example\"\n}' > variables.tf" 58 | expectedOutput: "" 59 | hint: "Crie um arquivo variables.tf com as definições de variáveis" 60 | 61 | - description: "Crie um arquivo de outputs" 62 | command: "echo -e 'output \"instance_id\" {\n description = \"ID da instância EC2\"\n value = aws_instance.example.id\n}\n\noutput \"public_ip\" {\n description = \"IP público da instância EC2\"\n value = aws_instance.example.public_ip\n}' > outputs.tf" 63 | expectedOutput: "" 64 | hint: "Crie um arquivo outputs.tf com as definições de outputs" 65 | 66 | - description: "Atualize a configuração" 67 | command: "terraform apply -auto-approve" 68 | expectedOutput: "Apply complete!" 69 | hint: "Use o comando terraform apply com -auto-approve" 70 | -------------------------------------------------------------------------------- /labs/terraform_fundamentos/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: terraform-fundamentos-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: terraform-fundamentos-es 11 | title: "Fundamentos de Terraform" 12 | description: "aprende los conceptos básicos de Terraform, incluyendo sintaxis HCL, providers, recursos y estados. Este laboratorio guiado explora los fundamentos de la infraestructura como código." 13 | duration: 40m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Configuración Inicial" 18 | description: "aprende a configurar un proyecto Terraform básico." 19 | steps: 20 | - description: "Crea un directorio para el proyecto" 21 | command: "mkdir -p terraform-lab && cd terraform-lab" 22 | expectedOutput: "" 23 | hint: "Usa el comando mkdir para crear el directorio" 24 | 25 | - description: "Crea el archivo de configuración principal" 26 | command: "echo -e 'terraform {\n required_providers {\n aws = {\n source = \"hashicorp/aws\"\n version = \"~> 4.0\"\n }\n }\n}\n\nprovider \"aws\" {\n region = \"us-east-1\"\n}\n\nresource \"aws_instance\" \"example\" {\n ami = \"ami-0c55b159cbfafe1f0\"\n instance_type = \"t2.micro\"\n\n tags = {\n Name = \"terraform-example\"\n }\n}' > main.tf" 27 | expectedOutput: "" 28 | hint: "Crea un archivo main.tf con la configuración básica" 29 | 30 | - description: "Inicializa Terraform" 31 | command: "terraform init" 32 | expectedOutput: "Terraform has been successfully initialized" 33 | hint: "Usa el comando terraform init" 34 | 35 | - name: "Gestión de Estado" 36 | description: "aprende a gestionar el estado de Terraform." 37 | steps: 38 | - description: "Crea un plan de ejecución" 39 | command: "terraform plan -out=tfplan" 40 | expectedOutput: "Plan: 1 to add" 41 | hint: "Usa el comando terraform plan" 42 | 43 | - description: "Aplica los cambios" 44 | command: "terraform apply tfplan" 45 | expectedOutput: "Apply complete!" 46 | hint: "Usa el comando terraform apply" 47 | 48 | - description: "Verifica el estado" 49 | command: "terraform show" 50 | expectedOutput: "aws_instance.example" 51 | hint: "Usa el comando terraform show" 52 | 53 | - name: "Variables y Outputs" 54 | description: "aprende a usar variables y outputs en Terraform." 55 | steps: 56 | - description: "Crea un archivo de variables" 57 | command: "echo -e 'variable \"instance_type\" {\n description = \"Tipo de la instancia EC2\"\n type = string\n default = \"t2.micro\"\n}\n\nvariable \"instance_name\" {\n description = \"Nombre de la instancia EC2\"\n type = string\n default = \"terraform-example\"\n}' > variables.tf" 58 | expectedOutput: "" 59 | hint: "Crea un archivo variables.tf con las definiciones de variables" 60 | 61 | - description: "Crea un archivo de outputs" 62 | command: "echo -e 'output \"instance_id\" {\n description = \"ID de la instancia EC2\"\n value = aws_instance.example.id\n}\n\noutput \"public_ip\" {\n description = \"IP pública de la instancia EC2\"\n value = aws_instance.example.public_ip\n}' > outputs.tf" 63 | expectedOutput: "" 64 | hint: "Crea un archivo outputs.tf con las definiciones de outputs" 65 | 66 | - description: "Actualiza la configuración" 67 | command: "terraform apply -auto-approve" 68 | expectedOutput: "Apply complete!" 69 | hint: "Usa el comando terraform apply con -auto-approve" 70 | -------------------------------------------------------------------------------- /labs/aws_s3-iam/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: aws-s3-iam-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: aws-s3-iam 11 | title: "S3 e IAM na AWS" 12 | description: "Aprenda a gerenciar buckets S3 e políticas IAM na AWS. Este laboratório guiado explora conceitos de armazenamento de objetos e controle de acesso na nuvem." 13 | duration: 40m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Gerenciamento de Buckets S3" 18 | description: "Aprenda a criar e configurar buckets S3." 19 | steps: 20 | - description: "Crie um bucket S3" 21 | command: "aws s3api create-bucket --bucket lab-bucket-$(date +%s) --region us-east-1" 22 | expectedOutput: "Location" 23 | hint: "Use o comando aws s3api create-bucket" 24 | 25 | - description: "Configure o bucket para hospedagem de site estático" 26 | command: "aws s3api put-bucket-website --bucket $(aws s3api list-buckets --query 'Buckets[0].Name' --output text) --website-configuration '{\"IndexDocument\":{\"Suffix\":\"index.html\"},\"ErrorDocument\":{\"Key\":\"error.html\"}}'" 27 | expectedOutput: "" 28 | hint: "Use o comando aws s3api put-bucket-website" 29 | 30 | - description: "Configure a política de bucket" 31 | command: "aws s3api put-bucket-policy --bucket $(aws s3api list-buckets --query 'Buckets[0].Name' --output text) --policy '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"PublicReadGetObject\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"s3:GetObject\",\"Resource\":\"arn:aws:s3:::$(aws s3api list-buckets --query \"Buckets[0].Name\" --output text)/*\"}]}'" 32 | expectedOutput: "" 33 | hint: "Use o comando aws s3api put-bucket-policy" 34 | 35 | - name: "Operações com Objetos S3" 36 | description: "Aprenda a gerenciar objetos em buckets S3." 37 | steps: 38 | - description: "Crie um arquivo de teste" 39 | command: "echo '

Hello from S3!

' > index.html" 40 | expectedOutput: "" 41 | hint: "Crie um arquivo HTML simples" 42 | 43 | - description: "Faça upload do arquivo para o bucket" 44 | command: "aws s3 cp index.html s3://$(aws s3api list-buckets --query 'Buckets[0].Name' --output text)/" 45 | expectedOutput: "upload:" 46 | hint: "Use o comando aws s3 cp" 47 | 48 | - description: "Verifique o conteúdo do bucket" 49 | command: "aws s3 ls s3://$(aws s3api list-buckets --query 'Buckets[0].Name' --output text)/" 50 | expectedOutput: "index.html" 51 | hint: "Use o comando aws s3 ls" 52 | 53 | - name: "Gerenciamento de IAM" 54 | description: "Aprenda a criar e gerenciar usuários e políticas IAM." 55 | steps: 56 | - description: "Crie um usuário IAM" 57 | command: "aws iam create-user --user-name lab-user" 58 | expectedOutput: "User" 59 | hint: "Use o comando aws iam create-user" 60 | 61 | - description: "Crie uma política de acesso ao S3" 62 | command: "aws iam create-policy --policy-name S3AccessPolicy --policy-document '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:GetObject\",\"s3:PutObject\"],\"Resource\":\"arn:aws:s3:::$(aws s3api list-buckets --query \"Buckets[0].Name\" --output text)/*\"}]}'" 63 | expectedOutput: "Policy" 64 | hint: "Use o comando aws iam create-policy" 65 | 66 | - description: "Anexe a política ao usuário" 67 | command: "aws iam attach-user-policy --user-name lab-user --policy-arn $(aws iam list-policies --query 'Policies[0].Arn' --output text)" 68 | expectedOutput: "" 69 | hint: "Use o comando aws iam attach-user-policy" 70 | -------------------------------------------------------------------------------- /labs/aws_s3-iam/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: aws-s3-iam-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: aws-s3-iam-es 11 | title: "S3 e IAM en AWS" 12 | description: "Aprende a administrar buckets S3 y políticas IAM en AWS. Este laboratorio guiado explora conceptos de almacenamiento de objetos y control de acceso en la nube." 13 | duration: 40m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Administración de Buckets S3" 18 | description: "Aprende a crear y configurar buckets S3." 19 | steps: 20 | - description: "Crea un bucket S3" 21 | command: "aws s3api create-bucket --bucket lab-bucket-$(date +%s) --region us-east-1" 22 | expectedOutput: "Location" 23 | hint: "Usa el comando aws s3api create-bucket" 24 | 25 | - description: "Configura el bucket para hospedaje de sitio web estático" 26 | command: "aws s3api put-bucket-website --bucket $(aws s3api list-buckets --query 'Buckets[0].Name' --output text) --website-configuration '{\"IndexDocument\":{\"Suffix\":\"index.html\"},\"ErrorDocument\":{\"Key\":\"error.html\"}}'" 27 | expectedOutput: "" 28 | hint: "Usa el comando aws s3api put-bucket-website" 29 | 30 | - description: "Configura la política del bucket" 31 | command: "aws s3api put-bucket-policy --bucket $(aws s3api list-buckets --query 'Buckets[0].Name' --output text) --policy '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"PublicReadGetObject\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"s3:GetObject\",\"Resource\":\"arn:aws:s3:::$(aws s3api list-buckets --query \"Buckets[0].Name\" --output text)/*\"}]}'" 32 | expectedOutput: "" 33 | hint: "Usa el comando aws s3api put-bucket-policy" 34 | 35 | - name: "Operaciones con Objetos S3" 36 | description: "Aprende a administrar objetos en buckets S3." 37 | steps: 38 | - description: "Crea un archivo de prueba" 39 | command: "echo '

Hello from S3!

' > index.html" 40 | expectedOutput: "" 41 | hint: "Crea un archivo HTML simple" 42 | 43 | - description: "Sube el archivo al bucket" 44 | command: "aws s3 cp index.html s3://$(aws s3api list-buckets --query 'Buckets[0].Name' --output text)/" 45 | expectedOutput: "upload:" 46 | hint: "Usa el comando aws s3 cp" 47 | 48 | - description: "Verifica el contenido del bucket" 49 | command: "aws s3 ls s3://$(aws s3api list-buckets --query 'Buckets[0].Name' --output text)/" 50 | expectedOutput: "index.html" 51 | hint: "Usa el comando aws s3 ls" 52 | 53 | - name: "Administración de IAM" 54 | description: "Aprende a crear y administrar usuarios y políticas IAM." 55 | steps: 56 | - description: "Crea un usuario IAM" 57 | command: "aws iam create-user --user-name lab-user" 58 | expectedOutput: "User" 59 | hint: "Usa el comando aws iam create-user" 60 | 61 | - description: "Crea una política de acceso a S3" 62 | command: "aws iam create-policy --policy-name S3AccessPolicy --policy-document '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:GetObject\",\"s3:PutObject\"],\"Resource\":\"arn:aws:s3:::$(aws s3api list-buckets --query \"Buckets[0].Name\" --output text)/*\"}]}'" 63 | expectedOutput: "Policy" 64 | hint: "Usa el comando aws iam create-policy" 65 | 66 | - description: "Asocia la política al usuario" 67 | command: "aws iam attach-user-policy --user-name lab-user --policy-arn $(aws iam list-policies --query 'Policies[0].Arn' --output text)" 68 | expectedOutput: "" 69 | hint: "Usa el comando aws iam attach-user-policy" 70 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "github.com/fatih/color" 6 | "github.com/spf13/cobra" 7 | 8 | "github.com/badtuxx/girus-cli/internal/common" 9 | ) 10 | 11 | var rootCmd = &cobra.Command{ 12 | Use: "girus", 13 | Short: common.T("GIRUS - Plataforma de Laboratórios Interativos", "GIRUS - Plataforma de Laboratorios Interactivos"), 14 | Long: common.T(`GIRUS é uma plataforma open-source de laboratórios interativos que permite a criação, 15 | gerenciamento e execução de ambientes de aprendizado prático para tecnologias como Linux, 16 | Docker, Kubernetes, Terraform e outras ferramentas essenciais para profissionais de DevOps, 17 | SRE, Dev e Platform Engineering.`, 18 | `GIRUS es una plataforma de código abierto para laboratorios interactivos que permite crear, 19 | gestionar y ejecutar entornos de aprendizaje práctico para tecnologías como Linux, 20 | Docker, Kubernetes, Terraform y otras herramientas esenciales para profesionales de DevOps, 21 | SRE, Dev y Platform Engineering.`), 22 | } 23 | 24 | // Execute executa o comando raiz 25 | func Execute() error { 26 | return rootCmd.Execute() 27 | } 28 | 29 | func init() { 30 | // Criar formatadores de cores 31 | magenta := color.New(color.FgMagenta).SprintFunc() 32 | cyan := color.New(color.FgCyan).SprintFunc() 33 | headerColor := color.New(color.FgCyan, color.Bold).SprintFunc() 34 | 35 | // Customizar templates de help 36 | cobra.AddTemplateFunc("magenta", func(s string) string { 37 | return magenta(s) 38 | }) 39 | 40 | cobra.AddTemplateFunc("cyan", func(s string) string { 41 | return cyan(s) 42 | }) 43 | 44 | cobra.AddTemplateFunc("header", func(s string) string { 45 | return headerColor(s) 46 | }) 47 | 48 | // Template personalizado para o help principal 49 | rootCmd.SetUsageTemplate(fmt.Sprintf(`{{header "%s"}} 50 | 51 | {{.Long}} 52 | 53 | {{header "%s"}} 54 | {{magenta .Use}} 55 | 56 | {{header "%s"}}{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} 57 | {{magenta .Name | printf "%%-12s"}} {{.Short}}{{end}}{{end}} 58 | 59 | {{header "%s"}} 60 | {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}} 61 | 62 | %s`, 63 | common.T("GIRUS - Plataforma de Laboratórios Interativos", "GIRUS - Plataforma de Laboratorios Interactivos"), 64 | common.T("Usage:", "Uso:"), 65 | common.T("Available Commands:", "Comandos Disponibles:"), 66 | common.T("Flags:", "Flags:"), 67 | common.T("Use \"girus [command] --help\" for more information about a command.", "Use \"girus [command] --help\" para obtener más información sobre un comando."))) 68 | 69 | // Template personalizado para o help de comandos 70 | rootCmd.SetHelpTemplate(fmt.Sprintf(`{{header .Name}} - {{.Short}} 71 | 72 | {{.Long}} 73 | 74 | {{header "%s"}} 75 | {{magenta .UseLine}} 76 | 77 | {{if .HasAvailableSubCommands}}{{header "%s"}}{{range .Commands}}{{if .IsAvailableCommand}} 78 | {{magenta .Name | printf "%%-12s"}} {{.Short}}{{end}}{{end}} 79 | {{end}} 80 | 81 | {{if .HasAvailableLocalFlags}}{{header "%s"}} 82 | {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}} 83 | 84 | {{if .HasAvailableInheritedFlags}}{{header "%s"}} 85 | {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}} 86 | `, 87 | common.T("Usage:", "Uso:"), 88 | common.T("Available Commands:", "Comandos Disponibles:"), 89 | common.T("Flags:", "Flags:"), 90 | common.T("Global Flags:", "Flags Globales:"))) 91 | 92 | // Adiciona os comandos 93 | rootCmd.AddCommand(createCmd) 94 | rootCmd.AddCommand(deleteCmd) 95 | rootCmd.AddCommand(listCmd) 96 | rootCmd.AddCommand(labCmd) 97 | rootCmd.AddCommand(repoCmd) 98 | rootCmd.AddCommand(statusCmd) 99 | rootCmd.AddCommand(versionCmd) 100 | rootCmd.AddCommand(stopCmd) 101 | rootCmd.AddCommand(startCmd) 102 | 103 | // Não adicionar updateCmd aqui, pois já é adicionado no update.go 104 | 105 | // Configura flags globais 106 | rootCmd.PersistentFlags().StringP("config", "c", "", common.T("arquivo de configuração (padrão: $HOME/.girus/config.yaml)", "archivo de configuración (predeterminado: $HOME/.girus/config.yaml)")) 107 | } 108 | -------------------------------------------------------------------------------- /labs/linux_monitoramento-sistema/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: linux-monitoramento-sistema-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: linux-monitoramento-sistema 11 | title: "Monitoramento Básico do Sistema Linux" 12 | description: "Utilize ferramentas como vmstat, iostat, free e explore o /proc para obter informações sobre o desempenho do sistema." 13 | duration: 20m 14 | image: "linuxtips/girus-devops:0.1" 15 | tasks: 16 | - name: "Verificando Uso de Memória (free, vmstat)" 17 | description: "Analise o consumo de memória RAM e Swap." 18 | steps: 19 | - "Visualize o uso de memória de forma legível:" 20 | - "`free -h`" 21 | - "Entenda as colunas: total, used, free, shared, buff/cache, available." 22 | - "Use vmstat para ver estatísticas de memória virtual (e outras) a cada 1 segundo, 2 vezes:" 23 | - "`vmstat 1 2`" 24 | - "Observe as colunas 'si' (swap in) e 'so' (swap out). Valores altos indicam uso excessivo de swap." 25 | tips: 26 | - type: "info" 27 | title: "Memória 'Available' vs 'Free'" 28 | content: "No Linux moderno, 'available' é uma estimativa mais realista da memória disponível para novas aplicações, pois considera a memória usada para cache que pode ser liberada." 29 | - type: "tip" 30 | title: "vmstat" 31 | content: "'vmstat' (Virtual Memory Statistics) fornece um resumo rápido de processos, memória, swap, I/O, sistema e CPU." 32 | validation: 33 | - command: "free -h | grep 'Mem:' &> /dev/null && echo 'ok'" 34 | expectedOutput: "ok" 35 | errorMessage: "O comando 'free -h' não produziu a saída esperada contendo 'Mem:'." 36 | 37 | - name: "Analisando Atividade de Disco (iostat)" 38 | description: "Verifique a utilização e o desempenho dos dispositivos de bloco (discos)." 39 | steps: 40 | - "Instale o pacote sysstat se necessário (pode já estar na imagem):" 41 | - "`sudo apt-get update && sudo apt-get install -y sysstat || echo 'sysstat já instalado'`" 42 | - "Visualize estatísticas de I/O para todos os dispositivos (-x), a cada 1 segundo, 2 vezes:" 43 | - "`iostat -x 1 2`" 44 | - "Observe colunas importantes como: %util (percentual de tempo que o disco esteve ocupado), await (tempo médio de espera por I/O), r/s (leituras por segundo), w/s (escritas por segundo)." 45 | tips: 46 | - type: "warning" 47 | title: "%util Alto" 48 | content: "Um %util consistentemente perto de 100% indica que o disco pode ser um gargalo de desempenho." 49 | validation: 50 | - command: "iostat -x 1 2 | grep 'Device' &> /dev/null && echo 'ok'" 51 | expectedOutput: "ok" 52 | errorMessage: "O comando 'iostat -x' não produziu a saída esperada contendo 'Device'." 53 | 54 | - name: "Explorando o Sistema de Arquivos /proc" 55 | description: "Navegue pelo /proc para obter informações detalhadas sobre o kernel e os processos." 56 | steps: 57 | - "/proc é um sistema de arquivos virtual que reflete o estado do kernel." 58 | - "Visualize informações sobre a CPU:" 59 | - "`cat /proc/cpuinfo`" 60 | - "Visualize informações sobre a memória:" 61 | - "`cat /proc/meminfo`" 62 | - "Visualize informações sobre as partições montadas:" 63 | - "`cat /proc/mounts`" 64 | - "Visualize informações sobre o processo atual (PID $$):" 65 | - "`ls -l /proc/$$/`" 66 | - "`cat /proc/$$/status`" 67 | tips: 68 | - type: "info" 69 | title: "/proc e Ferramentas" 70 | content: "Muitas ferramentas de monitoramento (como ps, top, free) obtêm suas informações lendo arquivos dentro do /proc." 71 | validation: 72 | - command: "grep 'model name' /proc/cpuinfo &> /dev/null && echo 'ok'" 73 | expectedOutput: "ok" 74 | errorMessage: "Não foi possível ler informações da CPU em /proc/cpuinfo." 75 | -------------------------------------------------------------------------------- /internal/templates/manifests/lab_04_linux_monitoramento-sistema.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: linux-monitoramento-sistema-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: linux-monitoramento-sistema 11 | title: "Monitoramento Básico do Sistema Linux" 12 | description: "Utilize ferramentas como vmstat, iostat, free e explore o /proc para obter informações sobre o desempenho do sistema." 13 | duration: 20m 14 | image: "linuxtips/girus-devops:0.1" 15 | tasks: 16 | - name: "Verificando Uso de Memória (free, vmstat)" 17 | description: "Analise o consumo de memória RAM e Swap." 18 | steps: 19 | - "Visualize o uso de memória de forma legível:" 20 | - "`free -h`" 21 | - "Entenda as colunas: total, used, free, shared, buff/cache, available." 22 | - "Use vmstat para ver estatísticas de memória virtual (e outras) a cada 1 segundo, 2 vezes:" 23 | - "`vmstat 1 2`" 24 | - "Observe as colunas 'si' (swap in) e 'so' (swap out). Valores altos indicam uso excessivo de swap." 25 | tips: 26 | - type: "info" 27 | title: "Memória 'Available' vs 'Free'" 28 | content: "No Linux moderno, 'available' é uma estimativa mais realista da memória disponível para novas aplicações, pois considera a memória usada para cache que pode ser liberada." 29 | - type: "tip" 30 | title: "vmstat" 31 | content: "'vmstat' (Virtual Memory Statistics) fornece um resumo rápido de processos, memória, swap, I/O, sistema e CPU." 32 | validation: 33 | - command: "free -h | grep 'Mem:' &> /dev/null && echo 'ok'" 34 | expectedOutput: "ok" 35 | errorMessage: "O comando 'free -h' não produziu a saída esperada contendo 'Mem:'." 36 | 37 | - name: "Analisando Atividade de Disco (iostat)" 38 | description: "Verifique a utilização e o desempenho dos dispositivos de bloco (discos)." 39 | steps: 40 | - "Instale o pacote sysstat se necessário (pode já estar na imagem):" 41 | - "`sudo apt-get update && sudo apt-get install -y sysstat || echo 'sysstat já instalado'`" 42 | - "Visualize estatísticas de I/O para todos os dispositivos (-x), a cada 1 segundo, 2 vezes:" 43 | - "`iostat -x 1 2`" 44 | - "Observe colunas importantes como: %util (percentual de tempo que o disco esteve ocupado), await (tempo médio de espera por I/O), r/s (leituras por segundo), w/s (escritas por segundo)." 45 | tips: 46 | - type: "warning" 47 | title: "%util Alto" 48 | content: "Um %util consistentemente perto de 100% indica que o disco pode ser um gargalo de desempenho." 49 | validation: 50 | - command: "iostat -x 1 2 | grep 'Device' &> /dev/null && echo 'ok'" 51 | expectedOutput: "ok" 52 | errorMessage: "O comando 'iostat -x' não produziu a saída esperada contendo 'Device'." 53 | 54 | - name: "Explorando o Sistema de Arquivos /proc" 55 | description: "Navegue pelo /proc para obter informações detalhadas sobre o kernel e os processos." 56 | steps: 57 | - "/proc é um sistema de arquivos virtual que reflete o estado do kernel." 58 | - "Visualize informações sobre a CPU:" 59 | - "`cat /proc/cpuinfo`" 60 | - "Visualize informações sobre a memória:" 61 | - "`cat /proc/meminfo`" 62 | - "Visualize informações sobre as partições montadas:" 63 | - "`cat /proc/mounts`" 64 | - "Visualize informações sobre o processo atual (PID $$):" 65 | - "`ls -l /proc/$$/`" 66 | - "`cat /proc/$$/status`" 67 | tips: 68 | - type: "info" 69 | title: "/proc e Ferramentas" 70 | content: "Muitas ferramentas de monitoramento (como ps, top, free) obtêm suas informações lendo arquivos dentro do /proc." 71 | validation: 72 | - command: "grep 'model name' /proc/cpuinfo &> /dev/null && echo 'ok'" 73 | expectedOutput: "ok" 74 | errorMessage: "Não foi possível ler informações da CPU em /proc/cpuinfo." 75 | -------------------------------------------------------------------------------- /internal/templates/manifests_es/lab_04_linux_monitoramento-sistema.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: linux-monitoramento-sistema-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: linux-monitoramento-sistema-es 11 | title: "Monitoramento Básico do Sistema Linux" 12 | description: "Utilize ferramentas como vmstat, iostat, free e explore o /proc para obter informações sobre o desempenho do sistema." 13 | duration: 20m 14 | image: "linuxtips/girus-devops:0.1" 15 | tasks: 16 | - name: "Verificando Uso de Memória (free, vmstat)" 17 | description: "Analise o consumo de memória RAM e Swap." 18 | steps: 19 | - "Visualize o uso de memória de forma legível:" 20 | - "`free -h`" 21 | - "Entenda as colunas: total, used, free, shared, buff/cache, available." 22 | - "Use vmstat para ver estatísticas de memória virtual (e outras) a cada 1 segundo, 2 vezes:" 23 | - "`vmstat 1 2`" 24 | - "Observe as colunas 'si' (swap in) e 'so' (swap out). Valores altos indicam uso excessivo de swap." 25 | tips: 26 | - type: "info" 27 | title: "Memória 'Available' vs 'Free'" 28 | content: "No Linux moderno, 'available' é uma estimativa mais realista da memória disponível para novas aplicações, pois considera a memória usada para cache que pode ser liberada." 29 | - type: "tip" 30 | title: "vmstat" 31 | content: "'vmstat' (Virtual Memory Statistics) fornece um resumo rápido de processos, memória, swap, I/O, sistema e CPU." 32 | validation: 33 | - command: "free -h | grep 'Mem:' &> /dev/null && echo 'ok'" 34 | expectedOutput: "ok" 35 | errorMessage: "O comando 'free -h' não produziu a saída esperada contendo 'Mem:'." 36 | 37 | - name: "Analisando Atividade de Disco (iostat)" 38 | description: "Verifique a utilização e o desempenho dos dispositivos de bloco (discos)." 39 | steps: 40 | - "Instale o pacote sysstat se necessário (pode já estar na imagem):" 41 | - "`sudo apt-get update && sudo apt-get install -y sysstat || echo 'sysstat já instalado'`" 42 | - "Visualize estatísticas de I/O para todos os dispositivos (-x), a cada 1 segundo, 2 vezes:" 43 | - "`iostat -x 1 2`" 44 | - "Observe colunas importantes como: %util (percentual de tempo que o disco esteve ocupado), await (tempo médio de espera por I/O), r/s (leituras por segundo), w/s (escritas por segundo)." 45 | tips: 46 | - type: "warning" 47 | title: "%util Alto" 48 | content: "Um %util consistentemente perto de 100% indica que o disco pode ser um gargalo de desempenho." 49 | validation: 50 | - command: "iostat -x 1 2 | grep 'Device' &> /dev/null && echo 'ok'" 51 | expectedOutput: "ok" 52 | errorMessage: "O comando 'iostat -x' não produziu a saída esperada contendo 'Device'." 53 | 54 | - name: "Explorando o Sistema de Arquivos /proc" 55 | description: "Navegue pelo /proc para obter informações detalhadas sobre o kernel e os processos." 56 | steps: 57 | - "/proc é um sistema de arquivos virtual que reflete o estado do kernel." 58 | - "Visualize informações sobre a CPU:" 59 | - "`cat /proc/cpuinfo`" 60 | - "Visualize informações sobre a memória:" 61 | - "`cat /proc/meminfo`" 62 | - "Visualize informações sobre as partições montadas:" 63 | - "`cat /proc/mounts`" 64 | - "Visualize informações sobre o processo atual (PID $$):" 65 | - "`ls -l /proc/$$/`" 66 | - "`cat /proc/$$/status`" 67 | tips: 68 | - type: "info" 69 | title: "/proc e Ferramentas" 70 | content: "Muitas ferramentas de monitoramento (como ps, top, free) obtêm suas informações lendo arquivos dentro do /proc." 71 | validation: 72 | - command: "grep 'model name' /proc/cpuinfo &> /dev/null && echo 'ok'" 73 | expectedOutput: "ok" 74 | errorMessage: "Não foi possível ler informações da CPU em /proc/cpuinfo." 75 | -------------------------------------------------------------------------------- /labs/docker_multi-stage-builds/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: docker-multi-stage-builds-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: docker-multi-stage-builds 11 | title: "Multi-stage Builds no Docker" 12 | description: "Aprenda a criar imagens Docker otimizadas usando multi-stage builds, reduzindo o tamanho final e melhorando a segurança. Este laboratório guiado explora técnicas avançadas de construção de imagens Docker para aplicações modernas." 13 | duration: 30m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Criando um Multi-stage Build Básico" 18 | description: "Aprenda os conceitos básicos de multi-stage builds." 19 | steps: 20 | - description: "Crie um Dockerfile com multi-stage build" 21 | command: "echo -e 'FROM golang:1.21 AS builder\nWORKDIR /app\nCOPY . .\nRUN go build -o main .\n\nFROM alpine:latest\nWORKDIR /app\nCOPY --from=builder /app/main .\nCMD [\"./main\"]' > Dockerfile" 22 | expectedOutput: "" 23 | hint: "Crie um Dockerfile com dois estágios: build e runtime" 24 | 25 | - description: "Crie um arquivo Go simples" 26 | command: "echo -e 'package main\n\nimport \"fmt\"\n\nfunc main() {\n fmt.Println(\"Hello from multi-stage build!\")\n}' > main.go" 27 | expectedOutput: "" 28 | hint: "Crie um programa Go básico" 29 | 30 | - description: "Construa a imagem" 31 | command: "docker build -t multi-stage-app ." 32 | expectedOutput: "Successfully built" 33 | hint: "Use o comando docker build para construir a imagem" 34 | 35 | - name: "Otimização de Imagens" 36 | description: "Aprenda técnicas para otimizar imagens Docker." 37 | steps: 38 | - description: "Verifique o tamanho da imagem" 39 | command: "docker images multi-stage-app" 40 | expectedOutput: "multi-stage-app" 41 | hint: "Use o comando docker images para ver o tamanho" 42 | 43 | - description: "Crie uma versão otimizada do Dockerfile" 44 | command: "echo -e 'FROM golang:1.21-alpine AS builder\nWORKDIR /app\nCOPY . .\nRUN go build -ldflags=\"-s -w\" -o main .\n\nFROM scratch\nCOPY --from=builder /app/main .\nCMD [\"./main\"]' > Dockerfile.optimized" 45 | expectedOutput: "" 46 | hint: "Crie um Dockerfile otimizado usando alpine e scratch" 47 | 48 | - description: "Construa a versão otimizada" 49 | command: "docker build -t multi-stage-app-optimized -f Dockerfile.optimized ." 50 | expectedOutput: "Successfully built" 51 | hint: "Construa a versão otimizada da imagem" 52 | 53 | - name: "Multi-stage Builds com Dependências" 54 | description: "Implemente multi-stage builds com gerenciamento de dependências." 55 | steps: 56 | - description: "Crie um Dockerfile para uma aplicação Node.js" 57 | command: "echo -e 'FROM node:18 AS deps\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci\n\nFROM node:18-alpine AS builder\nWORKDIR /app\nCOPY --from=deps /app/node_modules ./node_modules\nCOPY . .\nRUN npm run build\n\nFROM node:18-alpine\nWORKDIR /app\nCOPY --from=builder /app/dist ./dist\nCOPY --from=deps /app/node_modules ./node_modules\nCMD [\"node\", \"dist/index.js\"]' > Dockerfile.node" 58 | expectedOutput: "" 59 | hint: "Crie um Dockerfile para uma aplicação Node.js com três estágios" 60 | 61 | - description: "Crie um package.json básico" 62 | command: "echo -e '{\n \"name\": \"node-app\",\n \"version\": \"1.0.0\",\n \"scripts\": {\n \"build\": \"echo \\\"Build completed\\\"\"\n },\n \"dependencies\": {\n \"express\": \"^4.18.2\"\n }\n}' > package.json" 63 | expectedOutput: "" 64 | hint: "Crie um package.json com uma dependência" 65 | 66 | - description: "Construa a imagem Node.js" 67 | command: "docker build -t node-multi-stage -f Dockerfile.node ." 68 | expectedOutput: "Successfully built" 69 | hint: "Construa a imagem Node.js com multi-stage build" 70 | -------------------------------------------------------------------------------- /labs/linux_monitoramento-sistema/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: linux-monitoramento-sistema-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: linux-monitoramento-sistema-es 11 | title: "Monitoreo Básico del Sistema Linux" 12 | description: "Utiliza herramientas como vmstat, iostat, free y explora /proc para obtener información sobre el rendimiento del sistema." 13 | duration: 20m 14 | image: "linuxtips/girus-devops:0.1" 15 | tasks: 16 | - name: "Verificando Uso de Memoria (free, vmstat)" 17 | description: "Analiza el consumo de memoria RAM y Swap." 18 | steps: 19 | - "Visualiza el uso de memoria de forma legible:" 20 | - "`free -h`" 21 | - "Entiende las columnas: total, used, free, shared, buff/cache, available." 22 | - "Usa vmstat para ver estadísticas de memoria virtual (y otras) cada 1 segundo, 2 veces:" 23 | - "`vmstat 1 2`" 24 | - "Observa las columnas 'si' (swap in) y 'so' (swap out). Valores altos indican uso excesivo de swap." 25 | tips: 26 | - type: "info" 27 | title: "Memoria 'Available' vs 'Free'" 28 | content: "En Linux moderno, 'available' es una estimativa más realista de la memoria disponible para nuevas aplicaciones, pues considera la memoria usada para cache que puede ser liberada." 29 | - type: "tip" 30 | title: "vmstat" 31 | content: "'vmstat' (Virtual Memory Statistics) proporciona un resumen rápido de procesos, memoria, swap, I/O, sistema y CPU." 32 | validation: 33 | - command: "free -h | grep 'Mem:' &> /dev/null && echo 'ok'" 34 | expectedOutput: "ok" 35 | errorMessage: "El comando 'free -h' no produjo la salida esperada conteniendo 'Mem:'." 36 | 37 | - name: "Analizando Actividad de Disco (iostat)" 38 | description: "Verifica la utilización y el rendimiento de los dispositivos de bloque (discos)." 39 | steps: 40 | - "Instala el paquete sysstat si es necesario (puede ya estar en la imagen):" 41 | - "`sudo apt-get update && sudo apt-get install -y sysstat || echo 'sysstat ya instalado'`" 42 | - "Visualiza estadísticas de I/O para todos los dispositivos (-x), cada 1 segundo, 2 veces:" 43 | - "`iostat -x 1 2`" 44 | - "Observa columnas importantes como: %util (porcentaje de tiempo que el disco estuvo ocupado), await (tiempo promedio de espera por I/O), r/s (lecturas por segundo), w/s (escrituras por segundo)." 45 | tips: 46 | - type: "warning" 47 | title: "%util Alto" 48 | content: "Un %util consistentemente cerca del 100% indica que el disco puede ser un cuello de botella de rendimiento." 49 | validation: 50 | - command: "iostat -x 1 2 | grep 'Device' &> /dev/null && echo 'ok'" 51 | expectedOutput: "ok" 52 | errorMessage: "El comando 'iostat -x' no produjo la salida esperada conteniendo 'Device'." 53 | 54 | - name: "Explorando el Sistema de Archivos /proc" 55 | description: "Navega por /proc para obtener información detallada sobre el kernel y los procesos." 56 | steps: 57 | - "/proc es un sistema de archivos virtual que refleja el estado del kernel." 58 | - "Visualiza información sobre la CPU:" 59 | - "`cat /proc/cpuinfo`" 60 | - "Visualiza información sobre la memoria:" 61 | - "`cat /proc/meminfo`" 62 | - "Visualiza información sobre las particiones montadas:" 63 | - "`cat /proc/mounts`" 64 | - "Visualiza información sobre el proceso actual (PID $$):" 65 | - "`ls -l /proc/$$/`" 66 | - "`cat /proc/$$/status`" 67 | tips: 68 | - type: "info" 69 | title: "/proc y Herramientas" 70 | content: "Muchas herramientas de monitoreo (como ps, top, free) obtienen su información leyendo archivos dentro de /proc." 71 | validation: 72 | - command: "grep 'model name' /proc/cpuinfo &> /dev/null && echo 'ok'" 73 | expectedOutput: "ok" 74 | errorMessage: "No fue posible leer información de la CPU en /proc/cpuinfo." 75 | -------------------------------------------------------------------------------- /labs/kubernetes_configmaps-secrets/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: kubernetes-configmaps-secrets-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: kubernetes-configmaps-secrets 11 | title: "ConfigMaps e Secrets no Kubernetes" 12 | description: "Aprenda a gerenciar configurações e segredos no Kubernetes usando ConfigMaps e Secrets. Este laboratório guiado explora boas práticas de gerenciamento de configurações e dados sensíveis em aplicações containerizadas." 13 | duration: 35m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Trabalhando com ConfigMaps" 18 | description: "Aprenda a criar e usar ConfigMaps no Kubernetes." 19 | steps: 20 | - description: "Crie um ConfigMap a partir de um arquivo" 21 | command: "echo -e 'DB_HOST=localhost\nDB_PORT=5432' > config.env && kubectl create configmap app-config --from-env-file=config.env" 22 | expectedOutput: "configmap/app-config created" 23 | hint: "Use o comando kubectl create configmap com --from-env-file" 24 | 25 | - description: "Verifique o ConfigMap criado" 26 | command: "kubectl get configmap app-config -o yaml" 27 | expectedOutput: "app-config" 28 | hint: "Use o comando kubectl get configmap com -o yaml" 29 | 30 | - description: "Crie um pod usando o ConfigMap" 31 | command: "kubectl run config-pod --image=nginx --overrides='{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginx\",\"envFrom\":[{\"configMapRef\":{\"name\":\"app-config\"}}]}]}}'" 32 | expectedOutput: "pod/config-pod created" 33 | hint: "Use o comando kubectl run com --overrides para montar o ConfigMap" 34 | 35 | - name: "Gerenciando Secrets" 36 | description: "Aprenda a criar e usar Secrets no Kubernetes." 37 | steps: 38 | - description: "Crie um Secret para credenciais" 39 | command: "kubectl create secret generic db-credentials --from-literal=username=admin --from-literal=password=secret123" 40 | expectedOutput: "secret/db-credentials created" 41 | hint: "Use o comando kubectl create secret generic" 42 | 43 | - description: "Verifique o Secret criado" 44 | command: "kubectl get secret db-credentials -o yaml" 45 | expectedOutput: "db-credentials" 46 | hint: "Use o comando kubectl get secret com -o yaml" 47 | 48 | - description: "Crie um pod usando o Secret" 49 | command: "kubectl run secret-pod --image=nginx --overrides='{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginx\",\"env\":[{\"name\":\"DB_USER\",\"valueFrom\":{\"secretKeyRef\":{\"name\":\"db-credentials\",\"key\":\"username\"}}},{\"name\":\"DB_PASS\",\"valueFrom\":{\"secretKeyRef\":{\"name\":\"db-credentials\",\"key\":\"password\"}}}]}}'" 50 | expectedOutput: "pod/secret-pod created" 51 | hint: "Use o comando kubectl run com --overrides para montar o Secret" 52 | 53 | - name: "Montando ConfigMaps e Secrets como Volumes" 54 | description: "Implemente ConfigMaps e Secrets como volumes em pods." 55 | steps: 56 | - description: "Crie um ConfigMap para configuração" 57 | command: "echo -e 'server {\n listen 80;\n server_name localhost;\n}' > nginx.conf && kubectl create configmap nginx-config --from-file=nginx.conf" 58 | expectedOutput: "configmap/nginx-config created" 59 | hint: "Use o comando kubectl create configmap com --from-file" 60 | 61 | - description: "Crie um pod montando o ConfigMap como volume" 62 | command: "kubectl run nginx-config-pod --image=nginx --overrides='{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginx\",\"volumeMounts\":[{\"name\":\"config-volume\",\"mountPath\":\"/etc/nginx/conf.d\"}],\"volumes\":[{\"name\":\"config-volume\",\"configMap\":{\"name\":\"nginx-config\"}}]}]}}'" 63 | expectedOutput: "pod/nginx-config-pod created" 64 | hint: "Use o comando kubectl run com --overrides para montar o ConfigMap como volume" 65 | 66 | - description: "Verifique a montagem do volume" 67 | command: "kubectl exec nginx-config-pod -- ls -l /etc/nginx/conf.d" 68 | expectedOutput: "nginx.conf" 69 | hint: "Use o comando kubectl exec para verificar o conteúdo do diretório" 70 | -------------------------------------------------------------------------------- /internal/helpers/helpers.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os/exec" 7 | "runtime" 8 | "strings" 9 | "time" 10 | 11 | "github.com/schollz/progressbar/v3" 12 | ) 13 | 14 | type ProgressBarConfig struct { 15 | Total int 16 | Description string 17 | Width int 18 | ShowBytes bool 19 | SetPredictTime bool 20 | Throttle time.Duration 21 | RenderBlankState bool 22 | SpinnerType int 23 | } 24 | 25 | // portInUse verifica se uma porta está em uso 26 | func PortInUse(port int) bool { 27 | checkCmd := exec.Command("lsof", "-i", fmt.Sprintf(":%d", port)) 28 | return checkCmd.Run() == nil 29 | } 30 | 31 | // openBrowser abre o navegador com a URL especificada 32 | func OpenBrowser(url string) error { 33 | var cmd *exec.Cmd 34 | 35 | switch runtime.GOOS { 36 | case "linux": 37 | cmd = exec.Command("xdg-open", url) 38 | case "darwin": 39 | cmd = exec.Command("open", url) 40 | case "windows": 41 | cmd = exec.Command("cmd", "/c", "start", url) 42 | default: 43 | return fmt.Errorf("não foi possível abrir o navegador (sistema operacional não suportado)") 44 | } 45 | 46 | return cmd.Start() 47 | } 48 | 49 | // checkPortForwardNeeded verifica se o port-forward para o backend precisa ser reconfigurado 50 | func CheckPortForwardNeeded() bool { 51 | backendNeeded := false 52 | frontendNeeded := false 53 | 54 | // Verificar se a porta 8080 (backend) está em uso 55 | backendPortCmd := exec.Command("lsof", "-i", ":8080") 56 | if backendPortCmd.Run() != nil { 57 | // Porta 8080 não está em uso, precisamos de port-forward 58 | backendNeeded = true 59 | } else { 60 | // Porta está em uso, mas precisamos verificar se é o kubectl port-forward e se está funcional 61 | // Verificar se o processo é kubectl port-forward 62 | backendProcessCmd := exec.Command("sh", "-c", "ps -eo pid,cmd | grep 'kubectl port-forward' | grep '8080' | grep -v grep") 63 | if backendProcessCmd.Run() != nil { 64 | // Não encontrou processo de port-forward ativo ou válido 65 | backendNeeded = true 66 | } else { 67 | // Verificar se a conexão com o backend está funcionando 68 | backendHealthCmd := exec.Command("curl", "-s", "--head", "--max-time", "2", "http://localhost:8080/api/v1/health") 69 | backendNeeded = backendHealthCmd.Run() != nil // Retorna true (precisa de port-forward) se o comando falhar 70 | } 71 | } 72 | 73 | // Verificar se a porta 8000 (frontend) está em uso 74 | frontendPortCmd := exec.Command("lsof", "-i", ":8000") 75 | if frontendPortCmd.Run() != nil { 76 | // Porta 8000 não está em uso, precisamos de port-forward 77 | frontendNeeded = true 78 | } else { 79 | // Porta está em uso, mas precisamos verificar se é o kubectl port-forward e se está funcional 80 | // Verificar se o processo é kubectl port-forward 81 | frontendProcessCmd := exec.Command("sh", "-c", "ps -eo pid,cmd | grep 'kubectl port-forward' | grep '8000' | grep -v grep") 82 | if frontendProcessCmd.Run() != nil { 83 | // Não encontrou processo de port-forward ativo ou válido 84 | frontendNeeded = true 85 | } else { 86 | // Verificar se a conexão com o frontend está funcionando 87 | frontendCheckCmd := exec.Command("curl", "-s", "--max-time", "2", "-o", "/dev/null", "-w", "%{http_code}", "http://localhost:8000") 88 | var out bytes.Buffer 89 | frontendCheckCmd.Stdout = &out 90 | if frontendCheckCmd.Run() != nil { 91 | frontendNeeded = true 92 | } else { 93 | statusCode := strings.TrimSpace(out.String()) 94 | frontendNeeded = (statusCode != "200" && statusCode != "301" && statusCode != "302") 95 | } 96 | } 97 | } 98 | 99 | // Se qualquer um dos serviços precisar de port-forward, retorne true 100 | return backendNeeded || frontendNeeded 101 | } 102 | 103 | func CreateProgressBar(config ProgressBarConfig) *progressbar.ProgressBar { 104 | return progressbar.NewOptions( 105 | config.Total, 106 | progressbar.OptionSetDescription(config.Description), 107 | progressbar.OptionSetWidth(config.Width), 108 | progressbar.OptionShowBytes(config.ShowBytes), 109 | progressbar.OptionSetPredictTime(config.SetPredictTime), 110 | progressbar.OptionThrottle(config.Throttle*time.Millisecond), 111 | progressbar.OptionShowCount(), 112 | progressbar.OptionSpinnerType(config.SpinnerType), 113 | progressbar.OptionSetRenderBlankState(config.RenderBlankState), 114 | progressbar.OptionFullWidth(), 115 | ) 116 | } 117 | -------------------------------------------------------------------------------- /internal/templates/manifests_es/lab_10_kubernetes_configmaps-secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: kubernetes-configmaps-secrets-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: kubernetes-configmaps-secrets-es 11 | title: "ConfigMaps e Secrets no Kubernetes" 12 | description: "Aprenda a gerenciar configurações e segredos no Kubernetes usando ConfigMaps e Secrets. Este laboratório guiado explora boas práticas de gerenciamento de configurações e dados sensíveis em aplicações containerizadas." 13 | duration: 35m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Trabalhando com ConfigMaps" 18 | description: "Aprenda a criar e usar ConfigMaps no Kubernetes." 19 | steps: 20 | - description: "Crie um ConfigMap a partir de um arquivo" 21 | command: "echo -e 'DB_HOST=localhost\nDB_PORT=5432' > config.env && kubectl create configmap app-config --from-env-file=config.env" 22 | expectedOutput: "configmap/app-config created" 23 | hint: "Use o comando kubectl create configmap com --from-env-file" 24 | 25 | - description: "Verifique o ConfigMap criado" 26 | command: "kubectl get configmap app-config -o yaml" 27 | expectedOutput: "app-config" 28 | hint: "Use o comando kubectl get configmap com -o yaml" 29 | 30 | - description: "Crie um pod usando o ConfigMap" 31 | command: "kubectl run config-pod --image=nginx --overrides='{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginx\",\"envFrom\":[{\"configMapRef\":{\"name\":\"app-config\"}}]}]}}'" 32 | expectedOutput: "pod/config-pod created" 33 | hint: "Use o comando kubectl run com --overrides para montar o ConfigMap" 34 | 35 | - name: "Gerenciando Secrets" 36 | description: "Aprenda a criar e usar Secrets no Kubernetes." 37 | steps: 38 | - description: "Crie um Secret para credenciais" 39 | command: "kubectl create secret generic db-credentials --from-literal=username=admin --from-literal=password=secret123" 40 | expectedOutput: "secret/db-credentials created" 41 | hint: "Use o comando kubectl create secret generic" 42 | 43 | - description: "Verifique o Secret criado" 44 | command: "kubectl get secret db-credentials -o yaml" 45 | expectedOutput: "db-credentials" 46 | hint: "Use o comando kubectl get secret com -o yaml" 47 | 48 | - description: "Crie um pod usando o Secret" 49 | command: "kubectl run secret-pod --image=nginx --overrides='{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginx\",\"env\":[{\"name\":\"DB_USER\",\"valueFrom\":{\"secretKeyRef\":{\"name\":\"db-credentials\",\"key\":\"username\"}}},{\"name\":\"DB_PASS\",\"valueFrom\":{\"secretKeyRef\":{\"name\":\"db-credentials\",\"key\":\"password\"}}}]}}'" 50 | expectedOutput: "pod/secret-pod created" 51 | hint: "Use o comando kubectl run com --overrides para montar o Secret" 52 | 53 | - name: "Montando ConfigMaps e Secrets como Volumes" 54 | description: "Implemente ConfigMaps e Secrets como volumes em pods." 55 | steps: 56 | - description: "Crie um ConfigMap para configuração" 57 | command: "echo -e 'server {\n listen 80;\n server_name localhost;\n}' > nginx.conf && kubectl create configmap nginx-config --from-file=nginx.conf" 58 | expectedOutput: "configmap/nginx-config created" 59 | hint: "Use o comando kubectl create configmap com --from-file" 60 | 61 | - description: "Crie um pod montando o ConfigMap como volume" 62 | command: "kubectl run nginx-config-pod --image=nginx --overrides='{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginx\",\"volumeMounts\":[{\"name\":\"config-volume\",\"mountPath\":\"/etc/nginx/conf.d\"}],\"volumes\":[{\"name\":\"config-volume\",\"configMap\":{\"name\":\"nginx-config\"}}]}]}}'" 63 | expectedOutput: "pod/nginx-config-pod created" 64 | hint: "Use o comando kubectl run com --overrides para montar o ConfigMap como volume" 65 | 66 | - description: "Verifique a montagem do volume" 67 | command: "kubectl exec nginx-config-pod -- ls -l /etc/nginx/conf.d" 68 | expectedOutput: "nginx.conf" 69 | hint: "Use o comando kubectl exec para verificar o conteúdo do diretório" 70 | -------------------------------------------------------------------------------- /labs/kubernetes_configmaps-secrets/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: kubernetes-configmaps-secrets-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: kubernetes-configmaps-secrets-es 11 | title: "ConfigMaps y Secrets en Kubernetes" 12 | description: "Aprende a administrar configuraciones y secretos en Kubernetes usando ConfigMaps y Secrets. Este laboratorio guiado explora buenas prácticas de administración de configuraciones y datos sensibles en aplicaciones contenerizadas." 13 | duration: 35m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Trabajando con ConfigMaps" 18 | description: "Aprende a crear y usar ConfigMaps en Kubernetes." 19 | steps: 20 | - description: "Crea un ConfigMap a partir de un archivo" 21 | command: "echo -e 'DB_HOST=localhost\nDB_PORT=5432' > config.env && kubectl create configmap app-config --from-env-file=config.env" 22 | expectedOutput: "configmap/app-config created" 23 | hint: "Usa el comando kubectl create configmap con --from-env-file" 24 | 25 | - description: "Verifica el ConfigMap creado" 26 | command: "kubectl get configmap app-config -o yaml" 27 | expectedOutput: "app-config" 28 | hint: "Usa el comando kubectl get configmap con -o yaml" 29 | 30 | - description: "Crea un pod usando el ConfigMap" 31 | command: "kubectl run config-pod --image=nginx --overrides='{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginx\",\"envFrom\":[{\"configMapRef\":{\"name\":\"app-config\"}}]}]}}'" 32 | expectedOutput: "pod/config-pod created" 33 | hint: "Usa el comando kubectl run con --overrides para montar el ConfigMap" 34 | 35 | - name: "Gestionando Secrets" 36 | description: "Aprende a crear y usar Secrets en Kubernetes." 37 | steps: 38 | - description: "Crea un Secret para credenciales" 39 | command: "kubectl create secret generic db-credentials --from-literal=username=admin --from-literal=password=secret123" 40 | expectedOutput: "secret/db-credentials created" 41 | hint: "Usa el comando kubectl create secret generic" 42 | 43 | - description: "Verifica el Secret creado" 44 | command: "kubectl get secret db-credentials -o yaml" 45 | expectedOutput: "db-credentials" 46 | hint: "Usa el comando kubectl get secret con -o yaml" 47 | 48 | - description: "Crea un pod usando el Secret" 49 | command: "kubectl run secret-pod --image=nginx --overrides='{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginx\",\"env\":[{\"name\":\"DB_USER\",\"valueFrom\":{\"secretKeyRef\":{\"name\":\"db-credentials\",\"key\":\"username\"}}},{\"name\":\"DB_PASS\",\"valueFrom\":{\"secretKeyRef\":{\"name\":\"db-credentials\",\"key\":\"password\"}}}]}}'" 50 | expectedOutput: "pod/secret-pod created" 51 | hint: "Usa el comando kubectl run con --overrides para montar el Secret" 52 | 53 | - name: "Montando ConfigMaps y Secrets como Volúmenes" 54 | description: "Implementa ConfigMaps y Secrets como volúmenes en pods." 55 | steps: 56 | - description: "Crea un ConfigMap para configuración" 57 | command: "echo -e 'server {\n listen 80;\n server_name localhost;\n}' > nginx.conf && kubectl create configmap nginx-config --from-file=nginx.conf" 58 | expectedOutput: "configmap/nginx-config created" 59 | hint: "Usa el comando kubectl create configmap con --from-file" 60 | 61 | - description: "Crea un pod montando el ConfigMap como volumen" 62 | command: "kubectl run nginx-config-pod --image=nginx --overrides='{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginx\",\"volumeMounts\":[{\"name\":\"config-volume\",\"mountPath\":\"/etc/nginx/conf.d\"}],\"volumes\":[{\"name\":\"config-volume\",\"configMap\":{\"name\":\"nginx-config\"}}]}]}}'" 63 | expectedOutput: "pod/nginx-config-pod created" 64 | hint: "Usa el comando kubectl run con --overrides para montar el ConfigMap como volumen" 65 | 66 | - description: "Verifica el montaje del volumen" 67 | command: "kubectl exec nginx-config-pod -- ls -l /etc/nginx/conf.d" 68 | expectedOutput: "nginx.conf" 69 | hint: "Usa el comando kubectl exec para verificar el contenido del directorio" 70 | -------------------------------------------------------------------------------- /cmd/repo.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "text/tabwriter" 7 | 8 | "github.com/badtuxx/girus-cli/internal/common" 9 | "github.com/badtuxx/girus-cli/internal/repo" 10 | "github.com/spf13/cobra" 11 | ) 12 | 13 | var repoCmd = &cobra.Command{ 14 | Use: "repo", 15 | Short: common.T("Gerencia repositórios de laboratórios", "Gestiona repositorios de laboratorios"), 16 | Long: common.T(`Gerencia repositórios de laboratórios, permitindo adicionar, remover, listar e atualizar repositórios.`, `Gestiona repositorios de laboratorios, permitiendo agregar, eliminar, listar y actualizar repositorios.`), 17 | } 18 | 19 | var repoAddCmd = &cobra.Command{ 20 | Use: "add [nome] [url]", 21 | Short: common.T("Adiciona um novo repositório", "Agrega un nuevo repositorio"), 22 | Long: common.T(`Adiciona um novo repositório de laboratórios com o nome e URL especificados.`, `Agrega un nuevo repositorio de laboratorios con el nombre y URL especificados.`), 23 | Args: cobra.ExactArgs(2), 24 | RunE: func(cmd *cobra.Command, args []string) error { 25 | name := args[0] 26 | url := args[1] 27 | description, _ := cmd.Flags().GetString("description") 28 | 29 | rm, err := repo.NewRepositoryManager() 30 | if err != nil { 31 | return err 32 | } 33 | 34 | if err := rm.AddRepository(name, url, description); err != nil { 35 | return err 36 | } 37 | 38 | fmt.Printf(common.T("Repositório '%s' adicionado com sucesso.\n", "Repositorio '%s' agregado con éxito.\n"), name) 39 | return nil 40 | }, 41 | } 42 | 43 | var repoRemoveCmd = &cobra.Command{ 44 | Use: "remove [nome]", 45 | Short: common.T("Remove um repositório", "Elimina un repositorio"), 46 | Long: common.T(`Remove um repositório de laboratórios pelo nome.`, `Elimina un repositorio de laboratorios por su nombre.`), 47 | Args: cobra.ExactArgs(1), 48 | RunE: func(cmd *cobra.Command, args []string) error { 49 | name := args[0] 50 | 51 | rm, err := repo.NewRepositoryManager() 52 | if err != nil { 53 | return err 54 | } 55 | 56 | if err := rm.RemoveRepository(name); err != nil { 57 | return err 58 | } 59 | 60 | fmt.Printf(common.T("Repositório '%s' removido com sucesso.\n", "Repositorio '%s' eliminado con éxito.\n"), name) 61 | return nil 62 | }, 63 | } 64 | 65 | var repoListCmd = &cobra.Command{ 66 | Use: "list", 67 | Short: common.T("Lista todos os repositórios", "Lista todos los repositorios"), 68 | Long: common.T(`Lista todos os repositórios de laboratórios configurados.`, `Lista todos los repositorios de laboratorios configurados.`), 69 | RunE: func(cmd *cobra.Command, args []string) error { 70 | rm, err := repo.NewRepositoryManager() 71 | if err != nil { 72 | return err 73 | } 74 | 75 | repos := rm.ListRepositories() 76 | if len(repos) == 0 { 77 | fmt.Println(common.T("Nenhum repositório configurado.", "Ningún repositorio configurado.")) 78 | return nil 79 | } 80 | 81 | w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) 82 | fmt.Fprintln(w, common.T("NOME\tURL\tDESCRIÇÃO", "NOMBRE\tURL\tDESCRIPCIÓN")) 83 | for _, r := range repos { 84 | fmt.Fprintf(w, "%s\t%s\t%s\n", r.Name, r.URL, r.Description) 85 | } 86 | w.Flush() 87 | 88 | return nil 89 | }, 90 | } 91 | 92 | var repoUpdateCmd = &cobra.Command{ 93 | Use: "update [nome] [url]", 94 | Short: common.T("Atualiza um repositório", "Actualiza un repositorio"), 95 | Long: common.T(`Atualiza um repositório de laboratórios existente com novos dados.`, `Actualiza un repositorio de laboratorios existente con nuevos datos.`), 96 | Args: cobra.ExactArgs(2), 97 | RunE: func(cmd *cobra.Command, args []string) error { 98 | name := args[0] 99 | url := args[1] 100 | description, _ := cmd.Flags().GetString("description") 101 | 102 | rm, err := repo.NewRepositoryManager() 103 | if err != nil { 104 | return err 105 | } 106 | 107 | if err := rm.UpdateRepository(name, url, description); err != nil { 108 | return err 109 | } 110 | 111 | fmt.Printf(common.T("Repositório '%s' atualizado com sucesso.\n", "Repositorio '%s' actualizado con éxito.\n"), name) 112 | return nil 113 | }, 114 | } 115 | 116 | func init() { 117 | repoCmd.AddCommand(repoAddCmd, repoRemoveCmd, repoListCmd, repoUpdateCmd) 118 | 119 | // Flags para os comandos 120 | repoAddCmd.Flags().String("description", "", common.T("Descrição do repositório", "Descripción del repositorio")) 121 | repoUpdateCmd.Flags().String("description", "", common.T("Nova descrição do repositório", "Nueva descripción del repositorio")) 122 | } 123 | -------------------------------------------------------------------------------- /cmd/start.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "strings" 7 | 8 | "github.com/badtuxx/girus-cli/internal/common" 9 | "github.com/badtuxx/girus-cli/internal/k8s" 10 | "github.com/fatih/color" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var startCmd = &cobra.Command{ 15 | Use: "start", 16 | Short: common.T("Inicia o ambiente do GIRUS", "Inicia el entorno de GIRUS"), 17 | Long: common.T("Inicia o ambiente do GIRUS CLI, reiniciando o deployment do backend e do frontend.", "Inicia el entorno del GIRUS CLI, reiniciando los deployments del backend y del frontend."), 18 | Run: func(cmd *cobra.Command, args []string) { 19 | // Define os nomes dos deployments 20 | frontendDeploymentName := "girus-frontend" 21 | backendDeploymentName := "girus-backend" 22 | // Criando um client para interagir com o cluster do Kubernetes 23 | client, err := k8s.NewKubernetesClient() 24 | if err != nil { 25 | fmt.Printf("%s %s: %v\n", color.New().SprintFunc()(common.T("ERRO", "ERROR")), common.T("Erro ao criar cliente Kubernetes", "Error al crear cliente de Kubernetes"), err) 26 | return 27 | } 28 | 29 | ctx := context.Background() 30 | 31 | pods, err := client.ListRunningPods(ctx, "girus") 32 | if err != nil { 33 | fmt.Printf("%s %s: %v\n", color.New().SprintFunc()(common.T("ERRO", "ERROR")), common.T("Erro ao tentar pegar a lista de pods em execução no namespace do GIRUS", "Error al obtener la lista de pods en ejecución en el namespace de GIRUS"), err) 34 | fmt.Println(common.T("Leia o erro, se você não conseguir resolvê-lo, recrie o cluster.", "Lea el error; si no puede resolverlo, recree el cluster.")) 35 | return 36 | } 37 | // Pega todos os pods do namespace do girus 38 | var frontendPod string 39 | var backendPod string 40 | for _, pod := range pods { 41 | if strings.Contains(pod, "frontend") { 42 | frontendPod = pod 43 | } else if strings.Contains(pod, "backend") { 44 | backendPod = pod 45 | } 46 | } 47 | // Checa se o frontend já está executando antes de tentar iniciar o deployment 48 | isFrontendRunning, err := client.IsPodRunning(ctx, "girus", frontendPod) 49 | if isFrontendRunning { 50 | fmt.Println(common.T("O pod de frontend já está em execução.", "El pod de frontend ya está en ejecución.")) 51 | fmt.Println(common.T("Tente abrir o browser e navegar até http://localhost:8000.", "Intente abrir el navegador y acceder a http://localhost:8000.")) 52 | } 53 | if err != nil { 54 | fmt.Println(common.T("Nenhum pod do frontend encontrado no namespace do GIRUS...", "Ningún pod de frontend encontrado en el namespace de GIRUS...")) 55 | } 56 | 57 | // Checa se o backend já está executando antes de tentar iniciar o deployment 58 | isBackendRunning, err := client.IsPodRunning(ctx, "girus", backendPod) 59 | if isBackendRunning { 60 | fmt.Println(common.T("O pod de backend já está em execução.", "El pod de backend ya está en ejecución.")) 61 | fmt.Println(common.T("Tente abrir o browser e navegar até http://localhost:8000.", "Intente abrir el navegador y acceder a http://localhost:8000.")) 62 | fmt.Printf("%s %s\n", yellow(common.T("AVISO", "AVISO")), common.T("Cancelando.", "Cancelando.")) 63 | return 64 | } 65 | if err != nil { 66 | fmt.Println(common.T("Nenhum pod do backend encontrado no namespace do GIRUS...", "Ningún pod de backend encontrado en el namespace de GIRUS...")) 67 | } 68 | err = startDeployment(client, ctx, backendDeploymentName) 69 | if err != nil { 70 | fmt.Printf("%s %s: %v\n", color.New().SprintFunc()(common.T("ERRO", "ERROR")), common.T("Erro ao tentar iniciar o backend", "Error al intentar iniciar el backend"), err) 71 | return 72 | } 73 | err = startDeployment(client, ctx, frontendDeploymentName) 74 | if err != nil { 75 | fmt.Printf("%s %s: %v\n", color.New().SprintFunc()(common.T("ERRO", "ERROR")), common.T("Erro ao tentar iniciar o frontend", "Error al intentar iniciar el frontend"), err) 76 | return 77 | } 78 | }, 79 | } 80 | 81 | func startDeployment(client *k8s.KubernetesClient, ctx context.Context, deploymentName string) error { 82 | magenta := color.New(color.FgMagenta).SprintFunc() 83 | err := client.CreateDeployment(ctx, "girus", deploymentName) 84 | if err != nil { 85 | fmt.Printf("%s %s %s: %v\n", color.New().SprintFunc()(common.T("ERRO", "ERROR")), common.T("Erro ao tentar iniciar o deploy", "Error al intentar iniciar el deploy"), magenta(deploymentName), err) 86 | fmt.Println(common.T("Leia o erro, se você não conseguir resolvê-lo, recrie o cluster.", "Lea el error; si no puede resolverlo, recree el cluster.")) 87 | return err 88 | } 89 | 90 | return nil 91 | } 92 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | permissions: {} 12 | 13 | jobs: 14 | build: 15 | name: Build 16 | runs-on: ubuntu-latest 17 | 18 | permissions: 19 | contents: read 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 24 | with: 25 | persist-credentials: false 26 | fetch-depth: 0 # Fetch all history for tags and branches 27 | 28 | - name: Set up Go 29 | uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 30 | with: 31 | go-version-file: './go.mod' 32 | check-latest: true 33 | 34 | - name: Determine version 35 | id: version 36 | run: | 37 | # Check if this is a tag build 38 | if [[ $GITHUB_REF == refs/tags/v* ]]; then 39 | VERSION=${GITHUB_REF#refs/tags/v} 40 | else 41 | # If not a tag, use the latest tag + commit hash 42 | LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "0.0.0") 43 | LATEST_TAG=${LATEST_TAG#v} # Remove 'v' prefix if present 44 | COMMIT_SHORT=$(git rev-parse --short HEAD) 45 | VERSION="${LATEST_TAG}-dev.${COMMIT_SHORT}" 46 | fi 47 | 48 | echo "Determined version: $VERSION" 49 | echo "VERSION=$VERSION" >> $GITHUB_ENV 50 | echo "version=$VERSION" >> $GITHUB_OUTPUT 51 | 52 | - name: Set environment variables 53 | run: | 54 | # essa variavel de ambiente sera usada para injetar no ldflags do goreleaser 55 | echo "GOVERSION=$(go version | cut -d' ' -f3)" >> $GITHUB_ENV 56 | 57 | - uses: sigstore/cosign-installer@v3.8.1 # v3.8.1 58 | 59 | - uses: anchore/sbom-action/download-syft@v0.20.10 # v0.20.10 60 | 61 | - uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0 62 | with: 63 | version: latest 64 | args: release --clean --snapshot --skip=sign 65 | env: 66 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 67 | VERSION: ${{ env.VERSION }} 68 | 69 | - name: Check Binary 70 | run: | 71 | ./dist/girus-cli-linux-amd64 help 72 | ./dist/girus-cli-linux-amd64 version 73 | 74 | 75 | build-docker: 76 | runs-on: ubuntu-latest 77 | needs: build 78 | services: 79 | registry: 80 | image: registry:2 81 | ports: 82 | - 5000:5000 83 | steps: 84 | - name: Checkout repository 85 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 86 | with: 87 | persist-credentials: false 88 | fetch-depth: 0 # Fetch all history for tags and branches 89 | 90 | - name: Determine version 91 | id: version 92 | run: | 93 | # Check if this is a tag build 94 | if [[ $GITHUB_REF == refs/tags/v* ]]; then 95 | VERSION=${GITHUB_REF#refs/tags/v} 96 | else 97 | # If not a tag, use the latest tag + commit hash 98 | LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "0.0.0") 99 | LATEST_TAG=${LATEST_TAG#v} # Remove 'v' prefix if present 100 | COMMIT_SHORT=$(git rev-parse --short HEAD) 101 | VERSION="${LATEST_TAG}-dev.${COMMIT_SHORT}" 102 | fi 103 | 104 | echo "Determined version: $VERSION" 105 | echo "VERSION=$VERSION" >> $GITHUB_ENV 106 | echo "version=$VERSION" >> $GITHUB_OUTPUT 107 | 108 | - name: Set up QEMU 109 | uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 110 | 111 | - name: Set up Docker Buildx 112 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 113 | with: 114 | driver-opts: network=host 115 | 116 | - name: Build and push to local registry 117 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 118 | with: 119 | context: . 120 | file: ./Dockerfile 121 | push: true 122 | tags: localhost:5000/girus/girus-cli:latest 123 | build-args: | 124 | VERSION=${{ env.VERSION }} 125 | 126 | - name: Inspect 127 | run: | 128 | docker run localhost:5000/girus/girus-cli:latest version 129 | -------------------------------------------------------------------------------- /internal/repo/README.md: -------------------------------------------------------------------------------- 1 | # Repositórios de Laboratórios GIRUS 2 | 3 | Este documento explica como criar e gerenciar repositórios de laboratórios para a plataforma GIRUS. 4 | 5 | ## Estrutura de um Repositório 6 | 7 | Um repositório de laboratórios GIRUS deve seguir a seguinte estrutura: 8 | 9 | ``` 10 | repositorio/ 11 | ├── index.yaml # Índice do repositório 12 | └── labs/ # Diretório contendo os laboratórios 13 | ├── lab1/ 14 | │ ├── lab.yaml # Definição do laboratório 15 | │ └── assets/ # Recursos do laboratório (opcional) 16 | └── lab2/ 17 | ├── lab.yaml 18 | └── assets/ 19 | ``` 20 | 21 | ### Arquivo index.yaml 22 | 23 | O arquivo `index.yaml` é o ponto de entrada do repositório e deve seguir este formato: 24 | 25 | ```yaml 26 | apiVersion: v1 27 | generated: "2024-03-20T10:00:00Z" 28 | entries: 29 | lab-name: 30 | - name: lab-name 31 | version: "1.0.0" 32 | description: "Descrição do laboratório" 33 | keywords: 34 | - keyword1 35 | - keyword2 36 | maintainers: 37 | - "Nome " 38 | url: "https://github.com/seu-repo/raw/main/labs/lab-name/lab.yaml" 39 | created: "2024-03-20T10:00:00Z" 40 | digest: "sha256:hash-do-arquivo" 41 | ``` 42 | 43 | ### Arquivo lab.yaml 44 | 45 | Cada laboratório deve ter um arquivo `lab.yaml` que define sua estrutura e conteúdo: 46 | 47 | ```yaml 48 | apiVersion: girus.linuxtips.io/v1 49 | kind: Lab 50 | metadata: 51 | name: lab-name 52 | version: "1.0.0" 53 | description: "Descrição do laboratório" 54 | author: "Nome do Autor" 55 | created: "2024-03-20T10:00:00Z" 56 | spec: 57 | environment: 58 | image: ubuntu:22.04 59 | resources: 60 | cpu: "1" 61 | memory: "1Gi" 62 | volumes: 63 | - name: workspace 64 | mountPath: /workspace 65 | size: "1Gi" 66 | 67 | tasks: 68 | - name: "Nome da Tarefa" 69 | description: "Descrição da tarefa" 70 | steps: 71 | - description: "Descrição do passo" 72 | command: "comando" 73 | expectedOutput: "saída esperada" 74 | hint: "Dica para o usuário" 75 | 76 | validation: 77 | - name: "Nome da Validação" 78 | description: "Descrição da validação" 79 | checks: 80 | - command: "comando" 81 | expectedOutput: "saída esperada" 82 | errorMessage: "Mensagem de erro" 83 | ``` 84 | 85 | ## Criando um Repositório 86 | 87 | 1. Crie um novo repositório Git: 88 | ```bash 89 | mkdir girus-labs 90 | cd girus-labs 91 | git init 92 | ``` 93 | 94 | 2. Crie a estrutura básica: 95 | ```bash 96 | mkdir -p labs 97 | touch index.yaml 98 | ``` 99 | 100 | 3. Adicione seu primeiro laboratório: 101 | ```bash 102 | mkdir -p labs/meu-lab 103 | touch labs/meu-lab/lab.yaml 104 | ``` 105 | 106 | 4. Edite o arquivo `index.yaml` com as informações do seu repositório. 107 | 108 | 5. Edite o arquivo `lab.yaml` com a definição do seu laboratório. 109 | 110 | 6. Faça commit das alterações: 111 | ```bash 112 | git add . 113 | git commit -m "Primeiro laboratório" 114 | ``` 115 | 116 | 7. Publique o repositório em um serviço como GitHub, GitLab ou Bitbucket. 117 | 118 | ## Hospedando o Repositório 119 | 120 | O repositório pode ser hospedado em qualquer serviço que permita acesso aos arquivos via HTTP/HTTPS. Algumas opções: 121 | 122 | 1. **GitHub**: Use o recurso "raw" para acessar os arquivos: 123 | ``` 124 | https://github.com/seu-usuario/seu-repo/raw/main/labs/lab-name/lab.yaml 125 | ``` 126 | 127 | 2. **GitLab**: Use o recurso "raw" para acessar os arquivos: 128 | ``` 129 | https://gitlab.com/seu-usuario/seu-repo/raw/main/labs/lab-name/lab.yaml 130 | ``` 131 | 132 | 3. **Servidor Web**: Hospede os arquivos em um servidor web próprio. 133 | 134 | ## Adicionando o Repositório ao GIRUS 135 | 136 | Para adicionar seu repositório ao GIRUS, use o comando: 137 | 138 | ```bash 139 | girus repo add meu-repo https://github.com/seu-usuario/seu-repo/raw/main 140 | ``` 141 | 142 | ## Boas Práticas 143 | 144 | 1. **Versionamento**: Mantenha um histórico de versões dos laboratórios no `index.yaml`. 145 | 146 | 2. **Documentação**: Inclua documentação detalhada em cada laboratório. 147 | 148 | 3. **Validação**: Implemente validações robustas para garantir que os usuários completaram as tarefas corretamente. 149 | 150 | 4. **Recursos**: Mantenha os recursos (CPU, memória) em níveis razoáveis. 151 | 152 | 5. **Imagens**: Use imagens Docker oficiais e bem mantidas. 153 | 154 | 6. **Segurança**: Não inclua credenciais ou informações sensíveis nos laboratórios. 155 | 156 | ## Exemplo Completo 157 | 158 | Veja o diretório `example/` neste repositório para um exemplo completo de um repositório de laboratórios. -------------------------------------------------------------------------------- /labs/aws_rds-elasticache/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: aws-rds-elasticache-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: aws-rds-elasticache 11 | title: "RDS e ElastiCache na AWS" 12 | description: "Aprenda a configurar e gerenciar bancos de dados gerenciados com RDS e caches com ElastiCache na AWS. Este laboratório guiado explora conceitos de banco de dados e cache em nuvem." 13 | duration: 45m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Configurando RDS" 18 | description: "Aprenda a criar e configurar instâncias RDS." 19 | steps: 20 | - description: "Crie um grupo de subnets para RDS" 21 | command: "aws rds create-db-subnet-group --db-subnet-group-name lab-subnet-group --db-subnet-group-description 'Subnet group for RDS lab' --subnet-ids $(aws ec2 describe-subnets --filters 'Name=tag:Name,Values=PublicSubnet1' --query 'Subnets[0].SubnetId' --output text)" 22 | expectedOutput: "DBSubnetGroup" 23 | hint: "Use o comando aws rds create-db-subnet-group" 24 | 25 | - description: "Crie um grupo de segurança para RDS" 26 | command: "aws ec2 create-security-group --group-name RDSSecurityGroup --description 'Security group for RDS' --vpc-id $(aws ec2 describe-vpcs --filters 'Name=tag:Name,Values=LabVPC' --query 'Vpcs[0].VpcId' --output text)" 27 | expectedOutput: "GroupId" 28 | hint: "Use o comando aws ec2 create-security-group" 29 | 30 | - description: "Crie uma instância RDS" 31 | command: "aws rds create-db-instance --db-instance-identifier lab-db --db-instance-class db.t3.micro --engine mysql --master-username admin --master-user-password password123 --allocated-storage 20 --db-subnet-group-name lab-subnet-group --vpc-security-group-ids $(aws ec2 describe-security-groups --filters 'Name=group-name,Values=RDSSecurityGroup' --query 'SecurityGroups[0].GroupId' --output text)" 32 | expectedOutput: "DBInstance" 33 | hint: "Use o comando aws rds create-db-instance" 34 | 35 | - name: "Gerenciamento de RDS" 36 | description: "Aprenda a gerenciar e monitorar instâncias RDS." 37 | steps: 38 | - description: "Verifique o status da instância RDS" 39 | command: "aws rds describe-db-instances --db-instance-identifier lab-db --query 'DBInstances[0].DBInstanceStatus' --output text" 40 | expectedOutput: "available" 41 | hint: "Use o comando aws rds describe-db-instances" 42 | 43 | - description: "Crie um snapshot do banco de dados" 44 | command: "aws rds create-db-snapshot --db-snapshot-identifier lab-snapshot --db-instance-identifier lab-db" 45 | expectedOutput: "DBSnapshot" 46 | hint: "Use o comando aws rds create-db-snapshot" 47 | 48 | - description: "Configure backups automáticos" 49 | command: "aws rds modify-db-instance --db-instance-identifier lab-db --backup-retention-period 7 --preferred-backup-window '03:00-04:00'" 50 | expectedOutput: "DBInstance" 51 | hint: "Use o comando aws rds modify-db-instance" 52 | 53 | - name: "Configurando ElastiCache" 54 | description: "Aprenda a criar e configurar clusters ElastiCache." 55 | steps: 56 | - description: "Crie um grupo de subnets para ElastiCache" 57 | command: "aws elasticache create-cache-subnet-group --cache-subnet-group-name lab-cache-subnet --cache-subnet-group-description 'Subnet group for ElastiCache lab' --subnet-ids $(aws ec2 describe-subnets --filters 'Name=tag:Name,Values=PublicSubnet1' --query 'Subnets[0].SubnetId' --output text)" 58 | expectedOutput: "CacheSubnetGroup" 59 | hint: "Use o comando aws elasticache create-cache-subnet-group" 60 | 61 | - description: "Crie um grupo de segurança para ElastiCache" 62 | command: "aws ec2 create-security-group --group-name CacheSecurityGroup --description 'Security group for ElastiCache' --vpc-id $(aws ec2 describe-vpcs --filters 'Name=tag:Name,Values=LabVPC' --query 'Vpcs[0].VpcId' --output text)" 63 | expectedOutput: "GroupId" 64 | hint: "Use o comando aws ec2 create-security-group" 65 | 66 | - description: "Crie um cluster ElastiCache" 67 | command: "aws elasticache create-cache-cluster --cache-cluster-id lab-cache --engine redis --cache-node-type cache.t3.micro --num-cache-nodes 1 --cache-subnet-group-name lab-cache-subnet --security-group-ids $(aws ec2 describe-security-groups --filters 'Name=group-name,Values=CacheSecurityGroup' --query 'SecurityGroups[0].GroupId' --output text)" 68 | expectedOutput: "CacheCluster" 69 | hint: "Use o comando aws elasticache create-cache-cluster" 70 | -------------------------------------------------------------------------------- /labs/terraform_estado-remoto/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: terraform-estado-remoto-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: terraform-estado-remoto 11 | title: "Estado Remoto e Workspaces no Terraform" 12 | description: "Aprenda a configurar e gerenciar estado remoto no Terraform usando backends como S3 e DynamoDB, além de trabalhar com workspaces para diferentes ambientes." 13 | duration: 40m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Configurando Backend S3" 18 | description: "Aprenda a configurar um backend S3 para armazenar o estado do Terraform." 19 | steps: 20 | - description: "Crie um bucket S3 para o estado" 21 | command: "aws s3 mb s3://terraform-state-lab --region us-east-1" 22 | expectedOutput: "make_bucket: terraform-state-lab" 23 | hint: "Use o comando aws s3 mb para criar o bucket" 24 | 25 | - description: "Crie uma tabela DynamoDB para locking" 26 | command: "aws dynamodb create-table --table-name terraform-locks --attribute-definitions AttributeName=LockID,AttributeType=S --key-schema AttributeName=LockID,KeyType=HASH --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 --region us-east-1" 27 | expectedOutput: "TableDescription" 28 | hint: "Use o comando aws dynamodb create-table" 29 | 30 | - description: "Configure o backend no arquivo main.tf" 31 | command: "echo -e 'terraform {\n backend \"s3\" {\n bucket = \"terraform-state-lab\"\n key = \"terraform.tfstate\"\n region = \"us-east-1\"\n dynamodb_table = \"terraform-locks\"\n encrypt = true\n }\n\n required_providers {\n aws = {\n source = \"hashicorp/aws\"\n version = \"~> 4.0\"\n }\n }\n}\n\nprovider \"aws\" {\n region = \"us-east-1\"\n}\n\nresource \"aws_s3_bucket\" \"example\" {\n bucket = \"terraform-example-${terraform.workspace}\"\n\n tags = {\n Name = \"Example Bucket\"\n Environment = terraform.workspace\n }\n}' > main.tf" 32 | expectedOutput: "" 33 | hint: "Crie o arquivo main.tf com a configuração do backend" 34 | 35 | - name: "Trabalhando com Workspaces" 36 | description: "Aprenda a criar e gerenciar workspaces no Terraform." 37 | steps: 38 | - description: "Inicialize o Terraform com o novo backend" 39 | command: "terraform init" 40 | expectedOutput: "Terraform has been successfully initialized" 41 | hint: "Use o comando terraform init" 42 | 43 | - description: "Crie um workspace para desenvolvimento" 44 | command: "terraform workspace new dev" 45 | expectedOutput: "Created and switched to workspace \"dev\"" 46 | hint: "Use o comando terraform workspace new" 47 | 48 | - description: "Aplique a configuração no workspace dev" 49 | command: "terraform apply -auto-approve" 50 | expectedOutput: "Apply complete!" 51 | hint: "Use o comando terraform apply" 52 | 53 | - description: "Crie um workspace para produção" 54 | command: "terraform workspace new prod" 55 | expectedOutput: "Created and switched to workspace \"prod\"" 56 | hint: "Use o comando terraform workspace new" 57 | 58 | - description: "Aplique a configuração no workspace prod" 59 | command: "terraform apply -auto-approve" 60 | expectedOutput: "Apply complete!" 61 | hint: "Use o comando terraform apply" 62 | 63 | - name: "Gerenciamento de Estado" 64 | description: "Aprenda a gerenciar e manipular o estado do Terraform." 65 | steps: 66 | - description: "Liste todos os workspaces" 67 | command: "terraform workspace list" 68 | expectedOutput: "dev\nprod" 69 | hint: "Use o comando terraform workspace list" 70 | 71 | - description: "Verifique o estado atual" 72 | command: "terraform state list" 73 | expectedOutput: "aws_s3_bucket.example" 74 | hint: "Use o comando terraform state list" 75 | 76 | - description: "Visualize detalhes de um recurso" 77 | command: "terraform state show aws_s3_bucket.example" 78 | expectedOutput: "resource \"aws_s3_bucket\" \"example\"" 79 | hint: "Use o comando terraform state show" 80 | 81 | - description: "Mova um recurso entre workspaces" 82 | command: "terraform workspace select dev && terraform state mv aws_s3_bucket.example aws_s3_bucket.dev_example" 83 | expectedOutput: "Move \"aws_s3_bucket.example\" to \"aws_s3_bucket.dev_example\"" 84 | hint: "Use o comando terraform state mv" 85 | -------------------------------------------------------------------------------- /labs/aws_rds-elasticache/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: aws-rds-elasticache-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: aws-rds-elasticache-es 11 | title: "RDS y ElastiCache en AWS" 12 | description: "Aprende a configurar y administrar bases de datos administradas con RDS y caches con ElastiCache en AWS. Este laboratorio guiado explora conceptos de base de datos y cache en la nube." 13 | duration: 45m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Configurando RDS" 18 | description: "Aprende a crear y configurar instancias RDS." 19 | steps: 20 | - description: "Crea un grupo de subnets para RDS" 21 | command: "aws rds create-db-subnet-group --db-subnet-group-name lab-subnet-group --db-subnet-group-description 'Subnet group for RDS lab' --subnet-ids $(aws ec2 describe-subnets --filters 'Name=tag:Name,Values=PublicSubnet1' --query 'Subnets[0].SubnetId' --output text)" 22 | expectedOutput: "DBSubnetGroup" 23 | hint: "Usa el comando aws rds create-db-subnet-group" 24 | 25 | - description: "Crea un grupo de seguridad para RDS" 26 | command: "aws ec2 create-security-group --group-name RDSSecurityGroup --description 'Security group for RDS' --vpc-id $(aws ec2 describe-vpcs --filters 'Name=tag:Name,Values=LabVPC' --query 'Vpcs[0].VpcId' --output text)" 27 | expectedOutput: "GroupId" 28 | hint: "Usa el comando aws ec2 create-security-group" 29 | 30 | - description: "Crea una instancia RDS" 31 | command: "aws rds create-db-instance --db-instance-identifier lab-db --db-instance-class db.t3.micro --engine mysql --master-username admin --master-user-password password123 --allocated-storage 20 --db-subnet-group-name lab-subnet-group --vpc-security-group-ids $(aws ec2 describe-security-groups --filters 'Name=group-name,Values=RDSSecurityGroup' --query 'SecurityGroups[0].GroupId' --output text)" 32 | expectedOutput: "DBInstance" 33 | hint: "Usa el comando aws rds create-db-instance" 34 | 35 | - name: "Administración de RDS" 36 | description: "Aprende a administrar y monitorear instancias RDS." 37 | steps: 38 | - description: "Verifica el estado de la instancia RDS" 39 | command: "aws rds describe-db-instances --db-instance-identifier lab-db --query 'DBInstances[0].DBInstanceStatus' --output text" 40 | expectedOutput: "available" 41 | hint: "Usa el comando aws rds describe-db-instances" 42 | 43 | - description: "Crea un snapshot de la base de datos" 44 | command: "aws rds create-db-snapshot --db-snapshot-identifier lab-snapshot --db-instance-identifier lab-db" 45 | expectedOutput: "DBSnapshot" 46 | hint: "Usa el comando aws rds create-db-snapshot" 47 | 48 | - description: "Configura backups automáticos" 49 | command: "aws rds modify-db-instance --db-instance-identifier lab-db --backup-retention-period 7 --preferred-backup-window '03:00-04:00'" 50 | expectedOutput: "DBInstance" 51 | hint: "Usa el comando aws rds modify-db-instance" 52 | 53 | - name: "Configurando ElastiCache" 54 | description: "Aprende a crear y configurar clusters ElastiCache." 55 | steps: 56 | - description: "Crea un grupo de subnets para ElastiCache" 57 | command: "aws elasticache create-cache-subnet-group --cache-subnet-group-name lab-cache-subnet --cache-subnet-group-description 'Subnet group for ElastiCache lab' --subnet-ids $(aws ec2 describe-subnets --filters 'Name=tag:Name,Values=PublicSubnet1' --query 'Subnets[0].SubnetId' --output text)" 58 | expectedOutput: "CacheSubnetGroup" 59 | hint: "Usa el comando aws elasticache create-cache-subnet-group" 60 | 61 | - description: "Crea un grupo de seguridad para ElastiCache" 62 | command: "aws ec2 create-security-group --group-name CacheSecurityGroup --description 'Security group for ElastiCache' --vpc-id $(aws ec2 describe-vpcs --filters 'Name=tag:Name,Values=LabVPC' --query 'Vpcs[0].VpcId' --output text)" 63 | expectedOutput: "GroupId" 64 | hint: "Usa el comando aws ec2 create-security-group" 65 | 66 | - description: "Crea un cluster ElastiCache" 67 | command: "aws elasticache create-cache-cluster --cache-cluster-id lab-cache --engine redis --cache-node-type cache.t3.micro --num-cache-nodes 1 --cache-subnet-group-name lab-cache-subnet --security-group-ids $(aws ec2 describe-security-groups --filters 'Name=group-name,Values=CacheSecurityGroup' --query 'SecurityGroups[0].GroupId' --output text)" 68 | expectedOutput: "CacheCluster" 69 | hint: "Usa el comando aws elasticache create-cache-cluster" 70 | -------------------------------------------------------------------------------- /labs/terraform_estado-remoto/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: terraform-estado-remoto-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: terraform-estado-remoto-es 11 | title: "Estado Remoto y Workspaces en Terraform" 12 | description: "Aprende a configurar y administrar estado remoto en Terraform usando backends como S3 y DynamoDB, además de trabajar con workspaces para diferentes ambientes." 13 | duration: 40m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Configurando Backend S3" 18 | description: "Aprende a configurar un backend S3 para almacenar el estado de Terraform." 19 | steps: 20 | - description: "Crea un bucket S3 para el estado" 21 | command: "aws s3 mb s3://terraform-state-lab --region us-east-1" 22 | expectedOutput: "make_bucket: terraform-state-lab" 23 | hint: "Usa el comando aws s3 mb para crear el bucket" 24 | 25 | - description: "Crea una tabla DynamoDB para locking" 26 | command: "aws dynamodb create-table --table-name terraform-locks --attribute-definitions AttributeName=LockID,AttributeType=S --key-schema AttributeName=LockID,KeyType=HASH --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 --region us-east-1" 27 | expectedOutput: "TableDescription" 28 | hint: "Usa el comando aws dynamodb create-table" 29 | 30 | - description: "Configura el backend en el archivo main.tf" 31 | command: "echo -e 'terraform {\n backend \"s3\" {\n bucket = \"terraform-state-lab\"\n key = \"terraform.tfstate\"\n region = \"us-east-1\"\n dynamodb_table = \"terraform-locks\"\n encrypt = true\n }\n\n required_providers {\n aws = {\n source = \"hashicorp/aws\"\n version = \"~> 4.0\"\n }\n }\n}\n\nprovider \"aws\" {\n region = \"us-east-1\"\n}\n\nresource \"aws_s3_bucket\" \"example\" {\n bucket = \"terraform-example-${terraform.workspace}\"\n\n tags = {\n Name = \"Example Bucket\"\n Environment = terraform.workspace\n }\n}' > main.tf" 32 | expectedOutput: "" 33 | hint: "Crea el archivo main.tf con la configuración del backend" 34 | 35 | - name: "Trabajando con Workspaces" 36 | description: "Aprende a crear y administrar workspaces en Terraform." 37 | steps: 38 | - description: "Inicializa Terraform con el nuevo backend" 39 | command: "terraform init" 40 | expectedOutput: "Terraform has been successfully initialized" 41 | hint: "Usa el comando terraform init" 42 | 43 | - description: "Crea un workspace para desarrollo" 44 | command: "terraform workspace new dev" 45 | expectedOutput: "Created and switched to workspace \"dev\"" 46 | hint: "Usa el comando terraform workspace new" 47 | 48 | - description: "Aplica la configuración en el workspace dev" 49 | command: "terraform apply -auto-approve" 50 | expectedOutput: "Apply complete!" 51 | hint: "Usa el comando terraform apply" 52 | 53 | - description: "Crea un workspace para producción" 54 | command: "terraform workspace new prod" 55 | expectedOutput: "Created and switched to workspace \"prod\"" 56 | hint: "Usa el comando terraform workspace new" 57 | 58 | - description: "Aplica la configuración en el workspace prod" 59 | command: "terraform apply -auto-approve" 60 | expectedOutput: "Apply complete!" 61 | hint: "Usa el comando terraform apply" 62 | 63 | - name: "Administración de Estado" 64 | description: "Aprende a administrar y manipular el estado de Terraform." 65 | steps: 66 | - description: "Lista todos los workspaces" 67 | command: "terraform workspace list" 68 | expectedOutput: "dev\nprod" 69 | hint: "Usa el comando terraform workspace list" 70 | 71 | - description: "Verifica el estado actual" 72 | command: "terraform state list" 73 | expectedOutput: "aws_s3_bucket.example" 74 | hint: "Usa el comando terraform state list" 75 | 76 | - description: "Visualiza detalles de un recurso" 77 | command: "terraform state show aws_s3_bucket.example" 78 | expectedOutput: "resource \"aws_s3_bucket\" \"example\"" 79 | hint: "Usa el comando terraform state show" 80 | 81 | - description: "Mueve un recurso entre workspaces" 82 | command: "terraform workspace select dev && terraform state mv aws_s3_bucket.example aws_s3_bucket.dev_example" 83 | expectedOutput: "Move \"aws_s3_bucket.example\" to \"aws_s3_bucket.dev_example\"" 84 | hint: "Usa el comando terraform state mv" 85 | -------------------------------------------------------------------------------- /labs/aws_ec2-vpc/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: aws-ec2-vpc-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: aws-ec2-vpc 11 | title: "EC2 e VPC na AWS" 12 | description: "Aprenda a configurar e gerenciar instâncias EC2 e Virtual Private Cloud (VPC) na AWS. Este laboratório guiado explora conceitos fundamentais de computação em nuvem e networking na AWS." 13 | duration: 45m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Criando uma VPC" 18 | description: "Aprenda a criar e configurar uma VPC na AWS." 19 | steps: 20 | - description: "Crie uma VPC com CIDR 10.0.0.0/16" 21 | command: "aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=LabVPC}]'" 22 | expectedOutput: "VpcId" 23 | hint: "Use o comando aws ec2 create-vpc com --cidr-block" 24 | 25 | - description: "Crie subnets públicas e privadas" 26 | command: "aws ec2 create-subnet --vpc-id $(aws ec2 describe-vpcs --filters 'Name=tag:Name,Values=LabVPC' --query 'Vpcs[0].VpcId' --output text) --cidr-block 10.0.1.0/24 --availability-zone us-east-1a --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=PublicSubnet1}]'" 27 | expectedOutput: "SubnetId" 28 | hint: "Use o comando aws ec2 create-subnet para criar subnets" 29 | 30 | - description: "Configure a tabela de rotas" 31 | command: "aws ec2 create-route-table --vpc-id $(aws ec2 describe-vpcs --filters 'Name=tag:Name,Values=LabVPC' --query 'Vpcs[0].VpcId' --output text) --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=PublicRouteTable}]'" 32 | expectedOutput: "RouteTableId" 33 | hint: "Use o comando aws ec2 create-route-table para criar a tabela de rotas" 34 | 35 | - name: "Configurando Instâncias EC2" 36 | description: "Aprenda a criar e configurar instâncias EC2." 37 | steps: 38 | - description: "Crie um security group" 39 | command: "aws ec2 create-security-group --group-name LabSecurityGroup --description 'Security group for lab instances' --vpc-id $(aws ec2 describe-vpcs --filters 'Name=tag:Name,Values=LabVPC' --query 'Vpcs[0].VpcId' --output text)" 40 | expectedOutput: "GroupId" 41 | hint: "Use o comando aws ec2 create-security-group" 42 | 43 | - description: "Configure regras do security group" 44 | command: "aws ec2 authorize-security-group-ingress --group-id $(aws ec2 describe-security-groups --filters 'Name=group-name,Values=LabSecurityGroup' --query 'SecurityGroups[0].GroupId' --output text) --protocol tcp --port 22 --cidr 0.0.0.0/0" 45 | expectedOutput: "Return" 46 | hint: "Use o comando aws ec2 authorize-security-group-ingress" 47 | 48 | - description: "Lance uma instância EC2" 49 | command: "aws ec2 run-instances --image-id ami-0c55b159cbfafe1f0 --instance-type t2.micro --key-name MyKeyPair --security-group-ids $(aws ec2 describe-security-groups --filters 'Name=group-name,Values=LabSecurityGroup' --query 'SecurityGroups[0].GroupId' --output text) --subnet-id $(aws ec2 describe-subnets --filters 'Name=tag:Name,Values=PublicSubnet1' --query 'Subnets[0].SubnetId' --output text) --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=LabInstance}]'" 50 | expectedOutput: "InstanceId" 51 | hint: "Use o comando aws ec2 run-instances" 52 | 53 | - name: "Gerenciamento de Instâncias" 54 | description: "Aprenda a gerenciar e monitorar instâncias EC2." 55 | steps: 56 | - description: "Verifique o status da instância" 57 | command: "aws ec2 describe-instances --filters 'Name=tag:Name,Values=LabInstance' --query 'Reservations[0].Instances[0].State.Name' --output text" 58 | expectedOutput: "running" 59 | hint: "Use o comando aws ec2 describe-instances" 60 | 61 | - description: "Obtenha o endereço IP público" 62 | command: "aws ec2 describe-instances --filters 'Name=tag:Name,Values=LabInstance' --query 'Reservations[0].Instances[0].PublicIpAddress' --output text" 63 | expectedOutput: "\\d+\\.\\d+\\.\\d+\\.\\d+" 64 | hint: "Use o comando aws ec2 describe-instances para obter o IP" 65 | 66 | - description: "Monitore a utilização da CPU" 67 | command: "aws cloudwatch get-metric-statistics --namespace AWS/EC2 --metric-name CPUUtilization --dimensions Name=InstanceId,Value=$(aws ec2 describe-instances --filters 'Name=tag:Name,Values=LabInstance' --query 'Reservations[0].Instances[0].InstanceId' --output text) --start-time $(date -u +%Y-%m-%dT%H:%M:%SZ) --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) --period 300 --statistics Average" 68 | expectedOutput: "Datapoints" 69 | hint: "Use o comando aws cloudwatch get-metric-statistics" 70 | -------------------------------------------------------------------------------- /labs/aws_ec2-vpc/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: aws-ec2-vpc-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: aws-ec2-vpc-es 11 | title: "EC2 y VPC en AWS" 12 | description: "Aprende a configurar y administrar instancias EC2 y Virtual Private Cloud (VPC) en AWS. Este laboratorio guiado explora conceptos fundamentales de computación en la nube y networking en AWS." 13 | duration: 45m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Creando una VPC" 18 | description: "Aprende a crear y configurar una VPC en AWS." 19 | steps: 20 | - description: "Crea una VPC con CIDR 10.0.0.0/16" 21 | command: "aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=LabVPC}]'" 22 | expectedOutput: "VpcId" 23 | hint: "Usa el comando aws ec2 create-vpc con --cidr-block" 24 | 25 | - description: "Crea subnets públicas y privadas" 26 | command: "aws ec2 create-subnet --vpc-id $(aws ec2 describe-vpcs --filters 'Name=tag:Name,Values=LabVPC' --query 'Vpcs[0].VpcId' --output text) --cidr-block 10.0.1.0/24 --availability-zone us-east-1a --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=PublicSubnet1}]'" 27 | expectedOutput: "SubnetId" 28 | hint: "Usa el comando aws ec2 create-subnet para crear subnets" 29 | 30 | - description: "Configura la tabla de rutas" 31 | command: "aws ec2 create-route-table --vpc-id $(aws ec2 describe-vpcs --filters 'Name=tag:Name,Values=LabVPC' --query 'Vpcs[0].VpcId' --output text) --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=PublicRouteTable}]'" 32 | expectedOutput: "RouteTableId" 33 | hint: "Usa el comando aws ec2 create-route-table para crear la tabla de rutas" 34 | 35 | - name: "Configurando Instancias EC2" 36 | description: "Aprende a crear y configurar instancias EC2." 37 | steps: 38 | - description: "Crea un security group" 39 | command: "aws ec2 create-security-group --group-name LabSecurityGroup --description 'Security group for lab instances' --vpc-id $(aws ec2 describe-vpcs --filters 'Name=tag:Name,Values=LabVPC' --query 'Vpcs[0].VpcId' --output text)" 40 | expectedOutput: "GroupId" 41 | hint: "Usa el comando aws ec2 create-security-group" 42 | 43 | - description: "Configura reglas del security group" 44 | command: "aws ec2 authorize-security-group-ingress --group-id $(aws ec2 describe-security-groups --filters 'Name=group-name,Values=LabSecurityGroup' --query 'SecurityGroups[0].GroupId' --output text) --protocol tcp --port 22 --cidr 0.0.0.0/0" 45 | expectedOutput: "Return" 46 | hint: "Usa el comando aws ec2 authorize-security-group-ingress" 47 | 48 | - description: "Lanza una instancia EC2" 49 | command: "aws ec2 run-instances --image-id ami-0c55b159cbfafe1f0 --instance-type t2.micro --key-name MyKeyPair --security-group-ids $(aws ec2 describe-security-groups --filters 'Name=group-name,Values=LabSecurityGroup' --query 'SecurityGroups[0].GroupId' --output text) --subnet-id $(aws ec2 describe-subnets --filters 'Name=tag:Name,Values=PublicSubnet1' --query 'Subnets[0].SubnetId' --output text) --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=LabInstance}]'" 50 | expectedOutput: "InstanceId" 51 | hint: "Usa el comando aws ec2 run-instances" 52 | 53 | - name: "Administración de Instancias" 54 | description: "Aprende a administrar y monitorear instancias EC2." 55 | steps: 56 | - description: "Verifica el estado de la instancia" 57 | command: "aws ec2 describe-instances --filters 'Name=tag:Name,Values=LabInstance' --query 'Reservations[0].Instances[0].State.Name' --output text" 58 | expectedOutput: "running" 59 | hint: "Usa el comando aws ec2 describe-instances" 60 | 61 | - description: "Obtén la dirección IP pública" 62 | command: "aws ec2 describe-instances --filters 'Name=tag:Name,Values=LabInstance' --query 'Reservations[0].Instances[0].PublicIpAddress' --output text" 63 | expectedOutput: "\\d+\\.\\d+\\.\\d+\\.\\d+" 64 | hint: "Usa el comando aws ec2 describe-instances para obtener la IP" 65 | 66 | - description: "Monitorea la utilización de CPU" 67 | command: "aws cloudwatch get-metric-statistics --namespace AWS/EC2 --metric-name CPUUtilization --dimensions Name=InstanceId,Value=$(aws ec2 describe-instances --filters 'Name=tag:Name,Values=LabInstance' --query 'Reservations[0].Instances[0].InstanceId' --output text) --start-time $(date -u +%Y-%m-%dT%H:%M:%SZ) --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) --period 300 --statistics Average" 68 | expectedOutput: "Datapoints" 69 | hint: "Usa el comando aws cloudwatch get-metric-statistics" 70 | -------------------------------------------------------------------------------- /internal/repo/lab.go: -------------------------------------------------------------------------------- 1 | package repo 2 | 3 | import ( 4 | "fmt" 5 | "gopkg.in/yaml.v3" 6 | "io" 7 | "net/http" 8 | "os" 9 | "path/filepath" 10 | "time" 11 | ) 12 | 13 | // LabManager gerencia os laboratórios 14 | type LabManager struct { 15 | repoManager *RepositoryManager 16 | cachePath string 17 | } 18 | 19 | // NewLabManager cria uma nova instância do gerenciador de laboratórios 20 | func NewLabManager(repoManager *RepositoryManager) (*LabManager, error) { 21 | homeDir, err := os.UserHomeDir() 22 | if err != nil { 23 | return nil, fmt.Errorf("erro ao obter diretório home: %v", err) 24 | } 25 | 26 | cachePath := filepath.Join(homeDir, ".girus", "cache") 27 | if err := os.MkdirAll(cachePath, 0755); err != nil { 28 | return nil, fmt.Errorf("erro ao criar diretório de cache: %v", err) 29 | } 30 | 31 | return &LabManager{ 32 | repoManager: repoManager, 33 | cachePath: cachePath, 34 | }, nil 35 | } 36 | 37 | // GetLab obtém um laboratório específico 38 | func (lm *LabManager) GetLab(repoName, labName, version string) (*LabEntry, error) { 39 | repo, err := lm.repoManager.GetRepository(repoName) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | index, err := lm.getIndex(repo) 45 | if err != nil { 46 | return nil, err 47 | } 48 | 49 | // Procura o laboratório pelo ID 50 | for _, lab := range index.Labs { 51 | if lab.ID == labName { 52 | // Se a versão não for especificada, retorna o laboratório encontrado 53 | if version == "" { 54 | return &lab, nil 55 | } 56 | 57 | // Procura a versão específica 58 | if lab.Version == version { 59 | return &lab, nil 60 | } 61 | } 62 | } 63 | 64 | return nil, fmt.Errorf("laboratório '%s' não encontrado no repositório '%s'", labName, repoName) 65 | } 66 | 67 | // DownloadLab baixa um laboratório específico 68 | func (lm *LabManager) DownloadLab(repoName, labName, version string) error { 69 | lab, err := lm.GetLab(repoName, labName, version) 70 | if err != nil { 71 | return err 72 | } 73 | 74 | // Cria o diretório do laboratório 75 | labPath := filepath.Join(lm.cachePath, repoName, labName, lab.Version) 76 | if err := os.MkdirAll(labPath, 0755); err != nil { 77 | return fmt.Errorf("erro ao criar diretório do laboratório: %v", err) 78 | } 79 | 80 | // Baixa o arquivo do laboratório 81 | resp, err := http.Get(lab.URL) 82 | if err != nil { 83 | return fmt.Errorf("erro ao baixar laboratório: %v", err) 84 | } 85 | defer resp.Body.Close() 86 | 87 | if resp.StatusCode != http.StatusOK { 88 | return fmt.Errorf("erro ao baixar laboratório (status: %d)", resp.StatusCode) 89 | } 90 | 91 | // Salva o arquivo 92 | labFile := filepath.Join(labPath, "lab.yaml") 93 | out, err := os.Create(labFile) 94 | if err != nil { 95 | return fmt.Errorf("erro ao criar arquivo do laboratório: %v", err) 96 | } 97 | defer out.Close() 98 | 99 | if _, err := io.Copy(out, resp.Body); err != nil { 100 | return fmt.Errorf("erro ao salvar laboratório: %v", err) 101 | } 102 | 103 | return nil 104 | } 105 | 106 | // getIndex obtém o índice de um repositório 107 | func (lm *LabManager) getIndex(repo Repository) (*Index, error) { 108 | // Tenta obter do cache primeiro 109 | cacheFile := filepath.Join(lm.cachePath, repo.Name, "index.yaml") 110 | fmt.Printf("Verificando cache em: %s\n", cacheFile) 111 | 112 | // Verifica se o arquivo de cache existe e não está expirado 113 | if info, err := os.Stat(cacheFile); err == nil { 114 | // Verifica se o arquivo tem menos de 7 dias 115 | if time.Since(info.ModTime()) < 7*24*time.Hour { 116 | fmt.Println("Usando índice do cache") 117 | data, err := os.ReadFile(cacheFile) 118 | if err == nil { 119 | var index Index 120 | if err := yaml.Unmarshal(data, &index); err == nil { 121 | return &index, nil 122 | } 123 | } 124 | } else { 125 | fmt.Println("Cache expirado, baixando novo índice") 126 | } 127 | } 128 | 129 | // Se não estiver em cache ou estiver expirado, baixa do repositório 130 | indexURL := fmt.Sprintf("%s/index.yaml", repo.URL) 131 | fmt.Printf("Buscando índice em: %s\n", indexURL) 132 | resp, err := http.Get(indexURL) 133 | if err != nil { 134 | return nil, fmt.Errorf("erro ao acessar índice do repositório: %v", err) 135 | } 136 | defer resp.Body.Close() 137 | 138 | if resp.StatusCode != http.StatusOK { 139 | return nil, fmt.Errorf("erro ao acessar índice do repositório (status: %d)", resp.StatusCode) 140 | } 141 | 142 | data, err := io.ReadAll(resp.Body) 143 | if err != nil { 144 | return nil, fmt.Errorf("erro ao ler conteúdo do repositório: %v", err) 145 | } 146 | 147 | var index Index 148 | if err := yaml.Unmarshal(data, &index); err != nil { 149 | return nil, fmt.Errorf("erro ao decodificar índice do repositório: %v", err) 150 | } 151 | 152 | // Salva no cache 153 | if err := os.MkdirAll(filepath.Dir(cacheFile), 0755); err != nil { 154 | return nil, fmt.Errorf("erro ao criar diretório de cache: %v", err) 155 | } 156 | 157 | if err := os.WriteFile(cacheFile, data, 0644); err != nil { 158 | return nil, fmt.Errorf("erro ao salvar índice em cache: %v", err) 159 | } 160 | 161 | return &index, nil 162 | } 163 | -------------------------------------------------------------------------------- /cmd/stop.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "fmt" 7 | "os" 8 | "strings" 9 | 10 | "github.com/badtuxx/girus-cli/internal/common" 11 | "github.com/badtuxx/girus-cli/internal/k8s" 12 | "github.com/fatih/color" 13 | "github.com/spf13/cobra" 14 | ) 15 | 16 | var ( 17 | // Criar formatadores de cores 18 | red = color.New(color.FgRed).SprintFunc() 19 | cyan = color.New(color.FgCyan).SprintFunc() 20 | green = color.New(color.FgGreen).SprintFunc() 21 | yellow = color.New(color.FgYellow).SprintFunc() 22 | magenta = color.New(color.FgMagenta).SprintFunc() 23 | headerColor = color.New(color.FgCyan, color.Bold).SprintFunc() 24 | ) 25 | 26 | var stopCmd = &cobra.Command{ 27 | Use: "stop", 28 | Short: common.T("Parar o ambiente do GIRUS", "Detener el entorno de GIRUS"), 29 | Long: common.T("Parar o ambiente do GIRUS CLI, removendo todos os recursos criados pelo GIRUS CLI.", "Detener el entorno del GIRUS CLI eliminando todos los recursos creados por el GIRUS CLI."), 30 | Run: func(cmd *cobra.Command, args []string) { 31 | fmt.Printf(common.T("%s Você está prestes a parar o %s e o %s no cluster %s.\n", 32 | "%s Está a punto de detener %s y %s en el cluster %s.\n"), 33 | yellow(common.T("AVISO:", "AVISO:")), magenta("frontend"), magenta("backend"), magenta(clusterName)) 34 | fmt.Print(common.T("Deseja continuar? [s/N]: ", "¿Desea continuar? [s/N]: ")) 35 | 36 | reader := bufio.NewReader(os.Stdin) 37 | confirmStr, _ := reader.ReadString('\n') 38 | confirm := strings.TrimSpace(strings.ToLower(confirmStr)) 39 | 40 | if confirm != "s" && confirm != "sim" && confirm != "y" && confirm != "yes" { 41 | fmt.Println(common.T("Operação cancelada pelo usuário.", "Operación cancelada por el usuario.")) 42 | return 43 | } 44 | // Define os nomes dos deployments 45 | frontendDeploymentName := "girus-frontend" 46 | backendDeploymentName := "girus-backend" 47 | // Criando um client para interagir com o cluster do Kubernetes 48 | client, err := k8s.NewKubernetesClient() 49 | if err != nil { 50 | fmt.Printf("%s %s: %v\n", red(common.T("ERRO:", "ERROR:")), common.T("Erro ao criar cliente Kubernetes", "Error al crear cliente de Kubernetes"), err) 51 | return 52 | } 53 | 54 | ctx := context.Background() 55 | // Pega todos os pods do namespace do girus 56 | pods, err := client.ListRunningPods(ctx, "girus") 57 | if err != nil { 58 | fmt.Printf("%s %s: %v\n", red(common.T("ERRO:", "ERROR:")), common.T("Erro ao tentar pegar a lista de pods", "Error al obtener la lista de pods"), err) 59 | return 60 | } 61 | 62 | // Pega o nome dos pods do frontend e do backend 63 | var frontendPod string 64 | var backendPod string 65 | for _, pod := range pods { 66 | if strings.Contains(pod, "frontend") { 67 | frontendPod = pod 68 | } else if strings.Contains(pod, "backend") { 69 | backendPod = pod 70 | } 71 | } 72 | 73 | // Verifica se o backend está em execução, se sim, parar o deploy e remover o serviço 74 | if isRunning, _ := client.IsPodRunning(ctx, "girus", backendPod); isRunning { 75 | err := deleteDeployment(client, ctx, backendDeploymentName) 76 | if err != nil { 77 | fmt.Printf("falha ao tentar parar o deploy do backend do GIRUS: %v\n", err) 78 | return 79 | } 80 | fmt.Println("✅ Backend parado com sucesso.") 81 | 82 | } else { 83 | fmt.Println("⚠️ " + common.T("O backend não está em execução.", "El backend no está en ejecución.")) 84 | } 85 | 86 | // Verifica se o frontend está em execução, se sim, parar o deploy e remover o serviço 87 | if isRunning, _ := client.IsPodRunning(ctx, "girus", frontendPod); isRunning { 88 | err := deleteDeployment(client, ctx, frontendDeploymentName) 89 | if err != nil { 90 | fmt.Printf("%s %s: %v\n", red(common.T("ERRO:", "ERROR:")), common.T("falha ao tentar parar o deploy do frontend do GIRUS", "fallo al intentar detener el deploy del frontend de GIRUS"), err) 91 | return 92 | } 93 | fmt.Println("✅ " + common.T("Frontend parado com sucesso.", "Frontend detenido con éxito.")) 94 | } else { 95 | fmt.Println("⚠️ " + common.T("O frontend não está em execução..", "El frontend no está en ejecución.")) 96 | } 97 | }, 98 | } 99 | 100 | func deleteDeployment(client *k8s.KubernetesClient, ctx context.Context, deploymentName string) error { 101 | err := client.StopDeployAndWait(ctx, "girus", deploymentName) 102 | if err != nil { 103 | _, err := fmt.Fprintf(os.Stderr, "%s %s: %v\n", red(common.T("ERRO:", "ERROR:")), common.T("Erro ao tentar parar o deploy", "Error al intentar detener el deploy"), err) 104 | if err != nil { 105 | return err 106 | } 107 | 108 | fmt.Printf(common.T("%s Você quer forçar a parada do deployment %s?\n", 109 | "%s ¿Desea forzar la detención del deployment %s?\n"), yellow(common.T("AVISO:", "AVISO:")), magenta(deploymentName)) 110 | fmt.Print(common.T("Deseja continuar? [s/N]: ", "¿Desea continuar? [s/N]: ")) 111 | 112 | reader := bufio.NewReader(os.Stdin) 113 | confirmStr, _ := reader.ReadString('\n') 114 | confirm := strings.TrimSpace(strings.ToLower(confirmStr)) 115 | 116 | if confirm != "s" && confirm != "sim" && confirm != "y" && confirm != "yes" { 117 | fmt.Println(common.T("Operação cancelada pelo usuário.", "Operación cancelada por el usuario.")) 118 | return err 119 | } 120 | return err 121 | } 122 | 123 | return nil 124 | } 125 | -------------------------------------------------------------------------------- /README.es.md: -------------------------------------------------------------------------------- 1 | ![GIRUS](girus-logo.png) 2 | 3 | **Elige tu idioma / Escolha seu idioma:** [Portugués](README.md) | [Español](README.es.md) 4 | 5 | # GIRUS: Plataforma de Laboratorios Interactivos 6 | 7 | Versión 0.4.0 Codename: "Maracatu" - Mayo de 2025 8 | 9 | ## Visión General 10 | 11 | GIRUS es una plataforma open-source de laboratorios interactivos que permite la creación, gestión y ejecución de entornos de aprendizaje práctico para tecnologías como Linux, Docker, Kubernetes, Terraform y otras herramientas esenciales para profesionales de DevOps, SRE, Desarrollo y Platform Engineering. 12 | 13 | Desarrollada por LINUXtips, GIRUS se diferencia por ejecutarse localmente en la máquina del usuario, eliminando la necesidad de infraestructura en la nube o configuraciones complejas. A través de una CLI intuitiva, los usuarios pueden crear rápidamente entornos aislados y seguros donde practicar y perfeccionar sus habilidades técnicas. 14 | 15 | ## Principales Características 16 | 17 | - **Ejecución Local**: A diferencia de plataformas como Katacoda o Instruqt que funcionan como SaaS, GIRUS se ejecuta directamente en la máquina del usuario mediante contenedores Docker y Kubernetes. Lo mejor de todo: el proyecto es open source y gratuito. 18 | - **Entornos Aislados**: Cada laboratorio se ejecuta en un entorno aislado en Kubernetes, garantizando seguridad y evitando conflictos con el sistema host. 19 | - **Interfaz Intuitiva**: Terminal interactivo con tareas guiadas y validación automática del progreso. 20 | - **Instalación Fácil**: CLI simple que gestiona todo el ciclo de vida de la plataforma (creación, ejecución y eliminación). 21 | - **Actualización Sencilla**: Comando `update` integrado que verifica, descarga e instala nuevas versiones automáticamente. 22 | - **Laboratorios Personalizables**: Sistema de plantillas basado en ConfigMaps de Kubernetes que facilita la creación de nuevos laboratorios. 23 | - **Open Source**: Proyecto completamente abierto a contribuciones de la comunidad. 24 | - **Multilingüe**: Además del portugués, GIRUS ahora ofrece soporte oficial para español. El sistema de plantillas permite agregar fácilmente otros idiomas. 25 | 26 | ## Gestión de Repositorios y Laboratorios 27 | 28 | GIRUS implementa un sistema robusto de gestión de repositorios y laboratorios, similar a Helm para Kubernetes. Este sistema permite: 29 | 30 | ### Actualizar la CLI 31 | 32 | - **Verificar y Actualizar a la Última Versión**: 33 | ```bash 34 | girus update 35 | ``` 36 | Este comando comprueba si hay una versión más reciente del GIRUS CLI disponible, la descarga e instala, ofreciendo la opción de recrear el cluster tras la actualización para garantizar compatibilidad. 37 | 38 | ### Repositorios 39 | 40 | - **Agregar Repositorios**: 41 | ```bash 42 | girus repo add linuxtips https://github.com/linuxtips/labs/raw/main 43 | ``` 44 | - **Listar Repositorios**: 45 | ```bash 46 | girus repo list 47 | ``` 48 | - **Eliminar Repositorios**: 49 | ```bash 50 | girus repo remove linuxtips 51 | ``` 52 | - **Actualizar Repositorios**: 53 | ```bash 54 | girus repo update linuxtips https://github.com/linuxtips/labs/raw/main 55 | ``` 56 | 57 | ### Soporte para Repositorios Locales (file://) 58 | 59 | GIRUS también admite repositorios locales usando el prefijo `file://`. Esto es útil para probar laboratorios o desarrollar repositorios sin necesidad de publicarlos en un servidor remoto. 60 | 61 | #### Ejemplo de uso: 62 | 63 | ```bash 64 | # Agregando un repositorio local 65 | ./girus repo add mi-local file:///ruta/absoluta/a/tu-repo 66 | ``` 67 | 68 | ## Laboratorios 69 | 70 | - **Listar Laboratorios Disponibles**: 71 | ```bash 72 | girus lab list 73 | ``` 74 | - **Instalar Laboratorio**: 75 | ```bash 76 | girus lab install linuxtips linux-basics 77 | ``` 78 | - **Buscar Laboratorios**: 79 | ```bash 80 | girus lab search docker 81 | ``` 82 | 83 | ## Instalación 84 | 85 | ### Usando el script de instalación 86 | 87 | ```bash 88 | curl -sSL girus.linuxtips.io | bash 89 | ``` 90 | 91 | ### Usando el Makefile 92 | 93 | Clona el repositorio y ejecuta `make `. 94 | 95 | ### Compilación y Instalación 96 | 97 | * **`make build`** (o simplemente `make`): Compila el binario `girus` para tu sistema operativo actual y lo coloca en el directorio `dist/`. 98 | * **`make install`**: Compila el binario (si aún no está compilado) y lo mueve a `/usr/local/bin/girus`, requiriendo permisos de superusuario (`sudo`). 99 | * **`make clean`**: Elimina el directorio `dist/` y todos los archivos generados de build. 100 | * **`make release`**: Compila el binario `girus` para múltiples plataformas (Linux, macOS, Windows - amd64 y arm64) y los coloca en `dist/`. 101 | 102 | ### Versionamiento 103 | 104 | GIRUS CLI utiliza versionamiento dinámico basado en etiquetas git. Puedes verificar la versión actual ejecutando: 105 | 106 | ```bash 107 | ./girus version 108 | ``` 109 | 110 | ## Contribuyendo con Labs 111 | 112 | 1. Crea un nuevo directorio en `labs/`. 113 | 2. Agrega un archivo `lab.yaml` con la estructura del lab. 114 | 3. Actualiza `index.yaml` con la información del nuevo lab. 115 | 4. Envía un Pull Request. 116 | 117 | ## Soporte y Contacto 118 | 119 | * **GitHub Issues**: [github.com/badtuxx/girus-cli/issues](https://github.com/badtuxx/girus-cli/issues) 120 | * **GitHub Discussions**: [github.com/badtuxx/girus-cli/discussions](https://github.com/badtuxx/girus-cli/discussions) 121 | * **Discord de la Comunidad**: [discord.gg/linuxtips](https://discord.gg/linuxtips) 122 | 123 | ## Licencia 124 | 125 | Este proyecto se distribuye bajo la licencia GPL-3.0. Consulta el archivo [LICENSE](LICENSE) para más detalles. 126 | -------------------------------------------------------------------------------- /labs/terraform_modulos/lab.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: terraform-modulos-lab 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: terraform-modulos 11 | title: "Módulos e Reutilização de Código no Terraform" 12 | description: "Aprenda a criar e utilizar módulos no Terraform para reutilizar código e manter sua infraestrutura organizada. Este laboratório guiado explora boas práticas de modularização." 13 | duration: 45m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Criando um Módulo Básico" 18 | description: "Aprenda a criar um módulo básico para provisionar recursos AWS." 19 | steps: 20 | - description: "Crie a estrutura de diretórios para o módulo" 21 | command: "mkdir -p terraform-modules/modules/ec2 && cd terraform-modules" 22 | expectedOutput: "" 23 | hint: "Use o comando mkdir para criar a estrutura de diretórios" 24 | 25 | - description: "Crie o arquivo main.tf do módulo" 26 | command: "echo -e 'resource \"aws_instance\" \"this\" {\n ami = var.ami_id\n instance_type = var.instance_type\n\n tags = merge(\n var.tags,\n {\n Name = var.instance_name\n }\n )\n}' > modules/ec2/main.tf" 27 | expectedOutput: "" 28 | hint: "Crie o arquivo main.tf com a definição do recurso EC2" 29 | 30 | - description: "Crie o arquivo variables.tf do módulo" 31 | command: "echo -e 'variable \"ami_id\" {\n description = \"ID da AMI para a instância\"\n type = string\n}\n\nvariable \"instance_type\" {\n description = \"Tipo da instância EC2\"\n type = string\n default = \"t2.micro\"\n}\n\nvariable \"instance_name\" {\n description = \"Nome da instância EC2\"\n type = string\n}\n\nvariable \"tags\" {\n description = \"Tags para a instância\"\n type = map(string)\n default = {}\n}' > modules/ec2/variables.tf" 32 | expectedOutput: "" 33 | hint: "Crie o arquivo variables.tf com as definições de variáveis" 34 | 35 | - name: "Utilizando o Módulo" 36 | description: "Aprenda a utilizar o módulo criado em um projeto Terraform." 37 | steps: 38 | - description: "Crie o arquivo main.tf do projeto" 39 | command: "echo -e 'terraform {\n required_providers {\n aws = {\n source = \"hashicorp/aws\"\n version = \"~> 4.0\"\n }\n }\n}\n\nprovider \"aws\" {\n region = \"us-east-1\"\n}\n\nmodule \"web_server\" {\n source = \"./modules/ec2\"\n\n ami_id = \"ami-0c55b159cbfafe1f0\"\n instance_type = \"t2.micro\"\n instance_name = \"web-server\"\n\n tags = {\n Environment = \"dev\"\n Project = \"terraform-modules\"\n }\n}' > main.tf" 40 | expectedOutput: "" 41 | hint: "Crie o arquivo main.tf do projeto usando o módulo" 42 | 43 | - description: "Crie o arquivo outputs.tf do projeto" 44 | command: "echo -e 'output \"instance_id\" {\n description = \"ID da instância EC2\"\n value = module.web_server.instance_id\n}\n\noutput \"public_ip\" {\n description = \"IP público da instância EC2\"\n value = module.web_server.public_ip\n}' > outputs.tf" 45 | expectedOutput: "" 46 | hint: "Crie o arquivo outputs.tf para expor os outputs do módulo" 47 | 48 | - description: "Inicialize e aplique a configuração" 49 | command: "terraform init && terraform apply -auto-approve" 50 | expectedOutput: "Apply complete!" 51 | hint: "Use os comandos terraform init e apply" 52 | 53 | - name: "Módulos Aninhados" 54 | description: "Aprenda a criar e utilizar módulos aninhados para infraestrutura mais complexa." 55 | steps: 56 | - description: "Crie um módulo para VPC" 57 | command: "mkdir -p modules/vpc && echo -e 'resource \"aws_vpc\" \"this\" {\n cidr_block = var.vpc_cidr\n\n tags = merge(\n var.tags,\n {\n Name = var.vpc_name\n }\n )\n}\n\nresource \"aws_subnet\" \"this\" {\n vpc_id = aws_vpc.this.id\n cidr_block = var.subnet_cidr\n\n tags = merge(\n var.tags,\n {\n Name = \"${var.vpc_name}-subnet\"\n }\n )\n}' > modules/vpc/main.tf" 58 | expectedOutput: "" 59 | hint: "Crie o módulo VPC com recursos básicos" 60 | 61 | - description: "Atualize o módulo EC2 para usar a VPC" 62 | command: "echo -e 'resource \"aws_instance\" \"this\" {\n ami = var.ami_id\n instance_type = var.instance_type\n subnet_id = var.subnet_id\n\n tags = merge(\n var.tags,\n {\n Name = var.instance_name\n }\n )\n}' > modules/ec2/main.tf" 63 | expectedOutput: "" 64 | hint: "Atualize o módulo EC2 para incluir a subnet" 65 | 66 | - description: "Atualize o projeto principal" 67 | command: "echo -e 'module \"vpc\" {\n source = \"./modules/vpc\"\n\n vpc_cidr = \"10.0.0.0/16\"\n vpc_name = \"terraform-vpc\"\n subnet_cidr = \"10.0.1.0/24\"\n\n tags = {\n Environment = \"dev\"\n Project = \"terraform-modules\"\n }\n}\n\nmodule \"web_server\" {\n source = \"./modules/ec2\"\n\n ami_id = \"ami-0c55b159cbfafe1f0\"\n instance_type = \"t2.micro\"\n instance_name = \"web-server\"\n subnet_id = module.vpc.subnet_id\n\n tags = {\n Environment = \"dev\"\n Project = \"terraform-modules\"\n }\n}' > main.tf" 68 | expectedOutput: "" 69 | hint: "Atualize o projeto principal para usar os módulos aninhados" 70 | 71 | - description: "Aplique a configuração atualizada" 72 | command: "terraform apply -auto-approve" 73 | expectedOutput: "Apply complete!" 74 | hint: "Use o comando terraform apply" 75 | -------------------------------------------------------------------------------- /labs/terraform_modulos/lab_es.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: terraform-modulos-lab-es 5 | namespace: girus 6 | labels: 7 | app: girus-lab-template 8 | data: 9 | lab.yaml: | 10 | name: terraform-modulos-es 11 | title: "Módulos y Reutilización de Código en Terraform" 12 | description: "Aprende a crear y utilizar módulos en Terraform para reutilizar código y mantener tu infraestructura organizada. Este laboratorio guiado explora buenas prácticas de modularización." 13 | duration: 45m 14 | image: "linuxtips/girus-devops:0.1" 15 | privileged: true 16 | tasks: 17 | - name: "Creando un Módulo Básico" 18 | description: "Aprende a crear un módulo básico para provisionar recursos AWS." 19 | steps: 20 | - description: "Crea la estructura de directorios para el módulo" 21 | command: "mkdir -p terraform-modules/modules/ec2 && cd terraform-modules" 22 | expectedOutput: "" 23 | hint: "Usa el comando mkdir para crear la estructura de directorios" 24 | 25 | - description: "Crea el archivo main.tf del módulo" 26 | command: "echo -e 'resource \"aws_instance\" \"this\" {\n ami = var.ami_id\n instance_type = var.instance_type\n\n tags = merge(\n var.tags,\n {\n Name = var.instance_name\n }\n )\n}' > modules/ec2/main.tf" 27 | expectedOutput: "" 28 | hint: "Crea el archivo main.tf con la definición del recurso EC2" 29 | 30 | - description: "Crea el archivo variables.tf del módulo" 31 | command: "echo -e 'variable \"ami_id\" {\n description = \"ID de la AMI para la instancia\"\n type = string\n}\n\nvariable \"instance_type\" {\n description = \"Tipo de instancia EC2\"\n type = string\n default = \"t2.micro\"\n}\n\nvariable \"instance_name\" {\n description = \"Nombre de la instancia EC2\"\n type = string\n}\n\nvariable \"tags\" {\n description = \"Tags para la instancia\"\n type = map(string)\n default = {}\n}' > modules/ec2/variables.tf" 32 | expectedOutput: "" 33 | hint: "Crea el archivo variables.tf con las definiciones de variables" 34 | 35 | - name: "Utilizando el Módulo" 36 | description: "Aprende a utilizar el módulo creado en un proyecto Terraform." 37 | steps: 38 | - description: "Crea el archivo main.tf del proyecto" 39 | command: "echo -e 'terraform {\n required_providers {\n aws = {\n source = \"hashicorp/aws\"\n version = \"~> 4.0\"\n }\n }\n}\n\nprovider \"aws\" {\n region = \"us-east-1\"\n}\n\nmodule \"web_server\" {\n source = \"./modules/ec2\"\n\n ami_id = \"ami-0c55b159cbfafe1f0\"\n instance_type = \"t2.micro\"\n instance_name = \"web-server\"\n\n tags = {\n Environment = \"dev\"\n Project = \"terraform-modules\"\n }\n}' > main.tf" 40 | expectedOutput: "" 41 | hint: "Crea el archivo main.tf del proyecto usando el módulo" 42 | 43 | - description: "Crea el archivo outputs.tf del proyecto" 44 | command: "echo -e 'output \"instance_id\" {\n description = \"ID de la instancia EC2\"\n value = module.web_server.instance_id\n}\n\noutput \"public_ip\" {\n description = \"IP pública de la instancia EC2\"\n value = module.web_server.public_ip\n}' > outputs.tf" 45 | expectedOutput: "" 46 | hint: "Crea el archivo outputs.tf para exponer los outputs del módulo" 47 | 48 | - description: "Inicializa y aplica la configuración" 49 | command: "terraform init && terraform apply -auto-approve" 50 | expectedOutput: "Apply complete!" 51 | hint: "Usa los comandos terraform init y apply" 52 | 53 | - name: "Módulos Anidados" 54 | description: "Aprende a crear y utilizar módulos anidados para infraestructura más compleja." 55 | steps: 56 | - description: "Crea un módulo para VPC" 57 | command: "mkdir -p modules/vpc && echo -e 'resource \"aws_vpc\" \"this\" {\n cidr_block = var.vpc_cidr\n\n tags = merge(\n var.tags,\n {\n Name = var.vpc_name\n }\n )\n}\n\nresource \"aws_subnet\" \"this\" {\n vpc_id = aws_vpc.this.id\n cidr_block = var.subnet_cidr\n\n tags = merge(\n var.tags,\n {\n Name = \"${var.vpc_name}-subnet\"\n }\n )\n}' > modules/vpc/main.tf" 58 | expectedOutput: "" 59 | hint: "Crea el módulo VPC con recursos básicos" 60 | 61 | - description: "Actualiza el módulo EC2 para usar la VPC" 62 | command: "echo -e 'resource \"aws_instance\" \"this\" {\n ami = var.ami_id\n instance_type = var.instance_type\n subnet_id = var.subnet_id\n\n tags = merge(\n var.tags,\n {\n Name = var.instance_name\n }\n )\n}' > modules/ec2/main.tf" 63 | expectedOutput: "" 64 | hint: "Actualiza el módulo EC2 para incluir la subnet" 65 | 66 | - description: "Actualiza el proyecto principal" 67 | command: "echo -e 'module \"vpc\" {\n source = \"./modules/vpc\"\n\n vpc_cidr = \"10.0.0.0/16\"\n vpc_name = \"terraform-vpc\"\n subnet_cidr = \"10.0.1.0/24\"\n\n tags = {\n Environment = \"dev\"\n Project = \"terraform-modules\"\n }\n}\n\nmodule \"web_server\" {\n source = \"./modules/ec2\"\n\n ami_id = \"ami-0c55b159cbfafe1f0\"\n instance_type = \"t2.micro\"\n instance_name = \"web-server\"\n subnet_id = module.vpc.subnet_id\n\n tags = {\n Environment = \"dev\"\n Project = \"terraform-modules\"\n }\n}' > main.tf" 68 | expectedOutput: "" 69 | hint: "Actualiza el proyecto principal para usar los módulos anidados" 70 | 71 | - description: "Aplica la configuración actualizada" 72 | command: "terraform apply -auto-approve" 73 | expectedOutput: "Apply complete!" 74 | hint: "Usa el comando terraform apply" 75 | --------------------------------------------------------------------------------