docker

docker

第一章 安装docker

1.克隆虚拟机

bash 复制代码
#先修改主机名,ip地址

#卸除旧版本(可做可不做)
[root@docker~ 14:15:52]# yum remove docker-ce

#安装必要工具
[root@docker~ 14:20:32]# yum install -y yum-utils device-mapper-persistent-data lvm2 vim

#添加 Docker 阿里云镜像源
[root@docker~ 14:23:33]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo Adding repo from: https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

#生成yum缓存,目的是将新增的 Docker 镜像源的软件包信息下载到本地并缓存,加速后续安装 / 更新操作。
[root@docker~ 14:23:56]# yum makecache

#安装软件
[root@docker~ 14:24:34]# yum install -y docker-ce

#开启服务和查看状态
[root@docker~ 14:33:35]# systemctl enable docker.service --now
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
[root@docker~ 14:34:13]# systemctl status docker.service

2.配置镜像加速器(华为云)


看镜像加速器如何使用
bash 复制代码
#编辑配置文件
[root@docker~ 14:34:50]# vi /etc/docker/daemon.json
[root@docker~ 15:10:58]# cat /etc/docker/daemon.json
{
 "registry-mirrors":["https://39a647b5eebd49afb2bf08d443a75389.mirror.swr.myhuaweicloud.com"]
}

#重启服务
[root@docker~ 14:44:58]# systemctl restart docker

#查看镜像加速器
[root@docker~ 14:45:20]# docker info
.....
 Insecure Registries:
  127.0.0.0/8
 Registry Mirrors:
  `https://39a647b5eebd49afb2bf08d443a75389.mirror.swr.myhuaweicloud.com/`#看这里
 Live Restore Enabled: false

此时,关机打快照。

第二章 容器架构------what,why,

1.What - 什么是容器?

容器是一种轻量级、可移植、自包含的软件打包技术,使应用程序可以在几乎任何地方以相同的方式运 行。开发人员在自己笔记本上创建并测试好的容器,无需任何修改就能够在生产系统的虚拟机、物理服 务器或公有云主机上运行。

容器的组成:1. 容器本身 2. 依赖 :比如应用程序需要的库或其他软件

==容器在 Host 操作系统的用户空间中运行,与操作系统的其他进程隔离。这一点显著区别于传统的虚拟机。==而传统的虚拟化技术,比如 VMWare, KVM, Xen,目标是创建完整的虚拟机。为了运行应用,除了部署应 用本身及其依赖(通常几十 MB),还得安装整个操作系统(几十 GB)。

容器与虚拟机的区别

2. Why - 为什么需要容器?

因为容器使软件具备了超强的可移植能力。

3. How - 容器是如何工作的?

1.Docker核心概念 :镜像、容器和仓库而展开。

镜像 :是创建虚拟机的基础,类似于虚拟机镜像,可将其理解为一个只读模板。用户可以从网上下载一个已经做好的应用镜像,并直接使用。将镜像的内容和创建步骤描述在一个文本文件中,这个文件被称作 Dockerfile。

容器:是从镜像创建的应用运行实例,用户可以通过CLI(dockers)或是API启动,开始,停止和删除容器,并且容器是互相隔离,互不可见。

仓库:是docker集中存放镜像文件的场所。可以分为公开仓库和私有仓库。

2.docker架构
1.完整的Docker架构:

(1) 守护进程(Daemon):Docker守护进程(dockerd)侦听Docker API请求并管理Docker对象,,如图 像、容器、网络和卷。守护进程还可以与其他守护进程通信来管理Docker服务。

(2) REST API: 主要与Docker Daemon进行交互,比如Docker Cli或者直接调用REST API;

(3) 客户端(Docker Client): 它是与Docker交互的主要方式通过命令行接口(CLI)客户端(docker命 令),客户机将命令通过REST API发送给并执行其命令;

(4) Register Repository 镜像仓库: Docker注册表存储Docker镜像,可以采用Docker Hub是公共 注册仓库,或者采用企业内部自建的Harbor私有仓库;

(5) Image 镜像: 映像是一个只读模板,带有创建Docker容器的指令。映像通常基于另一个映像,还 需要进行一些额外的定制,你可以通过Docker Hub公共镜像仓库进行拉取对应的系统或者应用镜 像;

(6) Container 容器: 容器是映像的可运行实例。您可以使用Docker API或CLI创建、启动、停止、 移动或删除容器。您可以将一个容器连接到一个或多个网络,将存储附加到它,甚至根据它的当前 状态创建一个新映像。

(7) Services : Docker引擎支持集群模式服务允许您跨多个Docker守护进程()扩展管理容器,服务允 许您定义所需的状态,例如在任何给定时间必须可用的服务副本的数量。默认情况下,服务在所有 工作节点之间进行负载平衡。对于使用者来说Docker服务看起来是一个单独的应用程序;

2.Docker 的核心组件包括
  1. Docker 客户端 - Client
  2. Docker 服务器 - Docker daemon
  3. Docker 镜像 - Image
  4. Registry
  5. Docker 容器 - Containe
3. Docker组件如何协作
  1. Docker 客户端执行 docker run 命令。
  2. Docker daemon 发现本地没有 httpd 镜像。
  3. daemon 从 Docker Hub 下载镜像。
  4. 下载完成,镜像 httpd 被保存到本地。
  5. Docker daemon 启动容器。

4.镜像

1.base 镜像
含义:
  1. 不依赖其他镜像,从scratch构建。
  2. 其他镜像可以为之为基础进行扩展。

所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。并且base镜像提供的是最小安装的Linux 发行版。

2.最小镜像:hello-world

5.镜像的分层结构

Docker 支持通过扩展现有镜像,创建新的镜像。

实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。比如 我们现在构建一个新的镜像,Dockerfile 如下:

① 新镜像不再是从 scratch 开始,而是直接在 Debian base 镜像上构建。

② 安装 emacs 编辑器。

③ 安装 apache2。

④ 容器启动时运行 bash。

构建过程如图示:

可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一 层。

这样最大的好处就是:共享资源

可写的容器层

当容器启动时,一个新的可写层被加载到镜像的顶部。 这一层通常被称作"容器层","容器层"之下的都叫"镜像层"。

对容器增删改差操作如下:

注意

​ 1.只有容器层是可写的,容器层下面的所有镜像层都是只读的。

  1. 所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。
  2. 容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修 改,所以**镜像可以被多个容器共享**。

6.构建镜像

Docker 提供了两种构建镜像的方法:
  1. docker commit 命令
  2. Dockerfile 构建文件
1. docker commit

docker commit 命令是创建新镜像最直观的方法,其过程包含三个步骤: 1. 运行容器

2.修改容器

3.将容器保存为新的镜像

2. Dockerfile
1.Dockerfile内容基础知识:
  1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
  2. 指令按照从上到下,顺序执行
  3. #表示注释
  4. 每条指令都会创建一个新的镜像层并对镜像进行提交
2. 构建镜像过程
  1. 从 base 镜像运行一个容器。
  2. 执行一条指令,对容器做修改。
  3. 执行类似 docker commit 的操作,生成一个新的镜像层。
  4. Docker 再基于刚刚提交的镜像运行一个新容器。
  5. 重复 2-4 步,直到 Dockerfile 中的所有指令执行完毕。
过程解析

① 当前目录为 /root。

② Dockerfile 准备就绪。

③ 运行 docker build 命令, -t 将新镜像命名为 ubuntu-with-vim-dockerfile ,命令末尾的 . 指明 build context 为当前目录。Docker 默认会从 build context 中查找 Dockerfile 文件,我们也可以通过 - f 参数指定 Dockerfile 的位置。

④ 从这步开始就是镜像真正的构建过程。 首先 Docker 将 build context 中的所有文件发送给 Docker daemon。build context 为镜像构建提供所需要的文件或目录。 Dockerfile 中的 ADD、COPY 等命令可以将 build context 中的文件添加到镜像。此例中,build context 为当前目录 /root ,该目录下的所有文件和子目录都会被发送给 Docker daemon。 所以,使用 build context 就得小心了,不要将多余文件放到 build context,特别不要把 / 、 /usr 作 为 build context,否则构建过程会相当缓慢甚至失败。

⑤ Step 1:执行 FROM ,将 ubuntu 作为 base 镜像。

⑥ Step 2:执行 RUN ,安装 vim

⑦ 镜像构建成功。

⑧ 镜像重命名为ubuntu-with-vim-dockerfile

3.Dockerfile 常用指令
  1. FROM :指定base镜像,第一条必须是FROM。

  2. MAINTAINER:设置镜像作者,可以是任意字符串。

  3. COPY:将文件从build context 复制到镜像。

    COPY支持两种形式:

    1. COPY src dest

    2. COPY ["src","dest"]

      注意:src只能指定build context中的文件或者目录。

  4. ADD:与COPY 类似,从build context 复制文件到镜像。不过如果src是归档文件(tar,zip,tgz,xz等),文件会被自动解压到dest。

  5. ENV:设置环境变量。

  6. EXPOSE:指定容器中的进程会监听的端口,Docker可以将其暴露出来。

  7. VOLUME:为文件或者目录声明为volume。

  8. WORKDIR:为后面的RUN,CMD,ENTRYPOINT,ADD或COPY指令设置镜像中的当前工作目录。

  9. RUN:在容器中运行指定的命令。

  10. CMD:容器启动时运行指定的命令。Dockerfile可以有多个CMD指令,但只有最后一个才生效。CMD可以被docker run之后的参数替换。

  11. ENTRYPOINT:设置容器启动时的命令,也可以有多个。

注意:RUN CMD ENTRYPOINT 三者的区别

  1. RUN 执行命令并创建新的镜像层,RUN 经常用于安装软件包。
  2. CMD 设置容器启动后默认执行的命令及其参数,但 CMD 能够被 docker run 后面跟的命令行参 数替换。
  3. ENTRYPOINT 配置容器启动时运行的命令。

7.镜像的缓存特性

Docker 会缓存已有镜像的镜像层,构建新镜像时,如果某镜像层已经存在,就直接使用,无需重新创建。

