Docker 基础

Docker 基础

1 简介:

前言
统称来说,容器是一种工具,指的是可以装下其它物品的工具,以方便人类归纳放置物品、存储和异地运输,具体来说比如人类使用的衣柜、行李箱、背包等可以成为容器,但今天我们所说的容器是一种 IT 技术。
容器技术是虚拟化、云计算、大数据之后的一门新兴的并且是炙手可热的新技术,容器技术提高了硬件资源利用率、方便了企业的业务快速横向扩容、实现了业务宕机自愈功能,因此未来数年会是一个容器愈发流行的时代,这是一个对于IT 行业来说非常有影响和价值的技术,而对于 IT 行业的从业者来说,熟练掌握容器技术无疑是一个很有前景的行业工作机会。
容器技术最早出现在 freebsd 叫做 jail。

1.1 docker 简介:

1.1.1 Docker 是什么:

​ 首先 Docker 是一个在 2013 年开源的应用程序并且是一个基于 go 语言编写是一个开源的 PAAS 服务(Platform as a Service,平台即服务的缩写),go 语言是由google 开发,docker 公司最早叫 dotCloud 后由于 Docker 开源后大受欢迎就将公司改名为 Docker Inc,总部位于美国加州的旧金山,Docker 是基于 linux 内核实现,Docker 最早采用 LXC 技术(LinuX Container 的简写,LXC 是 Linux 原生支持的容器技术,可以提供轻量级的虚拟化,可以说 docker 就是基于 LXC 发展起来的(0.1.5 (2013-04-17),提供 LXC 的高级封装,发展标准的配置方法),而虚拟化技术 KVM(Kernel-based Virtual Machine) 基于模块实现,Docker 后改为自己研发并开源的 runc 技术运行容器(1.11.0 (2016-04-13)。
​ Docker now relies on containerd and runc to spawn containers。
​ Docker 相比虚拟机的交付速度更快,资源消耗更低,Docker 采用客户端/服务端架构,使用远程 API 来管理和创建 Docker 容器,其可以轻松的创建一个轻量级的、可移植的、自给自足的容器,docker 的三大理念是 build(构建)、ship(运输)、run(运行),Docker 遵从 apache 2.0 协议,并通过(namespace 及 cgroup 等)来提供容器的资源隔离与安全保障等,所以 Docke 容器在运行时不需要类似虚拟机(空运行的虚拟机占用物理机的一定性能开销)的额外资源开销,因此可以大幅提高资源利用率,总而言之Docker是一种用了新颖方式实现的轻量级虚拟机.类似于 VM 但是在原理和应用上和 VM 的差别还是很大的,并且 docker 的专业叫法是应用容器(Application Container)。

1.1.2 Docker 的组成:

https://docs.docker.com/engine/docker-overview/
​ Docker 主机(Host):一个物理机或虚拟机,用于运行 Docker 服务进程和容器。
​ Docker 服务端(Server):Docker 守护进程,运行 docker 容器。
​ Docker 客户端(Client):客户端使用 docker 命令或其他工具调用 docker API。
​ Docker 仓库(Registry): 保存镜像的仓库,类似于 git 或 svn 这样的版本控制系
​ Docker 镜像(Images):镜像可以理解为创建实例使用的模板。
​ Docker 容器(Container): 容器是从镜像生成对外提供服务的一个或一组服务系统,官方仓库: https://hub.docker.com/

1.1.3 Docker 对比虚拟机:

​ 资源利用率更高:一台物理机可以运行数百个容器,但是一般只能运行数十个虚拟机。
​ 开销更小:不需要启动单独的虚拟机占用硬件资源。
​ 启动速度更快:可以在数秒内完成启动。

​ 使用虚拟机是为了更好的实现服务运行环境隔离,每个虚拟机都有独立的内核,虚拟化可以实现不同操作系统的虚拟机,但是通常一个虚拟机只运行一个服务,很明显资源利用率比较低且造成不必要的性能损耗,我们创建虚拟机的目的是为了运行应用程序,比如 Nginx、PHP、Tomcat 等 web 程序,使用虚拟机无疑带来了一些不必要的资源开销,但是容器技术则基于减少中间运行环节带来较大的性能提升。

​ 但是,如上图一个宿主机运行了 N 个容器,多个容器带来的以下问题怎么解决:
​ 1.怎么样保证每个容器都有不同的文件系统并且能互不影响?
​ 2.一个 docker 主进程内的各个容器都是其子进程,那么实现同一个主进程下不同类型的子进程?各个进程间通信能相互访问(内存数据)吗?
​ 3.每个容器怎么解决 IP 及端口分配的问题?
​ 4.多个容器的主机名能一样吗?
​ 5.每个容器都要不要有 root 用户?怎么解决账户重名问题?
​ 以上问题怎么解决?

1.1.4 Linux Namespace 技术:

​ namespace 是 Linux 系统的底层概念,在内核层实现,即有一些不同类型的命名空间被部署在核内,各个 docker 容器运行在同一个 docker 主进程并且共用同一个宿主机系统内核,各 docker 容器运行在宿主机的用户空间,每个容器都要有类似于虚拟机一样的相互隔离的运行空间,但是容器技术是在一个进程内实现运行指定服务的运行环境,并且还可以保护宿主机内核不受其他进程的干扰和影响,如文件系统空间、网络空间、进程空间等,目前主要通过以下技术实现容器运行空间的相互隔离:

1.1.4.1 MNT Namespace:

​ 每个容器都要有独立的根文件系统有独立的用户空间,以实现在容器里面启动服务并且使用容器的运行环境,即一个宿主机是 ubuntu 的服务器,可以在里面启动一个 centos 运行环境的容器并且在容器里面启动一个 Nginx 服务,此 Nginx 运行时使用的运行环境就是 centos 系统目录的运行环境,但是在容器里面是不能访问宿主机的资源,宿主机是使用了 chroot 技术把容器锁定到一个指定的运行目录里面。
例如:/var/lib/containerd/io.containerd.runtime.v1.linux/moby/容器 ID
启动三个容器用于以下验证过程:

Server: Docker Engine - Community
Engine:
Version: 18.09.7
API version: 1.39 (minimum version 1.12)
Go version: go1.10.8
Git commit: 2d0083d
Built: Thu Jun 27 17:26:28 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 (网络工具)

验证容器的根文件系统:

1.1.4.2 IPC Namespace:

​ 一个容器内的进程间通信,允许一个容器内的不同进程的(内存、缓存等)数据访问,但是不能夸容器访问其他容器的数据。

1.1.4.3 UTS Namespace:

​ UTS namespace(UNIX Timesharing System 包含了运行内核的名称、版本、底层体系结构类型等信息)用于系统标识,其中包含了 hostname 和域名 domainname ,它使得一个容器拥有属于自己 hostname 标识,这个主机名标识独立于宿主机系统和其上的其他容器。

1.1.4.4 PID Namespace:

​ Linux 系统中,有一个 PID 为 1 的进程(init/systemd)是其他所有进程的父进程,那么在每个容器内也要有一个父进程来管理其下属的子进程,那么多个容器的进程通 PID namespace 进程隔离(比如 PID 编号重复、器内的主进程生成与回收子进程等)。
例如:下图是在一个容器内使用 top 命令看到的 PID 为 1 的进程是 nginx::

容器内的 Nginx 主进程与工作进程:

那么宿主机的 PID 究竟与容器内的 PID 是什么关系?
容器 PID 追踪:

1.1.4.4.1 查看宿主机上的 PID 信息:

1.1.4.4.2 查看容器中的 PID 信息:

1.1.4.5 Net Namespace:

​ 每一个容器都类似于虚拟机一样有自己的网卡、监听端口、TCP/IP 协议栈等,Docker 使用 network namespace 启动一个 vethX 接口,这样你的容器将拥有它自己的桥接 ip 地址,通常是 docker0,而 docker0 实质就是 Linux 的虚拟网桥,网桥是在 OSI 七层模型的数据链路层的网络设备,通过 mac 地址对网络进行划分,并且在不同网络直接传递数据。

1.1.4.5.1 查看宿主机的网卡信息:

1.1.4.5.2 查看宿主机桥接设备:

通过 brctl show 命令查看桥接设备:

1.1.4.5.3 实逻辑网络图:

1.1.4.5.4 宿主机 iptables 规则:

1.1.4.6 User Namespace:

​ 各个容器内可能会出现重名的用户和用户组名称,或重复的用户 UID 或者 GID,那么怎么隔离各个容器内的用户空间呢?
​ User Namespace 允许在各个宿主机的各个容器空间内创建相同的用户名以及相同的用户 UID 和 GID,只是会把用户的作用范围限制在每个容器内,即 A 容器和B 容器可以有相同的用户名称和 ID 的账户,但是此用户的有效范围仅是当前容器内,不能访问另外一个容器内的文件系统,即相互隔离、互补影响、永不相见。

1.1.5 Linux control groups:

​ 在一个容器,如果不对其做任何资源限制,则宿主机会允许其占用无限大的内存空间,有时候会因为代码 bug 程序会一直申请内存,直到把宿主机内存占完,为了避免此类的问题出现,宿主机有必要对容器进行资源分配限制,比如 CPU、内存等,Linux Cgroups 的全称是 Linux Control Groups,它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。此外,还能够对进程进行优先级设置,以及将进程挂起和恢复等操作。

1.1.5.1 验证系统 cgroups:

​ Cgroups 在内核层默认已经开启,从 centos 和 ubuntu 对比结果来看,显然内核较新的 ubuntu 支持的功能更多。

1.1.5.1.1 Centos 7.6 cgroups:

1.1.5.1.2 ubuntu cgroups:

1.1.5.1.3 cgroups 中内存模块:
# cat /boot/config-4.15.0-54-generic | grep MEM | grep CG
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
# CONFIG_MEMCG_SWAP_ENABLED is not set
CONFIG_SLUB_MEMCG_SYSFS_ON=y
1.1.5.1.4 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 上的线程。
1.1.5.1.5 查看系统 cgroups:
[root@node1 ~]# ll /sys/fs/cgroup/
total 0
drwxr-xr-x 5 root root 0 Jun 30 18:12 blkio
lrwxrwxrwx 1 root root 11 Jun 30 18:12 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 Jun 30 18:12 cpuacct -> cpu,cpuacct
drwxr-xr-x 5 root root 0 Jun 30 18:12 cpu,cpuacct
drwxr-xr-x 3 root root 0 Jun 30 18:12 cpuset
drwxr-xr-x 5 root root 0 Jun 30 18:12 devices
drwxr-xr-x 3 root root 0 Jun 30 18:12 freezer
drwxr-xr-x 3 root root 0 Jun 30 18:12 hugetlb
drwxr-xr-x 5 root root 0 Jun 30 18:12 memory
drwxr-xr-x 3 root root 0 Jun 30 18:12 net_cls
drwxr-xr-x 3 root root 0 Jun 30 18:12 perf_event
drwxr-xr-x 5 root root 0 Jun 30 18:12 systemd

有了以上的 chroot、namespace、cgroups 就具备了基础的容器运行环境,但是还需要有相应的容器创建与删除的管理工具、以及怎么样把容器运行起来、容器数据怎么处理、怎么进行启动与关闭等问题需要解决,于是容器管理技术出现了。

1.1.6 容器管理工具:

​ 目前主要是使用 docker,早期有使用 lxc。

1.1.6.1 lxc:

​ LXC:LXC 为 Linux Container 的简写。可以提供轻量级的虚拟化,以便隔离进程和资源,官方网站:https://linuxcontainers.org/
Ubuntu 安装 lxc:

root@docker-server1-201:~# apt install lxc lxd
root@docker-server1-201:~# lxc-checkconfig 		#检查内核对 lcx 的支持状况,必须全部为 lcx
root@docker-server1-201:~# lxc-create -t 模板名称 -n lcx-test
root@docker-server1-201:~# lxc-create -t download --name alpine12 -- --dist alpine --release 3.9 --arch amd64
Setting up the GPG keyring
Downloading the image index
Downloading the rootfs
Downloading the metadata
The image cache is now ready
Unpacking the rootfs
--- You just created an Alpinelinux 3.9 x86_64 (20190630_13:00) container. 
root@docker-server1-201:~# lxc-start alpine12 	#启动 lxc 容器
root@docker-server1-201:~# 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。

1.1.6.2 docker:

​ Docker 启动一个容器也需要一个外部模板但是较多镜像,docke 的镜像可以保存在一个公共的地方共享使用,只要把镜像下载下来就可以使用,最主要的是可以在镜像基础之上做自定义配置并且可以再把其提交为一个镜像,一个镜像可以被启动为多个容器。
​ Docker 的镜像是分层的,镜像底层为库文件且只读层即不能写入也不能删除数据,从镜像加载启动为一个容器后会生成一个可写层,其写入的数据会复制到容器目录,但是容器内的数据在删除容器后也会被随之删除。

1.1.6.3 pouch:

阿里开源的容器平台

https://www.infoq.cn/article/alibaba-pouch
https://github.com/alibaba/pouch

1.1.6 Docker 的优势:

​ 快速部署:短时间内可以部署成百上千个应用,更快速交付到线上。
​ 高效虚拟化:不需要额外的 hypervisor 支持,直接基于 linux 实现应用虚拟化,相比虚拟机大幅提高性能和效率。
​ 节省开支:提高服务器利用率,降低 IT 支出。
​ 简化配置:将运行环境打包保存至容器,使用时直接启动即可。
​ 快速迁移和扩展:可夸平台运行在物理机、虚拟机、公有云等环境,良好的兼容性可以方便将应用从 A 宿主机迁移到 B 宿主机,甚至是 A 平台迁移到 B 平台。

1.1.7 Docker 的缺点:

​ 隔离性:各应用之间的隔离不如虚拟机彻底。

1.1.8 docker(容器)的核心技术:

1.1.8.1 容器规范:

​ 容器技术除了的 docker 之外,还有 coreOS 的 rkt,还有阿里的 Pouch,为了保证容器生态的标准性和健康可持续发展,包括 Linux 基金会、Docker、微软、红帽谷歌和、IBM、等公司在 2015 年 6 月共同成立了一个叫 open container(OCI)的组织,其目的就是制定开放的标准的容器规范,目前 OCI 一共发布了两个规范,分别是 runtime spec 和 image format spec,有了这两个规范,不同的容器公司开发的容器只要兼容这两个规范,就可以保证容器的可移植性和相互可操作性。

1.1.8.1.1 容器 runtime(runtime spec):

​ runtime 是真正运行容器的地方,因此为了运行不同的容器 runtime 需要和操作系统内核紧密合作相互在支持,以便为容器提供相应的运行环境。
目前主流的三种 runtime:
​ Lxc:linux 上早期的 runtime,Docker 早期就是采用 lxc 作为 runtime。
​ runc:目前 Docker 默认的 runtime,runc 遵守 OCI 规范,因此可以兼容 lxc。
​ rkt:是 CoreOS 开发的容器 runtime,也符合 OCI 规范,所以使用 rktruntime 也可以运行 Docker 容器。
​ runtime 主 要 定 义 了 以 下 规 范 , 并 以 json 格 式 保 存 在/run/docker/runtime-runc/moby/容器 ID/state.json 文件,此文件会根据容器的状态
实时更新内容:

版本信息:存放 OCI 标准的具体版本号。
容器 ID:通常是一个哈希值,可以在所有 state.json 文件中提取出容器 ID 对容器进行批量操作(关闭、删除等),此文件在容器关闭后会被删除,容器启动后会自动生成。
PID:在容器中运行的首个进程在宿主机上的进程号,即将宿主机的那个进程设置为容器的守护进程。
容器文件目录:存放容器 rootfs 及相应配置的目录,外部程序只需读取 state.json 就可以定位到宿主机上的容器文件目录。
容器创建:创建包括文件系统、namespaces、cgroups、用户权限在内的各项内容。
容器进程的启动:运行容器启动进程,该文件在
/run/containerd/io.containerd.runtime.v1.linux/moby/容器 ID/config.json。
容器生命周期:容器进程可以被外部程序关停,runtime 规范定义了对容器操作信号的捕获,并做相应资源回收的处理,避免僵尸进程的出现。
1.1.8.1.2 容器镜像(image format spec):

OCI 容器镜像主要包含以下内容:

文件系统:定义以 layer 保存的文件系统,在镜像里面是 layer.tar,每个 layer 保存了和上层之间变化的部分,image format spec 定义了 layer 应该保存哪些文件,怎么表示增加、修改和删除的文件等操作。
manifest 文件:描述有哪些 layer,tag 标签及 config 文件名称。
config 文件:是一个以 hash 命名的 json 文件,保存了镜像平台,容器运行时容器运行时需要的一些信息,比如环境变量、工作目录、命令参数等。
index 文件:可选的文件,指向不同平台的 manifest 文件,这个文件能保证一个镜像可以跨平台使用,每个平台拥有不同的 manifest 文件使用 index 作为索引。
父镜像:大多数层的元信息结构都包含一个 parent 字段,指向该镜像的父镜像。
参数:
ID:镜像 ID,每一层都有 ID
tag 标签:标签用于将用户指定的、具有描述性的名称对应到镜像 ID仓库:Repository 镜像仓库
os:定义类型
architecture :定义 CPU 架构
author:作者信息
create:镜像创建日期

1.1.8.2 容器管理工具:

​ 管理工具连接 runtime 与用户,对用户提供图形或命令方式操作,然后管理工具将用户操作传递给 runtime 执行。
​ lxc 是 lxd 的管理工具。
​ Runc 的管理工具是 docker engine,docker engine 包含后台 deamon 和 cli 两部分,大家经常提到的 Docker 就是指的 docker engine。
​ Rkt 的管理工具是 rkt cli。

1.1.8.3 容器定义工具:

​ 容器定义工具允许用户定义容器的属性和内容,以方便容器能够被保存、共享和重建。
​ Docker image:是 docker 容器的模板,runtime 依据 docker image 创建容器。
​ Dockerfile:包含 N 个命令的文本文件,通过 dockerfile 创建出 docker image。
​ ACI(App container image):与 docker image 类似,是 CoreOS 开发的 rkt 容器的镜像格式。

1.1.8.4 Registry:

​ 统一保存镜像而且是多个不同镜像版本的地方,叫做镜像仓库。
​ Image registry:docker 官方提供的私有仓库部署工具。
​ Docker hub:docker 官方的公共仓库,已经保存了大量的常用镜像,可以方便大家直接使用。
​ Harbor:vmware 提供的自带 web 界面自带认证功能的镜像仓库,目前有很多公司使用。

1.1.8.5 编排工具:

​ 当多个容器在多个主机运行的时候,单独管理容器是相当复杂而且很容易出错,而且也无法实现某一台主机宕机后容器自动迁移到其他主机从而实现高可用
的目的,也无法实现动态伸缩的功能,因此需要有一种工具可以实现统一管理、动态伸缩、故障自愈、批量执行等功能,这就是容器编排引擎。
​ 容器编排通常包括容器管理、调度、集群定义和服务发现等功能。
​ Docker swarm:docker 开发的容器编排引擎。
​ Kubernetes:google 领导开发的容器编排引擎,内部项目为 Borg,且其同时支持docker 和 CoreOS。
​ Mesos+Marathon:通用的集群组员调度平台,mesos(资源分配)与 marathon(容器编排平台)一起提供容器编排引擎功能。

1.1.9 docker(容器)的依赖技术:

1.1.9.1 容器网络:

​ docker 自带的网络 docker network 仅支持管理单机上的容器网络,当多主机运行的时候需要使用第三方开源网络,例如 calico、flannel 等。

1.1.9.2 服务发现:

​ 容器的动态扩容特性决定了容器 IP 也会随之变化,因此需要有一种机制可以自动识别并将用户请求动态转发到新创建的容器上,kubernetes 自带服务发现功
能,需要结合 kube-dns 服务解析内部域名。

1.1.9.3 容器监控:

​ 可以通过原生命令 docker ps/top/stats 查看容器运行状态,另外也可以使heapster/ Prometheus 等第三方监控工具监控容器的运行状态。

1.1.9.4 数据管理:

​ 容器的动态迁移会导致其在不同的 Host 之间迁移,因此如何保证与容器相关的数据也能随之迁移或随时访问,可以使用逻辑卷/存储挂载等方式解决。

1.1.9.5 日志收集:

​ docker 原生的日志查看工具 docker logs,但是容器内部的日志需要通过 ELK等专门的日志收集分析和展示工具进行处理。

1.2 Docker 安装及基础命令介绍:

​ 官方网址:https://www.docker.com/
​ 系统版本选择:
​ Docker 目前已经支持多种操作系统的安装运行,比如 Ubuntu、CentOS、Redhat、Debian、Fedora,甚至是还支持了 Mac 和 Windows,在 linux 系统上需要内核版本在 3.10 或以上,docker 版本号之前一直是 0.X 版本或 1.X 版本,但是从 2017 年 3 月 1 号开始改为每个季度发布一次稳版,其版本号规则也统一变更为 YY.MM,例如 17.09 表示是 2017 年 9 月份发布的,本次演示的操作系统使用
Centos 7.5 为例。
​ Docker 版本选择:
​ Docker 之前没有区分版本,但是 2017 年初推出(将 docker 更名为)新的项目Moby,github 地址:https://github.com/moby/moby,Moby 项目属于 Docker 项目的全新上游,Docker 将是一个隶属于的 Moby 的子产品,而且之后的版本之后开始区分为 CE 版本(社区版本)和 EE(企业收费版),CE 社区版本和 EE 企业版本都是每个季度发布一个新版本,但是 EE 版本提供后期安全维护 1 年,而 CE版本是 4 个月,本次演示的 Docker 版本为 18.03,以下为官方原文:
https://blog.docker.com/2017/03/docker-enterprise-edition/
Docker CE and EE are released quarterly, and CE also has a monthly “Edge” option. Each Docker EE release is supported and maintained for one year and receives security and critical bugfixes during that period. We are also improving Docker CE maintainability by maintaining each quarterly CE release for 4 months. That gets Docker CE users a new 1-month window to update from one version to the next.

​ 与 kubernetes 结合使用的时候,要安装经过 kubernetes 官方测试通过的 docker版本,避免出现不兼容等未知的及不可预估的问题发生,kubernetes 测试过的docker 版本可以在 github 查询,具体如下:
https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.14.md#external-dependencies

1.2.1 下载 rpm 包安装:

​ 官方 rpm 包下载地址:
https://download.docker.com/linux/centos/7/x86_64/stable/Packages/
​ 二进制下载地址:
https://download.docker.com/
https://mirrors.aliyun.com/docker-ce/linux/static/stable/x86_64/
​ 阿里镜像下载地址:
https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages/

1.2.2 通过修改 yum 源安装:

[root@docker-server1 ~]# yum install -y yum-utils device-mapper-persistent-data lvm2
[root@docker-server1 ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@docker-server1 ~]# sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
[root@docker-server1 ~]# yum makecache fast
[root@docker-server1 ~]# yum install docker-ce

1.2.3 ubuntu 安装 docker、启动并验证服务:

root@docker-server1-201:~# apt-get remove docker docker-engine docker.io
root@docker-server1-201:~# apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common
root@docker-server1-201:~# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
root@docker-server1-201:~# sudo add-apt-repository    "deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
root@docker-server1-201:~# apt-get update
root@docker-server1-201:~# apt-cache madison docker-ce								#查看当前库所包含版本
root@docker-server1-201:~# apt install docker-ce=5:19.03.15~3-0~ubuntu-focal		#安装19.03版本
root@docker-server1-201:~# docker info

1.2.4 验证 docker 版本:

root@docker-server1-201:~# docker version

1.2.5 二进制安装

#将docker-19.03.15-binary-install.tar.gz包上传至目标服务器
root@docker-server3-203:~# mkdir /src
root@docker-server3-203:~# tar xf docker-19.03.15-binary-install.tar.gz -C /src
root@docker-server3-203:~# cd /src
root@docker-server3-203:/src# ll
total 76800
drwxr-xr-x  2 root root     4096 Apr 11  2021 ./
drwxr-xr-x 21 root root     4096 Dec 29 01:22 ../
-rw-r--r--  1 root root      647 Apr 11  2021 containerd.service
-rw-r--r--  1 root root 62436240 Feb  5  2021 docker-19.03.15.tgz					#修改安装版本只需要下载并替换为官方指定版本二进制包
-rwxr-xr-x  1 root root 16168192 Jun 24  2019 docker-compose-Linux-x86_64_1.24.1*
-rwxr-xr-x  1 root root     2708 Apr 11  2021 docker-install.sh*
-rw-r--r--  1 root root     1683 Apr 11  2021 docker.service
-rw-r--r--  1 root root      197 Apr 11  2021 docker.socket
-rw-r--r--  1 root root      454 Apr 11  2021 limits.conf
-rw-r--r--  1 root root      257 Apr 11  2021 sysctl.conf
root@docker-server3-203:/src# ./docker-install.sh									#运行脚本,自动安装
当前系统是Ubuntu 20.04.3 LTS \n \l,即将开始系统初始化、配置docker-compose与安装docker
docker/
docker/dockerd
docker/docker-proxy
docker/containerd-shim
docker/docker-init
docker/docker
docker/runc
docker/ctr
docker/containerd
su: user jack does not exist
docker 安装完成!
Created symlink /etc/systemd/system/multi-user.target.wants/containerd.service → /lib/systemd/system/containerd.service.
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /lib/systemd/system/docker.service.
Created symlink /etc/systemd/system/sockets.target.wants/docker.socket → /lib/systemd/system/docker.socket.
root@docker-server3-203:/src# docker version
Client: Docker Engine - Community
 Version:           19.03.15
 API version:       1.40
 Go version:        go1.13.15
 Git commit:        99e3ed8
 Built:             Sat Jan 30 03:11:43 2021
 OS/Arch:           linux/amd64
 Experimental:      false

1.2.6 验证 docker0 网卡:

在 docker 安装启动之后,默认会生成一个名称为 docker0 的网卡并且默认 IP 地址为 172.17.0.1 的网卡。

1.2.7 解决不支持 swap 限制警告:

root@docker-server1:~# vim /etc/default/grub
GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=2
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian` GRUB_CMDLINE_LINUX_DEFAULT="" GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0 cgroup_enable=memory swapaccount=1" 
root@docker-server1:~# update-grub
root@docker-server1:~# reboot

1.2.8 docker 存储引擎:

​ 目前 docker 的默认存储引擎为 overlay2,不同的存储引擎需要相应的系统支持,如需要磁盘分区的时候传递 d-type 文件分层功能,即需要传递内核参数开启格式化磁盘的时候的指定功能。

​ 历史更新信息:
https://github.com/moby/moby/blob/master/CHANGELOG.md
​ 官方文档关于存储引擎的选择文档:
https://docs.docker.com/storage/storagedriver/select-storage-driver/
​ 存储驱动类型:

AUFS(AnotherUnionFS)是一种 Union FS,是文件级的存储驱动。所谓 UnionFS 就是把不同物理位置的目录合并 mount 到同一个目录中。简单来说就是支持将不
同目录挂载到同一个虚拟文件系统下的文件系统。这种文件系统可以一层一层地叠加修改文件。无论底下有多少层都是只读的,只有最上层的文件系统是可写的。当需要修改一个文件时,AUFS 创建该文件的一个副本,使用 CoW 将文件从只读层复制到可写层进行修改,结果也保存在可写层。在 Docker 中,底下的只读层就是 image,可写层就是 Container,是 Docker 18.06 及更早版本的首选存储驱动程序,在内核 3.13 上运行 Ubuntu 14.04 时不支持 overlay2。
Overlay:一种 Union FS 文件系统,Linux 内核 3.18 后支持。
overlay2: Overlay 的升级版,到目前为止,所有 Linux 发行版推荐使用的存储类型。
devicemapper:是 CentOS 和 RHEL 的推荐存储驱动程序,因为之前的内核版本不支持 overlay2,但是当前较新版本的 CentOS 和 RHEL 现在已经支持 overlay2,因此推荐使用 overlay2。
ZFS(Sun-2005)/btrfs(Oracle-2007):目前没有广泛使用。
vfs:用于测试环境,适用于无法使用 copy-on-write 文件系统的情况。 此存储驱动程序的性能很差,通常不建议用于生产。

​ Docker 官方推荐首选存储引擎为 overlay2,devicemapper 存在使用空间方面的一些限制,虽然可以通过后期配置解决,但是官方依然推荐使用 overlay2,以下是网上查到的部分资料:
https://www.cnblogs.com/youruncloud/p/5736718.html

如果 docker 数据目录是一块单独的磁盘分区而且是 xfs 格式的,那么需要在格式化的时候加上参数-n ftype=1,否则后期在启动容器的时候会报错不支持 d-type。

Centos 7.2 报错界面:

Centos 7.3 修复此问题:

1.2.9 docker 服务进程:

通过查看 docker 进程,了解 docker 的运行及工作方式

1.2.9.1 查看宿主机进程树:

1.2.9.2 查看 containerd 进程关系:

有四个进程:
dockerd:被 client 直接访问,其父进程为宿主机的 systemd 守护进程。
docker-proxy:实现容器通信,其父进程为 dockerd
containerd:被 dockerd 进程调用以实现与 runc 交互。
containerd-shim:真正运行容器的载体,其父进程为 containerd。

1.3 docker 镜像加速配置:

1.3.1 获取加速地址:

​ 浏览器打开 http://cr.console.aliyun.com,注册或登录阿里云账号,点击左侧的镜像加速器,将会得到一个专属的加速地址,而且下面有使用配置说明:

1.3.2 生成配置文件:

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://pur7v6fb.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

1.4 修改存储类型和存储路径

#可以修改systemd文件或修改daemon.json文件来实现自定义docker配置
root@docker-server2-202:~# dockerd --help
root@docker-server1-201:~# vi /etc/docker/daemon.json 
{
  "registry-mirrors": ["https://pur7v6fb.mirror.aliyuncs.com"],					#镜像加速器地址
  "data-root": "/data/docker",													#存储路径
  "storage-driver": "overlay"													#存储引擎
}
root@docker-server1-201:~# mkdir /data/docker -p
root@docker-server1-201:~# systemctl restart docker
root@docker-server1-201:~# docker info
 Storage Driver: overlay
 Docker Root Dir: /data/docker

1.5 Docker 镜像管理:

​ Docker 镜像含有启动容器所需要的文件系统及所需要的内容,因此镜像主要用于创建并启动 docker 容器。
​ Docker 镜像含里面是一层层文件系统,叫做 Union File System(Union FS 联合文件系统),2004 年由纽约州立大学石溪分校开发,联合文件系统可以将多个目录挂载到一起从而形成一整个虚拟文件系统,该虚拟文件系统的目录结构就像普通 linux 的目录结构一样,docker 通过这些文件再加上宿主机的内核提供了一
个 linux 的虚拟环境,每一层文件系统我们叫做一层 layer,联合文件系统可以对每一层文件系统设置三种权限,只读(readonly)、读写(readwrite)和写出(whiteout-able),但是 docker 镜像中每一层文件系统都是只读的,构建镜像的时候,从一个最基本的操作系统开始,每个构建的操作都相当于做一层的修改,增加了一层文件系统,一层层往上叠加,上层的修改会覆盖底层该位置的可见性,这也很容易理解,就像上层把底层遮住了一样,当使用镜像的时候,我们只会看到一个完全的整体,不知道里面有几层也不需要知道里面有几层,结构如下:

​ 一个典型的 Linux 文件系统由bootfs和 rootfs两部分组成,bootfs(boot file system)主要包含bootloader和kernel,bootloader主要用于引导加载 kernel,当 kernel 被加载到内存中后 bootfs 会被 umount 掉,rootfs (root file system) 包含的就是典型Linux 系统中的/dev,/proc,/bin,/etc 等标准目录和文件,下图就是 docker image中最基础的两层结构,不同的 linux 发行版(如 ubuntu 和 CentOS ) 在 rootfs这一层会有所区别。
​ 但是对于 docker 镜像通常都比较小,官方提供的 centos 基础镜像在 200MB 左右,一些其他版本的镜像甚至只有几 MB,docker 镜像直接调用宿主机的内核,镜像中只提供 rootfs,也就是只需要包括最基本的命令、工具和程序库就可以了,比如 alpine镜像,在 5M 左右。
下图就是有两个不同的镜像在一个宿主机内核上实现不同的 rootfs。

容器、镜像父镜像:

​ docker 命令是最常使用的 docker 客户端命令,其后面可以加不同的参数以实现相应的功能,常用的命令如下:

1.5.1 搜索镜像:

在官方的 docker 仓库中搜索指定名称的 docker 镜像,也会有很多镜像。

root@docker-server1-201:~# docker search centos:7.2.1511						#指定版本号
root@docker-server1-201:~# docker search centos									#不指定版本
NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
centos                            The official build of CentOS.                   6953      [OK]       				#官方版本
ansible/centos7-ansible           Ansible on Centos7                              135                  [OK]
consol/centos-xfce-vnc            Centos container with "headless" VNC session…   132                  [OK]
jdeathe/centos-ssh                OpenSSH / Supervisor / EPEL/IUS/SCL Repos - …   121                  [OK]
centos/systemd                    systemd enabled base container.                 105                  [OK]
centos/mysql-57-centos7           MySQL 5.7 SQL database server                   92                   
imagine10255/centos6-lnmp-php56   centos6-lnmp-php56                              58                   [OK]

1.5.2 下载镜像:

从 docker 仓库将镜像下载到本地,命令格式如下:

# docker pull 仓库服务器:端口/项目名称/镜像名称:tag(版本)号
root@docker-server1-201:~# docker pull alpine

root@docker-server1-201:~# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
a2abf6c4d29d: Extracting [================================================>  ]  30.15MB/31.36MB		#可以看出镜像是分层的
a9edb18cadd1: Download complete 
589b7251471a: Download complete 
186b1aaa4aa6: Download complete 
b4df32aa5a72: Download complete 
a0bcbecc962e: Download complete 
Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Status: Downloaded newer image for nginx:latest														#不指定版本,默认使用最新版
docker.io/library/nginx:latest

root@docker-server1-201:~# docker pull centos:7.2.1511												#指定版本

1.5.3 查看本地镜像:

root@docker-server1-201:~# docker images
REPOSITORY   TAG        IMAGE ID       CREATED       SIZE
nginx        latest     605c77e624dd   6 hours ago   141MB
alpine       latest     c059bfaa849c   5 weeks ago   5.59MB
centos       7.2.1511   9aec5c5fe4ba   2 years ago   195MB
REPOSITORY 			#镜像所属的仓库名称
TAG 				#镜像版本号(标识符),默认为 latest
IMAGE ID 			#镜像唯一 ID 标示
CREATED 			#镜像创建时间
VIRTUAL SIZE 		#镜像的大小

1.5.4 镜像导出:

可以将镜像从本地导出问为一个压缩文件,然后复制到其他服务器进行导入使用。

#导出方法1:
root@docker-server1-201:~# docker save centos -o /opt/centos7.2.1511.tar.gz
#导出方法2:
root@docker-server1-201:~# docker save nginx > /opt/nginx.tar.gz
#查看镜像内容:
root@docker-server1-201:~# cd /opt
root@docker-server1-201:/opt# mkdir nginx
root@docker-server1-201:/opt# tar xf nginx.tar.gz -C /opt/nginx/
root@docker-server1-201:/opt# ll nginx					#可以看出,镜像内是分层的
total 48
drwxr-xr-x  8 root root 4096 Dec 30 01:48 ./
drwxr-xr-x 10 root root 4096 Dec 30 01:47 ../
drwxr-xr-x  2 root root 4096 Dec 29 19:28 251966644dfebf1556dc29856582a22dc3da15ef0c4da4757149aecc2fc0d676/
drwxr-xr-x  2 root root 4096 Dec 29 19:28 27b56d37a142eb86cd779544c546d2ba75e982ac611a61a8267ccee70e96b4e0/
drwxr-xr-x  2 root root 4096 Dec 29 19:28 4f8b55a86a83d3965995a621512129f5f5f357c37a1403cd1c74583ad2e34784/
drwxr-xr-x  2 root root 4096 Dec 29 19:28 5e6074f388a900f13a048419d4dfaa54308ccd20f255527d67426fe43eb940e8/
drwxr-xr-x  2 root root 4096 Dec 29 19:28 5fb7727e98ac8268967806b3256e4216749222b8e8bcd33e36168059745d7527/
-rw-r--r--  1 root root 7656 Dec 29 19:28 605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85.json
drwxr-xr-x  2 root root 4096 Dec 29 19:28 c5b80d9b8aafecd66e0485f2978041af6de901c4eb5d8de431ec46b4cd25685b/
-rw-r--r--  1 root root  586 Jan  1  1970 manifest.json
-rw-r--r--  1 root root   88 Jan  1  1970 repositories

root@docker-server1-201:/opt# cat manifest.json 		#此文件包含了镜像的相关配置,配置文件、分层
[{"Config":"605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85.json","RepoTags":["nginx:latest"],"Layers":["5fb7727e98ac8268967806b3256e4216749222b8e8bcd33e36168059745d7527/layer.tar","27b56d37a142eb86cd779544c546d2ba75e982ac611a61a8267ccee70e96b4e0/layer.tar","4f8b55a86a83d3965995a621512129f5f5f357c37a1403cd1c74583ad2e34784/layer.tar","251966644dfebf1556dc29856582a22dc3da15ef0c4da4757149aecc2fc0d676/layer.tar","c5b80d9b8aafecd66e0485f2978041af6de901c4eb5d8de431ec46b4cd25685b/layer.tar","5e6074f388a900f13a048419d4dfaa54308ccd20f255527d67426fe43eb940e8/layer.tar"]}]

#分层为了方便文件的共用,即相同的文件可以共用
[{"Config":" 配 置 文 件 .json","RepoTags":["docker.io/nginx:latest"],"Layers":[" 分 层1/layer.tar","分层 2 /layer.tar","分层 3 /layer.tar"]}]

1.5.5 镜像导入:

#将镜像导入到 docker
root@docker-server1-201:/opt# scp nginx.tar.gz root@192.168.3.202:/opt
root@docker-server2-202:~# cd /opt
#方法一:
root@docker-server2-202:/opt# docker load -i nginx.tar.gz 
2edcec3590a4: Loading layer [==================================================>]  83.86MB/83.86MB
e379e8aedd4d: Loading layer [==================================================>]     62MB/62MB
b8d6e692a25e: Loading layer [==================================================>]  3.072kB/3.072kB
f1db227348d0: Loading layer [==================================================>]  4.096kB/4.096kB
32ce5f6a5106: Loading layer [==================================================>]  3.584kB/3.584kB
d874fd2bc83b: Loading layer [==================================================>]  7.168kB/7.168kB
Loaded image: nginx:latest
#方法二:
root@docker-server2-202:/opt# docker load < nginx.tar.gz 
2edcec3590a4: Loading layer [==================================================>]  83.86MB/83.86MB
e379e8aedd4d: Loading layer [==================================================>]     62MB/62MB
b8d6e692a25e: Loading layer [==================================================>]  3.072kB/3.072kB
f1db227348d0: Loading layer [==================================================>]  4.096kB/4.096kB
32ce5f6a5106: Loading layer [==================================================>]  3.584kB/3.584kB
d874fd2bc83b: Loading layer [==================================================>]  7.168kB/7.168kB
Loaded image: nginx:latest
#验证镜像
root@docker-server2-202:/opt# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              605c77e624dd        6 hours ago         141MB

1.5.6 删除镜像:

root@docker-server2-202:/opt# docker rmi nginx
Untagged: nginx:latest
Deleted: sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
Deleted: sha256:b625d8e29573fa369e799ca7c5df8b7a902126d2b7cbeb390af59e4b9e1210c5
Deleted: sha256:7850d382fb05e393e211067c5ca0aada2111fcbe550a90fed04d1c634bd31a14
Deleted: sha256:02b80ac2055edd757a996c3d554e6a8906fd3521e14d1227440afd5163a5f1c4
Deleted: sha256:b92aa5824592ecb46e6d169f8e694a99150ccef01a2aabea7b9c02356cdabe7c
Deleted: sha256:780238f18c540007376dd5e904f583896a69fe620876cabc06977a3af4ba4fb5
Deleted: sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f

1.5.7 获取运行参数帮助:

root@docker-server1-201:~# docker daemon --help

1.5.8 命令总结:

# docker load -i centos-latest.tar.xz #导入本地镜像
# docker save > /opt/centos.tar #centos #导出镜像
# docker rmi 镜像 ID/镜像名称 #删除指定 ID 的镜像,通过镜像启动容器的时候镜像不能被删除,除非将容器全部关闭
# docker rm 容器 ID/容器名称 #删除容器
# docker rm 容器 ID/容器名-f #强制删除正在运行的容器
posted @ 2021-12-30 10:57  李卓航  阅读(423)  评论(0编辑  收藏  举报