# Pipeline con Gitlab & ArgoCD

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**.

![What is the difference between continuous delivery and continuous deployment?  - Quora](https://qph.fs.quoracdn.net/main-qimg-a82fe747cc53bd5dadb0ccee0f02af5c-pjlq align="center")

## ¿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](https://hub.docker.com/), como Registry, y [Kustomize](https://kustomize.io/) para modificar los manifiestos. La estructura de archivos, que se encuentra en este [repositorio](https://gitlab.com/santiagoagustinfernandez/devops), es la siguiente:

```yaml
├── 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](https://minikube.sigs.k8s.io/docs/start/), vamos a echar a correr ArgoCD.

Antes que nada vamos instalar ingress a nuestro cluster que nos servira para el acceso al mismo.

```yaml
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.

```yaml
192.168.205.129 dev-webpage-app.local prod-webpage-app.local
```

Generamos el namespace para **argocd** y aplicamos los manifiestos.

```yaml
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.

```yaml
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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405716014/19308a76-1e5c-4b87-85bc-af4c9691ac66.png align="center")

Obtenemos el password, con este comando, y estamos listos para utilizar ArgoCD.

```yaml
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405727411/514dc4a5-1176-427a-ba3e-7c047dc40607.png align="center")

## Gitlab

Una vez que generemos nuestro repositorio vamos a necesitar cargar variables. Para ello vamos a Proyecto &gt; Settings &gt; CI/CD &gt; Variables. En mi caso sume estas:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405740215/aea9ac85-7778-49b6-8d20-ffd0a7a22b86.png align="center")

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](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) 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.

```yaml
---
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!

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405774192/b17a9b1f-6d51-4089-8aeb-9efa5334924d.png align="center")

Vemos los ambientes de Dev & Prod.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405793940/da8f31d3-48a3-4d47-b0e1-4b22ace3d7d4.png align="center")

Aca los ambientes Dev con los componentes.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405810564/04c8f1d5-e4f8-4d8f-a279-b4d0effcfe82.png align="center")

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.

```yaml
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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405892097/4f181226-2045-4eb4-9bb1-16af691c655c.png align="center")

Empieza a correr nuestro pipeline, revisen que solo vamos a deployar sobre Dev. Para hacerlo en Prod sera necesario correrlo manualmente.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405912682/c245c1f3-1075-412b-afb0-8def93c18760.png align="center")

Revisamos el Sync de ArgoCD y ya contamos con la nueva imagen en Dev.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405919865/263f0e6f-a2d5-46fc-914b-35e2335bcafe.png align="center")

Si revisamos el tag de la imagen, que deployamos, tiene el tag: 8873af5. Revisamos en DockerHub y es el ultimo build.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405956999/dab80b58-7fe4-4704-acdc-dfad86606b69.png align="center")

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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405972362/35bc3bf5-77c6-4612-a8a3-9d8d70cae5d8.png align="center")

Ambiente Dev

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405986088/72c1e4ed-2ed4-436a-a210-06d428fd3a89.png align="center")

Mientras que en Prod tenemos la web, en una version anterior.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1707405994313/1b8d571b-89b1-48fc-8c8b-c1fa0c473f39.png align="center")

Espero que les haya servidor, este es un escenario 100% GitOps con un Pipeline DevOps. ¡Espero que les sume!
