# Multiarch building con tekton
---
## Multiarchitectura
---
## ¿Por qué multiarquitectura?
Porque ARM se está haciendo cada vez más popular
Raspberry con armv7 y armv8
Apple con M1 y M2
**AWS** lanzó tres generaciones de **graviton**
Todos los grandes cloud providers están publicando sus instancias ARM
---
Porque x86 tiene una base de mercado enorme
y además tenemos powerpc y [RISC-V](https://www.theregister.com/2022/10/05/china_riscvv_arm_datacenter/) ... ya podemos correr [ubuntu en starfive](https://canonical.com/blog/canonical-enables-ubuntu-on-starfive-visionfive2-risc-v-board)
---
## ¿Como se traduce eso hoy?
ARM nos permite bajar costos.
además en el caso de [Graviton](https://aws.amazon.com/es/ec2/graviton/), tenemos algunas ventajas en seguridad:
- cifrado de memoria
- caches dedicados para cada vCPU
- autenticación de punteros
- mejoras en el cifrado de volúmenes
ARM esta ampliamente soportada por muchas distribuciones Linux.
Peeeero, no todas las imágenes que usamos están compiladas para las arquitecturas que queremos.
---
## Entonces, a buildear
Construir nuestras imágenes puede implicar:
- realizar el build en arquitectura nativa
- usar un stage especial en Dockerfile que haga [cross-compile](https://www.docker.com/blog/faster-multi-platform-builds-dockerfile-cross-compilation-guide/)
- usar QEMU
[Docker tiene un buildkit que ya soporta multiarch](https://docs.docker.com/build/building/multi-platform/)
---
En particular elegí buildah porque prefiero que mis contenedores no dependan de una empresa en concreto, había probado [podman](https://podman.io/) (que comparte código con buildah) luego de que en [twitter me comentaron que había evolucionado mucho](https://twitter.com/pulpox/status/1316957164045553664), y tenían razón.

Tambien en esa fecha el cambio de manos de docker no me dejó del todo tranquilo.
---
## Buildah

No es mas que una tool que facilita la construcción de containers [OCI](https://opencontainers.org/)
No necesita un daemon corriendo, puede armar un contenedor desde cero (scratch) o bien desde un Dockerfile.
```bash
❯ buildah from alpine
alpine-working-container-1
```
[Podemos pegarle una mirada al quickstart](https://developers.redhat.com/blog/2021/01/11/getting-started-with-buildah#building_a_container)
---
Si necesito ejecutar un comando
```bash
❯ buildah run alpine-working-container-1 cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.18.0
PRETTY_NAME="Alpine Linux v3.18"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
```
Tengo muchos comandos disponibles con los cuales puedo modificar una imagen, la forma más cómoda y a la que estamos acostumbrados es mediante un Dockerfile
```
FROM alpine:latest
CMD echo "hola"
```
---
Y para buildearla
```bash
❯ buildah bud -f Dockerfile -t prueba
STEP 1/2: FROM alpine:latest
STEP 2/2: CMD echo "hola"
COMMIT prueba
Getting image source signatures
Copying blob bb01bd7e32b5 skipped: already exists
Copying blob 5f70bf18a086 done
Copying config e6633c211d done
Writing manifest to image destination
Storing signatures
--> e6633c211dff
Successfully tagged localhost/prueba:latest
e6633c211dff7216a43d3df9782ad5e843ca4b3ecf300284782945899b0682aa
```
bud = build-using-dockerfile
---
Luego para ejecutar, usando podman por ejemplo
```bash
❯ podman run --rm prueba
hola
```
---
Sí, si haces un alias de podman a docker usás los mismos comandos, con algunas ventajas al usar podman:
- deamonless
- seguro ([con rootleess containers no comprometemos seguridad por funcionalidad](https://blog.podman.io/2023/05/rootless-podman-user-namespaces-in-plain-english/))
Y como docker:
- opensource
- compatible con OCI
---
Y respecto al multiarch... los resultados en internet al respecto son una pesadilla, después de algo de prueba y error, la forma más concisa de alcanzarlo hoy es...
---
- crear un manifest con algo como `buildah manifest create multiarchmanifest`
- pasar el manifest al comando de build `buildah bud --manifest multiarchmanifest ...`
- también pasarle como argumentos al build las plataformas a buildear junto con la arquitectura `--jobs 3 --platform linux/arm,linux/arm64,linux/amd64`
- al realizar el push, pasarle un parámetro `--all` para que suba todas las imágenes referenciadas en el manifest
---
Hacemos una prueba ...
```bash
❯ buildah manifest create multiarchmanifest
1492c93e2d0cd4247fef281a19863c03fb39415ef0ce6fceb67b5a52aec1e588
```
---
```bash
❯ buildah bud -f Dockerfile --manifest multiarchmanifest --jobs 3 --platform linux/arm,linux/arm64,linux/amd64
[linux/amd64] STEP 1/2: FROM alpine:latest
[linux/arm64] STEP 1/2: FROM alpine:latest
[linux/arm/v7] STEP 1/2: FROM alpine:latest
Resolved "alpine" as an alias (/etc/containers/registries.conf.d/00-shortnames.conf)
Trying to pull docker.io/library/alpine:latest...
Resolved "alpine" as an alias (/etc/containers/registries.conf.d/00-shortnames.conf)
Trying to pull docker.io/library/alpine:latest...
[linux/amd64] STEP 2/2: CMD echo "hola"
[linux/amd64] COMMIT
Getting image source signatures
Copying blob bb01bd7e32b5 skipped: already exists
Copying blob 5f70bf18a086 skipped: already exists
Copying config b50effc8ed done
Writing manifest to image destination
Storing signatures
--> b50effc8ed11
b50effc8ed111c1a89b8fda158e1bb42cd842ec870dcd07bda892c764cb43bc5
Getting image source signatures
Getting image source signatures
Copying blob e14425cf8fb9 [--------------------------------------] 0.0b / 2.8MiB (skipped: 0.0b = 0.00%)
Copying blob e14425cf8fb9 done
Copying config d5aad8e3ba done
Writing manifest to image destination
Storing signatures
[linux/arm/v7] STEP 2/2: CMD echo "hola"
[linux/arm/v7] COMMIT
Getting image source signatures
Copying blob f27c3a1f7c02 skipped: already exists
Copying blob 5f70bf18a086 skipped: already exists
Copying config c4faaf96cc done
Writing manifest to image destination
Storing signatures
--> c4faaf96cc07
Copying blob 08409d417260 done
Copying config 44dd6f2230 done
Writing manifest to image destination
Storing signatures
[linux/arm64] STEP 2/2: CMD echo "hola"
[linux/arm64] COMMIT
Getting image source signatures
Copying blob 94dd7d531fa5 skipped: already exists
Copying blob 5f70bf18a086 skipped: already exists
Copying config 6c572ee3b5 done
Writing manifest to image destination
Storing signatures
--> 6c572ee3b5fb
6c572ee3b5fbf2c6686553aa5be1055776189f784fb8116521485c6c03a7f3b7
```
---
Inspecionamos el manifest
```bash
❯ buildah manifest inspect multiarchmanifest
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 750,
"digest": "sha256:9654098360c19a2ecb756a796606b4a5027d0b581cc2fb698d6195f8110e214a",
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 750,
"digest": "sha256:589da5a6a1d09ebe7699653012d48f03e68974819afc41ead88b396aaf0f60f1",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v7"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 750,
"digest": "sha256:1b0bc937f834fecdf44fdd954a898166801e787eef5bb128874d04c2257f077f",
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
}
}
]
}
```
---
Ok, hasta acá todo genial, veamos como meterlo en un CI/CD, cloud native style :octopus: :cloud:
---

---
# Nope!
dije... cloud native style...
---
## [Tekton](https://tekton.dev/)

Es un framework opensource para crear sistemas de CI/CD.
- Está disponible como [CRD](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions) (Kubernetes Custom Resource Definition)
- Se puede instalar en cualquier cluster Kubernetes
- Usa imágenes de contenedores para realizar las operaciones en nuestro pipeline de CI/CD
---
Veamos entonces algunos conceptos básicos...
---
### Steps:

La unidad más pequeña, es un contenedor que toma un **input** y produce un **ouput**
```yaml
steps:
- name: decir-hola
image: ubuntu
env:
- name: SALUDO
value: "Hola mundo"
script: |
echo ${SALUDO}
```
---
### Task

Es una secuencia de **steps** ejecutando una secuencia de **contenedores**. En kubernetes crea un **pod**.
Todos los steps en una tarea tienen acceso a un workspace compartido.
Es un [CR](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) (Custom Resource) de tipo Task.
---
Tiene un nombre para poder referenciarla y reutilizarla
```yaml
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: hola
spec:
params:
- name: saludo
default: Hola mundo
steps:
- name: decir-hola
image: ubuntu
script: |
echo $(params.saludo)
```
Tambien una lista de parametros con su nombre, descripciones y/o valores por defecto. A su vez tiene una lista de **steps**.
---
### TaskRun
Es el recurso que ejecuta una **Task**, acá es donde se proveen los parámetros y cualquier otro recurso que necesite una **Task**.
```yaml
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
generateName: saludador-
spec:
params:
- name: saludo
value: Todo bien gente?
taskRef:
- name: hola
```
[Recomiendo mirar el getting started](https://tekton.dev/docs/getting-started/)
---
### Tekton Pipeline
Las **tasks** comparten recursos mediante **results** y mediante **workspace**

- **results**: cuando la cantidad de datos a compartir es poca
- **workspace**: en caso contrario (crea un PVC en kubernetes)
---
```yaml
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: project-pipeline
spec:
params:
- name: api-url
- name: cloud-region
tasks:
- name: clone
taskRef:
name: git-clone
- name: build
taskRef:
name: build
runAfter:
- clone
- name: publish
taskRef:
name: publish
runAfter:
- build
```
---
Los pipelines se ejecutan usando un **PipelineRun** con los parámetros y recursos que necesite el **Pipeline**
```yaml
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: project-pipeline-run-
spec:
params:
- name: api-url
value: demo.com
- name: cloud-region
value: us-east-1
pipelineRef:
- name: project-pipeline
```
---
### Tekton Catalog

En https://hub.tekton.dev/ podemos encontrar un repositorio de tasks y pipelines reutilizables.
---
Entonces, vamos a instalar tekton en nuestro cluster kubernetes
```
kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
```
---
Luego vamos a buscar algún recurso de [buildah en el hub](https://hub.tekton.dev/?query=buildah)
---
Creamos una task propia con algunas modifaciones
```
kubectl apply -f https://gist.githubusercontent.com/pulpo/fa0a34e717de398754530917c8a274ae/raw/cf9231cb302030e6d9302c314bd7a233c7eddb9e/custombuildah.yaml
```
---
Adicionalmente agregamos otras task que vamos a necesitar, la de git-clone:
```
kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/git-clone/0.9/git-clone.yaml
```
Y luego estamos en condiciones de crear un pipelinerun
---
Como lo va a manejar kubernetes

---
Qué más hay para leer y probar?
- https://aws.amazon.com/es/blogs/aws-spanish/ejecucion-de-contenedores-multiarquitectura-con-amazon-eks/
- https://aws.amazon.com/es/blogs/containers/cloud-native-ci-cd-with-tekton-and-argocd-on-aws/
- https://aws.amazon.com/es/blogs/aws-spanish/comparando-el-desempeno-de-las-instancias-amazon-ec2-aws-graviton2-intel-x64-y-amd-epyc/
---
Preguntas?
---
### Bonus track: Ñamandú

```
kubectl apply -f https://gist.githubusercontent.com/pulpo/e5ea055c03786c0dc55e0847630a70dc/raw/e6ae77fe5c82f6923070b3ccae0a4741a6763988/namandu.yaml
```
---
{"title":"Multiarch building con tekton","author":"pulpo","type":"slide","slideOptions":{"theme":"sky","transition":"zoom"}}