Guía de inicio rápido: Implementa una app de lenguaje específico

En esta página, se muestra cómo hacer lo siguiente:

  1. Crear una app de Hello World
  2. Empaquetar la app en una imagen de contenedor con Cloud Build
  3. Crear un clúster en Google Kubernetes Engine (GKE)
  4. Implementar la imagen de contenedor en tu clúster

El ejemplo se muestra en varios lenguajes, pero ten en cuenta que puedes usar otros lenguajes además de los que se muestran.

Antes de comenzar

  1. Accede a tu Cuenta de Google.

    Si todavía no tienes una cuenta, regístrate para obtener una nueva.

  2. En la página de selección de proyectos de Cloud Console, selecciona o crea un proyecto de Cloud.

    Ir a la página Selector de proyectos

  3. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud. Obtén información sobre cómo confirmar que tienes habilitada la facturación para tu proyecto.

  4. Habilita las API de Cloud Build and Google Kubernetes Engine.

    Habilita las API

  5. Instala e inicializa el SDK de Cloud.
  6. kubectl se usa para administrar Kubernetes, el sistema de organización de clúster que usa GKE. Puedes instalar kubectl con gcloud:
    gcloud components install kubectl

Escribe la app de muestra

Si quieres obtener instrucciones para crear una app de Hello World que se ejecute en GKE, haz clic en tu lenguaje:

Go

  1. Crea un directorio nuevo llamado helloworld-gke y usa el comando de cambio de directorio en él:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crea un módulo nuevo llamado example.com/helloworld:

    go mod init example.com/helloworld
    
  3. Crea un archivo nuevo llamado helloworld.go y pega el código siguiente en él:

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    )
    
    func main() {
    	http.HandleFunc("/", handler)
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    	}
    
    	log.Printf("Listening on localhost:%s", port)
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
    }
    
    func handler(w http.ResponseWriter, r *http.Request) {
    	log.Print("Hello world received a request.")
    	target := os.Getenv("TARGET")
    	if target == "" {
    		target = "World"
    	}
    	fmt.Fprintf(w, "Hello %s!\n", target)
    }
    

    Con este código, se crea un servidor web que está a la escucha del puerto definido por la variable de entorno PORT.

Tu app está lista para empaquetarse en un contenedor de Docker y, luego, subirse a Container Registry.

Node.js

  1. Crea un directorio nuevo llamado helloworld-gke y usa el comando de cambio de directorio en él:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crea un archivo package.json con el contenido siguiente:

    {
      "name": "gke-helloworld",
      "version": "1.0.0",
      "description": "GKE hello world sample in Node",
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "author": "",
      "license": "Apache-2.0",
      "dependencies": {
        "express": "^4.16.4"
      }
    }
    
  3. En el mismo directorio, crea un archivo index.js y copia las líneas siguientes en él:

    const express = require('express');
    const app = express();
    
    app.get('/', (req, res) => {
      console.log('Hello world received a request.');
    
      const target = process.env.TARGET || 'World';
      res.send(`Hello ${target}!`);
    });
    
    const port = process.env.PORT || 8080;
    app.listen(port, () => {
      console.log('Hello world listening on port', port);
    });
    

    Con este código, se crea un servidor web que está a la escucha del puerto definido por la variable de entorno PORT.

Tu app está lista para empaquetarse en un contenedor de Docker y subirse a Container Registry.

Python

  1. Crea un directorio nuevo llamado helloworld-gke y usa el comando de cambio de directorio en él:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crea un archivo llamado app.py y pega el código siguiente en él:

    import os
    
    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        target = os.environ.get('TARGET', 'World')
        return 'Hello {}!\n'.format(target)
    
    if __name__ == "__main__":
        app.run(debug=True,host='0.0.0.0',port=int(os.environ.get('PORT', 8080)))
    

Java

