当前位置: 首页 > news >正文

Docker-镜像存储机制-网络

一、Docker镜像制作

1.制作前端应用镜像

配置文件:

[root@localhost front-dockerfile]# vi Dockerfile FROM nginx:1.22.1
COPY /dist  /usr/local/web/
COPY nginx.conf /etc/nginx/nginx.conf
CMD ["nginx", "-g", "daemon off;"][root@localhost front-dockerfile]# vi nginx.conf user  nginx;
worker_processes  auto;
error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;
events {worker_connections  1024;
}
http {include       /etc/nginx/mime.types;default_type  application/octet-stream;log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log  /var/log/nginx/access.log  main;sendfile        on;keepalive_timeout  65;server {listen       80;server_name  localhost;real_ip_header X-Real-IP;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;location / {root   /usr/local/web;index  index.html;try_files $uri $uri/ /index.html;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   /usr/share/nginx/html;}}
}

前端项目打包后会生成 dist 目录,一起打包到镜像里,目录结构如下:

[root@localhost front-dockerfile]# ll
总用量 8
drwxr-xr-x 7 root root 147  2月 21  2025 dist
-rw-r--r-- 1 root root 120  2月 24  2025 Dockerfile
-rw-r--r-- 1 root root 933  2月 21  2025 nginx.conf

制作镜像:

[root@localhost front-dockerfile]# docker build -t front-app:v1 .
[root@localhost front-dockerfile]# docker run -d front-app:v1

2.构建上下文

  • 当运行 docker build 命令时,当前工作目录被称为构建上下文——build context

  • docker build 默认查找当前目录的 Dockerfile 作为构建输入,也可以通过 -f 指定Dockerfile

    • docker build -f ./Dockerfile

  • 当 docker build 运行时,首先会构建上下文传输给 docker daemon,把没用的文件包含在构建上下文时,会导致传输时间长,构建需要的资源多,构建出的镜像大等问题。

    • 试着找一下包含较多文件的目录试一下区别

    • 可以通过 .dockerignore 文件从编译上下文排除文件

  • 需要确认构建上下文清晰,建议创建一个单独的目录放置 Dockerfile,并在目录中运行 docker build

注:随着版本的更新换代,目前来看构建上下文已经不怎么会影响到构建速度了,用处不大

3..dockerignore  文件

  • 在使用 Docker 构建镜像时,我们通常会将项目的文件和文件夹复制到镜像中
  • 然而,并不是所有的文件和文件夹都需要被复制进镜像中
  • 有时我们需要排除一些不需要的文件夹或文件,这就是使用 .dockerignore 文件的作用

例:如果我们只想将 app 文件夹复制到镜像中,而不包含 config 和 tests 文件夹,我们可以在 .dockerignore 文件中添加以下内容:

config/​
tests/

.dockerignore 文件的规则

  • #:用于添加注释。以 # 开头的行将被忽略

  • /path/to/folder:排除指定的文件夹以及其内容

  • /path/to/file:排除指定的文件

  • !:用于取反。如果文件夹被排除了,但是又想包含此文件夹内的某个文件,可以在前面加上 !

