Tráfego em escala de cinza e gerenciamento de versão do Knative Service

Este artigo apresenta principalmente a escala de cinza do tráfego do Knative Serving e demonstra como criar diferentes revisões e como fazer a escala de cinza de acordo com a proporção do tráfego entre as diferentes revisões por meio de um exemplo rest-api.

Implantar rest-api v1


  • Antes do teste de código  , precisamos escrever uma parte do código rest-api e ser capaz de distinguir entre as diferentes versões. Abaixo eu modifiquei com base no exemplo oficial.Para facilidade de uso, removi a dependência de github.com/gorilla/mux e substituí diretamente pelo pacote de sistema Golang net / http. Este código pode distinguir diferentes versões por meio da variável de ambiente RESOURCE.
package main



import (

    "fmt"

    "io/ioutil"

    "log"

    "net/http"

    "net/url"

    "os"



    "flag"

)



var resource string



func main() {

    flag.Parse()

    //router := mux.NewRouter().StrictSlash(true)



    resource = os.Getenv("RESOURCE")

    if resource == "" {

        resource = "NOT SPECIFIED"

    }



    root := "/" + resource

    path := root + "/{stockId}"



    http.HandleFunc("/", Index)

    http.HandleFunc(root, StockIndex)

    http.HandleFunc(path, StockPrice)



    if err := http.ListenAndServe(fmt.Sprintf(":%s", "8080"), nil); err != nil {

        log.Fatalf("ListenAndServe error:%s ", err.Error())

    }

}



func Index(w http.ResponseWriter, r *http.Request) {

    fmt.Fprintf(w, "Welcome to the %s app! \n", resource)

}



func StockIndex(w http.ResponseWriter, r *http.Request) {

    fmt.Fprintf(w, "%s ticker not found!, require /%s/{ticker}\n", resource, resource)

}



func StockPrice(w http.ResponseWriter, r *http.Request) {

    stockId := r.URL.Query().Get("stockId")



    url := url.URL{

        Scheme: "https",

        Host:   "api.iextrading.com",

        Path:   "/1.0/stock/" + stockId + "/price",

    }



    log.Print(url)



    resp, err := http.Get(url.String())

    if err != nil {

        fmt.Fprintf(w, "%s not found for ticker : %s \n", resource, stockId)

        return

    }



    defer resp.Body.Close()



    body, err := ioutil.ReadAll(resp.Body)



    fmt.Fprintf(w, "%s price for ticker %s is %s\n", resource, stockId, string(body))

}
  • O Dockerfile
    cria um arquivo chamado Dockerfile e copia o seguinte conteúdo para o arquivo. Execute o docker build --tag registry.cn-hangzhou.aliyuncs.com/knative-sample/rest-api-go:v1 --file ./Dockerfile. Comando para completar a compilação da imagem.

Quando você estiver testando, substitua registry.cn-hangzhou.aliyuncs.com/knative-sample/rest-api-go:v1 pelo seu próprio endereço de warehouse espelho.
Depois de compilar a imagem, execute docker push registry.cn-hangzhou.aliyuncs.com/knative-sample/rest-api-go:v1 para enviar a imagem para o warehouse de espelho.

FROM registry.cn-hangzhou.aliyuncs.com/knative-sample/golang:1.12 as builder



WORKDIR /go/src/github.com/knative-sample/rest-api-go

COPY . .



RUN CGO_ENABLED=0 GOOS=linux go build -v -o rest-api-go

FROM registry.cn-hangzhou.aliyuncs.com/knative-sample/alpine-sh:3.9

COPY --from=builder /go/src/github.com/knative-sample/rest-api-go/rest-api-go /rest-api-go



CMD ["/rest-api-go"]
  • Configuração do serviço A
    imagem já está lá, começamos a implantar o Knative Service. Salve o conteúdo a seguir em revision-v1.yaml e execute kubectl apply -f revision-v1.yaml para concluir a implantação do Knative Service.
apiVersion: serving.knative.dev/v1alpha1

kind: Service

metadata:

 name: stock-service-example

 namespace: default

spec:

 template:

   metadata:

     name: stock-service-example-v1

   spec:

     containers:

     - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/rest-api-go:v1

       env:

         - name: RESOURCE

           value: v1

       readinessProbe:

         httpGet:

           path: /

         initialDelaySeconds: 0

         periodSeconds: 3

A primeira instalação criará uma revisão chamada stock-service-example-v1 e 100% do tráfego irá para stock-service-example-v1.

 

Verifique os vários recursos do Serving Conforme mostrado na figura abaixo, vamos primeiro revisar os vários recursos envolvidos no Serving. A seguir, vamos dar uma olhada em cada configuração de recurso do revision-v1.yaml recém-implantado.

  • Knative Service
kubectl get ksvc stock-service-example --output yaml
  • Configuração Knative
kubectl get configuration -l \

"serving.knative.dev/service=stock-service-example" --output yaml
  • Revisão Knative
kubectl get revision -l \

"serving.knative.dev/service=stock-service-example" --output yaml
  • Rota Knative
kubectl get route -l \

"serving.knative.dev/service=stock-service-example" --output yaml

 

