One place for hosting & domains

      paquetes

      Información sobre la visibilidad de paquetes en Go


      Introducción

      Cuando se crea un paquete en Go, el objetivo final suele ser hacer que sea accesible para que otros desarrolladores lo utilicen, ya sea en paquetes de orden superior o en programas completos. Al importar el paquete, su pieza de código puede servir como bloque de creación para otras herramientas más complejas. Sin embargo, solo se pueden importar determinados paquetes. Esto se determina por la visibilidad del paquete.

      El término visibilidad en este contexto se refiere al espacio de archivo desde el que se puede hacer referencia a un paquete o a otra creación. Por ejemplo, si definimos una variable en una función, la visibilidad (el ámbito) de dicha variable solo se encuentra dentro de la función en la que se definió. De modo similar, si define una variable en un paquete, puede hacerla visible solamente a ese paquete o permitir que también sea visible fuera de él.

      El control cuidadoso de la visibilidad de los paquetes es importante al escribir código ergonómico, sobre todo cuando se deben tener en cuenta los cambios futuros que podría querer realizar en su paquete. Si necesita corregir un error, mejorar el rendimiento o cambiar una funcionalidad, le convendrá realizar la modificación de una forma que no rompa el código de nadie que utilice su paquete. Una manera de reducir al mínimo los cambios que provocan rupturas es permitir el acceso a las partes de su paquete que son necesarias para que se utilice de forma adecuada. Al limitar el acceso, puede realizar cambios de forma interna en su paquete con menos posibilidades de afectar la manera en que otros desarrolladores utilizan su paquete.

      A través de este artículo, aprenderá a controlar la visibilidad de los paquetes y a proteger partes de su código que solo se deben usar dentro de su paquete. Para hacerlo, crearemos un registrador básico a fin de registrar y depurar mensajes usando paquetes con diferentes grados de visibilidad de elementos.

      Requisitos previos

      Para seguir los ejemplos que se presentan en este artículo, necesitará lo siguiente:

      .
      ├── bin
      │
      └── src
          └── github.com
              └── gopherguides
      

      Elementos exportados y no exportados

      A diferencia de otros lenguajes de programación, como Java y Python, que utilizan* modificadores de acceso* como public, private o protected para especificar el ámbito, Go determina si un elemento es exported o unexported según la forma en que se declara. Exportar un elemento, en este caso, lo hace visible fuera del paquete actual. Si no se exportó, solo es visible y utilizable dentro del paquete en el que se definió.

      Esta visibilidad externa se controla escribiendo en mayúscula la primera letra del elemento declarado. Todas las declaraciones, como Types, Variables, Constants, Functions y demás que comienzan con una letra en mayúscula son visibles fuera del paquete actual.

      Veamos el siguiente código, prestando especial atención al uso de mayúsculas:

      greet.go

      package greet
      
      import "fmt"
      
      var Greeting string
      
      func Hello(name string) string {
          return fmt.Sprintf(Greeting, name)
      }
      

      Este código declara que está en el paquete greet. Luego, declara dos símbolos, una variable llamada Greeting y una función denominada Hello. Debido a que ambos comienzan con una letra mayúscula, ambos son exported y están disponibles para cualquier programa externo. Como se indicó anteriormente, crear un paquete que limite el acceso permitirá un mejor diseño de API y facilitará la actualización de su paquete a nivel interno sin interrumpir código que dependa de su paquete.

      Definir la visibilidad de paquetes

      Para analizar de forma más detallada el funcionamiento de la visibilidad de paquetes en un programa, crearemos un paquete logging y tendremos en cuenta lo que queremos que sea y no sea visible fuera de él. Este paquete logging se encargará de registrar en la consola todos los mensajes de nuestro programa. También analizará el nivel en el que realizamos el registro. El nivel describe el tipo de registro y será uno de tres estados: info, warning o error.

      Primero, dentro de su directorio src, crearemos un directorio llamado logging en el que dispondremos nuestros archivos de registro:

      A continuación, posiciónese en ese directorio:

      Luego, usando un editor como nano, cree un archivo llamado logging.go:

      Disponga el siguiente código en el archivo logging.go que acabamos de crear:

      logging/logging.go

      package logging
      
      import (
          "fmt"
          "time"
      )
      
      var debug bool
      
      func Debug(b bool) {
          debug = b
      }
      
      func Log(statement string) {
          if !debug {
              return
          }
      
          fmt.Printf("%s %sn", time.Now().Format(time.RFC3339), statement)
      }
      

      La primera línea de este código declaró un paquete llamado logging. En este paquete, hay dos funciones exported: Debug y Log. Cualquier otro paquete que importe el paquete logging puede invocar estas funciones. También hay una variable privada llamada debug. El acceso a esta variable solo es posible desde el paquete logging. Es importante observar que, si bien la función Debug y la variable debug tienen el mismo nombre, la función se escribe con la primera letra en mayúscula y la variable no. Esto las convierte en distintas declaraciones con diferentes ámbitos.

      Guarde y cierre el archivo.

      Para usar este paquete en otras áreas de nuestro código, podemos importarlo con import a un nuevo paquete. Crearemos este nuevo paquete, pero necesitaremos un directorio nuevo para almacenar esos archivos de origen primero.

      Saldremos del directorio logging, crearemos un nuevo directorio llamado cmd y nos posicionaremos en él:

      Cree un archivo llamado main.go en el directorio cmd que acabamos de crear:

      Ahora, podemos añadir el siguiente código:

      cmd/main.go

      package main
      
      import "github.com/gopherguides/logging"
      
      func main() {
          logging.Debug(true)
      
          logging.Log("This is a debug statement...")
      }
      

      Con esto, nuestro programa quedará totalmente escrito. Sin embargo, para poder ejecutar este programa, también debemos crear algunos archivos de configuración a fin de que nuestro código funcione correctamente. Go utiliza Go Modules para configurar las dependencias de paquetes para la importación de recursos. Estos módulos son archivos de configuración que se disponen en su directorio de paquetes e indican al compilador las ubicaciones desde las cuales se deben importar los paquetes. Si bien en este artículo no obtendrá información sobre los módulos, podemos escribir algunas líneas de configuración para que este ejemplo funcione a nivel local.

      Abra el siguiente archivo go.mod en el directorio cmd:

      A continuación, disponga el siguiente contenido en el archivo:

      go.mod

      module github.com/gopherguides/cmd
      
      replace github.com/gopherguides/logging => ../logging
      

      La primera línea de este archivo indica al compilador que el paquete cmd tiene la ruta de archivo github.com/gopherguides/cmd. La segunda línea indica al compilador que github.com/gopherguides/logging se encuentra a nivel local en el disco, en el directorio ../logging.

      También necesitaremos un archivo go.mod para nuestro paquete logging. Ingresaremos de nuevo en el directorio logging y crearemos un archivo go.mod:

      • cd ../logging
      • nano go.mod

      Añada el siguiente contenido al archivo:

      go.mod

      module github.com/gopherguides/logging
      

      Esto indica al compilador que el paquete logging que creamos, en realidad, es el paquete github.com/gopherguides/logging. Esto permite importar el paquete en nuestro paquete main con la siguiente línea que escribimos anteriormente:

      cmd/main.go

      package main
      
      import "github.com/gopherguides/logging"
      
      func main() {
          logging.Debug(true)
      
          logging.Log("This is a debug statement...")
      }
      

      Con esto, debería disponer de la siguiente estructura de directorios y distribución de archivos:

      ├── cmd
      │   ├── go.mod
      │   └── main.go
      └── logging
          ├── go.mod
          └── logging.go
      

      Ahora que completamos toda la configuración, podemos ejecutar el programa main desde el paquete cmd con el siguiente comando:

      Obtendrá un resultado similar al siguiente:

      Output

      2019-08-28T11:36:09-05:00 This is a debug statement...

      El programa imprimirá la hora actual en formato RFC 3339 seguida de cualquier instrucción que enviamos al registrador. RFC 3339 es un formato de hora que se diseñó para representar la hora en Internet y se utiliza comúnmente en archivos de registro.

      Debido a que las funciones Debug y Log se exportan desde el paquete logging, podemos usarlas en nuestro paquete main. Sin embargo, la variable debug que se muestra en el paquete logging no se exporta. Intentar hacer referencia a una declaración no exportada provocará un error en el tiempo de compilación.

      Añada la siguiente línea resaltada a main.go:

      cmd/main.go

      package main
      
      import "github.com/gopherguides/logging"
      
      func main() {
          logging.Debug(true)
      
          logging.Log("This is a debug statement...")
      
          fmt.Println(logging.debug)
      }
      

      Guarde y ejecute el archivo. Verá un error similar al siguiente:

      Output

      . . . ./main.go:10:14: cannot refer to unexported name logging.debug

      Ahora que vimos cómo se comportan los elementos exported y unexported en paquetes, veremos cómo se pueden exportar fields y methods desde structs.

      Visibilidad dentro de estructuras

      Si bien el esquema de visibilidad del registrador que creamos en la última sección puede funcionar con programas simples, comparte demasiado estado para ser útil desde el interior de varios paquetes. Esto se debe a que varios paquetes que podrían aplicar a las variables modificaciones que derivarían en estados contradictorios pueden acceder a las variables exportadas. Permitir que el estado de su paquete se modifique de esta manera hace que sea difícil predecir el comportamiento del programa. Con el diseño actual, por ejemplo, un paquete podría fijar la variable Debug en true y otro en false en la misma instancia. Esto generaría un problema porque los dos paquetes que importan el paquete logging se verían afectados.

      Podemos aislar el registrador creando una estructura y, luego, métodos que se desprendan de ella. Esto nos permitirá crear una instance de un registrador que se usará de forma independiente en cada paquete que la emplee.

      Aplique el siguiente cambio al paquete logging para volver a factorizar y aislar el registrador:

      logging/logging.go

      package logging
      
      import (
          "fmt"
          "time"
      )
      
      type Logger struct {
          timeFormat string
          debug      bool
      }
      
      func New(timeFormat string, debug bool) *Logger {
          return &Logger{
              timeFormat: timeFormat,
              debug:      debug,
          }
      }
      
      func (l *Logger) Log(s string) {
          if !l.debug {
              return
          }
          fmt.Printf("%s %sn", time.Now().Format(l.timeFormat), s)
      }
      

      En este código, creamos una estructura de Logger. Esta estructura alojará nuestro estado no exportado con el formato de hora para imprimir y la variable debug fijada en true o false. La función New establece el estado inicial con el que se crea el registrador, como el formato de hora y el estado de depuración. Luego, almacena los valores que asignamos a las variables no exportadas timeFormat y debug. También creamos un método llamado Log, con el tipo Logger, que toma una instrucción que queremos imprimir. Dentro del método Log hay una referencia a su variable de método local l para que se restablezca el acceso a sus campos internos, como l.timeFormat y l.debug.

      Este enfoque nos permitirá crear un Logger en muchos paquetes diferentes y utilizarlo independientemente de la forma en que se utilicen los demás paquetes.

      Para utilizarlo en otro paquete, modificaremos cmd/main.go de la siguiente manera:

      cmd/main.go

      package main
      
      import (
          "time"
      
          "github.com/gopherguides/logging"
      )
      
      func main() {
          logger := logging.New(time.RFC3339, true)
      
          logger.Log("This is a debug statement...")
      }
      

      Al ejecutar este programa, obtendrá el siguiente resultado:

      Output

      2019-08-28T11:56:49-05:00 This is a debug statement...

      En este código, creamos una instancia del registrador invocando la función exportada New. Almacenamos la referencia a esta instancia en la variable logger. Ahora, podemos invocar logging.Log para imprimir instrucciones.

      Si intentamos hacer referencia a un campo no exportado desde Logger, como el campo timeFormat, veremos un error en el tiempo de compilación. Intente añadir la siguiente línea resaltada y ejecutar cmd/main.go:

      cmd/main.go

      
      package main
      
      import (
          "time"
      
          "github.com/gopherguides/logging"
      )
      
      func main() {
          logger := logging.New(time.RFC3339, true)
      
          logger.Log("This is a debug statement...")
      
          fmt.Println(logger.timeFormat)
      }
      

      Esto generará el siguiente error:

      Output

      . . . cmd/main.go:14:20: logger.timeFormat undefined (cannot refer to unexported field or method timeFormat)

      El compilador reconoce que logger.timeFormat no se exporta y, por lo tanto, no se puede obtener desde el paquete logging.

      Visibilidad dentro de métodos

      Al igual que los campos de estructura, los métodos también se pueden exportar o no.

      Para ilustrar esto, añadiremos un registro nivelado a nuestro registrador. El registro nivelado es una forma de clasificar sus registros para poder buscar tipos específicos de eventos en ellos. Estos son los niveles que disponemos en nuestro registrador:

      • El nivel info, que representa eventos de tipo de información que informan acciones al usuario, como Program started o Email sent. Nos ayudan a depurar y controlar partes de nuestro programa para ver si el comportamiento es el previsto.

      • El nivel warning. Estos tipos de eventos detectan aspectos inesperados que no constituyen errores, como Email failed to send, retrying. Nos permiten ver partes de nuestro programa que no funcionan tan bien como esperamos.

      • El nivel error, que indica que el programa encontró un problema, como File not found. A menudo, esto generará fallas de funcionamiento en el programa.

      También es posible que desee activar y desactivar ciertos niveles de registro, en particular si su programa no funciona de la manera prevista y desea depurarlo. Añadiremos esta funcionalidad modificando el programa para que, cuando el valor de debug se fije en true, imprima todos los niveles de mensajes. De lo contrario, si se fija en false, solo imprimirá mensajes de error.

      Añada un registro nivelado realizando los siguientes cambios en logging/logging.go:

      logging/logging.go

      
      package logging
      
      import (
          "fmt"
          "strings"
          "time"
      )
      
      type Logger struct {
          timeFormat string
          debug      bool
      }
      
      func New(timeFormat string, debug bool) *Logger {
          return &Logger{
              timeFormat: timeFormat,
              debug:      debug,
          }
      }
      
      func (l *Logger) Log(level string, s string) {
          level = strings.ToLower(level)
          switch level {
          case "info", "warning":
              if l.debug {
                  l.write(level, s)
              }
          default:
              l.write(level, s)
          }
      }
      
      func (l *Logger) write(level string, s string) {
          fmt.Printf("[%s] %s %sn", level, time.Now().Format(l.timeFormat), s)
      }
      

      En este ejemplo, introdujimos un nuevo argumento en el método Log. Ahora, podemos pasar el level del mensaje de registro. El método Log determina el nivel de mensaje que tiene. Si se trata de un mensaje info o warning, y el campo debug es true, escribe el mensaje. De lo contrario, ignora el mensaje. Si se trata de cualquier otro nivel, como error, escribirá el mensaje de todos modos.

      En el método Log, se encuentra la mayor parte de la lógica para determinar si el mensaje se imprime. También introdujimos un método no exportado llamado write. El método write es el elemento que, de hecho, muestra el mensaje de registro.

      Ahora, podemos usar este registro nivelado en nuestro otro paquete cambiando cmd/main.go para que tenga el siguiente aspecto:

      cmd/main.go

      package main
      
      import (
          "time"
      
          "github.com/gopherguides/logging"
      )
      
      func main() {
          logger := logging.New(time.RFC3339, true)
      
          logger.Log("info", "starting up service")
          logger.Log("warning", "no tasks found")
          logger.Log("error", "exiting: no work performed")
      
      }
      

      Al ejecutar esto, obtendrá lo siguiente:

      Output

      [info] 2019-09-23T20:53:38Z starting up service [warning] 2019-09-23T20:53:38Z no tasks found [error] 2019-09-23T20:53:38Z exiting: no work performed

      En este ejemplo, cmd/main.go utilizó de forma correcta el método Log exportado.

      Ahora, podemos establecer el level de cada mensaje haciendo que el valor de debug cambie a false:

      main.go

      package main
      
      import (
          "time"
      
          "github.com/gopherguides/logging"
      )
      
      func main() {
          logger := logging.New(time.RFC3339, false)
      
          logger.Log("info", "starting up service")
          logger.Log("warning", "no tasks found")
          logger.Log("error", "exiting: no work performed")
      
      }
      

      Veremos que solo se imprimen los mensajes de nivel error:

      Output

      [error] 2019-08-28T13:58:52-05:00 exiting: no work performed

      Si intentamos invocar el método write desde fuera del paquete logging, observaremos un error de tiempo de compilación

      main.go

      package main
      
      import (
          "time"
      
          "github.com/gopherguides/logging"
      )
      
      func main() {
          logger := logging.New(time.RFC3339, true)
      
          logger.Log("info", "starting up service")
          logger.Log("warning", "no tasks found")
          logger.Log("error", "exiting: no work performed")
      
          logger.write("error", "log this message...")
      }
      

      Output

      cmd/main.go:16:8: logger.write undefined (cannot refer to unexported field or method logging.(*Logger).write)

      Cuando el compilador ve que usted intenta hacer referencia a algo de otro paquete que comienza con una letra minúscula, sabe que no se exporta y, por lo tanto, muestra un error del compilador.

      El registrador de este tutorial muestra la forma en que podemos escribir código que solo exponga las partes que queremos que los demás paquetes consuman. Dado que controlamos las partes del paquete que son visibles fuera de este, ahora podemos realizar cambios futuros sin afectar ningún código que dependa de nuestro paquete. Por ejemplo, si desea desactivar únicamente los mensajes de nivel de info cuando el valor de debug sea “false”, podría realizar este cambio sin afectar a ninguna otra parte de su API. También podría realizar cambios en el mensaje de registro para incluir más información, como el directorio desde el cual se ejecutaba el programa.

      Conclusión

      En este artículo, se mostró la forma de compartir código entre paquetes protegiendo, a su vez, los detalles de implementación de su paquete. Esto le permite exportar una API sencilla que en pocas ocasiones cambiará para ofrecer compatibilidad con versiones anteriores, pero permitirá que se realicen cambios en su paquete de forma privada, según sea necesario, para que funcione mejor en el futuro. Esta práctica se considera recomendada al crear paquetes y sus API correspondientes.

      Para obtener más información sobre paquetes en Go, consulte Importar paquetes en Go y Escribir paquetes en Go o vea toda nuestra serie Programar en Go.



      Source link

      Cómo instalar Software en los clústeres de Kubernetes con el administrador de paquetes de Helm


      Introducción

      Helm es un administrador de paquetes para Kubernetes que permite a los desarrolladores y operadores configurar e implementar de forma más sencilla aplicaciones en los clústeres de Kubernetes.

      En este tutorial, configuraremos Helm y lo utilizaremos para instalar, volver a configurar, restaurar y luego borrar una instancia de la aplicación Kubernetes Dashboard. El panel es una GUI de Kubernetes oficial basado en la web.

      Para obtener una descripción general conceptual de Helm y su ecosistema de paquetes, lea nuestro artículo Introducción a Helm.

      Requisitos previos

      Para este tutorial, necesitará lo siguiente:

      • Un clúster de Kubernetes 1.8, o versiones posteriores, con control de acceso basado en roles (RBAC) habilitado.
      • La herramienta de línea de comandos kubectl instalada en su equipo local, configurada para conectarse a su clúster. Puede leer más sobre la instalación de kubectl en la documentación oficial.

      Puede probar su conectividad con el siguiente comando:

      Si no ve errores, estará conectado al clúster. Si accede a varios clústeres con kubectl, asegúrese de verificar que haya seleccionado el contexto de clúster correcto:

      • kubectl config get-contexts

      Output

      CURRENT NAME CLUSTER AUTHINFO NAMESPACE * do-nyc1-k8s-example do-nyc1-k8s-example do-nyc1-k8s-example-admin docker-for-desktop docker-for-desktop-cluster docker-for-desktop

      En este ejemplo, el asterisco (<^>*^>) indica que estamos conectados al clúster do-nyc1-k8s-example. Para cambiar de clústeres ejecute:

      • kubectl config use-context context-name

      Cuando esté conectado al clúster correcto, continúe con el paso 1 para comenzar a instalar Helm.

      Paso 1: Instalar Helm

      Primero, instalaremos la utilidad de línea de comandos helm en nuestro equipo local. Helm proporciona una secuencia de comandos que gestiona el proceso de instalación en MacOS, Windows o Linux.

      Pase a un directorio editable y descargue la secuencia de comandos del repositorio de GitHub de Helm:

      • cd /tmp
      • curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > install-helm.sh

      Haga que la secuencia de comandos sea ejecutable con chmod:

      • chmod u+x install-helm.sh

      En este punto, puede utilizar su editor de texto favorito para abrir la secuencia de comandos e inspeccionarla a fin de asegurarse de que sea segura. Cuando esté satisfecho, ejecútela:

      Es posible que se le solicite la contraseña. Ingrésela y presione ENTER.

      Output

      helm installed into /usr/local/bin/helm Run 'helm init' to configure helm.

      A continuación, terminaremos la instalación agregando algunos componentes de Helm a nuestro clúster.

      Paso 2: Instalar Tiller

      Tiller es un complemento del comando helm que se ejecuta en su clúster, recibe comandos de helm y se comunica directamente con la API de Kubernetes para hacer el verdadero trabajo de crear y eliminar recursos. A fin de proporcionar a Tiller los permisos que necesita para ejecutarse en el clúster, crearemos un recurso serviceaccount de Kubernetes.

      Nota: Vincularemos serviceaccount al rol de clúster de cluster-admin. Esto permitirá que el superusuario del servicio de tiller acceda al clúster e instale todos los tipos de recursos en todos los espacios de nombres. Esto es adecuado para explorar Helm, pero es posible que desee una configuración más restringida para un clúster de Kubernetes de producción.

      Consulte la documentación oficial del RBAC de Helm para obtener más información sobre diferentes configuraciones del RBAC para Tiller.

      Cree la serviceaccount de tiller:

      • kubectl -n kube-system create serviceaccount tiller

      A continuación, vincule la serviceaccount de tiller al rol cluster-admin:

      • kubectl create clusterrolebinding tiller --clusterrole cluster-admin --serviceaccount=kube-system:tiller

      Ahora podemos ejecutar helm init, que instala Tiller en nuestro clúster, junto con algunas tareas de mantenimiento locales, como la descarga de información del repositorio stable:

      • helm init --service-account tiller

      Output

      . . . Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster. Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy. For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation Happy Helming!

      Para verificar que Tiller esté en ejecución, enumere los pods en el espacio de nombres de** kube-system**:

      • kubectl get pods --namespace kube-system

      Output

      NAME READY STATUS RESTARTS AGE . . . kube-dns-64f766c69c-rm9tz 3/3 Running 0 22m kube-proxy-worker-5884 1/1 Running 1 21m kube-proxy-worker-5885 1/1 Running 1 21m kubernetes-dashboard-7dd4fc69c8-c4gwk 1/1 Running 0 22m tiller-deploy-5c688d5f9b-lccsk 1/1 Running 0 40s

      El nombre del pod de Tiller comienza con el prefijo tiller-deploy-.

      Ahora que instalamos ambos componentes de Helm, estamos listos para usar helm en la instalación de nuestra primera aplicación.

      Paso 3: Instalar un chart de Helm

      Los paquetes de software de Helm se llaman charts. Helm viene preconfigurado con un repositorio seleccionado de charts llamado stable. Puede explorar los charts disponibles en el repositorio de GitHub asignado a ellos. Instalaremos Kubernetes Dashboard a modo de ejemplo.

      Utilice helm para instalar el paquete kubernetes-dashboard desde el repositorio stable:

      • helm install stable/kubernetes-dashboard --name dashboard-demo

      Output

      NAME: dashboard-demo LAST DEPLOYED: Wed Aug 8 20:11:07 2018 NAMESPACE: default STATUS: DEPLOYED . . .

      Observe la línea de NAME, resaltada en el resultado del ejemplo anterior. En este caso, especificamos el nombre dashboard-demo. Este es el nombre de nuestra versión. Una versión de Helm es una única implementación de un chart con una configuración específica. Puede implementar varias versiones del mismo chart, cada una con su propia configuración.

      Si no especifica su propio nombre de versión usando --name, Helm creará por usted un nombre al azar.

      Podemos solicitar a Helm una lista de versiones en este clúster:

      Output

      NAME REVISION UPDATED STATUS CHART NAMESPACE dashboard-demo 1 Wed Aug 8 20:11:11 2018 DEPLOYED kubernetes-dashboard-0.7.1 default

      Ahora podemos usar kubectl para verificar que se haya implementado un nuevo servicio en el clúster:

      Output

      NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE dashboard-demo-kubernetes-dashboard ClusterIP 10.32.104.73 <none> 443/TCP 51s kubernetes ClusterIP 10.32.0.1 <none> 443/TCP 34m

      Tenga en cuenta que por defecto el nombre de servicio correspondiente a nuestra versión es una combinación del nombre de versión de Helm y el nombre del chart.

      Ahora que implementamos la aplicación, utilicemos Helm para cambiar su configuración y actualizar la implementación.

      Paso 4: Actualizar una versión

      El comando helm upgrade puede utilizarse para actualizar una versión con un chart nuevo o actualizado, o para actualizar las opciones de configuración de este mismo.

      Haremos un cambio sencillo en nuestra versión de dashboard-demo para demostrar el proceso de actualización y reversión: actualizaremos el nombre del servicio de panel simplemente a dashboard, en lugar de dashboard-demo-kubernetes-dashboard​​​​​​.

      El chart kubernetes-dashboard proporciona una opción de configuración de fullnameOverride para controlar el nombre de servicio. Ejecutaremos helm upgrade con este conjunto de opciones:

      • helm upgrade dashboard-demo stable/kubernetes-dashboard --set fullnameOverride="dashboard"

      Visualizará un resultado similar al del paso inicial de ​​​​​​helm install.

      Verifique si sus servicios de Kubernetes reflejan los valores actualizados:

      Output

      NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.32.0.1 <none> 443/TCP 36m dashboard ClusterIP 10.32.198.148 <none> 443/TCP 40s

      Se actualizó nuestro nombre de servicio al nuevo valor.

      Nota: En este punto, es posible que desee cargar Kubernetes Dashboard en su navegador y revisarlo. Para hacerlo, primero ejecute el siguiente comando:

      Esto crea un proxy que le permite acceder a recursos de clústeres remotos desde su computadora local. Conforme a las instrucciones anteriores, su servicio de panel se llama kubernetes-dashboard y se ejecuta en el espacio de nombres default. Ahora podrá acceder al panel en la siguiente URL:

      http://localhost:8001/api/v1/namespaces/default/services/https:dashboard:/proxy/
      

      Si es necesario, sustituya su propio nombre de servicio y espacio de nombres por las partes resaltadas. Las instrucciones para el uso del panel quedan fuera del alcance de este tutorial, pero puede leer los documentos oficiales de Kubernetes Dashboard para obtener más información.

      A continuación, veremos la capacidad de Helm para revertir las versiones.

      Paso 5: Realizar una reversión de una versión

      Cuando actualizamos nuestra versión dashboard-demo en el paso anterior, creamos una segunda revisión de la versión. Helm conserva todos los detalles de las versiones anteriores en caso de que deba realizar una reversión a una configuración o un chart anterior.

      Utilice helm list para inspeccionar la versión de nuevo:

      Output

      NAME REVISION UPDATED STATUS CHART NAMESPACE dashboard-demo 2 Wed Aug 8 20:13:15 2018 DEPLOYED kubernetes-dashboard-0.7.1 default

      En la columna REVISON se indica que ésta es ahora la segunda revisión.

      Utilice helm rollback para revertir la primera revisión:

      • helm rollback dashboard-demo 1

      Debería ver el siguiente resultado, lo cual indica que la reversión se realizó:

      Output

      Rollback was a success! Happy Helming!

      En este punto, si ejecuta kubectl get services de nuevo, observará que el nombre de servicio se cambió de nuevo a su valor anterior. Helm volvió a implementar la aplicación con la configuración de la revisión 1.

      A continuación, veremos la eliminación de versiones con Helm.

      Paso 6: Eliminar una versión

      Es posible eliminar versiones de helm con el comando helm delete:

      • helm delete dashboard-demo

      Output

      release "dashboard-demo" deleted

      Aunque la versión se eliminó y la aplicación del panel ya no está en ejecución, Helm guarda toda la información de revisión en caso de que desee volver a implementar la versión. Si intentara instalar una nueva versión de dashboard-demo con helm install en este momento, vería un mensaje de error:

      Error: a release named dashboard-demo already exists.
      

      Si utiliza el indicador --deleted para enumerar sus versiones eliminadas, verá que la versión sigue vigente:

      Output

      NAME REVISION UPDATED STATUS CHART NAMESPACE dashboard-demo 3 Wed Aug 8 20:15:21 2018 DELETED kubernetes-dashboard-0.7.1 default

      Para eliminar realmente la versión y purgar todas las revisiones antiguas, utilice el indicador--purgecon el comando helm delete:

      • helm delete dashboard-demo --purge

      Con esto, la versión se eliminó realmente y podrá reutilizar el nombre de versión.

      Conclusión

      A través de este tutorial, instalamos la herramienta de línea de comandos helm y su servicio complementario tiller. También exploramos la instalación, la actualización, reversión y eliminación de charts y versiones de Helm.

      Para obtener más información sobre Helm y sus charts, consulte la documentación oficial de Helm.



      Source link

      Introducción a Helm, el administrador de paquetes de Kubernetes


      Introducción

      Implementar aplicaciones en Kubernetes (el popular y sólido sistema contenedor y organizador) puede ser un proceso complejo. Configurar una sola aplicación puede implicar crear varios recursos de interdependientes de Kubernetes (tales como lugares de descarga, servicios, implementaciones y ReplicaSets), cada uno de los cuales requiere la redacción de un archivo de manifiesto YAML detallado.

      Helm es un administrador de paquetes para Kubernetes que permite a los desarrolladores y operadores configurar e implementar de forma más sencilla aplicaciones y servicios en clústeres de Kubernetes.

      Actualmente, Helm es un proyecto oficial de Kubernetes y forma parte de Cloud Native Computing Foundation, una organización sin fines de lucro que respalda proyectos de código abierto en el ecosistema de Kubernetes y a su alrededor.

      En este artículo, proporcionaremos una descripción general de Helm y las diversas abstracciones que usa para simplificar la implementación de aplicaciones en Kubernetes. Si no conoce Kubernetes, Introducción a Kubernetes puede resultarle útil antes para familiarizarse con los conceptos básicos.

      Descripción general de Helm

      La mayoría de los sistemas operativos y de programación de lenguaje tienen su propio administrador de paquetes para la instalación y el mantenimiento de software. Helm proporciona el mismo conjunto de funciones básicas que muchos de los administradores que seguramente ya conoce, como apt de Debian o pip de Python.

      Helm puede:

      • Instalar software
      • Instalar de manera automática dependencias de software
      • Actualizar software
      • Configurar implementaciones de software
      • Obtener paquetes de software de repositorios

      Helm proporciona esta funcionalidad a través de los siguientes componentes:

      • Una herramienta de línea de comandos, helm, que proporciona la interfaz de usuario para todas las funcionalidades de Helm.
      • Un componente de servidor complementario, tiller, que funciona en su clúster de Kubernetes, escucha los comandos de helm y gestiona la configuración e implementación de versiones de software en el clúster.
      • El formato de empaquetado de Helm, llamado charts.
      • Un repositorio de charts oficiales seleccionados con charts empaquetados previamente para proyectos de software de código abierto populares.

      A continuación, investigaremos el formato de los charts en mayor detalle.

      Charts

      Los paquetes de Helm se llaman charts, y constan de algunos archivos de configuración YAML y algunas plantillas que se convierten en archivos de manifiesto de Kubernetes. Esta es la estructura de directorios básica de un chart:

      Example chart directory

      package-name/
        charts/
        templates/
        Chart.yaml
        LICENSE
        README.md
        requirements.yaml
        values.yaml
      

      Estos directorios y archivos tienen las siguientes funciones:

      • charts/: en este directorio se pueden disponer dependencias de charts administradas manualmente, aunque suele ser mejor usar requirements.yaml para vincular las dependencias de manera dinámica.
      • templates/: este directorio contiene archivos de plantillas que se combinan con valores de configuración (de values.yaml y la línea de comandos) y se representan en manifiestos de Kubernetes. Las plantillas usan el formato Go programming language.
      • Chart.yaml: archivo YAML con metadatos sobre el chart, como el nombre y la versión de este, la información del mantenedor, un sitio web relevante y palabras claves de búsqueda.
      • LICENSE: licencia de texto sin formato para el chart.
      • README.md: archivo readme con información para usuarios del chart.
      • requirements.yaml: archivo YAML que enumera las dependencias del chart.
      • values.yaml: archivo YAML con valores de configuración predeterminados para el chart.

      El comando helm puede instalar un chart de un directorio local o de una versión .tar.gz empaquetada de esta estructura de directorio. Estos charts empaquetados también pueden descargarse e instalarse automáticamente desde los repositorios de charts, o repos.

      A continuación, analizaremos los repositorios de charts.

      Repositorios de charts

      Un repo de charts de Helm es un sitio HTTP simple que proporciona un archivo index.yaml y charts empaquetados .tar.gz. El comando helm tiene subcomandos disponibles para ayudar a empaquetar charts y crear el archivo index.yaml necesario. En cualquier servidor web, servicio de almacenamiento de objetos o sitio estático, como las páginas GitHub, se pueden proporcionar estos archivos.

      Helm viene previamente configurado con un repositorio de charts predeterminado, conocido como stable. Este repo apunta a un depósito de almacenamiento de Google en https://kubernetes-charts.storage.googleapis.com. La fuente del repo *stable *se puede encontrar en el repositorio Git de helm/charts en GitHub.

      Los repos alternativos pueden agregarse con el comando helm repo add. Los siguientes son algunos repositorios alternativos populares:

      Si instala un chart que desarrolló a nivel local o uno de un repo, debe configurarlo para su instalación en particular. A continuación, veremos las configuraciones.

      Configuración de charts

      Un chart suele incorporar valores de configuración predeterminados en su archivo values.yaml. Algunas aplicaciones pueden implementarse completamente con valores predeterminados, pero por lo general deberá sobrescribir alguna de las configuraciones para que el chart cumpla con sus requisitos.

      El autor del chart determina los valores expuestos para la configuración. Algunos se usan para configurar Kubernetes antiguos y algunos pueden pasarse a través del contenedor subyacente para configurar la propia aplicación.

      A continuación, se brinda un fragmento de algunos valores de ejemplo:

      values.yaml

      service:
        type: ClusterIP
        port: 3306
      

      Estas son opciones para configurar un recurso de servicio de Kubernetes. Puede usar helm inspect values chart-name para desechar todos los valores de configuración disponibles para un chart.

      Estos valores pueden sobrescribirse redactando su propio archivo YAML y usándolo al ejecutar helm install, o al establecer opciones de manera individual en la línea de comandos con el indicador --set. Solo necesita especificar esos valores predeterminados que desee cambiar.

      Un chart de Helm implementado con una configuración particular se conoce como release. Hablaremos sobre los releases a continuación.

      Releases

      Durante la instalación de un chart, Helm combina las plantillas del chart con la configuración especificada por el usuario y los valores predeterminados de value.yaml. Estos se convierten en manifiestos de Kubernetes que se implementan a través de la API de Kubernetes. Con esto se crea un release, una configuración e implementación específica de un chart en particular.

      El concepto de los lanzamientos es importante, ya que posiblemente desee implementar la misma aplicación más de una vez en un clúster. Por ejemplo, es posible que necesite varios servidores de MySQL con distintas configuraciones.

      También es posible que quiera mejorar distintas instancias de un chart de manera individual. Es posible que una aplicación esté lista para un servidor MySQL actualizado, y que otra no lo esté. Con Helm, puede mejorar cada release de forma individual.

      Es posible que mejore un release porque se actualizó el chart de este o porque quiere actualizar la configuración del propio release. De cualquier manera, con cada mejora se creará una nueva revisión de un release y Helm le permitirá restablecer fácilmente revisiones anteriores en caso de que se produzca un problema.

      Creación de charts

      Si no puede encontrar un chart existente para el software que implementará, es posible que prefiera crear uno propio. Helm puede generar la estructura del directorio de un chart con helm create chart-name. Con esto, se creará una carpeta con los archivos y directorios que analizamos en la sección Charts anterior.

      A partir de este punto, debe completar los metadatos de su chart en Chart.yaml y disponer sus archivos de manifiesto de Kubernetes en el directorio templates. Luego, debe quitar las variables de configuración pertinentes de sus manifiestos y disponerlas en values.yaml,y luego incluirlas de nuevo en sus plantillas de manifiestos mediante el sistema de creación de plantillas.

      El comando helm tiene muchos subcomandos disponibles para ayudarlo a probar, empaquetar y administrar sus charts. Para obtener más información, consulte la documentación oficial de Helm vinculada al desarrollo de charts.

      Conclusión

      A lo largo de este artículo, hicimos una revisión de Helm, el administrador de paquetes de Kubernetes. Observamos la arquitectura de Helm y los componentes individuales helm y tiller, vimos en detalle el formato de charts de Helm y analizamos los repositorios de charts. También investigamos la forma de configurar un chart de Helm y de combinar e implementar las configuraciones y los charts como releases en clústeres de Kubernetes. Por último, vimos brevemente los conceptos básicos con los que se puede crear un chart cuando no hay uno adecuado disponible.

      Para obtener más información sobre Helm, consulte la documentación oficial de Helm. Para encontrar charts oficiales para Helm, consulte el repositorio oficial de Git helm/charts en GitHub.



      Source link