
NÀr Kubernetes var version v1.0.0 fanns det volympluggar (volume plugins). De behövdes för att koppla Kubernetes-system till lagringslösningar för persistenta (bestÀndiga) data i containrar. Antalet var begrÀnsat, och bland de första var lagringsleverantörer som GCE PD, Ceph, AWS EBS och andra.
Pluggarna levererades tillsammans med Kubernetes, vilket gav dem namnet in-tree. Men mÄnga ansÄg att den befintliga uppsÀttningen av sÄdana pluggar var otillrÀcklig. Hantverkare lade till enkla pluggar i Kubernetes-kÀrnan med hjÀlp av patchar, och byggde sedan sin egen version av Kubernetes för att installera den pÄ sina servrar. Men med tiden insÄg Kubernetes-utvecklarna att fisket problemet inte kunde lösas. MÀnniskor behövde en fiskespö. Och i versionen Kubernetes v1.2.0 dök det upp...
Flexvolume-plugin: ett enkelt fiskespö
Kubernetes-utvecklarna skapade FlexVolume-plugin, som var en logisk omslutning av variabler och metoder för att arbeta med Flexvolume-drivrutiner implementerade av tredjepartsutvecklare.
LÄt oss stanna upp och titta nÀrmare pÄ vad FlexVolume-drivrutinen representerar. Det Àr en exekveringsfil (binarfil, Python-skript, Bash-skript, etc.), som vid körning tar emot kommandoradsargument och returnerar ett meddelande med förutbestÀmda fÀlt i JSON-format. Första kommandoradsargumentet Àr alltid metoden, och de övriga argumenten Àr dess parametrar.

