Buongiorno a tutti, vi presentiamo una breve guida che vi porterà ad avere un cluster kubernetes completo e funzionante (sia nel cloud che in bare metal) in grado di avere storage in provisioning dinamica.
La guida sarà divisa in 4 parti:
- Rancher + Kubernetes
- Kubernetes + Heketi (GlusterFS)
- Collegare il proprio Registry privato a Kubernetes
Rancher + Kubernetes
Ci sono tantissimi modi per avviare un cluster kubernetes, uno di questi è Rancher.
Rancher è molto versatile perché permette di gestire più cluster Kubernetes con una unica interfaccia web unificata. Vi permette inoltre di gestire i nodi del cluster, l'aggiunta, la rimozione , il deploy di applicazioni tramite una webshell e altro.
In questa guida vedremo come avviare un cluster kubernetes di 5 nodi, utilizzando 3 nodi come orchestrator + etcd e 2 nodi come computing semplice (solo esecuzione dei pod).
I requisiti sono:
- 1 macchina con docker esterna dal cluster dove avvieremo il container di Rancher server
- 5 macchine virtuali ubuntu, dove andremo ad installare i prerequisiti e i vari nodi di kubernetes
- dimestichezza con i comandi Kubectl per la gestione di un cluster Kubernetes
- tutti i nodi devono essere nella stessa rete
Partiamo quindi con l'installazione di rancher server.
Lanciamo il comando che troviamo nel quickstart https://rancher.com/quick-start/
sudo docker run -d --restart=unless-stopped -p 8080:8080 rancher/server:stable
Una volta completato l'avvio, basterà accedere all'indirizzo ip del computer/server in cui abbiamo avviato rancher/server, es: http://10.42.0.2:8080
Ora dovremo creare un nuovo environment
kubernetes all'interno di Rancher, vediamo un piccolo video su come fare:
A questo punto dovremo aggiungere gli hosts, che saranno le altre nostre 5 macchine, clicchiamo dunque su add a hosts.
Prerequisiti dei nodi del cluster:
- Installazione di docker ad una versione compatibile con Rancher e Kubernetes http://rancher.com/docs/rancher/v1.6/en/hosts/
Brevemente possiamo installare la versione corretta di docker lanciando questo comando:
curl https://releases.rancher.com/install-docker/1.12.sh | sh
Partiamo prima di tutto a creare i 3 nodi master + etcd, per chi non ha mai usato Kubernetes sono i nodi che gestiscono il workload all'interno del cluster e contengono le informazioni di stato (etcd)
Vi verrà chiesto qual'è l'indirizzo pubblico accessibile dalle altre macchine di rancher server, inserite l'ip della rete lan comune.
Prendiamo il comando appena copiato e lanciamolo nei primi tre nodi, in questo modo si avvierà un container privilegiato che comincerà ad installare i servizi di Kubernetes all'interno del nodo. Notiamo che sono stati aggiunti due label, orchestration
e etcd
a true
.
NB: Lanciare un container alla volta e attendere che nella schermata hosts i servizi siano tutti attivi.
Vedremo una situazione simile alla seguente:
Bisognerà attendere fino a quando tutti i servizi avranno un pallino verde. Una volta che il primo hosts sarà attivo, potremo collegarci alla ui di kubernetes e verificarne lo stato.
In questo momento possiamo procedere all'aggiunta degli altri due nodi master, uno alla volta.
Completata l'installazione avremo una situazione così:
Procediamo dunque all'avvio dei due nodi computing:
Notiamo invece in questo caso, che è stato aggiunto solo il label compute
a true
.
Lanciamo il comando appena copiato nelle altre due macchine, e attendiamo che vadano online anche loro.
Alla fine di tutto il setup, potremo cominciare ad usare il nostro cluster kubernetes! Per prima cosa verifichiamo dalla webshell che il sistema sia up, con il comando:
kubectl get nodes
Avremo un output come il seguente:
NAME STATUS ROLES AGE VERSION
nodokube-1.c.nth-passage-183120.internal Ready <none> 17m v1.8.10-rancher1
nodokube-2.c.nth-passage-183120.internal Ready <none> 14m v1.8.10-rancher1
nodokube-3.c.nth-passage-183120.internal Ready <none> 9m v1.8.10-rancher1
nodokube-4.c.nth-passage-183120.internal Ready <none> 4m v1.8.10-rancher1
nodokube-5.c.nth-passage-183120.internal Ready <none> 4m v1.8.10-rancher1
Questo conclude la guida sull'installazione di un cluster Kubernetes utilizzando Rancher.
Kubernetes + Heketi
Passiamo ora a parlare dello storage in Kubernetes. Il modo più ovvio per creare i persistent volumes
e i persistent volume claims
è il modo manuale.
Si sceglie l'eventuale driver e si confiugrano i persistent volumes
che poi verranno utilizzati dai persistent volume claims
.
Tutto ciò però rende macchinosa e lenta la gestione dello storage in kubernetes. Per questo motivo sono stati creati dei sistemi di volume management con i quali si possono creare persistent volumes on demand tramite i persistent volume claims che vengono richiesti. Questa funzionalità si basa su un altro concetto di Kubernetes chiamato Storage Classes.
In questa guida vedremo come attivare Heketi, un provisioner che gestisce volumi basati su tecnologia GlusterFS. Questi volumi avranno come proprietà intrinseca la ridondanza e l'HA, perché creeremo una topologia basata sul mirroring di 3 nodi.
Il requisito per poter seguire questa guida passo passo è:
- Un cluster Kubernetes esistente
- Poter aggiungere 3 nodi kubernetes i quali hanno ognuno un disco aggiuntivo collegato alla macchina (in parole povere un /dev/sdb non formattato)
Nel mio caso ho 3 nodi aggiuntivi che ho chiamato diversamente per poterli riconoscere:
> kubectl get nodes
NAME STATUS ROLES AGE VERSION
nodokube-1.c.nth-passage-183120.internal Ready <none> 1d v1.8.10-rancher1
nodokube-2.c.nth-passage-183120.internal Ready <none> 1d v1.8.10-rancher1
nodokube-3.c.nth-passage-183120.internal Ready <none> 1d v1.8.10-rancher1
nodokube-4.c.nth-passage-183120.internal Ready <none> 1d v1.8.10-rancher1
nodokube-6-g1.c.nth-passage-183120.internal Ready <none> 1d v1.8.10-rancher1
nodokube-7-g2.c.nth-passage-183120.internal Ready <none> 1d v1.8.10-rancher1
nodokube-8-g3.c.nth-passage-183120.internal Ready <none> 1d v1.8.10-rancher1
- nodokube-6-g1
- nodokube-7-g2
- nodokube-8-g3
Questi 3 nodi contengono un disco aggiuntivo ssd da 30GB l'uno collegato in /dev/sdb
.
Quello che faremo sarà seguire la guida presente in https://github.com/heketi/heketi/blob/master/docs/admin/install-kubernetes.md
Verifichiamo il firewall
Nel mio caso i nodi sono tutti ubuntu, quindi non ho bisogno di aprire alcuna porta nel firewall. Nel caso in cui siano CentOs o altre distribuizioni, bisogna lanciare i comandi di iptables per aprire le porte di gluster nei nodi interessati:
iptables -N HEKETI
iptables -A HEKETI -p tcp -m state --state NEW -m tcp --dport 24007 -j ACCEPT
iptables -A HEKETI -p tcp -m state --state NEW -m tcp --dport 24008 -j ACCEPT
iptables -A HEKETI -p tcp -m state --state NEW -m tcp --dport 2222 -j ACCEPT
iptables -A HEKETI -p tcp -m state --state NEW -m multiport --dports 49152:49251 -j ACCEPT
service iptables save
Prerequisiti aggiuntivi
Nella guida ufficiale non sono indicati alcuni passaggi fondamentali, tra cui aggiungere in tutti i nodi del cluster il driver per il collegamento ad un volume gluster e ai 3 nodi che conterranno i pod di glusterfs la possibilità di gestire volumi in thin provision.
Dobbiamo quindi fare in tutti i nodi questi due comandi:
apt-get install -y glusterfs-client
modprobe dm_thin_pool
Deploy
GlusterFS daemonset
Creiamo il primo file, glusterfs-daemonset.json
{
"kind": "DaemonSet",
"apiVersion": "extensions/v1beta1",
"metadata": {
"name": "glusterfs",
"labels": {
"glusterfs": "deployment"
},
"annotations": {
"description": "GlusterFS Daemon Set",
"tags": "glusterfs"
}
},
"spec": {
"template": {
"metadata": {
"name": "glusterfs",
"labels": {
"glusterfs-node": "daemonset"
}
},
"spec": {
"nodeSelector": {
"storagenode" : "glusterfs"
},
"hostNetwork": true,
"containers": [
{
"image": "gluster/gluster-centos:latest",
"imagePullPolicy": "Always",
"name": "glusterfs",
"volumeMounts": [
{
"name": "glusterfs-heketi",
"mountPath": "/var/lib/heketi"
},
{
"name": "glusterfs-run",
"mountPath": "/run"
},
{
"name": "glusterfs-lvm",
"mountPath": "/run/lvm"
},
{
"name": "glusterfs-etc",
"mountPath": "/etc/glusterfs"
},
{
"name": "glusterfs-logs",
"mountPath": "/var/log/glusterfs"
},
{
"name": "glusterfs-config",
"mountPath": "/var/lib/glusterd"
},
{
"name": "glusterfs-dev",
"mountPath": "/dev"
},
{
"name": "glusterfs-cgroup",
"mountPath": "/sys/fs/cgroup"
}
],
"securityContext": {
"capabilities": {},
"privileged": true
},
"readinessProbe": {
"timeoutSeconds": 3,
"initialDelaySeconds": 60,
"exec": {
"command": [
"/bin/bash",
"-c",
"systemctl status glusterd.service"
]
}
},
"livenessProbe": {
"timeoutSeconds": 3,
"initialDelaySeconds": 60,
"exec": {
"command": [
"/bin/bash",
"-c",
"systemctl status glusterd.service"
]
}
}
}
],
"volumes": [
{
"name": "glusterfs-heketi",
"hostPath": {
"path": "/var/lib/heketi"
}
},
{
"name": "glusterfs-run"
},
{
"name": "glusterfs-lvm",
"hostPath": {
"path": "/run/lvm"
}
},
{
"name": "glusterfs-etc",
"hostPath": {
"path": "/etc/glusterfs"
}
},
{
"name": "glusterfs-logs",
"hostPath": {
"path": "/var/log/glusterfs"
}
},
{
"name": "glusterfs-config",
"hostPath": {
"path": "/var/lib/glusterd"
}
},
{
"name": "glusterfs-dev",
"hostPath": {
"path": "/dev"
}
},
{
"name": "glusterfs-cgroup",
"hostPath": {
"path": "/sys/fs/cgroup"
}
}
]
}
}
}
}
E lanciamo il comando di creazione
$ kubectl create -f glusterfs-daemonset.json
daemonset "glusterfs" created
A questo punto non abbiamo ancora i pod di glusterfs avviati, bisogna prima taggare i nodi con la chiave corretta. Procediamo quindi al tag come indicato nel daemonset
"spec": {
"nodeSelector": {
"storagenode" : "glusterfs"
}
$ kubectl label node nodokube-6-g1.c.nth-passage-183120.internal storagenode=glusterfs
node "nodokube-6-g1.c.nth-passage-183120.internal" labeled
$ kubectl label node nodokube-7-g2.c.nth-passage-183120.internal storagenode=glusterfs
node "nodokube-7-g2.c.nth-passage-183120.internal" labeled
$ kubectl label node nodokube-8-g3.c.nth-passage-183120.internal storagenode=glusterfs
node "nodokube-8-g3.c.nth-passage-183120.internal" labeled
A questo punto il daemonset
troverà i nodi con il tag corretto e procederà alla creazione dei pod:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
glusterfs-296z2 0/1 Running 0 36s
glusterfs-4cd5v 0/1 Running 0 32s
glusterfs-pgvgt 0/1 Running 0 40s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
glusterfs-296z2 1/1 Running 0 2m
glusterfs-4cd5v 1/1 Running 0 1m
glusterfs-pgvgt 1/1 Running 0 2m
Heketi service account
Ora dobbiamo creare un service account
per heketi, creiamo il file heketi-service-account.json
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"name": "heketi-service-account"
}
}
e lanciamo quindi il comando di creazione:
$ kubectl create -f heketi-service-account.json
serviceaccount "heketi-service-account" created
Ora dobbiamo fare in modo che questo service account possa controllare i pod glusterfs. Creiamo quindi un role binding
al service account
appena creato
$ kubectl create clusterrolebinding heketi-gluster-admin --clusterrole=edit --serviceaccount=default:heketi-service-account
clusterrolebinding "heketi-gluster-admin" created
A questo punto creiamo un secret
che avrà al suo interno le configurazioni dell'istanza di Heketi. La configurazione dovrà contenere il kubernetes
executor per far si che il server Heketi possa controllare i pod glusterfs.
Creiamo quindi il file heketi.json
{
"_port_comment": "Heketi Server Port Number",
"port": "8080",
"_use_auth": "Enable JWT authorization. Please enable for deployment",
"use_auth": false,
"_jwt": "Private keys for access",
"jwt": {
"_admin": "Admin has access to all APIs",
"admin": {
"key": "My Secret"
},
"_user": "User only has access to /volumes endpoint",
"user": {
"key": "My Secret"
}
},
"_glusterfs_comment": "GlusterFS Configuration",
"glusterfs": {
"_executor_comment": "Execute plugin. Possible choices: mock, kubernetes, ssh",
"executor": "kubernetes",
"_db_comment": "Database file name",
"db": "/var/lib/heketi/heketi.db",
"kubeexec": {
"rebalance_on_expansion": true
},
"sshexec": {
"rebalance_on_expansion": true,
"keyfile": "/etc/heketi/private_key",
"fstab": "/etc/fstab",
"port": "22",
"user": "root",
"sudo": false
}
},
"_backup_db_to_kube_secret": "Backup the heketi database to a Kubernetes secret when running in Kubernetes. Default is off.",
"backup_db_to_kube_secret": false
}
ATTENZIONE in questo esempio abbiamo disattivato l'autenticazione.
Lanciamo la creazione di questo secret:
$ kubectl create secret generic heketi-config-secret --from-file=./heketi.json
secret "heketi-config-secret" created
Avvio del pod di bootstrap di Heketi
A questo punto lanciamo un pod di bootstrap che si occuperà di creare il nostro cluster e di salvare la configurazione di heketi per il deploy successivo di produzione.
Creiamo il file heketi-bootstrap.json
{
"kind": "List",
"apiVersion": "v1",
"items": [
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "deploy-heketi",
"labels": {
"glusterfs": "heketi-service",
"deploy-heketi": "support"
},
"annotations": {
"description": "Exposes Heketi Service"
}
},
"spec": {
"selector": {
"name": "deploy-heketi"
},
"ports": [
{
"name": "deploy-heketi",
"port": 8080,
"targetPort": 8080
}
]
}
},
{
"kind": "Deployment",
"apiVersion": "extensions/v1beta1",
"metadata": {
"name": "deploy-heketi",
"labels": {
"glusterfs": "heketi-deployment",
"deploy-heketi": "deployment"
},
"annotations": {
"description": "Defines how to deploy Heketi"
}
},
"spec": {
"replicas": 1,
"template": {
"metadata": {
"name": "deploy-heketi",
"labels": {
"name": "deploy-heketi",
"glusterfs": "heketi-pod",
"deploy-heketi": "pod"
}
},
"spec": {
"serviceAccountName": "heketi-service-account",
"containers": [
{
"image": "heketi/heketi:dev",
"imagePullPolicy": "Always",
"name": "deploy-heketi",
"env": [
{
"name": "HEKETI_EXECUTOR",
"value": "kubernetes"
},
{
"name": "HEKETI_FSTAB",
"value": "/var/lib/heketi/fstab"
},
{
"name": "HEKETI_SNAPSHOT_LIMIT",
"value": "14"
},
{
"name": "HEKETI_KUBE_GLUSTER_DAEMONSET",
"value": "y"
}
],
"ports": [
{
"containerPort": 8080
}
],
"volumeMounts": [
{
"name": "db",
"mountPath": "/var/lib/heketi"
},
{
"name": "config",
"mountPath": "/etc/heketi"
}
],
"readinessProbe": {
"timeoutSeconds": 3,
"initialDelaySeconds": 3,
"httpGet": {
"path": "/hello",
"port": 8080
}
},
"livenessProbe": {
"timeoutSeconds": 3,
"initialDelaySeconds": 30,
"httpGet": {
"path": "/hello",
"port": 8080
}
}
}
],
"volumes": [
{
"name": "db"
},
{
"name": "config",
"secret": {
"secretName": "heketi-config-secret"
}
}
]
}
}
}
}
]
}
e quindi lanciamolo, verra creato un service
e un deployment
chiamati deploy-heketi
:
$ kubectl create -f heketi-bootstrap.json
service "deploy-heketi" created
deployment "deploy-heketi" created
Verifichiamo lo stato del pod:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
deploy-heketi-6b496b5777-9f2rp 0/1 Running 0 26s
glusterfs-296z2 1/1 Running 0 1h
glusterfs-4cd5v 1/1 Running 0 1h
glusterfs-pgvgt 1/1 Running 0 1h
kubectl get pods
NAME READY STATUS RESTARTS AGE
deploy-heketi-6b496b5777-9f2rp 1/1 Running 0 1m
glusterfs-296z2 1/1 Running 0 1h
glusterfs-4cd5v 1/1 Running 0 1h
glusterfs-pgvgt 1/1 Running 0 1h
Ora che abbiamo lanciato il pod di bootstrap possiamo configurare il portforwarding nella nostra macchina per utilizzare heketi-cli (scaricate heketi-cli da https://github.com/heketi/heketi/releases/).
Prendiamo il nome del pod di heketi, nel mio caso deploy-heketi-6b496b5777-9f2rp
e lanciamo il seguente comando
$ kubectl port-forward deploy-heketi-6b496b5777-9f2rp :8080
Forwarding from 127.0.0.1:64622 -> 8080
Nel mio caso è stato fatto il forward della porta 64622 del mio host verso il pod di deploy-heketi.
Verifichiamone il funzionamento:
$ curl http://localhost:64622/hello
Hello from Heketi
Settiamoci per comidita la variabile d'ambiente contenente l'indirizzo di heketi in modo da non dover scrivere ogni volta l'indirizzo del pod
$ export HEKETI_CLI_SERVER=http://localhost:64622
Caricamento topologia server gluster
A questo punto dobbiamo caricare la topologia dei nostri nodi contenenti i pod daemonset di glusterfs, indicando anche qual'è il disco della macchina che verrà formattato per l'utilizzo con i volumi di glusterfs.
Creiamo il file topology-load.json
{
"clusters": [
{
"nodes": [
{
"node": {
"hostnames": {
"manage": [
"nodokube-6-g1.c.nth-passage-183120.internal"
],
"storage": [
"10.142.0.8"
]
},
"zone": 1
},
"devices": [
"/dev/sdb"
]
},
{
"node": {
"hostnames": {
"manage": [
"nodokube-7-g2.c.nth-passage-183120.internal"
],
"storage": [
"10.142.0.9"
]
},
"zone": 1
},
"devices": [
"/dev/sdb"
]
},
{
"node": {
"hostnames": {
"manage": [
"nodokube-8-g3.c.nth-passage-183120.internal"
],
"storage": [
"10.142.0.7"
]
},
"zone": 1
},
"devices": [
"/dev/sdb"
]
}
]
}
]
}
Notiamo alcuni parametri:
- storage: è stato inserito l'ip fisso del nodo contenente il pod
- manage: è stato inserito l'hostname del nodo, nel mio caso nodokube-6-g1.c.nth-passage-183120.internal, etc
- devices: è stato inserito il path del disco aggiunto alla macchina virtuale
Carichiamo quindi la topologia via heketi-cli
nel nostro pod heketi:
$ ./heketi-cli topology load --json=topology-load.json
Creating cluster ... ID: 9ed46f67a517d5e46b9245e1214c2c03
Allowing file volumes on cluster.
Allowing block volumes on cluster.
Creating node nodokube-6-g1.c.nth-passage-183120.internal ... ID: 0379d0bb941a80c6ec65fed344306602
Adding device /dev/sdb ... OK
Creating node nodokube-7-g2.c.nth-passage-183120.internal ... ID: 7d271bdb173887adc09ecfc677604378
Adding device /dev/sdb ... OK
Creating node nodokube-8-g3.c.nth-passage-183120.internal ... ID: 8a547e452d0442f7e44a317e75c9fba8
Adding device /dev/sdb ... OK
Salvataggio database di heketi in un volume gluster
Qui arriva un punto abbastanza "magico". Dobbiamo creare un volume provisionato da deploy-heketi
che verrà poi usato dal vero pod heketi che utlizzeremo.
Chidiamo a heketi di crearci il volume
$ ./heketi-cli setup-openshift-heketi-storage
Saving heketi-storage.json
$ kubectl create -f heketi-storage.json
secret "heketi-storage-secret" created
endpoints "heketi-storage-endpoints" created
service "heketi-storage-endpoints" created
job "heketi-storage-copy-job" created
Dobbiamo attendere che il job sia completato, dopodiché possiamo procedere all'eliminazione dei pod di deploy
Verifichiamo lo stato con:
$ kubectl get jobs
NAME DESIRED SUCCESSFUL AGE
heketi-storage-copy-job 1 1 1m
Eliminiamo il deploy di bootstrap:
$ kubectl delete all,service,jobs,deployment,secret --selector="deploy-heketi"
deployment "deploy-heketi" deleted
job "heketi-storage-copy-job" deleted
pod "deploy-heketi-6b496b5777-9f2rp" deleted
service "deploy-heketi" deleted
secret "heketi-storage-secret" deleted
Creazione del long-term Heketi
Creiamo il file di deploy di heketi finale, heketi-deployment.json
{
"kind": "List",
"apiVersion": "v1",
"items": [
{
"kind": "Secret",
"apiVersion": "v1",
"metadata": {
"name": "heketi-db-backup",
"labels": {
"glusterfs": "heketi-db",
"heketi": "db"
}
},
"data": {
},
"type": "Opaque"
},
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "heketi",
"labels": {
"glusterfs": "heketi-service",
"deploy-heketi": "support"
},
"annotations": {
"description": "Exposes Heketi Service"
}
},
"spec": {
"selector": {
"name": "heketi"
},
"ports": [
{
"name": "heketi",
"port": 8080,
"targetPort": 8080
}
]
}
},
{
"kind": "Deployment",
"apiVersion": "extensions/v1beta1",
"metadata": {
"name": "heketi",
"labels": {
"glusterfs": "heketi-deployment"
},
"annotations": {
"description": "Defines how to deploy Heketi"
}
},
"spec": {
"replicas": 1,
"template": {
"metadata": {
"name": "heketi",
"labels": {
"name": "heketi",
"glusterfs": "heketi-pod"
}
},
"spec": {
"serviceAccountName": "heketi-service-account",
"containers": [
{
"image": "heketi/heketi:dev",
"imagePullPolicy": "Always",
"name": "heketi",
"env": [
{
"name": "HEKETI_EXECUTOR",
"value": "kubernetes"
},
{
"name": "HEKETI_FSTAB",
"value": "/var/lib/heketi/fstab"
},
{
"name": "HEKETI_SNAPSHOT_LIMIT",
"value": "14"
},
{
"name": "HEKETI_KUBE_GLUSTER_DAEMONSET",
"value": "y"
}
],
"ports": [
{
"containerPort": 8080
}
],
"volumeMounts": [
{
"mountPath": "/backupdb",
"name": "heketi-db-secret"
},
{
"name": "db",
"mountPath": "/var/lib/heketi"
},
{
"name": "config",
"mountPath": "/etc/heketi"
}
],
"readinessProbe": {
"timeoutSeconds": 3,
"initialDelaySeconds": 3,
"httpGet": {
"path": "/hello",
"port": 8080
}
},
"livenessProbe": {
"timeoutSeconds": 3,
"initialDelaySeconds": 30,
"httpGet": {
"path": "/hello",
"port": 8080
}
}
}
],
"volumes": [
{
"name": "db",
"glusterfs": {
"endpoints": "heketi-storage-endpoints",
"path": "heketidbstorage"
}
},
{
"name": "heketi-db-secret",
"secret": {
"secretName": "heketi-db-backup"
}
},
{
"name": "config",
"secret": {
"secretName": "heketi-config-secret"
}
}
]
}
}
}
}
]
}
Lanciamo il deploy:
$ kubectl create -f heketi-deployment.json
service "heketi" created
deployment "heketi" created
Ricreiamoci la regola di forward per testare che heketi funzioni
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
glusterfs-296z2 1/1 Running 0 2h
glusterfs-4cd5v 1/1 Running 0 2h
glusterfs-pgvgt 1/1 Running 0 2h
heketi-84684b87c-hqgld 1/1 Running 0 24s
$ kubectl port-forward heketi-84684b87c-hqgld :8080
Forwarding from 127.0.0.1:49337 -> 8080
$ export HEKETI_CLI_SERVER=http://localhost:49337
Verifichiamo il cluster:
$ ./heketi-cli cluster list
Clusters:
Id:9ed46f67a517d5e46b9245e1214c2c03 [file][block]
$ ./heketi-cli volume list
Id:e38d822489a5a5401f30c41d3c24fb8c Cluster:9ed46f67a517d5e46b9245e1214c2c03 Name:heketidbstorage
Creiamo una Storage Classes
Per prima cosa dobbiamo scoprire qual'è il clusterip del pod heketi:
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
heketi ClusterIP 10.43.105.131 <none> 8080/TCP 9m
heketi-storage-endpoints ClusterIP 10.43.124.82 <none> 1/TCP 14m
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 1d
Nel mio caso 10.43.105.131
. Creiamo il file heketi-storageclasses.yaml
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
name: gluster-heketi
provisioner: kubernetes.io/glusterfs
parameters:
resturl: "http://10.43.105.131:8080"
restuser: "joe" # non servono nell'esempio non essendoci autenticazione
restuserkey: "My Secret Life" # non servono nell'esempio non essendoci autenticazione
E creiamola con:
$ kubectl create -f heketi-storageclasses.yaml
storageclass "gluster-heketi" created
Rendiamola default per tutti i prossimi deployment che utilizzando persistent volume claim
:
$ kubectl patch storageclass gluster-heketi -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
storageclass "gluster-heketi" patched
PVC di test!
Creiamo finalmente il nostro persistent volume claim di test, chiamiamolo test-pvc.yml
:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gluster1
annotations:
volume.beta.kubernetes.io/storage-class: gluster-heketi
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
Ora arriva il momento della verità, la richiesta di creare un persistent volume al volo a heketi.
$ kubectl create -f test-pvc.yaml
persistentvolumeclaim "gluster1" created
Verifichiamo:
$ kubectl get pvc,pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc/gluster1 Bound pvc-9fd5feda-3725-11e8-902a-02611b0ceca9 2Gi RWX gluster-heketi 25s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv/pvc-9fd5feda-3725-11e8-902a-02611b0ceca9 2Gi RWX Delete Bound default/gluster1 gluster-heketi 19s
YEAH ci siamo riusciti! Ora non dovremo più preoccuparci di dover creare manualmente i pv all'interno di kubernetes!
Kubernetes + Private Docker Registry
Vediamo ora le modalità di aggiunta di un docker regisrtry
privato in modo tale che kubernetes possa fare il pull delle immagini.
La guida ufficiale si trova qui https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/.
Io vi darò un overview più rapida.
Iniziamo con il creare un secret che conterrà le nostre credenziali di accesso al registry:
$ kubectl create secret docker-registry regcred --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>
secret "regcred" created
Sostituite:
<your-registry-server>
con l'address del vostro registry<your-name>
con l'username di collegamento<your-pword>
con la password<your-email>
con la vostra email
... e abbiamo finito.
Se dovessimo avviare un pod presente con un immagine presente nel nostro registry privato, dovremmo aggiungere al nostro yaml la direttiva imagePullSecrets
indicando quale secret andiamo ad usare. Nel caso dell'esempio:
apiVersion: v1
kind: Pod
metadata:
name: private-reg
spec:
containers:
- name: private-reg-container
image: <your-private-image>
imagePullSecrets:
- name: regcred
Conclusioni
Abbiamo visto come creare un cluster Kubernetes da zero, creargli uno dei modi di deploy automatico dei volumi e come utilizzare il proprio registry docker per le immagini private.
In questo modo abbiamo un vero cluster funzionante con tutti i pezzi basilari per testare e sviluppare applicazioni cloud native!
Comments