Presentamos los contenedores


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

En este instructivo, no se requiere experiencia previa con contenedores ni Kubernetes. Sin embargo, si deseas leer una descripción general de la terminología principal de Kubernetes antes de comenzar este instructivo, consulta Comienza a aprender sobre Kubernetes (o, si prefieres aprender sobre Kubernetes en formato de cómic, consulta nuestro cómic de Kubernetes). Encontrarás recursos más detallados en la sección Próximos pasos 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 Trusted 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. Verify that billing is enabled for your Trusted 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.

Usar 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 siguientes editores de texto integrados:

    • El editor de Cloud Shell, al que accedes 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 Trusted Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    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 a través de 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 el 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 ello 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 a 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 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 la 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 la perspectiva 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 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 componentes de la aplicación de muestra 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 contenerizar 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 ensamblar 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 el 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) en el 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 el 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 contenerizar la aplicación, debes configurar algunas herramientas y servicios que usarás:

    1. Establece el proyecto Trusted Cloud predeterminado 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 deTrusted 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 en 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 un contenedor. Primero, crea un contenedor para el programa "hello world" server 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 Trusted Cloud by S3NS proyecto.

      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 de 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 los nombres de las imágenes que enviaste, 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
    

    Crea 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 conectando 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úster de código abierto de Kubernetes. Kubernetes proporciona los mecanismos que usas para interactuar con tu 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 Trusted Cloud y la región 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.

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

    La muestra contiene un manifiesto para server y otro para 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 el objeto 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 y que puedes crear y administrar en Kubernetes, y contiene uno o más contenedores.

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

    Aplicación en contenedor 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 "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 este valor a 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 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 del Pod para la Deployment 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 Service 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, aplica los manifiestos que especifican el estado deseado con kubectl.

    Implementa 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 en 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 Trusted Cloud ID del proyecto.

      • Si usas el editor de Cloud Shell, el archivo se guarda 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 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. Nuevamente, 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 Trusted Cloud ID del proyecto.

      • Si usas el editor de Cloud Shell, el archivo se guarda 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 tus 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 carga 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 de Compute Engine, los discos y los recursos de red.

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

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

    ¿Qué sigue?