写点什么

如何使用 Docker 部署 Go Web 应用程序

  • 2016-06-11
  • 本文字数:9708 字

    阅读完需:约 32 分钟

简介

虽然大部分 Go 应用程序可以编译为一个单一的二进制文件,但 Web 应用程序可能还有自己的模板和配置文件。如果一个项目中包含大量文件,可能会因为文件不同步而导致出错并造成更多严重问题。

您将通过本文了解如何使用 Docker 部署 Go Web 应用程序,以及 Docker 如何帮您改善开发工作流和部署过程。各种规模的团队都能从本文内容中获益。

目标

通过阅读本文,您将能:

  • 对 Docker 有一些基本了解,
  • 了解 Docker 如何帮您开发 Go 应用程序,
  • 知道如何为 Go 应用程序创建生产用 Docker 容器,并
  • 知道如何使用 Semaphore 将 Docker 容器持续部署到您的服务器。

前提要求

为了完成本文,您需要:

  • 在您的计算机和服务器上安装 Docker,并具备
  • 一台可以使用 SSH 密钥对 SSH 请求进行身份验证的服务器。

理解 Docker

Docker 可以帮您为自己的应用程序创建一个单一的可部署“单位”。这样的单位也叫做容器,其中包含了应用程序需要的一切。例如代码(或二进制文件)、运行时、系统工具,以及系统库文件。将所有这些需要的内容打包为一个单一的单位,可确保无论将应用程序部署在何处,都能提供完全相同的环境。这种技术还可以帮您维持完全一致的开发和生产环境,通常这些环境是很难被追踪的。

一旦搭建完成,容器的创建和部署将可自动进行。这本身就可以避免一系列问题。这些问题中大部分都是因为文件不同步,或开发和生产环境之间的差异导致的。Docker 可以解决这些问题。

相对于虚拟机的优势

容器提供了与虚拟机类似的资源分配和隔离等好处。然而相似之处仅此而已。

虚拟机需要自己的来宾操作系统,容器则能与宿主操作系统共享内核。这意味着容器更轻,需要的资源更少。虚拟机从本质上来说,实际上就是一个操作系统内部运行的另一个操作系统。然而容器更像是操作系统内部运行的一个应用程序。通常容器需要的资源(内存、磁盘空间等)远低于虚拟机,同时启动速度也比虚拟机快很多。

在开发过程中使用 Docker 所获得的收益

在开发工作中使用 Docker 可以获得的部分收益包括:

  • 所有团队成员共同使用一个标准的开发环境,
  • 集中更新依存组件,在任何位置使用相同的容器,
  • 从开发到生产可以使用完全相同的环境,并且
  • 更易于修复只可能在生产环境中遇到的潜在问题。

为何通过 Docker 使用 Go Web 应用程序?

大部分 Go 应用程序都是简单的二进制文件。这就引出了另一个问题 - 为何通过 Docker 使用 Go 应用程序?通过 Docker 使用 Go 的部分原因包括:

  • Web 应用程序通常包含模板和配置文件,Docker 有助于确保这些文件在库中保持完全同步。
  • Docker 能为开发和生产提供完全相同的环境。很多人经常遇到某个应用程序在开发环境中运行正常,但发布至生产环境中无法运行。使用 Docker 后将不再需要担心此类问题。
  • 在大型团队中,不同成员的计算机、操作系统,以及所安装的软件可能存在非常大的差异。Docker 提供了一种确保整个开发环境保持一致的机制。团队成员可以更高效,并可减少开发过程中的冲突和其他本可避免的问题。

创建一个简单的 Go Web 应用程序

我们将使用 Go 创建一个简单的 Web 应用程序作为本文的范例。这个我们称之为 _MathApp_ 的应用程序可以:

  • 暴露不同数学运算的过程,
  • 使用 HTML 模板创建视图,
  • 使用配置文件对应用程序进行定制,并
  • 针对所选功能提供测试。

访问/sum/3/6会打开一个显示了36相加后结果的页面。同理,访问/product/3/6会打开一个显示了36相乘后结果的页面。

本文中我们使用了 _Beego_ 框架。请注意,您自己的应用程序可以使用任何框架(或者完全不使用)。

最终的目录结构

