作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Elene Latsoshvili
Verified Expert in Engineering

Elene is a full-stack developer with 12+ years of experience. 她是语言/堆栈不可知论者,但她的主要领域是Java和JavaScript.

Expertise

PREVIOUSLY AT

Bank of Georgia
Share

当涉及到更新实时应用程序时, there are two fundamentally different ways of going about this.

在第一种方法中,我们对系统的状态进行增量更改. For example, we update files, 修改环境属性, 安装额外的必需品, and so on. 第二种方法, 我们拆掉整个机器,用新的映像和声明性配置(例如, 使用Kubernetes).

Laravel部署变得简单

This article mainly covers relatively small applications, 哪些可能不托管在云中, 不过我会提到怎么做 Kubernetes可以提供很大的帮助 us with deployments beyond the “no-cloud” scenario. 我们还将讨论成功执行更新的一些一般问题和技巧,这些问题和技巧可能适用于各种不同的情况, 不仅仅是使用Laravel部署.

为了演示的目的, I will be using a Laravel 示例,但请记住,任何PHP应用程序都可以使用类似的方法.

Versioning

对于初学者来说,知道当前部署在生产环境中的代码版本是至关重要的. It can be included in some file or at least in the name of a folder or file. As for the naming, if we follow the standard practice of 语义版本控制, we can include more information in it than just a single number.

看两个不同的版本, 这些附加的信息可以帮助我们很容易地理解它们之间引入的变化的性质.

显示语义版本控制解释的图像.

Versioning the release begins with a version control system, such as Git. Let’s say we have prepared a release for deployment, for example, version 1.0.3. When it comes to organizing these releases and code flows, 有不同的开发风格,如 基于主干的开发和Git流程,您可以根据团队的偏好和项目的具体情况选择或混合使用. 最后,我们很可能会在我们的主分支上相应地标记我们的版本.

After the commit, we can create a simple tag like this:

git tag v1.0.3

And then we include tags while executing the push command:

git push --tags

We can also add tags to old commits using their hashes.

将释放文件发送到目的地

Laravel deployment takes time, even if it’s simply copying files. However, even if it doesn’t take too long, our goal is to achieve zero downtime.

Therefore, 我们应该避免就地安装更新,也不应该更改正在使用的文件. Instead, 我们应该部署到另一个目录,只有在安装完全准备好后才进行切换.

实际上,有各种各样的工具和服务可以帮助我们进行部署,例如 Envoyer.io (by Laravel.网站设计师Jack McDade), Capistrano, Deployer, etc. 我还没有在生产中全部使用它们, so I cannot make recommendations or write a comprehensive comparison, but let me showcase the idea behind these products. If some (or all) of them cannot meet your requirements, 您始终可以创建自定义脚本,以您认为合适的最佳方式自动化该过程.

为了演示的目的, 假设我们的Laravel应用程序由Nginx服务器从以下路径提供服务:

/var/www/demo/public

首先,每次进行部署时,我们需要一个目录来放置发布文件. Also, we need a symlink which will point to the current working release. In this case, /var/www/demo 会成为我们的符号链接吗. Reassigning the pointer will allow us to quickly change releases.

Laravel部署文件处理

如果我们正在处理一个Apache服务器, we might need to allow following symlinks in the configuration:

+ FollowSymLinks选项

我们的结构可以是这样的:

/ opt /演示/释放/ v0.1.0
/ opt /演示/释放/ v0.1.1
/ opt /演示/释放/ v0.1.2

可能有一些文件需要在不同的部署中持久化.g., log files (if we are not using Logstash, obviously). 在Laravel部署的情况下,我们可能希望保留存储目录和 .环境配置文件. We can keep them separated from other files and use their symlinks instead.

In order to fetch our release files from the Git repository, 我们可以使用克隆或存档命令. Some people use git clone, but you cannot clone a particular commit or tag. 这意味着将获取整个存储库,然后选择特定的标记. When a repository contains many branches or a large history, its size is considerably larger than the release archive. So, if you don’t specifically need the git repo on production, you could use git archive. This allows us to fetch just a file archive by a specific tag. 使用后者的另一个优点是,我们可以忽略一些不应该出现在生产环境中的文件和文件夹, e.g., tests. For this, we just need to set the export-ignore property in the .gitattributes文件. In the OWASP安全编码实践清单 你可以找到以下建议: “在部署之前,删除测试代码或任何不打算用于生产的功能.”

If we are fetching the release from source version control system, git archive and export-ignore could help us with this requirement.

让我们看一看一个简化的脚本(它在生产环境中需要更好的错误处理):

deploy.sh

#!/bin/bash
#如果任何命令失败,终止执行
set -e

从脚本参数中获取标签
TAG=$1
GIT_REMOTE_URL='here should be a remote url of the repo'
BASE_DIR = / opt /演示

# Create folder structure for releases if necessary
RELEASE_DIR = BASE_DIR /版本/美元标签
mkdir -p $RELEASE_DIR
mkdir -p $BASE_DIR/storage
cd $RELEASE_DIR

# Fetch the release files from git as a tar archive and unzip
git archive \
    ——远程= $ GIT_REMOTE_URL \
    --format=tar \
    $TAG \
    | tar xf -

#使用composer安装laravel依赖项
Composer install -o——无交互——无开发

