摘要
本文内容转自网络,个人学习记录使用,请勿传播
Docker生命周期:Build,Ship and Run
“Build,Ship and Run” 是docker最早的一句宣传语,讲的是docker的整个生命周期。
- Build:指的是如何创建镜像
- Ship:指的是镜像如何流转
- Run:指的是镜像如何运行(进入运行态)
docker的整个生命周期实际上就是镜像的流转和状态的改变。
众所周知docker最核心的是容器技术,那么在docker中容器技术的是什么?镜像,而container仅仅只是容器(镜像的运行态),镜像才是docker容器技术的核心。
- Docker生命周期的流转基本都是通过镜像来流转的
- 容器是基于镜像启动的,没有镜像也就没有了容器
- 镜像采用分层技术
- 通过CoW技术让容器可以共享镜像的文件系统,确保底层数据不丢失
Docker为什么脱颖而出
开源
定义了镜像的概念
创建镜像:Build
build一个image
镜像基本操作
1 | # 查看镜像 |
容器是怎么变成镜像的
docker在发布初期就提供了将容器变成镜像的方法:
- 通过基础镜像创建镜像
- 然后登陆容器像普通的操作系统一样手动部署环境
- 然后将容器打包生成镜像
1 | docker commit -p container-id image-name |
但是这种方式生成的镜像,所有操作都在一个镜像层中,不利于后期的维护、管理。
Dockerfile
原理同样是将容器变成镜像,通过配置文件实现了镜像的自动创建
1 | # 一个简单的Dockerfile |
CMD
1 | 构建镜像后,情动容器默认执行的命令,如初始化环境,可以在run的时候被覆盖 |
ENTRYPOINT
1 | 与CMD命令有些像,但是默认不能被覆盖一般与CMD配合使用,可以配合docker run 传递参数 |
WORKDIR
1 | 可以用来切换目录,限定一些指令在目录下执行,也可以为最终的镜像设置工作目录 |
ENV
1 | 可以在镜像构建过程中设置环境变量,可以延续到以此镜像为基础的容器中,也可以用-e选项来传递环境变量 |
USER
1 | 指定启动的镜像使用的用户,默认是root |
VOLUME
1 | 指定容器启动的时候添加卷,一个卷可以存在一个或多个容器内的特定目录里面,可以实现将数据或者代码添加到镜像中而不是提交到镜像中,并且允许多个容器共享 |
ADD
1 | 用来将构建上下文中的文件或目录复制到镜像中 |
COPY
1 | COPY与ADD比较像,但是COPY不会做解压工作,只是单纯的拷贝。原路径要在构建上下文中,目标路径必须是一个绝对路径,如果目标目录不存在,会自动创建mkdir -p |
ONBUILD
1 | ONBUILD指令能为镜像添加触发器,当一个镜像被其他镜像用作基础镜像时,该镜像的触发器会被执行(如你的镜像需要从未准备好的位置添加代码,或者你需要执行特定于构建镜像的环境的构建脚本) |
镜像有哪些普遍存在的问题?
- 镜像层级(127层)
- 层级过多和过少都不利于维护和管理
- 镜像大小
- 镜像太大会给大量传输带来压力
- 镜像传输
- 如果镜像不可避免的过大,难免会对仓库和传输速度带来压力
- 镜像构建效率
- 构建镜像的操作负责将会影响镜像的构建效率
应该创建什么样的镜像
由于Dockerfile在创建镜像时每一条命令都会生成一层镜像,即使内容相同也会生成不同的镜像,下面的两个Dockerfile虽然内容一样,但是会生成镜像的镜像层也是不一样的。
1 | FROM centos:lastest |
1 | FROM centos:lastest |
- 在基础镜像选择上尽量选择合理尺寸的镜像
- 尽量减少镜像的层级
- 尽可能删除不需要的组件和不需要的文件以减少镜像的尺寸
- From最好不要用lastest标签,避免不同镜像的顶层是不同,从而无法复用
- 不变或者变化很少的体积较大的依赖库和经常修改的自有代码分开;尽量放在上层
- 尽量将公用部分做成基础镜像
- 过多的层级、过细的分层不利于维护和管理
- 尽量避免单层过大
- 因为cache缓存在运行Docker build命令的本地机器上,建议固定使用某台机器来进行Docker build,以便利用cache。
多阶段构建
将一个Dockerfile用于开发(其中包含构建应用程序所需的所有内容)以及一个用于生产的瘦客户端,它只包含你的应用程序以及运行它所需的内容。这被称为“建造者模式”。
Docker 17.05.0-ce版本以后支持多阶段构建。使用多阶段构建,你可以在Dockerfile中使用多个FROM语句,每条FROM指令可以使用不同的基础镜像,这样您可以选择性地将服务组件从一个阶段COPY到另一个阶段,在最终镜像中只保留需要的内容。
1 | FROM alpine AS builder |
一些好用的基础镜像
- alpine: 小巧的基础镜像(基础服务运行的利器)
- busybox:只包含busybox工具的镜像
- scrtch:离线空镜像(运行二进制bin文件的利器)
不同业务场景的镜像解决方案
业务场景 | 镜像选择 | 构建方式 | 部署方式 |
---|---|---|---|
二进制bin文件 | 构建:alpine 运行:scrtch |
多级构建 | 镜像部署 |
有环境依赖;无系统依赖;环境无系统依赖 | alpine | 先构建基础镜像 然后构建环境镜像 最后构建业务镜像 |
镜像部署 or 原地升级 |
有环境依赖;有系统依赖 | 选择需要依赖的系统镜像 | 同上 | 同上 |
有系统依赖;无环境依赖 | 同上 | 先构建基础镜像 然后构建业务镜像 |
同上 |
镜像流转:Ship
如何让镜像ship起来
- register
- harbor
- harbor集群
镜像的导入导出
image可以通过docker save|export
等方式导出一个镜像tar包,通过网络传输的方式将tar包传输到需要的位置,然后通过docker load|import
将tar包中的镜像导入。
Registry
镜像中心是docker官方提供的镜像存储仓库,它在docker技术发展初期给了image能够更加便捷的ship起来,但是随着docker生态的不断发展,用户对镜像管理、使用的需求,以及周边设施的完善,Registry能够提供的支持就显得有些不够了。而在这个时候docker又一次受到了来自友商的重击:Harbor
Harbor
Habor是由VMWare公司开发、开源的容器镜像仓库,它是在Docker Registry的基础上进行了相应的企业级扩展,从而获得了更加广泛的应用,这些新的企业级特性包括:
- 简单的搭建方式
- 友好的用户管理界面
- 基于角色的访问控制
- 提供了更好的性能和漏洞扫描等安全功能
- 提升用户使用Registry构建和运行环境传输镜像的效率
- 日志审计
- 多个Register之间的镜像同步功能
- 提供分层传输机制,优化网络传输
- 支持水平扩展,多种集群化方案,分担仓库压力
镜像同步
为什么要做镜像同步
- 容器规模庞大,需要多个镜像仓库分担压力
- 系统稳定性要求,多个仓库的集群提高系统健壮性
- 镜像仓库分级规则,上下级仓库依赖
- 镜像在不同环境的自动流转(如:开发环境上传镜像->流转到测试仓库->流转到线上仓库)
Harbor集群
主从同步
基于Harbor提供的镜像复制功能可以搭建多级别的主从复制集群,可以用来提高系统健壮性、分担仓库压力等。但是只配置主从集群还是解决不了仓库单点的问题。
双主复制
基于Harbor的镜像同步功能在两个节点间做双向同步(多节点同步待测试)来确保数据一致性,这样不需要考虑后端服务的维护成本,通过负载器对仓库节点做负载分发。
但是如果其中一个节点A挂掉,在此期间节点B产生了新的数据,节点A恢复后可能不会去同步数据(需要测试),而且双向同步势必会有一定的延迟,当需要同步的数据量过大时,延迟也一定会被放大。
- 优点:不增加后端服务维护成本
- 缺点:可能会出现数据不一致的问题、数据同步可能延迟
负载集群
负载集群需要多个仓库节点共享后端数据服务,如:
- 存储
- 数据库
- redis
然后通过负载器对多个仓库节点做负载分发。但是基础服务维护成本过大。
- 优点:可靠的负载集群
- 缺点:维护成本大
容器运行:Run
让容器run起来
容器基本操作
1 | # 查看容器 |
Run
通常来说我们在生产环境一般不会运行一个没有任何限制的容器(特殊情况除外),容器运行的时候我们会将一些基础配置和资源限制加到启动参数里面。
1 | docker run -d --name web \ |
这么一大堆参数放到命令行来执行不好维护的同时又不够优雅