Mi propio DevOps: creación de un CI solo en la nube para una aplicación web

¡Hola, Habr! Hoy hablaremos un poco sobre DevOps y la autoorganización usando uno de nuestros proyectos como ejemplo.





Comencemos con una frase con la que la mitad de los desarrolladores de la industria no están de acuerdo: "Cada desarrollador debería ser su propio DevOps". Alguien piensa que una persona dedicada aparte debería hacer esto, para que el desarrollador solo tenga que preocuparse por la calidad del código. Algunas personas tienden a pensar tanto en la canalización de entrega de código como en el código en sí. Creo que en las realidades modernas del mercado y en la abundancia de herramientas / conocimientos, un desarrollador debería poder configurar y mantener una canalización para la entrega rápida y predecible de un artefacto al entorno que necesita. A diferencia de los desarrolladores móviles, para quienes los problemas de entrega de aplicaciones e infraestructura son resueltos en gran medida por el proveedor (Google y Apple), los desarrolladores web y de backend deberían, si no poseer, al menos estar interesados ​​en las prácticas de entrega de código.





Y no estamos hablando de configurar algunos sistemas de construcción grandes y engorrosos, por los que generalmente se sacrifica toda una unidad de personal. No. DevOps no es una persona, sino un sistema de pequeños hábitos diarios basado en la autoorganización. Un concepto que crece de abajo hacia arriba y no de arriba ni de lado. Y si usted, como desarrollador, pudo acelerar el flujo de artefactos (el concepto favorito de los estadounidenses "Value Stream") en un pequeño porcentaje, felicitaciones, esto ya es el método DevOps. Le recomendamos que lea el Manual de DevOps de Gene Kim, el mejor libro para comprender este concepto (enlace al final del artículo).





En este artículo, te presentaremos una pequeña historia del nacimiento de DevOps en nuestro equipo, lo que nos permitió acelerar el desarrollo del proyecto. Esta historia se aplica tanto a un desarrollador en solitario como a un gran equipo.





OMS

- . , :





  • 3





  • 2 , QX (QA experience)





web- Angular 9.0, .





Atlassian, " ":





  • Jira





  • Bitbucket





  • CI Bitbucket Pipelines





  • Confluence.





Bitbucket $4/, 1500 Bitbucket Pipelines. . 90 Gitlab CI, Gitlab .





. , CI Docker- .





DevOps QX (QA experience) . Jira, Bitbucket Bitrise.io -, . : , №30 №170, Jira- №500. -, -









  • -









, - .

. , master ( trunk-based development master



).





.





- web . - , - . , , . CI web , . , , "" . , , (Kubernetes OpenShift, ), . .





: ? : Heroku, AWS, Netlify, Surge . AWS S3. , , S3 - S3 . AWS.





AWS?





  • . AWS , S3 2 :





    • ~ 2





    • ~ 12





    • - ~ 5





    • = 13 Mb





  • AWS API CLI. "Surge" , Amazon AWS. , CLI Heroku , Heroku Dynos .





  • AWS.





Amazon, EC2 . Docker Hub Elastic Container Registry, $100 . -, . .





№1: S3

, S3 bucket . (bitbucket-pipelines.yml), (html/css/js/img) S3 bucket. AWS CLI, , , Bitbucket Pipes ( Github actions), Pipe S3 bucket. : , - web.s3-website.ap-northeast-2.amazonaws.com.





AWS "Enable static hosting" . bucket .





- step:
      name: Build and deploy webadmin PR version into AWS for QA
      caches:
        - node
      script:
        #  
        - apk update && apk add git
        - npm install
        # 
        - npm run build:admin
        - cd dist/admin
        #   S3
        - pipe: atlassian/aws-s3-deploy:0.2.4
          variables:
            AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
            AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
            AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION
            S3_BUCKET: $S3_WEBADMIN_BUCKET_NAME
            DELETE_FLAG: 'true'
            LOCAL_PATH: $(pwd)
            ACL: 'public-read'

      
      



: - . .





:





  • -





  • QX -





№2: S3 bucket

S3 bucket . , - S3 jsn-web-manar



jsn-web-michael



. bitbucket-pipelines.yml



step - S3 PR .





: , - , , . :





  1. - . 3 -, . , . , , Chrome , - S3 .





  2. . - , , -, -. "" S3 . version-under-test .





  3. . git author name . , . , Bitbucket Pipelines Jira account, commit git author. , "Manar Kurmanov" "Dark Lord" 2 - .





️ .





:





  • -





  • QX -





№3: web

- footer :





, timestamp. - - , Jira- .





bitbucket-pipelines.yml





