Rails大作业管理:Gitlab CI/CD docker部署以及外网访问

在当Ruby课助教的过程中,老师提出了一个需求,既然我们都使用Gitlab,不如让学生的Rails项目都跑CI/CD,每次提交都自动部署,并且外网能够访问,这样让学生能够尝试CI/CD过程,又方便老师查看大作业的完成情况。

搭建Runner环境

在真实进行尝试之前,设计了两种方案,主要分别对应Gitlab Runner的shell executor和docker executor。从安全性和整合性的角度考虑,肯定是docker executor要较优一些,但是docker executor在执行完之后就会退出,所以最后一步就是将项目部署到其他站点,对于我们的场景显然是提高了复杂程度。当然画图技能是要同时锻炼一下的。第一张图中的Docker Runner其实应该是Docker + Runner with shell executor。
Rails大作业管理:Gitlab CI/CD docker部署以及外网访问_第1张图片
Rails大作业管理:Gitlab CI/CD docker部署以及外网访问_第2张图片

所以最后选择了shell executor的方案,同时为了安全和隔离,给每个gitlab-runner都打包一个docker环境,这样每个学生都对应一个docker容器,即使使用shell executor,他们也没办法破坏宿主机环境和其他同学的环境。而外网访问就可以通过docker的端口映射来做。

CSDN的markdown对Dockerfile的支持不太好,勉强这样看看吧。其中的注释也不删除了,可以看看在最终完成完整的Dockerfile之前都做了哪些探索工作。很多地方其实主要是为了GFW做的,不然很多软件源直接用原有的就行。

一开始是pull了gitlab-runner镜像然后bash进去装Rails环境,然后再commit成为新的base镜像,但是就是无论如何怎么都不能把gitlab-runner用户的bundle source配置成国内镜像,之前一直还用root用户配置,但bundle source配置是在home目录下所以更不可能配置好了。后来意识到这一点,于是切换到gitlab-runner用户去配置,但依然不能使用,查看了volume才知道,这个镜像把gitlab-runner的home目录作为一个volume挂载,所以我所有的用户配置都是无法保存的。
所以后来还是用Dockerfile从基础的ubuntu镜像安装所有的软件来做,有很多软件通过官方途径被GFW拦了,所以先下下来,通过COPY命令拷进镜像。配置如下的Dockerfile,然后执行sudo docker build -t hujuntao:gitlab-runner-base .建立一个image。

FROM ubuntu:16.04

""" apt source """
RUN apt-get update
RUN apt-get install -y apt-transport-https
RUN mv /etc/apt/sources.list /etc/apt/sources.list.old
COPY ./sources.list /etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y wget

""" install gitlab-runner """
COPY ./gitlab-runner-linux-amd64 /usr/local/bin/gitlab-runner
RUN chmod a+x /usr/local/bin/gitlab-runner
RUN useradd --create-home gitlab-runner --shell /bin/bash
RUN gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
# RUN gitlab-runner start # no use
RUN apt-get install -y git

""" install node.js """
# RUN apt-get install -y curl
# RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
# COPY ./setup_8.x /root/setup_8.x
# RUN bash /root/setup_8.x
# RUN apt-get install -y nodejs
RUN apt-get install xz-utils
RUN mkdir /usr/local/lib/nodejs
COPY ./node-v8.12.0-linux-x64.tar.xz /root/node-v8.12.0-linux-x64.tar.xz
RUN tar -xJvf /root/node-v8.12.0-linux-x64.tar.xz -C /usr/local/lib/nodejs
RUN mv /usr/local/lib/nodejs/node-v8.12.0-linux-x64 /usr/local/lib/nodejs/node-v8.12.0
RUN ln -s /usr/local/lib/nodejs/node-v8.12.0/bin/node /usr/bin/node
RUN ln -s /usr/local/lib/nodejs/node-v8.12.0/bin/npm /usr/bin/npm

# RUN su gitlab-runner
# RUN echo "export NODEJS_HOME=/usr/local/lib/nodejs/node-v8.12.0/bin" >> ~/.profile
# RUN echo "export PATH=$NODEJS_HOME:$PATH" >> ~/.profile
# RUN tail ~/.profile
# RUN exit

