Implemente uma aplicação

Este documento descreve como implementar uma aplicação no Google Distributed Cloud.

Antes de começar

Para implementar uma carga de trabalho, tem de ter um cluster de utilizador, híbrido ou autónomo capaz de executar cargas de trabalho.

Crie uma implementação

Os passos seguintes criam uma implementação no cluster:

  1. Copie o seguinte manifesto para um ficheiro com o nome my-deployment.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-deployment
    spec:
      selector:
        matchLabels:
          app: metrics
          department: sales
      replicas: 3
      template:
        metadata:
          labels:
            app: metrics
            department: sales
        spec:
          containers:
          - name: hello
            image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"
    
  2. Use kubectl apply para criar a implementação:

    kubectl apply -f my-deployment.yaml --kubeconfig CLUSTER_KUBECONFIG
    

    Substitua CLUSTER_KUBECONFIG pelo caminho do ficheiro kubeconfig para o seu cluster.

  3. Obtenha informações básicas sobre a sua implementação para confirmar que foi criada com êxito:

    kubectl get deployment my-deployment --kubeconfig CLUSTER_KUBECONFIG
    

    A saída mostra que a implementação tem três pods que estão todos disponíveis:

    NAME            READY   UP-TO-DATE   AVAILABLE   AGE
    my-deployment   3/3     3            3           27s
    
  4. Apresente a lista dos pods na sua implementação:

    kubectl get pods --kubeconfig CLUSTER_KUBECONFIG
    

    A saída mostra que a sua implementação tem 3 pods em execução:

    NAME                             READY   STATUS    RESTARTS   AGE
    my-deployment-869f65669b-5259x   1/1     Running   0          34s
    my-deployment-869f65669b-9xfrs   1/1     Running   0          34s
    my-deployment-869f65669b-wn4ft   1/1     Running   0          34s
    
  5. Obtenha informações detalhadas sobre a sua implementação:

    kubectl get deployment my-deployment --output yaml --kubeconfig CLUSTER_KUBECONFIG
    

    O resultado mostra detalhes sobre a especificação e o estado da implementação:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      ...
      generation: 1
      name: my-deployment
      namespace: default
      ...
    spec:
      ...
      replicas: 3
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: metrics
          department: sales
      ...
        spec:
          containers:
          - image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0
            imagePullPolicy: IfNotPresent
            name: hello
            resources: {}
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
    status:
      availableReplicas: 3
      conditions:
      - lastTransitionTime: "2023-06-29T16:17:17Z"
        lastUpdateTime: "2023-06-29T16:17:17Z"
        message: Deployment has minimum availability.
        reason: MinimumReplicasAvailable
        status: "True"
        type: Available
      - lastTransitionTime: "2023-06-29T16:17:12Z"
        lastUpdateTime: "2023-06-29T16:17:17Z"
        message: ReplicaSet "my-deployment-869f65669b" has successfully progressed.
        reason: NewReplicaSetAvailable
        status: "True"
        type: Progressing
      observedGeneration: 1
      readyReplicas: 3
      replicas: 3
      updatedReplicas: 3
    
  6. Descreva a sua implementação:

    kubectl describe deployment my-deployment --kubeconfig CLUSTER_KUBECONFIG
    

    A saída mostra detalhes formatados sobre a implementação, incluindo o ReplicaSet associado:

    Name:                   my-deployment
    Namespace:              default
    CreationTimestamp:      Thu, 29 Jun 2023 16:17:12 +0000
    Labels:                 <none>
    Annotations:            deployment.kubernetes.io/revision: 1
    Selector:               app=metrics,department=sales
    Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=metrics
              department=sales
      Containers:
      hello:
        Image:        us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0
        Port:         <none>
        Host Port:    <none>
        Environment:  <none>
        Mounts:       <none>
      Volumes:        <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    NewReplicaSetAvailable
    OldReplicaSets:  <none>
    NewReplicaSet:   my-deployment-869f65669b (3/3 replicas created)
    Events:
      Type    Reason             Age    From                   Message
      ----    ------             ----   ----                   -------
      Normal  ScalingReplicaSet  6m50s  deployment-controller  Scaled up replica set my-deployment-869f65669b to 3
    

Crie um serviço do tipo LoadBalancer

Uma forma de expor a sua implementação a clientes fora do cluster é criar um serviço do Kubernetes do tipo LoadBalancer.