Acesso ao serviço rest-api
O nome do serviço que implantamos é: stock-service-example. Para acessar este serviço, você precisa obter o IP do Gateway do Istio e, em seguida, usar o domínio stock-service-example para vincular o host e iniciar uma solicitação curl. Eu escrevi um script para a conveniência de teste. Crie um arquivo run-test.sh, copie o conteúdo a seguir no arquivo e, em seguida, conceda ao arquivo permissões executáveis. Execute este script para obter o resultado do teste.

#!/bin/bash



SVC_NAME="stock-service-example"

export INGRESSGATEWAY=istio-ingressgateway

export GATEWAY_IP=`kubectl get svc $INGRESSGATEWAY --namespace istio-system --output jsonpath="{.status.loadBalancer.ingress[*]['ip']}"`

export DOMAIN_NAME=`kubectl get route ${SVC_NAME} --output jsonpath="{.status.url}"| awk -F/ '{print $3}'`



curl -H "Host: ${DOMAIN_NAME}" http://${GATEWAY_IP}

Resultado do teste: a
partir do resultado de saída do comando abaixo, você pode ver que as informações retornadas são v1, indicando que a solicitação atingiu a v1.

└─# ./run-test.sh

Welcome to the v1 app!

 

Fluxo de 50% da escala de cinza para v2

Modifique o serviço para criar uma revisão v2 e crie um arquivo revision-v2.yaml com o seguinte conteúdo:

apiVersion: serving.knative.dev/v1alpha1

kind: Service

metadata:

  name: stock-service-example

  namespace: default

spec:

  template:

    metadata:

      name: stock-service-example-v2

    spec:

      containers:

      - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/rest-api-go:v1

        env:

          - name: RESOURCE

            value: v2

        readinessProbe:

          httpGet:

            path: /

          initialDelaySeconds: 0

          periodSeconds: 3

  traffic:

  - tag: v1

    revisionName: stock-service-example-v1

    percent: 50

  - tag: v2

    revisionName: stock-service-example-v2

    percent: 50

  - tag: latest

    latestRevision: true

    percent: 0

Podemos comparar a versão v1 e a versão v2 para descobrir que a configuração de tráfego foi adicionada à versão v2 do Serviço. Cada revisão é especificada no tráfego. Execute kubectl apply -f revision-v2.yaml para instalar a configuração da versão v2. Em seguida, execute o script de teste e você verá que v1 e v2 nos resultados retornados agora representam basicamente 50% de cada. Abaixo está o resultado do meu teste real.

└─# ./run-test.sh

Welcome to the v2 app!

└─# ./run-test.sh

Welcome to the v1 app!

└─# ./run-test.sh

Welcome to the v2 app!

└─# ./run-test.sh

Welcome to the v1 app!

 

Verifique a revisão com antecedência

No exemplo da v2 mostrado acima, o tráfego é distribuído diretamente para a v2 quando a v2 é criada. Se houver um problema com a v2 neste momento, 50% do tráfego será anormal. Abaixo, mostramos como verificar se o novo serviço de revisão está normal antes de encaminhar o tráfego. Vamos criar outra versão v3.
Crie um arquivo revision-v3.yaml com o seguinte conteúdo:

apiVersion: serving.knative.dev/v1alpha1

kind: Service

metadata:

  name: stock-service-example

  namespace: default

spec:

  template:

    metadata:

      name: stock-service-example-v3

    spec:

      containers:

      - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/rest-api-go:v1

        env:

          - name: RESOURCE

            value: v3

        readinessProbe:

          httpGet:

            path: /

          initialDelaySeconds: 0

          periodSeconds: 3

  traffic:

  - tag: v1

    revisionName: stock-service-example-v1

    percent: 50

  - tag: v2

    revisionName: stock-service-example-v2

    percent: 50

  - tag: latest

    latestRevision: true

    percent: 0

Execute kubectl apply -f revision-v3.yaml para implantar a versão v3. Em seguida, verifique a situação de revisão:

└─# kubectl get revision

NAME                       SERVICE NAME               GENERATION   READY   REASON

stock-service-example-v1   stock-service-example-v1   1            True

stock-service-example-v2   stock-service-example-v2   2            True

stock-service-example-v3   stock-service-example-v3   3            True

Você pode ver que três revisões foram criadas.
Neste ponto, vamos olhar para o efeito real do exemplo de serviço de estoque:

└─# kubectl get ksvc stock-service-example -o yaml

apiVersion: serving.knative.dev/v1beta1

kind: Service

metadata:

  annotations:

...

status:

...

  traffic:

  - latestRevision: false

    percent: 50

    revisionName: stock-service-example-v1

    tag: v1

    url: http://v1-stock-service-example.default.example.com

  - latestRevision: false

    percent: 50

    revisionName: stock-service-example-v2

    tag: v2

    url: http://v2-stock-service-example.default.example.com

  - latestRevision: true

    percent: 0

    revisionName: stock-service-example-v3

    tag: latest

    url: http://latest-stock-service-example.default.example.com

  url: http://stock-service-example.default.example.com

