我们花了好几个小时在我们的机器上开发应用程序,要求和复杂性越来越多。此外,任何现代应用程序都有多个容器、微服务、在不同环境中的部署、各种堆栈等。因此,任何能够使我们的流程更加敏捷的工具都是很方便的。
在这篇文章中,我想介绍一个强大的工具,它可以为你在开发过程中节省大量时间。这就是Tilt,它最近被Docker收购。
为了演示你能用Tilt做什么,我将使用我在一个关于微服务的演讲中使用的这个资源库(葡萄牙语)。这些例子将在Go中进行,但在官方文档中,你可以看到如何在其他技术和场景中使用它。
安装
第一步是在命令行中安装该程序。为此,在我的macOS上,我运行了。
curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash
文档显示了如何在其他操作系统上安装它。
第一个步骤
Tilt通过读取你项目根部的一个名为Tiltfile 的文件来工作。它的语法类似于Python ,而且文档非常详细,显示了我们可以使用的所有选项。
Tiltfile 文件的内容看起来像这样:
local_resource('auth', cmd='cd auth; go build -o bin/auth main.go',
serve_cmd='auth/bin/auth', deps=['auth/main.go', 'auth/security', 'auth/user', 'pkg'])
local_resource('feedbacks', cmd='cd feedbacks; go build -o bin/feedbacks main.go',
serve_cmd='feedbacks/bin/feedbacks', deps=['feedbacks/main.go', 'feedbacks/feedback', 'pkg'])
local_resource('votes', cmd='cd votes; go build -o bin/votes main.go',
serve_cmd='votes/bin/votes', deps=['votes/main.go', 'votes/vote', 'pkg'])
local_resource 函数配置将在你的本地机器上执行的动作,第一个参数是我们要给资源起的名字,这个名字在Tiltfile 中必须是唯一的。
cmd 参数包含要执行的命令。serve_cmd 参数中包含的信息将由Tilt执行,预计不会终止。也就是说,它是将运行我们的服务的命令。
最后一个参数,deps ,是最有趣的参数之一。它表明Tilt将监视哪些项目目录;如果有变化,它将自动运行该进程。因此,例如,如果auth/main.go 、auth/security 、auth/user 、pkg, 发生任何变化,auth 服务将被重新编译并再次运行。由于它是像Go这样的编译语言,这是一个很大的帮助,因为改变文件会自动生成,节省了我们开发人员的宝贵时间。
由于我们的项目由三个微服务组成,Tiltfile 的其余部分为所有的服务配置了相同的行为。
要运行Tilt,只需打开一个终端并输入。
就会出现以下内容。
按空格键可以进入Tilt的图形界面,我们会在那里花很多时间。
我们可以在这个界面上检查每个应用程序的编译日志,并再次执行需要的步骤。它还可以汇总应用程序的日志,并允许我们对其进行搜索。
编译错误也会出现在这个界面上。
到目前为止,光是我介绍的这些功能就应该足以把Tilt列入你的测试工具清单,对吗?但让我们再深入了解一下。
容器
现在让我们改进一下我们的环境。我们将增加为我们的微服务自动创建和更新容器的能力,而不是在本地运行二进制文件。毕竟,它们应该在生产环境中以这种方式运行。
新版本的Tiltfile ,看起来是这样的:
local_resource(
'auth-compile',
cmd='cd auth; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/auth main.go',
deps=['auth/main.go', 'auth/security', 'auth/user', 'pkg'],
)
docker_build(
'auth-image',
'./auth',
dockerfile='auth/Dockerfile',
)
local_resource(
'feedbacks-compile',
cmd='cd feedbacks; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/feedbacks main.go',
deps=['feedbacks/main.go', 'feedbacks/feedback', 'pkg'],
)
docker_build(
'feedbacks-image',
'./feedbacks',
dockerfile='feedbacks/Dockerfile',
)
local_resource(
'votes-compile',
cmd='cd votes; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/votes main.go',
deps=['votes/main.go', 'votes/vote', 'pkg'],
)
docker_build(
'votes-image',
'./votes',
dockerfile='votes/Dockerfile',
)
docker_compose('./docker-compose.yml')
我添加了docker_build 函数。顾名思义,它生成了容器镜像。为此,为每个微服务创建一个Dockerfile 是必要的。例如,auth 服务的镜像看起来像这样:
FROM alpine
ADD bin/auth /
EXPOSE 8081
CMD ["/auth"]
其他服务非常相似,只是改变了可执行文件的名称和端口:feedbacks 运行在端口8082 ,votes 运行在8083 。
在做这个改变的时候,Tilt会警告说,必须要有一些部署容器的方法;否则,它将无法工作。一种方法是创建一个docker-compose.yml 并在docker_compose 函数中使用它。你的内容看起来像这样:
version: "3"
services:
auth:
image: auth-image
ports:
- "8081:8081"
container_name: auth
feedbacks:
image: feedbacks-image
ports:
- "8082:8082"
container_name: feedbacks
votes:
image: votes-image
ports:
- "8083:8083"
container_name: votes
有了这些变化,Tilt现在可以观察到项目代码的修改,如果这些修改发生了,它就会进行编译、生成容器和更新环境的工作!
Kubernetes!
现在让我们把它变得更严肃一些!让我们让Tilt把我们的应用程序部署到Kubernetes集群上。为此,我将使用minikube,一个为开发而安装本地环境的解决方案。
在macOS上,只需运行:
brew install minikube
minikube start
现在我们已经建立了我们的集群,让我们改变我们的Tiltfile ,以反映新的环境:
load('ext://restart_process', 'docker_build_with_restart')
local_resource(
'auth-compile',
cmd='cd auth; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/auth main.go',
deps=['auth/main.go', 'auth/security', 'auth/user', 'pkg'],
)
docker_build_with_restart(
'auth-image',
'./auth',
dockerfile='auth/Dockerfile',
entrypoint=['/auth'],
live_update=[
sync('./auth/bin/auth', '/auth'),
],
)
k8s_yaml('auth/kubernetes.yaml')
k8s_resource('ms-auth', port_forwards=8081,
resource_deps=['auth-compile'])
local_resource(
'feedbacks-compile',
cmd='cd feedbacks; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/feedbacks main.go',
deps=['feedbacks/main.go', 'feedbacks/feedback', 'pkg'],
)
docker_build_with_restart(
'feedbacks-image',
'./feedbacks',
dockerfile='feedbacks/Dockerfile',
entrypoint=['/feedbacks'],
live_update=[
sync('./feedbacks/bin/feedbacks', '/feedbacks'),
],
)
k8s_yaml('feedbacks/kubernetes.yaml')
k8s_resource('ms-feedbacks', port_forwards=8082,
resource_deps=['feedbacks-compile'])
local_resource(
'votes-compile',
cmd='cd votes; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/votes main.go',
deps=['votes/main.go', 'votes/vote', 'pkg'],
)
docker_build_with_restart(
'votes-image',
'./votes',
dockerfile='votes/Dockerfile',
entrypoint=['/votes'],
live_update=[
sync('./votes/bin/votes', '/votes'),
],
)
k8s_yaml('votes/kubernetes.yaml')
k8s_resource('ms-votes', port_forwards=8083,
resource_deps=['votes-compile'])
这里有很多新的东西!
第一个是load 功能,它可以加载Tilt扩展。这是一种扩展工具功能的方式,有几个可用。这里我们使用docker_build_with_restart, ,它将更新在我们Kubernetes集群内运行的容器。
另一个变化是与Kubernetes内的应用程序部署设置有关。k8s_yaml 函数指出哪个文件包含用于部署的 "配方"。而k8s_resource 函数在这里被用来将集群端口转发到我们的本地环境,使测试更加方便。
auth/kubernetes.yaml 文件的内容是:
apiVersion: v1
kind: Service
metadata:
labels:
app: ms-auth
name: ms-auth
spec:
ports:
- port: 8081
name: http
protocol: TCP
targetPort: 8081
selector:
app: ms-auth
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ms-auth
labels:
app: ms-auth
spec:
selector:
matchLabels:
app: ms-auth
template:
metadata:
labels:
app: ms-auth
spec:
containers:
- name: ms-auth
image: auth-image
ports:
- containerPort: 8081
其他文件实际上是一样的,只是改变了二进制文件的名称和端口。
现在,Tilt为我们完成了所有繁重的工作。
要检查我们的微服务是否在集群上运行,我们可以使用命令:
kubectl get pods -n default
NAME READY STATUS RESTARTS AGE
ms-auth-7446897869-89r2j 1/1 Running 0 81s
ms-feedbacks-b5df67d6-wzbj2 1/1 Running 0 81s
ms-votes-76565ddc9c-nkkt7 1/1 Running 0 81s
结论
我不知道我是否成功地展示了我对这个工具有多兴奋!我已经用Tilt做了一段时间了。
我在一个复杂的项目上使用Tilt几周了,创建了一个Kubernetes控制器。由于所有这些自动化,我可以专注于应用逻辑,而其他部分则自动完成。这就节省了大量的时间。