# Aula 11 - ArgoCD + GitLab Runner (GitOps) Deploy de ArgoCD e GitLab Runner para pipeline CI/CD completo com GitOps. ## Arquitetura ``` ┌─────────────────────────────────────────────────────────────┐ │ GitLab (aula-10) │ │ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │ │ │ git push │───►│ GitLab CI │───►│ Registry │ │ │ │ (código) │ │ (Runner K8s)│ │ (imagem:tag) │ │ │ └─────────────┘ └──────┬───────┘ └───────────────┘ │ └────────────────────────────┼────────────────────────────────┘ │ atualiza manifests ▼ ┌─────────────────────────────────────────────────────────────┐ │ Repositório GitOps │ │ apps/node-bugado/ │ │ ├── deployment.yaml (image: registry.../node-bugado:sha) │ │ ├── service.yaml │ │ └── configmap.yaml │ └─────────────────────────────────────────────────────────────┘ │ │ sync automático ▼ ┌─────────────────────────────────────────────────────────────┐ │ ArgoCD │ │ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │ │ │ Application │───►│ Sync │───►│ Kubernetes │ │ │ │ CRD │ │ Controller │ │ (deploy) │ │ │ └─────────────┘ └──────────────┘ └───────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ## Pré-requisitos 1. **Cluster Talos na Hetzner** (aula-08) com: - NGINX Ingress Controller com LoadBalancer - Hetzner CSI Driver 2. **GitLab instalado** (aula-10) 3. **kubectl** e **helm** instalados ## Contexto do Cluster ```bash # Usar kubeconfig da aula-08 export KUBECONFIG=$(pwd)/../aula-08/kubeconfig kubectl cluster-info ``` ## Instalação ```bash cd aula-11 # Executar setup interativo chmod +x setup.sh ./setup.sh ``` O script instala: 1. **GitLab Runner** - Executor Kubernetes para pipelines CI 2. **ArgoCD** - GitOps CD para Kubernetes 3. Configura integração SSH com GitLab ## Componentes Instalados | Componente | Namespace | Recursos | Função | |------------|-----------|----------|--------| | ArgoCD Server | argocd | 256Mi/512Mi | UI + API | | ArgoCD Repo Server | argocd | 256Mi/512Mi | Git clone/sync | | ArgoCD Controller | argocd | 256Mi/512Mi | Reconciliation | | ArgoCD Redis | argocd | 64Mi/128Mi | Cache | | GitLab Runner | gitlab | 128Mi/256Mi | CI jobs como pods | | **Total** | | ~1.2Gi | | ## Acesso ### ArgoCD ``` URL: https://argocd.{domain} Username: admin Senha: kubectl get secret argocd-initial-admin-secret -n argocd \ -o jsonpath='{.data.password}' | base64 -d ``` ### GitLab Runner Verificar status em: `https://{gitlab-host}/admin/runners` ```bash # Ver pods do runner kubectl get pods -n gitlab -l app=gitlab-runner # Ver logs kubectl logs -n gitlab -l app=gitlab-runner -f ``` ## Configurar Pipeline GitOps ### 1. Criar Repositório GitOps no GitLab Crie um repositório `gitops-demo` com a estrutura: ``` gitops-demo/ └── apps/ └── node-bugado/ ├── configmap.yaml ├── deployment.yaml ├── service.yaml └── ingress.yaml ``` Use os arquivos de exemplo em `node-bugado/k8s/`. ### 2. Configurar Deploy Key ```bash # Gerar par de chaves ssh-keygen -t ed25519 -f argocd-deploy-key -N '' # Adicionar chave pública no GitLab: # Settings → Repository → Deploy Keys # Marcar "Grant write permissions" ``` ### 3. Conectar Repositório no ArgoCD Via UI: 1. Acesse https://argocd.{domain} 2. Settings → Repositories → Connect Repo 3. Method: SSH 4. URL: `git@git.{domain}:{usuario}/gitops-demo.git` 5. SSH private key: (conteúdo de argocd-deploy-key) Ou via CLI: ```bash argocd repo add git@git.kube.quest:usuario/gitops-demo.git \ --ssh-private-key-path argocd-deploy-key ``` ### 4. Criar ArgoCD Application ```bash kubectl apply -f - << 'EOF' apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: node-bugado namespace: argocd spec: project: default source: repoURL: git@git.kube.quest:usuario/gitops-demo.git targetRevision: HEAD path: apps/node-bugado destination: server: https://kubernetes.default.svc namespace: demo syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true EOF ``` ### 5. Configurar Pipeline no Repositório da App No repositório `node-bugado`: 1. Copie `.gitlab-ci.yml` de `node-bugado/.gitlab-ci.yml` 2. Configure variáveis em Settings → CI/CD → Variables: - `GITOPS_REPO`: `git@git.kube.quest:usuario/gitops-demo.git` - `DEPLOY_KEY`: Chave SSH privada (com write access ao repo gitops) ## Fluxo de Deploy 1. **Desenvolvedor** faz push no repositório `node-bugado` 2. **GitLab CI** dispara pipeline: - Build: Constrói imagem Docker - Push: Envia para GitLab Registry - Deploy: Atualiza `deployment.yaml` no repo GitOps 3. **ArgoCD** detecta mudança no repo GitOps 4. **ArgoCD** sincroniza com cluster Kubernetes 5. **Kubernetes** faz rolling update dos pods ## GitLab Runner - Executor Kubernetes O runner usa executor `kubernetes`, onde cada job CI: - Roda como um **pod efêmero** no cluster - Tem acesso a **Docker-in-Docker** para builds - É automaticamente **limpo** após conclusão - **Escala** conforme demanda de jobs ```yaml # gitlab-runner-values.yaml runners: executor: kubernetes privileged: true # Necessário para Docker-in-Docker namespace: gitlab ``` ### Por que Docker-in-Docker? Para construir imagens Docker dentro de um container (o job do CI), precisamos: 1. **Privileged mode**: Acesso ao kernel para criar containers 2. **Docker daemon**: Serviço Docker rodando no job Alternativas (mais seguras, mas mais complexas): - **Kaniko**: Build sem Docker daemon - **Buildah**: Build rootless ### Requisitos para Docker-in-Docker #### 1. Pod Security (Kubernetes 1.25+) Kubernetes 1.25+ aplica Pod Security Admission por padrão. O namespace `gitlab` precisa permitir pods privilegiados: ```bash kubectl label namespace gitlab \ pod-security.kubernetes.io/enforce=privileged \ pod-security.kubernetes.io/warn=privileged \ --overwrite ``` > **Nota**: O `setup.sh` já configura isso automaticamente. #### 2. Helper Image para ARM64 Em clusters com nodes ARM64 (como Hetzner CAX), o runner precisa usar o helper image correto. Configure em `gitlab-runner-values.yaml`: ```toml # Dentro de runners.config [[runners]] [runners.kubernetes] helper_image = "gitlab/gitlab-runner-helper:arm64-latest" ``` Sem isso, você verá erros como: ``` no match for platform in manifest: not found ``` ## Troubleshooting ### ArgoCD não sincroniza ```bash # Verificar status da Application kubectl get applications -n argocd # Ver detalhes kubectl describe application node-bugado -n argocd # Ver logs do controller kubectl logs -n argocd -l app.kubernetes.io/name=argocd-application-controller ``` ### Runner não aparece no GitLab ```bash # Verificar pod do runner kubectl get pods -n gitlab -l app=gitlab-runner # Ver logs kubectl logs -n gitlab -l app=gitlab-runner # Verificar registration token kubectl get secret gitlab-gitlab-runner-secret -n gitlab -o yaml ``` ### Jobs CI falham ```bash # Ver pods dos jobs kubectl get pods -n gitlab # Ver logs de um job específico kubectl logs -n gitlab runner-xxxxx-project-xxx-concurrent-xxx ``` ### Erro "violates PodSecurity" ``` violates PodSecurity "baseline:latest": privileged (containers must not set securityContext.privileged=true) ``` **Solução**: Configure o namespace para permitir pods privilegiados: ```bash kubectl label namespace gitlab \ pod-security.kubernetes.io/enforce=privileged \ --overwrite ``` ### Erro "no match for platform in manifest" ``` image pull failed: no match for platform in manifest: not found ``` **Causa**: O runner está tentando usar imagem x86_64 em node ARM64. **Solução**: Configure o helper image ARM64 no `gitlab-runner-values.yaml`: ```toml [[runners]] [runners.kubernetes] helper_image = "gitlab/gitlab-runner-helper:arm64-latest" ``` Depois faça upgrade do runner: ```bash helm upgrade gitlab-runner gitlab/gitlab-runner \ -n gitlab --reuse-values \ -f gitlab-runner-values.yaml ``` ### Erro SSH ao conectar repositório ```bash # Verificar known hosts kubectl get configmap argocd-ssh-known-hosts-cm -n argocd -o yaml # Adicionar manualmente ssh-keyscan git.kube.quest | kubectl create configmap argocd-ssh-known-hosts-cm \ --from-file=ssh_known_hosts=/dev/stdin -n argocd --dry-run=client -o yaml | kubectl apply -f - ``` ## Comandos Úteis ```bash # ArgoCD kubectl get applications -n argocd kubectl get pods -n argocd argocd app list argocd app sync node-bugado # GitLab Runner kubectl get pods -n gitlab -l app=gitlab-runner kubectl logs -n gitlab -l app=gitlab-runner -f # Ver todos os recursos do demo kubectl get all -n demo # Forçar re-sync argocd app sync node-bugado --force # Ver diff antes de sync argocd app diff node-bugado ``` ## Lições do Workshop 1. **GitOps**: Git como fonte única de verdade para estado do cluster 2. **Separação CI/CD**: GitLab CI = build, ArgoCD = deploy 3. **Runner Kubernetes**: Jobs como pods efêmeros e escaláveis 4. **Docker-in-Docker**: Build de imagens em containers privilegiados 5. **Auditoria**: Histórico de deploys = histórico Git 6. **Self-Heal**: ArgoCD corrige drift automaticamente 7. **Segurança**: Deploy Keys com permissão mínima ## Cleanup ```bash ./cleanup.sh ``` Remove ArgoCD e GitLab Runner. Não remove GitLab ou infraestrutura base. ## Custos | Recurso | Custo/mês | |---------|-----------| | ArgoCD + Runner (~1.2Gi) | Usa workers existentes | | **Total Adicional** | ~$0 | ## Próximos Passos - **Aula 12**: eStargz + Lazy Pulling - Converter imagens para formato eStargz - Demonstrar startup mais rápido com lazy pulling - Medir diferença de performance ## Referências - [ArgoCD Docs](https://argo-cd.readthedocs.io/en/stable/) - [ArgoCD Helm Chart](https://github.com/argoproj/argo-helm) - [GitLab Runner Kubernetes Executor](https://docs.gitlab.com/runner/executors/kubernetes.html) - [GitOps with GitLab + ArgoCD](https://medium.com/@andrew.kaczynski/gitops-in-kubernetes-argo-cd-and-gitlab-ci-cd-5828c8eb34d6)