Implementa una app de .NET en Google Kubernetes Engine con un flujo de trabajo de GitHub Actions

En este instructivo, se describe cómo usar un flujo de trabajo de acciones de GitHub, para implementar una aplicación web de Model-View-Controller (MVC) de ASP.NET que usa .NET en Google Kubernetes Engine (GKE).

Este instructivo está dirigido a ingenieros DevOps y desarrolladores que tienen conocimientos básicos de Microsoft .NET, acciones de GitHub y GKE. También necesitas una cuenta de GitHub para ejecutar este instructivo.

Objetivos

Implementa una aplicación web de ASP.NET Core que usa .NET 6.0 y se ejecuta en Linux en Google Kubernetes Engine.

En el siguiente diagrama, se muestra el flujo de trabajo de acciones de GitHub para implementar una aplicación web de ASP.NET MVC en Google Kubernetes Engine (GKE).

Diagrama conceptual del flujo de trabajo de GitHub Actions

En este instructivo, se muestra cómo completar las siguientes tareas para alcanzar tu objetivo:

  • Crea un repositorio de GitHub
  • Configura la autenticación
  • Implementa un clúster de GKE y un repositorio de Artifact Registry
  • Crea un flujo de trabajo de acciones de GitHub

Costos

En este documento, usarás los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios.

Es posible que los usuarios de Google Cloud nuevos cumplan con los requisitos para acceder a una prueba gratuita.

Cuando completes las tareas que se describen en este documento, podrás borrar los recursos que creaste para evitar que se te siga facturando. Para obtener más información, consulta Realiza una limpieza.

Antes de comenzar

  1. Accede a tu Google Cloud cuenta de. Si eres nuevo en Google Cloud, crea una cuenta para evaluar el rendimiento de nuestros productos en situaciones reales. Los clientes nuevos también obtienen $300 en créditos gratuitos para ejecutar, probar y, además, implementar cargas de trabajo.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Artifact Registry and Google Kubernetes Engine APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the Artifact Registry and Google Kubernetes Engine APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

Crea un repositorio de GitHub

Crea una bifurcación del repositorio dotnet-docs-samples en tu cuenta de GitHub. Este paso es necesario porque estamos compilando con acciones de GitHub.

  1. Ve al dotnet-docs-samples repositorio de GitHub.
  2. Haz clic en Fork.
  3. En la página Create a new fork, configura lo siguiente:

    • Owner : Tu cuenta de GitHub
    • Repository name : dotnet-docs-samples
  4. Haz clic en Create fork.

Configura la autenticación

Prepara tu Google Cloud proyecto para que las acciones de GitHub puedan autenticarse y acceder a los recursos en el Google Cloud proyecto.

Crea un proveedor y un grupo de federación de identidades para cargas de trabajo

Para permitir que las acciones de GitHub se autentiquen Google Cloud y se implementen en GKE, usa la federación de identidades para cargas de trabajo. Si usas la federación de identidades para cargas de trabajo, puedes evitar la necesidad de almacenar y administrar claves de cuentas de servicio para tu carga de trabajo de acciones de GitHub.

El uso de la federación de identidades para cargas de trabajo requiere un proveedor y un grupo de identidades para cargas de trabajo. Te recomendamos que uses un proyecto dedicado para administrar grupos de identidades para cargas de trabajo y proveedores. En este instructivo, para simplificar, crea el grupo y el proveedor en el mismo proyecto que tu clúster de GKE:

  1. Abre la Google Cloud consola.

  2. En la Google Cloud consola, activa Cloud Shell.

    Activa Cloud Shell

    En la parte inferior de la Google Cloud consola, se inicia una sesión de Cloud Shell en la que se muestra una ventana de línea de comandos. Cloud Shell es un entorno de shell con Google Cloud CLI ya instalada y con valores ya establecidos para el proyecto actual. La sesión puede tardar unos segundos en inicializarse.

  3. Crea un nuevo grupo de identidades para cargas de trabajo:

    gcloud iam workload-identity-pools create github-actions \
        --location="global" \
        --description="GitHub Actions tutorial" \
        --display-name="GitHub Actions"
    
  4. Agrega acciones de GitHub como proveedor de grupos de identidades para cargas de trabajo:

    gcloud iam workload-identity-pools providers create-oidc github-actions-oidc \
        --location="global" \
        --workload-identity-pool=github-actions \
        --issuer-uri="https://token.actions.githubusercontent.com/" \
        --attribute-mapping="google.subject=assertion.sub" \
        --attribute-condition="assertion.repository_owner=='ORGANIZATION'"
    

    Reemplaza ORGANIZATION por el nombre de tu organización de GitHub.

