Presentación de los contenedores


Si no tienes experiencia con las cargas de trabajo en contenedores, este tutorial es para ti. Te presenta los contenedores y la orquestación de contenedores explicándote cómo configurar una aplicación sencilla desde el código fuente hasta un contenedor que se ejecuta en GKE.

Para seguir este tutorial no es necesario tener experiencia previa con contenedores ni con Kubernetes. Sin embargo, si quieres leer una descripción general de la terminología básica de Kubernetes antes de empezar este tutorial, consulta Empezar a aprender sobre Kubernetes (o, si prefieres aprender sobre Kubernetes en formato cómic, consulta nuestro cómic de Kubernetes). Encontrarás recursos más detallados en la sección Próximos pasos, al final del tutorial.

Si ya conoces los contenedores y Kubernetes, puedes saltarte este tutorial y empezar a aprender sobre GKE.

Objetivos

  1. Descubre una aplicación sencilla de "Hola, mundo" con varios servicios.
  2. Ejecuta la aplicación desde la fuente.
  3. Conteneriza la aplicación.
  4. Crea un clúster de Kubernetes.
  5. Despliega los contenedores en el clúster.

Antes de empezar

Sigue estos pasos para habilitar la API de Kubernetes Engine:
  1. Ve a la página de Kubernetes Engine en la Google Cloud consola.
  2. Crea o selecciona un proyecto.
  3. Espera a que la API y los servicios relacionados se habiliten. Este proceso puede tardar varios minutos.
  4. Verify that billing is enabled for your Google Cloud project.

Preparar Cloud Shell

En este tutorial se usa Cloud Shell, que aprovisiona una máquina virtual g1-small de Compute Engine que ejecuta un sistema operativo Linux basado en Debian.

Usar Cloud Shell tiene las siguientes ventajas:

  • Un entorno de desarrollo de Python 3 (incluido virtualenv) está totalmente configurado.
  • Las herramientas de línea de comandos gcloud, docker, git y kubectl que se usan en este tutorial ya están instaladas.
  • Puedes elegir entre los editores de texto integrados:

    • Editor de Cloud Shell, al que puedes acceder haciendo clic en Abrir editor en la parte superior de la ventana de Cloud Shell.

    • Emacs, Vim o Nano, a los que puedes acceder desde la línea de comandos de Cloud Shell.

In the Google Cloud console, activate Cloud Shell.

Activate Cloud Shell

Descargar el código de ejemplo

  1. Descarga el código fuente de helloserver:

    git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples
    
  2. Cambia al directorio del código de ejemplo:

    cd anthos-service-mesh-samples/docs/helloserver
    

Explorar la aplicación multiservicio

La aplicación de ejemplo está escrita en Python. Tiene los siguientes componentes, que se comunican mediante REST:

  • server: un servidor básico con un endpoint GET, / , que imprime "hello world" en la ventana de la terminal.
  • loadgen: una secuencia de comandos que envía tráfico a server, con un número configurable de solicitudes por segundo (RPS).

Aplicación de ejemplo

Ejecutar la aplicación desde la fuente