Anslutningsschema för CIFS-delningar i OpenShift. Flexvolume-drivrutinen ligger mitt i centrum.
Minimalt antal metoder ser ut sÄ hÀr:
flexvolume_driver mount # ansvarar för att ansluta volymen till podden
# Format för det returnerade meddelandet:
{
"status": "Success"/"Failure"/"Not supported",
"message": "Anledningen till att denna status returnerades",
}
flexvolume_driver unmount # ansvarar för att koppla ifrÄn volymen frÄn podden
# Format för det returnerade meddelandet:
{
"status": "Success"/"Failure"/"Not supported",
"message": "Anledningen till att denna status returnerades",
}
flexvolume_driver init # ansvarar för att initiera pluginet
# Format för det returnerade meddelandet:
{
"status": "Success"/"Failure"/"Not supported",
"message": "Anledningen till att denna status returnerades",
// Anger om drivrutinen anvÀnder metoderna attach/detach
"capabilities":{"attach": True/False}
} AnvÀndning av metoder attach och detach bestÀmmer vilket scenario kubelet kommer att agera i nÀr drivrutinen anropas. Det finns ocksÄ specifika metoder expandvolume och expandfs, som ansvarar för dynamisk storleksÀndring av volymen.
Som exempel pÄ de förÀndringar som metoden tillför expandvolume, och tillsammans med den - möjligheten att Àndra storlek pÄ volymer i realtid kan du lÀsa om i Rook Ceph Operator.
HÀr Àr ett exempel pÄ implementering av Flexvolume-drivrutinen för att arbeta med NFS:
usage() {
err "Ogiltig anvÀndning. AnvÀndning: "
err "t$0 init"
err "t$0 mount <monteringskatalog> <json parametrar>"
err "t$0 unmount <monteringskatalog>"
exit 1
}
err() {
echo -ne $* 1>&2
}
log() {
echo -ne $* >&1
}
ismounted() {
MOUNT=`findmnt -n ${MNTPATH} 2>\/dev\/null | cut -d' ' -f1`
if [ "${MOUNT}" == "${MNTPATH}" ]; then
echo "1"
else
echo "0"
fi
}
domount() {
MNTPATH=$1
NFS_SERVER=$(echo $2 | jq -r '.server')
SHARE=$(echo $2 | jq -r '.share')
if [ $(ismounted) -eq 1 ] ; then
log '{"status": "FramgÄng"}'
exit 0
fi
mkdir -p ${MNTPATH} &> \/dev\/null
mount -t nfs ${NFS_SERVER}:\/ ${SHARE} ${MNTPATH} &> \/dev\/null
if [ $? -ne 0 ]; then
err "{ "status": "Misslyckande", "message": "Misslyckades med att montera ${NFS_SERVER}:${SHARE} vid ${MNTPATH}"}"
exit 1
fi
log '{"status": "FramgÄng"}'
exit 0
}
unmount() {
MNTPATH=$1
if [ $(ismounted) -eq 0 ] ; then
log '{"status": "FramgÄng"}'
exit 0
fi
umount ${MNTPATH} &> \/dev\/null
if [ $? -ne 0 ]; then
err "{ "status": "Misslyckades", "message": "Misslyckades med att avmontera volymen vid ${MNTPATH}"}"
exit 1
fi
log '{"status": "FramgÄng"}'
exit 0
}
op=$1
if [ "$op" = "init" ]; then
log '{"status": "FramgÄng", "capabilities": {"attach": false}}'
exit 0
fi
if [ $# -lt 2 ]; then
usage
fi
shift
case "$op" in
mount)
domount $*
;;
unmount)
unmount $*
;;
*)
log '{"status": "Inte stödd"}'
exit 0
esac
exit 1SÄ efter att ha förberett den körbara filen behöver du ladda upp drivrutinen till Kubernetes-klustret. Drivrutinen ska finnas pÄ varje nod i klustret enligt den förutbestÀmda sökvÀgen. Som standard valdes:
/usr/libexec/kubernetes/kubelet-plugins/volume/exec/ĐžĐŒŃ_ĐżĐŸŃŃаĐČŃĐžĐșа_Ń
ŃĐ°ĐœĐžĐ»ĐžŃа~ĐžĐŒŃ_ĐŽŃаĐčĐČĐ”Ńа/
⊠men vid anvĂ€ndning av olika distributioner av Kubernetes (OpenShift, RancherâŠ) kan sökvĂ€gen vara annorlunda.
Problematik med Flexvolume: hur ska man rÀtt hantera det?
Att distribuera Flexvolume-drivrutinen pÄ noderna i klustret visade sig vara en utmaning. Om du gör operationen en gÄng för hand Àr det lÀtt att stöta pÄ situationen dÀr nya noder lÀggs till i klustret: pÄ grund av tillsÀttning av en ny nod, automatisk horisontell skalning eller - vilket Àr vÀrre - att en nod byts ut pÄ grund av fel. I detta fall mÄste du arbeta med lagring pÄ dessa noder Àr omöjligt, sÄ lÀnge du fortfarande manuellt lÀgger till Flexvolume-drivrutinen pÄ dem.
Lösningen pÄ detta problem var en av Kubernetes-primitiverna - DaemonSet. NÀr en ny nod lÀggs till i klustret tilldelas en pod automatiskt frÄn vÄr DaemonSet, som kopplar ett lokalt volym pÄ sökvÀgen för att hitta Flexvolume-drivrutiner. Vid framgÄngsrik skapelse kopierar pod nödvÀndiga filer för drivrutinens funktion pÄ disken.
HÀr Àr ett exempel pÄ en sÄdan DaemonSet för att distribuera Flexvolume-plugin:
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: flex-set
spec:
template:
metadata:
name: flex-deploy
labels:
app: flex-deploy
spec:
containers:
- image:
name: flex-deploy
securityContext:
privileged: true
volumeMounts:
- mountPath: /flexmnt
name: flexvolume-mount
volumes:
- name: flexvolume-mount
hostPath:
path:⊠och ett exempel pÄ ett Bash-skript för att distribuera Flexvolume-drivrutinen:
#!/bin/sh
set -o errexit
set -o pipefail
VENDOR=k8s.io
DRIVER=nfs
driver_dir=$VENDOR${VENDOR:+"~"}${DRIVER}
if [ ! -d "/flexmnt/$driver_dir" ]; then
mkdir "/flexmnt/$driver_dir"
fi
cp "/$DRIVER" "/flexmnt/$driver_dir/.$DRIVER"
mv -f "/flexmnt/$driver_dir/.$DRIVER" "/flexmnt/$driver_dir/$DRIVER"
while : ; do
sleep 3600
doneViktigt att komma ihÄg Àr att kopieringsoperationen inte Àr atomÀr. Det finns stor risk att kubelet börjar anvÀnda drivrutinen innan förberedelseprocessen Àr klar, vilket kan orsaka fel i systemets funktion. En korrekt strategi skulle vara att först kopiera drivrutinsfilerna under ett annat namn, och dÀrefter anvÀnda en atomÀr byteoperation.

