如何使用蓝绿部署安全发布软件

介绍

现代开发实践经常区分部署和发布软件,部署是将新代码带到服务器的步骤,发布是新代码开始接收生产流量的步骤。

蓝色绿色部署是部署和发布软件的一种策略,它依赖于维护两个独立的可生产的环境,称为蓝色和绿色,以便轻松讨论。

前提条件

为了完成本指南,您将需要两个 Ubuntu 20.04 服务器部署在一个环境中,允许您在主机之间移动 IP 地址。 在 DigitalOcean 上, Reserved IPs可以提供此功能。这些服务器将代表两个平行环境,这些服务器可以替代地用于舞台和生产。

在每个服务器上,您应该有一个非根用户,其sudo配置用于管理功能. 您可以根据我们的 Ubuntu 20.04初始服务器设置指南来配置这些用户。

什么是蓝绿色部署?

蓝色绿色部署背后的基本概念,这是马丁·福勒(Martin Fowler)所引人注目的技术,即两组环境,每组能够在生产中为您的应用提供服务,被维持下来。

在这些环境(Web服务器或负载平衡器)的网络终端面前,路由器或其他流量导向机制将所有生产流量推向当前活跃的环境。

当计划推出新版本时,将其部署到非活跃环境中。对于蓝绿色部署,非活跃环境作为最后的舞台环境发挥作用。

一旦您在内部测试了部署并对其可靠性获得了信心,您可以通过调整路由机制来快速发布新版本。基本上,您在流量导向层上扭转开关,以便所有生产流量开始移动到您的新软件版本。

此时,您以前的软件版本已停用,但仍可访问. 如果您新活跃的部署出现任何严重问题,您可以通过更改路由机制再次返回以前的版本。

步骤1 - 创建本地应用程序

为了展示这一一般概念,我们将设置两个服务器环境. 每个服务器将安装一个 Web 服务器. 请记住,在本示例中,Web 服务器代表一个整个应用程序堆栈,其中可能包括负载平衡器,多个 Web 服务器,以及分布式或复制的数据库在后端。

我们将开始在本地计算机上开发一个应用程序。实际上,这只会是一个index.html页面,我们可以部署到我们的服务器上。

