🌎 Web | 使用 Travis CI 实现自动测试并部署

最近开了个新的项目,由于涉及到多人的协作,为了便于前端的开发,我把服务器部署到腾讯云的服务器上,并且利用 Travis CI 实现了从提交代码、运行测试、构建Docker镜像到部署服务的自动化流程。

依赖服务

首先,我们先要解决服务端所依赖的服务。本项目的服务端主要依赖于以下的服务:

  • MongoDB
  • Redis

这些服务通过docker很容易就可以实现部署,这里就不再详细说明了。

自动测试

下一步就是需要利用 Travis CI 实现自动测试了。

对于 Golang 来说,单元测试的实现是非常简单的,因此语言本身就提供了关于测试的库。只需要编写xxx_test.go文件,然后使用go test命令就可以进行测试。

现在主要遇到的问题就是本项目的单元测试主要测试的是对数据库的操作,因此需要先连接数据库,而在 Golang中我们很难指定测试文件的运行顺序,因此对于每个模块的测试,都需要先连接数据库,再执行测试代码,最后清理数据库。因此,我们不能按照 Golang 中传统的测试方式来写测试代码,而是需要自定义一套测试的顺序。

利用testing.T中的Run接口,实现自定义的测试序列

1
2
3
4
5
6
7
8
func TestCache(t *testing.T) {
t.Run("InitRedis", testInitRedis)
t.Run("InitDB", testInitDB)
t.Run("GetUserBaseInfo", testGetUserBaseInfo)
t.Run("testAddLike", testAddLike)
t.Run("DisconnectRedis", testDisconnectRedis)
t.Run("DisconnectDB", testDisconnectDB)
}

然后编写travis.yml,实现构建和测试,并且将测试结果上传到codecov进行分析

1
2
3
4
5
6
7
8
language: go
go:
- 1.12.x
script:
- go build
- go test -v -coverprofile="coverage.txt" -covermode=atomic ./app/models/...
after_success:
- bash <(curl -s https://codecov.io/bash)

构建Docker

在实现自动部署之前,我们需要在本地实现服务端的Docker打包并部署。

首先编写dockerfile构建镜像。

基于 Golang 1.12, 我们可以使用 go mod模块来安装依赖库,利用Docker我们可以加速这个过程。

具体的实现原理是使用一个中间层缓存镜像存储Golang 的编译以及依赖环境,然后每次编译如果go.mod没有发生变化,那就直接重用这个环境进行编译,而不需要再重新下载依赖进行编译。

通过切换WORKDIR就可以实现,具体操作如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
FROM golang:1.12 as build

ENV GOPROXY https://go.likeli.top
ENV GO111MODULE on

WORKDIR /go/cache

ADD go.mod .
ADD go.sum .
RUN go mod download

WORKDIR /go/release

ADD . .

RUN GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -installsuffix cgo -o main main.go

FROM scratch as prod

COPY --from=build /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=build /go/release/main /
COPY --from=build /go/release/config.yaml /

CMD ["/main"]

打包的时候需要将配置文件config.yaml一同COPY进去

然后使用docker-compose进行部署

1
2
3
4
5
6
7
8
version: '3'
services:
TimeForCoin:
build:
context: .
dockerfile: Dockerfile
image: time-for-coin
network_mode: host

自动部署

本地完成部署之后,就可以实现自动部署了。

自动部署的原理是再Travis CI 测试通过之后,通过ssh登陆到服务器,执行部署脚本。

在这个过程中,我们需要保护我们服务器的安全,并且不能影响到服务器中其他的服务,因此我新建了一个用户deploy专门用于部署,然后生成该用户的登陆密钥。

1
ssh-keygen -t rsa -C "deploy_key" -f ~/.ssh/id_ras_deploy

然后我们需要利用Travis提供的工具对这个密钥进行加密

1
2
3
4
gem install travis
travis login --auto # 登陆
touch .travis.yml
travis encrypt-file ~/.ssh/id_ras_deploy --add

然后脚本会自动在我们的travis.yaml中添加对密钥的解密指令。其原理是使用存储在环境变量中的密钥对文件进行解密,我们只需要把加密后的文件deploy.enc放在仓库中就可以了。

1
2
3
before_install:
- openssl aes-256-cbc -K $encrypted_f91baf41390f_key -iv $encrypted_f91baf41390f_iv
-in id_ras_deploy.enc -out ~/.ssh/id_ras_deploy -d

然后我们再编写一个部署的脚本,自动从GitHub上获取最新的源码,然后进行部署。

1
2
3
4
5
6
git checkout .
git clean -df
git pull
sudo docker-compose build
sudo docker-compose down
sudo docker-compose up -d

要实现远程ssh登陆,我们还需要做一点工作,在仓库中加入ssh_config配置文件,表明远程地址用户名以及密钥位置。

1
2
3
4
5
Host love.zhenly.cn
HostName love.zhenly.cn
StrictHostKeyChecking no
User deploy
IdentityFile ~/.ssh/deploy

最后修改一下travis.yaml,在after_success中加入远程登陆部署的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
language: go
go:
- 1.12.x
addons:
ssh_known_hosts:
- love.zhenly.cn
before_install:
- openssl aes-256-cbc -K $encrypted_da5ea0339585_key -iv $encrypted_da5ea0339585_iv
-in deploy.enc -out ~/.ssh/deploy -d
- chmod 600 ~/.ssh/deploy
- cp ssh_config ~/.ssh/config
script:
- go build
- go test -v -coverprofile="coverage.txt" -covermode=atomic ./app/models/...
after_success:
- bash <(curl -s https://codecov.io/bash)
- ssh deploy@love.zhenly.cn "cd ~/TimeForCoin/Server && source ~/.bashrc && bash ./deploy.sh"

最后当我们把船新的代码push到GitHub上的时候,Travis CI就会开始工作

1561699230889

当测试通过的时候,就会自动连接服务器,执行上面的部署脚本,拉取最新的代码并且进行打包部署。

1561699310439

小结

在这次项目中,首次使用自动部署的方式进行开发,每次提交代码后就可以直接测试并部署到服务器上,而前端也不需要在本地打开服务端进行测试,直接连接远程的测试服务器进行开发,极大地提高了开发的效率,感觉非常方便,果然技术发展的动力还是因为太懒了。因为懒得开本地服务端,懒得部署服务器,才搞出来这一套东西🐷。

🚀 项目: Github

土豪通道
0%