完成后的 MathApp 其目录结构应该是类似这样的:

复制代码
MathApp
├── conf
│ └── app.conf
├── main.go
├── main_test.go
└── views
├── invalid-route.html
└── result.html

我们会假设MathApp目录位于/app目录下。

程序主文件是位于应用程序根目录的main.go,这个文件中包含了应用的所有功能。main.go的部分功能可使用main_test.go进行测试。

views文件夹包含视图文件invalid-route.htmlresult.html。配置文件app.conf位于conf文件夹中。_Beego_ 可使用该文件对应用程序进行定制。

应用程序文件的内容

应用程序主文件 (main.go) 包含应用程序的所有逻辑。该文件的内容如下:

复制代码
// main.go
package main
import (
"strconv"
"github.com/astaxie/beego"
)
// The main function defines a single route, its handler
// and starts listening on port 8080 (default port for Beego)
func main() {
/* This would match routes like the following:
/sum/3/5
/product/6/23
...
*/
beego.Router("/:operation/:num1:int/:num2:int", &mainController{})
beego.Run()
}
// This is the controller that this application uses
type mainController struct {
beego.Controller
}
// Get() handles all requests to the route defined above
func (c *mainController) Get() {
//Obtain the values of the route parameters defined in the route above
operation := c.Ctx.Input.Param(":operation")
num1, _ := strconv.Atoi(c.Ctx.Input.Param(":num1"))
num2, _ := strconv.Atoi(c.Ctx.Input.Param(":num2"))
//Set the values for use in the template
c.Data["operation"] = operation
c.Data["num1"] = num1
c.Data["num2"] = num2
c.TplName = "result.html"
// Perform the calculation depending on the 'operation' route parameter
switch operation {
case "sum":
c.Data["result"] = add(num1, num2)
case "product":
c.Data["result"] = multiply(num1, num2)
default:
c.TplName = "invalid-route.html"
}
}
func add(n1, n2 int) int {
return n1 + n2
}
func multiply(n1, n2 int) int {
return n1 * n2
}

在您的应用程序中,这些内容可能分散保存在多个文件中。但是出于演示的用途,我们希望尽量确保内容足够简单。

测试文件的内容

main.go文件包含一些需要测试的功能。对这些功能的测试位于main_test.go,这个文件的内容如下:

复制代码
// main_test.go
package main
import "testing"
func TestSum(t *testing.T) {
if add(2, 5) != 7 {
t.Fail()
}
if add(2, 100) != 102 {
t.Fail()
}
if add(222, 100) != 322 {
t.Fail()
}
}
func TestProduct(t *testing.T) {
if multiply(2, 5) != 10 {
t.Fail()
}
if multiply(2, 100) != 200 {
t.Fail()
}
if multiply(222, 3) != 666 {
t.Fail()
}
}

如果希望进行持续部署,应用程序的测试就显得尤为有用。如果您已经准备好相应的测试,即可在无需担心为应用程序引入错误的情况下进行持续部署。

视图文件的内容

视图文件其实是 HTML 模板。应用程序可以使用这些文件显示对请求做出的回应。result.html的内容如下:

复制代码
<!-- result.html -->
<!-- This file is used to display the result of calculations -->
<!doctype html>
<html>
<head>
<title>MathApp - {{.operation}}</title>
</head>
<body>
The {{.operation}} of {{.num1}} and {{.num2}} is {{.result}}
</body>
</html>

invalid-route.html的内容如下:

复制代码
<!-- invalid-route.html -->
<!-- This file is used when an invalid operation is specified in the route -->
<!doctype html>
<html>
<head>
<title>MathApp</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="UTF-8">
</head>
<body>
Invalid operation
</body>
</html>

配置文件的内容

_Beego_ 可以使用app.conf文件配置应用程序,该文件的内容如下:

复制代码
; app.conf
appname = MathApp
httpport = 8080
runmode = dev

在这个文件中,

  • appname是运行该应用程序的进程对应的名称,
  • httpport是应用程序使用的端口,而
  • runmode决定了应用程序的运行模式。可用值包括对应开发环境的dev,以及对应生产环境的prod

在开发过程中使用 Docker

