我的web应用程序由3个docker容器组成:app
(带代码的主容器)、redis
和node
。我有一个部署shell脚本,它可以做以下事情:
- 从git克隆master(
git clone <...> $REVISION
) - 从文档根目录(
rm -rf $PROJECT_DIR
)中删除所有文件 - 将所有克隆到文档根目录中(
mv $REVISION $PROJECT_DIR
) - 停止所有正在运行的容器:(
docker-compose stop
) - 移除所有停止的容器(
docker-compose rm -f
) - 构建容器(
docker-compose build
) - 运行所有已构建的容器(
docker-compose up -d
) - 通过
docker exec
运行容器内的所有init和start脚本(例如:config编译器、nginx重载)
这对我来说很好,但我对这个计划有几个疑问:
- 在步骤6中,如果我不将文件更改为节点容器,它将使用已经构建的映像-这很快。但是,如果我更改了一些内容,容器将重新构建——它速度很慢,并且会增加未使用的图像
- 在最坏的情况下(当我对节点代码进行更改时),部署可能持续大约2-3分钟,在最好的情况下,大约持续30秒。但即便如此,对一些用户来说,这也是一个停机时间
正如我所认为的,我需要可用性来构建新容器(在旧容器的parralel中继续工作),并且只有在成功状态之后-更改应用程序使用的最新容器的标签。我该怎么做?
非常感谢您的评论。
我所做的是按照版本标记我的所有图像,然后标记"最新"。所以我有一张带有多个标签的图片。只需标记多个即可。当你按版本标记时,它可以让你毫无问题地在"最新"标签周围移动:
docker build -t=myApp .
docker tag myApp:latest myApp:0.8.1
现在,当你docker images
时,你会看到同一张图片列出两次,只是带有不同的标签(都是"最新"one_answers"0.8.1")
# the original container is still running while this builds ...
docker build -t=myApp .
# now tag "latest" to the newest version
docker tag myApp:latest myApp:0.8.2
# and now you can just stop and restart the container ...
docker rename myApp myApp-old
docker run -d --name=myApp -p 80:80 myApp:latest
这是你可以做的事情,但看起来你真的需要一种在没有任何停机时间的情况下交换容器的方法。零停机时间容器更改。
有一个我已经使用了几年的过程,为Docker容器使用Nginx反向代理。Jason Wilder在这篇博客文章中详细介绍了这样做的过程。
我将向您概述这将为您做些什么。jwilder/nginx-proxy
docker镜像将充当容器的反向代理,默认情况下,它会根据主机名对到容器的入站连接进行循环负载平衡。在构建并运行具有相同VIRTUAL_HOST
环境变量的容器后,nginx-proxy
会自动循环负载平衡这两个容器。通过这种方式,您可以启动新容器,它将开始为请求提供服务。然后你就可以放下你的另一个旧集装箱了。零停机更新。
只是一些细节:nginx-proxy
图像使用Jason Wilder的docker-gen
实用程序自动获取docker容器信息,然后将请求路由到每个容器。这意味着用一个新的环境变量(VIRTUAL_HOST
)启动普通容器,nginx-proxy
将自动开始将入站请求路由到容器。这最好用于在许多容器之间"共享"一个端口(例如tcp/80)。此外,这种反向代理意味着它可以处理HTTPS和HTTP身份验证,因此您不必在web容器中处理它。后端是未加密的(HTTP),但由于它在同一台主机上,所以没有问题。