notebook notebook
首页
  • 计算机网络
  • 计算机系统
  • 数据结构与算法
  • 计算机专业课
  • 设计模式
  • 前端 (opens new window)
  • Java 开发
  • Python 开发
  • Golang 开发
  • Git
  • 软件设计与架构
  • 大数据与分布式系统
  • 常见开发工具

    • Nginx
  • 爬虫
  • Python 数据分析
  • 数据仓库
  • 中间件

    • MySQL
    • Redis
    • Elasticsearch
    • Kafka
  • 深度学习
  • 机器学习
  • 知识图谱
  • 图神经网络
  • 应用安全
  • 渗透测试
  • Linux
  • 云原生
面试
  • 收藏
  • paper 好句
GitHub (opens new window)

学习笔记

啦啦啦,向太阳~
首页
  • 计算机网络
  • 计算机系统
  • 数据结构与算法
  • 计算机专业课
  • 设计模式
  • 前端 (opens new window)
  • Java 开发
  • Python 开发
  • Golang 开发
  • Git
  • 软件设计与架构
  • 大数据与分布式系统
  • 常见开发工具

    • Nginx
  • 爬虫
  • Python 数据分析
  • 数据仓库
  • 中间件

    • MySQL
    • Redis
    • Elasticsearch
    • Kafka
  • 深度学习
  • 机器学习
  • 知识图谱
  • 图神经网络
  • 应用安全
  • 渗透测试
  • Linux
  • 云原生
面试
  • 收藏
  • paper 好句
GitHub (opens new window)
  • Linux

  • 云原生

    • Docker

    • 专栏-深入容器

    • Kubernetes入门实战课-罗剑锋

      • 初识容器
        • 1. 初识 Docker:万事开头难
          • 1.1 Docker 的形态
          • 1.2 Docker 的安装
          • 1.3 Docker 的使用
          • 1.4 Docker 的架构简介
        • 2. 被隔离的进程:一起来看看容器的本质
          • 2.1 容器到底是什么
          • 2.2 隔离是怎么实现的
          • 2.3 容器的常见操作命令
        • 3. 如何编写正确、高效的 Dockerfile
          • 3.1 镜像的内部机制:分层
          • 3.2 Dockerfile 是什么
          • 3.3 怎样编写正确、高效的 Dockerfile
          • 3.4 docker build 是怎么工作的?
          • 3.5 课外小贴士
        • 4. 该怎样用好 Docker Hub 这个宝藏
          • 4.1 Registry
          • 4.2 Docker Hub
          • 4.3 如何在 Docker Hub 上挑选镜像
          • 4.4 Docker Hub 上镜像命名的规则是什么
          • 4.5 离线环境该怎么办
          • 4.6 课后小贴士
        • 5. 打破次元壁:容器该如何与外界互联互通
          • 5.1 如何拷贝容器内的数据
          • 5.2 如何共享主机上的文件
          • 5.3 如何实现网络互通
          • 5.4 如何分配服务端口号
          • 5.5 课外小贴士
      • Kubernetes 的安装与基本架构
      • YAML、Pod、Job、CronJob、ConfigMap、Secret
      • Deployment、Daemonset、Service、Ingress
      • PV、PVC、StorageClass、Provisioner、StatefulSet
      • 滚动更新、应用保障、集群管理
      • MetricsServer、Prometheus、CNI
    • 深入剖析 Kubernetes-张磊

    • Jenkins

  • 运维
  • 云原生
  • Kubernetes入门实战课-罗剑锋
yubin
2023-04-20
目录

初识容器

参考:Kubernetes 入门实战课 | 极客时间 (opens new window) 第 1-8 讲

# 1. 初识 Docker:万事开头难

# 1.1 Docker 的形态

目前使用 Docker 基本有两个选择——Docker Desktop 和 Docker Engine:

  • Docker Desktop:专门针对个人使用而设计,支持 Mac 和 Windows 的快速安装,并具有直观的图形界面,但仅限个人使用,不能商用。
  • Docker Engine:完全免费,只能在 Linux 中运行,血脉最纯正。

