Un pipeline simple, pero efectivo. 😉
Construimos un CI/CD con GitHub Actions, DockerHub & ArgoCD. Una manera sencilla de desplegar nuestras aplicaciones.
Introducción
Hace tiempo que no actualizo los proyectos DevOps del Blog, así que vamos a crear algo sencillo pero eficaz para aquellos que están haciendo sus primeras armas en este mundo.
Les comparto este proyecto para que puedan desplegarlo fácilmente en sus entornos. Un pipeline completo. Explicaremos cómo crear una imagen Docker y subirla a Docker Hub, utilizar un Helm Chart y modificarlo, automatizar estos procesos con GitHub Actions, para finalmente desplegarlo en nuestro Kubernetes via ArgoCD.
Aca el contenido del proyecto, pero tranquilos que vamos a ir paso a paso.
Creación de Imagen Docker
Vamos a crear local nuestra imagen docker, solo para probar que el Dockerfile está correcto y luego correrla en el puerto 8080.
¡Todo perfecto!
Repasamos los comandos.
# Construccion de Imagen, debemos estar en la carpeta app donde encontramos el Dockerfile
docker build . -t app
# Listar Imagenes
docker images
# Levantar el Contenedor
docker run -it --rm -d -p 8080:80 app
# Status del Contenedor
docker ps
El primer paso está correcto. ¡Seguimos!
Despliegue en Kubernetes
Vamos a revisar los manifiestos y desplegar. En este caso ya tenemos la imagen en DockerHub, para esta prueba, algo que luego hara GitHub Actions no solo sera el build, si no también el push al registro.
Vamos a repasar los comandos.
# Creo el Namespace app
kubectl create namespace app
# Aplico los manifiestos
kubectl apply -f .
# Revisamos el Ingress
kubectl get ingress -n app
# Listamos los artefactos del Namespace app
kubectl get all -n app
¿Le pegamos una mirada a cada manifiesto, dentro de k8s/manifest?
Primero el deployment.yaml
que referencia a la imagen subida a DockerHub.
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
namespace: app
labels:
app: app
spec:
replicas: 1
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
containers:
- name: app
image: safernandez666/app # Cambiar por tu imagen en DockerHub
ports:
- containerPort: 80
Segundo el service.yaml
.
apiVersion: v1
kind: Service
metadata:
name: app
namespace: app
labels:
app: app
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: app
type: ClusterIP
Y por último el ingress.yaml
, que referencia la FQDN que queremos resolver.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app
namespace: app
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: app.esprueba.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app
port:
number: 80
⚠️ Es necesario que tengamos desplegado ingress en nuestro cluster.
La resolucion, para esta prueba, del FQDN la hice modificando mis registro local apuntando a mi cluster de Kubernetes. Dependiendo de la plataforma se hace de diferente manera, si estás tocando Clusters seguramente sepas hacerlo. Si no sabes me avisas 📞 y te guio.
CI con GitHub Actions
Vamos al corazón de esta automatización. El manifiesto de GitHub Actions. Antes que nada vamos a sumar los secretos de DockerHub en las variables. Para ello en tu repositorio, debes hacer lo siguiente.
Vamos a cargar las variables de inicio para el login en DockerHub, una vez cargados los secretos, vamos modificar los permisos de GITHUB_TOKEN para poder escribir, desde la GitHub Actions en el YAML del Helm Chart.
Ahora si revisamos el Workflow que se puede generar desde acá.
name: Build and Push Docker Image to Docker Hub
on:
push:
branches:
- master
paths-ignore: # Si realizamos cambios, aqui, no se dispara el pipeline.
- 'k8s/**'
- 'README.md'
jobs:
build-and-update: # Construccion de la Imagen & Push en DockerHub
name: Build Image and Update Helm Chart
runs-on: ubuntu-latest
steps:
- name: Check out the repository
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Agregamos el TAG para subir no solo latest, si no tambien la version.
- name: Extract version number from GIT SHA
id: extract_sha
run: echo "BUILD_TAG=${GITHUB_SHA::7}" >> $GITHUB_ENV
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: app/
push: true
tags: safernandez666/app:latest, safernandez666/app:${{ env.BUILD_TAG }}
- name: Update tag in Helm Chart # Cambiamos por el numero de version el values.yaml
run: |
sed -i 's/tag: .*/tag: "${{ env.BUILD_TAG }}"/' app-chart/values.yaml
- name: Commit and push changes
run: |
git config --global user.email "santiagoagustinfernandez@gmail.com"
git config --global user.name "Santiago Fernandez"
git add app-chart/values.yaml
git commit -m "Update tag to '${{ env.BUILD_TAG }}' after building image"
git push
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Usando el token para autenticar el push
Perfecto, vamos a realizar un cambio para ver como interactua. Modificamos el archivo values.yaml
para actualizar la etiqueta con el número de versión después de construir la imagen. Ahora ponemos latest solo para ver el cambio 😎.
¡Hacemos el commit!
¡Excelente!
Se está realizando el Build y Subiendo a DockerHub. ¡Miremos le Job a detalle! Se modifico el archivo app-chart/values.yaml
con el tag:4044587
.
Revisemos el archivo del Helm Chart y el registro.
Todo está funcionando como queremos. Ahora solo nos queda instalar ArgoCD para desplegar la versión que deseamos.
CD con ArgoCD
¿Que es ArgoCD? No es ni más ni menos que una herramienta de despliegue continuo que nos permite automatizar el despliegue y la gestión de sus aplicaciones utilizando Git como una única fuente de verdad
Instalación de ArgoCD
Creamos el Namespace y descargamos los manifiestos.
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Ahora nos queda, para facilitar el ingreso, cambiar el servicio por LoadBalancer.
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
kubectl get svc argocd-server -n argocd
Obtenemos la dirección IP y por último necesitar el password para el usuario admin, con este comando podemos conocerlo.
kubectl get svc argocd-server -n argocd
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
Configuración de ArgoCD
Conectamos nuestro repositorio de GitHub.
Creamos un proyecto donde configuramos la fuente y con qué Cluster vamos a trabajar.
Ahora el paso final, crear la aplicación con algunas configuraciones básicas.
¡Uala! Ya tenemos el aplicativo sincronizado.
Cada vez que ArgoCD detecte un cambio en el repositorio hará el despliegue del Helm Chart, con la última versión de build que generamos.
Te dejo un video, para que lo veas en acción.
Espero que te sirva para comenzar en el mundo DevOps.
Saludos.