iT邦幫忙

0

學習筆記:CI/CD -- 使用 Travis CI 與 ElasticBeanstalk

tags: 學習筆記 AWS ElasticBeanstalk travis CI

在完成 Laravel 專案後,我試著將專案搭配上 CI/CD ,其中有許多跌跌撞撞,卻也透過這樣的過程學到了許多。因此想記錄下來。

持續整合(continuous integration)

簡述持續整合與為何使用它

CI 是什麼

參考 AWS 網站內容,視參考資料

持續整合是一項 DevOps 軟體開發實務,指的是開發人員在執行自動化建置與測試之後,定期將他們的程式碼變更合併到中央儲存庫。

持續整合最常是指軟體發行程序的建置或整合階段,而且需要自動化元件 (例如 CI 或建置服務) 與文化元件 (例如學習經常進行整合)。

持續整合的主要目標是更快發現和解決錯誤、改善軟體品質,還有減少驗證和發行新軟體更新所需的時間。

為何使用

  1. 因為整合過程是從最一開始的建立環境開始,這可以讓整個團隊成員有共同的標準。
  2. 團隊開發時可以及早發現,在整合上是否有所問題。

使用Travis CI

在培訓第一個月有上到 CI/CD 的課程,其中學習到了如何將 Travis CI 加入到自己的專案裡。

Travis CI 與 Laravel

首先,先在專案目錄下為 Travis CI 建立一個環境檔(.env.travis):

APP_NAME="app_name"
APP_ENV=testing
APP_KEY=Sometring
APP_DEBUG=true
APP_URL=http://localhost
DB_CONNECTION=testing
DB_TEST_USERNAME=root
DB_TEST_PASSWORD=
BCRYPT_ROUNDS=4
CACHE_DRIVER=array
MAIL_DRIVER=array
QUEUE_CONNECTION=sync
SESSION_DRIVER=array
BUGSNAG_API_KEY=randkey
MEDAL_BRONZE_III=50
MEDAL_BRONZE_II=100
MEDAL_BRONZE_I=150
MEDAL_SILVER_III=250
MEDAL_SILVER_II=350
MEDAL_SILVER_I=450
MEDAL_GOLD_III=600
MEDAL_GOLD_II=750

接著,在 config/database.php 新增測試環境需要的資料庫 testing

...

'testing' => [
  'driver' => 'mysql',
  'host' => env('DB_TEST_HOST', 'localhost'),
  'database' => env('DB_TEST_DATABASE', 'homestead'),
  'username' => env('DB_TEST_USERNAME', 'homestead'),
  'password' => env('DB_TEST_PASSWORD', 'secret'),
  'charset' => 'utf8',
  'collation' => 'utf8_unicode_ci',
  'prefix' => '',
  'strict' => false,
],

... 

最後,在專案目錄新增 .travis.yml,Travis CI 會讀這個檔案,並且開始從零開始建立環境,接著跑測試。我的 .travis.yml 如下:

dist: bionic
language: php
php:
  - 7.3

branch:
  only:
    - master

services:
  - mysql

install:
  - cp .env.travis .env
  - sudo mysql -e 'create database homestead;'
  - composer self-update
  - travis_retry composer install --no-interaction --prefer-dist --no-suggest

before_script:
  - php artisan key:generate
  - php artisan migrate

script:
  - vendor/bin/phpunit

cache:
  directories:
    - node_modules
    - "$HOME/.composer/cache/files"
    - vendor

至於如何將 github 與 travis CI 連動,使得每當你在特定的 branch commit 後可以啟動 travis CI 就不在此贅述。上述動作完成後,travis CI 就會在你 push 上 github 後就會開始幫你做環境建置與測試。

CD(continuous dilivery)

簡述持續交付

CD 是什麼

參考 AWS 網站內容,視參考資料

持續交付是現代應用程式開發的支柱,它透過在建置階段之後將所有程式碼部署到測試環境和/或生產環境,結合持續整合來進一步延伸。適當實作時,開發人員永遠都會有已經部署好的建置成品,且已通過標準化測試程序。

使用 AWS 的 ElasticBeanstalk

為何使用ElasticBeanstalk

會選擇使用ElasticBeanstalk 是因為我對於 AWS 的各項服務——例如權限設定、安排等等,都不太熟悉,所以才會選擇使用對初學者相對友善(建立環境友善)的 ElasticBeanstalk。

eb的優缺點為何

ElasticBeanstalk 的優勢在於建立環境非常方便,而且把應用到的服務都集中管理(instance, load balancer, security group, RDS...);但是劣勢也在於因為它幫你把所有東西都建立好了,所以自由度較低。對於指令和服務較不熟悉的我也不知道該如何因應自己的需求改變權限。

實際操作

進入 AWS 的頁面,選擇 ElasticBeanstalk,如果你是第一次進去,它會在頁面上顯示 "Get Started" 的按鈕;若不是第一次使用,則點選左邊 sidebar 的 "Applications",再點擊 "Create a new application"。

