走进Docker的世界

文章目录

  • 前言
  • 一、Docker相关概述
    • 1、什么是docker?
    • 2、为什么出现docker?
    • 2.1 容器与kvm虚拟化的对比
    • 2.2 docker的作用
  • 二、安装docker及配置文件调整
    • 1.配置宿主机网卡转发
    • 2.yum安装docker
    • 3.修改daemon.json文件
    • 4.修改docker镜像和容器的默认存储路径
    • 5.启动docker
  • 三、Docker的核心要素
  • 四、Docker实现原理
    • 4.1 什么是Cgroups?
    • 4.2 UnionFS联合文件系统
    • 4.3 镜像中每一层的文件都是分散在不同的目录中的,如何把这些不同目录的文件整合到一起呢?
  • 五、Docker网络
    • 5.1 网络模式种类
      • 5.1.2 bridge模式
      • 5.1.3 如何查看网桥?
      • 5.1.4 docker创建容器时会做哪些操作,才能实现容器间的联通?
      • 5.1.5 docker的容器间通信
      • 5.1.6 我们如何知道网桥上的这些虚拟网卡与容器端是如何对应?
      • 5.1.7 容器与宿主机之间的通信
  • 六、Docker常用操作命令


前言

介绍docker的前世今生,了解docker的实现原理,带大家如何编写最佳的Dockerfile构建镜像。通过本章的学习,大家会知道docker的概念及基本操作,并学会构建自己的业务镜像,并通过抓包的方式掌握Docker最常用的bridge网络模式的通信


一、Docker相关概述

1、什么是docker?

	docker是一个基于操作系统内核,提供轻量级虚拟化功能的C/S架构的软件产品。基于轻量的特性,解决软件交付过程中的环境依赖。
	是一个开放源代码的容器化平台,可快速、高效、可移植地构建、打包、部署和运行应用程序,容器就是在隔离的环境运行的一个进程,如果进程停止,容器就会销毁。隔离的环境拥有自己的系统文件,ip地址,主机名等。

2、为什么出现docker?

首先看一组图片对比
在这里插入图片描述

随着技术的更新迭代以及公司业务架构的变换,需要一种轻量、高效的虚拟化能力。因此由之前的传统业务部署方式-->虚拟化技术部署方式-->容器化部署方式的变化,
	每种部署方法都标志的一个技术时代的迭代.当下主流的就是容器化部署方式。那么这三种方式有什么优缺点呢?

Hypervisor: 一种运行在基础物理服务器和操作系统之间的中间软件层,可允许多个操作系统和应用共享硬件 。常见的VMware的 Workstation 、ESXi、微软的Hyper-V或者思杰的XenServer。

Container Runtime: 通过Linux内核虚拟化能力管理多个容器,多个容器共享一套操作系统内核。因此摘掉了内核占用的空间及运行所需要的耗时,使得容器极其轻量与快速。

2.1 容器与kvm虚拟化的对比

启动秒级(docker)分钟级(kvm)
硬盘使用一般为 MB一般为 GB
性能接近原生弱于
系统支持量单机支持上千个容器一般几十个
特性容器虚拟机

2.2 docker的作用

- 可以把应用程序代码及运行依赖环境打包成镜像,作为交付介质,在各环境部署

- 可以将镜像(image)启动成为容器(container),并且提供多容器的生命周期进行管理(启、停、删)

- container容器之间相互隔离,且每个容器可以设置资源限额

- 提供轻量级虚拟化功能,容器就是在宿主机中的一个个的虚拟的空间,彼此相互隔离,完全独立

二、安装docker及配置文件调整

1.配置宿主机网卡转发

为什么要配置网卡转发后续会在docker网络章节中具体详解

配置如下(示例):

cat <<EOF >  /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1
EOF
然后在执行 sysctl -p /etc/sysctl.d/docker.conf 进行内核参数加载

2.yum安装docker

在线安装(示例):

	1、如果服务器已经配置好了yum源,则直接执行  
		yum list docker-ce --showduplicates | sort -r  查看源中可用版本
		yum -y install xxxx  #安装 xxx是 查看后源中可用版本名称,复制替换xxx即可
	2、查看是否安装成功,返回版本信息则安装成功
		docker version