如无特别说明,本专栏接下来所说的 Docker 指的都是 Docker Engine。

# 1.2 Docker 的安装

  • 首先安装 docker:sudo apt install docker.io
  • 然后启动 Docker 服务:sudo service docker start
    • 这一步就是启动 Docker 的后台服务
  • 然后将当前用户加入 docker 组:sudo usermod -aG docker ${USER}
    • 这一步是把当前的用户加入Docker的用户组。这是因为操作Docker必须要有root权限,而直接使用root用户不够安全,加入Docker用户组是一个比较好的选择,这也是Docker官方推荐的做法。

上述命令执行完后,我们需要退出系统(exit),然后再重新登陆一次,这样才能让修改用户组的命令 usermod 生效。

可以通过 docker version 和 docker info 来验证是否安装成功。

  • docker version 会输出 Docker 客户端和服务器各自的版本信息
  • docker info 会显示当前 Docker 系统相关的信息,例如CPU、内存、容器数量、镜像数量、容器运行时、存储文件系统等等

# 1.3 Docker 的使用

  • docker ps:列出当前系统中正在运行的容器,加上 -a 就可以看到所有已运行完毕的容器
  • docker pull:拉取 docker image
  • docker images:列出当前 Docker 所存储的所有 images
  • docker run:从 image 启动 container
Docker 使用 busybox

busybox 是一个小巧精致的“工具箱”,把诸多 Linux 命令整合在一个可执行文件里,体积一般不超过 2MB,非常适合测试任务或嵌入式系统。

docker pull busybox  # 拉取busybox镜像
docker run busybox echo hello world
1
2

# 1.4 Docker 的架构简介

下图是 Docker 官网的一张图,描述了 Docker Engine 的内部角色和工作流程:

20230420212225

刚才我们敲的命令行 docker 实际上是一个客户端 client,它会与 Docker Engine 里的后台服务 Docker daemon 通信,而镜像则存储在远端的仓库 Registry 里,客户端并不能直接访问镜像仓库。

Docker client可以通过 build、 pull、 run 等命令向Docker daemon发送请求,而Docker daemon则是容器和镜像的“大管家”,负责从远端拉取镜像、在本地存储镜像,还有从镜像生成容器、管理容器等所有功能。所以,在Docker Engine里,真正干活的其实是默默运行在后台的Docker daemon,而我们实际操作的命令行工具“docker”只是个“传声筒”的角色。

# 2. 被隔离的进程:一起来看看容器的本质

广义上来说,容器技术是动态的容器、静态的镜像和远端的仓库这三者的组合。今天就来看看究竟什么是容器(即狭义的、动态的容器)。

# 2.1 容器到底是什么

容器封装了运行中的进程,并把进程与外界环境隔离开,让进程与外部系统互不影响。它就是一个特殊的隔离环境,它能够让进程只看到这个环境里的有限信息,不能对外界环境施加影响。

容器技术的另一个本领就是为应用程序加上资源隔离,在系统里切分出一部分资源,让它只能使用指定的配额。这可以避免容器内进程的过渡系统消耗,并充分利用计算机硬件,让有限的资源能够提供稳定可靠的服务。

# 2.2 隔离是怎么实现的

奥秘在于 Linux 内核所提供的三个技术:namespace、cgroup 和 chroot,虽然这三个技术的初衷都不是为了实现容器,但结合在一起就会发生奇妙的”化学反应“。

  • namespace:它可以创建出独立的文件系统、主机名、进程号、网络等资源空间,相当于给进程盖了一间小板房,这样就实现了系统全局资源和进程局部资源的隔离。
  • cgroup:全称是 Linux Control Group,用来实现对进程的 CPU、内存等资源的优先级和配额限制,相当于给进程的小板房加了一个天花板。
  • chroot:它可以更改进程的根目录,也就是限制访问文件系统,相当于给进程的小板房铺上了地砖。

