惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Privacy International News Feed
I
Intezer
T
Tenable Blog
S
Schneier on Security
Project Zero
Project Zero
G
GRAHAM CLULEY
酷 壳 – CoolShell
酷 壳 – CoolShell
小众软件
小众软件
Know Your Adversary
Know Your Adversary
博客园 - 司徒正美
The Cloudflare Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
N
News and Events Feed by Topic
博客园 - 叶小钗
宝玉的分享
宝玉的分享
L
LINUX DO - 热门话题
aimingoo的专栏
aimingoo的专栏
S
Secure Thoughts
Forbes - Security
Forbes - Security
T
The Exploit Database - CXSecurity.com
D
Darknet – Hacking Tools, Hacker News & Cyber Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 【当耐特】
罗磊的独立博客
IT之家
IT之家
H
Hacker News: Front Page
I
InfoQ
云风的 BLOG
云风的 BLOG
S
Security Affairs
M
MIT News - Artificial intelligence
GbyAI
GbyAI
Jina AI
Jina AI
Help Net Security
Help Net Security
Engineering at Meta
Engineering at Meta
大猫的无限游戏
大猫的无限游戏
Webroot Blog
Webroot Blog
L
Lohrmann on Cybersecurity
A
About on SuperTechFans
Attack and Defense Labs
Attack and Defense Labs
The Register - Security
The Register - Security
V
V2EX
G
Google Developers Blog
D
DataBreaches.Net
Apple Machine Learning Research
Apple Machine Learning Research
C
Cybersecurity and Infrastructure Security Agency CISA
J
Java Code Geeks
W
WeLiveSecurity
Cloudbric
Cloudbric
T
Tor Project blog

Nic Lin's Blog

謝明真 - 高效領導力的課後筆記 NFT 開發實戰!基礎智能合約入門 (3) NFT 開發實戰!基礎智能合約入門 (2) NFT 開發實戰!基礎智能合約入門 (1) 如何自我檢測 log4j CVE 漏洞 Rails 如何在資料寫入時記錄來源 IP 位置 如何經營工程師 Youtube 頻道 - Part 8 營收篇 如何經營工程師 Youtube 頻道 - Part 7 酸民文化篇 如何經營工程師 Youtube 頻道 - Part 5 設備器材篇 如何經營工程師 Youtube 頻道 - Part 4 後製剪輯篇 如何經營工程師 Youtube 頻道 - Part 3 文案企劃篇 如何經營工程師 Youtube 頻道 - Part 2 設備器材篇 如何經營工程師 Youtube 頻道 - Part 1 制訂頻道方向篇 如何經營工程師 Youtube 頻道 - Part 0 Rails 中避免 race condition 的最佳實踐(二) Rails 中避免 race condition 的最佳實踐(一) 10 分鐘整合 google sheet 做自動化開發功能週報 經營 Side Project 300 天所帶來的收穫及挑戰 我的 Youtube 影片製作流程 API 設計時必須注意的 HTTP header 底線問題 如何提升你的程式可讀性之實務技巧(三) 如何提升你的程式可讀性之實務技巧(二) 如何提升你的程式可讀性之實務技巧(一) Ruby 中使用 freeze 優化效能的時機 避免 React 中的 useEffect 無限 render 在 Rails 內輕量使用 Vue Component 的最佳實踐 如何在區域網路用 Docker 架設有 SSL 的 Gitlab 從被問到問人,那些我常問的面試問題 [Rails] 如何漂亮寫出可維護的 query (Maintainable Rails Query) 在已知長度情況下優化 slice 的性能 [ReactNative] 如何在 iOS APP 上主動要求用戶評分 Rails 的 scope 為什麼用 lambda? Proc 與 lambda 不同之處 淺談 Active Record 的 Lazy load 特性 Rails 專案搭配 Github Actions 進行 RSpec 自動化測試 JavaScript 中 require, import 的差別及效能 React 效能優化基本招 ES6 箭頭函式 (Arrow functions) 2 個月擁有 6000 用戶 Side project 這樣做(一) 如何讓自己成為失敗的軟體工程師 如何用 Rack::Attack 阻擋 DDOS / 惡意流量 用 OpenSSL 自簽開發用 HTTPS SSL 憑證 為機器加上登入訊息,在 ubuntu 設置登入歡迎詞 Ruby Memoization 性能優化之記憶化 淺談 SSH agent forwarding 和 proxy command 的安全風險與應用 [Rails] Service / Library / Concern 的差異 避免過度的 Defensive Programming 防禦性程式設計 1:1 攪亂器,如何用 Ruby 做可逆推序號 Rails 中的欄位及方法命名原則 [Rails] 用 puma-dev 作為本地開發伺服器 (支援 https 自簽憑證) 將 Rails 專案從手動部屬遷移使用 Capistrano 自動化部屬 工程師提昇自己的教學和簡報技術的方法 [筆記] Rails 3.2 升級 Rails 6.beta 經驗分享 Class method 氾濫帶來什麼問題 RDBMS 課程心得與筆記 常用的 Rails 開發規範 Rest-Client 如何做 Basic Authentication 驗證 [Rails] 何為 tld_lebgth? 遵循 Semantic Versioning 軟體開發語意化版本管理 請直接在 MySQL 裡面直接用 utf8mb4 取代 utf8 如何解決在 awesome print 中遇到 ActionController::Parameters unable to convert unpermitted 如何在 Mac 上升級 PostgreSQL 並遷移資料 如何解決 Mysql2::Error: Incorrect string value 讀書心得 - 「信任因子:信任如何影響大腦運作、激勵員工、達到組織目標」 我是如何寫部落格筆記的 讀書心得 - 「先問,為什麼?:顛覆慣性思考的黃金圈理論,啟動你的感召領導力」 [Rails] 解決 Reset Password 帶來的 token 洩漏問題 我的軟體工程師生涯:如何挑選適合你的公司 Rails 中的 delegate 用法 淺述 SSR SPA 優缺點 Rails 非同步工作請用 Global ID [React] Class Component 傳遞 props 的 2 種方式 好用的隱私權政策 URL 自動生成 Rails 5.1 之後的 tag helper Rails 5.2 Encrypted Credentials 最近面試被給的建議和書單 一般架構需要用到 K8S 嗎 透過 commit SHA 找 github Pull request 從零搭建,如何讓 Rails 跑在 Kubernetes(k8s)(二) React Stateless Functional Components 搞懂 React 中的 state 和 props 物件導向基本原則 SOLID (Ruby Sample) 在以太坊智能合約上是可以預測隨機數的 在台灣租屋必須注意的事 Rails 5 簡單雙向加解密 如何用 ABA 培養自律型員工 不要在 rake task 中定義 method, 請用 RAKE::DSL rails 非hash只想用array輸出page 如何處理陣列裡有重複的值 [Rails] 如何重設你的專案名稱 Ruby on Rails install on Mac 安裝步驟 使用 Friendly_id 與 Babosa 美化你的Rails 網址 Junior Rails 兩個月實戰心得 Devise使用Google實作登入 [iterm2] 如何新增alias 一個新鮮人找尋Rails工作的面試經驗 如何讓兩個資料表建立關聯 routing 的 namespace strong parameter user story 的格式 user story 是什麼?
如何在 Jenkins 上用 Docker 跑 Rails + Rspec 做 CI
Nic Lin · 2019-08-18 · via Nic Lin's Blog

