容器是什么
容器是一种基础工具,泛指任何可以用于容纳其他物品的工具,可以部分或完全封闭,被用于容纳,存储,运输物品;物体可以被放置在容器中,而容器可以保护内容物.
虚拟化技术有哪些
主机级别 虚拟化
完全 虚拟化:Vmware,Kvm,Xen
半 虚拟化:Xen,UML
Xen如果CPU不支持虚拟化技术那就是半虚拟化,如果支持就是全虚拟化
半虚拟化:修改内核,通过被虚拟化出来的操作系统它是运行在虚拟化技术软件上的,虚拟化出来的操作系统执行的进程还是运行在真实机器上
完全虚拟化:不需要修改内核,直接通过虚拟机化技术软件上运行的操作系统。
容器级别 虚拟化
LXC,OpenVz,Solaris Containers,FreeBSD jails
LXC(LinuX Container)容器是内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源,不需要提供指令解释机制以及全虚拟化的其他复杂性.容器可以有效的将单个操作系统管理的资源划分到孤立的组件中,以便更好的孤立组之间的平衡有冲突的资源使用需求。
早期容器应用在jail中,后来移植到linux中vserver(chroot),chroot所隔离仅仅只是看上去的,并没有真正隔离。
Linux namespace 是linux提供一种内核级别环境隔离的方法,有6种不同名称空间:
linux namesapce:
namespace 系统调用参数 隔离内容 内核版本 UTS CLONE_NEWUTS 主机名和域名 2.6.19 MOUNT CLONE_NEWNS 挂载点(文件系统) 2.4.19 IPC CLONE_NEWIPC 信号量,消息队列,共享内存 2.6.19 PID CLONE_NEWPID 进程变化 2.6.24 USER CLONE_NEWUSER 用户和用户组 3.8 NETWORK CLONE_NEWNET 网络设备,网络栈,端口等 2.6.29
Docker是什么
Docker是LXC增强版,Docker简化容器使用难度,通常一个容器中只运行一个进程.
对开发来说带来极大便利,分发容易,一次编写到处运行
然而对运维来说(有优点有缺点), 对开发极大便利需要运维干什么?
Docker安装
环境说明:
操作系统发行版:CentOS7.4
内核版本:3.10+
安装说明:
使用yum方式安装,下载国内docker的yum源,加速下载.
安装过程:
1 | wget -P /etc/yum.repos.d/ https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo |
此时docker已经启动了,现在我们来搞清楚什么是docker
Docker架构
c/s架构,由三个组件(Docker Daemon,Docker Client,Docker Registry)构成
Docker Registry:
类似GitHub,只不过Docker Registry是存放镜像的仓库,
当然也可以自己部署一个仓库,建议用Harbor。
Docker Daemon:
Docker进程,Docker核心服务。
这个类比数据库,比如数据库是放数据的,启动数据库后,等待客户端连接后才能操作。
也就是当docker启动时,等待docker客户端来操作。
Docker Client:
Docker客户端工具,用来操作Docker的
比如我想在仓库下载一个镜像,从而启动一个容器,在容器中启动一个nginx服务,都是在客户端操作的。(docker client是发出者,docker daemon是执行者)
这里提到的镜像和容器一定要区分清楚。
如果是开发,那这么理解:镜像就是你创建的类,容器就是你的对象,对象是通过类实例化而来。也就是容器通过镜像而来,(容器依赖于镜像)
不要问镜像怎么来的,上面提过镜像是在仓库中。
也不要问仓库中的镜像怎么来的,那是别人做好的。因为你也可以自己做镜像。
Docker客户端操作
1 | docker --help |
镜像类操作
1 | docker search SOFTWARE_NAME #查找镜像名称 |
容器类操作
1 | docker run #运行容器,需要指定镜像 |
Docker Image
Docker镜像包含启动容器的所需文件系统以及其内容,因此,用于创建并启动docker容器:
分层机制:
镜像采用分层构建机制,最底层为bootfs,其为rootfs。
rootfs:用于系统引导的文件系统,包含bootloader和kernel,容器启动完成后被卸载以节约内存资源
rootfs:位于bootfs之上,表现为docker容器根文件系统
传统模式中,系统启动时,内核挂载rootfs时首先将其挂载为“只读”模式,自检其完整性 完成后将其重新挂载为读写模式
docker中,rootfs由内核挂载为“只读”模式,而通过“联合挂载”技术额外挂载一个可写层,容器就是在镜像多了一个可写层
传统模式: | Docker: |
---|---|
docker镜像层级:
位于下层的镜像 称之为 父镜像(parent image),最底层的称之为 基础镜像(base image)
最上层“可读写成”,下面为“只读层”
联合挂载:
Aufs(advanced multi-layered unification filesystem ) 高级多层统一文件系统,同于实现linux平台中的联合挂载
Aufs是unionFS的重新实现,docker最初使用aufs作为容器文件系统层,目前仍作为存储后端之一来支持
Aufs另外一个实现是overlayFS,后者从3.18版本中开始被合并到linux内核中,overlayerFS是叠加文件系统
除了aufs,docker还支持btrFS,Device Mapper和VSF等。在ubuntu中,默认是aufs
device mapper在linux2.6中支持逻辑卷管理的通过设备映射机制,它为实现用于存储资源管理的块设备驱动提供一个高度模块化的内核架构,它通过一个个模块化的target driver插件实现对IO请求的过滤或者重新定向等工作,当前已经实现的target driver插件包括软raid,软加密,逻辑卷条带,多路径,镜像,快照等。
docker使用Thin provisioning的snapshot的技术实现了类似auFS分层镜像
1
2 docker info | grep "Storage Driver:" #来查看
Docker Container
Docker容器具有生命周期,”STOPD”,’CREATED’,’RUNNING’,’PAUSED’四个稳定状态,
容器一旦删除数据就会丢失,所以项目或者配置文件不要直接存放在容器中,通过卷(volume)的方式挂载至容器里.
Docker事件状态图:
Docker Registry
当容器启动时,docker daemon会试图先从本地获取相关镜像,当本地不存在的时候,其将从registry中下载该镜像并保存在本地
流程图:
docker client < - - - http/https - - - >docker daemon < - - - http/https - - - >docker registry
默认是使用https连接到registry,但是可以修改成http
Registry 分类
registry用于保存docker镜像,包括镜像的层次结构和元数据:
用户可自建registry,也可以使用官方的docker hub
分类:
sponsor registry 第三方registry,供客户和docker社区使用
mirror registry 第三方registry,只让客户用
verdor registry 由发布docker镜像的供应商提供registry
private registry 通过舍友防火墙和额外的安全层的私有实体提供的registry
repository及index
repository
由某种特定的docker镜像的所有迭代版本组成的镜像仓库
一个registry中可以存在多个repository
repository 可以为”顶层仓库”和“用户仓库”
用户仓库名称格式”用户名/仓库名”
每个仓库可以包含多个Tag,每个标签对应一个镜像
index
维护用户账号,镜像的校验以及公共命名空间的信息
相当于为Registry提供了一个完成用户认证等功能的检索接口
镜像相关操作
主要介绍镜像如何生成,和如何推送镜像至仓库
镜像生成方式:
有三种方式:基于容器方式,Dockerfile方式,Docker Hub Automated Builds
基于容器制作镜像:
1 | docker run --name web1 -it busybox |
基于Dockerfile制作镜像:
推送镜像
推送到官方
首先需要有hub.docker.com账号 ,hub.docker.com需要先建立好repositories
示例:这里的是zhuxyid/busyhttp命名,要跟本地的镜像保持一致
1 | docker login #输入账号密码才可以登录 |
推送到阿里云
需要修改docker配置文件中的推送地址
1 | 修改docker配置文件添加registry-mirrors,https://brjvf90f.mirror.aliyuncs.com为我自己的阿里云镜像仓库 |
镜像导入导出
1 | 在本地导出镜像包,推送到目标机 |
Docker网络
Docker安装后自动创建docker0网卡(虚拟)
网络虚拟化技术实现:
OVS:Open VSwitch 开源虚拟交换
SDN:Software Defined Network 软件定义网络(需要硬件和软件支持)
Docker网络接口
Docker有三种网络接口:
bridge,host,none,Containers
1 | docker image ls |
docker安装后,会生成docker0,此网卡是个NAT桥,当启动容器的时候,宿主机也会生成
veth*
虚拟网卡,该网卡和容器内的网卡绑定,而veth*
就是跟docker0相连,可以使用brctl show
来查看
1 | yum install bridge-utils |
Docker通讯
Docker中如果外部想访问内部的服务有如下三种方式:
Bridge方式:
通过桥接,然后设置dnat才能被其他主机访问
Containers方式:
容器可以将6个名称空间分层:
如:docker-a和docker-b
docker-a独立6个名称空间:USER,MOUNT,PID,UTS,NET,IPC
docker-b独立3个名称空间:USER,MOUNT,PID,另外UTS,NET,IPC共享docker-a的
Host方式:
相当于Open container方式,只不过直接使用宿主机的UTS.NET.IPC
Docker 网络相关命令
指定网络类型以及端口映射
1 | #docker run --name test -it --rm busybox:latest #运行busybox命名为test,执行完后直接删除 |
Bridge
1 | docker run --name test -it --network bridge --rm busybox:latest |
Containers
联盟式容器是指使用某个已存在容器的网络接口的容器,接口被联盟内的各容器共享使用,因此,联盟式容器彼此间完全无隔离
#创建一个监听于80端口的http服务容器
docker run -d --it --rm -p 80:80 busybox/httpd:laster
#创建一个联盟式容器
docker run --name web1 -it --rm busybox/httpd
docker run --name web2 --network container:web1 -it --rm busybox/httpd
#在web2中创建的文件web1看不到,因为隔离Mount名称空间,但是web1和web2的ip是一样的,因为web2共享了web1的Net名称空间
#联盟式容器彼此间 虽然 共享同一个网络名称空间,但其他名称空间如User,Mount,Pid等还是隔离的
#联盟式容器彼此间存在端口冲突的可能性,因此,通常只会在多个容器上的程序需要程序lookback接口互相通信,或对某已存在的容器的网络属性进行监控时才使用此模式的网络模型
Host
创建一个宿主机host的容器
1 | docker run --name webserver --network host -it --rm busybox/httpd |
Docker存储
关于卷
Docker镜像由多个只读层叠加而成,启动容器时,docker会加载只读镜像层 并在镜像栈顶部 添加一个 读写层,如果运行中容器修改了现有的一个已挂载的文件,那该文件将会从 读写层下面的只读层 复制到读写层,该文件的只读版本依然存在,只是已经被读写层中该文件的副本所修改,即“写时复制(COW)”机制
注意:在IO要求高应用中,如果使用容器的话,那么效率非常低
Container: /data/web < - - - - 建立绑定关系Mount - - - - > Host:/container/web1/data/web
在容器写入时候,可以绕过容器内部层级关系
命名空间Mount是相互独立的,可以共享,关联到存储卷Volume,只要容器挂载存储卷.当容器被停止或者删除后,文件内容不被删除。
为什么用存储卷
关闭并重启容器,其数据不受影响,但是删除容器,则数据全部丢失
存在的问题:
存储于联合文件系统中,不易于宿主机访问
容器间数据共享不便利
删除容器其数据丢失
卷的描述
卷在容器初始化时候 会自动创建,由base image提供的卷中数据会于此间 完成复制
卷的初衷是独立于容器的生命周期实现数据持久化,因此删除容器时不会删除卷,也不会对哪怕未被应用的卷做垃圾回收
卷为docker提供了独立于容器的数据管理机制
可以把”镜像” 比作成静态文件,例如“程序” ,把卷类比为动态内容,例如“数据”;于是镜像可以重用,而卷可以共享
卷实现了”程序(镜像)”和“数据(卷)”分离,以及 “程序(镜像)”和“制作镜像主机”分离,用户制作镜像时无需考虑镜像运行容器所在的主机环境
卷的类型
docker有两种类型的卷,每种类型都在容器中存在一个挂载点,但其在宿主机上的位置有所不同
绑定挂载卷 bind mount volume: 在宿主机人工指定特定路径,在容器也人工指定特定路径,将两者绑定
容器管理卷 docker-managed volume: 宿主机不需要指定路径(docker daemon),容器中需要指定路径,docker自动将两者绑定
如何使用卷
1 | docker run -v 选项 |
Docker资源限制
默认情况下,系统对容器没有做任何资源限制,容器可以使用掉宿主机所有资源。
docker provides可以控制Memory,CPU, Block IO(其实只能控制内存和CPU)
依赖于Linux Capabilities 。
这里需要注意:内存是非可压缩资源,CPU可压缩资源
如何内存被进程耗尽会触发OOME直接KILL进程,而CPU没有关系
OOM
在linux主机中,如果内核探测到当前宿主机没有足够内存可用(用于执行某些重要的系统功能)会抛出OOME 异常,并且kill掉某些进行保证其正常,一旦发生OOME,任何进程包括docker daemon在内,都有可能杀死。因此docker特地调整 docker daemon的OOM优先级,以免它被内核”杀死”,但容器的优先级并未被调整 。
优先级越低,得分越低,通常检测oom-adj,分数越高越容易被kill
不重要的业务建议oom-adj默认值,重要的调低oom-adj
Memory
从ram,swap两个层面:
1 | 限制单位k,b,m,g |
–memory-swap | –memory | 功能 |
---|---|---|
正数S | 正数M | 容器可用总空间为S,其中ram为M,swap为(S-M),如果S=M,则无可用swap资源 |
0 | 正数M | 相当没有设置swap(unset) |
unset | 正数M | 若主机(docker host)启用swap,则容器可用的swap为2*M |
1 | 正数M | 若主机(docker host)启用了swap,则容器可使用最大至主机上的所有swap空间的swap资源 |
注:在容器使用free命令可用看到swap空间并不具有 其所展现出空间的指示意义
设置–memory-swap必须大于–memory
1 | --memory-swapiness 限制容器的虚拟内存控制行为0~100间整数 |
CPU
默认情况下每个容器,可以使用CPU的资源.大多数系统,系统在调度时候使用CFS调度 (CFS完全公平调度器)
在docker1.13后,可以设置实时调度
1 | --cpus=<value> #设置CPU使用几核心,如果容器只设置了--cpus = 2,那么该容器只能使用200%的cpu |
docekr-stress-ng压缩
1 | docker run --rm lorel/docker-stress-ng --help |
小结
这些主要是针对CentOS7.4,对于其他平台或者版本可能实现方式略有不同。
如:在macOS下面对于 网络 和 卷 都有不同的地方。
网络在macOS中没有docker0桥,无法ping通容器,只能使用-P 或者-p映射端口的形式访问容器,或者通过host.docker.internal特殊DNS,解析为主机使用的内部IP地址。
卷的话如果要绑定User以外的目录,则需要修改权限让容器内部可以访问该目录,不然直接挂载会提示权限不足情况
暂时遇到这么多,感谢志哥让我遇到这么多坑。
主要是讲解一下Docker基础方面,后期的Dockerfile和Docker Registry在慢慢总结,如果本文有错误,还请大牛指出,谢谢:)