综合运用以上三个技术,一个四四方方、具有完善的隔离特性的容器就此出现了,进程也就可以搬进去快乐生活啦。

目前容器技术基本不再使用古老的 chroot 了,而是改用 pivot_root。

# 2.3 容器的常见操作命令

20230422145651

# 3. 如何编写正确、高效的 Dockerfile

这一大节来讲解镜像的内部机制,还有高效、正确地编写 Dockerfile 制作容器镜像的方法。

# 3.1 镜像的内部机制:分层

镜像就是一个打包文件,里面包含了应用程序及依赖环境,例如文件系统(fs)、env 以及 config params 等。这里面真正麻烦的是 fs,为了保证容器运行环境的一致性,镜像必须把 rootfs 都包含进来。

尽管 image 中不包含系统内核(因为 containers 共享了宿主机内核),但如果每个 image 都这样重复打包,会产生大量冗余(比如 1000 个 image 可能会有 1000 个 Ubuntu rootfs),对磁盘存储和网络传输都是很大的浪费。很自然地,我们可以想到应该把重复的部分抽取出来,也就是只存一份 Ubuntu rootfs,然后让所有基于此的 image 都共享这部分数据。这个思路就是 container image 的一个重大创新点:分层(Layer)。

容器镜像内部并不是一个平坦的结构,而是由许多的镜像层组成的,每层都是只读不可修改的一组文件,相同的层可以在镜像之间共享,然后多个层像搭积木一样堆叠起来,再使用一种叫“Union FS 联合文件系统”的技术把它们合并在一起,就形成了容器最终看到的文件系统:

20230422151448

使用 docker inspect nginx:alpine 可以看到镜像的分层信息,在输出的”RootFS“部分:

$ docker inspect nginx:alpine

...
"RootFS": {
  "Type": "layers",
  "Layers": [
    "sha256:9d982e0ac7aee7e383989508c9b7175fae67221f80323067252a0442c632a67f",
    "sha256:2ec9d5e75f88b8fa7403e3c42d85194c2bf6b9cc7f93c84e2fdd1949927a7eb5",
    "sha256:52207ccd9e991181a2faebabaf7530e57a14221460f841c820874d90acb0b29a","sha256:33dba95a3cfec929519ae7232359c2212eb68d807c663f3adf807e3d635850e0","sha256:42939f4641510d4b8c971124cd0a8f644e9b48934dbb5c689aa010a5169ecb0e","sha256:6003157f5511d91798b880a6309a7d674c2e4978f6b79a1c24f0225344aa4811"
  ]
}
1
2
3
4
5
6
7
8
9
10
11
  • 从上例可以看到,nginx:alpine 镜像里一共有 6 个 layer。

当你 docker pull 下载镜像时,Docker 会检查是否有重复的层,如果本地已存在就不会重复下载;同样在 docekr rmi 时如果 layer 被其他镜像共享的话,也不会被删除。

笔记

重点理解好:容器镜像是由多个只读的Layer构成的,同一个Layer可以被不同的镜像共享,减少了存储和传输的成本。

# 3.2 Dockerfile 是什么

Dockerfile 就是一个纯文本,里面记录了一系列的构建指令,每个指令都会生成一个 layer,Docker 会顺序执行这些指令并最终创建出一个新的 image 出来。

下面是一个 Dockerfile 示例:

# Dockerfile.busybox
FROM busybox                  # 选择基础镜像
CMD echo "hello world"        # 启动容器时默认运行的命令
1
2
3

然后可以使用 docker build 来创建镜像:

$ docker build -f Dockerfile.busybox .

Sending build context to Docker daemon   7.68kB
Step 1/2 : FROM busybox
 ---> d38589532d97
Step 2/2 : CMD echo "hello world"
 ---> Running in c5a762edd1c8
Removing intermediate container c5a762edd1c8
 ---> b61882f42db7
Successfully built b61882f42db7
1
2
3
4
5
6
7
8
9
10
  • -f 参数指定 Dockerfile 文件名
  • 最后需要跟一个文件路径,叫做构建上下文(build’s context)。这里只有一个简答的点号,表示当前路径的意思。

