如何在DigitalOcean自托管ReviewNinja使用Docker和CoreOS

ReviewNinja可以提高你的团队的代码审查过程中,本文将告诉你如何使用Docker和CoreOS迅速成立ReviewNinja你自己的自托管的实例上DigitalOcean。

介绍

代码审查已成为现代软件开发过程不可分割的一部分。 随着分布式版本控制系统的出现,特别是自GitHub诞生以来,pull request-review-merge模型在软件开发社区得到了普及。 然而,GitHub的内置pull请求审查系统有很多需要。 因此,存在许多与GitHub集成的第三方代码审查工具来改进流程。 ReviewNinja是一个这样的工具。

ReviewNinja增加了对香草拉GitHub的要求审核经验之上的一些功能。 它使我们能够通过给“忍者明星”明确签署一份拉要求的能力,所以有像条评论没有更多的需要:shipit: LGTM或其他流行的约定。 而且,您可以设置策略来阻止合并若拉请求不是由至少2个团队成员签字,或者如果有人喜欢添加评论!fix上拉请求。

ReviewNinja是由SAP开发和开源的。 它有一个托管版本 ,但我们可以在我们自己的服务器上部署它,使用它为我们的私人GitHub的仓库。

在本指南中,您将使用部署在DigitalOcean一个ReviewNinja实例DockerCoreOS 一个生产ReviewNinja实例有一个运动部件少,所以我们将使用docker-machine创建并控制远程主机Docker,以及docker-compose描述,构建和部署我们的。 我们将使用CoreOS作为Docker主机,这是为云部署定制的最小Linux分发。 全新安装CoreOS只有已systemd和Docker守护进程,所以我们提供我们的应用程序更多的资源。

先决条件

要完成本教程,您需要:

  • Docker, docker-machinedocker-compose安装在本地计算机上,这样你就可以建立,我们将部署应用程序图像。 您可以按照官方的安装文档的Docker获得这些工具进行配置。 这两种docker-machinedocker-compose与Docker应用在OSX和Windows自动安装,或者您也可以手动进行使用这些链接安装:
  • Git安装在本地机器上,因此您可以克隆ReviewNinja存储库以创建容器。 按照官方的Git安装文档 ,如果你需要实现这一先决条件。
  • 一个DigitalOcean访问令牌既读取和写入权限,您可以通过访问生成的应用程序和API页面。 复制此令牌,因为你需要使用它与docker-machine创建主机。
  • 其中1GB CoreOSDroplet,我们将使用配置docker-machine在本教程中。
  • 一个GitHub的帐户。

第1步 - 创建和激活基于CoreOS的Docker主机

让我们为我们的部署设置基础设施。 docker-machine工具,可以提供远程机器的Docker主机和从本地计算机控制它们。 它为许多流行的云提供商,包括DigitalOcean提供驱动程序。 我们将使用docker-machine创建一个CoreOSDroplet对我们Docker的主机。

切换到您的终端,并使用您的DigitalOcean访问令牌发出以下命令:

docker-machine create --driver=digitalocean \
--digitalocean-access-token=DIGITAL_OCEAN_ACCESS_TOKEN \
--digitalocean-image=coreos-stable \
--digitalocean-region=nyc3 \
--digitalocean-size=1GB \
--digitalocean-ssh-user=core \
reviewninja

我们告诉docker-machine创建一个名为DropletreviewninjaNYC3使用数据中心coreos-stable图像与1GB的内存。 请注意,我们指定--ssh-user=core ,因为在CoreOS安装的默认用户为core

运行此命令时,您将看到以下输出:

Running pre-create checks...
Creating machine...
(reviewninja) Creating SSH key...
(reviewninja) Creating Digital Ocean droplet...
(reviewninja) Waiting for IP address to be assigned to the Droplet...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with coreOS...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env reviewninja

让我们来看看这个新的Droplet被认可docker-machine 运行命令:

docker-machine ls

你会看到下面的输出,表明Docker主机reviewminja是在使用一个远程IP地址运行digitalocean驱动程序:

NAME          ACTIVE   DRIVER         STATE     URL                          SWARM   DOCKER    ERRORS
reviewninja            digitalocean   Running   tcp://your_ip_address:2376            v1.10.3

当我们创建Docker主机时,输出的最后一行告诉我们下一步做什么。 它说:

To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env reviewninja

所以让我们运行该命令:

docker-machine env reviewninja

您会看到以下消息:

export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://your_server_ip:2376"
export DOCKER_CERT_PATH="/home/kevin/.docker/machine/machines/reviewninja"
export DOCKER_MACHINE_NAME="reviewninja"
# Run this command to configure your shell:
# eval $(docker-machine env reviewninja)