注意:

  1. 当改变 Dockerfile 指令的执行顺序,或者修改或添加指令,都会使缓存失效。因为Dockerfile 中每一个指令都会创建一个镜像层,上层是依赖于下层的。无论什么时候,只要某一层发生 变化,其上面所有层的缓存都会失效。
  2. 如果在构建镜像时不使用缓存 ,可以在 docker build 命令中加上 --no-cache 参数

8.使用公共Registry-华为云:上传自己的镜像


创建组织:


注意:地区不一样,前缀也不一样

通过上面获取的指令,到docker虚拟机上登录

bash 复制代码
[root@docker~ 10:30:35]# docker login -u cn-north-4@HST3WI2OHLRO9NKLHLE4 -p 8c59602bbf7a66c5d438165f01f94df300b2fce00cd36f7a4c11d59b6bdc6d6b swr.cn-north-4.myhuaweicloud.com

`Login Succeeded`

#修改镜像名
[root@docker~ 10:29:00]# docker tag dockfile swr.cn-north-4.myhuaweicloud.com/gcf/dockerfile:v1

#查看镜像
[root@docker~ 10:30:21]# docker images
REPOSITORY                                        TAG       IMAGE ID       CREATED         SIZE 
swr.cn-north-4.myhuaweicloud.com/gcf/dockerfile   v1        fc6cad79bd3e   17 months ago   4.43MB
dockfile                                          latest    fc6cad79bd3e   17 months ago   4.43MB

#上传镜像
[root@docker~ 10:30:39]# docker push swr.cn-north-4.myhuaweicloud.com/gcf/dockerfile:v1
The push refers to repository [swr.cn-north-4.myhuaweicloud.com/gcf/dockerfile]
495ba00f2547: Pushed
v1: digest: sha256:b9d9d9a75ef28e276bec598abc9d871da2a3ed13bbec82290920122aee86d52f size: 527
#这里注意不同区域的前缀不一样,swr是固定的,但是cn-north并不是,

上传镜像命名规则:

最后设置公开别人也可以下载。

9.搭建本地镜像仓库

1.镜像仓库
bash 复制代码
#启动 registry 容器
[root@docker~ 10:31:14]# docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:2
Unable to find image 'registry:2' locally
2: Pulling from library/registry
44cf07d57ee4: Pull complete
bbbdd6c6894b: Pull complete
8e82f80af0de: Pull complete
3493bf46cdec: Pull complete
6d464ea18732: Pull complete
Digest: sha256:a3d8aaa63ed8681a604f1dea0aa03f100d5895b6a58ace528858a7b332415373
Status: Downloaded newer image for registry:2
b94d43b1113003030ac3485515d12433440b81c2a0fda0385a1a00677644f0ed

#查看镜像
[root@docker~ 11:10:37]# docker images
REPOSITORY                                        TAG       IMAGE ID       CREATED         SIZE
dockfile                                          latest    fc6cad79bd3e   17 months ago   4.43MB
registry                                          2         26b2eb03618e   2 years ago     25.4MB

#通过 docker tag 重命名镜像,使之与 registry 匹配
[root@docker~ 11:11:18]# docker tag dockfile:latest localhost:5000/dockerfile:latest
[root@docker~ 11:12:18]# docker images
REPOSITORY                                        TAG       IMAGE ID       CREATED         SIZE
localhost:5000/dockerfile                         latest    fc6cad79bd3e   17 months ago   4.43MB
dockfile                                          latest    fc6cad79bd3e   17 months ago   4.43MB
registry                                          2         26b2eb03618e   2 years ago     25.4MB

#通过 docker push 上传镜像。
[root@docker~ 11:12:24]# docker push localhost:5000/dockerfile:latest
The push refers to repository [localhost:5000/dockerfile]
495ba00f2547: Pushed
latest: digest: sha256:b9d9d9a75ef28e276bec598abc9d871da2a3ed13bbec82290920122aee86d52f size: 527

#查询 Docker 私有仓库的镜像列表
[root@docker~ 11:13:11]# curl http://localhost:5000/v2/_catalog
{"repositories":["dockerfile"]}

#下载之前先删除本地的镜像
[root@docker~ 11:14:52]# docker rmi dockfile:latest
Untagged: dockfile:latest
[root@docker~ 11:15:43]# docker rmi localhost:5000/dockerfile:latest
Untagged: localhost:5000/dockerfile:latest
Untagged: localhost:5000/dockerfile@sha256:b9d9d9a75ef28e276bec598abc9d871da2a3ed13bbec82290920122aee86d52f

##从自建仓库下载镜像
[root@docker~ 11:16:12]# docker pull localhost:5000/dockerfile:latest
latest: Pulling from dockerfile
Digest: sha256:b9d9d9a75ef28e276bec598abc9d871da2a3ed13bbec82290920122aee86d52f
Status: Downloaded newer image for localhost:5000/dockerfile:latest
localhost:5000/dockerfile:latest

#查看验证
[root@docker~ 11:16:39]# docker images
REPOSITORY                                        TAG       IMAGE ID       CREATED         SIZE
localhost:5000/dockerfile                         latest    fc6cad79bd3e   17 months ago   4.43MB
swr.cn-east-3.myhuaweicloud.com/gcf/dockfile      v1        fc6cad79bd3e   17 months ago   4.43MB
swr.cn-north-4.myhuaweicloud.com/gcf/dockerfile   v1        fc6cad79bd3e   17 months ago   4.43MB
registry                                          2         26b2eb03618e   2 years ago     25.4MB
2.企业级私有仓库Harbor

10. docker 常用命令

1. docker images : 显示镜像列表
2. docker pull :从仓库下载镜像
3. docker push :将镜像上传到仓库
4. docker tag:给镜像打标签

注意: 一个镜像可以对应多个tag,只有当最后一个tag删除时,镜像才会被真正删除。

5. docker build : 从Dockerfile构建镜像
6. docker history :显示镜像构建历史·
7. docker rmi :删除docker host 中的镜像
注意:rmi 只能删除host 上的镜像,不会删除仓库中的镜像
8.save------保存本地镜像为文件
9.load------将本地镜像文件导入本地
10. 删除所有容器和镜像的命令以及只删除处于退出状态的
bash 复制代码
[root@docker ~]# docker rm -f $(docker ps -aq)     #删除所有容器

[root@docker ~]# docker rmi -f $(docker images -aq)   #删除所有镜像

#批量删除处于退出状态的容器
[root@docker~ 19:11:03]# docker rm -f $(docker ps -aq -f status=exited)
9079217673ec
3999a4f1c5c4
[root@docker~ 19:12:55]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS         PORTS     NAMES
cf601041ad4a   httpd     "httpd-foreground"       5 minutes ago    Up 5 minutes   80/tcp    busy_roentgen
404b65372491   ubuntu    "/bin/bash -c 'while..."   14 minutes ago   Up 8 minutes             busy_antonelli

第三章 容器

1.运行容器

docker run =docker create +docker start

容器运行结束就会处于退出状态,只有加上-a才会显示出来。下面的例子可以佐证:

bash 复制代码
[root@docker ~]# docker create ubuntu     #使用ubuntu镜像创建容器
3999a4f1c5c4e6e3d2bdc37d3a836dfc24e4e3187124e1ddc897fa8ea74c6dd2  #新创建的容器长ID
[root@docker ~]# docker ps -a   #create的容器状态时Created
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS   PORTS     NAMES
3999a4f1c5c4   ubuntu    "/bin/bash"   2 seconds ago   `Created`             

[root@docker ~]# docker start 3999a4f1c5c4           #启动容器,刚创建的容器ID
3999a4f1c5c4

#这里可以看出处于退出状态,即使刚才start,但是运行结束就会退出。
[root@docker~ 18:46:12]# docker ps -a
CONTAINER ID   IMAGE     COMMAND       CREATED              STATUS                      PORTS     NAMES
3999a4f1c5c4   ubuntu    "/bin/bash"   `About a minute ago  Exited (0) 40 seconds ago  `          cranky_lewin

#使用ubuntu镜像创建容器并执行pwd命令
[root@docker~ 18:45:48]# docker run ubuntu pwd
/

#也是运行结束就会退出
[root@docker~ 18:46:50]# docker ps -a
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS                     PORTS     NAMES
9079217673ec   ubuntu    "pwd"         5 minutes ago   Exited (0) 5 minutes ago             suspicious_hertz
3999a4f1c5c4   ubuntu    "/bin/bash"   7 minutes ago   Exited (0) 6 minutes ago             cranky_lewin

#不加-a 是没有容器的
[root@docker~ 18:51:44]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

让容器一直处于运行状态就是让其一直有任务执行:

bash 复制代码
#-d 放在后台运行,就不会占据一个终端
[root@docker~ 18:54:12]# docker run -d ubuntu /bin/bash -c "while true;do sleep 1;echo haha;done"
404b65372491ba53ea80fad61843b0b15d6611b6642d4bfb1eca85353e6b13bc

[root@docker~ 18:58:11]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
404b65372491   ubuntu    "/bin/bash -c 'while..."   49 seconds ago   Up 48 seconds             busy_antonelli
[root@docker~ 18:58:59]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                      PORTS     NAMES
404b65372491   ubuntu    "/bin/bash -c 'while..."   53 seconds ago   Up 52 seconds                         busy_antonelli
9079217673ec   ubuntu    "pwd"                    12 minutes ago   Exited (0) 12 minutes ago             suspicious_hertz
3999a4f1c5c4   ubuntu    "/bin/bash"              14 minutes ago   Exited (0) 13 minutes ago             cranky_lewin

2.stop ,start , restart,--restart ,pause和unpause

bash 复制代码
#如果想要对其停止,用stop命令,用上面的ubuntu容器
#docker stop 可以停止运行的容器。
[root@docker~ 18:59:03]# docker stop 404
404
[root@docker~ 19:00:06]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS                       PORTS     NAMES
404b65372491   ubuntu    "/bin/bash -c 'while..."   About a minute ago   Exited (137) 2 seconds ago             busy_antonelli
9079217673ec   ubuntu    "pwd"                    13 minutes ago       Exited (0) 13 minutes ago              suspicious_hertz
3999a4f1c5c4   ubuntu    "/bin/bash"              15 minutes ago       Exited (0) 14 minutes ago              cranky_lewin
[root@docker~ 19:00:09]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

#停止后,可以用start重新启动,docker start 会保留容器的第一次启动时的所有参数。
[root@docker~ 19:00:12]# docker start 404
404
[root@docker~ 19:02:58]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
404b65372491   ubuntu    "/bin/bash -c 'while..."   4 minutes ago   Up 2 seconds             busy_antonelli


#restart 是相当于执行了以此stop+start
[root@docker~ 19:04:09]# docker restart 404
404
[root@docker~ 19:04:19]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
404b65372491   ubuntu    "/bin/bash -c 'while..."   6 minutes ago   Up 3 seconds             busy_antonelli


#容器可能会因某种错误而停止运行。对于服务类容器,我们通常希望在这种情况下容器能够自动重启。
#启动容器时设置 --restart 就可以达到这个效果。
#如果docker run -d httpd不加--restart=always参数,attach进去ctrl_c(终止进程)不会重启。
[root@docker~ 19:04:22]# docker run -d --restart=always httpd
cf601041ad4a417418aef775a4680734d1a22502b8f053039bd6503c9bdf3db9
[root@docker~ 19:07:04]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
cf601041ad4a   httpd     "httpd-foreground"       11 seconds ago   Up 10 seconds   80/tcp    busy_roentgen
404b65372491   ubuntu    "/bin/bash -c 'while..."   9 minutes ago    Up 2 minutes              busy_antonelli



#有时我们只是希望暂时让容器暂停工作一段时间,比如要对容器的文件系统打个快照,或者 dcoker host 需要使用 CPU,这时可以执行 docker pause 。
#处于暂停状态的容器不会占用 CPU 资源,直到通过 docker unpause 恢复运行。
[root@docker~ 19:09:07]# docker pause cf
cf
[root@docker~ 19:09:36]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                  PORTS     NAMES
cf601041ad4a   httpd     "httpd-foreground"       2 minutes ago    Up 2 minutes (Paused)   80/tcp    busy_roentgen
404b65372491   ubuntu    "/bin/bash -c 'while..."   11 minutes ago   Up 5 minutes                      busy_antonelli

#unpase恢复运行
[root@docker~ 19:09:41]# docker unpause cf
cf
[root@docker~ 19:11:00]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS         PORTS     NAMES
cf601041ad4a   httpd     "httpd-foreground"       4 minutes ago    Up 3 minutes   80/tcp    busy_roentgen
404b65372491   ubuntu    "/bin/bash -c 'while..."   12 minutes ago   Up 6 minutes             busy_antonelli

3.进入容器的方法--两种

1.docker attach
bash 复制代码
[root@docker~ 19:15:11]# docker run -d ubuntu /bin/bash -c "while true ; do sleep 1;echo hello;done"
0b7d18bf3d0a3eca5357ca6a81baf6be6447cb5f07f9d182bd491d36fbfb21b3
[root@docker~ 19:16:07]# docker attach 0b
hello
hello
hello
hello
.....
2.docker exec
bash 复制代码
#-it 以交互模式打开
[root@docker~ 19:17:54]# docker exec -it 0b bash
root@0b7d18bf3d0a:/# ps -elf
F S UID          PID    PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
4 S root           1       0  0  80   0 -  1081 -      11:15 ?        00:00:00 /bin/bash -c while true ; do sleep 1;echo hello;done
4 S root         133       0  0  80   0 -  1147 -      11:18 pts/0    00:00:00 bash
0 S root         159       1  0  80   0 -   674 hrtime 11:18 ?        00:00:00 sleep 1
4 R root         160     133  0  80   0 -  1984 -      11:18 pts/0    00:00:00 ps -elf
root@0b7d18bf3d0a:/#
两者区别:
  1. attach 直接进入容器 启动命令 的终端,不会启动新的进程。
  2. exec 则是在容器中打开新的终端,并且可以启动新的进程。
  3. 如果想直接在终端中查看启动命令的输出,用 attach;其他情况使用 exec。
3.docker logs 只查看启动命令的输出
bash 复制代码
[root@docker~ 19:31:26]# docker logs 0b
hello
hello
hello
hello
hello
....

#docker logs -f  ,-f 可以持续打印输出。

4.容器的类别

1.服务类容器:

mysql , web server等。 服务类容器以 daemon 的形式运行,对外提供服务,通过 -d 以后 台方式启动这类容器是非常合适的。如果要排查问题,可以通过 exec -it 进入容器。

2.工具类容器:

多使用基础镜像,例如 busybox、debian、ubuntu 等。通常给能我们提供一个临时的工作环境,通常以 run -it 方式运行。

5.指定容器的三种方法:

  1. 短ID。

  2. 长ID。

  3. 容器名称。 可通过 --name 为容器命名。重命名容器可执行 docker rename 。

6. 限制容器的使用

1.内存限额

与操作系统类似,容器可使用的内存包括两部分:物理内存和 swap

正常情况下,--memory-swap 的值包含容器可用内存和可用swap。

Docker 通过下面两组参数来控制 容器内存的使用量。

  1. -m 或 --memory :设置内存的使用限额,例如 100M, 2G。
  2. --memory-swap :设置 内存+swap 的使用限额。
bash 复制代码
#使用Dockerfile构建镜像ubuntu-with-stress
[root@docker~ 09:54:22]# docker pull ubuntu
[root@docker~ 09:57:03]# docker build -t ubuntu-with-stress .
[root@docker~ 10:05:40]# cat Dockerfile
FROM ubuntu
MAINTAINER gcf
RUN apt-get -y update  && apt-get -y install stress
ENTRYPOINT ["/usr/bin/stress"]

#--vm 1 :启动 1 个内存工作线程。--vm-bytes 280M :每个线程分配 280M 内存。
#比m多
[root@docker~ 10:00:37]# docker run -it -m 200M --memory-swap=300M ubuntu-with-stress --vm 1 --vm-bytes 280M -v                 
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 293601280 bytes
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 293601280 bytes
......


#与m相同
[root@docker~ 10:03:04]# docker run -it -m 200M --memory-swap=200M ubuntu-with-stress --vm 1 --vm-bytes 280M -v
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 293601280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: FAIL: [1] (425) <-- worker 7 got signal 9
stress: WARN: [1] (427) now reaping child worker processes
stress: FAIL: [1] (431) kill error: No such process
stress: FAIL: [1] (461) failed run completed in 0s
......

#不设置
[root@docker~ 10:04:21]# docker run -it -m 200M  ubuntu-with-stress --vm 1 --vm-bytes 280M -v
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [6] forked
stress: dbug: [6] allocating 293601280 bytes ...
stress: dbug: [6] touching bytes in strides of 4096 bytes ...
stress: dbug: [6] freed 293601280 bytes
stress: dbug: [6] allocating 293601280 bytes ...
stress: dbug: [6] touching bytes in strides of 4096 bytes ...
stress: dbug: [6] freed 293601280 bytes
.....

注意:

  1. 如果--memory-swap 设置为0 或者不设置,则容器可以使用的swap大小为-m值的两倍
  2. 如果 --memory-swap 的值和-m 值相同 ,则容器不能使用swap
  3. 如果 --memory-swap值为**-1**。它表示容器程序使用的内存受限,而可以使用的swap空间不受限制 (宿主机有多少swap空间该容器就可以使用多少)。
2.cpu限额

Docker 可以通过 -c 或 --cpu-shares 设置容器使用 CPU 的权重。如果不指定,默认值为 1024。

通过 cpu share 可以设置容器使用 CPU 的优先级。

比如在 host 中启动了两个容器:

docker run --name "container_A" -c 1024 ubuntu

docker run --name "container_B" -c 512 ubuntu

container_A 的 cpu share 1024,是 container_B 的两倍。当两个容器都需要 CPU 资源时, container_A 可以得到的 CPU 是 container_B 的两倍。

7.export 和 import 容器

1.export

作用:容器导出 将容器导出为一个tar包。

注意:不管此时这个容器是否处于运行状态,都可以导出为文件。

docker save 和 docker export 对比:

docker save :将镜像保存为文件,save会保存该镜像的所有元数据和历史记录。

docker export :将容器导出为文件,文件会丢失所有元数据和历史记录,仅保存容器当时的状 态,再次导入会当作全新的镜像。

2.import

作用:将export导出的tar包导入成为镜像

8.容器实现的底层技术

1.cgroup 实现资源限额

在 /sys/fs/cgroup/cpu/docker 目录中,Linux 会为每个容器创建一个 cgroup 目录,以容器长ID 命名,目录中包含所有与 cpu 相关的 cgroup 配置,文件 cpu.shares 保存的就是 --cpu-shares 的配置。

2. namespace 实现资源隔离。

1.Mount namespace

Mount namespace 让容器看上去拥有整个文件系统。 容器有自己的 / 目录,可以执行 mount 和 umount 命令。当然我们知道这些操作只在当前容器中生 效,不会影响到 host 和其他容器。

2.UTS namespace

UTS namespace 让容器有自己的 hostname。 默认情况下,容器的 hostname 是它的短 ID,可以通过 -h 或 --hostname 参数设置。

3.IPC namespace

IPC namespace 让容器拥有自己的共享内存和信号量(semaphore)来实现进程间通信,而不会与 host 和其他容器的 IPC 混在一起。

4.PID namespace

让容器在 host 中以进程的形式运行。所有容器的进程都挂在 dockerd 进程下,同时也可以看到容器自己的子进程。 如果我们进入到某个容 器, ps 就只能看到自己的进程了。而且进程的 PID 不同于 host 中对应进程的 PID,容器中 PID=1 的进程当然也不是 host 的 init 进程。也 就是说:容器拥有自己独立的一套 PID,这就是 PID namespace 提供的功能。

5.Network namespace

Network namespace 让容器拥有自己独立的网卡、IP、路由等资源。

6.User namespace

User namespace 让容器能够管理自己的用户,host 不能看到容器中创建的用户。

bash 复制代码
[root@docker~ 14:14:09]# docker run -d ubuntu /bin/bash -c "while true;do sleep 1;echo haha;done"
d1ccf28281f945aabb8537f95bdbb2c263df2e7f81633f1470dd462b74846a39
[root@docker~ 14:14:35]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
d1ccf28281f9   ubuntu    "/bin/bash -c 'while..."   4 seconds ago   Up 2 seconds             inspiring_chatterjee
[root@docker~ 14:14:38]# docker exec -it d1ccf28281f9 bash
root@d1ccf28281f9:/# useradd xiaoming  #容器内创建用户xiaoming
root@d1ccf28281f9:/# exit
exit

#宿主机并没有xiaoming用户
[root@docker~ 14:15:33]# su - xiaoming
su: user xiaoming does not exist

第四章--网络

1.三种网络模式 --none ,host , bridge

1. none

none网络的driver类型是null,无法与外界通信。可以通过 --network=none 指定使用 none 网络。

使用场景:对安全性要求高并且不需要联网的应用可以使用 none 网 络。 比如某个容器的唯一用途是生成随机密码,就可以放到 none 网络中避免密码被窃取。

2. host

挂在host网络上的容器共享宿主机的network namespace。即容器的网络配置与host网络配置完全一 样。可以通过 -- network=host 指定使用 host 网络。

bash 复制代码
[root@docker ~]# docker run -it --network=host busybox     #容器网络与宿主机相同
/ #
/ # ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000
   link/ether 00:0c:29:33:15:f6 brd ff:ff:ff:ff:ff:ff
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue
   link/ether 02:42:02:fd:82:b3 brd ff:ff:ff:ff:ff:ff
/ #
/ # hostname                               #容器主机与宿主机相同
docker
/ #
3.bridge

通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。

Docker 安装时会创建一个 命名为 docker0 的 linux bridge,实际上它是 Linux 的一个 bridge (网桥), 可以理解为一个软件交换机,它会在挂载到它的网口之间进行转发。如果不指定 --network ,创建的容器默认都会挂到 docker0 上。Docker 就创建了在主机和所有容器之间一个虚拟共享网络 。当创建一个 Docker 容器的时候,同时会创建 了一对 veth pair 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包), 这对接 口 一端在容器内即 eth0; 另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头

示例:
bash 复制代码
#先配置yum源用于安装软件
[root@docker~ 16:37:57]# cd /etc/yum.repos.d/
[root@dockeryum.repos.d 18:45:23]# vim cloud.repo
[centos-openstack-victoria]
name=CentOS 8 - OpenStack victoria
baseurl=https://mirrors.aliyun.com/centos-vault/8-stream/cloud/x86_64/openstack-victoria/
enabled=1
gpgcheck=0
[root@dockeryum.repos.d 18:46:02]# yum install -y bridge-utils
[root@dockeryum.repos.d 18:46:34]# cd

#查看系统中所有 Linux 网桥的基本信息
#当前 docker0 上没有任何其他网络设备,我们创建一个容器看看有什么变化。
[root@docker~ 18:46:41]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242167abbef       no

#创建容器
[root@docker~ 18:46:48]# docker run -itd --name busybox1 busybox
7368e4a7a8772d03dccf6062ee53a3fe217ddde71fecc99c044b685c4cb2c399

#一个新的网络接口 veth4c72c20 被挂到了docker0上, veth4c72c20就是新创建的容器的虚拟网卡。
[root@docker~ 18:47:14]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242167abbef       no              `veth4c72c20`

#查看容器的网络配置
[root@docker~ 18:47:25]# docker exec -it busybox1 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
       
       #容器里的网卡是20号网卡名字是eth0,对面就是21号
20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

注意: 这里容器的网卡是eth0@if21,为什么不是veth4c72c20

因为他俩实际上是一对vethpair。 veth pair 是成对存在的特殊网络设备,可 以把它们想象成由一根虚拟网线连接起来的一对网卡,网卡的一头( eth0@if21 )在容器中,另一头 (veth4c72c20)挂在网桥 docker0 上,其效果就是将 eth0@if21 也挂在了 docker0 上。

在宿主机上查看IP地址,可以证明docker0上的veth4c72c20和容器中的eth0@if21是一对。

bash 复制代码
#查看宿主机网络配置
[root@docker~ 18:49:24]# ip a
 ......
`21: veth4c72c20@if20`: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether 66:8f:c6:50:14:a2 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::648f:c6ff:fe50:14a2/64 scope link
       valid_lft forever preferred_lft forever
# veth4c72c20@if20 这里的意思就是宿主机21号网卡对面连接了一块20号的网卡。证明了容器eh0连接到了docker0网桥的veth4c72c20。

还可以发现eth0@if21已经配置了IP 172.17.0.2 ,但为什么是这个网段呢?

bash 复制代码
#查看bridge网络配置信息。
[root@docker~ 18:49:32]# docker network inspect bridge
[
    {
         ....
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",   `#这是bridge网络分配网段`
                    "Gateway": "172.17.0.1"
                }
            ]
        },
    ......
        "Containers": {
            "7368e4a7a8772d03dccf6062ee53a3fe217ddde71fecc99c044b685c4cb2c399": {
                "Name": "busybox1",
                "EndpointID": "40ad093ff0ee004b0a5c8cc0f7a2c66cedfbfe70fa8f4c73d9e806ae9f6a6feb",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",   `#分配给容器busybox1的地址`
                "IPv6Address": ""
            }
        },
         ......
    }
]

#由此可见, bridge 网络配置的 subnet 就是 172.17.0.0/16,并且网关是 172.17.0.1。

但是这个网关在哪呢?答案就是docker0

bash 复制代码
#查看docker0配置信息验证
[root@docker~ 18:51:50]# ip a |grep docker0
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    `inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0`

当前容器网络拓补图如图所示:

容器创建时,docker 会自动从 172.17.0.0/16 中分配一个 IP,这里 16 位的掩码保证有足够多的 IP 可以 供容器使用。

2.如何自定义容器网络

除了 none, host, bridge 这三个自动创建的网络,用户也可以根据业务需要创建 user-defined 网络。 Docker 提供三种 user-defined 网络驱动:bridge, overlay 和 macvlan。overlay 和 macvlan 用于创建 跨主机的网络。

bash 复制代码
#通过bridge驱动创建类似前面的默认的bridge网络
[root@docker~ 18:51:55]# docker network create --driver bridge my_net
6e49d1e704723c8f6ff2729a09aaf665a998b618b35e33e45bcf1dd263534b4a

#注意看这里的br-6e49d1e70472 是我们刚才新建的bridge网络my_net。
[root@docker~ 19:31:30]# brctl show
bridge name     bridge id               STP enabled     interfaces
`br-6e49d1e70472`         8000.024228c6bf9f       no
docker0         8000.0242167abbef       no              veth4c72c20

#查看my_net的配置信息
[root@docker~ 19:31:43]# docker network inspect my_net
[
    {
        "Name": "my_net",
        "Id": "6e49d1e704723c8f6ff2729a09aaf665a998b618b35e33e45bcf1dd263534b4a",
        "Created": "2026-03-12T19:31:30.161162669+08:00",
         ....
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",   `#这里是docker自动分配的IP 网段`
                    "Gateway": "172.18.0.1"
                }
            ]
        },
         ....
]
 

 

可以自己指定 IP 网段吗? 答案是:可以。

只需在创建网段时指定 --subnet 和 --gateway 参数:

自定义IP网段
bash 复制代码
#创建新的容器并指定网段
[root@docker~ 19:32:39]# docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net2                                     b5043aecb23c48de7addfbfd23bc469b9ea667f1576c88ede119a3783f45f235
[root@docker~ 19:35:01]# brctl show
bridge name     bridge id               STP enabled     interfaces
br-6e49d1e70472         8000.024228c6bf9f       no
`br-b5043aecb23c `      8000.0242a67d30ba       no
docker0         8000.0242167abbef       no              veth4c72c20
[root@docker~ 19:35:09]# docker network inspect my_net2
[
    {
        "Name": "my_net2",
        "Id": "b5043aecb23c48de7addfbfd23bc469b9ea667f1576c88ede119a3783f45f235",
        "Created": "2026-03-12T19:35:00.853315355+08:00",
         ......
            "Config": [
                {
                    "Subnet": "172.22.16.0/24",  `#这里可以看到确实是指定的网段`
                    "Gateway": "172.22.16.1"
                }
            ]
     ....
]

##同时宿主机上出现了与网桥my_net2同名的网卡
[root@docker~ 19:35:24]# ip a
 .....
23: `br-b5043aecb23c:`<NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:a6:7d:30:ba brd ff:ff:ff:ff:ff:ff
    inet 172.22.16.1/24 brd 172.22.16.255 scope global br-b5043aecb23c
       valid_lft forever preferred_lft forever
       
##查看my_net2网卡
[root@docker~ 19:36:02]# ip a |grep br-b5043aecb23c
23: br-b5043aecb23c: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    inet 172.22.16.1/24 brd 172.22.16.255 scope global br-b5043aecb23c

容器要使用新的网络,需要在启动时通过 --network 指定:

自定义使用新网络:--network
bash 复制代码
[root@docker~ 19:36:34]# docker run -it --network=my_net2 --name busybox2 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
24: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:16:10:02 brd ff:ff:ff:ff:ff:ff
    inet 172.22.16.2/24 brd 172.22.16.255 scope global eth0
       valid_lft forever preferred_lft forever
 
[root@docker~ 19:37:38]# brctl show
bridge name     bridge id               STP enabled     interfaces
br-6e49d1e70472         8000.024228c6bf9f       no
br-b5043aecb23c         8000.0242a67d30ba       no              vethb043db7
docker0         8000.0242167abbef       no              veth4c72c20

到目前为止,容器的 IP 都是 docker 自动从 subnet 中分配,我们能否指定一个静态 IP 呢? 答案是:可以,通过 --ip 指定。

自定义指定IP
bash 复制代码
[root@docker~ 19:38:58]# docker run -it --network=my_net2 --ip 172.22.16.8 --name busybox3 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
26: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:16:10:08 brd ff:ff:ff:ff:ff:ff
    inet 172.22.16.8/24 brd 172.22.16.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # [root@docker~ 19:39:35]#
#这里必须ctrl+p,crtl+q退出,如果exit退出,这个容器就会停止运行,
[root@docker~ 19:39:36]# brctl show
bridge name     bridge id               STP enabled     interfaces
br-6e49d1e70472         8000.024228c6bf9f       no
br-b5043aecb23c         8000.0242a67d30ba       no              vethb043db7
                                                        vethfc77c9a
docker0         8000.0242167abbef       no              veth4c72c20

[root@docker~ 19:52:10]# docker network inspect my_net2
[
    {
        "Name": "my_net2",
        "Id": "b5043aecb23c48de7addfbfd23bc469b9ea667f1576c88ede119a3783f45f235",
        "Created": "2026-03-12T19:35:00.853315355+08:00",
       ......
            "Config": [
                {
                    "Subnet": "172.22.16.0/24",
                    "Gateway": "172.22.16.1"
                }
            ]
        },
         ......
        "Containers": {
            "1541842c6fa3ad9f2fde014b9edf68f8480a4eb635343fe270251901c0711f98": {
                `"Name": "busybox3",
                "EndpointID": "211d20055eef77b069905a2e196ac5a142852aee4535a385b265be9ee0fbbffb",
                "MacAddress": "02:42:ac:16:10:08",
               ` "IPv4Address": "172.22.16.8/24",`   `#这里可以看到busybox3地址是自己设置的`
                "IPv6Address": ""
            },
            
    }
]

注意:只有使用 --subnet 创建的网络才能指定静态 IP。

目前网络拓扑图:

3.理解容器之间的连通性

需要思考两个问题对于上面的网络拓扑图:

  1. busybox2 与 busybox3 是否能ping通
  2. busybox2 或者是busybox3可以跟busybox1 ping 通吗
  3. 怎么实现第二个问题
1.第一个问题: 可以ping通
bash 复制代码
# 登陆busybox2 ping busybox3
[root@docker ~]# docker exec -it busybox2 sh
# ping my_net2网关地址
/ # ping -c 3 172.22.16.1
PING 172.22.16.1 (172.22.16.1): 56 data bytes
64 bytes from 172.22.16.1: seq=0 ttl=64 time=0.149 ms
64 bytes from 172.22.16.1: seq=1 ttl=64 time=0.116 ms
64 bytes from 172.22.16.1: seq=2 ttl=64 time=0.182 ms
--- 172.22.16.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.116/0.149/0.182 ms
#可见同一网络中的容器、网关之间都是可以通信的。
2.第二个问题: 不能
bash 复制代码
#让 busybox2 容器 ping buxybox1 容器:
/ # ping -c 3 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss
#显然不能ping通
3.怎么解决第二个问题
不能ping通的原因:

busybox1和busybox2或者busybox3不能ping通的原因是:iptables DROP 掉了网桥 docker0 与 br-b5043aecb23c(my_net2) 之间双向的流 量。

bash 复制代码
#查看 host 上的路由表:
[root@docker~ 15:04:10]# ip r
default via 192.168.108.2 dev ens160 proto static metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.18.0.0/16 dev br-28fd764df800 proto kernel scope link src 172.18.0.1 linkdown
172.22.16.0/24 dev br-becc40350ced proto kernel scope link src 172.22.16.1
192.168.108.0/24 dev ens160 proto kernel scope link src 192.168.108.30 metric 100
#172.17.0.0/16 和 172.22.16.0/24 两个网络的路由都定义好了。

#再看看 ip forwarding:
#为1,处于开启状态
[root@docker~ 15:04:15]# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
#条件都满足,为什么不能通行呢?

#我们还得看看 iptables:
[root@docker~ 15:04:42]# iptables-save
# Generated by iptables-save v1.8.5 on Sat Mar 21 15:05:01 2026
 .....
-A DOCKER-ISOLATION-STAGE-2 -o  br-b5043aecb23c -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o  br-6e49d1e70472 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
 ......
#这三条命令的意思是
#所有出站网卡为 br-b5043aecb23c(my_net2) 的流量,直接丢弃:代表禁止其他 Docker 网桥(如 br-6e49d1e70472、docker0)的流量进入 br-b5043aecb23c 网络
#所有出站网卡为 br-6e49d1e70472(my_net) 的流量,直接丢弃:代表禁止其他 Docker 网桥(如 br-b5043aecb23c、docker0)的流量进入 br-6e49d1e70472 网络
#所有出站网卡为 docker0 的流量,直接丢弃:代表禁止其他 Docker 网桥(如 br-b5043aecb23c、br-6e49d1e70472)的流量进入 docker0(默认桥接网络)

**从规则的命名 DOCKER-ISOLATION 可知 docker 在设计上就是要隔离不同的 netwrok。 **

解决答案:

那么接下来的问题是:怎样才能让 busybox1与busybox2 通信呢? 答案是:为 busybox1 容器添加一块 my_net2的网卡。这个可以通过 docker network connect 命令 实现。

bash 复制代码
 [root@docker~ 15:05:01]# docker network connect my_net2 busybox1

#查看busybox1发现多了一块网卡地址为172.22.16.3
[root@docker~ 15:07:01]# docker exec -it busybox1 sh
/ # ip a
 ......
20: eth1@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:16:10:03 brd ff:ff:ff:ff:ff:ff
    inet 172.22.16.3/24 brd 172.22.16.255 scope global eth1
       valid_lft forever preferred_lft forever
/ # exit

[root@docker~ 15:07:33]# brctl show
bridge name     bridge id               STP enabled     interfaces
br-6e49d1e70472         8000.024228c6bf9f       no
br-b5043aecb23c         8000.0242a67d30ba       no              vethb043db7
                                                        vethfc77c9a
                                                        `vethde24e0a`
docker0         8000.0242167abbef       no              veth4c72c20

#现在可以ping通验证
[root@docker~ 15:08:07]# docker exec -it busybox2 sh
/ # ping -c 3 172.22.16.3
PING 172.22.16.3 (172.22.16.3): 56 data bytes
64 bytes from 172.22.16.3: seq=0 ttl=64 time=0.241 ms
64 bytes from 172.22.16.3: seq=1 ttl=64 time=0.179 ms
64 bytes from 172.22.16.3: seq=2 ttl=64 time=0.147 ms

--- 172.22.16.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.147/0.189/0.241 ms

当前网络拓扑图:

补充点:怎么排查两块网卡不能互通的原因,

排查两块网卡不通的问题时,建议按以下顺序(从底层到上层):

  1. 先查转发开关:sysctl net.ipv4.ip_forward → 必须是 1,否则后续都白搭;
  2. 再查路由表:ip r → 确认目标网段有对应的路由规则(指向正确网卡);
  3. 最后查 iptables: 确认没有 DROP 跨网卡流量的规则。

4.容器通信的三种方式

容器之间可通过 IP,Docker DNS Server 或 joined 容器三种方式通信。

1.IP

两个容器要能通信,必须要有属于同一个网络的网卡。 满足这个条件后,容器就可以通过 IP 交互了。

2. Docker DNS Server

从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过"容器 名"通信。方法很简单,只要在启动时用 --name 为容器命名就可以了。

注意 :使用 docker DNS 有个限制:只能在 user-defined (用户自定义的)网络中使用。默认的 bridge 网络是无法 使用 DNS 的。

示例:

bash 复制代码
[root@docker~ 16:01:53]# docker run -it --network my_net2 --name bbox1 busybox
 #ctrl p+crtl q 退出
[root@docker~ 16:02:29]# docker run -it --network my_net2 --name bbox2 busybox
  #ctrl p+crtl q 退出
  
#去ping bbox1的时候就可以直接使用名字
[root@docker~ 16:02:39]# docker exec -it bbox2 sh
/ # ping -c 3 bbox1
PING bbox1 (172.22.16.4): 56 data bytes
64 bytes from 172.22.16.4: seq=0 ttl=64 time=0.316 ms
64 bytes from 172.22.16.4: seq=1 ttl=64 time=0.156 ms
64 bytes from 172.22.16.4: seq=2 ttl=64 time=0.172 ms

--- bbox1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.156/0.214/0.316 ms
#这里的两个容器都是使用上面自定义的网络my_net2
3.joined 容器

joined 容器非常特别,它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined 容器之 间可以通过 127.0.0.1 直接通信。

bash 复制代码
#创建一个 httpd 容器,名字为 web1。
[root@docker~ 16:08:59]# docker run -d -it --name web1 httpd
f90b880a8f9b1e0ec443c325939c70b1b699c84e2c6edfef527b92b1643723f2
[root@docker~ 16:20:20]# docker exec -it web1 bash
#执行apt-get是为了下载工具可以使用ip命令
root@f90b880a8f9b:/usr/local/apache2# apt-get update
root@f90b880a8f9b:/usr/local/apache2# apt-get install iproute2 -y
root@f90b880a8f9b:/usr/local/apache2# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
26: eth0@if27: <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@f90b880a8f9b:/usr/local/apache2# exit
exit

#--network container:web1 是 Docker 的容器网络模式,核心作用是:让新创建的 busybox 容器完全复用 web1 容器的网络命名空间。
[root@docker~ 17:03:02]# docker run -it --network container:web1 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
26: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
#可以看出busybox 和 web1 的网卡 mac 地址与 IP 完全一样,它们共享了相同的网络栈

#busybox 可以直接用 127.0.0.1 访问 web1 的 http 服务。
/ # wget 127.0.0.1
Connecting to 127.0.0.1 (127.0.0.1:80)
saving to 'index.html'
index.html           100% |*************************************************************************|   191  0:00:00 ETA
'index.html' saved
/ #
适合场景:
  1. 不同容器中的程序希望通过 loopback 高效快速地通信,比如 web server 与 app server。
  2. 希望监控其他容器的网络流量,比如运行在独立容器中的网络监控程序。

5.容器如何访问外部世界

访问的过程:
  1. busybox 发送 ping 包:172.17.0.2 > www.baidu.com
  2. docker0 收到包,发现是发送到外网的,交给 NAT 处理。
  3. NAT 将源地址换成 ens160的 IP:192.168.108.30 > www.baidu.com
  4. ping 包从 ens160 发送出去,到达 www.baidu.com

6.外部世界如何访问容器:端口映射。

docker 可将容器对外提供服务的端口映射到 host 的某个端口,外网通过该端口访问容器。容器启动时 通过 -p 参数映射端口:

除了映射动态端口,也可在 -p 中指定映射到 host 某个特定端口,例如可将 80 端口映射到 host 的 8080 端口:

访问过程:
  1. docker-proxy 监听 host 的 8080 端口。
  2. 当 curl 访问 192.168.108.30:8080时,docker-proxy 转发给容器 172.17.0.3:80。
  3. httpd 容器响应请求并返回结果。

7. 实战:安装tomcat实战

bash 复制代码
#从docker hub上拉取tomcat镜像到本地
[root@docker~ 09:37:02]# docker pull tomcat

#使用tomcat镜像创建容器实例(也叫运行镜像)
[root@docker~ 09:38:38]# docker run -itd -p 8080:8080 tomcat
0118d4c8509008446b40c7f21ab86039c1cd1001689fe1b4fef0f46f536d4605

访问首页

bash 复制代码
##进入tomcat容器
[root@docker~ 09:47:24]# docker exec -it 0118d bash
root@0118d4c85090:/usr/local/tomcat# ls webapps      ##查看webapps文件夹为空
root@0118d4c85090:/usr/local/tomcat# ls webapps.dist/     ##文件在webapps.dist
docs  examples  host-manager  manager  ROOT
root@0118d4c85090:/usr/local/tomcat# cp -ar webapps.dist/* webapps    #cp 过去
root@0118d4c85090:/usr/local/tomcat# ls webapps
docs  examples  host-manager  manager  ROOT
root@0118d4c85090:/usr/local/tomcat#

刷新一下就出现了。

第五章--存储

1.docker 的两类存储资源

Docker 为容器提供了两种存放数据的资源:
  1. 由 storage driver 管理的镜像层和容器层。
  2. Data Volume。
1.storage driver

Docker 用来管理容器和镜像的 "文件系统管理器" ------ 它负责处理镜像的分层存储、容器的可写层、以及镜像与容器之间的文件读写、共享和隔离,是 Docker 实现 "轻量级容器" 和 "镜像分层复用" 的核心技术。

运行 docker info 查看CentOS的默认 driver:

bash 复制代码
[root@docker~ 17:32:45]# docker info
 ....
 `Storage Driver: overlay2`
.....
2.Data Volume之bind mount
bind mount 是将 host 上已存在的目录或文件 mount 到容器。
示例1:目录

将docker host上的目录通过-v将其mount到httpd容器

bash 复制代码
#httpd 容器的默认网页根目录是 /usr/local/apache2/htdocs
#创建目录和文件
[root@docker~ 10:47:53]# mkdir htdocs
[root@docker~ 10:50:08]# cd htdocs/
[root@dockerhtdocs 10:50:12]# touch index.html
[root@dockerhtdocs 10:50:21]# vim index.html
[root@dockerhtdocs 10:50:46]# cd

#-p 宿主机端口:容器端口 是固定格式,冒号前是宿主机,冒号后是容器;
#-v 的完整格式是:-v 宿主机路径:容器内路径
#将宿主机上的htdocs目录挂载到容器httpd的/usr/local/apache2/htdocs上并进行端口映射
[root@docker~ 10:51:38]# docker run -d -p 80:80 -v ~/htdocs/:/usr/local/apache2/htdocs httpd
5289bc271499aca7d36f43d49c4404e63b1caa86f785d59a5f9814e247401594

[root@docker~ 10:51:41]# curl 127.0.0.1:80
<html><body><h1>This is a file in host file system !</h1></body></html>

#写入欢迎内容到index.html
[root@docker~ 10:52:00]# echo xiyangyang > ~/htdocs/index.html

#再次访问验证
[root@docker~ 10:52:14]# curl 127.0.0.1:80
xiyangyang

#停止删除容器
[root@docker~ 10:52:26]# docker stop 52
52
[root@docker~ 10:52:38]# docker rm 52
52

#文件内容依旧在
[root@docker~ 10:52:46]# cat ~/htdocs/index.html
xiyangyang
示例2:文件

bind mount单独指定一个文件。

bash 复制代码
#运行新容器用单独文件绑定
[root@docker~ 17:31:03]# docker run -d -p 80:80 -v ~/htdocs/index.html:/usr/local/apache2/htdocs/new_index.html httpd
11f8bb0e1d206111a0150739b1db21b5935eab355c9a6eb86c2f8810ea44f769

[root@docker~ 17:32:15]# curl 127.0.0.1:80
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>It works! Apache httpd</title>
</head>
<body>
<p>It works!</p>
</body>
</html>

[root@docker~ 17:32:28]# curl 127.0.0.1:80/new_index.html
xiyangyang

注意:

使用单一文件有一点要注意:host 中的源文件必须要存在,不然会当作一个新目录 bind mount 给容 器。

3.Data Volume之docker managed volume

docker managed volume 与 bind mount 在使用上的最大区别是不需要指定 mount 源,指明 mount point 就行了

示例:
bash 复制代码
#以httpd容器为例
[root@docker~ 11:07:18]# docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
6b0f07dd53f51658cff53741d16b9b4909a0a5fc115c689444cf7295d38b1137

#由此可以看出每当容器申请 mount docker manged volume 时,docker 都会在 /var/lib/docker/volumes 下生成一个目录,这个目录就是 mount 源。
[root@docker~ 11:07:57]# docker inspect 6b0f
....
        "Mounts": [
            {
                "Type": "volume",
                "Name": "ae411b27dbab81bb70f2b8b09b06601c5caa1363600ea834ef3fe7bcea7f96b3",
                "Source": "/var/lib/docker/volumes/ae411b27dbab81bb70f2b8b09b06601c5caa1363600ea834ef3fe7bcea7f96b3/_data",
                "Destination": "/usr/local/apache2/htdocs",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
.....

[root@docker~ 11:09:55]# ls -l /var/lib/docker/volumes/ae411b27dbab81bb70f2b8b09b06601c5caa1363600ea834ef3fe7bcea7f96b3/_data/
total 4
-rw-r--r-- 1 501 ftp 191 Nov  7 16:23 index.html

#发现volume 的内容跟容器原有 /usr/local/apache2/htdocs 完全一样
[root@docker ~]# curl 127.0.0.1:80
<html><body><h1>It works!</h1></body></html>
#是因为如果 mount point 指向的是已有目录,原有数据会被复制到 volume 中。

#更新数据
[root@docker~ 11:11:54]# echo hahahaha > /var/lib/docker/volumes/ae411b27dbab81bb70f2b8b09b06                                                            601c5caa1363600ea834ef3fe7bcea7f96b3/_data/index.html

#验证
[root@docker~ 11:12:11]# curl 127.0.0.1:80
hahahaha
创建过程:
  1. 容器启动时,简单的告诉 docker "我需要一个 volume 存放数据,帮我 mount 到目录 /abc"。
  2. docker 在 /var/lib/docker/volumes 中生成一个随机目录作为 mount 源。
  3. 如果 /abc 已经存在,则将数据复制到 mount 源,
  4. 将 volume mount 到 /abc
docker volume

除了通过 docker inspect 查看 volume,我们也可以用 docker volume 命令:

bash 复制代码
[root@docker ~]# docker volume ls
DRIVER   VOLUME NAME
local      ae411b27dbab81bb70f2b8b09b06601c5caa1363600ea834ef3fe7bcea7f96b3
[root@docker ~]# docker volume inspect ae411b27dbab81bb70f2b8b09b06601c5caa1363600ea834ef3fe7bcea7f96b3
.......

2.共享数据

1.容器与宿主机之间

两种类型的 data volume,它们均可实现在容器与 host 之间共享数据。

docker cp

作用:可以在容器和 host 之间拷贝数据

bash 复制代码
[root@docker~ 17:55:41]# docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
a453662422acb312697c4406251296d5cab6f5f1cdd7265383ad04e56d4f7e97
[root@docker~ 17:55:47]# curl 127.0.0.1:80
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>It works! Apache httpd</title>
</head>
<body>
<p>It works!</p>
</body>
</html>

##将host os的/root/htdocs/index.html拷贝到容器中的/usr/local/apache2/htdocs目录下
[root@docker~ 17:56:30]# docker cp ~/htdocs/index.html  a453662422ac:/usr/local/apache2/htdocs
Successfully copied 2.05kB to a453662422ac:/usr/local/apache2/htdocs
[root@docker~ 17:57:04]# curl 127.0.0.1:80
xiyangyang
2.容器之间
1.将共享数据放在bind mount中,奖后将其mount到多个容器。
bash 复制代码
#将 $HOME/htdocs mount 到三个 httpd 容器。
[root@docker~ 18:01:18]# docker run --name web1 -d -p 80 -v ~/htdocs/:/usr/local/apache2/htdocs httpd
6af29c84e4a512826b54ec26f1bd9b07902079eaa8f58d5e22d1a4807e8a210a
[root@docker~ 18:02:07]# docker run --name web2 -d -p 80 -v ~/htdocs/:/usr/local/apache2/htdocs httpd
79cc8d29b5fa6e11d24e1f75faed5e1c91068beb827cb65ae3cfa9bc37706dd2
[root@docker~ 18:02:25]# docker run --name web3 -d -p 80 -v ~/htdocs/:/usr/local/apache2/htdocs httpd
80ba8367322361572e757071138e601577b9225c5aa1bc993c8ca5d4afc1b5a6

#查看每个容器对应的映射端口
[root@docker~ 18:02:33]# docker ps
CONTAINER ID   IMAGE     COMMAND              CREATED          STATUS          PORTS                                     NAMES
80ba83673223   httpd     "httpd-foreground"   9 seconds ago    Up 7 seconds    0.0.0.0:32770->80/tcp, :::32770->80/tcp   web3
79cc8d29b5fa   httpd     "httpd-foreground"   17 seconds ago   Up 15 seconds   0.0.0.0:32769->80/tcp, :::32769->80/tcp   web2
6af29c84e4a5   httpd     "httpd-foreground"   35 seconds ago   Up 33 seconds   0.0.0.0:32768->80/tcp, :::32768->80/tcp   web1

#查看每个主页内容
[root@docker~ 18:02:41]# curl 127.0.0.1:32770
xiyangyang
[root@docker~ 18:02:59]# curl 127.0.0.1:32769
xiyangyang
[root@docker~ 18:03:09]# curl 127.0.0.1:32768
xiyangyang

#更新数据
[root@docker~ 18:03:11]# echo meiyangyang > htdocs/index.html

#再次查看验证都改变了且一样
[root@docker~ 18:03:41]# curl 127.0.0.1:32768
meiyangyang
[root@docker~ 18:03:46]# curl 127.0.0.1:32769
meiyangyang
[root@docker~ 18:03:49]# curl 127.0.0.1:32770
meiyangyang
2.使用volume container共享数据

volume container 是专门为其他容器提供 volume 的容器。它提供的卷可以是 bind mount,也可以是 docker managed volume。

bash 复制代码
#创建一个名为vc_data的容器,并且mount了两个 volume
[root@docker~ 18:08:58]# docker create --name vc_data -v ~/htdocs/:/usr/local/apache2/htdocs -v /other/userful/tools busybox
9ee669044dbdbb6d9d43aa65ce282035ea53c9e5556409febc459902530f8933

#查看这两个 volume
[root@docker~ 18:10:04]# docker inspect vc_data
[
    
        "Mounts": [
            {
                "Type": "bind",
                "Source": `"/root/htdocs",`
                "Destination": `"/usr/local/apache2/htdocs",`
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "volume",
                "Name": "fd52666fe1d663c93262ad90dc28b8e936b0f074bf7ca3a5322237a0da291da7",
                "Source": `"/var/lib/docker/volumes/fd52666fe1d663c93262ad90dc28b8e936b0f074bf7ca3a5322237a0da291da7/_data"`,
                "Destination": `"/other/userful/tools",`
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
.......

#其他容器可以通过 --volumes-from 使用 vc_data 这个 volume container:
[root@docker~ 18:10:17]# docker run --name web1 -d -p 80 --volumes-from vc_data httpd
0137433d9c8688899894e898a85c0c3b7809bc7b5dc8e38849bc7ab77149042e
[root@docker~ 18:11:02]# docker run --name web2 -d -p 80 --volumes-from vc_data httpd
516c4f0abf14d7f836e1f4673c2345d0304e3c50821da26e5172bbb698b9f0c4
[root@docker~ 18:11:11]# docker run --name web3 -d -p 80 --volumes-from vc_data httpd
53aa9c2c76ac8d39df391e214df27da3235a4b13bd79b64723699d98d085fdc7

#查看web1的volume会发现跟vc_data一样的
[root@docker~ 18:11:21]# docker inspect web1
 .......
        "Mounts": [
            {
                "Type": "volume",
                "Name": "fd52666fe1d663c93262ad90dc28b8e936b0f074bf7ca3a5322237a0da291da7",
                "Source": "/var/lib/docker/volumes/fd52666fe1d663c93262ad90dc28b8e936b0f074bf7ca3a5322237a0da291da7/_data",
                "Destination": "/other/userful/tools",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "bind",
                "Source": "/root/htdocs",
                "Destination": "/usr/local/apache2/htdocs",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
 .....
 
#查看映射端口
[root@docker~ 18:11:31]# docker ps
CONTAINER ID   IMAGE     COMMAND              CREATED          STATUS          PORTS                                     NAMES
53aa9c2c76ac   httpd     "httpd-foreground"   21 seconds ago   Up 20 seconds   0.0.0.0:32773->80/tcp, :::32773->80/tcp   web3
516c4f0abf14   httpd     "httpd-foreground"   31 seconds ago   Up 30 seconds   0.0.0.0:32772->80/tcp, :::32772->80/tcp   web2
0137433d9c86   httpd     "httpd-foreground"   40 seconds ago   Up 39 seconds   0.0.0.0:32771->80/tcp, :::32771->80/tcp   web1

#更新数据
[root@docker~ 18:11:41]# echo hahhaha > htdocs/index.html

#验证首页内容一样实现共享数据
[root@docker~ 18:11:59]# curl 127.0.0.1:32773
hahhaha
[root@docker~ 18:12:17]# curl 127.0.0.1:32772
hahhaha
[root@docker~ 18:12:20]# curl 127.0.0.1:32771
hahhaha
3.使用data-packed volume container(数据打包型卷容器)

原理:是将数据打包到镜像中,然后通过 docker managed volume 共享。

bash 复制代码
#写Dockerfile为后面构建镜像做准备
#ADD:将宿主机当前目录下的 htdocs 文件夹(文件 / 目录)复制到镜像的 /usr/local/apache2/htdocs 路径下;
#VOLUME 的作用与 -v 等效,因为这个目录就是 ADD 添加的目录,所以会将已有数据拷贝到 volume 中。
[root@docker~ 18:24:55]# vim Dockerfile
[root@docker~ 18:25:34]# cat Dockerfile
FROM busybox:latest
ADD htdocs /usr/local/apache2/htdocs
VOLUME /usr/local/apache2/htdocs

#更新数据
[root@docker~ 18:23:57]# echo hello > htdocs/index.html

#构建新镜像
[root@docker~ 18:25:36]# docker build -t datapacked .

#用新镜像创建 data-packed volume container:
[root@docker~ 18:25:40]# docker create --name vc_data1 datapacked
905f875825b7f099d2c7374454972c6043c746631e5210280deb333393c3da5d

#启动 httpd 容器并使用 data-packed volume container:
[root@docker~ 18:26:14]# docker run -d -p 80:80 --volumes-from vc_data1 httpd
19e2074779f0b0184c1e72b0d3409f05469a5b762e42bee1a773b43949f7a427

#查看首页内容验证
[root@docker~ 18:26:40]# curl 127.0.0.1:80
hello

3.volume生命周期管理

备份

因为 volume 实际上是 host 文件系统中的目录和文件,所以 volume 的备份实际上是对文件系统的备份。所有的本地镜像都存在 host 的 /myregistry 目录中,我们要做的就是定期备份这个目录。

恢复

volume 的恢复也很简单,如果数据损坏了,直接用之前备份的数据拷贝到 /myregistry 就可以了。

迁移

如果我们想使用更新版本的 Registry,这就涉及到数据迁移,方法是:

1. docker stop 当前 Registry 容器。

2. 启动新版本容器并 mount 原有 volume。 docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:latest 当然,在启用新容器前要确保新版本的默认数据路径是否发生变化。

销毁

可以删除不再需要的 volume,但一定要确保知道自己正在做什么,volume 删除后数据是找不回来的。

docker 不会销毁 bind mount,删除数据的工作只能由 host 负责。对于 docker managed volume,在 执行 docker rm 删除容器时可以带上 -v 参数,docker 会将容器使用到的 volume 一并删除,但前提 是没有其他容器 mount 该 volume,目的是保护数据,非常合理。 如果删除容器时没有带 -v 呢?这样就会产生孤儿 volume,好在 docker 提供了 volume 子命令可以对 docker managed volume 进行维护。

示例:
bash 复制代码
[root@docker~ 18:45:41]# docker volume ls
DRIVER    VOLUME NAME
[root@docker~ 18:45:54]# docker run --name bbox -v /test/data busybox
[root@docker~ 18:46:11]# docker volume ls
DRIVER    VOLUME NAME
local     7b1eced06de06fbf0bb933ead376f3d05f836702b20cff46cbcd13e618f1263c
 
[root@docker~ 18:46:25]# docker rm bbox
bb0x
[root@docker~ 18:46:35]# docker volume ls
DRIVER    VOLUME NAME
local     7b1eced06de06fbf0bb933ead376f3d05f836702b20cff46cbcd13e618f1263c

#这里volume必须是完整的长id
[root@docker~ 18:47:00]# docker volume  rm 7b1eced06de06fbf0bb933ead376f3d05f836702b20cff46cbcd13e618f1263c
7b1eced06de06fbf0bb933ead376f3d05f836702b20cff46cbcd13e618f1263c

#批量删除孤儿volume
[root@docker~ 18:47:13]# docker volume rm $(docker volume ls -q)

4. 实战:安装mysql

简单版

不支持中文,而且删除之后数据不存在。

bash 复制代码
[root@docker~ 14:31:50]# docker pull mysql:5.7

[root@docker~ 15:13:27]# docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
b0d0590408e6c297cda761c9088edb412abb4eb91c6f958340620f07d72269fe

[root@docker~ 15:14:12]# docker exec -it b0d0 bash
bash-4.2# mysql -uroot -p123456
mysql> CREATE DATABASE db01;
Query OK, 1 row affected (0.00 sec)

mysql> USE db01;
Database changed
mysql> CREATE TABLE table1(id int,name varchar(20));
Query OK, 0 rows affected (0.01 sec)


mysql> INSERT INTO table1 VALUES(1,'gcf');
Query OK, 1 row affected (0.03 sec)

mysql> SELECT * FROM table1;
+------+------+
| id   | name |
+------+------+
|    1 | gcf  |
+------+------+
1 row in set (0.00 sec)
bash 复制代码
#验证
mysql> SELECT * FROM table1;
+------+---------+
| id   | name    |
+------+---------+
|    1 | gcf     |
|    2 | xiaocui |
+------+---------+
2 rows in set (0.00 sec)
实战版
bash 复制代码
#新建mysql实例
[root@docker~ 15:41:25]# docker run -d -p 3306:3306 --privileged=true -v /gcf/mysql/log:/var/log/mysql -v /gcf/mysql/data:/var/lib/mysql -v /gcf/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
b10501aa2e757b43a3d3697c347ee1d79ccb935e1e77618fef1a93c61e23878f
[root@docker~ 15:44:17]# cd /gcf/mysql/conf/

##实现mysql支持中文
[root@dockerconf 15:44:42]# vim my.cnf
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8

[root@dockerconf 15:45:09]# docker restart mysql
mysql
[root@dockerconf 15:45:25]# docker exec -it mysql bash
bash-4.2# mysql -uroot -p123456
mysql> SHOW VARIABLES LIKE 'character%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

mysql> CREATE DATABASE db01;
Query OK, 1 row affected (0.00 sec)

mysql> USE db01;
Database changed
mysql> CREATE TABLE tablea(id int,name varchar(20));
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO tablea VALUES(1,'gqd');
Query OK, 1 row affected (0.07 sec)

mysql> SELECT * FROM tablea;
+------+------+
| id   | name |
+------+------+
|    1 | gqd  |
+------+------+
1 row in set (0.00 sec)
bash 复制代码
#验证,并且支持中文
mysql> SELECT * FROM tablea;
+------+--------+
| id   | name   |
+------+--------+
|    1 | gqd    |
|    2 | 张飞   |
+------+--------+
2 rows in set (0.00 sec)
删除之后重新创建数据依旧存在
bash 复制代码
[root@dockerconf 15:49:55]# docker rm -f b105
b105
[root@dockerconf 15:50:03]# docker run -d -p 3306:3306 --privileged=true -v /gcf/mysql/log:/var/log/mysql -v /gcf/mysql/data:/var/lib/mysql -v /gcf/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
339d8000dfd97d821212eacb6c8cb456e6cf57515f8c2e071113e3939be3d364

第六章------容器监控和容器日志

1.容器监控------Docker自带的监控子命令

ps
top

作用:查看容器进程。

-au:展示容器内所有用户的进程,并以包含用户信息的详细格式输出。

bash 复制代码
[root@docker ~]# docker top 容器名 -au
status

作用:列出容器的资源利用率。

bash 复制代码
[root@docker ~]# docker stats
cAdvisor

作用:cAdvisor 是 google 开发的容器监控工具。 通过http://[Host_IP]:8080 访问 cAdvisor,点击Docker Containers进去看容器具体信息

bash 复制代码
[root@docker ~]# docker run \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
google/cadvisor:latest

2.容器日志

attach
bash 复制代码
[root@docker ~]# docker attach  容器ID

attach 到了 httpd 容器,但并没有任何输出,这是因为当前没有新的日志信息。 为了产生一条新的日志,可以在 host 的另一个命令行终端执行 命令即可。

docker logs

第七章 ------Docker compose

Docker Compose(常简称为 compose)是 Docker 官方推出的多容器编排工具------ 你可以把它理解为 "Docker 容器的批处理脚本工具",核心作用是:用一个统一的 YAML 配置文件(docker-compose.yml)定义、管理多个相互依赖的 Docker 容器,通过一条命令就能完成所有容器的启动、停止、重启、删除等操作。

Docker Compose 可以轻松、高效地管理容器,它是一个用于定义和运行多容器的管理工具。

它通过一个单独的 docker-compose.yml 模板文件(YAML 格式)定义一组相关联资源集。

1.核心概念

服务 ( service ):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。

项目 ( project ):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文 件中定义。

Compose 的**默认管理对象是项目,**通过子命令对项目中的一组容器进行便捷地生命周期管理。

默认的模板文件名称为 docker-compose.yml 。

2. 实战------Wordpress

1.docker run 实现
bash 复制代码
#启动一个 MySQL 数据库容器(命名为 db),作为 WordPress 的数据存储
[root@docker~ 09:40:30]# docker run -itd --name db --restart always -v /db:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123 -e MYSQL_DATABASE=wordpress mysql

#启动 WordPress 应用容器(命名为 blog),并连接到前面的 MySQL 容器,对外暴露 80 端口供访问。
#-- link db :容器链接:将 blog 容器和 db 容器关联,让 WordPress 能访问到 MySQL 容器。
[root@docker~ 09:49:35]# docker run -itd --name blog -v /web:/var/www/html -p 80:80 --link db -e WORDPRESS_DB_HOST=db -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=123 -e WORDPRESS_DB_NAME=wordpress wordpress

#查看现象
[root@docker~ 09:57:27]# docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS         PORTS                               NAMES
7e8003cf5a20   wordpress   "docker-entrypoint.s..."   8 seconds ago   Up 5 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   blog
f665bd72d18e   mysql       "docker-entrypoint.s..."   8 minutes ago   Up 7 minutes   3306/tcp, 33060/tcp                 db
2. docker compose实现

通过docker compose怎么来统一管理这两个容器呢?

假设新建一个名为 wordpress 的文件夹,然后进入这个文件夹,创建 docker-compose.yml 文件

bash 复制代码
# 删除之前的环境
[root@docker~ 10:00:26]# docker rm -f 7e8003cf5a20 f665bd72d18e
7e8003cf5a20
f665bd72d18e
[root@docker~ 10:00:42]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES


## 通过docker compose实现多个容器一起启动
[root@docker~ 10:01:06]# cd wordpress/
[root@dockerwordpress 10:01:11]# vim docker-compose.yml
[root@dockerwordpress 10:09:03]# cat docker-compose.yml
services:
  blog:   ##服务名字,相当于docker run的时候指定的一个名称

    image: wordpress:latest  #必选,镜像的名字
    restart: always
    links:
      - db
    ports:   ##可选,等价于 docker run 里的 -p 选项指定端口映射
      - "80:80"
    environment:   ##可选,等价于 docker run 里的 --env 选项设置环境变量
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_USER=root
      - WORDPRESS_DB_PASSWORD=123
      - WORDPRESS_DB_NAME=wordpress
  db:
    image: mysql:latest
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=123
      - MYSQL_DATABASE=wordpress


##检测语法是否正确,无输出就是正确
[root@dockerwordpress 10:08:25]# docker compose config -q

#后端运行
[root@dockerwordpress 10:08:40]# docker compose up -d
[+] Running 3/3
 ✔ Network wordpress_default   Created                                         0.5s
 ✔ Container wordpress-db-1    Started                                         1.2s
 ✔ Container wordpress-blog-1  Started                                         1.7s
 
 #查看现象
[root@dockerwordpress 10:08:51]# docker ps
CONTAINER ID   IMAGE              COMMAND                  CREATED          STATUS          PORTS                               NAMES
848a93e2e7eb   wordpress:latest   "docker-entrypoint.s..."   14 seconds ago   Up 11 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   wordpress-blog-1
4f983752eab0   mysql:latest       "docker-entrypoint.s..."   14 seconds ago   Up 12 seconds   3306/tcp, 33060/tcp                 wordpress-db-1

错误点补充


外链图片转存中...(img-Ug0Zq54D-1777020333929)

2. docker compose实现

通过docker compose怎么来统一管理这两个容器呢?

假设新建一个名为 wordpress 的文件夹,然后进入这个文件夹,创建 docker-compose.yml 文件

bash 复制代码
# 删除之前的环境
[root@docker~ 10:00:26]# docker rm -f 7e8003cf5a20 f665bd72d18e
7e8003cf5a20
f665bd72d18e
[root@docker~ 10:00:42]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES


## 通过docker compose实现多个容器一起启动
[root@docker~ 10:01:06]# cd wordpress/
[root@dockerwordpress 10:01:11]# vim docker-compose.yml
[root@dockerwordpress 10:09:03]# cat docker-compose.yml
services:
  blog:   ##服务名字,相当于docker run的时候指定的一个名称

    image: wordpress:latest  #必选,镜像的名字
    restart: always
    links:
      - db
    ports:   ##可选,等价于 docker run 里的 -p 选项指定端口映射
      - "80:80"
    environment:   ##可选,等价于 docker run 里的 --env 选项设置环境变量
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_USER=root
      - WORDPRESS_DB_PASSWORD=123
      - WORDPRESS_DB_NAME=wordpress
  db:
    image: mysql:latest
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=123
      - MYSQL_DATABASE=wordpress


##检测语法是否正确,无输出就是正确
[root@dockerwordpress 10:08:25]# docker compose config -q

#后端运行
[root@dockerwordpress 10:08:40]# docker compose up -d
[+] Running 3/3
 ✔ Network wordpress_default   Created                                         0.5s
 ✔ Container wordpress-db-1    Started                                         1.2s
 ✔ Container wordpress-blog-1  Started                                         1.7s
 
 #查看现象
[root@dockerwordpress 10:08:51]# docker ps
CONTAINER ID   IMAGE              COMMAND                  CREATED          STATUS          PORTS                               NAMES
848a93e2e7eb   wordpress:latest   "docker-entrypoint.s..."   14 seconds ago   Up 11 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   wordpress-blog-1
4f983752eab0   mysql:latest       "docker-entrypoint.s..."   14 seconds ago   Up 12 seconds   3306/tcp, 33060/tcp                 wordpress-db-1

错误点补充

外链图片转存中...(img-uZR0Rq3G-1777020333929)

相关推荐
相思难忘成疾2 小时前
Linux SSH免密登录实验:基于Xshell的公钥认证机制
linux·运维·ssh·rhce
gushinghsjj2 小时前
主数据管理平台如何落地?怎么部署主数据管理平台?
大数据·运维·人工智能
梦想的旅途22 小时前
企微自动化办公:实现外部群聊的高级交互逻辑
运维·数据库·自动化·企业微信·rpa
其实防守也摸鱼5 小时前
GDB安装与配置(保姆级教程)【Linux、Windows系统】
linux·运维·windows·命令模式·工具·虚拟机·调试
Elastic 中国社区官方博客11 小时前
为 Elastic Cloud Serverless 和 Elasticsearch 引入统一的 API 密钥
大数据·运维·elasticsearch·搜索引擎·云原生·serverless
Agent手记11 小时前
制造业数字化升级:生产全流程企业级智能体落地解决方案 —— 基于LLM+超自动化全栈架构的智改数转深度实战
运维·ai·架构·自动化
云安全助手11 小时前
弹性云服务器+高防IP:让DDoS攻击不再是业务“生死劫”
运维·网络·安全
深色風信子12 小时前
Docker newapi
运维·docker·容器·newapi
闫利朋13 小时前
Ubuntu 24.04 桌面安装向日葵完整指南
linux·运维·ubuntu