CI / CD sin servidor en AWS



Sería genial si la implementación de copiar y pegar fuera cosa del pasado, pero, por desgracia, las cosas son diferentes. Sucede que los desarrolladores prefieren tal método de entrega. Aunque ahora escriba un artículo sobre por qué esto no está zumbando, pero usted sabe todo sin mí. Con una tendencia hacia la arquitectura sin servidor, las canalizaciones de CI / CD juegan un papel importante en la entrega de aplicaciones. También escribí sobre ellos en el artículo " 3 mejores consejos para su próximo proyecto sin servidor ".


Hace mucho tiempo que he estado interesado en el tema de CI y CD, y por primera vez lo encontré hace varios años, gracias a TeamCity. Actualmente, TeamCity todavía se utiliza para la mayoría de nuestras canalizaciones de CI / CD. TeamCity funciona muy bien, no tengo nada en contra, pero siempre me esfuerzo por mejorar el trabajo. Por ejemplo, sería bueno recopilar canalizaciones en forma de código; esta es una de las áreas en las que TeamCity no es tan bueno.


Aprendí las herramientas de integración y entrega en AWS hace algún tiempo, y aunque usamos CodeDeploy para otro proyecto que funciona en EC2, todavía no he implementado un proyecto sin servidor con ellos. Después de revisar las herramientas nuevamente, me di cuenta de esto: ahora hay una función de integración incorporada para implementar CloudFormation y Lambda, presumiblemente basada en SAM AWS; utilizamos el marco sin servidor : genera plantillas de CloudFormation, pero no funciona de forma inmediata con las herramientas de AWS.


Preparación


Utilizo los siguientes servicios de AWS: EC2, Docker, ECR, S3, IAM, CodeBuild, CodePipeline, CloudWatch, CloudTrail. Para mantenerse al día, debe comprender, al menos en un nivel básico, lo que hace cada uno de estos servicios.


Básicamente, escribo el código del lado del servidor en .NET, y esta guía también se basa en esta plataforma. Ninguna de las imágenes de CodeBuild precompiladas tiene un tiempo de ejecución .NET y NodeJS al mismo tiempo (NodeJS es necesario para el marco sin servidor). Si sus funciones Lambda están escritas en NodeJS, la configuración de la canalización de implementación es mucho más simple, ya que este es el único entorno de tiempo de ejecución requerido para la instalación en una imagen Docker (si es su caso, no dude en omitir la mayor parte del manual). Por un segundo, esta fue mi primera experiencia con contenedores, y estoy feliz de aprender algo nuevo.


Me atrevo a suponer que su código está en un determinado repositorio, por ejemplo, git. Para orientación, simplemente cargamos a S3 un archivo que contiene un paquete de código para su implementación; cómo lo consigues depende de ti. Tomando mi trabajo como base, siempre puedes ir más allá conectando tu canalización a repositorios como github o CodeCommit.


1. Cree una instancia EC2 e instale Docker


Ejecute una instancia estándar de AWS Linux 2 EC2; esto debería quedar claro sin explicación. Inicie sesión e instale Docker con los comandos:


sudo yum update -y sudo amazon-linux-extras install docker sudo service docker start 

También debe agregar el usuario ec2 al grupo de docker para ejecutar los comandos de Docker sin usar sudo:


 sudo usermod -a -G docker ec2-user 

Cuando se complete el comando, cierre la sesión y vuelva a iniciar sesión en su instancia EC2 para que el usuario ec2 reciba nuevos permisos. Asegúrese de que el usuario ec2 ejecute los comandos de Docker sin sudo:


 docker info 


Salida del docker info


2. Cree una imagen de Docker y colóquela en ECR


Supongamos que el paso anterior es exitoso; El siguiente paso es crear una imagen Docker que se ajuste a la ECR. AWS ofrece imágenes básicas para CodeBuild en github , y esto facilita la creación de su propia imagen.


También publiqué la imagen en github, en caso de que no quiera seguir estos pasos para crear la suya propia: https://github.com/effectivedigital/serverless-deployment-image


Copie las imágenes y vaya al directorio .NET Core 2.1:


 git clone https://github.com/aws/aws-codebuild-docker-images.git cd aws-codebuild-docker-images cd ubuntu/dot-net/core-2.1/ 

Abra Dockerfile en su editor de texto preferido:


 nano Dockerfile 

