เราได้เรียนรู้การใช้งาน Gitlab-ci กันมาพอสมควร คราวนี้ผมจะทำให้ดูว่าเราจะเขียน .gitlab-ci.yaml
ยังไงได้บ้าง โดยในครั้งนี้สำหรับสาวก Golang ว่าเราจะทำ CICD ได้ยังไงผ่าน gitlab
อันนี้เป็นโค็ดตัวอย่างที่ผมได้รองทำไว้สามารถ clone มาลองใช้งานได้เลย https://gitlab.com/twin-opensource/golang-cicd
เรามาดูที่ไฟล์ .gitlab-ci.yaml
กันว่าเป็นยังไงบ้าง
variables:
PACKAGE_PATH: /go/src/gitlab.com/twin-opensource/golang-cicd
.inject_gopath: &inject_gopath
before_script:
- mkdir -p $(dirname $PACKAGE_PATH)
- ln -s $CI_PROJECT_DIR $PACKAGE_PATH
- cd $PACKAGE_PATH
stages:
- dep
- build
- release
dep:
stage: dep
image: golang:1.10-alpine3.7
<<: *inject_gopath
script:
- apk add --no-cache curl git
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
- chmod +x /go/bin/dep
- dep ensure -v -vendor-only
artifacts:
name: "vendor-$CI_PIPELINE_ID"
paths:
- vendor/
expire_in: 1 hour
build:
stage: build
image: golang:1.10-alpine3.7
dependencies:
- dep
<<: *inject_gopath
script:
- GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o main .
artifacts:
name: "main-$CI_PIPELINE_ID"
paths:
- main
expire_in: 1 hour
release:
stage: release
image: docker:latest
services:
- docker:dind
dependencies:
- build
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
โดยขั้นตอนการทำงานจะเป็นในลักษณะแบบนี้
จะขออธิบายส่วนต่างๆ ใน .gitlab-ci.yaml
ให้อ่านกัน
variable
เป็นการสร้างตัวแปรขึ้นมาเพื่อใช้งาน โดยในกรณีนี้ผมจะสร้าง gopath ไว้ให้ถูกต้อง.inject_gopath
เป็นใช้งาน Anchors เพื่อให้สามารถ reuse คำสั่งมาใช้งานซ้ำได้ภายในไฟล์ yaml ซึ่งผมจะให้มันสร้าง directory ตาม PACKAGE_PATH
แล้วทำการสร้าง link จากโค็ดเราทั้งหมดไปวางใน PACKAGE_PATH
dep:
stage: dep
image: golang:1.10-alpine3.7
<<: *inject_gopath
script:
- apk add --no-cache curl git
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
- chmod +x /go/bin/dep
- dep ensure -v -vendor-only
artifacts:
name: "vendor-$CI_PIPELINE_ID"
paths:
- vendor/
expire_in: 1 hour
ในส่วนนี้ของ dep job ผมจะใช้ dep ซึ่งเป็น package manager ของ Golang ทำการติดตั้ง Liberies ต่างๆ โดยมันจะได้ vendor/
ก็ให้เราทำการ artifacts เก็บไว้โดยมีระยะเวลาหมดอายุ 1 ชั่วโมง
build:
stage: build
image: golang:1.10-alpine3.7
dependencies:
- dep
<<: *inject_gopath
script:
- GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o main .
artifacts:
name: "main-$CI_PIPELINE_ID"
paths:
- main
expire_in: 1 hour
หลังจากเราได้ vendor/ มาแล้ว ในส่วนของ build job ผมก็จะทำการโหลด vendor/ มาจาก dep job โดยใช้ dependencies:
แล้วตามด้วยชื่อ job
dependencies:
- dep
แล้วค่อยทำการ build golang GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o main .
จากนั้นจะได้ไฟล์ main ผมก็เอามาเก็บลง artifacts เหมือนเดิม
release:
stage: release
image: docker:latest
services:
- docker:dind
dependencies:
- build
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
ในส่วนของ release job ผมจะทำการโหลดไฟล์ main มาจาก build job แล้วก็นำมาทำ docker image จากนั้นก็โยนขึ้นไปเก็บไว้ที่ registry.gitlab.com โดยใน Dockerfile จะเป็นแบบนี้
FROM alpine:3.8
LABEL name="Golang CICD" \
version="1.0.0" \
org.label-schema.vcs-url="https://gitlab.com/twin-opensource/golang-cicd" \
org.label-schema.vendor="Twin synergy"
RUN apk --no-cache add ca-certificates \
&& apk add --update tzdata \
&& cp /usr/share/zoneinfo/Asia/Bangkok /etc/localtime \
&& apk del tzdata
COPY main /usr/local/bin/app
EXPOSE 8080
CMD ["/usr/local/bin/app"]
จะสังเกตุเห็นว่า ผมใช้ alpine เป็น os หลักเพื่อให้ไฟล์ image มันเล็ก แล้วแค่ COPY main ที่ได้มาใส่ไว้ จากนั้นก็ run มันขึ้นมา เราก็จะได้ golang application ที่ขนาดโครตเล็กมาใช้งานแล้ว
ลองเรียกใช้ด้วย docker จากนั้นทดสอบดู
$ docker run -p 8080:8080 registry.gitlab.com/twin-opensource/golang-cicd:master
$ curl http://localhost:8080/greeting
Hello, world!
เย้ ได้ Hello, world มาแล้ว
ขอให้สนุกกับการเขียน gitlab-ci นะครับ