Despliegue y configuración de infraestructura DevOps para tus proyectos

RMAG news

En este vídeo hemos aprendido a montarnos una pipeline de despliegue DevOps real usando cantidad de tecnologías, algunas de las cuales las hemos instalado: Gitlab, Gitlab CICD, Docker hub, Kubernetes(GKE) sobre Google Cloud Platform(GCP) o Kaniko.

Creación de un cluster sobre Google Cloud Platform(GCP)

Este paso lo hemos realizado desde la consola de GCP en https://console.cloud.google.com/ y es bastante visual, con lo que mejor os basáis en el vídeo.

Obviamente, podríamos haber contratado el cluster a través de cualquier otro proveeros cloud como Amazon o Azure o incluso instalar Kubernetes en nuestros propios servidores con K0s, K3s o similares(Tenemos vídeos y artículos de referencia sobre el tema).

Otra mejora hubiera sido contratar el servicio vía Gcloud o Terraform que nos permitía automatizar este paso. Pero esto ya es otra historia.

Configuración de credenciales de Docker Hub para el despliegue

Para poder desplegar sobre Kubernetes necesitamos un “Registry”, que básicamente, se trata de un repositorio donde almacenar las imágenes que vamos a desplegar. En este caso, para no liar mas el vídeo, hemos optado por usar Docker Hub, que nos permite usarlo como servicio SaaS y con su capa gratuita nos vale.

Para ello hemos tenido que configurar unas credenciales y lo hemos hecho vía su interfaz web así que es mas fácil verlo en el vídeo que explicarlo en un artículo.

Me guardo para otro vídeo como instalar alguna alternativa como Nexus para tener nuestro propio registry.

Acceso a Google Cloud Platform(GCP) usando la imagen Docker con Cloud SDK

Para conectarnos al Kubernetes sobre GCP hemos optado por hacerlo usando una imagen de Docker que nos provee el mismo Google. Esta imagen incluye de serie cantidad de utilidades para interactuar con GCP y Kubernetes como son: gcloud(Herramienta CLI para interactuar con GCP), bq(Utilidad para interactuar con los servicios de ingeniería de datos de GCP), gsutils(para subir fichero a GCP), kubectl, Helm, etc.

Hemos arrancado el contenedor con el comando:

docker run –rm -it -v .:/poc google/cloud-sdk:latest

Este commando básicamente arranca el contenedor habilitando el modo interactivo(parámetros -it), montando la carpeta actual en la carpeta /poc(parámetro -v .:/poc) y haciendo que se autodestruya al salir del contenedor(parámetro –rm).

Una vez dentro nos hemos logueado en GCP y configurado el cliente de kubernetes(kubectl) para que use nuestro cluster:

# Login dentro de GCP
gcloud auth login

# Configuración de kubectl apuntando a nuestro cluster
gcloud container clusters get-credentials –zone “ZONA DEL CLUSTER” –project “PROYECTO DE GCP” “NOMBRE DEL CLUSTER”

Instalación de Gitlab sobre Kubernetes(GKE) sobre GCP

Para instalar Gitlab hemos usado el siguiente manifiesto de kubernetes(gitlab.yaml):

kind: Namespace
apiVersion: v1
metadata:
name: gitlab
labels:
name: gitlab-namespace

apiVersion: apps/v1
kind: Deployment
metadata:
name: gitlab-deployment
namespace: gitlab
labels:
app: gitlab
spec:
replicas: 1
selector:
matchLabels:
app: gitlab
template:
metadata:
labels:
app: gitlab
spec:
containers:
– name: gitlab
image: gitlab/gitlab-ce:16.7.5-ce.0
env:
– name: GITLAB_OMNIBUS_CONFIG
value: “external_url ‘http://gitlab-service'”
– name: GITLAB_ROOT_PASSWORD
value: “YoutubePlus!”
ports:
– containerPort: 80

apiVersion: v1
kind: Service
metadata:
namespace: gitlab
name: gitlab-service
spec:
type: LoadBalancer
selector:
app: gitlab
ports:
– protocol: TCP
port: 80
targetPort: 80

Hemos usado el siguiente comando para aplicarlo:

Kubectl apply -f gitlab.yaml

Instalación del Runner de Gitlab

Los Runners de Gitlab son los encargado de ejecutar las tareas de las pipelines de Gitlab CICD y los hay de muchos tipos(locales, amazon, Docker, etc). Nosotros hemos optado por instalar una de tipo kubernetes.

Los Runners se instalan a nivel de grupo, por lo que hemos necesitado primero crear un grupo de gitlab y una vez dentro, ir a la pestaña “CI / CD” y “Runners” para obtener el token necesario para instalarlo(Esto lo podríamos haber automatizado usando el API de Gitlab, por si ha alguien le interesa).

Ya con nuestro token(parámetro registration-token) hemos usado el siguiente manifiesto para instalar el runner(gitlab-runner.yaml):

apiVersion: v1
kind: ServiceAccount
metadata:
name: gitlab-service-account-sa
namespace: gitlab
labels:
app: native-app
imagePullSecrets:
– name: registry-credentials

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gitlab-service-account-cr
namespace: gitlab
labels:
app: native-app
rules:
– apiGroups:
– ”
– apps
– autoscaling
– batch
– build.openshift.io
– image.openshift.io
– route.openshift.io
resources:
– services
– pods
– pods/log
– pods/exec
– pods/attach
– namespaces
– replicationcontrollers
– daemonsets.apps
– deployments
– replicasets
– statefulsets
– horizontalpodautoscalers
– cronjobs
– jobs
– daemonsets
– buildconfigs
– builds
– imagestreams
– imagestreamtags
– buildconfigs/instantiatebinary
– routes
– secrets
verbs:
– create
– watch
– get
– list
– update
– patch
– delete
– deletecollection

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: gitlab-service-account-rbcr
namespace: gitlab
roleRef:
kind: ClusterRole
name: gitlab-service-account-cr
apiGroup: rbac.authorization.k8s.io
subjects:
– kind: ServiceAccount
name: gitlab-service-account-sa
namespace: gitlab

apiVersion: apps/v1
kind: Deployment
metadata:
name: runner-0
namespace: gitlab
spec:
selector:
matchLabels:
name: runner-pod-0
template:
metadata:
namespace: gitlab
labels:
name: runner-pod-0
spec:
serviceAccount: gitlab-service-account-sa
serviceAccountName: gitlab-service-account-sa
containers:
– name: pod
image: alpinelinux/gitlab-runner:latest
command:
– “/bin/sh”
– “-c”
– |
gitlab-runner register
–kubernetes-privileged true
–non-interactive
–run-untagged=false
–executor kubernetes
–kubernetes-pull-policy always
–request-concurrency 10
–name ‘My Runner’
–kubernetes-image alpine:latest
–kubernetes-image-pull-secrets registry-credentials
–kubernetes-namespace gitlab
–kubernetes-service-account gitlab-service-account-sa
–tag-list kubernetes
–url “http://gitlab-service/”
–registration-token “GR1348941zBB3FQSts6S282gMoNNC”

cat /etc/gitlab-runner/config.toml

gitlab-runner run

Hemos usado el siguiente comando para aplicarlo:

Kubectl apply -f gitlab-runner.yaml

Creación de nuestro primer repo y programación de nuestra api python

El siguiente paso ha sido crear nuestro repo de Gitlab y clonarlo(Con cuidado con la URL que te autogenera el Gitlab) usando el comando:

git clone http://URL DE NUESTRO REPO

Hemos añadido dos fichero con nuestra aplicación:

requirements.txt(Contiene las dependencias de nuestra aplicación Python)

fastapi>=0.68.0,<0.69.0
uvicorn>=0.15.0,<0.16.0

main.py(Contiene nuestra aplicación Python)

from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.get(“/”)
def root():
return {“msg”: “Hello World”}

uvicorn.run(app, host=”0.0.0.0″, port=8080)

Dockerfile para generar las imágenes Docker

En nuestro repo también hemos creado un fichero llamado “Dockerfile” que contiene las instrucciones para generar la imagen que vamos a desplegar en Kubernetes:

FROM python:3.9

RUN mkdir /code
WORKDIR /code

ADD requirements.txt /code/requirements.txt
ADD main.py /code/main.py

RUN pip install –no-cache-dir –upgrade -r /code/requirements.txt

CMD [“python”, “main.py”]

Chart Helm para el despliegue