- step:
    name: Build PR version
    caches:
      - node
    script:
      # initial configuration
      - apk update && apk add git
      - npm install
      # preparing site footer text
      - TIMESTAMP_FILE="./src/app/some/folder/copyright.timestamp.html"
      - GIT_AUTHOR=$(git log -n 1 --format=format:'%an')
      - PR_URL="$BITBUCKET_GIT_HTTP_ORIGIN/pull-requests/$BITBUCKET_PR_ID"
      - BRANCH_TEXT="PR branch <a href=\\"$PR_URL\\">$BITBUCKET_BRANCH</a><br>"
      - echo $BRANCH_TEXT >> $TIMESTAMP_FILE
      - echo "Author $GIT_AUTHOR<br>" >> $TIMESTAMP_FILE
      - echo "Built at $(TZ=UTC-6 date '+%d-%m-%Y %H:%M') <br>" >> $TIMESTAMP_FILE
      - echo "</small>" >> $TIMESTAMP_FILE
      - cat $TIMESTAMP_FILE > src/app/target/folder/copyright.component.html
      # building artefacts
      - npm run build
    artifacts:
      paths:
        #     Build Step 
        - dist/web/**

      
      



, +100 QX, . . , 3 - S3 . ? , - S3 . Pipelines, Rerun.





, - . .





:





  • -





  • QX -





№4:

AWS API . :





  • S3 .





  • , - .









Bitbucket Pipes, AWS S3. Bitbucket Pipelines, CI , cloud-first Docker . aws-cli, AWS CLI (curl, sed, xargs).





bitbucket-pipelines.yml



. NOTE: AWS S3, .





- step:
    name: Deploy PR version into AWS bucket for QA
    image:
      name: amazon/aws-cli
    script:
      # 1.    aws cli   
      - aws configure set aws_access_key_id=$AWS_ACCESS_KEY_ID aws_secret_access_key=$AWS_SECRET_ACCESS_KEY
      # 2.     
      - export BUCKET_NAME=web-pullrequest-$BITBUCKET_PR_ID
      # 3.   AWS     ,     
      - if [ -z $(aws s3 ls | grep $BUCKET_NAME) ]; then aws s3api create-bucket --bucket $BUCKET_NAME --acl public-read --region ap-northeast-2 --create-bucket-configuration LocationConstraint=ap-northeast-2; fi
      # 4.      
      - aws s3api put-bucket-website --website-configuration "{\\"ErrorDocument\\":{\\"Key\\":\\"error.html\\"},\\"IndexDocument\\":{\\"Suffix\\":\\"index.html\\"}}" --bucket $BUCKET_NAME
      # 5.   
      - aws s3 rm s3://$BUCKET_NAME --recursive 
      # 5.     html/css/js
      - aws s3 cp dist/web s3://$BUCKET_NAME --acl public-read --recursive
      # 6.            
      - export PR_API_URL=https://api.bitbucket.org/2.0/repositories/$BITBUCKET_REPO_FULL_NAME/pullrequests/$BITBUCKET_PR_ID/comments
      - export BUCKET_PUBLIC_URL=http://$BUCKET_NAME.s3-website.ap-northeast-2.amazonaws.com
      - curl $PR_API_URL -u $CI_BB_USERNAME:$CI_BB_APP_PASSWORD --request POST --header 'Content-Type:application/json' --data "{\\"content\\":{\\"raw\\":\\"[http://$BUCKET_NAME.s3-website.ap-northeast-2.amazonaws.com](http://$BUCKET_NAME.s3-website.ap-northeast-2.amazonaws.com)\\"}}"

      
      



CI App-specific password. Atlassian , .





- .





" - S3 . ?" - . , 25 AWS - .





-.





- step:
    name: Remove dangling s3 buckets left after PR merges
    image:
        name: amazon/aws-cli
    script:
      # 1.   10  MERGED  
      - export API_URL="<https://api.bitbucket.org/2.0/repositories/$BITBUCKET_REPO_FULL_NAME/pullrequests?state=MERGED>"
      - curl "$API_URL" -u $CI_BB_USERNAME:$CI_BB_APP_PASSWORD > pr_list.json
      # 2.  ,  - 
      - aws s3 ls | grep -o '[a-zA-Z\\-]\\+pullrequest\\-[0-9]\\+' > buckets.txt
			- set +e
      #      -,   MERGED
      # (AWS API       )
      - echo "$(cat pr_list.json | grep -o '"id":\\s[0-9]\\+')" | sed 's/[^0-9]//g' | xargs -I{} grep {} buckets.txt | xargs -I{} aws s3 rm s3://{} --recursive
      #      -,   MERGED
      - echo "$(cat pr_list.json | grep -o '"id":\\s[0-9]\\+')" | sed 's/[^0-9]//g' | xargs -I{} grep {} buckets.txt | xargs -I{} aws s3api delete-bucket --bucket {}
      
      



:









  • QX - . ? , X (QX, DevX, HX) -





, .





#1: CORS

API (.amazonaws.com) (*.somebank.com), - CORS (cross origin resource sharing) . , , . , API api.server.com server.com. GET another.com "pre-flight" , "same-origin-policy".





, S3 API, Headers.





Access-Control-Allow-Origin: <http://bucket.s3-website.amazonaws.com>
# 
Access-Control-Allow-Origin: *

      
      



Cross Origin.





#2:

№4 :





aws s3 rm s3://$BUCKET_NAME --recursive 
      
      



AWS. , 4 .





, - 1 . 3 , - . , AWS API.





! S3 bucket aws-s3-deploy



pipe, , DELETE_FLAG



. bucket . #1 2 . .





#      S3   DELETE_FLAG
- pipe: atlassian/aws-s3-deploy:0.2.4
    variables:
      AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
      AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
      AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION
      S3_BUCKET: $S3_WEBADMIN_BUCKET_NAME
      DELETE_FLAG: 'true' #    
      LOCAL_PATH: $(pwd)
      ACL: 'public-read'

      
      



, DevOps . , CI/CD, .





La versión final bitbucket-pipelines.yml



se puede ver en el repositorio de github .





Leyendo materiales

  • Tutorial de CI / CD de Bitbucket - Sumérjase en la herramienta





  • Soporte CORS en Spring Boot





  • http://www.yamllint.com/ - aquí puede validar la estructura YAML si esta herramienta no está disponible





  • Manual de DevOps : para comprender el concepto con ejemplos. Lo recomendamos ampliamente.








All Articles