เขียน React แล้วมาทำ CI/CD ด้วย Circle CI, AWS S3 และ AWS CloudFront กันเถอะ

Supakorn Thongtra
Nextzy
Published in
7 min readApr 7, 2018
ci / cd life cycle

ในปัจจุบันส่วนหนึ่งที่สำคัญของการพัฒนา Software คือ การ run test, build และ deploy อยู่เสมอ ซึ่งหากไม่ได้มีการทำ CI/CD เอาไว้ ก็จะต้องมาทำ Manual เองทั้งหมด ตั้งแต่การ run test ให้เสร็จ ต่อด้วย run build ได้ไฟล์ build มา เอาไป deploy บน server รวมถึงเมื่อต้องการพัฒนา feature ใหม่ๆ หรือ มีการแก้ bug ต่างๆ ก็ต้องทำขั้นตอนทั้งหมดนี้ วนซ้ำไปเรื่อยๆ

จะดีกว่ามั้ยหากเราสามารถลดเวลาในการทำขั้นตอนซ้ำๆ เดิมๆ เหล่านี้ได้ และ สามารถระบุปัญหาหรือความผิดพลาดต่างๆ ที่เกิดขึ้นระหว่างการพัฒนา Software ได้อย่างรวดเร็ว ด้วยการทำ CI/CD ?

TL;DR

  • สร้าง react app ขึ้นมาแล้วอัพขึ้น repo ของ github
  • Setting AWS S3 ไว้สำหรับ deploy
  • Setting AWS Cloudfront เพื่อทำ https และ ทำ CDN
  • Setting Circle CI ไว้สำหรับ subscribe repository และ trigger เมื่อมี commit เข้ามา ให้ทำการ test, build, deploy ลง AWS

How it works

ci / cd process
  • เมื่อมีการ commit code ขึ้น repository ( เช่น github, bitbucket )
  • ตัว repository จะทำการ trigger (webhook) ไปบอกตัว ci ที่ subscribe repository นั้นๆอยู่
  • CI server ทำการรันคำสั่งตามที่เรากำหนดไว้ ( เช่น สั่งให้ run test, check syntax, build, deploy )
  • ถ้า process ไหน เกิดข้อผิดพลาด จะส่ง message มาบอกว่าผิดพลาดตรงส่วนไหน
  • developer ทำการ แก้บัคแล้ว commit code ขึ้นไปใหม่ ( กลับไปเริ่มต้นขั้นตอนแรก )

Getting Started

สร้าง repository ผ่าน github

react-circleci repository

สร้าง react project และทำการ เพิ่ม git เข้า project

$ npx create-react-app react-circleci
$ cd react-circleci
$ git init
$ git add .
$ git commit -m 'initial react circleci'
$ git remote add origin https://github.com/<user>/<repository-name>.git
$ git push -u origin master

( npx สามารถใช้ได้กับ npm version > 5.2 )

Setting up AWS

เข้าไปที่ https://s3.console.aws.amazon.com/s3/ ( ต้องสร้าง account ก่อน ซึ่งตอนสร้าง account จำเป็นต้องใส่บัตรเครดิต แนะนำให้ใช้ WeCard ของ truemoney ) หลังจากนั้น login เข้ามา กดที่ปุ่ม Create bucket ใส่ชื่อ Bucket name: reactcircleci.com แล้วกด Next ไปเรื่อยๆ จนถึงขั้นตอนสุดท้าย กด Create bucket เสร็จแล้วจะได้หน้าตาแบบนี้

create bucket success

เข้าไปที่ bucket ที่เราสร้างไว้ ( reactcircleci.com ) เลือกหัวข้อ Permissions -> Bucket Policy ทำการเพิ่ม JSON เข้าไป ( เพื่อบอกให้ bucket นี้สามารถเข้าถึง content ผ่าน browser ได้ ) แล้ว กด Save

#Bucket Policy JSON{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AddPerm",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::reactcircleci.com/*"
}
]
}

จากนั้นเข้าไปที่ My Security Credentials

security credentials

ให้ทำการสร้าง Access keys (access key ID and secret access key) -> Create New Access Key

create access key success

รันคำสั่ง aws configure แล้วทำการ เพิ่ม access id และ secret id เข้าไป

$ aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: us-west-2
Default output format [None]: json

