Bonjour, Habr! Aujourd'hui, nous allons parler un peu de DevOps et de l'auto-organisation en utilisant l'un de nos projets comme exemple.
Commençons par une phrase avec laquelle la moitié des développeurs de l'industrie ne sont pas d'accord: «Chaque développeur doit être son propre DevOps». Quelqu'un pense qu'une personne dédiée distincte devrait le faire, de sorte que le développeur n'aura qu'à se soucier de la qualité du code. Certaines personnes ont tendance à penser autant au pipeline de livraison de code qu'au code lui-même. Je crois que dans les réalités modernes du marché et une abondance d'outils / de connaissances, un développeur devrait être en mesure de mettre en place et de maintenir un pipeline pour une livraison rapide et prévisible d'un artefact à l'environnement dont il a besoin. Contrairement aux développeurs mobiles, pour qui les problèmes d'infrastructure et de livraison d'applications sont en grande partie résolus par le fournisseur (Google et Apple), les développeurs backend et Web devraient, sinon posséder, du moins s'intéresser aux pratiques de livraison de code.
Et nous ne parlons pas de mettre en place des systèmes de construction volumineux et encombrants, pour lesquels une unité d'état-major entière est généralement sacrifiée. Pas. DevOps n'est pas une personne, mais un système de petites habitudes quotidiennes basé sur l'auto-organisation. Un concept qui se développe de bas en haut, et non d'en haut ou de côté. Et si vous, en tant que développeur, avez pu accélérer le flux d'artefacts (le concept américain préféré "Value Stream") d'un petit pourcentage, alors félicitations - c'est déjà la voie DevOps. Nous vous recommandons de lire le manuel DevOps de Gene Kim - le meilleur livre pour comprendre ce concept (lien à la fin de l'article).
Dans cet article, nous vous présenterons une petite histoire de la naissance du DevOps dans notre équipe, qui nous a permis d'accélérer le développement du projet. Cette histoire s'applique à la fois à un développeur solo et à une grande équipe.
Qui
- . , :
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, .
La version finale bitbucket-pipelines.yml
peut être consultée dans le référentiel github .
Matériel de lecture
Tutoriel CI / CD de Bitbucket - Plongez dans l' outil
Prise en charge de CORS dans Spring Boot
http://www.yamllint.com/ - ici vous pouvez valider la structure YAML si cet outil n'est pas à portée de main
Manuel DevOps - pour comprendre le concept avec des exemples. Nous le recommandons vivement.