Agregue los comandos para instalar NodeJS y el marco sin servidor al final de otros comandos ya disponibles en el Dockerfile. Obtuve la mayoría de estos comandos de una imagen NodeJS Docker en el mismo repositorio de AWS:


 # Install Node Dependencies ENV NODE_VERSION="10.14.1" # gpg keys listed at https://github.com/nodejs/node#release-team RUN set -ex \ && for key in \ 94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \ B9AE9905FFD7803F25714661B63B535A4C206CA9 \ 77984A986EBC2AA786BC0F66B01FBB92821C587A \ 56730D5401028683275BD23C23EFEFE93C4CFFFE \ 71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \ FD3A5288F042B6850C66B31F09FE44734EB7990E \ 8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600 \ C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \ DD8F2338BAE7501E3DD5AC78C273792F7D83545D \ 4ED778F539E3634C779C87C6D7062848A1AB005C \ A48C2BEE680E841632CD4E44F07496B3EB3C1762 \ ; do \ gpg - keyserver hkp://p80.pool.sks-keyservers.net:80 - recv-keys "$key" || \ gpg - keyserver hkp://ipv4.pool.sks-keyservers.net - recv-keys "$key" || \ gpg - keyserver hkp://pgp.mit.edu:80 - recv-keys "$key" ; \ done RUN set -ex \ && wget "https://nodejs.org/download/release/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz" -O node-v$NODE_VER$ && wget "https://nodejs.org/download/release/v$NODE_VERSION/SHASUMS256.txt.asc" -O SHASUMS256.txt.asc \ && gpg - batch - decrypt - output SHASUMS256.txt SHASUMS256.txt.asc \ && grep " node-v$NODE_VERSION-linux-x64.tar.gz\$" SHASUMS256.txt | sha256sum -c - \ && tar -xzf "node-v$NODE_VERSION-linux-x64.tar.gz" -C /usr/local - strip-components=1 \ && rm "node-v$NODE_VERSION-linux-x64.tar.gz" SHASUMS256.txt.asc SHASUMS256.txt \ && ln -s /usr/local/bin/node /usr/local/bin/nodejs \ && rm -fr /var/lib/apt/lists/* /tmp/* /var/tmp/* RUN npm set unsafe-perm true CMD [ "node" ] # Install Serverless Framework RUN set -ex \ && npm install -g serverless 

Ahora recopilamos y etiquetamos la imagen:


 docker build -t aws/codebuild/dot-net . 

Después de completar el ensamblaje, ejecute la imagen: asegúrese de que todo funcione y de que el marco sin servidor esté instalado correctamente:


 docker run -it --entrypoint sh aws/codebuild/dot-net -c bash sls -v 


Ejecutando sls -v dentro de un nuevo contenedor


Luego, cree el repositorio en ECR con la AWS CLI. Después de ejecutar el comando, el nuevo repositorio se mostrará en la consola de AWS:


 aws ecr create-repository --repository-name codebuild-dotnet-node 


Respuesta de AWS CLI para crear un repositorio en ECR



Ahora marque la imagen aws / codebuild / dot-net creada previamente con el valor del repositorioUri del paso anterior:


 docker tag aws/codebuild/dot-net <ACCOUNTID>.dkr.ecr.ap-southeast-2.amazonaws.com/codebuild-dotnet-node 

Ejecute el comando get-login para obtener la línea de comandos de autenticación de inicio de sesión de Docker para el registro del contenedor:


 aws ecr get-login --no-include-email 


Ejecute el comando de inicio de sesión docker emitido por el comando get-login durante el último paso.


 docker login -u AWS -p eyJwYXlsb2FkIjoiNGZnd0dSaXM1L2svWWRLMmhJT1c0WWpOZEcxamJFeFJOK2VvT0Y5[...] https://<ACCOUNTID>.dkr.ecr.ap-southeast-2.amazonaws.com 

Si el inicio de sesión es exitoso, coloque la imagen del acoplador en el repositorio creado en ECR. Esto puede tomar varios minutos (dependiendo del tamaño de la imagen completa).


 docker push <ACCOUNTID>.dkr.ecr.ap-southeast-2.amazonaws.com/codebuild-dotnet-node 


Docker en EC2 crea nuestra imagen



Imagen de Docker en ECR