基本上要跑 Rails CI 通常有很多第三方服務搭 integrate 可以做到,但如果你遇到和我的環境類似,也許你可以考慮自己把 Rails 專案用 Docker 包起來後丟到 Jenkins 上去跑。

至於為什麼會這樣做呢?這是我遇到的場景

  • Rails 啟動有 data dependency (Redis 上沒「特別的」資料格式啟動不了)
  • Rails 啟動有特規的套件要裝(apt-get install 沒有的東西、或是要使用低版本的套件之類的…)
  • 沒有要付費使用第三方的 CI
  • 只有已經架好的 Jenkins

如果要能夠讓 Jenkins 把 code 拉下來跑 Rspec 測試,那麼就要去主機上裝很多套件(Ruby / MySQL / Redis / etc),而且還有指定低版本問題,再加上主機也不是只有單獨跑這個專案而已,為了不想要有其他影響的可能,所以最後決定就是把這些問題包到 Docker 裡面,這樣一來就可以把環境的部分處理掉,也可以有效隔離 dependency。

初步想法

這邊希望做到的是,Jenkins 從 Git Server 拉下專案,透過專案 Build image,然後用這個 image run test,所以會有一個場景是 Jenkins 上的 workspace 有了 Rails 專案,透過 Docker build 把 Rails 專案 sync 進容器的部分。

(Jenkins Pull Project) --> (Docker build image) --> (Run docker image)

如果 Docker Image 直接從 Ruby / MySQL / Redis 開始裝起,那每跑一次 Docker image 應該會久到爆炸,這不是一個有效率的作法,所以我們會把固定的環境先包成 Docker base,做一個基礎容器,然後再將 Rails 要用的容器堆疊在上面。

這樣一來,Jenkins 就可以在每次執行任務時,去拉下 Base Image 然後開始 Build Rails 專案,會節省掉要一直重新 Build Base Image 的部分。

所以我們計畫如下

  1. 先製作 Docker Base Image
  2. 包 test 專用 image
  3. 丟到 Jenkins 去跑

Docker Base

在這裡我做了一支 Image Base,主要安裝

  • GPG 指定版本號為 1 系列
  • Ruby 2.6.2
  • MySQL
  • Redis
  • SSDB