Crea una app de Spring Boot.

  1. Instala Java SE 8 o un JDK y cURL superior. Solo se requieren Java SE y cURL para crear el proyecto web nuevo en el paso siguiente. Dockerfile, que se describe más adelante, carga todas las dependencias en el contenedor.

  2. Desde tu terminal, crea un proyecto web vacío nuevo:

    curl https://start.spring.io/starter.zip \
        -d dependencies=web \
        -d javaVersion=1.8 \
        -d bootVersion=2.1.3.RELEASE \
        -d name=helloworld \
        -d artifactId=helloworld \
        -d baseDir=helloworld-gke \
        -o helloworld-gke.zip
    unzip helloworld-gke.zip
    cd helloworld-gke
    

    Ahora tienes un proyecto de Spring Boot nuevo en helloworld-gke.

  3. En el archivo src/main/java/com/example/helloworld/HelloworldApplication.java, actualiza la clase HelloworldApplication mediante un @RestController para controlar la asignación /.

    package com.example.helloworld;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    public class HelloworldApplication {
    
    	@Value("${TARGET:World}")
    	String target;
    
    	@RestController
    	class HelloworldController {
    		@GetMapping("/")
    		String hello() {
    			return "Hello " + target + "!";
    		}
    	}
    
    	public static void main(String[] args) {
    		SpringApplication.run(HelloworldApplication.class, args);
    	}
    }
    

    Con este código, se crea un servidor web que está a la escucha del puerto definido por la variable de entorno PORT.

Tu app está lista para empaquetarse en un contenedor de Docker y, luego, subirse a Container Registry.

C#

  1. Instala .NET Core SDK 2.2. Solo se requiere SDK de .NET Core para crear el proyecto web nuevo en el siguiente paso. Dockerfile, que se describe más adelante, carga todas las dependencias en el contenedor.

  2. Desde tu terminal, crea un proyecto web vacío nuevo:

    dotnet new web -o helloworld-gke
    
  3. Cambia el directorio a helloworld-gke.

  4. Si deseas actualizar la definición CreateWebHostBuilder en Program.cs especifica la URL del puerto para .UseUrls() a fin de definir el puerto de entrega. En el ejemplo, se muestra el puerto 8080, pero puedes usar otros puertos. Tu servidor debe detectar cualquier puerto que especifiques aquí:

    // Copyright (c) 2019 Google LLC.
    //
    // Licensed under the Apache License, Version 2.0 (the "License"); you may not
    // use this file except in compliance with the License. You may obtain a copy of
    // the License at
    //
    // http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    // License for the specific language governing permissions and limitations under
    // the License.
    
    using System;
    using Microsoft.AspNetCore;
    using Microsoft.AspNetCore.Hosting;
    
    namespace HelloGKE
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateWebHostBuilder(args).Build().Run();
            }
    
            public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
                WebHost.CreateDefaultBuilder(args)
                    .UseStartup<Startup>()
                    .UsePortEnvironmentVariable();
        }
    
        static class ProgramExtensions
        {
            // Google Cloud Run sets the PORT environment variable to tell this
            // process which port to listen to.
            public static IWebHostBuilder UsePortEnvironmentVariable(
                this IWebHostBuilder builder)
            {
                string port = Environment.GetEnvironmentVariable("PORT");
                if (!string.IsNullOrEmpty(port))
                {
                    builder.UseUrls($"http://0.0.0.0:{port}");
                }
                return builder;
            }
        }
    }
    

Tu app está lista para empaquetarse en un contenedor de Docker y, luego, subirse a Container Registry.

PHP

  1. Crea un directorio nuevo llamado helloworld-gke y usa el comando de cambio de directorio en él:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crea un archivo llamado index.php y pega el código siguiente en él:

    <?php
    $target = getenv('TARGET', true) ?: 'World';
    echo sprintf("Hello %s!", $target);
    

Tu app está lista para empaquetarse en un contenedor de Docker y, luego, subirse a Container Registry.

Ruby

  1. Crea un directorio nuevo llamado helloworld-gke y usa el comando de cambio de directorio en él:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crea un archivo llamado app.rb y pega el código siguiente en él:

    require 'sinatra'
    
    set :bind, '0.0.0.0'
    set :port, ENV['PORT'] || '8080'
    
    get '/' do
      target = ENV['TARGET'] || 'World'
      "Hello #{target}!\n"
    end
    

    Con este código, se crea un servidor web que recibe datos en el puerto definido por la variable de entorno PORT.

  3. Crea un archivo llamado Gemfile y copia la información siguiente en él:

    source 'https://rubygems.org'
    
    gem 'sinatra'
    gem 'rack', '>= 2.0.6'
    

