文章目录
- [docker 容器连接](#docker 容器连接)
-
- [端口映射 -P/-p](#端口映射 -P/-p)
-
- -P:镜像里声明的端口自动映射到宿主机的随机端口
- [-p :[宿主机IP:]宿主机端口:容器端口[/协议]](#-p :[宿主机IP:]宿主机端口:容器端口[/协议])
- [docker port 容器名:查"容器端口"对应到了"宿主机哪个地址和端口"](#docker port 容器名:查“容器端口”对应到了“宿主机哪个地址和端口”)
-
- [docker port 容器名 查看这个容器所有已经发布的端口映射](#docker port 容器名 查看这个容器所有已经发布的端口映射)
- [docker port 容器名 5000/docker port 容器名 5000/tcp.只看容器内部这个端口映射到了宿主机哪里](#docker port 容器名 5000/docker port 容器名 5000/tcp.只看容器内部这个端口映射到了宿主机哪里)
- [Docker 容器互联](#Docker 容器互联)
-
- [容器命名 --name](#容器命名 --name)
- 新建网络-d(driver):这个网络用什么网络驱动创建"
-
- bridge:一台机器内部,给几个容器拉了一个局域网。同一台电脑里的容器互相连网
- overlay:跨多台机器,把各台机器上的容器接成一个"虚拟大局域网"。跨多台电脑,把容器接到一个大网里
- [docker network create -d bridge test-net。在当前这台 Docker 主机上,建一个给容器用的本地桥接网络 test-net](#docker network create -d bridge test-net。在当前这台 Docker 主机上,建一个给容器用的本地桥接网络 test-net)
- [配置 DNS.给 Docker daemon 设置默认 DNS 服务器](#配置 DNS.给 Docker daemon 设置默认 DNS 服务器)
-
- [把域名翻译成 IP 地址,这个东西就是 DNS。域名解析系统,把人容易记的名字,翻译成机器要用的地址](#把域名翻译成 IP 地址,这个东西就是 DNS。域名解析系统,把人容易记的名字,翻译成机器要用的地址)
- [为什么要配置 DNS?遇到域名时,该去问谁来翻译?"](#为什么要配置 DNS?遇到域名时,该去问谁来翻译?”)
- [为什么 Docker 里经常要配 DNS?不配置 DNS容器默认继承系统或 Docker 的默认解析方式。配置 DNS你是在明确告诉 Docker:以后容器解析域名,优先去问这几个 DNS 服务器。](#为什么 Docker 里经常要配 DNS?不配置 DNS容器默认继承系统或 Docker 的默认解析方式。配置 DNS你是在明确告诉 Docker:以后容器解析域名,优先去问这几个 DNS 服务器。)
- dns服务器是谁配置的?怎么配置?电脑也没配置,仿佛自动可以解析
- DNS服务器怎么实现
- [docker run -it --rm ubuntu cat etc/resolv.conf.开一个临时 Ubuntu 容器,看看容器内部正在使用哪个 DNS 配置](#docker run -it --rm ubuntu cat etc/resolv.conf.开一个临时 Ubuntu 容器,看看容器内部正在使用哪个 DNS 配置)
-
- [不是在 /etc/docker/daemon.json 文件 配置的吗?为什么看cat etc/resolv.conf?Docker 的容器 DNS 配置最终会映射到容器里的 resolver 配置文件](#不是在 /etc/docker/daemon.json 文件 配置的吗?为什么看cat etc/resolv.conf?Docker 的容器 DNS 配置最终会映射到容器里的 resolver 配置文件)
- [为什么要给容器配置DNS?给容器配置 DNS,是为了让容器能正确地把域名解析成 IP,从而正常访问软件源、网站、接口和各种网络服务。](#为什么要给容器配置DNS?给容器配置 DNS,是为了让容器能正确地把域名解析成 IP,从而正常访问软件源、网站、接口和各种网络服务。)
- 手动指定容器的配置
-
- [docker run -it --rm -h host_ubuntu --dns=114.114.114.114 --dns-search=test.com ubuntu](#docker run -it --rm -h host_ubuntu --dns=114.114.114.114 --dns-search=test.com ubuntu)
-
- [-h 主机名,给容器起名](#-h 主机名,给容器起名)
- [--dns=IP_ADDRESS: 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名。](#--dns=IP_ADDRESS: 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名。)
-
- [etc/hosts = 把"域名或主机名"手动对应到 IP 地址的本地表](#etc/hosts = 把“域名或主机名”手动对应到 IP 地址的本地表)
- [Docker Dockerfile](#Docker Dockerfile)
-
- [什么是 Dockerfile?文本文件,里面写的是:"怎么一步一步制作一个 Docker 镜像。"](#什么是 Dockerfile?文本文件,里面写的是:“怎么一步一步制作一个 Docker 镜像。”)
-
- [RUN:用于执行后面跟着的命令行命令。shell 格式是"让 shell 帮你执行命令",exec 格式是"直接执行程序本身"。](#RUN:用于执行后面跟着的命令行命令。shell 格式是“让 shell 帮你执行命令”,exec 格式是“直接执行程序本身”。)
-
- [shell格式,RUN <命令行命令>。# <命令行命令> 等同于,在终端操作的 shell 命令。](# <命令行命令> 等同于,在终端操作的 shell 命令。)
- [exec 格式:RUN ["可执行文件", "参数1", "参数2"]](#exec 格式:RUN ["可执行文件", "参数1", "参数2"])
- [Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。下载、使用、清理,尽量放在同一个 RUN 里完成](#Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。下载、使用、清理,尽量放在同一个 RUN 里完成)
- [ docker build -t nginx:v3 . 使用当前目录中的 Dockerfile 和相关文件,构建一个名为 nginx:v3 的镜像](# docker build -t nginx:v3 . 使用当前目录中的 Dockerfile 和相关文件,构建一个名为 nginx:v3 的镜像)
-
- [. 是构建上下文是当前目录。](#. 是构建上下文是当前目录。)
- [上下文路径。Dockerfile 在构建时"能访问哪些本地文件"。只准用哪个目录里的材料做镜像](#上下文路径。Dockerfile 在构建时“能访问哪些本地文件”。只准用哪个目录里的材料做镜像)
- 指令详解
-
- COPY,从上下文目录中复制文件或者目录到容器里指定路径。
-
- [如果目标以 / 开头,就是相对于镜像根目录的绝对路径;如果不以 / 开头,它就是相对于当前 WORKDIR 的相对路径。目标不存在时,Docker 会创建缺失的目录](#如果目标以 / 开头,就是相对于镜像根目录的绝对路径;如果不以 / 开头,它就是相对于当前 WORKDIR 的相对路径。目标不存在时,Docker 会创建缺失的目录)
- [结尾有没有 / 很重要](#结尾有没有 / 很重要)
- [copy默认从 build context 复制,也可以用 --from 从 build stage、named context 或另一个 image 复制](#copy默认从 build context 复制,也可以用 --from 从 build stage、named context 或另一个 image 复制)
- ADD
-
- [本地 tar 自动解压](#本地 tar 自动解压)
- [ADD 支持从远程 URL 加文件,也支持把 Git 仓库作为源并克隆到镜像里的目标目录](#ADD 支持从远程 URL 加文件,也支持把 Git 仓库作为源并克隆到镜像里的目标目录)
- CMD
-
- [CMD <shell 命令>](#CMD <shell 命令>)
- [CMD ["可执行文件", "参数1", "参数2"](exec form)](#CMD ["可执行文件", "参数1", "参数2"](exec form))
- [CMD ["参数1", "参数2"] 给 ENTRYPOINT 提供默认参数的](#CMD ["参数1", "参数2"] 给 ENTRYPOINT 提供默认参数的)
- [docker run 能覆盖 CMD](#docker run 能覆盖 CMD)
- [多个 CMD 只有最后一个生效"](#多个 CMD 只有最后一个生效”)
- [ENTRYPOINT 规定"容器启动时一定要执行的主程序".-entrypoint 覆盖 Dockerfile 里的 ENTRYPOINT](#ENTRYPOINT 规定“容器启动时一定要执行的主程序”.-entrypoint 覆盖 Dockerfile 里的 ENTRYPOINT)
- [ENV 用来在镜像里设置环境变量。ENV 会持久保留到最终镜像和容器里](#ENV 用来在镜像里设置环境变量。ENV 会持久保留到最终镜像和容器里)
- [ARG 只在构建过程中可用,默认不会成为镜像里的环境变量,也不会自动出现在容器里](#ARG 只在构建过程中可用,默认不会成为镜像里的环境变量,也不会自动出现在容器里)
- [VOLUME 这个目录里的数据,不要只放在容器自己身上,最好单独存出去](#VOLUME 这个目录里的数据,不要只放在容器自己身上,最好单独存出去)
-
- [容器里的文件,默认是跟着容器走的.重启容器:容器还是那个容器,里面原来写进去的文件通常还在. 删除容器:那个容器本身没了,写在它自己里面的数据通常也就没了](#容器里的文件,默认是跟着容器走的.重启容器:容器还是那个容器,里面原来写进去的文件通常还在. 删除容器:那个容器本身没了,写在它自己里面的数据通常也就没了)
- [VOLUME 这个目录里的数据,不要只放在容器自己身上,最好单独存出去](#VOLUME 这个目录里的数据,不要只放在容器自己身上,最好单独存出去)
-
- [挂到宿主机自己指定的目录。宿主机目录:容器目录 → 你自己指定挂到本机哪里](#挂到宿主机自己指定的目录。宿主机目录:容器目录 → 你自己指定挂到本机哪里)
- [挂到 Docker 自己管理的一块存储。这叫 volume。你不给宿主机具体目录,只给一个卷名。卷名:容器目录 → 交给 Docker 管,宿主机具体位置你通常不用管。docker volume ls 列出docker 管理的卷](#挂到 Docker 自己管理的一块存储。这叫 volume。你不给宿主机具体目录,只给一个卷名。卷名:容器目录 → 交给 Docker 管,宿主机具体位置你通常不用管。docker volume ls 列出docker 管理的卷)
- [VOLUME /data,它只是在镜像里声明:容器里的 /data 是个适合挂外部存储的位置。真正"外部存储挂哪里",是在 docker run 时决定的](#VOLUME /data,它只是在镜像里声明:容器里的 /data 是个适合挂外部存储的位置。真正“外部存储挂哪里”,是在 docker run 时决定的)
- 忘了挂载,也会自动挂匿名卷"
- [docker run -v 能"修改挂载点](#docker run -v 能“修改挂载点)
- [镜像运行时,Docker 会为 /myvol 创建新 volume,并把镜像里这个位置原本已有的数据初始化到新 volume 里](#镜像运行时,Docker 会为 /myvol 创建新 volume,并把镜像里这个位置原本已有的数据初始化到新 volume 里)
- [EXPOSE 仅仅只是声明端口](#EXPOSE 仅仅只是声明端口)
- [WORKDIR:WORKDIR 会为后续的 RUN、CMD、ENTRYPOINT、COPY、ADD 设置工作目录;如果目录不存在,会自动创建。给后面的命令指定"默认当前目录"](#WORKDIR:WORKDIR 会为后续的 RUN、CMD、ENTRYPOINT、COPY、ADD 设置工作目录;如果目录不存在,会自动创建。给后面的命令指定“默认当前目录”)
-
- [RUN 文件系统变化会保留,shell 的"当前状态"不会保留。](#RUN 文件系统变化会保留,shell 的“当前状态”不会保留。)
- [WORKDIR 可以写多次,而且相对路径会基于前一个 WORKDIR 继续拼。绝对路径,直接重设](#WORKDIR 可以写多次,而且相对路径会基于前一个 WORKDIR 继续拼。绝对路径,直接重设)
- HEALTHCHECK
- [ONBUILD 先埋一个触发器,现在不执行,等别人拿这个镜像当基础镜像时再执行](#ONBUILD 先埋一个触发器,现在不执行,等别人拿这个镜像当基础镜像时再执行)
- [LABEL 给镜像贴"说明标签"](#LABEL 给镜像贴“说明标签”)
- [STOPSIGNAL:设置"当 Docker 要停止容器时,先发给容器主进程的那个信号"](#STOPSIGNAL:设置“当 Docker 要停止容器时,先发给容器主进程的那个信号”)
docker 容器连接
端口映射 -P/-p
-P:镜像里声明的端口自动映射到宿主机的随机端口
-P:把镜像里通过 EXPOSE 声明的所有端口,自动发布到宿主机的随机高位端口。Docker 官方也区分了 EXPOSE 和发布端口:EXPOSE 只是声明,真正发布到宿主机要靠 -p 或 -P

-p :[宿主机IP:]宿主机端口:容器端口[/协议]
宿主机IP:\]宿主机端口:容器端口\[/协议
如果不写宿主机 IP,Docker 默认会把端口发布到 所有网络接口,也就是通常看到的 0.0.0.0;如果写了 127.0.0.1,那就只有宿主机自己能访问;如果写了 /udp,那发布的就是 UDP 端口,不再是默认的 TCP。
TCP 和 UDP 是两套不同的端口映射。 也就是说,宿主机的 5000/tcp 和 5000/udp 不是同一个东西。




docker port 容器名:查"容器端口"对应到了"宿主机哪个地址和端口"
docker port 容器名 查看这个容器所有已经发布的端口映射

docker port 容器名 5000/docker port 容器名 5000/tcp.只看容器内部这个端口映射到了宿主机哪里

Docker 容器互联
容器命名 --name
新建网络-d(driver):这个网络用什么网络驱动创建"
-d 是 --driver,意思是:创建网络时,指定用哪一种网络驱动(network driver)。这个网络用什么网络驱动创建"。
Docker 官方说明,docker network create 里内置常见驱动有 bridge 和 overlay;如果你不写 --driver,默认会创建 bridge 网络。
bridge:一台机器里的容器网络
overlay:多台机器之间的容器网络


bridge:一台机器内部,给几个容器拉了一个局域网。同一台电脑里的容器互相连网


overlay:跨多台机器,把各台机器上的容器接成一个"虚拟大局域网"。跨多台电脑,把容器接到一个大网里


docker network create -d bridge test-net。在当前这台 Docker 主机上,建一个给容器用的本地桥接网络 test-net
配置 DNS.给 Docker daemon 设置默认 DNS 服务器

把域名翻译成 IP 地址,这个东西就是 DNS。域名解析系统,把人容易记的名字,翻译成机器要用的地址
DNS 就是把域名翻译成 IP 地址的系统;配置 DNS,就是指定"找谁来做这个翻译"。
配置 DNS 里的 IP,不是你要访问的目标地址,而是你拿来"问路"的服务器地址。
输入域名 → 问 DNS → 拿到目标 IP → 再访问网站。


为什么要配置 DNS?遇到域名时,该去问谁来翻译?"

为什么 Docker 里经常要配 DNS?不配置 DNS容器默认继承系统或 Docker 的默认解析方式。配置 DNS你是在明确告诉 Docker:以后容器解析域名,优先去问这几个 DNS 服务器。





dns服务器是谁配置的?怎么配置?电脑也没配置,仿佛自动可以解析

第一层:路由器/运营商在配

路由器,"网络总管"



电脑 → 路由器 → 运营商网络 → 互联网 → 网站服务器
第二层:公司网络管理员在配

第三层:自己手动配

DNS服务器怎么实现
DNS 服务器的实现,本质上就是一个维护"域名记录"的网络服务:它要么自己保存答案,要么按分层规则替你继续询问,最后把域名对应的结果返回给客户端。











docker run -it --rm ubuntu cat etc/resolv.conf.开一个临时 Ubuntu 容器,看看容器内部正在使用哪个 DNS 配置
-it
给你一个交互终端环境。
不过这条命令里其实不是必须,因为 cat 不是交互程序,不加通常也能跑。
--rm
容器运行结束后自动删除。
所以这是一个"一次性临时容器"。
启动一个临时 Ubuntu 容器在容器里执行 cat etc/resolv.conf
把文件内容输出到终端
命令结束,容器自动删除

不是在 /etc/docker/daemon.json 文件 配置的吗?为什么看cat etc/resolv.conf?Docker 的容器 DNS 配置最终会映射到容器里的 resolver 配置文件
"因为 daemon.json 是配置来源,resolv.conf 是容器里的实际结果,所以要看结果文件来验证配置是否生效。"



为什么要给容器配置DNS?给容器配置 DNS,是为了让容器能正确地把域名解析成 IP,从而正常访问软件源、网站、接口和各种网络服务。




手动指定容器的配置
docker run -it --rm -h host_ubuntu --dns=114.114.114.114 --dns-search=test.com ubuntu
临时开一个 Ubuntu 容器,主机名叫 host_ubuntu,查域名优先问 114.114.114.114,短主机名默认补 .test.com
--dns 解决的是:问谁查地址--dns-search 解决的是:遇到短名字时,自动补什么后缀。自动补域名后缀

-h 主机名,给容器起名


--dns=IP_ADDRESS: 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名。
etc/hosts = 把"域名或主机名"手动对应到 IP 地址的本地表





Docker Dockerfile
什么是 Dockerfile?文本文件,里面写的是:"怎么一步一步制作一个 Docker 镜像。"
它是干什么的
它告诉 Docker:
以哪个基础镜像开始
要装哪些软件
要复制哪些文件进去
工作目录设在哪
容器启动时执行什么命令





RUN:用于执行后面跟着的命令行命令。shell 格式是"让 shell 帮你执行命令",exec 格式是"直接执行程序本身"。

shell格式,RUN <命令行命令>。# <命令行命令> 等同于,在终端操作的 shell 命令。


exec 格式:RUN ["可执行文件", "参数1", "参数2"]
exec 格式里第一个元素,一般就是要直接运行的"可执行文件"或命令。
exec 格式里,第一个元素就是要直接启动的程序,后面的元素都是传给它的参数。



Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。下载、使用、清理,尽量放在同一个 RUN 里完成






$ docker build -t nginx:v3 . 使用当前目录中的 Dockerfile 和相关文件,构建一个名为 nginx:v3 的镜像
-t nginx:v3
给构建出来的镜像打标签。
这里:
nginx 是镜像名
v3 是标签 tag

. 是构建上下文是当前目录。


上下文路径。Dockerfile 在构建时"能访问哪些本地文件"。只准用哪个目录里的材料做镜像


为什么要有这个概念?





指令详解
COPY,从上下文目录中复制文件或者目录到容器里指定路径。
COPY = 从构建可访问的来源里拿文件,复制到当前镜像阶段里;源路径看 context,目标路径看 / 和 WORKDIR,目标不存在会自动建,结尾 / 会影响它被当成文件还是目录。
如果目标以 / 开头,就是相对于镜像根目录的绝对路径;如果不以 / 开头,它就是相对于当前 WORKDIR 的相对路径。目标不存在时,Docker 会创建缺失的目录




结尾有没有 / 很重要

copy默认从 build context 复制,也可以用 --from 从 build stage、named context 或另一个 image 复制





ADD
ADD 比 COPY 多了一些"额外能力",但正因为它会偷偷多做事,所以平时更推荐用 COPY。 Docker 官方现在的定义是:ADD 除了能从 build context 复制本地文件/目录,还能直接处理 远程 URL 和 Git 仓库;而 COPY 更"单纯",主要就是复制文件
本地 tar 自动解压




ADD 支持从远程 URL 加文件,也支持把 Git 仓库作为源并克隆到镜像里的目标目录


CMD
CMD 是给容器设置"默认启动命令"。
如果你运行容器时没有额外指定命令,就执行它;如果你在 docker run 后面又写了别的命令,通常会把它覆盖掉。Docker 官方对 CMD 的定义就是:为执行中的容器提供默认命令,且一个 Dockerfile 里只有最后一个 CMD 生效。

CMD <shell 命令>

CMD ["可执行文件", "参数1", "参数2"](exec form)

CMD ["参数1", "参数2"] 给 ENTRYPOINT 提供默认参数的

docker run 能覆盖 CMD


多个 CMD 只有最后一个生效"

ENTRYPOINT 规定"容器启动时一定要执行的主程序".-entrypoint 覆盖 Dockerfile 里的 ENTRYPOINT
ENTRYPOINT 用来规定"容器启动时一定要执行的主程序",而 CMD 更像是给这个主程序提供"默认参数"。 Docker 官方也是这么描述两者配合关系的:ENTRYPOINT 更适合把容器当成一个可执行程序来用,CMD 则适合给 ENTRYPOINT 提供默认参数;docker run 镜像 参数... 会覆盖 CMD,并把这些参数追加到 exec 形式的 ENTRYPOINT 后面




菜鸟应该是写错了
ENV 用来在镜像里设置环境变量。ENV 会持久保留到最终镜像和容器里
ENV 用来在镜像里设置环境变量。
设置以后,这个变量不仅能在后续的 RUN、CMD、ENTRYPOINT 等指令里用到,而且将来用这个镜像启动出来的容器里也会保留下来。




ARG 只在构建过程中可用,默认不会成为镜像里的环境变量,也不会自动出现在容器里
ARG 就是 构建时参数:它主要给 Dockerfile 的构建过程用,可以让你在 docker build 时传不同的值;但它不会像
ENV 那样自动变成运行中容器里的环境变量



VOLUME 这个目录里的数据,不要只放在容器自己身上,最好单独存出去
"挂外部存储"就是把容器里的某个目录,接到容器外面去。外面可以是你电脑上的一个真实目录,也可以是 Docker 帮你管理的一块数据区
容器里的文件,默认是跟着容器走的.重启容器:容器还是那个容器,里面原来写进去的文件通常还在. 删除容器:那个容器本身没了,写在它自己里面的数据通常也就没了




VOLUME 这个目录里的数据,不要只放在容器自己身上,最好单独存出去



"挂外部存储"就是把容器里的某个目录,接到容器外面去。外面可以是你电脑上的一个真实目录,也可以是 Docker 帮你管理的一块数据区
挂到宿主机自己指定的目录。宿主机目录:容器目录 → 你自己指定挂到本机哪里

挂到 Docker 自己管理的一块存储。这叫 volume。你不给宿主机具体目录,只给一个卷名。卷名:容器目录 → 交给 Docker 管,宿主机具体位置你通常不用管。docker volume ls 列出docker 管理的卷

VOLUME /data,它只是在镜像里声明:容器里的 /data 是个适合挂外部存储的位置。真正"外部存储挂哪里",是在 docker run 时决定的


忘了挂载,也会自动挂匿名卷"

docker run -v 能"修改挂载点

镜像运行时,Docker 会为 /myvol 创建新 volume,并把镜像里这个位置原本已有的数据初始化到新 volume 里

EXPOSE 仅仅只是声明端口


WORKDIR:WORKDIR 会为后续的 RUN、CMD、ENTRYPOINT、COPY、ADD 设置工作目录;如果目录不存在,会自动创建。给后面的命令指定"默认当前目录"

RUN 文件系统变化会保留,shell 的"当前状态"不会保留。
RUN 的文件改动会保留到下一层,所以你 RUN mkdir /app 创建的目录,后面通常也还在。
但是你在某个 RUN 里临时 cd 到别的目录,这个"当前目录状态"不会自动延续到下一个 RUN
WORKDIR 可以写多次,而且相对路径会基于前一个 WORKDIR 继续拼。绝对路径,直接重设



HEALTHCHECK





ONBUILD 先埋一个触发器,现在不执行,等别人拿这个镜像当基础镜像时再执行
ONBUILD 是在当前 Dockerfile 构建完成之后,当该镜像被别的 Dockerfile FROM 时才执行
LABEL 给镜像贴"说明标签"



STOPSIGNAL:设置"当 Docker 要停止容器时,先发给容器主进程的那个信号"



信号(signal)就是操作系统发给进程的一种"通知"




























