tags: 学习笔记
AWS
ElasticBeanstalk
travis CI
在完成 Laravel 专案后,我试着将专案搭配上 CI/CD ,其中有许多跌跌撞撞,却也透过这样的过程学到了许多。因此想记录下来。
持续整合(continuous integration)
简述持续整合与为何使用它
CI 是什么
参考 AWS 网站内容,视参考资料
持续整合是一项 DevOps 软体开发实务,指的是开发人员在执行自动化建置与测试之后,定期将他们的程式码变更合併到中央储存库。
持续整合最常是指软体发行程序的建置或整合阶段,而且需要自动化元件 (例如 CI 或建置服务) 与文化元件 (例如学习经常进行整合)。
持续整合的主要目标是更快发现和解决错误、改善软体品质,还有减少验证和发行新软体更新所需的时间。
为何使用
因为整合过程是从最一开始的建立环境开始,这可以让整个团队成员有共同的标準。团队开发时可以及早发现,在整合上是否有所问题。使用Travis CI
在培训第一个月有上到 CI/CD 的课程,其中学习到了如何将 Travis CI 加入到自己的专案里。
Travis CI 与 Laravel
首先,先在专案目录下为 Travis CI 建立一个环境档(.env.travis
):
APP_NAME="app_name"APP_ENV=testingAPP_KEY=SometringAPP_DEBUG=trueAPP_URL=http://localhostDB_CONNECTION=testingDB_TEST_USERNAME=rootDB_TEST_PASSWORD=BCRYPT_ROUNDS=4CACHE_DRIVER=arrayMAIL_DRIVER=arrayQUEUE_CONNECTION=syncSESSION_DRIVER=arrayBUGSNAG_API_KEY=randkeyMEDAL_BRONZE_III=50MEDAL_BRONZE_II=100MEDAL_BRONZE_I=150MEDAL_SILVER_III=250MEDAL_SILVER_II=350MEDAL_SILVER_I=450MEDAL_GOLD_III=600MEDAL_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: bioniclanguage: phpphp: - 7.3branch: only: - masterservices: - mysqlinstall: - cp .env.travis .env - sudo mysql -e 'create database homestead;' - composer self-update - travis_retry composer install --no-interaction --prefer-dist --no-suggestbefore_script: - php artisan key:generate - php artisan migratescript: - vendor/bin/phpunitcache: 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.exampledeploy: 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!
参考资料:
什么是持续整合?- https://aws.amazon.com/tw/devops/continuous-integration/Running Travis CI with Laravel - https://medium.com/@tik/running-travis-ci-with-laravel-2ef5034a5dcd什么是持续交付?- https://aws.amazon.com/tw/devops/continuous-delivery/ElasticBeanstalk 选项设定 - https://docs.aws.amazon.com/zh_tw/elasticbeanstalk/latest/dg/ebextensions-optionsettings.htmlDeploying a Laravel application to Elastic Beanstalk - https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/php-laravel-tutorial.html