那么这里发生了什么? Docker体系结构使用客户端 - 服务器模型。 Docker客户端可以通过Unix套接字或通过TCP进行通信。 通常,我们的Docker客户端通过Unix套接字与本地安装的Docker引擎进行通信。 但是,有一些环境变量可以设置为告诉Docker客户端通过TCP与Docker主机通信。 你看到的输出是一系列shell命令来设置环境变量。

最后一部分说:

# Run this command to configure your shell:
# eval $(docker-machine env reviewninja)

当您运行命令,你告诉shell来执行这些命令该设置将用于后续的环境变量docker命令。

所以,在你的shell中执行该命令:

eval $(docker-machine env reviewninja)

现在,如果你执行docker info ,您将看到有关远程Docker守护进程,而不是当地的Docker守护进程的信息:

docker info

该命令的输出将如下所示:

Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 0
Server Version: 1.10.3
 [...]
Labels:
 provider=digitalocean

:在运行您可能会收到以下错误docker命令:

Error response from daemon: client is newer than server (client API version: 1.24, server API version: 1.22)

这意味着您使用的Docker客户端版本与服务器的版本不兼容。 为了解决这个问题,环境变量设置DOCKER_API_VERSION到相同的版本作为服务器。 例如,如果服务器需要版本1.22,请执行以下命令:

export DOCKER_API_VERSION=1.22

然后尝试再次运行Docker命令。

我们的远程Docker主机现在可以通过Docker配置和访问。 在我们可以创建一个ReviewNinja容器之前,我们需要使用GitHub做一些工作。

第2步 - 注册GitHub OAuth应用程序

ReviewNinja需要使用GitHub的API访问您的存储库,所以我们将注册我们的ReviewNinja安装为GitHub OAuth应用程序。

首先,我们需要找出我们的服务器的IP地址。 我们可以使用docker-machine命令这样做:

docker-machine ip reviewninja

记录此命令显示的IP地址。 然后登录到您的GitHub帐户,并进入设置- >应用程序的OAuth - >开发应用程序 ,并按下注册一个新的应用程序按钮。

新的GitHub OAuth申请表

一旦您获得新应用程序的表单,请输入以下信息:

  1. 设置名称 review-ninja
  2. 设为首页网址 http:// your_ip_address
  3. 设置授权回调URLhttp:// your_ip_address /auth/GitHub/callback

然后,按注册申请按钮保存更改并创建应用程序。 这将在屏幕上显示新创建的应用程序。

客户端ID客户端密钥安全的地方的价值; 您很快就会将它们添加到ReviewNinja应用程序配置中。

GitHub应用程序客户端ID和密码

现在,你有你的钥匙,让我们开始建立我们的ReviewNinja实例。

第3步 - 创建ReviewNinja Docker容器

ReviewNinja是一个依赖于由MongoDB支持的存储层的Node.js应用程序。 因为我们把它放在生产环境中,我们将Node.js应用程序放在代理服务器后面,所以应用程序服务器不会直接暴露给互联网。 我们将使用Nginx来实现这个目的。 这是一个很多配置,因此,我们将使用Docker,撰写以声明的方式部署多个相关容器。 我们定义我们想要的配置,然后使用docker-compose工具,指定所有的运行时环境创建容器。

首先,我们需要获取ReviewNinja源代码。 使用Git在本地机器上克隆源代码:

git clone https://github.com/reviewninja/review.ninja.git

然后导航到项目的文件夹:

cd review.ninja

这个库包含Dockerfile ,它告诉Docker如何构建ReviewNinja应用图像。 如果您在自己喜欢的文本编辑器中打开此文件,则会看到以下内容:

Dockerfile
FROM node:0.12.2

COPY . /app

RUN npm install -g bower
RUN cd /app; npm install; bower install --allow-root;

WORKDIR /app

VOLUME ["/certs"]

EXPOSE 5000

CMD ["node", "/app/app.js"]

此文件指定此应用程序将使用的Node.js的版本。 然后,它会将所有当前文件夹中的文件到一个app文件夹,并安装所有的应用程序依赖。 然后,它暴露的端口5000和启动应用程序。 如需更详细的介绍Dockerfiles,请参阅本教程

该Dockerfile描述ReviewNinja应用程序容器,但我们可以形容我们的栈的组件,包括MongoDB的和Nginx的代理,通过使用一个名为docker-compose.yml ,这是一个YAML文件,配置文件的流行的格式。

你克隆的资源库有一个名为docker-compose-example.yml ,但我们会写我们自己从头文件,因为例如,一个不符合我们的需要。

首先,让我们定义我们的的存储。 创建文件docker-compose.yml并输入以下配置:

docker-compose.yml
version: "2"
services:
    db:
        image: mongo
        volumes:
            - /data:/data/db

db服务使用的官方MongoDB的图像上Docker Hub,Docker图像的中央存储库。 根据设计,Docker容器在停止和删除时会丢失它们的运行时状态。 这很好的web服务,因为它是无状态的。 对于我们的db服务,我们需要将数据保存到磁盘,所以我们不会失去所有的代码审核数据,如果我们停止或重新启动该服务。 这是volumes进来。在运行时,Docker守护程序可以运行在容器卷映射到主机上的目录的容器。

在我们的配置中,我们指定了以下内容:

docker-compose.yml

        volumes:
            - /data:/data/db

该主机的映射/data文件夹/data/db在容器中,这恰好是MongoDB的配置写入到容器内的文件夹中。 通过创建这个映射,由应用程序所做的更改在被持久化主机上/data文件夹,而不是在容器中。

接下来我们定义ReviewNinja应用程序容器。 这种添加到docker-compose.yml文件,现有的配置后:

docker-compose.yml
services:
    db:
    [...]

    web:
        build: .
        working_dir: /app/
        links:
            - db
        environment:
            MONGODB: mongodb://db/reviewninja
            GITHUB_CLIENT: YOUR_GITHUB_APP_ID
            GITHUB_SECRET: YOUR_GITHUB_APP_SECRET

注意 :确保web线垂直向上的db先前定义为YAML文件挑剔缩进服务定义。

我们使用build .它告诉docker-compose该图像应该从建立Dockerfile ,我们只是探讨在当前文件夹中。 然后,我们声明的链接db的形象,所以内部web容器,名称db将解析为IP地址db容器。 这提供了一个基本的服务发现机制; 我们不必知道的IP地址, db的时间提前及硬编码的容器或通过环境变量传递给它。 然后我们使用这个链接来定义MONGODB环境变量,使用mongodb://db/reviewninja作为值。

填写GITHUB_CLIENTGITHUB_SECRET与客户ID和秘密为您创建GitHub的应用程序。 ReviewNinja应用程序将在运行时读取这些环境变量。

最后,让我们来定义负载均衡服务,将转发来自端口的请求80到我们的Node.js应用程序使用的端口。 这种配置添加到该文件,用衬它垂直web刚创建的服务宣言:

docker-compose.yml
services:
    web:
    [...]
    nginx:
        image: nginx
        ports:
            - "80:80"
        volumes:
            - ./reviewninja.conf:/etc/nginx/conf.d/default
        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;'"
        links:
            - web

我们使用的正式的Nginx图像从Docker集线器和声明的端口映射80:80 ,其结合端口80主机端口80在容器中。 然后,我们创建了Nginx的配置文件存储在容器外的卷映射,我们宣布一个容器联动的app容器,所以我们可以通过名称和代理请求给它找到它。

command的声明是很长,所以让我们打破它。 它实际上在一行上运行两个命令。 第一个命令是echo -e ... > /etc/nginx/conf.d/default.conf ,这创造了ReviewNinja,它看起来像这样Nginx的配置文件:

default.conf
upstream backend {
    server web:5000;
}

server {
    listen       80;

    location / {
        proxy_pass http://backend;
    }
}

这定义了一个backend的上游和它指向的web:5000 价值web来自docker-compose.yml在文件links部分,端口5000是Node.js的服务器在使用的端口web容器。 然后,我们宣布,我们的Nginx服务器将在端口上运行80在容器上应代理的所有请求backend ,我们的应用程序服务器。

该命令,第二部分nginx -g 'daemon off' ,是运行在容器中的Nginx服务器进程的命令。 我们需要指定daemon off ,因为Nginx的在守护进程模式在默认情况下运行时,从正在运行的进程分离本身。 Docker将从容器入口点分离的任何程序视为“退出”,并终止容器,获取所有进程。 作为经验法则,在Docker容器中运行的任何进程都必须在前台运行。

这里就是整个docker-compose.yml文件,以防万一你想在移动之前要仔细检查你的配置:

docker-compose.yml
version: "2"
services:
    db:
        image: mongo
        volumes:
            - /data:/data/db
    web:
        build: .
        working_dir: /app/
        links:
            - db
        environment:
            MONGODB: mongodb://db/reviewninja
            GITHUB_CLIENT: YOUR_GITHUB_APP_ID
            GITHUB_SECRET: YOUR_GITHUB_APP_SECRET
    nginx:
        image: nginx
        ports:
            - "80:80"
        volumes:
            - ./reviewninja.conf:/etc/nginx/conf.d/default
        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;'"
        links:
            - web

看看在Docker,撰写文档 ,如果你想探索更多关于语法和选项docker-compose.yml

这需要我们为这个应用程序的配置。 保存docker-compose.yml文件; 是时候部署这个应用程序。

第4步 - 构建和部署容器

我们已经配置docker-compose来部署我们的应用程序ReviewNinja,一个MongoDB实例来保存数据,和Nginx的代理。 在我们部署这些容器中,让我们验证reviewninjaDocker机仍处于活动状态:

docker-machine active

你应该看到:

reviewninja

如果没有看到该输出,请务必运行

eval $(docker-machine env reviewninja)

再次确保您的环境设置正确。 然后重试。

一旦你确定你有一个积极的机器上,使用docker-compose打造出你的筹码:

docker-compose build

此过程可能需要很长时间,因为它会下载并配置Docker主机上的ReviewNinja应用程序的所有依赖关系。 您将看到以下输出:

db uses an image, skipping
Building web
Step 1 : FROM node:0.12.2
0.12.2: Pulling from library/node
[...]
Successfully built 106a1992d538

一旦构建过程完成,请验证您是否具有成功的映像:

docker images

你会看到下面的输出,表明图像reviewninja_web已成功创建:

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
reviewninja_web     latest              106a1992d538        3 minutes ago       946.6 MB

现在我们可以使用一个命令在我们的远程服务器上启动我们的数据库,我们的ReviewNinja应用程序和我们的Nginx代理:

docker-compose up -d

这带来了我们在定义的所有容器docker-compose文件。 我们使用-d (用于“分离”),以便在后台运行所有的容器,我们有我们的终端回到我们的控制。

Creating network "reviewninja_default" with the default driver
Pulling db (mongo:latest)...
latest: Pulling from library/mongo
[...]
Digest: sha256:d3f19457c816bb91c5639e3b1b50f67370e3b3a58b812d73446d7b966469c65e
Status: Downloaded newer image for mongo:latest
Creating reviewninja_db_1
Creating reviewninja_web_1
Creating reviewninja_nginx_1

让我们验证容器是否已启动并正在运行。 执行以下命令:

docker ps

您将看到如下所示的输出:

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                         NAMES
29f8e6f770d3        nginx               "nginx -g 'daemon off"   43 seconds ago      Up 41 seconds       0.0.0.0:80->80/tcp, 443/tcp   reviewninja_nginx_1
164564dd450a        reviewninja_web     "node /app/app.js"       45 seconds ago      Up 43 seconds       5000/tcp                      reviewninja_web_1
7cd9d03eb3b9        mongo               "/entrypoint.sh mongo"   46 seconds ago      Up 44 seconds       27017/tcp                     reviewninja_db_1

我们还希望确保服务正常运行。 要做到这一点,我们使用docker logs命令来查看容器的输出。 让我们查看ReviewNinja Web应用程序的日志。 我们可以通过它的ID,在上市参考值容器CONTAINER ID在前面的输出列,或它的名字。 在我们的例子中,名字是reviewninja_web_1 ,所以让我们看看该容器中的日志:

docker logs reviewninja_web_1

您将看到ReviewNinja应用程序的输出,指示它正在侦听连接:

In server/app.js
checking configs
✓ configs seem ok
Host:        http://localhost:5000
GitHub:      https://GitHub.com
GitHub-Api:  https://api.GitHub.com
bootstrap certificates
bootstrap static files
apply migrations
[...]
bootstrap mongoose
[...]
bootstrap passport
[...]
bootstrap controller
[...]
bootstrap api
[...]
bootstrap webhooks
[...]
bootstrap monkey patch

✓ bootstrapped, app listening on localhost:5000

输出表明ReviewNinja上监听端口5000

要从网络访问它,我们需要使用我们的Docker主机的IP,这是我们的CoreOS服务器。 如果你忘了你的服务器的IP地址,使用docker-machine找出来。

docker-machine ip reviewninja

在浏览器中http:// your_server_ip ,你会被忍者打hello:

ReviewNinja主页

最后,我们准备好使用我们自己的代码来使用应用程序。

第5步 - 使用ReviewNinja与存储库

让我们在测试存储库上试试我们的新的ReviewNinja实例。 我们会提供有关拉取请求的反馈,解决问题,接受更改并合并拉取请求。

