本章概述
- docker简介
- docker安装及基础命令介绍
- docker镜像加速配置
- docker镜像管理
- 容器操作基础命令
1.1 docker简介
前言
统称来说,容器是一种工具,指的是可以装下其它物品的工具,以方便人类归纳放置物品、存储和异地运输,具体来说比如人类使用的衣柜、行李箱、背包等可以成为容器,但今天我们所说的容器是一种 IT 技术。
容器技术是虚拟化、云计算、大数据之后的一门新兴的并且是炙手可热的新技术,容器技术提高了硬件资源利用率、方便了企业的业务快速横向扩容、实现了业务宕机自愈功能,因此未来数年会是一个容器愈发流行的时代,这是一个对于IT 行业来说非常有影响和价值的技术,而对于 IT 行业的从业者来说,熟练掌握容器技术无疑是一个很有前景的行业工作机会。
容器技术最早出现在 freebsd 叫做 jail。
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 发展起来的,提供 LXC 的高级封装,发展标准的配置方法),而虚拟化技术 KVM(Kernel-based Virtual Machine) 基于模块实现,Docker 后改为自己研发并开源的 runc 技术运行容器。
Docker相比虚拟机的交付速度更快,资源消耗更低,Docker 采用客户端/服务端架构,使用远程 API 来管理和创建 Docker 容器,其可以轻松的创建一个轻量级的、可移植的、自给自足的容器,docker 的三大理念是 build(构建)、share(共享)、 run(运行),Docker 遵从 apache 2.0 协议,并通过(namespace 及cgroup 等)来提供容器的资源隔离与安全保障等,所以 Docker 容器在运行时不需要类似虚拟机(空运行的虚拟机占用物理机 6-8%性能)的额外资源开销,因此可以大幅提高资源利用率,总而言之 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):镜像可以理解为创建实例使用的模板。官方镜像仓库: https://hub.docker.com/
Docker 容器(Container): 容器是从镜像生成对外提供服务的一个或一组服务。
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 容器运行在宿主机的用户空间,每个容器都要有类似于虚拟机一样的相互隔离的运行空间,但是容器技术是在一个进程内实现运行指定服务的运行环境,并且还可以保护宿主机内核不受其他进程的干扰和影响,如文件系统空间、网络空间、进程空间等,目前主要通过以下技术实现容器运行空间的相互隔离:
隔离类型 | 功能 | 系统调用参数 | 内核版本 |
---|---|---|---|
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 | Linux 2.6.29 |
User Namespace(user) | 提供用户隔离能力 | CLONE_NEWUSER | Linux 3.8 |
1.1.4.1 MNT Namespace
每个容器都要有独立的根文件系统有独立的用户空间,以实现在容器里面启动服务并且使用容器的运行环境,即一个宿主机是 ubuntu 的服务器,可以在里面启动一个 centos 运行环境的容器并且在容器里面启动一个 Nginx 服务,此 Nginx运行时使用的运行环境就是 centos 系统目录的运行环境,但是在容器里面是不能访问宿主机的资源,宿主机是使用了 chroot 技术把容器锁定到一个指定的运行目录里面。
例如:/var/lib/docker/overlay2/f8fd714c6c329ec25e577ee88cd44db29f2e8a04e3ddcc7312ff356884091428/merged
其中f8fd714c6c329ec25e577ee88cd44db29f2e8a04e3ddcc7312ff356884091428为随机生成的字串
启动容器查看容器根文件系统进行验证(由于还没有安装docker,以下信息仅用于验证)
docker信息如下:
拉起容器
docker run -d -it --name nginx-1 -p 80:80 nginx
进入容器查看根文件系统,可以看到容器有独立且完整的根文件系统
根据容器信息获取容器所在目录,可以看到容器内所有文件都锁定在该目录下
1.1.4.2 IPC Namespace
一个容器内的进程间通信,允许一个容器内的不同进程的(内存、缓存等)数据访问,但是不能夸容器访问其他容器的数据。
1.1.4.3 UTS Namespace
UTS namespace(UNIX Timesharing System 包含了运行内核的名称、版本、底层体系结构类型等信息)用于系统标识,其中包含了 hostname 和域名domainname ,它使得一个容器拥有属于自己 hostname 标识,这个主机名标识独立于宿主机系统和其上的其他容器。
容器具有独立的hostname
但容器内核和宿主机是一样的
1.1.4.4 PID Namespace
Linux 系统中,有一个 PID 为 1 的进程(init/systemd)是其他所有进程的父进程,那么在每个容器内也要有一个父进程来管理其下属的子进程,那么多个容器的进程通过 PID namespace 进行隔离(比如 PID 编号重复、容器内的主进程生成与回收子进程等)。
例如:下图是在nginx容器内使用 top 命令看到的 PID 为 1 的进程是 nginx
(由于该容器是由nginx镜像拉起的,因此pid为1的进程是nginx(容器会将应用主进程pid初始化为1),而物理服务器或虚拟机pid为1的进程是systemd,容器就是通过这种方式实现pid的隔离)
那么宿主机的 PID 究竟与容器内的 PID 是什么关系?
容器的PID是宿主机PID为1的systemd的一个子进程
可以通过以下方式查看
1、由于容器是运行在宿主机上的,因此可以在宿主机上查看容器内的进程
在宿主机查看nginx进程,可以看到nginx的master进程pid为1952,worker进程为2008,master进程的父进程为1925
2、查看pid为1925的进程,可以看到该进程是containerd-shim进程(简称为containerd),即沙箱,该进程用于提供docker容器的运行环境,而其父进程就是pid为1的systemd进程
3、由此得到以下结论:
nginx-master进程在宿主机上pid为1952,在容器内则会被初始化为pid为1的进程,nginx-master进程在宿主机上是宿主机上pid为1925的containerd-shim进程的一个子进程,containerd-shim被称为容器沙箱,为容器提供运行环境
具体查看下图:
通过pstree命令查看宿主机进程之间的树状结构,可以更加清晰的看到宿主机进程与容器进程之间的关联关系
docker容器就是通过将应用主进程初始化为pid为1作为容器父进程的方式实现了PID的隔离
知识延伸:
1、dockerd网络的生成
(1)生成iptables规则
在宿主机上创建一个容器,宿主机上会生成containerd进程,用于运行应用本身,还会生成dockerd进程,dockerd生成docker-proxy进程,docker-proxy调用内核生成iptables规则(即docker网络)
如下图:(绿线部分)
当用户或客户端访问公司内部服务时(假设目标地址为docker容器地址),会首先访问宿主机内核,内核通过匹配iptables规则,将该请求直接转发给docker容器,因此对于docker容器来说,iptables规则十分重要。
如下图:(黑线部分)
下图是宿主机上生成的iptables规则,红框内的规则是用于转发访问docker容器的请求自动生成的DNAT规则
(2)宿主机containerd和dockerd的关系
在宿主机上通过pstree命令可以更加清晰的看到各进程之间的关联关系
可以看到宿主机systemd进程下有两个进程分别是containerd-shim和dockerd
2、docker容器的进程调用关系
(1)docker容器的进程调用
以创建docker容器为例:
在客户端执行docker命令,docker会调用dockerd进程,而dockerd会调用containerd进程,然后创建容器
具体查看下图:(橙色线部分)
(2)dockerd和containerd的调用关系
那么,dockerd通过什么方式调用containerd的呢?
dockerd通过docker的service文件调用containerd,在docker的service文件中指定了containerd的socket文件路径(进程之间可以通过socket文件在本地实现对服务的调用)
如下图所示,docker.service文件中指定了containerd的socket文件路径,这样就可以实现dockerd对containerd的调用
注意:k8s也是通过这种方式进行调用,只不过调用dockerd的不再是docker命令,而是kubelet进程。kubelet进程调用dockerd,dockerd再调用containerd创建容器,而且新版本的k8s不再调用dockerd,而是直接调用containerd创建容器。
1.1.4.5 Net Namespace
每一个容器都类似于虚拟机一样有自己的网卡、监听端口、TCP/IP 协议栈等,Docker 使用 network namespace 启动一个 vethX 接口,这样你的容器将拥有它自己的桥接 ip 地址,通常是 docker0,而 docker0 实质就是 Linux 的虚拟网桥,网桥是在 OSI 七层模型的数据链路层的网络设备,通过 mac 地址对网络进行划分,并且在不同网络直接传递数据。
1、查看宿主机网卡信息
创建nginx-1容器时生成了一个veth网卡
2、查看宿主机桥接设备(为了方便查看,再次创建一个nginx容器)
可以看到veth设备桥接到docker0网卡上,此时docker0就相当于一个网桥,本主机上的所有创建容器时生成的网卡都会桥接到docker0上
3、docker网络逻辑图
容器网络通信分以下几种情况:
(1)同一主机上的容器通信,直接通过docker0转发(docker0网卡通过mac地址通信),不通过宿主机的eth0
(2)不同主机上的容器通信,veth网卡转发给docker0,docker0转发给eth0,由宿主机网卡实现与其他主机的通信
注意:如果要实现不同主机之间的网络转发,需要开启ipv4转发,即配置以下参数:
vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
(3)外部用户请求公司内部容器,通过宿主机内核匹配iptables规则实现(做目的地址转换,即DNAT)
(4)公司内部容器出公网,通过宿主机网卡eth0实现源地址转换(即SNAT)
4、查看宿主机iptables规则
1.1.4.6 User Namespace
各个容器内可能会出现重名的用户和用户组名称,或重复的用户 UID 或者GID,那么怎么隔离各个容器内的用户空间呢?
User Namespace 允许在各个宿主机的各个容器空间内创建相同的用户名以及相同的用户 UID 和 GID,只是会把用户的作用范围限制在每个容器内,即 A 容器和 B 容器可以有相同的用户名称和 ID 的账户,但是此用户的有效范围仅是当前容器内,不能访问另外一个容器内的文件系统,即相互隔离、互不影响、永不相见。
如下图:每个容器内都有超级管理员root及其他账户,且账户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、centos7 cgroups(参数的值为y说明已经开启)
2、ubuntu cgroups(参数的值为y说明已经开启)
3、cgroups 中内存模块
cat /boot/config-4.15.0-112-generic |grep -i mem |grep -i cg
CONFIG_MEMCG=y #限制内存已开启
CONFIG_MEMCG_SWAP=y #限制swap已开启
# CONFIG_MEMCG_SWAP_ENABLED is not set
CONFIG_SLUB_MEMCG_SYSFS_ON=y
4、cgroups 具体实现:
[root@node1 ~]# ll /sys/fs/cgroup/
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 上的线程。
有了以上的 chroot(把一个容器锁定到运行目录)、namespace(实现各个容器的资源隔离)、cgroups(容器资源限制)就具备了基础的容器运行环境,但是还需要有相应的容器创建与删除的管理工具、以及怎么样把容器运行起来、容器数据怎么处理、怎么进行启动与关闭等问题需要解决,于是容器管理技术出现了。
1.1.6 容器管理工具
目前主要是使用 docker,早期有使用 lxc。
1.1.6.1 lxc
LXC:LXC 为 Linux Container 的简写。可以提供轻量级的虚拟化,以便隔离进程和资源
官方网站:https://linuxcontainers.org/
Ubuntu 安装 lxc:(lxd是server端,相当于dockerd;lxc是客户端,相当于docker命令)
root@ubuntu:~# apt install lxc lxd
root@ubuntu:~# lxc-checkconfig #检查内核对 lcx 的支持状况,必须全部为 lcx(即要求全部支持,否则无法使用)
lxc 启动容器依赖于模板,清华模板源:https://mirrors.tuna.tsinghua.edu.cn/help/lxc-images/,但是做模板相对较难,需要手动一步步创构建文件系统、准备基础目录及可执行程序等,而且在大规模使用容器的场景很难横向扩展,另外后期代码升级也需要重新从头构建模板,基于以上种种原因便有了 docker。
1.1.6.2 docker
Docker 启动一个容器也需要一个外部模板(即docker镜像),docker的镜像可以保存在一个公共的地方共享使用,只要把镜像下载下来就可以使用,最主要的是可以在镜像基础之上做自定义配置并且可以再把其提交为一个镜像,一个镜像可以被启动为多个容器。
Docker 的镜像是分层的,镜像底层为库文件且只读层即不能写入也不能删除数据,从镜像加载启动为一个容器后会生成一个可写层,其写入的数据会复制到容器目录,但是容器内的数据在删除容器后也会被随之删除。
需要注意的是,如果把数据存放到容器内,容器删除后,容器内的数据也会被删除。因此在一般情况下,我们会把容器内的重要数据进行持久化,把数据存放到宿主机或存储中,关于容器内数据的持久化我们在后面会讲到。
1.1.6.3 pouch(阿里)
pouch简介:https://www.infoq.cn/article/alibaba-pouch
github项目地址:https://github.com/alibaba/pouch
pouch安装方法:https://developer.aliyun.com/mirror/pouch?spm=a2c6h.13651102.0.0.1aee1b11nHJGCG
1.1.7 Docker优缺点
Docker的优点:
快速部署:短时间内可以部署成百上千个应用,更快速交付到线上。
高效虚拟化:不需要额外的 hypervisor 支持,直接基于 linux 实现应用虚拟化,相比虚拟机大幅提高性能和效率。
节省开支:提高服务器利用率,降低 IT 支出。
简化配置:将运行环境打包保存至容器,使用时直接启动即可。
快速迁移和扩展:可跨平台运行在物理机、虚拟机、公有云等环境,良好的兼
容性可以方便将应用从 A 宿主机迁移到 B 宿主机,甚至是 A 平台迁移到 B 平台。
Docker的缺点:
隔离性:各应用之间的隔离不如虚拟机彻底。
比如:普通用户可以删除root用户创建的容器(普通用户要想执行docker命令,需要将该用户加入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,有了这两个规范,不同的容器公司开发的容器只要兼容这两个规范,就可以保证容器的可移植性和相互可操作性。
容器运行时规范(runtime spec)
runtime 是真正运行容器的地方,因此为了运行不同的容器 runtime 需要和操作系统内核紧密合作相互在支持,以便为容器提供相应的运行环境。目前主流的三种 runtime:
Lxc:linux 上早期的 runtime,Docker 早期就是采用 lxc 作为 runtime。
runc:目前 Docker 默认的 runtime,runc 遵守 OCI 规范,因此可以兼容rkt。
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就可以定位到宿主机上的容器文件目录
容器创建:创建包括文件系统、namespace、cgroups、用户权限在内的各项内容
容器进程的启动:运行容器启动进程。该文件在/run/containerd/io.containerd.runtime.v1.linux/moby/容器ID/config.json
容器生命周期:容器进程可以被外部程序关闭,runtime规范定义了对容器操作信息的捕获,并做相应资源回收的处理,避免僵尸进程的出现
容器镜像规范(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)先查看本地镜像
(2)导出镜像到本地并解压
mkdir -p /opt/nginx
docker save 6efc10a0510f > /opt/nginx/nginx-image.tar.gz #6efc10a0510f是指镜像ID
cd /opt/nginx
tar -xvf nginx-image.tar.gz
2、查看镜像文件
(1)可以看到存在manifest文件以及多个目录,这些目录就是镜像文件中的各层镜像的内容
(2)查看其中一层目录中的json文件,可以看到其中记录了本层镜像的信息
(3)可以看到其父镜为f322c98d37bfd99242735d58555ff5c813947ff0b9a765b50ae3c4c255fb8e40,而这个目录正是镜像文件中的其中一个目录
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 界面自带认证功能的镜像仓库,目前有很多公司使用。
harbor镜像示例:
172.18.200.101是指镜像仓库服务器地址,project是指项目名称,最后一级路径的是指镜像tag
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
1.1.8.5 编排工具
当多个容器在多个主机运行的时候,单独管理容器是相当复杂而且很容易出错,而且也无法实现某一台主机宕机后容器自动迁移到其他主机从而实现高可用的目的,也无法实现动态伸缩的功能,因此需要有一种工具可以实现统一管理、动态伸缩、故障自愈、批量执行等功能,这就是容器编排引擎。
容器编排通常包括容器管理、调度、集群定义和服务发现等功能。
现有的编排工具:
Docker swarm:docker 开发的容器编排引擎,轻量级的容器编排工具。
Kubernetes:业界使用量较高的编排工具,google 领导开发的容器编排引擎,内部项目为 Borg,且其同时支持docker 和 CoreOS。
Mesos+Marathon:通用的集群组员调度平台,mesos(资源分配)与 marathon(容器编排平台)一起提供容器编排引擎功能,该项目已经被废弃。
1.1.9 docker(容器)的依赖技术
1、容器网络:
docker 自带的网络 docker network 仅支持管理单机上的容器网络,当多主机运行的时候需要使用第三方开源网络,例如 calico、flannel 等。
2、服务发现:
容器的动态扩容特性决定了容器 IP 也会随之变化,因此需要有一种机制可以自动识别并将用户请求动态转发到新创建的容器上,kubernetes 自带服务发现功能,需要结合 kube-dns 服务解析内部域名。
3、容器监控:
可以通过原生命令 docker ps/top/stats 查看容器运行状态,另外也可以使heapster/ Prometheus 等第三方监控工具监控容器的运行状态。
4、数据管理:
容器的动态迁移会导致其在不同的 Host 之间迁移,因此如何保证与容器相关的数据也能随之迁移或随时访问,可以使用逻辑卷/存储挂载等方式解决。
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 月份发布的,本次演示的操作系统使用 ubuntu 1804 为例。
Docker 版本选择:
Docker 之前没有区分版本,但是 2017 年初推出(将 docker 更名为)新的项目Moby,github 地址:https://github.com/moby/moby,Moby 项目属于 Docker 项目的全新上游,Docker 将是一个隶属于的 Moby 的子产品,而且之后的版本之后开始区分为 CE 版本(社区版本)和 EE(企业收费版),CE 社区版本和 EE 企业版本都是每个季度发布一个新版本,但是 EE 版本提供后期安全维护 1 年,而CE 版本是 4 个月,本次演示的 Docker 版本为 20.10。
以下为官方原文: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 通过yum源安装docker
清华大学镜像源提供安装步骤:https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/
以下为详细安装步骤:
1.2.1.1 ubuntu1804安装docker
1、如果你过去安装过 docker,先删掉:
apt-get remove docker docker-engine docker.io containerd runc
2、安装依赖
apt-get install ca-certificates curl gnupg
3、信任 Docker 的 GPG 公钥并添加仓库:
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
4、查看可安装的docker-ce版本
apt-cache madison docker-ce
5、安装20.10版本的docker (可复制上一步输出的版本号指定版本号进行安装)
apt install docker-ce=5:20.10.24~3-0~ubuntu-bionic #安装完成后,Ubuntu会自动拉起docker服务
6、查看docker版本信息
docker info
1.2.1.2 centos7安装docker
1、如果你之前安装过 docker,请先删掉
yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
2、安装依赖
yum install -y yum-utils device-mapper-persistent-data lvm2
3、下载 repo 文件,并把软件仓库地址从官方地址替换为清华大学镜像源地址,方便安装
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo sed -i 's+https://download.docker.com+http://mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
5、安装docker
sudo yum makecache fast
sudo yum install docker-ce
6、启动docker并设置为开机自启动
systemctl start docker && systemctl enable docker
7、查看docker版本信息
1.2.2 通过二进制安装docker
1.2.2.1 下载docker二进制安装包
二进制安装包下载地址:
阿里云镜像源:https://mirrors.aliyun.com/docker-ce/linux/static/stable/x86_64/
清华大学镜像源:https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/static/stable/x86_64/
1、通过清华大学镜像源下载docker二进制安装包并解压
cd /usr/local/src
wget https:// mirrors.aliyun.com/docker-ce/linux/static/stable/x86_64/docker-20.10.24.tgz
tar -xvf docker-20.10.24.tgz
解压出来的是docker可执行命令
2、把解压出来的docker的二进制可执行命令复制到/usr/bin目录下,确保普通用户也可以执行这些命令
cp /usr/local/src/docker/* /usr/bin/
1.2.2.2 准备containerd.service文件
1、编辑containerd.service文件(也可以从其他已经安装docker的机器把该文件复制过来)
vim /lib/systemd/system/containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target
[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/bin/containerd
Type=notify
Delegate=yes
KillMode=process
Restart=always
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=1048576
# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
[Install]
WantedBy=multi-user.target
2、启动containerd服务并设置为开机自启动
systemctl start containerd && systemctl enable containerd
3、查看containerd服务状态
systemctl status containerd
1.2.2.3 准备docker.service文件
1、添加docker组
通过apt或者yum安装时,会自动创建docker组,因此通过二进制安装时需要手动添加docker组
groupadd docker
2、编辑docker.service文件(也可以从其他已经安装docker的机器把该文件复制过来)
vim /lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target docker.socket firewalld.service containerd.service
Wants=network-online.target
Requires=docker.socket containerd.service
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
# Both the old, and new location are accepted by systemd 229 and up, so using the old location
# to make them work for either version of systemd.
StartLimitBurst=3
# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
# this option work for either version of systemd.
StartLimitInterval=60s
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
# Comment TasksMax if your systemd version does not support it.
# Only systemd 226 and above support this option.
TasksMax=infinity
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
[Install]
WantedBy=multi-user.target
3、启动docker服务并设置为开机自启动
systemctl start docker && systemctl enable docker
如果出现以下报错,则需要把docker.socket启动(启动docker.socket在1.2.2.4章节)
4、查看docker服务状态
systemctl status docker
5、验证
执行命令:docker info
1.2.2.4 准备docker.socket文件
注意:docker服务拉起时依赖docker.socket文件,因此在拉起docker.service服务之前要先将docker.socket准备好
1、编辑docker.socket文件
vim /lib/systemd/system/docker.socket
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
2、启动docker.socket并设置为开机自启动
systemctl start docker.socket && systemctl enable docker.socket
3、查看docker.socket状态
systemctl status docker.socket
1.2.3 验证docker信息
root@docker-server1:~# docker info
Containers: 2 #当前主机运行的容器总数(包括正在运行的和退出的)
Running: 1 #有几个容器是正在运行的
Paused: 0 #有几个容器是暂停的
Stopped: 1 #有几个容器是停止的
Images: 3 #当前服务器的镜像数
Server Version: 20.10.24 #服务端版本
Storage Driver: overlay2 #正在使用的存储引擎
Backing Filesystem: extfs #后端文件系统,即服务器的磁盘文件系统
Supports d_type: true #是否支持d_type
Native Overlay Diff: true #是否支持差异数据存储
Logging Driver: json-file #日志类型
Cgroup Driver: cgroupfs #Cgroups 类型
Plugins: #插件
Volume: local #卷,local是指本地卷,容器数据会写入到本地卷中
Network: bridge host macvlan null overlay # 支持的网络类型,overlay跨主机通信
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog #日志类型
Swarm: inactive #是否支持 swarm
Runtimes: runc #已安装的容器运行时
Default Runtime: runc #默认使用的容器运行时
Init Binary: docker-init #初始化容器的守护进程,即 pid 为 1 的进程
containerd version: 2806fc1057397dbaeefbea0e4e17bddfbd388f38 #版本
runc version: v1.1.5-0-gf19387a # runc 版本
init version: de40ad0 #init 版本
Security Options: #安全选项
apparmor #安全模块, https://docs.docker.com/engine/security/apparmor/
seccomp #审计(操作),https://docs.docker.com/engine/security/seccomp/
Profile: default #默认的配置文件
Kernel Version: 4.15.0-112-generic #宿主机内核版本
Operating System: Ubuntu 18.04.5 LTS #宿主机操作系统
OSType: linux #宿主机操作系统类型
Architecture: x86_64 #宿主机架构
CPUs: 2 #宿主机 CPU 数量
Total Memory: 3.83GiB #宿主机总内存
Name: ubuntu #宿主机 hostname
ID: VQUG:Q2I5:5NJT:LZRP:WCO2:ZNEX:N4CC:ZAZY:G57X:SXCS:ZSMP:FQIE #宿主机ID
Docker Root Dir: /var/lib/docker #宿主机数据保存目录
Debug Mode (client): false #client 端是否开启 debug
Debug Mode (server): false #server 端是否开启 debug
Registry: https://index.docker.io/v1/ #镜像仓库
Labels: #其他标签
Experimental: false #是否测试版
Insecure Registries: #非安全的镜像仓库
127.0.0.0/8
Live Restore Enabled: false #是否开启活动重启(即docker重启后,容器是否随着进行重启)false是指docker重启,容器也跟着重启;true是指docker重启,容器不重启
Product License: Community Engine #产品许可信息
WARNING: No swap limit support #系统警告信息(没有开启 swap 资源限制)
1.2.4 解决不支持swap限制警告
1、安装完docker后,执行docker info会出现以下警告:WARNING: No swap limit support
如下图所示:
2、解决方法:
(1)在/etc/default/grub文件中添加以下内容:
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"
(2)修改完成后执行以下命令:
root@ubuntu:~# update-grub
root@ubuntu:~# reboot
(3)重启完成后再次执行docker info命令,警告已经消失
1.2.5 解决centos bridge警告
1、centos7安装docker后,执行docker info命令出现以下警告:
2、解决办法:
vim /etc/sysctl.conf
添加如下内容:
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
最后再执行:
sysctl -p
reboot
3、再次执行docker info告警消失
1.2.6 docker存储引擎
1.2.6.1 存储引擎介绍
目前 docker 的默认存储引擎为 overlay2,不同的存储引擎需要相应的系统支持,如需要磁盘分区的时候传递 d-type 文件分层功能,即需要传递内核参数开启格式化磁盘的时候的指定功能。
历史更新信息:
https://github.com/moby/moby/blob/master/CHANGELOG.md
官方文档关于存储引擎的选择文档:
https://docs.docker.com/storage/storagedriver/select-storage-driver/
存储驱动类型:
AUFS(Another UnionFS)是一种 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。
如何查看ftype的值,执行命令:
[root@centos7 ~]# xfs_info /
如果ftype=0,centos7.2操作系统启动docker时会存在以下报错
报错如下:
centos7.3修复该问题
1.2.6.2 如何修改存储引擎
注意:非必要情况不建议修改docker存储引擎,如果要修改,修改之前一定要先备份数据,包括:镜像、容器中的数据
1、修改之前查看本地有两个镜像和一个容器
2、查看目前在用的存储引擎为overlay2
3、修改docker存储引擎
方法1:在/etc/docker/daemon.json文件中修改
vim /etc/docker/daemon.json #注意,如果有多行配置,要在上一行末尾加上“逗号”,用以隔离多行不同的配置
{
"registry-mirrors": ["https://3lvei2wk.mirror.aliyuncs.com"],
"storage-driver":"overlay"
}
方法2:在/lib/systemd/system/docker.service文件中修改
vim /lib/systemd/system/docker.service
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --storage-driver=overlay #修改存储引擎为overlay
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
4、重启docker服务
systemctl daemon-reload && systemctl restart docker
5、查看修改后的存储引擎以及本地的镜像和容器
查看存储引擎,已经修改为overlay
查看本地镜像和容器,已经丢失。
因此修改存储引擎会造成数据丢失,所以不到万不得已不要修改存储引擎。
1.2.6.3 如何修改docker数据目录
docker容器的数据存储目录默认在/var/lib/docker目录,但有时需要把docker数据存储到空间更大的磁盘上,这就需要修改docker容器的数据存储目录
1、查看当前docker数据存储目录:
docker info
2、修改docker数据存储目录
vim /etc/docker/daemon.json #红色字体为新增配置,注意要在上一行配置末尾添加“逗号”,用以隔离多个配置
{
"registry-mirrors": ["https://3lvei2wk.mirror.aliyuncs.com"],
"storage-driver":"overlay2",
"data-root":"/data/docker"
}
3、创建docker数据存储目录(注意:/data/docker一般是磁盘挂载点,这里进行演示,不再进行挂载)
mkdir -p /data/docker
4、重启docker服务
systemctl daemon-reload && systemctl restart docker
5、查看修改后docker容器数据存储目录
docker info
1.2.7 docker服务进程
1.2.7.1 查看宿主机进程树
1.2.7.2 查看containerd进程关系
共有四个进程:
dockerd:被 client 直接访问,其父进程为宿主机的 systemd 守护进程。
docker-proxy:实现容器通信,创建并维护iptables规则,其父进程为 dockerd
docker-proxy进程:
containerd:被 dockerd 进程调用以实现与 runc 交互,用于创建容器containerd-shim:真正运行容器的载体,即容器沙箱,为容器提供运行环境
containerd相关进程:
1.2.7.3 containerd-shim命令使用
注:该命令不常用,了解即可
root@ubuntu:~# containerd-shim --help
Usage of containerd-shim:
-address string
grpc address back to main containerd
-containerd-binary containerd publish
path to containerd binary (used for containerd publish) (default "containerd")
-criu string
path to criu binary
-debug
enable debug output in logs
-namespace string
namespace that owns the shim
-runtime-root string
root directory for the runtime (default "/run/containerd/runc")
-socket string
socket path to serve
-systemd-cgroup
set runtime to use systemd-cgroup
-workdir string
path used to storge large temporary data
1.2.7.4 容器的创建与管理过程
通信流程:
1、在客户端通过docker命令把请求发送给dockerd,dockerd通过grpc通信协议和containerd模块通信(runc)交换。
注意:docker和containerd可以通信,是因为在docker.service文件中指定了containerd.socket文件路径(即/run/containerd/containerd.sock),所以dockerd可以通过containerd.socket文件与containerd通信。如下图所示:
2、containerd 在 dockerd 启动时被启动,然后 containerd 启动 grpc 请求监听,containerd 处理 dockerd发送的grpc 请求,根据请求做相应动作。
/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
3、若接收到的请求是创建容器,则containerd 拉起一个 container-shim 容器进程 , 并进行相应的创建操作。
4、container-shim 被拉起后,start/exec/create 拉起 runC 进程,通过 exit、control文件和 containerd 通信,通过父子进程关系和 SIGCHLD(信号)监控容器中进程状态。
5、在整个容器生命周期中,containerd 通过 epoll 监控容器文件,监控容器事件。
1.2.7.5 grpc简介
gRPC 是 Google 开发的一款高性能、开源和通用的 RPC 框架,支持众多语言客户端。
链接:https://www.grpc.io/
1.3 docker镜像加速配置
国内下载国外的镜像有时候会很慢,因此可以更改 docker 配置文件添加一个加速器,可以通过加速器达到加速下载镜像的目的。
1、获取加速地址
获取阿里云镜像加速:
(1)浏览器打开 http://cr.console.aliyun.com,注册或登录阿里云账号
(2)点击左侧的镜像工具-镜像加速器,将会得到一个专属的加速地址,而且下面有使用配置说明:
2、生成配置文件
sudo mkdir -p /etc/docker
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://3lvei2wk.mirror.aliyuncs.com"]
}
3、重启docker服务
sudo systemctl daemon-reload
sudo systemctl restart docker
4、验证
执行docker info命令查看镜像加速地址
1.4 docker镜像管理
Docker 镜像含有启动容器所需要的文件系统及所需要的内容,因此镜像主要用于创建并启动 docker 容器。
Docker 镜像含里面是一层层文件系统,叫做 Union File System(Union FS 联合文件系统),2004 年由纽约州立大学石溪分校开发,联合文件系统可以将多个目录挂载到一起从而形成一整个虚拟文件系统,该虚拟文件系统的目录结构就像普通 linux 的目录结构一样,docker 通过这些文件再加上宿主机的内核提供了一个 linux 的虚拟环境,每一层文件系统我们叫做一层 layer,联合文件系统可以对每一层文件系统设置三种权限,只读(readonly)、读写(readwrite)和写出(whiteout-able),但是 docker 镜像中每一层文件系统都是只读的,构建镜像的时候,从一个最基本的操作系统开始,每个构建的操作都相当于做一层的修改,增加了一层文件系统,一层层往上叠加,上层的修改会覆盖底层该位置的可见性,这也很容易理解,就像上层把底层遮住了一样,当使用镜像的时候,我们只会看到一个完全的整体,不知道里面有几层也不需要知道里面有几层,结构如下:
一个典型的 Linux 文件系统由 bootfs 和 rootfs 两部分组成,bootfs(boot filesystem) 主要包含 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。
容器、镜像、父镜像:
要想查看镜像各层,可以将镜像导出,然后解压
(1)导出镜像:
(2)解压镜像,以下为镜像各层内容
另外,使用docker history命令可以查看制作容器镜像时做了哪些历史操作(从下往上查看):
docker 命令是最常使用的 docker 客户端命令,其后面可以加不同的参数以实现相应的功能,常用的命令如下:
1.4.1 搜索镜像
在官方的 docker 仓库中搜索指定名称的 docker 镜像,也会有很多镜像。
root@ubuntu:/opt# docker search nginx:1.24.0 #可以指定版本号
root@ubuntu:/opt# docker search nginx #如果不指定版本号,默认拉取latest版本,即最新的镜像
1.4.2 下载镜像
从 docker 仓库将镜像下载到本地,命令格式如下:
docker pull 镜像仓库地址:端口/项目名称/镜像名称:tag(版本)号
如:docker pull harbor.magedu.com/magedu/nginx-ubuntu:20230512_143030
参数说明:
镜像仓库地址:可以是域名或IP地址,如果不指定,默认指向官方镜像仓库地址,即https://index.docker.io
端口:默认是80端口,也可以指定为其他端口,如果是其他端口,在拉取镜像时,需要指定具体的端口号
项目名称:仓库名称,一般以业务名称命名,便于区分镜像
镜像名称:具体的应用镜像,如:nginx、tomcat等
tag(版本)号:为镜像打上标签,用来区分镜像的版本,一般以时间打tag,便于区分
镜像下载中:
镜像下载完成:
1.4.3 查看本地镜像
下载完成的镜像比下载的大,因为下载完成后会解压
docker images
REPOSITORY #镜像所属的仓库名称
TAG #镜像版本号(标识符),默认为 latest
IMAGE ID #镜像唯一 ID 标示
CREATED #镜像创建时间
VIRTUAL SIZE #镜像的大小
1.4.4 镜像导出
可以将镜像从本地导出问为一个压缩文件,然后复制到其他服务器进行导入使用。
#导出方法 1:
root@ubuntu:~# docker save nginx -o /opt/nginx.tar.gz #这里的nginx是指镜像名称,也可以使用镜像ID,另外,导出镜像时可以指定tag,如果不指定,默认为latest版本
root@ubuntu:~# ls -lh /opt/nginx.tar.gz
#导出方法2:
root@ubuntu:~# docker save nginx > /opt/nginx-01.tar.gz
root@ubuntu:~# ls -lh /opt/nginx-01.tar.gz
查看镜像内容:
root@ubuntu:/opt# cd /opt/
root@ubuntu:/opt# tar -xvf nginx.tar.gz
root@ubuntu:/opt# cat manifest.json #该文件包含了镜像的相关配置,配置文件、分层
[{"Config":"605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85.json","RepoTags":["nginx:latest"],"Layers":["5df3f744c961b85bb93947d6a4288543c06e64b3130562ae7be85fdc9f7a5691/layer.tar","0cb59b23812a64ae9115a5cf081f05d3d1915c5d7d2304c64b1c3a07629122a9/layer.tar","728205feeb04d15cbf0b889a9336e553bf6d472a311724e567a156afe3cb105d/layer.tar","0e9f59de25dca39e1cc33d1b7a83f27668c800221d7f1062a5da0df9ba684f44/layer.tar","7e8578b7bc47a5f07742264aace8ee761078c30c1c2c2dafbc79a8ebd340c191/layer.tar","8c46511b06be8a5ed3d1478039cd8e3bcb0842b8a68c42babb5e9c4b6dc6beeb/layer.tar"]}]
注意:这里分层是为了方便文件的共用,即相同的基础镜像可以共用,这样不但不用重复下载相同的基础镜像,而且还降低了磁盘空间的使用
[{"Config":" 配 置 文 件 .json","RepoTags":["docker.io/nginx:latest"],"Layers":[" 分 层1/layer.tar","分层 2 /layer.tar","分层 3 /layer.tar"]}]
1.4.5 镜像导入
镜像可以共用,可以将本地镜像导入到另外一个装有 docker的服务器使用
scp /opt/nginx.tar.gz 172.31.7.151:/opt/
镜像导入方法1:
docker load -i /opt/nginx.tar.gz
docker images
镜像导入方法2:
docker load < /opt/nginx.tar.gz
docker images
1.4.6 删除镜像
docker rmi 镜像名称
注意:当一个镜像正在被容器使用时,该镜像无法删除,需要先将容器删除,才可以删除镜像
1.4.7 docker常用命令总结
获取运行参数帮助
docker daemon –help
企业使用镜像及常见操作:
搜索、下载、导出、导入、删除
命令总结:
# docker load -i centos-latest.tar.xz #导入本地镜像
# docker save > /opt/centos.tar #centos #导出镜像
# docker rmi 镜像 ID/镜像名称 #删除指定 ID 的镜像,通过镜像启动容器的时候镜像不能被删除,除非将容器全部关闭
# docker rm 容器 ID/容器名称 #删除容器
# docker rm 容器 ID/容器名-f #强制删除正在运行的容器
1.5 容器操作基础命令
命令格式:
# docker run [选项] [镜像名] [shell命令] [参数]
# docker run [参数选项] [镜像名称,必须在所有选项的后面] [/bin/echo 'hello world'] #单次执行,没有自定义容器名称
docker run centos /bin/echo 'hello wold' #启动的容器在执行完shell命令就退出了
1.5.1 从镜像启动一个容器
1、执行命令启动一个容器
docker run -it centos bash #执行该命令会直接进入到容器,并随机生成容器 ID 和名称。另外,如果镜像版本不指定,默认会使用最新版本的镜像
-i 是指为容器分配一个标准输出
-t 是指为容器分配一个tty(即终端)
2、退出容器
(1)执行exit命令退出容器,容器处于exited退出状态
(2)使用以下组合快捷键退出容器,容器可以正常运行:
ctrl+p+q #退出容器不注销
1.5.2 显示容器
1、显示正在运行的容器
docker ps
参数说明:
CONTAINER ID:是指容器id,每个容器的id在当前服务器上是唯一的,容器id由随机生成的字串组成,这里只显示前12位。
IMAGE:是指创建容器使用的镜像
COMMAND:在创建容器时运行的命令,如果没有指定命令,会执行构建镜像时指定的的默认命令
CREATED:容器创建的时间
STATUS:容器当前的状态
PORTS:显示容器端口和协议,以及宿主机到容器的端口映射,同一台服务器上映射到容器内的宿主机端口不能重复(如:当宿主机映射8081端口到nginx容器的80端口,那么宿主机映射端口到第2台nginx容器时,就不能再使用8081端口)
NAMES:容器名称,可以手动指定,如果不指定,会自动生成,容器名称在同一台服务器上是唯一的
2、显示所有容器(包括当前正在运行以及已经关闭的所有容器)
docker ps -a
1.5.3 删除容器
1、删除容器
如果容器处于退出状态(exited),可以直接删除
docker rm 容器id或容器名称
如果容器处于运行中,需要先停止容器,然后再删除容器
docker stop 容器id或名称
docker rm 容器id或名称
2、强制删除容器
即使容正在运行当中,也会被强制删除掉
docker rm -f ${容器id或容器名称}
3、同时删除多个容器:
docker rm命令后面跟容器id或容器名称,多个容器之间用空格隔开即可
docker rm -f 5b927fdf7f88 979fc4ff5474
1.5.4 后台启动容器
1、运行容器
docker run -it nginx #容器默认在前台运行,会占用当前终端,无法进行其他操作
2、如果想要容器处于后台,不占用当前终端,可以使用-d选项,使容器处于后台运行
1.5.5 容器端口映射
1.5.5.1 随机端口映射
1、运行容器
docker run -it -d -P nginx #后台启动容器并随机映射本地端口到容器的 80
2、查看随机生成的映射端口是32769
1.5.5.2 指定端口映射
方式 1:本地端口 81 映射到容器 80 端口:
# docker run -d -p 81:80 --name nginx-test-port1 nginx
方式 2:本地 IP:本地端口:容器端口
# docker run -d -p 172.31.7.150:82:80 --name nginx-test-port2 docker.io/nginx
方式 3:本地 IP:本地随机端口:容器端口
# docker run -d -p 172.31.7.150::80 --name nginx-test-port3 docker.io/nginx
方式 4:本机 ip:本地端口:容器端口/协议,默认为 tcp 协议
# docker run -d -p 172.31.7.150:83:80/udp --name nginx-test-port4 docker.io/nginx
方式 5:一次性映射多个端口+协议:
# docker run -d -p 86:80/tcp -p 443:443/tcp --name nginx-test-port5 docker.io/nginx
执行命令结果如下:
查看创建的容器:
红框内从下向上为创建容器的顺序
1.5.5.3 查看已经映射的端口
docker port nginx-test-port5
1.5.6 自定义容器名称
docker run -d -it --name nginx-test nginx
1.5.7 创建并进入运行容器
创建容器后进入容器,执行exit命令后,容器退出并关闭
docker run -t -i --name test-centos2 docker.io/centos bash
1.5.8 运行一次性容器
常用于执行一次性命令,命令执行完成后,容器自动删除。比如测试容器内服务是否可用
1、执行命令
docker run -it --rm --name nginx-delete-test nginx bash
2、由于容器退出就会自动删除,另起窗口查看该容器
3、退出容器后,再次查看容器
在另外的窗口再次查看该容器已经不存在
1.5.9 传递运行命令
容器需要有一个前台运行的进程才能保持容器的运行,可以通过传递运行参数保持容器处于运行状态。另外一种方法就是在构建镜像的时候指定容器启动时运行的前台命令。(此次展示传递运行参数的方式)
docker run -d centos /usr/bin/tail -f '/etc/hosts'
1.5.8 启动和关闭容器
docker stop 327a15e9dfa8
docker start 327a15e9dfa8
1.5.9 进入正在运行的容器
1.5.9.1 使用 attach 命令
使用方式为 docker attach 容器名,attach 类似于 vnc,操作会在各个容器界面显示,所有使用此方式进入容器的操作都是同步显示的且 exit 后容器将被关闭,且使用 exit 退出后容器关闭,不推荐使用,需要进入到有 shell 环境的容器,比如 centos 为例:
运行一个容器并进入
root@ubuntu:~# docker run -it centos bash
使用docker attach 进入该容器,执行命令
root@ubuntu:~# docker attach 6b7a3cdf85a9
[root@6b7a3cdf85a9 /]# ls
在另一个页面查看终端,显示同样的命令
1.5.9.2 使用 exec 命令
该命令是比较常用的命令,推荐使用此方式进入容器,使用exit退出容器后,容器还在运行
1.5.9.3 使用 nsenter命令
使用nsenter命令需要通过 PID 进入到容器内部,不过可以使用docker inspect 获取到容器的 PID。
使用docker inspect命令查看容器的详细信息
可以看到命令输出结果中显示很多字段,我们可以根据这些字段获取容器的某些信息
docker inspect 容器ID
示例:获取容器IP地址
docker inspect -f "{{.NetworkSettings.IPAddress}}" f8175eb9c030 #获取容器的ip地址
注意:在写字段时,要注意上下级关系,要求每一级的字段都要写上,如IPAddress字段在NetworkSettings字段下一级,在查看ip地址是,两级字段都要写明
1、如果服务器没有nsenter命令需要安装util-linux包使用该命令
apt install util-linux #安装 nsenter 命令
2、获取容器PID #{{.NetworkSettings.IPAddress}}和{{.State.Pid}}是指容器的参数字段,可根据这些字段获取容器的相关参数
docker inspect -f "{{.State.Pid}}" f8175eb9c030 #获取容器的PID
3、根据PID进入容器
nsenter -t 22285 -m -u -i -n -p
通过脚本进入容器:
由于使用nsenter命令进入容器比较麻烦,因此可以通过以下脚本进入容器
1、编辑脚本
vim docker_login.sh #通过位置变量获取容器id或容器名称,根据容器id或容器名称获取容器pid,使用nsenter命令根据pid进入容器
#!/bin/bash
docker_in(){
NAME_ID=$1
PID=$(docker inspect -f "{{.State.Pid}}" ${NAME_ID})
nsenter -t ${PID} -m -u -i -n -p
}
docker_in $1
2、测试脚本是否可以进入容器
可以看到,可以正常进入容器
1.5.10 查看容器内的hosts文件
1、进入容器内部,会自动将容器id和容器ip的解析关系加入到hosts文件中
root@ubuntu:~# docker exec -it afb298f48bde bash #为了便于后续测试,使用centos镜像拉起容器
root@afb298f48bde:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 afb298f48bde #默认会将实例的 ID 添加到自己的 hosts 文件
2、解析容器id测试
在容器内ping容器id,会解析为容器ip地址
root@afb298f48bde:/# ping afb298f48bde
1.5.11 查看容器日志
查看容器日志
root@ubuntu:~# docker logs --help
1、直接查看容器日志
root@ubuntu:~# docker logs 容器id
2、持续追踪容器日志,类似于tail -f
root@ubuntu:~# docker logs -f 容器id
3、查看容器的最后10行日志,类似于tail -n10
1.5.12 批量关闭容器
1、批量关闭正在运行的容器
root@ubuntu:~# docker stop $(docker ps -a -q) #正常关闭所有运行中的容器
或者docker stop `docker ps -a -q`
2、 批量强制关闭正在运行的容器
root@ubuntu:~# docker kill $(docker ps -a -q) #强制关闭所有运行中的容器
1.5.13 批量删除容器
1、批量删除已退出状态容器
root@ubuntu:~# docker rm -f `docker ps -aq -f status=exited`
2、批量删除所有容器
root@ubuntu:~# docker rm -f $(docker ps -a -q)
1.5.14 指定容器DNS
容器的dns服务,默认采用宿主机的 dns 地址。
为容器配置dns的方法有两种:
一是将 dns 地址配置在宿主机
二是将参数配置在 docker 启动脚本里面 --dns=1.1.1.1
1、容器默认使用宿主机dns
2、使用宿主机dns,如果宿主机使用的是公网dns,容器在访问内网域名时会无法解析,因此需要给容器单独配置dns地址,可以通过--dns参数指定容器dns
root@ubuntu:~# docker run -it --rm --dns 223.6.6.6 centos bash
1.5.15 其他命令
docker update 容器id或名称 --cpus 2 #更新容器配置,把容器cpu更改为2核
docker events #获取dockerd的实时事件,会在前台显示,比如:容器创建操作、删除操作等
docker wait 容器id #显示容器的退出状态码,如果容器是非正常退出,会产生非0的状态,可用于监控容器状态
docker run --restart #当服务器重启后,服务器上的容器是否随之启动,默认为no,即不随之启动
示例:docker run --restart=always -it -d -p 8081:80 --name nginx-test02 nginx #always是指随着服务器重启而启动
docker cp #把容器内的文件复制到宿主机,或者把宿主机的文件复制到容器内,其命令格式类似于scp
(1)把宿主机文件复制到容器内
root@ubuntu:~# echo "123" > test.log #宿主机本地创建文件
root@ubuntu:~# docker cp test.log 0ecebeabc806:/tmp #把宿主机文件复制到容器内
Successfully copied 2.05kB to 0ecebeabc806:/tmp
root@ubuntu:~# docker exec -it 0ecebeabc806 cat /tmp/test.log #通过传递运行命令查看容器内文件
123 #显示内容与宿主机一致
(2)把容器内文件复制到宿主机
root@ubuntu:~# docker cp 0ecebeabc806:/etc/nginx/nginx.conf ./ #把nginx容器的配置文件复制到本地
Successfully copied 2.56kB to /root/./
root@ubuntu:~# cat nginx.conf #由于内容过多,这里只粘贴部分nginx配置
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
…..
文章评论