Carga de trabalho com estado (StatefulSet)

Por que um StatefulSet é necessário

Em implantação, falamos sobre implantação. Os pods no controlador de implantação têm um recurso comum, ou seja, cada pod tem o mesmo nome e endereço IP. Quando necessário, a implantação pode criar um novo pod por meio do modelo de pod; quando não for necessário, a implantação pode excluir qualquer pod.

Mas, em alguns cenários, isso não atende à demanda. Por exemplo, em alguns cenários distribuídos, quando cada pod deve ter seu próprio estado separado, como um banco de dados distribuído, cada pod requer um armazenamento separado, então a implantação Não é possível atender à demanda.

Sob análise detalhada dos requisitos de aplicativos com estado, a característica do estado distribuído é principalmente que os papéis de cada parte do aplicativo são diferentes (ou seja, a divisão de trabalho). Por exemplo, o banco de dados está ativo e em espera e há dependências entre os pods. Correspondente ao Kubernetes é o pod Os requisitos são os seguintes:

  • O pod pode ser encontrado por outros pods, o que exige que o pod tenha um logotipo fixo.
  • Cada pod tem um armazenamento separado. Depois que o pod é excluído e restaurado, os dados lidos devem ser os mesmos de antes, caso contrário, o status será inconsistente.
    O Kubernetes fornece um StatefulSet para resolver esse problema, que é o seguinte:
  1. StatefulSet fornece um nome fixo para cada Pod. O nome do Pod adiciona um sufixo fixo de 0 a N. Depois que o Pod é reprogramado, o nome do Pod e o HostName permanecem inalterados.
  2. StatefulSet fornece um nome de domínio de acesso fixo para cada Pod por meio do Headless Service. O conceito de serviço será apresentado em detalhes em Service.
  3. O StatefulSet garante que os mesmos dados persistentes possam ser acessados ​​após o pod ser reprogramado, criando um PVC com um identificador fixo.

Carga de trabalho com estado (StatefulSet)

O seguinte experimentará essas características de StatefulSet criando um StatefulSet.

Criar serviço sem cabeça

Conforme mencionado anteriormente, a criação de um Statefulset requer um serviço sem comando para acesso ao Pod. O conceito de serviço será apresentado em detalhes em Serviço. Aqui, primeiro apresentaremos o método de criação de um serviço sem comando.

Use o seguinte arquivo para descrever o Headless Service, onde:

  • spec.clusterIP: deve ser definido como None, o que significa Headless Service.
  • spec.ports.port: número da porta de comunicação entre pods.
  • spec.ports.name: o nome da porta de comunicação entre os pods.
    apiVersion: v1
    kind: Service       # 对象类型为Service
    metadata:
    name: nginx
    labels:
    app: nginx
    spec:
    ports:
    - name: nginx     # Pod间通信的端口名称
      port: 80        # Pod间通信的端口号
    selector:
    app: nginx        # 选择标签为app:nginx的Pod
    clusterIP: None     # 必须设置为None,表示Headless Service

Execute o seguinte comando para criar um serviço sem cabeça.

# kubectl create -f headless.yaml 
service/nginx created

O serviço pode ser consultado após a criação.

# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx        ClusterIP   None         <none>        80/TCP    5s

Criar Statefulset

A definição YAML de Statefulset é basicamente a mesma de outros objetos, com duas diferenças principais:

  • serviceName especifica qual Statefulset de serviço sem comando usa e o nome do serviço sem comando precisa ser preenchido.
  • volumeClaimTemplates é usado para solicitar uma declaração persistente de PVC. Um modelo chamado data é definido aqui. Ele criará um PVC para cada Pod. O storageClassName especifica o tipo de armazenamento persistente, que será descrito em detalhes em PV, PVC e StorageClass; volumeMounts É para montar armazenamento para Pod. É claro que você pode excluir os campos volumeClaimTemplates e volumeMounts se não precisar armazená-los.
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
    name: nginx
    spec:
    serviceName: nginx                             # headless service的名称
    replicas: 3
    selector:
    matchLabels:
      app: nginx
    template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: container-0
          image: nginx:alpine
          resources:
            limits:
              cpu: 100m
              memory: 200Mi
            requests:
              cpu: 100m
              memory: 200Mi
          volumeMounts:                           # Pod挂载的存储
          - name:  data
            mountPath:  /usr/share/nginx/html     # 存储挂载到/usr/share/nginx/html
      imagePullSecrets:
        - name: default-secret
    volumeClaimTemplates:
    - metadata:
      name: data
    spec:
      accessModes:
      - ReadWriteMany
      resources:
        requests:
          storage: 1Gi
      storageClassName: csi-nas                   # 持久化存储的类型

Execute o seguinte comando para criar.

# kubectl create -f statefulset.yaml 
statefulset.apps/nginx created

Depois que o comando é executado, consulte o StatefulSet e o Pod, você pode ver que o sufixo do nome do Pod começa de 0 a 2, aumentando um a um.

# kubectl get statefulset
NAME    READY   AGE
nginx   3/3     107s

# kubectl get pods
NAME      READY   STATUS    RESTARTS   AGE
nginx-0   1/1     Running   0          112s
nginx-1   1/1     Running   0          69s
nginx-2   1/1     Running   0          39s

Nesse ponto, se você excluir manualmente o pod nginx-1 e, em seguida, consultar o pod novamente, verá que o StatefulSet recriou um pod com o mesmo nome. É possível ver que o nginx-1 acabou de ser criado no tempo de criação 5s.

# kubectl delete pod nginx-1
pod "nginx-1" deleted