Você pode ver que, embora a revisão v3 tenha sido criada, não há encaminhamento de tráfego porque não há tráfego. Neste ponto, quantas vezes você executar ./run-test.sh não obterá a saída da v3.
Você pode ver a configuração de revisão mais recente na configuração status.traffic do serviço: 

 - latestRevision: true

    percent: 0

    revisionName: stock-service-example-v3

    tag: latest

    url: http://latest-stock-service-example.default.example.com

Cada revisão tem seu próprio URL, então você só precisa iniciar uma solicitação com base no URL de revisão v3 para iniciar o teste.
Eu escrevi um script de teste, você pode salvar o seguinte script no arquivo latest-run-test.sh e, em seguida, executar este script para iniciar diretamente uma solicitação para a versão mais recente:

#!/bin/bash

export INGRESSGATEWAY=istio-ingressgateway

export GATEWAY_IP=`kubectl get svc $INGRESSGATEWAY --namespace istio-system --output jsonpath="{.status.loadBalancer.ingress[*]['ip']}"`

export DOMAIN_NAME=`kubectl get route ${SVC_NAME} --output jsonpath="{.status.url}"| awk -F/ '{print $3}'`



export LAST_DOMAIN=`kubectl get ksvc stock-service-example --output jsonpath="{.status.traffic[?(@.tag=='latest')].url}"| cut -d'/' -f 3`



curl -H "Host: ${LAST_DOMAIN}" http://${GATEWAY_IP}

Teste a versão v3 se não houver problema, você pode distribuir o tráfego para a versão v3.
Vamos criar outro arquivo de revisão-v3-2.yaml com o seguinte conteúdo:

apiVersion: serving.knative.dev/v1alpha1

kind: Service

metadata:

  name: stock-service-example

  namespace: default

spec:

  template:

    metadata:

      name: stock-service-example-v3

    spec:

      containers:

      - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/rest-api-go:v1

        env:

          - name: RESOURCE

            value: v3

        readinessProbe:

          httpGet:

            path: /

          initialDelaySeconds: 0

          periodSeconds: 3

  traffic:

  - tag: v1

    revisionName: stock-service-example-v1

    percent: 40

  - tag: v2

    revisionName: stock-service-example-v2

    percent: 30

  - tag: v3

    revisionName: stock-service-example-v3

    percent: 30

  - tag: latest

    latestRevision: true

    percent: 0

Use vimdiff para ver a diferença entre a revisão-v3.yaml e a revisão-v3-2.yaml:

revision-v3-2.yaml adiciona encaminhamento de tráfego para v3. Neste momento, execute ./run-test.sh e você pode ver que a proporção de v1, v2 e v3 é basicamente 4: 3: 3

└─# ./run-test.sh

Welcome to the v1 app!

└─# ./run-test.sh

Welcome to the v2 app!

└─# ./run-test.sh

Welcome to the v1 app!

└─# ./run-test.sh

Welcome to the v2 app!

└─# ./run-test.sh

Welcome to the v3 app!

... ...

 

Rollback de versão

A revisão do serviço Knative não pode ser modificada. A revisão criada por cada atualização das especificações do serviço permanecerá no kube-apiserver. Se o aplicativo for lançado para uma nova versão e você achar que há um problema e deseja reverter para a versão anterior, você só precisa especificar a Revisão correspondente e, em seguida, encaminhar o tráfego.

 

resumo

A escala de cinza e a reversão do Knative Service são todas baseadas no tráfego. A carga de trabalho (Pod) é criada automaticamente com base no tráfego de entrada. Portanto, o tráfego é o driver principal no modelo Knative Serving. Isso é diferente do lançamento de aplicativo tradicional e dos modelos em tons de cinza.

Suponha que haja um aplicativo app1. A abordagem tradicional é primeiro definir o número de instâncias do aplicativo (pod no sistema Kubernetes). Presumimos que o número de instâncias seja 10. Se você deseja publicar em escala de cinza, o método tradicional é publicar um pod primeiro. No momento, a distribuição de v1 e v2 é: 9 pods para v1 e 1 pod para v2. Se você quiser continuar a expandir o intervalo da escala de cinza, o número de pods na v2 aumentará e o número de pods na v1 diminuirá, mas o número total de pods permanece inalterado em 10.

No modelo Knative Serving, o número de pods é sempre autoadaptado de acordo com o tráfego e não precisa ser especificado com antecedência. Na escala de cinza, você só precisa especificar a proporção da escala de cinza do fluxo entre as diferentes versões. O número de instâncias de cada revisão é adaptável de acordo com o tamanho do tráfego e não precisa ser especificado com antecedência.

A partir da comparação acima, pode-se descobrir que o modelo Knative Serving pode controlar com precisão a faixa de influência da escala de cinza, garantindo que apenas uma parte do fluxo de escala de cinza. No entanto, a proporção da escala de cinza do pod no modelo tradicional não representa verdadeiramente a taxa de fluxo, é um método indireto de escala de cinza.

 

Fonte do manuscrito: Alibaba Cloud Developer Community

 

 

Acho que você gosta

Origin blog.csdn.net/weixin_40050195/article/details/97130593
Recomendado
Clasificación