Installation d’un cluster Kubernetes sur Rocky Linux 8

Dans cet article, nous allons présenter l’installation d’un cluster Kubernetes (que nous abrégerons K8s par la suite) sur Rocky Linux 8.5. Pour rappel, Kubernetes est un orchestrateur de conteneurs. Ce cluster sera composé de 3 noeuds Master qui exposerons l’api K8s sur une adresse IP virtuelle assurant la haute disponibilité via l’utilisation de HAProxy et Keepalived. Il sera également composé de deux noeuds Worker sur lesquels se déploieront les conteneurs. Par défaut, les conteneurs ne seront pas déployés sur les noeuds masters (taint) mais il sera tout à fait possible d’outrepasser cette fonctionnalité à l’aide d’une simple commande. L’installation se fera avec la version 1.24 de Kubernetes et donc n’utilisera pas docker-shim.

Prérequis

Nous supposons que toutes les machines sont installées avec une Rocky Linux 8.5 minimale, SELinux étant désactivé. Les noms des machines sont correctement configurés et les adresses IP correctement positionnées.Le swap est désactivé et les horloges sont synchronisées.Les manipulations suivantes sont à faire sur l’ensemble des machines.

Nous allons créer le fichier /etc/sysctl.d/98-k8s.conf :

net.ipv4.ip_forward=1
net.ipv4.ip_nonlocal_bind=1
net.bridge.bride-nf-call-iptables=1
net.netfilter.nf_conntrack_max=1000000

Puis appliquer les modifications grace à :

/sbin/sysctl --system

Nous allons ensuite créer le fichier /etc/modules-load.d/containerd.conf :

overlay
br_netfilter

Et charger directement ces modules :

modprobe overlay
modprobe br_netfilter

Puis nous allons ajouter au fichier /etc/hosts les lignes suivantes :

192.168.11.101   master-1
192.168.11.102   master-2
192.168.11.103   master-3
192.168.11.121   worker-1
192.168.11.122   worker-2
192.168.11.110   api.be-root.com api

Installation KeepAlived + HAProxy

Installation

Ces manipulations seront à faire sur les noeuds master uniquement.
Nous installons les paquets nécessaires :

dnf install -y haproxy keepalived psmisc

Nous allons ensuite créer le fichier /etc/keepalived/keepalived.conf :

global_defs {
  router_id LVS_DEVEL
}

vrrp_script check_haproxy {
  script "killall -0 haproxy"
  interval 2
  weight 2
}

vrrp_instance haproxy-vip {
  state master                    # mettre backup sur master-2 et master-3
  priority 250                    # 249 sur master-2 et sur master-3
  interface ens160                # a adapter en fonction du nom de l'interface reseau
  advert_int 1
  virtual_router_id 160

  unicast_src_ip 192.168.11.101     # Mettre l'ip de la machine actuelle
  unicast_peer {
     192.168.11.102                 # Mettre les IP des deux autres master
     192.168.11.103
  }

  authentication {
   auth_type PASS
   auth_pass 123456                 # Mettre une passphrase identique sur les 3 masters
  }
  virtual_ipaddress {
    192.168.11.110
  }

  track_script {
    check_haproxy
  }
}

Il nous reste ensuite à modifier firewalld et lancer keepalived :

firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
firewall-cmd --reload
systemctl enable --now keepalived

Sur le master-1, il est possible de vérifier que l’ip virtuelle est bien en fonctionnement :

Nous allons ensuite créer le fichier /etc/haproxy/haproxy.cfg :

global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats
    stats timeout 30s
    ssl-default-bind-ciphers PROFILE=SYSTEM
    ssl-default-server-ciphers PROFILE=SYSTEM


defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000


listen hafrontend
    bind *:16443
    mode tcp
    option tcplog
    default_backend kube-apiserver

backend kube-apiserver
    mode tcp
    option tcplog
    option ssl-hello-chk
    balance roundrobin
    server master-1 192.168.11.101:6443 cookie master-1 check
    server master-2 192.168.11.102:6443 cookie master-2 check
    server master-3 192.168.11.103:6443 cookie master-3 check

Puis il nous suffit de configurer firewalld (supprimer la ligne firewall-cmd qui correspond au noeud master courant) et lancer HAProxy :

firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101/32" port protocol="tcp" port="16443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102/32" port protocol="tcp" port="16443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103/32" port protocol="tcp" port="16443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121/32" port protocol="tcp" port="16443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122/32" port protocol="tcp" port="16443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.110/32" port protocol="tcp" port="6443" accept"
firewall-cmd --reload
systemctl enable --now haproxy

Vérification du fonctionnement

sur Master-1 :

L’adresse IP virtuelle est présente sur master-1. L’arrêt de haproxy provoque le transfert de l’adresse ip virtuelle vers un autre noeud master :

Le redémarrage de HAProxy sur master-1 provoque le transfert de l’adresse ip virtuelle à nouveau sur ce dernier :

Installation de containerd

L’installation est à faire sur l’ensemble des noeuds master et worker.

dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
dnf -y update
dnf install  -y containerd.io

Nous allons ensuite générer le fichier de configuration :

containerd config default | tee /etc/containerd/config.toml

Puis nous allons ensuite éditer le fichier /etc/containerd/config.toml pour y positionner l’option SystemdCgroup à true :

      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
          ....
          [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
            SystemdCgroup=true

Nous démarrons ensuite containerd :

systemctl enable --now containerd

Installation de Kubernetes

Prérequis

Nous allons créer le fichier /etc/yum.repos.d/k8s.repo sur l’ensemble des noeuds masters et workers:

[k8s]
name=k8s
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl

Les paquets kubelet kubeadm et kubectl sont exclus afin d’éviter tout update ultérieure non intentionnelle.

Installation de Master-1 :

Nous installons K8s :

dnf install -y iproute-tc
dnf install -y kubelet kubeadm kubectl --disableexcludes=k8s    
systemctl enable kubelet.service

Puis nous allons configurer firewalld (supprimez les lignes dont l’adresse source correspond au noeud master courant). Le réseau 10.0.0.0/23 sera réservé pour les pods. Il faut faire attention à ce qu’il n’interfère pas avec un réseau local existant :

firewall-cmd --add-rich-rule='rule protocol value=4 accept' --permanent	
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="179" accept"	
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="2379-2380" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="udp" port="4789" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="5473" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="6443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="10250" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="10251" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="10255" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="179" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="2379-2380" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="udp" port="4789" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="5473" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="6443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="10250" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="10251" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="10255" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="179" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="2379-2380" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="udp" port="4789" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="5473" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="6443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="10250" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="10251" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="10255" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="179" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="2379-2380" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="udp" port="4789" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="5473" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="6443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="10250" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="10251" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="10255" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="179" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="2379-2380" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="udp" port="4789" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="5473" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="6443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="10250" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="10251" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="10255" accept"

firewall-cmd --zone=public --add-port=30000-32767/tcp --permanent

firewall-cmd --permanent --new-zone=kubernetes_pods
firewall-cmd --permanent --zone=kubernetes_pods --set-target=ACCEPT
firewall-cmd --permanent --zone=kubernetes_pods --add-source=10.0.0.0/23 # Adapter en fonction du pod-network-cidr défini dans la commande kubeadm init sur le 1er master 

firewall-cmd --reload

Nous allons ensuite initialiser le noeud avec :

kubeadm init --control-plane-endpoint "api.be-root.com:16443" --upload-certs --pod-network-cidr=10.0.0.0/23

La commande nous fourni les lignes de commande kubeadm à utiliser pour l’installation des autres masters et workers. Comme nous les utiliserons plus tard, pensez à les noter :

Configurons notre environnement de travail :

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Dans le fichier /var/lib/kubelet/kubeadm-flags.env, ajoutons une ligne :

KUBELET_EXTRA_ARGS="--cgroup-driver=systemd"

et redémarrons kubelet :

systemctl restart kubelet

Nous allons ensuite installer le CNI Calico qui se chargera de la partie networking :

curl -L https://docs.projectcalico.org/manifests/tigera-operator.yaml -o tigera-operator.yaml
curl -L  https://docs.projectcalico.org/manifests/custom-resources.yaml -o custom-resources.yaml
curl -L https://github.com/projectcalico/calico/releases/download/v3.23.0/calicoctl-linux-amd64 -o /usr/bin/calicoctl
chmod +x  /usr/bin/calicoctl

Dans le fichier custom-resources.yaml, nous modifions la ligne cidr: 192.168.0.0/16 en :

cidr: 10.0.0.0/23

Puis nous lançons les deux commandes :

kubectl create -f tigera-operator.yaml
kubectl create -f custom-resources.yaml

Nous pouvons vérifier que tout s’est correctement déroulé et que le node master-1 est en état « Ready » :

Installation de Master-2 et Master-3 :

La procédure au départ est la même que pour Master-1 : ajout du dépôt K8s, installation de k8s et paramétrage de firewalld.

En revanche, au lieu de lancer la commande kubeadm init, nous allons utiliser la commande kubeadm join qui a été affichée sur master-1 lors de la phase d’initialisation :

 kubeadm join api.be-root.com:16443 --token bvvtg2.azhconkj5vbss727 \
         --discovery-token-ca-cert-hash sha256:8c1b0aa71b8a7b36c2fa7636092bb72b8fa64a6ac33fa2bab23740c54e1301d4 \
         --control-plane --certificate-key 9e023d8cf480c6e9671ce2b1c5f97a0fa2aa1c3c1ef1fbb58ef7b7029857314d

Nous configurons ensuite l’environnement de travail avec :

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Puis, dans le fichier /var/lib/kubelet/kubeadm-flags.env, ajoutons une ligne :

KUBELET_EXTRA_ARGS="--cgroup-driver=systemd"

et redémarrons kubelet :

systemctl restart kubelet

Il est inutile d’installer à nouveau le CNI.
Une fois l’installation de master-2 et master-3 achevée, nous pouvons vérifier que les 3 noeuds sont en état « Ready » :

Installation de Worker-1 et Worker-2 :

Nous commençons par configurer firewalld (supprimez le bloc correspondant au node courant) :

firewall-cmd --add-rich-rule='rule protocol value=4 accept' --permanent	

firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="179" accept"	
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="udp" port="4789" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="5473" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="6443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="10250" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="10251" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.101" port protocol="tcp" port="10255" accept"

firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="179" accept"	
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="udp" port="4789" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="5473" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="6443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="10250" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="10251" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.102" port protocol="tcp" port="10255" accept"

firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="179" accept"	
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="udp" port="4789" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="5473" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="6443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="10250" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="10251" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.103" port protocol="tcp" port="10255" accept"

firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="179" accept"	
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="udp" port="4789" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="5473" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="6443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="10250" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="10251" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.121" port protocol="tcp" port="10255" accept"

firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="179" accept"	
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="udp" port="4789" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="5473" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="6443" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="10250" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="10251" accept"
firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.11.122" port protocol="tcp" port="10255" accept"

firewall-cmd --add-port=30000-32767/tcp --permanent --zone=public

firewall-cmd --permanent --new-zone=kubernetes_pods
firewall-cmd --permanent --zone=kubernetes_pods --set-target=ACCEPT
firewall-cmd --permanent --zone=kubernetes_pods --add-source=10.0.0.0/23 # Adapter en fonction du pod-network-cidr défini dans la commande kubeadm init sur le 1er master 

firewall-cmd --reload

Puis nous installons K8s :

dnf install -y iproute-tc
dnf install -y kubelet kubeadm kubectl --disableexcludes=k8s    
systemctl enable kubelet.service

Nous utilisons ensuite la seconde ligne kubeadm join indiquée lors de l’installation du master-1 pour joindre le noeud au cluster :

kubeadm join api.be-root.com:16443 --token bvvtg2.azhconkj5vbss727 \
        --discovery-token-ca-cert-hash sha256:8c1b0aa71b8a7b36c2fa7636092bb72b8fa64a6ac33fa2bab23740c54e1301d4

Puis, dans le fichier /var/lib/kubelet/kubeadm-flags.env, ajoutons une ligne :

KUBELET_EXTRA_ARGS="--cgroup-driver=systemd"

et redémarrons kubelet :

systemctl restart kubelet

Nous pouvons ensuite, depuis un nœud master, vérifier que l’ensemble fonctionne correctement :

Test d’un déploiement

Déploiement de nginx

Sur un nœud master, créons le fichier test.yaml :

apiVersion: v1
kind: Service
metadata:
  name: test-nginx
  labels:
    run: test-nginx
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
    name: http
  - port: 443
    protocol: TCP
    name: https
  selector:
    run: test-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-nginx
spec:
  selector:
    matchLabels:
      run: test-nginx
  replicas: 1
  template:
    metadata:
      labels:
        run: test-nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

Puis lançons la commande :

kubectl create -f test.yaml

Nous pouvons vérifier le bon déploiement à l’aide de la commande kubectl get pod,svc -o wide :

Ici, nous pouvons voir que le pod nginx est lancé sur le worker-2. De même, une commande curl sur le port alloué au nodeport permet d’obtenir la page par défaut de nginx.

Déploiement d’un pod centos

Créons le fichier centos.yaml. Comme le pod nginx tourne sur worker-2, nous allons forcer la création du pod centos sur worker-1 :

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: centos
  name: centos
spec:
  nodeName: worker-1
  containers:
  - image: centos:8
    name: centos
    command: ["/bin/sleep", "3650d"]
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Never
status: {}

Nous créons ensuite le pod à l’aide de :

kubectl create -f centos.yaml

Nous pouvons ensuite voir que le pod est bien déployé sur worker-1 et que le pod centos peut communiquer avec le pod nginx grace au nom du service :

Nettoyage

Nous pouvons supprimer ce que nous avons crée précédemment grâce à :

kubectl delete -f centos.yaml
kubectl delete -f test.yaml

Nous voilà donc arrivé à la fin de ce (long!) article concernant la mise en place d’un cluster kubernetes. Dans les prochains articles, nous partirons de ce cluster de base pour l’enrichir de quelques fonctionnalités.

Installer un serveur Subversion sur Synology DSM 7

Avec la sortie de DSM en version 7, le paquet SVN Server permettant d’installer un serveur subversion sur un NAS Synology n’est plus supporté.

Pour ceux utilisant ce paquet sous DSM en version 6, il existe plusieurs solutions permettant d’outrepasser ce problème (passage à git, utiliser un serveur subversion externe, etc …) et donc d’envisager la mise à jour de DSMv6 vers DSMv7.

Dans cet article nous allons étudier une solution consistant à installer un conteneur docker pour faire tourner un serveur subversion sur le NAS Synology (à condition bien sûr, que votre NAS supporte l’installation du paquet Docker).
Nous verrons ensuite comment transférer les repositories subversion gérés via le paquet officiel SVN Server vers notre serveur nouvellement installé.

Installation d’un serveur SVN via Docker sur Synology DSM

Tout d’abord, si cela n’est pas encore fait, nous allons installer le paquet Docker depuis le Centre des Paquets de DSM.

Nous allons ensuite créer un répertoire svn sous le répertoire docker. Puis nous ferons trois répertoires qui nous servirons à rendre persistant les données du conteneur.

 

Nous allons ensuite lancer l’application Docker et y télécharger l’image clamy54/svn-svnadmin:latest.

Il s’agit d’une image basée sur ubuntu 20.04 LTS comportant les outils subversions ainsi qu’une interface web permettant d’administrer l’organisation de nos repositories subversion.

Nous allons ensuite créer le conteneur associé :

Puis, dans les paramètres avancés, nous allons configurer le redémarrage automatique du conteneur :

Nous allons ensuite associer les répertoires crées précédemment aux volumes exportés par le conteneur :

Puis rediriger des ports tcp du synology vers les ports 80/tcp et 443/tcp du conteneur :

Nous pouvons alors valider la création du conteneur et le démarrer.

Transfert des repositories svn

Le transfert des repositories est plutôt simple puisqu’il suffit d’arrêter le conteneur, puis de copier le contenu du répertoire /docker vers le répertoire /docker/svn/svn/ et de redémarrer le conteneur.

Il suffira ensuite de gérer les utilisateurs et droits d’accès directement depuis l’interface web iF-SVNAdmin fournie par le conteneur.

Accès au serveur Subversion et à l’interface iF.SVNAdmin

L’interface web est disponible en http ou https via les ports assignés précédemment.

Le login par défaut est admin et le mot de passe admin. Il est évident qu’il faut changer ce mot de passe par défaut au plus tôt.

Depuis cet interface, il nous est possible de créer des utilisateurs, des repositories et d’assigner des autorisations sur ces repositories.

L’accès  depuis un client svn se fera alors, par exemple, de la manière suivante :

svn checkout --username myuser https://synology_ip:8443/svn/myrepository ./localfolder

Pour plus d’informations sur les personnalisations possibles, rendez-vous sur la page officielle du conteneur.

VMWare ESXi : Créer manuellement une partition de coredump

Dans cet article, nous allons voir comment créer manuellement une partition de coredump, utilisée notamment pour récupérer les informations de débuggage lors d’un plantage d’un ESXi.

Pré-requis : Il faut avoir accès à la ligne de commande via ssh à l’hyperviseur ESXi. Le datastore vmfs local  doit également être vide car il sera supprimé lors de la manipulation.

Tout d’abord, nous allons utiliser la commande esxcfg-mpath -b afin de déterminer le nom de device associé au disque dur local :

[root@esxi:~]  esxcfg-mpath -b  
 naa.61866da0b8241a0020ee3286154ea8af : Local DELL Disk (naa.61866da0b8241a0020ee3286154ea8af)
 vmhba0:C2:T0:L0 LUN:0 state:active sas Adapter: 51866da0b8241a00  Target: 60ee3286154ea8af

Dans notre cas, le device se nomme naa.61866da0b8241a0020ee3286154ea8af

Nous allons ensuite utiliser la commande partedUtil getptbl « /vmfs/devices/disks/naa.61866da0b8241a0020ee3286154ea8af »  pour visualiser le partitionnement actuel du disque :

[root@esxi:~] partedUtil getptbl "/vmfs/devices/disks/naa.61866da0b8241a0020ee3286154ea8af"
gpt
36404 255 63 584843264
1 64 204863 C12A7328F81F11D2BA4B00A0C93EC93B systemPartition 128
5 208896 1232895 EBD0A0A2B9E5443387C068B6B72699C7 linuxNative 0
6 1234944 2258943 EBD0A0A2B9E5443387C068B6B72699C7 linuxNative 0
7 2260992 15470591 4EB2EA3978554790A79EFAE495E21F8D vmfsl 0
8 15472640 584843230 AA31E02A400F11DB9590000C2911D1B8 vmfs 0

Nous remarquons que le datastore  vmfs est la partition 8, qu’il commence au secteur 15472640, se termine au secteur 584843230 et qu’il possède le GUID AA31E02A400F11DB9590000C2911D1B8 (correspondant à un datastore vmfs).
Ces GUID sont fixés par vmware. La liste des GUID peut être obtenue par la commande  partedUtil showGuids :

[root@esxi:~] partedUtil showGuids
 Partition Type       GUID
 vmfs                 AA31E02A400F11DB9590000C2911D1B8
 vmkDiagnostic        9D27538040AD11DBBF97000C2911D1B8
 vsan                 381CFCCC728811E092EE000C2911D0B2
 virsto               77719A0CA4A011E3A47E000C29745A24
 VMware Reserved      9198EFFC31C011DB8F78000C2911D1B8
 Basic Data           EBD0A0A2B9E5443387C068B6B72699C7
 Linux Swap           0657FD6DA4AB43C484E50933C84B4F4F
 Linux Lvm            E6D6D379F50744C2A23C238F2A3DF928
 Linux Raid           A19D880F05FC4D3BA006743F0F84911E
 Efi System           C12A7328F81F11D2BA4B00A0C93EC93B
 Microsoft Reserved   E3C9E3160B5C4DB8817DF92DF00215AE
 Unused Entry         00000000000000000000000000000000

Il nous faut donc supprimer cette partition 8 afin d’y récupérer de l’espace pour pouvoir y recréer 2 partitions : une partition de type vmkDiagnostic et un nouveau datastore vmfs.
Pour supprimer la partition, la méthode la plus simple est de supprimer le datastore local depuis l’interface d’administration de l’ESXi. Il est également de le faire à l’aidre de la commande partedUtil.

Une fois la partition supprimée, la commande partedUtil getptbl « /vmfs/devices/disks/naa.61866da0b8241a0020ee3286154ea8af » affiche alors :

[root@esxi:~] partedUtil getptbl "/vmfs/devices/disks/naa.61866da0b8241a0020ee3286154ea8af"
 gpt
 36404 255 63 584843264
 1 64 204863 C12A7328F81F11D2BA4B00A0C93EC93B systemPartition 128
 5 208896 1232895 EBD0A0A2B9E5443387C068B6B72699C7 linuxNative 0
 6 1234944 2258943 EBD0A0A2B9E5443387C068B6B72699C7 linuxNative 0
 7 2260992 15470591 4EB2EA3978554790A79EFAE495E21F8D vmfsl 0

Le chiffre 36404 correspond au nombre de cylindres adressable (0-36404), 255 au nombre de têtes (0-255) et 63 au nombre de secteurs par piste (0-63).
La commande esxcli storage core device capacity list permet de connaitre les caractéristiques du disque :

[root@esxi:~] esxcli storage core device capacity list
 Device                                Physical Blocksize  Logical Blocksize  Logical Block Count         Size  Format Type
 ------------------------------------  ------------------  -----------------  -------------------  -----------  -----------
 mpx.vmhba2:C0:T5:L0                                  512                512                    0        0 MiB  512n
 naa.61866da0b8241a0020ee3286154ea8af                 512                512            584843264   285568 MiB  512n

Nous voyons donc que la taille d’un bloc est de 512 octets.
Une partition de coredump doit faire au moins 100Mo. Pour l’exemple, nous allons faire une partition de 200Mo.
Il faudra 200000000/512 = 390625 secteurs pour y loger cette partition. L’ancienne partition 8 commençait au secteur 15472640. Nous allons faire commencer cette nouvelle partition sur ce secteur
et nous allons la faire terminer sur le secteur 15472640+390625=15863265.

Nous allons donc créer cette nouvelle partition 8 avec un GUID de type vmkDiagnostic :

partedUtil add "/vmfs/devices/disks/naa.61866da0b8241a0020ee3286154ea8af" "gpt" "8 15472640 15863265 9D27538040AD11DBBF97000C2911D1B8 0" 

Nous allons ensuite recréer un datastore vmfs dont le premier secteur sera le multiple de 64 directement supérieur à 15863265 (afin d’aligner la partition sur le
premier secteur du cylindre suivant). En l’occurrence, ici, la partition commencera donc au secteur 15863296. Pour le dernier secteur, nous utiliserons la valeur correspondante de l’ancienne partition 8.
Cette nouvelle partition portera le numéro 9 et utilisera un GUID de type vmfs.

partedUtil add "/vmfs/devices/disks/naa.61866da0b8241a0020ee3286154ea8af" "gpt" "9 15863296 584843230 AA31E02A400F11DB9590000C2911D1B8 0"

Nous allons afficher maintenant les partitions de type coredump reconnues par le systeme :

[root@esxi:~] esxcli system coredump partition list
 Name                                    Path                                                        Active  Configured
 --------------------------------------  ----------------------------------------------------------  ------  ----------
 naa.61866da0b8241a0020ee3286154ea8af:8  /vmfs/devices/disks/naa.61866da0b8241a0020ee3286154ea8af:8   false       false

La partition 8 est donc bien détectée mais elle n’est ni configurée ni active. Nous allons donc le faire :

esxcli system coredump partition set --partition="naa.61866da0b8241a0020ee3286154ea8af::8"
esxcli system coredump partition set --enable true

La commande affiche alors :

[root@esxi:~] esxcli system coredump partition list
 Name                                    Path                                                        Active  Configured
 --------------------------------------  ----------------------------------------------------------  ------  ----------
 naa.61866da0b8241a0020ee3286154ea8af:8  /vmfs/devices/disks/naa.61866da0b8241a0020ee3286154ea8af:8    true        true

La partition coredump est donc maintenant configurée et active.
Il ne nous reste plus qu’à formater la partition 9 en vmfs :

vmkfstools -C vmfs6 -S esxi-local /vmfs/devices/disks/naa.61866da0b8241a0020ee3286154ea8af:9