MinIO proporciona almacenamiento de objetos compatible con AWS S3. Desde la última vez que revisé este producto, MinIO ha crecido hasta convertirse en una solución de calidad empresarial.

También han cambiado el logo, y por lo que veo, el “flamenco” o lo que sea el animal del logo ha quedado relegado al favicon y el footer de la página web…Yo mantendré por ahora el logo “antiguo” (que curiosamente, tiene al pájaro mirando hacia la izquierda ¯\_(ツ)_/¯)

En este artículo, voy a desplegarlo sobre Kubernetes de forma manual con un sólo servidor. Usaremos el almacenamiento en MinIO como destino de las copias de seguridad del clúster de Kubernetes usando Velero (en un próximo artículo).

La forma recomendada de desplegar MinIO en Kubernetes es a través de un operador o de una Helm Chart, como se describe en la documentación oficial: Deploy MinIO on Kubernetes. En mi caso lo despliego manualmente por aprender.

Siguiendo las buenas prácticas, creamos un Namespace para desplegar MinIO:

---
kind: Namespace
apiVersion: v1
metadata:
  name: minio

Como la finalidad de MinIO es la de proporcionar almacenamiento, definimos un Persistent Volume Claim (en este caso, usando la Storage Class por defecto en el clúster):

---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  namespace: minio
  name: minio-data
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi

En mi escenario, MinIO lo usaré para almacenar las copias de seguridad durante las pruebas con Velero, por eso defino un volumen de tamaño pequeño.

Con estos pre-requisitos mínimos, ya podemos definir el Deployment de MinIO:

---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: minio
  namespace: minio
spec:
  replicas: 1 
  selector:
    matchLabels:
      app: minio
  template:
    metadata:
      labels:
        app: minio
    spec:
      containers:
        - name: minio
          image: minio/minio
          command: ["minio"]
          args: ["server", "/data"]
          ports:
            - name: web-ui
              containerPort: 9000 
          volumeMounts:
            - name: minio-data
              mountPath: /data
      volumes:
        - name: minio-data
          persistentVolumeClaim:
            claimName: minio-data

Como no hemos especificado usuario y password, MinIO arranca con las credenciales por defecto: minioadmin (como usuario y password).

Para especificar credenciales personalizadas, hay que definir las variables de entorno MINIO_ROOT_USER y MINIO_ROOT_PASSWORD. Los valores de estas variables de entorno las obtendremos de un Secret.

Como los secretos en Kubernetes están ofuscados usando base64, uso kubectl create secret con la opción dry-run para generar el YAML de definición del Secret:

kubectl create secret generic minio-secret -n minio \
--from-literal=minio-root-user=ACCESSKEYEXAMPLE123 \
--from-literal=minio-root-password=wdvb5rtghn76yujm -o yaml --dry-run=client | tee minio-secret.yaml

Esto genera el YAML con los valores ya ofuscados (y evita errores):

---
apiVersion: v1
data:
  minio-root-password: d2R2YjVydGdobjc2eXVqbQ==
  minio-root-user: QUNDRVNTS0VZRVhBTVBMRTEyMw==
kind: Secret
metadata:
 name: minio-secret
 namespace: minio
type: Opaque

Actualizamos la definición del Deployment para que MinIO use las variables de entorno con las credenciales personalizadas (en spec.containers.env):

...
env:
  - name: MINIO_ROOT_USER
    valueFrom:
      secretKeyRef: 
        name: minio-secret
        key: minio-root-user
  - name: MINIO_ROOT_PASSWORD
    valueFrom:
      secretKeyRef:
        name: minio-secret
        key: minio-root-password
...

Finalmente, exponemos MinIO a través de un servicio.

En el escenario de usar MinIO como backend para las copias de seguridad de Velero, quizás tiene más sentido que el servicio sea de tipo ClusterIP, pero para validar que todo funciona como debe, uso NodePort para tener acceso sencillo a la interfaz web de MinIO.

--- 
kind: Service
apiVersion: v1
metadata:
  namespace: minio
  name: minio
spec:
  type: NodePort
  selector:
    app: minio
  ports:
    - name: web-ui
      protocol: TCP
      port: 9000

Tras desplegar el servicio, revisa qué puerto ha asignado Kubernetes a MinIO con:

$ kubectl get svc -n minio
NAME    TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
minio   NodePort   10.43.117.250   <none>        9000:30712/TCP   35h

Accede a la interfaz web de MinIO a través del puerto asignado (en mi caso, 30712) y accede con las credenciales especificadas en el Secret.


Versiones usadas en este artículo:

  • Minio: 2021-03-26T00:00:41Z (linux/amd64)
  • Kubernetes:
    • Client Version: v1.20.5
    • Server Version: v1.20.4+k3s1