Documentation

Testing kubernetes containers in local

Testear tu plataforma siempre es una tarea difícil y más cuando se debe de realizar en un servidor remoto, kubernetes no es la excepción así que deseamos validar nuestro sistema deberemos conectarnos al cluster y desde allí iniciar nuestros contenedores.

Como ya sabemos también hay costes añadidos, ya que por cada container que tengamos corriendo Google Cloud ira incrementando nuestra factura final. La solución es minikube, esta herramienta es capaz de emular nuestra configuración en un entorno local, y así podemos comprobar si todo funciona como esperamos.

Primeros pasos:

Instalar minikube

brew cask install minikube

Si todo es correcto necesitaremos inicial minikube con minikube start pero mejor si añadimos la opción -p para indicar el nombre de nuestro entorno de desarrollo.

$ minikube start -p gara-quant                                                                                                                   system: ruby 2.3.7p456
😄  minikube v1.2.0 on darwin (amd64)
🏃  Re-using the currently running virtualbox VM for "gara-quant" ...
⌛  Waiting for SSH access ...
🐳  Configuring environment for Kubernetes v1.15.0 on Docker 18.09.6
🔄  Relaunching Kubernetes v1.15.0 using kubeadm ...
⌛  Verifying: apiserver proxy etcd scheduler controller dns
🏄  Done! kubectl is now configured to use "gara-quant"
(base)

Una vez ejecutado este comando estaremos dentro de nuestro entorno aunque inicialmente de la sensación es de que nada ha pasado, ejecuta kubectl get nodes

$ kubectl get nodes                                                
NAME       STATUS   ROLES    AGE   VERSION
minikube   Ready    master   25m   v1.15.0

El paso siguiente seria crear nuestra configuración. Tenemos varias formas de hacerlo, la más sencilla y teniendo en cuenta que en este punto del tutorial ya sabemos como funciona ´Docker´ vamos a crear un sencillo ´docker-compose.yml´, en este caso con una sencilla instancia de postgres:

version: '3.3'
services:
  db:
    image: postgres
    restart: always
    environment:
      POSTGRES_PASSWORD: password

Obviamente docker-compose no funcionara dentro de kubernetes, pero Google Cloud ha desarrollado otro comando kompose que es capaz de traducir nuestro fichero en los necesarios ficheros para crear este contenedor. Para ello necesitamos primero instalar kompose :

brew install kompose

Una vez instalado, ejecutaremos:

$ kompose convert -f docker-componse.yml     
INFO Kubernetes file "db-deployment.yaml" created

Si abrimos db-deployment.yaml veremos que tenemos todas las configuraciones necesarias:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    kompose.cmd: kompose convert -f docker-componse.yml
    kompose.version: 1.17.0 (a74acad)
  creationTimestamp: null
  labels:
    io.kompose.service: db
  name: db
spec:
  replicas: 1
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        io.kompose.service: db
    spec:
      containers:
      - env:
        - name: POSTGRES_PASSWORD
          value: password
        image: postgres
        name: db
        resources: {}
      restartPolicy: Always
status: {}

Ahora tan solo tendríamos que levantar nuestro servicio:

$ kubectl apply -f db-deployment.yaml        
deployment.extensions/db created

Y veríamos la lista de nuestros servicios con:

$ kubectl apply -f db-deployment.yaml    
deployment.extensions/db configured

Después de esto ya tendremos nuestro servicio corriendo en nuestra máquina local.

$ kubectl get pods         
NAME                         READY   STATUS             RESTARTS   AGE
db-5dd999bdbd-6fnsd          1/1     Running            0          9m56s

Siguientes pasos:

Vamos a complicar más nuestra configuración y crear tres servicios, dos de ellos serán imágenes customizadas para React y otra más para nuestro backend en Java spring:

React

Primero creamos nuestro Dockerfile:

FROM node:12.5.0 as react-build

ARG REACT_APP_API_HOST
ARG PORT
ENV REACT_APP_API_HOST ${REACT_APP_API_HOST}
ENV PORT ${PORT}

WORKDIR /usr/src/app
RUN rm -rf .node_modules package-lock.json yarn.lock
RUN npm install -g serve
COPY ./ ./

RUN npm install

EXPOSE ${PORT}

RUN chmod +x /usr/src/app/run.sh

CMD ["/usr/src/app/run.sh"]

Creamos la image

docker build -t gara-quant-ui .
docker tag {image-hash} gara-quant-ui:0.0.1

Docker-compose:

version: '3.3'
services:
ferris-ui-login:
container_name: ferris-ui-login
image: gara-quant-ui:0.0.1
environment:
- REACT_APP_API_HOST=http://localhost:8088
- PORT=80
volumes:
- ./public/config.json:/usr/share/nginx/html/config.json
ports:
- "80:80"

Antes de crear nuestras images deberos ejecutar minikube docker-env -p gara-quant este comando hará que docker kubernetes busque primero en nuestro local host, de esta forma no tendremos que realizar docker push ${registry+image+name} cada vez que realizamos docker build -t ${image+name} .

$ minikube docker-env -p gara-quant
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.103:2376"
export DOCKER_CERT_PATH="/Users/ruben.fanjul/.minikube/certs"

Para cada terminal donde deseemos trabajar ejecutaremos eval $(minikube docker-env -p gara-quant) lo que hará que se carguen todas las configuraciones necesarias para Docker, como por ejemplo encontrar las imágenes.

minikube tunnel -p gara-quant ya que estamos en local todos los Pods que haga referencia a type: LoadBalancer estarán esperando por la asignación de una nueva IP por medio del servidor DNS. Este servidor DNS no existe en nuestra maquina local por lo que si ejecutamos kubectl get services veríamos:

$ minikube tunnel -p gara-quant     
Password:
Status:
machine: gara-quant
pid: 6464
route: 10.96.0.0/12 -> 192.168.99.103
minikube: Running
services: [ferris-ui-login]
errors:
minikube: no errors
router: no errors
loadbalancer emulator: no errors

Y si ahora volvemos a hacer kubectl get services veremos que ya tenemos EXTERNAL-IP

$ kubectl get services              
NAME              TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
ferris-ui         ClusterIP      10.99.244.192   <none>          80/TCP         10m
ferris-ui-login   LoadBalancer   10.97.168.184   10.97.168.184   80:30902/TCP   103s