本节将介绍在开发过程中使用 Docker 所能获得的收益,并会指导您完成在开发过程中使用 Docker 的步骤。

针对开发工作配置 Docker

我们会使用一个Dockerfile配置开发工作所用的 Docker。配置工作需要满足的开发环境要求如下:

  • 我们会使用上文提到的应用程序,
  • 文件必须能够从容器内部和外部访问,
  • 我们将使用beego包含的bee工具。该工具可用于在开发过程中实时重载 (Live reload) 应用(应用位于 Docker 容器内部),
  • Docker 将通过8080端口暴露该应用程序,
  • 在我们的计算机上,该应用程序位于/app/MathApp
  • 在 Docker 容器中,该应用程序位于/go/src/MathApp
  • 我们为开发工作创建的 Docker 映像名为ma-image,并且
  • 开发过程中所运行的 Docker 容器的名称为ma-instance

第 1 步 - 创建 Dockerfile

满足上述要求的 Dockerfile 内容如下:

复制代码
FROM golang:1.6
# Install beego and the bee dev tool
RUN go get github.com/astaxie/beego && go get github.com/beego/bee
# Expose the application on port 8080
EXPOSE 8080
# Set the entry point of the container to the bee command that runs the
# application and watches for changes
CMD ["bee", "run"]

第一行,

FROM golang:1.6使用 Go 的官方映像作为基础映像。这个映像是 Go _1.6_ 预安装的。该映像的$GOPATH值已被设置为/go。所有安装在/go/src的程序包都能通过go命令访问。

第二行,

RUN go get github.com/astaxie/beego && go get github.com/beego/bee安装 _beego_ 程序包和 _bee_ 工具。_beego_ 程序包将在应用程序内部使用,_bee_ 工具将用于在开发过程中实时重载代码。

第三行,

EXPOSE 8080通过开发计算机上容器的8080端口暴露该应用程序。最后一行,

CMD ["bee", "run"]使用bee命令开始对我们的应用程序进行实时重载。

第 2 步 - 构建映像

创建好 Docker 文件之后,可运行下列命令创建映像:

docker build -t ma-image .执行上述命令可创建一个名为ma-image的映像。随后所有负责开发这个应用程序的人都可以使用这个映像。这样即可确保整个团队获得完全一致的开发环境。

要查看您系统中的映像列表,请运行下列命令:

docker images执行该命令可以看到类似下面的内容:

复制代码
REPOSITORY TAG IMAGE ID CREATED SIZE
ma-image latest 8d53aa0dd0cb 31 seconds ago 784.7 MB
golang 1.6 22a6ecf1f7cc 5 days ago 743.9 MB

请注意,实际的映像名称和数量可能各不相同,不过您至少应该可以在列表中看到golangma-image映像。

第 3 步 - 运行容器

准备好ma-image之后,即可使用下列命令启动一个容器:

复制代码
docker run -it --rm --name ma-instance -p 8080:8080 \
-v /app/MathApp:/go/src/MathApp -w /go/src/MathApp ma-image

分别来看看上述命令的作用。

  • docker run命令可用于通过映像运行容器,
  • -it标记可以用交互式模式启动该容器,
  • --rm标记可以在容器关闭后清理其中的内容,
  • --name ma-instance可以将容器命名为ma-instance
  • -p 8080:8080标记使得容器可以通过8080端口访问,
  • -v /app/MathApp:/go/src/MathApp略微复杂,可以将/app/MathApp从计算机映射至容器的/go/src/MathApp目录。这样可以确保在容器内部和外部均可访问这些开发文件,并且
  • ma-image部分指定了容器内部使用的映像名称。

执行上述命令可启动 Docker 容器。这个容器可以将您的应用程序暴露到8080端口,还可以在您修改代码后自动重新构建您的应用程序。您将在控制台中看到下列输出结果:

复制代码
bee :1.4.1
beego :1.6.1
Go :go version go1.6 linux/amd64
2016/04/10 13:04:15 [INFO] Uses 'MathApp' as 'appname'
2016/04/10 13:04:15 [INFO] Initializing watcher...
2016/04/10 13:04:15 [TRAC] Directory(/go/src/MathApp)
2016/04/10 13:04:15 [INFO] Start building...
2016/04/10 13:04:18 [SUCC] Build was successful
2016/04/10 13:04:18 [INFO] Restarting MathApp ...
2016/04/10 13:04:18 [INFO] ./MathApp is running...
2016/04/10 13:04:18 [asm_amd64.s:1998][I] http server Running on :8080