ไปที่หัวข้อ Properties -> Static Web Hosting ตั้งค่าตามรูปข้างล่าง แล้ว กด Save

config static website hosting

ทำการติดตั้ง aws cli ผ่าน homebrew

$ brew install awscli

ถ้ายังไม่ได้ติดตั้ง homebrew ให้ติดตั้งตามลิ้งนี้ได้เลย https://brew.sh/index_th

จากนั้นให้ build react project ( reactcircleci ) เพื่อทำการ sync กับ aws s3 bucket เพื่อทดสอบว่าทำ authentication สำเร็จ

$ yarn build
$ aws s3 sync build/ s3://myawesomeapp.com --delete
(aws s3 sync <% path build folder %> s3://<% bucket-name %>/)

( — delete หมายถึงให้ลบ ตัว build ที่อยู่ข้างใน bucket ออกก่อน แล้วค่อย sync ตัวใหม่ลงไป)

โดยถ้าทำการ sync สำเร็จ จะได้หน้าตา command line ประมาณนี้

aws sync success

ทำการทดสอบ เข้า website ผ่าน Endpoint ที่ได้จากการ Setup Static website hosting ก่อนหน้านี้

Endpoint : http://reactcircleci.com.s3-website-ap-southeast-1.amazonaws.com

จะเห็นหน้า website เป็น ค่าเริ่มต้นของ create-react-app

react app on aws s3

ให้เพิ่มคำสั่ง deploy เข้าไปใน package.json ( สำหรับใช้รันใน circle ci )

{
"name": "react-circleci",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.3.1",
"react-dom": "^16.3.1",
"react-scripts": "1.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"deploy": "yarn build && aws s3 sync build/ s3://reactcircleci.com --delete"
}
}

CircleCI Setup

ทำการสร้าง account แล้วทำการ login ถ้า login สำเร็จจะถูก redirect ไปที่ https://circleci.com/dashboard ให้เลือกหัวข้อ Add Project แล้วเลือก repository ที่ต้องการ follow โดยคลิกที่ Set Up Project

add project to circle ci

หลังจากนั้นจะเข้ามาหน้า set up project เลือก Linux และ Node

set up circle ci

ทำการสร้าง folder .circleci และ ไฟล์ config.yml ผ่านคำสั่ง

$ mkdir .circleci && touch ./circleci/config.yml

โดยให้เขียนคำสั่งใน config.yml ดังนี้

# Javascript Node CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
#
version: 2
jobs:
build:
docker:
# specify the version you desire here
- image: circleci/node:7.10

# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
# documented at https://circleci.com/docs/2.0/circleci-images/
# - image: circleci/mongo:3.4.4
working_directory: ~/reposteps:
# Checkout the code from the branch into the working_directory
- checkout
# Log the current branch
- run:
name: Show current branch
command: echo ${CIRCLE_BRANCH}
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "package.json" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run: yarn install- save_cache:
paths:
- node_modules
key: v1-dependencies-{{ checksum "package.json" }}

# run tests!
- run: yarn test
- run: sudo apt-get update && sudo apt-get install -y python-dev
- run: sudo curl -O https://bootstrap.pypa.io/get-pip.py
- run: sudo python get-pip.py
- run: sudo pip install awscli --upgrade
- run: aws --version
- run: aws s3 ls
- run: yarn run deploy

คำสั่งข้างบนจะมีหน้าที่คร่าวๆดังนี้

  • ทำการ checkout คือ โหลด source code ล่าสุดมาจาก repository
  • log brach ของ repository ออกมา
  • ถ้าเจอ cache อยู่ให้เอา cache นั้นมาใช้
  • ทำการ yarn install
  • ทำการ save cahche ในที่นี้คือ node_modules
  • ทำการ yarn run test
  • ติดตั้ง aws cli
  • ทำการ yarn run deploy

กดปุ่ม Start Building

start building

หลังจากนั้นไปที่ Project Settings -> AWS Permissions ให้นำ AWS_ACCESS_KEY_ID และ AWS_SECRET_ACCESS_KEY ที่สร้างขึ้นมาก่อนหน้านี้มาใช้ ( สามารถ ใช้คำสั่ง vim ~/.aws/credentials เพื่อเข้าไปดู key ได้ ) แล้วกด Save AWS keys

aws keys in circle ci

หลังจากนั้นให้ commit file ที่ใช้ config circleci ขึ้นไปที่ github repository แล้วดูผลลัพธ์ในหน้า circleci/dashboard

