Pre-required

  • Remote linux server : Ubuntu 16.04 (use AWS EC2)
  • Create a repository on gitlab, example name : laravel-ci
  • Use composer to create a laravel project and push to laravel-ci.

Create GitLab CI

Gitlab CI有提供laravel範例yaml腳本,選用後修改調整

調整後的.gitlab-ci.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
stages:
 - test
 - build
 - deploy

cache:
  paths:
  - vendor/

test_php7.1_mysql5.7:
  stage: test
  image: mmx112945/docker-laravel-php:7.1
  services:
    - mysql:5.7
  variables:
    MYSQL_ROOT_PASSWORD: secret
    MYSQL_DATABASE: homestead
    MYSQL_USER: homestead
    MYSQL_PASSWORD: secret
  before_script:
    # Install & enable Xdebug for code coverage reports
    - pecl install xdebug
    - docker-php-ext-enable xdebug

    # Install Composer and project dependencies.
    - composer install 

    # Install Node dependencies.
    # - npm install (pass)

    # Copy over testing configuration.
    - cp .env.testing .env

    # Generate an application key. Re-cache.s
    - php artisan key:generate
    - php artisan config:cache

    # Run database migrations.
    - php artisan migrate:refresh
    # Run database seed
    - php artisan db:seed
  
  script:
    # run laravel tests
    - php vendor/bin/phpunit --coverage-text --colors=never --coverage-html=coverage
    # run frontend tests
    # - npm test (pass)
  artifacts:
    paths:
      - coverage/
    expire_in: 1 day

build_production:
  stage: build
  image: docker:stable
  services:
    - docker:dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - echo -e "$ENV_PRODUCTION" > .env
    - docker build --pull -t $CI_REGISTRY_IMAGE .
    - docker push $CI_REGISTRY_IMAGE

deploy_production:
  stage: deploy
  script:
    - mkdir -p ~/.ssh
    - echo -e "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - '[[ -f /.dockerenv ]] && echo -e "Host *\nStrictHostKeyChecking no\n" > ~/.ssh/config'
    - scp docker-compose.yml deploy.sh $SERVER_USER@$SERVER_URL:/home/ubuntu
    - ssh ubuntu@$SERVER_URL "chmod +x ./deploy.sh"
    - ssh ubuntu@$SERVER_URL "./deploy.sh $CI_DEPLOY_USER $CI_DEPLOY_PASSWORD"
 environment:
   name: production
   url: http://$SERVER_URL
 only:
   - master
 when: manual

catch

  • composer install後會產生 vendor/,做catch後,除非composer.json有變動更新,否則之後的jobs都會使用已經build好存在gitlab catch的vendor/。此外也可以因為不用再重build vendor/,而節省下其他jobs的執行時間。

test_php7.1_mysql5.7

  • image使用我已包好的docker laravel環境,加快job處理的時間
  • 需使用mysql services服務使用,因為phpunit時會使用DB相關操作,參考: What is a service
  • 安裝php debug tools,設定.env測試檔,特別注意MYSQL_HOST=mysql,參考: Using MySQL
  • phpunit執行後會產生coverage/程式覆蓋率報表
  • 如何設定與gitlab coverage連動

Settings > CI/CD > General pipelines頁面後,phpunit coverage parsing = ^\s*Lines:\s*\d+.\d+\% (依照自己程式語言設定)

之後在CI/CD > Jobs就可以看到coverage結果

另外可以在readme.md加上coverage or pipeline的icon → 看起來專業

build_production

  • 使用dind方式建置環境
  • Settings > CI/CD > Variables add ENV_PRODUCTION,將正式環境的.env內容存成變數然後拿來使用
  • $CI_REGISTRY_USER, $CI_REGISTRY_PASSWORD…等相關gitlab預設環境變數可以參考: GitLab CI/CD Variables

deploy_production

  • 在本機設定遠端SERVER的private ssh key
  • 將要執行deploy相關的檔案scp到遠端SERVER
  • 使用ssh方法,遠端下指令給SEVER執行deploy動作
  • 使用Settings > Repository > Deploy Tokens create read-only access to your repository and registry images → 將create後得到的username, token設定到enviroment variables : $CI_DEPLOY_USER, $CI_DEPLOY_PASSWORD
  • deploy.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash
CI_DEPLOY_USER=$1
CI_DEPLOY_PASSWORD=$2

[[ \"$(docker info | grep Swarm | sed 's/Swarm: //g')\" == \"inactive\" ]] && docker swarm init

docker login registry.gitlab.com -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD
docker-compose pull
docker stack deploy -c docker-compose.yml --with-registry-auth stack_laravel-ci

# 使用swarm, docker-compose的方式更新系統環境
  • 若有設定environment,則可以在 Operations > Environments 看到完成結果

Conclusion

使用GitLab CI服務,讓開發者在每次提交新版Code後自動測試+部屬,可以大幅提升系統測試品質,以及環境部屬上的缺失。像正式環境所用的config跟測試環境的config就會不一樣,傳統手動部屬的話,要是哪個天兵一閃失丟錯config到正式環境,那就要爆了。
GitLab自帶CI/CD服務,不需要再透過其他第三方CI/CD (Jenkins, Travis…),這點真的很方便,也很好上手。