介绍
随着分布式版本控制系统的出现,特别是GitHub的诞生,引用请求评审合并模型在软件开发社区中得到了普及。然而,GitHub的嵌入式引用请求评审系统留下了许多可取之处。
ReviewNinja添加了一些功能,在GitHub提取请求审查体验的顶部。它使我们能够通过给出忍者星
来明确退出提取请求,所以不再需要评论,例如:shipit:,LGTM或其他流行的惯例,并且您可以设置策略来阻止合并,如果提取请求没有被至少2名团队成员签名,或者如果有人在提取请求上添加评论,如
!fix`。
ReviewNinja是由SAP开发和开源的,它有一个托管版本(LINK0),但我们可以在自己的服务器上部署它,并用于我们的私人GitHub存储库。
在本指南中,你将使用 Docker和 CoreOS在DigitalOcean上部署一个ReviewNinja实例。 一个生产的ReviewNinja实例有几个移动部件,所以我们将使用docker-machine
创建和控制远程Docker主机,以及docker-compose
来描述,构建和部署我们的堆栈。 我们将使用CoreOS用于Docker主机,这是一种针对云部署的最小Linux发行版。
前提条件
要完成本教程,您将需要:
- 安装在本地机器上的Docker、 " Docker-机器 " 和 " Docker-compose " ,这样你就可以建立我们将部署的应用程序图像。 您可以跟随 [正式安装文档] (https://docs.docker.com/engine/installation/] 让 Docker 配置这些工具 。 "多克机"和"多克机-编组"都与OSX和Windows上的多克App自动安装,或者你可以使用这些链接手动安装:
- [多克机-编组安装导 (https://docs.docker.com/machine/install-machine/) -[多克机安装导 (https://docs.docker.com/compose/install/)
- Git安装在本地机上,这样就可以克隆ReviewNinja寄存器来创建容器. 如果您需要满足这一先决条件, 请遵循 [官方 Git 安装文档] (https://git-scm.com/book/en/v2/Getting-Started-Installing-Git ) 。
- 一个既能读又能写的数字海洋访问托肯,您可以通过访问应用程序和API页面来生成. 复制此标志, 因为您需要使用
接线机
来创建主机 。 - 1GB CoreOS Droplet, 我们将在此教程中使用
docker-机器
配置 。 - A [GitHub] (http://github.com) 账户. (英语)
步骤 1 — 创建和激活基于 CoreOS 的 Docker 主机
让我们为我们的部署设置基础设施。docker-machine
工具允许您提供远程机器作为Docker主机,并从您的本地机器中控制它们。它为许多流行的云提供商提供驱动程序,包括DigitalOcean。
切换到您的终端,并使用您的 DigitalOcean Access Token 发出以下命令:
1docker-machine create --driver=digitalocean \
2--digitalocean-access-token=DIGITAL_OCEAN_ACCESS_TOKEN \
3--digitalocean-image=coreos-stable \
4--digitalocean-region=nyc3 \
5--digitalocean-size=1GB \
6--digitalocean-ssh-user=core \
7reviewninja
我们告诉docker-machine
在NYC3
数据中心创建一个名为reviewninja
的Droplet,使用具有1GB
内存的coreos-stable
图像。
当您运行此命令时,您将看到以下输出:
1[secondary_label Output]
2Running pre-create checks...
3Creating machine...
4(reviewninja) Creating SSH key...
5(reviewninja) Creating Digital Ocean droplet...
6(reviewninja) Waiting for IP address to be assigned to the Droplet...
7Waiting for machine to be running, this may take a few minutes...
8Detecting operating system of created instance...
9Waiting for SSH to be available...
10Detecting the provisioner...
11Provisioning with coreOS...
12Copying certs to the local machine directory...
13Copying certs to the remote machine...
14Setting Docker configuration on the remote daemon...
15Checking connection to Docker...
16Docker is up and running!
17To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env reviewninja
让我们看看这个新的Droplet是否被docker-machine
识别出来。
1docker-machine ls
您将看到以下输出,表示 Docker 主机reviewminja
正在使用digitalocean
驱动程序在远程 IP 地址上运行:
1[secondary_label Output]
2NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
3reviewninja digitalocean Running tcp://your_ip_address:2376 v1.10.3
当我们创建 Docker 主机时,输出的最后一行告诉我们接下来要做什么。
1[secondary_label Output]
2To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env reviewninja
让我们运行这个命令:
1docker-machine env reviewninja
你会看到这个消息:
1[secondary_label Output]
2export DOCKER_TLS_VERIFY="1"
3export DOCKER_HOST="tcp://your_server_ip:2376"
4export DOCKER_CERT_PATH="/home/kevin/.docker/machine/machines/reviewninja"
5export DOCKER_MACHINE_NAME="reviewninja"
6# Run this command to configure your shell:
7# eval $(docker-machine env reviewninja)
那么这里发生了什么呢? Docker 架构使用客户端服务器模型。 Docker 客户端可以通过 Unix 接口或通过 TCP 进行通信. 通常,我们的 Docker 客户端会通过 Unix 接口与本地安装的 Docker 引擎交谈。
最后一部分说:
1[secondary_label Output]
2# Run this command to configure your shell:
3# eval $(docker-machine env reviewninja)
当您运行该命令时,您告诉壳执行这些命令,这些命令设置了将用于随后的docker
命令的环境变量。
所以,继续前进,并在你的壳中执行这个命令:
1eval $(docker-machine env reviewninja)
现在,如果你执行docker info
,你会看到有关远程Docker的信息,而不是你的本地Docker的信息:
1docker info
这个命令的输出将是这样的:
1[secondary_label Output]
2Containers: 0
3 Running: 0
4 Paused: 0
5 Stopped: 0
6Images: 0
7Server Version: 1.10.3
8 [...]
9Labels:
10 provider=digitalocean
<$>[注意]
注意:在运行docker
命令时,您可能会收到以下错误:
1Error response from daemon: client is newer than server (client API version: 1.24, server API version: 1.22)
这意味着您正在使用的 Docker 客户端版本与服务器版本不兼容。 要修复此问题,请将环境变量 DOCKER_API_VERSION
设置为与服务器相同的版本。
1export DOCKER_API_VERSION=1.22
然后尝试再次运行 Docker 命令。 <$>
我们的远程 Docker 主机现在通过 Docker 配置和访问,在我们创建一个 ReviewNinja 容器之前,我们需要使用 GitHub 做一些工作。
步骤 2 — 注册 GitHub OAuth 应用程序
ReviewNinja 需要使用 GitHub 的 API 来访问您的存储库,因此我们将注册我们的 ReviewNinja 安装作为 GitHub OAuth 应用程序。
首先我们需要找出我们的服务器的IP地址,我们可以使用docker-machine
命令来做到这一点:
1docker-machine ip reviewninja
记录此命令显示的 IP 地址,然后登录您的 GitHub 帐户,然后进入 设置 -> OAuth 应用程序 -> 开发人员应用程序,然后按一下 ** 注册新应用程序 ** 按钮。
一旦您收到新申请表,请输入以下信息:
- 设置 Name 到
review-ninja
. - 设置 Homepage URL 到
http://your_ip_address
. - 设置 授权回调 URL 到
http://your_ip_address/auth/GitHub/callback
.
然后按 **注册应用程序 ** 按钮来保存更改并创建应用程序. 这将显示在屏幕上新创建的应用程序。
将 Client ID和 Client Secret的值保存到安全的地方;您将很快将它们添加到ReviewNinja应用程序配置中。
现在你有你的密钥,让我们开始构建我们的ReviewNinja实例。
步骤 3 — 创建评论Ninja Docker容器
ReviewNinja 是一个依赖 MongoDB 的存储层的 Node.js 应用程序,并且由于我们将此置于生产环境中,我们会将 Node.js 应用程序置于代理服务器后面,以便应用程序服务器不会直接暴露在互联网上。我们将为此使用 Nginx。这需要配置很多,所以我们将使用 docker-compose以声明的方式部署多个相关容器。我们定义我们想要的配置,然后使用docker-compose
工具创建具有所有指定的运行环境的容器。
首先,我们需要获得ReviewNinja的源代码,使用Git在本地机器上克隆源代码:
1git clone https://github.com/reviewninja/review.ninja.git
然后导航到项目的文件夹:
1cd review.ninja
这个存储库包含一个Dockerfile
,它告诉Docker如何构建ReviewNinja应用程序图像. 如果你在你最喜欢的文本编辑器中打开这个文件,你会看到以下内容:
1[label Dockerfile]
2FROM node:0.12.2
3
4COPY . /app
5
6RUN npm install -g bower
7RUN cd /app; npm install; bower install --allow-root;
8
9WORKDIR /app
10
11VOLUME ["/certs"]
12
13EXPOSE 5000
14
15CMD ["node", "/app/app.js"]
此文件指定该应用程序将使用的 Node.js 版本,然后将当前文件夹中的所有文件复制到应用程序
文件夹中,并安装所有应用程序依赖性,然后暴露端口5000
并启动应用程序。
Dockerfile 描述了 ReviewNinja 应用程序容器,但我们可以描述我们的堆栈的组件,包括 MongoDB 和 Nginx 代理,使用一个名为 docker-compose.yml
的文件,这是一个 YAML 文件,这是一个流行的配置文件格式。
你克隆的存储库有一个名为docker-compose-example.yml
的文件,但我们将从头开始写自己的文件,因为一个例子不符合我们的需求。
首先,让我们为我们的堆栈定义存储空间. 创建文件 docker-compose.yml
并输入以下配置:
1[label docker-compose.yml]
2version: "2"
3services:
4 db:
5 image: mongo
6 volumes:
7 - /data:/data/db
db
服务使用了Docker Hub上的官方MongoDB图像(https://hub.docker.com/_/mongo/),这是Docker图像的中央存储库。根据设计,Docker容器在停止和删除时会失去运行状态。对于Web
服务来说,这很好,因为它没有状态。对于我们的db
服务,我们需要将数据存储到磁盘上,以免在停止或重新启动服务时失去所有代码审查数据。
在我们的配置中,我们指定了以下内容:
1[label docker-compose.yml]
2
3 volumes:
4 - /data:/data/db
这将主机的 /data' 文件夹地图到
/data/db' 在容器中,这发生在 MongoDB 文件夹被配置为写入容器内部。
接下来,我们定义了ReviewNinja应用程序容器,然后在现有配置后将其添加到docker-compose.yml文件中:
1[label docker-compose.yml]
2services:
3 db:
4 [...]
5
6 web:
7 build: .
8 working_dir: /app/
9 links:
10 - db
11 environment:
12 MONGODB: mongodb://db/reviewninja
13 GITHUB_CLIENT: YOUR_GITHUB_APP_ID
14 GITHUB_SECRET: YOUR_GITHUB_APP_SECRET
<$>[注]
注:确保web
与您之前定义为YAML文件的db
服务定义垂直排列,对入口不太清楚。
我們使用「build.」說「docker-compose」說圖像應該是從「Dockerfile」中建立的,我們剛剛在當前的文件夾中探索了它,然後我們宣佈連結到「db」圖像,所以在「web」容器內,名稱「db」將解決到「db」容器的IP地址。這提供了一個原始的服務發現機制;我們不必提前知道「db」容器的IP地址,並硬碼它或通過環境變量傳遞它。
填写GITHUB_CLIENT
和GITHUB_SECRET
以为您创建的GitHub应用程序的客户 ID和秘密。
最后,让我们定义负载平衡服务,将请求从端口80
转发到我们的Node.js应用程序使用的端口。
1[label docker-compose.yml]
2services:
3 web:
4 [...]
5 nginx:
6 image: nginx
7 ports:
8 - "80:80"
9 volumes:
10 - ./reviewninja.conf:/etc/nginx/conf.d/default
11 command: /bin/bash -c "echo -e 'upstream backend { server web:5000; }\nserver { listen 80; location / { proxy_pass http://backend; }}' > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
12 links:
13 - web
我们使用来自 Docker Hub 的 官方 Nginx 图像并声明一个 80:80’ 端口映射,将主机上的
80 端口绑定到容器中的 `80 端口。
命令
声明相当长,所以让我们把它分解下来。它实际上是在单行上运行两个命令。第一个命令是echo -e... > /etc/nginx/conf.d/default.conf
,它创建了 ReviewNinja 的 Nginx config 文件,它看起来像这样:
1[label default.conf]
2upstream backend {
3 server web:5000;
4}
5
6server {
7 listen 80;
8
9 location / {
10 proxy_pass http://backend;
11 }
12}
这定义了上游的后端
,并将其指向web:5000
。值web
来自docker-compose.yml
文件在链接
部分,而端口5000
是Node.js服务器在web
容器中使用的端口。
命令的第二部分,nginx -g``daemon off
是指令在容器中运行 Nginx 服务器流程。我们需要指定daemon off
,因为 Nginx 默认情况下在 daemon 模式下运行,将自己从运行流程中分离出来。Docker 认为从容器入口点分离的任何程序都退出
,并终止容器,收获所有流程。
以下是完整的.dll 文件,如果您想在继续前对配置进行双重检查:
1[label docker-compose.yml]
2version: "2"
3services:
4 db:
5 image: mongo
6 volumes:
7 - /data:/data/db
8 web:
9 build: .
10 working_dir: /app/
11 links:
12 - db
13 environment:
14 MONGODB: mongodb://db/reviewninja
15 GITHUB_CLIENT: YOUR_GITHUB_APP_ID
16 GITHUB_SECRET: YOUR_GITHUB_APP_SECRET
17 nginx:
18 image: nginx
19 ports:
20 - "80:80"
21 volumes:
22 - ./reviewninja.conf:/etc/nginx/conf.d/default
23 command: /bin/bash -c "echo -e 'upstream backend { server web:5000; }\nserver { listen 80; location / { proxy_pass http://backend; }}' > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
24 links:
25 - web
如果您想了解更多关于docker-compose.yml的语法和选项,请参阅 docker-compose 文档。
保存docker-compose.yml
文件;是时候部署这个应用程序了。
步骤 4 – 构建和部署容器
我们已经配置了docker-compose
来部署我们的ReviewNinja应用程序,一个MongoDB实例来存储数据,以及一个Nginx代理。
1docker-machine active
你应该看到:
1[secondary_label Output]
2reviewninja
如果你看不到这个输出,请确保运行
1eval $(docker-machine env reviewninja)
确保您的环境设置正确,然后再试一次。
一旦你确定你有一个活跃的机器,使用docker-compose
来构建你的堆栈:
1docker-compose build
此过程可能需要很长时间,因为它会下载和配置 Docker 主机上的 ReviewNinja 应用程序的所有依赖性。
1[secondary_label Output]
2db uses an image, skipping
3Building web
4Step 1 : FROM node:0.12.2
50.12.2: Pulling from library/node
6[...]
7Successfully built 106a1992d538
一旦构建过程完成,请验证您有成功的图像:
1docker images
您将看到以下输出,表明图像「reviewninja_web」已成功创建:
1[secondary_label Output]
2REPOSITORY TAG IMAGE ID CREATED SIZE
3reviewninja_web latest 106a1992d538 3 minutes ago 946.6 MB
现在我们可以用一个命令在我们的远程服务器上启动我们的数据库、我们的 ReviewNinja 应用程序和我们的 Nginx 代理:
1docker-compose up -d
这带来了我们在docker-compose
文件中定义的所有容器,我们使用-d
(用于分离
)以便所有容器在背景中运行,我们有我们的终端重新控制。
1[secondary_label Output]
2Creating network "reviewninja_default" with the default driver
3Pulling db (mongo:latest)...
4latest: Pulling from library/mongo
5[...]
6Digest: sha256:d3f19457c816bb91c5639e3b1b50f67370e3b3a58b812d73446d7b966469c65e
7Status: Downloaded newer image for mongo:latest
8Creating reviewninja_db_1
9Creating reviewninja_web_1
10Creating reviewninja_nginx_1
让我们检查容器是否已启动并运行. 执行以下命令:
1docker ps
你会看到这样的输出:
1[secondary_label Output]
2CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
329f8e6f770d3 nginx "nginx -g 'daemon off" 43 seconds ago Up 41 seconds 0.0.0.0:80->80/tcp, 443/tcp reviewninja_nginx_1
4164564dd450a reviewninja_web "node /app/app.js" 45 seconds ago Up 43 seconds 5000/tcp reviewninja_web_1
57cd9d03eb3b9 mongo "/entrypoint.sh mongo" 46 seconds ago Up 44 seconds 27017/tcp reviewninja_db_1
我们还想确保服务正常运行。为了做到这一点,我们使用docker logs
命令来查看一个容器的输出。让我们来检查ReviewNinja网络应用程序的日志。我们可以参考容器的ID,在上一个输出中列出的CONTAINER ID
列表中,或者它的名称。在我们的情况下,名称是reviewninja_web_1
,所以让我们来看看该容器的日志:
1docker logs reviewninja_web_1
您将看到 ReviewNinja 应用程序的输出,表示它正在收听连接:
1[secondary_label Output]
2In server/app.js
3checking configs
4✓ configs seem ok
5Host: http://localhost:5000
6GitHub: https://GitHub.com
7GitHub-Api: https://api.GitHub.com
8bootstrap certificates
9bootstrap static files
10apply migrations
11[...]
12bootstrap mongoose
13[...]
14bootstrap passport
15[...]
16bootstrap controller
17[...]
18bootstrap api
19[...]
20bootstrap webhooks
21[...]
22bootstrap monkey patch
23
24✓ bootstrapped, app listening on localhost:5000
输出显示,ReviewNinja正在倾听5000
端口。
要从网络上访问它,我们需要使用我们的Docker主机的IP,这是我们的CoreOS服务器. 如果您忘记了您的服务器的IP地址,请使用docker-machine
来查找。
1docker-machine ip reviewninja
指你的浏览器到http://your_server_ip
,你会被忍者欢迎:
最后,我们准备用我们自己的代码使用应用程序。
步骤 5 — 使用ReviewNinja与存储库
让我们在测试存储库中尝试我们的新的 ReviewNinja 实例,我们将对提取请求提供反馈,解决问题,接受更改,并将提取请求合并。
首先,我们需要允许ReviewNinja应用程序访问我们的GitHub帐户。点击登录
,然后您将被重定向到GitHub登录。
一旦您授权应用程序,您将被带到ReviewNinja的主要界面. 如果您有您希望使用ReviewNinja的私人存储库,您可以点击启用私人存储
链接:
然后,您将被重定向到GitHub,以便对ReviewNinja应用程序进行审查,以包括访问您的私人存储:
一旦您授予ReviewNinja您想要的访问权限,您可以添加一个存储库,以便您可以使用ReviewNinja为您的拉动请求工作流程。
创建这个样本存储库,这样我们就可以通过一些基本的ReviewNinja功能。这将创建你的帐户下的Github存储库,并添加到ReviewNinja。
示例存储库包含一个ReadMe.md
文件,该文件应该描述了ReviewNinja的代码审查流的一些特性。ReviewNinja-Welcome
存储库已经有从一个分支机构your_github_username-patch-1
打开的提取请求,该分支机构有更新后的ReadMe.md
文件副本。
点击该分支,你会看到主代码审查界面,在那里你可以浏览 diffs 并添加评论。
按钮 **合并拉动请求 ** 现在是琥珀,因为拉动请求的状态正在等待
。 状态将根据条件改变,您可以通过点击齿轮按钮来调整。
我们将在以后的行动中看到这一点,但现在,让我们添加一行评论。
1+ convenience we also have a dropdown menu to add these comments
让我们在这里稍微小心一点,建议将单词dropdown
更改为drop-down
。使用屏幕右侧的评论框添加评论,并将此标记为阻止问题,将!fix
添加到您的评论中,如下图所示:
标记的评论将被视为提取请求的问题
,提取请求的作者需要在ReviewNinja允许合并之前解决。
刷新页面,你现在会看到新问题在 合并拉动请求按钮上方列出的:
在本地机器上,使用Git来克隆存储库:
1git clone [email protected]:your_github_username/ReviewNinja-Welcome.git
2cd ReviewNinja-Welcome
然后检查需要工作的分支:
1git checkout your_github_username-patch-1
在你最喜欢的文本编辑器中打开ReadMe.md
,然后更改行,以便说放下
而不是放下
:
1label ReadMe.md
2To add a flag simply leave a comment with your desired flag. For
3convenience we also have a drop-down menu to add these comments
4automatically.
将文件保存到编辑器中,然后添加并进行更改:
1git add ReadMe.md
2git commit -m "Address code review feedback"
接下来,将更改推到Github的分支:
1git push origin your_github_username-patch-1
现在,刷新浏览器中的ReviewNinja界面,你会看到代码已更新,如果你再次点击行,你可以用!fixed
或!resolved
回复现有评论,如下图所示:
最后,现在我们对拉请求感到满意,让我们给它一个忍者明星作为正式登录。
然后刷新浏览器,并注意到拖拉请求状态更新为成功
,并将 Merge 拖拉请求按钮变为绿色:
您可以通过点击齿轮按钮来自定义拉请求的成功状态:
在页面重新加载后(您可能需要手动更新它),您将看到拉动请求的状态被更改为合并
。
要记住一件事: 评论Ninja 提取请求 是 GitHub 提取请求,反之亦然. 评论Ninja 上的评论将自动反映在 GitHub 提取请求页面上,反之亦然。
这种双向同步对于想要逐步迁移到ReviewNinja进行代码审查的团队来说非常有用。
结论
在本教程中,您使用了Docker、docker-machine
和docker-compose
来部署多层次的Web应用程序ReviewNinja,您学会了如何从现有应用程序创建Docker图像,以及如何从本地终端的舒适处定义和部署整个基础设施。
您还了解了 ReviewNinja 的一些强大的功能,以及如何使用这些功能来为 GitHub 提取请求流程添加一些工作流程控制。
幸福的代码评论!