GitLab+Jenkins+Rsync+PM2实现Node项目的持续集成与自动部署

前言

最原始的软件开发流程是,在本地搭建好环境,进行开发测试,然后去服务器上搭建环境,手动上传代码,运行测试,然后启动服务。实际上,近些年来出现了很多的工具,使得这些步骤可以自动化,大大降低人工出错的概率,提高生产效率。下面,我就把GitLab+Jenkins+Rsync+PM2实现的Node项目的持续集成以及自动部署的实验过程记录下来。

搭建环境

需要两台服务器作为演示,A主要进行代码管理、构建和分发,B主要运行实际应用。我这边系统使用的是Debian系的。

服务器A

GitLab

准备工作:

apt-get update
apt-get install curl openssh-server ca-certificates postfix

安装postfix的时候,选internet site,之后的 system mail name 填写你的服务器的IP地址。

准备好后开始安装:

curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | sudo bash
apt-get install gitlab-ee

如果 apt 下载很慢可以手动下载 https://packages.gitlab.com/gitlab/gitlab-ee/packages/ubuntu/trusty/gitlab-ee_10.2.2-ee.0_amd64.deb 然后用 dpkg -i 的方式安装。装了这个过后 NGINX, Postgres, Redis 就都装好了。

配置:

GitLab默认会占用80、8080和9090端口,Jenkins默认也会使用8080端口,所以将GitLab的默认端口为60200、60201、60202(你可以随意定制)

vim /etc/gitlab/gitlab.rb 修改

external_url 'http://<你的服务器ip>:60200'
unicorn['port'] = 60201
prometheus['listen_address'] = 'localhost:60202'

注意不能有多余空格。gitlab-ctl reconfigure生效配置,gitlab-ctl start启动。
如果要想发邮件的话还要配置第三方邮件 vim /etc/gitlab/gitlab.rb

gitlab_rails['smtp_enable'] = true 
gitlab_rails['smtp_address'] = "smtp.exmail.qq.com"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "***#**"
gitlab_rails['smtp_password'] = "**************"
gitlab_rails['smtp_domain'] = "qq.com"
gitlab_rails['smtp_authentication'] = :login 
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = true
gitlab_rails['gitlab_email_from'] = "***#**"
user["git_user_email"] = "***#**"

然后生效重启,打开http://<你的服务器IP>:60200访问,

Jenkins

准备工作:

wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u151-b12/e758a0de34e24606bca991d704f6dcbf/jdk-8u151-linux-x64.tar.gz"
tar xzvf jdk-8u151-linux-x64.tar.gz -C /usr/local/  
vim /etc/profile #(加入环境变量)
    export JAVA_HOME=/usr/local/jdk1.8.0_151
    export PATH=$JAVA_HOME/bin:$PATH

退出,source /etc/profile 生效,用 java -version 验证是否装好java。

开始安装:

curl -O http://mirrors.jenkins.io/war-stable/latest/jenkins.war 下载Jenkins,
nohup java -jar jenkins.war --httpPort=60203 & 后台启动并指定端口。
至此,Jenkins安装成功,可以用浏览器打开 http://<你的服务器ip>:60203
然后安装必要的插件(会提示你),依次点击 “系统管理” “管理插件”。
切换到“可选插件”,分别搜索“GitLab Plugin”和“Git Plugin”,然后点击“直接安装”。如果在“可选插件”里没有搜到,可能自带安装了

Node

apt-get update
apt-get install -y build-essential curl
curl -sL https://deb.nodesource.com/setup_8.x | bash 
apt-get install -y nodejs
node -v
v8.9.2
npm -v
5.5.1

Rsync

这个服务器主要使用Rsync来发布文件,所以不需要特殊配置,一般Linux都默认安装了,如果没有,则使用 apt-get install rsync。然后配置Rsync密码

echo "123" >> /etc/rsync.password
chmod -R 600 /etc/rsync.password

服务器B

Node

如A

PM2

npm install -g pm2
pm2 -v
2.8.0

Rsync

为了安全性不要直接使用ssh账号密码或者公钥私钥,而是构建Rsync服务。vim /etc/rsyncd.conf,修改配置,下面的配置只是一个示例,生产环境还要更安全的策略。

##rsyncd.conf start##
uid = root
gid = root
use chroot = yes
max connections = 200
timeout = 300
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log
ignore errors
read only = false
list = false
hosts allow = * 
hosts deny =10.0.8.9
auth users = backuser
secrets file = /etc/rsync.password
[webapp]
path = /var/webapp/

上面的的路径path不存在则需要创建 mkdir /var/webapp
echo "backuser:123" >> /etc/rsync.password 添加账号和密码,密码要与客户端(A)一直
chmod -R 600 /etc/rsync.password 修改权限
rsync --daemon 以守护进程方式来启动rsync服务
chkconfig rsync on将此服务设置成为开机自启动

应用开发

用express开发一个 hello world 作为演示,在本地工程目录

npm init #(按照提示输入参数)
npm install express --save  #(安装express)

然后创建app.js

var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello World!');
});

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});

node app.js 运行,然后http://localhost:3000/ 会得到 hello world

新建app.json

{
    "apps" : [
        {
            "name"        : "app",
            "script"      : "app.js",
            "log_date_format"  : "YYYY-MM-DD HH:mm:SS",
            "env": {
                "NODE_ENV": "production"
            },
            "watch" : [
                "app.js",
                "router",
                "util"
            ],
            "ignore_watch" : [
                "logs",
                "node_modules",
                "test"
            ]
        }
    ]
}

