使用 Jenkins 多机器部署 Node.js 应用

栏目: Node.js · 发布时间: 5年前

内容简介:全部配置详见:安装 GitLab 、Node.js、Publish over SSH 插件今天踩了不少坑。。。

全部配置详见: https://github.com/xuexb/DevOps/tree/master/jenkins-node

目标

  • [x] 负载均衡
  • [ ] 快速回滚
  • [x] 多机部署
  • [ ] 灰度发布

服务说明

  • GitLab - 用来存放示例代码、主动触发编译(Web Hook)
  • Jenkins - 编译
  • Nginx - 域名转发
  • Node.js - 提供多个虚拟的容器做为目标服务器,且这些虚拟机中已经安装 Node.js Yarn PM2 ,因为没有这么多真实的机器,毕竟穷。。。

前置依赖

  • 添加 Hosts : 127.0.0.1 fe.com jenkins.fe.com www.fe.com gitlab.fe.com node1.fe.com node2.fe.com node3.fe.com node4.fe.com node5.fe.com
  • 【可选】创建一个私有的 key : rm -rf ssh/* && ssh-keygen -t rsa -N '' -f ssh/id_rsa ,如果新创建的需要把 ssh/id_rsa.pub 复制到 .envAUTHORIZED_KEYS ,用来免密码登录 Node.js 的各个节点,注意需要使用 Linux 系统生成,macOS Mojave 生成的是 OPENSSH 格式,在 Publish over SSH 插件时有问题,其实你大可以不用生成,使用默认的

域名、端口说明

  • node*.fe.com - 虚拟出来的多个 Node.js 主机,目前是 1-5 个,如 node1.fe.com
  • www.fe.com - 负载均衡到 node1-5
  • jenkins.fe.com - Jenkins 地址
  • gitlab.fe.com - GitLab 地址
  • 宿主:80 - 提供 Nginx 反代
  • 宿主:22 - 提供 GitLab ssh clone 代理
  • node*:3000 - Node.js 容器内部使用 PM2 启动的服务,暴露的 Web Server 端口,由 Nginx 直接使用 容器名称:3000 做转发

GitLab 配置

  1. ssh/id_rsa.pub 公钥配置到帐户中,结合 Jenkins 安全凭证让 Jenkins 可以克隆 GitLab 项目
    使用 Jenkins 多机器部署 Node.js 应用
  2. http://gitlab.fe.com/profile/personal_access_tokens 创建 API token ,并记录下来,因为这个 token 只在第一次显示
    使用 Jenkins 多机器部署 Node.js 应用
  3. http://gitlab.fe.com/admin/application_settings/network#js-outbound-settings 管理员登录,开启 Allow requests to the local network from hooks and services
    使用 Jenkins 多机器部署 Node.js 应用

Jenkins 配置

安装 GitLab 、Node.js、Publish over SSH 插件

  1. 使用 GitLab 的 api token 创建一个 GitLab 插件使用的凭证,注意:
    • API token - 是刚才在 GitLab 创建的 API token
    • ID - 最好别设置,这个会自动生成一个唯一标识,在 pipeline 脚本中使用
    • 描述 - 可以设置描述当前 API token 的功能
    • 使用 Jenkins 多机器部署 Node.js 应用
  2. 系统设置中配置 Publish over SSH 插件,host 为宿主对应的 Node.js 容器名称:
    使用 Jenkins 多机器部署 Node.js 应用
  3. 配置任务的编译后配置,注意:

    • Source files - 匹配需要复制的源文件
    • Remove prefix - 删除的目录前缀,其实就是替换路径的意思
    • Remote directory - 远程路径,有个坑的是这里是基于 Publish over SSh 系统配置里的 Remote directory 的相对路径
    • Exec command - 执行命令
    • 使用 Jenkins 多机器部署 Node.js 应用
  4. 系统设置中配置 GitLab 插件,注意:由于是通过 Jenkins 容器向 GitLab 连接,host 需要是 GitLab 的容器名 gitlab :

    使用 Jenkins 多机器部署 Node.js 应用

  5. 添加一个 gitlab-root 的凭证用于克隆项目,注意:这里的私钥是 ssh/id_rsa 的内容,因为对应的公钥已经在 GitLab root 用户中添加了,这样就可以使用 gitlab-root 这个凭证克隆项目了,还要注意那个 host ,需要是 GitLab
    使用 Jenkins 多机器部署 Node.js 应用
    使用 Jenkins 多机器部署 Node.js 应用
  6. 全局 工具 里配置 Node.js ,这里以 v10.x 为例
    使用 Jenkins 多机器部署 Node.js 应用

难题

今天踩了不少坑。。。

1. 密钥、公钥

  1. 需要把密钥配置在 Jenkins 里一个凭据,在 GitLab 里添加公钥以让可以克隆项目
  2. 密钥需要配置到 .env 中,然后会透传给 https://hub.docker.com/r/dockerxman/docker-ubuntu-ssh/ 让其创建的 Node.js 虚拟服务器都可以使用公钥直接登录
  3. Publish over SSH 需要使用密钥,使其可以直接 SSH 免密码登录到 Node.js 虚拟服务器
  4. ssh key 不能使用 macOS Mojave 系统创建,否则不能过 Publish over SSH

2. Docker 配置的环境变量在 SSH 登录后不生效

为了更好的测试各个 Node.js 虚拟服务器分布,需要给每个虚拟服务器里配置个配置 ENV_LABEL ,表示当前服务器标签名,并在 Node.js 里设置了 Response.headers 的 X-Node-Label 字段,但发现在目标服务里的 Node.js 里获取不到,经过百般测试,发现需要:

  • 首先需要在 Docker 里对各个虚拟 Node.js 服务器配置变量,在 docker-compose.yml 文件对对各个节点配置 environment
  • 在 Node.js 虚拟服务器的 Dockerfile 里以自定义文件 env.sh 为入口(CMD),并在 env.sh 里向目标服务器写入到 ~/.env 为当前变量(因为在 docker-compose.yml 里配置的变量,在 Dockerfile 里可以读取到),如:
#!/bin/bash

# 写入一个标签变量,因为在 docker-compose.yml 里配置的使用 ssh 登录获取不到
echo "ENV_LABEL=$ENV_LABEL" > /root/.env
echo '[ -s "$HOME/.env" ] && \. "$HOME/.env"' >> /root/.bashrc

# 运行 dockerxman/docker-ubuntu-ssh:latest 的入口文件
if [ -f /run.sh ]; then
    /run.sh
fi
  • 在部署的 Node.js 项目中的部署脚本里需要先读到 $HOME/.env ,这样在部署脚本里就可以获取变量,但在 PM2 或者 Node.js 代码里还是获取不到,需要在部署脚本里 export 变量=${变量} 透传才可以
  • 由于 Node.js 项目由 PM2 启动,在 PM2 里的变量需要透传到 Node.js app 中,如 pm2.config.js PM2 启动配置:
module.exports = {
    apps: [
        {
            name: 'app',
            script: './index.js',
            env: {
                NODE_ENV: 'production',

                // 透传变量
                ENV_LABEL: process.env.ENV_LABEL,
            },
        },
    ],
};

Jenkins 任务日志

13:50:38 Started by user admin
13:50:38 Building in workspace /var/jenkins_home/workspace/node-demo
13:50:38 [WS-CLEANUP] Deleting project workspace...
13:50:38 [WS-CLEANUP] Deferred wipeout is used...
13:50:38 [WS-CLEANUP] Done
13:50:38 Cloning the remote Git repository
13:50:38 Cloning repository git@gitlab:root/node-demo.git
13:50:38  > git init /var/jenkins_home/workspace/node-demo # timeout=10
13:50:38 Fetching upstream changes from git@gitlab:root/node-demo.git
13:50:38  > git --version # timeout=10
13:50:38 using GIT_SSH to set credentials gitlab-root
13:50:38  > git fetch --tags --progress git@gitlab:root/node-demo.git +refs/heads/*:refs/remotes/origin/*
13:50:40  > git config remote.origin.url git@gitlab:root/node-demo.git # timeout=10
13:50:40  > git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
13:50:40  > git config remote.origin.url git@gitlab:root/node-demo.git # timeout=10
13:50:40 Fetching upstream changes from git@gitlab:root/node-demo.git
13:50:40 using GIT_SSH to set credentials gitlab-root-ssh
13:50:40  > git fetch --tags --progress git@gitlab:root/node-demo.git +refs/heads/*:refs/remotes/origin/*
13:50:41  > git rev-parse refs/remotes/origin/master^{commit} # timeout=10
13:50:42  > git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
13:50:42 Checking out Revision f6d9691839f578a4f880260871e2a39a263d2e45 (refs/remotes/origin/master)
13:50:42  > git config core.sparsecheckout # timeout=10
13:50:42  > git checkout -f f6d9691839f578a4f880260871e2a39a263d2e45
13:50:43 Commit message: "feat: fest"
13:50:43  > git rev-list --no-walk f6d9691839f578a4f880260871e2a39a263d2e45 # timeout=10
13:50:43 [node-demo] $ /bin/sh -xe /tmp/jenkins6335245445213181284.sh
13:50:43 + yarn -v
13:50:44 1.13.0
13:50:44 + node -v
13:50:44 v10.15.0
13:50:44 + npm -v
13:50:46 6.4.1
13:50:46 + yarn install
13:50:47 yarn install v1.13.0
13:50:47 [1/4] Resolving packages...
13:50:47 [2/4] Fetching packages...
13:50:47 [3/4] Linking dependencies...
13:50:49 [4/4] Building fresh packages...
13:50:49 Done in 2.55s.
13:50:49 + yarn test
13:50:50 yarn run v1.13.0
13:50:50 $ echo 'test'
13:50:50 test
13:50:50 Done in 0.27s.
13:50:50 + yarn build
13:50:51 yarn run v1.13.0
13:50:51 $ mkdir -p dist && ls | grep -vE '(README\.md|dist)' | xargs -I {} cp -r {} dist/
13:50:53 Done in 2.56s.
13:50:53 SSH: Connecting from host [541f45e72785]
13:50:53 SSH: Connecting with configuration [Node-1] ...
13:50:53 SSH: EXEC: STDOUT/STDERR from command [/bin/bash /root/app/deploy.sh] ...
13:50:54 Deploy in node1
13:50:54 v11.6.0
13:50:54 6.5.0-next.0
13:50:55 3.2.7
13:50:55 1.13.0
13:50:55 yarn install v1.13.0
13:50:55 [1/4] Resolving packages...
13:50:55 success Already up-to-date.
13:50:55 Done in 0.21s.
13:50:56 [PM2] Applying action reloadProcessId on app [app](ids: 0)
13:50:56 [PM2] [app](0) ✓
13:50:56 ┌──────────┬────┬─────────┬──────┬─────┬────────┬─────────┬────────┬─────┬───────────┬──────┬──────────┐
13:50:56 │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem       │ user │ watching │
13:50:56 ├──────────┼────┼─────────┼──────┼─────┼────────┼─────────┼────────┼─────┼───────────┼──────┼──────────┤
13:50:56 │ app      │ 0  │ 1.0.0   │ fork │ 983 │ online │ 1       │ 0s     │ 0%  │ 10.9 MB   │ root │ disabled │
13:50:56 └──────────┴────┴─────────┴──────┴─────┴────────┴─────────┴────────┴─────┴───────────┴──────┴──────────┘
13:50:56  Use `pm2 show <id|name>` to get more details about an app
13:50:56 SSH: EXEC: completed after 2,613 ms
13:50:56 SSH: Disconnecting configuration [Node-1] ...
13:50:56 SSH: Transferred 5 file(s)
13:50:56 SSH: Connecting from host [541f45e72785]
13:50:56 SSH: Connecting with configuration [Node-2] ...
13:50:56 SSH: EXEC: STDOUT/STDERR from command [/bin/bash /root/app/deploy.sh] ...
13:50:57 Deploy in node2
13:50:57 v11.6.0
13:50:57 6.5.0-next.0
13:50:57 3.2.7
13:50:57 1.13.0
13:50:58 yarn install v1.13.0
13:50:58 [1/4] Resolving packages...
13:50:58 success Already up-to-date.
13:50:58 Done in 0.19s.
13:50:58 [PM2] Applying action reloadProcessId on app [app](ids: 0)
13:50:58 [PM2] [app](0) ✓
13:50:58 ┌──────────┬────┬─────────┬──────┬─────┬────────┬─────────┬────────┬─────┬───────────┬──────┬──────────┐
13:50:58 │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem       │ user │ watching │
13:50:58 ├──────────┼────┼─────────┼──────┼─────┼────────┼─────────┼────────┼─────┼───────────┼──────┼──────────┤
13:50:58 │ app      │ 0  │ 1.0.0   │ fork │ 972 │ online │ 1       │ 0s     │ 0%  │ 10.8 MB   │ root │ disabled │
13:50:58 └──────────┴────┴─────────┴──────┴─────┴────────┴─────────┴────────┴─────┴───────────┴──────┴──────────┘
13:50:58  Use `pm2 show <id|name>` to get more details about an app
13:50:58 SSH: EXEC: completed after 2,408 ms
13:50:58 SSH: Disconnecting configuration [Node-2] ...
13:50:58 SSH: Transferred 5 file(s)
13:50:58 SSH: Connecting from host [541f45e72785]
13:50:58 SSH: Connecting with configuration [Node-3] ...
13:50:59 SSH: EXEC: STDOUT/STDERR from command [/bin/bash /root/app/deploy.sh] ...
13:50:59 Deploy in node3
13:50:59 v11.6.0
13:50:59 6.5.0-next.0
13:51:00 3.2.7
13:51:00 1.13.0
13:51:00 yarn install v1.13.0
13:51:00 [1/4] Resolving packages...
13:51:00 success Already up-to-date.
13:51:00 Done in 0.18s.
13:51:01 [PM2] Applying action reloadProcessId on app [app](ids: 0)
13:51:01 [PM2] [app](0) ✓
13:51:01 ┌──────────┬────┬─────────┬──────┬─────┬────────┬─────────┬────────┬─────┬───────────┬──────┬──────────┐
13:51:01 │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem       │ user │ watching │
13:51:01 ├──────────┼────┼─────────┼──────┼─────┼────────┼─────────┼────────┼─────┼───────────┼──────┼──────────┤
13:51:01 │ app      │ 0  │ 1.0.0   │ fork │ 684 │ online │ 1       │ 0s     │ 0%  │ 20.0 MB   │ root │ disabled │
13:51:01 └──────────┴────┴─────────┴──────┴─────┴────────┴─────────┴────────┴─────┴───────────┴──────┴──────────┘
13:51:01  Use `pm2 show <id|name>` to get more details about an app
13:51:01 SSH: EXEC: completed after 2,409 ms
13:51:01 SSH: Disconnecting configuration [Node-3] ...
13:51:01 SSH: Transferred 5 file(s)
13:51:01 SSH: Connecting from host [541f45e72785]
13:51:01 SSH: Connecting with configuration [Node-4] ...
13:51:01 SSH: EXEC: STDOUT/STDERR from command [/bin/bash /root/app/deploy.sh] ...
13:51:02 Deploy in node4
13:51:02 v11.6.0
13:51:02 6.5.0-next.0
13:51:03 3.2.7
13:51:03 1.13.0
13:51:03 yarn install v1.13.0
13:51:03 [1/4] Resolving packages...
13:51:03 success Already up-to-date.
13:51:03 Done in 0.19s.
13:51:04 [PM2] Applying action reloadProcessId on app [app](ids: 0)
13:51:04 [PM2] [app](0) ✓
13:51:04 ┌──────────┬────┬─────────┬──────┬─────┬────────┬─────────┬────────┬─────┬───────────┬──────┬──────────┐
13:51:04 │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem       │ user │ watching │
13:51:04 ├──────────┼────┼─────────┼──────┼─────┼────────┼─────────┼────────┼─────┼───────────┼──────┼──────────┤
13:51:04 │ app      │ 0  │ 1.0.0   │ fork │ 685 │ online │ 1       │ 0s     │ 0%  │ 20.3 MB   │ root │ disabled │
13:51:04 └──────────┴────┴─────────┴──────┴─────┴────────┴─────────┴────────┴─────┴───────────┴──────┴──────────┘
13:51:04  Use `pm2 show <id|name>` to get more details about an app
13:51:04 SSH: EXEC: completed after 2,809 ms
13:51:04 SSH: Disconnecting configuration [Node-4] ...
13:51:04 SSH: Transferred 5 file(s)
13:51:04 SSH: Connecting from host [541f45e72785]
13:51:04 SSH: Connecting with configuration [Node-5] ...
13:51:04 SSH: EXEC: STDOUT/STDERR from command [/bin/bash /root/app/deploy.sh] ...
13:51:05 Deploy in node5
13:51:05 v11.6.0
13:51:05 6.5.0-next.0
13:51:05 3.2.7
13:51:06 1.13.0
13:51:06 yarn install v1.13.0
13:51:06 [1/4] Resolving packages...
13:51:06 success Already up-to-date.
13:51:06 Done in 0.18s.
13:51:06 [PM2] Applying action reloadProcessId on app [app](ids: 0)
13:51:07 [PM2] [app](0) ✓
13:51:07 ┌──────────┬────┬─────────┬──────┬─────┬────────┬─────────┬────────┬─────┬───────────┬──────┬──────────┐
13:51:07 │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem       │ user │ watching │
13:51:07 ├──────────┼────┼─────────┼──────┼─────┼────────┼─────────┼────────┼─────┼───────────┼──────┼──────────┤
13:51:07 │ app      │ 0  │ 1.0.0   │ fork │ 685 │ online │ 1       │ 0s     │ 0%  │ 19.2 MB   │ root │ disabled │
13:51:07 └──────────┴────┴─────────┴──────┴─────┴────────┴─────────┴────────┴─────┴───────────┴──────┴──────────┘
13:51:07  Use `pm2 show <id|name>` to get more details about an app
13:51:07 SSH: EXEC: completed after 2,409 ms
13:51:07 SSH: Disconnecting configuration [Node-5] ...
13:51:07 SSH: Transferred 5 file(s)
13:51:07 Finished: SUCCESS

最终效果

每个 Node.js 服务都带有当前环境标签:

使用 Jenkins 多机器部署 Node.js 应用

使用 Jenkins 多机器部署 Node.js 应用

负载均衡入口:

使用 Jenkins 多机器部署 Node.js 应用

使用 Jenkins 多机器部署 Node.js 应用

参考连接


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Realm of Racket

Realm of Racket

Matthias Felleisen、Conrad Barski M.D.、David Van Horn、Eight Students Northeastern University of / No Starch Press / 2013-6-25 / USD 39.95

Racket is the noble descendant of Lisp, a programming language renowned for its elegance and power. But while Racket retains the functional goodness of Lisp that makes programming purists drool, it wa......一起来看看 《Realm of Racket》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器