# 忽略所有 .txt 文件
*.txt# 忽略所有文件夹和子文件夹中的 .log 文件
**/*.log# 排除 .git 文件夹及其内容
.git/# 排除 node_modules 文件夹及其内容
node_modules/# 但是包含 node_modules/myapp 文件夹及其内容
!node_modules/myapp/

4.多平台镜像介绍

(1)查看本地镜像支持的架构

[root@localhost ~]# docker inspect  nginx:1.22.1 | grep -i arch"Architecture": "amd64",

(2)查看远端仓库中的镜像支持的架构

[root@localhost ~]#docker manifest inspect nginx:1.22.1  | grep architecture"architecture": "amd64","architecture": "arm","architecture": "arm","architecture": "arm64","architecture": "386","architecture": "mips64le","architecture": "ppc64le","architecture": "s390x",

二、镜像存储机制

1.Docker镜像简介

  • Docker镜像是一个只读的Docker容器模板,含有启动Docker容器所需的文件系统结构及其内容
  • rootfs是Docker容器在启动时内部进程可见的文件系统,即Docker容器的根目录
  • 在Docker架构中,当Docker daemon为Docker容器挂载rootfs时,沿用了Linux内核启动时的方法,即将rootfs设为只读模式

  • 在挂载完毕之后,利用联合挂载(union mount)技术在已有只读rootfs上再挂载一个读写层

2.OverlayFS 存储原理

OverlayFS(解决镜像分层问题) 结构分为三个层: LowerDir、Upperdir、MergedDir:

  • LowerDir (只读层) 只读的 image layer,其实就是 rootfs, 包含镜像中的所有层

  • UpperDir (读写层) upperdir 则是在 lowerdir 之上的一层, 为读写层。容器在启动的时候会创建, 所有对容器的修改, 都是在这层。 比如容器启动写入的日志文件,或者是应用程序写入的临时文件。

  • MergedDir (合并层) merged 目录是容器的挂载点,在用户视角能够看到的所有文件,都是从这层展示的。

  • WorkDir (工作目录)workdir 是 OverlayFS 内部用于处理写入操作的 临时目录

例:查看当前启动容器的挂载点——

# 查看当前启动容器
​​​​[root@localhost ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                   CREATED          STATUS          PORTS     NAMES
79518939ce04   front-app:v1   "/docker-entrypoint.…"   51 minutes ago   Up 51 minutes   80/tcp    keen_ellis# 查看容器挂载点merged
[root@localhost ~]# df -h
文件系统        容量  已用  可用 已用% 挂载点
devtmpfs        4.0M     0  4.0M    0% /dev
tmpfs           1.8G     0  1.8G    0% /dev/shm
tmpfs           725M  9.1M  716M    2% /run
/dev/nvme0n1p3   16G  7.3G  8.8G   46% /
/dev/nvme0n1p1  2.0G  278M  1.7G   15% /boot
tmpfs           363M     0  363M    0% /run/user/0
overlay          16G  7.3G  8.8G   46% /var/lib/docker/overlay2/6a2005234d448560462ac6b4c12838a50181e0dbb2074ab4c44c2b6d72f480c4/merged# 查看挂载点下的文件
[root@localhost ~]# ls /var/lib/docker/overlay2/6a2005234d448560462ac6b4c12838a50181e0dbb2074ab4c44c2b6d72f480c4/merged
bin  boot  dev  docker-entrypoint.d  docker-entrypoint.sh  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

3.OverlayFS 演示

(1)创建演示目录和文件

# 创建需要的目录和文件
[root@localhost ~]# cd /tmp/
[root@localhost tmp]# mkdir upper lower merged work
[root@localhost tmp]# echo "I'm from lower" > lower/in_lower.txt
[root@localhost tmp]# echo "I'm from upper" > upper/in_upper.txt
[root@localhost tmp]# echo "I'm from lower" > lower/in_both.txt
[root@localhost tmp]# echo "I'm from upper" > upper/in_both.txt# 挂载 overlay 文件系统 
[root@localhost tmp]# mount -t overlay overlay \-o lowerdir=/tmp/lower,upperdir=/tmp/upper,workdir=/tmp/work \/tmp/merged

(2)查看文件合并后的效果

[root@localhost tmp]# cat /tmp/merged/in_lower.txt 
I'm from lower
[root@localhost tmp]# cat /tmp/merged/in_upper.txt 
I'm from upper# upper 层会覆盖 lower 层的文件 
[root@localhost tmp]# cat /tmp/merged/in_both.txt 
I'm from upper

(3)创建一个新文件

[root@localhost tmp]# echo 'new file' > merged/new_file
[root@localhost tmp]# ls -l */new_file
-rw-r--r-- 1 root root 9 11月 10 20:50 merged/new_file
-rw-r--r-- 1 root root 9 11月 10 20:50 upper/new_file

(4)删除一个文件

# 删除 merged 层的文件  in_both.txt
[root@localhost tmp]# rm merged/in_both.txt# 在 merged 层找不到文件  in_both.txt
# 在 upper 层还可以看到 in_both.txt, 但文件类型是 c (character )
[root@localhost tmp]# ls -l merged/in_both.txt lower/in_both.txt upper/in_both.txt
ls: 无法访问 'merged/in_both.txt': 没有那个文件或目录
-rw-r--r-- 1 root root   15 11月 10 20:43 lower/in_both.txt
c--------- 2 root root 0, 0 11月 10 20:51 upper/in_both.txt

三、分析镜像存储结构

1.下载redis6 的镜像

[root@localhost ~]# docker pull redis:6

2.查看镜像存储结构

[root@localhost ~]# docker inspect redis:6"GraphDriver": {"Data": {"LowerDir": "/var/lib/docker/overlay2/cf1e7eb869d44c4f60b77b007460b016e0d9e034aea3101595b84c24fdb01e76/diff:/var/lib/docker/overlay2/8a76b643063fb5e48a14c1fd78a731523e56ec6c68db4eb5d8a84db543a8757c/diff:/var/lib/docker/overlay2/dc23466c82e922705d9b6bebf2aed326e76785371657aace2cfdd3f6fb438c7b/diff:/var/lib/docker/overlay2/fed6af7dd89ae7ee82dcee6e7f8f8a6fe440b44408c77055da665692f1e1c236/diff:/var/lib/docker/overlay2/5eb42b1b2cb046a868b0d4784e25cda914902ad06fef3d5fb56e3659d25f21d2/diff:/var/lib/docker/overlay2/395e80505a884735be5f5c57d8f0c34959f79d0a27b0aadfb2a8ab185baf2568/diff:/var/lib/docker/overlay2/c0144e4a78f56a21ba47632b6579b8f825665bee26db834ccdab11f82389408c/diff","MergedDir": "/var/lib/docker/overlay2/fa26139f3606288d5b8ff30100ca20175e8bc61225962d6d945ed5044f89f489/merged","UpperDir": "/var/lib/docker/overlay2/fa26139f3606288d5b8ff30100ca20175e8bc61225962d6d945ed5044f89f489/diff","WorkDir": "/var/lib/docker/overlay2/fa26139f3606288d5b8ff30100ca20175e8bc61225962d6d945ed5044f89f489/work"},"Name": "overlay2"},# Docker 镜像在磁盘上解压后的目录:
[root@localhost ~]# ll /var/lib/docker/overlay2/

3.运行中容器的存储结构

