Dockerfile构建镜像以及网络
目录
- 一、什么是 Dockerfile?
- 二、Dockerfile 构建过程
- 三、Dockerfile 指令选项
- 四、实战制作镜像并发布
- 4.1 注册 Docker Hub 账号
- 4.2 构建镜像
- 4.3 构建dockerfile
- 4.4 推送镜像至docker hub
- 五、Docker 网络
- 5.1 本机网络理解
- 5.2 Docker0-Docker 的虚拟网桥
- 5.3 清空本机docker环境
- 5.4 veth-pair 技术
- 5.4.1 理解 Docker 网络中的 veth-pair
- 5.4.2 Docker 容器网络模型
- 5.5 docker网络模式
- 5.5.1 Docker 网络模式
- 5.5.2 使用默认 bridge 网络启动容器
- 5.5.3 创建自定义 bridge 网络
- 5.5.4 在自定义网络中启动容器
- 5.5.6 域名与容器访问
一、什么是 Dockerfile?
Dockerfile 是一个包含创建 Docker 镜像的所有命令的文本文件。每个命令都描述了镜像的一层,而通过 docker build
命令可以根据 Dockerfile 中的内容构建出一个镜像。通过 Dockerfile,你可以指定自己的镜像构建规则,只需要编辑或修改其中的指令,就能生成你所需的 Docker 镜像。
二、Dockerfile 构建过程
在 Dockerfile 中,指令通常用大写字母表示,每条指令都按顺序执行。#
符号用于注释,方便理解脚本的内容。每个指令都会创建镜像的一层,所以 Dockerfile 中的每个命令都会影响最终镜像的构成。通过这些指令,Dockerfile 会一步步构建出完整的镜像。
为了帮助理解,可以通过一张图片展示 Docker 镜像的构成以及其运行过程。
- Dockerfile:面向开发的文件,主要用于定义如何构建镜像。它描述了所有的构建步骤,就像是源代码一样,用来生成镜像。
- Docker 镜像:通过 Dockerfile 构建出来的镜像,最终用于发布和运行。它是一个“只读”的文件系统,包含了应用运行所需的所有依赖和环境。
- Docker 容器:容器是 Docker 镜像的运行实例,容器启动后就可以提供服务。它是一个轻量级、可移植、独立的运行环境。
1、Dockerfile 是构建镜像的脚本
2、Docker 镜像 是构建的产物
3、而 Docker 容器 则是运行镜像并提供服务的环境。
三、Dockerfile 指令选项
指令 | 描述 |
---|---|
FROM | 指定基础镜像,例如 FROM centos |
MAINTAINER | 镜像的作者和邮箱。**(已弃用,建议使用 ****LABEL** 代替) |
RUN | 在镜像构建过程中执行的命令,比如安装软件包或执行配置脚本。 |
CMD | 容器启动时执行的命令。(仅最后一个 CMD 指令生效,可被覆盖) |
EXPOSE | 指定容器开放的端口。 |
ENV | 设置环境变量,在后续指令中可以使用这些环境变量。 |
ADD | 将文件、目录或压缩包添加到镜像中,解压压缩包。 |
COPY | 复制文件或目录到镜像中,不会解压压缩包。 |
VOLUME | 设置卷,挂载主机目录或共享数据。 |
USER | 指定执行后续命令的用户和用户组,用户和用户组必须事先存在。 |
WORKDIR | 设置工作目录,类似于 cd 命令。后续命令将在该目录下执行。 |
ENTRYPOINT | 类似于 CMD 指令,但不会被 docker run 命令行指定的命令覆盖,会追加到启动命令中。 |
ONBUILD | 当构建继承此 Dockerfile 的镜像时,触发该指令执行。 |
LABEL | 给镜像添加元数据(如作者、版本等),格式为 KEY=VALUE ,如 LABEL org.opencontainers.image.authors="runoob" |
四、实战制作镜像并发布
4.1 注册 Docker Hub 账号
访问网址:https://hub.docker.com/ 注册一个 Docker Hub 账号。
2、在服务器上使用命令行登录
使用以下命令登录 Docker Hub:
- 登录命令:
docker login -u [账号名字]
- 退出登录命令:
docker logout
- 推送镜像到 Docker Hub:
docker push 账号/容器名字:版本号
如果看到 Login Succeeded
,就表示登录成功了
4.2 构建镜像
# 创建目录
mkdir dockerfile
cd dockerfile
ls# 编写Dockerfile文件
vim mydockerfile# 编写Dockerfile文件
FROM centos:7# 镜像的维护者信息
MAINTAINER ydk <123@qq.com># 设置环境变量 MYPATH
ENV MYPATH /usr/local# 设置工作目录为 $MYPATH,这里会进入到 /usr/local 目录
WORKDIR $MYPATH# 替换为阿里云的 CentOS 7 yum 源,并安装常用工具
RUN yum install -y wget && \mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup && \wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \yum clean all && \yum makecache && \yum -y install vim-enhanced net-tools && \yum clean all# 对外暴露 80 端口
EXPOSE 80# 指定容器启动时的命令
CMD echo $MYPATH # 这个 CMD 指令会显示环境变量 MYPATH
CMD echo "------------END-------------" # 这个 CMD 会输出分隔线
CMD /bin/bash # 实际执行的命令是 /bin/bash
4.3 构建dockerfile
docker build -f mydockerfile-t mycentos:1.0 .
输出
[root@docker dockerfile]# docker build -f mydockerfile -t mycentos:1.0 .
[+] Building 27.4s (7/7) FINISHED docker:default=> [internal] load build definition from mydockerfile 0.0s=> => transferring dockerfile: 1.16kB 0.0s=> [internal] load metadata for docker.io/library/centos:7 1.3s=> [internal] load .dockerignore 0.0s=> => transferring context: 2B 0.0s=> [1/3] FROM docker.io/library/centos:7@sha256:be65f488b7764ad3638f236b7b515b3678369a5124c47b8d32916d6487418ea4 0.0s=> CACHED [2/3] WORKDIR /usr/local 0.0s=> [3/3] RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-Base.repo && sed -i 's|#baseurl=http://mirror.centos.org|baseurl=ht 25.8s=> exporting to image 0.2s => => exporting layers 0.2s => => writing image sha256:4c2ce146990671fcecc87364ee0ea9cf13f7632845d13997f225f4a667867877 0.0s => => naming to docker.io/library/mycentos:1.0 0.0s
[root@docker dockerfile]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 1.0 4c2ce1469906 About a minute ago 284MB
docker history查看历史
[root@docker dockerfile]# docker history mycentos:1.0
IMAGE CREATED CREATED BY SIZE COMMENT
4c2ce1469906 4 minutes ago CMD ["/bin/sh" "-c" "echo \"工作目录: $MYPAT… 0B buildkit.dockerfile.v0
<missing> 4 minutes ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
<missing> 4 minutes ago RUN /bin/sh -c sed -i 's/mirrorlist/#mirrorl… 80.4MB buildkit.dockerfile.v0
<missing> 10 minutes ago WORKDIR /usr/local 0B buildkit.dockerfile.v0
<missing> 10 minutes ago ENV MYPATH=/usr/local 0B buildkit.dockerfile.v0
<missing> 10 minutes ago MAINTAINER ydk <123@qq.com> 0B buildkit.dockerfile.v0
<missing> 4 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 4 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 4 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
4.4 推送镜像至docker hub
根据官方文档要求,推送的镜像名称必须为
YOUR_DOCKER_HUB_ID/XXXX
,需要对镜像重新命名。
# 给镜像重新打标签
docker tag mycentos:1.0 YOUR_DOCKER_HUB_ID/mycentos7# 推送到 Docker Hub
docker push YOUR_DOCKER_HUB_ID/mycentos7
五、Docker 网络
5.1 本机网络理解
在使用 ifconfig
查看网络时,通常会看到三类网络接口:
[root@docker ~]# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255inet6 fe80::42:ffff:fea8:da4d prefixlen 64 scopeid 0x20<link>ether 02:42:ff:a8:da:4d txqueuelen 0 (Ethernet)RX packets 9164 bytes 375767 (366.9 KiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 13350 bytes 84857658 (80.9 MiB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 10.0.0.10 netmask 255.255.255.0 broadcast 10.0.0.255inet6 fe80::8853:b308:7a96:5216 prefixlen 64 scopeid 0x20<link>ether 00:0c:29:cb:83:30 txqueuelen 1000 (Ethernet)RX packets 375779 bytes 539933589 (514.9 MiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 88078 bytes 7043166 (6.7 MiB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536inet 127.0.0.1 netmask 255.0.0.0inet6 ::1 prefixlen 128 scopeid 0x10<host>loop txqueuelen 1000 (Local Loopback)RX packets 1 bytes 232 (232.0 B)RX errors 0 dropped 0 overruns 0 frame 0TX packets 1 bytes 232 (232.0 B)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- docker0
- 这是 Docker 自动创建的虚拟网桥,也是 Docker 容器的默认网络。
- 容器通过它可以和宿主机或其他容器通信。
- 本节的重点就是理解这个网络。
- eth32
- 这是本机的外网接口,用于连接互联网。
- 比如你的电脑访问网页时,就是通过
eth0
连接的。
- lo(Loopback 回环口)
- 本地回环地址,一般是
127.0.0.1
。 - 它可以用来代表本机自己,也就是
localhost
。 - 不经过外网就能让本机访问自己的服务。
- 本地回环地址,一般是
5.2 Docker0-Docker 的虚拟网桥
- docker0 其实就是一个叫
docker0
的虚拟网桥。 - 容器默认会连接到这个网桥,从而实现和宿主机及其他容器的网络通信。
查看 docker0 网桥
- 使用
brctl
命令查看网桥信息:
brctl show
- 如果系统没有安装
brctl
,可以用下面的命令安装(以 CentOS 为例):
yum -y install bridge-utils
运行 brctl show
后,你会看到类似这样的输出:
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242ffa8da4d no
- bridge name
- 网桥的名字。
- 例如 Docker 默认创建的虚拟网桥叫
docker0
。
- bridge id
- 网桥的唯一标识 ID(类似身份证号)。
- 每个网桥都有一个唯一的 8 字节标识,前两位是优先级,后六位是 MAC 地址。
- STP enabled
- 是否启用了 生成树协议 (Spanning Tree Protocol)。
- STP 用于避免网络环路,但 Docker 默认关闭(显示
no
)。
- interfaces
- 当前连接到这个网桥的网络接口列表。
- 对 Docker 来说,就是挂载到
docker0
上的容器虚拟网卡(veth)。 - 如果没有容器在运行或容器使用了自定义网络,这一列会为空。
5.3 清空本机docker环境
docker rm -f $(docker ps -aq)docker rmi -f $(docker images -aq)
5.4 veth-pair 技术
什么是 veth-pair?
veth-pair
(虚拟以太网对)是一种成对的虚拟网卡技术。- 容器内部的网络接口和宿主机通过 一对虚拟网卡 互相连接,就像“管道”一样。
- 一个网卡在容器内,另一个网卡挂在宿主机的
docker0
网桥上,实现网络通信。
1、启动两个 Tomcat 容器
我们先启动两个容器:
docker run -d -P --name=tomcat01 tomcat:9
docker run -d -P --name=tomcat02 tomcat:9
这里选择 tomcat:9
镜像,因为它自带 ip addr
等常用网络命令,方便我们查看网络信息。
2、查看容器 IP
进入容器查看 IP:
docker exec -it tomcat01 apt update && apt install -y iproute2[root@docker ~]# docker exec -it tomcat01 ip addr
12: eth0@if13: <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-netnsid 0inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0valid_lft forever preferred_lft forever[root@docker ~]# docker exec -it tomcat02 ip addr
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0valid_lft forever preferred_lft forever[root@docker ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.444 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.046 ms
^C
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1025ms
rtt min/avg/max/mdev = 0.046/0.245/0.444/0.199 ms
- 你会看到容器内部的网络接口(通常是
eth0
)和对应 IP。 - 如果用容器 IP 去 ping 宿主机 IP,会发现是通的。
5.4.1 理解 Docker 网络中的 veth-pair
- 容器 IP 与 docker0 网卡
- 每启动一个 Docker 容器,Docker 会给它分配一个 IP 地址。
- 安装 Docker 后,宿主机会生成一个叫 docker0 的虚拟网卡,它就像一个小桥梁,连接宿主机和容器。
- 这个连接桥梁用的就是 veth-pair 技术。
- 查看网卡
使用命令查看网卡信息:
ip addr
- 你会发现,多了两张网卡。
- 这两张就是容器启动后自动生成的 **veth-pair**。
- veth-pair 的配对关系
- 每对 veth-pair 都是成对出现的:
- 一端在容器内
- 一端在宿主机上(docker0 网桥)
- 例如:容器内的
veth64
对应宿主机的veth65
,容器内的veth66
对应宿主机的veth67
。 - 它就像一座桥,把容器的网络流量传到宿主机,再到其他容器或外网。
- 每对 veth-pair 都是成对出现的:
- 总结
- veth-pair = 虚拟网卡成对出现
- 一端连容器,一端连宿主机
- 功能 = 桥梁,让容器能互相通信并访问宿主机/外网
5.4.2 Docker 容器网络模型
- 共享同一个“路由器”
- 启动的容器比如
tomcat01
和tomcat02
,默认都会共用 docker0 这个虚拟网桥,相当于同一个路由器。 - 也就是说,如果不指定自定义网络,所有容器的网络流量都会通过 docker0 转发。
- 启动的容器比如
- 默认 IP 分配
- Docker 会给每个容器分配一个默认 IP,保证容器之间能互相通信,同时也能访问宿主机和外网。
- 虚拟网络高效
- Docker 的所有网络接口都是虚拟的,不需要物理网卡,
- 虚拟网络转发效率很高,适合快速启动和大量容器的场景。
5.5 docker网络模式
5.5.1 Docker 网络模式
Docker 提供了几种网络模式,每种模式的特点如下:
模式 | 特点 | 使用场景 |
---|---|---|
Host | 容器不创建自己的虚拟网卡,直接使用宿主机的 IP 和端口 | 高性能场景,需要容器和宿主机共享网络 |
Container | 容器共享指定容器的 IP,不创建自己的网卡 | 很少使用 |
None | 关闭容器的网络功能 | 安全隔离或特殊用途 |
Bridge | 默认模式,每个容器分配自己的 IP,通过 docker0 虚拟网桥和宿主机通信 | 常用模式,适合大多数场景 |
查看 Docker 网络列表:
[root@docker ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
ee84ebc238da bridge bridge local
575099ee0158 host host local
8145e741486a none null local
5.5.2 使用默认 bridge 网络启动容器
- 默认 bridge 网络就是 docker0。
- 启动容器示例:
docker run -d -P --name=tomcat01 --net bridge tomcat
注意:docker0 默认情况下不支持通过域名访问容器,--link
也不推荐使用。
5.5.3 创建自定义 bridge 网络
- 创建自定义网络只需要两步:
[root@docker ~]# docker network create \
> --driver bridge \
> --subnet 192.168.0.0/24 \
> --gateway 192.168.0.1 \
> testnet
cf4b683b3becc1cb10a68d7c950978473a6df36da5ab43bd727f70e367c65d55# 查看网络列表
[root@docker ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
ee84ebc238da bridge bridge local
575099ee0158 host host local
8145e741486a none null local
cf4b683b3bec testnet bridge local
- 查看网络详细信息:
[root@docker ~]# docker network inspect testnet
[{"Name": "testnet","Id": "cf4b683b3becc1cb10a68d7c950978473a6df36da5ab43bd727f70e367c65d55","Created": "2025-09-22T14:03:35.198907151+08:00","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": {},"Config": [{"Subnet": "192.168.0.0/24","Gateway": "192.168.0.1"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {},"Options": {},"Labels": {}}
]
5.5.4 在自定义网络中启动容器
- 启动容器并加入自定义网络
假设我们之前创建的自定义网络叫testnet
:
docker run -d -P --name=tomcat01-net --net=testnet tomcat:9
docker run -d -P --name=tomcat02-net --net=testnet tomcat:9
--net=testnet
表示容器加入我们创建的自定义网络。-P
表示 Docker 会随机映射容器端口到宿主机端口。
- 查看容器 IP
docker network inspect testnet
- 可以看到这两个容器在
testnet
网络中的 IP 地址。
5.5.6 域名与容器访问
- 域名访问与容器互通
- 前面提到的
docker0
缺点:不能通过容器名称访问容器。 - 自定义网络修复了这个问题:在同一个自定义网络下,容器可以直接通过 容器名互相访问。
- 测试容器互通
- 通过 IP ping 测试:
docker exec -it tomcat01-net ping -c 3 <tomcat02-net的IP>
- 通过容器名 ping 测试:
docker exec -it tomcat01-net ping -c 3 tomcat02-net
提示:-c
可以指定 ping 的次数,例如 -c 3
表示 ping 3 次