Kubernetes completo da zero su Raspberry Pi

Kubernetes completo da zero su Raspberry Pi

Di recente, una nota azienda ha annunciato di passare alla architettura ARM per la sua gamma di laptop. Sentendo questa notizia, mi sono ricordato: mentre rivedevo i prezzi di EC2 su AWS, ho notato i Graviton a un prezzo molto allettante. Il trucco, ovviamente, era che si trattava di ARM. All'epoca non pensavo che ARM fosse così serio...

Per me, quest'architettura è sempre stata associata a dispositivi mobili e altre diavolerie IoT. I "veri" server su ARM sembrano un po' insoliti, in qualche modo addirittura strani... Tuttavia, una nuova idea mi è venuta in mente, così in un weekend ho deciso di verificare cosa si può lanciare oggi su ARM. E per farlo, ho deciso di iniziare con qualcosa di vicino e famigliare: un cluster Kubernetes. Non un semplice "cluster" qualsiasi, ma tutto "in grande" per essere il più simile possibile a quello che sono abituato a vedere in produzione.

Secondo la mia concezione, il cluster deve essere accessibile da Internet, deve eseguire qualche applicazione web e deve avere almeno un sistema di monitoraggio. Per realizzare questa idea sarà necessaria una coppia (o più) di Raspberry Pi di almeno modello 3B+. La piattaforma per esperimenti potrebbe essere anche AWS, ma ero particolarmente interessato alle «lamanine» (che comunque erano rimaste inutilizzate). Quindi, installeremo su di esse un cluster Kubernetes con Ingress, Prometheus e Grafana.

Preparazione delle «lamanine»

Installazione dell'OS e SSH

Non mi sono soffermato molto sulla scelta dell'OS da installare: ho semplicemente preso l'ultima versione di Raspberry Pi OS Lite da sito ufficiale. Qui è disponibile la documentazione per l'installazione, tutte le operazioni devono essere eseguite su tutti i nodi del futuro cluster. Successivamente, sarà necessario eseguire le seguenti operazioni (anche su tutti i nodi).

Collegando il monitor e la tastiera, è necessario configurare preliminarmente la rete e SSH:

  1. Per il funzionamento del cluster, il master deve avere necessariamente un indirizzo IP statico, mentre sui nodi di lavoro è a discrezione. Ho preferito indirizzi statici ovunque per comodità di configurazione.
  2. L'indirizzo statico può essere configurato nel sistema operativo (nel file /etc/dhcpcd.conf esiste un esempio adeguato) oppure registrando il lease nel server DHCP utilizzato (nel mio caso — router domestico).
  3. il server ssh si attiva semplicemente in raspi-config (opzioni di interfaccia → ssh).

Dopo di che si può effettuare il login tramite SSH (di default il login è pi, e la password è raspberry o quella che è stata cambiata) e continuare con le impostazioni.

