一、背景

接上一篇《Docker复习之部署篇》,本文继续对Docker之日常维护常用操作做回顾总结。

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

1.1 Docker之namespace回顾

Docker依赖于Linux内核技术 chroot 、namespace 和 cgroup。Docker通过namespace实现了资源隔离,通过cgroups实现了资源限制,通过写时复制机制(copy-on-write)实现了高效的文件操作。首先,我们回顾下 namespace ;

我们知道,Docker本质上是宿主机上的进程(容器进程),而容器的资源隔离也就是指进程资源的隔离。而实现这种资源隔离的核心技术就是 Linux namespace。这种隔离是一种逻辑层面的,更像是抽象出多个轻量级的内核(容器进程),这些进程可以充分利用宿主机的资源,宿主机拥有的所有资源,这些容器进程都可以享有,但容器进程之间是隔离的,对应的,不同容器进程之间使用资源也是隔离的,这样,即使彼此之间进行相同的操作,也不会互相干扰,安全性得到保障。

Linux namespace 实现了 6 项资源隔离,基本上涵盖了一个小型操作系统的运行要素,包括主机名、用户权限、文件系统、网络、进程号、进程间通信,这6 项资源隔离分别对应 6 种系统调用,通过传入上表中的参数,调用 clone() 函数来完成。如下表:

查看当前进程下有哪些 namespace 隔离,可以查看文件 /proc/[pid]/ns ,/proc/[pid]/ns里设置这些符号链接的另一个作用是,一旦这些链接文件被打开,那么就算该namespace下的所有进程都已经结束,这个namespace也会一直存在,后续进程也可以再加进来。把/proc/[pid]/ns目录文件使用–bind方式挂载可以直到同样的作用,比如mount --bind /proc/2454/ns/uts uts;在Docker中,我们可以在进程都结束的情况下,通过这种形式把namespace保留下来,为以后有进程加入做准备。在Docker中,使用docker exec命令可以使用setns()函数加入已经存在的命名空间,在已经运行着的容器中执行一个新命令。如下所示:

可以看到,每一项 namespace 都附带一个编号,这是唯一标识 namespace 的,如果两个进程指向的 namespace 编号相同,则表示它们同在该 namespace 下。另外,在4.6 版本的内核中,namespace会多一个cgroup;其中:

1>UTS namespace 提供了主机名和域名的隔离,这样每个容器就拥有独立的主机名和域名了,在网络上就可以被视为一个独立的节点,在容器中对 hostname 的命名不会对宿主机造成任何影响。

2>IPC namespace 实现了进程间通信的隔离,包括常见的几种进程间通信机制,如信号量,消息队列和共享内存。我们知道,要完成 IPC,需要申请一个全局唯一的标识符,即 IPC 标识符,所以 IPC 资源隔离主要完成的就是隔离 IPC 标识符。(ipcs -q可查看消息队列情况;ipcmk -Q可创建一个消息队列)

3>PID namespace 完成的是进程号的隔离,它对进程PID重新标号; 为了做到进程空间的隔离,会首先在容器内创建出PID为1的进程(root namespace),其后它会再创建的新PID namespace被称为child namespace(树的子节点),而原来的PID namespace就是新创建的PID namespace的parent namespace(树的父节点)。这样,不同的PID namespace会形成一个层级体系。所属的父节点可以看到子节点中的进程,并可以通过信号等方式对子节点中的进程产生影响。但子节点却不能看到父节点PID namespace中的任何内容。另外,会发现容器内shell里执行ps,top等命令,还是可以看得到所有进程。说明并没有完全隔离。这是因为,像ps, top这些命令会去读/proc文件系统,因为/proc文件系统在父进程和子进程都是一样的,所以这些命令显示的东西都是一样的,当然我们可以临时重新挂载/proc来实现只看到PID namespace本身应该看到的进程。因此,我们还需要对文件系统进行隔离。

4>mount namespace:通过隔离文件系统挂载点对隔离文件系统来提供支持的,通过CLONE_NEWNS创建mount namespace后,父进程会把自己的文件结构复制给子进程中。而子进程中新的namespace中的所有mount操作都只影响自身的文件系统,而不对外界产生任何影响,即隔离后,不同的mount namespace中的文件结构发生变化也互不影响。这样可以做到比较严格地隔离。我们可以通过/proc/[pid]/mounts查看到所有挂载在当前namespace中的文件系统,通过/proc/[pid]/mountstats看到mount namespace中文件设备的统计信息,包括挂载文件的名字、文件系统的类型、挂载位置等。需要注意的是,文件系统结构复制这种隔离存在例外,比如父节点namespace中的进程挂载了一张CD-ROM,这时子节点namespace复制的目录结构是无法自动挂载上这张CD-ROM的,因为这种操作会影响到父节点的文件系统。

5>cgroup:控制组

cgroup ,它提供了一套机制用于控制一组特定进程对资源的使用。cgroup绑定一个进程集合到一个或多个子系统上。使​​​用​​​ cgroup,可​​​更​​​具​​​体​​​地​​​控​​​制​​​对​​​系​​​统​​​资​​​源​​​的​​​分​​​配​​​、​​​优​​​先​​​顺​​​序​​​、​​​拒​​​绝​​​、​​​管​​​理​​​和​​​监​​​控​​​。​​​可​​​更​​​好​​​地​​​根​​​据​​​任​​​务​​​和​​​用​​​户​​​分​​​配​​​硬​​​件​​​资​​​源​​​,提​​​高​​​总​​​体​​​效​​​率​​​。关于cgroup定义,参考官方解释:

