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

推荐订阅源

J
Java Code Geeks
F
Fortinet All Blogs
Martin Fowler
Martin Fowler
M
MIT News - Artificial intelligence
G
Google Developers Blog
P
Proofpoint News Feed
Recent Announcements
Recent Announcements
MyScale Blog
MyScale Blog
D
DataBreaches.Net
Stack Overflow Blog
Stack Overflow Blog
月光博客
月光博客
爱范儿
爱范儿
罗磊的独立博客
腾讯CDC
Hugging Face - Blog
Hugging Face - Blog
博客园 - 叶小钗
Vercel News
Vercel News
酷 壳 – CoolShell
酷 壳 – CoolShell
B
Blog
C
Check Point Blog
美团技术团队
宝玉的分享
宝玉的分享
Microsoft Security Blog
Microsoft Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

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 的性能
如何在 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

參考資源