Kubernes con kubeadm en HA

Una vez introducido, qué es kubernetes, en la entrada de hoy vamos a ver como montar un clúster en alta disponibilidad haciendo uso de la herramienta kubeadm. Aunque ésta herramienta está en una fase alpha/beta, como podemos ver en la matriz de madurez que nos brindan, sí es cierto que va bastante bien, al menos en las pruebas que he realizado. Lo haremos sobre Ubuntu 16.04, aunque ya que ha salido la nueva LTS de Ubuntu, perfectamente se podría realizar sobre esta.

Lo primero que vamos a hacer es definir el escenario que vamos a realizar, contaremos con:

  • Master: Contaremos con tres máquinas que ejercerán como tal.
  • Nodo: Al igual que con los másters (no tienen por qué coincidir), contaremos con tres.
  • Balanceador de carga: Será el encargado de atacar a la API de los masters.
  • Cliente: Desde ésta máquina atacaremos al clúster una vez esté configurado.

kubernetes-ha

La forma de realizarlo será, montar un clúster etcd con los tres masters, luego inicializar dichos masters y, por último, unir los nodos. ¿Suena fácil verdad?.

Creación de certificados.

Antes de empezar requeriremos de la creación de los certificados. Haremos uso de la herramienta CFSSL, desde cualquier máquina que dispongamos.

$ wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
$ wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
$ chmod +x cfssl*
$ sudo mv cfssl_linux-amd64 /usr/local/bin/cfssl
$ sudo mv cfssljson_linux-amd64 /usr/local/bin/cfssljson

Entonces creamos la entidad certificadora, desde dos ficheros, ca-config.json

{
  "signing": {
    "default": {
      "expiry": "8760h"
    },
    "profiles": {
      "kubernetes": {
        "usages": ["signing", "key encipherment", "server auth", "client auth"],
        "expiry": "8760h"
      }
    }
  }
}

ca-csr.json.

{
  "CN": "kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
  {
    "C": "IE",
    "L": "Cork",
    "O": "Kubernetes",
    "OU": "Kubernetes",
    "ST": "Cork Co."
  }
 ]
}

Procedemos a generar los certificados de la autoridad certificadora y la clave privada.

cfssl gencert -initca ca-csr.json | cfssljson -bare ca

Y entonces crearemos los certificados para el clúster etcd. Creamos el fichero kubernetes-csr.json.

{
  "CN": "kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
  {
    "C": "SP",
    "L": "Dos Hermanas",
    "O": "Kubernetes",
    "OU": "Kubernetes",
    "ST": "Rocio"
  }
 ]
}

Y ya generamos el certificado y la clave privada.

$ cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-hostname=10.32.0.1,IPMASTERX,IPMASTERY,IPMASTERZ,IPBALANCEADOR,127.0.0.1,kubernetes.default \
-profile=kubernetes kubernetes-csr.json | \
cfssljson -bare kubernetes

Entonces copiaremos las ficheros generados a los masters.

$ scp ca.pem kubernetes.pem kubernetes-key.pem USUARIO@IPMAQUINA:~

Preparación inicial.

Una vez con los certificados en cada máquina, realizaremos la instalación y configuración inicial de cada máquina (ésto es común a todos los masters y nodos).

Instalación de docker

  • Añadimos key y repositorio
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
# add-apt-repository "deb https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") $(lsb_release -cs) stable"
  • Actualizamos paquetería e instalamos docker 17.03
# apt update && apt-get install -y docker-ce=$(apt-cache madison docker-ce | grep 17.03 | head -1 | awk '{print $3}')

Instalación de kubeadm, kubelet y kubectl.

  • Añadimos key y repositorio de Google.
# curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
# echo "deb http://apt.kubernetes.io kubernetes-xenial main" >> /etc/apt/sources.list.d/kubernetes.list
  • Actualizamos paquetería e instalamos los paquetes.
# apt update && apt install -y kubelet kubeadm kubectl
  • Desactivamos SWAP
# swapoff -a 
# sed -i '/ swap / s/^/#/' /etc/fstab

Configuración del clúster etcd.

Una vez tengamos configurado todos los masters y nodos, procederemos a la instalación y configuración del clúster etcd, que lo haremos directamente desde los binarios.

  • Creamos los directorios de configuración de Etcd y movemos los certificados y claves que anteriormente habíamos pasado a la máquina.
$ sudo mkdir /etc/etcd /var/lib/etcd
$ sudo mv ~/ca.pem ~/kubernetes.pem ~/kubernetes-key.pem /etc/etcd
  • Descargamos, extraemos y movemos a /usr/local/bin los binarios de etcd
