Dicas e truques do Kubernetes: movendo recursos de cluster para o Helm 2



A necessidade de capturar os recursos do cluster Kubernetes pode surgir em condições de combate quando você não pode apenas recriá-los com as ferramentas Helm. Duas razões principais podem ser distinguidas:

  • Será simples - independentemente de você ter uma nuvem ou um bare metal.
  • Após a remoção, os serviços nas nuvens podem ser perdidos, e os Load Balancers associados em Kubernetes serão executados.

No nosso caso, a solução foi necessária para capturar o ingress-nginx trabalhando enquanto integrava nosso operador Kubernetes.

É estritamente inaceitável para Helm que os recursos que gerencia não sejam criados por ele.

"Se os recursos de liberação de sua equipe puderem ser alterados manualmente, prepare-se para encontrar os problemas descritos na seção: [BUG] Após o lançamento, o estado dos recursos de liberação no cluster não corresponde ao gráfico Helm descrito ." (do nosso último artigo )

Como observado anteriormente, o Helm funciona da seguinte maneira:

  1. Em cada instalação (instalação do helm install , comandos de helm upgrade ), o Helm armazena o manifesto de versão gerado no back-end de armazenamento . Por padrão, o ConfigMaps é usado: para cada revisão de uma liberação, o ConfigMap é criado no mesmo espaço para nome no qual o Tiller está sendo executado.
  2. Durante lançamentos repetidos ( helm upgrade ), o Helm compara o novo manifesto gerado com o manifesto antigo da mais recente revisão de IMPLANTAÇÃO do ConfigMap e aplica a diferença resultante no Kubernetes.

Com base nesses recursos, chegamos à conclusão de que é suficiente corrigir o ConfigMap (versão de back-end de armazenamento), ou seja, adotar recursos existentes no cluster.

O leme se refere ao ConfigMap no seguinte formato: %RELEASE_NAME.v%REVISION . Para obter entradas existentes, você deve executar o comando kubectl get cm -l OWNER=TILLER --namespace kube-system (por padrão, o Tiller é instalado no namespace kube-system - caso contrário, você deve especificar o usado).

 $ kubectl get cm -l OWNER=TILLER -n kube-system NAME DATA AGE release_name_1.v618 1 5d release_name_1.v619 1 1d release_name_2.v1 1 2d release_name_2.v2 1 3d 

Cada ConfigMap é apresentado neste formato:

 apiVersion: v1 data: release: H4sIAHEEd1wCA5WQwWrDMAyG734Kwc52mtvwtafdAh27FsURjaljG1kp5O3nNGGjhcJ21M/nT7+stVZvcEozO7LAFAgLnSNOdG4boSkHFCpNIb55R2bBKSjM/ou4+BQt3Fp19XGwcNoINZHggIJWAayaH6leJ/24oTIBewplpQEwZ3Ode+JIdanxqXkw/D4CGClMpoyNG5HlmdAH05rDC6WPRTC6p2Iv4AkjXmjQ/WLh04dArEomt9aVJVfHMcxFiD+6muTEsl+i74OF961FpZEvJN09HEXyHmdOklwK1X7s9my7eYdK7egk8b8/6M+HfwNgE0MSAgIAAA== kind: ConfigMap metadata: creationTimestamp: 2019-02-08T11:12:38Z labels: MODIFIED_AT: "1550488348" NAME: release_name_1 OWNER: TILLER STATUS: DEPLOYED VERSION: "618" name: release_name_1.v618 namespace: kube-system resourceVersion: "298818981" selfLink: /api/v1/namespaces/kube-system/configmaps/release_name_1.v618 uid: 71c3e6f3-2b92-11e9-9b3c-525400a97005 OU4 + BQt3Fp19XGwcNoINZHggIJWAayaH6leJ / 24oTIBewplpQEwZ3Ode + JIdanxqXkw / D4CGClMpoyNG5HlmdAH05rDC6WPRTC6p2Iv4AkjXmjQ / WLh04dArEomt9aVJVfHMcxFiD + 6muTEsl + i74OF961FpZEvJN09HEXyHmdOklwK1X7s9my7eYdK7egk8b8 / 6M + HfwNgE0MSAgIAAA == apiVersion: v1 data: release: H4sIAHEEd1wCA5WQwWrDMAyG734Kwc52mtvwtafdAh27FsURjaljG1kp5O3nNGGjhcJ21M/nT7+stVZvcEozO7LAFAgLnSNOdG4boSkHFCpNIb55R2bBKSjM/ou4+BQt3Fp19XGwcNoINZHggIJWAayaH6leJ/24oTIBewplpQEwZ3Ode+JIdanxqXkw/D4CGClMpoyNG5HlmdAH05rDC6WPRTC6p2Iv4AkjXmjQ/WLh04dArEomt9aVJVfHMcxFiD+6muTEsl+i74OF961FpZEvJN09HEXyHmdOklwK1X7s9my7eYdK7egk8b8/6M+HfwNgE0MSAgIAAA== kind: ConfigMap metadata: creationTimestamp: 2019-02-08T11:12:38Z labels: MODIFIED_AT: "1550488348" NAME: release_name_1 OWNER: TILLER STATUS: DEPLOYED VERSION: "618" name: release_name_1.v618 namespace: kube-system resourceVersion: "298818981" selfLink: /api/v1/namespaces/kube-system/configmaps/release_name_1.v618 uid: 71c3e6f3-2b92-11e9-9b3c-525400a97005 

Os manifestos gerados são armazenados em formato binário (no exemplo acima, com a chave .data.release ), por isso decidimos criar o release usando as ferramentas Helm padrão, mas com um stub especial, que é posteriormente substituído pelos manifestos dos recursos selecionados.

Implementação


O algoritmo da solução é o seguinte:

  1. Estamos preparando um arquivo manifest.yaml com manifestos de recursos para adoção (este item será discutido em mais detalhes abaixo).
  2. Criamos um gráfico no qual há um único modelo com um ConfigMap temporário, porque O Helm não pode criar uma liberação sem recursos.
  3. Criamos um templates/stub.yaml com um stub com tamanho igual ao número de caracteres em manifest.yaml (durante os experimentos, verificou-se que o número de bytes deve corresponder). Como um esboço, um conjunto de caracteres reproduzíveis deve ser selecionado, que permanecerá após a geração e armazenado no back-end de armazenamento. Para simplicidade e clareza, # usado # , ou seja:

     {{ repeat ${manifest_file_length} "#" }} 
  4. Instale o gráfico: helm install helm upgrade --install e helm upgrade --install .
  5. Substitua o stub na liberação de back-end de armazenamento pelos manifest.yaml recursos de manifest.yaml que foram selecionados para adoção na primeira etapa:

     stub=$(printf '#%.0s' $(seq 1 ${manifest_file_length})) release_data=$(kubectl get -n ${tiller_namespace} cm/${release_name}.v1 -o json | jq .data.release -r) updated_release_data=$(echo ${release_data} | base64 -d | zcat | sed "s/${stub}/$(sed -z 's/\n/\\n/g' ${manifest_file_path} | sed -z 's/\//\\\//g')/" | gzip -9 | base64 -w0) kubectl patch -n ${tiller_namespace} cm/${release_name}.v1 -p '{"data":{"release":"'${updated_release_data}'"}}' 
  6. Verificamos se o Tiller está disponível e captamos nossas alterações.
  7. Exclua o ConfigMap temporário (da segunda etapa).
  8. Além disso, o trabalho com o release não é diferente do normal.

A lista principal com a implementação descrita acima está disponível em:

 $ ./script.sh Example: ./script.sh foo bar-prod manifest.yaml Usage: ./script.sh CHART_NAME RELEASE_NAME MANIFEST_FILE_TO_ADOPT [TILLER_NAMESPACE] 

Como resultado do script, o lançamento de RELEASE_NAME é criado. Ele se associa a recursos cujos manifestos são descritos no arquivo MANIFEST_FILE_TO_ADOPT . CHART_NAME é gerado um gráfico CHART_NAME , que pode ser usado para acompanhar ainda mais os manifestos e lançamentos.

Ao preparar o manifesto com recursos, é necessário excluir os campos de serviço usados ​​pelo Kubernetes (esses são dados dinâmicos do serviço, portanto, é incorreto fazer a versão deles no Helm). Em um mundo ideal, o treinamento se resume a um comando: kubectl get RESOURCE -o yaml --export . Afinal, a documentação diz:

  --export=false: If true, use 'export' for the resources. Exported resources are stripped of cluster-specific information. 

... mas, como a prática demonstrou, a opção --export ainda --export , portanto, formatação de manifesto adicional será necessária. No service/release-name-habr abaixo, você deve remover os selfLink creationTimestamp e selfLink .

versão kubectl
 $ kubectl version Client Version: version.Info{Major:"1", Minor:"13", GitVersion:"v1.13.3", GitCommit:"721bfa751924da8d1680787490c54b9179b1fed0", GitTreeState:"clean", BuildDate:"2019-02-01T20:08:12Z", GoVersion:"go1.11.5", Compiler:"gc", Platform:"linux/amd64"} Server Version: version.Info{Major:"1", Minor:"13", GitVersion:"v1.13.3", GitCommit:"721bfa751924da8d1680787490c54b9179b1fed0", GitTreeState:"clean", BuildDate:"2019-02-01T20:00:57Z", GoVersion:"go1.11.5", Compiler:"gc", Platform:"linux/amd64"} 

kubectl obtém serviço / release-name-habr -o yaml --export
 apiVersion: v1 kind: Service metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app.kubernetes.io/instance":"release-name","app.kubernetes.io/managed-by":"Tiller","app.kubernetes.io/name":"habr","helm.sh/chart":"habr-0.1.0"},"name":"release-name-habr","namespace":"default"},"spec":{"ports":[{"name":"http","port":80,"protocol":"TCP","targetPort":"http"}],"selector":{"app.kubernetes.io/instance":"release-name","app.kubernetes.io/name":"habr"},"type":"ClusterIP"}} creationTimestamp: null labels: app.kubernetes.io/instance: release-name app.kubernetes.io/managed-by: Tiller app.kubernetes.io/name: habr helm.sh/chart: habr-0.1.0 name: release-name-habr selfLink: /api/v1/namespaces/default/services/release-name-habr spec: ports: - name: http port: 80 protocol: TCP targetPort: http selector: app.kubernetes.io/instance: release-name app.kubernetes.io/name: habr sessionAffinity: None type: ClusterIP status: loadBalancer: {} 

A seguir, exemplos de uso do script. Ambos demonstram como usar o script para adotar recursos que trabalham no cluster e, em seguida, excluí-los usando as ferramentas Helm.

Exemplo 1




Exemplo 2




Conclusão


A solução descrita no artigo pode ser finalizada e usada não apenas para adotar recursos do Kubernetes do zero, mas também para adicioná-los às versões existentes.

No momento, não há soluções que permitam aproveitar os recursos existentes no cluster, transferi-los para o gerenciamento do Helm. É possível que no Helm 3 seja implementada uma solução que cubra esse problema (pelo menos há uma proposta sobre esse assunto).

PS


Outro do ciclo de dicas e truques do K8s:


Leia também em nosso blog:

Source: https://habr.com/ru/post/pt441964/


All Articles