⼀、Docker
1、Docker介绍.pdf
1、Docker 是什么?
Docker 是⼀个开源的应⽤容器引擎,可以实现虚拟化,完全采⽤"沙
盒"机制,容器之间不会存在任何接⼝。
Docker 通过 Linux Container(容器)技术将任意类型的应⽤进⾏包
装,变成⼀种轻量级、标准化、可移植、⾃管理的组件。在包装应
⽤的同时,可连带该应⽤的依赖和环境⼀并进⾏打包,所以可以将
这种"包"移植到任意环境去运⾏,省去兼容性的问题。
2、Docker 和虚拟机的区别
Docker和虚拟机在以下⼋个⽅⾯存在差异:1. **启动速度:**Docker 启动速度⾮常快,属于秒级别,⽽虚拟机通
常需要⼏分钟去启动。
2. **资源消耗:**Docker 需要的资源更少,它直接运⾏在宿主机的内
核上,以⼀系列进程的结合形式存在。⽽虚拟机则需要消耗更多
的资源,因为它在操作系统级别进⾏虚拟化。
3. **轻量级:**Docker 更轻量,它的架构可以共⽤⼀个内核与共享应
⽤程序库,所占内存极⼩。⽽虚拟机则相对较重,需要消耗更多
的内存。
4. **隔离性:**虚拟机可以实现系统级别的隔离,⽽ Docker 则属于进
程之间的隔离,隔离性相对较弱。
5. **安全性:**Docker 的安全性也更弱。
6. **可管理性:**Docker 的集中化管理⼯具还不算成熟。
7. **兼容性:**开发⼈员不需要关系具体是哪个 Linux 操作系统,基本
市⾯上主流系统都可使⽤ Docker。
8. **数据持久性:**Docker ⽆法存储数据,当容器重启后,数据会消
失;⽽虚拟机可以存储各种数据,包括⽇志、数据库等。
3、Docker 解决的问题
(1)系统环境不⼀致问题
环境不同时可能会出现的环境问题:使⽤ docker 容器时:
将简易的操作系统、编写好的代码、部署完成的应⽤服务配置等打
包放到容器内,再转到鲸⻥上,由鲸⻥送到服务器,此时,⽆论是
什么运⾏环境,docker 容器都可以运⾏。(2)应⽤隔离问题
Linux 是⼀个⽀持多⽤户的操作系统,正因如此,可能会造成⽤户使
⽤时,互相之间占⽤资源过多,以致于服务器资源空间不⾜,⽽
docker 具有隔离性,可以在启动时就限定好硬件的使⽤率,当某个
容器到达或超过限定的阈值时,就会被 kill,此时需要运维⼈员对其
进⾏调试。
(3)服务器扩展问题
⽇常的业务量⼤多很平均,但在业务量繁多时期,⽐如"双⼗⼀",
"春运购票"等场景,就需要对服务器进⾏横向扩展才能将负载均衡下
来,⽽如果⼤规模地扩展服务器,待服务器满载时期过去,回到⽇
常业务量后,就会导致剩余资源极⼤地浪费。并且在扩展时,还要
对各种应⽤服务进⾏部署、调试等,⼯作量也⼗分庞⼤,所以,此
时使⽤ Docker 将会真正意义上实现快速部署,且耗费资源较少,尤
其不会出现兼容性的问题。
4、Docker 的优缺点
(1)优点
- **体积⼩:**减⼩系统的开销值,⼀台主机可以运⾏上千个容器。
- **启动迅捷:**更快速的交付和部署,docker容器 ,⽐传统虚拟机
要快很多,docker核⼼解决的问题就是利⽤容器实现VM类似的
功能。3. **操作⽅便:**通过配置 dockerfile 便⽀持灵活的⾃动化创建和部
署。 - **更轻松的扩展:**可以实现更简单的、更可靠的迁移,避免了兼容
性等问题。 - 更强的可扩展性和可移植性。
(2)缺点 - **安全问题:**如果没有正确配置,⼀个容器中的恶意代码可能会影
响到主机上的其他容器以及主机本身的安全。 - **存储问题:**当使⽤⼤量容器时,存储和管理容器映像可以变得⾮
常困难。这可能需要使⽤分布式存储或其他解决⽅案来管理⼤量
容器的存储。 - **性能问题:**在某些情况下,容器和虚拟机相⽐会导致性能损失。
这些性能问题越来越少,但是仍然需要考虑。 - **⽹络问题:**Docker 可能会在⽹络配置上存在⼀些问题,这可能
需要更多的时间来诊断和解决。 - **复杂性:**Docker 是⼀个⾮常灵活的系统,但这同时也让它更加
复杂。⻓时间使⽤ Docker 会产⽣⼤量的脚本和配置⽂件,这些
可能变得难以维护。 - **资源消耗:**使⽤ Docker 必须占⽤⼀些资源,包括 CPU、内
存、磁盘等等。如果运⾏容器的主机资源不⾜,可能会导致性能
问题。7. **学习曲线:**Docker 是⼀个相对新的技术,相⽐传统环境需要⼀
定的学习曲线。需要了解Docker 基本概念、命令和配置⽂件
等。 - **需要花费时间配置和管理:**使⽤ Docker 需要花时间配置和管理
容器集群和应⽤程序。需要配置每个容器,管理 Jenkins、
Kubernetes 等运⾏ Docker 容器的⼯具。 - **映像构建复杂:**构建Docker映像需要按照特定格式编写
Dockerfile 脚本,需要遵循⼀定的规范和流程,这可能需要更多
的时间和精⼒。
5、Docker 架构 - ⽤ docker pull 命令从 hub.docker.com 官⽹上下载 images (镜
像)。2. 可以⽤ docker save 命令将镜像保存到本地 tar ⽂件,也可以⽤
docker load 命令将本地tar ⽂件导⼊镜像。 - 可以⽤ docker build 构建 Dockerfile 镜像。
- 可以⽤ docker run 和 docker create 将镜像运⾏成 container
(容器),容器内可以安装所需要的 APP。 - 可以⽤ docker commit/export 将容器做成镜像反复的使⽤。
- 可以将⾃⼰制作的镜像发布到 hub.docker.com ⽹站,需要注册
账号。
6、Docker 核⼼概念 - 镜像(images):⼀个⾯向 docker 容器引擎的只读模板,也
是容器的基础,类似于 iso 镜像⽂件。 - **容器(container):**基于镜像所创建的虚拟实例,相当于⼀个
简易的 Linux 环境,可启停,且多个容器之间互相隔离。 - **仓库(Repository):**集中存放 docker 镜像的位置,可使⽤
docker pull 或 push 命令下载或上传到私有或公有仓库。 - **仓库注册服务器(registry):**存放仓库的地⽅,如果没有私有
仓库,则使⽤公共仓库 docker hub。
7、Docker 特性
**⽂件系统隔离:每个进程容器运⾏在⼀个完全独⽴的根⽂件系统
⾥。
资源隔离: 实现不同的容器的资源配额和调度,cgroup。⽹络隔离:**每个进程容器运⾏在⾃⼰的⽹络空间,拥有虚拟接⼝
和 IP 地址。
**⽇志记录:**Docker将收集到和记录的每个进程容器的标准流
(stdout/stderr/stdin),⽤于实时检索或者批量检索。
**变更管理:**容器⽂件系统的变更可以提交到新的镜像中,并可重
复使⽤以创建更多的容器。
**交互式shell:**Docker可以分配⼀个虚拟终端并且关联到任何容
器的标准输出上,例如运⾏⼀个⼀次性交互shell。
⼆、安装 Docker
1、Docker 要求2、安装 Docker
[root@doc ~]# cat << EOF | tee /etc/modules
load.d/k8s.conf
> overlay
> br_netfilter
> EOF
[root@doc ~]# modprobe overlay # 加载overlay内核
模块
[root@doc ~]# modprobe br_netfilter # 加载
br_netfilter内核模块[root@doc ~]# cat << EOF | tee
/etc/sysctl.d/k8s.conf
> net.bridge.bridge-nf-call-iptables = 1
> net.bridge.bridge-nf-call-ip6tables = 1
> net.ipv4.ip_forward = 1
> EOF
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
[root@doc ~]# sysctl --system
[root@doc ~]# yum install -y yum-utils device
mapper-persistent-data lvm2
[root@doc ~]# yum-config-manager --add-repo
https://mirrors.aliyun.com/docker
ce/linux/centos/docker-ce.repo
添加阿⾥云yum源
[root@doc ~]# yum install docker-ce docker-ce-cli
containerd.io docker-buildx-plugin docker-compose
plugin -y --allowerasing
安装docker,allowerasing:允许卸载旧版本
**overlay:**是⼀种⽂件系统层叠技术,常⽤于容器化平台(⽐如
Docker)中。它允许将多个⽂件系统叠加在⼀起,从⽽创建⼀个
统⼀可⻅的⽂件系统。通过加载 overlay 模块,可以在 Linux 系
统中使⽤ overlay ⽂件系统,并且它将提供⼀些额外的功能,⽐
如联合挂载、⽂件层叠等。
**br_netfilter:**Linux 内核中的⼀个模块,它提供了桥接设备(bridge device) 和⽹络过滤器(netfilter) 之间的集成。它允许在桥
接设备上使⽤⽹络过滤器功能,如防⽕墙规则、⽹络地址转换
(NAT) 等。通过加载 br_netfilter 模块,你可以在 Linux 系统中的
桥接设备上应⽤⽹络过滤规则对⽹络流量进⾏管理和控制。
device-mapper-persistent-data:⼀个Linux内核模块,它为
Device Mapper设备提供持久存储功能。DMPD提供了⼀个⽤于
存储映射关系的数据库,使得Device Mapper可以持久化存储映
射数据,以便在系统重新启动后仍然可以恢复之前的映射关系。
lvm2:Linux系统下的逻辑卷管理⼯具,LVM 的升级版,它是对
磁盘分区进⾏管理的⼀种机制,建⽴在硬盘和分区之上的⼀个逻
辑层,⽤来提⾼磁盘管理的灵活性。
3、设置阿⾥云镜像加速器
阿⾥云官⽹:https://www.aliyun.com/
登录后点击控制台控制台搜索"容器镜像服务ACR"
点击红框位置镜像⼯具⾃⼰的加速器地址:红框内代码复制到终端(每个⼈的不⼀样,要复制⾃⼰)命令
解释
docker
login(logout)
登录(登出) docker hub 账户,也可以指定某
个私有仓库登录,⽐如"docker login 私有仓
库地址 -u 登录⽤户"
三、Docker 基本操作
1、镜像操作
[root@doc ~]# sudo mkdir -p /etc/docker
[root@doc ~]# sudo tee /etc/docker/daemon.json <<-
'EOF'
> {
> "registry-mirrors":
["https://9ghz4eu4.mirror.aliyuncs.com"]
> }
> EOF
{
"registry-mirrors":
["https://9ghz4eu4.mirror.aliyuncs.com"]
}
[root@doc ~]# sudo systemctl daemon-reload
[root@doc ~]# sudo systemctl restart docker
[root@doc ~]# docker info | grep "https" # 查看
⾃⼰的镜像加速器地址
https://9ghz4eu4.mirror.aliyuncs.com/docker search 镜
像名
查找镜像,可根据名称、星级、是否官⽅发
布等条件查找(starts、official 等)
docker pull 镜像
名
下载某个镜像,不加标签默认下载最新版本
的镜像
docker images
查看现有镜像
docker inspect 镜
像名
查看镜像详细信息
docker tag 旧镜
像:标签 新镜像:标
签
可更改镜像的标签名,也可镜像名连同标签
⼀起修改成新镜像
docker rmi 镜像
名或镜像 id
删除某个镜像
docker save -o
保存位置 镜像名
保存导出某个镜像到某⼀位置
docker load < 保
存后⽣成的镜像
⽂件
导⼊本地保存的镜像⽂件
docker push 镜像
名
上传镜像,在上传之前需要将镜像使⽤ tag 命
令改名,改名为"仓库名/镜像"这种格式,才
可以上传
docker info
查看 docker 信息
cat 镜像⽂件 |
docker import -
镜像名:标签
导⼊本地镜像⽂件并设置名称docker system
prune --all --force
--volumes
删除所有未使⽤的⽂件,在 /var/lib/docker/
下
docker volume
prune
删除所有未使⽤的
卷,/var/lib/docker/volumes
docker system df 列出所有未使⽤的 docker ⽂件
docker image
prune -a
删除所有未使⽤的镜像
命令
解释
docker create -it
镜像 运⾏的程序
创建容器-i:让容器的输⼊保持打开-t:为容器
分配伪终端运⾏的程序:需要容器运⾏的某个
命令,如果想要容器持续运⾏,给/bin/bash
docker ps
查看所有容器,包括已退出的容器
docker ps -a
查看正在运⾏的容器
docker
start/stop/restart
容器名或 ID
启动/停⽌/重启某个容器
docker run [-itd]
容器名 运⾏的程
序 [-c 命令 ]
创建并启动容器等于 docker pull 命令+docker
create 命令+docker start 命令
docker attach 容 进⼊容器内部,可使⽤ exit 或 CTRL+D 退
2、容器操作器名/ID
出,也可以使⽤ CTRL+p+q
docker exec [-
itd] 容器名/ID
/bin/bash
分配⼀个 bash 环境再进⼊容器
docker export
容器名/ID > 保存
位置
导出容器到某个位置
docker import
本地容器⽂件 新
镜像名
导⼊某个容器⽂件到 docker 镜像并给新镜像
命名
docker commit
容器名/ID 新镜
像名
将某个容器保存⾄镜像
docker rm -f 容
器名/ID
删除容器,-f:强制删除
docker logs 容
器名/ID
查看容器标准输出的内容
docker run 的逻辑原理:执⾏此命令后,docker 后台会检测此容器
需要的镜像是否存在,如果本地不存在则去公共仓库下载。下载完
毕后,根据镜像创建⼀个容器,分配⼀个⽂件系统给容器,在只读
的镜像层外边挂载⼀层可读写层 ,从宿主机配置的⽹桥接⼝中桥接
⼀个虚拟机接⼝ 到容器中,分配⼀个地址池中的ip地址给容器执⾏⽤
户所执⾏的命令,执⾏完成后将容器终⽌运⾏。如果想让容器执⾏
完命令后继续运⾏,选项加 -d,此容器会在执⾏完命令后在后台运⾏。
0.启动docker守护进程
systemctl start docker
1.配置docker镜像站
{
"registry-mirrors": [
"https://do.nark.eu.org",
"https://dc.j8.work",
"https://docker.m.daocloud.io",
"https://dockerproxy.com",
"https://docker.mirrors.ustc.edu.cn",
"https://docker.nju.edu.cn"
]
}
2.docker search centos
3.dock pull centos
回顾29天 上午
1.介绍了docker
2.配置了dock的环境和安装了docker客户端和服务器
1.配置环境
3.启动了和关闭服务
4.查看镜像
/etc/modules-load.d/k8s.conf
/etc/sysctl.d/k8s.conf
#配置⼀个仓库
yum-config-manager --add-repo
https://mirrors.aliyun.com/docker
ce/linux/centos/docker-ce.repo
yum install docker-ce docker-ce-cli containerd.io
docker-buildx-plugin docker-compose-plugin -y
systemctl start|stop|restart docker.service
docker images5.搜索镜像
docker search tomcat|centos
6.下载镜像
vim /etc/docker/daemon.json
{
"registry-mirrors":[
"https://do.nark.eu.org",
"https://dc.j8.work",
"https://docker.m.daocloud.io",
"https://dockerproxy.com",
"https://docker.mirrors.ustc.edu.cn",
"https://docker.nju.edu.cn"
]
}
docker pull centos
1.运⾏容器
systemctl start docker.service
docker images
docker run -it --name=c0 centos:latest /bin/bash
2.当前运⾏的进程
3.当前位置和启动时间
4.cat /etc/redhat-release查看版本5.镜像是模版,容器是实例
6.容器中没有命令运
7.容器总是能轻易获取
8.配置yum
9.安装http
10.修改index⽂件
11.httpd -k start
12.访问
13.退出就没有服务了
14.查看docker进程
14.退出之后就没进程了
[root@4f651d1035c6 ~]# cat /etc/redhat-release
CentOS Linux release 8.4.210515.再次启动
16.接⼊到管理界⾯,将容器的命令⾏附加到当前的终端
17.启动服务,退出但是不中断 ctrl+p+q
不建议在⽣产中使⽤,不要⼿动启动和关闭容器,由编排⼯具
步骤
第⼀次创建容器
docker run -it --name=c0 centos:latest /bin/bash
配置阿⾥云的yum仓库
yum clean all && yum makecache
yum -y install httpdecho "docker_httpd_server" >
/var/www/html/index.html
systemctl start httpd
httpd -k start
curl localhost:80
在宿主上访问⽄
curl 172.17.0.2:80
⽆法在物理机器上访问,也⽆法ping到这个主机
如果没有指令正在执⾏,容器就会停⽌
exit
重启容器
docker start c0
c0
将c0的终端附加到当前的终端
docker attach c0
这个时候,httpd⼜停了
期望退出,服务继续运⾏
ctrl+p+q()
·⼀、Namespace
1、概念
Namespace 是实现 Linux 资源隔离的核⼼技术,实现了 6 项资源隔
离,包括主机名、⽤户权限、⽂件系统、⽹络、进程号、进程通
信。
2、作⽤
- **实现资源隔离:**通过使⽤Linux的Namespaces技术,Docker可
以在容器中创建独⽴的进程、⽂件系统、⽹络等环境。 - **提⾼安全性:**使⽤namespace可以实现不同⽤户或者不同进程
之间的隔离,防⽌相互⼲扰和攻击。 - 实现资源的限制和优化。
- **构建多租户系统:**通过namespace可以构建多租户系统,允许
多个⽤户或多个团队共享主机资源,但彼此之间的数据和权限是
隔离的,保证数据安全和系统稳定性。
3、资源隔离项 - **cgroup:**该 namespace 可单独管理⾃⼰的 cgroup,隐藏了进
程所属的控制组身份。 - ipc: 隔离 IPC,⽐如共享内存、信息量等。3. **network:**隔离⽹络资源,包括⽹络协议栈、⽹络设备、路由
表、防⽕墙、端⼝等。 - **mount:**隔离挂载信息,拥有独⽴的⽬录层次。
- **pid:**隔离进程号,使 namespace 中的进程 PID 单独编号。
- **time:**隔离启动时间点信息和单调时间。
- **user:**隔离⽤户管理权限机制(UID/GID),使 namespace 更
安全。 - **uts:**隔离主机信息,包括主机名、NIS domain name。
⼆、CGroup
1、概念
cgroup 是 Linux 内核提供的⼀种机制,该机制可以根据特定的⾏
为,将⼀系列任务及⼦任务整合或分隔到按资源划分等级的不同的
组内,为系统资源管理提供⼀个统⼀的框架。
cgroup可以限制被 namespace 隔离起来的资源,还可以为资源设置
权重、计算使⽤量、控制进程启停。
task 任务:cgroups 的属于中,task就表示系统的⼀个进程,在计
算机中的每⼀个进程都叫⼀个 task,task ⼀般使⽤PID进程表示。2、特点 - cgroups 的 API 以⼀个伪⽂件系统的⽅式实现,即⽤户可以通
过⽂件操作实现 cgroups 的组织管理。 - cgroups 的组织管理操作单元可以细粒度到线程级别,⽤户态代
码也可以针对系统分配的资源创建和销毁 cgroups,从⽽实现资
源再分配和管理。 - 所有资源管理的功能都以"subsystem (⼦系统)"的⽅式实现,接
⼝统⼀。 - ⼦进程创建之初与其⽗进程处于同⼀个 cgroups 的控制组。本
质上来说,cgroups 是内核附加在程序上的⼀系列钩⼦
(hooks),通过程序运⾏时对资源的调度触发相应的钩⼦以达到
资源追踪和限制的⽬的。
3、⽬的 - 为不同⽤户层⾯的资源管理,提供⼀个统⼀化的接⼝
- 单个进程的资源控制到操作系统层⾯的虚拟化
4、作⽤ - **资源限制(Resource Limitation):**cgroups 可以对进程组使⽤
的资源总额进⾏限制。如设定应⽤运⾏时使⽤内存的上限,⼀旦
超过这个配额就发出 OOM (Out of Memory) 。 - **优先级分配(Prioritization):**通过分配的 CPU 时间⽚数量及硬
盘 IO 带宽⼤⼩,实际上就相当于控制了进程运⾏的优先级。3. **资源统计 (Accounting):**cgroups 可以统计系统的资源使⽤
量,如 CPU 使⽤时⻓、内存⽤量等等,这个功能⾮常适⽤于计
费。 - **进程控制(Control):**cgroups 可以对进程组执⾏挂起、恢复等
操作。
三、Chroot
1、概念
chroot 是在 Linux 系统中的⼀种操作,它可以改变正在运作的软件
进程及其⼦进程的外显根⽬录。
2、作⽤ - 增加了系统的安全性,限制了⽤户的权⼒
-
- 在经过 chroot 之后,在新根下将访问不到旧系统的根⽬录
结构和⽂件,这样就增强了系统的安全性。⼀般会在⽤户登
录前应⽤ chroot,把⽤户的访问能⼒控制在⼀定的范围之
内。
- 在经过 chroot 之后,在新根下将访问不到旧系统的根⽬录
- 建⽴⼀个与原系统隔离的系统⽬录结构,⽅便⽤户的开发
-
- 使⽤ chroot 后,系统读取的是新根下的⽬录和⽂件,这是
⼀个与原系统根下⽂件不相关的⽬录结构。在这个新的环境
中,可以⽤来测试软件的静态编译以及⼀些与系统不相关的
独⽴开发。5. 切换系统的根⽬录位置,引导 Linux 系统启动以及急救系统等
- 使⽤ chroot 后,系统读取的是新根下的⽬录和⽂件,这是
-
- chroot 的作⽤就是切换系统的根位置,⽽这个作⽤最为明显
的是在系统初始引导磁盘的处理过程中使⽤,从初始 RAM
磁盘(initrd)切换系统的根位置并执⾏真正的 init。
四、虚拟化状态
1、完全解耦状态
完全解耦虚拟化状态就是为每个软件提供⼀个独⽴的运⾏环境。这
个环境在 hypervisor 层实现硬件的物理划分,并在每个划分的空间
内安装⼀个操作系统,然后在这个操作系统上运⾏想要的软件。2、半解耦状态
在同⼀个环境下可以同时运⾏两个相同的软件,分担软件服务器的
压⼒。这种状态下,所有东⻄都是以软连接的形式创建的,甚⾄包
括内核。⽽且不会改变内核的情况下放进去,为了兼容不同的操作
系统。
3、解耦和半解耦的区别
解耦是直接从硬件上⾯进⾏隔离的,在⼀个单独的系统中运⾏项
⽬。
半解耦运⾏在相对来说不是独⽴的容器⾥,相同的资源仪器使
⽤,以软链接的形式同步到容器中,需要不同的资源时,再单独
下载。
五、namespace:命名空间五、namespace:命名空间
1、查看 apache 的 namespace
[root@iZbp ~]# yum -y install httpd
[root@iZbp ~]# systemctl start httpd.service
[root@iZbp ~]# netstat -anpt |grep httpd
tcp6 0 0 :::80 :::*
LISTEN 2578447/httpd
[root@iZbp ~]# pidof httpd #⽤于查找httpd(指定服
务)的进程ID,包括主进程和其⼦进程
2578451 2578450 2578449 2578448 2578447
[root@iZbp ~]# cd /proc/2578447/ #进⼊到该服务进程⽬
录下
[root@iZbp 2578447]# ll ns #查看Apache服务的
namespace
total 0
lrwxrwxrwx 1 root root 0 Dec 5 20:35 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 20:31 mnt -> 'mnt:
[4026532268]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 net -> 'net:
[4026531992]'2、查看 pid=2 的 namespace
lrwxrwxrwx 1 root root 0 Dec 5 20:31 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:31 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 uts -> 'uts:
[4026531838]'3、查看容器是否与 nginx 进⾏隔离
[root@doc 43866]# ls -l /proc/2/ns
总⽤量 0
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 ipc ->
'ipc:[4026531839]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 mnt ->
'mnt:[4026531840]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 net ->
'net:[4026531992]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 pid ->
'pid:[4026531836]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 time ->
'time:[4026531834]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 user ->
'user:[4026531837]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 uts ->
'uts:[4026531838]'
[root@iZbp ~]# ps #此时的bash是当前系统的进程号 PID TTY TIME CMD
2646243 pts/0 00:00:00 bash
2665910 pts/0 00:00:00 ps
[root@iZbp ~]# docker run -itd --name test
centos:7 /bin/bash #运⾏docker容器
1af03b3055f728022d6a5acd51869e4982f3d13fd67625c614
12ea2021d59131
[root@iZbp ~]# ps #此时多出来的2666343是容器的进程
PID TTY TIME CMD
2646243 pts/0 00:00:00 bash
2666343 pts/0 00:00:00 bash
2666546 pts/0 00:00:00 ps
[root@iZbp ~]# docker inspect --format
'{{.State.Pid}}' test #使⽤--format参数直接提取容器
的pid, docker inspect是⽤来获取有关容器的详细信息,其中
{{.State.Pid}}表示获取容器的进程pid。
2666343
#查看test容器中的namespace信息,以及上⾯apache的进程的
namespace信息
[root@iZbp ~]# ll /proc/2666343/ns
total 0
lrwxrwxrwx 1 root root 0 Dec 5 21:03 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 21:03 ipc -> 'ipc:
[4026532208]'
lrwxrwxrwx 1 root root 0 Dec 5 20:58 mnt -> 'mnt:
[4026532206]'lrwxrwxrwx 1 root root 0 Dec 5 20:58 net -> 'net:
[4026532211]'
lrwxrwxrwx 1 root root 0 Dec 5 20:58 pid -> 'pid:
[4026532209]'
lrwxrwxrwx 1 root root 0 Dec 5 21:03
pid_for_children -> 'pid:[4026532209]'
lrwxrwxrwx 1 root root 0 Dec 5 21:03 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 21:03
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:58 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 21:03 uts -> 'uts:
[4026532207]'
[root@iZbp ~]# ll /proc/2578447/ns/
total 0
lrwxrwxrwx 1 root root 0 Dec 5 20:35 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 20:31 mnt -> 'mnt:
[4026532268]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 5 20:31 pid -> 'pid:
[4026531836]'4、对⽐得出结论
这⾥的数字就是"命名空间的名字",数字相同,则表示在同⼀个空间
内,不相同则表示不在同⼀个空间内。若在同⼀个空间内,表示会
发⽣"耦合"或"冲突",⽐如实验中 43866 和 2 的进程中 net 相同,
则他们不能使⽤相同的端⼝、IP等⽹络栈。但实验中 43866 和 2 的
进程中 mnt 的编号不相同,则不会发⽣冲突。
5、proc ⽬录
proc 是 Linux 系统下⼀个很重要的⽬录。 它跟 /etc,/home 等这些
系统⽬录不同,它不是⼀个真正的⽂件系统, ⽽是⼀个虚拟的⽂件
系统。 它不存在于磁盘, ⽽是存在于系统内存中。
lrwxrwxrwx 1 root root 0 Dec 5 20:35
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:31 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 uts -> 'uts:
[4026531838]'
#cgroup先不要考虑,观察其他的数值是否在同⼀个空间
#只有namespace的user和time没有被隔离。docker默认没有对
user和time的单独namespace/proc/cpuinifo
CPU的信息 (型号、家族、缓存⼤⼩等),对应命
令 top
/proc/meminfo
物理内存、交换空间,对应命令 free
/proc/mounts
已加载的⽂件系统的列表
/proc/devices
可⽤设备的列表
/proc/filesystems
被⽀持的⽂件系统
/proc/modules
已加载的模块
/proc/version
内核版本
/proc/cmdline
系统启动时输⼊的内核命令⾏参数
/proc/XXX
XXX是指以进程PID(数字编号)命名的⽬
录,每⼀个⽬录表示⼀个进程(即线程组)
/proc/swaps
要获知swap空间的使⽤情况
/proc/uptime
获取系统的正常运⾏时间
/proc/fs/nfsd/exports 列出由NFS共享的⽂件系统/proc/kmsg
该⽂件被作为内核⽇志信息源,它可以被
作为⼀个系统信息调⽤的接⼝使⽤
/proc/self
到当前进程/proc⽬录的符号链接,通过这
个⽬录可以获取当前运⾏进程的信息
/proc/pci
挂接在PCI总线上的设备
/proc/tty/driver/serial
串⼝配置、统计信息
/proc/version
系统版本信息,对应系统命令 uname -a
或 lsb_release
/proc/sys/kernel/ostype
/proc/sys/kernel/osrelease
/proc/sys/kernel/version
/proc/sys/kernel/hostname
主机名
/proc/sys/kernel/domainname
域名
/proc/partitions
硬盘设备分区信息
/proc/sys/dev/cdrom/info
CDROM信息/proc/locks
当前系统中所有的⽂件锁
/proc/loadavg
系统负荷信息,对应系统命令 top
/proc/uptime
系统启动后的运⾏时间,对应命
令 uptime
/proc/N[N 对应 pid 号 ]
获取进程运⾏状态,系统命令
ps aux 或 top
- chroot 的作⽤就是切换系统的根位置,⽽这个作⽤最为明显
- /proc/N pid为N的进程信息
- /proc/N/cmdline 进程启动命令
- /proc/N/cwd 链接到进程当前⼯作⽬录
- /proc/N/environ 进程环境变量列表
- /proc/N/exe 链接到进程的执⾏命令⽂件
- /proc/N/fd 包含进程相关的所有的⽂件描述符
- /proc/N/maps 与进程相关的内存映射信息
- /proc/N/mem 指代进程持有的内存,不可读
- /proc/N/root 链接到进程的根⽬录
- /proc/N/stat 进程的状态
- /proc/N/statm 进程使⽤的内存的状态
- /proc/N/status 进程状态信息,⽐stat/statm更具可读性
- /proc/self 链接到当前正在运⾏的进程14. /proc/N/ns 程序的namespace空间
六、namespace 隔离项
1、准备⼯作
[root@iZbp ~]# yum -y install gcc gcc-c++ #安装c
语⾔环境
[root@iZbp ~]# vim test.c #编写脚本⽂件
#define GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#define STACK_SIZE (1024 * 1024)
static char child_stack[STACK_SIZE];
char* const child_args[] = {
"/bin/bash",
NULL
};
int child_main(void* args) {
printf("在⼦进程中!\n");
execv(child_args[0], child_args);
return 1;}
int main() {
printf("程序开始: \n");
int child_pid = clone(child_main, child_stack +
STACK_SIZE, SIGCHLD, NULL);
waitpid(child_pid, NULL, 0);
printf("已退出\n");
return 0;
}
[root@iZbp ~]# gcc -Wall test.c -o test.o #编译名
为test.c的c源⽂件
[root@iZbp ~]# ls #查看⽣产源⽂件
test.c test.o
[root@iZbp ~]# ./test.o #执⾏c源⽂件
程序开始:
在⼦进程中!
[root@iZbp ~]# ps af #已完整的格式显示进程信息,显示
所有⽤户的进程,包括其他⽤户的进程
PID TTY STAT TIME COMMAND
2666343 pts/0 Ss+ 0:00 /bin/bash
2646243 pts/0 Ss 0:00 -bash
2726964 pts/0 S 0:00 \ ./test.o #在
test.o程序下开启了bash
2726965 pts/0 S 0:00 \_ /bin/bash
2727511 pts/0 R+ 0:00 \_ ps af
1360 tty1 Ss+ 0:00 /sbin/agetty -o -p --
\u --noclear tty1 linux1359 ttyS0 Ss+ 0:00 /sbin/agetty -o -p --
\u --keep-baud 115200,38400,9600 ttyS0 vt220
#得到test.o程序的进程为2726965,查看还进程和2号进程之间的
namespace
[root@iZbp ~]# ll /proc/2726965/ns/
total 0
lrwxrwxrwx 1 root root 0 Dec 5 21:24 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 21:24 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 21:17 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 5 21:24 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 5 21:17 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 21:24
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 21:24 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 21:24
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 21:17 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 21:24 uts -> 'uts:
[4026531838]'
[root@iZbp ~]# ll /proc/2/ns/2、UTS 的隔离 - UTSnamespace提供了主机名和域名的隔离,这样每个容器就
可以拥有了独⽴的主机名和域名
total 0
lrwxrwxrwx 1 root root 0 Dec 5 20:35 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 uts -> 'uts:
[4026531838]'
#根据结果显示所有数据值⼀致,全部没有被隔离2. 在⽹络上可以被视作⼀个独⽴的节点⽽⾮宿主机上的⼀个进程
[root@iZbp ~]# vim test.c #添加uts隔离设置
static char child_stack[STACK_SIZE];
char* const child_args[] = {
"/bin/bash",
NULL
};
int child_main(void* args) {
printf("在⼦进程中!\n");
sethostname("C测试",8); #添加,设置主机名和需要多少
字符
execv(child_args[0], child_args);
return 1;
}
int main() {
printf("程序开始: \n");
int child_pid = clone(child_main, child_stack +
STACK_SIZE,CLONE_NEWUTS | SIGCHLD, NULL);
#添加 CLONE_NEWUTS |
waitpid(child_pid, NULL, 0);
printf("已退出\n");
return 0;
}
[root@iZbp ~]# gcc -Wall test.c -o uts.o #将修改
的脚本⽣成程序[root@iZbp ~]# ls
test.c test.o uts.o
[root@iZbp ~]# ./uts.o #进⼊程序
程序开始:
在⼦进程中!
[root@C测试 ~]# ps af #程序的⽤户名发⽣改变
PID TTY STAT TIME COMMAND
2666343 pts/0 Ss+ 0:00 /bin/bash
2646243 pts/0 Ss 0:00 -bash
2815042 pts/0 S 0:00 \_ ./uts.o
2815043 pts/0 S 0:00 \_ /bin/bash
#⽣产⼀个新的bash
2815288 pts/0 R+ 0:00 \_ ps af
1360 tty1 Ss+ 0:00 /sbin/agetty -o -p --
\u --noclear tty1 linux
1359 ttyS0 Ss+ 0:00 /sbin/agetty -o -p --
\u --keep-baud 115200,38400,9600 ttyS0 vt220
[root@C测试 ~]#
[root@C测试 ~]# ll /proc/2815043/ns/ #查看该程序的
bash下的namespace
total 0
lrwxrwxrwx 1 root root 0 Dec 5 21:46 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 21:46 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 21:44 mnt -> 'mnt:
[4026531840]'lrwxrwxrwx 1 root root 0 Dec 5 21:46 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 5 21:44 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 21:46
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 21:46 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 21:46
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 21:44 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 21:46 uts -> 'uts:
[4026532269]'
[root@C测试 ~]# ll /proc/2/ns/ #查看2号进程的
namespace
total 0
lrwxrwxrwx 1 root root 0 Dec 5 20:35 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 pid -> 'pid:
[4026531836]'3、IPC 隔离 - 在容器中进程间通信采⽤的⽅法包括常⻅的信号量、消息队列和
共享内存 - 编辑测试
lrwxrwxrwx 1 root root 0 Dec 5 20:35
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 uts -> 'uts:
[4026531838]'
#对⽐之后UTS隔离了,其他选项没有隔离
#在docker中,每个镜像基本都以⾃⼰所提供的服务命名了⾃⼰的
hostname⽽没有对宿主机产⽣任何影响
[root@C测试 ~]# exit
exit
已退出
[root@iZbp ~]# vim test.c
int main() {
printf("程序开始: \n"); int child_pid = clone(child_main, child_stack +
STACK_SIZE,CLONE_NEWUTS | CLONE_NEWIPC | SIGCHLD,
NULL); #添加CLONE_NEWIPC
[root@iZbp ~]# gcc -Wall test.c -o ipc.o #将修改
后的脚本⽣成程序
[root@iZbp ~]# ls #查看⽣成后的程序
ipc.o test.c test.o uts.o
[root@iZbp ~]# ipcs #⽤来查看进程通信设施的状态
------ Message Queues -------- #显示消息列表
key msqid owner perms used
bytes messages
------ Shared Memory Segments -------- #共享内存
key shmid owner perms bytes
nattch status
------ Semaphore Arrays -------- #信号量
key semid owner perms nsems
0x00000000 10 apache 600 1
0x00000000 11 apache 600 1
0x00000000 12 apache 600 10x00000000 13 apache 600 1
0x00000000 14 apache 600 1
0x00000000 15 apache 600 1
[root@iZbp ~]# ipcmk -Q #创建消息队列
Message queue id: 0
[root@iZbp ~]# ipcmk -Q
Message queue id: 1
[root@iZbp ~]# ipcmk -Q
Message queue id: 2
[root@iZbp ~]# ipcs #查看添加消息队列后的进程通信设施
的状态
------ Message Queues --------
key msqid owner perms used
bytes messages
0x1cc53b4b 0 root 644 0
0
0xfeae48cf 1 root 644 0
0
0xc29931e5 2 root 644 0
0
------ Shared Memory Segments --------
key shmid owner perms bytes
nattch status ------ Semaphore Arrays --------
key semid owner perms nsems
0x00000000 10 apache 600 1
0x00000000 11 apache 600 1
0x00000000 12 apache 600 1
0x00000000 13 apache 600 1
0x00000000 14 apache 600 1
0x00000000 15 apache 600 1
[root@iZbp ~]# ./ipc.o #运⾏ipc.o程序
程序开始:
在⼦进程中!
[root@C测试 ~]# ipcs #在该程序内查看进程通信设施的状态
------ Message Queues -------- #ipc.o的程序内没有消
息队列
key msqid owner perms used
bytes messages
------ Shared Memory Segments --------key shmid owner perms bytes
nattch status
------ Semaphore Arrays --------
key semid owner perms nsems
[root@C测试 ~]# ps af #以完整的格式显示所有⽤户的进
程信息
PID TTY STAT TIME COMMAND
2666343 pts/0 Ss+ 0:00 /bin/bash
732492 pts/0 Ss 0:00 -bash
767041 pts/0 S 0:00 \_ ./ipc.o
767042 pts/0 S 0:00 \_ /bin/bash
#ipc.o程序执⾏bash
768002 pts/0 R+ 0:00 \_ ps af
1360 tty1 Ss+ 0:00 /sbin/agetty -o -p --
\u --noclear tty1 linux
1359 ttyS0 Ss+ 0:00 /sbin/agetty -o -p --
\u --keep-baud 115200,38400,9600 ttyS0 v
[root@C测试 ~]# ll /proc/767042/ns/ # 查看ipc.o程
序下bash的namespace
total 0
lrwxrwxrwx 1 root root 0 Dec 6 08:46 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 6 08:46 ipc -> 'ipc:
[4026532270]'lrwxrwxrwx 1 root root 0 Dec 6 08:45 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 6 08:46 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 6 08:45 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 6 08:46
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 6 08:46 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 6 08:46
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 6 08:45 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 6 08:46 uts -> 'uts:
[4026532269]'
[root@C测试 ~]# ll /proc/2/ns/ #查看2号进程的
namespace,对⽐
total 0
lrwxrwxrwx 1 root root 0 Dec 5 20:35 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 net -> 'net:
[4026531992]'4、PID 隔离 - docker容器内不能运⾏包管理器的程序
lrwxrwxrwx 1 root root 0 Dec 5 20:35 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 uts -> 'uts:
[4026531838]'
#对⽐后发现ipc的namespace已经不同了,此时的ipc和uts已经实
现隔离
#docker本身是通过socket或tcp进程通信
[root@iZbp ~]# ipcrm -q 0 #删除消息队列
[root@iZbp ~]# ipcrm -q 1
[root@iZbp ~]# ipcrm -q 2[root@iZbp ~]# docker ps -a #查看所有docker容器
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
1af03b3055f7 centos:7 "/bin/bash" 12 hours
ago Up 12 hours test
[root@iZbp ~]# docker exec -it test bash #进⼊到
名为test容器内
[root@1af03b3055f7 /]# yum -y install httpd #在容
器内安装httpd
[root@1af03b3055f7 /]# systemctl start httpd #
在容器内使⽤systemctl启动httpd
Failed to get D-Bus connection: Operation not
permitted #启动失败 - 失败原因
-
- 由于PID的隔离,在不同的命名空间可以有相同的PID
- PID的命令空间允许每个容器都有⾃⼰的init(PID 1),这
是所有进程的祖先。⽤于管理各种程序初始化任务,并在他
们终⽌时获得孤⽴的⼦进程 - 进程有两个PID:命名空间内的PID和主机系统上的命名空
间外部的PID - 测试未隔离时的效果
[root@iZbp ~]# ps af #查看主机系统上的进程信息
PID TTY STAT TIME COMMAND732492 pts/0 Ss 0:00 -bash
828143 pts/0 R+ 0:00 \_ ps af
1360 tty1 Ss+ 0:00 /sbin/agetty -o -p --
\u --noclear tty1 linux
1359 ttyS0 Ss+ 0:00 /sbin/agetty -o -p --
\u --keep-baud 115200,38400,9600 ttyS0 v
[root@iZbp ~]# ./ipc.o #执⾏ipc.o程序查看PID未隔
离时的效果
程序开始:
在⼦进程中!
[root@C测试 ~]# echo $$ #查看ipc.o程序bash的进程号
828649
[root@C测试 ~]# exit #离开ipc.o程序
exit
已退出
#可以看到未隔离时的PID号时延续主机上⾯的PID,在⼀个独⽴空间
内,第⼀个进程号不是1号进程,⽽是延续主机的进程 - 测试PID隔离后的效果
[root@iZbp ~]# vim test.c
int main() {
printf("程序开始: \n");
int child_pid = clone(child_main, child_stack +
STACK_SIZE,CLONE_NEWUTS | CLONE_NEWIPC
|CLONE_NEWPID| SIGCHLD, NULL); #添加CLONE_NEWPID
waitpid(child_pid, NULL, 0); printf("已退出\n");
return 0;
}
[root@iZbp ~]# gcc -Wall test.c -o pid.o #将脚本
⽣成程序
[root@iZbp ~]# ls #查看⽣成的pid.o程序
ipc.o pid.o test.c test.o uts.o
[root@iZbp ~]# ./pid.o #执⾏pid.o程序
程序开始:
在⼦进程中!
[root@C测试 ~]# echo $$ #在该程序内查看执⾏bash的进
程号
1 #此时的进程号是1,说明已经是这个空间内的第⼀个进程了
[root@C测试 ~]# ps af #查看完整的所有⽤户的进程信息
PID TTY STAT TIME COMMAND
732492 pts/0 Ss 0:00 -bash
847191 pts/0 S 0:00 \_ ./pid.o
847192 pts/0 S 0:00 \_ /bin/bash
#主机上的进程。有两个进程
848008 pts/0 R+ 0:00 \_ ps af
1360 tty1 Ss+ 0:00 /sbin/agetty -o -p --
\u --noclear tty1 linux
1359 ttyS0 Ss+ 0:00 /sbin/agetty -o -p --
\u --keep-baud 115200,38400,9600 ttyS0 v
[root@C测试 ~]# ll /proc/847192/ns/ #查看主机上
pid.o下bash的进程namespace
total 0lrwxrwxrwx 1 root root 0 Dec 6 09:11 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 ipc -> 'ipc:
[4026532205]'
lrwxrwxrwx 1 root root 0 Dec 6 09:10 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 6 09:10 pid -> 'pid:
[4026532206]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11
pid_for_children -> 'pid:[4026532206]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 6 09:10 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 uts -> 'uts:
[4026532204]'
[root@C测试 ~]# ll /proc/2/ns/ #查看2号进程的
namespace
total 0
lrwxrwxrwx 1 root root 0 Dec 6 09:11 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 ipc -> 'ipc:
[4026531839]'lrwxrwxrwx 1 root root 0 Dec 6 09:11 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 uts -> 'uts:
[4026531838]'
#对⽐之后,可以看到此时的pid数据值已经不⼀样了
[root@C测试 ~]# pstree
systemd"#"AliYunDun"""10*[{AliYunDun}]
"AliYunDunMonito"""25\*\[{AliYunDunMonito}\] "smartd
$"sshd"""sshd"""sshd"""bash"""pid.o"""bash"""pstre
e #可以看到进程之间的关系
[root@C测试 ~]# ps aux #主机上的1号进程是systemd
USER PID %CPU %MEM VSZ RSS TTY
STAT START TIME COMMANDroot 1 0.0 0.6 184304 12060 ?
Ss Nov30 0:09 /usr/lib/systemd/systemd
root 2 0.0 0.0 0 0 ? S
Nov30 0:00 [kthreadd]
#此时可以看出⽬前查到的都是主机系统上的进程信息,⽽不是新空
间内的。是因为此时的proc⽬录没有改变
[root@C测试 ~]# ls /proc/ #proc⽬录下的进程还是主机
上的进程
1 157 28 434 721 845170
interrupts partitions
10 158 29 435 732015 845172
iomem sched_debug
1004 16 290 437 732482 847191
ioports schedstat
11 160 291 437402 732485 847192
irq scsi
1131 161 292 438 732491 850882
kallsyms self
12 162 295 444 732492 9
kcore slabinfo
1211 17 3 464 743 acpi
keys softirqs
1224 1719 30 466 747 buddyinfo
key-users stat
13 18 300 467 750 bus
kmsg swaps1305 1878 302 468 751 cgroups
kpagecgroup sys
1327 2 31 469 752 cmdline
kpagecount sysrq-trigger
1341 20 32 470 753 consoles
kpageflags sysvipc
1344 22 33 471 759 cpuinfo
loadavg thread-self
1347 23 34 472 779100 crypto
locks timer_list
1349 24 35 473 791 devices
mdstat tty
1359 2578447 36 579 794 diskstats
meminfo uptime
1360 2578448 37 6 796 dma
misc version
14 2578449 38 614 799312 driver
modules vmallocinfo
1435 2578450 4 62 825610 execdomains
mounts vmstat
15 2578451 40 681 825617 fb
mtrr zoneinfo
155 26 41 693437 827638 filesystems
net
156 27 428472 719 844328 fs
pagetypeinfo5、MOUNT 隔离 - MOUNT命名空间是linux系统上实现的第⼀种类型的命名空间。
所以它的标识⽐较特殊是CLONE_NEWNS - 隔离后,不同mountnamespace中的⽂件结构发⽣变化也互不
影响 - mount传播挂载命令。默认所有挂载都是私有的
-
- 设置共享挂载:mount --make-shared 。共享挂载克隆的
挂载对象也是共享挂载;他们相互传播挂载事件
- 设置共享挂载:mount --make-shared 。共享挂载克隆的
- 从属挂载:mount --make-slave 。从属挂载克隆的挂载对
象也是从属的挂载 - 将⼀个从属挂载对象设置为共享、从属挂载,可以执⾏
mount --make-shared -
- 如果想把修改过的挂载对象重新标记为私有
mount --make-private
- 如果想把修改过的挂载对象重新标记为私有
-
- 挂载对象标记为不可绑定
mount --make-unbindable
#proc⽬录没有改变是因为没有对⽂件系统进程隔离,需要对mount
隔离1. 测试mount挂载
[root@C测试 ~]# vim test.c #添加mount隔离
int main() {
printf("程序开始: \n");
int child_pid = clone(child_main, child_stack +
STACK_SIZE,CLONE_NEWUTS | CLONE_NEWIPC
|CLONE_NEWPID| CLONE_NEWNS| SIGCHLD, NULL); #添加
CLONE_NEWNS
waitpid(child_pid, NULL, 0);
printf("已退出\n");
return 0;
}
[root@C测试 ~]# gcc -Wall test.c -o mnt.o #将脚本
⽣成程序
[root@C测试 ~]# ls #查看⽣成后的程序⽂件
ipc.o mnt.o pid.o test.c test.o uts.o
[root@C测试 ~]# ./mnt.o #运⾏mnt程序
程序开始:
在⼦进程中!
#此时并没有实现完全隔离,需要⼿动执⾏mount命令
[root@C测试 ~]# mount --make-private -t proc proc
/proc/ #对容器内的proc⽬录设置为私有挂载
[root@C测试 ~]# ls /proc/ #此时查看proc⽬录,发现已
经只有容器内的进程信息了1 crypto interrupts kpagecgroup
mounts slabinfo tty
46 devices iomem kpagecount
mtrr softirqs uptime
acpi diskstats ioports kpageflags
net stat version
buddyinfo dma irq loadavg
pagetypeinfo swaps vmallocinfo
bus driver kallsyms locks
partitions sys vmstat
cgroups execdomains kcore mdstat
sched_debug sysrq-trigger zoneinfo
cmdline fb keys meminfo
schedstat sysvipc
consoles filesystems key-users misc
scsi thread-self
cpuinfo fs kmsg modules
self timer_list
[root@C测试 ~]# ps aux #查看容器所有进程信息,只有容
器内的进程
USER PID %CPU %MEM VSZ RSS TTY
STAT START TIME COMMAND
root 1 0.0 0.3 27824 5856 pts/0 S
10:19 0:00 /bin/bash
root 47 0.0 0.2 58732 3924 pts/0
R+ 10:22 0:00 ps aux
[root@C测试 ~]# exitexit
已退出
#这个挂载修改后还会影响宿主机上⾯的挂载,宿主机也需要重新挂
载才可以还原
[root@iZbp ~]# mount --make-private -t proc proc
/proc/ #在宿主机上⾯执⾏proc的挂载
[root@iZbp ~]# ls /proc/ #查看proc⽬录
1 13 18 300 467 794
iomem sched_debug
10 1305 1878 302 468 796
ioports schedstat
1002231 1327 2 31 469 9
irq scsi
1004 1341 20 32 470 941511
kallsyms self
1033693 1344 22 33 471 991980
kcore slabinfo
1052123 1347 23 34 472 acpi
keys softirqs
1054700 1349 24 35 473 buddyinfo
key-users stat
1065188 1359 2578447 36 579 bus
kmsg swaps
1065189 1360 2578448 37 6 cgroups
kpagecgroup sys
1071096 14 2578449 38 614 cmdline
kpagecount sysrq-trigger1076512 1435 2578450 4 62 consoles
kpageflags sysvipc
1077826 15 2578451 40 681 cpuinfo
loadavg thread-self
1077830 155 26 41 719 crypto
locks timer_list
1077895 156 27 428472 721 devices
mdstat tty
1078161 157 28 434 743 diskstats
meminfo uptime
1078162 158 29 435 747 dma
misc version
1080287 16 290 437 750 driver
modules vmallocinfo
11 160 291 437402 751 execdomains
mounts vmstat
1131 161 292 438 752 fb
mtrr zoneinfo
12 162 295 444 753 filesystems
net
1211 17 3 464 759 fs
pagetypeinfo
1224 1719 30 466 791 interrupts
partitions
#此时宿主机上⾯的proc⽬录恢复正常[root@iZbp ~]# cat /boot/config-4.18.0-
305.3.1.el8.x86_64 | grep -i ns #查看那些是需要内核实
现的
CONFIG_INSTRUCTION_DECODER=y
CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
CONFIG_UTS_NS=y
CONFIG_TIME_NS=y
CONFIG_IPC_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y。。。。。
#这些namespace是没有被mount的
- 挂载对象标记为不可绑定
- systemd是使⽤内核,所以依旧⽆法⽤systemd进程启动程序。
- 解决⽅案⼀:/sbin/init是systemd的软连接。可以使⽤/sbin/init
进⼊容器。此⽅法在最新版本中已经不建议使⽤
[root@iZbp ~]# docker run -d --name test --
privileged rockylinux /sbin/init #增加--
privileged参数才能有权限执⾏systemd
795851a713f9ded5b250dfd0861c4dc97490409a5a745c4b28
587267e573ca1c
[root@iZbp ~]# docker exec -it test bash #进⼊容器
[root@795851a713f9 /]# yum -y install httpd #安装
httpd[root@795851a713f9 /]# systemctl start httpd #使
⽤systemd启动httpd程序
[root@iZbp ~]# which ps #在宿主机上⾯查看ps命令的安装
包
/usr/bin/ps
[root@iZbp ~]# rpm -qf /usr/bin/ps
procps-ng-3.3.15-6.el8.x86_64
[root@795851a713f9 /]# yum -y install procps-ng
#安装ps命令
USER PID %CPU %MEM VSZ RSS TTY
STAT START TIME COMMAND
root 1 0.1 0.5 89900 10200 ?
Ss 02:39 0:00 /sbin/init
root 18 0.0 0.4 87356 8120 ?
Ss 02:39 0:00 /usr/lib/systemd/systemd
dbus 26 0.0 0.2 54056 4172 ?
Ss 02:39 0:00 /usr/bin/dbus-daemon --s
root 45 0.0 0.2 19352 3712 pts/0
Ss 02:39 0:00 bash
root 135 0.0 0.6 258080 10852 ?
Ss 02:39 0:00 /usr/sbin/httpd -DFOREGR
apache 136 0.0 0.4 260664 7956 ? S
02:39 0:00 /usr/sbin/httpd -DFOREGR
apache 137 0.0 0.5 1908356 9588 ?
Sl 02:39 0:00 /usr/sbin/httpd -DFOREGR
apache 138 0.0 0.5 1777220 9700 ?
Sl 02:39 0:00 /usr/sbin/httpd -DFOREGRapache 139 0.0 0.5 1777220 9700 ?
Sl 02:39 0:00 /usr/sbin/httpd -DFOREGR
root 358 0.0 0.2 51864 3808 pts/0
R+ 02:40 0:00 ps aux - 解决⽅案⼆:直接使⽤execstart启动
[root@iZbp ~]# docker run -itd --name ssh
rockylinux bash #创建⼀个容器,⽤来演示sshd服务在容器
内如何启动
0cac21a08a57ee6de38e16e744d07d8d5a72d6eda40a9259fc
1b3997c5ecff7f
[root@iZbp ~]# docker exec -it ssh bash #进⼊
[root@0cac21a08a57 /]# yum -y install httpd #安装
httpd服务
[root@0cac21a08a57 /]# cat
/usr/lib/systemd/system/httpd.service #找到启动⽂
件
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND #
找到启动程序命令的路径
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
[root@0cac21a08a57 /]# /usr/sbin/httpd $OPTIONS -
DFOREGROUND & #使⽤命令启动程序,并放在后台运⾏
[1] 549[root@0cac21a08a57 /]# AH00558: httpd: Could not
reliably determine the server's fully qualified
domain name, using 172.17.0.2. Set the
'ServerName' directive globally to suppress this
message
[root@0cac21a08a57 /]# ps aux #查看进程已经开始运⾏
USER PID %CPU %MEM VSZ RSS TTY
STAT START TIME COMMAND
root 1 0.0 0.2 19240 3740 pts/0
Ss+ 02:47 0:00 bash
root 13 0.0 0.2 19352 3736 pts/1
Ss 02:48 0:00 bash
root 549 0.3 0.6 258080 10744 pts/1 S
02:55 0:00 /usr/sbin/httpd -DFOREGR
apache 550 0.0 0.4 260664 8044 pts/1 S
02:55 0:00 /usr/sbin/httpd -DFOREGR
apache 551 0.0 0.6 1908344 11696 pts/1
Sl 02:55 0:00 /usr/sbin/httpd -DFOREGR
apache 552 0.0 0.5 1777208 9648 pts/1
Sl 02:55 0:00 /usr/sbin/httpd -DFOREGR
apache 553 0.0 0.5 1777208 9648 pts/1
Sl 02:55 0:00 /usr/sbin/httpd -DFOREGR
root 765 0.0 0.2 51864 3780 pts/1
R+ 02:55 0:00 ps aux
#在宿主机上查看docker的IP地址
[root@iZbp /]# docker inspect ssh |grep 172 #过
滤dockerip的详细信息"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
#docker的IP地址
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
[root@iZbp /]# curl 172.17.0.2
<!doctype html>
<html>
#访问成功后显示httpd的图形测试⻚⾯
#启动容器内sshd服务
[root@iZbp ~]# docker exec -it ssh bash
[root@0cac21a08a57 /]# yum -y install passwd
iproute openssh-server #安装sshd需要的⼀些必要命令
#passwd:ssh连接需要密码,所以需要passwd设置root的密码
#openssh-server:ssh服务
[root@0cac21a08a57 /]# passwd root #设置root密码
Changing password for user root.
New password:
BAD PASSWORD: The password is shorter than 8
characters
Retype new password:
passwd: all authentication tokens updated
successfully.
[root@0cac21a08a57 /]# /usr/sbin/sshd -D OPTIONS CRYPTO_POLICY #启动sshd服务提示缺少三个秘钥⽂件
Unable to load host key: /etc/ssh/ssh_host_rsa_keyUnable to load host key:
/etc/ssh/ssh_host_ecdsa_key
Unable to load host key:
/etc/ssh/ssh_host_ed25519_key
sshd: no hostkeys available -- exiting.
[root@0cac21a08a57 /]# ssh-keygen -f
/etc/ssh/ssh_host_rsa_key #创建秘钥⽂件,回⻋使⽤默认
配置
[root@0cac21a08a57 /]# ssh-keygen -f
/etc/ssh/ssh_host_ecdsa_key
[root@0cac21a08a57 /]# ssh-keygen -f
/etc/ssh/ssh_host_ed25519_key
[root@0cac21a08a57 /]# vi /etc/ssh/sshd_config
PermitRootLogin yes #允许root⽤户登录
#UsePAM yes # #注释PAM认证,
[root@0cac21a08a57 /]# /usr/sbin/sshd -D & #启动
sshd服务
[1] 851
[root@0cac21a08a57 /]# ip a #查看ip地址
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc
noqueue state UNKNOWN group default qlen 1000
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
29: eth0@if30: <BROADCAST,MULTICAST,UP,LOWER_UP>
mtu 1500 qdisc noqueue state UP group default6、NETWORK 隔离 - 提供与⽹络相关的系统资源的隔离
- 每个⽹络命名空间都有⾃⼰的⽹络设备、IP 地址、ip 路由表、
端⼝、/rpto⽬录等 - 宿主机和容器的⽹络连接到⼀起并不发⽣冲突就是 net 隔离。
link/ether 02:42:ac:11:00:02 brd
ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope
global eth0
valid_lft forever preferred_lft forever
#在宿主上远程连接容器测试
[root@iZbp /]# ssh root@172.17.0.2 #远程登录成功
The authenticity of host '172.17.0.2 (172.17.0.2)'
can't be established.
RSA key fingerprint is
SHA256:FE6korMibbb8b1GzhYyn0YfbuxL2dw1XYjjfINfILAU
.
Are you sure you want to continue connecting
(yes/no/[fingerprint])? yes
Warning: Permanently added '172.17.0.2' (RSA) to
the list of known hosts.
root@172.17.0.2's password:
[root@0cac21a08a57 ~]#7、USER 隔离 - 隔离⽤户和组的ID号
- 进程的⽤于ID 和组ID在⽤户命名空间内外可能不同
- 进程对⽤户 命名空间内的操作具有完全的root权限,但对于空
间外的操作,该进程没有特权
七、cgroup:资源控制
1、限制容器对 CPU 的使⽤ - 所有容器可以平等地使⽤host CPU资源并且没有限制。
- docker可以通过-c或--cpu-shares设置容器使⽤CPU的权重。默
认1024。 - 为了实验的效果,将cpu改为1核1G。
#下载⼀个测试镜像progrium/stress(⽤于对系统资源(如 CPU
和内存)进⾏压⼒测试的⼯具)
[root@localhost ~]# docker pull progrium/stress
#下载⼀个测试镜像progrium/stress
Using default tag: latest
latest: Pulling from progrium/stress[DEPRECATION NOTICE] Docker Image Format v1, and
Docker Image manifest version 2, schema 1 support
will be removed in an upcoming release. Suggest
the author of docker.io/progrium/stress:latest to
upgrade the image to the OCI Format, or Docker
Image manifest v2, schema 2. More information at
https://docs.docker.com/go/deprecated-image-specs/
a3ed95caeb02: Pull complete
871c32dbbb53: Pull complete
dbe7819a64dd: Pull complete
d14088925c6e: Pull complete
58026d51efe4: Pull complete
7d04a4fe1405: Pull complete
1775fca35fb6: Pull complete
5c319e267908: Pull complete
Digest:
sha256:e34d56d60f5caae79333cee395aae93b74791d50e38
41986420d23c2ee4697bf
Status: Downloaded newer image for
progrium/stress:latest
docker.io/progrium/stress:latest
[root@localhost ~]# docker images #查看docker的全
部镜像
REPOSITORY TAG IMAGE ID CREATED
SIZE
nginx latest 605c77e624dd 23
months ago 141MBprogrium/stress latest db646a8f4087 9 years
ago 282MB - 启动aa容器cpu优先级别设置1024
[root@localhost ~]# docker run -itd --name aa --
cpu-shares 1024 progrium/stress --cpu 1
fb5b092c6bdaa8c41cdf3a5c4ae9da99a465440814e372b1ef
85d9de1db2758a - 启动bb容器cpu优先级别设置为512
[root@localhost ~]# docker run -itd --name bb --
cpu-shares 512 progrium/stress --cpu 1
2c5ea28903e5eafb2a6a1389fedc4704d3e75bfb63c2160fd5
11fd43d617c5ed - 查看确定后4227就是aa容器、4293就是bb容器(此结果为1核
1G)
#此结果使⽤2核2G的状态[root@haha cpu]# docker run -itd --name bb --cpu
shares 2048 progrium/stress --cpu 2
d97c8fe3b39ca69e0dc4b33081b8a837e365824ccab5574a5d
9ae10f83727bf8
[root@haha cpu]# docker run -itd --name aa --cpu
shares 1024 progrium/stress --cpu 2
ac6a659eadaca579f5349d6913c7384c80e091a49781e6a296
c54440fe1b4870
[root@haha cpu]# top
top - 17:25:37 up 2:50, 1 user, load average:
5.08, 2.55, 1.31
Tasks: 126 total, 5 running, 121 sleeping, 0
stopped, 0 zombie
%Cpu(s): 97.5 us, 1.8 sy, 0.0 ni, 0.0 id, 0.0
wa, 0.5 hi, 0.2 si, 0.0 st
MiB Mem : 1718.4 total, 181.8 free, 357.1
used, 1179.5 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0
used. 1195.5 avail Mem
PID USER PR NI VIRT RES SHR S
%CPU %MEM TIME+ COMMAND
542947 root 20 0 7320 96 0 R
69.0 0.0 0:04.22 stress
542948 root 20 0 7320 96 0 R
64.3 0.0 0:03.11 stress 542362 root 20 0 7320 96 0 R
28.7 0.0 0:11.87 stress
542363 root 20 0 7320 96 0 R
28.7 0.0 0:12.02 stress - 由于cgroup是伪⽂件系统的⽅式,可以直接修改⽂件
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND
CREATED STATUS
PORTS NAMES
2c5ea28903e5 progrium/stress "/usr/bin/stress
--v..." 4 minutes ago Up 4 minutes
bb
fb5b092c6bda progrium/stress "/usr/bin/stress
--v..." 4 minutes ago Up 4 minutes
aa
a44e1dce79c3 progrium/stress "/usr/bin/stress
--v..." 12 minutes ago Exited (1) 6 minutes ago
nice_golick
24c4a7961c24 progrium/stress "/usr/bin/stress
--v..." 15 minutes ago Exited (1) 12 minutes ago
sad_goldberg
[root@localhost ~]# cd
/sys/fs/cgroup/cpu/docker/cd10d4993cd21103c7b62638
7a1ede7907c313f164fa8506fe7f1839343a7964[root@localhost
cd10d4993cd21103c7b626387a1ede7907c313f164fa8506fe
7f1839343a7964]# ls
cgroup.clone_children cpuacct.usage
cpuacct.usage_percpu_sys cpuacct.usage_user
cpu.rt_period_us cpu.stat
cgroup.procs cpuacct.usage_all
cpuacct.usage_percpu_user cpu.cfs_period_us
cpu.rt_runtime_us notify_on_release
cpuacct.stat cpuacct.usage_percpu
cpuacct.usage_sys cpu.cfs_quota_us
cpu.shares tasks
[root@localhost
cd10d4993cd21103c7b626387a1ede7907c313f164fa8506fe
7f1839343a7964]# cat cpu.shares
512
[root@localhost
cd10d4993cd21103c7b626387a1ede7907c313f164fa8506fe
7f1839343a7964]# echo 1024 > cpu.shares
[root@localhost
cd10d4993cd21103c7b626387a1ede7907c313f164fa8506fe
7f1839343a7964]# top - 再次使⽤top查看,此时两个进程各占50左右(1核1G)2、限制容器对内存的使⽤
- 内存限额与操作系统类似,容器可以使⽤的内存包括两个部分:
物理内存和swap。 - docker可以通过下⾯两组参数控制容器内存的使⽤量。
#此时是2核2G的结果
[root@haha cpu]# docker run -itd --name bb --cpu
shares 2048 progrium/stress --cpu 2
493c9fae26670a4e9fec0633b67aeba0a1f337db381880b652
7809a6d31e4c75
[root@haha cpu]# docker run -itd --name aa --cpu
shares 2048 progrium/stress --cpu 2
01b20f41d8790ba194f25bf2949f7a170c56865f53750b5611
03315d9c80aa25
[root@haha cpu]# top
PID USER PR NI VIRT RES SHR S
%CPU %MEM TIME+ COMMAND
575051 root 20 0 7320 96 0 R
49.2 0.0 0:14.60 stress
574756 root 20 0 7320 96 0 R
47.8 0.0 0:15.51 stress
574755 root 20 0 7320 96 0 R
46.8 0.0 0:16.63 stress
575052 root 20 0 7320 96 0 R
45.5 0.0 0:10.77 stress3. 1. -m或-memory:设置内存使⽤的限额 - --memory-swap:设置内存+swap 的使⽤限额
[root@localhost ~]# docker run -itd -m 200M --
memory-swap=300M nginx
d66d856f0b284acb0501ab7c5c4c6d57b20e33d63d14cdd84e
cce1c7ea7b9ec3
#其含义是允许该容器最多使⽤ 200M 的内存和 100M 的
swap。默认情况下,上⾯两组参数为 -1,即对容器内存和 swap
的使⽤没有限制。使⽤ progrium/stress 镜像来为容器分配内
存。该镜像可⽤于对容器执⾏压⼒测试。
[root@localhost ~]# docker run -it -m 280M --
memory-swap=300M progrium/stress --vm 1 --vm-bytes
250M #为每个线程分配的内存要⼩于内存总量
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1
vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 262144000 bytes ...
stress: dbug: [7] touching bytes in strides of
4096 bytes ...
stress: dbug: [7] freed 262144000 bytes
stress: dbug: [7] allocating 262144000 bytes ...
stress: dbug: [7] touching bytes in strides of
4096 bytes ...
stress: dbug: [7] freed 262144000 bytesstress: dbug: [7] allocating 262144000 bytes ...
stress: dbug: [7] touching bytes in strides of
4096 bytes ...
stress: dbug: [7] freed 262144000 bytes
stress: dbug: [7] allocating 262144000 bytes ...
--vm 1 :启动1个内存⼯作线程
--vm-bytes 280M :每个线程分配280M内存
- 如果让⼯作线程分配的内存超过 380M,结果如下:[root@localhost ~]# docker run -it -m 200M --
memory-swap=300M progrium/stress --vm 1 --vm-bytes
380M #380M超过规定内存200M⼤⼩
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1
vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 398458880 bytes ...
stress: dbug: [7] touching bytes in strides of
4096 bytes ...
stress: FAIL: [1] (416) <-- worker 7 got signal 9
stress: WARN: [1] (418) now reaping child worker
processes
stress: FAIL: [1] (422) kill error: No such
process
stress: FAIL: [1] (452) failed run completed in 1s
分配的内存超过限额,stress 线程报错,容器退出。
- 如果在启动容器时只指定-m⽽不指定--memory-swap,那么--
memory-swap默认为-m的两倍,⽐如:
[root@localhost ~]# docker run -it -m 200M nginx
#此时容器最多使⽤200M物理内存和200M的swap
注: 容器最多使⽤ 200M 物理内存和 200M swap。3、限制 DPS 和 IOPS 的使⽤ - bps是byte per second,每秒读写的数据量
- iops是io per second,每秒IO的次数
- 参数
--device-read-bps:限制读某个设备的bps
--device-write-bps:限制写某个设备的bps
--device-read-iops:限制读某个设备的iops
--device-write-iops:限制写某个设备的iops
[root@localhost ~]# docker run -it --device-write
bps /dev/mapper/rl-root:30MB rockylinux
[root@24b6f6188dc7 /]# time dd if=/dev/zero
of=test.bak bs=1M count=800 oflag=direct
800+0 records in
800+0 records out
838860800 bytes (839 MB, 800 MiB) copied, 21.9722
s, 38.2 MB/s
real 0m21.975s
user 0m0.001s
sys 0m0.145s
[root@24b6f6188dc7 ~]# exit
exit通过 dd 测试在容器中写磁盘的速度。因为容器的⽂件系统是在
host /dev/sda 上的,在容器中写⽂件相当于对 host /dev/sda 进⾏
写操作。另外,oflag=direct指定⽤ direct IO ⽅式写⽂件,这样--
device-write-bps才能⽣效。结果表明,bps 41.9 MB/s 。作为对⽐
测试,如果不限速,结果如下:
4、限制容器对 CPU、内存、DPS、IOPS 的使⽤
⼋、chroot:切换根⽬录
[root@localhost ~]# docker run rockylinux
[root@localhost ~]# time dd if=/dev/zero
of=test.bak bs=1M count=800 oflag=direct
记录了800+0 的读⼊
记录了800+0 的写出
838860800 bytes (839 MB, 800 MiB) copied, 11.3069
s, 74.2 MB/s
real 0m11.329s
user 0m0.001s
sys 0m0.132s
[root@haha cpu]# docker run -itd --name test --
cpu-shares 1024 -m 200M --memory-swap=300M --
device-write-bps /dev/vda:30MB rockylinux
d844f77071177114cf542bcc7722dbbc739816de91271282fd
69e2e7a2b2b9f3**⼋、chroot:切换根⽬录**
1、通过 chroot 运⾏ busybox
busybox:⼀个集成了⼀百多个最常⽤Linux命令和⼯具的软件
⼯具箱,它在单⼀的可执⾏⽂件中提供了精简的Unix⼯具集。
BusyBox可运⾏于多款POSIX环境操作系统中,如Linux(包括
Android)、Hurd、FreeBSD等。
**$(docker create busybox):**将 docker create busybox 这条命
令的执⾏结果作为变量。
**docker export :**docker export 命令将所指定的 Docker 容器
进⾏导出操作。
**|:**管道符号⽤于将前⼀个命令的输出连接到下⼀个命令的输
⼊。
**tar -C rootfs -xvf -:**这部分命令使⽤tar命令来解压缩并提取tar
归档中的⽂件。
[root@doc ~]# cd /
[root@doc /]# mkdir test
[root@doc /]# docker export $(docker create
busybox) | tar -C test -xvf -
[root@doc /]# chroot test /bin/pwd # 通过chroot
执⾏pwd命令,发现根⽬录位置改变到了test
/-Crootfs:将⽂件提取到指定的⽬录rootfs中。这⾥的rootfs
表示⽂件提取的⽬标路径
-xvf -:通过-xvf选项解压缩并提取⽂件,其中"-"表示输⼊
来⾃于前⼀个命令的标准输出。
2、chroot 运⾏ sh
/bin/bash 报错,因为导⼊的 busybox 镜像内不包含
/bin/bash,只能指定 /bin/sh 执⾏ shell
3、检查 /bin/sh 的根⽬录
[root@doc /]# chroot test /bin/bash
chroot: failed to run command '/bin/bash': No such
file or directory
[root@doc /]# chroot test /bin/sh
/ #4、通过 chroot 制作简单系统
(1)创建⼩型系统的根⽬录
(2)复制命令到⼩根⽬录
[root@doc /]# chroot test /bin/sh
/ # echo $$
3552
[root@doc /]# pidof -s sh # 所以当前运⾏的chroot的
sh的进程号为3552
3552
[root@doc /]# ls -ld /proc/3552/root # 查询PID为
3552的进程根⽬录
lrwxrwxrwx. 1 root root 0 12⽉ 12 10:57
/proc/3552/root -> /test # 确认该进程的根⽬录被映射到
了/test上
[root@doc /]# mkdir linux # 这个linux会作为即将创建
的⼩型系统的根⽬录
[root@doc /]# cd linux/
[root@doc linux]# mkdir -p ./usr/bin/
[root@doc linux]# mkdir lib
[root@doc linux]# mkdir lib64
[root@doc linux]# which bash # 查看bash命令的路径
/usr/bin/bash[root@doc linux]# cp -v /usr/bin/bash ./usr/bin/
复制bash命令新系统的根⽬录下
'/usr/bin/bash' -> './usr/bin/bash'
[root@doc linux]# ldd /usr/bin/bash # 查看bash
⽂件的动态依赖关系,输出依赖的共享库及版本
linux-vdso.so.1 (0x00007ffdcfe8d000)
libtinfo.so.6 => /lib64/libtinfo.so.6
(0x00007ff3942ab000)
libdl.so.2 => /lib64/libdl.so.2
(0x00007ff3940a7000)
libc.so.6 => /lib64/libc.so.6
(0x00007ff393ce1000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff3947f6000)
[root@doc linux]# cp /lib64/libtinfo.so.6
/lib64/libdl.so.2 /lib64/libc.so.6 /lib64/ld
linux-x86-64.so.2 ./lib64/
将依赖共享库添加到⼩根⽬录的lib64⽬录下
[root@doc ~]# chroot /linux /usr/bin/bash # 测试
给个bash运⾏
bash-4.4# echo $$ # 查看当前进程的pid号
3728
复制命令的⽅法都⼀样,先复制命令程序,再查看依赖 lib 库⽂
件,然后根据信息,依次复制 lib 库⽂件到⼩型系统中的 lib 或
lib64 内
[root@doc linux]# cp /usr/bin/ls ./usr/bin/[root@doc linux]# ldd /usr/bin/ls
linux-vdso.so.1 (0x00007ffec15b6000)
libselinux.so.1 => /lib64/libselinux.so.1
(0x00007f619c99e000)
libcap.so.2 => /lib64/libcap.so.2
(0x00007f619c796000)
libc.so.6 => /lib64/libc.so.6
(0x00007f619c3d0000)
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0
(0x00007f619c14c000)
libdl.so.2 => /lib64/libdl.so.2
(0x00007f619bf48000)
/lib64/ld-linux-x86-64.so.2 (0x00007f619cdec000)
libpthread.so.0 => /lib64/libpthread.so.0
(0x00007f619bd28000)
[root@doc linux]# cp /lib64/libselinux.so.1
/lib64/libcap.so.2 /lib64/libc.so.6
/lib64/libpcre2-8.so.0 /lib64/libdl.so.2
/lib64/ld-linux-x86-64.so.2
/lib64/libpthread.so.0 /linux/lib64/
[root@doc linux]# chroot /linux/ /usr/bin/bash
bash-4.4# ls
lib lib64 usr
bash-4.4# echo $$ # 因为之前退出过这个⼩系统的bash,
所以再进时,pid号就会发⽣改变
3810
⼀、Docker 私有仓库
Docker 仓库(Repository)集中存放镜像的地⽅,⽽注册服务器
(Registry)是存放仓库的具体服务器。仓库可以被认为是⼀个具体
的项⽬或⽬录。
Docker 公共仓库:https://hub.docker.com
⼆、Docker 私有仓库的作⽤
- 镜像上传到公共仓库不⽅便管理,且仅需要局域⽹⽤户之间传递
镜像的情况,需要使⽤私有仓库。 - 节省⽹络带宽,不需要都去公共仓库下载镜像,只需要从私有仓
库下载即可。 - 提供镜像资源利⽤,针对公司内部开发,不能联⽹情况下,有⼀
些使⽤到的镜像可以推送到本地的私有仓库中,以供内部开发⼈
员便捷下载使⽤。
三、搭建 Docker 私有仓库的⽅案 - docker 官⽅提供的搭建私有仓库⼯具 registry。
- harbor 私有仓库。
四、搭建 docker 私有仓库操作系统
IP 地址
主机名
docker 版本
Rocky8.7
192.168.15.3
doc
docker24.0.7
四、搭建 docker 私有仓库
1、部署环境
2、下载部署 registry
[root@doc ~]# docker pull registry
Using default tag: latest
latest: Pulling from library/registry
79e9f2f55bf5: Pull complete
0d96da54f60b: Pull complete
5b27040df4a2: Pull complete
e2ead8259a04: Pull complete
3790aef225b9: Pull complete
Digest:
sha256:169211e20e2f2d5d115674681eb79d21a217b296b43
374b8e39f97fcf866b375
Status: Downloaded newer image for registry:latest
docker.io/library/registry:latest
[root@doc ~]# docker run -itd --volume
/opt/data/registry/:/var/lib/registry -p 5000:5000
--restart=always --name registry registry:latest
启动registry容器。# --volume:挂载,挂载源:挂载点。
-p:映射端⼝。
--restart=always:重启策略。
name registry:容器名。
9ab3d198bf059ab7db6f6934d6725874ba4bdc73d889da8b4b
a692575104e077
[root@doc ~]# docker ps
CONTAINER ID IMAGE COMMAND
CREATED STATUS PORTS
NAMES
9ab3d198bf05 registry:latest "/entrypoint.sh
/etc..." 5 seconds ago Up 4 seconds
0.0.0.0:5000->5000/tcp, :::5000->5000/tcp
registry
[root@doc ~]# netstat -anpt | grep 5000
tcp 0 0 0.0.0.0:5000
0.0.0.0:* LISTEN 7865/docker
proxy
tcp6 0 0 :::5000 :::*
LISTEN 7872/docker-proxy
[root@doc ~]# curl
http://127.0.0.1:5000/v2/_catalog # 查看镜像仓库列
表
{"repositories":[]} # 当前未上传任何镜像所以为空3、上传镜像到私有仓库
4、问题错误
[root@doc ~]# docker images
REPOSITORY TAG IMAGE ID CREATED
SIZE
busybox latest beae173ccac6 23 months
ago 1.24MB
nginx latest 605c77e624dd 23 months
ago 141MB
registry latest b8604a3fe854 2 years ago
26.2MB
[root@doc ~]# docker tag nginx:latest
192.168.15.3:5000/nginx:v1
改名,被上传镜像格式:域名或IP地址+端⼝/原镜像名
[root@doc ~]# docker push
192.168.15.3:5000/nginx:v1
The push refers to repository
[192.168.15.3:5000/nginx]
Get "https://192.168.15.3:5000/v2/": http: server
gave HTTP response to HTTPS client
报错(1)报错情况
(2)报错原因
因为Docker 从 1.3.X 之后默认 docker registry 使⽤的是 https,所
以当⽤dockerpull/push 命令下载、上传远程镜像时,如果远程
docker registry 是⾮ https 的时候就会报上⾯的错误,所以需要修改
⼀下docker启动参数。
(3)错误处理
[root@doc ~]# docker push
192.168.15.3:5000/nginx:v1
The push refers to repository
[192.168.15.3:5000/nginx]
Get "https://192.168.15.3:5000/v2/": http: server
gave HTTP response to HTTPS client
报错
[root@doc ~]# vim
/usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --
containerd=/run/containerd/containerd.sock --
insecure-registry 192.168.15.3:5000 # 添加参数
[root@doc ~]# systemctl daemon-reload
[root@doc ~]# systemctl restart docker.service--insecure-registry:⼀个⽤于将 Docker 客户端配置为信任不安
全的 Docker Registry 的选项。在默认情况下,Docker 客户端
只信任通过 HTTPS 进⾏通信的 Docker Registry,以确保安全
性。
5、再次上传镜像
[root@doc ~]# docker push
192.168.15.3:5000/nginx:v1
The push refers to repository
[192.168.15.3:5000/nginx]
d874fd2bc83b: Pushed
32ce5f6a5106: Pushed
f1db227348d0: Pushed
b8d6e692a25e: Pushed
e379e8aedd4d: Pushed
2edcec3590a4: Pushed
v1: digest:
sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0b
fd5c4c20a2fa2aaa7ede3 size: 1570
[root@doc ~]# curl
http://127.0.0.1:5000/v2/_catalog
{"repositories":["nginx"]} # 上传成功
[root@doc ~]# curl
http://127.0.0.1:5000/v2/nginx/tags/list
{"name":"nginx","tags":["v1"]} # 查看nginx镜像版
本6、拉取私有镜像
[root@doc ~]# ls
/opt/data/registry/docker/registry/v2/repositories
/ # 镜像存放于宿主机的位置
nginx
[root@doc ~]# docker rmi
192.168.15.3:5000/nginx:v1 # 先删除刚才的镜像
Untagged: 192.168.15.3:5000/nginx:v1
Untagged:
192.168.15.3:5000/nginx@sha256:ee89b00528ff4f02f24
05e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
[root@doc ~]# docker pull
192.168.15.3:5000/nginx:v1 # 再拉取私有仓库内的镜像
v1: Pulling from nginx
Digest:
sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0b
fd5c4c20a2fa2aaa7ede3
Status: Downloaded newer image for
192.168.15.3:5000/nginx:v1
192.168.15.3:5000/nginx:v1
[root@doc ~]# docker tag
192.168.15.3:5000/nginx:v1 nginx:v2 # 改名
[root@doc ~]# docker images # 查看所有镜像
REPOSITORY TAG IMAGE ID
CREATED SIZE7、其他主机上传
只要同在⼀个局域⽹内的所有主机都可向本地镜像仓库内上传镜
像,⽅法同上,在上传时只需注意:
当添加完参数后,就可向本地私有仓库上传。
busybox latest beae173ccac6
23 months ago 1.24MB
192.168.15.3:5000/nginx v1 605c77e624dd
23 months ago 141MB
nginx latest 605c77e624dd
23 months ago 141MB
nginx v2 605c77e624dd
23 months ago 141MB
registry latest b8604a3fe854
2 years ago 26.2MB
[root@doc ~]# vim
/usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --
containerd=/run/containerd/containerd.sock --
insecure-registry 192.168.15.3:5000 # 添加参数
[root@doc ~]# systemctl daemon-reload
[root@doc ~]# systemctl restart docker.service
Docker允许通过外部访问容器或者容器之间互联的⽅式来提供⽹络
服务。
容器启动之后,容器中可以运⾏⼀些⽹络应⽤,通过-p或-P参数来
指定端⼝映射。
宿主机的⼀个端⼝只能映射到容器内部的某⼀个端⼝上,⽐如:
8080->80之后,就不能8080->81。
容器内部的某个端⼝可以被宿主机的多个端⼝映射,⽐如: 8080-
>80,8090->80,8099->80。
⼀、为容器绑定宿主机端⼝
-p ⼩写p表示docker会选择⼀个具体的宿主机端⼝映射到容器
内部开放的⽹络端⼝上。
-P ⼤写P表示docker会随机选择⼀个宿主机端⼝映射到容器内
部开放的⽹络端⼝上。
[root@doc ~]# docker run -itd --name nginx1 -p
8080:80 nginx:latest
d9df73aa43cb496df80717f91170ea97912601fc25757cd4b7
125d3054f6d61a
[root@doc ~]# docker run -itd --name nginx2 -P
nginx:latest8cf5a8dce583990619ad38d847438564600edd490917d94fe4
cbd144ce7da195
[root@doc ~]# docker ps
CONTAINER ID IMAGE COMMAND
CREATED STATUS PORTS
NAMES
8cf5a8dce583 nginx:latest "/docker
entrypoint...." 10 seconds ago Up 9 seconds
0.0.0.0:32768->80/tcp, :::32768->80/tcp
nginx2
d9df73aa43cb nginx:latest "/docker
entrypoint...." 16 seconds ago Up 15 seconds
0.0.0.0:8080->80/tcp, :::8080->80/tcp
nginx1
9ab3d198bf05 registry:latest "/entrypoint.sh
/etc..." About an hour ago Up 48 minutes
0.0.0.0:5000->5000/tcp, :::5000->5000/tcp
registry
[root@doc ~]# netstat -anpt | grep 8080
tcp 0 0 0.0.0.0:8080
0.0.0.0:* LISTEN 9922/docker
proxy
tcp6 0 0 :::8080 :::*
LISTEN 9930/docker-proxy
[root@doc ~]# netstat -anpt | grep 32768访问本机地址:8080 即可访问到 nginx1 容器。
访问本机地址:32768 即可访问到 nginx2 容器,这是 -P 的随机映射
端⼝。
⼆、为容器绑定宿主机 IP
tcp 0 0 0.0.0.0:32768
0.0.0.0:* LISTEN 10046/docker
proxy
tcp6 0 0 :::32768 :::*
LISTEN 10052/docker-proxy[root@doc ~]# docker run -itd --name nginx3 -p
127.0.0.1:8888:80 nginx:latest
66347b8f5295247146ecfeeee4bf9cda313eb8b67c662a1fa0
7f10649c602ddf
[root@doc ~]# docker run -itd --name nginx4 -p
192.168.15.3:9999:80 nginx:latest
fd2c230b4c562e9531dd4e2208a59800284395e6afaa66eae6
41d75933442a1c
[root@doc ~]# docker ps
CONTAINER ID IMAGE COMMAND
CREATED STATUS PORTS
NAMES
fd2c230b4c56 nginx:latest "/docker
entrypoint...." 3 seconds ago Up 2 seconds
192.168.15.3:9999->80/tcp
nginx4
66347b8f5295 nginx:latest "/docker
entrypoint...." 10 seconds ago Up 9 seconds
127.0.0.1:8888->80/tcp
nginx3
访问 127.0.0.1:8888 即可访问到 nginx3 容器
访问 192.168.15.3:9999 即可访问到 nginx4 容器
但访问 192.168.15.3:8888 和 127.0.0.1:9999 就⽆法访问到
nginx三、容器指定通信协议
四、查看容器绑定端⼝和容器的 IP 地址
[root@doc ~]# docker run -itd --name nginx5 -p
7777:80/udp nginx:latest
9a90cd757d59de57c247543e9dda5d186798e12677e83239cd
28394e8424f467
[root@doc ~]# docker ps | grep nginx5
9a90cd757d59 nginx:latest "/docker
entrypoint...." 16 seconds ago Up 15 seconds
80/tcp, 0.0.0.0:7777->80/udp, :::7777->80/udp
nginx5
[root@doc ~]# netstat -anpu | grep 7777
udp 0 0 0.0.0.0:7777
0.0.0.0:* 10998/docker
proxy
udp6 0 0 :::7777 :::*
11004/docker-proxy 五、错误处理
1、启动容器时报错
错误信息:
[root@doc ~]# docker port nginx4
80/tcp -> 192.168.15.3:9999 # 容器绑定宿主机的IP和端
⼝
[root@doc ~]# docker inspect nginx4 | grep
IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.6", # 容器的
IP地址
"IPAddress": "172.17.0.6",
/usr/bin/docker-current: Error response from
daemon: driver failed programming external
connectivity on endpoint my-nginx
(db5a0edac68d1ea7ccaa3a1e0db31ebdf278076ef4851ee42
50221af6167f9ac): (iptables failed:
iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --
dport 8088 -j DNAT --to-destination
172.17.0.2:80 ! -i docker0: iptables: No
chain/target/match by that name.解决⽅案:
- 重启 docker 服务:systemctl restart docker
- 再 docker start $(docker ps -qa)
2、容器端⼝映射到宿主机后,外部⽆法访问宿主机绑定端
⼝
错误信息:
创建 docker 容器的时候,做了端⼝映射到宿主机,防⽕墙已关闭,
但是外部始终⽆法访问宿主机端⼝。
错误原因: - 这种情况基本就是因为宿主机没有开启路由转发功能,从⽽导致
外部⽹络访问宿主机对应端⼝是没能转发到 Docker Container
所对应的端⼝上。 - 也可能是宿主机对应端⼝被占⽤。
解决⽅案: - 设置路由转发
在 Linux 中开启 ip 转发的内核参数为:net.ipv4.ip_forward,查看是
否开启 ip转发:# cat /proc/sys/net/ipv4/ip_forward // 0:未开启,1:已开启
======
打开ip转发功能, 下⾯两种⽅法都是临时打开ip转发功能!
echo 1 > /proc/sys/net/ipv4/ip_forward
sysctl -w net.ipv4.ip_forward=1
======
永久⽣效的ip转发
vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
sysctl -p /etc/sysctl.conf // ⽴即⽣效
Linux 系统中也可以通过重启⽹卡来⽴即⽣效 (修改 sysctl.conf ⽂件
后⽣效)
- 关闭被占⽤端⼝的服务或修改容器端⼝
netstat -anpt | grep 占⽤端⼝确认端⼝冲突是哪个服务,可以选择关闭服务,也可以选择修改服
务端⼝
通过 docker 容器管理命令可以先将端⼝冲突的容器删除(docker
rm -f 容器名/ID),再通过 docker run -itd -p 命令重新指定,在删
除前要做好该容器的备份,以免数据丢失。
在指定容器的端⼝映射时,⼀定要确认好宿主机的端⼝是否已经被
占⽤,否则在真正的⽣产环境时,⼀旦处理起来,可能会造成⼀定
的数据损失。