Dockfile 看要放哪都可以,這個可以不用放在 Rails 目錄裡。

# Docker Base
FROM ruby:2.6.2
MAINTAINER NicLin

# We don't like apt-get warnings.
ENV DEBIAN_FRONTEND noninteractive

# Basic package
RUN apt-get update && apt-get install -y exiftool build-essential libpq-dev nodejs imagemagick gnupg1
RUN apt-get remove --auto-remove gpg
RUN cp /usr/bin/gpg1 /usr/bin/gpg

# === MySQL ===
RUN apt-get -y install mysql-server mysql-client --no-install-recommends

# === Redis ===
RUN apt-get -y -q install redis-server

# === SSDB ===
RUN wget --no-check-certificate https://github.com/ideawu/ssdb/archive/master.zip
RUN unzip master
RUN cd ssdb-master && make

docker build -t niclin:base .

這包在本地 Build 完後,就推到 Docker Hub 上了,如果有自己的 Server 也可以推自己的。

Test Image

現在我打算包一個「跑 Rspec」專用的 Image,他的生命週期就是

(Build Image) --> (Run Test Case) --> (Remove!)

這裡的 Dockfile 檔案就是直接放在 Rails 根目錄,因為這是每次 Jenkins 拉新的 code 下來要直接 build 的 docker image。

FROM 如果沒有指定自己的 server url,默認就是依照用戶名和 image 名稱直接去 docker hub 上抓

# Using Base Image
FROM niclin/base

MAINTAINER NicLin

# 設定一個程式起始的目錄
ENV APP_HOME /usr/src/app
RUN mkdir -p $APP_HOME

# 在這邊先加入 Gemfile 並 Bundle
COPY Gemfile $APP_HOME/Gemfile
COPY Gemfile.lock $APP_HOME/Gemfile.lock
RUN cd $APP_HOME && bundle install --jobs 4 --without development production

# 將現在(本地)所在專案目錄加入到 Docker Image 內
ADD . $APP_HOME

# 連結需要的檔案
RUN ln -s /usr/bin/convert /usr/local/bin/convert
RUN ln -s /usr/bin/exiftool /usr/local/bin/exiftool

# 加入 Jenkins workspace folder gpg key
# 這是我專案要用到的部分,一般人可能不需要就是了,可以跳過這裡
ADD ./gpg_home $APP_HOME/lib/gpg_home

# 連結需要的設定檔
RUN cp $APP_HOME/config/settings.yml.ci $APP_HOME/config/settings.yml
RUN cp $APP_HOME/config/storage.yml.ci $APP_HOME/config/storage.yml
RUN cp $APP_HOME/config/database.yml.ci $APP_HOME/config/database.yml

RUN cd $APP_HOME && RAILS_ENV=test bundle exec rake assets:precompile

# 設定 Docker 的工作目錄
WORKDIR $APP_HOME

ENTRYPOINT ["/bin/bash", "ci_script.sh"]

上面這隻 Docker image 要用到的東西有

  • config/settings.yml.ci
  • config/storage.yml.ci
  • config/database.yml.ci
  • ci_script.sh

上面 .ci 的部分就是我希望這些設定是只有給 CI server 用的,所以獨立出來。

ci_script.sh 的部分如下

service mysql start &&\
service redis-server start &&\
/ssdb-master/ssdb-server -d start /ssdb-master/ssdb.conf

RAILS_ENV=test bundle exec rake ci:initialize &&\
RAILS_ENV=test bundle exec rake db:create &&\
RAILS_ENV=test bundle exec rake db:migrate &&\
RAILS_ENV=test bundle exec rspec

至於這個啟動腳本就是在 Docker 啟動時直接做,所以放在 ENTRYPOINT 跑

  1. 啟動 MySQL
  2. 啟動 Redis
  3. 啟動 SSDB
  4. 跑 Redis data initialize
  5. 跑 database 建立
  6. 最後一步,跑 Rspec

如果要在自己電腦上先測試,可以在本地可以自己包一遍

docker build -t project:test .

然後直接執行看看會不會跑完整個任務

docker run -it project:test

Jenkins 設定

套件使用:

  • docker build and publish plugin
  1. 拉 Project
  2. shell 前置作業,看有沒有什麼固定檔案要先放的,如果沒有可以跳過此步
  3. 設定 Docker build, Skip publish
  4. shell 跑 docker run

小技巧:docker plugin 中的 build tag 打 $BUILD_NUMBER, 這樣他就會依照數字下去跑類似 project/test:142 ,然後最後一個 shell script 執行

docker run --rm project/test:$BUILD_NUMBER

這樣就可以確保跑完刪掉,一次性的測試,不會塞太多 Image 在 Jenkins Server

參考資源