cgroups, are a Linux kernel feature which allow processes to be organized into
hierarchical(层级树) groups whose usage of various types of resources canthen be limited and monitored.  The kernel's cgroup interface is provided through a pseudo-filesystem called cgroupfs.  Grouping is implemented in the core cgroup kernel code, while resource tracking and limits are implemented in a set of per-resource-type subsystems (memory, CPU, and so on).cgroups,是 Linux内核的功能,允许将进程组织按不通层级分配使用各种类型资源并且红纸和监控这些资源的使用。内核的 cgroup 接口就是通过名为 cgroupfs 的伪文件系统提供。分组在核心 cgroup 内核代码中实现,而资源跟踪和控制则在一组各类资源子系统中实现(如内存、CPU 等)。subsystem,可理解为一个通过cgroup提供的工具和接口来管理进程集合的模块。一个子系统就是一个典型的“资源控制器”,用来调度资源或者控制资源使用的上限。每种资源可以看作是一个子系统。子系统可以是以进程为单位的任何东西,

Cgroups主要由task,cgroup,subsystem及hierarchy构成:

●Task : 在Cgroups中,task就是系统的一个进程。
●Cgroup : Cgroups中的资源控制都以cgroup为单位实现的。cgroup表示按照某种资源控制标准划分而成的任务组,包含一个或多个Subsystems。一个任务可以加入某个cgroup,也可以从某个cgroup迁移到另外一个cgroup。
●Subsystem : Cgroups中的subsystem就是一个资源调度控制器(Resource Controller)。比如CPU子系统可以控制CPU时间分配,内存子系统可以限制cgroup内存使用量。
●Hierarchy(层级树) : hierarchy由一系列cgroup以一个树状结构排列而成,每个hierarchy通过绑定对应的subsystem进行资源调度。hierarchy中的cgroup节点可以包含零或多个子节点,子节点继承父节点的属性。整个系统可以有多个hierarchy。

cgroup主要提供了如下功能:

1>>Resource limitation: 限制资源使用,比如内存使用上限以及文件系统的缓存限制。
2>>Prioritization: 优先级控制,比如:CPU利用和磁盘IO吞吐。
3>>Accounting: 一些审计或一些统计,主要目的是为了计费。
4>>Control: 挂起进程,恢复执行进程。

【cgroup术语解析】:

kio: 这个subsystem可以为块设备设定输入/输出限制,比如物理驱动设备(包括磁盘、固态硬盘、USB等)。
cpu: 这个subsystem使用调度程序控制task对cpu的使用。
cpuacct: 这个subsystem自动生成cgroup中task对cpu资源使用情况的报告。
cpuset: 这个subsystem可以为cgroup中的task分配独立的cpu(此处针对多处理器系统)和内存。
devices 这个subsystem可以开启或关闭cgroup中task对设备的访问。
freezer 这个subsystem可以挂起或恢复cgroup中的task。
memory 这个subsystem可以设定cgroup中task对内存使用量的限定,并且自动生成这些task对内存资源使用情况的报告。
perfevent 这个subsystem使用后使得cgroup中的task可以进行统一的性能测试。{![perf: Linux cpu性能探测器,详见https://perf.wiki.kernel.org/index.PHP/MainPage]}
*net_cls 这个subsystem Docker没有直接使用,它通过使用等级识别符(classid)标记网络数据包,从而允许 Linux 流量控制程序(TC:Traffic Controller)识别从具体cgroup中生成的数据包。

查看/proc/[pid]/cgroup进程获取cgroup信息,输出内容以hierarchy-ID:controller-list:cgroup-path来显示。

查看/sys/fs/cgroup/目录,可查看每项资源的使用情况。比如:cpuacct/cpuacct.usage_percpu、cpuset/cpuset.cpus、cpu/cpu.cfs_period_us、cpu/cpu.cfs_quota_us、cpuacct/cpuacct.usage

查看/proc/stat文件,可获取所有CPU活动的信息,该文件中的所有值都是从系统启动开始累计到当前时刻

eg:cat /proc/stat | grep 'cpu '(周期/时间片/jiffies) ##得到的数字相加/HZ(cat /boot/config-`uname -r` | grep ‘^CONFIG_HZ=’,然后乘以10*9就是系统时间(纳秒)。

实践中,一般利用CGroup会做下面这些事:

●隔离一个进程集合(比如:nginx的所有进程),并限制他们所消费的资源,比如绑定CPU的核。
●为这组进程分配其足够使用的内存
●为这组进程分配相应的网络带宽和磁盘存储限制
●限制访问某些设备(通过设置设备的白名单)

eg:cat /boot/config-${uname -r} | grep CGROUP //查看linux是否启用了linux cgroups,“y”代表已经打开linux cgroups功能

更多参考Linux cgroup详解

二、操作命令

2.1 Docker 容器查看

首先,管理员对docker做日常维护,需要了解现有环境有多少docker实例,并连接进入docker实例虚拟机进行对应的管理维护;

我们执行 docker ps 命令来查看容器名称:docker ps -a或docker ps //显示当前正在运行的容器,输出如下:

参数概览:

示例:

1)显示最后被创建的容器:docker ps -l //相当于 docker ps -n 1
2) 详细输出,长内容不会截断:docker ps --no-trunc //其中 trunc 是 truncate 的缩写
3)只显示容器 ID:$ docker ps -q
4)显示容器文件大小:$ docker ps -s //输出结果可获得 2 个数值:一个是容器真实增加的大小,一个是整个容器的虚拟大小(容器虚拟大小 = 容器真实增加大小 + 容器镜像大小)。