Crea una cuenta de servicio

  1. En Cloud Shell, crea una cuenta de servicio que las acciones de GitHub puedan usar para publicar imágenes de Docker y realizar implementaciones en GKE:

    SERVICE_ACCOUNT=$(gcloud iam service-accounts create github-actions-workflow \
      --display-name "GitHub Actions workflow" \
      --format "value(email)")
    
  2. Otorga el rol de escritor de Artifact Registry (roles/artifactregistry.writer) a la cuenta de servicio para permitir que las acciones de GitHub envíen contenido a Artifact Registry:

    gcloud projects add-iam-policy-binding $(gcloud config get-value core/project) \
      --member serviceAccount:$SERVICE_ACCOUNT \
      --role roles/artifactregistry.writer
    
  3. Otorga el rol de desarrollador de Google Kubernetes Engine (roles/container.developer) a la cuenta de servicio para permitir que las acciones de GitHub envíen contenido a Artifact Registry:

    gcloud projects add-iam-policy-binding $(gcloud config get-value core/project) \
      --member serviceAccount:$SERVICE_ACCOUNT \
      --role roles/container.developer
    

Permite que el flujo de trabajo de acciones de GitHub use la cuenta de servicio

Permite que el flujo de trabajo de acciones de GitHub actúe en nombre de la cuenta de servicio y la use:

  1. Inicializa una variable de entorno que contenga el asunto que usa el flujo de trabajo de acciones de GitHub. Un asunto es similar a un nombre de usuario que identifica de forma única el repositorio y la rama de GitHub:

    SUBJECT=repo:OWNER/dotnet-docs-samples:ref:refs/heads/main
    

    Reemplaza OWNER por tu nombre de usuario de GitHub.

  2. Otorga permiso al asunto para que actúe en nombre de la cuenta de servicio:

    PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value core/project) --format='value(projectNumber)')
    
    gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT \
      --role=roles/iam.workloadIdentityUser \
      --member="principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/github-actions/subject/$SUBJECT"
    

Implementa un clúster de GKE y un repositorio de Artifact Registry

  1. Crea un repositorio para imágenes de Docker:

    gcloud artifacts repositories create clouddemo \
      --repository-format=docker \
      --location=us-central1
    
  2. Permite que la cuenta de servicio predeterminada de Compute Engine acceda al repositorio:

    gcloud projects add-iam-policy-binding $(gcloud config get-value core/project) \
      --member=serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \
      --role=roles/artifactregistry.reader
    
  3. Crea el clúster:

    gcloud container clusters create clouddemo-linux \
      --enable-ip-alias \
      --zone us-central1-a
    

    Este comando puede tardar varios minutos en completarse.

  4. Obtén el nombre y el número del proyecto del clúster:

    echo "Project ID: $(gcloud config get-value core/project)"
    echo "Project Number: $(gcloud projects describe $(gcloud config get-value core/project) --format=value\(projectNumber\))"
    

    Necesitarás estos valores más adelante.

Crea un flujo de trabajo de acciones de GitHub

Ahora puedes usar acciones de GitHub para configurar la integración continua. Por cada confirmación que se envía al repositorio de Git, un flujo de trabajo de acciones de GitHub compila el código y empaqueta los artefactos de la compilación en un contenedor de Docker. Luego, el contenedor se publica en Artifact Registry.

El repositorio ya contiene el siguiente Dockerfile:

#
# Copyright 2020 Google LLC
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you 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.
#

FROM mcr.microsoft.com/dotnet/aspnet:6.0
EXPOSE 8080

#------------------------------------------------------------------------------
# Copy publishing artifacts.
#------------------------------------------------------------------------------

WORKDIR /app
COPY CloudDemo.MvcCore/bin/Release/net6.0/publish/ /app/

ENV ASPNETCORE_URLS=http://0.0.0.0:8080

#------------------------------------------------------------------------------
# Run application in Kestrel.
#------------------------------------------------------------------------------

ENTRYPOINT ["dotnet", "CloudDemo.MvcCore.dll"]

El repositorio también contiene un manifiesto de Kubernetes:

#
# Copyright 2020 Google LLC
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you 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.
#

apiVersion: v1
kind: Service
metadata:
  name: clouddemo-netcore
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: clouddemo-netcore
  type: NodePort

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: clouddemo-netcore
spec:
  defaultBackend:
    service:
      name: clouddemo-netcore
      port:
        number: 80

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: clouddemo-netcore
spec:
  replicas: 2
  selector:
    matchLabels:
      app: clouddemo-netcore
  template:
    metadata:
      labels:
        app: clouddemo-netcore
    spec:
      containers:
      - name: clouddemo-netcore
        image: CLOUDDEMO_IMAGE
        ports:
          - containerPort: 8080
        livenessProbe:      # Used by deployment controller
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        readinessProbe:     # Used by Ingress/GCLB
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 3
          periodSeconds: 5
        resources:
          limits:
            memory: 1024Mi
          requests:
            memory: 256Mi

Crea un flujo de trabajo de acciones de GitHub que haga lo siguiente:

  • Autentica a Google Cloud usando la federación de identidades para cargas de trabajo y la cuenta de servicio que creaste antes.
  • Compila una imagen de Docker y envíala a Artifact Registry.
  • Implementa la imagen de Docker en GKE.

