Consejos y trucos de Kubernetes: reubicar recursos del clúster en Helm 2



La necesidad de tomar los recursos del grupo Kubernetes puede surgir en condiciones de combate cuando no puedes simplemente recrearlos con las herramientas Helm. Se pueden distinguir dos razones principales:

  • Será simple, independientemente de si tiene una nube o un metal desnudo.
  • Tras la eliminación, se pueden perder los servicios en las nubes, así como los equilibradores de carga asociados en Kubernetes.

En nuestro caso, se requería la solución para detectar el ingreso de trabajo -nginx 's mientras se integra nuestro operador Kubernetes.

Es estrictamente inaceptable para Helm que los recursos que administra no sean creados por él.

"Si los recursos de liberación de su equipo se pueden cambiar manualmente, prepárese para enfrentar los problemas descritos en la sección: [ERROR] Después de la implementación, el estado de los recursos de liberación en el clúster no corresponde al gráfico Helm descrito" . (de nuestro último artículo )

Como se señaló anteriormente, Helm funciona de la siguiente manera:

  1. Cada instalación (instalación de helm install , comandos de helm upgrade ) Helm guarda el manifiesto de lanzamiento generado en el backend de almacenamiento . De manera predeterminada, se usa ConfigMaps: para cada revisión de una versión, ConfigMap se crea en el mismo espacio de nombres en el que se ejecuta Tiller.
  2. Durante las implementaciones repetidas ( helm upgrade ) Helm compara el nuevo manifiesto generado con el antiguo manifiesto de la última revisión de lanzamiento DESPLEGADA de ConfigMap, y aplica la diferencia resultante en Kubernetes.

En base a estas características, hemos llegado a la conclusión de que es suficiente parchear ConfigMap (versión de back-end de almacenamiento) para recoger , es decir adoptar los recursos existentes en el clúster.

Tiller se refiere a ConfigMap en el siguiente formato: %RELEASE_NAME.v%REVISION . Para obtener entradas existentes, debe ejecutar el comando kubectl get cm -l OWNER=TILLER --namespace kube-system (de forma predeterminada, Tiller está instalado en el espacio de nombres kube-system ; de lo contrario, debe especificar el que se usa).

 $ 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 se presenta en este 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 

Los manifiestos generados se almacenan en forma binaria (en el ejemplo anterior con la clave .data.release ), por lo que decidimos crear el lanzamiento utilizando las herramientas estándar de Helm, pero con un código auxiliar especial, que luego se reemplaza con los manifiestos de los recursos seleccionados.

Implementación


El algoritmo de solución es el siguiente:

  1. Estamos preparando un archivo manifest.yaml con manifiestos de recursos para su adopción (este elemento se analizará con más detalle a continuación).
  2. Creamos un gráfico en el que hay una sola plantilla con un ConfigMap temporal, porque Helm no puede crear una versión sin recursos.
  3. Creamos un templates/stub.yaml con un stub que tendrá la misma longitud que la cantidad de caracteres en manifest.yaml (durante los experimentos resultó que la cantidad de bytes debe coincidir). Como código auxiliar, se debe seleccionar un conjunto de caracteres reproducible, que permanecerá después de la generación y se almacenará en el backend de almacenamiento. Por simplicidad y claridad, # usa # , # decir:

     {{ repeat ${manifest_file_length} "#" }} 
  4. Instale la tabla: helm install helm upgrade --install y helm upgrade --install .
  5. Reemplazamos el código auxiliar en la versión de back-end de almacenamiento con los manifest.yaml recursos de manifest.yaml que se seleccionaron para su adopción en el primer paso:

     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 que Tiller esté disponible y recogimos nuestros cambios.
  7. Elimine el ConfigMap temporal (del segundo paso).
  8. Además, el trabajo con el lanzamiento no es diferente del habitual.

Gist con la implementación descrita anteriormente está disponible en:

 $ ./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 del script, se crea el lanzamiento de RELEASE_NAME . Se asocia con recursos cuyos manifiestos se describen en el archivo MANIFEST_FILE_TO_ADOPT . También se CHART_NAME gráfico CHART_NAME , que se puede utilizar para acompañar aún más los manifiestos y lanzamientos en particular.

Al preparar un manifiesto con recursos, es necesario eliminar los campos de servicio que utilizan Kubernetes (estos son datos de servicio dinámico, por lo tanto, es incorrecto versionarlos en Helm). En un mundo ideal, el entrenamiento se reduce a un comando: kubectl get RESOURCE -o yaml --export . Después de todo, la documentación dice:

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

... pero, como ha demostrado la práctica, la opción --export todavía --export , por lo que se requerirá un formato de manifiesto adicional. En el service/release-name-habr continuación, debe eliminar los selfLink creationTimestamp y selfLink .

versión 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 obtener servicio / 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: {} 

Los siguientes son ejemplos del uso del script. Ambos demuestran cómo usar el script para adoptar recursos que trabajan en el clúster y luego eliminarlos usando las herramientas Helm.

Ejemplo 1




Ejemplo 2




Conclusión


La solución descrita en el artículo se puede finalizar y utilizar no solo para adoptar los recursos de Kubernetes desde cero, sino también para agregarlos a las versiones existentes.

Por el momento no hay soluciones que permitan aprovechar los recursos existentes en el clúster, transferirlos a la gestión de Helm. Es posible que en Helm 3 se implemente una solución que cubra este problema (al menos hay una propuesta sobre este tema).

PS


Otros del ciclo de consejos y trucos de K8s:


Lea también en nuestro blog:

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


All Articles