
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:
- 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. - 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:
- Estamos preparando um arquivo
manifest.yaml
com manifestos de recursos para adoção (este item será discutido em mais detalhes abaixo). - 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.
- 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} "#" }}
- Instale o gráfico:
helm install
helm upgrade --install
e helm upgrade --install
. - 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}'"}}'
- Verificamos se o Tiller está disponível e captamos nossas alterações.
- Exclua o ConfigMap temporário (da segunda etapa).
- 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: