docker-常见概念解释

简述Docker

Docker是一个开源的应用容器引擎,允许开发者打包他们的应用以及应用的依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器是完全使用沙盒机制,相互之间不会有任何接口。

常见命令解释

1. docker image ls --digests

这个命令是用来列出本地的Docker镜像,包括它们的摘要信息,重点是--digests

  • 作用: 镜像的摘要是一个SHA256哈希值,代表镜像内容的唯一标识。不同的镜像版本或构建会产生不同的摘要值,即使标签(如latestv2)相同。使用--digests选项可以帮助你确切地知道正在使用或分发的是哪个版本的镜像,增加了操作的精准性和安全性。
  • 为什么更精准: 标签可能会被重用于不同的镜像内容,但摘要值是基于镜像内容计算得出的,因此对于确切地标识和引用特定的镜像版本非常有用。

2. docker commit --author “xxx” --message “xxx” webserver nginx:v2 不推荐使用,建议用dockerfile或者compose

这个命令是用来从容器创建一个新的镜像。

  • --author选项: 指定创建镜像的作者信息,这对于记录镜像的来源非常有帮助。

  • --message选项: 提供关于镜像更改的信息,有助于其他用户了解这个镜像版本引入了哪些变动或特性。

  • webserver: 这是你要提交更改的容器的ID或名称,即你对哪个正在运行的容器的现有状态做了快照,以创建新镜像。

  • nginx:v2: 这是新创建的镜像的目标标签,其中nginx是镜像的名称,v2是这个镜像的版本标签。

  • 主要作用: 这个命令的主要作用是将对一个运行中容器所做的更改(文件变动、环境配置等)保存成一个新的镜像。这对于应用的快速迭代和版本管理非常有用,允许开发者在现有容器的基础上快速构建新的镜像版本。

DockerFile常用命令

1. CMD

Dockerfile中,CMD指令的主要目的是指定容器启动时默认执行的命令。当你运行一个容器时,CMD指令定义的命令会被执行,除非你在docker run命令后明确指定了其他命令。

比如CMD ["java", "MyApp"]这一行具体来说意味着:

  • 当这个Docker容器启动时,它会默认执行java MyApp这个命令。
  • 这里的java是启动Java应用程序的命令,而MyApp是你要运行的Java程序的主类名。
  • CMD指令中的命令使用JSON数组格式指定,这种格式推荐用于执行命令,因为它正确地将命令和参数分开处理,避免了shell中的一些解析问题。

这意味着当你基于这个Dockerfile创建镜像,并运行一个容器时,Docker会自动在容器内执行java MyApp命令,启动你的Java应用程序。这种方式使得容器化的应用可以预设一个明确的入口点,保证容器运行起来即执行你预定的应用逻辑。

如果你需要在容器启动时运行一些更复杂的命令或脚本,你也可以在CMD指令中指定它们,或者使用ENTRYPOINT指令来定义一个固定的启动命令,然后通过CMD提供该命令的默认参数。

2. RUN

CMD ["java", "MyApp"]RUN javac MyApp.java)在Dockerfile中扮演着不同的角色,让我们来逐一解析它们的含义和作用:

CMD ["java", "MyApp"]
  • 作用CMD指令在Docker中用于指定容器启动时默认执行的命令。在这个例子中,CMD ["java", "MyApp"]的意思是,当容器启动时,默认执行java MyApp命令,即运行编译后的Java程序MyApp
  • 特点:如果用户在启动容器时提供了命令(例如docker run <image> <command>),则CMD指定的默认命令将被用户提供的命令覆盖。CMD更多地作为容器的默认运行行为提供。
RUN javac MyApp.java
  • 作用RUN指令用于在构建Docker镜像的过程中执行命令,其结果会被包含在最终的镜像中。在这个例子中,RUN javac MyApp.java的意思是,在构建镜像的过程中,执行javac MyApp.java命令,即编译Java源文件MyApp.java生成可执行的Java字节码文件。这个步骤是在创建镜像的过程中完成的,而不是在容器运行时。
  • 特点RUN指令执行的命令及其结果(例如文件的创建、修改)会直接影响构建出的镜像内容,它是镜像构建过程的一部分。
为什么需要编译Java程序

编写Dockerfile时包含RUN javac MyApp.java的原因是,Java程序通常需要先从.java源文件编译成.class字节码文件,之后才能通过JVM(Java虚拟机)运行。这个编译过程需要在创建镜像时就完成,以确保镜像中包含了可直接运行的程序。

一个更精确的Dockerfile示例

为了避免混淆,我们应该确保在Docker镜像构建过程中明确区分编译和运行两个阶段。如果我们假设MyApp.java依赖于编译,那么在Dockerfile中使用RUN javac MyApp.java来编译Java程序是必要的。但要注意的是,如果你的Java项目很大并且有复杂的构建过程,可能需要使用更高级的构建工具(如Maven或Gradle),而不是简单的javac

# 假设基础镜像已经安装了Java
FROM some-base-image-with-java

# 将Java项目文件复制到镜像中
COPY ./my-java-project /app

# 设置工作目录
WORKDIR /app

# 编译Java程序
RUN javac MyApp.java

# 容器启动时运行Java程序
CMD ["java", "MyApp"]

这样,当你通过这个Dockerfile构建镜像,并随后运行容器时,容器会默认执行CMD指定的java MyApp命令,运行你的Java应用。
如果你的Java项目通常通过Git进行版本控制,并且使用Maven(假设compileinstall命令指的是Maven的生命周期阶段)或类似工具进行构建和部署,你的Dockerfile可以按照以下步骤编写,以确保在Docker容器中也能正确构建和运行你的项目。

基础步骤
  1. 从包含Java和Maven的基础镜像开始:选择一个已经安装了Java和Maven的Docker基础镜像。如果你使用的是其他构建工具(如Gradle),请选择相应的基础镜像或安装相应的工具。

  2. 复制项目文件到镜像中:使用COPY指令将项目文件从你的本地文件系统复制到镜像中。

  3. 构建项目:使用RUN指令执行Maven的构建命令,如mvn clean install,来构建你的项目。这会编译你的代码,运行测试,并打包成可执行的jar或war等格式。

  4. 设置启动命令:使用CMD指令指定容器启动时执行的命令,比如运行Maven生成的jar文件。

示例Dockerfile

假设你的Java项目是一个简单的Spring Boot应用,可以被打包成一个可执行的jar文件。以下是一个基本的Dockerfile示例:

# 使用一个包含Java和Maven的基础镜像
FROM maven:3.6.3-openjdk-11

# 设置工作目录
WORKDIR /app

# 将本地的项目文件复制到镜像的工作目录中
COPY . /app

# 使用Maven命令构建应用
RUN mvn clean install

# 暴露应用运行的端口
EXPOSE 8080

# 设置启动时运行Java应用
CMD ["java", "-jar", "target/myapp-0.0.1-SNAPSHOT.jar"]

注意事项

  • 基础镜像:选择合适的基础镜像非常重要,确保它包含了你的项目构建所需的所有环境和工具。maven:3.6.3-openjdk-11是一个包含了Maven和OpenJDK 11的官方镜像,适用于大多数Java项目。
  • 构建缓存:Docker在构建过程中会利用缓存来加速后续构建。如果你的项目依赖没有改变,RUN mvn clean install步骤可能会被缓存,导致实际上没有执行最新的构建。确保在需要的时候清除Docker缓存或适当使用Docker构建参数。
  • 部署:在实际部署过程中,你可能需要根据项目和运行环境的具体要求调整Dockerfile,比如设置环境变量、配置卷(Volumes)用于持久化或共享数据等。

通过这种方式,你可以将项目的构建和部署过程容器化,实现一致的开发、测试和生产环境,提高应用的可移植性和易部署性。

3.onbuild

Docker中的ONBUILD指令是一个特殊的指令,它允许一个镜像在作为基础(父)镜像被另一个构建使用时,触发一些预定义的指令。这些被触发的指令只会在ONBUILD镜像被继承时运行,而不是在ONBUILD镜像本身被构建时运行。这对于创建一些预配置的基础镜像特别有用,当这些基础镜像被其他项目或镜像继承时,可以自动执行一些初始化的构建步骤。

举例介绍

假设你正在创建一个Java应用的Docker基础镜像,你希望在这个基础镜像的基础上构建具体的应用镜像时,自动将应用的.jar文件复制到镜像中,并且设置默认的启动命令。你可以在基础镜像的Dockerfile中使用ONBUILD指令来实现这个目的。

基础镜像的Dockerfile
# 使用Java官方镜像作为基础镜像
FROM openjdk:11-jre-slim

# 设置工作目录
WORKDIR /app

# 当基础镜像被另一个Dockerfile继承时,复制构建上下文中的target/*.jar到工作目录
ONBUILD COPY target/*.jar /app/

# 当基础镜像被另一个Dockerfile继承时,设置容器启动时默认执行的命令
ONBUILD CMD ["java", "-jar", "app.jar"]

在这个例子中,ONBUILD COPYONBUILD CMD指令不会在基础镜像被构建时执行。相反,当另一个Dockerfile使用这个镜像作为基础镜像时,这些ONBUILD指令才会被触发。

派生镜像的Dockerfile
# 使用上面创建的基础镜像
FROM my-java-base-image

# 这里不需要额外的指令,因为ONBUILD指令会自动执行

当你构建这个派生镜像时,ONBUILD指令在基础镜像中定义的操作(如复制.jar文件和设置启动命令)会自动执行。这样,任何基于my-java-base-image基础镜像的Dockerfile都会自动继承这些构建步骤,简化了派生镜像的构建过程。

注意事项

  • ONBUILD指令通常用于构建那些被设计为作为其他镜像基础的镜像。
  • 使用ONBUILD指令需要谨慎,因为它可能会导致构建过程变得难以理解和预测,特别是在多级继承的情况下。
  • 确保派生镜像的构建上下文中包含了ONBUILD指令需要的文件或资源。

通过合理使用ONBUILD指令,可以极大地提高Docker镜像的重用性和模块化,使得基础镜像更加灵活和强大。

4. docker exec

docker exec命令在Docker容器中运行命令,它允许你在已经运行的容器内部执行单个命令或启动一个新的进程。这个命令非常强大,因为它提供了与运行中的容器交互的能力,而不需要重新启动容器。以下是docker exec的一些主要好处:

1. 实时调试和问题诊断

使用docker exec,你可以在容器运行期间进入容器内部,执行诊断命令,如ps, top, cat, tail等,帮助你实时监控和诊断应用程序的状态和问题。这对于快速定位问题和调试非常有帮助。

2. 动态修改容器状态

docker exec可以用来修改运行中容器的状态,例如,动态地修改配置文件或数据库迁移。这使得在不停止和重启容器的情况下,对应用进行必要的调整成为可能。

3. 便捷的数据管理

你可以使用docker exec命令来执行数据备份和恢复操作。例如,你可以在数据库容器内执行数据库备份命令,或将外部数据导入到容器中的数据库。

4. 容器内部管理任务

docker exec允许你执行容器内部的管理任务,比如更新软件包、执行脚本或启动辅助进程等。这对于管理和维护容器化应用非常方便。

5. 多进程管理

虽然每个Docker容器通常运行一个主进程,但有时你可能需要在同一个容器内运行额外的辅助进程。docker exec可以用来在容器内启动这些额外的进程,虽然这不是最佳实践(Docker容器理论上应该是单进程的),但在某些特定情况下可能非常有用。

使用示例

假设你有一个运行中的容器,其ID或名称为mycontainer,你想在其中执行一个shell命令。可以使用如下命令:

docker exec mycontainer ls /app

这个命令会在mycontainer容器的/app目录下执行ls命令,列出该目录下的文件和文件夹。

如果你需要以交互式终端的方式进入容器,可以使用:

docker exec -it mycontainer /bin/bash

这会启动/bin/bash进程在mycontainer容器中,提供一个交互式shell环境。

注意事项
  • 在使用docker exec时,应该谨慎考虑安全性,特别是当执行可能影响容器安全或稳定性的命令时。
  • 尽管docker exec非常强大,但最好避免在生产环境中频繁地使用它来进行应用程序的常规操作,因为这可能违背了容器应该是无状态和不可变的原则。

总之,docker exec是一个非常实用的工具,可以帮助开发人员和系统管理员在不打断服务的情况下,管理和调试容器化应用。

Docker提供了导入(docker import)和导出(docker export)容器的功能,这两个操作使得用户能够轻松地分享和迁移容器。让我们详细了解这两个命令的用途、用法以及它们之间的区别。

5. docker export

docker export命令用于将运行中的容器的文件系统导出为一个tar归档文件。这个操作主要用于备份容器的当前状态,或者需要将容器迁移到另一个系统上。它不会包括容器使用的卷、环境变量配置或已构建镜像的层次结构。

用法

假设有一个正在运行的容器,其ID或名称为mycontainer,你想要将其导出到一个名为container.tar的文件中:

docker export mycontainer > container.tar

或者使用-o选项直接指定输出文件:

docker export -o container.tar mycontainer
docker import

docker export相对应,docker import命令用于从归档文件创建一个Docker镜像。这个归档文件可以是通过docker export命令创建的,也可以是任意的tar归档文件。导入操作生成的是一个新的镜像,而不是一个容器。如果需要,可以从这个镜像启动新的容器。

用法

假设有一个名为container.tar的归档文件,你想要从这个文件创建一个新的镜像:

cat container.tar | docker import - new-image-name:tag

或者直接指定文件路径:

docker import container.tar new-image-name:tag

区别和选择

  • 导出容器 vs. 保存镜像docker export用于导出容器的文件系统,而docker save用于保存镜像及其元数据。如果你想保留关于镜像的构建信息和历史,使用docker save来保存镜像会更合适。
  • 导入归档文件 vs. 加载镜像docker import是从归档文件创建镜像,而docker load用于加载通过docker save命令保存的镜像文件。如果你有一个完整的镜像导出文件(包含元数据),应该使用docker load

使用场景

  • 备份和迁移:当需要备份某个容器的状态,或者将容器迁移到另一个没有Docker镜像仓库访问权限的环境时,docker exportdocker import非常有用。
  • 快速分享:如果你想快速分享一个容器的状态给其他人,而不关心保存整个镜像的历史和元数据,这两个命令也非常适合。

注意事项

  • 使用docker export导出的容器不包括其卷内的数据。如果容器配置了外部数据卷,这部分数据不会被包含在导出的文件中。
  • docker import创建的镜像不包含任何历史记录或构建信息,这意味着导入的镜像是一个新的起点,没有任何构建层次结构。

总之,docker exportdocker import提供了一种简单的方式来备份、迁移和分享容器的文件系统,但它们并不适用于需要保留镜像完整性和历史记录的场景。在实际使用中,应根据具体需求选择最合适的工具。

Docker中的缓存及清理

在Docker构建过程中清除缓存可以确保每一次都从头开始构建,这对于确保你的镜像总是使用最新的代码和依赖非常有帮助。以下是一些清除Docker缓存的方法:

使用docker build命令的--no-cache选项

这是最直接的方式来避免使用任何缓存,确保构建过程中的每一步都是全新执行的。使用--no-cache选项构建镜像的命令如下:

docker build --no-cache -t your-image-name .

这个命令会构建一个新的镜像,标签为your-image-name,并且在构建过程中不使用任何之前的缓存。这确保了所有的RUNCOPYADD指令都会重新执行。

使用docker build命令的--build-arg选项

如果你只想让某些步骤不使用缓存,可以通过改变构建参数(build arguments)的值来实现。因为当构建参数的值变化时,Docker会从改变点开始重新执行构建过程,之前的缓存将不会被使用。

docker build --build-arg CACHEBUST=$(date +%s) -t your-image-name .

这里,CACHEBUST是一个构建参数,其值为当前的Unix时间戳。因为这个值在每次构建时都会变,所以实际上每次构建都是从头开始的。记得在Dockerfile中引用这个构建参数:

ARG CACHEBUST

手动移除Docker缓存

除了在构建时指定不使用缓存,你还可以手动清除Docker的缓存数据。这包括移除悬挂镜像、未使用的数据卷、网络和构建缓存。以下是一些用于手动清理的命令:

  • 移除悬挂镜像:这些是未被标记且未被容器使用的镜像。

    docker image prune -f
    
  • 移除未使用的Docker对象:包括悬挂镜像、停止的容器、未使用的网络和数据卷。

    docker system prune -f
    
  • 移除构建缓存:删除所有构建缓存,释放空间。

    docker builder prune -f
    

使用这些命令可以帮助你管理Docker的磁盘使用,确保构建环境的清洁。然而,频繁地完全不使用缓存可能会显著增加构建时间。通常建议仅在确实需要确保一切从零开始时,才使用这些方法。

挂载点常见概念及内容

假设你启动容器后,使用 mount 命令,显示如下内容

overlay on / type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/CHY2UEXA4V7RWQ2CVFVMPJDJD3:/var/lib/docker/overlay2/l/JYGJT66M4W3AXKSX6MPE2475XC:/var/lib/docker/overlay2/l/LE57Z3FGPMENQHC2LTZJ6C2N3B:/var/lib/docker/overlay2/l/CE5MXRPWV7WKUP75A3LBE25VM5:/var/lib/docker/overlay2/l/UKSD6FNJZS34NFJCIINN5ARXXZ:/var/lib/docker/overlay2/l/W7RGUAUIQXE7Y4KAO6J7GFYO4U:/var/lib/docker/overlay2/l/4RNMZ2FCRZXBEHDVQ2IKDVVMBP:/var/lib/docker/overlay2/l/NTIIS4QFT6LKLQNOAYNEHPF6LF:/var/lib/docker/overlay2/l/EKJCQL4USCWLOCMLTHOLCE33WA,upperdir=/var/lib/docker/overlay2/816795dbf94a743a525f94b8f42c04b2d64fc39e7c8ffa269487d518192ab042/diff,workdir=/var/lib/docker/overlay2/816795dbf94a743a525f94b8f42c04b2d64fc39e7c8ffa269487d518192ab042/work) proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) tmpfs on /dev type tmpfs (rw,nosuid,size=65536k,mode=755) devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666) sysfs on /sys type sysfs (ro,nosuid,nodev,noexec,relatime) tmpfs on /sys/fs/cgroup type tmpfs (rw,nosuid,nodev,noexec,relatime,mode=755) cpuset on /sys/fs/cgroup/cpuset type cgroup (ro,nosuid,nodev,noexec,relatime,cpuset) cpu on /sys/fs/cgroup/cpu type cgroup (ro,nosuid,nodev,noexec,relatime,cpu) cpuacct on /sys/fs/cgroup/cpuacct type cgroup (ro,nosuid,nodev,noexec,relatime,cpuacct) blkio on /sys/fs/cgroup/blkio type cgroup (ro,nosuid,nodev,noexec,relatime,blkio) memory on /sys/fs/cgroup/memory type cgroup (ro,nosuid,nodev,noexec,relatime,memory) devices on /sys/fs/cgroup/devices type cgroup (ro,nosuid,nodev,noexec,relatime,devices) freezer on /sys/fs/cgroup/freezer type cgroup (ro,nosuid,nodev,noexec,relatime,freezer) net_cls on /sys/fs/cgroup/net_cls type cgroup (ro,nosuid,nodev,noexec,relatime,net_cls) perf_event on /sys/fs/cgroup/perf_event type cgroup (ro,nosuid,nodev,noexec,relatime,perf_event) net_prio on /sys/fs/cgroup/net_prio type cgroup (ro,nosuid,nodev,noexec,relatime,net_prio) hugetlb on /sys/fs/cgroup/hugetlb type cgroup (ro,nosuid,nodev,noexec,relatime,hugetlb) pids on /sys/fs/cgroup/pids type cgroup (ro,nosuid,nodev,noexec,relatime,pids) rdma on /sys/fs/cgroup/rdma type cgroup (ro,nosuid,nodev,noexec,relatime,rdma) misc on /sys/fs/cgroup/misc type cgroup (ro,nosuid,nodev,noexec,relatime,misc) cgroup on /sys/fs/cgroup/systemd type cgroup (ro,nosuid,nodev,noexec,relatime,xattr,name=systemd) mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime) shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=65536k) /dev/sde on /etc/resolv.conf type ext4 (rw,relatime,discard,errors=remount-ro,data=ordered) /dev/sde on /etc/hostname type ext4 (rw,relatime,discard,errors=remount-ro,data=ordered) /dev/sde on /etc/hosts type ext4 (rw,relatime,discard,errors=remount-ro,data=ordered) devpts on /dev/console type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666) proc on /proc/bus type proc (ro,nosuid,nodev,noexec,relatime) proc on /proc/fs type proc (ro,nosuid,nodev,noexec,relatime) proc on /proc/irq type proc (ro,nosuid,nodev,noexec,relatime) proc on /proc/sys type proc (ro,nosuid,nodev,noexec,relatime) tmpfs on /proc/acpi type tmpfs (ro,relatime) tmpfs on /proc/kcore type tmpfs (rw,nosuid,size=65536k,mode=755) tmpfs on /proc/keys type tmpfs (rw,nosuid,size=65536k,mode=755) tmpfs on /proc/timer_list type tmpfs (rw,nosuid,size=65536k,mode=755) tmpfs on /sys/firmware type tmpfs (ro,relatime)
现在对其中一些内容做些简单介绍:

Overlay 文件系统

  • Overlay: /type overlay部分表明这个容器使用了overlay2作为其存储驱动,它允许将多个目录层叠成单一的文件系统。lowerdirupperdirworkdir是overlay文件系统的关键组成部分,其中:
    • lowerdir是只读层,包含了镜像的基础层。
    • upperdir是可写层,包含了容器启动后所有的写操作(如文件修改和新文件创建)。
    • workdir是用于overlay文件系统操作的工作目录。

特殊文件系统

  • Proc: /proc是一个虚拟文件系统,提供了内核和进程信息的接口。
  • Tmpfs: 使用tmpfs挂载的目录如/dev/dev/shm,存储在内存中,不会持久化到磁盘。
  • Devpts: /dev/pts用于支持伪终端设备,使容器内部可以使用终端。
  • Sysfs: /sys提供了一个通过文件系统来访问和修改内核对象的接口,只读挂载到容器中。

Cgroup 文件系统

/sys/fs/cgroup目录下的各种挂载点对应于不同的Linux控制组(cgroups),它们用于限制、记录和隔离资源使用(CPU、内存、磁盘I/O等)。

其他挂载点

  • Mqueue: /dev/mqueue,用于POSIX消息队列。
  • 特定配置文件的挂载: /etc/resolv.conf/etc/hostname/etc/hosts这些文件通常从宿主机动态挂载到容器中,以保证容器有正确的网络配置和主机名解析设置。
  • Shm: /dev/shm是一个临时文件存储区域,通常用于进程间通信。

安全和隔离

  • 只读proc文件系统的挂载点(如/proc/sys/proc/irq等)说明容器中的应用程序受到限制,不能修改系统级的设置,这是Docker安全策略的一部分。
  • 临时文件系统(tmpfs)挂载点:如/proc/acpi/proc/kcore,这些通常用于防止容器修改或访问宿主机的核心部分,增加了隔离性。

这段输出揭示了Docker容器中文件系统的挂载策略和隔离技术。通过这种方式,Docker在提供必要的功能和灵活性的同时,也确保了容器的安全性和隔离性。

修改Docker容器的DNS

在Docker容器中更改DNS设置以使用特定的DNS服务器(如Google的8.8.8.8)而不是默认的(通常是宿主机的DNS设置),有几种方法可以实现。以下是一些常见的方法:

1. 在运行容器时指定DNS

当你使用docker run命令启动容器时,可以通过--dns选项来指定DNS服务器。例如,如果你想要使用Google的DNS服务器(8.8.8.8),可以这样做:

docker run --dns=8.8.8.8 <其他选项> <镜像名>

这将覆盖容器的/etc/resolv.conf文件,使得所有DNS查询都通过指定的DNS服务器(在这个例子中是8.8.8.8)。

2. 在Docker守护进程配置中设置默认DNS

如果你希望所有容器默认都使用特定的DNS服务器,而不是每次运行容器时都指定,你可以在Docker守护进程的配置文件中设置。Docker守护进程的配置文件通常位于/etc/docker/daemon.json。如果文件不存在,你可以创建它。

编辑或创建/etc/docker/daemon.json,加入以下内容:

{
  "dns": ["8.8.8.8"]
}

完成编辑后,你需要重启Docker守护进程以应用更改。这可以通过以下命令完成:

sudo systemctl restart docker

或者,如果你不使用systemd,可能需要使用其他命令如sudo service docker restart

3. 编辑容器的/etc/resolv.conf

另一个方法是,在容器已经启动之后,进入容器内部手动编辑/etc/resolv.conf文件,将nameserver设置为你想要的DNS服务器地址。这可以通过执行以下步骤完成:

  1. 使用docker exec命令进入运行中的容器:
docker exec -it <容器ID或名称> /bin/sh
  1. 使用文本编辑器(如vinano等)编辑/etc/resolv.conf文件,将nameserver行改为:
nameserver 8.8.8.8
  1. 保存文件并退出编辑器。

请注意,这种方法的改动在容器重启后不会保留。如果容器从镜像重新创建,更改也会丢失。

4. 修改宿主机的Docker Desktop

1. 确认Docker Desktop的设置
  • 打开Docker Desktop应用。
  • 进入Settings(设置)> Docker Engine(Docker引擎)。
  • 查看或修改"dns"设置为["8.8.8.8"],确保配置如下所示:
{
  "dns": ["8.8.8.8"]
}
  • 应用更改并重启Docker Desktop。

通过Docker Desktop进行的这种设置更改应该会覆盖任何由WSL2或Docker自身的默认设置。

2. 检查WSL2的resolv.conf管理

WSL2默认会自动管理resolv.conf文件,这可能会覆盖你的DNS设置。为了防止WSL2自动更改resolv.conf,你可以更新WSL2的配置来停止自动生成resolv.conf文件。

  • 在Windows中,编辑(如果不存在就创建)C:\Users\<你的用户名>\.wslconfig文件,并添加以下内容:
[wsl2]
generateResolvConf = false
  • 重启WSL2实例。你可以通过Windows命令行运行wsl --shutdown,然后重新打开WSL2终端来实现。
3. 手动设置WSL2的resolv.conf

在WSL2中,一旦你停用了自动管理resolv.conf,你可以手动编辑这个文件来指定DNS设置:

  • 打开WSL2终端。
  • 编辑/etc/resolv.conf文件(你可能需要sudo权限),设置内容如下:
nameserver 8.8.8.8
  • 保存文件并退出编辑器。
4. 重启Docker服务

在WSL2中,你可能需要重启Docker服务来确保配置的更改生效:

sudo service docker restart

或者,如果你是通过Docker Desktop启动的Docker服务,确保通过Docker Desktop界面重启Docker。

选择合适的方法

选择上述方法中的哪一个取决于你的具体需求:如果你只是临时需要更改一个容器的DNS设置,方法1可能是最简单的。如果你希望所有容器都使用相同的DNS设置,方法2更合适。方法3则适用于对正在运行的容器进行快速临时修改。

如果你在WSL2中的/etc/docker/daemon.json文件中已经设置了DNS,并且感觉设置没有生效,这可能是因为Docker Desktop对WSL2的集成方式导致的配置不生效。Docker Desktop在Windows上使用WSL2时,可能不完全遵循WSL2内的daemon.json配置文件。这里有几个步骤你可以尝试来确保DNS设置生效:

Docker网络连接

docker容器如何与宿主机进行网络交互

Docker0 虚拟网桥

首先,docker0虚拟网桥是Docker使用的默认网络桥接器。你可以将它想象成一个虚拟的交换机,它连接着不同的网络接口,允许数据包在它们之间转发。在Docker启动时,docker0网桥被自动创建,起到了容器和主机之间进行网络通信的桥梁作用。

IP地址分配

docker0网桥会被分配一个私有IP地址(通常是172.17.0.1),这个地址来自于专门为私人网络预留的IP地址段(根据RFC1918)。这个网桥的IP地址作为默认的网关地址,供容器使用。容器启动时,会自动获得同一网段(例如172.17.0.0/16)内的IP地址,从而能够通过docker0网桥与主机和其他容器通信。

Veth Pair 接口

每当一个Docker容器被创建时,Docker也会创建一对虚拟以太网接口(veth pair)。这对接口相当于一根双向的虚拟以太网电缆,数据包发送到一端会从另一端出来。

  • 容器内部的接口(eth0:一端的接口被放置在容器内,作为容器的网络接口(通常命名为eth0),让容器有了与外界通信的能力。
  • 挂载到docker0网桥的接口:另一端的接口则位于宿主机上,并被连接(挂载)到docker0网桥。这个接口的名称通常以veth开头,后面跟着一串字符(例如vethAQI2QT)。

网络通信

通过这种设置,主机可以与容器通信,容器之间也可以相互通信,所有的通信都通过docker0网桥进行。当数据包从一个容器发送出去时,它会经过容器内的eth0接口,通过与之对应的宿主机上的veth接口,进入docker0网桥,然后根据目的地被转发到另一个容器的eth0接口或者是宿主机的其他接口。

简单来说,Docker创建了一个虚拟的网络环境,其中docker0网桥像是一个交换机,连接着所有容器和宿主机的虚拟网络接口,使得宿主机和容器、容器与容器之间可以无缝通信。这个虚拟网络的架构为容器的网络通信提供了灵活性和隔离性。

  • 23
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值