容器 & 服务:Docker 应用的 Jenkins 构建 (二)
系列文章:
容器 & 服务:Jenkins 本地及 docker 安装部署
容器 & 服务:一个 Java 应用的 Docker 构建实战
一 概述
容器 & 服务:Docker 应用的 Jenkins 构建 中,通过 shell 编写的部署(deploy)脚本,初步把 Docker 纳入持续集成平台。但这个 demo 依然是玩具。因为我们只是做了一个简单的衔接,并没有完全实现上线的全部过程。而且,我们的 demo 应用只是一个空接口,没有涉及任何服务的部分。即使是持续集成本身,也没有做多机发布、回滚、平滑升级等等。本篇将列举这些问题,并逐个解构并在后续系列文章中逐个落实。
二 生产环境
实际的持续继承过程,在构建时会涉及代码版本校验,静态代码检查(可选),代码/产物(打包结果)上传到服务器,旧进程关闭 &新进程发布【这里也会涉及到平滑重启】。另外,在发布过程中也可能出现中断,导致只有部分机器人发布了新包,而其他机器保留旧包的情况,这时需要完善的回滚策略;
还有很多存在小流量测试/AB 测试,需要金丝雀发布、滚动发布、蓝绿发布等等。
另外,我们目前是直接使用 docker run 启动容器,但没有使用任何容器编排工具。实际的生产环境中,多达上百甚至数千的服务管理,x10 甚至 x100 以上数量级的容器规模,显然不可能使用这样原始的方式去管理,接下来就介绍一下容器编排的相关内容。
三 容器编排
开源的容器编排工具有 k8s,swarm,Marathon 等等,下面会简单介绍一下这三种工具。
3.1 kubernetes
即 k8s,资料应该是最多的,也是目前使用最为广泛的。K8s 还可以作为托管解决方案提供,对逻辑单元 pods 进行调度——pods 是一组部署到一起的容器,用于完成特定的任务。K8s 对 Docker 没有任何依赖,是 Cloud Native Computing Foundation(CNCF)项目的一部分。
本篇先不做详细描述,后面文章中会做专题讲解。
3.2 docker+swarm+compose
Docker Swarm 是 Docker 的原生编排工具,从 Docker 1.12 开始新增了 swarm 模式,用于跨多个主机进行编排,可以通过 Docker API 访问,也可以用它调用类似 docker compose 这样的工具,对服务和容器进行声明式编排。Docker Swarm 是 Docker Datacenter 的一部分,后者针对企业级容器部署。
3.3 mesos+marathon
编排框架 Marathon 基于 Apache Mesos 项目,通过 API 提供了跨数据中心的资源管理和调度抽象,而这些数据中心在物理上可能是分散的。Mesos 上的系统可以用底层的计算、网络和存储资源,就想虚拟机通过虚拟机管理程序使用底层资源一样。Marathon 支持 Mesos 容器运行时,也支持 Docker 容器运行时。
本篇将会使用 compose 和 swarm 对构建示例进行改造。
四 compose&swarm 介绍
4.1 Compose
Compose 是用于定义和运行多容器 Docker 应用程序的工具(也就是容器编排)。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
Compose 使用的三个步骤:
使用 Dockerfile 定义应用程序的环境。
使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
最后,执行 docker-compose up 命令来启动并运行整个应用程序。
由于本地使用的是 macos,Mac 的 Docker 桌面版和 Docker Toolbox 已经包括 Compose 和其他 Docker 应用程序,因此 Mac 用户不需要单独安装 Compose。Docker 安装说明可以参阅 MacOS Docker 安装。
4.2 YAML
YAML 是 "YAML Ain't a Markup Language"(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)。
YAML 的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等数据形态。它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件、倾印调试内容、文件大纲(例如:许多电子邮件标题格式和 YAML 非常接近)。
YAML 的配置文件后缀为 .yml,如:runoob.yml 。
基本语法:
大小写敏感
使用缩进表示层级关系
缩进不允许使用 tab,只允许空格
缩进的空格数不重要,只要相同层级的元素左对齐即可
'#'表示注释
4.3 Dockerfile 与 yml
Dockerfile 是拿来构建自定义镜像的,并没有直接生成容器。只是可以在运行镜像时运行容器而已。
做容器编排以部署环境,是使用 docker-compose.yml 文件进行的,里面可能会需要用到 Dockerfile 。
Dockerfile 把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像。
docker-compose 是官方开源项目,负责实现对 Docker 容器集群的快速编排,部署分布式应用。通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
4.4 Docker Compose 与 Docker Stack
docker 在 1.12 的时候引入了 swarm mode,其中有个 stack 命令,看起来两者的功能差不多,但还有一点差异的:
docker compose:
compose 是 fig 演变而来,python 脚本,需要单独安装,compose 可以 build image,compose 需要单独安装,compose 更多是 dev 环境使用。
docker stack:
stack 被集成进 docker 原生 CLI,go 编写,不支持 build image。stack 更适合 docker cloud 环境,用来管理集群。
一个 stack 是一组 services 的集合,它可以使你的 app 运行在指定的环境,一个 stack 文件是一个 YAML 文件,YAML 文件中定义了一个或者多个 services,和 docker-compose.yml 文件很相似,但是和 compose 又有一点小扩展。两者虽然都使用 compose.yml 文件,但是里面的命令有一丢丢的差别,stack 只支持 swarm 模式下使用,只支持 compose V3 格式。
五 部署脚本改造
5.1 docker-compose.yml
docker-compose 是通过识别工作目录下的 docker-compose.yml 文件,并根据文件内容进行构建的。一个简单的示例如下:
在命令行执行 docker-compose up 命令的输出如下:
在 docker 容器中,可以看到新创建和启动的容器:
后台执行,增加-d 参数即可,docker-compose up -d。
5.2 docker-compose up 命令
格式为docker-compose up [options] [SERVICE...]
,该命令可以自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。
默认情况下,docker-compose up
启动的容器都在前台,控制台将会同时打印所有容器的输出信息,可以很方便进行调试。当通过Ctrl+c
停止命令时,所有容器将会停止。如果希望在后台启动并运行所有的容器,使用docker-compose up -d
。
如果服务容器已经存在,并且在创建容器后更改了服务的配置(即docker-compose.yml
文件)或者镜像,那么docker-compose
会停止容器,然后重新创建容器。
注意: 这里的镜像修改指的是已经拉取到本地的镜像更改。当你的镜像仓库内容有变化,不会影响到本地的服务容器。如果你想更新本地的镜像,可以使用docker-compose pull [serviceName]
。
另外,如果你想防止在配置文件改动后服务容器进行更改,那么可以使用--no-recreate
参数。
有关该命令的其他参数,可以使用docker-compose up --help
查看。
更多 docker-compose 命令的详细描述,可以查看 docker 命令行的官方文档 。
5.3 docker stack
除了 docker-compose up 命令,我们也可以使用 docker stack deploy 来启动容器,执行命令和控制台输出如下:
5.4 Jenkins 部署脚本调整
回到 Jenkins 构建配置,把 shell 脚本内容调整如下:
然后在 Jenkins 中再次构建项目,确认容器启动无误。
相关文件和脚本已更新到项目代码中,地址:https://github.com/flamingstar/dockerdemo。
注:有一点需要注意,在 github 上新创建的项目,代码默认主分支命名变成了 main,这导致 jenkins 构建使用 master 分支的配置构建出错。如果发现是这种情况,那么需要在 git 中修改分支名称为 master。
六 容器资源与 k8s 初探
6.1 Container 中的异类
在构建这个 demo 之前,曾经也胡乱尝试过一些 docker 和 k8s 的示例,导致上述一系列操作后,发现 Containers 内的容器列表如下:
而这些容器与 docker run 操作 和 docker-compose up 操作启动的容器不同,在命令行试图用 docker stop 停止或 docker rm 删除时,发现消失一段时间后又会自动启动。这就是 k8s 干的"坏事"了。从命名方式也能看出,都带有/k8s_的前缀。
那么就顺便了解一下 k8s,并清理掉这些“坏”容器(实际上是 pods)。
在 Kubernetes 群集中,只能运行 pods。Pods 在 kubernetes 中是部署的原子单位。一个 Pod 是一个或者多个共存的容器,它们共享着相同的内核命名空间,比如网络命名空间。
关于 docker container 和 k8s 的 pod 之间的相关性和差异,可以看下kubernetes之七–Pods这篇文章。
6.2 k8s 几个命令及 pod 操作
6.2.1 获取 pods 列表
从这里我们可以看出各个 pod 的名字,READY,状态(STATUS),重启次数(RESTARTS),年龄(AGE)存活时间。
6.2.2 删除 pod
使用 kubectl delete 命令:
再次 kubectl get pods,发现 pod 还在,只是重启次数和 AGE 发生了变化:
why... 因为不懂啊!查了一下资料,有说正确删除 pod 的方法如下:
1、先删除 pod
2、再删除对应的 deployment
否则只是删除 pod 是不管用的,还会看到 pod,因为 deploy 使用的 yml 文件中定义了副本数量。ok,按照说明尝试一下:
6.2.3 查询并删除 deployments
执行删除:
再查看 deployments 和 pods,额,还在顽强的活着。。
通过k8s-pod管理,了解到“这种删除由于会触发了 replicas 的确保机制,所以需要删除 deployment”,不过上面删除 deployment 也失败了,这点比较奇怪。
6.2.4 回顾操作过程
java-demo 的几个 pod 先不去管它,历史遗留问题后面再处理。dockerdemoapplication1 是使用 docker-compose up 和 docker stack deploy 操作的,那么很可能就是操作方向错了(虽然 container 中都是 k8s_开头的命名)。
通过 docker stack services dockerdemoapplication1 查询服务:
果然是这个坑。既然这回找到了位置,那么从堆栈中删除应该就可以了吧?
再看 Idea 的 docker 栏(或控制台 docker ps),已经成功删除。
附:一些可能常用的 docker 操作
1、批量删除镜像
docker rmi docker images|grep none|awk '{print $3}'
删除操作示例:
2、强制删除所有镜像
3、批量停止容器
docker stop $(docker ps -a -q)
4、批量删除容器
docker rm $(docker ps -a -q)
版权声明: 本文为 InfoQ 作者【程序员架构进阶】的原创文章。
原文链接:【http://xie.infoq.cn/article/03a4836887b0a39f85b37da3a】。文章转载请联系作者。
评论