# 启动容器
[root@localhost ~]# docker run -d --name redis6 redis:6
199ed36330c133905bb2d7819519058f78a4c963093ce059323a1ff5f7bf42dd
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                   CREATED          STATUS          PORTS      NAMES
199ed36330c1   redis:6        "docker-entrypoint.s…"   11 seconds ago   Up 11 seconds   6379/tcp   redis6
[root@localhost ~]# docker inspect redis6"GraphDriver": {"Data": {"LowerDir": "/var/lib/docker/overlay2/42414edf9ad16c1ee14e280b82ab21bd79c1115d8156e8218b863801c133ef67-init/diff:/var/lib/docker/overlay2/fa26139f3606288d5b8ff30100ca20175e8bc61225962d6d945ed5044f89f489/diff:/var/lib/docker/overlay2/cf1e7eb869d44c4f60b77b007460b016e0d9e034aea3101595b84c24fdb01e76/diff:/var/lib/docker/overlay2/8a76b643063fb5e48a14c1fd78a731523e56ec6c68db4eb5d8a84db543a8757c/diff:/var/lib/docker/overlay2/dc23466c82e922705d9b6bebf2aed326e76785371657aace2cfdd3f6fb438c7b/diff:/var/lib/docker/overlay2/fed6af7dd89ae7ee82dcee6e7f8f8a6fe440b44408c77055da665692f1e1c236/diff:/var/lib/docker/overlay2/5eb42b1b2cb046a868b0d4784e25cda914902ad06fef3d5fb56e3659d25f21d2/diff:/var/lib/docker/overlay2/395e80505a884735be5f5c57d8f0c34959f79d0a27b0aadfb2a8ab185baf2568/diff:/var/lib/docker/overlay2/c0144e4a78f56a21ba47632b6579b8f825665bee26db834ccdab11f82389408c/diff","MergedDir": "/var/lib/docker/overlay2/42414edf9ad16c1ee14e280b82ab21bd79c1115d8156e8218b863801c133ef67/merged","UpperDir": "/var/lib/docker/overlay2/42414edf9ad16c1ee14e280b82ab21bd79c1115d8156e8218b863801c133ef67/diff","WorkDir": "/var/lib/docker/overlay2/42414edf9ad16c1ee14e280b82ab21bd79c1115d8156e8218b863801c133ef67/work"},"Name": "overlay2"},

4.向UpperDir 层写入文件

# 写入upper.txt文件
[root@localhost ~]# touch /var/lib/docker/overlay2/42414edf9ad16c1ee14e280b82ab21bd79c1115d8156e8218b863801c133ef67/diff/upper.txt

注:UpperDir层只能看到修改的文件,加上LowerDir层才是完整的MergedDir层;若想要改LowerDir层的文件,就会自动复制一个修改后的文件,存储在UpperDir层,覆盖掉原文件

5.Manifest.json文件

注:Manifest.json文件是一个镜像基础信息描述文件

[root@localhost ~]# docker save redis:6 -o redis6.tar
[root@localhost ~]# mkdir redis
[root@localhost ~]# tar -xf redis6.tar -C redis
[root@localhost ~]# cd redis
[root@localhost redis]# ll
总用量 16
drwxr-xr-x 3 root root   20 11月  4 08:27 blobs
-rw-r--r-- 1 root root  352 11月 10 21:19 index.json
-rw-r--r-- 1 root root 2589  1月  1  1970 manifest.json    #存放镜像中层的数据
-rw-r--r-- 1 root root   31  1月  1  1970 oci-layout
-rw-r--r-- 1 root root   83  1月  1  1970 repositories

查看manifest.json文件,找一个网站格式化变好看一点

注:Layers标签中的就是镜像每层所独有的层ID,在下载镜像的时候,仓库和本地的层ID就会相互比较,如果有的话就显示已存在,不会再次下载了

四、Docker网络

1.Docker 网络启动过程

  • Docker 服务启动时会首先在主机上自动创建一个 docker0 的虚拟网桥,网桥可以理解为一个二层交换机,负责挂载其上的接口之间进行包转发
  • Docker 随机分配一个本地未占用的私有网段中的一个地址给 docker0 接口,默认是 172.17.0.0/16 网段。此后启动的容器会自动分配一个该网段的地址。
  • 当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 互联接口。当向任一个接口发送包时,另外一个接口自动收到相同的包。
  • 互联接口的一端位于容器内,即 eth0;另一端在本地并被挂载到 docker0 网桥,名称以veth 开头(例如 vethae12ch)。
  • 通过这种方式,主机可以与容器通信,容器之间也可以相互通信。如此一来,Docker 就创建了在主机和所有容器之间一个虚拟共享网络。

注:172.17.0.1作为链接到网桥上的所有容器的网关地址,在宿主机上也能查看到

2.查看网桥