首先,我们需要允许ReviewNinja应用程序访问我们的GitHub帐户。 点击登录 ,你会被重定向到GitHub上登录你会被询问是否要允许ReviewNinja访问您的GitHub帐户:

通过GitHub授予应用程序权限

一旦您授权应用程序,您将被带到ReviewNinja的主界面。 如果您有私人仓库,你想ReviewNinja使用,则可以单击启用私人回购协议链接:

启用对私有存储库的访问

然后,您将被重定向到GitHub以修改您的ReviewNinja应用程序的授权,以包括对您的私有仓库的访问:

授权私有存储库

一旦您授予ReviewNinja您想要的访问权限,您可以添加一个存储库,以便您可以使用ReviewNinja为您的请求工作流。 当它使用ReviewNinja你的第一次,你有机会增加一个样本ReviewNinja-Welcome库:

添加样本存储库

创建该示例存储库,以便我们可以浏览一些基本的ReviewNinja功能。 这将在您的帐户下的Github上创建存储库,并将其添加到ReviewNinja。

样品库包含ReadMe.md是应该概述一些ReviewNinja的代码审查流程的特征文件。 ReviewNinja-Welcome库已经有一个拉请求来自分支开放your_github_username -patch-1具有的更新的副本ReadMe.md文件。 分支的名称将根据您的用户名而有所不同。

拉请求视图

点击该分支,您将看到主代码审查界面,您可以在其中浏览差异并添加评论。 您还将看到拉取请求状态框,其中概述拉取请求的状态和未决问题。

拉动请求状态框

合并拉请求按钮为琥珀色,因为现在拉请求的状态为“待定”。 状态将根据您可以通过单击齿轮按钮调整的条件而改变。 默认情况下,它需要至少1个忍者星为按钮变绿。

我们将在以后的行动中看到,但现在,让我们添加一个行注释。 点击说的那行代码

+ convenience we also have a dropdown menu to add these comments

添加行注释

让我们有点迂腐这里并建议这个词dropdown应改为drop-down 添加使用屏幕右边的评论框注释,将此作为阻塞问题通过添加!fix你的评论,如如下图:

标记一行

标记的注释将被视为拉取请求的“问题”,拉取请求的作者需要在ReviewNinja允许它合并之前解决。

刷新页面,现在您会看到合并拉请求按钮上面列出的新问题:

我们的问题

让我们解决这个问题。 在本地机器上,使用Git克隆存储库:

git clone git@GitHub.com:your_github_username/ReviewNinja-Welcome.git
cd ReviewNinja-Welcome

然后检查需要工作的分支:

git checkout your_github_username-patch-1

打开ReadMe.md在你最喜欢的文本编辑器和更改行说drop-down ,而不是dropdown

label ReadMe.md
To add a flag simply leave a comment with your desired flag. For
convenience we also have a drop-down menu to add these comments
automatically.

将文件保存在编辑器中,然后添加并提交更改:

git add ReadMe.md
git commit -m "Address code review feedback"

接下来,将更改推送到Github的分支:

git push origin your_github_username-patch-1

现在,在浏览器中刷新ReviewNinja界面。 你会看到代码的更新,如果你再次点击就行,你可以回复现有注释!fixed!resolved所示,如下图所示:

将问题标记为已解决

最后,现在我们对pull请求感到满意了,让我们给它一个忍者明星作为正式签名。 单击Add忍者星按钮:

忍者星

然后刷新浏览器,并观察拉请求状态更新为“成功”,并合并拉请求按钮为绿色:

准备合并

您可以通过点击齿轮按钮来自定义提出请求的成功条件:

定制

继续并点击“合并拉请求”。 页面重新加载后(您可能必须手动刷新),您将看到拉取请求的状态更改为“合并”。

合并

有一点要记住:ReviewNinja拉请求 GitHub上拉的请求,反之亦然。 对ReviewNinja的评论将自动反映在GitHub拉取请求页面上,反之亦然。 通过ReviewNinja合并的拉取请求也会反映在GitHub上:

GitHub pull请求被同步

这种双向同步对于想要逐渐迁移到ReviewNinja进行代码审查的团队来说非常有用。

结论

在本教程中,您使用Docker, docker-machine ,以及docker-compose部署ReviewNinja,多层Web应用程序。 您学习了如何从现有应用程序创建Docker映像,以及如何从舒适的本地终端定义和部署整个基础架构。

您还了解了ReviewNinja的一些强大功能,以及如何使用这些功能来向GitHub拉取请求过程添加一些工作流控制。

快乐代码审查!