Altre impostazioni

  1. Imposteremo il nome host. Nel mio esempio utilizzeremo pi-control e pi-worker.
  2. Controlliamo che il file system sia esteso all'intero disco (df -h /). Se necessario, può essere esteso tramite raspi-config.
  3. Cambiamos la password dell'utente predefinito in raspi-config.
  4. Disattiviamo il file di swap (è un requisito di Kubernetes; se sei interessato a maggiori dettagli su questo argomento, consulta issue #53533):
    dphys-swapfile swapoff
    systemctl disable dphys-swapfile
  5. Aggiorniamo i pacchetti all'ultima versione:
    apt-get update && apt-get dist-upgrade -y
  6. Installa Docker e pacchetti aggiuntivi:
    apt-get install -y docker docker.io apt-transport-https curl bridge-utils iptables-persistent

    Durante l'installazione di iptables-persistent sarà necessario salvare le impostazioni di iptables per ipv4, e nel file /etc/iptables/rules.v4 — aggiungere le regole nella catena FORWARD, in questo modo:

    # Generated by xtables-save v1.8.2 on Sun Jul 19 00:27:43 2020
    *filter
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    -A FORWARD -s 10.1.0.0/16  -j ACCEPT
    -A FORWARD -d 10.1.0.0/16  -j ACCEPT
    COMMIT
  7. Ora tutto è pronto per l'installazione del cluster Kubernetes.

Installazione di Kubernetes

Installazione di Kubernetes

A questo punto ho messo da parte le mie e le nostre risorse aziendali relative all'automazione dell'installazione e configurazione del cluster K8s. Invece, utilizziamo la documentazione ufficiale di kubernetes.io (leggermente integrata con commenti e abbreviazioni).

Aggiungiamo il repository di Kubernetes:

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt-get update

Nella documentazione viene poi proposto di installare il CRI (container runtime interface). Poiché Docker è già installato, procediamo oltre e installiamo i componenti principali:

sudo apt-get install -y kubelet kubeadm kubectl kubernetes-cni

Nella fase di installazione dei componenti principali ho subito aggiunto kubernetes-cni, che è necessario per il funzionamento del cluster. E qui c'è un punto importante: il pacchetto kubernetes-cni per qualche motivo non crea per impostazione predefinita la directory per le impostazioni degli interfaccia CNI, quindi ho dovuto crearla manualmente:

mkdir -p /etc/cni/net.d

Per il funzionamento del backend di rete, di cui parleremo in seguito, è necessario installare un plugin per CNI. Ho scelto il plugin portmap a me familiare (per l'elenco completo vedere in documentazione):

curl -sL https://github.com/containernetworking/plugins/releases/download/v0.7.5/cni-plugins-arm-v0.7.5.tgz | tar zxvf - -C /opt/cni/bin/ ./portmap

Configurazione di Kubernetes

Nodo con control plane

L'installazione del cluster è piuttosto semplice. Per accelerare questo processo e verificare che le immagini di Kubernetes siano disponibili, è possibile eseguire preliminarmente:

kubeadm config images pull

Adesso procediamo all'installazione vera e propria: inizializziamo il control plane del cluster:

kubeadm init --pod-network-cidr=10.1.0.0/16 --service-cidr=10.2.0.0/16 --upload-certs

Si noti che le sottoreti per i servizi e i pod non devono sovrapporsi tra loro né con le reti esistenti.

Alla fine verrà mostrato un messaggio che informa che tutto è andato bene e verrà anche indicato come unire i nodi di lavoro al control plane:

Il tuo piano di controllo Kubernetes è stato inizializzato con successo!
Per iniziare a utilizzare il tuo cluster, devi eseguire quanto segue come utente normale:
 mkdir -p $HOME/.kube
 sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
 sudo chown $(id -u):$(id -g) $HOME/.kube/config
Ora dovresti distribuire una rete pod nel cluster.
Esegui "kubectl apply -f [podnetwork].yaml" con una delle opzioni elencate su:
 https://kubernetes.io/docs/concepts/cluster-administration/addons/
Ora puoi unire qualsiasi numero di nodi del piano di controllo eseguendo il seguente comando su ciascuno come root:
 kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4 
   --discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050 
   --control-plane --certificate-key 72a3c0a14c627d6d7fdade1f4c8d7a41b0fac31b1faf0d8fdf9678d74d7d2403
Si prega di notare che la chiave di certificato fornisce accesso a dati sensibili del cluster, tienila segreta!
Come misura di sicurezza, i certificati caricati verranno eliminati tra due ore; se necessario, puoi utilizzare
"kubeadm init phase upload-certs --upload-certs" per ricaricare i certificati successivamente.
Puoi quindi unire qualsiasi numero di nodi di lavoro eseguendo quanto segue su ciascuno come root:
kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4 
   --discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050

Seguiamo le raccomandazioni per aggiungere la configurazione per l'utente. Consiglio inoltre di aggiungere subito il completamento automatico per kubectl:

 kubectl completion bash > ~/.kube/completion.bash.inc
 printf "
 # Completamento della shell Kubectl
 source '$HOME/.kube/completion.bash.inc'
 " >> $HOME/.bash_profile
 source $HOME/.bash_profile

A questo punto è già possibile vedere il primo nodo nel cluster (anche se non è ancora pronto):

root@pi-control:~# kubectl get no
NOME         STATO     RUOLI    ETÀ   VERSIONE
pi-control   NonPronto   master   29s   v1.18.6

Configurazione di rete

Successivamente, come indicato nel messaggio dopo l'installazione, sarà necessario impostare la rete nel cluster. La documentazione offre la possibilità di scegliere tra Calico, Cilium, contiv-vpp, Kube-router e Weave Net… Qui mi sono discostato dalle istruzioni ufficiali e ho scelto l'opzione che mi è più familiare e comprensibile: flannel in modalità host-gw (per ulteriori dettagli sugli backend disponibili, vedere la documentazione del progetto).

Installarlo nel cluster è piuttosto semplice. Per iniziare, scarichiamo i manifesti:

wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

Poi cambiamo nelle impostazioni il tipo da vxlan con host-gw:

sed -i 's/vxlan/host-gw/' kube-flannel.yml

… e la sottorete dei pod — dal valore predefinito a quello specificato durante l'inizializzazione del cluster:

sed -i 's#10.244.0.0/16#10.1.0.0/16#' kube-flannel.yml

Dopo di che creiamo le risorse:

kubectl create -f kube-flannel.yml

Fatto! Dopo un po', il primo nodo K8s passerà allo stato Pronto:

NOME         STATO   RUOLI    ETÀ   VERSIONE
pi-control   Pronto    master   2m    v1.18.6

Aggiunta di un nodo di lavoro

Ora possiamo aggiungere un worker. Per farlo, dopo aver installato Kubernetes seguendo lo scenario descritto sopra, è sufficiente eseguire il comando ricevuto in precedenza:

kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4 
    --discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050

A questo punto, possiamo considerare il cluster pronto:

root@pi-control:~# kubectl get no
NOME         STATO    RUOLI    ETA    VERSIONE
pi-control   Pronto    master   28m    v1.18.6
pi-worker    Pronto       2m8s   v1.18.6

Avevo solo due Raspberry Pi a disposizione, quindi non volevo dare via una di esse solo per il control plane. Così ho rimosso la taint installata automaticamente dal nodo pi-control, eseguendo:

root@pi-control:~# kubectl edit node pi-control

… e rimuovendo le righe:

 - effect: NoSchedule
   key: node-role.kubernetes.io/master

Riempimento del cluster con il minimo necessario

Prima di tutto, avremo bisogno di Helm. Certo, è possibile fare tutto anche senza di esso, ma Helm consente di configurare alcuni componenti a proprio piacimento senza dover modificare i file. E, di fatto, è solo un file binario che "non chiede nulla".

Quindi, andiamo su helm.sh nella sezione docs/installation e eseguiamo il comando da lì:

curl -s https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

Dopo di che, aggiungiamo il repository dei chart:

helm repo add stable https://kubernetes-charts.storage.googleapis.com/

Ora installiamo i componenti infrastrutturali secondo il progetto:

  • Ingress controller;
  • Prometheus;
  • Grafana;
  • cert-manager.

Ingress controller

Il primo componente — Ingress controller — si installa abbastanza facilmente ed è pronto all'uso "out of the box". È sufficiente accedere al sezione bare-metal del sito e eseguire il comando di installazione da lì:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.34.1/deploy/static/provider/baremetal/deploy.yaml

Tuttavia, in quel momento il "raspberry" ha iniziato a risentire e a lottare con IOPS del disco. Infatti, insieme all'Ingress controller vengono installate molte risorse, si effettuano molte richieste all'API e, di conseguenza, molti dati vengono scritti in etcd. Insomma, o la scheda di memoria di classe 10 non è molto performante, oppure le schede SD non sono sufficienti per tale carico. Tuttavia, dopo circa 5 minuti tutto è partito.

È stato creato un namespace e in esso è apparso il controller e tutto ciò che gli serve:

root@pi-control:~# kubectl -n ingress-nginx get pod
NOME                                        PRONTO   STATO      RIAVVI     ETÀ
 ingress-nginx-admission-create-2hwdx        0/1     Completato   0          31s
 ingress-nginx-admission-patch-cp55c         0/1     Completato   0          31s
 ingress-nginx-controller-7fd7d8df56-68qp5   1/1     In esecuzione     0          48s

Prometheus

Gli altri due componenti si installano abbastanza facilmente tramite Helm dal chart repo.

Troviamo Prometheus, creiamo un namespace e installiamo in esso:

helm search repo stable | grep prometheus
kubectl create ns monitoring
helm install prometheus --namespace monitoring stable/prometheus --set server.ingress.enabled=True --set server.ingress.hosts={"prometheus.home.pi"}

Per impostazione predefinita, Prometheus richiede 2 dischi: uno per i dati di Prometheus stesso e uno per i dati di AlertManager. Poiché non è stata creata alcuna classe di storage nel cluster, i dischi non verranno richiesti e i pod non si avvieranno. Per le installazioni bare metal di Kubernetes, di solito utilizziamo Ceph rbd, ma nel caso di Raspberry Pi è decisamente eccessivo.

Pertanto, creeremo un semplice storage locale su hostpath. I manifesti PV (persistent volume) per prometheus-server e prometheus-alertmanager sono combinati nel file prometheus-pv.yaml in Repository Git con esempi per l'articolo. La directory per il PV deve essere creata in anticipo sul disco del nodo al quale vogliamo collegare Prometheus: nell'esempio è specificato nodeAffinity per hostname pi-worker e su di esso sono state create le directory /data/localstorage/prometheus-server e /data/localstorage/prometheus-alertmanager.

Scarichiamo (cloniamo) il manifesto e lo aggiungiamo a Kubernetes:

kubectl create -f prometheus-pv.yaml

A questo punto mi sono imbattuto per la prima volta nel problema dell'architettura ARM. Kube-state-metrics, che viene installato per default nel chart di Prometheus, ha rifiutato di avviarsi. Ha restituito l'errore:

root@pi-control:~# kubectl -n monitoring logs prometheus-kube-state-metrics-c65b87574-l66d8
standard_init_linux.go:207: exec user process caused "exec format error"

Il fatto è che per kube-state-metrics viene utilizzata un'immagine del progetto CoreOS, che non è disponibile per ARM:

kubectl -n monitoring get deployments.apps prometheus-kube-state-metrics -o=jsonpath={.spec.template.spec.containers[].image}
quay.io/coreos/kube-state-metrics:v1.9.7

Ho dovuto fare un po' di ricerche e trovare, per esempio, quest'immagine. Per utilizzarla, aggiorniamo il rilascio specificando quale immagine utilizzare per kube-state-metrics:

helm upgrade prometheus --namespace monitoring stable/prometheus --set server.ingress.enabled=True --set server.ingress.hosts={"prometheus.home.pi"} --set kube-state-metrics.image.repository=carlosedp/kube-state-metrics --set kube-state-metrics.image.tag=v1.9.6

Controlliamo che tutto sia partito:

root@pi-control:~# kubectl -n monitoring get po
NAME                                             READY   STATUS              RESTARTS   AGE
prometheus-alertmanager-df65d99d4-6d27g          2/2     Running             0          5m56s
prometheus-kube-state-metrics-5dc5fd89c6-ztmqr   1/1     Running             0          5m56s
prometheus-node-exporter-49zll                   1/1     Running             0          5m51s
prometheus-node-exporter-vwl44                   1/1     Running             0          4m20s
prometheus-pushgateway-c547cfc87-k28qx           1/1     Running             0          5m56s
prometheus-server-85666fd794-z9qnc               2/2     Running             0          4m52s

Grafana e cert-manager

Per grafici e dashboard installiamo Grafana:

helm install grafana --namespace monitoring stable/grafana --set ingress.enabled=true --set ingress.hosts={"grafana.home.pi"}

Alla fine dell'output ci mostreranno come ottenere la password di accesso:

kubectl get secret --namespace monitoring grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo

Per ordinare i certificati installiamo cert-manager. Per la sua installazione ci rivolgiamo a documentazione, che offre i comandi appropriati per Helm:

helm repo add jetstack https://charts.jetstack.io

helm install 
  cert-manager jetstack/cert-manager 
  --namespace cert-manager 
  --version v0.16.0 
  --set installCRDs=true

Per certificati autofirmati per uso domestico, questo è più che sufficiente. Se invece è necessario ottenere lo stesso Let’s Encrypt, è necessario configurare anche un issuer di cluster. Maggiori dettagli sono disponibili nel nostro articolo «Certificati SSL da Let’s Encrypt con cert-manager in Kubernetes».

Personalmente, ho optato per l'opzione presente nell'esempio della documentazione, decidendo che l'opzione di staging di LE fosse sufficiente. Modifico l'e-mail nell'esempio, salvo in un file e aggiungo al cluster (cert-manager-cluster-issuer.yaml):

kubectl create -f cert-manager-cluster-issuer.yaml

Ora posso ordinare un certificato, ad esempio per Grafana. Per questo sarà necessario un dominio e l'accesso al cluster dall'esterno. Ho già un dominio e ho configurato il traffico inoltrando le porte 80 e 443 sul mio router domestico secondo il servizio ingress-controller creato:

kubectl -n ingress-nginx get svc
NAME                                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.2.206.61            80:31303/TCP,443:30498/TCP   23d

In questo caso, la porta 80 è mappata su 31303 e la 443 su 30498. (Le porte vengono generate casualmente, quindi potrebbero essere diverse per voi.)

Ecco un esempio di certificato (cert-manager-grafana-certificate.yaml):

apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: grafana
  namespace: monitoring
spec:
  dnsNames:
    - grafana.home.pi
  secretName: grafana-tls
  issuerRef:
    kind: ClusterIssuer
    name: letsencrypt-staging

Aggiungiamolo al cluster:

kubectl create -f cert-manager-grafana-certificate.yaml

Dopo questo, verrà creato una risorsa Ingress, attraverso la quale verrà effettuata la validazione con Let’s Encrypt:

root@pi-control:~# kubectl -n monitoring get ing
NAME                        CLASS    HOSTS                        ADDRESS         PORTS   AGE
cm-acme-http-solver-rkf8l      grafana.home.pi      192.168.88.31   80      72s
grafana                        grafana.home.pi      192.168.88.31   80      6d17h
prometheus-server              prometheus.home.pi   192.168.88.31   80      8d

Dopo che la validazione è completata, vedremo che la risorsa certificate è pronta, e nel segreto sopra menzionato grafana-tls si trova il certificato e la chiave. Possiamo subito controllare chi ha emesso il certificato:

root@pi-control:~# kubectl -n monitoring get certificate
NAME      READY   SECRET        AGE
grafana   True    grafana-tls   13m

root@pi-control:~# kubectl -n monitoring get secrets grafana-tls -ojsonpath="{.data['tls.crt']}" | base64 -d | openssl x509 -issuer -noout
issuer=CN = Fake LE Intermediate X1

Torniamo a Grafana. Dobbiamo apportare alcune modifiche al suo rilascio Helm, aggiornando le impostazioni per TLS in base al certificato creato.

Per fare ciò, scarichiamo il chart, apportiamo le modifiche e lo aggiorniamo dalla directory locale:

helm pull --untar stable/grafana

Modifichiamo il file grafana/values.yaml impostazioni TLS:

  tls:
    - secretName: grafana-tls
      hosts:
        - grafana.home.pi

Qui possiamo anche configurare Prometheus installato come datasource:

datasources:
  datasources.yaml:
    apiVersion: 1
    datasources:
    - name: Prometheus
      type: prometheus
      url: http://prometheus-server:80
      access: proxy
      isDefault: true

Ora aggiorniamo il chart Grafana dalla directory locale:

helm upgrade grafana --namespace monitoring ./grafana  --set ingress.enabled=true --set ingress.hosts={"grafana.home.pi"}

Verifichiamo che in Ingress grafana sia stato aggiunto il porto 443 e ci sia accesso tramite HTTPS:

root@pi-control:~# kubectl -n monitoring get ing grafana
NAME      CLASS    HOSTS                     ADDRESS         PORTS     AGE
grafana   <none>   grafana.home.pi           192.168.88.31   80, 443   63m

root@pi-control:~# curl -kI https://grafana.home.pi
HTTP/2 302
server: nginx/1.19.1
date: Tue, 28 Jul 2020 19:01:31 GMT
content-type: text/html; charset=utf-8
cache-control: no-cache
expires: -1
location: /login
pragma: no-cache
set-cookie: redirect_to=%2F; Path=/; HttpOnly; SameSite=Lax
x-frame-options: deny
strict-transport-security: max-age=15724800; includeSubDomains

Per dimostrare Grafana in azione, puoi scaricare e aggiungere dashboard per kube-state-metrics. Ecco come appare:

Kubernetes completo da zero su Raspberry Pi

Ti consiglio anche di aggiungere un dashboard per node exporter: mostrerà in dettaglio cosa sta succedendo con le "mali" (carico CPU, utilizzo della memoria, rete, disco, ecc.).

Dopo di che, considero che il cluster è pronto per ricevere e avviare applicazioni!

Nota sulla compilazione

Per compilare applicazioni per architettura ARM, ci sono almeno due opzioni. Prima di tutto, puoi compilare su un dispositivo ARM. Tuttavia, guardando l'attuale utilizzo di due Raspberry Pi, ho capito che non ce la faranno nemmeno a farlo. Quindi ho ordinato una nuova Raspberry Pi 4 (è più potente e ha ben 4 GB di RAM) — ho intenzione di compilare su di essa.

La seconda opzione è la creazione di un'immagine Docker multiarchitetturale su una macchina più potente. Per fare ciò, c'è l'estensione docker buildx. Se l'applicazione è scritta in un linguaggio compilabile, sarà necessaria una cross-compilation per ARM. Non descriverò tutte le impostazioni per questo percorso, poiché richiederebbe un articolo a parte. Adottando questo approccio, si possono ottenere immagini "universali": Docker, eseguito su una macchina ARM, caricherà automaticamente l'immagine corrispondente all'architettura.

Conclusione

L'esperimento effettuato ha superato tutte le mie aspettative: [almeno] un Kubernetes "vanilla" con il suo database si comporta dignitosamente su ARM, e durante la sua configurazione sono emersi solo alcune piccole questioni.

I Raspberry Pi 3B+ reggono il carico della CPU, ma le loro schede SD rappresentano un chiaro collo di bottiglia. I colleghi mi hanno consigliato che in alcune versioni c'è la possibilità di avviarsi da USB, dove è possibile collegare un SSD: allora la situazione dovrebbe migliorare.

Ecco un esempio del carico della CPU durante l'installazione di Grafana:

Kubernetes completo da zero su Raspberry Pi

Per esperimenti e per "provare", ritengo che un cluster Kubernetes sui "Raspberry" trasmetta di gran lunga meglio le sensazioni di utilizzo rispetto a Minikube, poiché tutti i componenti del cluster si installano e funzionano "professionalmente".

C'è un'idea di aggiungere all'cluster l'intero ciclo CI/CD, completamente implementato su Raspberry Pi. Inoltre, sarei felice se qualcuno potesse condividere la propria esperienza riguardo la configurazione di K8s su AWS Graviton.

P.S. Sì, la "produzione" potrebbe essere più vicina di quanto pensassi:

Kubernetes completo da zero su Raspberry Pi

P.P.S.

Leggete anche nel nostro blog:

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster