Presentamos los contenedores


Si no estás familiarizado con las cargas de trabajo en contenedores, este instructivo es para ti. Te presenta los contenedores y la organización de contenedores guiándote para configurar una aplicación simple desde el código fuente a un contenedor que se ejecuta en GKE.

No se requiere experiencia previa con contenedores ni Kubernetes para realizar este instructivo. Sin embargo, si quieres leer una descripción general de la terminología básica de Kubernetes antes de comenzar este instructivo, consulta Comienza a aprender sobre Kubernetes (o si prefieres aprender sobre Kubernetes en forma de cómic, consulta nuestro cómic de Kubernetes). Encontrarás recursos más detallados en la sección Qué sigue al final del instructivo.

Si ya conoces los contenedores y Kubernetes, puedes omitir este instructivo y comenzar a aprender sobre GKE.

Objetivos

  1. Explorarás una aplicación “Hello World” simple de varios servicios.
  2. Ejecuta la aplicación desde la fuente.
  3. Organizarás la aplicación en contenedores.
  4. Crearás un clúster de Kubernetes.
  5. Implementarás los contenedores en el clúster.

Antes de comenzar

Sigue los pasos que se indican a continuación para habilitar la API de Kubernetes Engine:
  1. Visita la página de Kubernetes Engine en la consola de Google Cloud .
  2. Crea o selecciona un proyecto.
  3. Espera a que la API y los servicios relacionados se habiliten. Esto puede tomar varios minutos.
  4. Make sure that billing is enabled for your Google Cloud project.

Prepara Cloud Shell

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

El uso de Cloud Shell tiene las siguientes ventajas:

  • Un entorno de desarrollo de Python 3 (incluido virtualenv) está completamente configurado.
  • Las herramientas de línea de comandos de gcloud, docker, git y kubectl que se usan en este instructivo 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 en Cloud Shell.

In the Google Cloud console, activate Cloud Shell.

Activate Cloud Shell

At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

Descarga el código de muestra

  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 muestra:

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

Explora la aplicación de varios servicios

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

  • server: Es un servidor básico con un extremo GET, / , que imprime “Hello World” en la ventana de la terminal.
  • loadgen: Es una secuencia de comandos que envía tráfico al server, con una cantidad configurable de solicitudes por segundo (RPS).

Aplicación de ejemplo

Ejecuta la aplicación desde la fuente

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

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

    python3 server/server.py
    

    En el inicio, el server muestra lo siguiente:

    INFO:root:Starting server...
    
  2. Abre otra ventana de la 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 la terminal, envía una solicitud al server:

    curl http://localhost:8080
    

    El resultado de server es el siguiente:

    Hello World!
    
  4. En la misma pestaña, cambia 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. Inicia 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 para el server:

    python3 loadgen.py
    

    En el inicio, el resultado de loadgen es similar al 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 que ejecuta 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 las herramientas de redes, toda la aplicación ahora se ejecuta en el mismo host, lo que te permite usar localhost para enviar solicitudes a server.

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

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

    deactivate
    

Organiza la aplicación en contenedores

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 instructivo, se usa Docker para contener la aplicación.

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

El código fuente de este instructivo incluye un Dockerfile para el server y loadgen con todos los comandos necesarios para compilar las imágenes. A continuación, se incluye el Dockerfile para el 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, puedes ver lo siguiente:

  • La instrucción FROM python:3-slim as base le indica a Docker que use la imagen de Python 3 más reciente como imagen base.
  • La instrucción COPY . . copia los archivos fuente del directorio de trabajo actual (en este caso, server.py) al sistema de archivos del contenedor.
  • El ENTRYPOINT define la instrucción que se usa para ejecutar el contenedor. En este ejemplo, la instrucción es similar a la que usaste 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, pero sirve como documentación que necesitas para abrir el puerto 8080 cuando ejecutas el contenedor.

Prepárate para organizar la aplicación en contenedores

Antes de contener la aplicación, debes configurar las herramientas y los servicios que usarás:

  1. Establece el proyecto predeterminado Google Cloud para Google Cloud CLI.

    gcloud config set project PROJECT_ID
  2. Establece la región predeterminada para Google Cloud CLI.

    gcloud config set compute/region us-central1
    

Crea el repositorio

Para crear un repositorio nuevo para imágenes de contenedores de Docker en Artifact Registry, haz lo siguiente:

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

    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 a Artifact Registry con Google Cloud CLI:

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

Crea contenedores para el server

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

  1. Cambia al directorio en el que se encuentra el server de muestra:

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

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

    La marca -t representa la etiqueta de Docker. Este es el nombre de la imagen que debes usar en la implementación del contenedor.

  3. Envía la imagen a Artifact Registry:

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

Crea contenedores para el loadgen

A continuación, crea un contenedor para el servicio del generador de cargas de la misma manera:

  1. Cambia al directorio en el que se encuentra el loadgen de muestra:

    cd ../loadgen
    
  2. Compila 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
    

Obtén una lista de las imágenes

Obtén una lista de las imágenes en el repositorio para confirmar que se enviaron:

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

El resultado debería mostrar una lista de los nombres de las imágenes que enviaste, similar a la siguiente:

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

Cree un clúster de GKE

En este punto, puedes ejecutar los contenedores en la VM de Cloud Shell con el comando docker run. Sin embargo, para ejecutar cargas de trabajo de producción confiables, debes administrar los contenedores de una manera más unificada. Por ejemplo, debes asegurarte de que los contenedores se reinicien si fallan y necesitas una forma de escalar verticalmente e iniciar instancias adicionales de un contenedor para manejar los aumentos de tráfico.

GKE puede ayudarte a satisfacer estas necesidades. GKE es una plataforma de organización de contenedores que funciona mediante la conexión de VMs a un clúster. Cada VM se conoce como un nodo. Los clústeres de GKE funcionan con el sistema de administración de clústeres de código abierto de Kubernetes. Kubernetes proporciona los mecanismos a través de los cuales interactúas con el clúster.

Para ejecutar los contenedores en GKE, primero debes crear un clúster y, luego, 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 y la región Google Cloud predeterminados que estableciste antes.

    El comando para crear el clúster toma unos minutos en completarse. Cuando el clúster está listo, el resultado es 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 de kubectl para que puedas usarla a fin de administrar el clúster:

    gcloud container clusters get-credentials container-intro
    

Examina los manifiestos de Kubernetes

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

“Imperativo” significa basado en un verbo: “haz esto”.

Por el contrario, Kubernetes opera en función de un modelo declarativo. Esto significa que, en lugar de indicarle a Kubernetes qué hacer con exactitud, le proporcionas a Kubernetes el estado deseado. Por ejemplo, Kubernetes inicia y finaliza los Pods según sea necesario para que el estado real del sistema coincida con el estado deseado.

Debes especificar 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 más objetos de Kubernetes.

La muestra contiene un manifiesto para server y loadgen. Cada manifiesto especifica el estado deseado para el objeto Deployment de Kubernetes (que administra la ejecución de tu contenedor, empaquetado para la administración como un Pod de Kubernetes) y Service (que proporciona una dirección IP para el Pod). Un Pod es la unidad de procesamiento más pequeña que se puede implementar en Kubernetes y que contiene uno o más contenedores.

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

Aplicación alojada en contenedores que se ejecuta en GKE

Puedes obtener más información sobre los pods, las implementaciones y los servicios en Comienza a aprender sobre Kubernetes o en los recursos que se encuentran al final de esta página.

Servidor

Primero, observa el manifiesto del server de "Hello World":

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 del objeto Deployment.
  • El primer campo spec contiene una descripción del estado deseado.
  • spec.replicas especifica la cantidad de Pods deseados.
  • La sección spec.template define una plantilla de Pod. En la especificación para los Pods, se incluye el campo image, que es el nombre de la imagen que se extraerá de Artifact Registry. En el siguiente paso, actualizarás esta imagen a la nueva 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 cargas de redes, que tiene una dirección IP estable y a la que se puede acceder desde fuera del clúster.
  • targetPort: Recuerda que el comando EXPOSE 8080 en el Dockerfile no expone ningún puerto. Debes exponer el puerto 8080 para poder acceder al contenedor de server fuera del clúster. En este caso, hellosvc.default.cluster.local:80 (nombre corto: hellosvc) se asigna al puerto 8080 de la IP del Pod helloserver.
  • port: Este es el número de puerto que usan otros servicios en el clúster cuando envían solicitudes.

Generador de cargas

El objeto Deployment en loadgen.yaml es similar a server.yaml. Una diferencia notable es que la especificación de Pod para la Deployment de loadgen tiene un campo llamado env. En esta sección, se definen las variables de entorno que requiere loadgen, que configuraste antes cuando ejecutaste 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

Debido a que loadgen no acepta solicitudes entrantes, el campo type se establece en ClusterIP. Este tipo de servicio proporciona una dirección IP estable que las entidades del clúster pueden usar, pero la dirección IP no está expuesta a clientes externos.

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

Implementa los contenedores en GKE

Para implementar los contenedores, aplicas los manifiestos que especifican el estado deseado con kubectl.

Implementa el server

  1. Cambia al directorio en el que se encuentra el server de muestra:

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

  3. Reemplaza el nombre en el campo image por el nombre de tu imagen de Docker.

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

    Reemplaza PROJECT_ID por el ID de tu proyecto de Google Cloud .

    • Si usas el editor de Cloud Shell, el archivo se guardará automáticamente. Para volver a la ventana de la terminal, haz clic en Abrir terminal.
    • Si usas un editor de texto en Cloud Shell, guarda y cierra server.yaml.
  4. Implementa el manifiesto en Kubernetes:

    kubectl apply -f server.yaml
    

    El resultado es similar a este:

    deployment.apps/helloserver created
    service/hellosvc created
    

Implementa 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. Una vez más, reemplaza el nombre en el campo image por el nombre de tu imagen de Docker.

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

    Reemplaza PROJECT_ID por el ID de tu proyecto de Google Cloud .

    • Si usas el editor de Cloud Shell, el archivo se guardará automáticamente. Para volver a la ventana de la terminal, haz clic en Abrir terminal.
    • Si usas un editor de texto en Cloud Shell, guarda y cierra loadgen.yaml.
  4. Implementa el manifiesto en tu clúster:

    kubectl apply -f loadgen.yaml
    

    Si se ejecuta de forma correcta, el comando responde con lo siguiente:

    deployment.apps/loadgenerator created
    service/loadgensvc created
    

Verifica tu implementación

Después de implementar tus manifiestos en el clúster, verifica que los contenedores se hayan implementado correctamente:

  1. Verifica el estado de los Pods en 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 desde el Pod loadgen. Reemplaza POD_ID por el identificador del Pod del generador de cargas del resultado anterior.

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

    kubectl get service hellosvc
    

    El resultado es similar a este:

    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 a hellosvc. Reemplaza EXTERNAL_IP por la dirección IP externa de tu hellosvc.

    curl http://EXTERNAL_IP
    

    Deberías ver el mensaje “Hello World!” del servidor.

Limpia

Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos usados en este instructivo, borra el proyecto que contiene los recursos o conserva el proyecto y borra los recursos individuales.

Si no quieres borrar todo el proyecto, haz lo siguiente:

  • Borra el clúster de GKE. Cuando borras el clúster, se borran todos los recursos que lo conforman, como las instancias, los discos y los recursos de red de Compute Engine.

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

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

¿Qué sigue?