5)docker ps –format参数可以实现格式化输出自定义列,提供了基于 Go模板 的日志格式化输出辅助功能。

-format=“TEMPLATE”
Pretty-print containers using a Go template.
Valid placeholders:
.ID - Container ID
.Image - Image ID
.Command - Quoted command
.CreatedAt - Time when the container was created.
.RunningFor - Elapsed time since the container was started.
.Ports - Exposed ports.
.Status - Container status.
.Size - Container disk size.
.Names - Container names.
.Labels - All labels assigned to the container.
.Label - Value of a specific label for this container. For example {{.Label “com.docker.swarm.cpu”}}
.Mounts - Names of the volumes mounted in this container

示例: docker ps --format “table {{.ID}}\t{{.Names}}\t{{.Ports}}\t{{.Status}}” //点号表示当前对象及上下文,直接通过{{.}}获取当前对象。

Go模板可用的可用的占位符如下:

eg:docker ps --format “{{.ID}}: {{.Command}}” // 当使用了 --format 选项,那么 ps 命令只会输出 template 中指定的内容;如果想带上表格列头,需要再 template 中加上 table 指令:docker ps --format “table {{.ID}}: {{.Command}}”

6)过滤显示:Filter

当容器数量过多,或者想排除干扰容器,可以通过 --filter 或 -f 选项,过滤需要显示的容器。支持的过滤条件非常丰富,包括:


使用该选项时,可按以下 3 条准则来进行过滤操作:

1>选项后跟的都是键值对 key=value (可不带引号),如果有多个过滤条件,就多次使用 filter 选项。例如:

eg1:docker ps --filter id=b61c9e9040e0 --filter name=vpm.redis.1

2>相同条件之间的关系是或,不同条件之间的关系是与。例如:

eg:docker ps --filter name=vpm.redis.1 --filter name=indexserver --filter status=running

以上过滤条件会找出 name 包含 vpm.redis.1 或 indexserver 并且 status 为 running 的容器。

3> id 和 name,支持正则表达式

eg:docker ps --filter name=^/bingohuang$   //精确匹配 name 为 bingohuang 的容器。注意,容器实际名称,开头是有一个正斜线 / ,可用 docker inspect看到
eg:docker ps --filter name=\.*bingohuang.\*   //匹配 name 包含 bingohuang 的容器,和 --filter name=bingohuang 一个效果eg:docker rm $(docker ps -q --filter name=.*bingohuang.* --filter status=exited --filter status=dead2>/dev/null)    //清理名称包含 bingohuang,且状态为 exited 或 dead 的容器

其他知识:容器的 metadata 在 /var/lib/docker/containers/containerId/ 目录下,其中 containerId-json.log 文件中记录了回写的内容。

7)容器与宿主机端口映射查看

除docker ps 外,我们还可使用 docker port 可以查看指定 (ID 或者名字)容器的某个确定端口映射到宿主机的端口号。

docker port container_id
docker port container_name

2.2 Docker 容器连接

连接指定容器,实际是运行一个容器或在已运行的容器中执行命令来连接进入容器,执行:

1)运行:docker run -d -P --name runoob training/webapp python app.py //–name 标识来命名容器,为让外部也可以访问这些应用,可以通过 -P(大) 或 -p(小) 参数来指定端口映射。P :是容器内部端口随机映射到主机的高端口。-p : 是容器内部端口绑定到指定的主机端口。

docker run -d -p 5000:5000 training/webapp python app.py
docker run -d -p 127.0.0.1:5001:5000 training/webapp python app.py  //-d(–detach)容器后台运行,并且打印容器id

验证:docker port 命令可以查看端口的绑定/映射情况,如:

docker port CONTAINER [PRIVATE_PORT[/PROTO]]

eg:docker port adoring_stonebraker 5000


2)连接docker exec -it 容器名称/容器ID sh //-i(–interactive)表即使没有连接,也要保持标准输入保持打开状态,一般与 -t (–tty,分配一个伪tty)连用;-t 指示 docker 要创建一个伪 tty 终端,连接容器的标准输入接口,之后用户就可以通过终端进行输入。退出时直接exit即可。

当然也可以使用:docker attach 容器名称,区别如下:

attach进入终端后,没办法退出而不停止容器,要退出只能输入exit,但这样就将容器停止了,另外一个缺点是,如果多个容器同时attach到相同的容器,在一个窗口中操作的结果,会同步显示到所有窗口。因此我们才用docker exec -it 容器名称 sh;

docker attach [container_id] //连接一个正在运行的container实例(即实例必须为start状态,可以多个窗口同时attach一个container实例)

eg:docker exec nginx ip a     //在容器内执行命令,查看容器的ip

docker start -i //启动一个container并进入交互模式(相当于先start,在attach);使用start是启动已经创建过得container,使用run则通过image开启一个新的container。

在容器上做了一堆操作后,比如在ubuntu的基础上安装了一些软件、部署了一些应用之类,希望分发到其它机器,最简单的办法就是把容器重新生成一个新镜像,然后其它人或到新的主机上直接docker pull你的新镜像就可以了。

docker commit -a 作者名字 -m 提交原因 -p 容器ID 镜像名称:版本号

eg:docker commit -m="你的镜像声明" -a="junn" 基于的当前container_ID junn/ubuntu:v2(你要发布的镜像名称:标签)
docker run -t -i junn/ubuntu:v2 /bin/bash  //用上述镜像启动新的容器即可,这样就无缝迁移到新环境了

提交完成后查看执行:docker images

附:查看docker容器初始登录后的root密码,因该密码是随机分配的,执行:

docker logs  [container_id]  2>&1 | grep 'User: ' | tail -n1

2.3 容器镜像

当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载。

1)可以使用 docker images 来列出本地主机上的镜像;使用-q :只显示镜像ID;


其中,REPOSITORY:表示镜像的仓库源;TAG:镜像的标签;IMAGE ID:镜像ID;CREATED:镜像创建时间;SIZE:镜像大小;同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本;

docker images --tree :显示镜像的所有层(layer)'
docker rmi  <image ID>: 删除一个或多个image

2)利用镜像创建容器实例

docker run -t -i ubuntu:14.04 /bin/bash   //-i: 交互式操作,-t为实例分配一个终端,bash表进入容器进入shell环境,这也是默认的

3)在线查找镜像

可以从 Docker Hub 网站来搜索镜像,Docker Hub 网址为: https://hub.docker.com/;也可以使用 docker search 命令来搜索镜像,–automated :只列出 automated build类型的镜像;-s :列出收藏数不小于指定值的镜像。

docker search image_name   //从Docker HUB上搜索镜像


然后找到需要的镜像,然后pull下载即可。

4)获取/下载一个新的镜像:

当想下载这个镜像,我们可以使用 docker pull 命令来拉取下载它。

eg:docker pull ubuntu:13.10

5)自定义创建镜像

当我们从 docker 镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改。

A、从已经创建的容器中更新镜像,并且提交这个镜像;

B、使用 Dockerfile 指令来创建一个新的镜像,Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

这里只讨论第2种,使用命令 docker build 从零开始来创建一个新的镜像。首先这需要创建一个 Dockerfile 文件,它包含了一组指令,告诉 Docker 该如何构建我们的镜像。Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。如下就是一个dockerfile的示例:

FROM    centos:6.7   ##指明创建镜像基于的原始镜像,即你要使用哪个镜像源
MAINTAINER      Fisher "fisher@sudops.com"RUN     /bin/echo 'root:123456' |chpasswd  //告诉docker启动后在镜像内要执行的命令
RUN     useradd runoob  //RUN后跟的<命令行命令> 等同于,在终端操作的 shell 命令
RUN     /bin/echo 'runoob:123456' |chpasswd
RUN     /bin/echo -e "LANG=\"en_US.UTF-8\"" >/etc/default/local
EXPOSE  22
EXPOSE  80
CMD     /usr/sbin/sshd -D

确认后,执行:docker build -t runoob/centos:6.7 -f ./dockerfile //-t :指定要创建的目标镜像名,创建过程会打印到标准输出; -f:读取的镜像配置

注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。如是多条语句,可用&&,只创建一层镜像。

镜像配置文件参数

–build-arg=[ ] :设置镜像创建时的变量;

–cpu-shares :设置 cpu 使用权重;

–cpu-period :限制 CPU CFS周期;

–cpu-quota :限制 CPU CFS配额;

–cpuset-cpus :指定使用的CPU id;

–cpuset-mems :指定使用的内存 id;

–disable-content-trust :忽略校验,默认开启;

-f :指定要使用的Dockerfile路径;

–force-rm :设置镜像过程中删除中间容器;

–isolation :使用容器隔离技术;

–label=[] :设置镜像使用的元数据;

-m :设置内存最大值;

–memory-swap :设置Swap的最大值为内存+swap,"-1"表示不限swap;

–no-cache :创建镜像的过程不使用缓存;

–pull :尝试去更新镜像的新版本;

–quiet, -q :安静模式,成功后只输出镜像 ID;

–rm :设置镜像成功后删除中间容器;

–shm-size :设置/dev/shm的大小,默认值是64M;

–ulimit :Ulimit配置。

–tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。

–network: 默认 default。在构建期间设置RUN指令的网络模式

eg:docker build -t nginx:v3 .  //其中最后的.表构建容器镜像的上下文路径,即当前路径下所有文件都会被当做构建镜像的文件,发给docker引擎(Sending build context to Docker daemon)

注意: 上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成镜像构建过程缓慢。

6)设置镜像标签

使用 docker tag 命令,为镜像添加一个新的标签。

eg: docker tag 860c279d2fec junn/centos:v2   //860c279d2fec是镜像ID,后跟用户名称、镜像源名(repository name)和新的标签名(tag)。

2.4 容器创建

1)创建一个容器

docker run :创建一个新的容器并运行一个命令

用法: docker run [OPTIONS] IMAGE [COMMAND] [ARG…]或

eg:docker run -itd --name ubuntu-test ubuntu /bin/bash //交互模式运行一个容器并分配一个伪终端且启动加载bash环境,这样就可以交互式登录,-d指定容器后台运行,–name为容器自定义个名称 ,采用一个名称为ubuntu的镜像来启动加载OS;

eg:docker pull training/webapp # 载入镜像
docker run -d -P training/webapp python app.py //利用上述镜像启动web服务容器,-P指定将容器内部使用的网络端口随机映射到外部使用的主机上(宿主机)。
docker ps //验证,输出如下,我们看到容器内5000 端口(默认 位Python Flask 的端口)映射到宿主机端口 32769 上,我们外部访问32769就可将服务映射/转发到容器内部真正的服务上
CONTAINER ID IMAGE COMMAND … PORTS
d3d5e39ed9d3 training/webapp “python app.py” … 0.0.0.0:32769->5000/tcp

docker run -d -p 5000:5000 training/webapp python app.py //或者-p直接指定容器与宿主间端口映射关系

参数:

-d: 后台运行容器,并返回容器ID;

–name=“nginx-lb”: 为容器指定一个名称;

-p: 指定端口映射,格式为:主机(宿主)端口:容器端口

–volume , -v: 绑定一个卷

-i: 以交互模式运行容器,通常与 -t 同时使用,-it

-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;

-P: 随机端口映射,容器内部端口随机映射到主机的高端口

-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;

–dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;

–dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;

-h “mars”: 指定容器的hostname;

-e username=“ritchie”: 设置环境变量;

–env-file=[]: 从指定文件读入环境变量;

–env key=value 添加配置变量

–cpuset=“0-2” or --cpuset=“0,1,2”: 绑定容器到指定CPU运行;

-m :设置容器使用内存最大值;

–net=“bridge”: 指定容器的网络连接类型,支持 bridge/host/none/container:<name|id> 四种类型;

–link=[]: 添加链接到另一个容器;

–expose=[]: 开放一个端口或一组端口;

eg1:docker run -it busybox /bin/bash    //以交互方式运行shell命令行eg2:docker run -d -p 80:80 --name nginx nginx   //以后台方式运行nginx,并把容器的80端口映射到宿主机的80端口,容器名称nginxeg3:docker run -d -p 80:80 --name nginx --link tomcat:tomcat -v /logs/:/var/logs/nginx nginx   //以后台方式运行nginx,并把容器的80端口映射到宿主机的80端口,容器名称nginx,连接tomcat容器,把宿主机的/logs目录挂载到容器中的/var/logs/nginx目录

2)容器使用卷(volumn)

通过使用(挂载)卷到容器,可以把hostd机上的某个目录"插入"到容器中,然后容器中就能直接访问host机上的文件了,即使容器删除掉,卷里的数据仍然可能持久保存。

eg:docker run -it -v /Users/yjmyzz/docker_volumn:/opt/webapp --name myubuntu ubuntu /bin/bash   //-v /Users/yjmyzz/docker_volumn:/opt/webapp的部分,意思就是将机/Users/yjmyzz/docker_volumn这个目录映射到容器中的/opt/webapp

3)启停容器实例

docker start container_ID  //容器ID从docker ps -a获取
docker stop container_ID
docker restart container_ID
docker rm -f container_ID  //删除容器时,容器必须是停止状态
docker container prune(修剪/削减)  //清理掉所有处于终止状态的容器

4)容器的导出和导入

比如,我们要迁移容器时,需要导出本地某个容器,可以使用 docker export 命令:

docker export container_ID > ubuntu16.04.tar  //导出容器快照到本地文件

迁移到目标主机后,再使用 docker import 从容器快照文件中恢复为新的容器启动镜像:

cat docker/ubuntu.tar | docker import - New/ubuntu:v1
docker images  //验证,这时可看到上述新的镜像,然后就可以以该镜像从新启动容器了

2.5 Docker新建网络

docker network create -d bridge test-net   //-d:参数指定 Docker 网络类型,有 bridge、overlay。其中 overlay 网络类型用于 Swarm mode

docker network ls //查看当前网络

可以在宿主机的 /etc/docker/daemon.json 文件中增加以下内容来设置全部容器的 DNS,配置完,需要重启 docker 才能生效:

{
“dns” : [
“114.114.114.114”,
“8.8.8.8”
]
}
设置后,启动容器的 DNS 会自动配置为 114.114.114.114 和 8.8.8.8。

查看容器的 DNS 是否生效请执行以下命令,它会输出容器的 DNS 信息:

$ docker run -it --rm  ubuntu  cat etc/resolv.conf   //--rm:容器退出时自动清理容器内部的文件系统

如果手动手动指定容器的DNS配置,可执行:

docker run -it --rm -h host_ubuntu --dns=114.114.114.114 --dns-search=blue.cn ubuntu //-h HOSTNAME 或者 --hostname=HOSTNAME: 设定容器的主机名,它会被写到容器内的 /etc/hostname 和 /etc/hosts。–dns=IP_ADDRESS: 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名。–dns-search=DOMAIN: 设定容器的搜索域,当设定搜索域为 .example.com 时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 host.example.com。如果在容器启动时没有指定 --dns 和 --dns-search,Docker 会默认用宿主主机上的 /etc/resolv.conf 来配置容器的 DNS。

2.6 Docker 镜像仓库

容器中,仓库(Repository)就是集中存放容器的基础,即镜像的地方。其中,Docker 官方维护了一个公共仓库 Docker Hub;


1)仓库的登录和退出

docker login  //输入之前注册的用户名和密码
docker logout
docker search ubuntu //查找相关镜像
docker pull ubuntu:18.04
docker tag ubuntu:18.04 username/ubuntu:18.04  //完成一些初始化和定制后,可重新打标签
docker push username/ubuntu:18.04  //上传到官方仓库

2)仓库Registry

仓库注册服务器(registry)是用来存放仓库的地方,里面存放着多个仓库,而在每个仓库当中集中存放这某一类镜像,它们通过不同的标签(tag)来进行区分。

2.7 Docker其他命令

1)获取日志:使用docker logs : 获取容器的日志

用法docker logs [OPTIONS] CONTAINER

参数

-f : 跟踪日志输出

-t : 显示时间戳

–tail :仅列出最新N条容器日志

–since :显示某个开始时间的所有日志

eg:docker logs nginxdocker logs -f nginx    #追踪模式

2)使用docker inspect:获取容器/镜像的元数据

docker inspect命令可查看 Docker 的底层信息。它会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息。

用法:docker inspect [OPTIONS] NAME|ID [NAME|ID…]

参数

-f :指定返回值的模板文件。

-s :显示总的文件大小。

–type :为指定类型返回JSON。

3)使用docker top 查看容器中运行的进程信息,支持 ps 命令参数

4)使用docker cp 用于容器与主机之间的数据拷贝

用法:

docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|
docker cp [OPTIONS] SRC_PATH| CONTAINER:DEST_PATH

参数:-L :保持源目标中的链接

5)删除container

用法:docker rm 镜像名称或者容器id(container)

批量删除:

docker rm -f | $(docker ps -a -q)
docker ps -a -q | xargs docker rm
docker rm -f container_ID

6)启停:

docker start/stop/restart (docker 启动、停止、重启)<container>docker kill CONTAINER  强制停止

【docker stop 与 docker kill 的区别】

docker stop命令来停掉容器的时候,docker默认会允许容器中的应用程序有10秒的时间用以终止运行。在docker stop命令执行的时候,会先向容器中PID为1的进程发送系统信号SIGTERM,然后等待容器中的应用程序终止执行,如果等待时间达到设定的超时时间,或者默认的10秒,会继续发送SIGKILL的系统信号强行kill掉进程。在容器中的应用程序,可以选择忽略和不处理SIGTERM信号,不过一旦达到超时时间,程序就会被系统强行kill掉,因为SIGKILL信号是直接发往系统内核的,应用程序没有机会去处理它。在使用docker stop命令的时候,我们唯一能控制的是超时时间,比如设置为20秒超时:

docker stop --time=20 container_name

docker kill命令不会给容器中的应用程序有任何gracefully shutdown的机会。它会直接发出SIGKILL的系统信号,以强行终止容器程序的运行。docker kill没有任何的超时时间设置,它会直接发送SIGKILL信号,以及用户通过signal参数指定的其他信号。对比以上,docker kill适合用来强行终止程序并实现快速停止容器。而如果希望程序能够gracefully shutdown的话,应用docker stop;

docker kill --signal=SIGINT container_name  //向docker中的程序发送SIGINT信号

7)Dockerfile中CMD命令的用法回顾

1>用法1:CMD command param1 param2

这种方式,其实是以shell的方式运行程序。最终程序被执行时,类似于/bin/sh -c的方式运行了我们的程序,这样会导致/bin/sh以PID为1的进程运行,而我们的程序只不过是它fork/execs出来的子进程而已。

2>用法2;使用 CMD [“executable”,”param1”,”param2”]

这种方式启动程序,执行和启动时,我们的程序会被直接启动执行,而不是以shell的方式,这样我们的程序就能以PID=1的方式开始执行了。

8)查看docker 容器启动的完整命令

可以借助python模块runlike来实现,执行:

1>yum install -y python-pip //OS里默认有pip3,也可以直接用,可pip install --upgrade pip升级到21.2.4

2>pip install runlike

3> which runlike //验证

4>命令语法:runlike -p <容器名>|<容器ID>

帮助手册:https://github.com/lavie/runlike

5> pip执行报错:

pip -V //报错如下

Traceback (most recent call last):File "/usr/local/bin/pip", line 7, in <module>from pip._internal.cli.main import mainFile "/usr/local/lib/python3.5/dist-packages/pip/_internal/cli/main.py", line 57sys.stderr.write(f"ERROR: {exc}")^
SyntaxError: invalid syntax

这是因为默认的python运行为2.7版本,而pip默认也是python2.7来安装,故会报3.5错误;
如果没有python3,只需执行:sudo apt-get remove python-pip;sudo apt-get install python-pip

如果是3.5 需下载3.5的pip支持包:
apt-get remove python-pip
wget https://bootstrap.pypa.io/pip/3.5/get-pip.py
python3.5 get-pip.py


9)docker top

用来查看一个容器里面的进程信息的,用法:

docker top 容器IDdocker stats  //查看当前主机下所有容器占用内存和cpu的情况

10)镜像导出,导入
docker load && docker save

eg1:docker save registry:2.7.1 >registry-2.7.1.tar //可以把一个镜像保存到tar文件中eg2:docker load < registry-2.7.1.tar  //把镜像从tar文件导入到docker中

11)docker events

用以实时获取docker的各种事件信息

12)docker update

当我们docker run 了之后却发现里面有一些参数并不是想要的状态,比如配置的nginx容器cpu或者内存太小,这个时候就可以使用docker update去修改这些参数

docker update nginx --cpus 2

13)docker history

当修改了一个镜像,但是忘记了每一层的修改命令,或者想查看一个镜像是怎么构建的时候就可以使用这个命令

14)docker wait: 查看容器的退出状态,了解指定容器是正常退出的还是异常退出

15)docker diff

当运行了一个容器,但是不知道容器里修改了哪一些文件的时候可以使用这个命令

三、实例应用

3.1、Docker 容器误退出后重新进入的几种方式:

1>借助工具nsenter

nsenter是一个命令行工具,用来进入到进程的linux namespace中。docker提供了exec命令可以进入到容器中,nsenter具有跟docker exec差不多的执行效果,但是更底层,特别是docker daemon进程异常的时候,nsenter的作用就显示出来了,常用于排查线上的docker问题。

在这之前,要连接到容器,需要找到容器的第一个进程的PID,通过这个PID,就可以连接到这个容器,执行:

docker inspect --format “{{ .State.Pid }}” //–format参数可简写为-f;docker ps获取容器id;

然后借助linux自带命令nsenter,它可以访问另一个进程的名字空间,正常工作需要有 root 权限。通过该工具我们就可以重新连接到容器。

如果系统中没有安装的话,可下载安装,下载地址:wget https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.32/util-linux-2.32.tar.gz(或wget https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.36/util-linux-2.36.tar.gz);从util-linux版本2.23开始,nsenter工具就包含在其中。安装如下:

tar -xzvf util-linux-2.32.tar.gz
cd util-linux-2.32/
./configure --without-ncurses
make nsenter  //编译nsenter
cp nsenter /usr/local/bin

完成后,执行:

nsenter --target $PID --mount --uts --ipc --net --pid,连接容器示例:nsenter --target 23592 --mount --uts --ipc --net --pid   //这样就成功进入pid=23592的容器了

2> 借助libcontainer中的nsinit工具:

另外,从0.9版本开始,Docker自身就具有一个管理容器的库,名字为 libcontainer。libcontainer中的nsinit工具允许用户直接访问linux名字空间和cgroup内核。

nsinit读取的是位于/var/lib/docer/execdriver/native/容器目录下的配置数据。要运行nsinit,你需要切换到容器目录下。由于/var/lib/docker目录对于root用户是只读权限,因此你还需要root权限。通过docker的ps命令,你可以确定容器ID。一旦你进入/var/lib/docker目录,你就可以连接容器了:

nsinit exec /bin/bash

四、相关概念和重要内容

4.1、Dockfile文件编写说明

FROM 现有容器镜像 //指明定制的镜像都是基于 FROM 的镜像名称/ID
RUN <命令行命令> //其中<命令行命令> 等同于,在终端操作的 shell 命令。
RUN [“可执行文件”, “参数1”, “参数2”] //比如:RUN [“./test.php”, “dev”, “offline”] 等价于 RUN ./test.php dev offline
COPY [–chown=:] <源路径1>… <目标路径>
COPY [–chown=:] [“<源路径1>”,… “<目标路径>”] //等同与docker copy 其中,[–chown=:]:可选参数,用户改变复制到容器内文件的拥有者和属组。
CMD <shell 命令>
CMD [“<可执行文件或命令>”,“”,“”,…] //推荐使用该形式
CMD [“”,“”,…] / /该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
ENTRYPOINT [“”,“”,“”,…] //ENTRYPOINT类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序,它试验定参,而一般变参使用 CMD,且 CMD 多用于给 ENTRYPOINT 传参。但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。且如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。示例如下:
ENTRYPOINT [“nginx”, “-c”] # 定参
CMD [“/etc/nginx/nginx.conf”] # 变参 ,传给ENTRYPOINT使用,相当于执行:nginx -c /etc/nginx/nginx.conf
ENV //设置定义了环境变量,这样在后续的指令中,就可以使用这个环境变量了
ENV = =…
ARG <参数名>[=<默认值>] //构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只对 docker build 的过程中有效,不影响容器内部,构建好的镜像内不存在此环境变量。但可在构建命令 docker build 中使用 --build-arg <参数名>=<值> 来覆盖。
VOLUME [“<路径1>”, “<路径2>”…] //定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷;这样可以避免重要的数据,因容器重启而丢失,这是非常致命的;避免容器不断变大
VOLUME <路径> //在启动容器 docker run 的时候,我们可通过 -v 参数修改挂载点
EXPOSE <端口1> [<端口2>…] //声明端口;在运行时使用docker run -P 自动随机映射 EXPOSE 的端口
WORKDIR <工作目录路径> //指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
USER <用户名>[:<用户组>] //用于指定容器启动后执行后续命令的用户和用户组(用户和用户组必须提前已经存在)
HEALTHCHECK [选项] CMD <命令> //设置检查容器健康状况的命令
HEALTHCHECK NONE //如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK [选项] CMD <命令> //这边 CMD 后面跟随的命令使用
ONBUILD <其它指令> //用于延迟构建命令的执行。在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
LABEL <key>=<value> <key>=<value> <key>=<value> … //用来以键值对的形式给镜像添加一些元数据(标签说明)

4.2、Docker容器的分层结构

首先我们来说下UnionFS(联合文件系统); Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以构建出各种具体的应用镜像。

特性: 一次同时加载多个文件系统,但对外面,只能看到一个文件系统,*UnionFS加载后会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

Docker镜像的加载原理:

docker镜像实际上由一层层的文件系统组成,这种层级的文件系统UnionFS。 bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。

rootfs(root file system),在bootfs之上。包含的就是典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。Docker镜像层都是只读的,容器层是可写的;当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。

Docker 镜像是由多个文件系统(只读层)叠加而成,每个层仅包含了前一层的差异部分。当我们启动一个容器的时候,Docker 会加载镜像层并在其上添加一个可写层。容器上所做的任何更改,譬如新建文件、更改文件、删除文件,都将记录与可写层上。容器层与镜像层的结构如下图所示:

容器与镜像最大的区别就在于可写层上。如果运行中的容器修改了现有的一个已存在的文件,那该文件将会从可写层下的只读层复制到可写层,该文件的只读版本仍然存在,只是已经被可写层中该文件的副本所隐藏。其中,多个容器共享镜像的结构如下所示:

4.3、容器数据卷

为防止放在容器中的数据,当容器删除以后,数据出现丢失。引入了将数据持久化的需求,即容器之间数据共享:将Docker容器中产生的数据同步到本地。这就是容器数据卷的技术:也叫目录的挂载,将容器内的目录挂载到宿主机上面。

这样的话,即使容器没有启动,要修改容器内的数据也只需在本地操作即可,同时容器间也可以进行数据的共享。其中:

1)匿名挂载: 就是我们在进行挂载时不写主机内路径,只写容器内路径,docker会自动帮我们在主机生成一个目录用于容器的数据挂载;使用docker volume ls查看可看到OLUME_NAME中没有具体的名字,只有一串地址值
2)具名挂载:容器创建前使用-v 卷名:容器内路径来进行挂载
docker run -d -it -v centos:/home/test:rw //还可配合ro/rw 改变读写权限
docker volume ls //但是此时只知道将容器内的数据卷挂载到了主机,具体挂载到了哪个位置则需要使用inspect来查看
docker volume inspect centos

Docker容器回顾之运维篇相关推荐

  1. 蚂蚁金服 Service Mesh 大规模落地系列 - 运维篇

    <蚂蚁金服 Service Mesh 大规模落地系列>将会从核心.RPC.消息.无线网关.控制面.安全.运维.测试等模块对 Service Mesh 双十一大规模落地实践进行详细解析,文末 ...

  2. centos7 如何安装部署k8s_架构运维篇(五):Centos7/Linux中安装部署RocketMQ

    上一篇 架构运维篇(四):Centos7/Linux中Tomcat安装SSL证书实践 这一篇讲一下在Centos7/Linux安装RocketMQ,MQ的具体应用场景和使用就不再啰嗦了.我在没有使用过 ...

  3. 视频教程-Prometheus+Grafana企业级监控实战(运维篇)2020年视频教程-Linux

    Prometheus+Grafana企业级监控实战(运维篇)2020年视频教程 资深DevOps工程师,曾经在华为,乐逗游戏工作,目前就职于知名物流公司工作 希望结合工作实践 给大家带来很多干货 周龙 ...

  4. java安装不上有关故障排除,Java有关问题排查(运维篇)

    Java问题排查(运维篇) 每一位开发想必都会遇到线上服务告警,而导致这样原因的肯能有流量增加或是代码中bug异常没有抓住导致,而此刻我们就需要去排查问题. 1:业务增加,导致FGC频繁发送,如果不知 ...

  5. 阿里云注册集群+Prometheus 解决多云容器集群运维痛点

    作者:左知 容器集群可观测现状 随着 Kubernetes(K8s)容器编排工具已经成为事实上行业通用技术底座,容器集群监控经历多种方案实践后,Prometheus 最终成为容器集群监控的事实标准. ...

  6. spring Boot 2 运维篇(spring boot程序的打包与部署,多环境开发配置文件的配置,spring boot集成日志框架)

    目录 1.SpringBoot程序的打包与运行 程序打包 程序运行 SpringBoot程序打包失败处理 命令行启动常见问题及解决方案 SpringBoot项目快速启动(Linux版) 2.配置高级 ...

  7. 运维篇Docker之初见本尊 1

    关注微信公众号:半路猿 和你一起分享半路出家程序员成长路上的所学所想所得 1.Docker是什么? ​ Docker官网 Modernize your applications, accelerate ...

  8. 【运维篇】Docker知识点万字吐血大总结,学完阿里叫我明天去入职

    一.Docker概述 1.1.虚拟化技术发展史 在虚拟化技术出现之前,如果我们想搭建一台服务器,我们需要做如下的工作: → 购买一台硬件服务器. → 在硬件服务器上安装配置操作系统系统. → 在操作系 ...

  9. 解读 2018 之运维篇:我们离高效智能的运维还有多远

    2018 年接近尾声,InfoQ 策划了"解读 2018"年终技术盘点系列文章,希望能够给读者清晰地梳理出重要技术领域在这一年来的发展和变化.本篇文章是运维领域 2018 年终盘点 ...

最新文章

  1. Thinkpad SL400 issue
  2. 【深度学习入门到精通系列】特别正经的合理调参介绍~❤️
  3. 如何在linux操作系统中安装oracle数据库,并设置开机自启动
  4. MySQL 内连接查询
  5. 【京东个人中心】——Nodejs/Ajax/HTML5/Mysql爬坑之注册与登录监听
  6. Word2Vec在中文的应用
  7. Word文档打不开怎么办
  8. 软件项目管理 2.3.项目章程
  9. ei会议和ei源刊的区别_ei和核心期刊的区别在哪里?
  10. 服务器运维 考什么证书,腾讯云服务器运维高级工程师认证(TCP)证书有效期、考试内容、费用...
  11. 常州大学/教务系统/教室相关
  12. jle汇编_汇编学习之路
  13. 牛客网——找出直系亲属
  14. 这个毕业季,让海马体照相馆为简历添“战斗力”
  15. android实现页面黑白色
  16. tekla相贯线展开CAD相贯线展开弧形管展开弯管展开理想3V
  17. 我的读书笔记——Spring
  18. android ios打包工具下载,IOS移动开发之快速打包工具---- iTunes 降级 到12.6,回到你熟悉的版本...
  19. b站 python_Python批量下载Bilibili(B站)1080P60fps视频-pip打包安装
  20. 端口映射提速工具PortTunnel用法

热门文章

  1. R语言 基于共现提取《雪中悍刀行》人物关系并画网络图
  2. 总结编译Liblas库时的问题(会及时更新解决博友遇到的问题)
  3. 彷徨 | HBase的详细介绍(概念以及特性)
  4. 【Python】有红、黄、绿三种颜色的球,编程计算摸出球的各种颜色搭配
  5. 解决linux对D盘(非系统盘)只有只读权限,无法创建文件夹 (linux 重新挂载盘符)
  6. 超融合架构和服务器虚拟化是什么关系?主流超融合厂商服务器虚拟化产品对比分析
  7. 通过opencv实现将图片转换为视频
  8. 后期处理体积-电影校色
  9. 语音识别开发---基于科大讯飞开放平台
  10. MySQL——插入数据