若要检查整个环境,请通过浏览器访问http://localhost:8080/sum/4/5。您应该能看到类似下图的结果:

注意:上述步骤假设您在自己的本地计算机上执行操作。

第 4 步 - 开发应用程序

随后一起来看看这种做法能对开发工作起到什么帮助。执行下文操作的过程中请确保容器始终处于运行状态。在main.go文件中,将第 _#34_ 行从

c.Data["operation"] = operation修改为

c.Data["operation"] = "real " + operation保存改动的同时,您应该能看到类似下面的内容:

复制代码
2016/04/10 13:17:51 [EVEN] "/go/src/MathApp/main.go": MODIFY
2016/04/10 13:17:51 [SKIP] "/go/src/MathApp/main.go": MODIFY
2016/04/10 13:17:52 [INFO] Start building...
2016/04/10 13:17:56 [SUCC] Build was successful
2016/04/10 13:17:56 [INFO] Restarting MathApp ...
2016/04/10 13:17:56 [INFO] ./MathApp is running...
2016/04/10 13:17:56 [asm_amd64.s:1998][I] http server Running on :8080

要查看这些改动,请用浏览器访问http://localhost:8080/sum/4/5。您应该能看到类似下图的结果:

如您所见,保存改动后,您的应用程序可以自动构建并开始提供服务。

在生产环境中使用 Docker

本节将介绍如何在 Docker 容器中部署 Go 应用程序。我们将使用 Semaphore 实现下列目标:

  • 改动的代码推送到 Git 代码库后自动进行构建,
  • 自动运行测试,
  • 如果构建成功并通过测试,创建一个 Docker 映像,
  • 将 Docker 映像推送至 Docker Hub,并
  • 更新服务器以使用最新的 Docker 映像。

为生产环境创建 Dockerfile

在开发过程中,我们的目录结构如下:

复制代码
MathApp
├── conf
│ └── app.conf
├── main.go
├── main_test.go
└── views
├── invalid-route.html
└── result.html

由于我们希望为这个项目构建 Docker 映像,因此需要创建一个在生产环境中使用的 Dockerfile。请在项目的根目录下创建 Dockerfile,随后新的目录结构应该是类似下面这样的:

复制代码
MathApp
├── conf
│ └── app.conf
├── Dockerfile
├── main.go
├── main_test.go
└── views
├── invalid-route.html
└── result.html

在 Dockerfile 中输入下列内容:

复制代码
FROM golang:1.6
# Create the directory where the application will reside
RUN mkdir /app
# Copy the application files (needed for production)
ADD MathApp /app/MathApp
ADD views /app/views
ADD conf /app/conf
# Set the working directory to the app directory
WORKDIR /app
# Expose the application on port 8080.
# This should be the same as in the app.conf file
EXPOSE 8080
# Set the entry point of the container to the application executable
ENTRYPOINT /app/MathApp

详细看看上述每条命令的作用。第一条命令,

FROM golang:1.6指定了在开发过程中所用的同一个golang:1.6映像基础之上构建映像。第二条命令,

RUN mkdir /app可以在容器的根目录下创建名为app的目录。这个目录将用于保存项目文件。第三组命令,

复制代码
ADD MathApp /app/MathApp
ADD views /app/views
ADD conf /app/conf

可以将库、视图文件夹,以及配置文件夹从计算机复制到映像内的应用程序文件夹中。第四条命令,

WORKDIR /app可将映像的工作目录设置为/app。第五条命令,

EXPOSE 8080可以从容器中暴露8080端口。这个端口应该与应用程序的app.conf文件中指定的端口完全一致。最后一条命令,

ENTRYPOINT /app/MathApp可将映像的入口点 (Entry point) 设置为应用程序的二进制文件。这样即可启动该二进制文件,并开始在8080端口提供服务。

自动构建和测试