Para crear el flujo de trabajo de acciones de GitHub, haz lo siguiente:

  1. En GitHub, ve a tu bifurcación del dotnet-docs-samples repositorio.
  2. Haz clic en Add file > Create new file.
  3. En el campo de texto Name your file, ingresa el siguiente nombre:

    .github/workflows/deploy-gke.yaml
    
  4. Copia el siguiente código en el archivo:

    name: Build and Deploy to GKE
    
    on:
      push:
        branches:
          - main
    
    env:
      PROJECT_ID: PROJECT_ID
      PROJECT_NUMBER: PROJECT_NUMBER
    
      CLUSTER: clouddemo-linux
      CLUSTER_ZONE: us-central1-a
    
      REPOSITORY: clouddemo
      REPOSITORY_REGION: us-central1
    
      IMAGE: clouddemo
    
    jobs:
      build:
        runs-on: ubuntu-latest
        permissions:
          id-token: write
          contents: read
    
        steps:
        - name: Checkout
          uses: actions/checkout@v3
    
        #
        # Authenticate to Google Cloud using workload identity federation
        #
        - id: 'auth'
          name: 'Obtain access token by using workload identity federation'
          uses: 'google-github-actions/auth@v0'
          with:
            create_credentials_file: true
            token_format: access_token
            workload_identity_provider: projects/${{ env.PROJECT_NUMBER }}/locations/global/workloadIdentityPools/github-actions/providers/github-actions-oidc
            service_account: github-actions-workflow@${{ env.PROJECT_ID }}.iam.gserviceaccount.com
    
        - name: Connect to Artifact Registry
          run: |-
            echo ${{ steps.auth.outputs.access_token }} | docker login -u oauth2accesstoken --password-stdin https://${{ env.REPOSITORY_REGION }}-docker.pkg.dev
    
        - name: Connect to GKE
          uses: google-github-actions/get-gke-credentials@v0
          with:
            cluster_name: ${{ env.CLUSTER }}
            location: ${{ env.CLUSTER_ZONE }}
    
        #
        # Build the .NET code
        #
        - name: Build solution
          run: |-
            dotnet publish applications/clouddemo/netcore/CloudDemo.MvcCore.sln \
                --configuration Release \
                --framework net6.0
    
        #
        # Build the Docker image and push it to Artifact Registry
        #
        - name: Create image tag
          run: echo "IMAGE_TAG=${{ env.REPOSITORY_REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE }}:$GITHUB_SHA" >> $GITHUB_ENV
    
        - name: Lock image version in deployment.yaml
          run: sed -i 's|CLOUDDEMO_IMAGE|${{ env.IMAGE_TAG }}|g' applications/clouddemo/netcore/deployment.yaml
    
        - name: Build Docker image
          run: docker build --tag "${{ env.IMAGE_TAG }}" applications/clouddemo/netcore
    
        - name: Publish Docker image to Google Artifact Registry
          run: docker push "${{ env.IMAGE_TAG }}"
    
        #
        # Deploy to GKE
        #
        - name: Deploy to GKE
          run: kubectl apply -f applications/clouddemo/netcore/deployment.yaml
        

    Reemplaza los siguientes valores:

    • PROJECT_ID: Es el ID del proyecto que contiene el clúster de GKE.
    • PROJECT_NUMBER: Es el número del proyecto que contiene el clúster de GKE.
  5. En la sección Commit new file, ingresa un mensaje de confirmación, por ejemplo, Add workflow y haz clic en Commit new file.

  6. En el menú, haz clic en Actions y espera a que se complete el flujo de trabajo.

    El flujo de trabajo puede tardar varios minutos en completarse.

  7. En la Google Cloud consola, actualiza la página Ingress y servicios.

    Ir a Ingress y Service

  8. Ve a la pestaña Ingress.

  9. Ubica el servicio de Ingress del clúster clouddemo y espera a que su estado cambie a Correcto. Esto podría llevar varios minutos.

  10. Abre el vínculo en la columna Frontends de la misma fila. El balanceador de cargas tarda unos minutos en estar disponible, por lo que es posible que la app de CloudDemo no se cargue al principio. Cuando el balanceador de cargas esté listo, verás la app de CloudDemo con el título personalizado, pero esta vez se estará ejecutando en el clúster de producción.

Limpia

Una vez que completes el instructivo, puedes limpiar los recursos que creaste para que dejen de usar la cuota y generar cargos. En las siguientes secciones, se describe cómo borrar o desactivar estos recursos.

Borra el repositorio de GitHub

Para borrar el repositorio de GitHub, consulta Borra un repositorio. Si borras el repositorio, se perderán todos los cambios del código fuente.

Borra el proyecto

La manera más fácil de eliminar la facturación es borrar el proyecto que creaste para el instructivo.

    Borra un Google Cloud proyecto:

    gcloud projects delete PROJECT_ID

¿Qué sigue?