创建到“storage”和“storage”的符号链接.env`
ln -sf $BASE_DIR/.env ./
rm -rf storage && ln -sf $BASE_DIR/storage ./

#运行数据库迁移
PHP工匠迁移——无交互——强制

#运行laravel优化命令
PHP工匠优化
PHP工匠缓存:清除
PHP工匠路由:缓存
PHP工匠视图:清除
PHP工匠配置:缓存

# Remove existing directory or symlink for the release and create a new one.
NGINX_DIR = / var / www /公众
mkdir -p $NGINX_DIR
rm -f $NGINX_DIR/demo
ln -sf $RELEASE_DIR $NGINX_DIR

For deploying our release, we could just execute the following:

deploy.sh v1.0.3

Note: 在这个例子中,v1.0.3是我们版本的git标签.

作曲家制作?

您可能已经注意到,脚本正在调用Composer来安装依赖项. 尽管您在许多文章中都看到过这种方法,但这种方法可能存在一些问题. Generally, 最佳实践是创建应用程序的完整构建,并通过基础设施的各种测试环境推进该构建. 最后,您将得到一个经过彻底测试的构建,它可以安全地部署到生产环境中. Even though every build should be reproducible from scratch, it does not mean that we should rebuild the app on different stages. 当我们把composer安装在产品上时, 这不是真正的构建与测试的一个,这是什么可能会出错:

  • Network error can interrupt downloading dependencies.
  • 库供应商可能并不总是遵循SemVer.

网络错误很容易被发现. Our script would even stop executing with an error. 但是,如果不运行测试,可能很难确定库中的重大更改, 在生产环境中不能这样做吗. 在安装依赖项时, Composer, npm, and other similar tools rely on 语义版本控制–major.minor.patch. If you see ~1.0.2 .在作曲家.Json,表示安装版本1.0.2或最新补丁版本,如1.0.4. If you see ^1.0.2,表示安装版本1.0.2或最新的次要版本或补丁版本,如1.1.0. 我们相信库供应商会在引入任何重大更改时更改主号, but sometimes this requirement is missed or not followed. 过去也有过这样的案例. 即使你把固定的版本放在你的作曲器里.json, your dependencies might have ~ and ^ in their composer.json.

如果它是可访问的,在我看来,一个更好的方法是使用工件存储库(Nexus, JFrog, etc.). 包含所有必要依赖项的发布版本最初只创建一次. 该工件将存储在存储库中,并从中提取用于各种测试阶段. 此外,这将是要部署到生产环境的构建,而不是从Git重新构建应用程序.

保持代码和数据库兼容

我第一眼爱上Laravel的原因是它的作者对细节的关注, 考虑到开发人员的便利性, and also incorporated a lot of best practices into the framework, 比如数据库迁移.

Database migrations allow us to have our database and code in sync. 它们的更改都可以包含在一次提交中,因此是一次发布. However, this does not mean that any change can be deployed without downtime. 在部署过程中的某个时刻, there will be different versions of the application and database running. In case of problems, this point might even turn into a period. 我们应该始终尝试使它们与它们的同伴的先前版本兼容:旧数据库-新应用程序, 新数据库-旧应用程序.

例如,假设有一个 address 列,需要把它分成 address1 and address2. To keep everything compatible, we might need several releases.

  1. 在数据库中添加两个新列.
  2. Modify the application to use new fields whenever possible.
  3. Migrate address 数据到新列并删除它.

这个案例也是一个很好的例子,说明小的更改如何更适合部署. 它们的回滚也更容易. If we are changing the codebase and database for several weeks or months, it might be impossible to update the production system without downtime.

Kubernetes的一些伟大之处

Even though the scale of our application might not need clouds, nodes, and Kubernetes, I would still like to mention what deployments look like in K8s. In this case, 我们不改变系统, 而是声明我们想要实现什么以及应该在多少个副本上运行什么. Then, Kubernetes makes sure that the actual state matches the desired one.

只要我们准备好了新版本, 我们在其中创建一个包含新文件的映像, 用新版本标记图像, 然后传给K8s. The latter will quickly spin up our image inside a cluster. 它将根据我们提供的准备情况检查等待应用程序准备就绪, 然后不知不觉地将流量重定向到新应用程序,并杀死旧应用程序. 我们可以很容易地有几个版本的应用程序运行,这将让我们执行蓝/绿或金丝雀部署只需几个命令.

如果你感兴趣的话,演讲中有一些令人印象深刻的演示。”9 Steps to Awesome with Kubernetes by Burr Sutter.”

了解基本知识

  • 什么是Laravel ?为什么要使用它?

    Laravel is an opinionated PHP framework with MVC architecture, providing modern tools and expressive syntax for rapid development, maintenance, testing, and, consequently, 更短的发布周期.

  • Laravel受欢迎吗?

    根据2019年的图表,Laravel是最受欢迎的PHP框架.

  • Laravel的优势是什么?

    Eloquent ORM, 流畅查询生成器, 伟大的文档, and always up-to-date Laracasts are definitely making the framework stand out. Laravel通过提供像Artisan这样的工具来支持自动化和快速开发.

聘请Toptal这方面的专家.
Hire Now
Elene Latsoshvili

Elene Latsoshvili

Verified Expert in Engineering

第比利斯,格鲁吉亚

2019年1月21日成为会员

作者简介

Elene is a full-stack developer with 12+ years of experience. 她是语言/堆栈不可知论者,但她的主要领域是Java和JavaScript.

作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

Expertise

PREVIOUSLY AT

Bank of Georgia

世界级的文章,每周发一次.

输入您的电子邮件,即表示您同意我们的 privacy policy.

世界级的文章,每周发一次.

输入您的电子邮件,即表示您同意我们的 privacy policy.

Toptal开发者

Join the Toptal® community.