离线安装(示例):

	1、如果服务器不通外网,则使用我已经下载好的安装包即可,执行install.sh 脚本安装即可,只针对x86_64操作系统
		下载地址 https://download.csdn.net/download/weixin_50902636/88713671
	2、查看是否安装成功,返回版本信息则安装成功
		docker version

3.修改daemon.json文件

vim /etc/docker/daemon.json
{
  "log-driver":"json-file",
  "log-opts": {"max-size":"200m", "max-file":"3"},
  "exec-opts": ["native.cgroupdriver=systemd"],
  "insecure-registries": [
    "https://harbor.test.local"
}

配置文件含义解释:
	log-driver:指定容器日志的驱动程序。在这个例子中,json-file表示将日志输出到JSON格式的文件中。
	
	log-opts:给出了进一步的日志选项。max-size指定了每个日志文件的最大大小(在这里是200MB),max-file指定了要保留的最大日志文件数(在这里是3个)。
	
	exec-opts:指定Docker守护进程的执行选项。在这个例子中,native.cgroupdriver=systemd表示使用systemd作为Cgroups驱动程序。

	insecure-registries:列出了Docker守护进程信任的不安全的注册表地址。在这个例子中,Docker将信任https://harbor.test.local,即允许从这个地址拉取和推送镜像,即使这个地址没有经过认证或加密。

敲黑板: 看重点
	面试知识点:
		`之前面试时,被面试官问道,你们的docker日志是怎么清理的,以上的日志配置就是回答项,别再说找到对应的容器ID进行echo '' > xxx-json.log了,假如容器过多,难不成手动一个个清理~~`

4.修改docker镜像和容器的默认存储路径

	这里就会有人问道,为什么要修改这个,请看下面的VCR,随着时间增长,docker的默认存储路径/var/lib/docker/会逐渐将/目录打满,
众所周知,生产环境的/根目录本身就没有多少磁盘量,像我的环境中一般是50GB左右,长此以往会占满根目录,为了杜绝后患,在安装时我们就将该隐患给排除掉,
具体操作,请看以下大屏幕
	
	vim /usr/lib/systemd/system/docker.service 找到以下文件
	ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
	
	修改为这个 --graph 指定了新的Docker镜像和容器的存储路径
	ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --graph /export/docker

在这里插入图片描述

5.启动docker

	systemctl daemon-reload
	systemctl start docker
	systemctl enable docker

三、Docker的核心要素

在这里插入图片描述

docker有三大核心要素:
	
	镜像(image): 打包了业务代码及运行环境的包,是静态的文件,不能直接对外提供服务。
	
	容器(container): 镜像的运行时,可以对外提供服务。

	仓库(registry): 存放镜像的地方
		共有仓库: Docker hub 、阿里 ...
		私有仓库: harbor 自行搭建

四、Docker实现原理

首先,要清楚docker的优点在于: 轻量级的虚拟化、容器的快速启停,那么虚拟化核心需要解决的问题就是资源隔离和资源限制

	虚拟化硬件技术: 它是通过一个hypervisor层实现对资源的彻底隔离
	容器: 则是操作系统级别的虚拟化,利用的是linux内核的Cgroup和Namespace特性来实现隔离

通俗将就是docker会在启动一个容器时,调用linux内核的Namespace接口,创建一个虚拟空间,创建的时间支持设置以下几种:

名称作用
pid namespace用于进程隔离
net namespace管理网络接口隔离
ipc namespace管理对IPC资源的访问隔离
mnt namespace管理文件系统挂载点隔离
uts namespace隔离主机名、域名
user namespace隔离用户、用户组

但是,通过上述的namespace接口只能保证容器之间的隔离,但是没法控制每个容器占用多少资源,如果某个容器正在执行CPU密集型的任务,那么就会影响到其他容器中任务的性能与执行效率,导致多个容器相互影响并抢占资源,从而导致容器宕机.

综上所述,就会出现一个新问题,如何对容器的资源使用进行限制就成了解决进程虚拟资源隔离之后的主要问题
在这里插入图片描述
因此,从而引出linux内核的另一个机制Cgroups

4.1 什么是Cgroups?

	cgroups是Control Groups的简称,是linux内核提供的一种机制,它可以根据需求把一系列任务及子任务整合到按资源划分等级的不同组中,从而为系统资源管理提供一个统一的框架。

	Cgroups能够隔离宿主机上的物理资源,例如:CPU、MEM、disk.每个cgroup都是一组被相同的标准和参数限制的进程,而我们需要做的,其实就是把容器这个进程加入到指定的Cgroup中。

4.2 UnionFS联合文件系统

	linux内核提供的Namespace和cgroup分别解决了容器的资源隔离和资源限制,那么容器是很轻量的,通常每台机器中可以运行几十上百个容器,
这些个容器是共用一个image,还是各自将这个image复制了一份,然后各自独立运行呢? 

如果每个容器之间都是全量的文件系统拷贝,那么会导致至少如下问题:
	- 运行容器的速度会变慢
	- 容器和镜像对宿主机的磁盘空间的压力

如何解决上述的问题,则引入了联合文件系统以及镜像分层,如以下例子:
docker镜像是由一系列的层组成的,每层代表Dockerfile中的一条指令

	FROM ubuntu:15.04
	COPY . /app
	RUN make /app
	CMD python /app/app.py

这里的 Dockerfile 包含4条命令,其中每一行就创建了一层,下面显示了上述Dockerfile构建出来的镜像运行的容器层的结构:
在这里插入图片描述

	镜像就是由这些层一层一层堆叠起来的,镜像中的这些层都是只读的,当我们运行容器的时候,就可以在这些基础层至上添加新的可写层,
也就是我们通常说的`容器层`,对于运行中的容器所做的所有更改(比如写入新文件、修改现有文件、删除文件)都将写入这个容器层.

有了上述的描述,就能更好的回答了容器是共用一个image还是复制一份image单独使用的问题

	对容器层的操作,主要利用了写时复制(CoW)技术。CoW就是copy-on-write,表示只在需要写时才去复制,这个是针对已有文件的修改场景。
CoW技术可以让所有的容器共享image的文件系统,所有数据都从image中读取,只有当要对文件进行写操作时,才从image里把要写的文件复制到自己的文件系统进行修改。

	所以无论有多少个容器共享同一个image,所做的写操作都是对从image中复制到自己的文件系统中的复本上进行,并不会修改image的源文件,且多个容器操作同一个文件,会在每个容器的文件系统里生成一个复本,每个容器修改的都是自己的复本,相互隔离,相互不影响。使用CoW可以有效的提高磁盘的利用率。 

在这里插入图片描述

4.3 镜像中每一层的文件都是分散在不同的目录中的,如何把这些不同目录的文件整合到一起呢?

	UnionFS 其实是一种为 Linux 操作系统设计的用于把多个文件系统联合到同一个挂载点的文件系统服务。
	它能够将不同文件夹中的层联合(Union)到了同一个文件夹中,整个联合的过程被称为联合挂载(Union Mount)。

在这里插入图片描述
上图是AUFS的实现,AUFS是作为Docker存储驱动的一种实现,Docker 还支持了不同的存储驱动,包括 aufs、devicemapper、overlay2、zfs 和 Btrfs 等等,在最新的 Docker 中,overlay2 取代了 aufs 成为了推荐的存储驱动,但是在没有 overlay2 驱动的机器上仍然会使用 aufs 作为 Docker 的默认驱动。

五、Docker网络

	docker容器是一块具有隔离性的虚拟系统,容器内可以有自己独立的网络空间
	主要通过docker网络要实现以下功能:
		- 多个容器之间是如何实现通信的呢?
		- 容器和宿主机之间又是如何实现的通信呢?
		- 使用-p参数是怎么实现的端口映射?

5.1 网络模式种类

在使用docker run创建Docker容器时,可以用--net选项指定容器的网络模式,Docker有以下4种网络模式:

	- bridge模式,使用--net=bridge指定,默认设置

	- host模式,使用--net=host指定,容器内部网络空间共享宿主机的空间,效果类似直接在宿主机上启动一个进程,端口信息和宿主机共用

	- container模式,使用--net=container:NAME_or_ID指定 指定容器与特定容器共享网络命名空间

	- none模式,使用--net=none指定网络模式为空,即仅保留网络命名空间,但是不做任何网络相关的配置(网卡、IP、路由等)

5.1.2 bridge模式

本文主要讲bridge即桥接模式,在创建容器时,如果没有指定网络模式,则默认就是桥接bridge模式,下面是桥接模式的一个示意图
在这里插入图片描述

	在深入学习桥接模式时,首先要了解以下概念:
		在linux中能够起到虚拟交换机作用的网络设备就是网桥,它是一个工作在数据链路层的设备,主要功能就是根据MAC 地址将数据包转发到网桥的不同端口上实现容器之间的联通。

5.1.3 如何查看网桥?

yum install -y bridge-utils #安装命令

[root@k8snode01 ~]# brctl show #查看网桥
bridge name     bridge id               STP enabled     interfaces
cni0            8000.4ad53cf978fe       no              veth3c2abeae
                                                        veth617f2dd3
                                                        veth65d9457c
                                                        veth6b40ac8e
                                                        veth757e7d9b
                                                        veth7fa26f47
                                                        veth909d83df
                                                        veth9bc5d22f
                                                        vetha9f1b82b
                                                        vethb627deae
                                                        vethd3d9ebd5
                                                        vethf5e89e13
docker0         8000.0242456ef1e2       no

5.1.4 docker创建容器时会做哪些操作,才能实现容器间的联通?

- 创建一对虚拟接口/网卡,也就是veth pair;
- veth pair的一端桥接 到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 vethxxxxxx;
- veth paid的另一端放到新启动的容器内部,并修改名字作为 eth0,这个网卡/接口只在容器的命名空间可见;
- 从网桥可用地址段中(也就是与该bridge对应的network)获取一个空闲地址分配给容器的 eth0
- 配置容器的默认路由
补充:
	veth pair:  成对出现的一种虚拟网络设备,数据从一端进,从另一端出。用于解决网络命名空间之间的隔离。(解决宿主机与容器之间的网络通信)

从5.1.4可以清楚的知道,整个过程是由docker自动帮助我们完成的,那么下面请看具体的通信过程

5.1.5 docker的容器间通信

1、登录测试服务器,执行以下命令
	docker rm -f `docker ps -aq`
	docker ps
	brctl show # 查看网桥中的接口,目前没有

2、创建测试容器nginx-test1
	docker run -d --name test1 nginx:alpine
	brctl show # 查看网桥中的接口,已经把test1的veth端接入到网桥中
	ip a |grep veth # 已在宿主机中可以查看到
	docker exec -ti test1 sh 
	/ # ifconfig  # 查看容器的eth0网卡及分配的容器ip

3、再创建测试容器nginx-test2
	docker run -d --name test2 nginx:alpine
	docker exec -ti test1 sh 
	/ # ifconfig  # 查看容器的eth0网卡及分配的容器ip

4、进入nginx-test2容器,执行以下命令
	docker exec -ti test1 sh 
	curl 172.17.0.2:80  #curl 容器1的IP地址
	<!DOCTYPE html>
	<html>
	<head>
	<title>Welcome to nginx!</title>
	<style>
	发现容器2能curl通容器1
	容器2访问容器1流程分析:
		1、进入容器2,执行route -n eth0是容器2里的默认路由设备
		/ # route -n #检查路由
	Kernel IP routing table
	Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
	0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
	172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

		2、所有对172.17.0.0/16 网段的请求,都会被交给eth0来处理(即上面的第二条路由规则),网关是0.0.0.0,这意味着是一条直连路由规则
凡是匹配到这条规则的IP包,经过本机的eth0网卡,通过二层(数据链路层)直接发往目的主机

		3、而要通过二层网络到达 test1 容器,就需要有 172.17.0.2 这个 IP 地址对应的 MAC 地址。所以test2容器的网络协议栈,就需要通过 eth0 网卡发送一个 ARP 广播,来通过 IP 地址查找对应的 MAC 地址

		4、这个 eth0 网卡,是一个 Veth Pair虚拟设备对,它的一端在这个 test2 容器的 Network Namespace 里,而另一端则位于宿主机上(Host Namespace),并且被“插”在了宿主机的 docker0 网桥上。网桥设备的一个特点是插在桥上的网卡都会被当成桥上的一个端口来处理,而端口的唯一作用就是接收流入的数据包,然后把这些数据包的“生杀大权”(比如转发或者丢弃),全部交给对应的网桥设备处理。

		5、因此ARP的广播请求也会由docker0来负责转发,这样网桥就维护了一份端口与mac的信息表,因此针对test2的eth0拿到mac地址后发出的各类请求,同样走到docker0网桥中由网桥负责转发到对应的容器中。
	
# 网桥会维护一份mac映射表,我们可以大概通过命令来看一下,
[root@nginx02 ~]# brctl showmacs docker0
port no mac addr                is local?       ageing timer
  2     46:57:6d:fe:e2:b4       yes                0.00
  2     46:57:6d:fe:e2:b4       yes                0.00
  1     aa:fe:fd:cf:0f:53       yes                0.00
  1     aa:fe:fd:cf:0f:53       yes                0.00
## 这些mac地址是主机端的veth网卡对应的mac,可以查看一下
$ ip a 
5: veth89481c7@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether aa:fe:fd:cf:0f:53 brd ff:ff:ff:ff:ff:ff link-netnsid 0
7: veth129a5c1@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 46:57:6d:fe:e2:b4 brd ff:ff:ff:ff:ff:ff link-netnsid 1

容器间通信示意图

5.1.6 我们如何知道网桥上的这些虚拟网卡与容器端是如何对应?

## 查看test1容器的网卡索引
[root@nginx02 ~]# docker exec -ti test1 cat /sys/class/net/eth0/ifindex
4

## 主机中找到虚拟网卡后面这个@ifxx的值,如果是同一个值,说明这个虚拟网卡和这个容器的eth0网卡是配对的。
[root@nginx02 ~]# ip a |grep @if
5: veth89481c7@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
7: veth129a5c1@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
#!/bin/bash
#当容器过多时,该脚本可快速匹配虚拟网卡和哪个容器端是对应的
for container in $(docker ps -q); do
    iflink=`docker exec -it $container sh -c 'cat /sys/class/net/eth0/iflink'`
    iflink=`echo $iflink|tr -d '\r'`
    veth=`grep -l $iflink /sys/class/net/veth*/ifindex`
    veth=`echo $veth|sed -e 's;^.*net/\(.*\)/ifindex$;\1;'`
    echo $container:$veth
done

5.1.7 容器与宿主机之间的通信

	1、添加端口映射,启动一个名为test的容器
	docker run --name test -d -p 8088:80 nginx:alpine
	
	2、在本宿主机上和与宿主机同一网段的机器上curl 暴露出来的8088端口,发现也能curl通
	
	3、因此,请看下面的流向图,进行进一步分析

在这里插入图片描述

	容器与宿主机通信流程:
		1、访问本机的8088端口,数据包会从流入方向进入本机,因此涉及到PREROUTING和INPUT链,
			我们是通过做宿主机与容器之间加的端口映射,所以肯定会涉及到端口转换,那哪个表是负责存储端口转换信息的呢,就是nat表,负责维护网络地址转换信息的。因此我们来查看一下PREROUTING链的nat表
		[root@nginx02 ~]# iptables -t nat -nvL PREROUTING
		Chain PREROUTING (policy ACCEPT 70 packets, 4200 bytes)
		 pkts bytes target     prot opt in     out     source               destination         
		8279K  497M DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0      ADDRTYPE match dst-type LOCAL
		
		2、上述的TARGET为DOCKER,很明显DOCKER不是标准的动作,那DOCKER是什么呢?我们通常会定义自定义的链,这样把某类对应的规则放在自定义链中,然后把自定义的链绑定到标准的链路中,因此,此处DOCKER 是自定义的链。使用以下命令查看DOCKER这个自定义链上的规则
		[root@nginx02 ~]# iptables -t nat -nvL DOCKER
		Chain DOCKER (2 references)
 		pkts bytes target     prot opt in     out     source               destination         
    	0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
    	1    60 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0       tcp dpt:8088 to:172.17.0.4:80
		
		3、此条规则就是对主机收到的目的端口为8088的tcp流量进行DNAT转换,将流量发往172.17.0.4:80,172.17.0.4地址就是我们上面创建的test容器的ip地址,流量走到网桥上了,后面就走网桥的转发就ok了

		4、根据图可知,数据包在出口方向走POSTROUTING链,我们查看一下规则
		[root@nginx02 ~]# iptables -t nat -nvL POSTROUTING
		Chain POSTROUTING (policy ACCEPT 5359 packets, 325K bytes)
 		pkts bytes target     prot opt in     out     source               destination         
    	0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           
   		0     0 MASQUERADE  tcp  --  *      *       172.17.0.4           172.17.0.4           tcp dpt:80
   		注意:
   			MASQUERADE这个动作是什么意思,其实是一种更灵活的SNAT,把源地址转换成主机的出口ip地址:
   				这条规则会将源地址为172.17.0.0/16的包(也就是从Docker容器产生的包),并且不是从docker0网卡发出的,进行源地址转换,转换成主机网卡的地址。
   				大概的过程就是ACK的包在容器里面发出来,会路由到网桥docker0,网桥根据宿主机的路由规则会转给宿主机网卡eth0,这时候包就从docker0网卡转到eth0网卡了,并从eth0网卡发出去,这时候这条规则就会生效了,把源地址换成了宿主机eth0的ip地址。
	抓包分析:
		首先访问宿主机的8088端口,我们抓一下宿主机的eth0:
			tcpdump -i eth0 port 8088 -w host.cap
		
		然后最终包会流入容器内,那我们抓一下容器内的eth0网卡:
			tcpdump -i eth0 port 80 -w container.cap
		
		然后再另外一台机器访问一下:
			curl 192.168.1.10:8088 #该IP地址是运行容器test的宿主机地址
		
		停止抓包,拷贝容器内的包到宿主机:
			docker cp test:/root/container.cap /root/
		
		将container.cap host.cap两个文件下载到本地使用wireshark将包合并后进行分析。分析结果如下
		进到容器内的包做DNAT,出去的包做SNAT

在这里插入图片描述

六、Docker常用操作命令

	docker image ls										查看本地都有哪些镜像
	docker pull redis:6.0								拉取镜像
	docker pull --platform=linux/arm64  镜像地址			在centos操作系统上拉取arm环境的镜像(--platform标志可用于在FROM引用多平台镜像的情况下指定镜像的平台。构建镜像也可使用该参数 如:linux/amd64, linux/arm64, or windows/amd64)
	docker inspect redis:6.0			    			查看镜像的详细信息
	docker tag alpine:latest qfedu.com/alpine:latest    镜像打标签
	docker image rm redis:6.0							删除镜像
	docker  rmi $(docker images -q)						删除所有镜像
	docker container ls 								查看容器
	docker kill 容器名									强行停止容器
	docker ps -a										查看本地运行的容器
	docker logs -f 容器名/ID							查看某个容器的日志
	docker  start 容器名/ID								启动已存在的容器
	docker  stop 容器名/ID								停止正在运行的容器
	docker  restart 容器名/ID							重启容器
	docker rm 容器名/ID									删除容器	
	docker rm $(docker ps -a -q)                        删除所有已停止的容器
	docker run -itd -name 容器名 -p  映射的端口号:自身端口号  镜像名称:版本  启动一个新的容器并后台运行,-d后台执行
	docker  stop $(docker ps -a -q)					停止所有容器
	docker exec -it 容器名 bash  						进入容器内的命令行
	docker cp ./index.html 容器名:/usr/share/nginx/html/ 拷贝宿主机文件至某个容器内
	docker logs -f 容器名								查看容器日志
	docker system prune -a -f							删除停止的容器、无用的数据卷、网络和无tag的镜像
	docker	save IMAGE id -o /path/file.tar.gz			镜像导出
	docker  load -i /path/file.tar.gz					镜像导入
	docker save 镜像名1 镜像2 > /path/all.tar.gz			一次导出多个镜像
	docker top  容器ID									查看容器中的进程
	docker stats 容器ID									查看容器资源利用率(动态获取)
	docker stats 容器ID --no-stream  					查看容器资源利用率(静态获取)
	docker diff 容器ID									查看容器的文件结构更改
	docker commit -a "guodong" -m "my db" 容器ID  mymysql:v1 将旧容器保存为新的镜像,并添加提交人信息和说明信息。
	docker port 容器ID									查看容器的端口映射情况。 	
	docker pause db01									暂停数据库容器db01提供服务 
	docker unpause db									恢复数据库容器 db0 提供服务
	docker build -f /path/to/a/Dockerfile .				通过 -f Dockerfile文件的位置 创建镜像
	docker push myapache:v1								推送镜像到镜像仓库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/312586.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

高效构建Java应用:Maven入门和进阶(四)

高效构建Java应用&#xff1a;Maven入门和进阶&#xff08;四&#xff09; 四. Maven聚合和继承特性4.1 Maven工程继承关系4.2 Maven工程聚合关系 四. Maven聚合和继承特性 4.1 Maven工程继承关系 继承概念 Maven 继承是指在 Maven 的项目中&#xff0c;让一个项目从另一个项目…

GLES学习笔记---立方体贴图(一张图)

一、首先看一张效果图 立方体贴图 二、纹理坐标划分 如上图是一张2D纹理&#xff0c;我们需要将这个2D纹理贴到立方体上&#xff0c;立方体有6个面&#xff0c;所以上面的2D图分成了6个面&#xff0c;共有14个纹理坐标 三、立方体 上边的立方体一共8个顶点坐标&#xff0c;范围…

Redis(四)事务

文章目录 事务Redis事务 vs 数据库事务常用命令总结 事务 一个队列中、一次性、顺序性、排他性执行一系列命令 官网https://redis.io/docs/interact/transactions/ Redis事务 vs 数据库事务 概述详述1、单独的隔离操作Redis的事务仅仅是保证事务里的操作会被连续独占的执行&a…

2022 年全国职业院校技能大赛高职组云计算赛项试卷

【赛程名称】云计算赛项第一场-私有云 某企业拟使用OpenStack 搭建一个企业云平台&#xff0c;以实现资源池化弹性管理、企业应用集中管理、统一安全认证和授权等管理。 系统架构如图 1 所示&#xff0c;IP 地址规划如表 1 所示。 图 1 系统架构图 表 1 IP 地址规划 设备…

Java零基础教学文档第四篇:HTML_CSS_JavaScript(2)

【HTML】 【主要内容】WEB: 1&#xff0e;Web前端简介 2&#xff0e;创建第一个前端项目 3&#xff0e;相关标签详解 4&#xff0e;表格标签详解 5&#xff0e;表单标签详解 6&#xff0e;框架和实体字符 【学习目标】 1. Web前端简介 1.1 为什么要学习Web前端&#…

【Python机器学习】SVM——预处理数据

为了解决特征特征数量级差异过大&#xff0c;导致的模型过拟合问题&#xff0c;有一种方法就是对每个特征进行缩放&#xff0c;使其大致处于同一范围。核SVM常用的缩放方法是将所有的特征缩放到0和1之间。 “人工”处理方法&#xff1a; import matplotlib.pyplot as plt from…

Java异常处理之旅:解救迷失的程序员

目录​​​​​​​ 一、前言 二、基础知识 2.1 异常的概念 ​​​​​​2.2 异常分类 2.3 异常处理的原则 ​​​​​​三、异常处理的语法 3.1 try-catch语句 3.2 finally语句 3.3 throw语句 3.4 throws关键字 3.5 自定义异常 四、常见异常及处理方式 4.1 NullP…

【C语言】linux内核set_task_stack_end_magic函数

一、函数定义 void set_task_stack_end_magic(struct task_struct *tsk) {unsigned long *stackend;stackend end_of_stack(tsk);*stackend STACK_END_MAGIC; /* for overflow detection */ } 内核版本6.4.3、6.7。 二、代码解读 解读1 这段代码是一个在Linux内核中定…

芯课堂 | 固件升级方法及架构

本次介绍一种固件升级方法及架构。 所述方法通过运行引导加载程序&#xff0c;并基于引导加载程序&#xff0c;获取启动引导标志位&#xff1b; 在启动引导标志位为预设枚举标志位时&#xff0c;执行对应启动引导标志位的固件升级动作&#xff1b; 在启动引导标志位为非预设…

Cesium 模型压平

最近整理了下手上的代码&#xff0c;以下是对模型压平的说明。 原理是使用了customShader来重新设置了模型的着色器&#xff0c;通过修改模型顶点的坐标来实现了压平。 废话不多说&#xff0c;下面上代码&#xff1a; /*** class* description 3dtiles模型压平*/ class Flat…

leetcode 每日一题 2024年01月11日 构造有效字符串的最少插入数

题目 2645. 构造有效字符串的最少插入数 给你一个字符串 word &#xff0c;你可以向其中任何位置插入 “a”、“b” 或 “c” 任意次&#xff0c;返回使 word 有效 需要插入的最少字母数。 如果字符串可以由 “abc” 串联多次得到&#xff0c;则认为该字符串 有效 。 示例 …

辞旧岁,赢新篇,创维汽车召开年度会议立足过去,展望未来

为辞旧迎新&#xff0c;再创辉煌&#xff0c;创维汽车于1月4日-5日召开了事业部年度会议。本次会议将23年整体运营情况作出总结并对新一年的发展作出了目标规划。创维集团、创维汽车创始人黄宏生先生&#xff0c;开沃新能源汽车集团执行董事兼首席运营官诸萍女士&#xff0c;创…

记录一次华为云服务器扩容系统磁盘

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 1. 扩容步骤 1.1 在华为云控制台操作磁盘扩容 1.2 服务器上操作扩容步骤 1&#xff09;fdisk -l 查看扩容情况&#xff0c;确认…

git: Updates were rejected because the tip of your current branch is behind

一、报错含义 由于本地分支的tip落后远程分支&#xff0c;push操作被拒绝。 二、产生原因 我再本地拉去了新的分支并未同步到远程仓库&#xff0c;在新分支进行开发&#xff0c;由于前几天同步也创建了该分支并同步到了远程仓库&#xff0c;导致我本次push失败 三、解决方…

【CSS】首个字符占用多行,并自定义样式

效果 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>首字母大写</title><style&…

C++力扣题目111--二叉树的最小深度

力扣题目链接(opens new window) 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明: 叶子节点是指没有子节点的节点。 示例: 给定二叉树 [3,9,20,null,null,15,7], 返回它的最小深度 2 思路 看完了这篇104.二…

原生微信小程序-两次设置支付密码校验,密码设置二次确认

效果 具体代码 1、wxml <view style"{{themeColor}}"><view classcontainer><view class"password_content"><view wx:if{{type 1}}><view class"title"><view class"main_title">设置支付密码…

【Android开发】不同Activity之间的数据回传实例(一)摘桃子游戏

一、功能介绍 该项目实现的功能主要有&#xff1a; 在首页显示一个按钮点击该按钮跳转到桃园页面在桃园页面&#xff0c;点击桃子会弹窗显示摘到几个桃子&#xff0c;同时被点击桃子消失&#xff0c;总桃子数1点击退出桃园会返回首页&#xff0c;首页桃子数会根据点击的桃子数…

PPT插件-大珩助手-《提取选中的幻灯片》-选中新建

选中新建 提取选中的幻灯片到新的幻灯文稿中。PDF编辑器可以提取指定的页面到新的PDF文档中&#xff0c;PPT没有这个功能&#xff0c;因此开发。 软件介绍 PPT大珩助手是一款全新设计的Office PPT插件&#xff0c;它是一款功能强大且实用的PPT辅助工具&#xff0c;支持Wps Wo…

锂电池的电压和容量怎么计算?

锂电池组是由电池单体&#xff08;电芯&#xff09;通过串并联来组成 1、串联(S)增加电压&#xff0c;容量不变。 例如&#xff1a;1个磷酸铁锂电池的额定电压为3.2V&#xff0c;容量为4000mAH&#xff0c;将10个磷酸铁锂电芯串联&#xff0c;电池组电压&#xff1a;3.2v*10&a…