StorageClass
No artigo anterior, aprendemos a usar PV e PVC, mas os PVs anteriores são todos estáticos, o que isso significa? Se eu quiser usar um PVC, devo criar manualmente um PV. Também dissemos que esse método não pode atender em grande parte às nossas necessidades. Por exemplo, temos um aplicativo que requer uma simultaneidade de armazenamento relativamente alta. Outro aplicativo tem requisitos mais altos para velocidade de leitura e gravação, especialmente para aplicativos do tipo StatefulSet, não é apropriado simplesmente usar PV estático. Nesse caso, precisamos usar PV dinâmico, que é o que queremos hoje. Aprenda StorageClass.
criar
Para usar o StorageClass, temos que instalar o programa de configuração automática correspondente. Por exemplo, se usarmos nfs como back-end de armazenamento aqui, então precisamos usar um programa de configuração automática nfs-client, que também o chamamos de Provisioner. Este programa usa nosso O servidor nfs foi configurado para criar volumes persistentes automaticamente, ou seja, para criar PV automaticamente para nós.
- O PV criado automaticamente
${namespace}-${pvcName}-${pvName}
é criado no diretório de dados compartilhado no servidor NFS com este formato de nomenclatura - E quando o PV for reciclado, ele será
archieved-${namespace}-${pvcName}-${pvName}
armazenado no servidor NFS neste formato de nomenclatura.
Claro, antes da implantação nfs-client
, precisamos primeiro instalar com sucesso o servidor nfs. Já passamos no artigo anterior. O endereço do serviço é 10.151.30.57 e o diretório de dados compartilhado é **/data/k8s/**, e então implantarmos nfs -client é suficiente, também podemos consultar diretamente a documentação do nfs-client: https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client, basta instalá-lo .
Etapa 1 : configurar a implantação, substituir os parâmetros correspondentes internos por nossa própria configuração nfs (nfs-client.yaml)
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-client-provisioner
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: quay.io/external_storage/nfs-client-provisioner:latest
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: fuseim.pri/ifs
- name: NFS_SERVER
value: 10.151.30.57
- name: NFS_PATH
value: /data/k8s
volumes:
- name: nfs-client-root
nfs:
server: 10.151.30.57
path: /data/k8s
Passo 2 : Substitua as variáveis de ambiente NFS_SERVER e NFS_PATH e, é claro, também inclua a configuração do nfs abaixo. Podemos ver que usamos um nfs-client-provisioner aqui, então também precisamos criar um sa e, em seguida, vinculá-lo Permissões serviceAccount
correspondentes : (nfs-client-sa.yaml)
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
Criamos um novo chamado nfs-client-provisioner aqui ServiceAccount
e, em seguida, vinculamos um chamado nfs-client-provisioner-runner ClusterRole
, que ClusterRole
declarou algumas permissões, incluindo adicionar persistentvolumes
, excluir, modificar, verificar etc. Permissões, para que possamos usar isso ServiceAccount
para criar PVs automaticamente.
Etapa 3 : Após a conclusão da declaração de implantação do nfs-client, podemos criar um StorageClass
objeto: (nfs-client-class.yaml)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: course-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
Declaramos um objeto chamado course-nfs-storage , observe que o valor correspondente StorageClass
abaixo deve ser igual ao valor da variável de ambiente PROVISIONER_NAME acima.provisioner
Deployment
Agora vamos criar esses objetos de recurso:
$ kubectl create -f nfs-client.yaml
$ kubectl create -f nfs-client-sa.yaml
$ kubectl create -f nfs-client-class.yaml
Após a conclusão da criação, verifique o status do recurso:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
...
nfs-client-provisioner-7648b664bc-7f9pk 1/1 Running 0 7h
...
$ kubectl get storageclass
NAME PROVISIONER AGE
course-nfs-storage fuseim.pri/ifs 11s
nova construção
StorageClass
O objeto de recurso acima foi criado com sucesso. Em seguida, vamos testar o PV dinâmico por meio de um exemplo. Primeiro, crie um objeto PVC: (test-pvc.yaml)
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
Aqui declaramos um objeto PVC, adotamos o modo de acesso ReadWriteMany, e solicitamos um espaço de 1Mi, mas podemos ver que não identificamos nenhuma informação associada a StorageClass no arquivo PVC acima, então se criarmos diretamente este objeto PVC agora , podemos vincular automaticamente ao objeto PV apropriado? Obviamente não (desde que não haja PV adequado), temos dois métodos aqui para usar o objeto StorageClass que criamos acima para criar automaticamente um PV adequado para nós:
- O primeiro método: adicione um identificador para declarar o objeto StorageClass neste objeto PVC, aqui podemos usar um atributo annotations para identificá-lo, conforme a seguir:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
annotations:
volume.beta.kubernetes.io/storage-class: "course-nfs-storage"
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
- O segundo método: podemos definir o StorageClass deste curso-nfs-storage como o back-end de armazenamento padrão do Kubernetes e podemos usar o comando kubectl patch para atualizar:
$ kubectl patch storageclass course-nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
Os dois métodos acima são possíveis. Claro, para não afetar o comportamento padrão do sistema, ainda usamos o primeiro método aqui, basta criá-lo diretamente:
$ kubectl create -f test-pvc.yaml
persistentvolumeclaim "test-pvc" created
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
...
test-pvc Bound pvc-73b5ffd2-8b4b-11e8-b585-525400db4df7 1Mi RWX course-nfs-storage 2m
...
Podemos ver que um objeto PVC chamado test-pvc foi criado com sucesso e o status já é Bound. Um objeto VOLUME correspondente também foi gerado? A coluna mais importante é STORAGECLASS. Ela tem valor agora? O objeto StorageClass que acabamos de criar é course-nfs-storage.
Então olhe para o objeto PV:
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
...
pvc-73b5ffd2-8b4b-11e8-b585-525400db4df7 1Mi RWX Delete Bound default/test-pvc course-nfs-storage 8m
...
Você pode ver se um objeto PV associado é gerado automaticamente, o modo de acesso é RWX e a política de reciclagem é Delete.Este objeto PV não é criado manualmente por nós, mas é criado automaticamente por meio de nosso objeto StorageClass acima. É assim que o StorageClass é criado.
teste
Em seguida, vamos usar um exemplo simples para testar o objeto PVC que declaramos acima com StorageClass: (test-pod.yaml)
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: busybox
imagePullPolicy: IfNotPresent
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-pvc
O Pod acima é muito simples. Ele usa um contêiner busybox para criar um arquivo SUCCESS no diretório /mnt e, em seguida, monta o diretório /mnt no objeto de recurso test-pvc recém-criado acima. A verificação é muito simples, apenas você precisa para verificar se existe um arquivo SUCCESS no diretório de dados compartilhado em nosso servidor nfs:
$ kubectl create -f test-pod.yaml
pod "test-pod" created
Em seguida, podemos visualizar os dados no diretório de dados compartilhados do servidor nfs:
$ ls /data/k8s/
default-test-pvc-pvc-73b5ffd2-8b4b-11e8-b585-525400db4df7
Podemos ver que há uma pasta com um nome longo abaixo. O método de nomenclatura desta pasta é o mesmo que nossas regras acima: ** namespace − {namespace}-name es p a ce − {pvcName}-${pvName}** é o mesmo e verifique se há outros arquivos nesta pasta:
$ ls /data/k8s/default-test-pvc-pvc-73b5ffd2-8b4b-11e8-b585-525400db4df7
SUCCESS
Vemos que há um arquivo SUCCESS abaixo, isso prova que nossa verificação acima foi bem-sucedida?
Além disso, podemos ver que estamos criando manualmente um objeto PVC aqui. No trabalho real, usar StorageClass é mais um tipo de serviço StatefulSet. Para o tipo de serviço StatefulSet, também podemos usar StorageClass diretamente por meio de um atributo volumeClaimTemplates, conforme a seguir : ( test-statefulset-nfs.yaml)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nfs-web
spec:
serviceName: "nginx"
replicas: 3
selector:
matchLabels:
app: nfs-web
template:
metadata:
labels:
app: nfs-web
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
annotations:
volume.beta.kubernetes.io/storage-class: course-nfs-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
Na verdade, sob volumeClaimTemplates está um template de um objeto PVC, que é similar ao template em nosso StatefulSet. Na verdade é um template de um Pod. Não criamos objetos PVC separadamente, mas usamos este template para criar objetos dinamicamente. Sim , esse método é muito usado no tipo de serviço StatefulSet.
Crie o objeto acima diretamente:
$ kubectl create -f test-statefulset-nfs.yaml
statefulset.apps "nfs-web" created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
...
nfs-web-0 1/1 Running 0 1m
nfs-web-1 1/1 Running 0 1m
nfs-web-2 1/1 Running 0 33s
...
Após a conclusão da criação, você pode ver que os três pods acima foram executados com sucesso e, em seguida, verifique o objeto PVC:
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
...
www-nfs-web-0 Bound pvc-cc36b3ce-8b50-11e8-b585-525400db4df7 1Gi RWO course-nfs-storage 2m
www-nfs-web-1 Bound pvc-d38285f9-8b50-11e8-b585-525400db4df7 1Gi RWO course-nfs-storage 2m
www-nfs-web-2 Bound pvc-e348250b-8b50-11e8-b585-525400db4df7 1Gi RWO course-nfs-storage 1m
...
Podemos ver se 3 objetos PVC também são gerados. O nome é composto do nome do modelo e do nome do Pod. Esses 3 objetos PVC também são vinculados. Obviamente, também podemos vê-lo quando verificamos o PV. 3 objetos PV correspondentes :
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
... 1d
pvc-cc36b3ce-8b50-11e8-b585-525400db4df7 1Gi RWO Delete Bound default/www-nfs-web-0 course-nfs-storage 4m
pvc-d38285f9-8b50-11e8-b585-525400db4df7 1Gi RWO Delete Bound default/www-nfs-web-1 course-nfs-storage 4m
pvc-e348250b-8b50-11e8-b585-525400db4df7 1Gi RWO Delete Bound default/www-nfs-web-2 course-nfs-storage 4m
...
Visualize o diretório de dados compartilhados no servidor nfs:
$ ls /data/k8s/
...
default-www-nfs-web-0-pvc-cc36b3ce-8b50-11e8-b585-525400db4df7
default-www-nfs-web-1-pvc-d38285f9-8b50-11e8-b585-525400db4df7
default-www-nfs-web-2-pvc-e348250b-8b50-11e8-b585-525400db4df7
...
Ele também tem três diretórios de dados correspondentes? É assim que usamos StorageClass. StorageClass é usado principalmente para serviços do tipo StatefulSet. Continuaremos a aprender sobre isso nos artigos a seguir.