También nos falta una carpeta llamada helm que va a contener todos los ficheros con nuestro chart para desplegar el repo:

/Helm/Chart.yaml (Fichero que describe nuestro chart)

name: my-super-app
version: 0.0.1
appVersion: “1.0”
description: Mi Super App

/helm/values.yaml(Valores o variables que configuran nuestro chart)

appname: test1
environment: dev
namespace: test1

image: test1

/helm/templates/deployment.yaml (Template Helm para configurar el despliegue)

apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ $.Values.appname }}-{{ $.Values.environment }}-deployment
namespace: {{ $.Values.namespace }}
spec:
selector:
matchLabels:
name: {{ $.Values.appname }}-{{ $.Values.environment }}-pod
template:
metadata:
namespace: {{ $.Values.namespace }}
labels:
name: {{ $.Values.appname }}-{{ $.Values.environment }}-pod
spec:
containers:
– name: pod
image: {{ $.Values.image }}
imagePullSecrets:
– name: regcred

/helm/templates/service.yaml (Template Helm para configurar el servicio)

apiVersion: v1
kind: Service
metadata:
name: {{ $.Values.appname }}-service
namespace: {{ $.Values.namespace }}
spec:
type: LoadBalancer
selector:
name: {{ $.Values.appname }}-{{ $.Values.environment }}-pod
ports:
– protocol: TCP
port: 8080
targetPort: 8080

Configurar el Pipeline de despliegue

Esto es quizás lo mas importante del vídeo, en Gitlab CICD, el pipeline de despliegue viene configurado en un fichero en el propio repo llamado “.gitlab-ci.yml”. En nuestro caso nos hemos configurado un pipeline con cuatro stages “version”, “tests”, “build image” y “deploy”:

variables:
KUBERNETES_NAMESPACE: test1
DOCKER_REGISTRY_HOST: https://index.docker.io/v1/
DOCKER_REGISTRY_USER: acoronadoc
DOCKER_REGISTRY_PASSWORD: dckr_pat_GegpqyANy7NViEmIDjNQATERUmM

default:
tags:
– kubernetes
image: alpine:latest

stages:
– version
– test
– build-image
– deploy

version:
stage: version
script:
– echo “VERSION=$(date +%Y%m%d%H%M%S%N)-$CI_COMMIT_BRANCH” >> build.env
artifacts:
reports:
dotenv: build.env

test:
stage: test
script:
– echo “Testing…”

buid-image:
stage: build-image
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [“”]
script:
– pwd
– ls
– mkdir -p /kaniko/.docker
– |
echo “{ “auths”: { “$DOCKER_REGISTRY_HOST”: { “auth”: “$(echo -n $DOCKER_REGISTRY_USER:$DOCKER_REGISTRY_PASSWORD | base64 -w0)” } } }” > /kaniko/.docker/config.json
– cat /kaniko/.docker/config.json
– /kaniko/executor –context $CI_PROJECT_DIR –dockerfile $CI_PROJECT_DIR/Dockerfile –destination=$DOCKER_REGISTRY_USER/$CI_PROJECT_NAME:$VERSION

deploy:
stage: deploy
script:
– apk add kubectl helm
– cd helm
– kubectl create namespace $KUBERNETES_NAMESPACE –dry-run=client -o yaml | kubectl apply -f –
– kubectl create secret docker-registry regcred -n $KUBERNETES_NAMESPACE –docker-server=$DOCKER_REGISTRY_HOST –docker-username=$DOCKER_REGISTRY_USER –docker-password=$DOCKER_REGISTRY_PASSWORD –dry-run=client -o yaml | kubectl apply -f –
– helm upgrade –install $CI_PROJECT_NAME . –set image=$DOCKER_REGISTRY_USER/$CI_PROJECT_NAME:$VERSION

Si lo analizáis bien veréis que tenemos un script por stage, en el vídeo los he comentado.

Subir código y ver como se despliega

Con todo ahora ya solo nos queda añadir todos los ficheros al repo(Cuidado porque el .gitlab-ci.yml se tiene que especificar al ser oculto), hacer el commit y hacer el push para ver los resultados:

git add *
git add .gitlab-ci.yml

git commit -m “Primer commit”

git push

Y el resto ya es historia 😀

Leave a Reply

Your email address will not be published. Required fields are marked *