$ wget https://github.com/coreos/etcd/releases/download/v3.2.11/etcd-v3.2.11-linux-amd64.tar.gz 
$ tar xvzf etcd-v3.2.11-linux-amd64.tar.gz 
$ sudo mv etcd-v3.2.11-linux-amd64/etcd* /usr/local/bin/
  • Creamos la unidad etcd, (/etc/systemd/system/etcd.service) estableciendo las ips correspondientes.
[Unit]
Description=etcd
Documentation=https://github.com/coreos


[Service]
ExecStart=/usr/local/bin/etcd \
  --name master{X,Y,Z} \
  --cert-file=/etc/etcd/kubernetes.pem \
  --key-file=/etc/etcd/kubernetes-key.pem \
  --peer-cert-file=/etc/etcd/kubernetes.pem \
  --peer-key-file=/etc/etcd/kubernetes-key.pem \
  --trusted-ca-file=/etc/etcd/ca.pem \
  --peer-trusted-ca-file=/etc/etcd/ca.pem \
  --peer-client-cert-auth \
  --client-cert-auth \
  --initial-advertise-peer-urls https://IpMaster{X,Y,Z}:2380 \
  --listen-peer-urls https://IpMaster{X,Y,Z}:2380 \
  --listen-client-urls https://IpMaster{X,Y,Z}:2379,http://127.0.0.1:2379 \
  --advertise-client-urls https://IpMaster{X,Y,Z}:2379 \
  --initial-cluster-token etcd-cluster-0 \
  --initial-cluster IpMasterX=https://IpMasterX:2380,IpMasterY=https://IpMasterY:2380,IpMasterZ=https://IpMasterZ:2380 \
  --initial-cluster-state new \
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5



[Install]
WantedBy=multi-user.target
  • Entonces recargamos los servicios, activamos etcd y lo arrancamos.
# systemctl daemon-reload 
# systemctl enable etcd
# systemctl start etcd

Una vez hayamos configurado los tres, podemos comprobar que realmente se ha creado con el siguiente comando, desde cualquier master.

$ ETCDCTL_API=3 etcdctl member list

Inicialización del primer master K8S.

Lo primero que realizaremos será crear el fichero config.yaml como el que vemos a continuación.

apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
api:
  advertiseAddress: IpMaster{X,Y,Z}
etcd:
  endpoints:
  - https://IpMasterX:2379
  - https://IpMasterY:2379
  - https://IpMasterZ:2379
  caFile: /etc/etcd/ca.pem
  certFile: /etc/etcd/kubernetes.pem
  keyFile: /etc/etcd/kubernetes-key.pem
networking:
  podSubnet: 10.244.0.0/16
apiServerCertSANs:
- IpBalanceador
apiServerExtraArgs:
  apiserver-count: "3"

Esto es para especificarle que no nos monte etcd si no que ya lo tenemos nosotros configurado y que, red de overlay vamos a usar, en mi caso, Flannel. Ya podemos iniciarlo.

# kubeadm init --config=config.yaml

Una vez inicializado el primer master, copiamos a los otros masters la carpeta pki que genera dicha inicialización.

$ sudo scp -r /etc/kubernetes/pki USUARIO@IPMAQUINA:~

Unión de los demás master K8S.

Eliminaremos los ficheros apiserver que hemos pasado desde el primer master, y movemos la carpeta pki, que nos trajimos, al directorio /etc/kubernetes.

$ rm ~/pki/apiserver.*
$ sudo mv ~/pki /etc/kubernetes/

Entonces creamos el fichero config.yaml que vimos en la inicialización del primer master y unimos el siguiente master. Así con cada uno de los distintos masters que habíamos acordado unir.

# kubeadm init --config=config.yaml

Nos quedamos con el comando que nos sale por pantalla.

Uniendo los nodos.

Para los nodos es muy sencillo, simplemente ejecutaremos el comando que nos soltó por pantalla la última inicialización del master, que será del estilo siguiente.

# kubeadm join 10.10.40.92:6443 --token [yourtoken] --discovery-token-ca-cert-hash sha256:[yourtokencacert_hash]

Y una vez estén todos los nodos unidos, podremos comprobar que realmente es así, ejecutando en cualquiera de los masters.

# kubectl --kubeconfig /etc/kubernetes/admin.conf get nodes

Configuración del balanceador.