Arbetsschema för Ceph i Rook-operatören: Flexvolume-drivrutinen i diagrammet Àr belÀgen inom Rook-agenten.
Ett annat problem vid anvÀndning av Flexvolume-drivrutiner Àr att för de flesta lagringslösningar pÄ noden i klustret mÄste nödvÀndig programvara installeras (till exempel paketet ceph-common för Ceph). Ursprungligen var Flexvolume-pluginet inte tÀnkt att implementera sÄ komplexa system.
Den ursprungliga lösningen pÄ detta problem kan ses i implementationen av Flexvolume-drivrutinen hos Rook-operatören:
SjÀlva drivrutinen Àr utformad som en RPC-klient. IPC-socketen för kommunikation ligger i samma katalog som sjÀlva drivrutinen. Vi minns att det vore bra att anvÀnda en DaemonSet för att kopiera drivrutinsfiler, vilket kopplar en katalog med drivrutinen som volym. Efter kopiering av nödvÀndiga drivrutinsfiler överlever rook den hÀr podden, och ansluter till IPC-socketen via den anslutna volymen som en fullstÀndig RPC-server. Paketet ceph-common Àr redan installerat inuti poddcontainern. IPC-socketen ger sÀkerhet för att kubelet kommer att kommunicera med just den podden som finns pÄ samma nod. Allt genialt Àr enkelt!..
FarvÀl, vÄra kÀra... in-tree plugins!
Utvecklare av Kubernetes har upptÀckt att antalet lagringsplugins i kÀrnan Àr tjugo. FörÀndringar i var och en av dem gÄr igenom hela releasescykeln för Kubernetes pÄ ett eller annat sÀtt.
Det visar sig att för att anvÀnda en ny version av lagringsplugin, mÄste hela klustret uppgraderas. Dessutom kan du kanske bli förvÄnad över att den nya versionen av Kubernetes plötsligt blir inkompatibel med den Linux-kÀrna som anvÀnds... SÄ du torkar bort tÄrarna och, medan du biter i lÀpparna, diskuterar du med chefer och anvÀndare om nÀr uppgraderingen av Linux-kÀrnan och Kubernetes-klustret ska göras. Med en möjlig stillestÄndstid för tjÀnsterna.
Situationen Àr mer Àn komisk, eller hur? Hela gemenskapen har insett att detta förfarande inte fungerar. Genom en kraftfull ÄtgÀrd har utvecklarna av Kubernetes meddelat att nya plugins för lagring inte lÀngre kommer att accepteras i kÀrnan. Dessutom, som vi redan vet, har flera brister upptÀckts i implementeringen av Flexvolume-pluginet...
Den senaste pluginen som tillsats för att för alltid reda ut frÄgan om persistenta datalagringar Àr CSI. Dess alfa-version, som mer fullstÀndigt kallas Utanför-TrÀd CSI Volym Plugins, presenterades i release .
Container Storage Interface, eller snurrande CSI 3000!
Först och frÀmst vill jag pÄpeka att CSI inte bara Àr en volymplugin, utan en riktig för skapande av anvÀndarspecifika komponenter för datalagring.Det förvÀntades att system för containerorkestrering, sÄsom Kubernetes och Mesos, skulle "lÀra sig" att arbeta med komponenter implementerade enligt denna standard. Och nu har Kubernetes redan lÀrt sig.
Hur fungerar CSI-pluginet i Kubernetes? CSI-pluginet arbetar med speciella drivrutiner (CSI-drivrutiner) skrivna av tredjepartsutvecklare. En CSI-drivrutin i Kubernetes mÄste minst bestÄ av tvÄ komponenter (poddar):
- Controller â hanterar externa persistenta lagringar. Det distribueras som en gRPC-server, dĂ€r den primĂ€ra anvĂ€ndningen Ă€r
StatefulSet. - Node â ansvarar för montering av persistenta lagringar till klusterknutar. OcksĂ„ implementerat som en gRPC-server, men för den anvĂ€nds den primĂ€ra anvĂ€ndningen
DaemonSet.