Entonces podemos abrir el acceso a la imagen desde ECR a cualquier persona. El permiso debe estar bloqueado en el entorno de trabajo, pero en este ejemplo lo abriremos. Vaya a la pestaña de permisos en la consola de AWS, seleccione "Cambiar política JSON" e inserte el siguiente elemento en la política:


 { "Version": "2008-10-17", "Statement": [ { "Sid": "EnableAccountAccess", "Effect": "Allow", "Principal": "*", "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:BatchGetImage", "ecr:DescribeImages", "ecr:DescribeRepositories", "ecr:GetAuthorizationToken", "ecr:GetDownloadUrlForLayer", "ecr:GetRepositoryPolicy", "ecr:ListImages" ] } ] } 

3. Crear una tubería


Es hora de recoger la tubería. Para simplificar el proceso, hacer que sea multi-implementable y apegarse a la forma desastrosa de la arquitectura sin servidor, construí una tubería usando el marco sin servidor. Puede lograr el mismo resultado construyendo en CloudFormation.


No copiaré toda la fuente de mi archivo serverless.yml, cópielo desde github: https://github.com/effectivedigital/serverless-deployment-pipeline


Consulte la plantilla sin servidor para ver exactamente lo que hará, pero, en resumen, configura los siguientes elementos:


  • 3 segmentos S3
  • Política de 1 segmento
  • 3 roles de IAM
  • 1 proyecto CodeBuild
  • 1 código de tubería
  • 1 evento de CloudWatch
  • 1 rastro de CloudTrail

Luego actualice DockerImageArn para su imagen en ECR. Si desea crear paquetes de implementación con un nombre que no sea Deployment.zip , también actualice DeploymentFilename :


 DockerImageArn: <ACCOUNTID>.dkr.ecr.ap-southeast-2.amazonaws.com/codebuild-dotnet-node:latest DeploymentFilename: Deployment.zip 

Eso es todo, la tubería está lista para su implementación. Ejecute el comando de implementación sin servidor y espere hasta que esté configurado:


 sls deploy -v 


Creación de una pila de framework sin servidor CloudFormation



Creado por la tubería de framework sin servidor CodePipeline



Creado por el proyecto de marco sin servidor Proyecto CodeBuild


4. Agregue buildSpec.yml a su aplicación


Cuando CodePipeline detecta un cambio en el archivo de implementación en S3, le dice a CodeBuild que inicie e intente compilar e implementar la aplicación. Sin embargo, CodeBuild también debe saber qué comandos deben ejecutarse para compilar e implementar la aplicación, y buildSpec.yml contiene instrucciones que CodeBuild seguirá.


Creé una aplicación muy simple "Hello world" que incluye un ejemplo de archivo buildSpec.yml que puedes usar: https://github.com/effectivedigital/serverless-deployment-app
O cree el archivo buildSpec.yml en aplicaciones existentes y complételo de acuerdo con las instrucciones a continuación:


 version: 0.2 phases: pre_build: commands: - chmod a+x * build: commands: - ./build.sh post_build: commands: - sls deploy -v -s $STAGE 

5. Verificación de la tubería


Ahora todo está listo para el primer lanzamiento de su tubería. Cree un paquete llamado Deployment.zip , debe incluir todos los archivos para su aplicación sin servidor y el archivo buildSpec.yml.


Después de unos momentos, CloudTrail debería registrar un evento PutObject y activar la regla del evento CloudWatch, que luego activa el activador CodePipeline.



Deployment.zip arrancó en S3



CodePipeline lanzado, la compilación está activada


Si pasamos a los detalles del paso AWS CodeBuild, podemos ver el proceso de compilación e implementación:



CodeBuild recibirá la salida de la imagen de Docker de compilación e implementación



Implementación exitosa!


La nueva aplicación implementada por nuestra tubería también aparece en CloudFormation:



Puede probar el punto final de API creado en nuestra aplicación simple (la URL está en la salida de CodeBuild o en la API de Gateway) y asegurarse de que la aplicación funciona correctamente:



Cartero para llamar a API


Breves conclusiones


CodePipeline le permite crear una canalización CI / CD escalable, flexible y económica, ayuda a resolver algunos problemas asociados con las canalizaciones tradicionales creadas en servidores.
Me gustaría ir más allá y agregar pruebas unitarias después de la implementación a la mezcla, pero el tema merece un artículo separado, ¡y esta es una ocasión para leernos en el futuro!

Source: https://habr.com/ru/post/440756/


All Articles