一旦将改动的代码推送至代码库, Semaphore 就可以帮您轻松地自动构建并测试代码。这里介绍了如何添加您的GitHub 或Bitbucket 项目,以及在Semaphore 上设置Golang 项目的方法。

Go 项目的默认配置可解决下列问题:

  • 抓取依存项,
  • 构建项目,并
  • 运行测试。

完成上述过程后,便可通过 Semaphore 仪表板查看最新构建的状态并对其进行测试。如果构建或测试失败,整个过程将暂停,且不部署任何内容。

通过 Semaphore 为自动化开发创建初始环境

设置好构建过程后,下一步需要配置部署过程。若要部署应用程序,您需要:

  1. 构建 Docker 映像,
  2. 将 Docker 映像推送至 Docker Hub,并
  3. 更新服务器以拉取新的映像,随后据此启动一个新的 Docker 容器。

首先我们需要在 Semaphore 上设置项目以进行持续部署

前三个步骤相对较为简单:

  • 选择部署方法,
  • 选择部署策略,并
  • 选择部署过程所使用的代码库分支。

第 4 步(设置部署命令)我们将使用下一节介绍的命令。目前可以留空并执行下一个步骤。

第 5 步,输入服务器上用户的 SSH 密钥。这样即可在无需密码的情况下,以安全的方式在服务器上执行某些部署命令。

第 6 步,可以为服务器命名。如果不指定名称,Semaphore 会为服务器分配类似server-1234这样的随机名称。

在服务器上设置更新脚本

接下来需要设置部署过程,这样 Semaphore 即可构建新映像并将其上传至 Docker Hub。设置完成后,Semaphore 将通过一条命令在服务器上执行脚本,发起更新过程。

为此我们需要将下列文件以update.sh为名放置在服务器上。

复制代码
#!/bin/bash
docker pull $1/ma-prod:latest
if docker stop ma-app; then docker rm ma-app; fi
docker run -d -p 8080:8080 --name ma-app $1/ma-prod
docker rmi $(docker images --filter "dangling=true" -q --no-trunc)

使用下列命令使得该文件可以执行:

chmod +x update.sh随后来看看这个文件是如何生效的。这个脚本可以接受单一参数,并在自己的命令中使用这个参数。这个参数可以是您在 Docker Hub 上的用户名。例如可以通过下面这样的格式使用该命令:

./update.sh docker_hub_username为了理解具体的用途,随后再来看看文件中的每条命令。

第一条命令,

docker pull $1/ma-prod:latest将最新映像从 Docker Hub 拉取到服务器上。如果您在 Docker Hub 上的用户名是demo_user,这条命令将从 Docker Hub 拉取名为demo_user/ma-prod,且被标记为latest的映像。

第二条命令,

if docker stop ma-app; then docker rm ma-app; fi可以停止并移除任何曾以ma-app为名启动的容器。

第三条命令,

docker run -d -p 8080:8080 --name ma-app $1/ma-prod使用能够反映最新构建中所有变动的最新映像启动一个新的容器(名为ma-app)。

最后一条命令,

docker rmi $(docker images --filter "dangling=true" -q --no-trunc)可从服务器上删除任何未使用的映像。这个清理工作可以确保服务器整洁,并能降低磁盘空间的使用。

注意:这个文件必须放置在上一步骤中所用 SSH 密钥对应用户的根目录下。如果文件位置有变化,下文使用的部署命令也需要酌情更新。

设置项目配合 Docker 工作

默认情况下,Semaphore 上的新项目会使用Ubuntu 14.04 LTS v1603平台。这个平台并非 Docker 自带的。因为我们感兴趣的是 Docker 的使用,因此需要更改Semaphore 的平台设置以使用 Ubuntu 14.04 LTS v1603(支持 Docker 的 Beta 测试版)平台。

设置环境变量

为了在开发过程中以安全的方式使用 Docker Hub,我们需要将自己的凭据存储在 Semaphore 自动初始化出来的环境变量内。

我们需要存储下列变量:

  • DH_USERNAME - Docker Hub 用户名
  • DH_PASSWORD - Docker Hub 密码
  • DH_EMAIL - Docker Hub 邮件地址

可以参考这里了解如何用安全的方式设置环境变量

设置部署命令

