在 Gitlab 上为 Rails 6+ 设置 CI/CD 的完整指南
Gitlab 上 Rails 的持续集成/部署
我们将取得什么成果?
GITLAB-CI
我们开始做吧
结论
Gitlab 上 Rails 的持续集成/部署
在这篇博文中,我们将介绍设置 Gitlab 所需的步骤,以便
在一切顺利的情况下运行 Rails 构建、测试和部署。
我将特别关注rails system test
如何使它们正常工作。
我们将使用 Heroku 来部署我们的暂存应用程序。
我们将取得什么成果?
构建阶段
该构建将包含:
- 安装依赖项
- 数据库设置
- 资产预编译(资产和 webpacker)
测试阶段
集成测试
在此阶段,我们将运行所有集成测试,这些测试基本上依次
运行:bundle exec rails test
系统测试
这是我们持续集成中最令人兴奋、最重要的部分。
系统测试在测试需要大量使用
JavaScript(React 或 Vue 应用)的复杂 UI 以及与外部服务(例如)交互时非常有用。Google
Map Places
系统测试将模拟普通用户,像普通用户一样在我们的应用程序上点击并填写输入。
此阶段执行的主要命令是bundle exec rails test:system
。
在这种情况下,交互事实是使用容器嵌入运行真实浏览器来获取和测试我们的前端。Selenium
Chrome browser
部署阶段
这是一个简单的步骤,我们将把我们的应用程序部署到暂存环境。
GITLAB-CI
Gitlab 为所有人提供了一个方案(我们应该感谢他们
所做的一切工作),该方案定义了如何测试/部署代码
以及执行这些任务所需的所有服务。
所有说明都存储.gitlab-ci
在我们仓库的根目录中。
这为我们提供了一种集中且简单的方法来管理我们的源代码和
持续的集成FREE
。
它是如何工作的
CI 遵循以下简单步骤:
- 启动
services
您在.gitlab-ci
- 将您的 repo 复制到主容器中。
- 运行其中所需的所有脚本
使用缓存加速 CI
Gitlab 允许我们缓存文件夹和文件,并在后续任务中使用它们。
无需重新编译所有依赖项,甚至无需下载它们。
就我们的情况而言,缓存所有依赖gems
项node_modules
可以节省几分钟时间。
使用工件来调试我们的测试
当系统测试失败时,测试将保存screenshots
在一个temp
文件夹中。
这artifacts
使我们能够保存这些文件并将它们与工作联系起来。
当我们想要调试失败的系统测试时,这将对我们有很大帮助。
我们开始做吧
1. 构建
准备构建容器
构建将在容器中执行,因此我们应该有一个包含
所有所需依赖项的容器。
对于现代 Rails 应用程序,我们应该包括:
- 红宝石
- 节点 + 纱线
- 一些系统库
这是dockerfile
FROM ruby:2.4.3
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update -qqy && apt-get install -qqyy yarn nodejs postgresql postgresql-contrib libpq-dev cmake
RUN rm -rf /var/lib/apt/lists/*
简单呀!
构建容器
docker build .
Sending build context to Docker daemon 2.048kB
Step 1/6 : FROM ruby:2.6.5
2.6.5: Pulling from library/ruby
16ea0e8c8879: Pull complete
50024b0106d5: Pull complete
ff95660c6937: Pull complete
9c7d0e5c0bc2: Pull complete
29c4fb388fdf: Pull complete
069ad1aadbe0: Pull complete
e7188792d9dd: Pull complete
bae7e74440d1: Pull complete
Digest: sha256:2285f291f222e1b53d22449cc52bad2112f519bcce60248ea1c4d5e8f14c7c04
Status: Downloaded newer image for ruby:2.6.5
---> 2ff4e698f315
Step 2/6 : RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
---> Running in abb67e50af3e
Warning: apt-key output should not be parsed (stdout is not a terminal)
OK
Removing intermediate container abb67e50af3e
---> 461e2dd2134d
Step 3/6 : RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
---> Running in 414f508a391c
## Installing the NodeSource Node.js 8.x LTS Carbon repo...
.....
Processing triggers for libc-bin (2.28-10) ...
Removing intermediate container af1183021a8d
---> 603cab5f6952
Step 6/6 : RUN rm -rf /var/lib/apt/lists/*
---> Running in 53c5950a25c1
Removing intermediate container 53c5950a25c1
---> 42b50699301e
Successfully built 42b50699301e
标记
docker tag 42b50699301e registry.gitlab.com/[ORG]/[REPO]/[CONTAINER]:v1
现在,我们应该发布这个容器以使 GitlabCI 能够使用它。
Gitlab
再次免费为我们提供容器注册中心!
因此我们只需要将这个容器推送到项目注册表中。
首先,你应该登录 gitlab registry
docker login registry.gitlab.com
# use your gitlab credential
并推
docker push registry.gitlab.com/[ORG]/[REPO]/[CONTAINER]:v1 # v1 is my version tag
如果您的ADSL
网络连接上传速度较慢,您可以去
小睡一会儿 ;)
一旦推送完成,我们就可以进入下一步。
构建脚本
这是 gitlab-ci 文件中的主要构建部分
image: "registry.gitlab.com/[ORG]/[REPO]/[CONTAINER]:v1"
variables:
LC_ALL: C.UTF-8
LANG: en_US.UTF-8
LANGUAGE: en_US.UTF-8
RAILS_ENV: "test"
POSTGRES_DB: test_db
POSTGRES_USER: runner
POSTGRES_PASSWORD: ""
# cache gems and node_modules for next usage
.default-cache: &default-cache
cache:
untracked: true
key: my-project-key-5.2
paths:
- node_modules/
- vendor/
- public/
build:
<<: *default-cache
services:
- postgres:latest
stage: build
script:
- ruby -v
- node -v
- yarn --version
- which ruby
- gem install bundler --no-ri --no-rdoc
- bundle install --jobs $(nproc) "${FLAGS[@]}" --path=vendor
- yarn install
- cp config/database.gitlab config/database.yml
- RAILS_ENV=test bundle exec rake db:create db:schema:load
- RAILS_ENV=test bundle exec rails assets:precompile
因此我们使用之前创建的图像来托管构建。
我们应该在项目中添加 aconfig/database.gitlab
来替换原始
数据库配置,并使用自定义主机和凭据连接到
由 GitlabCI 启动的 postgres 容器。
services:
- postgres:latest
Gitlab 在读取此行时将启动数据库容器(postgress)并
使用之前定义的变量来设置数据库
POSTGRES_DB: test_db
POSTGRES_USER: runner
POSTGRES_PASSWORD: ""
它将config/database.gitlab
告诉我们的 rails 应用程序如何连接数据库
,因此在应用程序启动之前,它将database.yml
被自定义的数据库取代
。
test:
adapter: postgresql
encoding: unicode
pool: 5
timeout: 5000
host: postgres
username: runner
password: ""
database: test_db
2.集成测试脚本
无需对此进行更多解释
integration_test:
<<: *default-cache
stage: test
services:
- postgres:latest
- redis:alpine
script:
- gem install bundler --no-ri --no-rdoc
- bundle install --jobs $(nproc) "${FLAGS[@]}" --path=vendor
- cp config/database.gitlab config/database.yml
- bundle install --jobs $(nproc) "${FLAGS[@]}" --path=vendor
- RAILS_ENV=test bundle exec rake db:create db:schema:load
- RAILS_ENV=test bundle exec rails assets:precompile
- bundle exec rake test
3. 系统测试脚本
实现系统测试的基础设施非常有趣。
要运行测试,我们应该启动一个浏览器(在容器中)并从 rails 服务器(从另一个容器)获取页面。
system_test:
<<: *default-cache
stage: test
services:
- postgres:latest
- redis:alpine
- selenium/standalone-chrome:latest
script:
- gem install bundler --no-ri --no-rdoc
- bundle install --jobs $(nproc) "${FLAGS[@]}" --path=vendor
- cp config/database.gitlab config/database.yml
- export selenium_remote_url="http://selenium__standalone-chrome:4444/wd/hub/"
- bundle install --jobs $(nproc) "${FLAGS[@]}" --path=vendor
- RAILS_ENV=test bundle exec rake db:create db:schema:load
- RAILS_ENV=test bundle exec rails assets:precompile
- bundle exec rake test:system
artifacts:
when: on_failure
paths:
- tmp/screenshots/
我们应该告诉 capybara 使用正确的IP
而不是localhost
,因为这里我们的浏览器
和服务器在两个不同的容器中。
在environment/test.rb
,添加以下行
net = Socket.ip_address_list.detect{|addr| addr.ipv4_private? }
ip = net.nil? ? 'localhost' : net.ip_address
config.domain = ip
config.action_mailer.default_url_options = { :host => config.domain }
Capybara.server_port = 8200
Capybara.server_host = ip
我们应该告诉系统测试在哪里找到chrome driver
控制浏览器、更新application_system_test_case.rb
require "test_helper"
require "socket"
def prepare_options
driver_options = {
desired_capabilities: {
chromeOptions: {
args: %w[headless disable-gpu disable-dev-shm-usage] # preserve memory & cpu consumption
}
}
}
driver_options[:url] = ENV['selenium_remote_url'] if ENV['selenium_remote_url']
driver_options
end
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :selenium, using: :chrome, screen_size: [1400, 1400],
options: prepare_options
end
将会rails system test
截取屏幕截图并保存到tmp/screenshots
如您所见,屏幕截图已存储并附加到工作中,太棒了!
4. 暂存部署
build
如果阶段成功,这将部署我们的代码tests
。
deploy_staging:
stage: deploy
variables:
HEROKU_APP_NAME: YOUR_HEROKU_APP_NAME
dependencies:
- integration_test
- system_test
only:
- master
script:
- gem install dpl
- dpl --provider=heroku --app=$HEROKU_APP_NAME --api-key=$HEROKU_API_KEY
存储HEROKU_API_KEY
在项目设置中的安全位置
有关此内容的更多信息,请参阅Gitlab 变量文档
结论
Gitlab
是一个令人惊叹的项目,它提供了一个非常好的平台,所有东西都
很好地集成在一起,编码体验得到了增强。
最后,让我们希望迁移能够 为项目Google compute engine
提供更好的稳健性和更少的问题。
长住 Gitlab !!
干杯!
这是完整的Gitlab CI
文件