docker核心原理
Namespace命名空间
- Docker的运行和命名空间有着密切的联系,Docker中每一个容器都有一个独立的位置
- 容器在运行时,就会在一个空间内,也就是说每个docker容器就是一个单独的空间
容器的概念
容器是一个大的分类,和操作系统一样,有许多的系统,Docker是容器中的一种
虽然容器是一个大的种类,但是通过容器对容器镜像实例化后也称之为容器
容器主要分为 Docker Podman coreOS lxc buildah skopo等
Podman
是红帽公司收购的,基于redhat_linux之上,可以yum直接安装
yum -y install podman
使用方法
和docker基本相同
podman pull centos # 从红帽仓库下载centos镜像 podman images # 查看已有镜像 podman run -it --name test centos /bin/bash # 运行并进入容器 podman rm -f test # 删除test容器 podman ps # 查看正在运行的容器
docker镜像的分类
- 应用类镜像,操作系统类镜像,工具类镜像
httpd就是工具类镜像
centos是系统类镜像
busybox是工具类镜像
虚拟化的分类
- 分为半解耦和完全解耦
系统命令的是如何运作的
首先user下达指令去操作shell
shell通过调用system进程通过调用lib库的文件去操控软件进程
软件通过系统驱动调用内核
内核直接调用硬件,所以用户的命令下达到了硬件,做出了相应的工作这里的驱动程序和lib库文件起到了关键的作用
每个硬件都有驱动程序,无论是u盘还是鼠标等,要发挥出硬件的性能,就需要驱动的支持,如果没有驱动,那么硬件有可能不会工作
lib 也叫库文件,该文件写入了各种各样的程序说明信号,用来告诉系统某一个软件的操作
对于虚拟化来说硬件是相同的,所以驱动程序是可以通用的,库文件也有一定的通用性,比如一些服务的启动命令都是一样的
耦合:
耦合就是两个或者两个以上的程序因为互相的作用而影响彼此,比如端口号相同就是耦合,也就是冲突
因为同一个程序运行在一个系统中会有耦合,所以要解耦
完全解耦化
例如 VMware KVM等这些软件使用的都是完全解耦虚拟化
完美的没有任何冲突的
当我们在同一个操作系统中运行相同的软件程序时,它们会发生冲突。解除耦合则是为一个软件分配一个环境,使其独立运行。
例如
手机里的应用分身,还有经常使用的VMware虚拟机也是使用这种方式
当我们想要同时运行多个web服务器时,需要创建两个操作系统
从指定硬件层面(CPU、MEM、DISK)→安装内核→安装系统→安装lib库→安装service(驱动程序)→安装应用软件
每个系统之间都是互相独立的
半解耦化
使同一个环境下可以同时运行两个相同的软件,分担软件服务器的压力。
直接使用物理机上的硬件资源(CPU、MEM、DISK)和kernel(内核)例如:
docker会直接使用系统镜像构建出一个容器,以文件夹的方式存放在操作系统上。
而容器内部的运行环境比如lib库将通过ln -s(软链接)的形式使用。
这样使得应用程序误以为一个文件夹就是一个操作系统。
区别
半解耦是每个系统之间能共用的共用,确保容器体积会比虚拟机小很多,app只需要在安装时安装自己对应的lib库,bin指令集即可
完全解耦是每运行一个操作系统都需要重新启动和加载其他系统文件,每个系统之间的文件是相互独立的
如果当web访问量变大,需要多开几台web应用来缓解时,半解耦只需要在当前服务启动容器即可,不需要去启动操作系统,容器中的web应用会在沙盒运行,而完全解耦需要再启动一台虚拟机,也就相当于再次启动一台系统,在去运行web,运行完成后比半解耦慢很多
Docker的特性
容器具备了超强的可移植性
打包对象,任何软件以及依赖都可以打包在一起
解决硬件的依赖关系,容器不需要更改就几乎可以运行在所有的平台上
隔离性,资源,网络,库都是被隔离的,不会出现依赖问题
自动化,提供了标准为操作内容 可以快速的启动和迁移
容器意味着,环境隔离和可重复性:开发人员只需要为应用创建一次运行环境,打包为容器,便可以在任何电脑上使用,容器环境与其他host主机环境是隔离的,运维人员只需要配置好标准的环境,更加高效,一致和可重复性。容器消除了开发,测试,生产环境当中的不一致性
docker的隔离
隔离的本质:不在统一的范围
ipc 信号量 消息队列和共享内存
mnt 挂载点和文件系统
net 网络设备,网站,端口
pid 进程编号
user 用户和组
uts 主机名和域名上面这些只要app之间有一项不同就说明已经隔离了
uts 和 ipc隔离
容器之间主机名的不同来进行隔离
容器之间的pic消息队列的不同进行隔离
pid隔离
说到pid隔离,也就说到docker的一个bug了
不同空间的的进程可以有相同的pid号,系统中的第一个pid编号一定是1,也就是第一个进程pid号一定是1
在linux中第一个进程是 init进程,版本不同,也有可能是systemd进程,而其他进程都是该进程的子进程
在docker中第一个进程是我们进入docker时运行的命令,这是目前还没有解决的问题
如果需要pid的1号为 systemd的话需要进行提权操作,不过这个操作不建议
docker run --restart always -d --name test4 --privileged centos /sbin/init # /sbin/init 就是1号进程 --privileged 就是提权
net隔离
当物理机已经运行一个apache进程时,再进入命名空间去运行一个apache,会报出端口被占用的错误,就需要进行网络隔离
NET网络隔离包括了设备,ipv4/ipv6协议栈,防火墙,路由表、端口、socket等。
物理的网络设备最多存在一个net命名空间中,可以通过虚拟网络端对端,
不同的net命名空间创建通道,达到网络通讯的目的
如果有多块网卡,可以将网卡分配给新建net命名空间,当net命名空间被释放时,所有的内部进程都会中止,物理网卡就会返回到root的命名空间中
创建网络空间
# 创建test_ns的network命名空间
[root@localhost ~]# ip netns add test_ns
# 查看test_ns中的网卡,只有一个lo网卡,且状态为DOWN
[root@localhost ~]# ip netns exec test_ns ip link list
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# lo的DOWN状态下是无法进行iso封装数据的
[root@localhost ~]# ip netns exec test_ns ping 127.0.0.1
connect: Network is unreachable # 因为没有开启lo网卡
# 开启lo网卡并ping自己测试
[root@localhost ~]# ip netns exec test_ns ip link set dev lo up
[root@localhost ~]# ip netns exec test_ns ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.161 ms
为网络空间添加网卡
# 添加 veth0 和veth1 类型是 veth peer类型
[root@localhost ~]# ip link add veth0 type veth peer name veth1
# 宿主机的网卡编号是全局的,无论哪个空间编号不会重复
[root@localhost ~]# ip a
12: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 3a:3e:0e:0a:1f:bf brd ff:ff:ff:ff:ff:ff
13: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 56:83:20:7a:c5:3a brd ff:ff:ff:ff:ff:ff
[root@localhost ~]# ip link set veth1 netns test_ns # 将veth1放入test_ns命名空间
[root@localhost ~]# ip netns exec test_ns ip a
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
12: veth1@if13: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether be:a8:bd:76:bd:71 brd ff:ff:ff:ff:ff:ff link-netnsid 0
配置ip地址
# 为test_ns中的veth1配置ip为10.1.1.1,并启动
[root@localhost ~]# ip netns exec test_ns ifconfig veth1 10.1.1.1/24 up
# 网络设备对的另一个配置ip,作为和网络命名空间网桥地址
[root@localhost ~]# ifconfig veth0 10.1.1.2/24
# ping test_ns命名空间
[root@localhost ~]# ping 10.1.1.1
# ping当前命名空间
[root@localhost ~]# ip netns exec test_ns ping 10.1.1.2
# 查看现有的网络命名空间
[root@localhost ~]# ip netns
test_ns (id: 1)
- 概念
- 数据想要联通,用网线传输数据,网线一端是veth(虚拟以太网卡),另一端peer,一个peer只能插一个veth,
- peer都插在交换机上,交换机负责转发数据
小结
隔离没有写的太明白
https://www.feiyiblog.com/2020/03/25/Docker是如何实现容器隔离的/参考该博客
pid隔离后 会有一个 1号进程的问题和物理机的pid是想通的,没有实现隔离,需要将容器和主机进行mount隔离
本博客所有文章是以学习为目的,如果有不对的地方可以一起交流沟通共同学习 邮箱:1248287831@qq.com!