One place for hosting & domains

      Registro

      Cómo configurar un registro de Docker privado en Ubuntu 18.04


      El autor seleccionó la Apache Software Foundation para recibir una donación como parte del programa Write for DOnations.

      Introducción

      Docker Registry es una aplicación que gestiona el almacenamiento y el envío de imágenes de contenedores de Docker. Los registros centralizan las imágenes de contenedores y reducen el tiempo de compilación para los desarrolladores. Las imágenes de Docker garantizan el mismo entorno de ejecución a través de la virtualización, pero crear una imagen puede suponer una inversión significativa en términos de tiempo. Por ejemplo, en vez de instalar dependencias y paquetes por separado para usar Docker, los desarrolladores pueden descargar una imagen comprimida de un registro que contenga todos los componentes necesarios. Además, los desarrolladores pueden automatizar la introducción de imágenes en un registro usando herramientas de integración continua, como TravisCI, para actualizar imágenes sin problemas durante la producción y el desarrollo.

      Docker también tiene un registro público gratuito, Docker Hub, que puede alojar sus imágenes de Docker personalizadas, pero existen situaciones en las que no le convendrá que su imagen esté disponible públicamente. Las imágenes normalmente contienen todo el código necesario para ejecutar una aplicación. Por lo tanto, usar un registro privado es preferible cuando se utiliza software propio.

      A través de este tutorial, configurará y protegerá su propio Docker Registry privado. Usará Docker Compose para definir las configuraciones a fin de ejecutar Nginx y sus aplicaciones de Docker para reenviar el tráfico del servidor de HTTPS al contenedor de Docker en ejecución. Una vez que complete este tutorial, podrá introducir una imagen de Docker personalizada en su registro privado y extraer la imagen de forma segura desde un servidor remoto.

      Requisitos previos

      Antes de iniciar esta guía, necesitará lo siguiente:

      • Dos servidores de Ubuntu 18.04 configurados conforme a la guía de configuración inicial para servidores de Ubuntu 18.04, incluidos un usuario sudo no root y un firewall. Un servidor alojará su Docker Registry privado y el otro será su servidor cliente.
      • Docker y Docker Compose instalados en ambos servidores siguiendo el tutorial Cómo instalar Docker Compose en Ubuntu 18.04. Solo necesitará completar el primer paso de este tutorial para instalar Docker Compose. En este tutorial se explica la forma de instalar Docker como parte de sus requisitos previos.
      • Nginx instalado en su servidor de Docker Registry privado, conforme al tutorial Cómo instalar Nginx en Ubuntu 18.04.
      • Nginx protegido con Let´s Encrypt en su servidor para el Docker Registry privado, conforme a Cómo proteger Nginx con Let´s Encrypt. Asegúrese de redireccionar todo el tráfico de HTTP a HTTPS en el paso 4.
      • Un nombre de dominio que resuelve en el servidor que está usando para el Docker Registry privado. Configurará esto como parte del requisito previo de Let´s Encrypt.

      Paso 1: Instalar y configurar el Docker Registry

      La herramienta de línea de comandos de Docker es útil para iniciar y administrar uno o dos contenedores de Docker. Sin embargo, para una implementación completa la mayoría de las aplicaciones que se ejecutan dentro de contenedores de Docker requieren que otros componentes se ejecuten en paralelo. Por ejemplo, muchas aplicaciones web constan de un servidor web, como Nginx, que presente el código de la aplicación, un lenguaje de creación de secuencia de comandos interpretado como PHP, y un servidor de base de datos como MySQL.

      Con Docker Compose, puede escribir un archivo .yml para configurar los ajustes de cada uno de los contenedores y la información que estos deben transmitirse entre sí. Puede usar la herramienta de línea de comandos docker-componse para emitir comandos a todos los componentes que forman su aplicación.

      Docker Registry es en sí misma una aplicación con varios componentes, por lo que utilizará Docker Compose para administrar su configuración. Para iniciar una instancia del registro, configurará un archivo docker-compose.yml para definir la ubicación en la que su registro almacenará sus datos.

      En el servidor que creó para alojar su Docker Registry privado, puede crear un directorio docker-registry, moverlo a él, y luego crear una subcarpeta data con los siguientes comandos:

      • mkdir ~/docker-registry && cd $_
      • mkdir data

      Utilice su editor de texto para crear el archivo de configuración docker-compose.yml:

      Añada el siguiente contenido al archivo, que describe la configuración básica para un Docker Registry:

      docker-compose.yml

      version: '3'
      
      services:
        registry:
          image: registry:2
          ports:
          - "5000:5000"
          environment:
            REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
          volumes:
            - ./data:/data
      

      En la sección environment se establece una variable de entorno en el contenedor de Docker Registry con la ruta /data. La aplicación Docker Registry verifica esta variable de entorno cuando se inicia, y como resultado, comienza a guardar sus datos en la carpeta /data.

      Sin embargo, debido a que incluyó la línea volumes: - ./data:/data, Docker comenzará a asignar el directorio /data de ese contenedor a /data en su servidor de registro. Como resultado final, los datos de Docker Registry se almacenan en ~/docker-registry/data en el servidor de registro.

      La sección ports, con la configuración 5000:5000, indica a Docker que asigne el puerto 5000 en el servidor al puerto 5000 en el contenedor en ejecución. Esto le permite enviar una solicitud al puerto 5000 en el servidor, y que la solicitud se reenvíe a la aplicación de registro.

      Ahora puede iniciar Docker Compose para comprobar la configuración:

      Verá las barras de descarga en su resultado, que muestran que Docker está descargando la imagen de Docker Registry del registro propio de Docker. En un minuto o dos, verá un resultado similar al siguiente (las versiones pueden variar):

      Output of docker-compose up

      Starting docker-registry_registry_1 ... done Attaching to docker-registry_registry_1 registry_1 | time="2018-11-06T18:43:09Z" level=warning msg="No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable." go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="redis not configured" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="Starting upload purge in 20m0s" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="listening on [::]:5000" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2

      Abordará el mensaje de advertencia No HTTP secret provided posteriormente en este tutorial. El resultado muestra que el contenedor se está iniciando. La última línea del resultado muestra que comenzó a escuchar correctamente en el puerto 5000.

      Por defecto, Docker Compose esperará su intervención. Por ello, pulse CTRL+C para apagar su contenedor de Docker Registry.

      Configuró una escucha completa de Docker Registry en el puerto 5000. En este momento, el registro no se iniciará a menos que lo abra manualmente. Además, Docker Registry no tiene ningún mecanismo de autenticación incorporado, por lo que actualmente no es seguro y está completamente abierto al público. En los siguientes pasos, abordará estos problemas de seguridad.

      Paso 2: Configurar el reenvío de puertos de Nginx

      Ya tiene HTTPS configurado en su servidor de Docker Registry con Nginx, lo que significa que ahora puede configurar el enrutamiento de puertos de Nginx al puerto 5000. Una vez que complete este paso, podrá acceder a su registro directamente en example.com.

      Como parte del requisito previo de Cómo proteger Nginx con Let´s Encrypt, ya configuró el archivo /etc/nginx/sites-available/example.com que contiene la configuración de su servidor.

      Abra este archivo con su editor de texto:

      • sudo nano /etc/nginx/sites-available/example.com

      Encuentre la línea location existente. Tendrá el siguiente aspecto:

      /etc/nginx/sites-available/example.com

      ...
      location / {
        ...
      }
      ...
      

      Deberá reenviar el tráfico al puerto 5000, donde se ejecutará su registro. También le conviene adjuntar encabezados a la solicitud al registro, que proporcionan información adicional desde el servidor con cada solicitud y respuesta. Elimine el contenido de la sección location, y añada el siguiente contenido a dicha sección:

      /etc/nginx/sites-available/example.com

      ...
      location / {
          # Do not allow connections from docker 1.5 and earlier
          # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
          if ($http_user_agent ~ "^(docker/1.(3|4|5(?!.[0-9]-dev))|Go ).*$" ) {
            return 404;
          }
      
          proxy_pass                          http://localhost:5000;
          proxy_set_header  Host              $http_host;   # required for docker client's sake
          proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
          proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
          proxy_set_header  X-Forwarded-Proto $scheme;
          proxy_read_timeout                  900;
      }
      ...
      

      La sección $http_user_agent verifica que la versión de Docker del cliente sea superior a la 1.5 y garantiza que UserAgent no sea una aplicación de Go. Debido a que usa la versión 2.0 del registro, los clientes más antiguos no son compatibles. Para obtener más información, puede encontrar la configuración de encabezados nginx en la guía Nginx Docker Registry.

      Guarde el archivo y ciérrelo. Aplique los cambios reiniciando Nginx:

      • sudo service nginx restart

      Puede confirmar que Nginx enrute el tráfico al puerto 5000 ejecutando el registro:

      • cd ~/docker-registry
      • docker-compose up

      En una ventana del navegador, abra la siguiente URL:

      https://example.com/v2
      

      Verá un objeto JSON vacío, o lo siguiente:

      {}
      

      En su terminal, verá un resultado similar al siguiente:

      Output of docker-compose up

      registry_1 | time="2018-11-07T17:57:42Z" level=info msg="response completed" go.version=go1.7.6 http.request.host=cornellappdev.com http.request.id=a8f5984e-15e3-4946-9c40-d71f8557652f http.request.method=GET http.request.remoteaddr=128.84.125.58 http.request.uri="/v2/" http.request.useragent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7" http.response.contenttype="application/json; charset=utf-8" http.response.duration=2.125995ms http.response.status=200 http.response.written=2 instance.id=3093e5ab-5715-42bc-808e-73f310848860 version=v2.6.2 registry_1 | 172.18.0.1 - - [07/Nov/2018:17:57:42 +0000] "GET /v2/ HTTP/1.0" 200 2 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7"

      Puede ver la última línea desde la cual se realizó una solicitud GET a /v2/, que es el punto final al que envío la solicitud desde su navegador. El contenedor recibió la solicitud que realizó, desde el puerto del enrutamiento, y devolvió una respuesta {}. El código 200 en la última línea del resultado significa que el contenedor gestionó la solicitud correctamente.

      Ahora que configuró el enrutamiento de puertos, puede mejorar la seguridad de su registro.

      Paso 3: Configurar la autenticación

      Con las solicitudes de proxy de Nginx, puede proteger su registro con autenticación HTTP para administrar el acceso a su Docker Registry. Para conseguir esto, creará un archivo de autenticación con htpasswd y le añadirá usuarios. La autenticación HTTP se configura rápidamente y es segura a través de una conexión HTTPS, que es la que el registro usará.

      Puede instalar el paquete htpasswd ejecutando lo siguiente:

      • sudo apt install apache2-utils

      Ahora creará el directorio en el que almacenará nuestras credenciales de autenticación y se posicionará en ese directorio. $ se expande al último argumento del comando anterior; en este caso, ~/docker-registry/auth:

      • mkdir ~/docker-registry/auth && cd $_

      A continuación, creará el primer usuario de como se muestra a continuación, sustituyendo username por el nombre de usuario que desee usar. El indicador -B especifica el cifrado bcrypt, que es más seguro que el cifrado predeterminado. Introduzca la contraseña cuando se le solicite:

      • htpasswd -Bc registry.password username

      *Nota: *Para agregar más usuarios, vuelva a ejecutar el comando anterior sin la opción -c, (la “c” significa “crear”):

      • htpasswd registry.password username

      A continuación, editará el archivo docker-compose.yml para indicar a Docker que utilice el archivo que creó con el propósito de autenticar usuarios.

      • cd ~/docker-registry
      • nano docker-compose.yml

      Puede añadir variables de entorno y un volumen para el directorio auth/ que creó editando el archivo docker-compose.yml, para indicar a Docker la forma en que desea autenticar usuarios. Añada el siguiente contenido resaltado al archivo:

      docker-compose.yml

      version: '3'
      
      services:
        registry:
          image: registry:2
          ports:
          - "5000:5000"
          environment:
            REGISTRY_AUTH: htpasswd
            REGISTRY_AUTH_HTPASSWD_REALM: Registry
            REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
            REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
          volumes:
            - ./auth:/auth
            - ./data:/data
      

      Para REGISTRY_AUTH especificó htpasswd, que es el esquema de autenticación que está usando, y fijó REGISTRY_AUTH_HTPASSWD_PATH en la ruta del archivo de autenticación. Por último, REGISTRY_AUTH_HTPASSWD_REALM es el nombre de dominio de htpasswd.

      Ahora puede verificar que su autenticación funcione correctamente ejecutando el registro y comprobando que solicite a los usuarios un nombre de usuario y una contraseña.

      En una ventana del navegador, abra https://example.com/v2.

      Después de ingresar username y la contraseña correspondiente, verá {} una vez más. Con esto, confirmó la configuración básica de autenticación; el registro solo mostró el resultado después de que usted introducido el nombre de usuario y la contraseña correctos. De esta manera, protegió su registro y puede continuar usándolo.

      Paso 4: Iniciar Docker Registry como un servicio

      Le convendrá asegurarse de que su registro se inicie siempre que el sistema se cargue. Si se produce un error imprevisto en el sistema, le convendrá asegurarse de que el registro se reinicie cuando el servidor lo haga. Abra docker-compose.yml:

      Añada la siguiente línea de contenido en registry:

      docker-compose.yml

      ...
        registry:
          restart: always
      ...
      

      Puede iniciar su registro como proceso en segundo plano, lo que le permitirá cerrar la sesión ssh y persistir el proceso:

      Con su registro ejecutándose en segundo plano, ahora podrá preparar Nginx para subir archivos.

      Paso 5: Aumentar el tamaño para la carga de archivos para Nginx

      Para poder introducir una imagen en el registro, deberá asegurarse de que este pueda gestionar cargas de archivos grandes. Aunque Docker divide las cargas de imágenes grandes en capas separadas, a veces pueden ocupar más de 1 GB. Por defecto, Nginx tiene un límite de 1 MB para las cargas de archivos, de modo que deberá editar el archivo de configuración para nginx y fijar en 2 GB el tamaño máximo para la carga de archivos.

      • sudo nano /etc/nginx/nginx.conf

      Busque la sección http y añada la siguiente línea:

      /etc/nginx/nginx.conf

      ...
      http {
              client_max_body_size 2000M;
              ...
      }
      ...
      

      Finalmente, reinicie Nginx para aplicar los cambios en la configuración:

      • sudo service nginx restart

      Ahora puede subir imágenes grandes a su Docker Registry sin errores de Nginx.

      Paso 6: Hacer publicaciones en su Docker Registry privado

      Ahora estará listo para publicar una imagen en su Docker Registry privado, pero primero deberá crear una imagen. Para este tutorial, creará una imagen sencilla basada en la imagen de ubuntu de Docker Hub. Docker Hub es un registro alojado públicamente, con muchas imágenes preconfiguradas que pueden utilizarse para “dockerizar” rápidamente aplicaciones. Usando la imagen de ubuntu, probará la introducción en su registro y la y extracción de este.

      Desde su servidor cliente, cree una imagen pequeña y vacía para la introducción en su nuevo registro; los indicadores -i y -t le proporcionan acceso de shell interactivo al contenedor:

      • docker run -t -i ubuntu /bin/bash

      Tras terminar la descarga, se posicionará dentro de una instrucción de Docker. Tenga en cuenta que el ID de su contenedor después de root@ variará. Realice un cambio rápido en el sistema de archivos creando un archivo llamado SUCCESS. En el siguiente paso, podrá usar este archivo para determinar si el proceso de publicación se realiza correctamente:

      Cierre el contenedor de Docker:

      Con el siguiente comando, se crea una nueva imagen llamada test-image basada en la imagen que ya está en ejecución y se suma cualquier cambio que haya realizado. En nuestro caso, la adición del archivo /SUCCESS se incluye en la nueva imagen.

      Aplique el cambio:

      • docker commit $(docker ps -lq) test-image

      En este punto, la imagen solo existe a nivel local. Ahora podrá introducirla en el nuevo registro que creó. Inicie sesión en su Docker Registry:

      • docker login https://example.com

      Introduzca el username y la contraseña correspondiente antes utilizados. A continuación, etiquetará la imagen con la ubicación del registro privado para introducirla en él:

      • docker tag test-image example.com/test-image

      Introduzca la imagen recién etiquetada en el registro:

      • docker push example.com/test-image

      El resultado debe tener un aspecto similar al siguiente:

      Output

      The push refers to a repository [example.com/test-image] e3fbbfb44187: Pushed 5f70bf18a086: Pushed a3b5c80a4eba: Pushed 7f18b442972b: Pushed 3ce512daaf78: Pushed 7aae4540b42d: Pushed ...

      Con esto, habrá verificado que su registro gestione la autenticación de usuarios y permita que los usuarios autenticados introduzcan imágenes en el registro. A continuación, confirmará que también puede extraer imágenes del registro.

      Vuelva al servidor de su registro para poder probar la extracción de la imagen desde su servidor de cliente. También es posible probar esto desde un tercer servidor.

      Inicie sesión con el nombre de usuario y la contraseña que estableció previamente:

      • docker login https://example.com

      Con esto, estará listo para extraer la imagen. Utilice el nombre de su dominio e imagen, que etiquetó en el paso previo:

      • docker pull example.com/test-image

      Docker descargará la imagen y lo conducirá a la línea de comandos. Si ejecuta la imagen en el servidor de registro, verá que el archivo SUCCESS que creó antes estará allí:

      • docker run -it example.com/test-image /bin/bash

      Liste sus archivos dentro del shell de bash:

      Verá el archivo SUCCESS que creó para esta imagen:

      SUCCESS  bin  boot  dev  etc  home  lib  lib64  media   mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
      

      Con esto, habrá terminado de configurar un registro seguro en el cual los usuarios puedan introducir imágenes personalizadas y desde el cual pueden extraerlas.

      Conclusión

      A través de este tutorial, configuró su propio Docker Registry privado y publicó una imagen de Docker. Como se mencionó en la introducción, también puede usar TravisCI o una herramienta CI similar para automatizar la introducción directa en un registro privado. Al aprovechar Docker y los registros en su flujo de trabajo, puede garantizar que la imagen que contiene el código tendrá el mismo comportamiento en cualquier máquina, ya sea para la producción o el desarrollo. Para obtener más información sobre la escritura de archivos de Docker, puede leer este tutorial de Docker en el que se explica el proceso.



      Source link

      Cómo configurar una pila de registro de Elasticsearch, Fluentd y Kibana (EFK) en Kubernetes


      Introducción

      Cuando se ejecutan múltiples servicios y aplicaciones en un clúster de Kubernetes, una pila de registro centralizada de nivel de clúster puede servirle para clasificar y analizar rápidamente el gran volumen de datos de registro producidos por sus Pods. Una solución de registro centralizada popular es la pila de Elasticsearch, Fluentd y Kibana (EFK).

      Elasticsearch es un motor de búsqueda en tiempo real, distribuido y escalable que permite una búsqueda completa de texto y estructurada, además de análisis. Se suele usar para indexaciones y búsquedas en grandes volúmenes de datos de registro, pero también se puede emplear para buscar muchos tipos diferentes de documentos.

      Elasticsearch se suele implementar con Kibana, un poderoso frontend de visualización de datos y un panel de control para Elasticsearch. Kibana le permite explorar sus datos de registro de Elasticsearch a través de una interfaz web y crear paneles de control y consultas para responder rápidamente a preguntas y obtener información sobre sus aplicaciones de Kubernetes.

      En este tutorial, usaremos Fluentd para recopilar, transformar y enviar datos de registro al backend de Elasticsearch. Fluentd es un recopilador de datos de código abierto popular que configuraremos en nuestros nodos de Kubernetes para seguir archivos de registro de contenedores, filtrar y transformar los datos de registro y entregarlos al clúster de Elasticsearch, donde se indexarán y almacenarán.

      Comenzaremos configurando e iniciando un clúster escalable de Elasticsearch y luego crearemos el servicio y la implementación de Kubernetes de Kibana. Para finalizar, configuraremos Fluentd como DaemonSet para que se ejecute en todos los nodos de trabajo de Kubernetes.

      Requisitos previos

      Antes de comenzar con esta guía, asegúrese de contar con lo siguiente:

      • Un clúster de Kubernetes 1.10, o una versión posterior, con control de acceso basado en roles (RBCA) activado

        • Compruebe que su clúster cuente con suficientes recursos para implementar la pila EFK y, si no es así, escale su clúster agregando nodos de trabajo. Implementaremos un clúster de 3 Pods de Elasticsearch (puede reducir el número a 1 si es necesario) y un único Pod de Kibana. En cada nodo de trabajo también se ejecutará un Pod de Fluentd. El clúster de esta guía consta de 3 nodos de trabajo y un panel de control administrado.
      • La herramienta de línea de comandos kubectl instalada en su máquina local, configurada para establecer conexión con su clúster. Puede obtener más información sobre la instalación de kubectl en la documentación oficial.

      Cuando tenga estos componentes configurados, estará listo para comenzar con esta guía.

      Paso 1: Crear un espacio de nombres

      Antes de implementar un clúster de Elasticsearch, primero crearemos un espacio de nombres en el que instalaremos toda nuestra instrumentación de registro. Kubernetes le permite separar objetos que se ejecutan en su clúster usando una abstracción “clúster virtual” llamada “Namespaces” (espacios de nombres). En esta guía, crearemos un espacio de nombres kube-logging en el cual instalaremos los componentes de la pila EFK. Este espacio de nombres también nos permitirá limpiar y eliminar la pila de registros sin pérdida de funciones en el clúster de Kubernetes.

      Para comenzar, primero investigue los espacios de nombres de su clúster usando kubectl:

      kubectl get namespaces
      

      Debería ver los siguientes tres espacios de nombres iniciales, que vienen ya instalados con su clúster Kubernetes:

      Output

      • NAME STATUS AGE
      • default Active 5m
      • kube-system Active 5m
      • kube-public Active 5m

      El espacio de nombres default aloja los objetos que se crean sin especificar un espacio de nombres. El espacio de nombres kube-system contiene objetos creados y usados por el sistema Kubernetes, como ​​​​​​kube-dns​​​​​​, ​​​​​​kube-proxy​​​​ y ​​​kubernetes-dashboard​​​​​​. Se recomienda guardar este espacio de nombres limpio sin contaminarlo con las cargas de trabajo de aplicaciones e instrumentos.

      El espacio de nombres kube-public es otro de los que se crean automáticamente y se puede usar para almacenar objetos para los cuales desee habilitar la lectura y el acceso en todo el clúster, incluso para usuarios sin autenticar.

      Para crear el espacio de nombres kube-logging, abra primero y edite un archivo llamado kube-logging.yaml usando su editor favorito. Por ejemplo, nano:

      Dentro de su editor, pegue el siguiente YAML de objeto de espacio de nombres:

      kube-logging.yaml

      kind: Namespace
      apiVersion: v1
      metadata:
        name: kube-logging
      

      A continuación, guarde y cierre el archivo.

      Aquí especificamos el kind del objeto de Kubernetes como objeto Namespace. Para obtener más información los objetos Namespace, consulte el Tutorial de espacios de nombres en la documentación oficial de Kubernetes. También especificamos la versión API de Kubernetes utilizada para crear el objeto (v1) y le damos un name: kube-logging.

      Cuando haya creado el archivo objeto de espacio de nombres kube-logging.yaml, cree el espacio de nombres usando kubectl create con el indicador de nombre de archivo -f:

      • kubectl create -f kube-logging.yaml

      Debería ver el siguiente resultado:

      Output

      namespace/kube-logging created

      A continuación, puede confirmar que el espacio de nombres se creó correctamente:

      En este punto, debería ver el nuevo espacio de nombres kube-logging:

      Output

      NAME STATUS AGE default Active 23m kube-logging Active 1m kube-public Active 23m kube-system Active 23m

      Ahora podemos implementar un clúster de Elasticsearch en este espacio de nombres de registro aislado.

      Paso 2: Crear el StatefulSet de Elasticsearch

      Ahora que creamos un espacio de nombres para alojar nuestra pila de registro, podemos comenzar a implementar sus diferentes componentes. Primero, empezaremos implementando un clúster de Elasticsearch de 3 nodos.

      En esta guía, usamos 3 Pods de Elasticsearch para evitar el problema de “cerebro dividido” que se produce en clústeres altamente disponibles y con muchos nodos. A un nivel superior, “cerebro dividido” es lo que surge cuando uno o más nodos no pueden comunicarse con los demás, y se eligen varios maestros “divididos”. Al haber 3 nodos, si uno se desconecta del clúster temporalmente, los otros dos pueden elegir un nuevo maestro y el clúster puede seguir funcionando mientras el último nodo intenta volver a unirse. Para obtener más información, consulte Una nueva era para la coordinación de clústeres en Elasticsearch y Configuraciones de voto.

      Crear el servicio sin encabezado

      Para comenzar, crearemos un servicio de Kubernetes sin encabezado llamado elasticsearch que definirá un dominio DNS para los 3 Pods. Un servicio sin encabezado no realiza un equilibrio de carga ni tiene un IP estático; para obtener más información sobre los servicios sin encabezado, consulte la documentación oficial de Kubernetes.

      Abra un archivo llamado elasticsearch_svc.yaml usando su editor favorito:

      • nano elasticsearch_svc.yaml

      Péguelo en el siguiente YAML de servicio de Kubernetes:

      elasticsearch_svc.yaml

      kind: Service
      apiVersion: v1
      metadata:
        name: elasticsearch
        namespace: kube-logging
        labels:
          app: elasticsearch
      spec:
        selector:
          app: elasticsearch
        clusterIP: None
        ports:
          - port: 9200
            name: rest
          - port: 9300
            name: inter-node
      

      A continuación, guarde y cierre el archivo.

      Definimos un Service llamado elasticsearch en el espacio de nombres kube-logging y le asignamos la etiqueta app:elasticsearch. A continuación, fijamos .spec.selector en app: elasticsearch para que el servicio seleccione Pods con la etiqueta app:elasticsearch. Cuando asociemos nuestro StatefulSet de Elasticsearch con este servicio, este último mostrará registros DNS A orientados a los Pods de Elasticsearch con la etiqueta app: elasticsearch.

      A continuación, configuraremos clusterIP:None que elimina el encabezado del servicio. Por último, definiremos los puertos 9200 y 9300 que se usan para interactuar con la API REST y para las comunicaciones entre nodos, respectivamente.

      Cree el servicio usando kubectl:

      • kubectl create -f elasticsearch_svc.yaml

      Debería ver el siguiente resultado:

      Output

      service/elasticsearch created

      Por último, verifique bien que el servicio se haya creado correctamente usando kubectl get:

      kubectl get services --namespace=kube-logging
      

      Debería ver lo siguiente:

      Output

      NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 26s

      Ahora que configuramos nuestro servicio sin encabezado y un dominio estable .elasticsearch.kube-logging.svc.cluster.local para nuestros Pods, podemos crear el StatefulSet.

      Crear el StatefulSet

      Un StatefulSet de Kubernetes le permite asignar una identidad estable a los Pods y otorgar a estos un almacenamiento estable y persistente. Elasticsearch requiere un almacenamiento estable para persistir datos en reinicios y reprogramaciones de Pods. Para obtener más información sobre el volumen de trabajo de StatefulSet, consulte la página de StatefulSet en los documentos de Kubernetes.

      Abra un archivo llamado elasticsearch_statefulset.yaml usando su editor favorito:

      • nano elasticsearch_statefulset.yaml

      Veremos sección a sección la definición del objeto de StatefulSet y pegaremos bloques a este archivo.

      Comience pegando el siguiente bloque:

      elasticsearch_statefulset.yaml

      apiVersion: apps/v1
      kind: StatefulSet
      metadata:
        name: es-cluster
        namespace: kube-logging
      spec:
        serviceName: elasticsearch
        replicas: 3
        selector:
          matchLabels:
            app: elasticsearch
        template:
          metadata:
            labels:
              app: elasticsearch
      

      En este bloque, definimos un StatefulSet llamado es-cluster en el espacio de nombres kube-logging. A continuación, lo asociamos con nuestro servicio elasticsearch ya creado usando el campo serviceName. Esto garantiza que se pueda acceder a cada Pod de StatefulSet usando la de dirección DNS es-cluster-[1,2].elasticsearch.kube-logging.svc.cluster.local, donde [0,1,2] corresponde al ordinal de número entero asignado.

      Especificamos 3 replicas (Pods) y fijamos el selector matchLabels en app: elasticsearch, que luego replicamos en la sección .spec.template.metadata. Los campos .spec.selector.matchLabels y .spec.template.metadata.labels deben coincidir.

      Ahora podemos pasar a la especificación del objeto. Péguelo en el siguiente bloque de YAML inmediatamente debajo del bloque anterior:

      elasticsearch_statefulset.yaml

      . . .
          spec:
            containers:
            - name: elasticsearch
              image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
              resources:
                  limits:
                    cpu: 1000m
                  requests:
                    cpu: 100m
              ports:
              - containerPort: 9200
                name: rest
                protocol: TCP
              - containerPort: 9300
                name: inter-node
                protocol: TCP
              volumeMounts:
              - name: data
                mountPath: /usr/share/elasticsearch/data
              env:
                - name: cluster.name
                  value: k8s-logs
                - name: node.name
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.name
                - name: discovery.seed_hosts
                  value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch"
                - name: cluster.initial_master_nodes
                  value: "es-cluster-0,es-cluster-1,es-cluster-2"
                - name: ES_JAVA_OPTS
                  value: "-Xms512m -Xmx512m"
      

      Aquí definimos los Pods en StatefulSet. Llamamos a los contenedores elasticsearch y elegimos la imagen de Docker docker.elastic.co/elasticsearch/elasticsearch:7.2.0. En este momento, puede modificar esta etiqueta de imagen para que se corresponda con su propia imagen interna de Elasticsearch, o a una versión distinta. Tenga en cuenta que, a los efectos de esta guía, solo se ha probado Elasticsearch 7.2.0.

      A continuación, usamos el campo resources para especificar que el contenedor necesita que se garantice al menos 0,1 vCPU y puede tener ráfagas de hasta 1 vCPU (lo que limita el uso de recursos de Pods cuando se realiza una ingestión inicial grande o se experimenta un pico de carga). Debería modificar estos valores según su carga prevista y los recursos disponibles. Para obtener más información sobre solicitudes y límites de recursos, consulte la documentación oficial de Kubernetes.

      A continuación, abriremos los puertos 9200 y 9300 y les asignaremos nombres para la comunicación de la API REST y entre nodos, respectivamente. Especificaremos un volumeMount llamado data que montará el PersistentVolume llamado data en el contenedor en la ruta /usr/share/elasticsearch/data. Definiremos los VolumeClaims para este StatefulSet en un bloque YAML posterior.

      Por último, configuraremos algunas variables de entorno en el contenedor:

      • cluster.name: nombre del clúster de Elasticsearch, que en esta guía es k8s-lologs.
      • node.name: nombre del nodo, que configuramos en el campo .metadata.name usando valueFrom. Esto se resolverá en es-cluster-[0,1,2] según el ordinal asignado al nodo.
      • discovery.seed_hosts: este campo establece una lista de nodos que el maestro puede elegir en el clúster e iniciarán el proceso de descubrimiento del nodo. En esta guía, gracias al servicio sin encabezado que configuramos antes, nuestros Pods tienen dominios del tipo es-cluster-[0,2].elasticsearch.kube-logging.svc.cluster.local, por lo que configuramos esta variable como corresponde. Usando la resolución DNS de Kubernetes de espacio de nombres locales, podemos acortar esto a es-cluster-[0,1,2].elasticsearch. Para obtener más información sobre el descubrimiento de Elasticsearch, consulte la documentación oficial de Elasticsearch.
      • cluster.initial_master_nodes: este campo también especifica una lista de nodos que el maestro puede elegir y que participarán en el proceso de elección de maestro. Tenga en cuenta que para este campo debería identificar nodos por sus node.name, no sus nombres de host.
      • ES_JAVA_OPTS: aquí lo fijamos en -Xms512m -Xmxx512m, que indica a la JVM que utilice un tamaño de pila mínimo y máximo de 512 MB. Debería ajustar estos parámetros según la disponibilidad y las necesidades de recursos de su clúster. Para obtener más información, consulte Configurar el tamaño de la pila.

      El siguiente bloque que pegaremos tiene este aspecto:

      elasticsearch_statefulset.yaml

      . . .
            initContainers:
            - name: fix-permissions
              image: busybox
              command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
              securityContext:
                privileged: true
              volumeMounts:
              - name: data
                mountPath: /usr/share/elasticsearch/data
            - name: increase-vm-max-map
              image: busybox
              command: ["sysctl", "-w", "vm.max_map_count=262144"]
              securityContext:
                privileged: true
            - name: increase-fd-ulimit
              image: busybox
              command: ["sh", "-c", "ulimit -n 65536"]
              securityContext:
                privileged: true
      

      En este bloque, definimos varios Contenedores Init que se ejecutan antes del contenedor principal de la aplicación elasticsearch. Estos contenedores Init se ejecutan para que se completen en el orden en que se definen. Para obtener más información sobre los Contenedores Init, consulte la documentación oficial de Kubernetes.

      El primero, llamado fix-permissions, ejecuta un comando chown para cambiar el propietario y el grupo del directorio de datos de Elasticsearch a 1000:1000, el UID de usuario de Elasticsearch. Por defecto, Kubernetes instala el directorio de datos como root, con lo cual Elasticsearch no puede acceder a él. Para obtener más información sobre este paso, consulte “Notas vinculadas al uso de producción y a los valores predeterminados”.

      El segundo, llamado increase-vm-max-map, ejecuta un comando para aumentar los límites del sistema operativo en los recuentos de mmap, lo que por defecto puede ser demasiado bajo. Esto puede provocar errores de memoria. Para obtener más información sobre este paso, consulte la documentación oficial de Elasticsearch.

      El siguiente contenedor Init que se ejecutará es increase-fd-ulimit, que ejecuta el comando ulimit para aumentar el número máximo de descriptores de archivos abiertos. Para obtener más información sobre este paso, consulte “Notas vinculadas al uso de producción y a los valores predeterminados” en la documentación oficial de Elasticsearch.

      Nota: en las Notas de Elasticsearch vinculadas al uso de producción también se menciona la desactivación del intercambio por motivos de rendimiento. Según su instalación o proveedor de Kubernetes, es posible que el intercambio ya esté inhabilitado. Para comprobarlo, aplique exec en un contenedor ejecutándose y ejecute cat /proc/swaps para enumerar los dispositivos de intercambio activos. Si no ve nada, el intercambio estará inhabilitado.

      Ahora que definimos nuestro contenedor principal de la aplicación y los contenedores Init que se ejecutan antes para ajustar el SO del contenedor, podemos añadir la pieza final a nuestro archivo de definición de objeto StatefulSet: volumeClaimTemplates.

      Pegue el siguiente bloque de volumeClaimTemplate:

      elasticsearch_statefulset.yaml

      . . .
        volumeClaimTemplates:
        - metadata:
            name: data
            labels:
              app: elasticsearch
          spec:
            accessModes: [ "ReadWriteOnce" ]
            storageClassName: do-block-storage
            resources:
              requests:
                storage: 100Gi
      

      En este bloque, definimos el volumeClaimTemplates de StatefulSet. Kubernetes lo usará para crear PersistentVolumes para los Pods. En el bloque anterior, lo llamamos data (que es el name al que nos referimos en el volumeMount previamente definido) y le asignamos la misma etiqueta app: elasticsearch que a nuestro StatefulSet.

      A continuación, especificamos su modo de acceso como ReadWriteOnce, lo que significa que solo un nodo puede montarlo con atributos de lectura y escritura. En esta guía, definimos la clase de almacenamiento como do-block-storage debido a que usamos un clúster de Kubernetes DigitalOcean para fines demostrativos. Debería cambiar este valor según el punto en que ejecute su clúster de Kubernetes. Para obtener más información, consulte la documentación de Persistent Volume.

      Por último, especificaremos que nos gustaría que cada PersistentVolume tuviese un tamaño de 100 GiB. Debería ajustar este valor según sus necesidades de producción.

      La especificación completa de StatefulSet debería tener un aspecto similar a este:

      elasticsearch_statefulset.yaml

      apiVersion: apps/v1
      kind: StatefulSet
      metadata:
        name: es-cluster
        namespace: kube-logging
      spec:
        serviceName: elasticsearch
        replicas: 3
        selector:
          matchLabels:
            app: elasticsearch
        template:
          metadata:
            labels:
              app: elasticsearch
          spec:
            containers:
            - name: elasticsearch
              image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
              resources:
                  limits:
                    cpu: 1000m
                  requests:
                    cpu: 100m
              ports:
              - containerPort: 9200
                name: rest
                protocol: TCP
              - containerPort: 9300
                name: inter-node
                protocol: TCP
              volumeMounts:
              - name: data
                mountPath: /usr/share/elasticsearch/data
              env:
                - name: cluster.name
                  value: k8s-logs
                - name: node.name
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.name
                - name: discovery.seed_hosts
                  value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch"
                - name: cluster.initial_master_nodes
                  value: "es-cluster-0,es-cluster-1,es-cluster-2"
                - name: ES_JAVA_OPTS
                  value: "-Xms512m -Xmx512m"
            initContainers:
            - name: fix-permissions
              image: busybox
              command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
              securityContext:
                privileged: true
              volumeMounts:
              - name: data
                mountPath: /usr/share/elasticsearch/data
            - name: increase-vm-max-map
              image: busybox
              command: ["sysctl", "-w", "vm.max_map_count=262144"]
              securityContext:
                privileged: true
            - name: increase-fd-ulimit
              image: busybox
              command: ["sh", "-c", "ulimit -n 65536"]
              securityContext:
                privileged: true
        volumeClaimTemplates:
        - metadata:
            name: data
            labels:
              app: elasticsearch
          spec:
            accessModes: [ "ReadWriteOnce" ]
            storageClassName: do-block-storage
            resources:
              requests:
                storage: 100Gi
      

      Cuando esté satisfecho con su configuración de Elasticsearch, guarde y cierre el archivo.

      Ahora, implemente StatefulSet usando kubectl:

      • kubectl create -f elasticsearch_statefulset.yaml

      Debería ver el siguiente resultado:

      Output

      statefulset.apps/es-cluster created

      Puede controlar la implementación de StatefulSet usando kubectl rollout status:

      • kubectl rollout status sts/es-cluster --namespace=kube-logging

      Debería ver el siguiente resultado a medida que se implemente el clúster:

      Output

      Waiting for 3 pods to be ready... Waiting for 2 pods to be ready... Waiting for 1 pods to be ready... partitioned roll out complete: 3 new pods have been updated...

      Cuando se implemenen todos los Pods, podrá comprobar que su clúster de Elasticsearch funcione correctamente realizando una solicitud en la API REST.

      Para hacerlo, primero, reenvíe el puerto local 9200 al puerto 9200 en uno de los nodos de Elasticsearch (es-cluster-0) usando kubectl port-forward:

      • kubectl port-forward es-cluster-0 9200:9200 --namespace=kube-logging

      A continuación, en una ventana de terminal separada, realice una solicitud curl en la API REST:

      • curl http://localhost:9200/_cluster/state?pretty

      Debería ver el siguiente resultado:

      Output

      { "cluster_name" : "k8s-logs", "compressed_size_in_bytes" : 348, "cluster_uuid" : "QD06dK7CQgids-GQZooNVw", "version" : 3, "state_uuid" : "mjNIWXAzQVuxNNOQ7xR-qg", "master_node" : "IdM5B7cUQWqFgIHXBp0JDg", "blocks" : { }, "nodes" : { "u7DoTpMmSCixOoictzHItA" : { "name" : "es-cluster-1", "ephemeral_id" : "ZlBflnXKRMC4RvEACHIVdg", "transport_address" : "10.244.8.2:9300", "attributes" : { } }, "IdM5B7cUQWqFgIHXBp0JDg" : { "name" : "es-cluster-0", "ephemeral_id" : "JTk1FDdFQuWbSFAtBxdxAQ", "transport_address" : "10.244.44.3:9300", "attributes" : { } }, "R8E7xcSUSbGbgrhAdyAKmQ" : { "name" : "es-cluster-2", "ephemeral_id" : "9wv6ke71Qqy9vk2LgJTqaA", "transport_address" : "10.244.40.4:9300", "attributes" : { } } }, ...

      Esto indica que nuestro clúster de Elasticsearch k8s-logs se creó correctamente con 3 nodos: es-cluster-0, es-cluster-1 y es-cluster-2. El nodo maestro actual es es-cluster-0.

      Ahora que su clúster de Elasticsearch está configurado y en ejecución, puede configurar un frontend de Kibana para él.

      Paso 3: Crear la implementación y el servicio de Kibana

      Para iniciar Kibana en Kubernetes, crearemos un servicio llamado kibana y una implementación que consta de una réplica de Pod. Puede escalar el número de replicas según sus necesidades de producción y, de forma opcional, especificar un tipo de LoadBalancer para el servicio a fin de cargar solicitudes de equilibrio en los pods de implementación.

      En este caso, crearemos el servicio y la implementación en el mismo archivo. Abra un archivo llamado kibana.yaml en su editor favorito:

      Péguelo en la siguiente especificación de servicio:

      kibana.yaml

      apiVersion: v1
      kind: Service
      metadata:
        name: kibana
        namespace: kube-logging
        labels:
          app: kibana
      spec:
        ports:
        - port: 5601
        selector:
          app: kibana
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: kibana
        namespace: kube-logging
        labels:
          app: kibana
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: kibana
        template:
          metadata:
            labels:
              app: kibana
          spec:
            containers:
            - name: kibana
              image: docker.elastic.co/kibana/kibana:7.2.0
              resources:
                limits:
                  cpu: 1000m
                requests:
                  cpu: 100m
              env:
                - name: ELASTICSEARCH_URL
                  value: http://elasticsearch:9200
              ports:
              - containerPort: 5601
      

      A continuación, guarde y cierre el archivo.

      En esta especificación, definimos un servicio llamado kibana en el espacio de nombres kube-logging y le asignamos la etiqueta app: kibana.

      También especificamos que el acceso a este debería ser posible en el puerto 5601 y que debería usar la etiqueta app: kibana para seleccionar los Pods de destino del servicio.

      En la especificación Deployment, definimos una implementación llamada kibana y especificamos que quisiéramos 1 réplica de Pod.

      Usamos la imagen docker.elastic.co/kibana/kibana:7.2.0. Ahora puede sustituir su propia imagen de Kibana privada o pública que usará.

      Especificamos que nos quisiéramos al menos 0,1 vCPU garantizado para el Pod, con un límite de 1 vCPU. Debería cambiar estos valores según su carga prevista y los recursos disponibles.

      A continuación, usaremos la variable de entorno ELASTICSEARCH_URL para establecer el punto final y el puerto para el clúster de Elasticsearch. Al usar DNS de Kubernetes, este punto final corresponde a su nombre de servicio elasticsearch. Este dominio se resolverá en una lista de direcciones IP para los 3 Pods de Elasticsearch. Para obtener más información sobre el DNS de Kubernetes, consulte DNS para servicios y Pods.

      Por último, fijamos el puerto de contenedor de Kibana en el valor 5601, al cual el servicio kibana reenviará las solicitudes.

      Cuando esté satisfecho con su configuración de Kibana, podrá implementar el servicio y la implementación usando kubectl:

      • kubectl create -f kibana.yaml

      Debería ver el siguiente resultado:

      Output

      service/kibana created deployment.apps/kibana created

      Puede comprobar que la implementación se haya realizado con éxito ejecutando el siguiente comando:

      • kubectl rollout status deployment/kibana --namespace=kube-logging

      Debería ver el siguiente resultado:

      Output

      deployment "kibana" successfully rolled out

      Para acceder a la interfaz de Kibana, reenviaremos un puerto local al nodo de Kubernetes ejecutando Kibana. Obtenga la información del Pod de Kibana usando kubectl get:

      • kubectl get pods --namespace=kube-logging

      Output

      NAME READY STATUS RESTARTS AGE es-cluster-0 1/1 Running 0 55m es-cluster-1 1/1 Running 0 54m es-cluster-2 1/1 Running 0 54m kibana-6c9fb4b5b7-plbg2 1/1 Running 0 4m27s

      Aquí observamos que nuestro Pod de Kibana se llama kibana-6c9fb4b5b7-plbg2.

      Reenvíe el puerto local 5601 al puerto 5601 de este Pod:

      • kubectl port-forward kibana-6c9fb4b5b7-plbg2 5601:5601 --namespace=kube-logging

      Debería ver el siguiente resultado:

      Output

      Forwarding from 127.0.0.1:5601 -> 5601 Forwarding from [::1]:5601 -> 5601

      Ahora, en su navegador web, visite la siguiente URL:

      http://localhost:5601
      

      Si ve la siguiente página de bienvenida de Kibana, significa que implementó con éxito Kibana en su clúster de Kubernetes:

      Pantalla de bienvenida de Kibana

      Ahora puede proseguir con la implementación del componente final de la pila EFK: el colector de registro, Fluentd.

      Paso 4: Crear el DaemonSet de Fluentd

      En esta guía, configuraremos Fluentd como DaemonSet, que es un tipo de carga de trabajo de Kubernetes que ejecuta una copia de un Pod determinado en cada nodo del clúster de Kubernetes. Al usar este controlador de DaemonSet, implementaremos un Pod de agente de registro de Fluentd en cada nodo de nuestro clúster. Para obtener más información sobre esta arquitectura de registro, consulte “Usar un agente de registro de nodo” de los documentos oficiales de Kubernetes.

      En Kubernetes, los flujos de registro de las aplicaciones en contenedores que realizan registros en stdout y stderr se capturan y redireccionan a los archivos de JSON de los nodos. El Pod de Fluentd controlará estos archivos de registro, filtrará los eventos de registro, transformará los datos de registro y los enviará al backend de registro de Elasticsearch que implementamos en el Paso 2.

      Además de los registros de contenedores, el agente de Fluentd controlará los registros de componentes del sistema de Kubernetes, como kubelet, kube-proxy y los registros de Docker. Para ver una lista completa de fuentes controladas por el agente de registro de Fluentd, consulte el archivo kubernetes.conf utilizado para configurar el agente de registro. Para obtener más información sobre el registro en los clústeres de Kubernetes, consulte “Realizar registros en el nivel de nodo” de la documentación oficial de Kubernetes.

      Empiece abriendo un archivo llamado fluentd.yaml en su editor de texto favorito:

      Una vez más, realizaremos el pegado en las definiciones de objeto de Kubernetes bloque por bloque y proporcionaremos contexto a medida que avancemos. En esta guía, usamos la especificación de DaemonSet de Fluentd proporcionada por los encargados de mantenimiento de Fluentd. Otro recurso útil proporcionado por los encargados de mantenimiento de Fluentd es Kuberentes Fluentd.

      Primero, pegue la siguiente definición de ServiceAccount:

      fluentd.yaml

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: fluentd
        namespace: kube-logging
        labels:
          app: fluentd
      

      Aquí, crearemos una cuenta de servicio llamada fluentd que los Pods de Fluentd usarán para acceder a la API de Kubernetes. La crearemos en el espacio de nombres kube-logging y una vez más le asignaremos la etiqueta app: fluentd. Para obtener más información sobre las cuentas de servicio de Kubernetes, consulte Configurar cuentas de servicio para Pods en los documentos oficiales de Kubernetes.

      A continuación, pegue el siguiente bloque de ClusterRole:

      fluentd.yaml

      . . .
      ---
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: fluentd
        labels:
          app: fluentd
      rules:
      - apiGroups:
        - ""
        resources:
        - pods
        - namespaces
        verbs:
        - get
        - list
        - watch
      

      Aquí definiremos un ClusterRole llamado fluentd al que concederemos los permisos get, list y watch en los objetos pods y namespaces. Los clusterRoles le permiten conceder acceso a recursos de Kubernetes con ámbito de clúster como nodos. Para obtener más información sobre el control de acceso basado en roles y los roles de clústeres, consulte Usar la autorización de RBACen la documentación oficial de Kubernetes.

      A cotninuación, pegue el siguiente bloque de ClusterRoleBinding:

      fluentd.yaml

      . . .
      ---
      kind: ClusterRoleBinding
      apiVersion: rbac.authorization.k8s.io/v1
      metadata:
        name: fluentd
      roleRef:
        kind: ClusterRole
        name: fluentd
        apiGroup: rbac.authorization.k8s.io
      subjects:
      - kind: ServiceAccount
        name: fluentd
        namespace: kube-logging
      

      En este bloque, definimos un ClusterRoleBinding llamado fluentd que une el ClusterRole de fluentd a la cuenta de servicio de fluentd. Esto concede a la cuenta de servicio de fluentd los permisos enumerados en el rol de clúster de fluentd.

      En este punto, podemos comenzar a realizar el pegado en la especificación real de DaemonSet:

      fluentd.yaml

      . . .
      ---
      apiVersion: apps/v1
      kind: DaemonSet
      metadata:
        name: fluentd
        namespace: kube-logging
        labels:
          app: fluentd
      

      Aquí definimos un DaemonSet llamado fluentd en el espacio de nombres kube-logging y le asignamos la etiqueta app: fluentd.

      A continuación, pegue la siguiente sección:

      fluentd.yaml

      . . .
      spec:
        selector:
          matchLabels:
            app: fluentd
        template:
          metadata:
            labels:
              app: fluentd
          spec:
            serviceAccount: fluentd
            serviceAccountName: fluentd
            tolerations:
            - key: node-role.kubernetes.io/master
              effect: NoSchedule
            containers:
            - name: fluentd
              image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1
              env:
                - name:  FLUENT_ELASTICSEARCH_HOST
                  value: "elasticsearch.kube-logging.svc.cluster.local"
                - name:  FLUENT_ELASTICSEARCH_PORT
                  value: "9200"
                - name: FLUENT_ELASTICSEARCH_SCHEME
                  value: "http"
                - name: FLUENTD_SYSTEMD_CONF
                  value: disable
      

      Aquí hacemos coincidir la etiqueta app:fluentd definida en .metadata.labels y luego asignamos la cuenta de servicio de fluentd al DaemonSet. También seleccionamos la app:fluentd como los Pods administrados por este DaemonSet.

      A continuación, definimos una tolerancia de NoSchedule para que coincida con el rasgo equivalente de los nodos maestros de Kubernetes. Esto garantizará que el DaemonSet también se despliegue a los maestros de Kubernetes. Si no desea ejecutar un Pod de Fluentd en sus nodos maestros, elimine esta tolerancia. Para obtener más información sobre los rasgos y las tolerancias de Kubernetes, consulte “Rasgos y tolerancias" en los documentos oficiales de Kubernetes.

      A continuación, empezaremos a definir el contenedor de Pods, que llamamos fluentd.

      Usaremos la imagen oficial de Debian v1.4.2 proporcionada por los responsables de mantenimiento de Fluentd. Si quiere usar su propia imagen privada o pública de Fluentd o una versión de imagen distinta, modifique la etiqueta image en la especificación del contenedor. El Dockerfile y el contenido de esta imagen están disponibles en el repositorio de Github fluentd-kubernetes-daemonset.

      A continuación, configuraremos Fluentd usando algunas variables de entorno:

      • FLUENT_ELASTICSEARCH_HOST: lo fijaremos enala dirección de servicio sin encabezado de Elasticsearch definida anteriormente: elasticsearch.kube-logging.svc.cluster.local. Esto se resolverá en una lista de direcciones IP para los 3 Pods de Elasticsearch. El host real de Elasticsearch probablemente será la primera dirección IP de esta lista. Para distribuir registros en el clúster, deberá modificar la configuración del complemento de resultados de Elasticsearch de Fluentd. Para obtener más información sobre este complemento, consulte Complemento de resultado de Elasticsearch.
      • FLUENT_ELASTICSEARCH_PORT: lo fijaremos en 9200, el puerto de Elasticsearch que configuramos antes.
      • FLUENT_ELASTICSEARCH_SCHEME: lo fijaremos en http.
      • FLUENTD_SYSTEMD_CONF: lo fijaremos en disable para eliminar el resultado relacionado con systemd que no está configurado en el contenedor.

      Por último, pegue la siguiente sección:

      fluentd.yaml

      . . .
              resources:
                limits:
                  memory: 512Mi
                requests:
                  cpu: 100m
                  memory: 200Mi
              volumeMounts:
              - name: varlog
                mountPath: /var/log
              - name: varlibdockercontainers
                mountPath: /var/lib/docker/containers
                readOnly: true
            terminationGracePeriodSeconds: 30
            volumes:
            - name: varlog
              hostPath:
                path: /var/log
            - name: varlibdockercontainers
              hostPath:
                path: /var/lib/docker/containers
      

      Aquí especificamos un límite de memoria de 512 MiB en el Pod de FluentD y garantizamos 0,1 vCPU y 200 MiB de memoria. Puede ajustar estos límites y estas solicitudes de recursos según su volumen de registro previsto y los recursos disponibles.

      A continuación, montamos las rutas host /var/log y /var/lib/docker/containers en el contenedor usando volumeMounts varlog y varlibdockercontainers. Estos volúmenes se definen al final del bloque.

      El parámetro final que definimos en este bloque es terminationGracePeriodSeconds, que proporciona a Fluentd 30 segundos para cerrarse de forma correcta tras recibir una señal SIGTERM. Tras 30 segundos, los contenedores se envían a una señal SIGKILL El valor predeterminado de terminationGracePeriodSeconds es de 30 segundos, con lo cual en la mayoría de los casos este parámetro puede omitirse. Para obtener más información sobre la terminación de las cargas de trabajo de Kubernetes de forma correcta, consulte en Google “Buenas prácticas de Kubernetes: cierre correcto”.

      La especificación completa de Fluentd debería tener un aspecto similar a este:

      fluentd.yaml

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: fluentd
        namespace: kube-logging
        labels:
          app: fluentd
      ---
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: fluentd
        labels:
          app: fluentd
      rules:
      - apiGroups:
        - ""
        resources:
        - pods
        - namespaces
        verbs:
        - get
        - list
        - watch
      ---
      kind: ClusterRoleBinding
      apiVersion: rbac.authorization.k8s.io/v1
      metadata:
        name: fluentd
      roleRef:
        kind: ClusterRole
        name: fluentd
        apiGroup: rbac.authorization.k8s.io
      subjects:
      - kind: ServiceAccount
        name: fluentd
        namespace: kube-logging
      ---
      apiVersion: apps/v1
      kind: DaemonSet
      metadata:
        name: fluentd
        namespace: kube-logging
        labels:
          app: fluentd
      spec:
        selector:
          matchLabels:
            app: fluentd
        template:
          metadata:
            labels:
              app: fluentd
          spec:
            serviceAccount: fluentd
            serviceAccountName: fluentd
            tolerations:
            - key: node-role.kubernetes.io/master
              effect: NoSchedule
            containers:
            - name: fluentd
              image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1
              env:
                - name:  FLUENT_ELASTICSEARCH_HOST
                  value: "elasticsearch.kube-logging.svc.cluster.local"
                - name:  FLUENT_ELASTICSEARCH_PORT
                  value: "9200"
                - name: FLUENT_ELASTICSEARCH_SCHEME
                  value: "http"
                - name: FLUENTD_SYSTEMD_CONF
                  value: disable
              resources:
                limits:
                  memory: 512Mi
                requests:
                  cpu: 100m
                  memory: 200Mi
              volumeMounts:
              - name: varlog
                mountPath: /var/log
              - name: varlibdockercontainers
                mountPath: /var/lib/docker/containers
                readOnly: true
            terminationGracePeriodSeconds: 30
            volumes:
            - name: varlog
              hostPath:
                path: /var/log
            - name: varlibdockercontainers
              hostPath:
                path: /var/lib/docker/containers
      

      Cuando termine de configurar el DaemonSet de Fluentd, guarde y cierre el archivo.

      Ahora, ejecute el DaemonSet usando kubectl:

      • kubectl create -f fluentd.yaml

      Debería ver el siguiente resultado:

      Output

      serviceaccount/fluentd created clusterrole.rbac.authorization.k8s.io/fluentd created clusterrolebinding.rbac.authorization.k8s.io/fluentd created daemonset.extensions/fluentd created

      Verifique que su DaemonSet se despliegue correctamente usando kubectl:

      • kubectl get ds --namespace=kube-logging

      Debería ver el siguiente estado:

      Output

      NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE fluentd 3 3 3 3 3 <none> 58s

      Esto indica que hay 3 Pods de fluentd en ejecución, lo que corresponde al número de nodos en nuestro clúster de Kubernetes.

      Ahora podemos comprobar Kibana para verificar que los datos de registro se recopilen y envíen correctamente a Elasticsearch.

      Con kubectl port-forward todavía abierto, vaya a http://localhost:5601.

      Haga clic en Discover en el menú de navegación izquierdo:

      Descubrir Kibana

      Debería ver la siguiente ventana de configuración:

      Configuración del patrón de indexación de Kibana

      Esto le permite definir los índices de Elasticsearch que desea explorar en Kibana. Para obtener más información, consulte Definir sus patrones de indexación en los documentos oficiales de Kibana. Por ahora, simplemente usaremos el patrón comodín logstash-* para capturar todos los datos de registro de nuestro clúster de Elasticsearch. Introduzca logstash-* en la casilla de texto y haga clic en Next step.

      Accederá a la siguiente página:

      Configuración del patrón de indexación de Kibana

      Aquí puede configurar el campo de Kibana que usará para filtrar los datos de registro por tiempo. En el menú desplegable, seleccione el campo @timestamp y presione Create index pattern.

      Luego, presione Discover en el menú de navegación izquierdo.

      Debería ver un gráfico de histograma y algunas entradas recientes en el registro:

      Registros entrantes de Kibana

      En este punto, habrá configurado e implementado correctamente la pila EFK en su clúster de Kubernetes. Si desea aprender a usar Kibana para analizar sus datos de registro, consulte la Guía de usuario de Kibana.

      En la siguiente sección opcional, implementaremos un Pod counter simple que imprime números en stdout y encuentra sus registros en Kibana.

      Paso 5 (opcional): Probar el registro de contenedores

      Para demostrar un caso básico de uso de Kibana de exploración de los últimos registros de un Pod determinado, implementaremos un Pod counter que imprime números secuenciales en stdout.

      Comencemos creando el Pod. Abra un archivo llamado counter.yaml en su editor favorito:

      A continuación, pegue la siguiente especificación de Pod:

      counter.yaml

      apiVersion: v1
      kind: Pod
      metadata:
        name: counter
      spec:
        containers:
        - name: count
          image: busybox
          args: [/bin/sh, -c,
                  'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
      

      Guarde y cierre el archivo.

      Este es un Pod mínimo llamado counter que ejecuta un bucle while e imprime números de forma secuencial.

      Implemente el counter de Pods usando kubectl:

      • kubectl create -f counter.yaml

      Cuando el Pod se cree y esté en ejecución, regrese a su panel de control de Kibana.

      Desde la página Discover, en la barra de búsqueda escriba kubernetes.pod_name:counter. Con esto se filtrarán los datos de registro para Pods que tengan el nombre counter.

      A continuación, debería ver una lista de entradas de registro para el Pod counter:

      Registros counter en Kibana

      Puede hacer clic en cualquiera de las entradas de registro para ver metadatos adicionales, como el nombre del contenedor, el nodo de Kubernetes, el espacio de nombres y otros.

      Conclusión

      En esta guía, demostramos la forma de instalar y configurar Elasticsearch, Fluentd y Kibana en un clúster de Kubernetes. Usamos una arquitectura de registro mínima que consta de un único agente de registro de Pod que se ejecuta en cada nodo de trabajo de Kubernetes.

      Antes de implementar esta pila de registro en su clúster de Kubernetes de producción, la mejor opción es ajustar los requisitos y límites de recursos como se indica en esta guía. También es posible que desee configurar X-Pack para habilitar funciones integradas de seguimiento y seguridad.

      La arquitectura de registro que usamos aquí consta de 3 Pods de Elasticsearch, un Pod único de Kibana (sin equilibrio de carga) y un conjunto de Pods de Fluentd se implementaron como un DaemonSet. Es posible que desee escalar esta configuración según su caso de uso de producción. Para obtener más información sobre el escalamiento de su pila de Elasticsearch y Kibana, consulte Escalamiento de Elasticsearch.

      Kubernetes también permite arquitecturas de agentes de registro más complejas que pueden ajustarse mejor a su caso de uso. Para obtener más información, consulte Arquitectura de registro en los documentos de Kubernetes.



      Source link

      Como Configurar um Registro Privado do Docker no Ubuntu 18.04


      O autor selecionou a Apache Software Foundation para receber uma doação como parte do programa Write for DOnations

      Introdução

      O Registro Docker é uma aplicação que gerencia o armazenamento e a entrega de imagens de container do Docker. Os registros centralizam imagens de container e reduzem o tempo de criação para desenvolvedores. As imagens do Docker garantem o mesmo ambiente de runtime por meio da virtualização, mas a criação de uma imagem pode envolver um investimento de tempo significativo. Por exemplo, em vez de instalar dependências e pacotes separadamente para usar o Docker, os desenvolvedores podem baixar uma imagem compactada de um registro que contém todos os componentes necessários. Além disso, os desenvolvedores podem automatizar o envio de imagens para um registro usando ferramentas de integração contínua, tais como o TravisCI, para atualizar continuamente as imagens durante a produção e o desenvolvimento.

      O Docker também tem um registro público gratuito, Docker Hub, que pode hospedar suas imagens personalizadas do Docker, mas há situações em que você não deseja que sua imagem fique disponível publicamente. As imagens geralmente contém todo o código necessário para executar uma aplicação, portanto, é preferível usar um registro privado ao usar um software proprietário.

      Neste tutorial, você irá configurar e proteger seu próprio Registro Docker privado. Você irá usar o Docker Compose para definir configurações para executar suas aplicações Docker e o Nginx para encaminhar o tráfego do servidor de HTTPS para o container do Docker em execução. Depois de concluir este tutorial, você poderá enviar uma imagem do Docker personalizada para seu registro privado e baixar a imagem com segurança de um servidor remoto.

      Pré-requisitos

      Antes de iniciar este guia, você precisará do seguinte:

      • Dois servidores Ubuntu 18.04 configurados seguindo a Configuração Inicial de servidor com Ubuntu 18.04, incluindo um usuário sudo não-root e um firewall. Um servidor irá hospedar seu Registro Docker privado e o outro será o seu servidor cliente.

      • Docker e Docker-Compose instalados em ambos os servidores seguindo o tutorial How To Install Docker Compose on Ubuntu 18.04. Você só precisa concluir a primeira etapa deste tutorial para instalar o Docker Compose. Este tutorial explica como instalar o Docker como parte de seus pré-requisitos.

      • Nginx instalado no seu servidor de Registro Docker privado seguindo o tutoral Como Instalar o Nginx no Ubuntu 18.04.

      • Nginx protegido com o Let’s Encrypt em seu servidor de Registro Docker privado, seguindo o tutorial Como Proteger o Nginx com o Let’s Encrypt no Ubuntu 18.04. Certifique-se de redirecionar todo o tráfego de HTTP para HTTPS no Passo 4.

      • Um nome de domínio que resolve para o servidor que você está usando para o Registro de Docker privado. Você configurará isso como parte do pré-requisito para o Let’s Encrypt.

      Passo 1 — Instalando e Configurando o Registro Docker

      A ferramenta de linha de comando do Docker é útil para iniciar e gerenciar um ou dois containers Docker, mas, para um deployment completo, a maioria das aplicações em execução dentro de containers do Docker exige que outros componentes sejam executados em paralelo. Por exemplo, muitas aplicações web consistem em um servidor web, como o Nginx, que oferece e serve o código da aplicação, uma linguagem de script interpretada, como o PHP, e um servidor de banco de dados, como o MySQL.

      Com o Docker Compose, você pode escrever um arquivo .yml para definir a configuração de cada container e as informações que os containers precisam para se comunicarem uns com os outros. Você pode usar a ferramenta de linha de comando docker-compose para emitir comandos para todos os componentes que compõem a sua aplicação.

      O próprio Registro Docker é uma aplicação com vários componentes, portanto, você utilizará o Docker Compose para gerenciar sua configuração. Para iniciar uma instância do registro, você irá configurar um arquivo docker-compose.yml para definir o local onde seu registro armazenará seus dados.

      No servidor que você criou para hospedar seu Registro Docker privado, você pode criar um diretório docker-registry, mover-se para ele, e criar uma subpasta data com os seguintes comandos:

      • mkdir ~/docker-registry && cd $_
      • mkdir data

      Use o seu editor de texto para criar o arquivo de configuração docker-compose.yml:

      Adicione o seguinte conteúdo ao arquivo, que descreve a configuração básica para o Registro Docker:

      docker-compose.yml

      version: '3'
      
      services:
        registry:
          image: registry:2
          ports:
          - "5000:5000"
          environment:
            REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
          volumes:
            - ./data:/data
      

      A seção environment define uma variável de ambiente no container do Registro Docker com o caminho /data. A aplicação do Registro Docker verifica essa variável de ambiente quando é inicializada e, como resultado, começa a salvar seus dados na pasta /data.

      No entanto, como você incluiu a linha volumes: - ./data:/data, e o Docker irá começar a mapear o diretório /data daquele container para /data em seu servidor de registro. O resultado final é que os dados do Registro Docker são armazenados em ~/docker-registry/data no servidor do registro.

      A seção ports, com a configuração 5000:5000, diz ao Docker para mapear a porta 5000 no servidor para a porta 5000 no container em execução. Isso lhe permite enviar uma solicitação para a porta 5000 no servidor, e ter essa solicitação encaminhada para a aplicação do registro.

      Agora você pode iniciar o Docker Compose para verificar a configuração:

      Você verá barras de download em sua saída que mostram o Docker baixando a imagem do Registro Docker do próprio Docker Registry. Em um ou dois minutos, você verá uma saída semelhante à seguinte (as versões podem variar):

      Output of docker-compose up

      Starting docker-registry_registry_1 ... done Attaching to docker-registry_registry_1 registry_1 | time="2018-11-06T18:43:09Z" level=warning msg="No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable." go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="redis not configured" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="Starting upload purge in 20m0s" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="listening on [::]:5000" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2

      Você abordará a mensagem de aviso No HTTP secret provided posteriormente neste tutorial. A saída mostra que o container está iniciando. A última linha da saída mostra que ele começou a escutar com sucesso na porta 5000.

      Por padrão, o Docker Compose permanecerá aguardando sua entrada, então pressione CTRL+C para encerrar seu container do Registro Docker.

      Você configurou um Registro Docker completo, escutando na porta 5000. Nesse ponto, o registro não será iniciado, a menos que você o faça manualmente. Além disso, o Registro Docker não vem com nenhum mecanismo de autenticação integrado, por isso está atualmente inseguro e completamente aberto ao público. Nos passos quem seguem, você abordará essas preocupações de segurança.

      Passo 2 — Configurando o Encaminhamento de Porta no Nginx

      Você já tem HTTPS configurado em seu servidor de Registro Docker com Nginx, o que significa que agora você pode configurar o encaminhamento de porta do Nginx para a porta 5000. Depois de concluir esta etapa, você pode acessar seu registro diretamente em example.com.

      Como parte do pré-requisito para o guia Como Proteger o Nginx com o Let's Encrypt no Ubuntu 18.04, você já configurou o arquivo /etc/nginx/sites-available/example.com contendo a configuração do seu servidor.

      Abra o arquivo com seu editor de texto:

      sudo nano /etc/nginx/sites-available/example.com
      

      Encontre a linha location existente. Isso parecerá assim:

      /etc/nginx/sites-available/example.com

      ...
      location / {
        ...
      }
      ...
      

      Você precisa encaminhar o tráfego para a porta 5000, onde seu registro estará em execução. Você também deseja anexar cabeçalhos à solicitação para o registro, que fornecem informações adicionais do servidor com cada solicitação e resposta. Exclua o conteúdo da seção location e inclua o seguinte conteúdo nessa seção:

      /etc/nginx/sites-available/example.com

      ...
      location / {
          # Do not allow connections from docker 1.5 and earlier
          # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
          if ($http_user_agent ~ "^(docker/1.(3|4|5(?!.[0-9]-dev))|Go ).*$" ) {
            return 404;
          }
      
          proxy_pass                          http://localhost:5000;
          proxy_set_header  Host              $http_host;   # required for docker client's sake
          proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
          proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
          proxy_set_header  X-Forwarded-Proto $scheme;
          proxy_read_timeout                  900;
      }
      ...
      

      A seção $http_user_agent verifica se a versão do Docker do cliente está acima de 1.5 e garante que o UserAgent não seja uma aplicação Go. Como você está usando a versão 2.0 do registro, os clientes mais antigos não são suportados. Para mais informações, você pode encontrar a configuração do cabeçalho do nginx em Docker's Registry Nginx guide.

      Salve e saia do arquivo. Aplique as alterações reiniciando o Nginx:

      • sudo service nginx restart

      Você pode confirmar que o Nginx está encaminhando o tráfego para a porta 5000 executando o registro:

      • cd ~/docker-registry
      • docker-compose up

      Em uma janela do navegador, abra a seguinte URL:

      https://example.com/v2
      

      Você verá um objeto JSON vazio, ou:

      {}
      

      No seu terminal, você verá uma saída semelhante à seguinte:

      Output of docker-compose up

      registry_1 | time="2018-11-07T17:57:42Z" level=info msg="response completed" go.version=go1.7.6 http.request.host=cornellappdev.com http.request.id=a8f5984e-15e3-4946-9c40-d71f8557652f http.request.method=GET http.request.remoteaddr=128.84.125.58 http.request.uri="/v2/" http.request.useragent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7" http.response.contenttype="application/json; charset=utf-8" http.response.duration=2.125995ms http.response.status=200 http.response.written=2 instance.id=3093e5ab-5715-42bc-808e-73f310848860 version=v2.6.2 registry_1 | 172.18.0.1 - - [07/Nov/2018:17:57:42 +0000] "GET /v2/ HTTP/1.0" 200 2 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7"

      Você pode ver da última linha que uma requisição GET foi feita para /v2/, que é o endpoint para o qual você enviou uma solicitação do seu navegador. O container recebeu a solicitação que você fez, do encaminhamento de porta, e retornou uma resposta de {}. O código 200 na última linha da saída significa que o container tratou a solicitação com sucesso.

      Agora que você configurou o encaminhamento de porta, é possível melhorar a segurança do seu registro.

      Passo 3 — Configurando a Autenticação

      Com o Nginx fazendo proxy das solicitações corretamente, agora você pode proteger seu registro com autenticação HTTP para gerenciar quem tem acesso ao seu Registro Docker. Para conseguir isso, você irá criar um arquivo de autenticação com o htpasswd e adicionará usuários a ele. A autenticação HTTP é rápida de configurar e segura em uma conexão HTTPS, que é o que o registro usará.

      Você pode instalar o pacote htpasswd executando o seguinte:

      • sudo apt install apache2-utils

      Agora você irá criar o diretório onde você armazenará nossas credenciais de autenticação e irá se mover para esse diretório. O $_ expande para o último argumento do comando anterior, neste caso ~/docker-registry/auth:

      • mkdir ~/docker-registry/auth && cd $_

      Em seguida, você irá criar o primeiro usuário da seguinte forma, substituindo nome_usuário pelo nome de usuário que deseja usar. A flag -B especifica criptografia bcrypt, que é mais segura que a criptografia padrão. Digite a senha quando solicitado:

      • htpasswd -Bc registry.password nome_usuário

      Nota: Para adicionar mais usuários execute novamente o comando anterior sem a opção -c (o c é para criar):

      • htpasswd registry.password nome_usuário

      A seguir, você irá editar o arquivo docker-compose.yml para dizer ao Docker para usar o arquivo que você criou para autenticar usuários.

      • cd ~/docker-registry
      • nano docker-compose.yml

      Você pode adicionar variáveis de ambiente e um volume para o diretório auth/ que você criou, editando o arquivo docker-compose.yml para informar ao Docker como você deseja autenticar usuários. Adicione o seguinte conteúdo destacado ao arquivo:

      docker-compose.yml

      version: '3'
      
      services:
        registry:
          image: registry:2
          ports:
          - "5000:5000"
          environment:
            REGISTRY_AUTH: htpasswd
            REGISTRY_AUTH_HTPASSWD_REALM: Registry
            REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
            REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
          volumes:
            - ./auth:/auth
            - ./data:/data
      

      Para REGISTRY_AUTH, você especificou htpasswd, que é o esquema de autenticação que você está utilizando, e definiu REGISTRY_AUTH_HTPASSWD_PATH para o caminho do arquivo de autenticação. Finalmente, REGISTRY_AUTH_HTPASSWD_REALM significa o nome do domínio do htpasswd.

      Agora você pode verificar se sua autenticação funciona corretamente, executando o registro e verificando se ele solicita um nome de usuário e uma senha.

      Em uma janela do navegador, abra https://example.com/v2.

      Depois de digitar o nome_usuário e a senha correspondente, você verá o {} mais uma vez. Você confirmou a configuração básica da autenticação: o registro só retornou o resultado depois que você digitou o nome de usuário e a senha corretos. Agora você já protegeu seu registro e pode continuar utilizando-o.

      Passo 4 — Iniciando o Registro Docker como um Serviço

      Você quer garantir que seu registro seja iniciado sempre que o sistema for inicializado. Se houver algum travamento imprevisto do sistema, você quer ter certeza de que o registro seja reiniciado quando o servidor for reinicializado. Abra o docker-compose.yml:

      Adicione a seguinte linha de conteúdo logo abaixo de registry::

      docker-compose.yml

      ...
        registry:
          restart: always
      ...
      

      Você pode iniciar seu registro como um processo em segundo plano, o que permitirá que você saia da sessão ssh e persista o processo:

      Com o seu registro em execução em segundo plano, agora você pode preparar o Nginx para uploads de arquivos.

      Passo 5 — Aumentando o Tamanho do Upload de Arquivos para o Nginx

      Antes de poder enviar uma imagem para o registro, você precisa garantir que o registro possa lidar com grandes uploads de arquivos. Embora o Docker divida os uploads de imagens grandes em camadas separadas, às vezes elas podem ter mais de 1GB. Por padrão, o Nginx tem um limite de 1MB para uploads de arquivos, então você precisa editar o arquivo de configuração do nginx e configurar o tamanho máximo de upload do arquivo para 2GB.

      • sudo nano /etc/nginx/nginx.conf

      Encontre a seção http e adicione a seguinte linha:

      /etc/nginx/nginx.conf

      ...
      http {
              client_max_body_size 2000M;
              ...
      }
      ...
      

      Por fim, reinicie o Nginx para aplicar as alterações de configuração:

      • sudo service nginx restart

      Agora você pode enviar imagens grandes para o seu Registro Docker sem erros no Nginx.

      Passo 6 — Publicando em seu Registro Docker Privado

      Agora você está pronto para publicar uma imagem no seu Registro Docker privado, mas primeiro é preciso criar uma imagem. Para este tutorial, você criará uma imagem simples baseada na imagem ubuntu do Docker Hub. O Docker Hub é um registro hospedado publicamente, com muitas imagens pré-configuradas que podem ser aproveitadas para "Dockerizar" rapidamente as aplicações. Usando a imagem ubuntu, você vai testar o envio e o download de imagens do seu registro.

      Do seu servidor cliente, crie uma imagem pequena e vazia para enviar para o seu novo registro. As flags -i e -t lhe fornecem acesso interativo ao shell no container:

      • docker run -t -i ubuntu /bin/bash

      Após o término do download, você estará dentro de um prompt do Docker, observe que o ID do container após root@ irá variar. Faça uma rápida mudança no sistema de arquivos criando um arquivo chamado SUCCESS. No próximo passo, você poderá usar esse arquivo para determinar se o processo de publicação foi bem-sucedido:

      Saia do container do Docker:

      O comando a seguir cria uma nova imagem chamada test-image com base na imagem já em execução, além de todas as alterações que você fez. No nosso caso, a adição do arquivo /SUCCESS está incluída na nova imagem.

      Faça o commit da alteração:

      • docker commit $(docker ps -lq) test-image

      Neste ponto, a imagem só existe localmente. Agora você pode enviá-la para o novo registro que você criou. Faça o login no seu Registro Docker:

      • docker login https://example.com

      Digite o nome_usuário e a senha correspondente de antes. Em seguida, você colocará uma tag na imagem com a localização do registro privado para enviar a ele:

      • docker tag test-image example.com/test-image

      Envie a imagem recém-marcada para o registro:

      • docker push example.com/test-image

      Sua saída será semelhante à seguinte:

      Output

      The push refers to a repository [example.com/test-image] e3fbbfb44187: Pushed 5f70bf18a086: Pushed a3b5c80a4eba: Pushed 7f18b442972b: Pushed 3ce512daaf78: Pushed 7aae4540b42d: Pushed ...

      Você verificou que seu registro trata a autenticação do usuário e permite que usuários autenticados enviem imagens ao registro. Em seguida, você confirmará que também é possível extrair ou baixar imagens do registro.

      Passo 7 — Baixando de seu Registro Docker Privado

      Retorne ao seu servidor de registro para que você possa testar o download da imagem a partir do seu servidor cliente. Também é possível testar isso a partir de um outro servidor.

      Faça o login com o nome de usuário e senha que você configurou anteriormente:

      • docker login https://example.com

      Agora você está pronto para baixar a imagem. Use seu nome de domínio e nome de imagem, que você marcou na etapa anterior:

      • docker login example.com/test-image

      O Docker irá baixar a imagem e retornar você ao prompt. Se você executar a imagem no servidor de registro, verá que o arquivo SUCCESS criado anteriormente está lá:

      • docker run -it example.com/test-image /bin/bash

      Liste seus arquivos dentro do shell bash:

      Você verá o arquivo SUCCESS que você criou para esta imagem:

      SUCCESS  bin  boot  dev  etc  home  lib  lib64  media   mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
      

      Você terminou de configurar um registro seguro para o qual os usuários podem enviar e baixar imagens personalizadas.

      Conclusão

      Neste tutorial, você configurou seu próprio Registro Docker privado e publicou uma imagem Docker. Como mencionado na introdução, você também pode usar o TravisCI ou uma ferramenta de CI semelhante para automatizar o envio diretamente para um registro privado. Ao aproveitar o Docker e os registros em seu fluxo de trabalho, você pode garantir que a imagem que contém o código resulte no mesmo comportamento em qualquer máquina, seja em produção ou em desenvolvimento. Para obter mais informações sobre como escrever arquivos do Docker, você pode ler o tutorial do Docker, que explica o processo.

      Por Young Kim



      Source link