Docker简介
Docker是什么
-
首先 Docker 是 一个在 2013 年开源的应用程序并且是一个基于 go 语言编写是一个开源的 PAAS 服务 Platform as a Service 平台即服 务的缩写 go 语言是由 google 开发 docker 公司最早叫 dotCloud 后由于 Docker 开源后大受欢迎就将公司改名为 Docker Inc 总部位于美国加州的旧金山 D ocker 是基于 linux 内核实现 Docker 最早采用 LXC 技术 LinuX Container 的简写 LXC 是 Linux 原生支持的容器技术可以提供轻量级的虚拟化可以说 Docker 就是基于 LXC 发展起来的,提供 LXC 的高级封装,发展标准的配置方法而虚拟化技术 KVM Kernelbased Virtual Machine 基于模块实现,Docker 后改为自己研发并开源的 runc 技术运行容器。
-
Docker 相比虚拟机的交付速度更快资源消耗更低 Docker 采用客户端 服务端架构 ,使用远程 API 来管理和创建 Docker 容器 ,其可以轻松的创建一个轻量级的、可移植的、自给自足的容器, docker 的三大理念是 build( 构建 、ship运输 、run运行 Docker 遵从 apache 2.0协议 ,并通过 namespace 及 cgroup 等)来提供容器的资源隔离与安全保障等 ,所以 Docke 容器在运行时不需要类似虚拟机(空运行的虚拟机占用物理机 68% 性能)的额外资源开销,因此可以大幅提高资源利用率 总而言之 Docker 是一种用了新颖方式实现的轻量级虚拟机类似于 VM 但是在原理和应用上和 VM 的差别还是很大的,并且 docker 的专业叫法是应用容器 (Application)。
Docker的组成
- 官方介绍文档:https://docs.docker.c
om/engine/docker overview/ - Docker 主机(Host):一个物理机或虚拟机,用于运行Docker服务进程和容器。
- Docker 服务端(Server):Docker守护进程,运行docker容器。
- Docker 客户端(Client):客户端使用docker命令或者其他工具调用docker API。
- Docker 仓库(Registry):保存镜像的仓库,类似于git或svn这样的版本控制系统。
官方仓库地址:https://hub.docker.com/ - Docker 镜像(Images):镜像可以理解为创建实例使用的模板。
- Docker 容器(Containe): 容器是从镜像生成对外提供服务的一个或一组服务。
Docker对比虚拟机
- 资源利用率更高:一台物理机可以运行数百个容器,但是一般只能运行数十个虚拟机。
- 开销更小:不需要启动单独的虚拟机占用硬件资源
- 启动速度更快:可以在数秒内完成启动
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e5AO3NaO-1634096301107)(https://bokebi.cn/wp-content/uploads/2020/02/5e48eb3a39ce8.png)]
- 使用虚拟机是为了更好的实现服务运行环境隔离,每个虚拟机都有独特的内核,虚拟化可以实现不同操作系统的虚拟机,但是通常一个虚拟机只运行一个服务,很明显资源利用率你较低且造成不必要的性能损耗,我们创建虚拟机的目的是为了运行应用程序,比如Nginx、PHP、Tomcat等web程序,使用虚拟机无疑带了一些不必要的资源开销,但是容器技术则基于减少中间运行环节带来的较大的性能提升。
- 但是,如上图一个宿主机运行了N个容器,多个容器带来的以下问题怎么解决:
- 1.怎么样保证每个容器都有不同的文件系统并且能互不影响?
- 2.一个docker主进程内的各个容器都是其子进程,那么实现同一个主进程下不同类型的子进程?各个进程间通信能互相访问(内存数据)吗?
- 3.每个容器怎么解决IP及端口分配的问题?
- 4.多个容器的主机名能一样吗?
- 5.每个容器都要不要有root用户?怎么解决账户重名问题?
- 以上问题怎么解决?
Linux Namespace技术
- namespace是linux系统的底层概念,在内核层实现,即有一些不同类型的命名空间被部署在内核,各个docker容器运行在同一个docker主进程并且共用同一个宿主机系统内核,各docker容器运行在宿主机的用户空间,每个容器都要有类似于虚拟机一样的相互隔离的运行空间,但是容器技术是在一个进程内实现运行指定服务的运行环境,并且还可以保护宿主机内核不被其他进程的干扰和影响,如文件系统空间,网络空间,进程空间,目前主要通过以下技术实现容器运行空间相互隔离。
隔离类型 | 功能 | 系统调用参数 | 内核版本 |
---|---|---|---|
MNT Namespace(mount) | 提供磁盘挂载点和文件系统的隔离能力 | CLONE_NEWNS | Linux 2.4.19 |
IPC Namespace(Inter-Process Communication) | 提供进程间通信的隔离能力 | CLONE_NEWIPC | Linux 2.6.19 |
UTS Namespace(UNIX Timesharing System) | 提供主机名隔离能力 | CLONE_NEWUTS | Linux 2.6.19 |
PID Namespace(Process Identification) | 提供进程隔离能力 | CLONE_NEWPID | Linux 2.6.24 |
Net Namespace(network) | 提供网络隔离能力 | CLONE_NEWNET | Linux2.6.29 |
User Namespace(user) | 提供用户隔离能力 | CLONE_NEWUSER | Linux 3.8 |
MNT Namespace
-
每个容器都要有独立的跟文件系统、有独立的用户空间以实现在容器里面启动服务并且使用容器的运行环境,即一个宿主机是ubuntu的服务器,可以在里面启动一个centos运行环境的容器并且在容器里面启动一个Nginx服务,此Nginx运行时使用的运行环境就是centos系统目录的运行环境,但是在容器里面是不能访问宿主机的紫云,宿主机是使用了chroot技术吧容器锁定到一个指定的运行目录里面。
-
列如::/var/lib/containerd/io.containerd.runtime.v1.linux/moby/容器ID
-
启动三个容器用于以下验证过程
//查看docker 版本
root@bj-magedu-v-study-14:~# docker version
Client:
Version: 18.09.9
API version: 1.39
Go version: go1.11.13
Git commit: 039a7df9ba
Built: Wed Sep 4 16:57:28 2019
OS/Arch: linux/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 18.09.9
API version: 1.39 (minimum version 1.12)
Go version: go1.11.13
Git commit: 039a7df
Built: Wed Sep 4 16:19:38 2019
OS/Arch: linux/amd64
Experimental: false
# docker run -d --name nginx-1 -p 80:80 nginx
# docker run -d --name nginx-2 -p 81:80 nginx
# docker run -d --name nginx-3 -p 82:80 nginx
- Debian系统安装基础命令:
# apt update
# apt install procps (top 命令)
# apt install iputils-ping (ping 命令)
# apt install net-tools ( 网络工具)
- 验证容器的根文件系统
IPC Namespace
- 一个容器内的进程间通信,允许一个容器内的不同进程的(内存、缓存等)数据访问,但是不能跨容器访问其他容器的数据。
UTS Namespace
- UTS namespace(UNIX Timesharing System 包 含了运行内核的名称、版本、底层体系结构类型等信息)用于系统标识,其中包含了hostname和域名domainname,它使得一个容器拥有属于自己的hostname标识,这个主机名标识独立于宿主主机系统和其上的其他容器。
PID Namespace
-
linux系统中,有一个PID为1的进程(init/systemd)是其他所有进程的父进程,那么在每个容器内也要有一个父进程来管理其下属的子进程,那么多容器的进程同PID namespace进程隔离(比如PID编号重复、容器内的主进程生成于回收子进程等)。
-
例如:下图是在一个容器内使用 top 命令看到的 PID 为1的进程是nginx
- 容器内的Nginx主进程于工作进程
- 那么宿主机的 PID 究竟与容器内的 PID 是什么关系?
查看宿主机上的PID信息
查看容器中的PID信息
NET Namespace
- 每一个容器都类似于虚拟机一样有自己的网卡、 监听端口、 TCP/IP 协议栈等,Docker使用 network namespace 启动一个 vethX 接口,这样你的容器将拥有它自己的桥接 ip 地址,通常是 docker0 ,而 docker0 实质就是 Linux 的虚拟网桥,网桥是在 OSI 七层模型的数据链路层的网络设备,通过 mac 地址对网络进行划分,并且在不同网络直接传递数据。
查看宿主机的网卡信息
查看宿主机桥接设备
实际逻辑网络图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OxSqGTFD-1634096301118)(https://bokebi.cn/wp-content/uploads/2020/02/5e4913285da90.png)]
宿主机iptables规则
USER Namespace
- 各容器内可能会出现重名的用户和用户组名称,或重复的用户 UID 或者 GID 那么怎么隔离各个容器内的用户空间呢?
- User Namespace 允许在各个宿主机的各个容器空间内创建相同的用户名以及相同的用户 UID 和 GID 只是会把用户的作用范围限制在每个容器内,即 A 容器和 B 容器可以有相同的用户名称和 ID 的账户,但是此用户的有效范围仅是当前容器内,不能访问另外一个容器内的文件系统,即相互隔离、互不影响、永不相见。
Linux control groups
- 在一个容器 ,如果不对其做任何资源限制,则宿主机 会允许其占用无限大的内存空间,有时候会因为代码 bug 程序会一直申请内存,直到把宿主机内存占完,为了避免此类的问题出现,宿主机有必要对容器进行资源分配限制,比如 CPU、内存等,Linux Cgroups 的全称是 Linux Control Groups 它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU 、内存、磁盘、网络带宽等等。此外,还能够对进程进行优先级设置,以及将进程挂起和恢复等操作。
验证系统cgroups
- Cgroups 在内核层默认已经开启从 centos 和 ubuntu 对比结果来看显然内核较新的 ubuntu 支持的功能更多。
Centos 7.6 cgroups
ubuntu cgroups
cgroups中内存模块
cgroups具体实现
blkio: 块设备 IO 限制。
cpu: 使用调度程序为 cgroup 任务提供 cpu 的访问。
cpuacct: 产生 cgroup 任务的 cpu 资源报告。
cpuset: 如果是多核心的 cpu ,这个子系统会为 cgroup 任务分配单独的 cpu
和内存。
devices: 允许或拒绝 cgroup 任务对设备的访问。
freezer: 暂停和恢复 cgroup 任务。
memory: 设置每个 cgroup 的内存限制以及产生内存资源报告。
net_cls: 标记每个网络包以供 cgroup 方便使用。
ns: 命名空间子系统。
perf_event: 增加了对每 group 的监测跟踪的能力,可以监测属于某个特定的
group 的所有线程以及运行在特定 CPU 上的线程。
查看系统cgroups
root@bj-magedu-v-study-14:~# ll /sys/fs/cgroup/
total 0
drwxr-xr-x 15 root root 380 Feb 16 16:00 ./
drwxr-xr-x 10 root root 0 Feb 16 16:00 ../
dr-xr-xr-x 5 root root 0 Feb 16 16:00 blkio/
lrwxrwxrwx 1 root root 11 Feb 16 16:00 cpu -> cpu,cpuacct/
lrwxrwxrwx 1 root root 11 Feb 16 16:00 cpuacct -> cpu,cpuacct/
dr-xr-xr-x 5 root root 0 Feb 16 16:00 cpu,cpuacct/
dr-xr-xr-x 3 root root 0 Feb 16 16:00 cpuset/
dr-xr-xr-x 5 root root 0 Feb 16 16:00 devices/
dr-xr-xr-x 3 root root 0 Feb 16 16:00 freezer/
dr-xr-xr-x 3 root root 0 Feb 16 16:00 hugetlb/
dr-xr-xr-x 5 root root 0 Feb 16 16:00 memory/
lrwxrwxrwx 1 root root 16 Feb 16 16:00 net_cls -> net_cls,net_prio/
dr-xr-xr-x 3 root root 0 Feb 16 16:00 net_cls,net_prio/
lrwxrwxrwx 1 root root 16 Feb 16 16:00 net_prio -> net_cls,net_prio/
dr-xr-xr-x 3 root root 0 Feb 16 16:00 perf_event/
dr-xr-xr-x 5 root root 0 Feb 16 16:00 pids/
dr-xr-xr-x 2 root root 0 Feb 16 16:00 rdma/
dr-xr-xr-x 6 root root 0 Feb 16 16:00 systemd/
dr-xr-xr-x 5 root root 0 Feb 16 16:00 unified/
- 有了以上的 chroot、namespace、cgroups 就具备了基础的容器运行环境,但是还需要相应的容器创建与删除的管理工具、以及怎么样把容器运行起来、容器数据怎么处理、怎么进行启动与关闭等问题需要解决,于容器管理技术出现了。
容器管理工具
- 目前主要是使用 docker 早期有使用 lxc 。
lxc
-
LXC:LXC 为 Linux Container 的简写。可以提供轻量级的虚拟化,以便隔离进程和资源,官方网站:https://linuxcontainers.org/
-
ubuntu 安装 lxc
root@s1:~# apt install lxc lxd
Reading package lists... Done
Building dependency tree
Reading state information... Done
lxd is already the newest version (3.0.3 0ubuntu1~18.04.1).
lxc is already the newest version (3.0.3 0ubuntu1~18.04.1).
root@s1:~# lxc-checkconfig # 检查内核对 lcx 的支持 状况 ,必须全部为 lcx
root@s1:~# lxc-create -t 模板名称 -n lcx-test
root@s1:~# lxc-create -t download --name alpine12 -- --dist alpine --release3.9 --arch amd64
Setting up the GPG keyring
Downloading the image index
Downloading the rootfs
Downloading the metadata
The image c ache is now ready
Unpacking the rootfs
You just created an Alpinelinux 3.9 x86_64 (20190630_13:00) container.
root@s1:~# lxc-start alpine12 #启动lxc容器
root@s1:~# lxc-attach alpine12 #进入lxc容器
~ # ifconfig
eth0 Link encap:Ethernet HWaddr 00:16:3E :DF:54:94
inet addr:10.0.3.115 Bcast:10.0.3.255 Mask:255.255.255.0
inet6 addr: fe80::216:3eff:fedf:5494/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:18 errors:0 dropped:0 overruns:0 frame:0
TX packets:13 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2102 (2.0 KiB) TX bytes:1796 (1.7 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
~ # uname -a
Linux alpine12 4.15.0 20 generic #21 Ubuntu SMP Tue Apr 24 06:16:15 UTC 2018
x86_64 Linux
~ # cat /etc/issue
Welcome to Alpine Linux 3.9
Kernel \r on an \m (\l)
-----------------------------------------------------
命令备注
-t 模板: -t选项后面跟的是模板,模式可以认为是一个原型,用来说明我们需要一个什么样的容器(比如容器里面需不需要有 vim, apache 等软件).模板实际上就是一个脚本文件(位于 /usr/share/lxc/templates 目录),我们这里指定 download 模板(lxc-create会调用lxc-download 脚本,该脚本位于刚说的模板目录中)是说明我们目前没有自己模板,需要下载官方的模板。
--name 容器名称: 为创建的容器命名
--: --用来说明后面的参数是传递给 download 脚本的,告诉脚本需要下载什么样的模板
--dist 操作系统名称:指定操作系统
--release 操作系统: 指定操作系统,可以是各种 Linux 的变种
--arch 架构: 指定架构,是 x86 还是 arm,是32位还是64位
- lxc启动容器依赖于模板,清华模板源:https://mirrors.tuna.tsinghua.edu.cn/help/lxc-images/ 但是做模板相对较难需要手动一步步创构建文件系统、准备基础目录及可执行程序等,而且在大规模使用容器的场景很难横向扩展,另外后期代码升级也需要重新从头构建模板基于以上种种原因便有了 docker 。
docker
- Docker 启动一个容器也需要一个外部模板但是较多镜像,docker 的镜像可以保存在一个公共的地方共享使用,只要把镜像下载下来就可以使用,最主要的是可以在镜像基础之上做自定义配置并且可以再把其提交为一个镜像,一个镜像可以被启动为多个容器。
- Docker 的镜像是分层的,镜像底层为库文件且只读层即不能写入也不能删除数据,从镜像加载启动为一个容器后会生成一个可写层,其写入的数据会复制到容器目录 但是容器内的数据在删除容器后也会被随之删除。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DZo9tXPq-1634096301123)(https://bokebi.cn/wp-content/uploads/2020/02/5e49249f4b167.png)]
pouch
Docker的优势
- 快速部署:短时间内可以部署成百上千个应用,更快速交付到线上
- 高效虚拟化:不需要额外的 hypervisor 支持,直接基于 linux 实现应用虚拟化,相比虚拟机大幅提高性能和效率
- 节省开支:提高服务利用率,降低IT指出
- 简化配置:将运行环境打包保存至容器,使用时直接启动即可
- 快速迁移和扩展:可跨平台运行在物理、虚拟机、公有云等环境,良好的兼容性可以方便将应用从A宿主机迁移到B宿主机。甚至是A平台迁移B平台。
Docker的缺点
- 隔离性:各应用之间的隔离不如虚拟机彻底。
Docker(容器)的核心技术
-
容器规范
- 容器技术除了的 docker 之外 ,还有 coreOS 的 rkt 还有阿里的 Pouch 为了保证容器生态的标准性和健康可持续发展,包括 Linux 基金会、Docker、微软、红帽谷歌和、IBM、等公司在2015年6月共同成立了一个叫 open container (OCI) 的组织,其目的就是制定开放的标准的容器规范,目前 OCI 一共发布了两个规范,分别是 runtime spec 和 image format spec 有了这两个规范不同的容器公司开发的容器只要兼容这两个规范,就可以保证容器的可移植性和相互可操作性。
-
容器runtime
- runtime 是真正运行容器的地方,因此为了运行不同的容器 runtime 需要和操作系统内核紧密合作相互在支持,以便为容器提供相应的运行环境。
- 目前主流的三种 runtime
- Lxc:linux 上早期的 runtime,Docker 早期就是采用 lxc 作为 runtime 。
- runc:目前 Docker 默认的 runtime runc 遵守 OCI 规范,因此可以兼容 lxc 。
- rkt:是 CoreOS 开发的容器 runtime,也符合 OCI 规范,所以使用 rktruntime 也可以运行 Docker 容器。
-
容器管理工具
- 管理工具连接 runtime 与用户,对用户提供图形或命令方式操作,然后管理工具将用户的操作传递给 runtime 执行。
- lxc 是 lxd 的管理工具。
- Runc 的管理工具是 docker engine,docker engine 包含后台 deamon 和 cli 两部分,大家经常提到的 Docker 就是指的 docker engine。
- Rkt 的管理工具是 rkt cli。
-
容器定义工具
- 容器定义工具允许用户定义容器的属性和内容,以方便容器能够被保存、共享和重建。
- Docker image:是 docker 容器的模板,runtime 依据 docker image 创建容器。
- Dockerfile:包含 N 个命令的文本文件,通过 dockerfile 创建出 docker image。
- ACI(App container): 与 docker image 类似,是 CoreOS 开发的 rkt 容器的镜像格式。
-
Registry
- 统一保存镜像而且是多个不同镜像版本的地方,叫做镜像仓库。
- Image registry:docker 官方提供的私有仓库部署工具。
- Docker hub:docker 官方的公共仓库已经保存了大量的常用镜像,可以方便大家直接使用。
- Harbor:vmware 提供的自带 web 界面自带认证功能的镜像仓库,目前有很多公司使用。
172.18.200.101/project/ centos:7.2.1511
172.18.200.101/project/ centos: latest
172.18.200.101/project/java 7.0.59:v1
172.18.200.101/project/java 7.0.59 :v2
- 编排工具
- 当过多个容器在多个主机运行的时候,单独管理容器时相当复杂而且很容易出错,而且也无法实现某一台主机宕机后容器自动迁移到其他主机从而实现高可用的目的,也无法实现动态伸缩的功能,因此需要有一种工具可以实现统一管理、动态伸缩、故障自愈、批量执行等功能,这就是容器编排引擎。容器编排通常包括容器管理、调度、集群定义和服务发现等功能。
- Docker swarm:docker 开发的容器编排引擎。
- Kubernetes:google 领导开发的容器编排引擎,内部项目为 Borg,且其同时支持 docker 和 CoreOS。
- Mesos+Marathon:通用的集群组员调度平台,mesos (资源分配)与 marathon (容器编排平台)一起提供容器编排引擎功能。
Docker(容器)的依赖技术
-
容器网络:
- docker自带网络 docker nerwork 仅支持管理单机上的容器网络,当主机运行的时候需要使用第三方开源网站,流入 calico、flannel 等。
-
服务发现
- 容器的动态扩展特性决定了容器 IP 也会随之变化,因此需要有一种机制可以自动识别并将用户亲贵动态转发到新创建的容器上, kubernetes 自带服务发现功能,需要结合 kube-dns 服务解析内部域名。
-
容器监控
- 可以通过原生命令 docker ps/top/stats 查看容器运行状态,另外也可以使 heapster/Prometheus 等第三方监控工具监控容器的运行状态。
-
数据管理
- 容器的动态迁移会导致其在不同的 Host 之间迁移,因此如何保证与容器相关的数据也能随之迁移或随时访问,可以使用逻辑卷/存储挂载等方式解决。
-
日志收集
- docker 原生的日志查看工具 docker logs,但是容器内部的日志需要通过 ELK 等专门的日志收集分析和展示工具进行处理。