[root@localhost ~]# dnf -y install bridge-utils
[root@localhost ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.024298a9901e	no		veth496a9c6vetha0016ca
# 有两个接口,表面该网桥已经连接了两个启动的容器
# 容器内接口 eth0@if11,宿主机上对应 ID 为 11 的接口,这个接口在宿主机上可以看到
[root@2944dfe3ba3f data]# ip ad
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope host valid_lft forever preferred_lft forever
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0valid_lft forever preferred_lft forever

3.Docker网络连通性

(1)容器访问外部

注:默认可以通信容器与虚拟机类似,有自己的ip和dns地址,可以访问外网容器本身的dns地址继承自宿主机

注:容器中的地址是一个私有地址,想要访问外网需要做地址转换SNAT,在容器访问外网的时候,Docker会自动调用iptables实现SNAT(同时会损耗网络性能)

(2)外部访问容器

  • 容器允许外部访问,可以在docker [container] run 时候通过 -p 或 -P 参数来启用,将容器的端口映射到宿主机上
  • 不管用哪种办法,其实也是在本地的 iptable 的 nat 表中添加相应的规则,将访问外部IP地址的包进行目标地址DNAT,将目标地址修改为容器的 IP 地址

例:以一个开放 80 端口的 Nginx 容器为例,使用 -P 时,会自动映射本地 32768~65535 范围内的随机端口到容器的 80 端口(不符合我们的使用习惯,一般不用)

查看日志【docker logs -f】,此时外部访问就可以正常访问到容器

再次查看防火墙规则

(3)容器访问容器

  • 容器默认都连接在 Docker0 网桥上,都可以互相访问,相当连于在一台二层交换机上。
  • 但是容器的 IP 地址是动态变化的,如果两个应用之间要互相访问就无法通过 IP 地址互相通信,Docker 提供两种方案来解决
  1. --link 传统方式,目前 Docker 官网已不建议使用
  2. user-defined networks 用户定义网络

如容器172.17.0.2访问容器172.17.0.4

注:这里存在一个问题,容器通过ip访问,但容器的ip不是固定的;所以我们通常需要想办法屏蔽掉ip地址,通过域名来解决,容器这里用的是容器名

在启动容器时定义容器名,在hosts文件中添加转换关系(一般情况下):

例:

--link方式:启动两个容器,分别部署wordpress项目 和mysql

下载镜像:

docker pull registry.cn-beijing.aliyuncs.com/xxhf/wordpress:php7.4​
docker tag registry.cn-beijing.aliyuncs.com/xxhf/wordpress:php7.4 wordpress:php7.4​
​
docker pull registry.cn-beijing.aliyuncs.com/xxhf/mysql:8.0​
docker tag registry.cn-beijing.aliyuncs.com/xxhf/mysql:8.0 mysql:8.0

运行 mysql 容器:

[root@docker ~]# docker run -d --name db_wordpress --restart always \​
-e MYSQL_ROOT_PASSWORD=wordpress \​
-e MYSQL_DATABASE=db_wordpress \​
-e MYSQL_USER=wordpress_rw  \​
-e MYSQL_PASSWORD=123456 \​
-p 3306:3306 mysql:8.0​
​
[root@docker ~]# docker ps ​
CONTAINER ID   IMAGE       COMMAND                  CREATED              STATUS              PORTS                                                  NAMES​
ded235356e6f   mysql:5.7   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   db_wordpress

验证数据库正常运行:

[root@docker ~]# docker run -d --link db_wordpress -it mysql-client -uroot -pwordpress -hdb_wordpress​
​
[root@docker ~]# docker attach 3c5e8d2f9198​
MySQL [(none)]> ​
MySQL [(none)]> show databases;​
+--------------------+​
| Database           |​
+--------------------+​
| information_schema |​
| db_wordpress       |​
| mysql              |​
| performance_schema |​
| sys                |​
+--------------------+​
5 rows in set (0.001 sec)​
​
MySQL [(none)]> use db_wordpress​
Database changed​
MySQL [db_wordpress]> show tables; ​
Empty set (0.000 sec)​
​

运行 WordPress 容器:

[root@docker ~]# docker run -d --name wordpress --restart always --link db_wordpress \
-e WORDPRESS_DB_HOST=db_wordpress:3306 \
-e WORDPRESS_DB_USER=wordpress_rw \
-e WORDPRESS_DB_PASSWORD=123456 \
-e WORDPRESS_DB_NAME=db_wordpress \
-p  80:80  wordpress:php7.4

测试:通过浏览器访问装有wordpress项目的容器的宿主机ip,测试项目能否正常运行


user-defined networks:(优先使用)

创建一个用户定义网络:

[root@docker ~]# docker network create wp-net 
e4e3d1ee70620fec8e4a5a22f9b0db737faaf5f6e8d67a2958f98f0fc86af975
[root@docker ~]# 
[root@docker ~]# docker network  ls 
NETWORK ID     NAME      DRIVER    SCOPE
0cc88dcd390d   bridge    bridge    local
385ab96da9ee   host      host      local
43634758fc70   none      null      local
e4e3d1ee7062   wp-net    bridge    local

注:创建网络的同时也会创建一个网桥

重新运行 MySQL 和 WordPress 容器:

docker run -d --name db_wordpress --restart always \​
--network wp-net \​
-e MYSQL_ROOT_PASSWORD=wordpress \​
-e MYSQL_DATABASE=db_wordpress \​
-e MYSQL_USER=wordpress_rw  \​
-e MYSQL_PASSWORD=123456 \​
-p 3306:3306 mysql:8.0​
​
docker run -d --name wordpress --restart always --network wp-net  \​
-e WORDPRESS_DB_HOST=db_wordpress:3306 \​
-e WORDPRESS_DB_USER=root \​
-e WORDPRESS_DB_PASSWORD=wordpress \​
-e WORDPRESS_DB_NAME=db_wordpress \​
-p  80:80  wordpress:php7.4

自定义网桥可以自动实现容器间的DNS解析,没有修改 /etc/hosts 文件:

[root@docker ~]# docker exec  wordpress cat /etc/hosts
127.0.0.1        localhost
::1        localhost ip6-localhost ip6-loopback
fe00::0        ip6-localnet
ff00::0        ip6-mcastprefix
ff02::1        ip6-allnodes
ff02::2        ip6-allrouters
172.18.0.3        24e49d0f2225

注:此时两个容器之间同样可以互通

五、Docker网络模式

注:常见的有三种网络驱动模式:host、bridge、none

1.host 模式

  • 如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace
  • 而是和宿主机共用一个Network Namespace,容器与宿主机不做网络隔离
  • 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
  • 容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的

# 运行一个使用 host 网络模式的容器
[root@localhost ~]# docker run -d --net=host nginx:1.22.1 
778a3ab83f1db6fbebaba17123188b171df95175f1ffd4b9518168b50791c026[root@localhost ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                   CREATED         STATUS         PORTS     NAMES
778a3ab83f1d   nginx:1.22.1   "/docker-entrypoint.…"   2 seconds ago   Up 2 seconds             sad_taussig# 容器详情中没有 IP 地址
[root@localhost ~]# docker inspect 778a3ab83f1d | grep -i ipaddr"SecondaryIPAddresses": null,"IPAddress": "","IPAddress": "",# 宿主机可以看到 80 端口的监听 
[root@localhost ~]# netstat -nltp | grep nginx
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1504/nginx: master  
tcp6       0      0 :::80                   :::*                    LISTEN      1504/nginx: master# 宿主机可以访问 nginx 服务 
[root@localhost ~]# curl 127.0.0.1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
.................................

2.bridge 模式

  • Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口)。
  • Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信
  • --network bridge:设置容器工作在bridge模式下,即将容器接口添加至 docker0 网桥
# docker0 网桥 
[root@localhost ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02420c888553	no		# docker0 接口
[root@localhost ~]# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255ether 02:42:0c:88:85:53  txqueuelen 0  (Ethernet)RX packets 0  bytes 0 (0.0 B)RX errors 0  dropped 0  overruns 0  frame 0TX packets 0  bytes 0 (0.0 B)TX errors 0  dropped 2 overruns 0  carrier 0  collisions 0

配置 docker0 网络配置:编辑 /etc/docker/daemon.json

{"registry-mirrors": ["https://docker.1ms.run","https://docker.mybacc.com","https://docker.m.daocloud.io","https://bkr5wo56.mirror.aliyuncs.com","https://chdp0mbf.mirror.aliyuncs.com"],"insecure-registries": ["reg.xxhf.cc","172.17.0.1:5000","192.168.5.100:5000"],"bip": "192.168.1.1/24","fixed-cidr": "192.168.1.0/24"
}[root@localhost ~]# systemctl restart docker

观察Docker 0 ip地址

[root@localhost ~]# ifconfig 
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500inet 192.168.1.1  netmask 255.255.255.0  broadcast 192.168.1.255ether 02:42:0c:88:85:53  txqueuelen 0  (Ethernet)RX packets 0  bytes 0 (0.0 B)RX errors 0  dropped 0  overruns 0  frame 0TX packets 0  bytes 0 (0.0 B)TX errors 0  dropped 2 overruns 0  carrier 0  collisions 0

启动容器查看容器ip地址

[root@localhost ~]# docker run -d nginx:1.22.1
7dc5110927b48ff9b5d12be008f6bfc68c08e75a1d59408bf0da3cf9c8cdfcd7# 默认使用bridge模式
[root@localhost ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02420c888553	no		veth81e66ce# ip地址和网段变为192.168.1.2
[root@localhost ~]# docker inspect 7dc5110927b4 | grep -i ipaddr"SecondaryIPAddresses": null,"IPAddress": "192.168.1.2","IPAddress": "192.168.1.2",

3.none 模式

  • 此模式下容器不参与网络通信,运行于此类容器中的进程仅能访问本地环回接口,仅适用于进程无须网络通信的场景中,例如备份,进程诊断及各种离线任务等
  • --network=none:设置模式容器工作在none模式下
# 使用 none 网络模式,容器内只有 loopback 接口
[root@localhost ~]# docker run  -it --rm --network=none busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope host valid_lft forever preferred_lft forever

六、Docker命名空间

  • Docker 是借助 Linux 内核技术 Namespace 来实现隔离的, Linux Namespaces 机制提供一种资源隔离方案
  • PID,IPC,Network 等系统资源不再是全局性的, 而是属于某个特定的 Namespace
  • 每个 namespace 下的资源对于其他 namespace 下的资源都是透明, 不可见的。 因此在操作系统层面上看, 就会出现多个相同 pid 的进程
  • 系统中可以同时存在多个进程号为 0,1,2 的进程, 由于属于不同的 namespace, 所以它们之间并不冲突,在用户层面上只能看到属于用户自己 namespace 下的资源

1.内核支持的 Namespace 类型

2.Namespace 常用操作

注:容器本身就是一个进程

(1)查看当前系统下的 namespace

[root@localhost ~]# lsnsNS TYPE   NPROCS   PID USER   COMMAND
4026531834 time      157     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 31
4026531835 cgroup    154     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 31
4026531836 pid       154     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 31
4026531837 user      157     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 31
4026531838 uts       151     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 31
4026531839 ipc       154     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 31
4026531840 net       154     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 31
4026531841 mnt       144     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 31
4026531862 mnt         1    32 root   kdevtmpfs
4026532496 mnt         1   512 root   /usr/lib/systemd/systemd-udevd
4026532497 uts         1   512 root   /usr/lib/systemd/systemd-udevd
4026532657 mnt         1   556 root   /sbin/auditd
4026532658 mnt         2   582 dbus   /usr/bin/dbus-broker-launch --scope system --audit
4026532659 mnt         1   599 chrony /usr/sbin/chronyd -F 2
4026532660 mnt         1   584 root   /usr/sbin/NetworkManager --no-daemon
4026532661 mnt         1   587 root   /usr/sbin/irqbalance --foreground
4026532662 mnt         1   588 root   /usr/lib/systemd/systemd-logind
4026532664 uts         1   588 root   /usr/lib/systemd/systemd-logind
4026532665 uts         1   599 chrony /usr/sbin/chronyd -F 2
4026532695 mnt         3  2073 root   nginx: master process nginx -g daemon off;
4026532696 uts         3  2073 root   nginx: master process nginx -g daemon off;
4026532697 ipc         3  2073 root   nginx: master process nginx -g daemon off;
4026532698 pid         3  2073 root   nginx: master process nginx -g daemon off;
4026532699 cgroup      3  2073 root   nginx: master process nginx -g daemon off;
4026532700 net         3  2073 root   nginx: master process nginx -g daemon off;
4026532784 mnt         1   660 root   /usr/sbin/rsyslogd -n

(2)查看某个进程的 namespace

注:目录中的1是进程id;proc目录是内存的映射,再查看当前父进程下的子进程,发现namespace号都是相同的,说明这两个进程处于相同命名空间,没有做隔离

(3)进入某个 namespace 执行命令

# 进入系统主进程下执行 ip addr 命令,查看到的结果跟在系统 bash下 执行 ip addr 结果一样
[root@localhost ~]# nsenter -t 1 -n ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope host valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000link/ether 00:0c:29:0b:45:32 brd ff:ff:ff:ff:ff:ffaltname enp3s0inet 192.168.5.100/24 brd 192.168.5.255 scope global noprefixroute ens160valid_lft forever preferred_lft foreverinet6 fe80::20c:29ff:fe0b:4532/64 scope link noprefixroute valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:0c:88:85:53 brd ff:ff:ff:ff:ff:ffinet 192.168.1.1/24 brd 192.168.1.255 scope global docker0valid_lft forever preferred_lft foreverinet6 fe80::42:cff:fe88:8553/64 scope link valid_lft forever preferred_lft forever
5: veth81e66ce@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether be:78:fe:3e:e0:57 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet6 fe80::bc78:feff:fe3e:e057/64 scope link valid_lft forever preferred_lft forever

(4)运行一个容器,在容器的 namespace 下执行命令

# 运行一个容器
[root@localhost ~]# docker run -d nginx:1.22.1
abb42feaac9f1112c0ea26a0ec9dfc381afd4cfda4688e02ba312b3d0091540c
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                   CREATED          STATUS          PORTS     NAMES
abb42feaac9f   nginx:1.22.1   "/docker-entrypoint.…"   7 seconds ago    Up 6 seconds    80/tcp    crazy_mcclintock# 查看容器的进程号
[root@localhost ~]# docker inspect  abb42feaac9f | grep -i pid"Pid": 2301,"PidMode": "","PidsLimit": null,# 在容器的 namespace 中执行 命令
[root@localhost ~]# nsenter  -t 2301 -n ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope host valid_lft forever preferred_lft forever
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:c0:a8:01:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 192.168.1.3/24 brd 192.168.1.255 scope global eth0valid_lft forever preferred_lft forever# 查询容器的 ip 地址,可以看到跟在容器的命名空间中执行产生的结果是一样的
[root@localhost ~]# docker inspect  abb42feaac9f | grep -i ipaddr"SecondaryIPAddresses": null,"IPAddress": "192.168.1.3","IPAddress": "192.168.1.3",

(5)每个容器都在单独的 Namespace 里

[root@localhost ~]# docker run --name c1 -d nginx:1.22.1
2be8b46708e2e0e59724e44c4a24615b9be953a041b68431177ee73b0b40135d
[root@localhost ~]# docker run --name c2 -d nginx:1.22.1
4130b06156b79b50c5881fcb487424d2b99a77e7f8f5211324aefc2369a027cd
[root@localhost ~]# docker inspect c1 | grep -i pid"Pid": 2438,"PidMode": "","PidsLimit": null,
[root@localhost ~]# docker inspect c2 | grep -i pid"Pid": 2544,"PidMode": "","PidsLimit": null,
[root@localhost ~]# ll /proc/2438/ns
总用量 0
lrwxrwxrwx 1 root root 0 11月 11 19:46 cgroup -> 'cgroup:[4026532915]' #与宿主机隔离
lrwxrwxrwx 1 root root 0 11月 11 19:46 ipc -> 'ipc:[4026532913]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 mnt -> 'mnt:[4026532911]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 net -> 'net:[4026532916]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 pid -> 'pid:[4026532914]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 pid_for_children -> 'pid:[4026532914]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 time -> 'time:[4026531834]' #与宿主机不隔离
lrwxrwxrwx 1 root root 0 11月 11 19:46 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 user -> 'user:[4026531837]' #与宿主机不隔离
lrwxrwxrwx 1 root root 0 11月 11 19:46 uts -> 'uts:[4026532912]'
[root@localhost ~]# ll /proc/2544/ns
总用量 0
lrwxrwxrwx 1 root root 0 11月 11 19:46 cgroup -> 'cgroup:[4026532977]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 ipc -> 'ipc:[4026532975]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 mnt -> 'mnt:[4026532973]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 net -> 'net:[4026532978]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 pid -> 'pid:[4026532976]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 pid_for_children -> 'pid:[4026532976]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 time -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 11月 11 19:46 uts -> 'uts:[4026532974]'

注:Docker 默认没有启用 user namespace;另外也可以发现,容器与宿主机的time和user都说不隔离的,和宿主机的namespace相同,但容器本身和宿主机是隔离的

(6)运行一个容器,和宿主机的网络不做隔离

[root@localhost ~]# docker run --network=host --name=nginx-c1 -d nginx:1.22.1
d3a28508aed120a89e44e6be7bf00c5c4e63a1c03df5f57bc185cd257d45df53
[root@localhost ~]# docker inspect nginx-c1 | grep -i pid"Pid": 2673,"PidMode": "","PidsLimit": null,
[root@localhost ~]# ll /proc/2673/ns
总用量 0
lrwxrwxrwx 1 root root 0 11月 11 20:03 cgroup -> 'cgroup:[4026533037]'
lrwxrwxrwx 1 root root 0 11月 11 20:03 ipc -> 'ipc:[4026533035]'
lrwxrwxrwx 1 root root 0 11月 11 20:02 mnt -> 'mnt:[4026533033]'
lrwxrwxrwx 1 root root 0 11月 11 20:03 net -> 'net:[4026531840]'
lrwxrwxrwx 1 root root 0 11月 11 20:03 pid -> 'pid:[4026533036]'
lrwxrwxrwx 1 root root 0 11月 11 20:03 pid_for_children -> 'pid:[4026533036]'
lrwxrwxrwx 1 root root 0 11月 11 20:03 time -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 11月 11 20:03 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 11月 11 20:03 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 11月 11 20:03 uts -> 'uts:[4026533034]'

同宿主机的namespace做比对,此时容器和宿主机的网络不做隔离:

3.网络 Namespace

(1)使用 ip netns 命令

# 创建一个名为 nstest 的 network namespace
[root@localhost ~]# ip netns add nstest# 列出系统已存在的 network namespace 
[root@localhost ~]# ip netns list
nstest
[root@localhost ~]# ip netns list
nstest
[root@localhost ~]# ls -al /var/run/netns/
总用量 0
drwxr-xr-x  2 root root  60 11月 11 20:09 .
drwxr-xr-x 29 root root 820 11月 11 20:09 ..
-r--r--r--  1 root root   0 11月 11 20:09 nstest# 在 network namespace 中执行命令
[root@localhost ~]# ip netns  exec nstest ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00# 删除 network namespace: nstest 
[root@localhost ~]# ip netns delete nstest
[root@localhost ~]# ip netns  exec nstest ip addr
Cannot open network namespace "nstest": No such file or directory

(2)启动none 模式容器

[root@localhost ~]# docker run --network=none -it busybox[root@localhost ~]# docker ps 
CONTAINER ID   IMAGE          COMMAND                   CREATED          STATUS          PORTS     NAMES
9de3d276e7f2   busybox        "sh"                      29 seconds ago   Up 28 seconds             elegant_montalcini[root@localhost ~]# docker exec 9de3d276e7f2 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope host valid_lft forever preferred_lft forever

(3)查看网络配置

# 方法一:获取容器进程ID
[root@localhost ~]# docker inspect  9de3d276e7f2 | grep -i pid"Pid": 2770,"PidMode": "","PidsLimit": null,# 方法二:获取容器进程ID
[root@localhost ~]# docker inspect  -f '{{.State.Pid}}' 9de3d276e7f2
2770[root@localhost ~]# nsenter  -t 2770 -n ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope host valid_lft forever preferred_lft forever

(4)创建一个自定义网络 net0

[root@localhost ~]#  docker network create -d bridge --subnet 172.100.0.0/16 net0
99d0bed960d85201d48f81f03f086b2890f69fab097a88717616b7e9dddf336b# 以上命令创建了一个名为 net0 的网桥,网络 ID 是 99d0bed960d8520...。该网络使用的是 bridge 模
式,网段是 172.100.0.0/16, 该网络的第一个IP地址 172.100.0.1 分配给了网桥,网桥的名字可以通过下面
命令查到[root@localhost ~]# ip a
12: br-99d0bed960d8: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:b3:ac:74:c9 brd ff:ff:ff:ff:ff:ffinet 172.100.0.1/16 brd 172.100.255.255 scope global br-99d0bed960d8valid_lft forever preferred_lft forever# 如果想查看网桥的详细信息,可以使用 inspect 命令
[root@localhost ~]# docker network inspect net0
[{"Name": "net0","Id": "99d0bed960d85201d48f81f03f086b2890f69fab097a88717616b7e9dddf336b","Created": "2025-11-11T20:33:27.746090575+08:00","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": {},"Config": [{"Subnet": "172.100.0.0/16"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {},"Options": {},"Labels": {}}
]

(5)为容器绑定 veth pair 网卡

[root@localhost ~]# mkdir -p /var/run/netns
[root@localhost ~]# PID=$(docker inspec​t  -f '{{.State.Pid}}' 9​​​​​​​​​​​​​de3d276e7f2)​​ 
IPADDR=172.100.0.2​ 
NETMASK=255.255.0.0​ 
GATEWAY=172.100.0.1
[root@localhost ~]# ln -s /proc/$PID/ns/net /var/run/netns/$PID
[root@localhost ~]# ip netns  ls
2770​ # 创建一对veth pair,vetha 和 vethb 
[root@localhost ~]# ip link add vetha type veth peer name vethb# 将 vetha 绑定到网桥
[root@localhost ~]# brctl addif br-99d0bed960d8 vetha# 启用 vetha
[root@localhost ~]# ip link set vetha up# vethb 放入指定的网络命名空间
[root@localhost ~]# ip link set vethb netns 2770# 在指定的命名空间中将 vethb 改名为 eth0 
[root@localhost ~]# nsenter -t 2770 -n ip link set dev vethb name eth0# 启用 eth0 
[root@localhost ~]# nsenter -t 2770 -n ip link set eth0 up# 为 eth0 添加 IP 地址
[root@localhost ~]# nsenter -t 2770 -n ip addr add 172.100.0.2/16 dev eth0# 添加默认网关
[root@localhost ~]# nsenter -t 2770 -n ip route add default via 172.100.0.1

(6)验证通信

/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope host valid_lft forever preferred_lft forever
13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue qlen 1000link/ether 72:6e:83:12:6f:28 brd ff:ff:ff:ff:ff:ffinet 172.100.0.2/16 scope global eth0valid_lft forever preferred_lft foreverinet6 fe80::706e:83ff:fe12:6f28/64 scope link valid_lft forever preferred_lft forever
/ # ping www.baidu.com
PING www.baidu.com (110.242.70.57): 56 data bytes
64 bytes from 110.242.70.57: seq=0 ttl=127 time=2.211 ms
64 bytes from 110.242.70.57: seq=1 ttl=127 time=2.187 ms
64 bytes from 110.242.70.57: seq=2 ttl=127 time=1.655 ms
64 bytes from 110.242.70.57: seq=3 ttl=127 time=2.814 ms
^C
--- www.baidu.com ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 1.655/2.216/2.814 ms

补充:

# 容器内
/ # ps -ef
PID   USER     TIME  COMMAND1 root      0:00 sh16 root      0:00 ps -ef#宿主机
[root@localhost ~]# ps -ef | grep 2770
root        2770    2749  0 20:14 pts/0    00:00:00 sh
root        3052    2796  0 20:52 pts/1    00:00:00 grep --color=auto 2770

注:2770只是宿主机中的一个普通进程,但在容器中就是1号进程,一旦宿主机中杀死2770进程,容器就会立刻关闭

http://www.dtcms.com/a/596330.html

相关文章:

  • 线性代数 - 从方程组到行列式
  • 景德镇做网站公司中国邮政做特产的网站
  • 【Linux】进程间通信(三)System V 共享内存完全指南:原理、系统调用与 C++ 封装实现
  • 记一次cssd无法启动故障处理
  • 开源 Objective-C IOS 应用开发(一)macOS 的使用
  • ElasticSearch详解(篇一)
  • flash网站价格网站推广的特点
  • 【C++ 面试题】内存对齐
  • busybox:启动阶段的静态 IP 配置过程
  • k8s 中遇到Calico CrashLoopBackOff 的解决方法
  • zookeeper单机版安装
  • 【Excel导入】读取WPS格式嵌入单元格内的图片
  • 福清建设银行网站网红营销的作用
  • 34节点配电网牛顿-拉夫逊潮流计算 + 分布式电源(DG)多场景分析的 MATLAB
  • 分布式专题——53 ElasticSearch高可用集群架构实战
  • 电子商务网站建设与设计网站常州建设
  • 学习编程好么 | 编程的好处与学习路径分析
  • 从中间件的历史来看移动App开发的未来
  • Faster-Whisper:更快更好的开源Asr模型
  • ubuntu部署whisper+speaker_large+qwen【gradio界面版】
  • 阿里云通过中国信通院首批安全可信中间件评估
  • 正点原子【第四期】Linux之驱动开发学习笔记-12.1 Linux 阻塞和非阻塞 IO 实验
  • 做网站fjfzwl门户wordpress主题下载
  • Elasticsearch的用法
  • LLMChain for Chat Models in LangChain
  • 【JAVA进阶】SpringBoot启动流程深度解析:从main方法到应用就绪的完整旅程
  • 昆明建设厅培训网站创意设计文案
  • 如何为虚拟机配置多渠道、可聚合、更智能的告警通知机制?
  • 分布式容器镜像自动同步系统 设计方案
  • 智联无界,术教相融:分布式医疗示教系统重构医疗教学新生态