Para criar um serviço do tipo LoadBalancer:

  1. Copie o seguinte manifesto para um ficheiro com o nome my-service.yaml:

    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
    spec:
      selector:
        app: metrics
        department: sales
      type: LoadBalancer
      ports:
      - port: 80
        targetPort: 8080
    

    Seguem-se os aspetos importantes a compreender acerca do serviço neste exercício:

    • Qualquer Pod que tenha a etiqueta app: metrics e a etiqueta department: sales é membro do serviço. Os pods em my-deployment têm estas etiquetas.

    • Quando um cliente envia um pedido para o serviço na porta TCP80, o pedido é encaminhado para um pod membro na porta TCP 8080.

    • Cada membro do pod tem de ter um contentor que esteja a ouvir na porta TCP 8080.

    Por predefinição, o contentor hello-app escuta na porta TCP 8080. Pode ver esta definição de porta consultando o Dockerfile e o código-fonte da app.

  2. Use kubectl apply para criar o serviço no cluster:

    kubectl apply -f my-service.yaml --kubeconfig CLUSTER_KUBECONFIG
    

    Substitua CLUSTER_KUBECONFIG pelo caminho do ficheiro kubeconfig para o seu cluster.

  3. Veja o seu serviço:

    kubectl get service my-service --output yaml --kubeconfig CLUSTER_KUBECONFIG
    

    O resultado é semelhante ao seguinte:

    apiVersion: v1
    kind: Service
    metadata:
      ...
      name: my-service
      namespace: default
      ...
    spec:
      allocateLoadBalancerNodePorts: true
      clusterIP: 10.96.2.165
      clusterIPs:
      - 10.96.2.165
      externalTrafficPolicy: Cluster
      internalTrafficPolicy: Cluster
      ipFamilies:
      - IPv4
      ipFamilyPolicy: SingleStack
      ports:
      - nodePort: 31565
        port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: metrics
        department: sales
      sessionAffinity: None
      type: LoadBalancer
    status:
      loadBalancer:
        ingress:
        - ip: 192.168.1.13
    

    Na saída anterior, pode ver que o seu serviço tem um clusterIP e um endereço IP externo. Também tem um nodePort, um port e um targetPort.

    O clusterIP não é relevante para este exercício. O endereço IP externo (status.loadBalancer.ingress.ip) provém do intervalo de endereços que especificou quando definiu os conjuntos de endereços do equilibrador de carga (spec.loadBalancer.addressPools) no ficheiro de configuração do cluster.

    Por exemplo, considere os valores apresentados no resultado anterior para o seu serviço:

    • Endereço IP externo: 192.168.1.13
    • port: 80
    • nodePort: 31565
    • targetPort: 8080

    Um cliente envia um pedido para 192.168.1.13 na porta TCP 80. O pedido é encaminhado para o balanceador de carga e, a partir daí, é encaminhado para um pod membro na porta TCP 8080.

  4. Ligue para o seu serviço:

    curl INGRESS_IP_ADDRESS
    

    Substitua INGRESS_IP_ADDRESS pelo endereço IP de entrada na secção status do serviço que obteve no passo anterior (status.loadBalancer.ingress).

    O resultado mostra uma mensagem Hello, world!:

    Hello, world!
    Version: 2.0.0
    Hostname: my-deployment-869f65669b-wn4ft
    

Limites de portas do LoadBalancer

O tipo LoadBalancer é uma extensão do tipo NodePort. Assim, um serviço do tipo LoadBalancer tem um endereço IP do cluster e um ou mais valores nodePort. Por predefinição, o Kubernetes atribui portas de nós a serviços do tipo LoadBalancer. Estas atribuições podem esgotar rapidamente as portas de nós disponíveis dos 2768 atribuídos ao seu cluster. Para guardar portas de nós, desative a atribuição de portas de nós do balanceador de carga definindo o campo allocateLoadBalancerNodePorts como false na especificação do serviço LoadBalancer. Esta definição impede que o Kubernetes atribua portas de nós a serviços LoadBalancer. Para mais informações, consulte o artigo Desativar a atribuição de NodePort do equilibrador de carga na documentação do Kubernetes.

Segue-se um manifesto para criar um serviço que não usa nenhuma porta de nó:

apiVersion: v1
kind: Service
metadata:
  name: service-does-not-use-nodeports
spec:
  selector:
    app: my-app
  type: LoadBalancer
  ports:
  - port: 8000
  # Set allocateLoadBalancerNodePorts to false
  allocateLoadBalancerNodePorts: false

Elimine o seu serviço

Para eliminar o seu serviço:

  1. Use kubectl delete para eliminar o seu serviço do cluster:

    kubectl delete service my-service --kubeconfig CLUSTER_KUBECONFIG
    
  2. Verifique se o seu serviço foi eliminado:

    kubectl get services --kubeconfig CLUSTER_KUBECONFIG
    

    O resultado já não mostra my-service.

Elimine a sua implementação

Para eliminar a sua implementação:

  1. Use kubectl delete para eliminar a sua implementação do cluster:

    kubectl delete deployment my-deployment --kubeconfig CLUSTER_KUBECONFIG
    

    Verifique se a implementação foi eliminada:

    kubectl get deployments --kubeconfig CLUSTER_KUBECONFIG
    

    O resultado já não mostra my-deployment.

O que se segue?

Crie um serviço e uma entrada