Docker速成:新手变专家!

Docker介绍

容器历史

1、Chroot Jail 就是常见的chroot命令的用法。它在1979年的时候就出现了,被认为是最早的容器化技术之一。它可以把一个进程的文件系统隔离起来。

2、The FreeBSD Jail (监狱)实现了操作系统级别的虚拟化,他是操作系统级别虚拟化技术的先驱之一。2000年,伴随FreeBSD4.0版的发布

3、Linux VServer http://linux-vserver.org 使用添加到Linux内核的系统级别的虚拟化功能实现的专用虚拟服务器。允许创建许多独立的虚拟专用服务器(VPS),这些虚拟专用服务器在单个物理服务器上全速同时运行,从而有效地共享硬件资源。VPS提供与传统Linux服务器几乎相同的操作系统环境。可以在这样的VPS上启动所有服务(例如ssh,邮件,Web和数据库服务器),而无需(或者在特殊情况下只需进行很少的修改),就像在任何真实服务器上一样。每个VPS都有自己的用户账户数据库和root密码,并且与其他虚拟机服务器隔离,但它们共享相同的硬件资源。

4、Solaris Containers 也是操作系统级别的虚拟化技术,专为X866和SPARC系统设计。Solaris容器是系统资源控制和通过"区域"提供边界隔离的组合。

5、OpenVZ 是一种Linux中操作系统级别的虚拟化技术。它允许创建多个安全隔离的Linux容器,即VPS。

6、Process Containers 由Google的工程师开发,一般被称为cgroups。

7、LXC 为Linux Container的简写。可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。Linux Container 提供了在单一可控主机节点上支持多个相互隔离的server Container同时执行的机制。Linux COntainer有点像chroot,提供了一个拥有自己进程和网络空间的虚拟环境,但又有别于虚拟机,因为lxc是一种操作系统层次上的资源虚拟化。

8、Warden 在最初阶段,Warden使用LXC作为容器运行时。如今已被CloudFoundy取代。

9、LMCTFY 是Google的容器技术栈的开源版本。Google的工程师一直在与docker的libertainer团队合作,并将libertainerde核心概念进行抽象并移植到此项目中,该项目的进展不明,估计会被libcontainer取代。

10、Docker 是一个可以将应用及其依赖打包到几乎可以在任何服务器上运行的容器工具。

11、RKT 是Rocket的缩写,他是一个专注安全和开放标准的应用程序引擎。
总上所述,docker并不是第一个容器化技术,但它确实最知名的一个。

Docker是什么

Docker(码头工人)是一个开源项目,诞生于2013年初,最初是dotCloud公司(后由于Docker开源后大受欢迎就将公司名改为Docker Inc,总部位于美国加州的旧金山)内部的一个开源的PAAS服务的业余项目。它基于Google公司推出的Go语言实现。项目后来加入了Linux基金会,遵从了Apache2.0协议,项目代码在GitHub上进行维护。

Docker是基于Linux内核实现,Docker是最早采用LXC技术,LXC是Linux原生支持的容器技术,可以提供轻量级的虚拟化,可以说docker就是基于LXC发展起来的,提供LXC的高级封装,标准的配置方法,在LXC的基础上,docekr提供了一系列更强大的功能。而虚拟化技术KVM基于模块实现,后来Docker改为自己研发并开源的runc技术运行容器,彻底抛弃了LXC。

Docker相比虚拟机的交付速度更快,资源消耗更低,Docker采用客户端/服务端架构,使用远程API来管理和创建容器,其可以轻松的创建一个轻量级的、可移植的、自给自足的容器,docker的三大理念是build(构建)、ship(运输)、run(运行),Docker遵从Apache2.0协议,并通过(namespace及cgroup等)来提供容器的资源隔离与安全保障等,所以Docker容器在运行时不需要类似虚拟机(空运行的虚拟机占用物理机6%~8%性能)的额外资源开销,因此可以大幅提高资源利用率,总而言之Docker是一种用了新颖方式实现的轻量级虚拟机,类似于VM,但是在原理和应用上和VM的差别还是很大的,并且Docker的专业叫法是应用容器(Application Container)。
Docker的主要目标 :Build,Ship and Run Any App,Anywhere,即通过对应用组件的封装(Packaging)、分发(Distribution)、部署(Deployment)。运行(Runtime)等生命周期的管理,达到应用组件级别的"一次封装,到处运行"。这里的应用组件,既可以是一个Web应用,也可以是一套数据库服务,甚至是一个操作系统。将应用运行在Docker容器上,可以实现跨平台,跨服务器,只需一次配置准备好相关的应用环境,即可实现到处运行,保证研发和生产环境的一致性,解决了应用和运行环境的兼容性问题,从而极大提升了部署效率,减少故障的可能性。
使用Docker容器化封装应用程序的意义

  • 统一基础设施环境-docker环境
    • 硬件的组成配置
    • 操作系统的版本
    • 运行时环境的异构
  • 统一程序打包(装箱)方式-docker镜像
    • Java程序
    • python程序
    • nodejs程序
  • 统一程序部署(运行)方式-docker容器
    • java -jar......--->docker run ......
    • python manage.py......--->docker run ......
    • npm run dev ......--->docker run ......

Docker和虚拟机,物理主机


容器和虚拟机比较

  • 传统虚拟机是虚拟出一个主机硬件,并且运行一个完整的操作系统,然后在这个操作系统上安装和运行软件
  • 容器内的应用直接运行在宿主机的内核之上,容器并没有自己的内核,也不需要虚拟硬件,相当轻量化
  • 每个容器间是互相隔离,每个容器内都有一个属于自己的独立文件系统,独立的进程空间,网络空降,用户空间等,所以在同一个宿主机上的多个容器之间彼此不会互相影响

容器和虚拟机比较

  • 资源利用率更高:开销更小,不需要启动单独的虚拟机OS内核占用硬件资源,可以将服务器性能压榨到极致,虚机一般会有5%~20%的损耗,容器运行基本无损耗,所以生产中一台物理机只能运行数十个虚拟机,但是一般可以运行数百个容器
  • 启动速度更快:可以在数秒内完成启动
  • 占用空间更小:容器一般占用的磁盘空间以MB为单位,而虚拟机以GB
  • 集成性更好:和CI/CD(持续集成/持续部署)相关技术结合性更好,实现打报警箱发布测试可以一键运行,做到自动化并快速的部署管理,实现高效的开发生命周期

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

根据实验,一个运行着Centos的KVM虚机启动后,在不做优化的情况下,虚机自己就占用100~200M内存。此外,用户应用运行在虚机里,它对宿主机操作系统的调用就不可避免地要经过虚拟化软件的拦截和处理,这本身又是一层性能损耗,尤其对计算资源、网络和磁盘I/O的损耗非常大。

比如。一台96G内存的物理服务器,为了运行java程序的虚拟机一般需要分配4核8G的资源,只能运行13台左右的虚机,但是改为在docker容器上运行Java程序,每个容器只需要分配4G内存即可,同样的物理服务器就可以运行25个左右的容器,运行数量相当于提高一倍,可以大幅节省IT支出,通常情况下至少可以节约一半以上的物理设备

Docker的组成

  • Docker主机(Host):一个物理机或虚拟机,用于运行Docker服务进程和容器,也称为宿主机,node节点
  • Docker服务端(Server):Docker守护进程,运行Docker容器
  • Docker客户端(Client):客户端使用docker命令或其他工具调用docker API
  • Docker镜像(Images):镜像可以理解为创建实例使用的模板,本质上就是一些程序文件的集合
  • Docker仓库(Registry):保存镜像的仓库,可以搭建私有仓库harbor
  • Docker容器(Container):容器是从镜像生成对外提供服务的一个或一组服务,其本质就是将镜像中的程序启动后生成进程

Namespace

一个宿主机运行了N个容器,多个容器共用一个OS,必然带来以下问题:

  • 怎样保证每个容器都有不同的文件系统并且互不影响?
  • 一个docker主进程内的各个容器都是其子进程,那么如何实现同一个主进程下不同类型的子进程?各个容器子进程间能相互通信(内存数据)吗?
  • 每个容器怎么解决IP及端口分配的问题?
  • 多个容器的主机名能一样吗?
  • 每个容器都要不要有root用户?怎么解决账户重名问题?

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

隔离类型 功能 系统调用参数 内核版本
MNT Namespace(mount) 提供磁盘挂载点和文件系统的隔离能力 CLONE_NEWNS 2.4.19
IPC Namespace(Inter Process Communication) 提供进程间通信的隔离能力,包括信号量,消息队列和共享内存 CLONE_NEWIPC 2.6.19
UTS Namespace(UNIX Timesharing System) 提供内核,主机名和域名隔离能力 CLONE_NEWUTS 2.6.19
PID Namespace (Process Identification) 提供进程隔离能力 CLONE_NEWPID 2.6.24
Net Namespace(network) 提供网络隔离能力,包括网络设备,网络栈,端口等 CLONE_NEWNET 2.6.29
User Namespace(user) 提供用户隔离能力,包括用户和组 CLONE_NEWUSER 3.8
MNT Namespace

每个容器都要有独立的根文件系统有独立的用户空间,以实现在容器里面启动服务并且使用容器的运行环境,即一个宿主机是ubuntu的服务器,可以在里面启动一个centos运行环境的容器并且在容器里面启动一个nginx服务,此nginx运行时使用的运行环境就是centos系统目录的运行环境,但是在容器里面是不能访问宿主机的资源,宿主机是使用了chroot技术把容器锁定到一个指定的运行目录里面。

IPC Namespace

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

UTS Namespace

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

PID Namespace

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

NET Namespace

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

User Namespace

各个容器内可能会出现重名的用户和用户组名称,或重复的用户UID或者GID,那么怎么隔离各个容器内的用户空间呢?

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

Control groups

Linux Cgroups的全称是Linux Control Groups,是Linux内核的一个功能,最早由Google的工程师(主要是Paul Menage和Rohit Seth)在2006年发起,最早的名称为进程容器 (process containers)。在2007年时,因为在Linux内核中,容器(container)这个名词有许多不同的意义,为避免混乱,被重命名为cgroup,并且被合并到2.6.24版的内核中去。自那以后,又添加了很多功能。

如果不对一个容器做任何资源限制,则宿主机会允许其占用无限大的内存空间,有时候会因为代码bug程序会一直申请内存,直到把宿主机内存占完,为了避免此类的问题出现,宿主机有必要对容器进行资源分配限制,比如CPU、内存等。

Cgroups最主要的作用,就是限制一个进程组能够使用的资源上限,包括CPU、内存、磁盘、网络带宽等。此外,还能够对进程进行优先级设置,资源的计量以及资源的控制(比如:将进程挂起和恢复等操作)。

验证系统 cgroups

Cgroups在内核层默认已经开启,从Centos和Ubuntu不同版本对比,显然内核较新的支持的功能更多。
Centos7.4 cgroups:

shell 复制代码
[root@jk-k8s ~]# cat /etc/redhat-release

CentOS Linux release 7.4.1708 (Core)

[root@jk-k8s ~]#

[root@jk-k8s ~]# grep CGROUP /boot/config-3.10.0-693.el7.x86_64

CONFIG_CGROUPS=y

# CONFIG_CGROUP_DEBUG is not set

CONFIG_CGROUP_FREEZER=y

CONFIG_CGROUP_PIDS=y

CONFIG_CGROUP_DEVICE=y

CONFIG_CGROUP_CPUACCT=y

CONFIG_CGROUP_HUGETLB=y

CONFIG_CGROUP_PERF=y

CONFIG_CGROUP_SCHED=y

CONFIG_BLK_CGROUP=y

# CONFIG_DEBUG_BLK_CGROUP is not set

CONFIG_NETFILTER_XT_MATCH_CGROUP=m

CONFIG_NET_CLS_CGROUP=y

CONFIG_NETPRIO_CGROUP=y

[root@jk-k8s ~]#

cgroups中内存模块

shell 复制代码
[root@jk-k8s ~]# grep MEMCG /boot/config-3.10.0-693.el7.x86_64

CONFIG_MEMCG=y

CONFIG_MEMCG_SWAP=y

CONFIG_MEMCG_SWAP_ENABLED=y

CONFIG_MEMCG_KMEM=y
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
shell 复制代码
[root@jk-k8s ~]# ll /sys/fs/cgroup/

总用量 0

drwxr-xr-x 5 root root  0 8月  19 09:46 blkio

lrwxrwxrwx 1 root root 11 8月  19 09:46 cpu -> cpu,cpuacct

lrwxrwxrwx 1 root root 11 8月  19 09:46 cpuacct -> cpu,cpuacct

drwxr-xr-x 5 root root  0 8月  19 09:46 cpu,cpuacct

drwxr-xr-x 3 root root  0 8月  19 09:46 cpuset

drwxr-xr-x 5 root root  0 8月  19 09:46 devices

drwxr-xr-x 3 root root  0 8月  19 09:46 freezer

drwxr-xr-x 3 root root  0 8月  19 09:46 hugetlb

drwxr-xr-x 5 root root  0 8月  19 09:46 memory

lrwxrwxrwx 1 root root 16 8月  19 09:46 net_cls -> net_cls,net_prio

drwxr-xr-x 3 root root  0 8月  19 09:46 net_cls,net_prio

lrwxrwxrwx 1 root root 16 8月  19 09:46 net_prio -> net_cls,net_prio

drwxr-xr-x 3 root root  0 8月  19 09:46 perf_event

drwxr-xr-x 3 root root  0 8月  19 09:46 pids

drwxr-xr-x 5 root root  0 8月  19 09:46 systemd

[root@jk-k8s ~]#

[root@jk-k8s ~]# cat /sys/fs/cgroup/cpu/docker/5a1b43275caa1f8c9fff9ea8ccd3813d4a25acf698f15a3ec5eacd77948833b5/cpuacct.usage

109845268

[root@jk-k8s ~]#

[root@jk-k8s ~]# cat /sys/fs/cgroup/memory/docker/5a1b43275caa1f8c9fff9ea8ccd3813d4a25acf698f15a3ec5eacd77948833b5/memory.limit_in_bytes

9223372036854771712

[root@jk-k8s ~]# cat /sys/fs/cgroup/memory/docker/5a1b43275caa1f8c9fff9ea8ccd3813d4a25acf698f15a3ec5eacd77948833b5/memory.max_usage_in_bytes

12566528

[root@jk-k8s ~]#

容器管理工具

LXC

官网:https://linuxcontainers.org

Linux Container 可以提供轻量级的虚拟化功能,以便隔离进程和资源,包括一系列容器的管理工具软件,如,lxc-create,lxc-start,lxc-attach等,但这技术功能不完善,目前较少使用。

docker

docker相当于增强版的LXC,功能更为强大和易用,也是当前最主流的容器前端管理工具

docker先启动一个容器也需要一个外部模板,也称为镜像,docker的镜像可以保存在一个公共的地方共享使用,只要把镜像下载下来就可以使用,最主要的是可以在镜像基础之上做自定义配置并且可以再把其提交为一个镜像,一个镜像可以被启动为多个容器。

docker的镜像是分层的,镜像底层为库文件且只读层即不能写入也不能删除数据,从镜像加载启动为一个容器后会生成一个可写层,其写入的数据会复制到宿主机上对应容器的目录,但是容器内的数据在删除容器后也会被随之删除。

pouch

https://github.com/alibaba/pouch

Pouch(小袋子)起源于2011年,并于2017年11月19日上午,在中国开源年会现场,阿里巴巴正式开源了基于Apache2.0协议的容器技术Pouch。Pouch是一款轻量级的容器技术,拥有快速高效、可移植性高、资源占用少等特性,主要帮助阿里更快的做到内部业务的交付,同时提高超大规模下数据中心的物理资源利用率

目前的容器方案大多基于Linux内核提供的cgroup和namespace来实现隔离,然后这样轻量级方案存在弊端:

  • 容器间,容器与宿主机间,共享一个内核
  • 内核实现的隔离资源,维度不足

面对如此的内核现状,阿里巴巴采取了三个方面的工作,来解决容器的安全问题:

  • 增强容器的隔离维度,比如网络带宽、磁盘使用量
  • 给内核提交patch,修复容器的资源可见性问题,cgroup方面的bug
  • 实现基于Hypervisor的容器,通过创建新内核来实现容器隔离
Podman

https://podman.io

虽然目前docker是管理Linux容器最好的耳工具,注意没有之一,但是podman的横空出现即将改变这一点

什么是Podman?

Podman即Pod Manager tool,从名称上可以看出和kubernets的pod的密切联系,不过就其功能来说,简言之:alias docker = podman,是centos8新集成的功能,或许不就的未来会替代docker

Podman是一个为Kubernetes而生的开源的容器管理工具,原来是CRI-O(即容器运行时接口CRI和开放容器计划OCI)项目的一部分,后来被分离成一个单独的项目叫libpod。其可在大多数Linux平台上使用,它是一种无守护程序的容器引擎,用于在Linux系统上开发,管理和运行任何符合Open Container Initiative(OCI)标准的容器和容器镜像。

Podman提供了一个与docker兼容的命令前端,Podman里面87%的指令都和docker cli相同,因此可以简单地为docker cli别名,即"alias docker = podman",事实上,podman使用的一些库也是docker的一部分。

Podman和docker不同之处
  • docker需要在系统上运行一个守护进程(docker daemon),这会产生一定的开销,而podman不需要
  • 启动容器的方式不同: docker cli 命令通过 API 跟 docker engine(引擎)交互告诉它我想创建一个 container,然后 docker engine 才会调用 OCI containner runtime(runc) 来启动一个container。这代表container的process(进程)不会是docker cli 的chlid process(子进程)而是Docker Engine 的 child process。Podman是直接给OCI container runtime(runc)进行交互来创建container的,所以container process 直接是podman的child process。
  • 因为docker有docker daemon,所以docker启动的容器支持 --restart策略,但是podman不支持
  • docker需要使用root用户来创建容器,这可能会产生安全风向,尤其是当用户知道docker run命令的 --privileged选项时。podman既可以由root用户运行,也可以由非特权用户运行
  • docker在Linux上作为守护进程运行扼杀了容器社区的创新。如果要更改容器的工作方式,则需要更改docker守护程序并将这些更改推送到上游。没有守护进程,容器基础结构更加模块化,更容易进行更改。podman的无守护进程架构更加灵活和安全。

Docker的优势

  • 快速部署:短时间内可以部署成百上千个应用,更快速交付到线上
  • 高效虚拟化:不需要额外hypervisor支持,基于Linux内核实现应用虚拟化,相比虚拟机大幅提高性能和效率
  • 节省开支:提高服务器利用率,降低IT支持
  • 简化配置:将运行环境打包保存至容器,使用时直接启动即可
  • 环境统一:将开发,测试,生产的应用运行环境进行标准化统一,减少环境不一样带来的各种问题
  • 快速迁移和扩展:可实现跨平台运行物理机、虚拟机、公有云等环境,良好的兼容性可以方便将应用从A宿主机迁移到B宿主机,甚至是A平台迁移到B平台
  • 更好的实现面向服务的架构,推荐一个容器只运行一个应用,实现分布的应用模型,可以方便的进行横向扩展,符合开发中高内聚,低耦合的要求,减少不同服务器之间的相互影响

Docker的缺点

  • 多个容器共用宿主机的内核,各应用之间的隔离不如虚拟机彻底
  • 由于和宿主机之间的进程也是隔离的,需要进入容器查看和调试容器内进程等资源,变得比较困难和繁琐
  • 如果容器内进程需要查看和调试,需要在每个容器内都需要安装相应的工具,这也造成存储空间的重复浪费

容器的核心技术

容器规范

OCI官网:https://opencontainers.org

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

容器runtime

runtime是真正运行容器的地方,因此为了运行不同的容器runtime需要和操作系统内核紧密合作相互在支持,以便为容器提供相应的运行环境

runtime类型:

  • LXC:Linux上早期的runtime,在2013年docker刚发布的时候,就是采用lxc作为runtime,docker把lxc复杂的容器创建与使用方式简化为docker自己的一套命令体系。随着docker的发展,原有的lxc不能满足docker的需求,比如跨平台功能
  • Libcontainer:随着docker的不断发展,重新定义容器的实现标准,将底层实现都抽象化到Libcontainer的接口。这就意味着,底层容器的实现方式变成了一种可变的方案,无论是使用namespace、cgroups技术抑或是使用systemd等其他方案,只要实现了Lincontainer定义的一组接口,docker都可以运行。这也为docker实现全面的跨平台带来了可能。
  • runc:早期libcontainer是docker公司控制的一个开源项目,OCI的成立后,docker把libcontainer项目移交给了OCI组织,runc就是在libcontainer的基础上进化而来,是目前docker默认的runtime,runc遵守OCI规范
  • 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 image):与docker image类似,是CoreOS开发的rkt容器的镜像格式

镜像仓库

统一保存镜像而且是多个不同镜像版本的地方,叫做镜像仓库

  • Docker hub:docker官方的公共仓库,已经保存了大量的常用镜像,可以方便大家直接使用
  • 阿里云,网易等第三方镜像的公共仓库
  • Image registry:docker官方提供的私有仓库部署工具,无web管理界面,目前使用较少
  • Harbor:vmware提供自带web界面自带认证功能的镜像私有仓库,目前有很多公司使用
容器编排工具

当多个容器在多个主机运行的时候,单独管理容器是相当复杂而且很容易出错,而且也无法实现某一台主机宕机后容器自动迁移到其他主机从而实现高可用的目的,也无法实现动态伸缩功能,因此需要有一种工具可以实现统一管理、动态伸缩、故障自愈、批量执行等功能,这就是容器编排引擎

容器编排通常包括容器管理、调度、集群定义和服务发现等功能

  • Docker compose:docker官方实现单机容器的编排工具
  • Docker swarm:docker官方开发的容器编排引擎,支持overlay network
  • Mesos+Marathon:Mesos是Apache下的开源分布式资源管理框架,它被称为是分布式系统的内核。Mesos最初是由加州大学伯克利分校的AMPLab开发的,后在Twitter得到广泛使用。通用的集群组员调度平台,Mesos(资源分配)与marathon(容器编排平台)一起提供容器编排引擎功能
  • Kubernetes:Google领导开发的容器编排引擎,内部项目为Borg,且其同时支持docker和CoreOS,当前已成为容器编排工具的标准
docker依赖的技术
容器网络

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

服务发现

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

容器监控

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

数据管理

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

日志收集

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

Docker安装及基础命令介绍

Docker安装准备

https://www.docker.com
OS版本的选择:

docker目前支持多种操作系统的安装运行,如Centos,Ubuntu,Redhat,Debian,Fedora,Mac,Windows,在Linux系统上需要内核版本在3.10或以上
docker版本选择:

docker版本号之前一直是0.x版本或1.x版本,从2017年3月1号开始改为每个季度发布一次稳定版,其版本号规则也统一变更为YY.MM,例如20.10表示2020年10月发布的

docker之前没有区分版本,但是2017年推出(将docker更名为)新的项目Moby,github地址:https://github.com/moby/moby ,Moby项目属于Docker项目全新上游,docker将是一个隶属于Moby的子产品,而且之后的版本开始区分CE(Docker Community Edition,社区版本)和EE(Docker Enterprise Edition,企业收费版),CE社区版和EE企业版都是每个季度发布一个新版本,但是EE版提供后期安全维护1年,而CE版是4个月。

安装和删除方法

官方文档:https://docs.docker.com/engine/install/

阿里云文档:https://developer.aliyun.com/mirror/docker-ce?spm=a2c6h.13651102.0.0.3e221b11guHCWE

Centos安装和删除docker

官方文档:https://docs.docker.com/engine/install/centos/

CentOS 6 因内核太旧,即使支持安装docker,但会有各种问题,不建议安装

CentOS 7的extras源虽然可以安装docker,但包比较旧,建议从官方源或镜像源站点下载安装docker

CentOS 8 有新技术podman代替docker

因此建议在CentOS 7 上安装 docker

shell 复制代码
# extras 源中包名为docker

[root@centos7 ~]# yum list docker

已加载插件:fastestmirror

Loading mirror speeds from cached hostfile

 * base: mirrors.bupt.edu.cn

 * extras: mirrors.neusoft.edu.cn

 * updates: mirrors.nju.edu.cn

可安装的软件包

docker.x86_64                                 2:1.13.1-209.git7d71120.el7.centos                                  extras
下载rpm包安装

官方rpm包下载地址:https://download.docker.com/linux/centos/7/x86_64/stable/Packages/

阿里镜像下载地址:https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages/

通过yum源安装:

由于官网yum源太慢,下面使用阿里云的yum源进行安装