虽然已经完成初始设置,但目前还无法进行部署。原因在于还没有配置需要运行的命令。

首先我们需要输入完成部署过程所需的命令,为此请在Semaphore 上打开您的项目首页。

"> 在这个页面上,点击 Servers选项下的服务器名称,随后可以看到下列界面:

点击页面右侧,页头下方的Edit server按钮。

在下列页面上,我们需要注意底部名为Deploy commands的选项。点击其中的Change deploy commands链接,开始编辑要运行的命令。

在编辑框中输入下列命令,并点击Save Deploy Commands按钮:

复制代码
go get -v -d ./
go build -v -o MathApp
docker login -u $DH_USERNAME -p $DH_PASSWORD -e $DH_EMAIL
docker build -t ma-prod .
docker tag ma-prod:latest $DH_USERNAME/ma-prod:latest
docker push $DH_USERNAME/ma-prod:latest
ssh -oStrictHostKeyChecking=no your_server_username@your_ip_address "~/update.sh $DH_USERNAME"

注意:请将上述命令中your_server_username@your_ip_address内容替换为您的实际值。

随后一起来仔细看看上述这些命令的用途。

前两条命令go getgo build是标准的 Go 命令,分别用于拉取依存项和构建项目。请注意go build命令指定的可执行文件的名称应该是MathApp。这个名称应该与 Dockerfile 中所用名称一致。

第三条命令,

docker login -u $DH_USERNAME -p $DH_PASSWORD -e $DH_EMAIL使用(上文操作中设置的)环境变量与 Docker Hub 进行身份验证,这样我们才可以推送最新映像。第四条命令,

docker build -t ma-prod .根据最新代码基构建一个名为ma-prod的 Docker 映像。第五条命令,

docker tag ma-prod:latest $DH_USERNAME/ma-prod:latest为最新创建的映像添加your_docker_hub_username/ma-prod:latest标签。这样我们就可以将该映像推送至 Docker Hub 上相应的代码库中。第六条命令,

docker push $DH_USERNAME/ma-prod:latest可将该映像推送至 Docker Hub。最后一条命令,

ssh -oStrictHostKeyChecking=no your_server_username@your_ip_address "~/update.sh $DH_USERNAME"使用ssh命令登录到您的服务器,执行我们在上文步骤中创建的 update.sh 脚本。这个脚本可以从 Docker Hub 获取最新映像,并据此启动一个新的容器。

部署应用程序

截至目前我们并未真正将应用程序部署到服务器,因此先来进行手工部署。请注意这一操作并非是必须的。当您下一次将改动的代码推送至代码库后,只要构建和测试都能成功完成,Semaphore 将自动部署您的应用程序。我们这里进行手工部署只是为了测试一切都能正常工作。

您可以阅读 Semaphore 文档了解如何在构建页面手工部署应用程序。

应用程序部署完毕后,可通过下列地址访问:

http://your_ip_address:8080/sum/4/5

访问结果应该类似下图所示:

结果与开发过程中看到的完全相同。唯一的差异在于此处访问时使用的 URL 并不是localhost,而是服务器的 IP 地址。

对配置进行测试

至此已配置了自动构建和部署过程,我们的工作流也得以大幅简化。让我们对代码进行一些细小的改动,然后看看服务器上的应用程序是如何自动更新以反映这些改动的。

试试看将文字的颜色由黑色改为红色。为此请在views/result.html文件中,将第 _#8_ 行由

<body>改为

<body style="color: red">随后保存文件,并在您的应用程序目录中使用下列命令提交改动:

复制代码
git add views/result.html
git commit -m 'Change the color of text from black (default) to red'

使用下列命令将改动推送至代码库:

git push origin mastergit push命令成功执行后,Semaphore 会检测到代码库中的改动,并自动开始构建过程。构建过程(包括测试过程)成功完成后,Semaphore 将启动部署过程。Semaphore 仪表板会实时显示构建和部署过程的状态。

一旦 Semaphore 仪表板显示构建和部署过程均已完成,请刷新下列页面:

http://your_ip_address:8080/sum/4/5

随后您将可以看到类似下图的结果:

结论

在这篇文章中,我们了解到如何为 Go 应用程序创建 Docker 容器,并使用 Semaphore 将 Docker 容器部署至服务器。