circle ci dashboard

เมื่อเราทำการ commit ไฟล์ขึ้น repository แล้ว ตัว github จะทำการ trigger ไปหา circleci แล้ว circleci จะทำการรันคำสั่งตามที่เรากำหนดไว้ใน config.yml หากสำเร็จจะขึ้น SUCCESS หากไม่สำเร็จจะขึ้น FAILED ( เราสามารถส่ง message succes หรือ failed ไปหา third-party อื่นๆ ได้ เช่น line, slack, email)

หลังจากนี้ทุกครั้งที่มีการ commit file จะทำการรันคำสั่งใน circleci โดยเราสามารถแยกได้ว่า ให้รัน circleci เฉพาะ branch ที่เรากำหนด ตัวอย่างประมาณนี้ ( โดย ${CIRCLE_BRANCH} จะทำหน้าที่ get ชื่อ branch ของ repository ออกมา)

# Build project with different configuration based on the current branch
- run:
name: Building
command: |
if [ "${CIRCLE_BRANCH}" == "staging" ]; then
yarn build-stg
elif [ "${CIRCLE_BRANCH}" == "master" ]; then
yarn build-prod
else
yarn build-dev
fi

Setting AWS CloudFront

สังเกตว่า ตัว aws ที่เรา deploy ไปก่อนหน้านี้ ( http://reactcircleci.com.s3-website-ap-southeast-1.amazonaws.com/ )ยังไม่เป็น https ให้เข้าไปที่ https://console.aws.amazon.com/cloudfront/home เลือก Create Distribution -> Get Started แล้วทำการ setting ดังนี้ แล้วกด Create Distribution

config aws cloudfront
  • Origin Domain Name : reactcircleci.com.s3-website-ap-southeast-1.amazonaws.com (endpoint ของ s3)
  • Origin ID: S3-reactcircleci.com
  • Viewer Protocol Policy: Redirect HTTP to HTTPS
config aws cloudfront
  • Default Root Object: index.html

เมื่อเสร็จแล้วจะได้หน้าตาแบบนี้ พร้อมกับ status: In Progress รอประมาณ 15–20 นาที ถึงจะขึ้น status: Deployed

config aws cloudfront

หลังจากขึ้น status: Deployed สามารถเข้าดูผลลัพธ์ได้จาก Domain Name https://dhhqbyhy7gv01.cloudfront.net/ จะพบว่าเป็น https แล้ว

react app https with aws cloudfront

To do next …

  • ทดสอบ Circle CI กับ platform อื่นๆ ( iOS, Android )
  • netlify เป็นหนึ่งในตัวเลือกที่น่าสนใจหากมี repository บน Gitlab ( CircleCI ยังทำได้แค่บน Github และ Bitbucket )
  • NOW เป็นอีกตัว Deploy ที่ set up ง่ายกว่า aws รวมถึงมีการทำ https ให้เลย จากที่ลองทำ ยังมีติดอยู่ตรงที่ เมื่อเราทำการ now —-public จะได้ dynamic domain มาแบบนี้ https://circleci-deployment-sfdfayelld.now.sh/ สามารถทำ alias ได้แบบนี้ https://circleci-deployment-production.now.sh/ แต่ยังติดตรงให้มันทำ alias auto บน ci ไม่ได้

Conclusion

  • ในตัวของ CircleCI ยังสามารถทำอะไรได้มากกว่านี้อีกมาก
  • จะเห็นว่าการทำ CI / CD ในขั้นตอนที่เริ่มนั้นใช้เวลาพอสมควร แต่ก็แลกมาด้วยความคุ้มค่าในระยะยาว
  • เมื่อมีการเริ่มต้น project ใหม่ ควรเริ่มต้นวางโครง CI / CD ไว้เลย
  • การทำ run test, build, deploy แบบ Manual เป็น cost ที่ไม่ควรเอาเวลาทำอย่างอื่นของเราไปแลก
  • การทำ CI / CD จะสามารถหา Bug Creator ได้ง่ายมาก ฮ่าๆ
  • Alternatives CI -> Jenkins , Travis CI

สุดท้ายมีข้อผิดพลาด หรือ ควรเพิ่มเติมตรงไหน สามารถแนะนำเข้ามาได้เลยครับ :)

--

--