shell 复制代码
rm -rf /etc/yum.repos.d/*



# centos 7 安装docker依赖三个yum源:Base,Extras,docker-ce

wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo



yum clean all

yum install docker-ce -y

systemctl enable --now docker
删除docker
shell 复制代码
yum remove docker-ce



# 删除docker资源存放的相关文件

rm -ef /var/lib/docker
Docker 程序环境

Centos7 查看docker相关文件

shell 复制代码
[root@centos ~]# rpm -ql docker-ce

/usr/bin/docker-init

/usr/bin/docker-proxy

/usr/bin/dockerd

/usr/lib/systemd/system/docker.service

/usr/lib/systemd/system/docker.socket

[root@centos ~]#

[root@centos ~]# rpm -ql docker-ce

/usr/bin/docker-init

/usr/bin/docker-proxy

/usr/bin/dockerd

/usr/lib/systemd/system/docker.service

/usr/lib/systemd/system/docker.socket

[root@centos ~]#

[root@centos ~]# rpm -ql docker-ce-cli

/usr/bin/docker

/usr/libexec/docker/cli-plugins/docker-app

/usr/libexec/docker/cli-plugins/docker-buildx

/usr/share/bash-completion/completions/docker

/usr/share/doc/docker-ce-cli-20.10.17

/usr/share/doc/docker-ce-cli-20.10.17/LICENSE

/usr/share/doc/docker-ce-cli-20.10.17/MAINTAINERS

/usr/share/doc/docker-ce-cli-20.10.17/NOTICE

/usr/share/doc/docker-ce-cli-20.10.17/README.md

/usr/share/fish/vendor_completions.d/docker.fish

/usr/share/man/man1/docker-attach.1.gz

/usr/share/man/man1/docker-build.1.gz

/usr/share/man/man1/docker-builder-build.1.gz

/usr/share/man/man1/docker-builder-prune.1.gz

/usr/share/man/man1/docker-builder.1.gz

/usr/share/man/man1/docker-checkpoint-create.1.gz

/usr/share/man/man1/docker-checkpoint-ls.1.gz

/usr/share/man/man1/docker-checkpoint-rm.1.gz

/usr/share/man/man1/docker-checkpoint.1.gz

/usr/share/man/man1/docker-commit.1.gz

/usr/share/man/man1/docker-config-create.1.gz

/usr/share/man/man1/docker-config-inspect.1.gz

/usr/share/man/man1/docker-config-ls.1.gz

/usr/share/man/man1/docker-config-rm.1.gz

/usr/share/man/man1/docker-config.1.gz

/usr/share/man/man1/docker-container-attach.1.gz

/usr/share/man/man1/docker-container-commit.1.gz

/usr/share/man/man1/docker-container-cp.1.gz

/usr/share/man/man1/docker-container-create.1.gz

/usr/share/man/man1/docker-container-diff.1.gz

/usr/share/man/man1/docker-container-exec.1.gz

/usr/share/man/man1/docker-container-export.1.gz

/usr/share/man/man1/docker-container-inspect.1.gz

/usr/share/man/man1/docker-container-kill.1.gz

/usr/share/man/man1/docker-container-logs.1.gz

/usr/share/man/man1/docker-container-ls.1.gz

/usr/share/man/man1/docker-container-pause.1.gz

/usr/share/man/man1/docker-container-port.1.gz

/usr/share/man/man1/docker-container-prune.1.gz

/usr/share/man/man1/docker-container-rename.1.gz

/usr/share/man/man1/docker-container-restart.1.gz

/usr/share/man/man1/docker-container-rm.1.gz

/usr/share/man/man1/docker-container-run.1.gz

/usr/share/man/man1/docker-container-start.1.gz

/usr/share/man/man1/docker-container-stats.1.gz

/usr/share/man/man1/docker-container-stop.1.gz

/usr/share/man/man1/docker-container-top.1.gz

/usr/share/man/man1/docker-container-unpause.1.gz

/usr/share/man/man1/docker-container-update.1.gz

/usr/share/man/man1/docker-container-wait.1.gz

/usr/share/man/man1/docker-container.1.gz

/usr/share/man/man1/docker-context-create.1.gz

/usr/share/man/man1/docker-context-export.1.gz

/usr/share/man/man1/docker-context-import.1.gz

/usr/share/man/man1/docker-context-inspect.1.gz

/usr/share/man/man1/docker-context-ls.1.gz

/usr/share/man/man1/docker-context-rm.1.gz

/usr/share/man/man1/docker-context-update.1.gz

/usr/share/man/man1/docker-context-use.1.gz

/usr/share/man/man1/docker-context.1.gz

/usr/share/man/man1/docker-cp.1.gz

/usr/share/man/man1/docker-create.1.gz

/usr/share/man/man1/docker-diff.1.gz

/usr/share/man/man1/docker-events.1.gz

/usr/share/man/man1/docker-exec.1.gz

/usr/share/man/man1/docker-export.1.gz

/usr/share/man/man1/docker-history.1.gz

/usr/share/man/man1/docker-image-build.1.gz

/usr/share/man/man1/docker-image-history.1.gz

/usr/share/man/man1/docker-image-import.1.gz

/usr/share/man/man1/docker-image-inspect.1.gz

/usr/share/man/man1/docker-image-load.1.gz

/usr/share/man/man1/docker-image-ls.1.gz

/usr/share/man/man1/docker-image-prune.1.gz

/usr/share/man/man1/docker-image-pull.1.gz

/usr/share/man/man1/docker-image-push.1.gz

/usr/share/man/man1/docker-image-rm.1.gz

/usr/share/man/man1/docker-image-save.1.gz

/usr/share/man/man1/docker-image-tag.1.gz

/usr/share/man/man1/docker-image.1.gz

/usr/share/man/man1/docker-images.1.gz

/usr/share/man/man1/docker-import.1.gz

/usr/share/man/man1/docker-info.1.gz

/usr/share/man/man1/docker-inspect.1.gz

/usr/share/man/man1/docker-kill.1.gz

/usr/share/man/man1/docker-load.1.gz

/usr/share/man/man1/docker-login.1.gz

/usr/share/man/man1/docker-logout.1.gz

/usr/share/man/man1/docker-logs.1.gz

/usr/share/man/man1/docker-manifest-annotate.1.gz

/usr/share/man/man1/docker-manifest-create.1.gz

/usr/share/man/man1/docker-manifest-inspect.1.gz

/usr/share/man/man1/docker-manifest-push.1.gz

/usr/share/man/man1/docker-manifest-rm.1.gz

/usr/share/man/man1/docker-manifest.1.gz

/usr/share/man/man1/docker-network-connect.1.gz

/usr/share/man/man1/docker-network-create.1.gz

/usr/share/man/man1/docker-network-disconnect.1.gz

/usr/share/man/man1/docker-network-inspect.1.gz

/usr/share/man/man1/docker-network-ls.1.gz

/usr/share/man/man1/docker-network-prune.1.gz

/usr/share/man/man1/docker-network-rm.1.gz

/usr/share/man/man1/docker-network.1.gz

/usr/share/man/man1/docker-node-demote.1.gz

/usr/share/man/man1/docker-node-inspect.1.gz

/usr/share/man/man1/docker-node-ls.1.gz

/usr/share/man/man1/docker-node-promote.1.gz

/usr/share/man/man1/docker-node-ps.1.gz

/usr/share/man/man1/docker-node-rm.1.gz

/usr/share/man/man1/docker-node-update.1.gz

/usr/share/man/man1/docker-node.1.gz

/usr/share/man/man1/docker-pause.1.gz

/usr/share/man/man1/docker-plugin-create.1.gz

/usr/share/man/man1/docker-plugin-disable.1.gz

/usr/share/man/man1/docker-plugin-enable.1.gz

/usr/share/man/man1/docker-plugin-inspect.1.gz

/usr/share/man/man1/docker-plugin-install.1.gz

/usr/share/man/man1/docker-plugin-ls.1.gz

/usr/share/man/man1/docker-plugin-push.1.gz

/usr/share/man/man1/docker-plugin-rm.1.gz

/usr/share/man/man1/docker-plugin-set.1.gz

/usr/share/man/man1/docker-plugin-upgrade.1.gz

/usr/share/man/man1/docker-plugin.1.gz

/usr/share/man/man1/docker-port.1.gz

/usr/share/man/man1/docker-ps.1.gz

/usr/share/man/man1/docker-pull.1.gz

/usr/share/man/man1/docker-push.1.gz

/usr/share/man/man1/docker-rename.1.gz

/usr/share/man/man1/docker-restart.1.gz

/usr/share/man/man1/docker-rm.1.gz

/usr/share/man/man1/docker-rmi.1.gz

/usr/share/man/man1/docker-run.1.gz

/usr/share/man/man1/docker-save.1.gz

/usr/share/man/man1/docker-search.1.gz

/usr/share/man/man1/docker-secret-create.1.gz

/usr/share/man/man1/docker-secret-inspect.1.gz

/usr/share/man/man1/docker-secret-ls.1.gz

/usr/share/man/man1/docker-secret-rm.1.gz

/usr/share/man/man1/docker-secret.1.gz

/usr/share/man/man1/docker-service-create.1.gz

/usr/share/man/man1/docker-service-inspect.1.gz

/usr/share/man/man1/docker-service-logs.1.gz

/usr/share/man/man1/docker-service-ls.1.gz

/usr/share/man/man1/docker-service-ps.1.gz

/usr/share/man/man1/docker-service-rm.1.gz

/usr/share/man/man1/docker-service-rollback.1.gz

/usr/share/man/man1/docker-service-scale.1.gz

/usr/share/man/man1/docker-service-update.1.gz

/usr/share/man/man1/docker-service.1.gz

/usr/share/man/man1/docker-stack-deploy.1.gz

/usr/share/man/man1/docker-stack-ls.1.gz

/usr/share/man/man1/docker-stack-ps.1.gz

/usr/share/man/man1/docker-stack-rm.1.gz

/usr/share/man/man1/docker-stack-services.1.gz

/usr/share/man/man1/docker-stack.1.gz

/usr/share/man/man1/docker-start.1.gz

/usr/share/man/man1/docker-stats.1.gz

/usr/share/man/man1/docker-stop.1.gz

/usr/share/man/man1/docker-swarm-ca.1.gz

/usr/share/man/man1/docker-swarm-init.1.gz

/usr/share/man/man1/docker-swarm-join-token.1.gz

/usr/share/man/man1/docker-swarm-join.1.gz

/usr/share/man/man1/docker-swarm-leave.1.gz

/usr/share/man/man1/docker-swarm-unlock-key.1.gz

/usr/share/man/man1/docker-swarm-unlock.1.gz

/usr/share/man/man1/docker-swarm-update.1.gz

/usr/share/man/man1/docker-swarm.1.gz

/usr/share/man/man1/docker-system-df.1.gz

/usr/share/man/man1/docker-system-events.1.gz

/usr/share/man/man1/docker-system-info.1.gz

/usr/share/man/man1/docker-system-prune.1.gz

/usr/share/man/man1/docker-system.1.gz

/usr/share/man/man1/docker-tag.1.gz

/usr/share/man/man1/docker-top.1.gz

/usr/share/man/man1/docker-trust-inspect.1.gz

/usr/share/man/man1/docker-trust-key-generate.1.gz

/usr/share/man/man1/docker-trust-key-load.1.gz

/usr/share/man/man1/docker-trust-key.1.gz

/usr/share/man/man1/docker-trust-revoke.1.gz

/usr/share/man/man1/docker-trust-sign.1.gz

/usr/share/man/man1/docker-trust-signer-add.1.gz

/usr/share/man/man1/docker-trust-signer-remove.1.gz

/usr/share/man/man1/docker-trust-signer.1.gz

/usr/share/man/man1/docker-trust.1.gz

/usr/share/man/man1/docker-unpause.1.gz

/usr/share/man/man1/docker-update.1.gz

/usr/share/man/man1/docker-version.1.gz

/usr/share/man/man1/docker-volume-create.1.gz

/usr/share/man/man1/docker-volume-inspect.1.gz

/usr/share/man/man1/docker-volume-ls.1.gz

/usr/share/man/man1/docker-volume-prune.1.gz

/usr/share/man/man1/docker-volume-rm.1.gz

/usr/share/man/man1/docker-volume.1.gz

/usr/share/man/man1/docker-wait.1.gz

/usr/share/man/man1/docker.1.gz

/usr/share/man/man5/Dockerfile.5.gz

/usr/share/man/man5/docker-config-json.5.gz

/usr/share/man/man8/dockerd.8.gz

/usr/share/zsh/vendor-completions/_docker
Docker 命令帮助

官方文档:https://docs.docker.com/reference/

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

shell 复制代码
# docker 命令格式

# COMMAND 分为 

# Management Commands 指定管理员的资源对象类型,较新的命令用法,将命令按资源类型进行分类,方便使用

# Commands 对不同资源操作的命令不分类,使用容易产生混乱

docker [OPTIONS] COMMAND



# docker 命令有很多子命令,可以用下面方法查看帮助

# docker 命令帮助

man docker

docker

docker --help



# docker 子命令帮助

man docker -COMMAND

docker COMMAND --help
查看docker相关信息
查看docker版本
shell 复制代码
[root@centos ~]# docker version

Client: Docker Engine - Community

 Version:           20.10.17

 API version:       1.41

 Go version:        go1.17.11

 Git commit:        100c701

 Built:             Mon Jun  6 23:05:12 2022

 OS/Arch:           linux/amd64

 Context:           default

 Experimental:      true



Server: Docker Engine - Community

 Engine:

  Version:          20.10.17

  API version:      1.41 (minimum version 1.12)

  Go version:       go1.17.11

  Git commit:       a89b842

  Built:            Mon Jun  6 23:03:33 2022

  OS/Arch:          linux/amd64

  Experimental:     false

 containerd:

  Version:          1.6.7

  GitCommit:        0197261a30bf81f1ee8e6a4dd2dea0ef95d67ccb

 runc:

  Version:          1.1.3

  GitCommit:        v1.1.3-0-g6724737

 docker-init:

  Version:          0.19.0

  GitCommit:        de40ad0
查看docker详细信息
shell 复制代码
[root@centos ~]# docker info
Client:
 Context:    default
 Debug Mode: false # client端是否开启debug
 Plugins:
  app: Docker App (Docker Inc., v0.9.1-beta3)
  buildx: Docker Buildx (Docker Inc., v0.8.2-docker)
  scan: Docker Scan (Docker Inc., v0.17.0)

Server:
 Containers: 0 # 当前主机运行的容器总数
  Running: 0	 # 正在运行的容器个数
  Paused: 0	   # 暂停的容器个数
  Stopped: 0   # 停止的容器个数
 Images: 0     # 当前服务器的镜像个数
 Server Version: 20.10.17    # 服务端版本
 Storage Driver: overlay2    # 正在使用的存储引擎
  Backing Filesystem: xfs    # 后端文件系统,即服务器的磁盘文件系统
  Supports d_type: true      # 是否支持 d_type
  Native Overlay Diff: true  # 是否支持差异数据存储
  userxattr: false
 Logging Driver: json-file   # 日志类型
 Cgroup Driver: cgroupfs		 # Cgroups类型
 Cgroup Version: 1
 Plugins:										 # 插件
  Volume: local							 # 卷
  Network: bridge host ipvlan macvlan null overlay    # overlay 跨主机通信
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog # 日志类型
 Swarm: inactive						 # 是否支持 swarm
 Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
 Default Runtime: runc       # 默认使用的容器运行时
 Init Binary: docker-init    # 初始化容器的守护进程,即pid为1的进程
 containerd version: 0197261a30bf81f1ee8e6a4dd2dea0ef95d67ccb # 版本
 runc version: v1.1.3-0-g6724737	# runc版本
 init version: de40ad0			 # init 版本
 Security Options:           # 安全选项
  seccomp                    # 安全计算模块,即制容器操作
   Profile: default					 # 默认的配置文件
 Kernel Version: 3.10.0-693.el7.x86_64    # 宿主机内核版本
 Operating System: CentOS Linux 7 (Core)  # 宿主机操作系统
 OSType: linux														# 宿主机操作系统类型
 Architecture: x86_64											# 宿主机架构
 CPUs: 2																	# 宿主机CPU数量
 Total Memory: 1.792GiB										# 宿主机总内存
 Name: centos															# 宿主机 hostname
 ID: E66M:LPI3:YB2Z:LJKN:LNB2:P7Z3:6HYX:DSFF:KISM:SSJX:PVIF:B2ZM  # 宿主机 ID
 Docker Root Dir: /var/lib/docker				# 宿主机关于docker数据的保存目录
 Debug Mode: false											# server 端是否开启debug
 Registry: https://index.docker.io/v1/	# 仓库路径
 Labels:
 Experimental: false										# 是否是测试版
 Insecure Registries:	
  127.0.0.0/8														# 非安全的镜像库
 Live Restore Enabled: false            # 是否开启活动重启 (重启docker-daemon 不关闭容器)
查看docker0网卡

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

Docker存储引擎
  • AUFS是一种UnionFs,是文件级的存储驱动。Aufs是之前的UnionFS的重新实现,2006年由JunjiroOkajima开发,所谓UnionFS就是把不同物理位置的目录合并mount到同一个目录中。简单来说就是支持将不同目录挂载到一个虚拟文件系统下。这种可以层层地叠加修改文件。无论底下有多少都是只读的,最上系统可写的。当需要修改一个文件时,AUFS常见该文件的一个副本,使用CoW将文件从只读层复制到可写进行修改,结果也保存在Docker中,底下的只读层就是image,可写层就是Container。aufs被拒绝合并到主线Linux。其代码被批评为"dense,unreadable,uncommented 密集、不可读、未注释"。相反,OverlayFS被合并到Linux内核中。在多次尝试将aufs合并到主线内核失败后,作者放弃了AUFS是docker18.06及更早版本的首选存储驱动程序,在内核3.13上运行ubuntu14.04时不支持overlay2
  • Overlay:一种UnionFS文件系统,Linux内核3.18后支持
  • Overlay2:Overlay的升级版,到目前为止,所有Linux发行版推荐使用的存储类型,也是docker默认使用的存储引擎为overlay2,需要磁盘分区支持d-type功能,因此需要系统磁盘的额外支持,相对AUFS来说Overlay2有以下优势:更简单的设计;从3.18开始就进入了Linux内核主线;资源消耗更少
  • devicemapper:因为Centos7.2和RHEL7.2的之前版本内核版本不支持overlay2,默认使用的存储驱动程序,最大数据容量只支持100G且性能不佳,当前较新版本的CentOS已经支持overlay2,因此推荐使用overlay2,另外此存储引擎已在Docker Engine 18.09中弃用
  • ZFS(Sun-2005)/btrfs(Oracle-2007):目前没有广泛使用
  • VFS:用于测试环境,适用于无法使用copy-on-write时的情况。此存储驱动程序的性能很差,通常不建议用于生产

Docker官方推荐首选存储引擎为overlay2,其次为devicemapper,但是devicemapper存在使用空间方面的一些限制,虽然可以通过后期配置解决,但是官方依然推荐使用overlay2,以下是生产故障示例:https://www.cnblogs.com/youruncloud/p/5736718.html

docker服务进程

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

docker的进程关系

docker相关的四个进程:

  • dockerd:服务器程序,被client直接访问,其父进程为宿主机的systemd守护进程
  • docker-proxy:每个进程docker-proxy实现对应一个需要网络通信的容器,管理宿主机和容器之间端口映射,其父进程为dockerd,如果容器不需要网络则无需启动
  • containerd:被dockerd进程调用以实现与runc交互
  • containerd-shim:真正运行容器的载体,每个容器对应一个containerd-shim进程,其父进程为containerd
容器的创建与管理过程

通信流程:

1.dockerd通过grpc和containerd模块通信,dockerd由libcontainerd负责和containerd进行交换,docker和containerd通信socket文件:/run/containerd/containerd.sock

2.containerd在docker启动时被启动,然后containerd启动grpc请求监听,containerd处理grpc请求,根据请求做相应动作

3.若是run,start或是exec容器,containerd拉起一个container-shim,并进行相应的操作

4.container-shim被拉起后,start/exec/create拉起runc进程,通过exit、control文件和containerd通信,通过父子进程关系和SIGCHLD监控容器中进程状态

5.在整个容器生命周期中,container通过epoll监控容器文件,监控容器事件

gRPC简介

官网:https://www.grpc.io

gRPC是Google开发的一款高性能、开源和通用的RPC框架,支持众多语言客户端

Docker 服务管理

docker服务基于C/S结构,可以实现基于本地和远程方式进行管理

shell 复制代码
# Dockerd守护进程启动选项
-H tcp://host:port
	 unix:///path/to/socket,
	 fd://* or fd://socketfd

# 守护进程默认配置
-H unix:///var/run/docker.sock

# 使用Docker客户端命令选项
-H tcp://host:port
   unix:///path/to/socket,
   fd://* or fd://socketfd

# 客户端默认配置:
-H unix:///var/run/docker.sock

# docker客户端也可以使用环境变量DOCKER_HOST,代替 -H选项
export DOCKER_HOST="tcp://docker-server:2375"

镜像管理

镜像结构和原理

镜像即创建容器的模板,含有启动容器所需要的文件系统及所需要的内容,因此镜像主要用于方便和快速的创建启动容器。

镜像里面是一层层的文件系统,叫做Union FS(联合文件系统),联合文件系统,可以将几层目录挂载到一起(就想千层饼,洋葱头,俄罗斯套娃一样),形成一个虚拟文件系统,虚拟文件系统的目录结构就像普通Linux的目录结构一样,镜像通过这些文件再加上宿主机的内核共同提供了一个Linux的虚拟环境,每一层文件系统叫做一层layer,联合文件系统可以对每一层文件系统设置三种权限,只读(readonly)、读写(readwrite)、和写出(whiteout-able),但是镜像中每一层文件系统都是只读的,构建镜像的时候,从一个最基本的操作系统开始,每个构建提交的操作都相当于做一层的修改,增加了一层文件系统,一层层往上叠加,上层的修改会覆盖底层该位置的可见性,这也很容易理解,就像上层把底层遮住了一样,当使用镜像的时候,我们只会看到一个完全的整体,不知道里面有几层。

一个典型的Linux文件系统由bootfs和rootfs两部分组成

bootfs(boot file system)主要包含bootloader和kernel,bootloader主要用于引导加载kernel,Linux刚启动时会加载bootfs文件系统,当boot加载完后,kernel被加载到内存中后接管系统的控制权,bootfs会被umount掉

rootfs(root file system)包含的就是典型Linux系统中的 /dev,/proc,/bin,/etc等标准目录和文件,不同的Linux发行版(如ubuntu 和 CentOS)主要在rootfs这一层会有所区别。

一般的镜像通常都比较小,官方提供的Ubuntu镜像只有60M多点,而CentOS基础镜像也只有200M左右,一些其他版本的镜像甚至只有几M,比如:busybox 才1.22M,Alpine镜像也只有5M左右。镜像直接调用宿主机的内核,镜像中提供rootfs,也就是只需要包括最基本的命令,配置文件和程序库等相关文件就可以了。

容器、镜像和父镜像关系

查看镜像的分层结构

shell 复制代码
[root@centos7 ~]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
1efc276f4ff9: Pull complete
baf2da91597d: Pull complete
05396a986fd3: Pull complete
6a17c8e7063d: Pull complete
27e0d286aeab: Pull complete
b1349eea8fc5: Pull complete
Digest: sha256:790711e34858c9b0741edffef6ed3d8199d8faa33f2870dea5db70f16384df79
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

# 查看镜像分层历史
[root@centos7 ~]# docker image history nginx
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
b692a91e4e15   2 weeks ago   /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon...   0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  STOPSIGNAL SIGQUIT           0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  EXPOSE 80                    0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  ENTRYPOINT ["/docker-entr...   0B
<missing>      2 weeks ago   /bin/sh -c #(nop) COPY file:09a214a3e07c919a...   4.61kB
<missing>      2 weeks ago   /bin/sh -c #(nop) COPY file:0fd5fca330dcd6a7...   1.04kB
<missing>      2 weeks ago   /bin/sh -c #(nop) COPY file:0b866ff3fc1ef5b0...   1.96kB
<missing>      2 weeks ago   /bin/sh -c #(nop) COPY file:65504f71f5855ca0...   1.2kB
<missing>      2 weeks ago   /bin/sh -c set -x     && addgroup --system -...   61.1MB
<missing>      2 weeks ago   /bin/sh -c #(nop)  ENV PKG_RELEASE=1~bullseye   0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  ENV NJS_VERSION=0.7.6        0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  ENV NGINX_VERSION=1.23.1     0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  LABEL maintainer=NGINX Do...   0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>      2 weeks ago   /bin/sh -c #(nop) ADD file:0eae0dca665c7044b...   80.4MB

[root@centos7 ~]# docker inspect nginx
[
    {
        "Id": "sha256:b692a91e4e1582db97076184dae0b2f4a7a86b68c4fe6f91affa50ae06369bf5",
        "RepoTags": [
            "nginx:latest"
        ],
        "RepoDigests": [
            "nginx@sha256:790711e34858c9b0741edffef6ed3d8199d8faa33f2870dea5db70f16384df79"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2022-08-02T05:17:19.274343015Z",
        "Container": "5f19bc2cd794cd60ec845cbed7a60c85003dc56f26ee807f9eea2480bc465b76",
        "ContainerConfig": {
            "Hostname": "5f19bc2cd794",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.23.1",
                "NJS_VERSION=0.7.6",
                "PKG_RELEASE=1~bullseye"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"nginx\" \"-g\" \"daemon off;\"]"
            ],
            "Image": "sha256:0417134432daa8913f92f7bf71641a8fa7ab3405c91b717dde22c855e71eef4d",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
            },
            "StopSignal": "SIGQUIT"
        },
        "DockerVersion": "20.10.12",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.23.1",
                "NJS_VERSION=0.7.6",
                "PKG_RELEASE=1~bullseye"
            ],
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
            "Image": "sha256:0417134432daa8913f92f7bf71641a8fa7ab3405c91b717dde22c855e71eef4d",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
            },
            "StopSignal": "SIGQUIT"
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 141538863,
        "VirtualSize": 141538863,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/65721405d33c804de8b1ce344e01ea1cb20a15b526846ddd0914236141d12a74/diff:/var/lib/docker/overlay2/769ff70d994c30f2c3aca1a752b6320d7908f4a7aebd56ef58557b9d39cb3170/diff:/var/lib/docker/overlay2/ecbbdc176f03365bcf157e7409d045d16173793abb43d908328c28aa5235af85/diff:/var/lib/docker/overlay2/14a39e34b10a24fab8c7dccff4a3fcd34bdede808fda2921fcb2c033b1871e92/diff:/var/lib/docker/overlay2/3826983a7f0fa4365113c866622eb0af797919100279ba1db6bdd352330e4699/diff",
                "MergedDir": "/var/lib/docker/overlay2/7194cc85a5c2bf12f4d2fb0e2c57ff356c47981bda94be0e9bcf503391080797/merged",
                "UpperDir": "/var/lib/docker/overlay2/7194cc85a5c2bf12f4d2fb0e2c57ff356c47981bda94be0e9bcf503391080797/diff",
                "WorkDir": "/var/lib/docker/overlay2/7194cc85a5c2bf12f4d2fb0e2c57ff356c47981bda94be0e9bcf503391080797/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:92a4e8a3140f7a04a0e5a15793adef2d0e8889ed306a8f95a6cfb67cecb5f212",
                "sha256:e3257a399753c995f54856b0cea3c2b6aa1a95d9a7b542668a46fa4eacf62d53",
                "sha256:3a89c8160a43d70433241934b1d418f641e6d207a10b558b67f8aafdb15416b0",
                "sha256:f91d0987b144553456431bcb8cc8ddf5d03362701bc2ffc128ce2bd57182defb",
                "sha256:bdc7a32279ccdf5aba13d3e50b7b16103e03ff8ef27424ac1a33df24e5a9f602",
                "sha256:b539cf60d7bb42871a005e949b550800b99fada0b1c1bca01654e8a506ba2138"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]
[root@centos7 ~]# docker save nginx -o nginx.tar
[root@centos7 ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    b692a91e4e15   2 weeks ago   142MB
[root@centos7 ~]# ll -h nginx.tar
-rw------- 1 root root 140M 8月  22 23:00 nginx.tar

[root@centos7 ~]# mkdir data
[root@centos7 ~]# tar -xf nginx.tar -C data/
[root@centos7 ~]# ll data/
总用量 16
drwxr-xr-x 2 root root   50 8月   2 13:17 0b71b9002c2056073a621264c914f1778296599761548ff1e34d39dc883ed029
drwxr-xr-x 2 root root   50 8月   2 13:17 19dee729285a1f8f34b15874db48c7b4b60f6041914f2cad9b1de169795de836
drwxr-xr-x 2 root root   50 8月   2 13:17 1c65531519b901e0508c411808f7dc2497a6549926bda748896f59aaddc4eed4
drwxr-xr-x 2 root root   50 8月   2 13:17 6387aff546d7c159c6e082ea910391bc9c331ff19f75c73d45780def09a8c989
drwxr-xr-x 2 root root   50 8月   2 13:17 75e6a412e4bda1a8b9e5690c6f8c218c0649ca965207ff15f4f2e114e859ec86
-rw-r--r-- 1 root root 7653 8月   2 13:17 b692a91e4e1582db97076184dae0b2f4a7a86b68c4fe6f91affa50ae06369bf5.json
drwxr-xr-x 2 root root   50 8月   2 13:17 e9bee565b6a50b23d35427abf3f6756a842c5d75d3c8e3d63f412cb3dae90409
-rw-r--r-- 1 root root  586 1月   1 1970 manifest.json
-rw-r--r-- 1 root root   88 1月   1 1970 repositories

[root@centos7 ~]# cat data/manifest.json
[{"Config":"b692a91e4e1582db97076184dae0b2f4a7a86b68c4fe6f91affa50ae06369bf5.json","RepoTags":["nginx:latest"],"Layers":["1c65531519b901e0508c411808f7dc2497a6549926bda748896f59aaddc4eed4/layer.tar","e9bee565b6a50b23d35427abf3f6756a842c5d75d3c8e3d63f412cb3dae90409/layer.tar","6387aff546d7c159c6e082ea910391bc9c331ff19f75c73d45780def09a8c989/layer.tar","75e6a412e4bda1a8b9e5690c6f8c218c0649ca965207ff15f4f2e114e859ec86/layer.tar","0b71b9002c2056073a621264c914f1778296599761548ff1e34d39dc883ed029/layer.tar","19dee729285a1f8f34b15874db48c7b4b60f6041914f2cad9b1de169795de836/layer.tar"]}]

[root@centos7 ~]# du -sh data/*
12K	data/0b71b9002c2056073a621264c914f1778296599761548ff1e34d39dc883ed029
16K	data/19dee729285a1f8f34b15874db48c7b4b60f6041914f2cad9b1de169795de836
80M	data/1c65531519b901e0508c411808f7dc2497a6549926bda748896f59aaddc4eed4
12K	data/6387aff546d7c159c6e082ea910391bc9c331ff19f75c73d45780def09a8c989
12K	data/75e6a412e4bda1a8b9e5690c6f8c218c0649ca965207ff15f4f2e114e859ec86
8.0K	data/b692a91e4e1582db97076184dae0b2f4a7a86b68c4fe6f91affa50ae06369bf5.json
60M	data/e9bee565b6a50b23d35427abf3f6756a842c5d75d3c8e3d63f412cb3dae90409
4.0K	data/manifest.json
4.0K	data/repositories

搜索镜像

官网:https://hub.docker.com

执行docker search命令进行搜索
powershell 复制代码
Usage:	docker search [OPTIONS] TERM

Options:
	-f, --filter filter		Filter output based on conditions provided
			--format string		Pretty-print search using a Go template
			--limit int				Max number of search results	(default 25)
			
说明:
OFFICIAL:官方
AUTOMATED:使用第三方docker服务来帮助编译镜像,可以在互联网上面直接拉取到镜像,减少了繁琐的编译过程

例:查找centos镜像

shell 复制代码
[root@centos7 ~]# docker search centos
NAME                                         DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
centos                                       The official build of CentOS.                   7288      [OK]
kasmweb/centos-7-desktop                     CentOS 7 desktop for Kasm Workspaces            24
couchbase/centos7-systemd                    centos7-systemd images with additional debug...   4                    [OK]
dokken/centos-7                              CentOS 7 image for kitchen-dokken               3
continuumio/centos5_gcc5_base                                                                3
dokken/centos-stream-9                                                                       2
dokken/centos-stream-8                                                                       2
spack/centos7                                CentOS 7 with Spack preinstalled                1
spack/centos6                                CentOS 6 with Spack preinstalled                1
datadog/centos-i386                                                                          0
dokken/centos-6                              CentOS 6 image for kitchen-dokken               0
ustclug/centos                               Official CentOS Image with USTC Mirror          0
dokken/centos-8                              CentOS 8 image for kitchen-dokken               0
corpusops/centos-bare                        https://github.com/corpusops/docker-images/     0
bitnami/centos-extras-base                                                                   0
corpusops/centos                             centos corpusops baseimage                      0
couchbase/centos-72-java-sdk                                                                 0
couchbase/centos-72-jenkins-core                                                             0
couchbase/centos-70-sdk-build                                                                0
bitnami/centos-base-buildpack                Centos base compilation image                   0                    [OK]
couchbase/centos-69-sdk-nodevtoolset-build                                                   0
fnndsc/centos-python3                        Source for a slim Centos-based Python3 image...   0                    [OK]
couchbase/centos-69-sdk-build                                                                0
dokken/centos-5                              EOL DISTRO: For use with kitchen-dokken, Bas...   0
spack/centos-stream                                                                          0

搜索点赞100个以上的镜像

shell 复制代码
[root@centos7 ~]# docker search --filter=stars=100 centos
NAME      DESCRIPTION                     STARS     OFFICIAL   AUTOMATED
centos    The official build of CentOS.   7288      [OK]

alpine介绍

Alpine操作系统是一个面向安全的轻型Linux发行版。它不同于通常Linux发行版Alpine采用了musl libc 和 busybox以减小系统的体积和运行时资源消耗,但功能上比busybox又完善的多,因此得到开源社区越来也多的青睐。在保持瘦身的同时,Alpine还提供了自己的包管理工具apk,可以通过https://pkgs.alpinelinux.org/packages 查询包信息,也可以直接通过apk命令直接查询和安装各种软件。

Alpine由非商业组织维护的,支持广泛场景的Linux发行版,它特别为资深/重度Linux用户而优化,关注安全,性能和资源效能。Alpine镜像可以适用于更多常用场景,并且是一个优秀的可以适用于生产的基础系统/环境。

Alpine Docker镜像也继承了Alpine Linux发行版的这些优势。相比于其他Docker镜像,它的容量非常小,仅仅只有5M左右,且拥有非常友好的包管理机制。官方镜像来自docker-alpine项目。

目前Docker官方已开始推荐使用Alpine替代之前的Ubuntu作为基础镜像环境。这样会带来多个好处。包括镜像下载速度加快,镜像安全性提高,主机之间的切换更方便,占用更少磁盘空间等。

下表是官方镜像的大小比较

shell 复制代码
REPOSITORY   TAG       IMAGE ID       CREATED                  SIZE
debian       latest    dd8bae8d259f   Less than a second ago   124MB
alpine       latest    9c6f07244728   12 days ago              5.54MB
ubuntu       latest    df5de72bdb3b   2 weeks ago              77.8MB
centos       latest    5d0da3dc9764   11 months ago            231MB
alpine管理软件
shell 复制代码
# 修改源替换成阿里源,将里面 dl-cdn.alpinelinux.org 改成 mirrors.aliyun.com
vi /etc/apk/repositories
https://mirrors.aliyun.com/alpine/v3.16/main
https://mirrors.aliyun.com/alpine/v3.16/community

# 更新源
apk update

# 安装软件
apk add vim 

# 删除软件
apk del openssh openntp vim

例:

shell 复制代码
/ # apk --help
apk-tools 2.12.9, compiled for x86_64.

usage: apk [<OPTIONS>...] COMMAND [<ARGUMENTS>...]

Package installation and removal:
  add        Add packages to WORLD and commit changes
  del        Remove packages from WORLD and commit changes

System maintenance:
  fix        Fix, reinstall or upgrade packages without modifying WORLD
  update     Update repository indexes
  upgrade    Install upgrades available from repositories
  cache      Manage the local package cache

Querying package information:
  info       Give detailed information about packages or repositories
  list       List packages matching a pattern or other criteria
  dot        Render dependencies as graphviz graphs
  policy     Show repository policy for packages
  search     Search for packages by name or description

Repository maintenance:
  index      Create repository index file from packages
  fetch      Download packages from global repositories to a local directory
  manifest   Show checksums of package contents
  verify     Verify package integrity and signature

Miscellaneous:
  audit      Audit system for changes
  stats      Show statistics about repositories and installations
  version    Compare package versions or perform tests on version strings

This apk has coffee making abilities.
For more information: man 8 apk

/ # apk add nginx
(1/2) Installing pcre (8.45-r2)
(2/2) Installing nginx (1.22.0-r1)
Executing nginx-1.22.0-r1.pre-install
Executing nginx-1.22.0-r1.post-install
Executing busybox-1.35.0-r17.trigger
OK: 7 MiB in 16 packages

/ # apk info nginx
nginx-1.22.0-r1 description:
HTTP and reverse proxy server (stable version)

nginx-1.22.0-r1 webpage:
https://www.nginx.org/

nginx-1.22.0-r1 installed size:
1124 KiB

/ # apk manifest nginx
sha1:d21a96358a10b731f8847e6d32799efdc2a7f421  etc/logrotate.d/nginx
sha1:cbf596ddb3433a8e0d325f3c188bec9c1bb746b3  etc/nginx/fastcgi.conf
sha1:da38e2a0dded838afbe0eade6cb837ac30fd8046  etc/nginx/fastcgi_params
sha1:9b85e5091018455091d7f135c4a160ad9487516a  etc/nginx/mime.types
sha1:44195d2ab691d6251a0ac0190aebf7a1c2eea05d  etc/nginx/nginx.conf
sha1:379c1e2a2a5ffb8c91a07328d4c9be2bc58799fd  etc/nginx/scgi_params
sha1:cc2fcdb4605dcac23d59f667889ccbdfdc6e3668  etc/nginx/uwsgi_params
sha1:b56312b641dffaa622d197625f4b867817824475  usr/sbin/nginx
sha1:7b2a4da1a14166442c10cbf9e357fa9fb53542ca  usr/share/nginx/http-default_server.conf
sha1:35db17c18ce0b9f84a3cc113c8a9e94e19f632b1  var/lib/nginx/logs
sha1:c3f02ca81f7f2c6bde3f878b3176f225c7781c7d  var/lib/nginx/modules
sha1:0510312d465b86769136983657df98c1854f0b60  var/lib/nginx/run
sha1:835b9dec419c01420e78602527a9fba8c463521c  var/lib/nginx/html/50x.html
sha1:c51a3f0e6de4eb802d5630941c3fd9e1d0efae4b  var/lib/nginx/html/index.html
Debian(Ubuntu)建议安装的基础包

在很多软件官方提供的镜像都使用的是Debian(Ubuntu)的系统,比如:nginx,tomcat,mysql,httpd等,但镜像内缺少很多常用的调试工具,当需要进入容器内进行调试管理时,可以安装以下常用工具包

shell 复制代码
apt update									# 安装软件钱需要先更新索引
apt install procps					# 提供top,ps,free等命令
apt install psmic						# 提供pstree,killall等命令
apt install iputils-ping		# 提供ping命令
apt install net-tools				# 提供netstat网络工具等

下载镜像

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

shell 复制代码
docker pull [OPTION] NAME[:TAG|@GIGEST]
OPTIONS:
	-a,--all-tags									Download all tagged images in the repository
		 --disable-content-trust		Skip image verification (default true)
		 --platform string					Set platform if server is multi-platform capable
 	-q,--quit											Suppress verbose output
 	
NAME:是镜像名,一般的形式  仓库服务器:端口/项目名称/镜像名称
:TAG:即版本号,如果不指定:TAG,则下载最新版镜像
镜像下载说明
shell 复制代码
[root@centos7 ~]# docker pull hello-world
Using default tag: latest			# 默认下载最新版本
latest: Pulling from library/hello-world
2db29710123e: Pull complete		# 分层下载
Digest: sha256:7d246653d0511db2a6b2e0436cfd0e52ac8c066000264b3ce63331ac66dca625 # 摘要
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest			# 下载的完整地址

镜像下载保存的路径:

/var/lib/docker/overlay2/镜像ID

注意:镜像下载完成后,会自动解压缩,比官网显示的可能会大很多,如:centos8.1.1911下载时只有70M,下载完后显示237M

例:从docker官网下载镜像

shell 复制代码
docker pull hello-world
docker pull alpine
docker pull busybox
docker pull nginx
docker pull centos
docker pull centos:centos7.7.1908
docekr pull docker.io/library/mysql:5.7.29
docker pull mysql:5.6.47

docker镜像加速配置

docker镜像官方的下载站点是:https://hub.docker.com/

从国内下载官方的镜像站点有时候会很慢,因此可以更改docker配置文件添加一个加速器,可以通过加速器达到加速下载镜像的目的。国内有许多公司都提供了docker加速镜像,比如:阿里云,腾讯云,网易云等。

shell 复制代码
1.安装/升级Docker客户端
推荐安装1.10.0以上版本的Docker客户端,参考文档 docker-ce

2.配置镜像加速器
修改daemon配置文件 /etc/docker/daemon.json
mkdir -p /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"registry-mirrors":["https://docker.mirrors.ustc.edu.cn"]
}
EOF

# 网易云:https://hub-mirror.c.163.com/
# 腾讯云:https://mirror.ccs.tencentyun.com

systemctl daemon-reload
systemctl restart docker

查看本地镜像

docker images可以查看下载至本地的镜像

shell 复制代码
docker images [OPTIONS] [REPOSITORY[:TAG]]
docker image ls [OPTIONS] [REPOSITORY[:TAG]]

# 常用选项
-q,--quiet					Only show numberic IDs
-a,--all						Show all images (default hides intermediate images)
	 --digests				Show digests
	 --no-trunc				Don't truncate output
-f,--filter filter	Filter output based on conditions provided
	 --format string  Pretty-print images using a Go template

执行结果的显示信息说明

shell 复制代码
REPOSITORY		# 镜像所属的仓库名称
TAG						# 镜像版本号(标识符),默认为latest
IMAGE ID			# 镜像唯一ID标识,如果ID相同,说明是同一个镜像有多个名称
VREATED				# 镜像在仓库中被创建时间
SIZE					# 镜像的大小

Repository仓库

  • 由某特定的docker镜像的所有迭代版本组成的镜像仓库
  • 一个Registry中可以存在多个Repository
  • Repository可分为"顶层仓库"和"用户仓库"
  • Repository用户仓库名称一般格式为"用户名/仓库名"
  • 每个Repository仓库可以包含多个Tag,每个标签对应一个镜像

镜像导出

利用docker save命令可以将本地镜像导出为一个tar文件,然后复制到其他服务器进行导入使用

shell 复制代码
docker save [OPTIONS] IMAGE [IMAGE...]

# 选项:
-o,--output string  write to a file,instead of STDOUT

常见用法:

shell 复制代码
docker save -o /path/file.tar IMAGE1 IMAGE2 ...
docker save IMAGE1 IMAGE2... > /path/file.tar

镜像导入

利用docker load 命令可以将镜像导出的压缩文件再导入

shell 复制代码
docker load [OPTIONS]

# 选项
-i,--input string		Read from tar archive,instead of STDIN
-q,--quiet					Suppress the load output

常见用法:

shell 复制代码
docker load -i /path/file.tar
docker load < /path/file.tar

删除镜像

docker rmi 命令可以删除镜像

shell 复制代码
docker rmi [OPTIONS] IMAGE [IMAGE...]
docker image rm [OPTIONS] IMAGE [IMAGE...]

# 选项
-f,--force			Force removal of the image
	 --no-prune		Do not delete untagged parents

常见用法:

shell 复制代码
[root@centos7 ~]# docker images
REPOSITORY    TAG              IMAGE ID       CREATED                  SIZE
debian        latest           dd8bae8d259f   Less than a second ago   124MB
alpine        latest           9c6f07244728   13 days ago              5.54MB
ubuntu        latest           df5de72bdb3b   2 weeks ago              77.8MB
hello-world   latest           feb5d9fea6a5   11 months ago            13.3kB
centos        latest           5d0da3dc9764   11 months ago            231MB
centos        centos7.7.1908   08d05d1d5859   2 years ago              204MB

# 根据IMAGE ID删除镜像
[root@centos7 ~]# docker rmi 08d
Untagged: centos:centos7.7.1908
Untagged: centos@sha256:50752af5182c6cd5518e3e91d48f7ff0cba93d5d760a67ac140e2d63c4dd9efc
Deleted: sha256:08d05d1d5859ebcfb3312d246e2082e46cb307f0e896c9ac097185f0b0b19e56
Deleted: sha256:034f282942cd6c3abf9384601a57f080f8f75cc7f58527db8e07573d9d14ab46

# 根据REPOSITORY名称删除镜像
[root@centos7 ~]# docker rmi centos
Untagged: centos:latest
Untagged: centos@sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Deleted: sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6
Deleted: sha256:74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59

# 删除多个镜像
[root@centos7 ~]# docker rmi debian ubuntu
Untagged: debian:latest
Untagged: debian@sha256:875e4e2bae4d7ff53fe7f3672b15630439479fd10da081477a14208122fe8f31
Deleted: sha256:dd8bae8d259fed93eb54b3bca0adeb647fc07f6ef16745c8ed4144ada4d51a95
Deleted: sha256:655ed1b7a4286ce965b8942644f665a3aeafac315f023b3d75fabdbd4be12dd0
Untagged: ubuntu:latest
Untagged: ubuntu@sha256:34fea4f31bf187bc915536831fd0afc9d214755bf700b5cdb1336c82516d154e
Deleted: sha256:df5de72bdb3b711aba4eca685b1f42c722cc8a1837ed3fbd548a9282af2d836d
Deleted: sha256:629d9dbab5edeac7fa51f205839d7f9bb629a5e83548da3a183fb66c22fe7af7

# 删除所有镜像
[root@centos7 ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
alpine        latest    9c6f07244728   13 days ago     5.54MB
hello-world   latest    feb5d9fea6a5   11 months ago   13.3kB
[root@centos7 ~]# docker rmi -f `docker images -q`
Untagged: alpine:latest
Untagged: alpine@sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad
Deleted: sha256:9c6f0724472873bb50a2ae67a9e7adcb57673a183cea8b06eb778dca859181b5
Deleted: sha256:994393dc58e7931862558d06e46aa2bb17487044f670f310dffe1d24e4d1eec7
Untagged: hello-world:latest
Untagged: hello-world@sha256:7d246653d0511db2a6b2e0436cfd0e52ac8c066000264b3ce63331ac66dca625
Deleted: sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412
Deleted: sha256:e07ee1baac5fae6a26f30cabfe54a36d3402f96afda318fe0a96cec4ca393359
[root@centos7 ~]# docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

镜像打标签

docker tag可以给镜像打标签,类似起别名,但通常要遵守一定的命名规范,才可以上传到指定的仓库

shell 复制代码
# 格式
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

# TARGET_IMAGE[:TAG]格式一般形式
仓库主机FQDN或IP[:端口]/项目名(或用户名)/image名字:版本

# TAG 默认为latest

**总结:**企业使用镜像及常见操作:搜索、下载、导出、导入、删除

shell 复制代码
docker search centos
docker pull alpine
docker images
docker save > /opt/centos.tar centos
docker load < /opt/centos.tar
docker rmi 镜像ID/镜像名称

容器操作基础命令

容器相关命令

shell 复制代码
[root@centos7 ~]# docker container

Usage:  docker container COMMAND

Manage containers

Commands:
  attach      Attach local standard input, output, and error streams to a running container
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes to files or directories on a container's filesystem
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  inspect     Display detailed information on one or more containers
  kill        Kill one or more running containers
  logs        Fetch the logs of a container
  ls          List containers
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  prune       Remove all stopped containers
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  run         Run a command in a new container
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  wait        Block until one or more containers stop, then print their exit codes

Run 'docker container COMMAND --help' for more information on a command.

启动容器

docker run 可以启动容器,进入到容器,并随机生成容器ID和名称

启动第一个容器
shell 复制代码
[root@centos7 ~]# docker run hello-world



Hello from Docker!

This message shows that your installation appears to be working correctly.



To generate this message, Docker took the following steps:

 1. The Docker client contacted the Docker daemon.

 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.

    (amd64)

 3. The Docker daemon created a new container from that image which runs the

    executable that produces the output you are currently reading.

 4. The Docker daemon streamed that output to the Docker client, which sent it

    to your terminal.



To try something more ambitious, you can run an Ubuntu container with:

 $ docker run -it ubuntu bash



Share images, automate workflows, and more with a free Docker ID:

 https://hub.docker.com/



For more examples and ideas, visit:

 https://docs.docker.com/get-started/



[root@centos7 ~]# docker ps -a

CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES

46f601445bd8   hello-world   "/hello"   30 seconds ago   Exited (0) 29 seconds ago             festive_sammet

[root@centos7 ~]#
启动容器的流程
启动容器的用法
shell 复制代码
docker run [选项] [镜像名] [shell命令] [参数]



# 选项

-i                          Keep STDIN open even if not attached,通常和-t一起用

-t                          分配 pseudo-TTY,通常和-i一起使用,注意对应容器必须运行shell才支持进入

-d                          后台运行,默认前台运行

--name string               容器名称

--h,--hostname string       容器 hostname

--rm                        容器关闭后自动删除容器

-p list                     指定要映射的端口到内部容器开放的端口

-P                          随机映射端口到内部容器开放的端口(49000~49900)

--dns list                  设置DNS

--entrypoint string         运行指令

--restart policy

-e,--env=[]                 设置环境变量

--env-file=[]

---restart (容器的重启策略)可以指定四种不同的policy

  • no,默认策略,在容器退出时不重启容器
  • no-failure,在容器非正常退出时(退出状态非0),才会重启容器
  • on-failure=3,在容器非正常退出时重启容器,最多重启3次
  • always,在容器退出时总是重启容器unless-stopped,在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止的容器

**注意:**容器启动后,如果容器内没有前台运行的进程,将自动退出停止

shell 复制代码
# 运行容器 启动容器时会自动随机字符作为容器名

[root@centos7 ~]# docker pull alpine

Using default tag: latest

latest: Pulling from library/alpine

59bf1c3509f3: Pull complete

Digest: sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300

Status: Downloaded newer image for alpine:latest

docker.io/library/alpine:latest

[root@centos7 ~]# docker run alpine

[root@centos7 ~]# docker ps -a

CONTAINER ID   IMAGE     COMMAND     CREATED         STATUS                     PORTS     NAMES

bc5efb3b7f37   alpine    "/bin/sh"   3 seconds ago   Exited (0) 2 seconds ago             elated_villani



# 一次性运行容器中的命令

# 启动容器在执行完shell命令就退出,用于测试

[root@centos7 ~]# docker pull busybox

Using default tag: latest

latest: Pulling from library/busybox

5cc84ad355aa: Pull complete

Digest: sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678

Status: Downloaded newer image for busybox:latest

docker.io/library/busybox:latest

[root@centos7 ~]# docker run busybox echo "Hello chensir"

Hello chensir

[root@centos7 ~]# docker ps

CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

[root@centos7 ~]# docker ps -a

CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                      PORTS     NAMES

4ce437d13ae3   busybox   "echo 'Hello chensir'"   17 seconds ago   Exited (0) 17 seconds ago             optimistic_goldberg



# 指定容器名称

[root@centos7 ~]# docker run --name pine alpine

[root@centos7 ~]# docker ps

CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

[root@centos7 ~]# docker ps -a

CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS                     PORTS     NAMES

9c34dd8204d0   alpine    "/bin/sh"                7 seconds ago   Exited (0) 6 seconds ago             pine



# 运行交互式容器并退出

[root@centos7 ~]# docker run -it busybox sh

/ # exit



# 使用exit退出容器后 容器也停止了

[root@centos7 ~]# docker ps -l

CONTAINER ID   IMAGE     COMMAND   CREATED          STATUS                     PORTS     NAMES

4b3203a20472   busybox   "sh"      10 seconds ago   Exited (0) 3 seconds ago             brave_pascal



[root@centos7 ~]# docker run -it busybox sh

/ # 

# 在容器中 同时按三个键 ctrl+p+q 退出后 容器不会停止

[root@centos7 ~]# docker ps

CONTAINER ID   IMAGE     COMMAND   CREATED         STATUS         PORTS     NAMES

6ad4551530b5   busybox   "sh"      9 seconds ago   Up 8 seconds             jolly_mestorf



# 设置容器内的主机名

[root@centos7 ~]# docker run -it --name a1 -h chensir.ink alpine

/ # hostname

chensir.ink

/ # 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  chensir.ink chensir



# 一次性运行容器,退出后立即删除,用于测试

[root@centos7 ~]# docker run --rm alpine cat /etc/issue

Welcome to Alpine Linux 3.15

Kernel \r on an \m (\l)



[root@centos7 ~]# docker ps -a

CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
什么是守护式容器
  • 能够长期运行
  • 无需交互式会话
  • 适合运行应用程序和服务
privileged 选项

大约在0.6版,-----privileged选项被引入docker。使用该参数,container内的root拥有真正的root权限。否则,container内的root只是外部的一个普通用户权限。privileged启动的容器,可以看到很多host上的设备,并且可以执行mount。甚至允许你在docker容器中启动docker容器。

查看容器信息

显示当前存在容器
docker ps [OPTIONS]
docker container ls [OPTIONS]
# 选项
-a			Show all containers (default shows just running)
-q			Only display numeric IDs
-s			Display total file sizes
-f			Filter output based on conditions provided
-l			Show the latest created container (includes all states)
-n			Show n last created containers (includes all states)
(default -1)

示例:

# 显示运行的容器

docker ps



# 显示全部容器,包括退出状态的容器

docker ps -a



# 显示全部容器,包括退出状态的容器的 容器ID

docker ps -aq



# 显示全部容器,包括退出状态的容器的大小

docker ps -as



# 显示最新创建的容器(停止的容器也能显示)

docker ps -l



# 显示指定状态的容器

docker ps -f 'status=exited'

docker ps -f 'status=running'
查看容器内的进程
docker top CONTAINER [PS OPTIONS]

示例:

[root@centos7 ~]# docker run -d httpd

Unable to find image 'httpd:latest' locally

latest: Pulling from library/httpd

a2abf6c4d29d: Already exists

dcc4698797c8: Pull complete

41c22baa66ec: Pull complete

67283bbdd4a0: Pull complete

d982c879c57e: Pull complete

Digest: sha256:0954cc1af252d824860b2c5dc0a10720af2b7a3d3435581ca788dff8480c7b32

Status: Downloaded newer image for httpd:latest

ec9e58e706932e56509ce001191e7b52cd5f16b6b1ec25852a2947872aff3cff

[root@centos7 ~]# docker top ec9

UID            PID            PPID           C              STIME          TTY            TIME           CMD

root           15067          15047          0              04:33          ?              00:00:00       httpd -DFOREGROUND

33             15094          15067          0              04:33          ?              00:00:00       httpd -DFOREGROUND

33             15095          15067          0              04:33          ?              00:00:00       httpd -DFOREGROUND

33             15096          15067          0              04:33          ?              00:00:00       httpd -DFOREGROUND
查看容器资源使用情况
docker stats [OPTIONS] [CONTAINER...]



# 选项

-a,--all                Show all containers (default shows just running)

   --format string      Pretty-print images using a Go template

   --no-stream          Disable streaming stats and only pull the first result

   --no-trunc           Do not truncate output
查看容器的详细信息

docker inspect 可以查看docker各种对象的详细信息,包括:镜像,容器,网络等

docker inspect [OPTIONS] NAME|ID [NAME|ID...]

# 选项

-f string  Format the output using the given Go trmplate

-s         Display total file sizes if the type is container

删除容器

docker rm 可以删除容器

docker rm [OPTIONS] CONTAINER [CONTAINER...]

docker container rm [OPTIONS] CONTAINER [CONTAINER...]

# 选项

-f      Force the removal of a running container (uses SIGKILL)

-v      Remove

示例:

# 删除所有的容器

docker rm -f `docker ps -aq`



# 删除指定状态的容器

docker rm -f `docker ps -qf status=exited`



# 删除所有停止的容器

docker container prune -f

容器的启动和停止

docker start|stop|restart|pause|unpause 容器ID



# 批量正常启动或关闭所有容器

docker start `docker ps -qa`

docker stop `docker ps -qa`

给正在运行的容器发信号

docekr kill 可以给容器发信号,默认SIGKILL,即9

docker kill [OPTIONS] CONTAINER [CONTAINER...]

# 选项

-s string Signal to send to the container (default "KILL")

示例:

# 关闭容器

docker kill nginx



# 强制关闭所有容器

docker kill `docker ps -qa`

进入正在运行的容器

使用attach命令

docker attach 容器名,attach类似于vnc,操作会在同一个容器的多个会话界面同步显示,所有使用此方式进入容器的操作都是同步显示的,且使用exit退出后容器自动关闭,不推荐使用,需要进入到有shell环境的容器

使用exec命令

在运行中的容器启动新进程可以执行单次命令及进入容器,测试环境使用此方式,使用exit退出,容器还在运行,推荐此方式

docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

# 常用选项
-d				Detached mode:run command in the background
-e				Set environment variables
-i				Keep STDIN open even if not attached
-t				Allocate a psedu-TTY

# 常见用法
docker exec -it 容器ID sh|bash
使用nsenter命令

nsenter命令需要通过PID进入到容器内部,且退出后仍能正常运行,不过需要事先使用docker inspect 获取到容器的PID,目前凡是使用较少,此工具来自于until-linux包

# 安装nsenter命令
yum install -y util-linux

# 获取容器的IP
docker inspect -f "{{.NetworkSettings.IPAddress}}" 容器ID

# 获取容器的PID,通过PID进入到容器内
docker inspect -f "{{.State.Pid}}" 容器ID
nsenter -t Pid -m -u -i -n -p
脚本方式

将nsenter命令写入到脚本进行调用,方便进入容器看日志或排错

cat docker-in.sh
#!/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

示例

[root@centos7 ~]# vim docker-in.sh
[root@centos7 ~]# cat docker-in.sh
#!/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
[root@centos7 ~]# chmod +x docker-in.sh
[root@centos7 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
fd056baa9925   nginx     "/docker-entrypoint...."   39 minutes ago   Up 38 minutes   80/tcp    nginx03
4fb4c31a6342   nginx     "/docker-entrypoint...."   39 minutes ago   Up 38 minutes   80/tcp    nginx01
[root@centos7 ~]# ./docker-in.sh fd05
root@fd056baa9925:/# exit
logout
[root@centos7 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
fd056baa9925   nginx     "/docker-entrypoint...."   40 minutes ago   Up 39 minutes   80/tcp    nginx03
4fb4c31a6342   nginx     "/docker-entrypoint...."   40 minutes ago   Up 39 minutes   80/tcp    nginx01

暴露所有容器端口

容器启动后,默认处于预定义的NAT网络中,所以外部网络的主机无法直接访问容器中网络服务

docker run -P 可以将事先容器预定义的所有端口映射宿主机的网卡的随机端口

使用随机端口时,当停止容器后在启动可能会导致端口发生变化

# 示例 映射容器所有暴露端口至随机本地端口
docker run -d -P nginx

docker port 可以查看容器的端口映射关系

docker port CONTAINER [PRIVATE_PORT[/PROTO]]

# 示例
docker port nginx01
docker port nginx01 53/udp

指定端口映射

docker run -p 可以将容器的预定义的指定端口映射到宿主机的相应端口

注意:多个容器映射到宿主机端口不能冲突,但容器内使用的端口可以相同

# 方式1:容器80端口映射到宿主机本地随机端口
docker run -p 80 --name nginx-test-port1 nginx

# 方式2:容器80端口映射到宿主机本地端口81
docker run -p 81:80 --name nginx-test-port2 nginx

# 方式3:宿主机本地IP:宿主机本地端口:容器端口
docker run -p 10.0.0.100:82:80 --name nginx-test-port3 nginx

# 方式4:宿主机本地IP:苏知机本地随机端口:容器端口
docker run -p 10.0.0.100::80 --name nginx-test-port4 nginx

# 方式5:宿主机本机IP:宿主机本地端口:容器端口/协议,默认为tcp协议
docker run -p 10.0.0.100:83:80/udp --name nginx-test-port5 nginx

# 方式6:一次映射多个端口+协议
docker run -p 8080:80/tcp -p 8443:443/tcp -p 53:53/udp --name-test-port6 nginx

修改已经创建的容器的端口映射关系

[root@centos7 ~]# docker run -d -p 80:80 --name nginx01 nginx
cd1db7f176806254fdf3089f32fcbd0094ec376ea3d8d4e481093cad353d9d48
[root@centos7 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                               NAMES
cd1db7f17680   nginx     "/docker-entrypoint...."   2 minutes ago   Up 2 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp   nginx01
[root@centos7 ~]# ll /var/lib/docker/containers/cd1db7f176806254fdf3089f32fcbd0094ec376ea3d8d4e481093cad353d9d48/
总用量 28
-rw-r----- 1 root root 2302 8月  23 08:29 cd1db7f176806254fdf3089f32fcbd0094ec376ea3d8d4e481093cad353d9d48-json.log
drwx------ 2 root root    6 8月  23 08:29 checkpoints
-rw------- 1 root root 2904 8月  23 08:29 config.v2.json
-rw-r--r-- 1 root root 1512 8月  23 08:29 hostconfig.json
-rw-r--r-- 1 root root   13 8月  23 08:29 hostname
-rw-r--r-- 1 root root  174 8月  23 08:29 hosts
drwx--x--- 2 root root    6 8月  23 08:29 mounts
-rw-r--r-- 1 root root   69 8月  23 08:29 resolv.conf
-rw-r--r-- 1 root root   71 8月  23 08:29 resolv.conf.hash
[root@centos7 ~]# systemctl stop docker
[root@centos7 ~]# vim /var/lib/docker/containers/cd1db7f176806254fdf3089f32fcbd0094ec376ea3d8d4e481093cad353d9d48/hostconfig.json
"PortBindings":{"80/tcp":[{"HostIp":"","HostPort":"80"}]}
# PortBindings 后面的 80/tcp 对应的是容器内部的80端口,HostPort对应的是映射到宿主机的端口80,修改此处为8000
"PortBindings":{"80/tcp":[{"HostIp":"","HostPort":"8000"}]}
[root@centos7 ~]# systemctl start docker
[root@centos7 ~]# docker port nginx01
80/tcp -> 0.0.0.0:8000
80/tcp -> :::8000

查看容器的日志

docker logs 可以查看容器中运行的进程在控制台输出的日志信息

格式

docker logs [OPTIONS] CONTAINER
# 选项:
--details					Show extra details provided to logs
-f,--follow				Follow log output
--since string		Show logs since timestamp
--tail string			Number of lines to show from the end of the logs (default "all")
-t,--timestamps		Show timestamps
--until string		Show logs before a timestamp

示例

# 查看所有日志
docker logs 容器ID

# 查看倒数几行的日志
docker logs --tail 行数 容器ID

# 显示日志时间
docker logs --tail 行数 -t  容器ID

# 持续跟踪日志
docker logs -f 容器ID

传递运行命令

容器需要有一个前台运行的进程才能保持容器的运行,通过传递运行参数是一种方式,另外也可以在构建镜像的时候指定容器启动时运行的前台命令

容器里的PID为1的守护进程的实现方式

  • 服务类:如:Nginx,Tomcat,Apache,但服务不能停

  • 命令类:如:tail -f /etc/hosts,主要用于测试环境,注意 tail -f <服务访问日志>会产生不必要的磁盘IO

    [root@centos7 ~]# docker run -d alpine
    fc8dc5bee8367725a759f15417316a619b098af88f1ad7f7113fa314dd6e3f34
    [root@centos7 ~]# docker ps -a
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    fc8dc5bee836 alpine "/bin/sh" 6 seconds ago Exited (0) 5 seconds ago exciting_chebyshev
    [root@centos7 ~]# docker run -d alpine tail -f /etc/hosts
    05a4c6863bcc9d7c4b9f0abeec2316a9cce0f0e3f2aeb37bfa57fcd2bcdf8d52
    [root@centos7 ~]# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    05a4c6863bcc alpine "tail -f /etc/hosts" 2 seconds ago Up 1 second vigilant_lumiere
    [root@centos7 ~]# docker exec -it 05a sh
    / # ps aux
    PID USER TIME COMMAND
    1 root 0:00 tail -f /etc/hosts
    7 root 0:00 sh
    13 root 0:00 ps aux
    [root@centos7 ~]# docker ps -a
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    05a4c6863bcc alpine "tail -f /etc/hosts" About a minute ago Up About a minute vigilant_lumiere

容器内部的hosts文件

容器会自动将容器的ID加入自己的/etc/hosts文件中,并解析成容器的IP

[root@centos7 ~]# docker run -it centos /bin/bash
[root@8f4c940da642 /]# 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	8f4c940da642  # 默认会将实例的ID 添加到自己的hosts文件
[root@8f4c940da642 /]# hostname
8f4c940da642
[root@8f4c940da642 /]# ping 8f4c940da642
PING 8f4c940da642 (172.17.0.3) 56(84) bytes of data.
64 bytes from 8f4c940da642 (172.17.0.3): icmp_seq=1 ttl=64 time=0.071 ms
64 bytes from 8f4c940da642 (172.17.0.3): icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 8f4c940da642 (172.17.0.3): icmp_seq=3 ttl=64 time=0.058 ms
^C
--- 8f4c940da642 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 0.058/0.062/0.071/0.010 ms

# 修改容器的hosts文件
[root@centos7 ~]# docker run -it --rm --add-host chensir.ink:8.8.8.8 --add-host chensir.com:6.6.6.6 busybox
/ # 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
8.8.8.8	chensir.ink
6.6.6.6	chensir.com
172.17.0.4	4397ad2a1497
/ # ping chensir.ink
PING chensir.ink (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=127 time=70.911 ms
64 bytes from 8.8.8.8: seq=1 ttl=127 time=69.407 ms
64 bytes from 8.8.8.8: seq=2 ttl=127 time=64.564 ms
64 bytes from 8.8.8.8: seq=3 ttl=127 time=69.504 ms
^C
--- chensir.ink ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 64.564/68.596/70.911 ms
/ # ping chensir.com
PING chensir.com (6.6.6.6): 56 data bytes
^C
--- chensir.com ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss

指定容器DNS

容器的dns服务器,采用宿主机的dns地址,可以用下面方式指定其他的DNS地址

  • 将dns地址配置在宿主机

  • 在容器启动时加选项 --dns=x.x.x.x

  • 在/etc/docker/daemon.json 文件中指定

    容器的DNS默认从宿主机的DNS获取

    [root@centos7 ~]# cat /etc/resolv.conf

    Generated by NetworkManager

    search localdomain
    nameserver 10.0.0.1
    [root@centos7 ~]#
    [root@centos7 ~]# docker run -it --rm centos sh
    sh-4.4# cat /etc/resolv.conf

    Generated by NetworkManager

    search localdomain
    nameserver 10.0.0.1

    指定DNS地址

    [root@centos7 ~]# docker run -it --rm --dns 1.1.1.1 --dns 8.8.8.8 centos bash
    [root@3e9468f64df2 /]# cat /etc/resolv.conf
    search localdomain
    nameserver 1.1.1.1
    nameserver 8.8.8.8

    指定domain名

    [root@centos7 ~]# docker run -it --rm --dns 1.1.1.1 --dns 8.8.8.8 --dns-search a.com --dns-search b.com busybox
    / # cat /etc/resolv.conf
    search a.com b.com
    nameserver 1.1.1.1
    nameserver 8.8.8.8

    配置文件指定DNS和搜索domain名

    [root@centos7 ~]# vim /etc/docker/daemon.json
    {
    "storage-driver": "overlay2",
    "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn"
    ],
    "dns": [
    "114.114.114.114",
    "8.8.8.8"
    ],
    "dns-search": [
    "chensir.ink",
    "chensir.xyz"
    ]
    }
    [root@centos7 ~]# systemctl restart docker
    [root@centos7 ~]# cat /etc/resolv.conf

    Generated by NetworkManager

    search localdomain
    nameserver 10.0.0.1
    [root@centos7 ~]# docker run -it centos bash
    [root@8d3436934bb1 /]# cat /etc/resolv.conf
    search chensir.ink chensir.xyz
    nameserver 114.114.114.114
    nameserver 8.8.8.8

    用--dns指定优先级高

    [root@centos7 ~]# docker run -it --rm --dns 8.8.4.4 centos bash
    c[root@61c97fb7deb7 /]# cat /etc/resolv.conf
    search chensir.ink chensir.xyz
    nameserver 8.8.4.4

容器内和宿主机之间复制文件

docker cp [OPTION] CONTAINER:SRC_PATH DEST_PATH|-
dpcker cp [OPTION] SRC_PATH|- CONTAINER:DEST_PATH
Options:
	-a,--archive				Archive mode (copy all uid/gid information)
	-L,--follow-link		Always follow symbol link in SRC_PATH

使用systemd控制容器运行

[root@centos7 ~]# vim /etc/systemd/system/hello.service
[Unit]
Description=Hello world
Description=Hello world
After=docker.service
Requires=docker.service
[Service]
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker kill busybox-hello
ExecStartPre=-/usr/bin/docker rm busybox-hello
ExecStartPre=-/usr/bin/docker pull busybox
ExecStart=/usr/bin/docker run --name busybox-hello busybox /bin/sh -c "while true;do echo Hello world; sleep 1; done"
ExecStop=/usr/bin/docker kill busybox-hello
[Install]
wantedBy=multi-user.target

[root@centos7 ~]# systemctl daemon-reload
[root@centos7 ~]# systemctl enable --now hello.service

传递环境变量

有些容器运行时,需要传递变量,可以使用 -e <参数> 或 - - env-file <参数文件> 实现

[root@centos7 ~]# docker run --name mysql01 mysql:5.7.31
WARNING: IPv4 forwarding is disabled. Networking will not work.
2022-08-23 02:08:23+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.31-1debian10 started.
2022-08-23 02:08:23+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2022-08-23 02:08:23+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.31-1debian10 started.
2022-08-23 02:08:23+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
	You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD
	
[root@centos7 ~]# docker run --name mysql-test1 -v /data/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wpuser -e MYSQL_PASSWORD=123456 -d -p 3306:3306 mysql:5.7.31
WARNING: IPv4 forwarding is disabled. Networking will not work.
ba743ba4068b36c7b2ff804decbb0c5f22aaa8ab0b20ce8bc4c4380ccc990674

[root@centos7 ~]# docker run --name mysql-test2 -v /root/mysql/:/etc/conf.d -v /data/mysql2:/var/lib/mysql --env-file=env.list -d -p 3307:33077 mysql:5.7.31

[root@centos7 ~]# cat /root/mysql/mysql-test.cnf
[mysqld]
server-id=100
log-bin=mysql-bin

[root@centos7 ~]# cat env.list
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=wordpress
MYSQL_USER=wpuser
MYSQL_PASSWORD=wppass

Docker镜像制作和管理

Docker镜像说明

Docker镜像中有没有内核

从镜像大小上来说,一个比较小的镜像只有1M多点或者几M,而内核文件需要几十M,因此镜像里面是没有内核的,镜像在被启动为容器后将直接使用宿主机的内核,而镜像本身则只提供相应的rootfs,即系统正常运行所必须的用户空间的文件系统,比如:/dev/,/proc,/bin,/etc等目录,容器当中/boot目录时空的,而/boot当中保存的就是与内核相关的文件和目录。

为什么没有内核

由于容器启动和运行过程中是直接使用了宿主机的内核,不会直接调用物理硬件,所以不会涉及到硬件驱动,因此也无需容器内拥有自己的内核和驱动。而如果使用虚拟机技术,对应每个虚拟机都有自己独立的内核。

容器中的程序后台运行会导致此容器启动后立即退出

Docker容器如果希望启动后能持续运行,就必须有一个能前台持续运行的进程,如果在容器中启动系统的服务,如:httpd,php-fpm等均为后台进程模式运行,就导致docker在前台没有运行的应用,这样的容器启动后会立即退出。所以一般会将服务程序以前台方式运行,对于有一些可能不知道怎么实现前台运行的程序,只需要在你启动的该程序之后添加类似于tail,top这种可以前台运行的程序即可。比较常用的方法,如 tail -f /etc/hosts 。

# httpd
ENTRYPOINT ["/usr/sbin/apache2"]
CMD ["-D","FOREGROUND"]

# nginx
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]

# 用脚本运行容器
cat run_haproxy.sh
#!/bin/bash
haproxy -f /etc/haproxy/haproxy.cfg
tail -f /etc/hosts

tail -n1 Dockerfile
CMD ["run_haproxy.sh"]

docker镜像生命周期

制作镜像方式

Docker镜像制作类似于虚拟机的镜像(模板)制作,即按照公司的实际业务需求将需要安装的软件、相关配置等基础环境配置完成,然后将其做成镜像,最后再从镜像批量生成容器实例,这样可以极大的简化相同环境的部署工作

Docker的镜像制作分为手动制作(基于容器)和自动制作(基于Dockerfile),企业通常都是基于Dockerfile制作镜像

# 通过修改现有容器,将之手动构建为镜像
docker commit

# 通过Dockerfile文件,批量构建为镜像
docker build

将现有容器通过docker commit手动构建镜像

基于容器手动制作镜像步骤

docker commit

docker commit [OPTION] CONTAINER [REPOSITORY[:TAG]]
# 选项
-a,--author string			Author
-c,--change list				Apply Dockerfile instruction to the created image
-m,--message string			Commit message
-p,--pause							Pause container during commit (default true)

# 说明
制作镜像和CONTAINER状态无关,停止状态也可以制作镜像
如果没有指定[REPOSITORY[:TAG]],REPOSITORY和TAG都为<none>
提交的时候标记TAG号:生产中常用,后期可以根据TAG标记创建不同版本的镜像以及创建不同版本的容器

基于容器手动制作镜像步骤具体如下:

1.下载一个系统的官方基础镜像,如:CentOS 或 Ubuntu

2.基于基础镜像启动一个容器,并进入到容器

3.在容器里面做配置操作

  • 安装基础命令
  • 配置运行环境
  • 安装服务和配置服务
  • 放业务程序和代码

4.提交为一个新镜像 docker commit

5.基于自己的镜像创建容器并测试访问

基于busybox制作httpd镜像

[root@centos7 ~]# docker run -it --name b1 busybox
WARNING: IPv4 forwarding is disabled. Networking will not work.
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # mkdir /data/html -p
/ # echo httpd website in busybox > /data/html/index.html
/ # httpd --help
BusyBox v1.34.1 (2021-12-29 21:12:15 UTC) multi-call binary.

Usage: httpd [-ifv[v]] [-c CONFFILE] [-p [IP:]PORT] [-u USER[:GRP]] [-r REALM] [-h HOME]
or httpd -d/-e/-m STRING

Listen for incoming HTTP requests

	-i		Inetd mode
	-f		Don't daemonize
	-v[v]		Verbose
	-p [IP:]PORT	Bind to IP:PORT (default *:80)
	-u USER[:GRP]	Set uid/gid after binding to port
	-r REALM	Authentication Realm for Basic Authentication
	-h HOME		Home directory (default .)
	-c FILE		Configuration file (default {/etc,HOME}/httpd.conf)
	-m STRING	MD5 crypt STRING
	-e STRING	HTML encode STRING
	-d STRING	URL decode STRING
/ # exit

# 格式1:
[root@centos7 ~]# docker commit -a "chensir<root@chensir.ink>" -c 'CMD /bin/httpd -fv -h /data/html' -c "EXPOSE 80" b1 httpd-busybox:v1.0
sha256:0b59f1b5b2b1dca5f0386098a558b09593f652761c8a40e8723abdba2a0b43ce
[root@centos7 ~]# docker images
REPOSITORY      TAG       IMAGE ID       CREATED         SIZE
httpd-busybox   v1.0      0b59f1b5b2b1   4 seconds ago   1.24MB

# 格式2:
[root@centos7 ~]# docker commit -a "chensir<root@chenisr.ink>" -c 'CMD ["/bin/httpd","-f","-v","-h","/data/html"]' -c "EXPOSE 80" b1 httpd-busybox:v1.0
sha256:4100f91eb2e4949651fa401949791c746e34ae65e35fdbf456aa3bd55d703c72

[root@centos7 ~]# docker run -d -P --name httpd01 httpd-busybox:v1.0
WARNING: IPv4 forwarding is disabled. Networking will not work.
5a68de75aa05b374faeef9e08de92ffa3679cfaa240700f6ff1614576e24f3c4
[root@centos7 ~]# docker port httpd01
80/tcp -> 0.0.0.0:49157
80/tcp -> :::49157
[root@centos7 ~]# docker inspect -f "{{.NetworkSettings.Networks.bridge.IPAddress}}" httpd01
172.17.0.2

# 对应格式1
[root@centos7 ~]# docker inspect -f "{{.Config.Cmd}}" httpd01
[/bin/sh -c /bin/httpd -fv -h /data/html]

# 对应格式2
[root@centos7 ~]# docker inspect -f "{{.Config.Cmd}}" httpd01
[/bin/httpd -f -v -h /data/html]

[root@centos7 ~]# docker exec -it httpd01 sh
/ # pstree -p
httpd(1)
/ # ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/httpd -f -v -h /data/html
    8 root      0:00 sh
   14 root      0:00 ps aux
/ # read escape sequence
[root@centos7 ~]# curl 172.17.0.2
httpd website in busybox
[root@centos7 ~]# curl 127.0.0.1:49157
httpd website in busybox
[root@centos7 ~]# docker commit -a "chensir<chensir@chensir.ink>" b1 httpd-busybox:v2.0
sha256:b83d0a45c90bbfc368b57629af1985ec3f6d4bf05b870650fd7b73eb72c9771a
[root@centos7 ~]# docker images
REPOSITORY      TAG       IMAGE ID       CREATED          SIZE
httpd-busybox   v2.0      b83d0a45c90b   6 seconds ago    1.24MB
httpd-busybox   v1.0      fc393ccc5dd0   16 minutes ago   1.24MB
[root@centos7 ~]# docker run -d --name web2 -p 81:80 httpd-busybox:v2.0 /bin/httpd -fv -h /date/html
WARNING: IPv4 forwarding is disabled. Networking will not work.
ef52ca935dc26a7283bc5a9de537f8fb1540de81f12729356c011041744fb6b0

基于官方镜像生成的容器制作tomcat镜像

下载官方的tomcat镜像并运行
[root@centos7 ~]# docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE
[root@centos7 ~]# docker run -d -p 8080:8080 tomcat
Unable to find image 'tomcat:latest' locally
latest: Pulling from library/tomcat
0e29546d541c: Pull complete
9b829c73b52b: Pull complete
cb5b7ae36172: Pull complete
6494e4811622: Pull complete
668f6fcc5fa5: Pull complete
dc120c3e0290: Pull complete
8f7c0eebb7b1: Pull complete
77b694f83996: Pull complete
0f611256ec3a: Pull complete
4f25def12f23: Pull complete
Digest: sha256:9dee185c3b161cdfede1f5e35e8b56ebc9de88ed3a79526939701f3537a52324
Status: Downloaded newer image for tomcat:latest
WARNING: IPv4 forwarding is disabled. Networking will not work.
38cedc776327713d0d3081ddc26f0097b4f2b5a0981cc08a9afdfc0056e24434
[root@centos7 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND             CREATED         STATUS         PORTS                                       NAMES
38cedc776327   tomcat    "catalina.sh run"   2 minutes ago   Up 2 minutes   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   gracious_booth
[root@centos7 ~]# curl -I 127.0.0.1:8080
HTTP/1.1 404
Content-Type: text/html;charset=utf-8
Content-Language: en
Transfer-Encoding: chunked
Date: Tue, 23 Aug 2022 15:47:57 GMT
修改容器
[root@centos7 ~]# docker exec -it 38c bash
root@38cedc776327:/usr/local/tomcat# ls
BUILDING.txt	 LICENSE  README.md	 RUNNING.txt  conf  logs	    temp     webapps.dist
CONTRIBUTING.md  NOTICE   RELEASE-NOTES  bin	      lib   native-jni-lib  webapps  work
root@38cedc776327:/usr/local/tomcat# ls webapps
root@38cedc776327:/usr/local/tomcat# ls webapps.dist/
ROOT  docs  examples  host-manager  manager
root@38cedc776327:/usr/local/tomcat# cp -a webapps.dist/* webapps/
root@38cedc776327:/usr/local/tomcat# ls webapps
ROOT  docs  examples  host-manager  manager
root@38cedc776327:/usr/local/tomcat# exit
exit
[root@centos7 ~]# curl -I 127.0.0.1:8080
HTTP/1.1 200
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 23 Aug 2022 15:52:21 GMT
提交新镜像
[root@centos7 ~]# docker commit -m "add webapps app" -a "chensir" 38c tomcat:9.0.37-v1
sha256:399beff7540e7ade5ec2f34a794a3e972351dd66b2ccab1fb73604d7a1b3518f
[root@centos7 ~]# docker images
REPOSITORY   TAG         IMAGE ID       CREATED         SIZE
tomcat       9.0.37-v1   399beff7540e   4 seconds ago   684MB
tomcat       latest      fb5657adc892   8 months ago    680MB
[root@centos7 ~]# docker history tomcat:9.0.37-v1
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
399beff7540e   43 seconds ago   catalina.sh run                                 4.43MB    add webapps app
fb5657adc892   8 months ago     /bin/sh -c #(nop)  CMD ["catalina.sh" "run"]    0B
<missing>      8 months ago     /bin/sh -c #(nop)  EXPOSE 8080                  0B
<missing>      8 months ago     /bin/sh -c set -eux;  nativeLines="$(catalin...   0B
<missing>      8 months ago     /bin/sh -c set -eux;   savedAptMark="$(apt-m...   20.2MB
<missing>      8 months ago     /bin/sh -c #(nop)  ENV TOMCAT_SHA512=c2d2ad5...   0B
<missing>      8 months ago     /bin/sh -c #(nop)  ENV TOMCAT_VERSION=10.0.14   0B
<missing>      8 months ago     /bin/sh -c #(nop)  ENV TOMCAT_MAJOR=10          0B
<missing>      8 months ago     /bin/sh -c #(nop)  ENV GPG_KEYS=A9C5DF4D22E9...   0B
<missing>      8 months ago     /bin/sh -c #(nop)  ENV LD_LIBRARY_PATH=/usr/...   0B
<missing>      8 months ago     /bin/sh -c #(nop)  ENV TOMCAT_NATIVE_LIBDIR=...   0B
<missing>      8 months ago     /bin/sh -c #(nop) WORKDIR /usr/local/tomcat     0B
<missing>      8 months ago     /bin/sh -c mkdir -p "$CATALINA_HOME"            0B
<missing>      8 months ago     /bin/sh -c #(nop)  ENV PATH=/usr/local/tomca...   0B
<missing>      8 months ago     /bin/sh -c #(nop)  ENV CATALINA_HOME=/usr/lo...   0B
<missing>      8 months ago     /bin/sh -c #(nop)  CMD ["jshell"]               0B
<missing>      8 months ago     /bin/sh -c set -eux;   arch="$(dpkg --print-...   343MB
<missing>      8 months ago     /bin/sh -c #(nop)  ENV JAVA_VERSION=11.0.13     0B
<missing>      8 months ago     /bin/sh -c #(nop)  ENV LANG=C.UTF-8             0B
<missing>      8 months ago     /bin/sh -c #(nop)  ENV PATH=/usr/local/openj...   0B
<missing>      8 months ago     /bin/sh -c { echo '#/bin/sh'; echo 'echo "$J...   27B
<missing>      8 months ago     /bin/sh -c #(nop)  ENV JAVA_HOME=/usr/local/...   0B
<missing>      8 months ago     /bin/sh -c set -eux;  apt-get update;  apt-g...   11.3MB
<missing>      8 months ago     /bin/sh -c apt-get update && apt-get install...   152MB
<missing>      8 months ago     /bin/sh -c set -ex;  if ! command -v gpg > /...   18.9MB
<missing>      8 months ago     /bin/sh -c set -eux;  apt-get update;  apt-g...   10.7MB
<missing>      8 months ago     /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>      8 months ago     /bin/sh -c #(nop) ADD file:c03517c5ddbed4053...   124MB
# 删除当前的容器
[root@centos7 ~]# docker rm -f 38c
38c
[root@centos7 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
利用新镜像启动容器
[root@centos7 ~]# docker run -d -p 8080:8080 --name tomcat tomcat:9.0.37-v1
[root@centos7 ~]# docker ps
CONTAINER ID   IMAGE              COMMAND             CREATED        STATUS         PORTS                                       NAMES
ff4f232c7ce0   tomcat:9.0.37-v1   "catalina.sh run"   15 hours ago   Up 5 minutes   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   tomcat
[root@centos7 ~]# hostname -I
10.0.0.14 172.17.0.1
测试新镜像启动的容器

浏览器访问 http://10.0.0.14:8080 出现画面即可

基于Ubuntu的基础镜像利用apt安装手动制作nginx的镜像

# 启动容器

[root@centos7 ~]# docker run -it -p 80 --name nginx_ubuntu ubuntu bash

# 查看ubuntu系统信息

root@d35021705364:/# cat /etc/os-release

NAME="Ubuntu"

VERSION="20.04.3 LTS (Focal Fossa)"

ID=ubuntu

ID_LIKE=debian

PRETTY_NAME="Ubuntu 20.04.3 LTS"

VERSION_ID="20.04"

HOME_URL="https://www.ubuntu.com/"

SUPPORT_URL="https://help.ubuntu.com/"

BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"

PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"

VERSION_CODENAME=focal

UBUNTU_CODENAME=focal

# 更新源

root@d35021705364:/# apt update

Get:1 http://security.ubuntu.com/ubuntu focal-security InRelease [114 kB]

Get:2 http://archive.ubuntu.com/ubuntu focal InRelease [265 kB]

Get:3 http://security.ubuntu.com/ubuntu focal-security/universe amd64 Packages [888 kB]

Get:4 http://archive.ubuntu.com/ubuntu focal-updates InRelease [114 kB]

Get:5 http://security.ubuntu.com/ubuntu focal-security/multiverse amd64 Packages [27.5 kB]

Get:6 http://security.ubuntu.com/ubuntu focal-security/main amd64 Packages [2091 kB]

Get:7 http://archive.ubuntu.com/ubuntu focal-backports InRelease [108 kB]

Get:8 http://archive.ubuntu.com/ubuntu focal/restricted amd64 Packages [33.4 kB]

Get:9 http://archive.ubuntu.com/ubuntu focal/multiverse amd64 Packages [177 kB]

Get:10 http://security.ubuntu.com/ubuntu focal-security/restricted amd64 Packages [1462 kB]

Get:11 http://archive.ubuntu.com/ubuntu focal/main amd64 Packages [1275 kB]

Get:12 http://archive.ubuntu.com/ubuntu focal/universe amd64 Packages [11.3 MB]

Get:13 http://archive.ubuntu.com/ubuntu focal-updates/universe amd64 Packages [1183 kB]

Get:14 http://archive.ubuntu.com/ubuntu focal-updates/restricted amd64 Packages [1572 kB]

Get:15 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages [2547 kB]

Get:16 http://archive.ubuntu.com/ubuntu focal-updates/multiverse amd64 Packages [30.2 kB]

Get:17 http://archive.ubuntu.com/ubuntu focal-backports/universe amd64 Packages [27.4 kB]

Get:18 http://archive.ubuntu.com/ubuntu focal-backports/main amd64 Packages [55.1 kB]

Fetched 23.3 MB in 28s (841 kB/s)

Reading package lists... Done

Building dependency tree

Reading state information... Done

34 packages can be upgraded. Run 'apt list --upgradable' to see them.

# 安装nginx

root@d35021705364:/# apt install -y nginx

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following additional packages will be installed:

  fontconfig-config fonts-dejavu-core iproute2 libatm1 libbsd0 libcap2 libcap2-bin libelf1 libexpat1 libfontconfig1 libfreetype6 libgd3 libicu66

  libjbig0 libjpeg-turbo8 libjpeg8 libmnl0 libnginx-mod-http-image-filter libnginx-mod-http-xslt-filter libnginx-mod-mail libnginx-mod-stream

  libpam-cap libpng16-16 libssl1.1 libtiff5 libwebp6 libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxml2 libxpm4 libxslt1.1 libxtables12

  nginx-common nginx-core tzdata ucf

Suggested packages:

  iproute2-doc libgd-tools fcgiwrap nginx-doc ssl-cert

The following NEW packages will be installed:

  fontconfig-config fonts-dejavu-core iproute2 libatm1 libbsd0 libcap2 libcap2-bin libelf1 libexpat1 libfontconfig1 libfreetype6 libgd3 libicu66

  libjbig0 libjpeg-turbo8 libjpeg8 libmnl0 libnginx-mod-http-image-filter libnginx-mod-http-xslt-filter libnginx-mod-mail libnginx-mod-stream

  libpam-cap libpng16-16 libssl1.1 libtiff5 libwebp6 libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxml2 libxpm4 libxslt1.1 libxtables12 nginx

  nginx-common nginx-core tzdata ucf

0 upgraded, 40 newly installed, 0 to remove and 34 not upgraded.

Need to get 15.8 MB of archives.

After this operation, 60.8 MB of additional disk space will be used.

Get:1 http://archive.ubuntu.com/ubuntu focal/main amd64 libbsd0 amd64 0.10.0-1 [45.4 kB]

Get:2 http://archive.ubuntu.com/ubuntu focal/main amd64 libcap2 amd64 1:2.32-1 [15.9 kB]

Get:3 http://archive.ubuntu.com/ubuntu focal/main amd64 libelf1 amd64 0.176-1.1build1 [44.0 kB]

Get:4 http://archive.ubuntu.com/ubuntu focal/main amd64 libmnl0 amd64 1.0.4-2 [12.3 kB]

Get:5 http://archive.ubuntu.com/ubuntu focal/main amd64 libxtables12 amd64 1.8.4-3ubuntu2 [28.4 kB]

Get:6 http://archive.ubuntu.com/ubuntu focal/main amd64 libcap2-bin amd64 1:2.32-1 [26.2 kB]

Get:7 http://archive.ubuntu.com/ubuntu focal/main amd64 iproute2 amd64 5.5.0-1ubuntu1 [858 kB]

Get:8 http://archive.ubuntu.com/ubuntu focal/main amd64 libatm1 amd64 1:2.5.1-4 [21.8 kB]

Get:9 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libexpat1 amd64 2.2.9-1ubuntu0.4 [74.4 kB]

Get:10 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 tzdata all 2022a-0ubuntu0.20.04 [294 kB]

Get:11 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libicu66 amd64 66.1-2ubuntu2.1 [8515 kB]

Get:12 http://archive.ubuntu.com/ubuntu focal/main amd64 libpam-cap amd64 1:2.32-1 [8352 B]

Get:13 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libssl1.1 amd64 1.1.1f-1ubuntu2.16 [1321 kB]

Get:14 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libxml2 amd64 2.9.10+dfsg-5ubuntu0.20.04.4 [640 kB]

Get:15 http://archive.ubuntu.com/ubuntu focal/main amd64 ucf all 3.0038+nmu1 [51.6 kB]

Get:16 http://archive.ubuntu.com/ubuntu focal/main amd64 libpng16-16 amd64 1.6.37-2 [179 kB]

Get:17 http://archive.ubuntu.com/ubuntu focal/main amd64 libxau6 amd64 1:1.0.9-0ubuntu1 [7488 B]

Get:18 http://archive.ubuntu.com/ubuntu focal/main amd64 libxdmcp6 amd64 1:1.1.3-0ubuntu1 [10.6 kB]

Get:19 http://archive.ubuntu.com/ubuntu focal/main amd64 libxcb1 amd64 1.14-2 [44.7 kB]

Get:20 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libx11-data all 2:1.6.9-2ubuntu1.2 [113 kB]

Get:21 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libx11-6 amd64 2:1.6.9-2ubuntu1.2 [575 kB]

Get:22 http://archive.ubuntu.com/ubuntu focal/main amd64 fonts-dejavu-core all 2.37-1 [1041 kB]

Get:23 http://archive.ubuntu.com/ubuntu focal/main amd64 fontconfig-config all 2.13.1-2ubuntu3 [28.8 kB]

Get:24 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libfreetype6 amd64 2.10.1-2ubuntu0.2 [341 kB]

Get:25 http://archive.ubuntu.com/ubuntu focal/main amd64 libfontconfig1 amd64 2.13.1-2ubuntu3 [114 kB]

Get:26 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libjpeg-turbo8 amd64 2.0.3-0ubuntu1.20.04.1 [117 kB]

Get:27 http://archive.ubuntu.com/ubuntu focal/main amd64 libjpeg8 amd64 8c-2ubuntu8 [2194 B]

Get:28 http://archive.ubuntu.com/ubuntu focal/main amd64 libjbig0 amd64 2.1-3.1build1 [26.7 kB]

Get:29 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libwebp6 amd64 0.6.1-2ubuntu0.20.04.1 [185 kB]

Get:30 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libtiff5 amd64 4.1.0+git191117-2ubuntu0.20.04.3 [162 kB]

Get:31 http://archive.ubuntu.com/ubuntu focal/main amd64 libxpm4 amd64 1:3.5.12-1 [34.0 kB]

Get:32 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libgd3 amd64 2.2.5-5.2ubuntu2.1 [118 kB]

Get:33 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 nginx-common all 1.18.0-0ubuntu1.3 [37.7 kB]

Get:34 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libnginx-mod-http-image-filter amd64 1.18.0-0ubuntu1.3 [14.8 kB]

Get:35 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libxslt1.1 amd64 1.1.34-4ubuntu0.20.04.1 [151 kB]

Get:36 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libnginx-mod-http-xslt-filter amd64 1.18.0-0ubuntu1.3 [13.0 kB]

Get:37 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libnginx-mod-mail amd64 1.18.0-0ubuntu1.3 [42.8 kB]

Get:38 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libnginx-mod-stream amd64 1.18.0-0ubuntu1.3 [67.3 kB]

Get:39 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 nginx-core amd64 1.18.0-0ubuntu1.3 [425 kB]

Get:40 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 nginx all 1.18.0-0ubuntu1.3 [3620 B]

Fetched 15.8 MB in 9s (1680 kB/s)

debconf: delaying package configuration, since apt-utils is not installed

Selecting previously unselected package libbsd0:amd64.

(Reading database ... 4127 files and directories currently installed.)

Preparing to unpack .../00-libbsd0_0.10.0-1_amd64.deb ...

Unpacking libbsd0:amd64 (0.10.0-1) ...

Selecting previously unselected package libcap2:amd64.

Preparing to unpack .../01-libcap2_1%3a2.32-1_amd64.deb ...

Unpacking libcap2:amd64 (1:2.32-1) ...

Selecting previously unselected package libelf1:amd64.

Preparing to unpack .../02-libelf1_0.176-1.1build1_amd64.deb ...

Unpacking libelf1:amd64 (0.176-1.1build1) ...

Selecting previously unselected package libmnl0:amd64.

Preparing to unpack .../03-libmnl0_1.0.4-2_amd64.deb ...

Unpacking libmnl0:amd64 (1.0.4-2) ...

Selecting previously unselected package libxtables12:amd64.

Preparing to unpack .../04-libxtables12_1.8.4-3ubuntu2_amd64.deb ...

Unpacking libxtables12:amd64 (1.8.4-3ubuntu2) ...

Selecting previously unselected package libcap2-bin.

Preparing to unpack .../05-libcap2-bin_1%3a2.32-1_amd64.deb ...

Unpacking libcap2-bin (1:2.32-1) ...

Selecting previously unselected package iproute2.

Preparing to unpack .../06-iproute2_5.5.0-1ubuntu1_amd64.deb ...

Unpacking iproute2 (5.5.0-1ubuntu1) ...

Selecting previously unselected package libatm1:amd64.

Preparing to unpack .../07-libatm1_1%3a2.5.1-4_amd64.deb ...

Unpacking libatm1:amd64 (1:2.5.1-4) ...

Selecting previously unselected package libexpat1:amd64.

Preparing to unpack .../08-libexpat1_2.2.9-1ubuntu0.4_amd64.deb ...

Unpacking libexpat1:amd64 (2.2.9-1ubuntu0.4) ...

Selecting previously unselected package tzdata.

Preparing to unpack .../09-tzdata_2022a-0ubuntu0.20.04_all.deb ...

Unpacking tzdata (2022a-0ubuntu0.20.04) ...

Selecting previously unselected package libicu66:amd64.

Preparing to unpack .../10-libicu66_66.1-2ubuntu2.1_amd64.deb ...

Unpacking libicu66:amd64 (66.1-2ubuntu2.1) ...

Selecting previously unselected package libpam-cap:amd64.

Preparing to unpack .../11-libpam-cap_1%3a2.32-1_amd64.deb ...

Unpacking libpam-cap:amd64 (1:2.32-1) ...

Selecting previously unselected package libssl1.1:amd64.

Preparing to unpack .../12-libssl1.1_1.1.1f-1ubuntu2.16_amd64.deb ...

Unpacking libssl1.1:amd64 (1.1.1f-1ubuntu2.16) ...

Selecting previously unselected package libxml2:amd64.

Preparing to unpack .../13-libxml2_2.9.10+dfsg-5ubuntu0.20.04.4_amd64.deb ...

Unpacking libxml2:amd64 (2.9.10+dfsg-5ubuntu0.20.04.4) ...

Selecting previously unselected package ucf.

Preparing to unpack .../14-ucf_3.0038+nmu1_all.deb ...

Moving old data out of the way

Unpacking ucf (3.0038+nmu1) ...

Selecting previously unselected package libpng16-16:amd64.

Preparing to unpack .../15-libpng16-16_1.6.37-2_amd64.deb ...

Unpacking libpng16-16:amd64 (1.6.37-2) ...

Selecting previously unselected package libxau6:amd64.

Preparing to unpack .../16-libxau6_1%3a1.0.9-0ubuntu1_amd64.deb ...

Unpacking libxau6:amd64 (1:1.0.9-0ubuntu1) ...

Selecting previously unselected package libxdmcp6:amd64.

Preparing to unpack .../17-libxdmcp6_1%3a1.1.3-0ubuntu1_amd64.deb ...

Unpacking libxdmcp6:amd64 (1:1.1.3-0ubuntu1) ...

Selecting previously unselected package libxcb1:amd64.

Preparing to unpack .../18-libxcb1_1.14-2_amd64.deb ...

Unpacking libxcb1:amd64 (1.14-2) ...

Selecting previously unselected package libx11-data.

Preparing to unpack .../19-libx11-data_2%3a1.6.9-2ubuntu1.2_all.deb ...

Unpacking libx11-data (2:1.6.9-2ubuntu1.2) ...

Selecting previously unselected package libx11-6:amd64.

Preparing to unpack .../20-libx11-6_2%3a1.6.9-2ubuntu1.2_amd64.deb ...

Unpacking libx11-6:amd64 (2:1.6.9-2ubuntu1.2) ...

Selecting previously unselected package fonts-dejavu-core.

Preparing to unpack .../21-fonts-dejavu-core_2.37-1_all.deb ...

Unpacking fonts-dejavu-core (2.37-1) ...

Selecting previously unselected package fontconfig-config.

Preparing to unpack .../22-fontconfig-config_2.13.1-2ubuntu3_all.deb ...

Unpacking fontconfig-config (2.13.1-2ubuntu3) ...

Selecting previously unselected package libfreetype6:amd64.

Preparing to unpack .../23-libfreetype6_2.10.1-2ubuntu0.2_amd64.deb ...

Unpacking libfreetype6:amd64 (2.10.1-2ubuntu0.2) ...

Selecting previously unselected package libfontconfig1:amd64.

Preparing to unpack .../24-libfontconfig1_2.13.1-2ubuntu3_amd64.deb ...

Unpacking libfontconfig1:amd64 (2.13.1-2ubuntu3) ...

Selecting previously unselected package libjpeg-turbo8:amd64.

Preparing to unpack .../25-libjpeg-turbo8_2.0.3-0ubuntu1.20.04.1_amd64.deb ...

Unpacking libjpeg-turbo8:amd64 (2.0.3-0ubuntu1.20.04.1) ...

Selecting previously unselected package libjpeg8:amd64.

Preparing to unpack .../26-libjpeg8_8c-2ubuntu8_amd64.deb ...

Unpacking libjpeg8:amd64 (8c-2ubuntu8) ...

Selecting previously unselected package libjbig0:amd64.

Preparing to unpack .../27-libjbig0_2.1-3.1build1_amd64.deb ...

Unpacking libjbig0:amd64 (2.1-3.1build1) ...

Selecting previously unselected package libwebp6:amd64.

Preparing to unpack .../28-libwebp6_0.6.1-2ubuntu0.20.04.1_amd64.deb ...

Unpacking libwebp6:amd64 (0.6.1-2ubuntu0.20.04.1) ...

Selecting previously unselected package libtiff5:amd64.

Preparing to unpack .../29-libtiff5_4.1.0+git191117-2ubuntu0.20.04.3_amd64.deb ...

Unpacking libtiff5:amd64 (4.1.0+git191117-2ubuntu0.20.04.3) ...

Selecting previously unselected package libxpm4:amd64.

Preparing to unpack .../30-libxpm4_1%3a3.5.12-1_amd64.deb ...

Unpacking libxpm4:amd64 (1:3.5.12-1) ...

Selecting previously unselected package libgd3:amd64.

Preparing to unpack .../31-libgd3_2.2.5-5.2ubuntu2.1_amd64.deb ...

Unpacking libgd3:amd64 (2.2.5-5.2ubuntu2.1) ...

Selecting previously unselected package nginx-common.

Preparing to unpack .../32-nginx-common_1.18.0-0ubuntu1.3_all.deb ...

Unpacking nginx-common (1.18.0-0ubuntu1.3) ...

Selecting previously unselected package libnginx-mod-http-image-filter.

Preparing to unpack .../33-libnginx-mod-http-image-filter_1.18.0-0ubuntu1.3_amd64.deb ...

Unpacking libnginx-mod-http-image-filter (1.18.0-0ubuntu1.3) ...

Selecting previously unselected package libxslt1.1:amd64.

Preparing to unpack .../34-libxslt1.1_1.1.34-4ubuntu0.20.04.1_amd64.deb ...

Unpacking libxslt1.1:amd64 (1.1.34-4ubuntu0.20.04.1) ...

Selecting previously unselected package libnginx-mod-http-xslt-filter.

Preparing to unpack .../35-libnginx-mod-http-xslt-filter_1.18.0-0ubuntu1.3_amd64.deb ...

Unpacking libnginx-mod-http-xslt-filter (1.18.0-0ubuntu1.3) ...

Selecting previously unselected package libnginx-mod-mail.

Preparing to unpack .../36-libnginx-mod-mail_1.18.0-0ubuntu1.3_amd64.deb ...

Unpacking libnginx-mod-mail (1.18.0-0ubuntu1.3) ...

Selecting previously unselected package libnginx-mod-stream.

Preparing to unpack .../37-libnginx-mod-stream_1.18.0-0ubuntu1.3_amd64.deb ...

Unpacking libnginx-mod-stream (1.18.0-0ubuntu1.3) ...

Selecting previously unselected package nginx-core.

Preparing to unpack .../38-nginx-core_1.18.0-0ubuntu1.3_amd64.deb ...

Unpacking nginx-core (1.18.0-0ubuntu1.3) ...

Selecting previously unselected package nginx.

Preparing to unpack .../39-nginx_1.18.0-0ubuntu1.3_all.deb ...

Unpacking nginx (1.18.0-0ubuntu1.3) ...

Setting up libexpat1:amd64 (2.2.9-1ubuntu0.4) ...

Setting up libxau6:amd64 (1:1.0.9-0ubuntu1) ...

Setting up libssl1.1:amd64 (1.1.1f-1ubuntu2.16) ...

debconf: unable to initialize frontend: Dialog

debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76.)

debconf: falling back to frontend: Readline

debconf: unable to initialize frontend: Readline

debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.30.0 /usr/local/share/perl/5.30.0 /usr/lib/x86_64-linux-gnu/perl5/5.30 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.30 /usr/share/perl/5.30 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.)

debconf: falling back to frontend: Teletype

Setting up nginx-common (1.18.0-0ubuntu1.3) ...

debconf: unable to initialize frontend: Dialog

debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76.)

debconf: falling back to frontend: Readline

debconf: unable to initialize frontend: Readline

debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.30.0 /usr/local/share/perl/5.30.0 /usr/lib/x86_64-linux-gnu/perl5/5.30 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.30 /usr/share/perl/5.30 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.)

debconf: falling back to frontend: Teletype

Setting up libatm1:amd64 (1:2.5.1-4) ...

Setting up libjbig0:amd64 (2.1-3.1build1) ...

Setting up libcap2:amd64 (1:2.32-1) ...

Setting up tzdata (2022a-0ubuntu0.20.04) ...

debconf: unable to initialize frontend: Dialog

debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76.)

debconf: falling back to frontend: Readline

debconf: unable to initialize frontend: Readline

debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.30.0 /usr/local/share/perl/5.30.0 /usr/lib/x86_64-linux-gnu/perl5/5.30 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.30 /usr/share/perl/5.30 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.)

debconf: falling back to frontend: Teletype

Configuring tzdata

------------------



Please select the geographic area in which you live. Subsequent configuration questions will narrow this down by presenting a list of cities,

representing the time zones in which they are located.



  1. Africa   3. Antarctica  5. Arctic  7. Atlantic  9. Indian    11. SystemV  13. Etc

  2. America  4. Australia   6. Asia    8. Europe    10. Pacific  12. US

Geographic area: 6



Please select the city or region corresponding to your time zone.



  1. Aden      13. Barnaul     25. Dushanbe     37. Jerusalem     49. Macau         61. Pyongyang      73. Taipei         85. Vientiane

  2. Almaty    14. Beirut      26. Famagusta    38. Kabul         50. Magadan       62. Qatar          74. Tashkent       86. Vladivostok

  3. Amman     15. Bishkek     27. Gaza         39. Kamchatka     51. Makassar      63. Qostanay       75. Tbilisi        87. Yakutsk

  4. Anadyr    16. Brunei      28. Harbin       40. Karachi       52. Manila        64. Qyzylorda      76. Tehran         88. Yangon

  5. Aqtau     17. Chita       29. Hebron       41. Kashgar       53. Muscat        65. Rangoon        77. Tel_Aviv       89. Yekaterinburg

  6. Aqtobe    18. Choibalsan  30. Ho_Chi_Minh  42. Kathmandu     54. Nicosia       66. Riyadh         78. Thimphu        90. Yerevan

  7. Ashgabat  19. Chongqing   31. Hong_Kong    43. Khandyga      55. Novokuznetsk  67. Sakhalin       79. Tokyo

  8. Atyrau    20. Colombo     32. Hovd         44. Kolkata       56. Novosibirsk   68. Samarkand      80. Tomsk

  9. Baghdad   21. Damascus    33. Irkutsk      45. Krasnoyarsk   57. Omsk          69. Seoul          81. Ujung_Pandang

  10. Bahrain  22. Dhaka       34. Istanbul     46. Kuala_Lumpur  58. Oral          70. Shanghai       82. Ulaanbaatar

  11. Baku     23. Dili        35. Jakarta      47. Kuching       59. Phnom_Penh    71. Singapore      83. Urumqi

  12. Bangkok  24. Dubai       36. Jayapura     48. Kuwait        60. Pontianak     72. Srednekolymsk  84. Ust-Nera

Time zone: 70  # 配置时区





Current default time zone: 'Asia/Shanghai'

Local time is now:      Wed Aug 24 15:05:46 CST 2022.

Universal Time is now:  Wed Aug 24 07:05:46 UTC 2022.

Run 'dpkg-reconfigure tzdata' if you wish to change it.



Setting up libcap2-bin (1:2.32-1) ...

Setting up libx11-data (2:1.6.9-2ubuntu1.2) ...

Setting up libpng16-16:amd64 (1.6.37-2) ...

Setting up libmnl0:amd64 (1.0.4-2) ...

Setting up libwebp6:amd64 (0.6.1-2ubuntu0.20.04.1) ...

Setting up fonts-dejavu-core (2.37-1) ...

Setting up ucf (3.0038+nmu1) ...

debconf: unable to initialize frontend: Dialog

debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76.)

debconf: falling back to frontend: Readline

debconf: unable to initialize frontend: Readline

debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.30.0 /usr/local/share/perl/5.30.0 /usr/lib/x86_64-linux-gnu/perl5/5.30 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.30 /usr/share/perl/5.30 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.)

debconf: falling back to frontend: Teletype

Setting up libjpeg-turbo8:amd64 (2.0.3-0ubuntu1.20.04.1) ...

Setting up libxtables12:amd64 (1.8.4-3ubuntu2) ...

Setting up libbsd0:amd64 (0.10.0-1) ...

Setting up libelf1:amd64 (0.176-1.1build1) ...

Setting up libpam-cap:amd64 (1:2.32-1) ...

debconf: unable to initialize frontend: Dialog

debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76.)

debconf: falling back to frontend: Readline

debconf: unable to initialize frontend: Readline

debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.30.0 /usr/local/share/perl/5.30.0 /usr/lib/x86_64-linux-gnu/perl5/5.30 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.30 /usr/share/perl/5.30 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.)

debconf: falling back to frontend: Teletype

Setting up libjpeg8:amd64 (8c-2ubuntu8) ...

Setting up libnginx-mod-mail (1.18.0-0ubuntu1.3) ...

Setting up libxdmcp6:amd64 (1:1.1.3-0ubuntu1) ...

Setting up libxcb1:amd64 (1.14-2) ...

Setting up fontconfig-config (2.13.1-2ubuntu3) ...

Setting up iproute2 (5.5.0-1ubuntu1) ...

debconf: unable to initialize frontend: Dialog

debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76.)

debconf: falling back to frontend: Readline

debconf: unable to initialize frontend: Readline

debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.30.0 /usr/local/share/perl/5.30.0 /usr/lib/x86_64-linux-gnu/perl5/5.30 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.30 /usr/share/perl/5.30 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.)

debconf: falling back to frontend: Teletype

Setting up libicu66:amd64 (66.1-2ubuntu2.1) ...

Setting up libnginx-mod-stream (1.18.0-0ubuntu1.3) ...

Setting up libfreetype6:amd64 (2.10.1-2ubuntu0.2) ...

Setting up libx11-6:amd64 (2:1.6.9-2ubuntu1.2) ...

Setting up libtiff5:amd64 (4.1.0+git191117-2ubuntu0.20.04.3) ...

Setting up libfontconfig1:amd64 (2.13.1-2ubuntu3) ...

Setting up libxml2:amd64 (2.9.10+dfsg-5ubuntu0.20.04.4) ...

Setting up libxpm4:amd64 (1:3.5.12-1) ...

Setting up libgd3:amd64 (2.2.5-5.2ubuntu2.1) ...

Setting up libxslt1.1:amd64 (1.1.34-4ubuntu0.20.04.1) ...

Setting up libnginx-mod-http-image-filter (1.18.0-0ubuntu1.3) ...

Setting up libnginx-mod-http-xslt-filter (1.18.0-0ubuntu1.3) ...

Setting up nginx-core (1.18.0-0ubuntu1.3) ...

invoke-rc.d: could not determine current runlevel

invoke-rc.d: policy-rc.d denied execution of start.

Setting up nginx (1.18.0-0ubuntu1.3) ...

Processing triggers for libc-bin (2.31-0ubuntu9.2) ...

# 查看nginx版本

root@d35021705364:/# nginx -v

nginx version: nginx/1.18.0 (Ubuntu)

root@d35021705364:/# grep include /etc/nginx/nginx.conf

include /etc/nginx/modules-enabled/*.conf;

  include /etc/nginx/mime.types;

  include /etc/nginx/conf.d/*.conf;

  include /etc/nginx/sites-enabled/*;

root@d35021705364:/# grep root /etc/nginx/sites-enabled/default

  root /var/www/html;

  # deny access to .htaccess files, if Apache's document root

# root /var/www/example.com;

root@d35021705364:/# echo Nginx website in Docker > /var/www/html/index.html

root@d35021705364:/# exit

exit



# 提交为镜像

[root@centos7 ~]# docker commit -a 'chensir' -m 'nginx-ubuntu:20.04' nginx_ubuntu nginx_ubuntu20.04:v1.18.0

sha256:b33b57cff5d3c68c56b5826490ddcb0c9e7751f2d275a9d6d1e43d63764f78b0

[root@centos7 ~]# docker images

REPOSITORY          TAG         IMAGE ID       CREATED         SIZE

nginx_ubuntu20.04   v1.18.0     b33b57cff5d3   5 seconds ago   169MB



# 从制作的新镜像启动容器并测试访问

[root@centos7 ~]# docker run -d -p 80 --name nginx-web nginx_ubuntu20.04:v1.18.0 nginx -g 'daemon off;'

06098c8bc2ec93978167950adfa5e827c75174aba306337165813a9e950b1972

[root@centos7 ~]# docker ps

CONTAINER ID   IMAGE                       COMMAND                  CREATED         STATUS         PORTS                                     NAMES

06098c8bc2ec   nginx_ubuntu20.04:v1.18.0   "nginx -g 'daemon of..."   2 seconds ago   Up 2 seconds   0.0.0.0:49162->80/tcp, :::49162->80/tcp   nginx-web

[root@centos7 ~]# docker ps

CONTAINER ID   IMAGE                       COMMAND                  CREATED         STATUS         PORTS                                     NAMES

06098c8bc2ec   nginx_ubuntu20.04:v1.18.0   "nginx -g 'daemon of..."   2 seconds ago   Up 2 seconds   0.0.0.0:49162->80/tcp, :::49162->80/tcp   nginx-web

[root@centos7 ~]# docker port nginx-web

80/tcp -> 0.0.0.0:49162

80/tcp -> :::49162

[root@centos7 ~]# curl 127.0.0.1:49162

Nginx website in Docker

基于CentOS的基础镜像利用yum安装手动制作nginx的镜像

[root@centos7 ~]# docker pull centos:centos7.7.1908

centos7.7.1908: Pulling from library/centos

f34b00c7da20: Pull complete

Digest: sha256:50752af5182c6cd5518e3e91d48f7ff0cba93d5d760a67ac140e2d63c4dd9efc

Status: Downloaded newer image for centos:centos7.7.1908

docker.io/library/centos:centos7.7.1908

[root@centos7 ~]# docker images

REPOSITORY          TAG              IMAGE ID       CREATED          SIZE

centos              centos7.7.1908   08d05d1d5859   2 years ago      204MB

[root@centos7 ~]# docker run -it centos:centos7.7.1908 bash



# 修改时区

[root@0b3db04f3a72 /]# rm -f /etc/localtime

[root@0b3db04f3a72 /]# ln -s ../usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 更改yum源

[root@0b3db04f3a72 /]# yum install -y wget

[root@0b3db04f3a72 /]# wget -P /etc/yum.repos.d/ http://mirrors.aliyun.com/repo/Centos-7.repo

[root@0b3db04f3a72 /]# wget -P /etc/yum.repos.d/ http://mirrors.aliyun.com/repo/epel-7.repo

[root@0b3db04f3a72 /]# yum install -y nginx



# 安装相关软件和工具

# yum 安装 nginx

[root@0b3db04f3a72 /]# yum install -y nginx

# 安装常用命令

[root@0b3db04f3a72 /]# yum install -y vim curl iproute net-tools

# 清理yum缓存

[root@0b3db04f3a72 /]# rm -rf /var/cache/yum/*



# 修改服务的配置信息关闭服务后台运行

# 关闭nginx后台运行

[root@0b3db04f3a72 /]# vim /etc/nginx/nginx.conf

user nginx;

daemon off; # 关闭后台运行



# 准备程序和数据

# 自定义web界面

[root@0b3db04f3a72 /]# rm -rf /usr/share/nginx/html/index.html

[root@0b3db04f3a72 /]# echo "Nginx Page in Docker" > /usr/share/nginx/html/index.html



# 提交为镜像

# docker commit命令在宿主机基于容器ID提交为镜像

[root@centos7 ~]# docker commit -a "chensir" -m "nginx yum v1" -c "EXPOSE 80 443" 0b3db04f3a72 chensir/centos-nginx:1.16.1.v1

sha256:3f649568eaca282c2ff0864d725bb0310862849e9393abfb14f49fa60d7071f7

[root@centos7 ~]# docker images

REPOSITORY             TAG              IMAGE ID       CREATED          SIZE

chensir/centos-nginx   1.16.1.v1        3f649568eaca   17 seconds ago   322MB

centos                 centos7.7.1908   08d05d1d5859   2 years ago      204MB



# 从制作的镜像启动容器

[root@centos7 ~]# docker run -d -p 8080:80 --name my-centos-nginx chensir/centos-nginx:1.16.1.v1 /usr/sbin/nginx

df983ecee256956f34af0ca6089331bd9bd1863ad24d35defef05c86e6cab5f2

[root@centos7 ~]# docker ps

CONTAINER ID   IMAGE                            COMMAND                  CREATED          STATUS          PORTS                                            NAMES

df983ecee256   chensir/centos-nginx:1.16.1.v1   "/usr/sbin/nginx"        5 seconds ago    Up 5 seconds    443/tcp, 0.0.0.0:8080->80/tcp, :::8080->80/tcp   my-centos-nginx



# 访问测试镜像

[root@centos7 ~]# curl 127.0.0.1:8080

Nginx Page in Docker

利用DockerFile文件执行docker build自动构建镜像

Dockerfile使用详解

Dockerfile介绍

Dockerfile是一种被Docker程序解释执行的脚本,由一条条的命令组成的,没条命令对应Linux下面的一条命令,Docker程序将这些DockerFile指令再翻译成真正的Linux命令,其有自己的书写方式和支持的命令,Docker程序读取DockerFile并根据指令生成Docker镜像,相比手动制作的镜像方式,DockerFile更能直观的展示镜像是怎么产生的,有了DockerFile,当后期有额外的需求时,只要在之前的DockerFile添加或者修改响应的命令即可重新的Docker镜像,避免了重复手动制作镜像的麻烦,类似与shell脚本一样,可以方便高效的制作镜像。

Docker守护程序Dockerfile逐一运行指令,如有必要,将每个指令的结果提交到新镜像,然后最终输出新镜像的ID。Docker守护程序将自动清理之前发送的上下文

请注意,每条指令都是独立运行的,并会导致创建新镜像,比如 RUN cd/tmp对下一条指令不会有任何影响。

Docker将尽可能用中间镜像层(缓存),以显著加速docker build命令的执行过程,这由Using cache控制台输出中的消息提示

Dockerfile镜像制作和使用流程

Dockerfile文件的制作镜像的分层结构

# 按照业务类型或系统类型等方式划分创建目录环境,方便后期镜像比较多的时候进行分类

[root@centos7 ~]# mkdir -p /data/dockerfile/{web/{nginx,apache,tomcat,jdk},system/{centos,ubuntu,alpine,debin}}

[root@centos7 ~]# tree /data/dockerfile/

/data/dockerfile/

├── system

│   ├── alpine

│   ├── centos

│   ├── debin

│   └── ubuntu

└── web

    ├── apache

    ├── jdk

    ├── nginx

    └── tomcat

Dockerfile文件格式

Dockerfile 是一个有特定语法格式的文本文件

Dockerfile 官方说明:https://docs.docker.com/engine/reference/builder/

帮助:man 5 dockerfile

Dockerfile文件说明

  • 每一行Dockerfile的指令开头,指令不区分大小写,但是惯例使用大写
  • 使用#开始作为注释
  • 每一行只支持一条指令,没调指令可以携带多个参数
  • 指令按文件的顺序从上至下进行执行
  • 每个指令的执行会生成一个新的镜像层,为了减少分层和镜像大小,尽可能将多条指令合并成一条指令
  • 制作镜像一般可能需要反复多次,每次执行Dockerfile都按顺序执行,从头开始,已经执行过的指令已经缓存,不需要在执行,如果后续有一行新的指令没执行过,其往后的指令将会重新执行,所以为加速镜像制作,将最常变化的内容放下dockerfile的文件的后面

Dockerfile相关指令

ADD

COPY

ENV

EXPOSE

FROM

LABEL

STOPSIGNAL

USER

VOLUME

WORKDIR
FROM:指定基础镜像

定制镜像,需要先有一个基础镜像,在这个基础镜像上进行定制。

FROM 就是指定基础镜像,此指令通常必须放在Dockerfile文件第一个非注释行。后续的指令都是运行于此基准镜像所提供的的运行环境

基础镜像可以是任何可用镜像文件,默认情况下,docker build会在docker主机上查找指定的镜像文件,若不存在,则会从docker hub registry上拉取所需的镜像文件。如果找不到指定的镜像文件,docker build会返回一个错误信息
如何选择合适的镜像呢?

对于不同的软件官方都提供了相关的docker镜像,比如:nginx、redis、mysql、httpd、tomcat等服务类的镜像,也有操作系统类,如:centos、ubuntu、debian等。建议使用官方镜像,比较安全。

FROM [--platform=<platform>] <image> [AS <name>]

FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]

FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]



# 说明:

--platform 指定镜像的平台,比如:linux/amd64,linux/arm64,or windows/amd64

tag 和 digest是可选项,如果不指定,默认为latest

说明:关于scrach镜像

FROM scratch # 所有镜像的起源镜像,相当于object类

参考链接:

https://hub.docker.com/_/scratch?tab=description

https://docs.docker.com/develop/develop-images/baseimages/

该镜像是一个空的镜像,可以用于构建busybox等超小镜像,可以说是真正的从零开始构建属于自己的镜像

该镜像在构建基础镜像(例如Debian和busybox)或超最小镜像(仅包含一个二进制文件及其所需内容,例如:hello-world)的上下文中最有用。



# 示例

FROM ubuntu

FROM ubuntu:bionic

FROM debian:buster-slim
LABEL:指定镜像元数据

可以指定镜像元数据,如:镜像作者等

LABEL <key>=<value> <key>=<value> <key>:<value>...



# 示例

LABEL "com.example.vendor"="ACME Incorporated"

LABEL com.example.label-with-value="foo"

LABEL version="1.0"

LABEL description="This text illustrates that label-values can span multiple lines"

一个镜像可以有多个label,还可以写在一行中,即多个标签写法,可以减少镜像的大小

# 多标签写法

LABEL multi.label1="value1" multi.label2="value2" other="value3"

# 多行格式

LABEL multi.label1="value1" \

      multi.label2="value2" \

      other="value3"

docker inspect 命令可以查看LABEL

docker inspect centos:centos7.7.1908



"Labels": {

  "org.label-schema.build-date": "20191024",

  "org.label-schema.license": "GPLv2",

  "org.label-schema.name": "CentOS Base Image",

  "org.label-schema.schema-version": "1.0",

  "org.label-schema.vendor": "CentOS"

}
RUN:执行shell命令

RUN指令用来在构建镜像阶段需要执行FROM指定镜像所支持的shell命令。

通常各种基础镜像一般都支持丰富的shell命令

注意:RUN可以写多个,每一个RUN指令都会建立一个镜像层,所以尽可能合并成一条指令,比如将多个shell命令通过&&连接一起成为一条指令

每个RUN都是独立运行的,和前一个RUN无关

# shell 格式:相当于 /bin/sh -c <命令> 此种形式支持环境变量

RUN <命令>



# exec 格式:此种形式不支持环境变量,注意:是双引号,不能是单引号

RUN ["可执行文件","参数1","参数2"]



# exec格式可以指定其他shell

RUN ["/bin/bash","-c","echo hello chensir"]

说明

shell格式中,<command>通常是一个shell命令,且以 "/bin/sh -c" 来运行它,这意味着此进程在容器中的PID不为1,不能接受Unix信号,因此,当使用 docker stop <container> 命令停止容器时,此进程接收不到SIGTERM信号



exec格式中的参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面<paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以 "/bin/sh -c" 来发起,因此常见的shell操作如变量替换以及通配符(?,*)替换将不会进行;不过,如果要运行的命令依赖于shell特性的话,可以将其替代换为类似下面的格式。

RUN ["/bin/bash","-c","<executable>","<laram1>"]

# 示例

RUN echo '<h1>Hello,Docker</h1>' > /usr/share/nginx/html/index.html

RUN ["/bin/bash","-c","echo hello world"]

RUN yum install -y epel-release

 && yum install -y nginx

 && rm -rf /usr/share/nginx/html/* 

 && echo "<h1>docker test nginx</h1>" > /usr/share/nginx/html/index.html

 

# 示例多个前后RUN命令独立无关和shell命令不同

# world.txt并不存放在app内

RUN cd /app

RUN echo "hello" > world.txt
ENV:设置环境变量

ENV可以定义环境变量和值,会被后续指令(ENV,ADD,COPY,RUN等)通过 K E Y 或 KEY或 KEY或{KEY}进行引用,并在容器运行时保存

# 变量赋值格式1 此格式只能对一个key赋值,<key>之后的所有内容均会被视作其<value>的组成部分

ENV <key> <value> 



# 变量赋值格式2 此格式可以支持多个key赋值,定义多个变量建议使用,减少镜像层

# 如果<value>中包含空格,可以以反斜杠 \ 进行转义,也可以通过对<value>加引号进行标识;反斜杠也可用于读行

ENV <key1>=<value1> <key2>=<value2> ... 



# 只使用一次变量

RUN <key>=<value> <command>



# 引用变量

RUN $key



# 变量支持高级赋值格式

${key:-word}

${key:+word}

如果运行容器是需要修改变量,可以执行下面通过基于exec机制实现

注意:下面方式只影响容器运行时环境,而不影响构建镜像的过程,即只能覆盖 docker run时的环境变量,而不会影响docker build时的环境变量的值

docker run -e | --env <key>=<value>



# 说明

-e,--env list             # Set environment variables

   --env-file filename    # Read in a file of environment variables

   

# 示例:两种格式功能相同

# 格式1

ENV myName="John Doe" myDog=Rex\ The\ Dog myCat=fluffy

# 格式2

ENV myName John Doe

ENV myDog Rex The Dog

ENV myCat fluffy

[root@centos7 ~]# cat Dockerfile

FROM busybox

LABEL maintainer="chensir <root@chensir.ink>"

ENV NAME zhao xing chen

RUN touch $NAME.txt



[root@centos7 ~]# cat build.sh

#!/bin/bash

TAG=$1

docker build -t test:$TAG .



[root@centos7 ~]# ./build.sh v5.0
COPY:复制文本

复制本地宿主机的文件 到容器中

COPY [--chown=<user>:<group>] <src>... <dest>



# 路径中有空白字符时,建议使用此格式

COPY [--chown=<user>:<group>] ["<src>",..."<dest>"]

说明:

  • 可以是多个,可以使用通配符,通配符规则满足Go的filepath.Match规则

  • 必须是build上下文中的路径(Dockerfile 所在目录的相对路径),不能是其父目录中的文件

  • 如果是目录,则其内部文件或子目录会被递归复制,但目录自身不会被复制

  • 如果指定了多个,或在其中使用了通配符,则必须是一个目录,且必须是以 / 结尾

  • 可以是绝对路径或者是WORKDIR指定的相对路径

  • 使用COPY指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等

  • 如果事先不存在,它会被自动创建,这包括其父目录路径,即递归创建目录

    COPY hom* /mydir/

    COPY hom?.txt /mydir/

ADD:复制和解包文件

该命令可以认为是增强版的COPY,不仅支持COPY,还支持自动解包。可以将复制指定的文件到容器中

ADD [--chown=<user>:<group>] <src>...<dest>

ADD [--chown=<user>:<group>] ["<src>",..."<dest>"]

说明:

  • 可以是Dockerfile所在目录的一个相对路径;也可是一个URL;还可以是一个tar文件(自动解压)
  • 可以是绝对路径或是WORKDIR指定的相对路径
  • 如果是目录,只复目录中的内容,而非目录本身
  • 如果是一个URL,下载后的文件权限自动设置为600
  • 如果为URL且不以/结尾,则指定的文件将被下载并直接被创建,如果以/结尾,则文件名URL指定的文件将被直接下载并保存为/
  • 如果是一个本地文件系统上的打包文件,如:gz,bz2,xz,它将被解包,其行为类似 "tar -x" 命令,但是通过URL获取到的tar文件将不会自动展开
  • 如果有多个,或间接或直接使用了通配符,则必须是一个以/结尾的目录路径;如果不以/结尾。则被视作一个普通文件
CMD:容器启动命令

一个容器中需要持续运行的进程一般只有一个,CMD用来指定启动程序时默认执行的一个命令,且其运行结束后,容器也会停止,所以一般CMD指定的命令为持续运行且为前台命令

  • 如果docker run没有指定任何的执行命令或者dockerfile里面也没有ENTRYPOINT,那么开启容器时就会执行CMD指定的默认命令

  • 前面介绍过的RUN命令是在构建镜像执行的命令,注意二者的不同之处

  • 每个Dockerfile只能有一条CMD命令。如指定了多条,只有最后一条被执行

  • 如果用户启动容器时用docker run xxx指定运行的命令,则会覆盖CMD指定的命令

    使用exec执行,推荐方式,第一个参数必须是命令的全路径,此种形式而不支持环境变量

    CMD ["executable","param1","param2"]

    在 /bin/sh 中执行,提供给需要交互的应用;池中形式支持环境变量

    CMD command param1 param2

    提供给ENTRYPOINT命令的默认参数

    CMD ["param1","param2"]

    示例

    CMD ["nginx","-g","daemon off"]

ENTRYPOINT:入口点

功能类似于CMD,配置容器启动后执行的命令及参数

# 使用exec执行

ENTRYPOINT ["executable","param1","param2"]



# shell中执行

ENTRYPOINT command param1 param2
  • ENTRYPOINT不能被docker run提供的参数覆盖,而是追加,即如果docker run命令有参数,那么参数全部都会作为ENTRYPOINT的参数
  • 如果docker run后面没有额外的参数,但是Dockerfile中的CMD里有(即上面的第三种用法),即Dockerfile中即有CMD也有ENTRYPOINT,那么CMD的全部内容会作为ENYRTPOINT的参数
  • 如果docker run后面有额外参数,同时Dockerfile中既有CMD也有ENTRYPOINT,那么docker run后面的参数覆盖掉CMD参数内容,最终作为ENTRYPOINT的参数
  • 可以通过docker run - -entrypoint string参数在运行时替换,注意string不要加空格
  • 使用CMD要在运行时重新写命令本身,然后在后面才能追加运行参数,ENTRYPOINT则可以运行时无需重写命令皆可以直接接收新参数
  • 每个Dockerfile中只能有一个ENTRYPOINT,当指定多个时,只有最后一个生效
ARG:构建参数

ARG指令在build阶段指定变量,和ENV不同的是,容器运行时不会存在这些环境变量

ARG <name>[=<default value>]

如果和ENV同名,ENV覆盖ARG变量

可以用 docekr build --build-arg <参数名>=<值> 来覆盖

说明:ARG和FROM

# FROM指令支持由第一个FROM之前的任何ARG指令声明的变量

# 示例:

ARG CODE_VERSION=latest

FROM base:${CODE_VERSION}

CMD /code/run-app

FROM extras:${CODE_VERSION}

CMD /code/run-extras



# 在FROM之前声明的ARG在构建阶段之外,所以它不能在FROM之后的任何指令中使用。要使用在第一个FROM之前声明的ARG的默认值,请在构建阶段内使用没有值的SRG指令



# 示例:

ARG VERSION=latest

FROM busybox:$VERSION

ARG VERSION

RUN echo $VERSION > image_version
VOLUME:匿名卷

在容器中创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保存的数据等,一般会将宿主机上的目录挂载至VOLUME指令指定的容器目录。即使容器后期被删除,次宿主机的目录仍会保留,从而实现容器数据的持久保存

宿主机的目录为 /var/lib/docker/volumes/<volume_id>/_data

VOLUME <容器内路径>

VOLUME ["<容器内路径1","容器内路径2"]

注意:

  • Dockerfile中的VOLUME实现的是匿名数据卷,无法指定宿主机路径和容器目录的挂载关系

  • 通过docker rm -fv <容器ID> 可以删除容器的同时删除VOLUME指定的卷

    示例:在容器创建两个 /data/ , /data2的挂载点

    VOLUME ["/data1","/data2"]

EXPOSE:暴露端口

指定服务端的容器需要对外暴露(监听)的端口号,以实现容器与外部通信

EXPOSE仅仅是声明容器打算使用什么端口而已,并不会真正暴露端口,即不会自动在宿主机进行端口映射

因此,在启动容器时需要通过-P或-p,Docker主机才会真正分配一个端口转发到指定暴露的端口才可使用
注意:即使Dockerfile没有EXPOSE端口指令,也可以通过docker run -p临时暴露容器内程序真正监听的端口,所以EXPOSE相当于指定默认的暴露端口,可以通过docker run -P/-p 进行真正暴露

EXPOSE <port>[/ <protocol>] [<port>[/ <protocol>]...]

# 说明

<protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议



# 示例

EXPOSE 80 443

EXPOSE 11211/udp 11211/tcp
WORKDIR:指定工作目录

为后续的RUN、CMD、ENTRYPOINT指令配置工作目录,当运行容器后,进入容器内WORKDIR指定的默认目录

WORKDIR指定工作目录(或称当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR会自行创建

WORKDIR /path/to/workdir



# 示例

# 两次 RUN 独立运行,不在同一个目录

RUN cd /app

RUN echo "hello" > world.txt



# 如果想实现相同目录可以使用 WORKDIR

WORKDIR /app

RUN echo "hello" > world.txt



# 可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径

WORKDIR /a

WORKDIR b

WORKDIR c

RUN pwd

# 最终路径为 /a/b/c
ONBUILD:子镜像引用父镜像的指令

可以用来配置当构建当前镜像的子镜像时,会自动触发执行的命令,但在当前镜像构建时,并不会执行,即延迟到子镜像构建时才执行

ONBUILD [INSTRUCTION]



# Dockerfile使用如下的内容创建了镜像 image-A

ONBUILD ADD https://chensir.ink/pic/a.png /data

ONBUILD RUN rm -rf /*

ONBUILD RUN /usr/local/bin/python-build --dir /app/src...



# 如果基于image-A创建新的镜像image-B时,新的Dockerfile中使用FROM image-A指定基础竟像时,会自动执行ONBUILD指令内容,等价于在后面添加了两条指令。

FROM image-A

# Automatically run the following

ADD https://chensir.ink/pic/a.png /data

RUN /usr/local/bin/python-build --dir /app/src...

说明:

  • 尽管任何指令都可以注册成为触发器指令,但ONBUILD不能自我使用,且不会触发FROM和MAINTAINER指令
  • 使用ONBUILD指令的镜像,推荐在标签中注明,例如 ruby:1.9-onbuild
USER:指定当前用户

指定运行容器时的用户名或UID,后续的RUN也会使用指定用户

当服务不需要管理员权限时,可以通过该命令指定运行用户

这个用户必须是事先建立好的,否则无法切换

如果没有指定USER,默认是root身份执行

USER <user>[:<group>]

USER <UID>[:<GID>]



# 示例

RUN groupadd -r mysql && useradd -r -g mysql mysql

USER mysql
HEALTHCHECK:监控检查

检查容器的健康性

# 设置检查容器健康状况的命令

HEALTHCHECK [选项] CMD <命令>



# 如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK NONE



# HEALTHCHECK 支持下列选项:

--interval=<间隔>           # 两次健康检查的间隔,默认30秒

--timeout=<时长>            # 健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认30秒

--retries=<次数>            # 当连续失败指定次数后,则将容器状态视为 unhealthy,默认3次

--start-period=<FDURATION> # default:0s



# 检查结果返回值

0 # success

1 # unhealth

2 # reserved



# 示例

FROM nginx

RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/spt/lists/*

HEALTHCHECK --interval=5s --timeout=3s \

CMD curl -fs http://localhost/ || exit 1
STOPSIGNAL:退出容器信号

STOPSIGNAL指令设置将被发送到容器退出的系统调用信号。该信号可以是与内核syscall表中的位置匹配的有效无符号数字,也可以是SIGNAME格式的信号名称(如SIGKILL)

STOPSIGNAL signal
SHELL:指定shell

SHELL指令允许覆盖用于命令的shell形式的默认SHLL,必须在Dockerfile中以JSON形式编写SHELL指令。

SHELL ["executable","parameters"]

在Linux上默认SHELL程序 ["/bin/sh","-c"],在Windows上,默认SHELL程序为 ["cmd","/S","/C"]。

SHELL指令在Windows上特别有用,在Windows上有两个常用且往前不同的本机SHELL:cmd和powershell,以及包括sh在内的备用shell

SHELL指令可以出现多次。每个SHELL指令将覆盖所有先前的SHELL指令,并影响所有后续的指令

.dockerignore文件

与.gitignore文件类似,生成构建上下文时Docker客户端应忽略的文件和文件夹指定模式

.dockerignore使用Go的文件路径规则filepath.Match
完整的语法

#  # 以#开头的行为注释

*  # 匹配任何非分隔符字符序列

?  # 匹配任何单个非分隔符

\\ # 表示 \

** # 匹配任意数量的目录(包括零)例如 **/*.go 将排除在所有目录中以.go结尾的所有文件,包括构建上下文的根

!  # 表示取反,可用于排除例外情况



# 示例

# 排除 test 目录下的所有文件

test/*



# 排除 md 目录下的 xttblog.md 文件

md/xttblog.md



# 排除 xttblog 为前缀的文件和文件夹

xttblog?



# 排除所有目录下的 .sql文件夹

**/*.sql



# 除了README的md不排外,排除所有md文件,但不排除README-secret.md

*.md

!README*.md

README-secret.md



# 除了所有README的md文件以外的md都排除

*.md

README-sevret.md

!README*.md
dockerfile构建过程和指令总结
Dockerfile 构建过程
  • 从基础镜像运行一个容器
  • 执行一条指令,对容器做出修改
  • 执行类似docker commit的操作,提交一个新的中间镜像层(可以利用中间层镜像创建容器进项调试和排错)
  • 再基于刚提交的镜像运行一个新容器
  • 执行Dockerfile中的下一条指令,直至所有指令执行完毕
Dockerfile指令总结
BUILD RUN BOTH
FROM CMD WORKDIR
LABEL VOLUME USER
COPY EXPOSE ENV
ADD ENTRYPOINT
RUN
ONBUILD
.dockerignore

构建镜像docker build命令

docker build [OPTION] PATH | URL |-

说明:

PATH | URL | -   # 可以是本地路径,也可以是URL路径。如设置为 -,则从标准输入获取Dockerfile的内容

-f,--file string # Dockerfile文件名,默认为PATH/Dockerfile

--force-rm       # 总是删除中间层容器,创建镜像失败时,删除临时容器

--no-cache       # 不使用之前构建中创建的缓存

-q --quiet=false # 不显示Dockerfile的RUN运行的输出结果

--rm=true        # 创建镜像成功时,删除临时容器

-t --tag list    # 设置注册名称、镜像名称、标签。格式为 <注册名称>/<镜像名称>:<标签>(标签默认为latest)

Docker数据管理

容器数据管理介绍

Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层

如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版仍然存在,只是已经被读写层中该文件的副本所隐藏,即"写时复制(COW copy on write)机制"

如果将正在运行中的容器修改生成了新的数据,那么新产生的数据将会被复制到读写层,进行持久化保存,这个读写层也就是容器的工作目录,也为写时复制(COW)机制

Docker容器的分层

容器的数据分层目录

  • LowerDir:image镜像层,即镜像本身,只读
  • UpperDir:容器的上层,可读写,容器变化的数据存放在此处
  • MergedDir:容器的文件系统,使用Union FS(联合文件系统)将lowerdir和upperdir合并完成后给容器使用,最终呈现给用户的统一视图
  • WorkDir:容器在宿主机的工作目录,挂载后内容会被清空,且在使用过程中其内容用户不可见

每个镜像层目录中都包含了一个文件link,文件内容则是当前层对应的短标识符,镜像层的内容则存放在diff目录

删除容器后,所有数据目录都随之而删除

哪些数据需要持久化

有状态的协议

有状态协议就是通信双方要记住双方,并且共享一些信息。而无状态协议的通信每次都是独立的,与上一次的通信没什么关系。

"状态"可以理解为"记忆",有状态对应有记忆,无状态对应无记忆

  • 左侧是无状态的http请求服务,右侧为有状态
  • 下层为不需要存储的服务,上层为需要存储的部分服务

容器数据持久保存方式

如果要将写入到容器的数据永久保存,则需要建工人那个器中的数据保存到宿主机的指定目录

Docker的数据类型分为两种:

  • 数据卷(Data Volume):直接将宿主机目录挂载至容器的指定的目录,推荐使用此种方式,此方式较常用
  • 数据卷容器(Data Volume Container):间接使用宿主机空间,数据卷容器是将宿主机的目录挂载至一个专门的数据卷容器,然后让其他容器通过数据卷容器读写宿主机的数据,此方式不常用

数据卷(data volume)

数据卷的特点和使用

数据卷实际上就是宿主机上的目录或是文件,可以被直接mount到容器当中使用

实际生产环境中,需要针对不同类型的服务、不同类型的数据存储要求做相应的规划,最终保证服务的可扩展性、稳定性以及数据的安全性

数据卷使用场景
  • 数据库
  • 日志输出
  • 静态web页面
  • 应用配置文件
  • 多容器间目录或文件共享
数据卷的特点
  • 数据卷是目录或者文件,并且可以在多个容器之间共同使用,实现容器之间共享和重用
  • 对数据卷更改数据在所有容器里面会立即更新
  • 数据卷的数据可以持久保存,及时删除使用该容器卷的容器也不影响
  • 在容器里面的写入数据不会影响到镜像本身,即容器卷的变化不会影响镜像的更新
  • 依赖于宿主机目录,宿主机出问题,上面容器会受影响,当宿主机较多时,不方便统一管理
  • 匿名和命名数据卷在容器启动时初始化,如果容器使用的镜像在挂载点包含了数据,会开呗到新的初始化的数据卷中
数据卷使用方法

启动容器时,可以指定使用数据卷实现容器数据的持久化,数据卷有三种

  • 指定宿主机目录或文件:指定宿主机的具体路径和容器路径的挂载关系

  • 匿名卷:不指定数据名称,只指定容器内目录路径充当挂载点,docker自动指定宿主机的路径进行挂载

  • 命名卷:指定数据卷的名称和容器路径的挂载关系

    docker run 命令的以下格式可以实现数据卷

    -v,--volume=[host-src:]container-dest[:options]

    <options>

    ro 从容器内对此数据卷是只读,不写此项默认为可读可写

    rw 从容器内对此数据卷可读可写,此为默认值

    指定宿主机目录或文件格式:

    将宿主机目录挂载容器目录,两个目录都可自动创建

    -v <宿主机绝对路径的目录或文件>:<容器目录或文件>[:ro]

    匿名卷,只指定容器内路径,没有指定宿主机路径信息,宿主句自动生成/var/lib/docker/vlumes/<卷ID>/_data目录,并挂在至容器指定路径

    -v <容器内路径>

    示例

    docker run --name nginx -v /etc/nginx nginx

    命名卷将固定的存放在/var/lib/docker/volumes/<卷名>/_data

    -v <卷名>:<容器目录路径>

    可以通过以下命令事先创建,如没有事先创建卷名,docker run时也会自动创建卷

    docker volume create <卷名>

    示例

    docker run -d -p 80:80 --name nginx01 -v vol1:/usr/share/nginx/html nginx

    docker rm的 -v 选项可以上处容器时,同时删除相关联的匿名卷

    管理卷命令

    docker volume COMMAND

    Commands:

    create
    
    inspect
    
    ls
    
    prune
    
    rm
    
    
    
    # 查看数据卷的挂载关系
    
    docker inspect --format="{{.Mounts}}" <容器ID>
    
    
    
    # 删除所有数据卷
    
    docker volume rm `docker volume ls -q`
    

数据卷容器

数据卷容器介绍

在Dockerfile中创建的是匿名数据卷无法直接实现多个容器之间共享数据

数据卷容器最大的功能是可以让数据在多个docker容器之间共享

相当于先要创建一个后台运行的容器作为Server,用于提供数据卷,这个卷可以为其他容器提供数据存储服务,其他使用此卷的容器作为client端,但此方法不常使用

缺点:依赖一个Server的容器,所以此Server出了问题,其他Client容器都会受影响

使用数据卷容器

启动容器时,指定使用数据卷容器

docker run 命令的一下选项可以实现数据卷容器

--volume-from <数据卷容器>

数据卷容器总结

将提供的容器Server删除,已经运行的容器Client依然可以使用挂载的卷,因为容器是通过挂载访问数据的,但是无法创建新的卷容器客户端,但是再把卷容器Server创建后即可正常创建卷容器Client,此方式可以用于线上共享数据目录等环境,因为即使数据卷容器被删除了,其他已经运行的容器依然可以挂载使用

由此可知,数据卷容器的功能知识将数据挂载信息传递给了其他使用数据卷容器的容器,而数据卷容器本身并不是提供数据存储功能

数据卷容器可以作为共享的方式为其他容器提供文件共享,类似于NFS,可以在生产中启动一个实例挂载本地的目录,然后其他的容器分别挂载此容器的目录,即可保证各容器之间的数据一致性

数据卷容器的Server和Client可以不使用同一个镜像生成

网络管理

Docker默认的网络通信

Docker安装后默认的网络设置

docker容器创建后,必不可少的要和其他主机或容器进行网络通信

Docker服务安装完成之后,默认在每个宿主机会生成一个名称为docker0的网卡其IP地址都是172.17.0.1/16

创建容器后的网络配置

每次新建容器后

  • 宿主机多了一个虚拟网卡,和容器的网卡组合成一个网卡,比如:137:veth8ca6e42@if136,而在容器内的网卡名为136,可以看出和宿主机的网卡之间的关联
  • 容器会自动获取一个172.17.0.0/16网段的随机地址,默认从172.17.0.2开始,第二次为172.17.0.3,以此类推
  • 容器获取的地址并不固定,每次容器重启,可能会发生地址变化

容器间的通信

同一个宿主机的不同容器可相互通信

默认情况下

  • 同一个宿主机的不同容器之间可以相互通信

    dockerd --icc Enable inter-container communication (default true)

    --icc=false # 此配置可以禁止同一个宿主机的容器之间通信

  • 不同宿主机之前的容器IP地址重复,默认不能相互通信

禁止同一个宿主机的不同容器间通信
[root@centos7 ~]# vim /usr/lib/systemd/system/docker.service

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --icc=false

[root@centos7 ~]# systemctl daemon-reload

[root@centos7 ~]# systemctl restart docker

修改默认的网络设置

新建容器默认使用docekr0的网络配置,可以修改默认指向自定义的网桥网络

# 用自定义的网桥代替默认的docker0

# 查看默认网络

[root@centos7 ~]# ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1

    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

    inet 127.0.0.1/8 scope host lo

       valid_lft forever preferred_lft forever

    inet6 ::1/128 scope host

       valid_lft forever preferred_lft forever

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000

    link/ether 00:1c:42:2d:76:72 brd ff:ff:ff:ff:ff:ff

    inet 10.0.0.14/24 brd 10.0.0.255 scope global dynamic eth0

       valid_lft 1219sec preferred_lft 1219sec

    inet6 fe80::b56f:3e7e:8cac:f26d/64 scope link

       valid_lft forever preferred_lft forever

3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN

    link/ether 02:42:c6:6c:af:1d brd ff:ff:ff:ff:ff:ff

    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0

       valid_lft forever preferred_lft forever

    inet6 fe80::42:c6ff:fe6c:af1d/64 scope link

       valid_lft forever preferred_lft forever

[root@centos7 ~]# yum install -y bridge-utils

[root@centos7 ~]# brctl addbr br0

[root@centos7 ~]# ip a a 192.168.100.1/24 dev br0

[root@centos7 ~]# brctl show

bridge name bridge id   STP enabled interfaces

br0   8000.000000000000 no

docker0   8000.0242c66caf1d no

[root@centos7 ~]# ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1

    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

    inet 127.0.0.1/8 scope host lo

       valid_lft forever preferred_lft forever

    inet6 ::1/128 scope host

       valid_lft forever preferred_lft forever

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000

    link/ether 00:1c:42:2d:76:72 brd ff:ff:ff:ff:ff:ff

    inet 10.0.0.14/24 brd 10.0.0.255 scope global dynamic eth0

       valid_lft 1100sec preferred_lft 1100sec

    inet6 fe80::b56f:3e7e:8cac:f26d/64 scope link

       valid_lft forever preferred_lft forever

3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN

    link/ether 02:42:c6:6c:af:1d brd ff:ff:ff:ff:ff:ff

    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0

       valid_lft forever preferred_lft forever

    inet6 fe80::42:c6ff:fe6c:af1d/64 scope link

       valid_lft forever preferred_lft forever

22: br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000

    link/ether 72:ed:44:ff:22:a5 brd ff:ff:ff:ff:ff:ff

    inet 192.168.100.1/24 scope global br0

       valid_lft forever preferred_lft forever

[root@centos7 ~]# vim /usr/lib/systemd/system/docker.service

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -b br0

[root@centos7 ~]# systemctl daemon-reload

[root@centos7 ~]# systemctl restart docker

[root@centos7 ~]# ps -ef |grep dockerd

root      6763     1  1 11:36 ?        00:00:00 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -b br0

root      6911  6651  0 11:36 pts/1    00:00:00 grep --color=auto dockerd

[root@centos7 ~]# docker run --rm alpine hostname -i

192.168.100.2

容器名称互联

新建容器时,docker会自动分配容器名称,容器ID和IP地址,导致容器名称,容器ID和IP都不固定,那么如何区分不同的容器,实现和确定目标容器的通信呢?解决方案是给容器起个固定的名称,容器之间通过固定名称实现确定目标的通信

有两种固定名称

  • 容器名称
  • 容器名称的别名

通过容器名称互联

容器名称介绍

即在同一个宿主机上的容器之间可以通过自定义的容器名称相互访问,比如:一个业务前端静态页面是使用nginx,动态页面使用的是Tomcat,另外还需要负载均衡调度器,如:haproxy对请求调度至nginx和Tomcat的容器,由于容器在启动的时候其内部IP地址是DHCP随机分配的,而给容器起个固定的名称,则是相对比较固定的,因此比较适用于此场景
注意:如果被引用的容器地址变化,必须重启当前容器才能生效

容器名称实现

docker run创建容器,可使用 --link选项实现容器名称的引用

--link list

# 格式:



# 先创建指定名称的容器

docker run --name <容器名称>



# 再创建容器时引用上面容器的名称

docker run --link <目标通信的容器ID或容器名称>

通过自定义容器别名互联

容器别名介绍

自定义的容器名称可能后期会发生变化,那么一旦名称发生变化,容器内程序之间也必须要随之发生变化,比如:程序通过固定的容器名称进行服务调用,但是容器名称发生变化之后再使用之前的名称肯定是无法成功调用,每次都进行更改的话又比较麻烦,因此可以使用自定义别名的方式解决,即容器名称可以随意更改,只要不更改别名即可

容器别名实现
docker run --name <容器名称>

docker run -d --name 容器名称 --link <目标容器名称>:<容器别名>

docker run -d --name 容器名称 --link <目标容器名称>:"<容器别名> <容器别名> <容器别名>" # 可以是多个别名

Docker网络连接模式

Docker网络支持5种网络模式:

  • none

  • bridge

  • host

  • container

  • network-name

    查看默认的网络模式

    [root@centos7 ~]# docker network ls

    NETWORK ID NAME DRIVER SCOPE

    adaac389304f bridge bridge local

    5feb362eb28e host host local

    00f34cf82248 none null local

网络模式指定
# 默认新建的容器使用Bridge模式,创建容器时,docker run 命令使用以下指定网络模式

docker run --network <model>

docker run --net=<mode>



<model>: # 可以是以下值

  none

  bridge

  host

  container:<容器名或容器ID>

  <自定义网络名称>
bridge网络模式
bridge网络模式架构

bridge模式是docker的默认模式,即不指定任何模式就是bridge模式,也是使用比较多的模式,此模式创建的容器会为每一个容器分配自己的网络IP等信息,并将容器连接到一个虚拟网桥与外界通信。可以和外部网络之间进行通信,通过SNAT访问网络,使用DNAT可以让容器被外部主机访问,所以此模式也称为NAT模式

此模式宿主机需要启动ip_forward功能

bridge网络模式特点:

  • 网络资源隔离:不同宿主机的容器无法直接通信,各自使用独立网络
  • 无需手动配置:容器默认自动获取172.17.0.0/16的IP地址,此地址可以修改
  • 可访问外网:利用宿主机的物理网卡,SNAT连接外网
  • 外部主机无法直接访问容器:可以通过配置DNAT接收外网的访问
  • 性能较低:因为可通过NAT,望路转换带来更多的损耗
  • 端口管理繁琐:每个容器必须手动指定唯一的端口,容器产生端口冲突
bridge模式的默认设置
# 查看bridge模式信息

[root@centos7 ~]# docker network inspect bridge

[

    {

        "Name": "bridge",

        "Id": "adaac389304f7654edfab8612d6d82ec5b13b6e81331a296c98fa6c824eb79dd",

        "Created": "2022-08-26T13:11:24.088093198+08:00",

        "Scope": "local",

        "Driver": "bridge",

        "EnableIPv6": false,

        "IPAM": {

            "Driver": "default",

            "Options": null,

            "Config": [

                {

                    "Subnet": "192.168.100.0/24",

                    "Gateway": "192.168.100.1"

                }

            ]

        },

        "Internal": false,

        "Attachable": false,

        "Ingress": false,

        "ConfigFrom": {

            "Network": ""

        },

        "ConfigOnly": false,

        "Containers": {},

        "Options": {

            "com.docker.network.bridge.default_bridge": "true",

            "com.docker.network.bridge.enable_icc": "true",

            "com.docker.network.bridge.enable_ip_masquerade": "true",

            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",

            "com.docker.network.bridge.name": "br0",

            "com.docker.network.driver.mtu": "1500"

        },

        "Labels": {}

    }

]



# 查看宿主机的网络状态

# 安装docker后 默认启动ip_forward

[root@centos7 ~]# cat /proc/sys/net/ipv4/ip_forward

1

[root@centos7 ~]# iptables -vnL -t nat

Chain PREROUTING (policy ACCEPT 2 packets, 424 bytes)

 pkts bytes target     prot opt in     out     source               destination

    1    64 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL



Chain INPUT (policy ACCEPT 1 packets, 64 bytes)

 pkts bytes target     prot opt in     out     source               destination



Chain OUTPUT (policy ACCEPT 3 packets, 984 bytes)

 pkts bytes target     prot opt in     out     source               destination

    0     0 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL



Chain POSTROUTING (policy ACCEPT 3 packets, 984 bytes)

 pkts bytes target     prot opt in     out     source               destination

    0     0 MASQUERADE  all  --  *      !br0    192.168.100.0/24     0.0.0.0/0



Chain DOCKER (2 references)

 pkts bytes target     prot opt in     out     source               destination

    0     0 RETURN     all  --  br0    *       0.0.0.0/0            0.0.0.0/0
修改默认的bridge模式网络配置
[root@centos7 ~]# vim /lib/systemd/system/docker.service

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.100.0.1/24

[root@centos7 ~]# systemctl daemon-reload

[root@centos7 ~]# systemctl restart docker

[root@centos7 ~]# docker network inspect bridge

[

    {

        "Name": "bridge",

        "Id": "d1f65af6a2d6d9f8e73cf830c47236f5df50c7d04690bde64f499a43c82328eb",

        "Created": "2022-08-26T14:04:28.649359443+08:00",

        "Scope": "local",

        "Driver": "bridge",

        "EnableIPv6": false,

        "IPAM": {

            "Driver": "default",

            "Options": null,

            "Config": [

                {

                    "Subnet": "10.100.0.0/24",

                    "Gateway": "10.100.0.1"

                }

            ]

        },

        "Internal": false,

        "Attachable": false,

        "Ingress": false,

        "ConfigFrom": {

            "Network": ""

        },

        "ConfigOnly": false,

        "Containers": {},

        "Options": {

            "com.docker.network.bridge.default_bridge": "true",

            "com.docker.network.bridge.enable_icc": "true",

            "com.docker.network.bridge.enable_ip_masquerade": "true",

            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",

            "com.docker.network.bridge.name": "docker0",

            "com.docker.network.driver.mtu": "1500"

        },

        "Labels": {}

    }

]
Host模式

如果指定host模式启动的容器,那么新创建的容器不会创建自己的虚拟网卡,而是直接使用宿主的网卡和IP地址,因此在容器里面查看到的IP信息就是宿主机的信息,访问容器的时候直接使用宿主机IP+容器端口即可,不过容器内除网络以外的其他资源,如文件系统、系统进程等仍然和宿主机保持隔离

此模式由于直接使用宿主机的网络无需转换,网络性能最高,但是个容器使用的端口不能相同,适用于运行容器端口比较固定的业务

Host网络模式特点:

  • 使用参数 - -network host 指定
  • 共享宿主机网络
  • 网络性能无损耗
  • 网络故障排除相对简单
  • 各容器网络无隔离
  • 网络资源无法分别统计
  • 端口管理困难:容易产生端口冲突
  • 不支持端口映射
none模式

在使用none模式后,Docker容器不会进行任何网洛洛配置,没有网卡,没有IP 也没有路由,因此默认无法与外界通信,需要手动添加网卡配置IP等,所以极少使用

none模式特点:

  • 使用参数 - -network none 指定
  • 默认无网络功能,无法和外部通信
Container模式

使用此模式创建的容器需指定和一个已经存在的容器共享一个网络,而不是和宿主机共享网络,新创建的容器不会创建自己的网卡也不会配置自己的IP,而是和一个被指定的已经存在的容器共享IP和端口范围,因此这个容器的端口不能被指定容器的端口冲突,除了网络之外的文件系统、进程信息等仍然保持相互隔离,两个容器的进程可以通过lo网卡进行通信

Container模式特点:

  • 使用参数 - -network container:名称或ID 指定
  • 与宿主机网络隔离
  • 容器间共享网络空间
  • 适合频繁的容器间的网络通信
  • 直接使用对方的网络,较少使用
自定义网络模式

除了以上的网络模式,也可以自定义网络,使用自定义的网段地址,网关等信息
注意:自定义网络内的容器可以直接通过容器名进行相互的访问,而无需使用 - -link

可以使用自定义网络模式,实现不同集群应用的独立网络管理,而互不影响,而且在一个网络内,可以直接利用容器名相互访问非常便利

自定义网实现
[root@centos7 ~]# docker network --help

Usage:  docker network COMMAND

Manage networks

Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

Run 'docker network COMMAND --help' for more information on a command.

# 创建自定义网络  注意mode不支持host和none
docker network create -d <mode> --subnet <CIDR> --gateway  <网关> <自定义网络名称>

# 查看自定义网络
docker network inspect <自定义网络名称或网络ID>

# 引用自定义网络
docker run --network <自定义网络名称> <镜像名称>

# 删除自定义网络
docker network rm <自定义网络名称或网络ID>

Docker仓库管理

Docker仓库,类似于yum仓库,是用来保存镜像的仓库。为了方便的管理和使用docker镜像,可以将镜像集中保存至Docker仓库中,将制作好的镜像push到仓库集中保存,在需要镜像时,从仓库中pull镜像即可。

Docker仓库分为公有云仓库和私有云仓库

公有云仓库:由互联网公司对外公开的仓库

  • 官方
  • 阿里云等第三方仓库

私有云仓库:组织内部搭建的仓库,一般只为组织内部使用,常使用下面软件搭建仓库

  • docekr registory
  • docker harbor

官方Docker仓库

https://hub.docker.com

# 用户登录 输入账号密码即可
docker login

# 上传本地镜像前必须先给上传的镜像用docker tag命令打标签
# 标签格式 docker.io/用户账号/镜像名:TAG
docker tag alpine:3.11 docker.io/xchensir/alpine:3.11-v1

# 上传本地镜像至官网
docker push docker.io/xchensir/alpine:3.11-v1

私有云单机仓库Docker Registry

Docker Registry作为Docker的核心组件之一负责单主机的镜像内容的存储与分发,客户端的docker pull以及push命令都将直接与registry进行交互,最初版本的registry由python实现,由于设计初期在安全性,性能以及API的设计上有着诸多缺陷,该版本在0.9之后停止开发,由新项目distribution(新的docker register被称为Distribution)来重新设计并开发下一代registry,新的项目由go语言开发,所有的API,底层存储方式,系统架构都进行了全面的重新设计,已解决上一代registry中存在的问题,2016年4月registry2.0正式发布,docker1.6版本开始支持registry2.0,而八月份随着docker1.8发布,docker hub正式启用2.1版本registry全面替代之前版本registry,新版registry对镜像存储格式进行了重新设计和旧版不兼容,docker1.5和之前的版本无法读取2.0的镜像,另外,Registry2.4版本之后支持了回收站机制,也就是可以删除镜像,在2.4版本之前是不支持删除镜像的,所以最好使用大于Registry2.4版本

官方文档地址 https://docs.docker.com/registry/

官方部署文档 https://github.com/docker/docker.github.io/blob/master/registry/deploying.md

搭建单机仓库

# 下载 docker registry 镜像
[root@centos7 ~]# docker pull registry:2.7.1

# 创建授权用户密码使用目录
[root@centos7 ~]# mkdir -p /etc/docker/auth

# 创建授权的registry用户和密码
# 创建registry用户 用于上传和下载镜像
[root@centos7 ~]# yum install -y httpd
[root@centos7 ~]# htpasswd -Bbn chensir 123456 > /etc/docker/auth/registry
[root@centos7 ~]# cat /etc/docker/auth/registry
chensir:$2y$05$KP9hiJW3W5ZvwfTeWUctEuak6vHxsHOdJpMRoHRfYQnIXfmEsceOS

[root@centos7 ~]# docker run -d -p 5000:5000 --restart=always --name registry -v /etc/docker/auth/:/auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/registry registry:2.7.1
f2373f9e7c67bf628feb6222ff716cab115d63ffce9791179ef4797a00338145

[root@centos7 ~]# docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS          PORTS                                       NAMES
f2373f9e7c67   registry:2.7.1   "/entrypoint.sh /etc..."   47 seconds ago   Up 46 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   registry
[root@centos7 ~]# docker port f23
5000/tcp -> 0.0.0.0:5000
5000/tcp -> :::5000

# 登陆仓库
# docker login 默认使用https登录,而docker registry为http,所以默认登录失败
[root@centos7 ~]# docker login 10.0.0.14:5000
Username: chensir
Password:
Error response from daemon: Get "https://10.0.0.14:5000/v2/": http: server gave HTTP response to HTTPS client

# 修改配置使docker login支持HTTP协议
[root@centos7 ~]# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 10.0.0.14:5000
[root@centos7 ~]# systemctl daemon-reload
[root@centos7 ~]# systemctl restart docker

# 再次登录 验证成功
[root@centos7 ~]# docker login 10.0.0.14:5000
Authenticating with existing credentials...
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

# 打包并上传镜像
[root@centos7 ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
test         v1        401a15cbac90   8 days ago      1.24MB
[root@centos7 ~]# docker tag test:v1 10.0.0.14:5000/test:v1
[root@centos7 ~]# docker push 10.0.0.14:5000/test:v1
The push refers to repository [10.0.0.14:5000/test]
084326605ab6: Pushed
v1: digest: sha256:c04ecf7d8a544273ae7b7d1cda2f6c123a9690fc56c705dd5e16a20c65bba555 size: 527

# 下载镜像
[root@centos7 ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
registry     2.7.1     b8604a3fe854   9 months ago   26.2MB
[root@centos7 ~]# docker pull 10.0.0.14:5000/test:v1
v1: Pulling from test
50783e0dfb64: Pull complete
Digest: sha256:c04ecf7d8a544273ae7b7d1cda2f6c123a9690fc56c705dd5e16a20c65bba555
Status: Downloaded newer image for 10.0.0.14:5000/test:v1
10.0.0.14:5000/test:v1
[root@centos7 ~]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED        SIZE
10.0.0.14:5000/test   v1        401a15cbac90   8 days ago     1.24MB
registry              2.7.1     b8604a3fe854   9 months ago   26.2MB

Docker之分布式仓库Harbor

Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,由VMware开源,其通过添加一些企业必须的功能特性,例如安全、标识和管理等,扩展了开源Docker Distribution。作为一个企业级私有Registry服务器,Harbor提供了更好的性能和安全。提升用户使用Registry构建和运行环境传输镜像的效率。Harbor支持安装在多个Registry节点的镜像资源复制,镜像全部保存在私有Registry中,确保数据和知识产权在公司内部网络中管控,另外,Harbor也提供了高级的安全特性,诸如用户管理,访问控制和活动审计等

vmware官方开源服务 https://vmware.github.io

harbor官方github地址 https://github.com/goharbor/harbor

harbor官方网址 https://goharbor.io

harbor官方文档 https://goharbor.io/docs/

Harbor功能

  • 基于角色的访问控制:用户与Docker镜像仓库通过"项目"进行组织管理,一个用户可以对多个镜像仓库在同一命名空间(project)里有不同的权限
  • 镜像复制:镜像可在多个Registry实例中复制(同步)。尤其适合负载均衡,高可用,混合云和多云场景
  • 图形化用户界面:用户可以通过浏览器来浏览,检索当前Docker镜像仓库,管理项目和命名空间
  • AD/LDAP支:Harbor可以集成企业内部已有的AD/LDAP,用于鉴权认证管理
  • 国际化:已拥有英文、中文、德文、日文和俄文的本地化版本
  • RESTful API:提供给管理员对于Harbor更多的操控,使得其它管理软件集成变得更容易
  • 部署简单:提供在线和离线两种安装工具,也可以安装到vSphere平台(OVA方式)虚拟设备

Harbor组成

  • proxy:对应启动组件Nginx。它是一个nginx反向代理,代理Notary client(镜像认证)、Docker client(镜像上传下载等)和浏览器的访问请求(Core Service)给后端的各服务
  • UI(Core Service):对应启动组件harbor-ui。底层数据存储使用mysql数据库,主要提供了四个子功能:
    • UI:一个Web管理页面
    • API:Harbor暴露的API服务
    • Auth:用户认证服务,decode后的token中的用户信息在这里进行认证;auth后端可以接db、ldap、uaa三种认证实现
    • Token服务:负责根据用户在每个project中的role来为每一个docker push/pull命令发布一个token,如果从docker client发送给registry的请求没带token,registry会重定向请求到token服务创建token
  • Registry:对应启动组件registry。负责存储镜像文件和处理镜像的pull/push命令。Harbor对镜像进行强制的访问控制,Registry会将客户端的每个pull、push请求转发到token服务来获取有效的token
  • Admin Service:对应启动组件harbor-adminserver。是系统的配置管理中心附带检查存储用量,ui和job server启动时需要加载adminserver配置
  • Job Service:对应启动组件harbor-jobservice。负责镜像复制的工作,他和registry通信,从一个registry pull镜像然后push到另一个registry,并记录job_log
  • Log Collector:对应启动组件harbor-log。日志汇总组件,通过docker的log-drive把日志汇总到一起
  • DB:对应启动组件harbor-db,负责存储project、user、role、replication、image_scan、access等的metadata数据

安装Harbor

下载地址:https://github.com/vmware/harbor/releases

环境准备:四台机器 两台harbor服务器,两台harbor客户端上传和下载镜像

安装docker
rm -rf /etc/yum.repos.d/*

# centos 7 安装docker依赖三个yum源:Base,Extras,docker-ce
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

yum clean all
yum install docker-ce -y
systemctl enable --now docker
安装docker-compose
[root@centos7 ~]# wget -O /usr/local/bin/docker-compose https://github.com/docker/compose/releases/download/v2.10.2/docker-compose-linux-x86_64

[root@centos7 ~]# chmod +x /usr/local/bin/docker-compose

[root@centos7 ~]# ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

[root@centos7 ~]# docker-compose --version
下载Harbor安装包并解压缩安装启动
# 推荐下载离线完整版安装包

[root@centos7 ~]# wget https://github.com/goharbor/harbor/releases/download/v2.6.0/harbor-offline-installer-v2.6.0.tgz

[root@centos7 ~]# mkdir /apps

[root@centos7 ~]# tar xvf harbor-offline-installer-v2.6.0.tgz  -C /apps/

[root@centos7 ~]# cp /apps/harbor/harbor.yml.tmpl /apps/harbor/harbor.yml

[root@centos7 ~]# vim /apps/harbor/harbor.yml

hostname: 10.0.0.16               # 修改此行,指向当前主机IP

harbor_admin_password: 123456     # 修改此行指定harbor登录用户admin的密码,默认用户/密码 admin/Harbor12345



# 安装docker 先安装python

[root@centos7 ~]# /apps/harbor/install.sh



# 安装后会自动开启很多先关容器

[root@centos7 ~]# docker ps

CONTAINER ID   IMAGE                                COMMAND                  CREATED         STATUS                   PORTS                                   NAMES

5a84db870a20   goharbor/nginx-photon:v2.6.0         "nginx -g 'daemon of..."   4 minutes ago   Up 4 minutes (healthy)   0.0.0.0:80->8080/tcp, :::80->8080/tcp   nginx

c8ab9fcba25b   goharbor/harbor-jobservice:v2.6.0    "/harbor/entrypoint...."   4 minutes ago   Up 4 minutes (healthy)                                           harbor-jobservice

7bb48de3447b   goharbor/harbor-core:v2.6.0          "/harbor/entrypoint...."   4 minutes ago   Up 4 minutes (healthy)                                           harbor-core

d680480c0ef3   goharbor/redis-photon:v2.6.0         "redis-server /etc/r..."   4 minutes ago   Up 4 minutes (healthy)                                           redis

09bbe5448ad2   goharbor/harbor-registryctl:v2.6.0   "/home/harbor/start...."   4 minutes ago   Up 4 minutes (healthy)                                           registryctl

88f5bcdd4c4b   goharbor/harbor-portal:v2.6.0        "nginx -g 'daemon of..."   4 minutes ago   Up 4 minutes (healthy)                                           harbor-portal

4e8d142ecb96   goharbor/registry-photon:v2.6.0      "/home/harbor/entryp..."   4 minutes ago   Up 4 minutes (healthy)                                           registry

645b169ac0cf   goharbor/harbor-db:v2.6.0            "/docker-entrypoint...."   4 minutes ago   Up 4 minutes (healthy)                                           harbor-db

7c9e23d67190   goharbor/harbor-log:v2.6.0           "/bin/sh -c /usr/loc..."   4 minutes ago   Up 4 minutes (healthy)   127.0.0.1:1514->10514/tcp               harbor-log



# 实现开机自动启动harbor

# 方式1:通过service文件实现

[root@centos7 ~]# vim /lib/systemd/system/harbor.service

[Unit]

Description=Harbor

After=docker.service systemd-networked.service systemd-resolved.service

Requires=docker.service

Documentation=http://github.com/vmware/harbor



[Service]

Type=simple

Restart=on-failure

RestartSec=5

ExecStart=/usr/bin/docker-compose -f /apps/harbor/docker-compose.yml up

ExecStop=/usr/bin/docker-compose -f /apps/harbor/docker-compose.yml down



[Install]

WantedBy=multi-user.target



# 方式2:通过rc.local实现

[root@centos7 harbor]# cat /etc/rc.local

#!/bin/bash

cd /apps/harbor

/usr/bin/docker-compose up

[root@centos7 harbor]# chmod +x /etc/rc.local



# 至此安装完毕 用浏览器访问 http://10.0.0.16

# 用户名:admin 密码:前面harbor.yml指定的密码
命令行登录harbor
[root@centos7 ~]# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 10.0.0.16 --insecure-registry 10.0.0.17
[root@centos7 ~]# systemctl daemon-reload
[root@centos7 ~]# systemctl restart docker
[root@centos7 harbor]# docker login 10.0.0.16
Username: admin
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

# 查看进程是否添加上面的设置
[root@centos7 ~]# ps aux |grep dockerd
root      7875  0.5  4.1 1777524 78544 ?       Ssl  10:07   0:00 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 10.0.0.16 --insecure-registry 10.0.0.17
root      9420  0.0  0.0 112680   984 pts/1    S+   10:09   0:00 grep --color=auto dockerd
本地镜像打标签上传至harbor
# 修改images的名称,不修改成指定格式无法将镜像上传到harbor仓库
# 格式为 (项目名需要登录Harbor管理页面去新建 如果不事先建立项目,上传镜像失败)
Harbor主机IP/项目名/image名字:版本

# 例如
[root@centos7 ~]# docker images
REPOSITORY                      TAG       IMAGE ID       CREATED         SIZE
busybox-chensir                 v1.0      71a52e0618a5   3 seconds ago   1.24MB
[root@centos7 ~]# docker login 10.0.0.16
Authenticating with existing credentials...
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
[root@centos7 ~]# docker tag busybox-chensir:v1.0 10.0.0.16/chensir/busybox-chensir:v1.0
[root@centos7 ~]# docker push 10.0.0.16/chensir/busybox-chensir:v1.0
The push refers to repository [10.0.0.16/chensir/busybox-chensir]
c1cf1676e7d0: Pushed
v1.0: digest: sha256:c501ccda169599fb77102ad0c2e2568336eaccf9ad83c94aec0d6f28fb55c0a0 size: 527
下载harbor镜像

在10.0.0.15的centos7主机上无需登录,即可下载镜像

注:下载前需修改docker的service文件,加入harbor服务器的地址才可以下载

[root@centos7 ~]# docker pull 10.0.0.16/chensir/busybox-chensir:v1.0
Error response from daemon: Get "https://10.0.0.16/v2/": dial tcp 10.0.0.16:443: connect: connection refused
[root@centos7 ~]# vim /lib/systemd/system/docker.service
[root@centos7 ~]# systemctl daemon-reload
[root@centos7 ~]# systemctl restart docker
[root@centos7 ~]# docker pull 10.0.0.16/chensir/busybox-chensir:v1.0
v1.0: Pulling from chensir/busybox-chensir
2c39bef88607: Pull complete
Digest: sha256:c501ccda169599fb77102ad0c2e2568336eaccf9ad83c94aec0d6f28fb55c0a0
Status: Downloaded newer image for 10.0.0.16/chensir/busybox-chensir:v1.0
10.0.0.16/chensir/busybox-chensir:v1.0
[root@centos7 ~]# vim /lib/systemd/system/docker.service
[root@centos7 ~]# docker images
REPOSITORY                          TAG       IMAGE ID       CREATED       SIZE
10.0.0.16/chensir/busybox-chensir   v1.0      71a52e0618a5   2 hours ago   1.24MB
修改harbor配置
# 后期修改harbor配置,比如:修改IP地址等,可执行以下步骤生效
# 方法1:
[root@centos7 ~]# cd /apps/harbor/
# 停止harbor相关容器
[root@centos7 harbor]# docker-compose stop
# 修改配置
[root@centos7 harbor]# vim harbor.yml
# 更新配置
[root@centos7 harbor]# /apps/harbor/prepare
# 启动harbor
[root@centos7 harbor]# docker-compose start

# 方法2:
[root@centos7 harbor]# /apps/harbor/install.sh
实现harbor高可用

Harbor支持基于策略的Docker镜像复制功能,这类似于MySQL的主从同步,其可以实现不同的数据中心,不同的运行环境之间同步镜像,并提供友好的管理界面,大大简化了实际运维中的镜像管理工作,已经有很多互联网公司使用harbor搭建内网docker仓库的案例,并且还有实现了双向复制功能

多个harbor需要登录管理页面新建相同的项目,然后在系统管理==>仓库管理==>新建目标,系统管理==>复制管理==>新建规则 互相之前配置

Harbor安全配置https

harbor默认使用http,为了安全可以使用https

# 生成私钥和证书

[root@centos7 ~]#

[root@centos7 ~]# touch /root/.rnd

[root@centos7 ~]# mkdir /apps/harbor/certs

[root@centos7 ~]# cd /apps/harbor/certs/



# 生成CA证书

[root@centos7 certs]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -subj "/CN=ca.chensir.ink" -days 365 -out ca.crt

Generating a 4096 bit RSA private key

................................................................................++

..++

writing new private key to 'ca.key'

-----



# 生成harbor主机的证书申请

[root@centos7 certs]# openssl req -newkey rsa:4096 -nodes -sha256 -subj "/CN=ca.chensir.ink" -keyout harbor.chensir.ink.key -out harbor.chensir.ink.csr

Generating a 4096 bit RSA private key

..................................................................................................................................................................................................................................................++

...........................................................................................++

writing new private key to 'harbor.chensir.ink.key'

-----



# 给harbor主机颁发证书

[root@centos7 certs]# openssl x509 -req -in harbor.chensir.ink.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out harbor.chensir.ink.crt

Signature ok

subject=/CN=ca.chensir.ink

Getting CA Private Key



[root@centos7 certs]# tree /apps/harbor/certs/

/apps/harbor/certs/

├── ca.crt

├── ca.key

├── ca.srl

├── harbor.chensir.ink.crt

├── harbor.chensir.ink.csr

└── harbor.chensir.ink.key



0 directories, 6 files



# 修改配置文件

[root@centos7 certs]# vim /apps/harbor/harbor.yml

# https related config

https:

  # https port for harbor, default is 443

  port: 443

  # The path of cert and key files for nginx

  certificate: /apps/harbor/certs/harbor.chensir.ink.crt

  private_key: /apps/harbor/certs/harbor.chensir.ink.key

  

# 更新配置

[root@centos7 harbor]# /apps/harbor/prepare

# 启动harbor

[root@centos7 harbor]# docker-compose start
在客户端下载CA的证书
# 直接登录和上传下载镜像会报错

[root@centos7 ~]# vim /etc/hosts

10.0.0.16 harbor.chensir.ink

[root@centos7 ~]# docker login harbor.chensir.ink

Username: admin

Password:

Error response from daemon: Get "https://harbor.chensir.ink/v2/": x509: certificate has expired or is not yet valid: current time 2022-09-08T13:41:28+08:00 is before 2022-09-08T06:20:55Z



# 在客户端下载CA证书

[root@centos7 ~]# mkdir -pv /etc/docker/certs.d/harbor.chensir.org/

[root@centos7 ~]# scp -r harbor.chensir.ink:/apps/harbor/certs/ca.crt /etc/docker/certs.d/harbor.chensir.org/

[root@centos7 ~]# tree /etc/docker/certs.d/

/etc/docker/certs.d/

└── harbor.chensir.org

    └── ca.crt



1 directory, 1 file

单机编排 Docker Compose

当在宿主机启动较多容器的时候,如果都是手动操作会觉得比较麻烦而且容易出错,此时推荐使用docker单机编排工具docker-compose

docker-compose是docker容器的一种单机编排服务,docker-compose是一个管理多个容器的工具,比如:可以解决容器之间的依赖关系,就像启动一个nginx前端的时候会调用后端额Tomcat,那就得先启动Tomcat,但是启动Tomcat容器还需要依赖数据库,那就还得启动数据库,docker-compose可以用来解决这样的嵌套依赖关系,并且可以替代docker命令对容器进行创建、启动和停止等手工的操作

因此,如果说docker命令就像linux的命令,docker-compose就像shell脚本,可以自动的执行容器批量操作,从而实现自动化的容器管理,或者说docker命令相当于Ansible命令,那么docker compose文件,就相当于ansible-playbook的yaml文件

docker-compose 项目是Docker官方开源项目,负责实现对Docker容器集群的快速编排,docker-compose将所管理的容器分为三层,分别是工程(project),服务(service)以及容器(Container)

命令格式

[root@centos7 certs]# docker-compose --help
Usage:  docker compose [OPTIONS] COMMAND

# 选项说明
-f  								# 指定compose模板文件,默认为docker-compose.yml
-p 								  # 指定项目名称,默认将使用当前所在目录名称作为项目名
--verbose						# 显示更多输出信息
--log-level LEVEL 	# 定义日志级别 (DEBUG,INFO,WARNING,ERROR,CRITICAL)
--no-ansi 					# 不显示ANSI 控制字符
-v 									# 显示版本

# 以下命令选项,需要造docker-compose.yml 文件所在目录里执行
build			# 构建镜像
bundle		# 从当前docker compose 文件生成一个以<当前目录>为名称的json格式的Docker Bundle备份文件
config -q # 查看当前配置,没有错误不输出任何信息
create		# 创建服务,较少使用
down			# 停止和删除所有容器、网络、镜像和卷
events		# 从容器接收实时事件,可以指定json日志格式,较少使用
exec			# 进入指定容器进行操作
help			# 显示帮助信息
images    # 显示镜像信息,较少使用
kill			# 强制终止运行中的容器
logs			# 查看容器的日志
pause			# 暂停服务
port			# 查看端口
ps				# 列出容器,较少使用
pull			# 重新拉去镜像,镜像发生变化后,需要重新拉去镜像,较少使用
push			# 上传镜像
restart		# 重启服务,较少使用
rm				# 删除已经停止的服务
run				# 一次性运行容器
scale			# 设置指定服务运行的容器个数
start			# 启动服务,较少使用
stop			# 停止服务,较少使用
top				# 显示容器运行状态
unpause		# 取消暂定
up				# 床架并启动容器,较少使用

docker-compose文件格式

https://docs.docker.com/compose/compose-file/

docker-compose文件是一个yaml格式的文件,所以注意行首的缩进很严格

默认docker-compose命令会调用当前目录下的docker-compose.yml文件,因此一般执行docker-compose命令先进入docker-compose.yml文件所在目录

docker-compose启动单各容器

注意:使用docker-compose之前,先安装docker

创建docker-compose文件

docker-compose文件可以在任意目录没创建文件名为docker-compose.yml配置文件,要注意前后的缩进

[root@centos7 ~]# docker-compose --version
Docker Compose version v2.10.2
[root@centos7 ~]# mkdir /data/docker-compose
[root@centos7 ~]# cd /data/docker-compose/
[root@centos7 docker-compose]# vim docker-compose.yml
services:
 service-nginx-web:
  image: nginx
  container_name: nginx-web
  expose:
   - 80
   - 443
  ports:
   - "80:80"
   - "443:443"
# 查看配置和检查格式
[root@centos7 docker-compose]# docker-compose config
[root@centos7 docker-compose]# docker-compose config -q

启动/停止/删除/容器

注意:必须要在docker-compose文件所在的目录执行

# 前台启动
[root@centos7 docker-compose]# docker-compose up
# 后台启动
[root@centos7 docker-compose]# docker-compose up -d
# 停止容器
[root@centos7 docker-compose]# docker-compose stop
# 启动容器
[root@centos7 docker-compose]# docker-compose start
# 重新启动
[root@centos7 docker-compose]# docker-compose restart
# 只删除停止的容器
[root@centos7 docker-compose]# docker-compose rm
# 停止并删除容器及镜像
[root@centos7 docker-compose]# docker-compose down

指定同时启动容器的数量

[root@centos7 docker-compose]# vim docker-compose.yml
services:
 service-nginx-web:
  image: nginx
#  container_name: nginx-web  同时启动多个同一镜像的容器,不要指定容器名称,否则会冲突
  expose:
   - 80
   - 443
#  ports:   同时启动多个同一镜像,不要指定端口号,否则会冲突
#   - "80:80"
#   - "443:443"
[root@centos7 docker-compose]# docker-compose up -d --scale service-nginx-web=5

docker-compose启动多个容器

# 编辑docker-compose文件并使用数据卷
# 注意:同一个文件,数据卷的优先级比镜像内的文件优先级高
[root@centos7 docker-compose]# vim docker-compose.yml
services:
 service-nginx-web:
  image: nginx
  container_name: nginx-web
  volumes:
   - /data/nginx:/apps/nginx/html # 指定数据卷,将宿主机/data/nginx挂载到容器/apps/nginx/html
  expose:
   - 80
   - 443
  ports:
   - "80:80"
   - "443:443"
 service-tomcat-app1:
  image: tomcat
  expose:
   - 8080
  ports:
   - "8081:8080"
# 在宿主机准备nginx测试页面文件
[root@centos7 docker-compose]# mkdir /data/nginx
[root@centos7 docker-compose]# echo Docker compose test page > /data/nginx/index.html
[root@centos7 docker-compose]# docker-compose up -d

Docker的资源限制

https://docs.docker.com/config/containers/resource_constraints/

默认情况下,容器没有资源的使用限制,可以使用主机内核调度程序允许的尽可能多的资源

Docker提供了控制容器使用资源的方法,可以限制容器使用多少内存或CPU等,在docker run命令的运行时配置标志实现资源限制功能。

其中许多功能都要求宿主机的内核支持,要检查是否支持这些功能,可以使用docker info命令,如果内核中的某项特性可能会在输出结尾处看到警告,可参考 https://docs.docker.com/engine/install/linux-postinstall/#your-kernel-does-not-support-cgroup-swap-limit-capabilities 消除警告

OOM(Out of Memory Exception)

对于Linux主机,如果没有足够的内存来执行其他重要的系统任务,将会抛出OOM,随后系统会开始杀死进程已释放内存,凡是运行在宿主机的进程都有可能被kill,包括Dockerd和其他的应用程序,如果重要的系统进程被kill,会导致和该进程相关的服务全部宕机。通常越消耗内存比较大的应用越容易被kill,比如:MySQL数据库,java程序等

产生OOM异常时,Dockerd尝试通过调整Docker守护程序上的OOM优先级来减轻这些风险,以便它系统上的其他进程更不可能被杀死但是容器的OOM优先级未调整,这使得单个容器被杀死的可能性比Docker守护程序或其他系统进程被杀死的可能性更大,不推荐通过守护程序或容器上手动设置 oom-score-adj为极端负数,或通过在容器上设置 oom-kill-disable来绕过这些安全措施
oom优先级机制

linux会为每个进程算一个分数,最终将分数最高的kill

/proc/PID/oom_score_adj

# 范围为 -1000 到 1000,值越高越容易被宿主机kill掉,如果将该值设置为-1000,则进程永远不会被宿主机 kernel kill



/proc/PID/oom_adj

# 范围为 -17 到 +15 取值越高越容易被干掉,如果是 -17 则表示不能被 kill 该设置的存在是为了和旧版的linux内核兼容



/proc/PID/oom_score

# 这个值是系统综合进程的内存消耗量、CPU、时间(utime +、存活时间(uptime - start time))和oom_adj计算出的进程得分,消耗内存越多得分越高,容易被宿主机 kernel强制杀死

查看oom相关值

# docker服务进程的oom默认值

[root@centos7 docker-compose]# cat /proc/`pidof dockerd`/oom_adj

-8

[root@centos7 docker-compose]# cat /proc/`pidof dockerd`/oom_score

0

[root@centos7 docker-compose]# cat /proc/`pidof dockerd`/oom_score_adj

-500

容器的内存限制

Docker可以强制执行硬性内存限制,即只允许容器使用给定的内存大小

Docker也可以执行非硬性内存限制,即容器可以使用尽可能多的内存,除非内核检测到主机上的内存不够用了

内存相关选项

https://docs.docker.com/config/containers/resource_constraints/

以下设置大部分的选取正整数,跟着一个后缀 b,k,m,g 表示字节,千字节,兆字节或千兆字节

选项 描述
-m 容器可以使用的最大物理内存,硬限制,此选项最小允许值为 4m(4MB),常用
--memory-swap 允许此容器交换到磁盘的内存量,必须先用 -m 对内存限制才可以使用,详细说明如下
--memory-swappiness 设置容器使用交换分区的倾向性,值越高表示越倾向于使用swap分区,范围0-100,0为能不用就不用,100为能用就用
--memory-reservation 允许指定小于 --memory 的软限制,当docker检测到主机上的争用或内存不足时会激活该限制,如果使 --memory-reservation,则必须将其设置为低于 --memory才能使其优先生效。因为它是软限制,所以不能保证容器不超过限制
--kernel-memory 容器可以使用的最大内核内存量,最小为4m,由于内核内存与用户空间内存隔离,因此无法与用户空间内存直接交换,因此内核内存不足的容器可能会阻塞宿主机资源,这会对主机和其他容器或者其他服务进程产生影响,因此不建议设置内核内存大小
--oom-kill-disable 默认情况下,如果发生内存不足(OOM)错误,则内核将终止容器中的进程。要更改此行为,请使用该 --oom-kill-disable选项。仅在设置了 -m选项的容器上禁用OOM。如果-m未设置该标志,则主机可能会用完内存,内核可能需要终止系统的进程以释放内存
# 示例
[root@centos7 ~]# docker run -e MYSQL_ROOT_PASSWORD=123456 -it --rm -m 1g --oom-kill-disable mysql:5.7.29
[root@centos7 docker-compose]# sysctl -a |grep swappiness
sysctl: reading key "net.ipv6.conf.all.stable_secret"
sysctl: reading key "net.ipv6.conf.default.stable_secret"
sysctl: reading key "net.ipv6.conf.docker0.stable_secret"
sysctl: reading key "net.ipv6.conf.eth0.stable_secret"
sysctl: reading key "net.ipv6.conf.lo.stable_secret"
vm.swappiness = 30

swap限制

--memory-swap # 只有设置 --memory 后才会有意义。使用swap,可以让容器将超出限制部分的内存置换到磁盘上,WARNING:经常将内存交换到磁盘的应用程序会降低性能

不同的 --memory-swap 设置会产生不同的效果

--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空间
--memory-swap # 值为正数,那么--memory 和 --memory-swap都必须要设置,--memory-swap表示你能使用的内存和swap分区大小的总和,例如:--memory=300m,--memory-swap=1g,那么该容器能够使用300m物理内存和700m swap,即--memory是实际物理内存大小值不变,而swap的实际计算方式为(--memory-swap)-(--memory)= 容器可用swap
--memory-swap # 如果设置为0,则忽略该配置,并将该值视为未设置,即未设置交换分区
--memory-swap # 如果等于--memory的值,并且--memory设置为正整数,容器无权访问swap
--memory-swap # 如果未设置,如果宿主机开启了swap,则容器的swap值最大为2*(--memory),即两倍物理内存大小,例如,如果--memory="300m"与--memory-swap没有设置,改哦让其可以使用300m总的内存和600m交换空间,但是并不准确(在容器使用free命令所看到的的swap空间并不精确,毕竟每个容器都可以看到具体大小,宿主机的swap是有上限的,而且不是所有容器看到的累计大小)
--memory-swap # 如果设置为-1,如果宿主机开启了swap,则容器可以使用主机上swap的最大空间

注意:在容器中执行free命令看到的是宿主机的内存和swap使用,而非容器自身的swap使用情况

stress-ng压力测试工具

stress-ng是一个压力测试工具,可以通过软件仓库进行安装,也提供了docker版本容器

# centos
yum install -y stress-ng
# 容器方式安装
docker pull lorel/docker-stress-ng

假如一个容器未做内存使用限制,则该容器可以利用到系统内存最大空间,默认创建的容器没有做内存资源限制

# 默认一个workers分配256M内存,2个即占512M内存
[root@centos7 ~]# docker run --name c1 -it --rm lorel/docker-stress-ng --vm 2
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm

# 上面命令是前台执行,下面在另一个终端窗口执行,可以看奥占用512M左右内存
[root@centos7 ~]# docker stats
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O     BLOCK I/O   PIDS
a28df8e66a8b   c1        197.23%   512.0MiB / 1.792GiB   28.02%    648B / 0B   0B / 0B     5

# 指定内存最大值
[root@centos7 ~]# docker run --name c1 -it --rm -m 300m lorel/docker-stress-ng --vm 2
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm

# 在另一窗口执行,一次性查看资源使用情况
[root@centos7 ~]# docker stats --no-stream
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O     PIDS
c769402345f5   c1        163.55%   300MiB / 300MiB     100.00%   648B / 0B   6.75GB / 0B   5

# 内存限制 200M
[root@centos7 ~]# docker run -it --rm -m 200M lorel/docker-stress-ng --vm 2 --vm-bytes 256M
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm

[root@centos7 ~]# docker stats --no-stream
CONTAINER ID   NAME              CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O    PIDS
c384505f559d   hardcore_shtern   192.41%   199.9MiB / 200MiB   99.96%    648B / 0B   741MB / 0B   5

# 查看基于 cgroup对容器进行资源的大小限制
[root@centos7 ~]# cat /sys/fs/cgroup/memory/docker/c384505f559d799d9a20d0fbee95e131539778f3b0063829fdcf22226d435582/memory.limit_in_bytes
209715200

# 动态修改内存限制
[root@centos7 ~]# echo 300*1024*1024|bc
314572800
[root@centos7 ~]# echo 314572800 > /sys/fs/cgroup/memory/docker/c384505f559d799d9a20d0fbee95e131539778f3b0063829fdcf22226d435582/memory.limit_in_bytes
[root@centos7 ~]# cat /sys/fs/cgroup/memory/docker/c384505f559d799d9a20d0fbee95e131539778f3b0063829fdcf22226d435582/memory.limit_in_bytes
314572800
[root@centos7 ~]# docker stats --no-stream
CONTAINER ID   NAME              CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O     PIDS
c384505f559d   hardcore_shtern   181.25%   300MiB / 300MiB     100.00%   648B / 0B   10.7GB / 0B   5

# 通过echo命令可以改内存限制的值,但是可以在原基础上增大内存限制,缩小内存限制会报错 
# -bash: echo: 写错误: 无效的参数

# 内存大小软限制
[root@centos7 ~]# docker run -it --rm -m 256m --memory-reservation 128m --name c1 lorel/docker-stress-ng --vm 2 --vm-bytes 256m
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm

[root@centos7 ~]# docker stats --no-stream
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O     PIDS
9fd1ea32cc83   c1        178.48%   255.9MiB / 256MiB   99.96%    648B / 0B   1.44GB / 0B   5

# 查看硬限制
[root@centos7 ~]# cat /sys/fs/cgroup/memory/docker/9fd1ea32cc83788b3f223295d6976295fcb307b0adaf9b82ea883f1fba129c49/memory.limit_in_bytes
268435456

# 查看软限制
[root@centos7 ~]# cat /sys/fs/cgroup/memory/docker/9fd1ea32cc83788b3f223295d6976295fcb307b0adaf9b82ea883f1fba129c49/memory.soft_limit_in_bytes

# 软限制不能高于硬限制

# 关闭OOM机制
# 查看docker OOM机制默认值
[root@centos7 ~]# cat /sys/fs/cgroup/memory/docker/memory.oom_control
oom_kill_disable 0
under_oom 0

#启动容器时关闭OOM机制
[root@centos7 ~]# docker run -it --rm -m 200m --oom-kill-disable lorel/docker-stress-ng --vm 2 --vm-bytes 256m
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm
[root@centos7 ~]# docker stats --no-stream
CONTAINER ID   NAME          CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O     PIDS
b0bccc1c29f7   epic_edison   0.00%     185.1MiB / 200MiB   92.56%    648B / 0B   28.7kB / 0B   5
[root@centos7 ~]# cat /sys/fs/cgroup/memory/docker/b0bccc1c29f7355073442a1d84270827a19dc38a9258eafb5b3f017e3378cae0/memory.oom_control
oom_kill_disable 1
under_oom 1
交换分区限制
docker run -it --rm -m 256m --memory-swap 512m --name c1 centos bash
cat /sys/fs/cgroup/memory/docker/容器ID/memory.memsw.limit_in_bytes

容器的CPU限制

一个宿主机,有几十个核心的CPU,但是宿主机上可以同时运行成百上千个不同的进程用已处理不同的任务,多进程共用一个CPU的核心为可压缩资源,即一个核心的 CPU可以通过调整而运行多个进程,但是同一个单位时间内只能有一个进程在CPU上运行,那这么多的进程怎么在CPU上执行可调度的呢

Linux kernel进程的调度基于CFS(Completely Fair Scheduler),完全公平调度

服务器资源密集型
  • CPU密集型的场景:优先级越低越好,计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、数据处理、对视频频进行高清解码等等,全靠CPU的运算能力。
  • IO密集型的场景:优先级值高点,设计到网络。磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等IO操作完成(因为IO的速度远远低于CPU和内存的速度),比如Web应用,高并发,数据量大的动态网站来说,数据库应该为IO密集型

CFS原理

cfs定义了进程调度的新模型,它给cfs_rq(cfs的run queue)中的每一个进程安排一个虚拟时钟vruntime。如果一个进程得以执行,随着时间的增长,其vruntime将不断增大。没有得到执行的进程vruntime不变,而调度器总是选择vruntime跑得最慢的那个进程来执行。这就是所谓的"完全公平"。为了区别不同优先级的进程,优先级高的进程vruntime增长得慢,以至于它可能得到更多的运行机会。CFS的意义在于,在一个混杂着打来年计算型进程和IO交互进程的系统中,CFS调度器相对其它调度器在对待IO交互进程要更加友善和公平。

配置默认的CFS调度程序

默认情况下,每个容器对主机的CPU周期的访问都是不受限制的。可以设置各种约束,以限制给定容器对主机CPU周期的访问。大多数用户使用并配置默认的CFS调度程序。在Docker1.13及更高版本中,还可以配置realtime scheduler

CFS是用于常规Linux进程的Linux内核CPU调度程序。通过几个运行时标志,可以配置对容器拥有的CPU资源的访问量。使用这些设置时,Docker会在主机上修改容器cgroup的设置

选项 描述
--cpus 指定一个容器可以使用多少个可用的CPU核心资源。例如,如果主机有两个CPU,如果设置了--cpus="1.5",则可以保证容器最多使用1.5个CPU(如果是4核CPU,那么还可以是4核心上每核用一点,但是总计是1.5核心的CPU)。这相当于设置--cpu-period=100000和--cpu-quota="150000"。此设置可在Docker1.13及更高版本中可用,目的是替代--cpu-period和--cpu-quota两个参数,从而是配置更简单,但是最大不能超过宿主机的CPU总核心数(在操作系统看到的CPU超线程后的数值),此项常用
--cpu-period 过时选项,指定CPU CFS调度程序周期,必须与cpu-quta一起使用。默认为100微秒。大多数用户不会更改默认设置。如果使用Docker1.13或更高版本,请改用cpus
--cpu-quota 过时选项,在容器上添加CPU CFS配额,计算方式为cpu-quota/cpu-period的结果值,docker1.13及以上版本通常使用cpus设置此值
--cpuset-cpus 用于指定容器运行的CPU编号,也就是所谓的CPU绑定。如果一个或多个CPU,则容器可以使用逗号分隔的列表或连字符分隔的CPU范围。第一个CPU编号为0.有效值可能是0-3(使用第一,第二,第三和第四CPU)或1,3(使用第二和第四CPU)
--cpu-shares 用于设置cfs中调度的相对最大比例权重,cpu-share的值越高的容器,将会分得更多的时间片(宿主机多核CPU总数为100%,假如容器A为1024,容器B为2048,那么容器B将最大是容器A的可用CPU的两倍),默认的时间片1024,最大262144.这是一个软限制。
使用stress-ng测试CPU配置
# 查看stress-n关于CPU的帮助
[root@centos7 ~]# docker run -it --rm --name c1 lorel/docker-stress-ng |grep cpu
 -c N, --cpu N            start N workers spinning on sqrt(rand())
       --cpu-ops N        stop when N cpu bogo operations completed
 -l P, --cpu-load P       load CPU by P %%, 0=sleep, 100=full load (see -c)
       --cpu-method m     specify stress cpu method m, default is all
Example: stress-ng --cpu 8 --io 4 --vm 2 --vm-bytes 128M --fork 4 --timeout 10s

# 不限制容器CPU
# 占用4个CPU资源,但只是平均的使用CPU资源
docker run -it --rm lorel/docker-stress-ng --cpu 4
# 限制使用CPU
docker run -it --rm --cpus 1.5 lorel/docker-stress-ng --cpu 4
# 绑定CPU
# 一般不建议绑在0号CPU上,因0号CPU一般会较忙
docker run -it --rm --cpus 1.5 --cpuset-cpus 2,4-5 lorel/docker-stress-ng --cpu 4

# 多个容器的CPU利用率比例
docker run -it --rm --name c1 --cpu-shares 1000 lorel/docker-stress-ng --cpu 4
docker run -it --rm --name c2 --spu-shares 500 lorel/docker-stress-ng --cpu 4

# 查看c1容器的cpu利用比例
cat /sys/fs/cgroup/cpu,cpuacct/docker/c1容器ID/cpu.shares
# 查看c2容器的cpu利用比例
cat /sys/fs/cgroup/cpu,cpuacct/docker/c2容器ID/cpu.shares
# 再打开新的容器,CPU分配比例会动态调整

# 动态调整cpu shares值
echo 2000 > /sys/fs/cgroup/cpu,cpuacct/docker/容器ID/cpu.shares

可视化图形工具Portainer

Portainer是一个可视化的容器镜像的图形管理工具,利用Portainer可以轻松构建,管理和维护Docker环境。而且完全免费,基于容器化的安装方式,方便高效。

官方站点:https://www.portainer.io

安装Portainer

[root@centos7 ~]# docker search portainer |head -n 3
NAME                                   DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
portainer/portainer                    This Repo is now deprecated, use portainer/p...   2262
portainer/portainer-ce                 Portainer CE - a lightweight service deliver...   1350

# portainer项目废弃
# portainer-ce项目替代portainer
[root@centos7 ~]# docker pull portainer/portainer-ce
Using default tag: latest
latest: Pulling from portainer/portainer-ce
772227786281: Pull complete
96fd13befc87: Pull complete
bc9eaab2cad1: Pull complete
6458f72e4747: Pull complete
Digest: sha256:444ade51d69d7fca889c7aa14525c459dba313a0e7ca79aee985e6c0749427de
Status: Downloaded newer image for portainer/portainer-ce:latest
docker.io/portainer/portainer-ce:latest
[root@centos7 ~]# docker volume create portainer_data
portainer_data
[root@centos7 ~]# docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
7d62ec92aaaca24218d44b13155fb47fb752847a596a1f732b90167687a986c3

浏览器访问 http://ip:9000

docker命令总结

attach      # 当前shell下attach连接指定运行镜像

build       # 通过Dockerfile定制镜像

commit      # 提交当前容器为新的镜像

cp          # 从容其中拷贝指定文件或者目录到宿主机中

create      # 创建一个新的容器,同run 但不能启动

diff        # 查看dokcer 容器变化

events      # 从docker服务获取容器实时事件

exec        # 在已存在的容器上运行命令

export      # 导出容器的内容作为一个tar 归档文件[对应import]

history     # 展示一个镜像形成的历史

images      # 列出系统当前镜像

import      # 从tar包中的内容创建一个新的文件系统映像[对应export]

info        # 显示系统相关系统

inspect     # 查看容器详细信息

kill        # kill指定容器

load        # 从一个tar包中加载一个镜像[对应save]

login       # 注册或者登录一个docker源服务器

logout      # 从当前docker registry退出

logs        # 输出当前日志信息

port        # 查看映射端口对应的容器内部源端口

pause       # 暂停容器

ps          # 列出容器列表

pull        # 从docker镜像源服务器拉取指定镜像或者库镜像

push        # 推送指定镜像或者库镜像至docker源服务器

restart     # 重启运行的容器

rm          # 移除一个或多个容器

rmi         # 移除一个或多个镜像[无容器使用该镜像才可删除,否则需要删除相关容器才可继续 或 -f 强制删除]

run         # 创建一个新的容器并运行一个命令

save        # 保存一个镜像为一个tar包[对应load]

search      # 在docker hub中搜索镜像

start       # 启动容器

stop        # 停止容器

tag         # 给源中镜像打标签

top         # 查看容器中运行的进程信息

unpause     # 取消暂停容器

version     # 查看docker版本号

wait        # 截取容器停止时的退出状态值
相关推荐
嘤嘤怪呆呆狗1 小时前
【开发问题记录】使用 Docker+Jenkins+Jenkins + gitee 实现自动化部署前端项目 CI/CD(centos7为例)
前端·vue.js·ci/cd·docker·gitee·自动化·jenkins
Carry_NJ2 小时前
docker-compose样例
运维·docker·容器
梁萌8 小时前
Linux安装Docker
linux·运维·docker·helloworld·容器化部署
翱翔-蓝天8 小时前
在 CentOS 系统上安装 ClickHouse
运维·docker·容器
cdg==吃蛋糕11 小时前
docker代理配置
docker·容器·eureka
web1350858863512 小时前
使用docker compose安装gitlab
docker·容器·gitlab
IT机器猫12 小时前
Docker完整技术汇总
运维·docker·容器
董健正12 小时前
Docker安装
docker·容器·docker-compose
gs8014013 小时前
替换 Docker.io 的 Harbor 安全部署指南:域名与 IP 双支持的镜像管理解决方案
docker·harbor
coco_1998_213 小时前
nvidia docker, nvidia docker2, nvidia container toolkits区别
docker·容器