持续集成(CI)指的是开发人员尽可能频繁地集成代码,并且在自动化构建将每个提交合并到共享存储库之前和之后都要进行测试的实践。
CI加快了您的开发过程,并最大限度地降低了生产中关键问题的风险,但设置并非易事; 自动构建在不同的环境中运行,其中运行时依赖项的安装和外部服务的配置可能与本地和开发环境中的不同。
Docker是一个容器化平台,旨在简化环境标准化问题,因此应用程序的部署也可以标准化。对于开发人员,Docker允许您通过在本地容器中运行应用程序组件来模拟本地计算机上的生产环境。使用Docker Compose可以轻松自动化这些容器,而与应用程序和底层操作系统无关。
同时,您也可以选择使用腾讯云容器服务,腾讯云容器服务基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务。
本教程使用Docker Compose演示CI工作流的自动化。
我们将创建一个Dockerized“Hello world”类型的Python应用程序和一个Bash测试脚本。Python应用程序需要运行两个容器:一个用于应用程序本身,一个用于存储的Redis容器,作为应用程序的依赖项。
然后,测试脚本将在其自己的容器中进行Docker化,整个测试环境转移到docker-compose.test.yml文件,这样我们就可以确保在新的统一应用程序环境中运行每个测试执行。
此方法显示了每次测试时如何为应用程序构建相同的,全新的测试环境,包括其依赖关系。
因此,我们将CI工作流的自动化独立于测试中的应用程序和底层基础架构。
在开始之前,您将需要:
如果您的服务器上尚未提供Docker,最简单的方法是下载并执行官方Docker安装脚本,该脚本会提示输入sudo密码:
wget -qO- https://get.docker.com/ | sh
为了更容易使用Docker,请使用以下命令将用户添加到docker组:
sudo usermod -aG docker $(whoami)
注销然后登录到您的服务器以激活用户的docker组。
Docker Compose是一个开源工具,用于使用声明式方法定义和运行多容器应用程序。要安装Docker Compose,请执行以下命令:
sudo apt-get update
sudo apt-get -y install python-pip
sudo pip install docker-compose
执行以下命令验证docker-compose
是否已正确安装:
docker-compose --version
你应该看到类似的东西:
docker-compose version 1.6.2, build 4d72027
这应该告诉您已安装的docker-compose
的版本。
在这一步中,我们将创建一个简单的Python应用程序,作为您可以使用此设置测试的应用程序类型的示例。
通过执行以下命令为我们的应用程序创建一个新文件夹:
cd ~
mkdir hello_world
cd hello_world
使用nano编辑新文件app.py
:
nano app.py
添加以下内容:
from flask import Flask
from redis import Redis
app = Flask(__name__)
redis = Redis(host="redis")
@app.route("/")
def hello():
visits = redis.incr('counter')
html = "<h3>Hello World!</h3>" \
"<b>Visits:</b> {visits}" \
"<br/>"
return html.format(visits=visits)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=80)
app.py
是一个基于Flask的Web应用程序,它连接到Redis数据服务。visits = redis.incr('counter')
这一行增加了访问次数并在Redis中保留了此值。最后,Hello World
消息以及访问次数以HTML格式返回。
我们的应用有两个依赖,Flask
和Redis
,你可以在头两行看到他们。我们必须先定义这些依赖项,然后才能执行应用程序。编辑新文件:
nano requirements.txt
添加内容:
Flask
Redis
Docker使用一个名为Dockerfile
的文件来为给定应用程序指示构建Docker镜像所需的步骤。编辑新文件:
nano Dockerfile
添加以下内容:
FROM python:2.7
WORKDIR /app
ADD requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt
ADD app.py /app/app.py
EXPOSE 80
CMD ["python", "app.py"]
让我们分析每一行的含义:
FROM python:2.7
:表示我们的“Hello World”应用程序映像是从官方python:2.7
Docker镜像构建的WORKDIR /app
:将Docker镜像内的工作目录设置为 /app
ADD requirements.txt /app/requirements.txt
:将文件requirements.txt
添加到我们的Docker镜像RUN pip install -r requirements.txt
:安装应用程序pip
依赖项ADD app.py /app/app.py
:将我们的应用程序源代码添加到Docker镜像中EXPOSE 80
:表示我们的应用程序可以通过端口80(标准公共Web端口)访问CMD ["python", "app.py"]
:启动我们的应用程序的命令此Dockerfile
文件包含构建“Hello World”应用程序主要组件所需的所有信息。
依赖性
现在我们来看一个更复杂的例子。我们的应用程序需要Redis作为外部服务。这种依赖类型在传统的Linux环境中每次都很难以相同的方式设置,但是使用Docker Compose,我们每次都可以以可重复的方式进行设置。
让我们创建一个docker-compose.yml
文件来开始使用Docker Compose。
编辑新文件:
nano docker-compose.yml
添加以下内容:
web:
build: .
dockerfile: Dockerfile
links:
- redis
ports:
- "80:80"
redis:
image: redis
此Docker Compose文件指示如何在两个Docker容器中本地启动“Hello World”应用程序。
它定义了两个容器,web
和redis
。
web
使用当前文件夹作为build
上下文,并从我们刚刚创建的Dockerfile
文件构建我们的Python应用程序。这是我们为Python应用程序制作的本地Docker镜像。它定义了一个到redis
容器的链接,以便访问redis
容器IP。它还使用您的Ubuntu服务器的公共IP从Internet公开访问端口80redis
的标准公共Docker镜像执行 redis
在此步骤中,我们将部署应用程序,最后它将可通过Internet访问。从部署工作流程的目的来看,您可以将其视为开发,登台或生产环境,因为您可以多次以相同的方式部署应用程序。
docker-compose.yml
和Dockerfile
文件允许您通过以下命令来自动执行本地环境的部署:
docker-compose -f ~/hello_world/docker-compose.yml build
docker-compose -f ~/hello_world/docker-compose.yml up -d
第一行从Dockerfile
文件构建我们的本地应用程序映像。第二行以守护进程模式(-d)
来运行web
和redis
容器,如文件docker-compose.yml
中所指定的。
通过执行以下命令检查是否已创建应用程序容器:
docker ps
这应该显示两个名为helloworld_web_1
和helloworld_redis_1
的运行容器。
让我们检查应用程序是否已启动。我们可以通过执行以下命令获取容器helloworld_web_1
的IP :
WEB_APP_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' helloworld_web_1)
echo $WEB_APP_IP
检查Web应用程序是否返回正确的消息:
curl http://${WEB_APP_IP}:80
这应该返回如下信息:
<h3>Hello World!</h3><b>Visits:</b> 1<br/>
每次点击此端点时,访问次数都会增加。您还可以通过访问Ubuntu服务器的公共IP地址从浏览器访问“Hello World”应用程序。
如何自定义您自己的应用程序
设置自己的应用程序的关键是将您的应用程序放在自己的Docker容器中,并从自己的容器中运行每个依赖项。然后,您可以使用Docker Compose定义容器之间的关系。
现在我们将为Python应用程序创建一个测试脚本。这将是一个检查应用程序HTTP输出的简单脚本。该脚本是您可能希望作为持续集成部署过程的一部分运行的测试类型的示例。
编辑新文件:
nano test.sh
添加以下内容:
sleep 5
if curl web | grep -q '<b>Visits:</b> '; then
echo "Tests passed!"
exit 0
else
echo "Tests failed!"
exit 1
fi
test.sh
测试我们的“Hello World”应用程序的基本Web连接。它使用cURL来检索访问次数并报告测试是否通过。
为了测试我们的应用程序,我们需要部署一个测试环境。而且,我们希望确保它与我们在步骤5中创建的实时应用程序环境完全相同。
首先,我们需要通过创建一个新的Dockerfile文件来Docker化我们的测试脚本。编辑新文件:
nano Dockerfile.test
添加以下内容:
FROM ubuntu:trusty
RUN apt-get update && apt-get install -yq curl && apt-get clean
WORKDIR /app
ADD test.sh /app/test.sh
CMD ["bash", "test.sh"]
Dockerfile.test
扩展官方ubuntu:trusty
映像以安装curl
依赖项,添加tests.sh
到映像文件系统,并指示CMD
使用Bash执行测试脚本的命令。
一旦我们的测试进行了Docker化,它们就可以以可复制和不可知的方式执行。
下一步是将我们的测试容器链接到我们的“Hello World”应用程序。这是Docker Compose再次可以帮助到我们的地方。编辑新文件:
nano docker-compose.test.yml
添加以下内容:
sut:
build: .
dockerfile: Dockerfile.test
links:
- web
web:
build: .
dockerfile: Dockerfile
links:
- redis
redis:
image: redis
Docker Compose文件的后半部分以与前一个文件相同的方式部署主web
应用程序及其redis
依赖项docker-compose.yml
。这是指定web
和redis
容器的文件的一部分。唯一的区别是web
容器不再暴露端口80,因此在测试期间应用程序将无法通过公共Internet访问。因此,您可以看到我们正在构建应用程序及其依赖项,与在实时部署中完全相同。
该docker-compose.test.yml
文件还定义了一个sut
容器(以测试中的系统命名 ),负责执行我们的集成测试。该sut
容器指定当前目录为我们的build
目录,并指定了Dockerfile.test
文件。它链接到web
容器,因此我们的test.sh
脚本可以访问应用程序容器的IP地址。
如何自定义您自己的应用程序
请注意,docker-compose.test.yml
可能包括许多外部服务和多个测试容器。Docker将能够在单个主机上运行所有这些依赖项,因为每个容器共享底层操作系统。
如果要在应用程序上运行更多测试,可以为它们创建其他Dockerfiles,类似于上面显示的Dockerfile.test
文件。
然后,您可以在docker-compose.test.yml
文件中的sut
容器下添加其他容器,引用其他Dockerfiles。
最后,将Docker的想法从本地环境扩展到测试环境,我们通过执行以下操作,使用Docker自动测试应用程序:
docker-compose -f ~/hello_world/docker-compose.test.yml -p ci build
此命令构建docker-compose.test.yml
所需的本地映像。请注意,我们用-f
来指向docker-compose.test.yml
和-p
来表示特定的项目名称。
现在执行以下命令来启动新的测试环境:
docker-compose -f ~/hello_world/docker-compose.test.yml -p ci up -d
执行以下命令检查sut
容器的输出:
docker logs -f ci_sut_1
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 42 100 42 0 0 3902 0 --:--:-- --:--:-- --:--:-- 4200
Tests passed!
最后,检查sut
容器的退出代码以验证您的测试是否已通过:
docker wait ci_sut_1
产量
0
这个命令执行后,如果测试通过,那么$?
的值将是0
。否则,我们的应用程序测试失败。
请注意,其他CI工具可以克隆我们的代码存储库并执行这些命令来验证测试是否与应用程序的最新位一起传递,而不必担心运行时依赖性或外部服务配置。
就是这样!我们已经在与我们的生产环境相同的新建环境中成功运行了测试。
感谢Docker和Docker Compose,我们已经能够自动化如何构建应用程序(Dockerfile
),如何部署本地环境(docker-compose.yml
),如何构建测试图像(Dockerfile.test
)以及如何对任何应用程序执行(集成)测试(docker-compose.test.yml
)。
特别是,使用该docker-compose.test.yml
文件进行测试的优点是该测试过程:
docker-compose.test.yml
的方式独立于被测应用程序本教程展示了如何测试简单的“Hello World”应用程序的示例。
现在是时候使用您自己的应用程序文件,Docker化您自己的应用程序测试脚本,并创建自己docker-compose.test.yml
的应用程序以在新的和不可变的环境中测试您的应用程序。
更多Ubuntu教程请前往腾讯云+社区学习更多知识。
参考文献:《How To Configure a Continuous Integration Testing Environment with Docker and Docker Compose on Ubuntu 14.04》
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。