Crea una canalización de IC/EC con Azure Pipelines y Google Kubernetes Engine

Last reviewed 2022-11-29 UTC

En este instructivo, se muestra cómo usar Azure Pipelines, Google Kubernetes Engine (GKE) y Container Registry de Google a fin de crear una canalización de integración continua/implementación continua (CI/CD) para una aplicación web ASP.NET MVC. Para los fines de este instructivo, puedes seleccionar entre dos aplicaciones de ejemplo:

  • Una aplicación web de ASP.NET Core que usa .NET 6.0 y se ejecuta en Linux
  • Una aplicación web ASP.NET MVC que usa .NET Framework 4 y se ejecuta en Windows

La canalización de CI/CD usa dos clústeres de GKE independientes, uno para el desarrollo y otro para la producción, como se muestra en el siguiente diagrama.

Diagrama conceptual de la canalización de CI/CD en el que se muestra cómo los desarrolladores y los usuarios finales interactúan con la aplicación

Al comienzo de la canalización, los desarrolladores confirman cambios en la base de código de ejemplo. Esta acción activa la canalización para crear una nueva versión y para implementarla en el clúster de desarrollo. Un administrador de versiones puede promover la versión para que se implemente en el clúster de producción.

Este instructivo está dirigido a ingenieros DevOps y desarrolladores. Se supone que tienes conocimientos básicos de Microsoft .NET, Azure Pipelines y GKE. Para este instructivo también es necesario tener acceso de administrador a una cuenta de Azure DevOps.

Objetivos

  • Conectar Container Registry de Google con Azure Pipelines para publicar imágenes de Docker
  • Preparar una app de muestra de .NET para implementarla en GKE
  • Autenticar de forma segura en GKE sin tener que utilizar la autenticación heredada
  • Utilizar la administración de versiones de Azure Pipelines para organizar las implementaciones de GKE

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.

Consulta la página de precios de Azure DevOps para conocer las tarifas que podrían aplicarse por su uso.

Antes de comenzar

Por lo general, se recomienda usar proyectos diferentes para las cargas de trabajo de desarrollo y producción, a fin de que las funciones y los permisos de administración de identidades y accesos (IAM) se puedan otorgar de forma individual. Por cuestiones prácticas, en este instructivo se usa un solo proyecto para ambos clústeres de GKE, el de desarrollo y el de producción.

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

    Go to project selector

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

  3. Asegúrate de tener una cuenta de Azure DevOps y de contar con acceso de administrador. Si todavía no tienes una cuenta de Azure DevOps, puedes registrarte en su página principal.

Crea un proyecto de Azure DevOps

