[Devops] CI/CD cùng CircleCI và Deployer cho dự án Laravel
This post hasn't been updated for 4 years
Chào tất cả bà con, sau 1 thời gian vắng bóng mình lại quay lại đây, đợt vừa rồi bận quá nên cũng không chia sẻ được gì nhiều, thôi thì cũng đang có series về Deploy, thì mình làm luôn 1 bài về CI/CD bằng cách sử dụng CircleCI và Deployer mọi người nhé.
Như ae Sun thì có SunCI và nếu muốn setup để nghịch ngợm thì phải tầm keymember hoặc là leader trở lên mới có quyền fetch dự án về SunCI để test nên cũng khá bất cập.
Nhưng đến với CircelCI thì mọi người build thoải mái nhé, chức năng và giao diện theo mình đánh giá còn sịn sò hơn SunCI nữa. Ok lan man thế thôi chúng ta bắt đầu thôi.
Để có thể làm được bài này đảm bảo mọi người đã hoặc từng làm qua những bài này:
1 option thêm nếu bạn muốn viết Test cho dự án của mình thì bạn cần phải có kinh nghiệm về UnitTest và IntegrationTest
Thôi chốt lại để có thể làm tốt và hiểu được về CI/CD các bạn phải có khá là nhiều kinh nghiệm về Build Server, Auto deploy, Check convention JS,PHP, Config được Test trong dự án laravel, Biết sử dụng docker, build dockerhub ...
OK chuẩn bị kiến thức thể là đủ rồi, mình triển thôi =))
Setup config.yml file
Để bắt đầu mọi người phải có 1 project (của mình là laravel), 2 là phải đang sử dụng Github hoặc Bitbucket nhé
Sau khi đã thỏa mã 2 điều kiện trên, trong folder root của project của bạn, bạn tạo 1 folder có tên là .circleci và bên trong đó tạo thêm 1 file config.yml. Sau khi tạo, thì cấu trúc folder của mình sẽ có dạng như sau:
OK nội dung cơ bản của nó sẽ như sau
version: 2
jobs:
build_and_test:
docker:
- image: framgia/laravel-workspace
steps:
- checkout
- run: cp .env.example .env
# composer cache
- restore_cache:
keys:
- vendor-v1-{{ checksum "composer.lock" }}
- run: composer install
- save_cache:
key: vendor-v1-{{ checksum "composer.lock" }}
paths:
- vendor
# run test
- run: phpcs --standard=Framgia app
Giải thích qua 1 vài syntax mn nhé
- Gồm có 2 phần chính là docker và steps
-
Đầu tiên bạn có thể thấy ở phần docker mình đang sử dụng một image có tên là framgia/laravel-workspace. Đối với các bạn đã biết về Docker hay chưa biết về Docker thì đơn giản image giống như 1 cái hộp đã được cài một số thứ hỗ trợ chúng ta trong việc chạy test project như php, composer, git và tool dùng để kiểm tra convention cho php là phpcs cùng một vài tool khác. Nội dung cụ thể image bạn có thể xem ở đây.
-
Tiếp đó phần steps là các bước lần lượt mà chúng ta sẽ chạy cho project của chúng ta, cụ thể:
- checkout - Clone code từ github - đây là lệnh mặc định của CircleCI.
- run: [lệnh] - Các lệnh cần thực hiện.
- restore_cache - Khôi phục lại folder chứa cái package (vendor/) dựa trên file composer.lock
- save_cache - Lưu lại folder vendor nesu file composer.lock bị thay đổi hay do bạn xóa hoặc thêm package mới.
- Việc cache lại folder vendor giúp tăng tốc cho bản build của bạn cho những lần chạy sau vì thay vì phải install lại các package thì đầu thì ta có thể tái sử dụng lại folder vendor của bản build trước đó nếu file composer.lock không bị thay đổi.
-
Sau khi đã config xong thì ae push code lên repo nhé
Init project
Mọi người vào trang https://circleci.com/ sau đó login bằng github hoặc Bitbucket của mọi người nhé, mình dùng github cho quen nhé, sau khi login xong nó sẽ chuyển hướng đến trang dashboard là ok
Mọi người chọn vào mục ADD PROJECT nhé Sau đó chọn project cần Setup, Mọi người chọn project của mn nhé, click vào button Set up Project nhé
Vào màn hình này thì sẽ có chỗ chọn Hệ điều hành, ngôn ngữ, nó đã mặc định cho mình rồi, mình code PHP mà =)) Lúc này chọn Start Building là ok, chọn thì nó sẽ chuyển sang màn hình build, và nó sẽ chạy bản build đầu tiên
Chờ nó build 1 tý mình ok
Success rồi đúng không, phê lòi, lầu đầu mà mượt mà như thế là do mình đã chạy test phpcs trước ở dưới local rồi, còn nếu mn và bị fail thì click vào detail để xem nó fail cái gì để sửa rồi push lại nhé
Tỷ dụ như cái này bị fail eslint thì mình chỉ cần vào xem nó fail chỗ nào rồi sửa và push lại thôi
CI
OK như trên là mọi người đã có thể tự build 1 bản rồi, giờ thì check nhiều hơn nhé, check thêm ESLINT, TEST trong laravel nhé. Mọi người update lại file config.yml nhé
version: 2
jobs:
build_and_test:
docker:
- image: framgia/laravel-workspace
- image: mysql:5.7
environment:
MYSQL_HOST: 127.0.0.1
MYSQL_DATABASE: homestead
MYSQL_USER: homestead
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: root
steps:
- checkout
- run: cp .env.testing.example .env.testing
# composer cache
- restore_cache:
keys:
- vendor-v1-{{ checksum "composer.lock" }}
- run: composer install
- save_cache:
key: vendor-v1-{{ checksum "composer.lock" }}
paths:
- vendor
# Yarn
- restore_cache:
name: Restore yarn cache
keys:
- yarn-{{ checksum "yarn.lock" }}
- yarn-
- run: yarn
- save_cache:
paths:
- node_modules
key: yarn-{{ checksum "composer.json" }}
- run:
name: Check convention javarscript
command: npm run eslint
# run test
- run: php artisan key:generate --env=testing
- run:
name: Check convention PHP
command: phpcs --standard=Framgia app
- run:
name: Check connection database
command: framgia-ci test-connect 127.0.0.1 3306 60
- run: php artisan migrate --seed --env=testing
- run:
name: Check PhpUnit
command: ./vendor/bin/phpunit
Để có thể chạy được Test trong laravel cần phải có 1 cái database để chạy test đúng ko , đó chính là lúc mn thêm cái image mysql:5.7 đấy
- image: mysql:5.7
environment:
MYSQL_HOST: 127.0.0.1
MYSQL_DATABASE: homestead
MYSQL_USER: homestead
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: root
lúc này mọi người config vài cái biến môi trường để có thể kết nối được nhé, Bạn cần đảm bảo rằng trong file .env.testing.example của bạn cũng có phần khai báo cơ sở dữ liệu với các thông tin về host, tên database, username và password trùng với mục ta vừa thêm ở trên như sau:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
Sau khi đã làm 2 việc trên, ta tiếp tục thêm lệnh sau vào trong file .circleci/config.yml như sau nhé:
- run:
name: Check convention javarscript
command: npm run eslint
- run: php artisan key:generate --env=testing
- run:
name: Check convention PHP
command: phpcs --standard=Framgia app
- run:
name: Check connection database
command: framgia-ci test-connect 127.0.0.1 3306 60
- run: php artisan migrate --seed --env=testing
- run:
name: Check PhpUnit
command: ./vendor/bin/phpunit
Mỗi câu lệnh run mình thêm 2 lệnh con đó là name và command để đến lúc build nó hiện thị name lên cho nó sịn thay vì là hiện thị câu lệnh ấy. Trong đoạn này thì mình có cho thêm check convention của js bằng Eslint nhé.
- run:
name: Check convention javarscript
command: npm run eslint
cái này mn phải đảm bảo trong projec mn đã setup eslint rồi nhé. Ai chưa tìm hiểu thì xem lại ở đây
Để chạy được test chắc chắn file env của mn phải có key đúng không, thêm vào mà chạy thôi
- run: php artisan key:generate --env=testing
Tiếp theo là check PHPCS theo chuẩn của Framgia. mình thấy chuẩn này khá là ổn, nó chỉ bắt những convention cần thiết nhất. chứ theo full của psr2 .. thì nó bắt nhiều lắm, nào là viết doc cho function cho class ... đủ thứ trên đời.
- run:
name: Check convention PHP
command: phpcs --standard=Framgia app
Tiếp theo là phần test connect với database xem đã ok chưa và chạy migrate
- run:
name: Check connection database
command: framgia-ci test-connect 127.0.0.1 3306 60
- run: php artisan migrate --seed --env=testing
cái framgia-ci là 1 tool của Framgia, nó có sẵn trong cái image framgia/laravel-workspace mn nhé, nó là open source nên cứ lấy mà dùng thôi hihi
Phần cuối là chạy test
- run:
name: Check PhpUnit
command: ./vendor/bin/phpunit
OK ngon hàng push lên rồi thử xem nó chạy như thế nào , mà nhớ mn thao tác cái này thì tạo 1 branch mới rồi push lên tạo pull compare với develop nhé Sau khi đẩy lên nó build thì đang báo lỗi JS, ok xem lỗi và check dưới local và push lên thôi
Xanh lè rồi đúng không, nhìn là đã muốn merged thôi =))
CD
Phần trên là setup CI ok rồi đúng không, sau khi check CI tất cả ok thì auto deploy thôi, =)) mình thấy cái phần CD của thằng này khá là ổn, trong file config mình có thể tùy biến được rất nhiều thứ, như CI pass thì phải approved mới được deploy lên môi trường Development, rồi có phần require chạy lần lượt, Deploy xong môi trường này mới được deploy môi trường khác, Giao diện để mình có thể hình dung được cách tiến trình của nó cũng khá trực quan .
Ví dụ như 1 quy trình như này
Khi mọi người setup xong khi Circle build nó sẽ hiện rất trực quan và mỗi 1 job sẽ là 1 bản build
OK trên lý thuyết là thế , còn lại thì mình deploy cùng lắm là 1 - 2 môi trường thôi, như bài này thì mình chỉ auto deploy lên môi trường development thôi nhé
Để làm được đến đoạn này thì mọi người phải có
-
1 Server đã setup đầy đủ để có thể chạy được project laravel rồi nhé
-
Đã config được deployer và đã deploy được lên server này. Nếu ai chưa làm được thì thử làm qua 3 bài này đã nhé
Ai đã từng setup server thì để biết 1 cách để có thể truy cập vào server thì có thể thông qua ssh-key đúng không, thằng Circle này cũng vậy, muốn auto deploy được thì mình phải cho phép thằng CircleCI này ssh vào được server đúng không, thế thì mình làm như sau nhé
Mọi người copy cái private key ở thư mục ~/.ssh/id_rsa ở máy local của mọi người và paste cái này cùng với hostname của server vào SSH Permission trong phần setting của project trên CircleCI nhé.
Mọi người có thể đọc kỹ ở đây nhé
sau đó copy nhém vào phần modal như bên dưới
sau khi add ssh key thì nó sẽ gen cho mn 1 cái mã, lúc này mn config lại file config.yml nữa là ok
Của mình là private nên ứ show lên cho mn xem đâu hehe, Sau khi đã add ok thì mình chỉnh lại file config.yml tý nhé
deploy_development:
docker:
- image: framgiaciteam/deb-deploy:7.3
steps:
- add_ssh_keys:
fingerprints:
- "e9:93:45:b9:d9:88:ae:b7:b3:e3:66:bf:d2:2e:7c:6f"
- checkout
- run:
name: Deploy Develop to development
command: |
if [ -z `ssh-keygen -F '34.66.101.233'` ]; then
ssh-keyscan -H '34.66.101.233' >> ~/.ssh/known_hosts
fi
dep deploy -vv
Để có thể deploy được trên circle CI thì phải đảm bảo là dưới máy local của mọi người đã deploy bằng deployer ok rồi nhé. lúc này file known_hosts nó sẽ lưu thông tin những host mà đã deploy vào.
Giờ circel CI chì cần có cái private của máy các bạn là có thể giả định là máy của mn và có thể ssh vào server để deploy được. Đây chính là đoạn check xem đã ssh được vào server chưa (Như SunCI thì sẽ gen cho mình có 1 cái ssh key public luôn, mình chỉ cần nhém cái sshkey đấy vào file authorized_keys là được , nhưng Circle không có gen cho mình thì mình cần phải lấy cái private key của máy local của mình để gỉa định thôi ).
if [ -z `ssh-keygen -F '34.66.101.233'` ]; then
ssh-keyscan -H '34.66.101.233' >> ~/.ssh/known_hosts
fi
Thêm 1 phần deploy development vào phần job nhé, trong này sẽ có 1 cái image framgiaciteam/deb-deploy:7.3 , cái này mình cứ dùng của Sun, mọi người rảnh có thể tự build cái image make by me cho sịn sò cũng được , Và cuối dùng chạy câu lệnh deployer thôi
command: dep deploy -vv
Ok thế là ổn rồi, còn deployer config như nào thì mn xem ở bài mà mình đã note ở trên nhé.
Thằng Cicle này nó có 1 chức năng là chạy theo workflows, ở cái workflow này mình muốn thằng nào chạy thì nó chạy, hay là đặt điều kiện là thằng này pass thằng kia mới được chạy khá là hay,
workflows:
version: 2
build-and-deploy:
jobs:
- build_and_test
- deploy_development:
requires:
- build_and_test
filters:
branches:
only: develop
Qua đoạn này thì dân chơi nhìn phát đoán ngay là làm gì đúng không, đó là ta sẽ chạy job
chạy thằng build_and_test => deploy_development (Yêu cầu thằng build_and_test phải pass tất cả rồi mới được chạy thằng deploy, và ở thằng deploy này chỉ chạy khi code được update ở nhánh develop)
. OK ngon hàng, đẩy code lên nào , mọi người để lên cái nhánh mn đang code, chờ nó pass hết thì merged vào develop nhé. Khi merged vào thì nó sẽ có 1 bản build
Bản build này chỉ là để check convention và chạy Test thôi
Khi bản build đấy ngon thì nó sẽ chạy job auto deploy
Mọi người click vào chỗ running kia thì sẽ nhìn thấy 2 cái job của mn đã config sẵn
Thế là xong. chờ bản build kia chạy pass là ngon ăn thôi, làm cốc cafe để tận hưởng nào.
Ở thằng này mình thích nhất là đoạn approved, ví dụ như auto deploy lên production hoặc là một môi trường nào đấy mà cần phải suy nghĩ chẳng hạn thì chức năng này khá hợp lý
Ta chỉ cần thêm đoạn code này vào file config thôi
- build_and_test
- hold_for_approval:
type: approval
requires:
- build_and_test
Rồi push lên để cảm nhận nhé: Lên xem bản build nó sẽ như thế này
Chờ build test xong, pass thì nhảy sang job, chờ mình appprove, nếu mình chọn approved thì mới được sang job deploy hehe
Lên hình và cảm nhận nhé
Notification
Phần notification thì nó support slack chứ chưa có chatwork nên mình ko config nữa, mọi người thử xem thế nào nhé.
Thôi thì minh cũng hướng dẫn luôn, như bình thường thì chỉ cần báo noti về box là khi build pass hoặc fail thôi đúng không, ok mọi người sửa lại file .yml 1 tý nhé
- run:
name: Sending notification
when: on_fail
command: |
if [[ true ]]; then
curl -X POST -H "X-ChatWorkToken: $CHATWORK_TOKEN" -d \
"body=[To:2359460]
[info][title]Build $CIRCLE_BUILD_NUM - FAIL[/title]
Repo: $CIRCLE_PROJECT_REPONAME
Author: $CIRCLE_USERNAME
Branch: $CIRCLE_BRANCH
Build link: https://circleci.com/gh/tranvanmy/RemindBot/$CIRCLE_BUILD_NUM
[/info]" \
"https://api.chatwork.com/v2/rooms/$CHATWORK_ROOM_ID/messages"
fi
- run:
name: Sending notification
when: on_success
command: |
if [[ true ]]; then
curl -X POST -H "X-ChatWorkToken: $CHATWORK_TOKEN" -d \
"body=[To:2359460]
[info][title]Build $CIRCLE_BUILD_NUM - SUCCESS[/title]
Repo: $CIRCLE_PROJECT_REPONAME
Author: $CIRCLE_USERNAME
Branch: $CIRCLE_BRANCH
Build link: https://circleci.com/gh/tranvanmy/RemindBot/$CIRCLE_BUILD_NUM
[/info]" \
"https://api.chatwork.com/v2/rooms/$CHATWORK_ROOM_ID/messages"
fi
Phần này mọi người cho vào cuối của mỗi job muốn bắn noti là được. Có 1 vài biến như $CHATWORK_TOKEN , $CHATWORK_ROOM_ID để tránh bị lộ thông tin thì mọi người config trong phần Enviroment Variables là được nhé.
Còn những biến như $CIRCLE_PROJECT_REPONAME, $CIRCLE_USERNAME .. là mặc định của Circle CI . mọi xem qua ở đây nhé: https://circleci.com/docs/2.0/env-vars/
Khi build pass hoặc fail thì có noti ngay
Kết Luận
Ok bài này của mình đến đây thôi, ai mà đọc đến đây thì mn cũng khá là kiên trì đấy ạ, vì để có thể thao tác được bài này , có thể setup được ngon lành thì kiến thức của các bạn cũng phải thuộc dạng hầm hố rồi =))
Đợt này mình đang làm series về CI/CD . bài sau mình làm 1 bài về autodeploy với github action nhé, 1 công cụ của github cũng mới phát triển nhé
All Rights Reserved