现在您已经可以使用 Docker 简化下一个 Go 应用程序的开发工作。如果您有任何问题,欢迎发布到下方的评论区。

作者

Kulshekhar Kabra是一位独立开发者,他的工作可以方便地接触到各种新技术,并将其运用到新项目中。只要工作之余有闲时间,他还很喜欢撰写技术文章并制作视频教程。

阅读英文原文 How To Deploy a Go Web Application with Docker


感谢陈兴璐对本文的策划和审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2016-06-11 17:2911575
用户头像

发布了 283 篇内容, 共 107.7 次阅读, 收获喜欢 62 次。

关注

评论

发布
暂无评论
发现更多内容

react源码分析:实现react时间分片

flyzz177

React

JavaScript刷LeetCode心得

js2030code

JavaScript LeetCode

前端工程师leetcode算法面试必备-简单的二叉树

js2030code

JavaScript LeetCode

从React源码来学hooks是不是更香呢

flyzz177

React

react源码中的生命周期和事件系统

flyzz177

React

云智慧蝉联中国IT统一运维ITSM软件市场第一!

云智慧AIOps社区

ITSM IT运维 运维管理

从React源码角度看useCallback,useMemo,useContext

flyzz177

React

FL Studio2024永久免费版音乐程序

茶色酒

FL Studio FL Studio2023 FL Studio21

为什么 OpenCV 计算的视频 FPS 是错的

百度Geek说

OpenCV ffmpeg 12 月 PK 榜 帧率

【其他】快出数量级的性能是怎样炼成的

No8g攻城狮

MySQL sql 数据库·

MatrixOne 0.6.0 :首个云原生架构的HTAP数据库发布!

MatrixOrigin

分布式数据库 云原生数据库 国产数据库 MatrixOrigin MatrixOne

带你实现react源码的核心功能

flyzz177

React

云原生时代数据库运维体系演进

vivo互联网技术

数据库 运维 故障自愈

ArgoDB 5.1 正式发布:多模融合、实时分析和数据安全多重升级

星环科技

星环科技TDS 2.4.0 发布: 数据开发、数据治理、数据运营套件能力再次升级

星环科技

你可能需要的6个React开发小技巧

千锋IT教育

Mybatis源码解析之执行SQL语句

京东科技开发者

缓存 mybatis sql 源码学习 数据库·

使用Spring Data Redis 发布订阅消息

码语者

redis Spring Boot message

四步骤打造银行智能标签体系,助力银行精准营销

袋鼠云数栈

智能标签 数据画像

react源码分析:babel如何解析jsx

flyzz177

React

用javascript分类刷leetcode3.动态规划(图文视频讲解)

js2030code

JavaScript LeetCode

开源依赖项管理指南

SEAL安全

12 月 PK 榜 依赖管理 传递依赖 开源依赖项

真希望你也明白runtime.Map和sync.Map

面向加薪学习

面试 并发 源码阅读 go语言 Map集合

跳板攻击中如何追踪定位攻击者主机(上)

郑州埃文科技

数据安全 网络攻击 跳板攻击

超1800万累计观看,多次占据热榜前列……“无障碍字幕直播间”带来的远不止这些!

猿始人

BEVFormer-accelerate:基于EasyCV加速BEVFormer

阿里云大数据AI技术

深度学习 算法 计算机视觉 12 月 PK 榜

聚焦技术创新!旺链科技荣获“宝山区企业技术中心”认定

旺链科技

区块链 产业区块链 技术创新 12 月 PK 榜

教你用JavaScript实现点击支付框

小院里的霍大侠

JavaScript 小白 编程开发 实战案例 初学者

GaussDB(DWS)运维 :遇到truncate执行慢,怎么办

华为云开发者联盟

数据库 后端 华为云 12 月 PK 榜

Java开发如何通过IoT边缘ModuleSDK进行协议转换

华为云开发者联盟

Java 开发 华为云 12 月 PK 榜

想做长期的 AB 实验?快来看看这些坑你踩了没

京东科技开发者

测试 测试原则 复盘归因 A/B 测试

如何使用Docker部署Go Web应用程序_语言 & 开发_大愚若智_InfoQ精选文章