# kubectl get pods
NAME      READY   STATUS    RESTARTS   AGE
nginx-0   1/1     Running   0          3m4s
nginx-1   1/1     Running   0          5s
nginx-2   1/1     Running   0          1m10s

Insira o contêiner para visualizar o nome do host do contêiner, você pode ver que também é nginx-0, nginx-1 e nginx-2.

# kubectl exec nginx-0 -- sh -c 'hostname'
nginx-0
# kubectl exec nginx-1 -- sh -c 'hostname'
nginx-1
# kubectl exec nginx-2 -- sh -c 'hostname'
nginx-2

Ao mesmo tempo, você pode dar uma olhada nos PVCs criados pelo StatefulSet.Você pode ver que esses PVCs são nomeados com "nome do PVC-StatefulSet nome-número" e estão no estado Bound.

# kubectl get pvc
NAME           STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
data-nginx-0   Bound    pvc-f58bc1a9-6a52-4664-a587-a9a1c904ba29   1Gi        RWX            csi-nas        2m24s
data-nginx-1   Bound    pvc-066e3a3a-fd65-4e65-87cd-6c3fd0ae6485   1Gi        RWX            csi-nas        101s
data-nginx-2   Bound    pvc-a18cf1ce-708b-4e94-af83-766007250b0c   1Gi        RWX            csi-nas        71s

ID de rede de StatefulSet

Depois que o StatefulSet é criado, você pode ver que o pod tem um nome fixo. Como funciona o serviço Headless? Ele usa DNS para fornecer um nome de domínio fixo para o pod, de modo que o pod possa ser acessado usando o nome de domínio, mesmo se o pod for recriado Como resultado, o endereço IP do pod muda e o nome de domínio não muda.

Depois que o serviço sem cabeça é criado, o IP de cada pod terá um nome de domínio no formato a seguir.

<pod-name>. <svc-name>. <namespace> .svc.cluster.local

Por exemplo, os nomes de domínio dos três pods acima são:

  • nginx-0.nginx.default.svc.cluster.local
  • nginx-1.nginx.default.svc.cluster.local
  • nginx-1.nginx.default.svc.cluster.local
    pode ser omitido durante o acesso real . <namespace> .svc.cluster.local .

O comando a seguir usará a imagem tutum / dnsutils para criar um pod, entre no contêiner do pod, use o comando nslookup para visualizar o nome de domínio correspondente ao pod, você verá que o endereço IP do pod pode ser resolvido. Aqui você pode ver que o endereço do servidor DNS é 10.247.3.10, que é a instalação padrão do plug-in CoreDNS ao criar um cluster CCE para fornecer serviços DNS. A função do CoreDNS será descrita em detalhes na rede Kubernetes posteriormente.

$ kubectl run -i --tty --image tutum/dnsutils dnsutils --restart=Never --rm /bin/sh 
If you don't see a command prompt, try pressing enter.
/ # nslookup nginx-0.nginx
Server:         10.247.3.10
Address:        10.247.3.10#53
Name:   nginx-0.nginx.default.svc.cluster.local
Address: 172.16.0.31

/ # nslookup nginx-1.nginx
Server:         10.247.3.10
Address:        10.247.3.10#53
Name:   nginx-1.nginx.default.svc.cluster.local
Address: 172.16.0.18

/ # nslookup nginx-2.nginx
Server:         10.247.3.10
Address:        10.247.3.10#53
Name:   nginx-2.nginx.default.svc.cluster.local
Address: 172.16.0.19

Nesse ponto, se você excluir manualmente esses dois pods, consultar o IP do pod recriado pelo StatefulSet e usar o comando nslookup para resolver o nome de domínio do pod, poderá descobrir que nginx-0.nginx e nginx-1.nginx ainda podem resolver o pod correspondente. Isso garante que a identidade da rede StatefulSet permaneça inalterada.

StatefulSet armazena estado

Conforme mencionado acima, o StatefulSet pode ser usado para armazenamento persistente por meio de PVC para garantir que os mesmos dados persistentes possam ser acessados ​​depois que o Pod for reprogramado. Quando o Pod for excluído, o PVC não será excluído.

Figura 1 Processo de reconstrução do pod de StatefulSet
Carga de trabalho com estado (StatefulSet)

O seguinte irá verificar como isso é feito por meio de operações reais, executar o seguinte comando, escrever algum conteúdo no diretório / usr / share / nginx / html de nginx-1, por exemplo, modificar o conteúdo de index.html para "hello mundo".

# kubectl exec nginx-1 -- sh -c 'echo hello world > /usr/share/nginx/html/index.html'

Após a modificação, se você acessá-lo no Pod “http://localhost”,那就会返回“hello world”.

# kubectl exec -it nginx-1 -- curl localhost
hello world

Nesse ponto, se você excluir manualmente o pod nginx-1 e, em seguida, consultá-lo novamente, verá que o StatefulSet recriou um pod com o mesmo nome e que o nginx-1 acabou de ser criado no tempo de criação 4s.

# kubectl delete pod nginx-1
pod "nginx-1" deleted

# kubectl get pods
NAME       READY   STATUS    RESTARTS   AGE
nginx-0    1/1     Running   0          14m
nginx-1    1/1     Running   0          4s
nginx-2    1/1     Running   0          13m

Se você visitar a página index.html do pod novamente, verá que "hello world" ainda é retornado, o que significa que o pod ainda está acessando o mesmo armazenamento.

# kubectl exec -it nginx-1 -- curl localhost
hello world

Acho que você gosta

Origin blog.51cto.com/14051317/2553698
Recomendado
Clasificación