介绍
现代开发实践通常区分部署和发布软件。 部署是涉及将新代码放到服务器上的步骤。 释放是新代码开始接收生产流量的步骤。
蓝绿部署是部署和发布软件的策略。 它依赖于维护两个单独的生产能力环境,昵称蓝色和绿色,以方便讨论。 在本指南中,我们将讨论如何在DigitalOcean上使用蓝绿部署来简化将用户转换到新版本软件的过程。
先决条件
为了完成本指南,您将需要在环境中部署两个Ubuntu 14.04服务器,以便您能够轻松地在主机之间移动IP地址。 在DigitalOcean, 浮动IP地址可以提供此功能。 这些服务器将代表两个并行环境,可替代地用于暂存和生产。 您可以随意调用这些服务器,但在本指南中,我们将其称为“蓝色”和“绿色”。
在这些服务器,你应该有一个非root用户sudo
配置管理功能。 您可以按照我们的配置这些用户的Ubuntu 14.04服务器初始设置指南 。
什么是蓝绿部署?
后面的蓝绿色的部署,通过由流行技术的基本概念, 这篇文章从Martin Fowler的,是两套环境中,每一个都能够服务于生产应用程序,得以维持。 这两个环境应该几乎相同。 按照惯例,这些被称为蓝色和绿色环境。
这些环境中只有一个处于活动状态,并且在任何时间都接收生产流量。 在这些环境(Web服务器或负载平衡器)的Web端点之前,路由器或其他流量引导机制将所有生产流量推送到当前活动的环境。
计划新版本时,会将其部署到非活动环境。 对于蓝绿部署,非活动环境充当最终的暂存环境。 它非常接近地反映了生产环境,可以用于最终测试,然后决定推动变更。
一旦您在内部测试过部署并且对其稳健性有信心,您就可以通过调整路由机制快速,轻松地发布新版本。 基本上,您在交通指挥层翻转交换机,以便所有生产流量开始移动到您的新软件版本。 先前活动的环境变为非活动环境,并且先前的登台环境将成为新的生产环境。
此时,您以前的软件版本是非活动的,但仍可访问。 如果您的新活动部署遇到任何严重问题,恢复到以前的版本就像再次修改路由机制一样简单。
示例场景
为了演示这个一般概念,我们将设置两个服务器环境。 每个都将安装一个Web服务器。 请记住,在此示例中,Web服务器表示整个应用程序,可以在后端包括负载均衡器,多个Web服务器和分布式或复制数据库。 我们在本指南中使用Web服务器,因为它代表了可以演示此发布模式的最小环境。
我们将开始在我们的本地计算机上开发一个“应用程序”。 在现实中,这只会是一个index.html
页面,我们可以部署到我们的服务器。 我们将配置一个git
后收到钩上的每个我们的服务器,使我们可以通过发出简单的部署git push
。 我们将部署我们的应用程序的初始版本到我们的两个服务器。
在本指南中,我们将使用一个DigitalOcean 浮动IP地址作为我们的路由机制。 浮动IP提供了一种将流量从一个服务器移动到另一个服务器的简单机制。 我们将创建一个浮动IP,并将其指向我们的绿色服务器,将其设置为我们的初始生产机器。
然后我们将修改我们的应用程序并将其部署到我们的蓝色服务器。 此时,生产流量仍将由未改变的绿色服务器提供。 然后我们可以测试蓝色服务器,以确保我们的部署成功,没有错误。 当我们准备好了,我们可以将浮动IP移动到新版本的代码,只需重新分配浮动IP地址到蓝色服务器。
创建本地应用程序
我们将从创建我们的“应用程序”开始。 如上所述,这实际上只是一个索引页面,我们的Web服务器可以显示。 它允许我们演示不同的“版本”的应用程序,而没有实际开发的开销。
在您的本地系统(或在其他Droplet),安装git
使用平台的首选方法。 如果本地计算机运行Ubuntu,您可以键入以下命令安装:
sudo apt-get update
sudo apt-get install git
我们需要以承诺一个设置一些配置设置git
存储库。 我们将通过键入以下内容设置我们的名称和电子邮件地址:
git config --global user.name "Your Name"
git config --global user.email "username@email.com"
使用我们的配置集,我们可以为我们的新应用程序创建一个目录,并移入其中:
mkdir ~/sample_app
cd ~/sample_app
通过键入以下内容在我们的应用程序目录中初始化一个git存储库:
git init
现在,创建index.html
表示我们的应用程序文件:
nano index.html
在里面,我们将只指定我们的应用程序的版本号。 这样,我们可以轻松地知道我们的应用程序在每个服务器上的版本:
App v1
保存并在完成后关闭文件。
要完成,我们可以添加index.html
文件到git
临时区域,然后通过键入承诺:
git add .
git commit -m "initializing repository with version 1"
随着我们的文件提交,我们将暂时停止我们的本地机器上的应用程序开发,并专注于设置我们的蓝色和绿色Web服务器。
配置蓝色和绿色Web服务器
接下来,我们将使用功能性Web服务器来设置我们的绿色和蓝色环境。 我们将在本指南中使用Apache。 登录到您的服务器与sudo
用户上手。
我们可以很容易地安装Apache apt
。 更新本地软件包索引并通过键入以下内容安装Web服务器软件:
sudo apt-get update
sudo apt-get install apache2
这应该在两个Web服务器上安装和启动Apache。
接下来,我们将创建和配置一个“部署”用户。 此用户将有机会获得Apache的Web根目录和将自己裸露git
库,在这里,我们将我们的应用推到。
创建deploy
通过键入用户:
sudo adduser --disabled-password deploy
这将创建一个禁用密码身份验证的新用户。
我们将通过Apache的默认Web根目录给予这个新用户所有权。 这是位于/var/www/html
。 通过键入以下内容更改此目录的所有权:
sudo chown -R deploy:deploy /var/www/html
这是我们所需要的,我们的简单部署,只依靠移动文件到web根。
如果您是从本指南和部署步骤将需要root权限不同的是,你要密码的配置sudo
用于与使用所需要的命令权限deploy
帐户。
这可以通过创建一个新的做sudoers
的文件内/etc/sudoers.d
目录:
sudo visudo -f /etc/sudoers.d/90-deployment
在此文件中,您可以添加在部署期间需要运行的命令。 这些可以这样指定:
deploy ALL=(ALL) NOPASSWD: first_deployment_command, second_deployment_command, ...
保存并在完成后关闭文件。 这应该允许deploy
用户正确执行所需的命令没有密码。
在绿色和蓝色Web服务器上设置Git部署
现在,我们已经安装了Apache和用户配置来执行的部署,我们可以配置一个光秃秃git
存储库,以我们的应用推到。 然后,我们可以建立一个post-receive
钩,当我们把它推到我们的服务器将自动部署我们的主分支的最新版本。
通过安装开始git
两个服务器的:
sudo apt-get install git
接下来,我们需要登录为我们deploy
的用户。 我们可以做到这一点与sudo
通过键入:
sudo su - deploy
在我们的deploy
用户的主目录,为我们的示例应用程序的目录,就像我们做了我们的本地计算机上。 创建后移动到目录:
mkdir ~/sample_app
cd ~/sample_app
我们将初始化git
像我们做我们的本地系统上此目录中的回购协议。 但是,我们的服务器上,我们将包括--bare
选项。 这将创建一个git
回购没有工作目录。 相反,平时隐藏在内容.git
目录将被放置到主文件夹:
git init --bare
我们将成立post-receive
钩旁边。 这仅仅是一个脚本后,将部署我们的变化git push
时。 您可以通过阅读了解更多有关此部署策略本指南 。 我们应该把这个脚本在hooks
我们的回购目录。 通过键入以下内容创建并打开文件:
nano hooks/post-receive
在里面,粘贴以下部署脚本。 这基本上与上面链接的文章中概述的脚本相同。 我们使用的是GIT_DIR
变量来表示我们git
服务器,则在回购WORK_TREE
变量指定我们的Apache文档根目录,并HOSTNAME
抢我们的服务器对进度消息的主机名。 该脚本将部署的所有更改master
分支到web目录。 在下面的脚本中不需要更改:
#!/bin/bash
GIT_DIR=/home/deploy/sample_app
WORK_TREE=/var/www/html
HOSTNAME=$(hostname)
while read oldrev newrev ref
do
if [[ $ref =~ .*/master$ ]];
then
echo "Master ref received. Deploying master branch to $HOSTNAME..."
git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -f
echo "Git hooks deploy complete."
else
echo "Ref $ref successfully received. Doing nothing: only the master branch may be deployed on this server."
fi
done
如果您是从本指南偏离,需要更复杂的部署步骤,将其添加到then
在上面的脚本子句。 请确保需要在本节提升权限的任何步骤使用sudo
命令。 此外,请确保使用的所有命令sudo
位置将被添加到sudoers
文件在最后一节的底部指定。
保存并在完成后关闭文件。
修改的权限post-receive
挂钩上,使得git
可以在适当的时间执行:
chmod +x hooks/post-receive
在蓝色和绿色服务器上配置SSH密钥访问
接下来,我们将配置SSH密钥,这样git
能够推动改变我们的网络服务器,而不会提示输入密码。
在开发机上创建或显示您的公钥
在您的本地或开发计算机 ,检查,看看是否有一个SSH密钥已经被输入配置:
cat ~/.ssh/id_rsa.pub
如果你已经有了一个SSH密钥对,您还是应该看到一些看起来像这样:
Outputssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDilFdzkgBcSKdh6tx5pLf+HH6Pv7z7jRZ7cSo6lQvecWOOgGl/wHCVZWx1ULvrF7VgJpgugLwxYsFh3E39sm1+7zeAlRxhFrbWvATwpAEwh5m0+48LTmvXCnJ8/om+GfmAwplmzGk/DNs5trVeagG62Css0rypdoNuLrVdCVKUXGXbO6KnpOsBqoM2HvZKtQ8j1gx+1UUnvK9LYes+ZzC2XZZeBh2dGABe7HNnd8+6e1f2ZjPEKAEV2fPJGAGaAQOnzSKJkUt/B9PdKFbCjnnG1sT0kQoxMRIAiqfR7wa7PUQCM5Orm5S92OTNcnRr8bWVjN18bWCyXkpxxWbIvVU/ user@devel
如果命令正确执行,复制所显示的全部文本。 我们将在下一节中使用它。 你现在可以安全地跳过。
如果您没有在本地机器上的SSH密钥,你可能会看到类似这样的错误:
Outputcat: /home/user/.ssh/id_rsa.pub: No such file or directory
如果是这样的话,你可以创建通过键入新的公共和私人密钥对:
ssh-keygen
在所有提示中按ENTER键接受默认值。 在创建密钥,再键入cat
命令来显示新的公共密钥:
cat ~/.ssh/id_rsa.pub
这应该正确地执行这一次。 复制显示的行以在下一部分中使用。
将您的公共SSH密钥添加到绿色和蓝色服务器上的部署用户
回到你的绿色和蓝色的服务器,我们将授权我们的本地或开发机器上我们的帐户连接到我们deploy
的用户。
当你deploy
的用户,创建~/.ssh
目录。 在内部,打开一个文件名为authorized_keys
:
mkdir ~/.ssh
nano ~/.ssh/authorized_keys
在此文件中,粘贴从本地计算机复制的输出:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDilFdzkgBcSKdh6tx5pLf+HH6Pv7z7jRZ7cSo6lQvecWOOgGl/wHCVZWx1ULvrF7VgJpgugLwxYsFh3E39sm1+7zeAlRxhFrbWvATwpAEwh5m0+48LTmvXCnJ8/om+GfmAwplmzGk/DNs5trVeagG62Css0rypdoNuLrVdCVKUXGXbO6KnpOsBqoM2HvZKtQ8j1gx+1UUnvK9LYes+ZzC2XZZeBh2dGABe7HNnd8+6e1f2ZjPEKAEV2fPJGAGaAQOnzSKJkUt/B9PdKFbCjnnG1sT0kQoxMRIAiqfR7wa7PUQCM5Orm5S92OTNcnRr8bWVjN18bWCyXkpxxWbIvVU/ user@devel
保存并在完成后关闭文件。
接下来,锁定权限,以便SSH可以使用您创建的文件:
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~/.ssh
在本地开发机上配置Git远程
现在,我们有SSH密钥访问配置为我们的网络服务器,并设置每个服务器上我们的应用程序目录,我们可以添加我们的蓝色和绿色服务器,在我们当地的遥控器git
应用程序库。
在本地计算机上,回到应用程序目录:
cd ~/sample_app
添加远程引用,这样git
可以推动更改您的绿色和蓝色的web服务器:
git remote add blue deploy@blue_server_ip:sample_app
git remote add green deploy@green_server_ip:sample_app
我们现在应该能够将我们的应用程序推送到我们的两个服务器。 让我们通过将我们的应用程序的版本1推送到两个服务器来测试它。
git push blue master
git push green master
您可能必须在首次部署时接受每个服务器的密钥指纹。 你应该看到看起来像这样的输出:
OutputThe authenticity of host '111.111.111.111 (111.111.111.111)' can't be established.
ECDSA key fingerprint is 30:a1:2c:8b:ec:98:a3:3c:7f:4a:db:46:2b:96:b5:06.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '111.111.111.111' (ECDSA) to the list of known hosts.
Counting objects: 3, done.
Writing objects: 100% (3/3), 246 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: Master ref received. Deploying master branch to blue...
remote: Git hooks deploy complete.
To deploy@111.111.111.111:sample_app
* [new branch] master -> master
正如你所看到的,与开头的行“远程”包含echo
从报表post-receive
我们的服务器挂机。 记住将您的应用推送到两个服务器。
我们可以测试我们的应用程序的初始部署成功与curl:
curl blue_server_ip
curl green_server_ip
对于这两个调用,响应应如下所示:
OutputApp v1
这表明我们的部署脚本工作正常。
设置浮动IP地址以路由流量
现在我们已经部署了应用程序的初始版本,我们可以创建一个浮动IP地址,并将其指向我们的“绿色”服务器。
在DigitalOcean控制面板中,单击“网络”选项卡,然后单击“浮动IP”菜单项。 在提供的菜单中,选择您的绿色服务器,然后单击“分配浮动IP”按钮:
几秒钟后,应将IP分配给您的绿色服务器:
现在,您可以使用此IP地址作为生产应用程序部署中的主要入口点。 如果您想为您的网络应用设置域名,您可以将域指向此浮动IP地址。
通过键入以下内容,测试可通过浮动IP地址访问您的应用程序:
curl floating_IP_addr
您应该会看到应用程式的第1版:
OutputApp v1
绿色服务器当前正在提供此响应。
实践蓝绿部署
现在我们的配置完成了,我们可以演示蓝绿部署如何在实践中。 目前,我们的浮动IP地址指向我们的绿色服务器。 如前所述,浮动IP地址表示生产流量,并且将是我们将附加我们的应用程序的域名的位置。
进行应用程序更改
在本地或开发机器上,我们可以对我们的应用程序进行一些更改。 打开索引文件:
cd ~/sample_app
nano index.html
让我们通过增加版本号来对我们的应用程序做一个简单的,可见的更改:
App v2
保存并在完成后关闭文件。
将文件添加到git
通过键入临时区域并提交您的更改:
git add .
git commit -m "Application version 2"
推送到非活动环境
接下来,我们可以将新的更改推送到非活动环境中。 这将使我们有机会测试我们的部署,而不会影响我们的生产服务器。
由于我们的浮动IP地址目前指向我们的绿色环境,我们将部署到我们的蓝色服务器。 在本地开发机器上键入以下内容,将新更改推送到蓝色环境:
git push blue master
如果我们访问我们的浮动IP地址 ,我们应该看到,我们的版本的应用程序的1仍然被送达:
curl Floating_IP_addr
OutputApp v1
然而,如果我们看看我们的蓝色服务器的普通的IP地址 ,我们可以测试我们的应用程序的版本2:
curl blue_server_IP
OutputApp v2
这是我们的期望和我们想要的。 我们现在可以通过我们需要的任何内部测试来运行我们的蓝色服务器环境。 一直以来,绿色服务器将继续为我们的生产流量服务。
翻转生产到新的环境
一旦您测试了应用程序的最新版本,并确信它正在按预期执行,我们可以将生产流量切换到蓝色服务器。
为此,最简单的方法是访问DigitalOcean控制面板。 单击“网络”选项卡,然后选择“浮动IP”导航项。 在“浮动IP”列表中,您应该会看到您的浮动IP,它当前指向绿色服务器:
我们切换之前,在终端窗口之一,启动while
循环,这样我们可以通过浮动IP地址重复的请求。 这使我们可以立即看到我们的生产应用程序版本从v1转换到v2:
while true; do curl Floating_ip_addr; sleep 2; done
它应该开始输出Web请求的结果:
OutputApp v1
App v1
App v1
App v1
现在,要进行切换并“释放”您的软件的新版本,单击浮动IP分配右侧的蓝色按钮重新分配IP地址。 选择您的蓝色服务器:
几秒钟后,您的浮动IP将重新分配给您的蓝色服务器。 在终端窗口中,切换应该是明显的:
OutputApp v1
App v1
App v2
App v2
停止while
按下“CTRL-C”循环。
您的生产流量现在正路由到您的应用程序的新版本。 您之前的生产服务器(绿色服务器)现在设置为回滚机器和下一个暂存区域。
如果在将流量移动到新版本的应用程序后,您发现了一个问题,此版本策略允许您快速,无痛地回滚到以前的版本。 为此,只需逆向过程,将您的浮动IP地址指向绿色服务器。
处理数据库更新
上面概述的情景被简化,以便专注于部署和发布策略本身。 然而,我们没有涉及更复杂,但常见的设置,如涉及数据库的那些。
有几种不同的策略可用于处理两个环境之间的持久数据。
可以为每个环境维护单独的数据库。 但是,此策略将要求您将生产数据库中的数据复制到非活动数据库,并在启动切换时停止事务。 基本上,这将需要实时数据库迁移以及每次部署的几分钟停机时间。 这可能很快变得非常耗时和容易出错。
一个更好的选择是通常在绿色和蓝色环境之间共享单个数据库系统。 应用程序代码可以使用蓝绿发布策略进行切换,而数据库本身将由两个环境使用。
此方法的主要关注点是如何部署和发布包含非向后兼容数据库迁移的更新。 如果我们将一个新版本部署到临时数据库,以不能使用当前生产部署的方式添加或更改数据库,我们将打破我们的应用程序。
为了防止这种情况发生,通常最好将迁移与您的代码库部署分开部署,并在必要时分阶段部署。 该修改过程有时称为蓝绿松石绿色部署 。 基本上,它取决于部署您的应用程序代码的中间版本,可以处理数据库的旧版本和新版本。
中间应用程序代码与旧版本几乎完全相同,但使用一些额外的逻辑来为迁移后存在的新数据结构做准备。 通常,这是通过构造迁移来实现的,使得它们创建完全新的数据结构而不是修改现有的数据结构。 这样,您可以保留旧的数据结构,让我们说一个表,并创建一个包含突变更改的新数据结构。
中间绿松石部署作为迁移过程的第一步。 这个部署将首先读取和写入旧表,但它将检查新结构的存在。 接下来,运行迁移本身,在旧版本的旁边创建新版本的数据结构。 绿松石部署的逻辑应被配置为识别出新的结构是在地方,它应该开始书写的变化既旧结构和新的结构。 它将继续从旧结构读取暂时。
此时,所有新活动都将记录在两个数据结构中。 您可以用来自旧结构的数据回填新结构,沿着这种方式转换它以满足新结构的条件。 此操作完成后,所有记录都应存在于这两个位置。 要继续转换,下一个应用程序部署可能继续写入这两个结构,但可能从新结构读取。 在确认一切顺利运行之后,另一个部署可能会切断旧结构的写入,并且旧的结构可能会被删除。
这个过程首先看起来相当复杂,但在实践中通常不是太多额外的工作。 主要工作包括建立一个临时使用遗产和新结构的安全网。 这让您有时间在提交之前深入测试迁移,并允许您随时回滚到数据结构的上一个工作版本。 对于这个数据迁移如何发生的一个例子,来看看一些这些幻灯片从迈克·布里廷在Etsy的。
结论
虽然有许多其他策略可以用于将部署与实际版本的新代码分开,但蓝绿部署是一个相当简单的机制,可以快速实施。 它提供了一个完美镜像生产环境的良好的分段环境,同时在发布后提供即时回滚机会,如果事情没有按预期的那样进行。