之後,會到建立環境的環節

在此我選擇使用較舊的 Linux 版本,原因後述。

完成建置環境後,回到專案裡的.travis.yml,在原本的指令後,新增自動部署的指令:

# 在 travis CI 幫你打包前做的事
before_deploy:
  # 修改 .env.example,把相關資料改進去
  - sed -in-place 's/localhost/www.aaa.net/g' .env.example

deploy:
  provider: elasticbeanstalk
  edge: true
  skip_cleanup: true
  # AWS_ACCESS_KEY 和 AWS_SECRET_KEY 可以存進 travis CI 裡
  access_key_id: $AWS_ACCESS_KEY
  secret_access_key: $AWS_SECRET_KEY
  region: "<region name>"
  app: "<app name>"
  env: "<env name>"
  bucket_name: "<bucket name>"

after_deploy:
  - echo "done deploying"

其中,$AWS_ACCESS_KEY$AWS_SECRET_KEY 要到 Travis CI 的網站上去設置:首先進入 setting

接下來在頁面下方選擇你的專案:

最後再將你不想秀出來的 key 值放進去囉。

下一個步驟,因為自動部署進 eb 的檔案裡並沒有 .env 檔,所以我們需要在程式部署完成後,把 .env 檔生出來。這裡我們需要在專案裡建立一個 .ebextensions 的資料夾,在這個資料夾中放進一個 .config 檔(檔名不重要),內容如下:

container_commands:
  01_init_env:
    command: |
      sudo cp .env.example .env
      php artisan key:generate
  02_init_db:
    command: "php artisan migrate"

這裡的指令會在部署完成後,幫我們生出 .env 檔,隨後生成一把 Laravel 需要用到的 key。
隨後,第二個指令是幫我們做 migration。(不需擔心會蓋掉資料庫裡的舊有資料,因為如果已經migrate 過了會被記錄,則php artisan migrate 這個指令會得到 Nothing to migrate!

最後,別忘了我們要將資料庫連接到 RDS 上的 mysql db,所以我們需要再次編輯專案中的 config/database.php

...

'mysql' => [
            'driver' => 'mysql',
            // for local env.
            // 'url' => env('DATABASE_URL'),
            // 'host' => env('DB_HOST', '127.0.0.1'),
            // 'port' => env('DB_PORT', '3306'),
            // 'database' => env('DB_DATABASE', 'forge'),
            // 'username' => env('DB_USERNAME', 'forge'),
            // 'password' => env('DB_PASSWORD', ''),

            // for elasticbeanstalk env.
            'host' => env('RDS_HOSTNAME', '127.0.0.1'),
            'port' => env('RDS_PORT', '3306'),
            'database' => env('RDS_DB_NAME', 'forge'),
            'username' => env('RDS_USERNAME', 'forge'),
            'password' => env('RDS_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],
        
...

這樣 git push 後,應該就會成功的進到 travis CI 後進行環境測試、成功再打包部署到 AWS 上囉!

部署完成後,點進網址應該會發現頁面會顯示 "Forbidden" 的警告訊息,這是因為 Linux 會在 /var/www/html 這個目錄下尋找 index.php,但 Laravel 專案的 index.php 是在 /var/www/html/public 下,它找不到所以才會壞掉。

所以,你需要到 ElasticBeanstalk 裡,進入到你的環境中,點選左側 sidebar 的 configuration,之後再選擇 software

之後再把 document root 改成 /public,讓它重新 run 一次就可以囉!

碰到的困難

ElasticBeanstalk 裡 Linux 的版本問題

上述在 eb 建置環境的過程中,會選擇較舊的 Linux 版本是因為我發現最新的版本在部署完成後,會發現程式只讀得到首頁,其他的頁面,例如/login, /register 都會讀不到。

解決的方法是在 /etc/nginx/conf.d/elasticbeanstalk 加上一個00-custom.conf 檔:

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

就可以 work。(因為/etc/nginx/nginx.conf 內有一行指令是他會收到所有在/etc/nginx/conf.d/elasticbeanstalk.conf 檔)

但是我發現無法在.ebextensions 下新增檔案的指令,更精確來說,我無法在 /etc 下新增檔案。唯一的辦法是,我只能進入 instance 內,在裡面直接新增檔案。我目前還是沒有找出原因。

storage/logs/Laravel.log 如鬼魅般時不時就來騷擾我

如標題。目前仍困擾不解。

心得

第一次完成從無(Literally 空空如也)到有(線上部署完成,有個網址可以點進去看到自己的專案),覺得很有成就感。雖然在過程中撞牆撞不停,其中也有不少步驟還沒釐清楚,但是這也代表我還有很大得成長空間。

期許能帶著這次專案的經驗的養分繼續向前!Keep Coding!


參考資料:


尚未有邦友留言

立即登入留言