Halo, Habr! Hari ini kita akan berbicara sedikit tentang DevOps dan organisasi mandiri menggunakan salah satu proyek kita sebagai contoh.
Mari kita mulai dengan frasa yang tidak disetujui oleh separuh developer di industri ini: "Setiap developer harus menjadi DevOpsnya sendiri." Seseorang berpikir bahwa orang yang berdedikasi harus melakukan ini, sehingga pengembang hanya perlu mengkhawatirkan kualitas kode. Beberapa orang cenderung berpikir tentang pipeline pengiriman kode sebanyak yang mereka pikirkan tentang kode itu sendiri. Saya percaya bahwa dalam realitas pasar modern dan banyaknya alat / pengetahuan, seorang pengembang harus dapat mengatur dan memelihara saluran pipa untuk pengiriman artefak yang cepat dan dapat diprediksi ke lingkungan yang dia butuhkan. Tidak seperti pengembang seluler, yang masalah infrastruktur dan pengiriman aplikasinya sebagian besar diselesaikan oleh vendor (Google dan Apple), pengembang backend dan web seharusnya, jika tidak memiliki, setidaknya tertarik pada praktik pengiriman kode.
Dan kami tidak berbicara tentang menyiapkan beberapa sistem build yang besar dan tidak praktis, yang biasanya dikorbankan oleh seluruh unit staf. Tidak. DevOps bukanlah orang, tetapi sistem kebiasaan kecil sehari-hari berdasarkan organisasi mandiri. Sebuah konsep yang tumbuh dari bawah ke atas, dan bukan dari atas atau ke samping. Dan jika Anda, sebagai pengembang, dapat mempercepat aliran artefak (konsep favorit Amerika "Arus Nilai") dengan persentase kecil, maka selamat - ini sudah menjadi cara DevOps. Kami menyarankan Anda membaca Buku Pegangan DevOps oleh Gene Kim - buku terbaik untuk memahami konsep ini (tautan di akhir artikel).
Pada artikel ini, kami akan menyajikan kepada Anda sejarah kecil kelahiran DevOps di tim kami, yang memungkinkan kami untuk mempercepat pengembangan proyek. Kisah ini berlaku untuk pengembang solo dan tim besar.
Siapa
- . , :
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, .
Versi final bitbucket-pipelines.yml
dapat dilihat di repositori github .
Bahan bacaan
Tutorial CI / CD Bitbucket - Menyelami Alat
-
http://www.yamllint.com/ - di sini Anda dapat memvalidasi struktur YAML jika alat ini tidak tersedia
Buku pegangan DevOps - untuk memahami konsep dengan contoh. Kami sangat merekomendasikannya.