""" isntall ruby 2.5.1 """
# RUN apt-get update
# RUN apt-get install -y ruby-full zlib1g-dev libsqlite3-dev build-essential
RUN apt-get install -y libsqlite3-dev build-essential
COPY ./ruby-install-0.7.0.tar.gz /root/ruby-install-0.7.0.tar.gz
# RUN mkdir /root/ruby-install-0.7.0
RUN tar -xzvf /root/ruby-install-0.7.0.tar.gz -C /root
RUN cd /root/ruby-install-0.7.0 && make install
RUN ruby-install --system ruby 2.5.1
RUN gem environment

""" configure permission for installing """
RUN chmod -R a+wX /usr/local/lib/ruby/gems/2.5.0
RUN chmod a+w /usr/local/bin
RUN npm root -g
RUN chmod a+w /usr/local/lib/nodejs/node-v8.12.0/lib/node_modules
RUN chmod a+w /usr/bin

""" configure the source of gem and bundler """
# RUN su gitlab-runner
USER gitlab-runner
RUN gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/
RUN gem install bundle
RUN bundle config mirror.https://rubygems.org https://gems.ruby-china.com
RUN bundle config
RUN gem install rails sqlite3 puma sass-rails uglifier coffee-rails turbolinks jbuilder bootsnap
RUN gem install tzinfo-data
RUN npm config set registry https://registry.npm.taobao.org
# RUN npm install -g cnpm  --registry=https://registry.npm.taobao.org
# RUN cnpm install -g nrm
# RUN nrm use taobao
# RUN exit
USER root

""" copy script for stop puma server """
COPY ./puma-stop /usr/local/bin
RUN chmod a+x /usr/local/bin/puma-stop

""" keep running """
CMD tail -f /dev/null

关于运行CI/CD

.gitlab-ci.yml文件示例

test:
	stage: test
	script:
	- bundle install
	- rails db:migrate RAILS_ENV=test
	- rails test

deploy:
	stage: deploy
	script:
	- puma-stop
	- bundle install
	- rails db:migrate
	- nohup rails server -d -b 0.0.0.0 -p 3000 &
	only:
	- master

首先要注意的是我们使用了-d以及&参数来使rails后台运行,因为docker中的runner不是multi-runner。如果不使用这些参数的话,pipeline中的这个job就会一直停留在前台,处于running状态,即使你cancel掉这个job,仍然会有一个gitlab login的session存在,导致后面的pipeline都stuck。同时显示指定了监听0.0.0.0,否则只会响应本地的请求。

另外我们使用了两次rails db:migrate,因为test和deploy的环境是不一样的,但是其实bundle install可以只需要执行一次,因为bundle的包是安装在全局的。

puma-stop是我自己写的一个脚本,用于停止之前后台运行的rails服务。其中第一行的[t]的作用是防止grep匹配到自己。

line=$(ps aux | grep "[t]cp://0\.0\.0\.0:3000")
re="gitlab-\+\s[[:digit:]]+\s.*"
if [[ line ~= re ]]; then
	kill $BASH_MATCHES[0]
fi

读取学号csv创建runner

[ "$UID" = "" ] || {
        echo "sudo required"
        exit 1
}
if [ $# -eq 0 ]; then
        echo "Usage: xxx.sh [STUDENT_CSV]" 1>&2
        exit 1
fi

cat $1 | while IFS="," read id token port
do
        docker create --name gitlab-runner-$id --publish $port:3000 hujuntao/rails-runner:v1.0
        docker start gitlab-runner-$id
        docker exec gitlab-runner-$id gitlab-runner register --non-interactive --url "http://ruby-git.act.buaa.edu.cn" --registration-token "$token" --executor "shell" --description "shell-runner" --tag-list "rails,nodejs" --run-untagged --locked="false"
        docker exec gitlab-runner-$id sh -c "su gitlab-runner && bundle config mirror.https://rubygems.org https://gems.ruby-china.com"
        docker exec gitlab-runner-$id gitlab-runner start
done

你可能感兴趣的:(Ruby,虚拟化)