Crea contenedores para la app con Cloud Build

  1. Si quieres crear contenedores para la app de muestra, crea un archivo nuevo llamado Dockerfile en el mismo directorio que los archivos de origen y copia el siguiente contenido:

    Go

    # Use the offical Golang image to create a build artifact.
    # This is based on Debian and sets the GOPATH to /go.
    # https://hub.docker.com/_/golang
    FROM golang:1.12 as builder
    
    # Copy local code to the container image.
    WORKDIR /app
    COPY . .
    
    # Build the command inside the container.
    RUN CGO_ENABLED=0 GOOS=linux go build -v -o helloworld
    
    # Use a Docker multi-stage build to create a lean production image.
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM alpine
    RUN apk add --no-cache ca-certificates
    
    # Copy the binary to the production image from the builder stage.
    COPY --from=builder /app/helloworld /helloworld
    
    # Run the web service on container startup.
    CMD ["/helloworld"]
    

    Node.js

    # Use the official lightweight Node.js 10 image.
    # https://hub.docker.com/_/node
    FROM node:10-slim
    
    # Create and change to the app directory.
    WORKDIR /usr/src/app
    
    # Copy application dependency manifests to the container image.
    # A wildcard is used to ensure both package.json AND package-lock.json are copied.
    # Copying this separately prevents re-running npm install on every code change.
    COPY package*.json ./
    
    # Install production dependencies.
    RUN npm install --only=production
    
    # Copy local code to the container image.
    COPY . ./
    
    # Run the web service on container startup.
    CMD [ "npm", "start" ]
    

    Agrega otro archivo .dockerignore para asegurarte de que los archivos locales no afecten el proceso de compilación del contenedor:

    Dockerfile
    README.md
    node_modules
    npm-debug.log
    

    Python

    # Use the official lightweight Python image.
    # https://hub.docker.com/_/python
    FROM python:3.7-slim
    
    # Copy local code to the container image.
    ENV APP_HOME /app
    WORKDIR $APP_HOME
    COPY . ./
    
    # Install production dependencies.
    RUN pip install Flask gunicorn
    
    # Run the web service on container startup. Here we use the gunicorn
    # webserver, with one worker process and 8 threads.
    # For environments with multiple CPU cores, increase the number of workers
    # to be equal to the cores available.
    CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app
    

    Agrega un archivo .dockerignore para asegurarte de que los archivos locales no afecten el proceso de compilación del contenedor:

    Dockerfile
    README.md
    *.pyc
    *.pyo
    *.pyd
    __pycache__
    

    Java

    # Use the official maven/Java 8 image to create a build artifact.
    # https://hub.docker.com/_/maven
    FROM maven:3.5-jdk-8-alpine as builder
    
    # Copy local code to the container image.
    WORKDIR /app
    COPY pom.xml ./
    COPY src ./src/
    
    # Build a release artifact.
    RUN mvn package -DskipTests
    
    # Use AdoptOpenJDK for base image.
    # It's important to use OpenJDK 8u191 or above that has container support enabled.
    # https://hub.docker.com/r/adoptopenjdk/openjdk8
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM adoptopenjdk/openjdk8:jdk8u202-b08-alpine-slim
    
    # Copy the jar to the production image from the builder stage.
    COPY --from=builder /app/target/helloworld-*.jar /helloworld.jar
    
    # Run the web service on container startup.
    CMD ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/helloworld.jar"]
    

    C#

    # Use Microsoft's official lightweight .NET images.
    # https://hub.docker.com/r/microsoft/dotnet
    
    FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine AS build
    WORKDIR /app
    
    # Install production dependencies.
    # Copy csproj and restore as distinct layers.
    COPY *.csproj ./
    RUN dotnet restore
    
    # Copy local code to the container image.
    COPY . ./
    
    # Build a release artifact.
    RUN dotnet publish -c Release -o out
    
    # Run the web service on container startup in a lean production image.
    FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-alpine
    WORKDIR /app
    
    COPY --from=build /app/out ./
    CMD ["dotnet", "HelloGKE.dll"]
    

    Agrega un archivo .dockerignore para asegurarte de que los archivos locales no afecten el proceso de compilación del contenedor:

    Dockerfile
    README.md
    **/obj/
    **/bin/
    

    PHP

    # Use the official PHP 7.2 image.
    # https://hub.docker.com/_/php
    FROM php:7.2-apache
    
    # Copy local code to the container image.
    COPY index.php /var/www/html/
    
    # Use port 8080 in Apache configuration files.
    RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
    
    # Configure PHP for development.
    # Switch to the production php.ini for production operations.
    # RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
    # https://hub.docker.com/_/php#configuration
    RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
    

    Agrega un archivo .dockerignore para asegurarte de que los archivos locales no afecten el proceso de compilación del contenedor:

    Dockerfile
    README.md
    vendor
    

    Ruby

    # Use the official lightweight Ruby image.
    # https://hub.docker.com/_/ruby
    FROM ruby:2.5-slim
    
    # Install production dependencies.
    WORKDIR /usr/src/app
    COPY Gemfile ./
    RUN bundle install
    
    # Copy local code to the container image.
    COPY . ./
    
    # Run the web service on container startup.
    CMD ["ruby", "./app.rb"]
    

  2. Obtén tu ID del proyecto de Google Cloud:

    gcloud config get-value project
    

    Compila tu imagen de contenedor con Cloud Build, que es similar a ejecutar docker build y docker push, pero se realiza en Google Cloud. Reemplaza project-id por tu ID de Google Cloud:

    gcloud builds submit --tag gcr.io/project-id/helloworld-gke .
    

    La imagen se almacena en Container Registry.

