Meu próprio DevOps: construindo um CI somente em nuvem para um aplicativo da web

Olá, Habr! Hoje vamos falar um pouco sobre DevOps e auto-organização usando um de nossos projetos como exemplo.





Vamos começar com uma frase com a qual metade dos desenvolvedores do setor discorda: "Cada desenvolvedor deve ter seu próprio DevOps." Alguém acha que uma pessoa separada e dedicada deve fazer isso, de forma que o desenvolvedor só terá que se preocupar com a qualidade do código. Algumas pessoas tendem a pensar sobre o pipeline de entrega de código tanto quanto pensam sobre o próprio código. Acredito que nas realidades modernas do mercado e na abundância de ferramentas / conhecimento, um desenvolvedor deve ser capaz de configurar e manter um pipeline para entrega rápida e previsível de um artefato ao ambiente de que necessita. Ao contrário dos desenvolvedores móveis, para quem os problemas de infraestrutura e entrega de aplicativos são amplamente resolvidos pelo fornecedor (Google e Apple), os desenvolvedores de back-end e da web devem, se não possuir, pelo menos estar interessados ​​nas práticas de entrega de código.





E não estamos falando sobre configurar alguns sistemas de construção grandes e pesados, para os quais uma unidade de equipe inteira é geralmente sacrificada. Não. DevOps não é uma pessoa, mas um sistema de pequenos hábitos diários baseados na auto-organização. Um conceito que cresce de baixo para cima e não de cima ou para os lados. E se você, como desenvolvedor, conseguiu acelerar o fluxo de artefatos (o conceito americano favorito "Value Stream") em uma pequena porcentagem, então parabéns - esse já é o jeito do DevOps. Recomendamos que você leia o DevOps Handbook de Gene Kim - o melhor livro para entender esse conceito (link no final do artigo).





Neste artigo, apresentaremos uma pequena história do nascimento do DevOps em nossa equipe, o que nos permitiu acelerar o desenvolvimento do projeto. Esta história se aplica tanto a um desenvolvedor solo quanto a uma grande equipe.





Quem

- . , :





  • 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, .





A versão final bitbucket-pipelines.yml



pode ser visualizada no repositório github .





Materiais de leitura

  • Tutorial de CI / CD do Bitbucket - Mergulhe na ferramenta





  • Suporte CORS no Spring Boot





  • http://www.yamllint.com/ - aqui você pode validar a estrutura YAML se esta ferramenta não estiver disponível





  • Manual do DevOps - para entender o conceito com exemplos. É altamente recomendável.








All Articles