Implementa una app de .NET Framework en Google Kubernetes Engine mediante un flujo de trabajo de Acciones de GitHub


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

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

Objetivos

Implementa una aplicación web ASP.NET MVC que use .NET Framework 4 y se ejecute en Windows en Google Kubernetes Engine.

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

Diagrama conceptual del flujo de trabajo de Acciones de GitHub

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 nuevos de Google Cloud califiquen para obtener una prueba gratuita.

Cuando finalices las tareas que se describen en este documento, puedes borrar los recursos que creaste para evitar que continúe la facturación. Para obtener más información, consulta Cómo realizar una limpieza.

Antes de comenzar

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

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

    Enable the APIs

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

    Go to project selector

  6. Make sure that billing is enabled for your Google Cloud project.

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

    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 compilamos con Acciones de GitHub.

  1. Ve al repositorio de GitHub dotnet-docs-samples.
  2. Haz clic en Fork.
  3. En la página Crear un tenedor nuevo, configura lo siguiente:

    • Propietario: Tu cuenta de GitHub
    • Nombre del repositorio: dotnet-docs-samples
  4. Haz clic en Crear bifurcación.

Configura la autenticación

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

Crear un grupo y proveedor de federación de Workload Identity

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

El uso de la federación de Workload Identity requiere un grupo y un proveedor de Workload Identity. Te recomendamos que uses un proyecto dedicado para administrar grupos y proveedores de Workload Identity. En este instructivo, por cuestiones de simplicidad, crea el grupo y el proveedor en el mismo proyecto que el clúster de GKE:

  1. Abre la consola de Google Cloud.

  2. 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.

  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 Workload Identity:

    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"
    

Crea una cuenta de servicio

  1. En Cloud Shell, crea una cuenta de servicio que GitHub Actions pueda usar para publicar imágenes de Docker y, también, implementarlas 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 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 a Artifact Registry:

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

Permitir que el flujo de trabajo de Acciones de GitHub use la cuenta de servicio

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

  1. Inicializa una variable de entorno que contenga el asunto que usa el flujo de trabajo de GitHub Actions. Un sujeto 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 sujeto para actuar 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 las 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-windows \
      --enable-ip-alias \
      --zone us-central1-a
    
    gcloud container node-pools create clouddemo-windows-pool \
      --cluster=clouddemo-windows \
      --image-type=WINDOWS_LTSC_CONTAINERD \
      --no-enable-autoupgrade \
      --machine-type=n1-standard-2 \
      --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á 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 GitHub Actions 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/windows/servercore/iis:windowsservercore-ltsc2019
EXPOSE 80
SHELL ["powershell", "-command"]

#------------------------------------------------------------------------------
# Add LogMonitor so that IIS and Windows logs are emitted to STDOUT and can be
# picked up by Docker/Kubernetes.
#
# See https://github.com/microsoft/windows-container-tools/wiki/Authoring-a-Config-File
# for details.
#------------------------------------------------------------------------------

ADD https://github.com/microsoft/windows-container-tools/releases/download/v1.1/LogMonitor.exe LogMonitor/
ADD LogMonitorConfig.json LogMonitor/

#------------------------------------------------------------------------------
# Copy publishing artifacts to webroot.
#------------------------------------------------------------------------------

ADD CloudDemo.Mvc/bin/Release/PublishOutput/ c:/inetpub/wwwroot/

#------------------------------------------------------------------------------
# Configure IIS using the helper functions from deployment.ps1.
#------------------------------------------------------------------------------

ADD deployment.ps1 /
RUN . /deployment.ps1; \
	Install-Iis; \
	Register-WebApplication -AppName "CloudDemo"; \
	Remove-Item /deployment.ps1

#------------------------------------------------------------------------------
# Run IIS, wrapped by LogMonitor.
#------------------------------------------------------------------------------

ENTRYPOINT ["C:\\LogMonitor\\LogMonitor.exe", "C:\\ServiceMonitor.exe", "w3svc"]

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-net4
  annotations:
    cloud.google.com/neg: '{"ingress": false}' # Disable NEG

spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
    name: http
  selector:
    app: clouddemo-net4
  type: NodePort

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

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: clouddemo-net4
spec:
  replicas: 2
  selector:
    matchLabels:
      app: clouddemo-net4
  template:
    metadata:
      labels:
        app: clouddemo-net4
    spec:
      nodeSelector:
        kubernetes.io/os: windows
      containers:
      - name: clouddemo-net4
        image: CLOUDDEMO_IMAGE
        ports:
          - containerPort: 80
        livenessProbe:      # Used by deployment controller
          httpGet:
            path: /health
            port: 80
          initialDelaySeconds: 120
          periodSeconds: 5
        readinessProbe:     # Used by Ingress/GCLB
          httpGet:
            path: /health
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 5
        resources:
          limits:
            memory: 1024Mi
          requests:
            memory: 256Mi

Crea un flujo de trabajo de GitHub Actions que realice las siguientes acciones:

  • Autentícate en Google Cloud con la federación de Workload Identity y la cuenta de servicio que creaste antes.
  • Compila una imagen de Docker y, luego, impleméntala en Artifact Registry.
  • Implementar la imagen de Docker en GKE

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

  1. En GitHub, ve a la bifurcación del repositorio dotnet-docs-samples.
  2. Haga clic en Agregar archivo > Crear archivo nuevo.
  3. En el campo de texto Name your file, ingrese 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-windows
      CLUSTER_ZONE: us-central1-a
    
      REPOSITORY: clouddemo
      REPOSITORY_REGION: us-central1
    
      IMAGE: clouddemo
    
    jobs:
      build:
        runs-on: windows-2019  # Matches WINDOWS_LTSC in GKE
        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: Setup MSBuild
          uses: microsoft/setup-msbuild@v1
    
        - name: Setup NuGet
          uses: NuGet/setup-nuget@v1
    
        - name: Restore NuGet packages
          run: nuget restore applications/clouddemo/net4/CloudDemo.Mvc.sln
    
        - name: Build solution
          run: msbuild /t:Rebuild /p:Configuration=Release /p:DeployOnBuild=true /p:PublishProfile=FolderProfile /nologo applications/clouddemo/net4/CloudDemo.Mvc.sln
    
        #
        # 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 }}:$env:GITHUB_SHA" >> $env:GITHUB_ENV
    
        - name: Lock image version in deployment.yaml
          shell: pwsh
          run: (Get-Content applications\clouddemo\net4\deployment.yaml) -replace "CLOUDDEMO_IMAGE","${{ env.IMAGE_TAG }}" | Out-File -Encoding ASCII applications\clouddemo\net4\deployment.yaml
    
        - name: Build Docker image
          run: docker build --tag "${{ env.IMAGE_TAG }}" applications/clouddemo/net4
    
        - 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/net4/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 Confirmar archivo nuevo, ingresa un mensaje de confirmación, por ejemplo, Add workflow, y haz clic en Confirmar archivo nuevo.

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

    El flujo de trabajo puede tardar varios minutos en completarse.

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

    Ir a Ingress y Service

  8. Ve a la pestaña Entrada.

  9. Ubica el servicio Ingress para el clúster clouddemo y espera a que su estado cambie a Ok. 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, que esta vez se ejecuta 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.

    Delete a Google Cloud project:

    gcloud projects delete PROJECT_ID

¿Qué sigue?