Ejercicio: Implementación de una solución de varios contenedores en un clúster de Kubernetes
La canalización de versión que se proporciona con el proyecto está diseñada para compilar la solución como contenedor de Docker e implementarla en Azure App Service. Para admitir la implementación de varios contenedores en un clúster de Kubernetes, debe modificar esta canalización.
En esta unidad aprenderá a:
- Actualizar la canalización para desencadenar al confirmar en la rama principal.
- Definición de las variables que se van a compartir en la canalización.
- Compile y publique imágenes de Docker.
- Publicar manifiestos de Kubernetes.
- Agregar una tarea para crear un secreto de extracción de imágenes a fin de usarlo entre las instancias de Kubernetes y las del registro de contenedor
- Implementar imágenes actualizadas en un clúster de Kubernetes.
Actualización de la canalización para admitir desencadenadores
Inicie sesión en su organización de Azure DevOps y vaya a su proyecto.
Seleccione Canalizaciones y elija la canalización.
Seleccione Editar para editar azure-pipelines.yml.
Andy: Esta era la fase de compilación que teníamos para la solución anterior de un solo contenedor. Sabía que no se iba a ejecutar correctamente, así que la deshabilité. Podemos empezar por volver a habilitar desencadenadores para las confirmaciones en la rama
main
.Reemplace la línea
trigger
existente en la parte superior del archivo por el siguiente fragmento de código. Esto desencadena una ejecución de canalización cada vez que se realiza una confirmación en la rama principal.trigger: - 'main'
Definición de variables accesibles en la canalización
Andy: Va a ser necesario agregar dos variables de canalización. Uno para especificar el nombre del repositorio de tabla de clasificación, que es tabla de clasificación. El otro es para el nombre del secreto de extracción de imágenes que se usa para compartir entre instancias de AKS y ACR durante la implementación.
Agregue el siguiente código resaltado a la sección
variables
.variables: buildConfiguration: 'Release' leaderboardRepository: 'leaderboard' webRepository: 'web' tag: '$(Build.BuildId)' imagePullSecret: 'secret'
Compilación y publicación de la imagen de Docker en Azure Container Registry
Andy: Ya tenemos una tarea para compilar la aplicación web como contenedor de Docker, que publicamos en nuestro registro de contenedor. Podemos simplemente usar una segunda tarea para hacer lo mismo con la tabla de clasificación.
Agregue una segunda tarea
Docker@2
que compile y publique el contenedor de tablas de clasificación con el fragmento de código resaltado a continuación. Agregue esta tarea después de la tarea del contenedor web.- task: Docker@2 displayName: 'Build and push the web image to container registry' inputs: command: buildAndPush buildContext: $(Build.Repository.LocalPath) repository: $(webRepository) dockerfile: '$(Build.SourcesDirectory)/Tailspin.SpaceGame.Web/Dockerfile' containerRegistry: 'Container Registry Connection' tags: | $(tag) - task: Docker@2 displayName: 'Build and push the leaderboard image to container registry' inputs: command: buildAndPush buildContext: $(Build.Repository.LocalPath) repository: $(leaderboardRepository) dockerfile: '$(Build.SourcesDirectory)/Tailspin.SpaceGame.LeaderboardContainer/Dockerfile' containerRegistry: 'Container Registry Connection' tags: | $(tag)
Sugerencia
Asegúrese de que la tarea que agregue aquí usa sangría coherente con la tarea anterior, ya que el espacio en blanco es importante en un archivo YAML.
Publicación de los manifiestos de Kubernetes
Andy: Creo que podemos pasar a la fase siguiente. ¿Creéis que falta algo?
Mara: mencionó que había algunos archivos de manifiesto en el proyecto de código fuente que definen la implementación y los servicios que Kubernetes necesitará en la implementación. Deberíamos publicarlos antes de finalizar esta fase.
Andy: ¿Por qué? ¿No estarán de todas formas en el disco local?
Mara: Lo estarían si agregáramos las tareas de implementación en la misma fase que la compilación. Sin embargo, como nuestras tareas de implementación tienen lugar en una fase Implementación propia, se ejecuta en un entorno nuevo, incluso es probable que en un agente distinto. Debemos asegurarnos de publicar cualquier cosa que esta fase genere que la otra fase necesite.
Andy: Buena observación. ¿Es fácil de hacer? Solo hay que asegurarse de que la carpeta manifests se copie en el nuevo agente.
Mara: Para eso está la tarea PublishBuildArtifacts@1
. Es tan común que incluso tiene una forma abreviada, publish
.
Agregue una tarea
publish
que almacene la carpeta manifests para una fase futura, como se muestra a continuación. Asegúrese de que la sangría de esta tarea coincide con la de la tarea anterior.- task: Docker@2 displayName: 'Build and push the leaderboard image to container registry' inputs: command: buildAndPush buildContext: $(Build.Repository.LocalPath) repository: $(leaderboardRepository) dockerfile: '$(Build.SourcesDirectory)/Tailspin.SpaceGame.LeaderboardContainer/Dockerfile' containerRegistry: 'Container Registry Connection' tags: | $(tag) - publish: '$(Build.SourcesDirectory)/manifests' artifact: manifests
Reemplazo de la fase de implementación
Mara: Voy a reemplazar la fase Implementación existente por una que use un trabajo de implementación. Un trabajo de implementación es un tipo de trabajo especial que nos permite asociar nuestra implementación con el entorno de Azure DevOps creado anteriormente. Esto facilita el seguimiento del historial de implementación, lo que será especialmente útil a medida que nuestras soluciones se vuelvan más sofisticadas.
Quite la fase Implementación existente (todo lo que aparece después de la fase de compilación) y reemplácela por el siguiente fragmento de código. Tome nota de la línea resaltada que indica el entorno de implementación que se va a usar.
- stage: 'Deploy' displayName: 'Deploy the containers' dependsOn: Build jobs: - deployment: Deploy displayName: Deploy pool: vmImage: 'ubuntu-20.04' environment: 'Dev' variables: - group: Release strategy: runOnce: deploy: steps:
Mara: El primer paso que agregaremos en la fase de implementación consiste en descargar los artefactos de manifiesto publicados anteriormente mediante la tarea
DownloadBuildArtifacts@0
.Andy: A ver si adivino: ¿existe la forma abreviada
download
para esa tarea?Mara: ¡Efectivamente! Podemos usar el especificador
current
para indicar que queremos el artefacto de la ejecución actual de la canalización.Agregue las líneas resaltadas como primer paso de la fase Implementación.
- stage: 'Deploy' displayName: 'Deploy the containers' dependsOn: Build jobs: - deployment: Deploy displayName: Deploy pool: vmImage: 'ubuntu-20.04' environment: 'spike.default' variables: - group: Release strategy: runOnce: deploy: steps: - download: current artifact: manifests
Andy: Ahora tenemos que crear un secreto de extracción de imágenes que se compartirá entre nuestras instancias de ACR y AKS. ¿Hay alguna una tarea que podamos usar?
Mara: Lo estaba mirando ahora mismo y estamos de suerte. La tarea
KubernetesManifest@0
admite una acción para crear el secreto necesario.
Tarea de manifiesto de Kubernetes
La tarea del manifiesto de Kubernetes está diseñada para administrar todas las operaciones de implementación estándar necesarias para Kubernetes. Admite varias opciones de action
que van desde la creación de secretos hasta la implementación de imágenes. En este caso, se usa la acción createSecret
, junto con los siguientes parámetros:
action
indica la característica que se va a ejecutar. En este caso,createSecret
crea el secreto compartido.connectionType
especifica el tipo de conexión de servicio que se va a usar. Opciones: azureResourceManager o kubernetesServiceConnection.secretName
especifica el nombre del secreto que se va a crear.dockerRegistryEndpoint
especifica el nombre de la conexión de Azure Container Registry Services.azureSubscriptionConnection
especifica el nombre de la conexión de servicios ARM.azureResourceGroup
especifica el nombre del grupo de recursos.kubernetesCluster
especifica el nombre del clúster de AKS.namespace
especifica el espacio de nombres de Kubernetes al que se aplica esta acción.
Agregue el fragmento de código siguiente al final de la canalización. Asegúrese de que tanto el nombre del grupo de recursos como el nombre del clúster coinciden con los nombres de los que creó anteriormente. Asegúrese de que la sangría de esta tarea coincide con la de la tarea de descarga.
- task: KubernetesManifest@1 displayName: Create imagePullSecret inputs: action: createSecret connectionType: azureResourceManager secretName: $(imagePullSecret) dockerRegistryEndpoint: 'Container Registry Connection' azureSubscriptionConnection: 'Kubernetes Cluster Connection' azureResourceGroup: 'tailspin-space-game-rg' kubernetesCluster: 'tailspinspacegame-24591' namespace: 'default'
Andy: El paso final consiste en desencadenar la implementación de nuestras imágenes en el clúster de Kubernetes. Según la documentación, parece que podemos usar la misma tarea, pero con una acción y parámetros diferentes.
action
indica la característica que se va a ejecutar. En este caso,deploy
para implementar en el clúster de AKS.connectionType
especifica el tipo de conexión de servicio que se va a usar. Opciones: azureResourceManager o kubernetesServiceConnection.azureSubscriptionConnection
especifica el nombre de la conexión de servicios ARM.azureResourceGroup
especifica el nombre del grupo de recursos.kubernetesCluster
especifica el nombre del clúster de AKS.namespace
especifica el espacio de nombres de Kubernetes al que se aplica esta acción.imagePullSecrets
especifica la lista de secretos necesarios para extraer del registro de contenedor.containers
especifica la lista de imágenes del contenedor para implementar.
Agregue el fragmento de código siguiente al final de la canalización. Asegúrese de que tanto el nombre del grupo de recursos como el nombre del clúster coinciden con los nombres de los que creó anteriormente. Asegúrese de que la sangría de esta tarea coincide con la de la tarea anterior.
- task: KubernetesManifest@1 displayName: Deploy to Kubernetes cluster inputs: action: deploy connectionType: azureResourceManager azureSubscriptionConnection: 'Kubernetes Cluster Connection' azureResourceGroup: 'tailspin-space-game-rg' kubernetesCluster: 'tailspinspacegame-24591' namespace: 'default' manifests: | $(Pipeline.Workspace)/manifests/deployment.yml $(Pipeline.Workspace)/manifests/service.yml imagePullSecrets: | $(imagePullSecret) containers: | $(RegistryName)/$(webRepository):$(tag) $(RegistryName)/$(leaderboardRepository):$(tag)
Ejecución de la canalización
Seleccione Guardar en la esquina superior derecha de la página. Seleccione Guardar para confirmar el mensaje de confirmación.
Seleccione Ejecutar, confirme el nombre de la rama y, a continuación, seleccione Ejecutar para desencadenar una ejecución de canalización.
Seleccione Canalizaciones y, a continuación, seleccione la canalización para ver los registros a medida que se ejecuta la canalización.
Después de completar la ejecución de la canalización, seleccione Entornos en el panel izquierdo y, a continuación, seleccione el entorno de desarrollo para ver los trabajos de implementación.
Consultemos nuestra aplicación web implementada y el punto de conexión de API. Para ello, debemos obtener las direcciones IP externas para los servicios web y de tabla de clasificación.
Vaya a Azure Portal, seleccione el clúster de AKS y, a continuación, seleccione Servicios y entradas.
Seleccione la dirección IP externa del servicio web para ver el sitio en AKS.
Regrese a la ventana de Azure Portal donde se quedó y, a continuación, copie la dirección IP externa del servicio de tabla de clasificación. Esta dirección IP es la ubicación en la que se hospeda la API de la tabla de clasificación de forma pública.
Reemplace el marcador de posición en el siguiente vínculo por la dirección IP externa que copió. También puede agregar un parámetro de consulta
pageSize=10
para facilitar la visualización de la respuesta de JSON en el explorador. Use una dirección URL como la siguiente en una nueva pestaña del explorador.http://[IP]/api/Leaderboard?pageSize=10
Aparecerá la respuesta de JSON sin formato de la API de tablas de clasificación hospedada en el clúster de AKS. Ahora tiene una API REST a la que puede llamar desde otras aplicaciones.
Andy: ¡Ha salido muy bien! Creo que el uso de Kubernetes es una manera excelente de adoptar una estrategia de microservicios más amplia.