{"id":2871,"date":"2019-01-09T17:06:38","date_gmt":"2019-01-09T21:06:38","guid":{"rendered":"http:\/\/arielantigua.com\/weblog\/?p=2871"},"modified":"2021-02-19T14:09:26","modified_gmt":"2021-02-19T18:09:26","slug":"kubernetes-en-premisa-con-metallb-en-modo-bgp","status":"publish","type":"post","link":"https:\/\/arielantigua.com\/weblog\/2019\/01\/kubernetes-en-premisa-con-metallb-en-modo-bgp\/","title":{"rendered":"Kubernetes en premisa con MetalLB en modo BGP."},"content":{"rendered":"<p>Kubernetes en premisa con MetalLB en modo BGP.<\/p>\n<p>Una de las desventajas de tener un <em>cluster<\/em> de <em>k8s<\/em> en premisa es la falta de <strong><em>LoadBalancer<\/em><\/strong>. Gracias a MetalLB esto est\u00e1 resuelto de una manera f\u00e1cil y elegante.<\/p>\n<p>Cuando queremos publicar servicios en k8s, lo hacemos usando un <em>Ingress Controller<\/em> (<strong>nginx<\/strong> o <strong>Traefik<\/strong> por nombrar algunos). Este servicio se apoya de las direcciones IP de los hosts si no tenemos LoadBalancer. El tema se complica cuando queremos publicar servicios que no son HTTP o HTTPS, s\u00e9 que <em>nginx<\/em> puede publicar otros protocolos. La ventaja de un IP via LoadBalancer es que podemos usarlos en varios servicios (pods) y publicar cualquier puerto en TCP o UDP.<\/p>\n<p>MetalLB<\/p>\n<p>Los requerimientos son los siguientes:<\/p>\n<ul>\n<li>Un cluster de k8s en la versi\u00f3n 1.9.0 o m\u00e1s reciente y que no tenga un tipo de LoadBalancer en funcionamiento, esto quiere decir que tendr\u00edamos problemas usando esta soluci\u00f3n en GKE por ejemplo.<\/li>\n<li>Una configuraci\u00f3n de cluster que pueda coexistir con MetalLB <a href=\"https:\/\/metallb.universe.tf\/installation\/network-addons\/\">https:\/\/metallb.universe.tf\/installation\/network-addons\/<\/a><\/li>\n<li>Direcciones IPv4 para asignar usando este servicio.<\/li>\n<li>Dependiendo del modo operativo, podr\u00edamos necesitar un router que soporte BGP.<\/li>\n<li><a href=\"https:\/\/metallb.universe.tf\/#requirements\">https:\/\/metallb.universe.tf\/#requirements<\/a><\/li>\n<\/ul>\n<p>En mis primeras pruebas, MetalLB fue configurado usando Layer2 (capa 2), es la forma m\u00e1s r\u00e1pida de probar esta soluci\u00f3n, despu\u00e9s de varios d\u00edas de desplegar aplicaciones que hac\u00edan uso de LoadBalancer me di cuenta de que algunas direcciones IP de momento no respond\u00edan a las peticiones ARP que son necesarias para alcanzar dicha direcci\u00f3n IP. Por esta raz\u00f3n ahora desplegare MetalLB usando BGP.<\/p>\n<ul>\n<li>En Layer2 <a href=\"https:\/\/metallb.universe.tf\/configuration\/#layer-2-configuration\">https:\/\/metallb.universe.tf\/configuration\/#layer-2-configuration<\/a><\/li>\n<\/ul>\n<p>En modo BGP, la configuraci\u00f3n es m\u00e1s extensa y cuanta con campos que tendr\u00e1n sentido si se ha usado BGP anteriormente.<\/p>\n<p>En mi caso, ya tengo algo de experiencia usando este protocolo y por eso decid\u00ed cambiar de Layer2 a BGP en lugar de buscar una soluci\u00f3n al problema descrito anteriormente. Adem\u00e1s, mi router de core soporte BGP.<\/p>\n<p><strong>Configuraci\u00f3n en Mikrotik RouterOS.<\/strong><\/p>\n<p>Debemos preparar el router (o en su defecto un Switch con L3 &amp; BGP) para aceptar sesiones BGP desde los nodos de k8s, MetalLB ejecutara un agente en todos los nodos de k8s y estos iniciaran una sesi\u00f3n BGP con nuestro router.<\/p>\n<p><strong>Configuraci\u00f3n b\u00e1sica en RouterOS &#8211; CLI:<\/strong><\/p>\n<pre>\/routing bgp instance\nset default as=64635 redistribute-connected=yes redistribute-static=yes router-id=10.45.254.2\n\/routing bgp peer\nadd multihop=no name=kube1 remote-address=172.22.35.25 remote-as=64636 ttl=default\nadd multihop=no name=kube2 remote-address=172.22.35.26 remote-as=64636 ttl=default\nadd multihop=no name=kube3 remote-address=172.22.35.27 remote-as=64636 ttl=default<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Instalando MetalLB.<\/strong><\/p>\n<p>kubectl apply -f <a href=\"https:\/\/raw.githubusercontent.com\/google\/metallb\/v0.7.3\/manifests\/metallb.yaml\">https:\/\/raw.githubusercontent.com\/google\/metallb\/v0.7.3\/manifests\/metallb.yaml<\/a><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1172\" height=\"271\" class=\"wp-image-2872\" src=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-4.png\" srcset=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-4.png 1172w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-4-300x69.png 300w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-4-768x178.png 768w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-4-1024x237.png 1024w\" sizes=\"auto, (max-width: 1172px) 100vw, 1172px\" \/><\/p>\n<p>Tambi\u00e9n se puede instalar usando Helm, para m\u00e1s informaci\u00f3n: <a href=\"https:\/\/metallb.universe.tf\/installation\/\">https:\/\/metallb.universe.tf\/installation\/<\/a><\/p>\n<p>Revisamos nuestro entorno k8s para validar que tenemos los componentes de MetalLB en un correcto estado.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1011\" height=\"323\" class=\"wp-image-2873\" src=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-5.png\" srcset=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-5.png 1011w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-5-300x96.png 300w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-5-768x245.png 768w\" sizes=\"auto, (max-width: 1011px) 100vw, 1011px\" \/><\/p>\n<p>\u00a1Excelente! Tenemos tres speaker, uno en cada nodo.<\/p>\n<p><strong>Configurando MetalLB.<\/strong><\/p>\n<p>Necesitamos un <em>kind<\/em> tipo <em>ConfigMap<\/em> para aplicar la configuraci\u00f3n deseada a MetalLB.<\/p>\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\n\napiVersion: v1\n\nkind: ConfigMap\n\nmetadata:\n\nnamespace: metallb-system\n\nname: config\n\ndata: config: |\n\npeers:\n\n- peer-address: 172.22.35.1\n\npeer-asn: 64635\n\nmy-asn: 64636\n\naddress-pools:\n\n- name: default\n\nprotocol: bgp\n\naddresses:\n\n- 172.22.35.64\/26\n\nbgp-advertisements:\n\n- aggregation-length: 32\n\nlocalpref: 100\n\ncommunities:\n\n- name: public\n\nprotocol: bgp\n\naddresses:\n\n- 200.1.154.64\/26\n\nauto-assign: false\n\nbgp-advertisements:\n\n- aggregation-length: 32\n\nlocalpref: 100\n\ncommunities:\n\n<\/pre>\n<p>Aplicamos el configMap:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"671\" height=\"63\" class=\"wp-image-2874\" src=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-6.png\" srcset=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-6.png 671w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-6-300x28.png 300w\" sizes=\"auto, (max-width: 671px) 100vw, 671px\" \/><\/p>\n<p>Si todos nuestros par\u00e1metros son correctos, revisamos en el core router y debemos tener las sesiones BGP establecidas.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"881\" height=\"166\" class=\"wp-image-2875\" src=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-7.png\" srcset=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-7.png 881w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-7-300x57.png 300w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-7-768x145.png 768w\" sizes=\"auto, (max-width: 881px) 100vw, 881px\" \/><\/p>\n<p><strong>\u00bfQu\u00e9 tenemos?<\/strong><\/p>\n<p>En este punto deberemos contar con la opci\u00f3n de seleccionar una direcci\u00f3n IP, en mi caso podr\u00eda ser del pool llamado default o del pool llamado public, se puede diferenciar que las IP del pool llamado public son ruteables y existen en la tabla de Internet (200.1.154.0\/24).<\/p>\n<p>Vamos a inicializar un <em>pod<\/em> que haga uso de una direcci\u00f3n del pool default. Para esto usare un contenedor con un servicio de SMTP el cual no necesita almacenamiento.<\/p>\n<p><strong>Deployment + Service<\/strong><\/p>\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\napiVersion: extensions\/v1beta1\nkind: Deployment\nmetadata:\nlabels:\napp: smtp\nname: smtp\nspec:\nprogressDeadlineSeconds: 600\nreplicas: 1\nrevisionHistoryLimit: 10\nselector:\nmatchLabels:\napp: smtp\nstrategy:\nrollingUpdate:\nmaxSurge: 1\nmaxUnavailable: 1\ntype: RollingUpdate\ntemplate:\nmetadata:\ncreationTimestamp: null\nlabels:\napp: smtp\nspec:\ncontainers:\n- env:\n- name: RELAY_NETWORKS\nvalue: 172.22.35.0\/24:10.45.0.0\/16:200.1.154.0\/24\nimage: namshi\/smtp\nimagePullPolicy: IfNotPresent\nname: smtp\nports:\n- containerPort: 25\nname: smtp-port\n---\napiVersion: v1\nkind: Service\nmetadata:\ncreationTimestamp: null\nlabels:\napp: smtp\nname: smtp\nannotations:\nmetallb.universe.tf\/allow-shared-ip: ekvm\nmetallb.universe.tf\/address-pool: default\nspec:\nexternalTrafficPolicy: Local\nports:\n- name: smtp\nnodePort: 25\nport: 25\nprotocol: TCP\ntargetport: smtp-port\nselector:\napp: smtp\nloadBalancerIP: 172.22.35.70\ntype: LoadBalancer&amp;lt;\/pre&amp;gt;\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"669\" height=\"190\" class=\"wp-image-2876\" src=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-8.png\" srcset=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-8.png 669w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-8-300x85.png 300w\" sizes=\"auto, (max-width: 669px) 100vw, 669px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"784\" height=\"125\" class=\"wp-image-2877\" src=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-9.png\" srcset=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-9.png 784w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-9-300x48.png 300w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-9-768x122.png 768w\" sizes=\"auto, (max-width: 784px) 100vw, 784px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"744\" height=\"486\" class=\"wp-image-2878\" src=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-10.png\" srcset=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-10.png 744w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-10-300x196.png 300w\" sizes=\"auto, (max-width: 744px) 100vw, 744px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"817\" height=\"177\" class=\"wp-image-2879\" src=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-11.png\" srcset=\"https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-11.png 817w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-11-300x65.png 300w, https:\/\/arielantigua.com\/weblog\/wp-content\/uploads\/2019\/01\/word-image-11-768x166.png 768w\" sizes=\"auto, (max-width: 817px) 100vw, 817px\" \/><\/p>\n<p>\u00a1Excelente!<\/p>\n<p>\u00a1Nuestro servicio de SMTP responde en el IP asignado por MetalLB!<\/p>\n<p>El pr\u00f3ximo paso es el almacenamiento.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Kubernetes en premisa con MetalLB en modo BGP. Una de las desventajas de tener un cluster de k8s en premisa es la falta de LoadBalancer. Gracias a MetalLB esto est\u00e1 resuelto de una manera f\u00e1cil y elegante. Cuando queremos publicar servicios en k8s, lo hacemos usando un Ingress Controller (nginx o Traefik por nombrar algunos). [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[128,10,131,124],"tags":[129,139,132],"class_list":["post-2871","post","type-post","status-publish","format-standard","hentry","category-kubernetes","category-linux","category-rancher","category-ubuntu","tag-k8s","tag-kubernetes","tag-rancher"],"_links":{"self":[{"href":"https:\/\/arielantigua.com\/weblog\/wp-json\/wp\/v2\/posts\/2871","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/arielantigua.com\/weblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/arielantigua.com\/weblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/arielantigua.com\/weblog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/arielantigua.com\/weblog\/wp-json\/wp\/v2\/comments?post=2871"}],"version-history":[{"count":0,"href":"https:\/\/arielantigua.com\/weblog\/wp-json\/wp\/v2\/posts\/2871\/revisions"}],"wp:attachment":[{"href":"https:\/\/arielantigua.com\/weblog\/wp-json\/wp\/v2\/media?parent=2871"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/arielantigua.com\/weblog\/wp-json\/wp\/v2\/categories?post=2871"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/arielantigua.com\/weblog\/wp-json\/wp\/v2\/tags?post=2871"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}