Para familiarizarte con la aplicación de ejemplo, ejecútala en Cloud Shell:

  1. En el directorio sample-apps/helloserver, ejecuta server:

    python3 server/server.py
    

    Al iniciarse, server muestra lo siguiente:

    INFO:root:Starting server...
    
  2. Abre otra ventana de terminal para poder enviar solicitudes al server. Para hacerlo en Cloud Shell, haz clic en Abrir una pestaña nueva para abrir otra sesión.

  3. En la nueva ventana de terminal, envía una solicitud a server:

    curl http://localhost:8080
    

    El resultado de server es el siguiente:

    Hello World!
    
  4. En la misma pestaña, ve al directorio que contiene la secuencia de comandos loadgen:

    cd anthos-service-mesh-samples/docs/helloserver/loadgen
  5. Crea las siguientes variables de entorno:

    export SERVER_ADDR=http://localhost:8080
    export REQUESTS_PER_SECOND=5
    
  6. Inicio virtualenv:

    virtualenv --python python3 env
    
  7. Activa el entorno virtual:

    source env/bin/activate
    
  8. Instala los requisitos de loadgen:

    pip3 install -r requirements.txt
    
  9. Ejecuta la aplicación loadgen para generar tráfico en server:

    python3 loadgen.py
    

    Al iniciarse, la salida de loadgen es similar a la siguiente:

    Starting loadgen: 2024-10-11 09:49:51.798028
    5 request(s) complete to http://localhost:8080
    
  10. Ahora, abre la ventana de terminal en la que se está ejecutando server. Deberías ver mensajes similares a los siguientes:

    127.0.0.1 - - [11/Oct/2024 09:51:28] "GET / HTTP/1.1" 200 -
    INFO:root:GET request,
    Path: /
    Headers:
    Host: localhost:8080
    User-Agent: python-requests/2.32.3
    Accept-Encoding: gzip, deflate
    Accept: */*
    Connection: keep-alive
    

    Desde el punto de vista de la red, toda la aplicación se ejecuta ahora en el mismo host, lo que te permite usar localhost para enviar solicitudes al server.

  11. Para detener loadgen y server, pulsa Ctrl-c en cada ventana de terminal.

  12. En la ventana de terminal loadgen, desactiva el entorno virtual:

    deactivate
    

Contenerizar la aplicación

Para ejecutar la aplicación en GKE, debes empaquetar los dos componentes de la aplicación de ejemplo en contenedores. Un contenedor es un paquete que contiene todos los elementos necesarios para que tu aplicación se ejecute en cualquier entorno. En este tutorial se usa Docker para crear un contenedor de la aplicación.

Para crear un contenedor de la aplicación con Docker, necesitas un Dockerfile. Un Dockerfile es un archivo de texto que define los comandos necesarios para ensamblar el código fuente de la aplicación y sus dependencias en una imagen de contenedor. Después de crear la imagen, súbela a un registro de contenedores, como Artifact Registry.

El código fuente de este tutorial incluye un Dockerfile tanto para server como para loadgen con todos los comandos necesarios para crear las imágenes. A continuación, se muestra el Dockerfile de server:

FROM python:3.13-slim as base
FROM base as builder
RUN apt-get -qq update \
    && apt-get install -y --no-install-recommends \
        g++ \
    && rm -rf /var/lib/apt/lists/*

# Enable unbuffered logging
FROM base as final
ENV PYTHONUNBUFFERED=1

RUN apt-get -qq update \
    && apt-get install -y --no-install-recommends \
        wget

WORKDIR /helloserver

# Grab packages from builder
COPY --from=builder /usr/local/lib/python3.* /usr/local/lib/

# Add the application
COPY . .

EXPOSE 8080
ENTRYPOINT [ "python", "server.py" ]

En este archivo, puede ver lo siguiente:

  • La instrucción FROM python:3-slim as base indica a Docker que use la imagen de Python 3 más reciente como imagen base.
  • La instrucción COPY . . copia los archivos de origen del directorio de trabajo actual (en este caso, server.py) en el sistema de archivos del contenedor.
  • ENTRYPOINT define la instrucción que se usa para ejecutar el contenedor. En este ejemplo, la instrucción es similar a la que has usado para ejecutar server.py desde el código fuente.
  • La instrucción EXPOSE especifica que server escucha en el puerto 8080. Esta instrucción no expone ningún puerto, sino que sirve como documentación para indicar que debes abrir el puerto 8080 cuando ejecutes el contenedor.

Preparar la contenedorización de la aplicación

Antes de contenerizar la aplicación, debes configurar las herramientas y los servicios que vas a usar:

  1. Define el proyecto Google Cloud predeterminado de Google Cloud CLI.

    gcloud config set project PROJECT_ID
  2. Define la región predeterminada de Google Cloud CLI.

    gcloud config set compute/region us-central1
    

Crear el repositorio

Para crear un repositorio de imágenes de contenedor Docker en Artifact Registry, sigue estos pasos:

  1. Asegúrate de que el servicio Artifact Registry esté habilitado en tuGoogle Cloud proyecto.

    gcloud services enable artifactregistry.googleapis.com
    
    
  2. Crea el repositorio de Artifact Registry:

    gcloud artifacts repositories create container-intro --repository-format=docker \
        --location=us-central1 \
        --description="My new Docker repository"
    
  3. Configura la autenticación de Docker en Artifact Registry mediante la CLI de Google Cloud:

    gcloud auth configure-docker us-central1-docker.pkg.dev
    

Contenedorizar el server

Ahora es el momento de crear un contenedor para tu aplicación. Primero, crea un contenedor para el archivo "hello world" server y envía la imagen a Artifact Registry:

  1. Cambia al directorio donde se encuentra el ejemplo server:

    cd ~/anthos-service-mesh-samples/docs/helloserver/server/
  2. Crea la imagen con Dockerfile:

    docker build -t us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver:v0.0.1 .
    
    • Sustituye PROJECT_ID por el ID de tu Google Cloud proyecto.

    La bandera -t representa la etiqueta de Docker. Es el nombre de la imagen que usas al implementar el contenedor.

  3. Envía la imagen a Artifact Registry:

    docker push us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver:v0.0.1
    

Contenedorizar el loadgen

A continuación, crea un contenedor para el servicio de generador de carga de la misma forma:

  1. Cambia al directorio donde se encuentra el ejemplo loadgen:

    cd ../loadgen
    
  2. Crea la imagen:

    docker build -t us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen:v0.0.1 .
    
  3. Envía la imagen a Artifact Registry:

    docker push us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen:v0.0.1
    

Enumera las imágenes

Obtén una lista de las imágenes del repositorio para confirmar que se han enviado:

gcloud container images list --repository us-central1-docker.pkg.dev/PROJECT_ID/container-intro

En la salida se deben mostrar los nombres de las imágenes que has enviado, de forma similar a lo siguiente:

NAME
us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver
us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen

Crear un clúster de GKE

En este punto, podrías ejecutar los contenedores en la VM de Cloud Shell con el comando docker run. Sin embargo, para ejecutar cargas de trabajo de producción fiables, debes gestionar los contenedores de una forma más unificada. Por ejemplo, debes asegurarte de que los contenedores se reinicien si fallan y necesitas una forma de ampliar y poner en marcha instancias adicionales de un contenedor para gestionar los aumentos de tráfico.

GKE puede ayudarte a satisfacer estas necesidades. GKE es una plataforma de orquestación de contenedores que funciona conectando máquinas virtuales en un clúster. Cada máquina virtual se denomina nodo. Los clústeres de GKE se basan en el sistema de gestión de clústeres de código abierto de Kubernetes. Kubernetes proporciona los mecanismos a través de los cuales interactúas con tu clúster.

Para ejecutar los contenedores en GKE, primero debes crear un clúster y, a continuación, conectarte a él:

  1. Crea el clúster:

    gcloud container clusters create-auto container-intro
    

    El comando gcloud crea un clúster en el proyecto Google Cloud y la región predeterminados que hayas definido anteriormente.

    El comando para crear el clúster tarda unos minutos en completarse. Cuando el clúster esté listo, el resultado será similar al siguiente:

     NAME: container-intro
     LOCATION: us-central1
     MASTER_VERSION: 1.30.4-gke.1348000
     MASTER_IP: 34.44.14.166
     MACHINE_TYPE: e2-small
     NODE_VERSION: 1.30.4-gke.1348000
     NUM_NODES: 3
     STATUS: RUNNING
    
  2. Proporciona credenciales a la herramienta de línea de comandos kubectl para que puedas usarla para gestionar el clúster:

    gcloud container clusters get-credentials container-intro
    

Examinar manifiestos de Kubernetes

Cuando ejecutaste la aplicación desde el código fuente, usaste un comando imperativo: python3 server.py

Imperativo significa que se basa en verbos: "haz esto".

Por el contrario, Kubernetes funciona con un modelo declarativo. Esto significa que, en lugar de decirle a Kubernetes exactamente qué debe hacer, le proporcionas el estado deseado. Por ejemplo, Kubernetes inicia y finaliza pods según sea necesario para que el estado real del sistema coincida con el estado deseado.

Especificas el estado deseado en un archivo llamado manifiesto. Los manifiestos se escriben en lenguajes como YAML o JSON y contienen la especificación de uno o varios objetos de Kubernetes.

El ejemplo contiene un manifiesto para server y otro para loadgen. Cada manifiesto especifica el estado deseado del objeto de implementación de Kubernetes (que gestiona la ejecución del contenedor, empaquetado para la gestión como un pod de Kubernetes) y del servicio (que proporciona una dirección IP al pod). Un pod es la unidad de computación desplegable más pequeña que puedes crear y gestionar en Kubernetes, y contiene uno o varios contenedores.

En el siguiente diagrama se muestra la aplicación que se ejecuta en GKE:

Aplicación en contenedores que se ejecuta en GKE

Puedes consultar más información sobre pods, implementaciones y servicios en la sección Empezar a aprender sobre Kubernetes o en los recursos que aparecen al final de esta página.

Servidor

Primero, consulta el manifiesto de la aplicación "hello world" server:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helloserver
  template:
    metadata:
      labels:
        app: helloserver
    spec:
      containers:
      - image: gcr.io/google-samples/istio/helloserver:v0.0.1
        imagePullPolicy: Always
        name: main
      restartPolicy: Always
      terminationGracePeriodSeconds: 5

Este manifiesto contiene los siguientes campos:

  • kind indica el tipo de objeto.
  • metadata.name especifica el nombre de la implementación.
  • El primer campo spec contiene una descripción del estado deseado.
  • spec.replicas especifica el número de pods que se quieren.
  • La sección spec.template define una plantilla de pod. En la especificación de los pods se incluye el campo image, que es el nombre de la imagen que se va a extraer de Artifact Registry. En el siguiente paso, actualizarás este valor con la nueva imagen que acabas de crear.

El Servicio hellosvc se define de la siguiente manera:

apiVersion: v1
kind: Service
metadata:
  name: hellosvc
spec:
  ports:
  - name: http
    port: 80
    targetPort: 8080
  selector:
    app: helloserver
  type: LoadBalancer
  • LoadBalancer: los clientes envían solicitudes a la dirección IP de un balanceador de carga de red, que tiene una dirección IP estable y se puede acceder a él desde fuera del clúster.
  • targetPort: Recuerda que el comando EXPOSE 8080 de Dockerfile no expone ningún puerto. Expón el puerto 8080 para poder acceder al contenedor server fuera del clúster. En este caso, hellosvc.default.cluster.local:80 (nombre abreviado: hellosvc) se asigna al puerto 8080 de la IP del pod helloserver.
  • port: es el número de puerto que usan otros servicios del clúster al enviar solicitudes.

Generador de carga

El objeto Deployment de loadgen.yaml es similar a server.yaml. Una diferencia notable es que la especificación de Pod de loadgen Deployment tiene un campo llamado env. En esta sección se definen las variables de entorno que requiere loadgen, que ya has definido al ejecutar la aplicación desde la fuente.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: loadgenerator
spec:
  replicas: 1
  selector:
    matchLabels:
      app: loadgenerator
  template:
    metadata:
      labels:
        app: loadgenerator
    spec:
      containers:
      - env:
        - name: SERVER_ADDR
          value: http://hellosvc:80/
        - name: REQUESTS_PER_SECOND
          value: '10'
        image: gcr.io/google-samples/istio/loadgen:v0.0.1
        imagePullPolicy: Always
        name: main
        resources:
          limits:
            cpu: 500m
            memory: 512Mi
          requests:
            cpu: 300m
            memory: 256Mi
      restartPolicy: Always
      terminationGracePeriodSeconds: 5

Como loadgen no acepta solicitudes entrantes, el campo type se ha definido como ClusterIP. Este tipo de servicio proporciona una dirección IP estable que pueden usar las entidades del clúster, pero la dirección IP no se expone a los clientes externos.

apiVersion: v1
kind: Service
metadata:
  name: loadgensvc
spec:
  ports:
  - name: http
    port: 80
    targetPort: 8080
  selector:
    app: loadgenerator
  type: ClusterIP

Desplegar los contenedores en GKE

Para implementar los contenedores, aplica los manifiestos que especifican el estado que quieres mediante kubectl.

Desplegar el server

  1. Cambia al directorio donde se encuentra el ejemplo server:

    cd ~/anthos-service-mesh-samples/docs/helloserver/server/
  2. Abre server.yaml en el editor de Cloud Shell (o en el editor de texto que prefieras).

  3. Sustituye el nombre del campo image por el nombre de tu imagen de Docker.

    image: us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver:v0.0.1
    

    Sustituye PROJECT_ID por el ID de tu proyecto. Google Cloud

    • Si usas el editor de Cloud Shell, el archivo se guarda automáticamente. Vuelve a la ventana de la terminal haciendo clic en Abrir terminal.
    • Si estás usando un editor de texto en Cloud Shell, guarda y cierra server.yaml.
  4. Despliega el manifiesto en Kubernetes:

    kubectl apply -f server.yaml
    

    El resultado debería ser similar al siguiente:

    deployment.apps/helloserver created
    service/hellosvc created
    

Desplegar el loadgen

  1. Cambia al directorio en el que se encuentra loadgen.

    cd ../loadgen
    
  2. Abre loadgen.yaml en un editor de texto, como antes.

  3. De nuevo, sustituye el nombre del campo image por el nombre de tu imagen Docker.

    image: us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen:v0.0.1
    

    Sustituye PROJECT_ID por el ID de tu proyecto. Google Cloud

    • Si usas el editor de Cloud Shell, el archivo se guarda automáticamente. Vuelve a la ventana de la terminal haciendo clic en Abrir terminal.
    • Si estás usando un editor de texto en Cloud Shell, guarda y cierra loadgen.yaml.
  4. Despliega el manifiesto en tu clúster:

    kubectl apply -f loadgen.yaml
    

    Si la acción se realiza correctamente, el comando mostrará lo siguiente:

    deployment.apps/loadgenerator created
    service/loadgensvc created
    

Verificar la implementación

Después de implementar los manifiestos en el clúster, comprueba que los contenedores se han implementado correctamente:

  1. Comprueba el estado de los pods de tu clúster:

    kubectl get pods
    

    El comando responde con un estado similar al siguiente:

    NAME                             READY   STATUS    RESTARTS   AGE
    helloserver-69b9576d96-mwtcj     1/1     Running   0          58s
    loadgenerator-774dbc46fb-gpbrz   1/1     Running   0          57s
    
  2. Obtén los registros de la aplicación del pod loadgen. Sustituye POD_ID por el identificador del pod del generador de carga de la salida anterior.

    kubectl logs POD_ID
    
  3. Obtén las direcciones IP externas de hellosvc:

    kubectl get service hellosvc
    

    El resultado debería ser similar al siguiente:

    NAME         TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
    hellosvc     LoadBalancer   10.81.15.158   192.0.2.1       80:31127/TCP   33m
    
  4. Envía una solicitud al hellosvc. Sustituye EXTERNAL_IP por la dirección IP externa de tu hellosvc.

    curl http://EXTERNAL_IP
    

    Debería aparecer el mensaje "Hello World!" del servidor.

Limpieza

Para evitar que los recursos utilizados en este tutorial se cobren en tu cuenta de Google Cloud, elimina el proyecto que contiene los recursos o conserva el proyecto y elimina los recursos.

Si no quieres eliminar todo el proyecto, sigue estos pasos:

  • Elimina el clúster de GKE. Al eliminar el clúster, se eliminan todos los recursos que lo componen, como las instancias de Compute Engine, los discos y los recursos de red.

     gcloud container clusters delete container-intro
    
  • Elimina el repositorio de Artifact Registry:

     gcloud artifacts repositories delete container-intro --location=us-central1
    

Siguientes pasos