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 .
: , - , , . :
- . 3 -, . , . , , Chrome , - S3 .
. - , , -, -. "" S3 . version-under-test .
. 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
-
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.