极客时间运维进阶训练营第一周作业
极客时间|训练营 X 马哥教育

-
OCI 1.0 定义了镜像标准,容器运行时标准等等:
-
CRI-容器运行接口(设计容器环境,例如containerd、rkt需要执行此标准);
-
CNI-容器网络接口(在k8s中运行容器且需要为容器提供网路支持的情况下要符合CNI标准)。
隔离类型
|
功能
|
系统调用参数
|
内核版本
|
MNT Namespace(mount)
|
提供磁盘挂载点和文件系统的隔离能力
|
CLONE_NEWNS
|
Linux 2.4.19
|
IPC Namespace(Inter-Process Communication)
|
提供进程间通信的隔离能力
|
CLONE_NEWIPC
|
Linux 2.6.19
|
UTS Namespace(UNIX Timesharing System)
|
提供主机名隔离能力
|
CLONE_NEWUTS
|
Linux 2.6.19
|
PID Namespace(Process Identification)
|
提供进程隔离能力
|
CLONE_NEWPID
|
Linux 2.6.24
|
Net Namespace(network)
|
提供网络隔离能力
|
CLONE_NEWNET
|
Linux 2.6.29
|
User Namespace(user)
|
提供用户隔离能力
|
CLONE_NEWUSER
|
Linux 3.8
|
Time Namespace
|
提供时间隔离能力 |
CLONE_NEWTIME
|
Linux 5.6
|
Syslog Namespace |
提供syslog隔离能力
|
syslog namespace首先是由华为的工程师RuiXiang(瑞翔)提出的,但没有合并到Linux内核,之后systemd在2020年2月实现了一个名为journal namespace的类似功能
|
|
Control group(cgroup)Namespace
|
提供进程所属的控制组的身份隔离
|
Linux 4.6
|
root@docker-server1:~#cat /boot/config-5.15.0-43-generic | grep CGROUP | grep -v "^#" | wc -l 22 root@docker-server1:~#cat /boot/config-5.15.0-43-generic | grep MEM | grep CG | grep -v "^#" CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_KMEM=y
-
常见的runtime:
-
runc:目前Docker和containerd默认的runtime,基于go语言开发,遵循OCI规范;
-
crun:redhat推出的运行时,基于c语言开发,集成在podman内部,遵循OCI规范;
-
gVisor:google推出的运行时,基于go语言开发,遵循OCI规范。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ~#docker info Containers: 2 #当前主机运行的容器总数 Running: 1 #有几个容器是正在运行的 Paused: 0 #有几个容器是暂停的 Stopped: 1 #有几个容器是停止的 Images: 3 #当前服务器的镜像数 Server Version: 20.10.18 #服务端版本 Storage Driver: overlay2 #当前使用的存储引擎 Backing Filesystem: xfs #后端文件系统,即服务器的磁盘文件系统 Supports d_type: true #是否支持d_type Native Overlay Diff: true #是否支持差异数据存储 userxattr: false #是否在挂载文件系统启用对扩展用户属性的支持(如文件的 mime 类型、字符集或编码) Logging Driver: json-file #日志类型 Cgroup Driver: systemd #Cgroups类型,19.03及之前为Cgroups Cgroup Version: 2 #Cgroup 版本 Plugins: #插件 Volume: local #支持的卷插件 Network: bridge host macvlan null overlay # overlay夸主机通信 Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog #日志类型 Swarm: inactive #是否支持swarm Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc #已安装的容器运行时 Default Runtime: runc #默认使用的容器运行时 Init Binary: docker-init #初始化容器的守护进程,即pid为1的进程 containerd version: 9cd3357b7fd7218e4aec3eae239db1f68a5a6ec6 #版本 runc version: v1.1.4-0-g5fd4c4d # runc版本 init version: de40ad0 #init版 |
Docker存储引擎:
Overlay:UnionFS文件系统,Linux内核3.18后支持;
overlay2: Overlay的升级版,到目前为止,所有Linux发行版推荐使用的存储类型;
devicemapper:是CentOS和RHEL的早期使用的存储驱动程序,因为之前的内核版本较低不支持overlay2,但是当前较新版本的CentOS和RHEL现在已经支持overlay2,因此推荐使用overlay2;
ZFS(Sun-2005)/btrfs(Oracle-2007):目前没有广泛使用;
vfs: 用于测试环境,适用于无法使用copy-on-write文件系统的情况。 此存储驱动程序的性能很差,通常不建议用于生产环境;
AUFS(Another UnionFS): 是早期的一种UnionFS文件系统的实现,是Docker 18.06及更早版本使用的存储引擎。
https://docs.docker.com/storage/storagedriver/select-storage-driver/
以下是Docker配置参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 | ~ # cat /etc/docker/daemon.json { "graph" : "/var/lib/docker" , "storage-driver" : "overlay2" , "insecure-registries" : [ "harbor.magedu.com" , "harbor.myserver.com" , "192.168.1.16" ], "registry-mirrors" : [ "https://9916w1ow.mirror.aliyuncs.com" ], "exec-opts" : [ "native.cgroupdriver=systemd" ], "live-restore" : false , "log-opts" : { "max-file" : "5" , "max-size" : "100m" } } ~ # systemctl restart docker |
注意:centos 7.2及之前的版本默认使用devicemapper存储引擎,不能直接使用overlay存储引擎,除非新添加一快磁盘作为docker的数据盘, 并在格式化的时候指定格式化参数-n ftype=1,否则报错。但是,Centos 7.3版本开始修复此问题。
镜像管理操作步骤:
1、制作镜像;
2、上传镜像;
3、下载镜像;
4、查找镜像;
5、导出镜像/导入镜像;
6、删除镜像;
7、查询镜像。
命令如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ~ # docker image --help Usage: docker image COMMAND Manage images Commands: build #从Docker文件构建新的镜像 history #查询镜像的构建历史 import #从本地或远程的压缩包等导入镜像,可以指定导入后的镜像名称 inspect #显示一个或多个镜像的详细信息 load #从一个tar包或标准输入导入镜像 ls #列出本地的所有镜像 prune #删除本地未使用的镜像 pull #从镜像仓库下载镜像到本地 push #从本地上传镜像到镜像仓库 rmi #删除一个或者多个本地镜像 save #保存一个或者多个镜像到一个tar包(默认保存到当前终端的标准输出) tag #对镜像打一个新的标签 ~ # docker search centos #搜索镜像 |
Docker命令详解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | # docker run -it centos:7.9.2009 # docker attach 63fbc2d5a3ec #attach进入容器后操作会在多窗口同步且退出后其它终端也会一起退出。 # docker build #从dockerfile构建镜像 # docker commit -a "jack jack@magedu.com" -m "v2" --change="EXPOSE 80 443" 8ddf4ce923ef new-nginx-image #将容器提交为一个本地镜像 # docker cp 源 目的 #从容器和宿主机相互拷贝文件或目录 # docker create -it --name test1 nginx:1.20.2 #创建一个新的容器且创建后的容器处于退出状态 # docker diff 8ddf4ce923ef #对比容器和镜像有差异的文件或目录 # docker events #获取dockerd的实时事件,创建删除容器等操作 # docker exec -it 40e6379cf371 sh/bash #推进入到容器执行命令操作,推荐使用此方式 # docker export 8ddf4ce923ef -o new-nginx-image.tar.gz #将容器的文件系统导出为一个本地压缩包,非镜像格式 # docker history centos:7.9.2009 #查看的镜像的构建历史 # docker images #查看本地所有镜像 # docker import new-nginx-image.tar.gz #导入export导出的压缩包,导入后的镜像不完整,不能用于创建容器 # docker info #显示系统信息 # docker inspect 50fe74b50e0d #显示docker对象(镜像、网络、容器等)的详细信息 # docker kill $(docker ps -a -q) 强制关闭所有运行中的容器 # docker load -i nginx-1.20.2.tar.gz #从一个tar包或标准输入导入镜像 # docker login #登录镜像仓库 # docker logout #登出镜像仓库 # docker logs -f nginx-container-test1 #持续查看容器标准输出和错误输出的日志 # docker pause 81b344cff55d #暂停一个或者多个容器 # docker port 81b344cff55d #列出一个容器端口映射关系 # docker ps #列出容器,加上-a是列出包含为运行的所有容器 # docker pull nginx:1.20.2 #从镜像仓库下载镜 # docker push nginx:1.20.2 #从本地上传镜像到镜像仓库(需要登录认证) # docker rename awesome_cerf nginx-container1 #重命名容器 # docker restart ID/容器名称 #重启容器 # docker rm -f 11445b3a84d3 #强制删除运行中的容器 # docker rm -f `docker ps -aq -f status=exited` #批量删除已退出容器 # docker rm -f $(docker ps -a -q) #批量删除所有容器 # docker rmi -f 53ec353d8dc4 90a4cd9dfe4c #删除一个或多个镜像 # docker run -it docker.io/centos bash #创建并进入容器,ctrl+p+q退出容器不注销 # docker run -it --name nginx-test1 nginx:1.20.2 #自定义容器名称 # docker run -p 80:80/tcp -p 443:443/tcp -p 53:53/udp --name nginx-container-test1 nginx:1.20.2 #创建容器并指定多端口映射 # docker run -d -p 80:80 --name nginx-container-test1 nginx:1.20.2 #后台运行容器 # docker run -it --rm --name nginx-delete-test nginx:1.20.2 bash #单次运行容器 # docker run -it -d centos:7.9.2009 /usr/bin/tail -f '/etc/hosts' #创建容器的时候传递命令及参数 # docker save 50fe74b50e0d > nginx-1.20.2.tar.gz #保存一个或多个镜像到一个压缩文件(默认是标准输出) # docker search nginx #搜索镜像 # docker start ID/容器名称 #启动一个或多个容器 # docker stats #显示容器资源的实时统计信息 # docker stop ID/容器名称 #停止一个或多个容器 # docker tag nginx:1.20.2 harbor.magedu.net/myserver/nginx:1.20.2 #为镜像添加一个新的tag # docker unpause 81b344cff55d #取消一个或多个容器的暂停 # docker update 容器 --cpus 2 #更新容器配置信息,比如资源限制的值 # docker version #显示docker client和docker server的版本信息 # docker wait #一直等待容器退出并显示容器的退出状态码 |
Docker数据管理:
如果正在运行中的容器修如果生成了新的数据或者修改了现有的一个已经存在的文件内容,那么新产生的数据将会被复制到读写层进行持久化保存,这个读写层也就是容器的工作目录,此即“写时复制(COW) copy on write”机制。
如下图是将对根的数据写入到了容器的可写层,但是把/data中的数据写入到了一个另外的volume中用于数据持久化。

Lower Dir:image镜像层(镜像本身,只读);
Upper Dir:容器的上层(读写);
Merged Dir:容器的文件系统,使用Union FS(联合文件系统)将lowerdir和upper Dir:合并给容器使用;
Work Dir:容器在宿主机的工作。
Docker的镜像是分层设计的,镜像层是只读的,通过镜像启动的容器添加了一层可读写的文件系统,用户写入的数据都保存在这一层当中;
如果要将写入到容器的数据永久保存,则需要将容器中的数据保存到宿主机的指定目录,目前Docker的数据类型分为两种:
一是数据卷(data volume),数据卷实际上就是宿主机上的目录或者是文件,可以被直接mount到容器当中作为容器的本地文件系统使用,实际生产环境中,需要针对不同类型的服务、不同类型的数据存储要求做相应的规划,最终保证服务的可扩展性、稳定性以及数据的安全性;
(基于数据卷通过将宿主机的文件或目录挂载到容器的指定目录,当容器中的挂载目录产生的新数据即可间接的保存到宿主机以实现持久化的目的)
二是数据卷容器(Data volume container), 数据卷容器是将宿主机的目录挂载至一个专用的数据卷容器,然后让其他容器通过数据卷容器继承挂载的目录或文件,以实现将新产生的数据持久化到宿主机的目的。
创建数据卷:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # docker volume create nginx-data # docker volume ls DRIVER VOLUME NAME local nginx-data # docker run -it -d -p 80:80 -v nginx-data:/data nginx:1.20.2 4445e4640c74e1c503a7f8c704270abd58c5bc70aacf600e39945f7fd74ac810 # docker exec -it 4445e4640c74 bash root@4445e4640c74:/ # echo "nginx web" > /data/index.html root@4445e4640c74:/ # exit exit root@docker-server1:~ # ls /var/lib/docker/volumes/nginx-data/_data/index.html /var/lib/docker/volumes/nginx-data/_data/index .htm |
数据目录挂载:
以数据卷的方式,将自定义的宿主机目录或文件提供给容器使用,比如容器可以直接挂载宿主机本地的数据目录(如mysql容器的数据持久化)、 配置文件(如nginx的配置文件)、静态文件(如web服务的图片或js文件)等,只需要在创建容器的时候指定挂载即可。
1 2 3 4 5 6 7 8 9 | # mkdir /data/testapp –p # echo "testapp web page" > /data/testapp/index.html # cat /data/testapp/index.html testapp web page /*启动两个测试容器,web1容器和web2容器,分别测试能否访问到宿主机的数据,注意使用- v 参数,将宿主机目录映射到容器内部,web2的ro表示在容器内对该目录只读,默认的权限是可读写的:*/ # docker run -d --name web1 -v /data/testapp:/usr/share/nginx/html/testapp -p 80:80 nginx:1.20.2 # docker run -d --name web2 -v /data/testapp:/usr/share/nginx/html/testapp:ro -p 81:80 |
数据目录及配置多卷挂载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //nginx 多卷挂载: # mkdir /data/nginx/conf -p # docker cp web1:/etc/nginx/nginx.conf /data/nginx/conf/ # docker run -d --name web3 -v /data/testapp:/usr/share/nginx/html/testapp -v /data/nginx/conf/nginx .conf: /etc/nginx/nginx .conf:ro -p 83:80 nginx:1.20.2 //mysql 容器: # docker pull mysql:5.7.38 # docker run -it -d -p 3306:3306 -v /data/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.38 48e88061e80b9983d0d735f29a176efb810de32f0bd30e12893def798783b9d9 # mysql -uroot -p123456 -h172.31.6.201 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> |
删除容器:
1 2 3 4 5 | 创建容器的时候指定参数会删除 /var/lib/docker/containers/ 的容器数据目录,但是不会删除数据卷的内容,如下: # docker rm -f web3 # ls /data/testapp/index.html /data/testapp/index .html #挂载的数据卷不会被删除 |
数据卷的特点及使用:
数据卷是宿主机的目录或者文件,并且可以在多个容器之间共同使用;
在宿主机对数据卷更改数据后会在所有容器里面会立即更新;
数据卷的数据可以持久保存,即使删除使用使用该容器卷的容器也不影响;
在容器里面的写入数据不会影响到镜像本身。
数据卷使用场景:
容器数据持久化(mysql数据、nginx日志等类型);
静态web页面挂载;
应用配置文件挂载;
多容器间的目录或文件共享。
数据卷容器:
数据卷容器功能是可以让数据在多个docker容器之间共享,即先要创建一个后台运行的A容器作为Server,之后创建的B容器、C容器等都可以同时访问A容器的内容,因此数据卷容器用于为其它容器提供卷的挂载继承服务,数据卷为其它容器提供数据读写服务, A容器称为server端、其它容器成为client端:
1 2 3 4 5 6 7 8 9 | // 卷容器Server: # docker run -d --name volume-server -v /data/testapp:/usr/share/nginx/html/testapp -v /data/nginx/conf/nginx .conf: /etc/nginx/nginx .conf:ro registry.cn-hangzhou.aliyuncs.com /zhangshijie/pause :3.8 // client1: # docker run -d --name web1 --volumes-from volume-server -p80:80 nginx:1.20.2 // client2: # docker run -d --name web2 --volumes-from volume-server -p81:80 nginx:1.20.2 |
特点:
适用于同类服务的数据卷共享;
client会继承卷server挂载和挂载权限;
停止卷server,也不影响已经运行的容器、甚至也不影响新建容器;
删除卷server,不影响已经运行的容器,但是不能新建容器。
Docker网络:
Docker服务安装完成之后,默认在每个宿主机会生成一个名称为docker0的网卡其IP地址都是172.17.0.1/16,并且会生成三种不同类型的网络:
1 2 3 4 5 6 7 8 9 | root@docker-server1:~ # ifconfig docker0 docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 inet6 fe80::42:d9ff:fe20:16d9 prefixlen 64 scopeid 0x20<link> ether 02:42:d9:20:16:d9 txqueuelen 0 (Ethernet) RX packets 1920 bytes 101778 (101.7 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 2203 bytes 16910412 (16.9 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions |
另外会额外创建三个默认网络,用于不同的使用场景:
1 2 3 4 5 | root@docker-server1:~ # docker network list NETWORK ID NAME DRIVER SCOPE 438a9be14ef8 bridge bridge local #桥接网络,默认使用的模式,容器基于SNAT进行地址转换访问宿主机以外的环境; 4c026356e4d1 host host local #host网络,直接使用宿主机的网络( 不创建net namespace),性能最好,但是容器端口不能冲突; 8d70da095b8e none null local #空网络,容器不会分配有效的IP地址(只有一个回环网卡用于内部通信),用于离线数据处理等场景。 |
bridge模式:
docker的默认模式即不指定任何模式就是bridge模式,也是目前使用比较多的网络模式,此模式创建的容器会为每一个容器分配自己的网络IP等信息,并将容器连接到一个虚拟网桥与外界通信。
1 2 | # docker network inspect bridge # docker run -it -d --name nginx-web1-bridge-test-container -p 80:80 --net=bridge nginx:1.2 |
host模式:
host模式就是直接使用宿主机的IP地址,创建的容器如果指定了使用host模式,那么新创建的容器不会创建自己的虚拟网卡,而是直接使用宿主机的网卡和IP地址,因此在容器里面查看到的IP信息就是宿主机的信息,访问容器的时候直接使用宿主机IP+容器端口即可,而且某一个端口一旦被其中一个容器占用那么其它容器就不能再监听此端口,不过容器的其它资源比如容器的文件系统、容器系统进程等还是基于namespace相互隔离。
此模式的网络性能最高,但是各容器之间端口不能相同,适用于运行容器端口比较固定的业务。
1 2 3 4 5 | # docker run -it -d --name nginx-web1-host-test-container -p 80:80 --net=host nginx:1.20.2 root@docker-server1:~ # docker exec -it 0092ca554f bash root@docker-server1:/ # apt update && apt install net-tools root@docker-server1:/ # ifconfig root@docker-server1:/ # netstat -tanlp |
none模式:
none模式就是无IP模式,在使用none模式后,docker容器不会进行任何网络配置,其没有网卡、没有IP也没有路由,因此默认无法与外界通信,需要手动添加网卡配置IP等,所以极少使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 | # docker run -it -d --name nginx-web1-none-test-container -p 80:80 --net=none busybox sleep 10000000 # docker exec -it 3c54e90c209a sh / # ifconfig lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) / # ping 223.6.6.6 PING 223.6.6.6 (223.6.6.6): 56 data bytes ping : sendto: Network is unreachable |
container模式:
Container模式即容器模式,使用参数--net=container:目标容器名称/ID指定,使用此模式创建的容器需指定和一个已经存在的容器共享一个网络namespace,而不会创建独立的namespace,即新创建的容器不会创建自己的网卡也不会配置自己的IP,而是和一个已经存在的被指定的目标容器共享对方的IP和端口范围,因此这个容器的端口不能和被指定的目标容器端口冲突,除了网络之外的文件系统、用户信息、进程信息等仍然保持相互隔离,两个容器的进程可以通过loopback网卡及容器IP进行通信。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # docker run -it -d --name nginx-container -p 80:80 --net=bridge nginx:1.22.0-alpine # docker run -it -d --name php-container --net=container:nginx-container php:7.4.30-fpm-alpine // 分别进入容器验证IP地址信息——验证net namesapce: # ls /var/run/netns/netns # ln -s /var/run/docker/netns/* /var/run/netns/ # ip netns list default # ip netns exec 10844980eee7 ip a 72: eth0@if73: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link /ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netns default inet 172.17.0.2 /16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever |
第一课总结:
容器基于namespace实现资源隔离;
容器基于cgroup实现资源限制;
kubernetes环境中由kubelet接受指令通过CRI等标准调用运行时实现容器的生命周期管理;
Docker的存储引擎推荐使用overlay2;
Docker中的重要数据通过-v选项挂载数据卷实现持久化;
Docker的网络有多种模式,但在单机docker环境下主要使用bridge模式。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律