Por fin empezamos con algo aplicable al día a día. Hoy vamos a desplegar una aplicación(o aplicaciones) en dos replicas y vamos a entrar a un único end-point, con lo que el sistema se encargará de dirigirnos a la replica libre. Vamos a usar el ejemplo de MEAN + Kubernetes que viene en la web de Kubernetes.
$ git clone https://github.com/ijason/NodeJS-Sample-App.git app $ mv app/EmployeeDB/* app/ $ sed -i — ‘s/localhost/mongo/g’ ./app/app.js
Con esto hemos clonado la aplicación y cambiado el host de MongoDb a mongo, que es donde estamos sirviendo nuestra mongoDB en el clúster.
Ahora debemos construir la aplicación, más exactamente, construir un docker con nuestra aplicación:
FROM hypriot/rpi-node:latest RUN mkdir -p /usr/src/app WORKDIR /usr/src/app COPY ./app/ ./ RUN npm install CMD ["node", "app.js"]
Aquí nos separamos del ejemplo de la web oficial, puesto que la imagen de NodeJS , no la podemos obtener de la imagen oficial, puesto que no esta compilada para procesadores ARM. Buscamos la rpi-node compilada para Raspeberry Pi.
Ahora es momento de construir el contenedor:
$ docker build -t royoruiz/app .
Como la estamos construyendo en el nodo master, si hacemos:
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE royoruiz/app latest 6de3a87e6030 4 days ago 443.7 MB kubernetesonarm/kube2sky 0.7.0 3d072f0b5927 6 days ago 21.33 MB kubernetesonarm/kube2sky latest 3d072f0b5927 6 days ago 21.33 MB kubernetesonarm/skydns 0.7.0 d04b6e5f5d28 6 days ago 10.69 MB kubernetesonarm/skydns latest d04b6e5f5d28 6 days ago 10.69 MB kubernetesonarm/etcd 0.7.0 ee60556c23ea 6 days ago 30.01 MB kubernetesonarm/etcd latest ee60556c23ea 6 days ago 30.01 MB kubernetesonarm/pause 0.7.0 069bbbda844d 6 days ago 247.4 kB kubernetesonarm/pause latest 069bbbda844d 6 days ago 247.4 kB kubernetesonarm/hyperkube 0.7.0 59dcac1ac2b9 6 days ago 164.4 MB kubernetesonarm/hyperkube latest 59dcac1ac2b9 6 days ago 164.4 MB kubernetesonarm/flannel 0.7.0 b17272d53005 6 days ago 23.36 MB kubernetesonarm/flannel latest b17272d53005 6 days ago 23.36 MB luxas/alpine 0.7.0 61798fc5237e 6 days ago 7.707 MB luxas/alpine latest 61798fc5237e 6 days ago 7.707 MB kubernetesonarm/build 0.7.0 f92e2d94fbcd 6 days ago 1.188 GB kubernetesonarm/build latest f92e2d94fbcd 6 days ago 1.188 GB luxas/go 0.7.0 98973d1ab768 6 days ago 376.6 MB luxas/go latest 98973d1ab768 6 days ago 376.6 MB resin/rpi-raspbian jessie 33a11ff83d4f 11 days ago 80.01 MB hypriot/rpi-node latest 43db5ff75509 2 weeks ago 439 MB kubernetesonarm/grafana latest 8ea26f4ef5a3 10 weeks ago 162.4 MB kubernetesonarm/influxdb latest 447951a687c6 10 weeks ago 18.38 MB kubernetesonarm/heapster latest 1d034674fc0e 10 weeks ago 39.51 MB kubernetesonarm/loadbalancer latest 6b262f2fd318 10 weeks ago 34.75 MB kubernetesonarm/registry latest 4c9c964f89e9 10 weeks ago 21.34 MB hypriot/rpi-swarm latest c298de062190 12 weeks ago 13.27 MB mangoraft/mongodb-arm latest 9ec67fdd9b31 5 months ago 822 MB
Pero debemos moverla al registro local para poder acceder desde el deployment de la aplicación.
Primero debemos taggear nuestra imagen:
$ docker tag royoruiz/app:latest registry.kube-system:5000/royoruiz/app:latest
Para ahora, realizar un push hacia el registro:
$ docker push registry.kube-system:5000/royoruiz/app:latest
Algunos comandos útiles para saber si todo ha ido bien:
$ curl -v -X GET http://registry.kube-system:5000/v2/_catalog * Hostname was NOT found in DNS cache * Trying 10.0.0.20... * Connected to registry.kube-system (10.0.0.20) port 5000 (#0) > GET /v2/_catalog HTTP/1.1 > User-Agent: curl/7.38.0 > Host: registry.kube-system:5000 > Accept: */* > < HTTP/1.1 200 OK < Content-Type: application/json; charset=utf-8 < Docker-Distribution-Api-Version: registry/2.0 < Date: Sun, 29 May 2016 18:38:00 GMT < Content-Length: 51 < {"repositories":["royoruiz/app","royoruiz/myapp"]} * Connection #0 to host registry.kube-system left intact
O este otro:
$ curl -v -X GET http://registry.kube-system:5000/v2/royoruiz/app/tags/list * Hostname was NOT found in DNS cache * Trying 10.0.0.20... * Connected to registry.kube-system (10.0.0.20) port 5000 (#0) > GET /v2/royoruiz/app/tags/list HTTP/1.1 > User-Agent: curl/7.38.0 > Host: registry.kube-system:5000 > Accept: */* > < HTTP/1.1 200 OK < Content-Type: application/json; charset=utf-8 < Docker-Distribution-Api-Version: registry/2.0 < Date: Sun, 29 May 2016 18:39:17 GMT < Content-Length: 42 < {"name":"royoruiz/app","tags":["latest"]} * Connection #0 to host registry.kube-system left intact
Es curioso que para que funcione el deployment en lugar del DNS se debe poner la IP interna del cluster:
$ kubectl --namespace=kube-system get svc -o wide NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR heapster 10.0.0.251 <none> 80/TCP 5d k8s-app=heapster kube-dns 10.0.0.10 <none> 53/UDP,53/TCP 1d k8s-app=kube-dns kubernetes-dashboard 10.0.0.110 <none> 80/TCP 5d k8s-app=kubernetes-dashboard monitoring-grafana 10.0.0.178 <none> 80/TCP 5d name=influxGrafana monitoring-influxdb 10.0.0.67 <none> 8083/TCP,8086/TCP 5d name=influxGrafana registry 10.0.0.20 <none> 5000/TCP 2d k8s-app=registry
Lo podéis ver en el web-controller.yml:
apiVersion: v1 kind: ReplicationController metadata: labels: name: web name: web-controller spec: replicas: 2 template: metadata: labels: name: web spec: containers: - image: 10.0.0.20:5000/royoruiz/app:latest name: web ports: - containerPort: 3000 name: http-server
En la imagen, ponemos la ip interna del nodo asignado al registry.
Debemos poner un servicio para asociar ese RC con un nombre:
apiVersion: v1 kind: Service metadata: name: web labels: name: web spec: type: LoadBalancer ports: - port: 80 targetPort: 3000 protocol: TCP selector: name: web
Hacemos deploy de los dos, primero el controller y luego el servicio y esperamos que se levanten los pods requeridos.
Para ver nuestras aplicaciones, vamos al panel de control y observamos el external point que nos ha dado:
En un navegador, vamos a http://ip_master:32639/ :
Como alternativa, podemos subir la imagen a un registro público como DockerHub de nuestras aplicaciones y evitar problemas con registry, que ciertamente ha sido complicado de manejar.
En la siguiente entrada, como hacer actualizaciones de la aplicación sin perder servicio y de forma automática.
¿Qué os ha parecido?