# 3.3 怎样编写正确、高效的 Dockerfile

这里讲一下编写 Dockerfile 的一些常用指令和最佳实践。

# 1)FROM

首先因为构建镜像的第一条指令必须是 FROM,所以基础镜像的选择非常关键。如果关注的是镜像的安全和大小,那么一般会选择 Alpine;如果关注的是应用的运行稳定性,那么可能会选择 Ubuntu、Debian、CentOS。

# 2)COPY

然后可以使用 COPY 命令将构建上下文中的一些文件打包到镜像中。注意,不能使用构建上下文之外的文件。

COPY ./a.txt  /tmp/a.txt    # 把构建上下文里的a.txt拷贝到镜像的/tmp目录
COPY /etc/hosts  /tmp       # 错误!不能使用构建上下文之外的文件
1
2

# 3)RUN、ARG 和 ENV

RUN 命令可以执行任意的 shell 命令,比如更新系统、安装应用、下载文件、创建目录、编译程序等等,实现任意的镜像构建步骤,非常灵活。

RUN 通常会是Dockerfile里最复杂的指令,会包含很多的Shell命令,但Dockerfile里一条指令只能是一行,所以有的 RUN 指令会在每行的末尾使用续行符 \,命令之间也会用 && 来连接,这样保证在逻辑上是一行,就像下面这样:

RUN apt-get update \
    && apt-get install -y \
        build-essential \
        curl \
        make \
        unzip \
    && cd /tmp \
    && curl -fSL xxx.tar.gz -o xxx.tar.gz\
    && tar xzf xxx.tar.gz \
    && cd xxx \
    && ./config \
    && make \
    && make clean
1
2
3
4
5
6
7
8
9
10
11
12
13

有的时候在Dockerfile里写这种超长的 RUN 指令很不美观,而且一旦写错了,每次调试都要重新构建也很麻烦,所以你可以采用一种变通的技巧:把这些Shell命令集中到一个脚本文件里,用 COPY 命令拷贝进去再用 RUN 来执行:

COPY setup.sh  /tmp/                # 拷贝脚本到/tmp目录

RUN cd /tmp && chmod +x setup.sh \  # 添加执行权限
    && ./setup.sh && rm setup.sh    # 运行脚本然后再删除
1
2
3
4

RUN 指令实际上就是Shell编程,如果你对它有所了解,就应该知道它有变量的概念,可以实现参数化运行,这在 Dockerfile 里也可以做到,需要使用两个指令 ARG 和 ENV:

  • ARG:它创建的变量只在镜像构建过程中可见,容器运行时不可见
  • ENV:它创建的变量不仅能够在构建镜像的过程中使用,在容器运行时也能够以环境变量的形式被应用程序使用

# 4)EXPOSE

它用来声明容器对外服务的端口号:

EXPOSE 443           # 默认是 tcp 协议
EXPOSE 53/udp        # 可以指定 udp 协议
1
2

讲了这些 Dockerfile 指令之后,我还要特别强调一下,因为每个指令都会生成一个镜像层,所以 Dockerfile 里最好不要滥用指令,尽量精简合并,否则太多的层会导致镜像臃肿不堪。

# 3.4 docker build 是怎么工作的?

“构建上下文”是什么意思呢?

因为命令行 docker 只是一个简单的客户端,真正的镜像构建工作是由服务端的 Docker daemon 来完成的,所以 docker 客户端就只能把构建上下文目录打包上传(显示信息 Sending build context to Docker daemon ),这样服务器才能够获取本地的这些文件。

但把构建上下文打包的过程可能会把一些无用的文件(比如 README、.git 等)也拷贝进镜像了,为避免这个文件,你可以在构建上下文目录中建一个 .dockerignore 文件,语法与 .gitignore 类似,用来排除掉那些不需要的文件。

下面是一个简单的示例,表示不打包上传后缀是“swp”“sh”的文件:

# docker ignore
*.swp
*.sh
1
2
3

