Dockerfile构建镜像以及网络

目录

  • [一、什么是 Dockerfile?](#一、什么是 Dockerfile?)
  • [二、Dockerfile 构建过程](#二、Dockerfile 构建过程)
  • [三、Dockerfile 指令选项](#三、Dockerfile 指令选项)
  • 四、实战制作镜像并发布
    • [4.1 注册 Docker Hub 账号](#4.1 注册 Docker Hub 账号)
    • [4.2 构建镜像](#4.2 构建镜像)
    • [4.3 构建dockerfile](#4.3 构建dockerfile)
    • [4.4 推送镜像至docker hub](#4.4 推送镜像至docker hub)
  • [五、Docker 网络](#五、Docker 网络)
    • [5.1 本机网络理解](#5.1 本机网络理解)
    • [5.2 Docker0-Docker 的虚拟网桥](#5.2 Docker0-Docker 的虚拟网桥)
    • [5.3 清空本机docker环境](#5.3 清空本机docker环境)
    • [5.4 veth-pair 技术](#5.4 veth-pair 技术)
      • [5.4.1 理解 Docker 网络中的 veth-pair](#5.4.1 理解 Docker 网络中的 veth-pair)
      • [5.4.2 Docker 容器网络模型](#5.4.2 Docker 容器网络模型)
    • [5.5 docker网络模式](#5.5 docker网络模式)
      • [5.5.1 Docker 网络模式](#5.5.1 Docker 网络模式)
      • [5.5.2 使用默认 bridge 网络启动容器](#5.5.2 使用默认 bridge 网络启动容器)
      • [5.5.3 创建自定义 bridge 网络](#5.5.3 创建自定义 bridge 网络)
      • [5.5.4 在自定义网络中启动容器](#5.5.4 在自定义网络中启动容器)
      • [5.5.6 域名与容器访问](#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:

  • 登录命令:
plain 复制代码
docker login -u [账号名字]
  • 退出登录命令:
plain 复制代码
docker logout
  • 推送镜像到 Docker Hub:
plain 复制代码
docker push 账号/容器名字:版本号

如果看到 Login Succeeded,就表示登录成功了

4.2 构建镜像

bash 复制代码
# 创建目录
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

bash 复制代码
docker build -f mydockerfile-t mycentos:1.0 .

输出

bash 复制代码
[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查看历史

bash 复制代码
[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,需要对镜像重新命名。

bash 复制代码
# 给镜像重新打标签
docker tag mycentos:1.0 YOUR_DOCKER_HUB_ID/mycentos7

# 推送到 Docker Hub
docker push YOUR_DOCKER_HUB_ID/mycentos7

五、Docker 网络

5.1 本机网络理解

在使用 ifconfig 查看网络时,通常会看到三类网络接口:

bash 复制代码
[root@docker ~]# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 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 0
        TX packets 13350  bytes 84857658 (80.9 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.0.10  netmask 255.255.255.0  broadcast 10.0.0.255
        inet6 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 0
        TX packets 88078  bytes 7043166 (6.7 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::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 0
        TX packets 1  bytes 232 (232.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  1. docker0
    • 这是 Docker 自动创建的虚拟网桥,也是 Docker 容器的默认网络。
    • 容器通过它可以和宿主机或其他容器通信。
    • 本节的重点就是理解这个网络。
  2. eth32
    • 这是本机的外网接口,用于连接互联网。
    • 比如你的电脑访问网页时,就是通过 eth0 连接的。
  3. lo(Loopback 回环口)
    • 本地回环地址,一般是 127.0.0.1
    • 它可以用来代表本机自己,也就是 localhost
    • 不经过外网就能让本机访问自己的服务。

5.2 Docker0-Docker 的虚拟网桥

  • docker0 其实就是一个叫 docker0虚拟网桥
  • 容器默认会连接到这个网桥,从而实现和宿主机及其他容器的网络通信。

查看 docker0 网桥

  1. 使用 brctl 命令查看网桥信息:
plain 复制代码
brctl show
  1. 如果系统没有安装 brctl,可以用下面的命令安装(以 CentOS 为例):
plain 复制代码
yum -y install bridge-utils

运行 brctl show 后,你会看到类似这样的输出:

plain 复制代码
[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环境

bash 复制代码
docker rm -f $(docker ps -aq)

docker rmi -f $(docker images -aq)

5.4 veth-pair 技术

什么是 veth-pair?

  • veth-pair(虚拟以太网对)是一种成对的虚拟网卡技术。
  • 容器内部的网络接口和宿主机通过 一对虚拟网卡 互相连接,就像"管道"一样。
  • 一个网卡在容器内,另一个网卡挂在宿主机的 docker0 网桥上,实现网络通信。

1、启动两个 Tomcat 容器

我们先启动两个容器:

plain 复制代码
docker run -d -P --name=tomcat01 tomcat:9
docker run -d -P --name=tomcat02 tomcat:9

这里选择 tomcat:9 镜像,因为它自带 ip addr 等常用网络命令,方便我们查看网络信息。

2、查看容器 IP

进入容器查看 IP:

plain 复制代码
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 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_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 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_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

  1. 容器 IP 与 docker0 网卡
    • 每启动一个 Docker 容器,Docker 会给它分配一个 IP 地址。
    • 安装 Docker 后,宿主机会生成一个叫 docker0 的虚拟网卡,它就像一个小桥梁,连接宿主机和容器。
    • 这个连接桥梁用的就是 veth-pair 技术
  2. 查看网卡
    使用命令查看网卡信息:
plain 复制代码
ip addr
复制代码
- 你会发现,多了两张网卡。
- 这两张就是容器启动后自动生成的 **veth-pair**。
  1. veth-pair 的配对关系
    • 每对 veth-pair 都是成对出现的:
      • 一端在容器内
      • 一端在宿主机上(docker0 网桥)
    • 例如:容器内的 veth64 对应宿主机的 veth65,容器内的 veth66 对应宿主机的 veth67
    • 它就像一座桥,把容器的网络流量传到宿主机,再到其他容器或外网。
  2. 总结
    • veth-pair = 虚拟网卡成对出现
    • 一端连容器,一端连宿主机
    • 功能 = 桥梁,让容器能互相通信并访问宿主机/外网

5.4.2 Docker 容器网络模型

  1. 共享同一个"路由器"
    • 启动的容器比如 tomcat01tomcat02,默认都会共用 docker0 这个虚拟网桥,相当于同一个路由器。
    • 也就是说,如果不指定自定义网络,所有容器的网络流量都会通过 docker0 转发。
  2. 默认 IP 分配
    • Docker 会给每个容器分配一个默认 IP,保证容器之间能互相通信,同时也能访问宿主机和外网。
  3. 虚拟网络高效
    • Docker 的所有网络接口都是虚拟的,不需要物理网卡,
    • 虚拟网络转发效率很高,适合快速启动和大量容器的场景。

5.5 docker网络模式

5.5.1 Docker 网络模式

Docker 提供了几种网络模式,每种模式的特点如下:

模式 特点 使用场景
Host 容器不创建自己的虚拟网卡,直接使用宿主机的 IP 和端口 高性能场景,需要容器和宿主机共享网络
Container 容器共享指定容器的 IP,不创建自己的网卡 很少使用
None 关闭容器的网络功能 安全隔离或特殊用途
Bridge 默认模式,每个容器分配自己的 IP,通过 docker0 虚拟网桥和宿主机通信 常用模式,适合大多数场景

查看 Docker 网络列表:

plain 复制代码
[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
  • 启动容器示例:
plain 复制代码
docker run -d -P --name=tomcat01 --net bridge tomcat

注意:docker0 默认情况下不支持通过域名访问容器,--link 也不推荐使用。

5.5.3 创建自定义 bridge 网络

  • 创建自定义网络只需要两步:
plain 复制代码
[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
  • 查看网络详细信息:
plain 复制代码
[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 在自定义网络中启动容器

  1. 启动容器并加入自定义网络
    假设我们之前创建的自定义网络叫 testnet
plain 复制代码
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 会随机映射容器端口到宿主机端口。
  1. 查看容器 IP
plain 复制代码
docker network inspect testnet
  • 可以看到这两个容器在 testnet 网络中的 IP 地址。

5.5.6 域名与容器访问

  1. 域名访问与容器互通
  • 前面提到的 docker0 缺点:不能通过容器名称访问容器
  • 自定义网络修复了这个问题:在同一个自定义网络下,容器可以直接通过 容器名互相访问
  1. 测试容器互通
  • 通过 IP ping 测试:
plain 复制代码
docker exec -it tomcat01-net ping -c 3 <tomcat02-net的IP>
  • 通过容器名 ping 测试:
plain 复制代码
docker exec -it tomcat01-net ping -c 3 tomcat02-net

提示:-c 可以指定 ping 的次数,例如 -c 3 表示 ping 3 次

相关推荐
明月看潮生4 小时前
编程与数学 03-009 Linux 操作系统应用 16_Linux 邮件服务器
linux·运维·服务器·青少年编程·编程与数学
艾莉丝努力练剑4 小时前
【测试开发/测试】详解测试用例(上):测试用例、万能公式
运维·经验分享·测试开发·测试
wangchen_04 小时前
传输层协议UDP、TCP
网络·tcp/ip·udp
鹤顶红6535 小时前
Python -- 人生重开模拟器(简易版)
服务器·前端·python
2302_799525745 小时前
【Shell】Shell脚本基础知识
linux·bash
conkl5 小时前
PyCharm 在 Linux 上的安装指南
linux·ide·pycharm
zhangzeyuaaa5 小时前
Linux 进程名查看与pkill命令的使用
linux·运维·服务器
上海云盾安全满满5 小时前
游戏开发公司应该要注意哪些网络安全问题
网络·安全·web安全
美好的事情能不能发生在我身上5 小时前
Linux实用操作以及基础命令
linux·运维·服务器