在本指南中,我们将使用DigitalOcean(保留IP地址)(https://andsky.com/tech/tutorials/how-to-use-floating-ips-on-digitalocean)作为我们的路由机制。保留IP提供一个流量从一个服务器移动到另一个服务器的机制。

然后,我们将修改我们的应用程序并部署到我们的蓝色服务器上。 生产流量将在这个时候从未改变的绿色服务器中提供服务。 然后我们可以测试蓝色服务器,以确保我们的部署成功,并且没有错误。

正如上文所述,这实际上只是我们的Web服务器可以显示的索引页面,它允许我们展示应用程序的不同版本,而无需实际开发。

在本地系统(或其他 Droplet)上,使用平台的偏好方法安装 git

1sudo apt update
2sudo apt install git

在 Mac、Windows 或其他 Linux 环境中,如果尚未安装,您应该安装 git 遵循其文档

我们需要设置几个配置设置,以便致力于一个git存储库. 我们将通过键入设置我们的名字和电子邮件地址:

1git config --global user.name "Your Name"
2git config --global user.email "[email protected]"

使用我们的配置集,我们可以为我们的新应用程序创建一个目录并进入它:

1mkdir ~/sample_app
2cd ~/sample_app

在我们的应用程序目录中初始化 git 存储库,键入:

1git init

现在,创建代表我们的应用程序的index.html文件,使用nano或您最喜欢的文本编辑器:

1nano index.html

内部,我们只会指定应用程序的版本号码,这样我们就可以知道应用程序的哪个版本在每个服务器上:

1[label ~/sample_app/index.html]
2App v1

完成后保存并关闭文件. 如果您正在使用nano,请按Ctrl+X,然后在提示时按YEnter

最后,我们可以将index.html文件添加到git阶段区域,然后通过键入:

1git add .
2git commit -m "initializing repository with version 1"

随着我们的文件的承诺,我们会暂时停止在本地机器上的应用开发,并专注于设置我们的蓝色和绿色Web服务器。

步骤2:配置蓝色和绿色 Web 服务器

接下来,我们将致力于设置我们的绿色和蓝色环境,使用功能性Web服务器。我们将在本指南中使用Apache。

<$>[注] **注:**本节中的步骤应在蓝色和绿色服务器上完成。

我们可以用apt安装Apache。更新本地包索引并通过键入安装Web服务器软件:

1sudo apt update
2sudo apt install apache2

这应该在您的两个 Web 服务器上安装和启动 Apache。

接下来,我们应该创建并配置一个部署用户,这个用户将可以访问Apache的Web根,并拥有我们将推送我们的应用程序的git库。

通过键入创建一个部署用户:

1sudo adduser --disabled-password deploy

这将创建一个新的用户,密码身份验证被禁用。

我们将赋予这个新的用户对Apache的默认网页根的所有权. 此处位于 /var/www/html

1sudo chown -R deploy:deploy /var/www/html

这就是我们所需要的部署,它只依赖于将文件移动到 Web 根。

<$>[注] 注: 如果您正在偏离本指南,并且您的部署步骤需要根权限,则您将想要配置无密码的sudo权限,以便使用与部署帐户所需的命令。

这可以通过在 /etc/sudoers.d 目录中创建一个新的 sudoers 文件来完成:

1sudo visudo -f /etc/sudoers.d/90-deployment

在此文件中,您可以添加您需要在部署期间运行的命令,这些命令可以这样指定:

1[label /etc/sudoers.d/90-deployment]
2deploy ALL=(ALL) NOPASSWD: first_deployment_command, second_deployment_command, ...

完成后保存并关闭文件,这应该允许部署用户正确执行所需的命令,而无需密码

步骤 3 – 在绿色和蓝色 Web 服务器上设置 Git 部署

现在我们已经安装了Apache并配置了一个用户来执行部署,我们可以配置一个空白的git存储库来推动我们的应用程序。

<$>[注] **注:**本节中的步骤应在蓝色和绿色服务器上完成。

开始安装git在您的两个服务器上:

1sudo apt install git

接下来,我们需要作为我们的部署用户登录,我们可以通过键入sudo来做到这一点:

1sudo su - deploy

在我们的部署用户主目录中,为我们的样本应用程序创建一个目录,就像我们在本地计算机上一样。

1mkdir ~/sample_app
2cd ~/sample_app

我们将像我们在本地系统上一样在该目录中初始化一个git复制程序,但是在我们的服务器上,我们将包含--bare选项,从而创建一个没有工作目录的git复制程序,相反,通常隐藏在git目录中的内容将被放入主文件夹:

1git init --bare

我们将下次设置一个接收后链接,这只是在发生git push后将部署我们的更改的脚本。您可以通过阅读 此指南来了解更多有关此部署策略的信息。

1nano hooks/post-receive

内部,粘贴下面的部署脚本. 这基本上是上文链接的文章中描述的相同的脚本。我们正在使用一个GIT_DIR变量来表示我们在服务器上的git重复,一个WORK_TREE变量来指定我们的Apache文档根,一个HOSTNAME来抓住我们服务器的主机名称进行进展消息。本脚本将部署到网页目录的主要分支的所有更改。

 1[label /home/deploy/sample_app/hooks/post-receive]
 2#!/bin/bash
 3
 4GIT_DIR=/home/deploy/sample_app
 5WORK_TREE=/var/www/html
 6HOSTNAME=$(hostname)
 7
 8while read oldrev newrev ref
 9do
10    if [[ $ref =~ .*/main$ ]];
11    then
12        echo "Main ref received. Deploying main branch to $HOSTNAME..."
13        git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -f
14        echo "Git hooks deploy complete."
15    else
16        echo "Ref $ref successfully received. Doing nothing: only the main branch may be deployed on this server."
17    fi
18done

如果您正在偏离本指南并需要更复杂的部署步骤,请将其添加到上面的脚本中的然后条款中。 请确保在本节中需要提高权限的任何步骤都使用sudo命令。

保存并关闭文件,当你完成。

更改接收后链接上的权限,以便git能够在适当的时间执行它:

1chmod +x hooks/post-receive

步骤 4 – 在蓝色和绿色服务器上配置 SSH 密钥访问

接下来,我们将配置SSH密钥,以便git可以将更改推向我们的Web服务器,而不需要密码。

在您的本地或开发计算机上,检查您是否已经通过键入配置了 SSH 密钥:

1cat ~/.ssh/id_rsa.pub

如果你已经拥有一个SSH密钥对,你应该看到这样的东西:

1[secondary_label Output]
2ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDilFdzkgBcSKdh6tx5pLf+HH6Pv7z7jRZ7cSo6lQvecWOOgGl/wHCVZWx1ULvrF7VgJpgugLwxYsFh3E39sm1+7zeAlRxhFrbWvATwpAEwh5m0+48LTmvXCnJ8/om+GfmAwplmzGk/DNs5trVeagG62Css0rypdoNuLrVdCVKUXGXbO6KnpOsBqoM2HvZKtQ8j1gx+1UUnvK9LYes+ZzC2XZZeBh2dGABe7HNnd8+6e1f2ZjPEKAEV2fPJGAGaAQOnzSKJkUt/B9PdKFbCjnnG1sT0kQoxMRIAiqfR7wa7PUQCM5Orm5S92OTNcnRr8bWVjN18bWCyXkpxxWbIvVU/ user@devel

如果命令正确执行,请复制完整显示的文本,我们将在下一节中使用。

如果您在本地机器上没有SSH密钥,您可能会看到一个类似于此的错误:

1[secondary_label Output]
2cat: /home/user/.ssh/id_rsa.pub: No such file or directory

如果是这样的情况,您可以通过键入创建新的公钥和私钥对:

1ssh-keygen

按 Enter 按一下所有提示,以接受默认值. 创建密钥后,重新键入cat命令以显示新的公共密钥:

1cat ~/.ssh/id_rsa.pub

此时应正确执行. 复制显示的行以在下一节中使用。

在您的绿色和蓝色服务器上,我们将授权我们本地或开发机器上的帐户连接到我们的部署用户。

作为你的部署用户,创建一个~/.ssh目录. 内部,打开一个名为authorized_keys的文件:

1mkdir ~/.ssh
2nano ~/.ssh/authorized_keys

在此文件中,粘贴您从本地机器复制的输出:

1[label ~/.ssh/authorized_keys]
2ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDilFdzkgBcSKdh6tx5pLf+HH6Pv7z7jRZ7cSo6lQvecWOOgGl/wHCVZWx1ULvrF7VgJpgugLwxYsFh3E39sm1+7zeAlRxhFrbWvATwpAEwh5m0+48LTmvXCnJ8/om+GfmAwplmzGk/DNs5trVeagG62Css0rypdoNuLrVdCVKUXGXbO6KnpOsBqoM2HvZKtQ8j1gx+1UUnvK9LYes+ZzC2XZZeBh2dGABe7HNnd8+6e1f2ZjPEKAEV2fPJGAGaAQOnzSKJkUt/B9PdKFbCjnnG1sT0kQoxMRIAiqfR7wa7PUQCM5Orm5S92OTNcnRr8bWVjN18bWCyXkpxxWbIvVU/ user@devel

保存并关闭文件,当你完成。

接下来,锁定权限,以便 SSH 可以使用您创建的文件:

1chmod 600 ~/.ssh/authorized_keys
2chmod 700 ~/.ssh

步骤 5 – 在本地开发机器上配置 Git 远程

现在,我们已经配置了 SSH 密钥访问到我们的 Web 服务器和我们在每个服务器上设置的应用程序目录,我们可以将我们的蓝色和绿色服务器添加到我们的本地git应用程序库中。

在本地机器上,返回应用程序目录:

1cd ~/sample_app

添加远程引用,以便git可以将更改推向您的绿色和蓝色 Web 服务器:

1git remote add blue deploy@blue_server_ip:sample_app
2git remote add green deploy@green_server_ip:sample_app

我们现在应该能够将我们的应用推向我们的两个服务器,让我们通过将我们的应用程序的版本1推到两个服务器来测试它。

1git push blue main
2git push green main

您可能需要在首次部署时接受每个服务器的密钥指纹,您应该看到这样的输出:

 1[secondary_label Output]
 2The authenticity of host '111.111.111.111 (111.111.111.111)' can't be established.
 3ECDSA key fingerprint is 30:a1:2c:8b:ec:98:a3:3c:7f:4a:db:46:2b:96:b5:06.
 4Are you sure you want to continue connecting (yes/no)? yes
 5Warning: Permanently added '111.111.111.111' (ECDSA) to the list of known hosts.
 6Counting objects: 3, done.
 7Writing objects: 100% (3/3), 246 bytes | 0 bytes/s, done.
 8Total 3 (delta 0), reused 0 (delta 0)
 9remote: Main ref received. Deploying main branch to blue...
10remote: Git hooks deploy complete.
11To [email protected]:sample_app
12 * [new branch]      main -> main

正如你所看到的,以远程:开头的行包含我们服务器上的接收后链接的回声声明。

我們可以測試我們應用程式的初始部署是否成功使用 curl:

1curl blue_server_ip
2curl green_server_ip

对于这两种呼叫,答案应该如下:

1[secondary_label Output]
2App v1

这表明我们的部署脚本运行正确。

设置为路由流量保留的 IP 地址

现在我们已经部署了我们的应用程序的初始版本,我们可以创建一个保留的IP地址,并最初将其指向我们的绿色服务器。

在DigitalOcean控制面板上,点击网络选项卡,然后点击保留IP菜单项。在提供的菜单中,选择您的绿色服务器,然后点击分配保留IP按钮:

DigitalOcean create Reserved IP

几秒钟后,应该将IP分配给您的绿色服务器:

DigitalOcean Reserved IP assigned

您现在可以将此 IP 地址用作生产应用程序部署的主要入口点. 如果您想为您的 Web 应用程序设置域名,则将域名指向此保留 IP 地址。

通过键入测试您的应用程序是否可以通过保留IP地址访问:

1curl reserved_IP_addr

你应该看到你的应用程序的版本1:

1[secondary_label Output]
2App v1

绿色服务器目前正在提供这种响应。

第6步:实践蓝绿部署

现在,我们的配置已经完成,我们可以展示蓝绿部署在实践中是如何工作的。 目前,我们的保留IP地址指向我们的绿色服务器. 如前所述,保留IP地址代表了生产流量,这将是我们将应用程序域名附加到的地方。

在您的本地或开发机器上,我们可以对我们的应用程序进行一些更改。

1cd ~/sample_app
2nano index.html

让我们通过增加版本号来对我们的应用程序进行明显的更改:

1[label ~/sample_app/index.html]
2App v2

保存并关闭文件,当你完成。

将文件添加到git阶段区域,并通过键入进行更改:

1git add .
2git commit -m "Application version 2"

接下来,我们可以将新的变化推向我们的非活跃环境,这将使我们有机会测试我们的部署,而不会影响我们的生产服务器。

由于我们的保留IP地址目前指向我们的绿色环境,我们将部署到我们的蓝色服务器。

1git push blue main

如果我们访问我们的 保留IP地址,我们应该看到我们的应用程序的版本1仍然在服务:

1curl reserved_IP_addr
1[secondary_label Output]
2App v1

但是,如果我们检查我们的蓝色服务器的常规IP地址,我们可以测试我们的应用程序的版本2:

1curl blue_server_IP
1[secondary_label Output]
2App v2

这是我们所期望的,也是我们想要的。我们现在可以通过我们需要的任何内部测试来运行我们的蓝色服务器环境。

一旦您测试了您的应用程序的最新版本,并确信它按预期运行,我们可以将生产流量转移到蓝色服务器。

要做到这一点,请访问DigitalOcean控制面板。 点击网络选项卡,然后选择保留IP导航项目。 在保留IP列表中,您应该看到您的保留IP,目前指向绿色服务器:

DigitalOcean Reserved IP assigned

在我们切换之前,在您的终端窗口中,启动一个暂时循环,以便我们可以通过保留IP地址进行重复请求。

1while true; do curl reserved_ip_addr; sleep 2; done

它应该开始输出网页请求的结果:

1[secondary_label Output]
2App v1
3App v1
4App v1
5App v1

现在,要切换并发布你的软件的新版本,请点击保留IP分配的右侧蓝色按钮重新分配IP地址。

DigitalOcean reassign IP address

在几秒钟内,您的保留IP将重新分配到您的蓝色服务器. 在您的终端窗口中,更改应该是显而易见的:

1[secondary_label Output]
2App v1
3App v1
4App v2
5App v2

通过按Ctrl+C来停止循环。

您的生产流量现在正在路由到您的应用程序的新版本. 您以前的生产服务器,绿色服务器,现在已设置为您的回滚机和您的下一个舞台区域。

如果在将流量转移到新版本的应用程序后,您发现一个问题,此发布策略允许您快速无痛地滚回以前的版本。

步骤 7 – 处理数据库更新(可选)

上面描述的场景被缩小,以便专注于部署和发布策略本身,我们不涵盖更复杂的,但常见的设置,如涉及数据库的设置。

您可以使用几种不同的策略来处理两个环境之间的持久数据。

您可以为每个环境维护一个单独的数据库,但这项策略将要求您将生产数据库中的数据复制到非活跃的数据库,并在启动交换时停止交易。

更好的替代方案通常是在绿色和蓝色环境之间共享单个数据库系统. 应用程序代码可以使用蓝色和绿色发布策略进行切换,而数据库本身则可用于两种环境。

这种方法的主要问题是如何部署和发布包括非反向兼容的数据库迁移的更新. 如果我们部署一个新的版本,以增加或改变数据库的方式,以不与当前的生产部署工作,我们将打破我们的应用程序。

为了防止这种情况发生,通常最好将迁移部署与代码库部署分开,并在必要时逐步部署。 这种修改过程有时被称为 蓝色绿色部署

中间应用程序代码几乎完全与旧版本相同,但具有一些额外的逻辑,为迁移发生后将存在的新数据结构做好准备. 通常,通过构建迁移来实现,以便它们创建全新的数据结构,而不是修改现有的数据结构。

该部署将首先从旧表中读取并写入旧表中,但它会检查新结构是否存在。接下来,迁移本身正在运行,并在旧版本旁创建数据结构的新版本。

在此时,所有新活动都将被记录在两个数据结构中。您可以用旧结构的数据填补新结构,在途中将其转换,以满足新结构的条件。当完成时,您的所有记录都应该存在于两个位置。 为了继续过渡,下一个应用部署可能会继续写到两个结构,但可能会从新结构中读取。

这个过程起初可能看起来很重要,但通常在实践中没有太多的额外工作。主要的工作包括建立一个安全网,该网将暂时使用传统和新结构。这会让你有时间在参与之前深入测试你的迁移,并允许你在任何时候返回你的数据结构的以前的工作版本。 对于这种数据迁移的例子,请看看Etsy的Mike Brittain的一些(这些幻灯片)(http://www.slideshare.net/mikebrittain/mbrittain-continuous-deploymentalm3public/50)。

结论

虽然有许多其他策略可以用来将部署与你的新代码的实际发布分开,但蓝色绿色部署是一个快速实现的机制,它提供了一个良好的舞台环境,完全反映了生产环境,同时在发布后提供即时回归机会,如果情况不如预期。

接下来,您可能想学习如何使用现代Kubernetes工具(https://andsky.com/tech/tutorials/how-to-deploy-to-kubernetes-using-argo-cd-and-gitops)执行蓝绿色部署,例如ArgoCD。

Published At
Categories with 技术
comments powered by Disqus