Arbetsflödet för CSI-pluginet i Kubernetes
Du kan lÀsa om nÄgra andra detaljer om CSI:s funktionalitet, till exempel i artikeln "», vi publicerade för ett Är sedan.
Fördelarna med en sÄdan implementering
- För grundlĂ€ggande saker â som till exempel registrering av drivrutiner för noder â har utvecklarna av Kubernetes implementerat en uppsĂ€ttning containrar. Det Ă€r inte lĂ€ngre nödvĂ€ndigt att sjĂ€lva generera JSON-svar med capabilities, som gjordes för Flexvolume-plugin.
- IstÀllet för att "lasta" körbara filer pÄ noderna lÀgger vi nu ut poddar i klustret. Detta Àr vad vi frÄn början förvÀntar oss av Kubernetes: alla processer sker inom containrar som deployas med hjÀlp av Kubernetes-primitiver.
- För att implementera komplexa drivrutiner behöver vi inte lÀngre utveckla en RPC-server och RPC-klient. Klienten har utvecklarna av Kubernetes implementerat Ät oss.
- Ăverföring av argument för arbete via gRPC-protokollet Ă€r mycket enklare, mer flexibelt och mer pĂ„litligt Ă€n att överföra dem via kommandoradsargument. För att förstĂ„ hur man lĂ€gger till stöd för mĂ€tningar av volymanvĂ€ndning i CSI genom att lĂ€gga till en standardiserad gRPC-metod kan man bekanta sig med för drivrutinen vsphere-csi.
- Kommunikationen sker via IPC-sockets för att undvika förvirring om till vilken pod kubelet har skickat begÀran.
Den hÀr listan pÄminner dig kanske om nÄgot? Fördelarna med CSI Àr lösningen pÄ de problemen, som inte beaktades vid utvecklingen av Flexvolume-plugin.
Slutsatser
CSI som standard för implementering av anpassade plugins för interaktion med datalagring har mottagits mycket varmt av samhÀllet. Dessutom, tack vare sina fördelar och mÄngsidighet, skapas CSI-drivrutiner Àven för lagringssystem som Ceph eller AWS EBS, plugins för vilka lades till redan i den första versionen av Kubernetes.
I början av 2019 meddelades att in-tree plugins . Stödet för Flexvolume-plugin kommer att fortsÀtta, men utvecklingen av nya funktioner för det kommer att upphöra.
Vi har redan erfarenhet av att anvÀnda ceph-csi, vsphere-csi och Àr redo att lÀgga till den hÀr listan! SÄ hÀr lÄngt klarar CSI de uppgifter som Älagts den utmÀrkt, och vi fÄr se vad som hÀnder dÀrnÀst.
Kom ihÄg att allt nytt Àr vÀl omprövat gammalt!
P.S.
LÀs Àven i vÄr blogg:
- «»;
- «»;
- «».
KĂ€lla: habr.com