Lo realizaremos con HAProxy, con lo que lo instalaremos directamente de los repositorios de Ubuntu.

# apt update && apt install haproxy -y

Estableceremos la siguiente configuración de HAProxy, y reiniciaremos el servicio para que adopte los cambios.

Fichero /etc/haproxy/haproxy.cfg

global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        # Default ciphers to use on SSL-enabled listening sockets.
        # For more information, see ciphers(1SSL). This list is from:
        #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
        ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
        ssl-default-bind-options no-sslv3

defaults

        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

        frontend kubernetes
        bind IpBalanceador:6443
        option tcplog
        mode tcp
        default_backend kubernetes-master-nodes

        backend kubernetes-master-nodes
        mode tcp
        balance roundrobin
        option ssl-hello-chk
        server master-1 IpMasterX:6443
        server master-2 IpMasterY:6443
        server master-3 IpMasterZ:6443

Reinicio del servicio.

# systemctl restart haproxy

Configuración del cliente.

Aquí copiaremos desde cualquier master el fichero /etc/kubernetes/admin.conf.

# ssh USUARIO@IPCLIENTE mkdir ~/.kube
# scp /etc/kubernetes/admin.conf USUARIO@IPCLIENTE:~/.kube/config

Ya de vuelta en el cliente instalamos kubectl, como vimos anteriormente en la instalación de kubelet, kubeadm kubectl, pero ésta vez sólo es necesario éste último. Y modificamos en el fichero config pasado anteriormente las siguientes líneas.

...
server: https://IpBalanceador:6443
...

Y le cambiamos los permisos.

$ chmod 600 ~/.kube/config

Y ya podremos acceder a nuestro clúster, lo primero que haremos será desplegar la red de overlay, ya que en estos momentos, todos los nodos y masters deben aparecer en estado Not Ready debido a que no hay red configurada.

Despliegue de la red de overlay

Como ya indicamos en el podSubnet la red 10.244.0.0/16 para el despliegue de flannel, ésta es la que vamos a desplegar, podemos realizarlo directamente desde el cliente.

$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

Y, esperando un poco, podremos ver que los componentes del clúster van apareciendo en estado Ready. Y los pods que se despliegan en el namespace kube-system.

$ kubectl get nodes
$ kubectl get pods -n kube-system

Tal que así.

ubuntu@cliente:~$ kubectl get nodes
NAME       STATUS    ROLES     AGE       VERSION
master-1   Ready     master    1d        v1.10.2
master-2   Ready     master    19h       v1.10.2
master-3   Ready     master    19h       v1.10.2
nodo-1     Ready         19h       v1.10.2
nodo-2     Ready         19h       v1.10.2
nodo-3     Ready         19h       v1.10.2
ubuntu@cliente:~$ kubectl get pods -n kube-system
NAME                               READY     STATUS    RESTARTS   AGE
kube-apiserver-master-1            1/1       Running   0          1d
kube-apiserver-master-2            1/1       Running   0          19h
kube-apiserver-master-3            1/1       Running   0          19h
kube-controller-manager-master-1   1/1       Running   0          1d
kube-controller-manager-master-2   1/1       Running   0          19h
kube-controller-manager-master-3   1/1       Running   0          19h
kube-dns-86f4d74b45-g4khn          3/3       Running   0          1d
kube-flannel-ds-8x7zh              1/1       Running   0          26s
kube-flannel-ds-gmqtq              1/1       Running   0          26s
kube-flannel-ds-lbvz5              1/1       Running   0          26s
kube-flannel-ds-mqprb              1/1       Running   0          26s
kube-flannel-ds-nmbz2              1/1       Running   0          26s
kube-flannel-ds-rbhkb              1/1       Running   0          26s
kube-proxy-4d6lp                   1/1       Running   0          19h
kube-proxy-74cbp                   1/1       Running   0          19h
kube-proxy-d6s7s                   1/1       Running   0          19h
kube-proxy-dzl77                   1/1       Running   0          19h
kube-proxy-fhz2t                   1/1       Running   0          1d
kube-proxy-zv6n9                   1/1       Running   0          19h
kube-scheduler-master-1            1/1       Running   0          1d
kube-scheduler-master-2            1/1       Running   0          19h
kube-scheduler-master-3            1/1       Running   0          19h

Ya podríamos empezar a desplegar nuestros servicios

 Referencias
https://kubernetes.io/docs/setup/independent/high-availability/
https://blog.inkubate.io/install-and-configure-a-multi-master-kubernetes-cluster-with-kubeadm/
Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s