Azure DevOps se usa con el fin de administrar el código fuente, ejecutar compilaciones y pruebas, y organizar la implementación en GKE. Para comenzar, crea un proyecto en tu cuenta de Azure DevOps.

  1. Ve a la página principal de Azure DevOps (https://dev.azure.com/YOUR_AZURE_DEVOPS_ACCOUNT_NAME).
  2. Haz clic en Nuevo proyecto.
  3. Ingresa un nombre para el proyecto, como CloudDemo.
  4. Configura la Visibilidad como Privada y, luego, haz clic en Crear.
  5. Después de crear el proyecto, haz clic en Repos en el menú de la izquierda.
  6. Haz clic en Importar para bifurcar el repositorio dotnet-docs-samples de GitHub y, luego, establece los siguientes valores:
    • Tipo de repositorio: Git
    • URL de clonación: https://github.com/GoogleCloudPlatform/dotnet-docs-samples.git
  7. Haga clic en Import.

    Una vez completado el proceso de importación, verás el código fuente del repositorio de dotnet-docs-samples.

Conecta Azure Pipelines a Google Container Registry

Antes de configurar la integración continua para la app de CloudDemo, debes conectar Azure Pipelines a Container Registry. Esta conexión permite que Azure Pipelines publique imágenes de contenedor en Container Registry.

Configura una cuenta de servicio para publicar imágenes

Crea una cuenta de servicio de Google Cloud en tu proyecto:

  1. Abre la consola de Google Cloud.

  2. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

  3. Para ahorrar tiempo cuando escribes el ID del proyecto y las opciones de la zona de Compute Engine, establece los valores de configuración predeterminados; para ello, ejecuta los siguientes comandos:

    gcloud config set project PROJECT_ID
    gcloud config set compute/zone us-central1-a
    

    Reemplaza PROJECT_ID por el ID de tu proyecto:

  4. Habilita la API de Container Registry en el proyecto

    gcloud services enable containerregistry.googleapis.com
    
  5. Crea una cuenta de servicio que Azure Pipelines use para publicar imágenes de Docker:

    gcloud iam service-accounts create azure-pipelines-publisher \
        --display-name="Azure Pipelines Publisher"
    
  6. Otorga la función de IAM de administrador de almacenamiento (roles/storage.admin) a la cuenta de servicio para permitir que Azure Pipelines se envíe a Container Registry:

    AZURE_PIPELINES_PUBLISHER=azure-pipelines-publisher@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com
    
    gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
        --member serviceAccount:$AZURE_PIPELINES_PUBLISHER \
        --role roles/storage.admin
    
  7. Genera una clave de cuenta de servicio:

    gcloud iam service-accounts keys create azure-pipelines-publisher.json \
        --iam-account $AZURE_PIPELINES_PUBLISHER
    
    tr -d '\n' < azure-pipelines-publisher.json > azure-pipelines-publisher-oneline.json
    
  8. Visualiza el contenido del archivo de claves de la cuenta de servicio:

    echo $(<azure-pipelines-publisher-oneline.json)
    

    Necesitas la clave de la cuenta de servicio en uno de los siguientes pasos.

Crea una conexión de servicio para Container Registry de Google

En Azure Pipelines, crea una conexión de servicio nueva para Container Registry:

  1. En el menú de Azure DevOps, selecciona Configuración del proyecto y, luego, selecciona Canalizaciones > Conexiones de servicio.
  2. Haz clic en Crear conexión de servicio.
  3. En la lista, selecciona Registro de Docker y, luego, haz clic en Siguiente.
  4. En el diálogo, ingresa valores para los siguientes campos:
    • Tipo de registro: Otros
    • Registro de Docker: https://gcr.io/PROJECT_ID, y reemplaza PROJECT_ID por el nombre de tu proyecto (por ejemplo, https://gcr.io/azure-pipelines-test-project-12345)
    • ID de Docker: _json_key
    • Contraseña: Pega el contenido de azure-pipelines-publisher-oneline.json
    • Nombre de conexión del servicio: gcr-tutorial
  5. Haz clic en Guardar para crear la conexión.

Compila de forma continua

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

El repositorio ya contiene el siguiente Dockerfile:

.NET/Linux

#
# 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"]

.NET Framework/Windows

#
# 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"]

Ahora, debes crear una canalización nueva que use la sintaxis YAML:

  1. Mediante Visual Studio o un cliente git de línea de comandos, clona el repositorio de Git nuevo y revisa la rama main.
  2. En la raíz del repositorio, crea un archivo llamado azure-pipelines.yml.
  3. Copia el siguiente código en el archivo:

    .NET/Linux

    resources:
    - repo: self
      fetchDepth: 1
    pool:
      vmImage: ubuntu-20.04
    trigger:
    - main
    variables:
      TargetFramework: 'net6.0'
      BuildConfiguration: 'Release'
      DockerImageName: 'PROJECT_ID/clouddemo'
    steps:
    - task: DotNetCoreCLI@2
      displayName: Publish
      inputs:
        projects: 'applications/clouddemo/netcore/CloudDemo.MvcCore.sln'
        publishWebProjects: false
        command: publish
        arguments: '--configuration $(BuildConfiguration) --framework=$(TargetFramework)'
        zipAfterPublish: false
        modifyOutputPath: false
    - task: CmdLine@1
      displayName: 'Lock image version in deployment.yaml'
      inputs:
        filename: /bin/bash
        arguments: '-c "awk ''{gsub(\"CLOUDDEMO_IMAGE\", \"gcr.io/$(DockerImageName):$(Build.BuildId)\", $0); print}'' applications/clouddemo/netcore/deployment.yaml > $(build.artifactstagingdirectory)/deployment.yaml"'
    - task: PublishBuildArtifacts@1
      displayName: 'Publish Artifact'
      inputs:
        PathtoPublish: '$(build.artifactstagingdirectory)'
    - task: Docker@2
      displayName: 'Login to Container Registry'
      inputs:
        command: login
        containerRegistry: 'gcr-tutorial'
    - task: Docker@2
      displayName: 'Build and push image'
      inputs:
        Dockerfile: 'applications/clouddemo/netcore/Dockerfile'
        command: buildAndPush
        repository: '$(DockerImageName)'
    

    .NET Framework/Windows

    resources:
    - repo: self
      fetchDepth: 1
    pool:
      vmImage: windows-2019     # Matches WINDOWS_LTSC in GKE
      demands:
      - msbuild
      - visualstudio
    trigger:
    - master
    variables:
      Solution: 'applications/clouddemo/net4/CloudDemo.Mvc.sln'
      BuildPlatform: 'Any CPU'
      BuildConfiguration: 'Release'
      DockerImageName: 'PROJECT_ID/clouddemo'
    steps:
    - task: NuGetCommand@2
      displayName: 'NuGet restore'
      inputs:
        restoreSolution: '$(Solution)'
    - task: VSBuild@1
      displayName: 'Build solution'
      inputs:
        solution: '$(Solution)'
        msbuildArgs: '/p:DeployOnBuild=true /p:PublishProfile=FolderProfile'
        platform: '$(BuildPlatform)'
        configuration: '$(BuildConfiguration)'
    - task: PowerShell@2
      displayName: 'Lock image version in deployment.yaml'
      inputs:
        targetType: 'inline'
        script: '(Get-Content applications\clouddemo\net4\deployment.yaml) -replace "CLOUDDEMO_IMAGE","gcr.io/$(DockerImageName):$(Build.BuildId)" | Out-File -Encoding ASCII $(build.artifactstagingdirectory)\deployment.yaml'
    - task: PublishBuildArtifacts@1
      displayName: 'Publish Artifact'
      inputs:
        PathtoPublish: '$(build.artifactstagingdirectory)'
    - task: Docker@2
      displayName: 'Login to Container Registry'
      inputs:
        command: login
        containerRegistry: 'gcr-tutorial'
    - task: Docker@2
      displayName: 'Build and push image'
      inputs:
        Dockerfile: 'applications/clouddemo/net4/Dockerfile'
        command: buildAndPush
        repository: '$(DockerImageName)'
    
    

    Reemplaza PROJECT_ID por el nombre del proyecto y, luego, guarda el archivo.

  4. Confirma los cambios y envíalos a Azure Pipelines.

    Visual Studio

    1. Abre Team Explorer y haz clic en el ícono de página principal.
    2. Haz clic en Cambios.
    3. Ingresa un mensaje de confirmación, como Add pipeline definition.
    4. Haz clic en Confirmar todo y enviar.

    Línea de comandos

    1. Almacena en etapa intermedia todos los archivos modificados:

      git add -A
      
    2. Confirma los cambios en el repositorio local:

      git commit -m "Add pipeline definition"
      
    3. Envía los cambios a Azure DevOps:

      git push
      
  5. En el menú de Azure DevOps, selecciona Canalizaciones y, luego, haz clic en Crear canalización.

  6. Selecciona Azure Repos Git.

  7. Selecciona tu repositorio.

  8. En la página Revisar la canalización de YAML, haz clic en Ejecutar.

    Se activará una compilación nueva. Es posible que la compilación tarde alrededor de 6 minutos en completarse.

  9. Para verificar que la imagen se publicó en Container Registry, cambia al proyecto en la consola de Google Cloud y selecciona Container Registry > Imágenes y, luego, haz clic en clouddemo.

    Se muestra una sola imagen y su etiqueta. La etiqueta corresponde al ID numérico de la compilación que se ejecutó en Azure Pipelines.

Implementa de forma continua

Debido a que Azure Pipelines compila el código de forma automática y publica las imágenes de Docker de cada confirmación, ahora puedes enfocarte en la implementación.

A diferencia de otros sistemas de integración continua, Azure Pipelines distingue entre la implementación y la compilación, y ofrece un conjunto especializado de herramientas etiquetadas como Administración de versiones para todas las tareas relacionadas con la implementación.

La Administración de versiones de Azure Pipelines se basa en los siguientes conceptos:

  • El término versión hace referencia a un conjunto de artefactos que conforman una versión específica de la app y que, por lo general, son el resultado de un proceso de compilación.
  • La implementación se refiere al proceso de tomar una actualización e implementarla en un entorno específico.
  • Una implementación realiza un conjunto de tareas, que se pueden agrupar en trabajos.
  • Las etapas te permiten segmentar la canalización y se pueden usar para organizar implementaciones en varios entornos, por ejemplo, entornos de desarrollo y prueba.

El artefacto principal que produce el proceso de compilación de CloudDemo es la imagen de Docker. Sin embargo, debido a que la imagen de Docker se publica en Container Registry, la imagen está fuera del alcance de Azure Pipelines. Por ende, la imagen no funciona bien como definición de una versión.

Para implementar en Kubernetes, también necesitas un manifiesto, que se parece a una factura de materiales. El manifiesto no solamente define los recursos que se supone que Kubernetes creará y administrará, sino que, además, especifica la versión exacta de la imagen de Docker que se utilizará. El manifiesto de Kubernetes es adecuado para funcionar como el artefacto que define la versión en la Administración de versiones de Azure Pipelines.

Configura la implementación de Kubernetes

Para ejecutar CloudDemo en Kubernetes, necesitarás los siguientes recursos:

  • Una implementación que defina un solo pod que ejecute la imagen de Docker producida por la compilación
  • Un servicio NodePort que vuelve al pod accesible para el balanceador de cargas
  • Un Ingress que exponga la aplicación a la Internet pública mediante un balanceador de cargas de HTTP(S) de Cloud

El repositorio ya contiene el siguiente manifiesto de Kubernetes que define estos recursos:

.NET/Linux

#
# 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

.NET Framework/Windows

#
# 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

Configura los entornos de desarrollo y producción

Antes de volver a la Administración de versiones de Azure Pipelines, deberás crear el clúster de GKE.

Crea clústeres de GKE

  1. Regresa a tu instancia de Cloud Shell.

  2. Habilita la API de GKE para tu proyecto:

    gcloud services enable container.googleapis.com
  3. Crea el clúster de desarrollo; para ello, utiliza el siguiente comando. Ten en cuenta que puede tardar unos minutos en completarse:

    .NET/Linux

    gcloud container clusters create azure-pipelines-cicd-dev --enable-ip-alias
    

    .NET Framework/Windows

    gcloud container clusters create azure-pipelines-cicd-dev --enable-ip-alias
    
    gcloud container node-pools create azure-pipelines-cicd-dev-win \
        --cluster=azure-pipelines-cicd-dev \
        --image-type=WINDOWS_LTSC \
        --no-enable-autoupgrade \
        --machine-type=n1-standard-2
    
  4. Crea el clúster de producción mediante el siguiente comando. Ten en cuenta que puede tomar unos minutos en completarse:

    .NET/Linux

    gcloud container clusters create azure-pipelines-cicd-prod --enable-ip-alias
    

    .NET Framework/Windows

    gcloud container clusters create azure-pipelines-cicd-prod --enable-ip-alias
    
    gcloud container node-pools create azure-pipelines-cicd-prod-win \
        --cluster=azure-pipelines-cicd-prod \
        --image-type=WINDOWS_LTSC \
        --no-enable-autoupgrade \
        --machine-type=n1-standard-2
    

Conecta Azure Pipelines al clúster de desarrollo

Así como puedes usar Azure Pipelines para conectarte a un registro externo de Docker, como Container Registry, Azure Pipelines admite la integración de clústeres de Kubernetes externos.

Es posible autenticarse en Container Registry mediante una cuenta de servicio de Google Cloud, pero Azure Pipelines no admite el uso de cuentas de servicio de Google Cloud para la autenticación con GKE. En su lugar, debes usar una cuenta de servicio de Kubernetes.

Por lo tanto, para conectar Azure Pipelines al clúster de desarrollo, primero debes crear una cuenta de servicio de Kubernetes.

  1. En Cloud Shell, conéctate al clúster de desarrollo:

    gcloud container clusters get-credentials azure-pipelines-cicd-dev
  2. Crea una cuenta de servicio de Kubernetes para Azure Pipelines:

    kubectl create serviceaccount azure-pipelines-deploy
  3. Crea un Secret de Kubernetes que contenga una credencial de token para Azure Pipelines:

    kubectl create secret generic azure-pipelines-deploy-token --type=kubernetes.io/service-account-token --dry-run -o yaml \
      | kubectl annotate --local -o yaml -f - kubernetes.io/service-account.name=azure-pipelines-deploy \
      | kubectl apply -f -
    
  4. Asigna la función cluster-admin a la cuenta de servicio mediante la creación de una vinculación de función de clúster:

    kubectl create clusterrolebinding azure-pipelines-deploy --clusterrole=cluster-admin --serviceaccount=default:azure-pipelines-deploy
  5. Define la dirección IP del clúster:

    gcloud container clusters describe azure-pipelines-cicd-dev --format=value\(endpoint\)
    

    Necesitarás esta dirección en un momento.

  6. En el menú de Azure DevOps, selecciona Configuración del proyecto y, luego, Canalizaciones > Conexiones de servicio.

  7. Haz clic en Nueva conexión de servicio.

  8. Selecciona Kubernetes y haz clic en Siguiente.

  9. Establece la siguiente configuración:

    • Método de autenticación: Cuenta de servicio
    • URL del servidor: https://PRIMARY_IP. Reemplaza PRIMARY_IP por la dirección IP que definiste antes.
    • Secret: El Secret de Kubernetes que creaste antes. Para obtener el Secret, ejecuta el siguiente comando, copia el Secret y, luego, cópialo en la página de Azure.
      kubectl get secret azure-pipelines-deploy-token -o yaml
    • Nombre de la conexión de servicio: azure-pipelines-cicd-dev
  10. Haz clic en Guardar.

Conecta Azure Pipelines al clúster de producción

Para conectar Azure Pipelines al clúster de producción, puedes seguir el mismo enfoque.

  1. En Cloud Shell, conéctate al clúster de producción:

    gcloud container clusters get-credentials azure-pipelines-cicd-prod
  2. Crea una cuenta de servicio de Kubernetes para Azure Pipelines:

    kubectl create serviceaccount azure-pipelines-deploy
  3. Asigna la función cluster-admin a la cuenta de servicio mediante la creación de una vinculación de función de clúster:

    kubectl create clusterrolebinding azure-pipelines-deploy --clusterrole=cluster-admin --serviceaccount=default:azure-pipelines-deploy
  4. Define la dirección IP del clúster:

    gcloud container clusters describe azure-pipelines-cicd-prod --format=value\(endpoint\)
    

    Necesitarás esta dirección en un momento.

  5. En el menú de Azure DevOps, selecciona Configuración del proyecto y, luego, Canalizaciones > Conexiones de servicio.

  6. Haz clic en Nueva conexión de servicio.

  7. Selecciona Kubernetes y haz clic en Siguiente.

  8. Establece la siguiente configuración:

    • Método de autenticación: Cuenta de servicio
    • URL del servidor: https://PRIMARY_IP. Reemplaza PRIMARY_IP por la dirección IP que definiste antes.
    • Secreto: Ejecuta el siguiente comando en Cloud Shell y copia el resultado:
      kubectl get secret $(kubectl get serviceaccounts azure-pipelines-deploy -o custom-columns=":secrets[0].name") -o yaml
    • Nombre de la conexión de servicio: azure-pipelines-cicd-prod.
  9. Haz clic en Guardar.

Configura la canalización de la versión

Después de configurar la infraestructura de GKE, vuelve a Azure Pipelines para automatizar la implementación, lo que incluye las siguientes acciones:

  • Implementar en el entorno de desarrollo
  • Solicitar aprobación manual antes de iniciar una implementación en el entorno de producción
  • Implementar en el entorno de producción

Crea una definición de la versión

Como primer paso, crea una nueva definición de la versión.

  1. En el menú de Azure DevOps, selecciona Canalizaciones > Versiones.
  2. Haz clic en Nueva canalización.
  3. En la lista de plantillas, selecciona Trabajo vacío.
  4. Cuando se te solicite un nombre para la etapa, ingresa Development.
  5. En la parte superior de la pantalla, nombra la versión CloudDemo-KubernetesEngine.
  6. En el diagrama de la canalización, junto a Artifacts (Artefactos), haz clic en Add (Agregar).
  7. Selecciona Compilar y agrega la siguiente configuración:

    • Tipo de origen: Compilación
    • Origen (canalización de compilación): Selecciona la definición de compilación (solo debe haber una opción)
    • Versión predeterminada: Latest
    • Alias de origen: manifest
  8. Haga clic en Agregar.

  9. En el cuadro Artefacto, haz clic en el ícono del rayo Desencadenador de implementación continua para agregar un desencadenador de implementación.

  10. En Desencadenador de implementación continua, establece la opción como Habilitado.

  11. Haz clic en Guardar.

  12. Si lo deseas, ingresa un comentario y, luego, haz clic en Aceptar para confirmar.

    La canalización se muestra de la siguiente manera.

    Captura de pantalla de la canalización actualizada en Azure Pipelines

Implementa en el clúster de desarrollo

Una vez que creaste la definición de la versión, puedes configurar la implementación en el clúster de desarrollo de GKE.

  1. En el menú, cambia a la pestaña Tareas.
  2. Haz clic en Trabajo de agente y establece la siguiente configuración:

    • Grupo de agentes: Azure Pipelines
    • Especificación del agente: ubuntu-18.04
  3. Junto a Trabajo de agente, haz clic en Add a task to agent job para agregar un paso a la fase.

  4. Selecciona la tarea Implementar en Kubernetes y haz clic en Agregar.

  5. Haz clic en la tarea recién agregada y establece la siguiente configuración:

    • Nombre visible: Deploy
    • Acción: implementar
    • Conexión de servicio de Kubernetes: azure-pipelines-cicd-dev
    • Espacio de nombres: default
    • Estrategia: ninguna
    • Manifiestos: manifest/drop/deployment.yaml
  6. Haz clic en Guardar.

  7. Si lo deseas, ingresa un comentario y, luego, haz clic en Aceptar para confirmar.

Implementa en el clúster de producción

Por último, configura la implementación en el clúster de producción de GKE.

  1. En el menú, pasa a la pestaña Canalización.
  2. En la casilla Etapas, selecciona Agregar > Nueva etapa.
  3. En la lista de plantillas, selecciona Trabajo vacío.
  4. Cuando se te solicite un nombre para la etapa, ingresa Production.
  5. Haz clic en el ícono del rayo de la etapa recién creada.
  6. Establece la siguiente configuración:

    • Seleccionar activador: After stage
    • Etapas: Dev
    • Aprobaciones previas a la implementación: (habilitadas)
    • Responsables de aprobación: Selecciona tu propio nombre de usuario.

    La canalización ahora se ve de la siguiente manera:

    Captura de pantalla de la canalización actualizada en Azure Pipelines

  7. Pasa a la pestaña Tareas.

  8. Mantén el mouse sobre la pestaña Tareas y selecciona Tareas > Producción

  9. Haz clic en Trabajo de agente y establece la siguiente configuración:

    • Grupo de agentes: Azure Pipelines
    • Especificación del agente: ubuntu-18.04
  10. Haz clic en Add a task to agent job para agregar un paso a la fase.

  11. Selecciona la tarea Implementar en Kubernetes y haz clic en Agregar.

  12. Haz clic en la tarea recién agregada y establece la siguiente configuración:

    • Nombre visible: Deploy
    • Acción: implementar
    • Conexión de servicio de Kubernetes: azure-pipelines-cicd-prod
    • Espacio de nombres: default
    • Estrategia: ninguna
    • Manifiestos: manifest/drop/deployment.yaml
  13. Haz clic en Guardar.

  14. Si lo deseas, ingresa un comentario y, luego, haz clic en Aceptar para confirmar.

Ejecuta la canalización

Ahora que configuraste toda la canalización, realiza un cambio en el código fuente para probarla:

  1. En tu computadora local, abre el archivo Index.cshtml desde el repositorio de Git que clonaste antes:

    .NET/Linux

    El archivo se encuentra en applications\clouddemo\netcore\CloudDemo.MvcCore\Views\Home\

    .NET Framework/Windows

    El archivo se encuentra en applications\clouddemo\net4\CloudDemo.Mvc\Views\Home\

  2. En la línea 26, cambia el valor de ViewBag.Title de Home Page a This app runs on GKE.

  3. Confirma tus cambios y envíalos a Azure Pipelines.

    Visual Studio

    1. Abre Team Explorer y haz clic en el ícono de página principal.
    2. Haz clic en Cambios.
    3. Ingresa un mensaje de confirmación, como Change site title.
    4. Haz clic en Confirmar todo y enviar.

    Línea de comandos

    1. Almacena en etapa intermedia todos los archivos modificados:

      git add -A
      
    2. Confirma los cambios en el repositorio local:

      git commit -m "Change site title"
      
    3. Envía los cambios a Azure Pipelines:

      git push
      
  4. En el menú de Azure DevOps, selecciona Canalizaciones. Se activará una compilación.

  5. Cuando se complete la compilación, selecciona Canalizaciones > Versiones. Se iniciará un proceso de actualización.

  6. Haz clic en Release-1 para abrir la página de detalles y espera a que el estado de la etapa de Desarrollo cambie a Finalizado.

  7. En la consola de Google Cloud, selecciona Kubernetes Engine > Ingress y servicios > Ingress.

  8. Ubica el servicio de Ingress del clúster azure-pipelines-cicd-dev y espera a que su estado cambie a Correcto. Esto podría llevar varios minutos.

  9. Abre el vínculo en la columna Frontends de la misma fila. Es posible que al principio te encuentres con un error debido a que el balanceador de cargas tarda unos minutos en estar disponible. Cuando esté listo, verás que CloudDemo se implementó y usa el título personalizado.

  10. En Azure Pipelines, haz clic en el botón Aprobar (Approve) ubicado en la etapa de Producción (Prod) para promover la implementación en el entorno de producción.

    Si no ves el botón, es posible que primero debas aprobar o rechazar una versión anterior.

  11. Si lo deseas, ingresa un comentario y, luego, haz clic en Aprobar (Approve) para confirmarlo.

  12. Espera a que el estado del entorno Prod cambie a Succeeded (Correcto). Es posible que tengas que actualizar de forma manual la página en tu navegador.

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

  14. Ubica el servicio de Ingress del clúster azure-pipelines-cicd-prod y espera a que su estado cambie a Correcto. Esto podría llevar varios minutos.

  15. Abre el vínculo en la columna Frontends de la misma fila. De nuevo, es posible que al principio te encuentres con un error, debido a que el balanceador de cargas tarda unos minutos en estar disponible. Cuando esté listo, verás la aplicación de CloudDemo con el título personalizado, pero esta vez se estará ejecutando en el clúster de producción.

Limpia

Para evitar que se generen más costos después de completar este instructivo, borra las entidades que creaste.

Borra el proyecto de Azure Pipelines

Para borrar el proyecto de Azure Pipelines, consulta la documentación de servicios de Azure DevOps. Si borras el proyecto de Azure Pipelines, se perderán todos los cambios del código fuente.

Borra el desarrollo y los proyectos de Google Cloud

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

¿Qué sigue?