另外关于Dockerfile,一般应该在命令行里使用 -f 来显式指定。但如果省略这个参数, docker build 就会在当前目录下找名字是 Dockerfile 的文件。所以,如果只有一个构建目标的话,文件直接叫“Dockerfile”是最省事的。

在构建时,也可以加一个 -t 参数,也就是指定镜像的 tag,这样 Docker 在构建完成后会自动给镜像添加名字。当然,名字必须要符合上节课里的命名规范,用 : 分隔名字和标签,如果不提供标签默认就是“latest”。

关于镜像的构建,还有很多高级技巧等待你去探索,比如使用缓存、多阶段构建等等,你可以再参考 Docker 官方文档 (opens new window),或者一些知名应用的镜像(如 Nginx、Redis、Node.js 等)进一步学习。

# 3.5 课外小贴士

  • 我们也可以使用命令“docker commit”从运行中的容器直接生成镜像,但这样不具有 Dockerfle“ 文档化的优点,一般不推荐使用。
  • Docker 镜像遵循的是 OCI (Open Container Initi-atve)标准,所以制作出来的镜像文件也能够被其他的容器技术 (如 Kata、Kubernetes) 识别并运行。
  • Union FS 有 多 种实 现,例 如 aufs、btrfs、de-vice-mapper 等,目前 Docker 使用的是 overlay2,可以在“docker info”中查看。
  • 在 Dockerfle 里还可以使用另一个与“COPY”很类似的“ADD”指令,它不仅能够拷贝文件,还支持下载和自动解压缩,但过多的操作让它的含义比较模糊,不容易控制,个人不推荐使用。
  • “ENTRYPOINT”是一个与“CMD”类似的指令,也可以定义启动命令,相当于“docker run xxx ENTRY-POINT CMD”,不过没有“CMD”常用。
  • 可以使用“docker history”命令回放完整的镜像的构建过程,有的时候对于镜像排错很有用。

# 4. 该怎样用好 Docker Hub 这个宝藏

镜像文件该如何管理呢?

# 4.1 Registry

镜像仓库 Registry 就是所有镜像都在这里登记保管,就像是一个巨大的档案馆。docker pull 命令就是让 Docker daemon 去 Registry 下载镜像。Registry 除了提供拉取镜像的功能外,还提供了上传、查询、删除等多个功能。

# 4.2 Docker Hub

默认的镜像仓库就是 Docker Hub (opens new window),它是官方 Registry 服务。里面不仅有 Docker 自己打包的镜像,而且还对公众免费开放。

# 4.3 如何在 Docker Hub 上挑选镜像

在Docker Hub上有官方镜像、认证镜像 和非官方镜像的区别。

  • 官方镜像:由 Docker 公司提供,经过了严格的漏洞扫描和安全检测,支持x86_64、arm64等多种硬件架构,还具有清晰易读的文档,一般来说是我们构建镜像的首选,也是我们编写Dockerfile的最佳范例。这种镜像会有一个“Official image”的标记。
  • 认证镜像:有一个“Verified publisher”的标记,就是认证发行商,比如Bitnami、Rancher、Ubuntu等。它们都是颇具规模的大公司,类似于微博的“大V”。
  • 非官方镜像:有一种是“半官方镜像”,因为经过 Docker 认证是要交钱的,很多公司不想交钱,就没有经过认证,但这类也比较可靠。剩下的就是民间镜像了,这类往往由于条件所限,质量难以保证。

除了查看镜像是否为官方认证,我们还应该再结合其他的条件来判断镜像质量是否足够好。做法和GitHub差不多,就是看它的下载量、星数、还有更新历史,简单来说就是“好评”数量。最好还是随大流。

Dockerhub 上镜像的命名方式是“用户名/应用名”的形式,比如 ubuntu/nginx 等。所以,我们在使用 docker pull 下载这些非官方镜像的时候,就必须把用户名也带上,否则默认就会使用官方镜像。

# 4.4 Docker Hub 上镜像命名的规则是什么

镜像还存在许多版本,也就多个 tag。直接使用默认的“latest”虽然简单方便,但在生产环境里是一种非常不负责任的做法,会导致版本不可控。所以我们还需要理解Docker Hub上标签命名的含义,才能够挑选出最适合我们自己的镜像版本。

下面拿官方的Redis镜像作为例子,解释一下这些标签都是什么意思。

20230422163445

通常来说,镜像标签的格式是 应用的版本号加上操作系统。

版本号你应该比较了解吧,基本上都是 主版本号+次版本号+补丁号 的形式,有的还会在正式发布前出rc版(候选版本,release candidate)。而操作系统的情况略微复杂一些,因为各个Linux发行版的命名方式“花样”太多了。

Alpine、CentOS的命名比较简单明了,就是数字的版本号,像这里的 alpine3.15 ,而Ubuntu、Debian则采用了代号的形式。比如Ubuntu 18.04是 bionic,Ubuntu 20.04是 focal,Debian 9是 stretch,Debian 10是 buster,Debian 11是 bullseye。

另外,有的标签还会加上 slim、 fat,来进一步表示这个镜像的内容是经过精简的,还是包含了较多的辅助工具。通常 slim 镜像会比较小,运行效率高,而 fat 镜像会比较大,适合用来开发调试。

下面我就列出几个标签的例子来说明一下。

  • nginx:1.21.6-alpine,表示版本号是1.21.6,基础镜像是最新的Alpine。
  • redis:7.0-rc-bullseye,表示版本号是7.0候选版,基础镜像是Debian 11。
  • node:17-buster-slim,表示版本号是17,基础镜像是精简的Debian 10。

# 4.5 离线环境该怎么办

Docker 提供了:

  • save 命令将 image 导出为压缩包:docker save ngx-app:latest -o ngx.tar
  • load 命令从压缩包导入 Docker:docker load -i ngx.tar 或 docker load --input ngx.tar

# 4.6 课后小贴士

  • 由于 Docker Hub 服务器在国外,国内访问会比较慢所以就出现了不少镜像加速网站,可以在“/etc/dock-er/daemon.json”里配置。但不知道出于什么原因,近几年很多网站都停止了这项服务,十分可惜。
  • 虽然 Docker Hub 一家独大,但市面上仍然有其他的竞争者,它们不甘心“ 寄人篱下 ”,就自己开了独立的镜像仓库,典型的有 Red Hat 的 quay.io、Google 的gcr.io、还有 GitHub 的 ghcr.io。
  • Docker 官方镜像也有用户名,就是“library”,例如“library/nginx”,但一般都省略不写。
  • 我们也可以用命令行 docker search 来快速查找 Docker Hub 里的镜像。

# 5. 打破次元壁:容器该如何与外界互联互通

这一大节讲讲有哪些手段能够在容器与外部系统之间沟通交流。

# 5.1 如何拷贝容器内的数据

docker cp 命令可以在宿主机和容器之间拷贝文件:

docker cp a.txt 062:/tmp  # 外界 -> 容器内
docker cp 062:/tmp/a.txt ./b.txt  # 容器内 -> 外界
1
2

# 5.2 如何共享主机上的文件

挂载 volume 即可。在 docker run 命令运行时,指定 -v 参数,格式是 “宿主机路径:容器内路径”,代表让容器宿主机的某个目录。

# 5.3 如何实现网络互通

网络互通的关键在于“打通”容器内外的网络,而处理网络通信无疑是计算机系统里最棘手的工作之一,有许许多多的名词、协议、工具,在这里我也没有办法一下子就把它都完全说清楚,所以只能从“宏观”层面讲个大概,帮助你快速理解。

Docker提供了三种网络模式,分别是 null、 host 和 bridge:

# 1)null 模式

null 是最简单的模式,也就是没有网络,但允许其他的网络插件来自定义网络连接,这里就不多做介绍了。

# 2)host 模式

