Hallo Habr! Heute werden wir am Beispiel eines unserer Projekte ein wenig über DevOps und Selbstorganisation sprechen.
Beginnen wir mit einem Satz, dem die Hälfte der Entwickler in der Branche nicht zustimmt: "Jeder Entwickler sollte sein eigenes DevOps sein." Jemand ist der Meinung, dass eine separate dedizierte Person dies tun sollte, damit sich der Entwickler nur um die Qualität des Codes kümmern muss. Einige Leute neigen dazu, über die Codebereitstellungs-Pipeline genauso nachzudenken wie über den Code selbst. Ich glaube, dass ein Entwickler in der modernen Realität des Marktes und einer Fülle von Tools / Kenntnissen in der Lage sein sollte, eine Pipeline für die schnelle und vorhersehbare Lieferung eines Artefakts an die von ihm benötigte Umgebung einzurichten und zu warten. Im Gegensatz zu mobilen Entwicklern, bei denen Infrastruktur- und Anwendungsbereitstellungsprobleme weitgehend vom Anbieter (Google und Apple) gelöst werden, sollten Backend- und Webentwickler, wenn sie nicht Eigentümer sind, zumindest an Codebereitstellungspraktiken interessiert sein.
Und wir sprechen nicht über die Einrichtung einiger großer und umständlicher Build-Systeme, für die normalerweise eine ganze Personaleinheit geopfert wird. Nein. DevOps ist keine Person, sondern ein System täglicher kleiner Gewohnheiten, die auf Selbstorganisation beruhen. Ein Konzept, das von unten nach oben wächst und nicht von oben oder von der Seite. Und wenn Sie als Entwickler den Fluss von Artefakten (das amerikanische Lieblingskonzept "Value Stream") um einen kleinen Prozentsatz beschleunigen konnten, dann herzlichen Glückwunsch - dies ist bereits der DevOps-Weg. Wir empfehlen Ihnen, das DevOps-Handbuch von Gene Kim zu lesen - das beste Buch zum Verständnis dieses Konzepts (Link am Ende des Artikels).
In diesem Artikel präsentieren wir Ihnen eine kleine Geschichte der Geburt von DevOps in unserem Team, die es uns ermöglicht hat, die Entwicklung des Projekts zu beschleunigen. Diese Geschichte gilt sowohl für einen Einzelentwickler als auch für ein großes Team.
WHO
- . , :
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, .
Die endgültige Version bitbucket-pipelines.yml
kann im Github-Repository angezeigt werden .
Lesematerial
Bitbuckets CI / CD-Tutorial - Tauchen Sie ein in das Tool
CORS-Unterstützung im Spring Boot
http://www.yamllint.com/ - hier können Sie die YAML-Struktur überprüfen, wenn dieses Tool nicht verfügbar ist
DevOps-Handbuch - zum Verständnis des Konzepts anhand von Beispielen. Wir empfehlen es sehr.