Crea un clúster de Kubernetes Engine

Un clúster de GKE es un conjunto administrado de máquinas virtuales de Compute Engine que operan como un solo clúster de GKE. En este instructivo, se usa un solo nodo.

  1. Crea el clúster. Reemplaza your-gcp-zone por la zona de Google Cloud en la que deseas alojar tu clúster. Para obtener una lista completa, consulta Geografía y regiones.

    gcloud container clusters create helloworld-gke \
       --num-nodes 1 \
       --enable-basic-auth \
       --issue-client-certificate \
       --zone your-gcp-zone
    
  2. Verifica si tienes acceso al clúster. Con el comando siguiente, se enumeran los nodos de tu clúster de contenedores que están en funcionamiento y que indican que tiene acceso a él.

    kubectl get nodes
    

    Si detectas errores, consulta la Guía de solución de problemas de Kubernetes

Implementación en GKE

Si quieres implementar tu app en el clúster de GKE que creaste, necesitas dos objetos de Kubernetes.

  1. Una Implementación para definir tu app.
  2. Un servicio para definir cómo acceder a tu app.

Implementa una app

La app tiene un servidor frontend que controla las solicitudes web. Define los recursos del clúster necesarios para ejecutar el frontend en un archivo nuevo llamado deployment.yaml. Estos recursos se describen como una implementación. Debes usar implementaciones para crear y actualizar un ReplicaSet y sus pods asociados.

  1. Crea el archivo deployment.yaml en el mismo directorio que tus otros archivos y copia el contenido siguiente. Reemplaza $GCLOUD_PROJECT por tu ID del proyecto de Google Cloud:

    # This file configures the hello-world app which serves public web traffic.
    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: helloworld-gke
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: hello
      template:
        metadata:
          labels:
            app: hello
        spec:
          containers:
          - name: hello-app
            # Replace $GCLOUD_PROJECT with your project ID
            image: gcr.io/$GCLOUD_PROJECT/helloworld-gke:latest
            # This app listens on port 8080 for web traffic by default.
            ports:
            - containerPort: 8080
            env:
              - name: PORT
                value: "8080"
    
  2. Implementa el recurso en el clúster:

    kubectl apply -f deployment.yaml
    
  3. Haz un seguimiento del estado de Deployment.

    kubectl get deployments
    

    El objeto Deployment se completa cuando todas las implementaciones AVAILABLE se encuentran READY.

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    hello-deployment   1/1     1            1           20s
    

    Si el objeto Deployment tiene un error, vuelve a ejecutar kubectl apply -f deployment.yaml para actualizarlo con los cambios.

  4. Cuando la implementación finalice, podrás ver los pods que creó.

    kubectl get pods
    