host 的意思是直接使用宿主机网络,相当于去掉了容器的网络隔离(其他隔离依然保留),所有的容器会共享宿主机的IP地址和网卡。这种模式没有中间层,自然通信效率高,但缺少了隔离,运行太多的容器也容易导致端口冲突。

host 模式需要在 docker run 时使用 --net=host 参数,下面我就用这个参数启动 Nginx:

docker run -d --rm --net=host nginx:alpine
1

为了验证效果,我们可以在本机和容器里分别执行 ip addr 命令,查看网卡信息:

ip addr                    # 本机查看网卡
docker exec xxx ip addr    # 容器查看网卡
1
2
20230422164827
20230422164841

可以看到这两个 ip addr 命令的输出信息是完全一样的,比如都是一个网卡ens160,IP地址是“192.168.10.208”,这就证明Nginx容器确实与本机共享了网络栈。

# 3)bridge 模式

第三种 bridge,也就是桥接模式,它有点类似现实世界里的交换机、路由器,只不过是由软件虚拟出来的,容器和宿主机再通过虚拟网卡接入这个网桥(图中的docker0),那么它们之间也就可以正常的收发网络数据包了。不过和host模式相比,bridge模式多了虚拟网桥和网卡,通信效率会低一些。

20230422164940

和host模式一样,我们也可以用 --net=bridge 来启用桥接模式,但其实并没有这个必要,因为Docker默认的网络模式就是bridge,所以一般不需要显式指定。

下面我们启动两个容器Nginx和Redis,就像刚才说的,没有特殊指定就会使用bridge模式:

docker run -d --rm nginx:alpine    # 默认使用桥接模式
docker run -d --rm redis           # 默认使用桥接模式
1
2

然后我们还是在本机和容器里执行 ip addr 命令(Redis容器里没有ip命令,所以只能在Nginx容器里执行):

20230422165049

对比一下刚才host模式的输出,就可以发现容器里的网卡设置与宿主机完全不同,eth0是一个虚拟网卡,IP地址是B类私有地址“172.17.0.2”。

我们还可以用 docker inspect 直接查看容器的 ip 地址:

docker inspect xxx |grep IPAddress
1
20230422165210

这显示出两个容器的IP地址分别是“172.17.0.2”和“172.17.0.3”,而宿主机的IP地址则是“172.17.0.1”,所以它们都在“172.17.0.0/16”这个Docker的默认网段,彼此之间就能够使用IP地址来实现网络通信了。

# 5.4 如何分配服务端口号

在编写 Dockerfile 时,可以用 EXPOSE 指令声明容器对外的端口号,在 docker run 时也可以使用 -p 参数来实现端口映射。

# 5.5 课外小贴士

  • Docker 还可以使用“volume”命令创建独立挂载的数据卷”,但它的用法与 Kubernetes 差距较大,为了避免混淆这里就不介绍了。
  • Docker 官方推荐使用来代替“-v”,但--mount--mount”用法很繁琐,而“-v”已经有了很长的应用历史了,所以我还是建议用较为方便的“-v”。
  • -v 挂载目录时如果发现源路径不存在会自动创建这有时候会是一个“坑”,当主机目录被意外删除时会导致容器里出现空目录,让应用无法按预想的流程工作。
  • -v 挂载目录默认是可读可写的,但也可以加上 :ro 变成只读,可以防止容器意外修改文件,例如 -v /tmp:/tmp:ro
  • IPv4 地址是 32 位,分为 5 类 (ABCDE),ABC 类地址中各有一部分网段可以私用,“172.16.0.0/16~172.31.0.0/16”就都属于 B 类私有地址。
编辑 (opens new window)
上次更新: 2023/04/26, 13:34:07
Kubernetes 如何与容器运行时一起工作
Kubernetes 的安装与基本架构

← Kubernetes 如何与容器运行时一起工作 Kubernetes 的安装与基本架构→

最近更新
01
Deep Reinforcement Learning
10-03
02
误删数据后怎么办
04-06
03
MySQL 一主多从
03-22
更多文章>
Theme by Vdoing | Copyright © 2021-2024 yubincloud | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×