将代码上传至服务器B,然后 pm2 start app.json 运行 即可在浏览器访问 http://B-ip:3000 得到 hello world

持续集成和自动部署

配置 Gitlab

首次登陆的密码是会提示你去服务器找,用户是root,然后修改你的用户账号信息,添加你自己常用的电脑上的git公钥。
创建一个新项目 webapp ,创建好过后项目会显示该项目对应的用户信息(会提示你修改)

Git global setup

git config --global user.name "MageekChiu"
git config --global user.email "mageekchiu@mail.**.cn"

在本地项目目录下,新建 .gitignore 文件(window 要用 命令行 rename才可以)

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

node_modules/

然后执行

git init
git remote add origin git@A-ip:root/webapp.git
git add .
git commit -m "Initial commit"
git push -u origin master

即可提交服务器仓库,以后每次修改都要

git add .
git commit -m "修改备注"

配置 jenkins

首先配置GitLab插件:
打开GitLab,点击“setting”——“Account”,复制“Private token”,或者应该首先生成personal access token。
打开Jenkins,点击“系统管理”——“系统设置”,点击“配置”下拉框,点击“Gitlab”选项配置GitLab
Connection Name 随便,如 gitlab,“Git Host URL”填GitLab的访问地址,
然后Credentials点“Add”——“jenkins”,在弹出框里,“kind”选择“GitLab API Token”,将先前复制的“Private token”粘贴到“API token”输入框中,然后点击“Add”,添加后,Credentials选择刚刚新建的gitlab,
最后点击“test connection”,看到“Success”就成功了。然后点击页面底下的“apply”,再点击“save”

然后配置Git插件:
需要注意的是装Jenkins的机器上一定要装git: apt-get install git 这样Jenkins才能去 gitlab 拉取文件。
打开Jenkins,点击“系统管理”——“系统设置”,点击“配置”下拉框,选择“Git plugin”选项,设置Git插件的全局配置,填入上面的 global setting 如 global user.name等,然后点击“apply”——“save”

生成访问Gitlab的ssh秘钥:
打开GitLab,点击右上角的“setting”—— SSH Keys,就可以进入到添加界面。
在jenkins所在服务器上生成密钥
ssh-keygen -t rsa -C "root@<你服务器的ip地址>" -b 4096
ssh-keygen -t rsa -C "root@" -b 4096
全部按 Enter 使用默认值,这会生成一对公钥和私钥。打开公钥复制到gitlab的添加界面,然后点击“add key”,并记住私钥的存放路径。

创建一个Jenkins Job:
直接点新建,“item name”可以随便起,然后点击“构建一个自由风格的软件项目”,点击“OK”,至此,创建一个Job成功了。然后配置这个job,选择“源码管理”,选择“Git”,然后去GitLab中复制项目地址,粘贴到“Repository URL”,然后点击“credentials”后面的“Add”按钮
在弹出页面里面:
● Kind 选择 SSH Username with private key
● Username 填 root
● PrivateKey 选择 From a file on jenkins master ,然后将服务器的 私钥的存放路径(/root/.ssh/id_rsa ) 粘贴进去
然后点击“Add”,在“credentials”里选择我们刚刚创建的认证方式。如果没报错,说明成功了,点击页面底部的“apply”。如果出错了,会在“Repository URL”和“Credentials”之间显示红色的错误信息。

选择 构建触发器:
选择 Build when a change is pushed to GitLab. 记住这个 GitLab CI Service URL ,点击高级
Secret token 那一行下面 点击 generate。记住这个token
选择 构建:
选择 execute shell

npm install 
WEB_SERVER_IP=B的ip
PROJECT=webapp/
rsync -arqz --delete-before $WORKSPACE/ $WEB_SERVER_IP::$PROJECT --exclude ".git" --password-file=/etc/rsync.password 

这一段代码的主要目的是构建,并分发代码,如果有多个应用服务器就要分发到多个服务器上。

配置gitab的webhook:
点击webapp 项目下面的setting的integrations 输入刚才的 GitLab CI Service URL 和 Secret Token
然后点击add webhook ,再测试一下选择 push events 如果显示Hook executed successfully: HTTP 200 即成功,然后在jenkins里面查看是有一次构建记录的。

这样jenkins就会在代码发生变化时自动拉取代码到本地,构建,然后用rsync分发给各个应用服务器,结合PM2的watch功能实现自动发现代码更新并重启的功能,达到自动部署的目的

最终效果测试

修改代码,把hello world改为hello gitlab+enkins然后 add、commit、push 。在A上面gitlab有提交记录,jenkins有构建记录,在B上面用 pm2 ls 发现项目是restart了,浏览器查看也变成hello gitlab+enkins 了。
尝试成功!
虽然这个配置比较麻烦,但是持续集成和自动部署的带来的好处是更大的:代码有版本管理,可以快速迭代、快速回滚,同时保持高质量、自动多机部署防止人工错误,每次构建都有记录,构建幂等......

参考

http://blog.csdn.net/ruangong1203/article/details/73065410

原文

后记

这个过程已经比较自动化了,但是还是有太多的环境搭建过程,比如webapp一般都会用到mysql、redis、MongoDB等等,一个更自动化的过程应该引入docker,这方面以后有机会再尝试。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342