Implementa el servicio

Los servicios proporcionan un solo punto de acceso a un conjunto de pods. Si bien es posible acceder a un solo pod, los pods son efímeros y solo se puede acceder de manera confiable mediante una dirección del servicio. En tu app de Hello World, el servicio “hello” define un balanceador de cargas para acceder a los hello-app pods desde una sola dirección IP. Este servicio se define en el archivo service.yaml.

  1. Crea el archivo service.yaml en el mismo directorio que tus otros archivos de origen con el contenido siguiente:

    # The hello service provides a load-balancing proxy over the hello-app
    # pods. By specifying the type as a 'LoadBalancer', Kubernetes Engine will
    # create an external HTTP load balancer.
    apiVersion: v1
    kind: Service
    metadata:
      name: hello
    spec:
      type: LoadBalancer
      selector:
        app: hello
      ports:
      - port: 80
        targetPort: 8080
    

    Los pods se definen por separado desde el servicio que usa los pods. Kubernetes usa etiquetas para seleccionar los pods a los que se dirige un servicio. Gracias a las etiquetas, puedes tener un servicio que se dirija a los pods desde conjuntos de réplicas diferentes y tener varios servicios que apunten a un pod en particular.

  2. Crea el servicio Hello World:

    kubectl apply -f service.yaml
    
  3. Obtén la dirección IP externa del servicio:

    kubectl get services
    

    Puede tardar hasta 60 segundos asignar la dirección IP. La dirección IP externa aparecerá en la columna EXTERNAL-IP para el servicio hello.

    NAME         TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
    hello        LoadBalancer   10.22.222.222   35.111.111.11   80:32341/TCP   1m
    kubernetes   ClusterIP      10.22.222.1     <none>          443/TCP        20m
    

Visualiza una app implementada

Ya implementaste todos los recursos necesarios para ejecutar la app de Hello World en GKE. Usa la dirección IP externa del paso anterior para subir la app a tu navegador web y visualiza tu app en ejecución.

# Example cURL call to your running application on GKE (external IP address of service)
curl 35.111.111.11
Hello World!

Realiza una limpieza

Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos que usaste en esta guía de inicio rápido:

Se cobra por las instancias de Compute Engine que se ejecutan en tu clúster y por la imagen de contenedor en Container Registry.

Borra el proyecto

Si borras tu proyecto de Cloud, se dejan de facturar todos los recursos que usaste en ese proyecto.

  1. En Cloud Console, ve a la página Administrar recursos.

    Ir a la página Administrar recursos

  2. En la lista de proyectos, selecciona el proyecto que deseas borrar y haz clic en Borrar .
  3. En el cuadro de diálogo, escribe el ID del proyecto y haz clic en Cerrar para borrar el proyecto.

Borra tu clúster y contenedor

Si deseas conservar tu proyecto, pero solo borrar los recursos que usaste en este instructivo, borra tu clúster y la imagen.

Para borrar un clúster con la herramienta de línea de comandos de gcloud, ejecuta el comando siguiente:

gcloud container clusters delete helloworld-gke

Si deseas borrar una imagen de uno de tus repositorios de Container Registry, ejecuta el comando siguiente:

gcloud container images delete gcr.io/project-id/helloworld-gke

Próximos pasos

Para obtener más información sobre Kubernetes, consulta los vínculos siguientes:

Para obtener más información sobre la implementación en GKE, consulta los vínculos siguientes:

Para obtener más información sobre la implementación en GKE directo desde tu IDE con Cloud Code, consulta los vínculos siguientes: