Pipeline con Gitlab & ArgoCD
Les propongo generar un pipeline con Gitlab como Continuous Integration y ArgoCD para el Continuous Deployment & Continuous Delivery
Hacía mucho que no escribía alguna entrada. Les propongo generar un pipeline, como dice el título, con Gitlab como Continuous Integration y ArgoCD para el Continuous Deployment & Continuous Delivery. La diferencia en CD es que podemos hacer los pasajes automáticamente y/o manualmente. Como buena práctica vamos a pasar al ambiente de Dev, como Deployment o Automático, y luego el pasaje a Prod, como Delivery o Manual.
¿Que vamos a necesitar?
Vamos a instalar minikube para tener nuestro cluster de Kubernetes, donde tendremos ArgoCD y los diferentes Namespaces, Dev & Prod. Usaremos Dockerhub, como Registry, y Kustomize para modificar los manifiestos. La estructura de archivos, que se encuentra en este repositorio, es la siguiente:
├── Dockerfile
├── README.md
├── argocd
│ └── argocd.yaml
├── deployment
│ ├── dev
│ │ ├── deployment.yaml
│ │ ├── ingress.yaml
│ │ ├── kustomization.yaml
│ │ ├── namespace.yaml
│ │ └── service.yaml
│ └── prod
│ ├── deployment.yaml
│ ├── ingress.yaml
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── service.yaml
├── hello.conf
└── index.html
Instalación de ArgoCD
Una vez que tenemos instalado y funcionando minikube, acá les dejo Step by Step, vamos a echar a correr ArgoCD.
Antes que nada vamos instalar ingress a nuestro cluster que nos servira para el acceso al mismo.
minikube addons enable ingress
Generaremos las entradas FQDN de nuestros ambientes. En mi caso voy a generar dos entradas con la dirección del cluster. La dirección con el comando minikube ip, la obtenemos, para generar los registros. Aca encontraras un tutorial, para modificar en cada Sistema Operativo.
192.168.205.129 dev-webpage-app.local prod-webpage-app.local
Generamos el namespace para argocd y aplicamos los manifiestos.
kubectl create ns argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Para acceder a ArgoCD vamos cambiar el servicio de ClusterIP a NodePort.
kubectl patch svc argocd-server -n argocd --type='json' -p '[{"op":"replace","path":"/spec/type","value":"NodePort"}]'
Vamos a revisar el puerto, para ingresar a la interfaz UI. En nuestro caso abriremos un navegador en http://192.168.205.129:30738
Obtenemos el password, con este comando, y estamos listos para utilizar ArgoCD.
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
Gitlab
Una vez que generemos nuestro repositorio vamos a necesitar cargar variables. Para ello vamos a Proyecto > Settings > CI/CD > Variables. En mi caso sume estas:
Carge las necesarias para conectarme a DockerHub, como CI_REGISTRY, CI_REGISTRY_USER y CI_REGISTRY_PASSWORD & las necesarias para poder "pushear" en el repositorio. Para ello es necesario sacar un Token o PAT, aqui dejo instructivo. ¿Por que es necesario, este ultimo? Para modificar el kustomize.yaml y cargar el nombre de la imagen docker, con referencia al TAG del Build.
Es hora de configurar nuestras aplicaciones en Kubernetes usando GitOps. Como mencioné antes, Argo CD viene con ArgoCLI y ArgoCD GUI. Estos son los manifiestos que configuran aplicaciones web para entornos de DEV y PROD.
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: webpage-app-dev
namespace: argocd
spec:
project: default
destination:
server: https://kubernetes.default.svc
namespace: dev
source:
repoURL: https://gitlab.com/santiagoagustinfernandez/devops.git
targetRevision: HEAD
path: deployment/dev
syncPolicy:
syncOptions:
- CreateNamespace=true
automated:
selfHeal: true
prune: true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: webpage-app-prod
namespace: argocd
spec:
project: default
destination:
server: https://kubernetes.default.svc
namespace: prod
source:
repoURL: https://gitlab.com/santiagoagustinfernandez/devops.git
targetRevision: HEAD
path: deployment/prod
syncPolicy:
syncOptions:
- CreateNamespace=true
automated:
selfHeal: true
prune: true
Lo mas importante del manifiesto, que comparti, es lo siguiente:
name — El nombre de nuestra aplicación en ArgoCD
namespace — Tiene que ser el mismo que nuestra instancia ArgoCD
project — Donde sera configurada la aplicación.
repo URL — URL del código fuente.
target revision — ¿Que rama vamos usar?
path — En que path, del repositorio, estan nuestros manifiestos Kubernetes.
destination — La dirección del Cluster, donde vamos a deployar.
¡Aplicamos el manifiesto!
Vemos los ambientes de Dev & Prod.
Aca los ambientes Dev con los componentes.
Ahora manos a la obra, agregamos nuestro pipeline en gitlab-ci.yaml, que genera nuestro pipeline. Vamos a tener 3 stages, donde hacemos el build de la imagen docker y los de deploy en Dev & Prod. Es importante diferenciar que el deploy en Prod necesita una aprobación manual, primero debemos saber que en Dev no hay problemas.
stages:
- build
- deploy-dev
- deploy-prod
variables:
IMAGE_NAME: "webpage-app"
CI_DOCKERHUB_USER: "safernandez666"
build:
image: docker:19.03.12
stage: build
services:
- docker:19.03.12-dind
rules:
- if: $CI_PIPELINE_SOURCE == "push"
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build . -t $CI_REGISTRY/$CI_DOCKERHUB_USER/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA
- docker tag $CI_REGISTRY/$CI_DOCKERHUB_USER/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA $CI_REGISTRY/$CI_DOCKERHUB_USER/$IMAGE_NAME:latest
# PUSH IMAGE COMMIT SHA and LATEST
- docker push $CI_REGISTRY/$CI_DOCKERHUB_USER/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA
- docker push $CI_REGISTRY/$CI_DOCKERHUB_USER/$IMAGE_NAME:latest
deploy-dev:
stage: deploy-dev
image: alpine:3.11
before_script:
- apk add --no-cache git curl bash
- curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
- mv kustomize /usr/local/bin/
- git remote set-url origin https://${CI_USERNAME}:${CI_PUSH_TOKEN}@gitlab.com/santiagoagustinfernandez/devops.git
- git config --global user.email "santiagoagustinfernandez@gmail.com"
- git config --global user.name "santiagoagustinfernandez"
script:
- git checkout -B main
- cd deployment/dev
- kustomize edit set image $CI_REGISTRY/$CI_DOCKERHUB_USER/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA
- cat kustomization.yaml
- git commit -am 'DEV image update'
- git push -f origin main
only:
- main
deploy-prod:
stage: deploy-prod
image: alpine:3.11
before_script:
- apk add --no-cache git curl bash
- curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
- mv kustomize /usr/local/bin/
- git remote set-url origin https://${CI_USERNAME}:${CI_PUSH_TOKEN}@gitlab.com/santiagoagustinfernandez/devops.git
- git config --global user.email "santiagoagustinfernandez@gmail.com"
- git config --global user.name "santiagoagustinfernandez"
script:
- git checkout -B main
- git pull origin main
- cd deployment/prod
- kustomize edit set image $CI_REGISTRY/$CI_DOCKERHUB_USER/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA
- cat kustomization.yaml
- git commit -am 'PROD image update'
- git push -f origin main
only:
- main
when: manual
Vamos hacer una modificación en el index.html y hacer el push.
Empieza a correr nuestro pipeline, revisen que solo vamos a deployar sobre Dev. Para hacerlo en Prod sera necesario correrlo manualmente.
Revisamos el Sync de ArgoCD y ya contamos con la nueva imagen en Dev.
Si revisamos el tag de la imagen, que deployamos, tiene el tag: 8873af5. Revisamos en DockerHub y es el ultimo build.
Si esta todo ok, podemos darle run al build en el ambiente Prod. En este estadio tenemos la version vieja y nueva corriendo, una en cada ambiente.
Ambiente Dev
Mientras que en Prod tenemos la web, en una version anterior.
Espero que les haya servidor, este es un escenario 100% GitOps con un Pipeline DevOps. ¡Espero que les sume!