docker
笔记参照:
https://blog.csdn.net/qq_21197507/article/details/115071715
https://blog.51cto.com/u_14518853/4894194
1、docker概述
1.1、docker为什么出现
工作中,经常出现“在我的机器上可正常工作”的问题
因为环境不一致等原因导致。。。
Docker的思想就来自于集装箱!
隔离:Docker核心思想!打包装箱!每个箱子是互相隔离的。
Docker通过隔离机制,可以将服务器利用到极致!
1.2、docker的历史
Docker 是基于Go 语言实现的开源容器项目,诞生于2013 年年初,最初发起者是 dotCloud 公司。Docker 自开源后受到广泛的关注和l 讨论,目前已有多个相关项目(包括 Docker 三剑客、Kubemetes 等),逐渐形成了围绕Docker 容器的生态体系。 由于Docker 在业界造成的影响力实在太大, dotCloud 公司后来也直接改名为Docker Inc ,并专注于Docker 相关技术和产品的开发。
自从dotCloud公司开源其Docker项目后,凭借其便捷的Docker镜像技术解决了当时困扰众多PaaS项目的难题:如何为应用打包,让用户将本地的应用顺利迁移到PaaS平台,而不用顾忌应用的开发语言、配置、依赖包等诸多因素,也因此开启了全新的Docker容器时代。
1.3、docker能干嘛
对开发和运维( DevOps )人员来说,可能最梦寐以求的效果就是一次创建或配置, 之后可以在任意地方、任意时间让应用正常运行。
具体说来, Docker 在开发和运维过程中,具有如下几个方面的优势:
-
更快速的交付和部署
使用Docker ,开发人员可以使用镜像来快速构建一套标准的开发环境;开发完成之后,测试和运维人员可以直接使用完全相同环境来部署代码。只要开发测试过的代码,就可以确保在生产环境无缝运行。Docker 可以快速创建和删除容器,实现快速迭代,大量节约开发、测试、部署的时间。并且,整个过程全程可见,使团队更容易理解应用的创建和工作过程。
-
更高效的资源利用
Docker 容器的运行不需要额外的虚拟化管理程序(Virtual Machine Manager, VMM ,以及Hypervisor)支持,它是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低。跟传统虚拟机方式相比,要提高一到两个数量级。
-
更轻松的迁移和扩展
Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等,同时支持主流的操作系统发行版本。这种兼容性让用户可以在不同平台之间轻松地迁移应用。
-
更简单的更新管理
使用Dockerfile ,只需要小小的配置修改,就可以替代以往大量的更新工作。并且所有修改都以增量的方式被分发和更新,从而实现自动化并且高效的容器管理。
Docker 和常见的虚拟化方式的不同之处

传统方式是在硬件层面实现虚拟化,需要有额外的虚拟机管理应用和虚拟机操作系统 层。Docker 容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,因此更加 轻量级。
Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。
作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多;Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。
2、docker安装
2.1、docker的基本组成

-
镜像(Image)
什么是 Docker 镜像?简单的理解,Docker 镜像就是一个 Linux 的文件系统(Root FileSystem),这个文件系统里面包含可以运行在 Linux 内核的程序以及相应的数据。
通过镜像启动一个容器,一个镜像就是一个可执行的包,其中包括运行应用程序所需要的所有内容:包含代码,运行时间,库,环境变量和配置文件等。
Docker 把 App 文件打包成为一个镜像,并且采用类似多次快照的存储技术,可以实现:
- 多个 App 可以共用相同的底层镜像(初始的操作系统镜像)
- App 运行时的 IO 操作和镜像文件隔离
- 通过挂载包含不同配置/数据文件的目录或者卷(Volume),单个 App 镜像可以用来运行无数个不同业务的容器
-
容器(container)
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

-
仓库(repository)
仓库可看成一个代码控制中心,用来保存镜像。
仓库分为公有仓库和私有仓库。(很类似git)
Docker Hub是国外的。
阿里云…都有容器服务器(配置镜像加速!)
2.2、安装docker
显示操作系统内核版本号
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# uname -r
3.10.0-1160.81.1.el7.x86_64
查看系统信息
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"
安装
#1.卸载旧版本
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
#2.需要的安装包
yum install -y yum-utils
#3.设置镜像的仓库
#上述方法默认是从国外的,不推荐
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
#推荐使用国内的
yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#更新yum软件包索引
yum makecache fast
#4.安装docker相关的 docker-ce 社区版 而ee是企业版
yum install docker-ce docker-ce-cli containerd.io # 这里我们使用社区版即可
#5.启动docker
systemctl start docker
#6. 使用docker version查看是否按照成功
docker version
#7. 测试
docker run hello-world
docker版本

运行hello-world

查看镜像
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 18 months ago 13.3kB
[root@iZwz9bo1dt9faz5t06j6ijZ ~]#
卸载docker
#1. 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
#2. 删除资源
rm -rf /var/lib/docker
# /var/lib/docker 是docker的默认工作路径!
2.3、阿里云镜像加速
1、找到阿里云的容器镜像服务

2、找到镜像加速器

3、配置使用
#1.创建一个目录
mkdir -p /etc/docker
#2.编写配置文件
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://irgp9g5e.mirror.aliyuncs.com"]
}
EOF
#3.重启服务
systemctl daemon-reload
systemctl restart docker
2.4、回滚hello-world流程

底层原理
docker是怎么工作的
docker是一个client-server结构的系统,docker守护进程运行在主机上,然后通过socket连接从客户端访问docker守护进程。
docker守护进程从客户端接收命令,并按照命令,管理运行在主机上的容器。
一个docker容器,是一个运行时环境,可以简单理解为进程运行的集装箱。

为什么docker比vm快
- Docker有这比虚拟机更少的抽象层,由于Docker不需要Hypervisor实现硬件资源虚拟化,运行在Docker上的程序直接使用的都是实际物理机上的硬件资源,因此在CPU、内存利用率上有明显的优势。
- **Docker利用的是宿主机的内核,而不需要使用Guest OS ** ,因此当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核,而避免引寻 ,加载操作系统内核是个比较费事费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest OS,返回的新建的过程是分钟级别,而docker直接使用的是宿主机上的操作系统,则省略了返回这个的过程,因此新建一个docker容器只需要几秒钟。
虚拟机与Docker架构对比图:


3、docker的常用命令
官方文档常用命令地址:https://docs.docker.com/reference/

3.1、帮助命令
#显示docker的版本信息。
docker version
#显示docker的系统信息,包括镜像和容器的数量
docker info
#帮助命令
docker --help
docker 命令 --help
3.2、镜像命令
docker image 查看所有本地主机上的镜像
参数和选项
-a, --all 列出所有镜像-q, --quiet 只显示镜像id
测试
1、查看本地主机上的镜像
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 18 months ago 13.3kB
[root@iZwz9bo1dt9faz5t06j6ijZ ~]#
解释:
- REPOSITORY 镜像的仓库源
- TAG 镜像的标签(版本) latest表示最新的版本
- IMAGE ID 镜像id
- CREATED 镜像的创建时间
- SIZE 镜像的大小
2、列出所有镜像的id
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker images -aq
feb5d9fea6a5
docker search 搜索镜像
镜像仓库地址:https://hub.docker.com/
参数和选项
-f, --filter filter 基于条件过滤
测试
1、搜索mysql镜像
在docker仓库上搜

也可以这样搜

2、搜索出来的镜像收藏STARS数量大于3000的
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker search mysql -f=STARS=3000

docker pull 下载镜像
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker pull mysql
Using default tag: latest #不如不指定tag,默认就是latest
latest: Pulling from library/mysql
72a69066d2fe: Pull complete #分层下载,docker images的核心,联合文件系统
93619dbc5b36: Pull complete
99da31dd6142: Pull complete
626033c43d70: Pull complete
37d5d7efb64e: Pull complete
ac563158d721: Pull complete
d2ba16033dad: Pull complete
688ba7d5c01a: Pull complete
00e060b6d11d: Pull complete
1c04857f594f: Pull complete
4d7cfa90e6ea: Pull complete
e0431212d27d: Pull complete
Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709 #签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest #真实地址
----
#docker pull mysql
#等价于
#docker pull docker.io/library/mysql:latest
----
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker pull mysql:5.7 #指定版本下载
5.7: Pulling from library/mysql
72a69066d2fe: Already exists
93619dbc5b36: Already exists
99da31dd6142: Already exists
626033c43d70: Already exists
37d5d7efb64e: Already exists
ac563158d721: Already exists
d2ba16033dad: Already exists
0ceb82207cd7: Pull complete
37f2405cae96: Pull complete
e2482e017e53: Pull complete
70deed891d42: Pull complete
Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker images #查看镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 5.7 c20987f18b13 15 months ago 448MB
mysql latest 3218b38490ce 15 months ago 516MB
hello-world latest feb5d9fea6a5 18 months ago 13.3kB
docker rmi删除镜像
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker rmi -f 镜像id #删除指定镜像
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker rmi -f 镜像id1 镜像id2 镜像id3 #删除多个镜像
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker rmi -f $(docker images -aq) #删除所有镜像

3.3、容器命令
我们有了镜像,才能创建容器,所以先下载一个centos镜像来学习
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker pull centos

启动容器
docker run [可选参数] 容器名或者容器id
创建一个新的容器并运行一个命令
可选参数
- -i: 以交互模式运行容器,通常与 -t 同时使用
- -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用
- -P: 随机端口映射,容器内部端口随机映射到主机的端口
- -p: 指定端口映射,格式为:主机(宿主)端口:容器端口
- -d: 后台运行容器,并返回容器ID;
- --name="nginx-lb": 为容器指定一个名称
- -e username="ritchie": 设置环境变量
测试
1、使用镜像centos以交互模式启动一个容器,在容器内执行/bin/bash命令
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -it centos /bin/bash

退出容器
exit #直接退出容器并关闭
快捷键:ctrl+p+q #容器不关闭退出 注意p和q的顺序!
列出所有的容器
docker ps
可选参数
- **-a :**显示所有的容器,包括未运行的。
- **-n :**列出最近创建的n个容器。
- **-q :**静默模式,只显示容器编号。
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps #列出当前正在运行的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e769f9d12d28 centos "/bin/bash" 16 seconds ago Up 16 seconds mystifying_bell
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e769f9d12d28 centos "/bin/bash" 25 seconds ago Up 25 seconds mystifying_bell
cd2b6006d431 centos "/bin/bash" 48 seconds ago Exited (0) 48 seconds ago vigorous_kilby
0fe74c1cbcf8 centos "/bin/bash" 18 minutes ago Exited (137) 16 minutes ago nervous_morse
332fd2aa8995 centos "/bin/bash" 18 minutes ago Exited (0) 18 minutes ago amazing_borg
b204f1dec292 5d0da3dc9764 "/bin/bash" 20 minutes ago Exited (0) 20 minutes ago clever_grothendieck
556e1ecba57e feb5d9fea6a5 "/hello" 2 days ago Exited (0) 2 days ago stoic_keller
93adc83b7466 feb5d9fea6a5 "/hello" 2 weeks ago Exited (0) 2 weeks ago eloquent_dubinsky
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps -aq
e769f9d12d28
cd2b6006d431
0fe74c1cbcf8
332fd2aa8995
b204f1dec292
556e1ecba57e
93adc83b7466
[root@iZwz9bo1dt9faz5t06j6ijZ ~]#
删除容器
docker rm -f 容器id # 删除指定容器
docker rm -f $(docker ps -aq) # 删除所有容器
docker ps -a -q|xargs docker rm -f # 删除所有的容器
启动和停止容器
docker start 容器id # 启动容器
docker restart 容器id # 重启容器
docker stop 容器id # 停止当前正在运行的容器
docker kill 容器id # 强制停止当前的容器

3.4、常用其他命令
后台启动命令
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -d centos
fcdd8111042db1bc8cdb1304910142fff5b4c2ac18e96e695d2943257e8ade89
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZwz9bo1dt9faz5t06j6ijZ ~]#
# 问题,后端启动容器后,docker ps,发现centos停止了
# 常见的坑, docker 容器使用后台运行, 就必须要有一个前台进程,docker发现没有应用,就会自动停止
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -d -it centos #这种启动容器后就不会关闭了
0968ab2a263d41beb063e12a40a45024b749d49897f9edd6eec78828b5f0b896
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0968ab2a263d centos "/bin/bash" 4 seconds ago Up 3 seconds admiring_boyd
查看日志
docker logs [参数与参选] 容器id
参数与选项
- -f : 跟踪日志输出
- -t : 显示时间戳
- **--since :**显示某个开始时间的所有日志
- -n或者**--tail :**仅列出最新N条容器日志
# docker logs -tf -n=10 容器id
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker logs -tf -n=10 a72f233b693f
# 这里没有日志,我们自己编写一段shell脚本
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -d -it centos /bin/bash -c "while true;do echo zyy hello;sleep 1;done"
a72f233b693f204e78a94671df7060de418cf03d3f7c9bdc6c224fc3a5fc2c05
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a72f233b693f centos "/bin/bash -c 'while…" 4 seconds ago Up 3 seconds hopeful_wescoff
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker logs -tf -n=10 a72f233b693f
2023-03-26T02:36:20.853549289Z zyy hello
2023-03-26T02:36:21.855575170Z zyy hello
2023-03-26T02:36:22.857717770Z zyy hello
2023-03-26T02:36:23.859828174Z zyy hello
2023-03-26T02:36:24.861974759Z zyy hello
2023-03-26T02:36:25.864026002Z zyy hello
2023-03-26T02:36:26.866091408Z zyy hello
2023-03-26T02:36:27.868137295Z zyy hello
2023-03-26T02:36:28.870218421Z zyy hello
2023-03-26T02:36:29.872311002Z zyy hello
2023-03-26T02:36:30.874521421Z zyy hello
2023-03-26T02:36:31.876815315Z zyy hello
2023-03-26T02:36:32.878998053Z zyy hello
2023-03-26T02:36:33.880995085Z zyy hello
2023-03-26T02:36:34.883166453Z zyy hello
2023-03-26T02:36:35.885199608Z zyy hello
...
命令docker run -d -it centos /bin/bash -c "while true;do echo zyy hello;sleep 1;done"解释:
该命令会不停地输出字符串 "zyy hello",每隔 1 秒钟输出一次,直到容器被停止。
其中,各个参数的含义如下:
docker run是 Docker 命令的基本语法,用于启动一个新的容器。-d参数表示在后台运行容器。centos参数表示使用的镜像名称,这里使用的是 CentOS 镜像。/bin/bash -c "while true;do echo zyy hello;sleep 1;done"参数表示在容器内部执行的 shell 命令。其中/bin/bash是 shell 的路径,-c参数表示在 shell 中执行指定的命令。这里的命令是一个无限循环,不停地输出字符串 "zyy hello"。
查看容器中的进程信息
docker top 容器id
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8f02758fe0db centos "/bin/bash" 3 seconds ago Up 3 seconds compassionate_poincare
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker top 8f02758fe0db
UID PID PPID C STIME TTY TIME CMD
root 17764 17743 0 10:48 ? 00:00:00 /bin/bash
[root@iZwz9bo1dt9faz5t06j6ijZ ~]#
查看镜像的元数据
docker inspect 容器id 元数据 (meta data)——"data about data" 描述数据的数据,一般是结构化数据
元数据是指从信息资源中抽取出来的用于说明其特征、内容的结构化的数据(如题名,版本、出版数据、相关说明,包括检索点等),用于组织、描述、检索、保存、管理信息和知识资源
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker inspect 8f02758fe0db
[
{
"Id": "8f02758fe0db015c95ea2d2c61806573bce8d7cb80cecd3bcc5378d340a0cb4a",
"Created": "2023-03-26T02:48:59.227650262Z",
"Path": "/bin/bash",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 17764,
"ExitCode": 0,
"Error": "",
"StartedAt": "2023-03-26T02:48:59.520077966Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6",
"ResolvConfPath": "/var/lib/docker/containers/8f02758fe0db015c95ea2d2c61806573bce8d7cb80cecd3bcc5378d340a0cb4a/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/8f02758fe0db015c95ea2d2c61806573bce8d7cb80cecd3bcc5378d340a0cb4a/hostname",
"HostsPath": "/var/lib/docker/containers/8f02758fe0db015c95ea2d2c61806573bce8d7cb80cecd3bcc5378d340a0cb4a/hosts",
"LogPath": "/var/lib/docker/containers/8f02758fe0db015c95ea2d2c61806573bce8d7cb80cecd3bcc5378d340a0cb4a/8f02758fe0db015c95ea2d2c61806573bce8d7cb80cecd3bcc5378d340a0cb4a-json.log",
"Name": "/compassionate_poincare",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"ConsoleSize": [
50,
174
],
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": [],
"BlkioDeviceWriteBps": [],
"BlkioDeviceReadIOps": [],
"BlkioDeviceWriteIOps": [],
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/6a2de276a5a9415b776293e5ec786fa5c0f43bcc35d937b9726eee76d5d3d92d-init/diff:/var/lib/docker/overlay2/a88c68da7a2c4a3390c008afd816a4c718160bff2eb70f1de8987209ad34a7ba/diff",
"MergedDir": "/var/lib/docker/overlay2/6a2de276a5a9415b776293e5ec786fa5c0f43bcc35d937b9726eee76d5d3d92d/merged",
"UpperDir": "/var/lib/docker/overlay2/6a2de276a5a9415b776293e5ec786fa5c0f43bcc35d937b9726eee76d5d3d92d/diff",
"WorkDir": "/var/lib/docker/overlay2/6a2de276a5a9415b776293e5ec786fa5c0f43bcc35d937b9726eee76d5d3d92d/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "8f02758fe0db",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": true,
"OpenStdin": true,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash"
],
"Image": "centos",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20210915",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "907d78b2abf5b30265866452bd753e6a66458c0daed56e9aab5d145f9fa95c0a",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/907d78b2abf5",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "0638f1bce8b8c03e725ea034d4067876afab4c0030414fa9cb0aa7058cd4a51e",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "a3187499d9b1427eb9dcaa7901657d42964c2997c434e765caeb3d126d1eeba3",
"EndpointID": "0638f1bce8b8c03e725ea034d4067876afab4c0030414fa9cb0aa7058cd4a51e",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]
进入当前正在运行的容器
方式一:docker exec
docker exec -it 容器id /bin/bash
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8f02758fe0db centos "/bin/bash" 18 minutes ago Up About a minute compassionate_poincare
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker exec -it 8f02758fe0db /bin/bash
[root@8f02758fe0db /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 03:05 pts/0 00:00:00 /bin/bash
root 15 0 0 03:08 pts/1 00:00:00 /bin/bash
root 29 15 0 03:08 pts/1 00:00:00 ps -ef
[root@8f02758fe0db /]#
方式二:docker attach
docker attach 容器id
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker attach 8f02758fe0db
[root@8f02758fe0db /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 03:05 pts/0 00:00:00 /bin/bash
root 15 0 0 03:08 pts/1 00:00:00 /bin/bash
root 31 1 0 03:10 pts/0 00:00:00 ps -ef
[root@8f02758fe0db /]#
区别
# docker exec # 进入容器后开启一个新的终端,可以在里面操作
# docker attach # 进入容器正在执行的终端,不会启动新的进程
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
356ee5e84d55 centos "/bin/bash" 15 seconds ago Up 15 seconds cranky_wilson
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker exec -it 356ee5e84d55 /bin/bash #进入容器
[root@356ee5e84d55 /]# exit #退出容器
exit
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps #发现容器依然运行
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
356ee5e84d55 centos "/bin/bash" About a minute ago Up About a minute cranky_wilson
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker attach 356ee5e84d55 #进入容器
[root@356ee5e84d55 /]# exit #退出容器
exit
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps #发现容器停止
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZwz9bo1dt9faz5t06j6ijZ ~]#
从容器拷贝到主机上、从主机拷贝到容器上
docker cp 容器id:容器文件 主机路径
docker cp 主机文件 容器id:容器路径
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
45ee18e9901f centos "/bin/bash" 23 seconds ago Up 23 seconds xenodochial_hellman
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker exec -it 45ee18e9901f /bin/bash #进入容器
[root@45ee18e9901f /]# cd /home/
[root@45ee18e9901f home]# ls
[root@45ee18e9901f home]# touch hello.java #/home/下新建一个文件hello.java
[root@45ee18e9901f home]# ls
hello.java
[root@45ee18e9901f home]# exit #退出容器,并不会关闭容器
exit
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
45ee18e9901f centos "/bin/bash" About a minute ago Up About a minute xenodochial_hellman
[root@iZwz9bo1dt9faz5t06j6ijZ home]# cd /home/zyy #进去主机指定目录
[root@iZwz9bo1dt9faz5t06j6ijZ zyy]# ls
[root@iZwz9bo1dt9faz5t06j6ijZ zyy]# docker cp 45ee18e9901f:/home/hello.java /home/zyy #从容器拷贝到主机上
Successfully copied 1.536kB to /home/zyy
[root@iZwz9bo1dt9faz5t06j6ijZ zyy]# ls #发现拷贝成功
hello.java
[root@iZwz9bo1dt9faz5t06j6ijZ zyy]# touch zyy.java #主机上创建一个文件zyy.java
[root@iZwz9bo1dt9faz5t06j6ijZ zyy]# ls
hello.java zyy.java
[root@iZwz9bo1dt9faz5t06j6ijZ zyy]# docker cp zyy.java 45ee18e9901f:/home #主机拷贝到容器上
Successfully copied 1.536kB to 45ee18e9901f:/home
[root@iZwz9bo1dt9faz5t06j6ijZ zyy]# docker exec -it 45ee18e9901f /bin/bash #进入容器
[root@45ee18e9901f /]# cd /home/
[root@45ee18e9901f home]# ls #发现拷贝成功
hello.java zyy.java
3.5、命名大全
https://pythondjango.cn/python/tools/2-docker-dockerfile/

4、练习
4.1、docker安装nginx
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker search nginx #1.查找nginx镜像
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
nginx Official build of Nginx. 18287 [OK]
bitnami/nginx Bitnami nginx Docker Image 155 [OK]
bitnami/nginx-ingress-controller Bitnami Docker Image for NGINX Ingress Contr… 23 [OK]
ubuntu/nginx Nginx, a high-performance reverse proxy & we… 83
kasmweb/nginx An Nginx image based off nginx:alpine and in… 4
rancher/nginx-ingress-controller 11
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker pull nginx #2.下载nginx镜像
Using default tag: latest
latest: Pulling from library/nginx
a2abf6c4d29d: Pull complete
a9edb18cadd1: Pull complete
589b7251471a: Pull complete
186b1aaa4aa6: Pull complete
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker images #3.查看nginx镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 15 months ago 141MB
centos latest 5d0da3dc9764 18 months ago 231MB
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -it -d --name nginx02 -p 3344:80 nginx #4.启动nginx镜像
756a17e3d66eec7cc89fe68b5090473f976f1afacc8048b4564bb3e7854d27ef
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps #5.查看nginx容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
756a17e3d66e nginx "/docker-entrypoint.…" 6 seconds ago Up 5 seconds 0.0.0.0:3344->80/tcp, :::3344->80/tcp nginx02
45ee18e9901f centos "/bin/bash" 3 hours ago Up 3 hours
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# curl localhost:3344 #6.访问nginx容器
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker exec -it nginx02 /bin/bash #7.进入容器
root@756a17e3d66e:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
docker run -it -d --name nginx02 -p 3344:80 nginx解释
docker run:启动一个新的容器-it:表示启用交互式终端并分配一个伪终端,这样我们可以在容器中交互式地执行命令。-d:表示将容器运行在后台(守护进程)。--name nginx02:给容器起一个名字叫做nginx02。-p 3344:80:将主机的 3344 端口映射到容器的 80 端口,这样我们就可以通过主机的 3344 端口来访问容器内的 Nginx 服务。nginx:表示要启动的镜像名称为nginx。
因此,这个命令的作用是在 Docker 中启动一个名为 nginx02 的容器,运行 Nginx 服务,并将容器的 80 端口映射到主机的 3344 端口,以便我们可以通过访问主机的 3344 端口来访问 Nginx 服务。容器会在后台运行,并启用交互式终端。
登录阿里云,开启3344端口

浏览器可以直接访问

4.2、docker安装一个tomcat
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker pull tomcat # 下载镜像
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker images #查看镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 15 months ago 141MB
tomcat 9.0 b8e65a4d736d 15 months ago 680MB
tomcat latest fb5657adc892 15 months ago 680MB
centos latest 5d0da3dc9764 18 months ago 231MB
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -d -p 3355:8080 --name tomcat01 tomcat #启动容器
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps #查看容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
39c699abdaf2 tomcat "catalina.sh run" 18 seconds ago Up 17 seconds 0.0.0.0:3355->8080/tcp, :::3355->8080/tcp tomcat01
756a17e3d66e nginx "/docker-entrypoint.…" 43 minutes ago Up 43 minutes 0.0.0.0:3344->80/tcp, :::3344->80/tcp nginx02
45ee18e9901f centos "/bin/bash" 4 hours ago Up 4 hours xenodochial_hellman
启动容器后,开通阿里云服务的3355端口

访问服务

发现服务可以访问,但是没有页面
进入服务
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker exec -it 39c699abdaf2 /bin/bash
root@39c699abdaf2:/usr/local/tomcat/webapps# ls
root@39c699abdaf2:/usr/local/tomcat/webapps#
发现webapp下为空
# 原因:阿里云镜像的原因,阿里云默认是最小的镜像,所以不必要的都剔除掉
# 保证最小可运行的环境!
解决方案:将webapps.dist下的文件都拷贝到webapps下即可
root@39c699abdaf2:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@39c699abdaf2:/usr/local/tomcat# cd webapps
root@39c699abdaf2:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
刷新一下服务,就页面了

问题:我们以后要部署项目,如果每次都要进入容器是不是十分麻烦?要是可以在容器外部提供一个映射路径,比如webapps,我们在外部放置项目,就自动同步内部就好了!
4.3、docker安装elasticsearch
elasticsearch暴露的端口很多
十分耗内存(所以体现测试的时候可以提前把其他docker容器先停止,启动时可以限制堆内存大小)
es 的数据一般需要放置到安全目录!挂载
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -d --name es -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
Unable to find image 'elasticsearch:7.6.2' locally
7.6.2: Pulling from library/elasticsearch
ab5ef0e58194: Pull complete
c4d1ca5c8a25: Pull complete
941a3cc8e7b8: Pull complete
43ec483d9618: Pull complete
c486fd200684: Pull complete
1b960df074b2: Pull complete
1719d48d6823: Pull complete
Digest: sha256:1b09dbd93085a1e7bca34830e77d2981521a7210e11f11eda997add1c12711fa
Status: Downloaded newer image for elasticsearch:7.6.2
47f6fe60c0f9ce6e88f3c9ece266e3ede8b849f57a4d1c1aa3f515ffec72a38d
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# curl localhost:9200
{
"name" : "47f6fe60c0f9",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "bbkkYZB3SdepgzEV_-B-AQ",
"version" : {
"number" : "7.6.2",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build_date" : "2020-03-26T06:34:37.794943Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker stats #查看cpu状态


docker run -d --name es -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2命令解释
这是一个使用 Docker 命令行工具来启动一个 Elasticsearch 版本为 7.6.2 的容器,并设置了一些选项和参数。
具体来说,这些选项和参数的含义如下:
-d表示在后台运行容器,即以“守护进程”模式运行,不会占用当前终端的控制台;--name es表示给容器起一个名称为 "es";-p 9200:9200 -p 9300:9300表示将容器内部的 9200 端口和 9300 端口映射到主机的 9200 和 9300 端口上,以便在主机上通过浏览器或客户端连接 Elasticsearch;-e "discovery.type=single-node"表示设置 Elasticsearch 的节点类型为 "single-node",即单节点模式,这是一个简单的运行 Elasticsearch 的方式,适用于测试或开发环境;-e ES_JAVA_OPTS="-Xms64m -Xmx512m"表示设置 Elasticsearch 的 Java 虚拟机参数,其中 "-Xms64m" 表示设置初始堆大小为 64MB,"-Xmx512m" 表示设置最大堆大小为 512MB;elasticsearch:7.6.2表示要运行的容器镜像名称和版本号,这里是 Elasticsearch 官方提供的 7.6.2 版本。
总体来说,这个命令的作用是在 Docker 中启动一个 Elasticsearch 7.6.2 的容器,并将容器内部的端口映射到主机上,以便在主机上访问 Elasticsearch。其中的选项和参数可以根据需要进行修改或调整。
5、portainer可视化面板安装
- portainer(先用这个)
- rancher(CI/DI再用)
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
ce7fe4df829ef8d8a9bc31297008102481a0e2b7b09e619b8eb5caec3a5fcd85
[root@iZwz9bo1dt9faz5t06j6ijZ ~]#
docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer解释
这是一个用于运行 Docker 容器的 Docker 命令。具体来说,该命令启动了一个名为 Portainer 的 Docker 容器,并将容器的 9000 端口映射到主机的 8088 端口,以便在主机上通过浏览器访问 Portainer。
以下是各个参数的含义:
-d:表示以后台模式运行容器。-p 8088:9000:表示将容器的 9000 端口映射到主机的 8088 端口。--restart=always:表示容器在停止后总是会自动重启。-v /var/run/docker.sock:/var/run/docker.sock:表示将主机的 Docker 守护进程的 Unix 套接字文件(/var/run/docker.sock)挂载到容器的同一位置,从而让 Portainer 可以管理主机上的其他 Docker 容器。--privileged=true:表示在容器中开启特权模式,以便 Portainer 能够访问主机上的 Docker 守护进程。
总之,这个命令的作用是在主机上启动一个 Portainer 容器,以便通过 web 界面来管理和监控其他 Docker 容器。
阿里云服务端开启端口8088

登录:http://120.79.234.62:8088/#/init/admin

进入面板



6、docker镜像
6.1、镜像是什么?
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含
运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
6.2、docker镜像加载原理
UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,
它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系
统下(unite several directories into a single virtual fifilesystem)。Union 文件系统是 Docker 镜像的基
础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件
系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot fifile system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启
动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是
一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已
由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root fifile system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标
准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

平时我们安装进虚拟机的CentOS都是好几个G,为什么Docker这里才200M?

对于一个精简的OS,rootfs 可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直
接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版, bootfs基本是一
致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
6.3、分层理解
我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker pull redis
Using default tag: latest
latest: Pulling from library/redis
a2abf6c4d29d: Already exists
c7a4e4382001: Pull complete
4044b9ba67c9: Pull complete
c8388a79482f: Pull complete
413c8bb60be2: Pull complete
1abfd3011519: Pull complete
Digest: sha256:db485f2e245b5b3329fdc7eff4eb00f913e09d8feb9ca720788059fdc2ed8339
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest
[root@iZwz9bo1dt9faz5t06j6ijZ ~]#
思考:为什么Docker镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机
只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服
务了,而且镜像的每一层都可以被共享。
查看镜像分层的方式可以通过 docker image inspect 命令!
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker image inspect redis:latest
[
{
//....
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f",
"sha256:9b24afeb7c2f21e50a686ead025823cd2c6e9730c013ca77ad5f115c079b57cb",
"sha256:4b8e2801e0f956a4220c32e2c8b0a590e6f9bd2420ec65453685246b82766ea1",
"sha256:529cdb636f61e95ab91a62a51526a84fd7314d6aab0d414040796150b4522372",
"sha256:9975392591f2777d6bf4d9919ad1b2c9afa12f9a9b4d260f45025ec3cc9b18ed",
"sha256:8e5669d8329116b8444b9bbb1663dda568ede12d3dbcce950199b582f6e94952"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
理解:
所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之
上,创建新的镜像层。
举一个简单的例子,假如基于 Ubuntu Linux 16.04 创建一个新的镜像,这就是新镜像的第一层;如果
在该镜像中添加 Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就
会创建第三个镜像层。
该镜像当前已经包含 3 个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了
一个简单的例子,每个镜像层包含 3 个文件,而镜像包含了来自两个镜像层的 6 个文件。

上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有 6 个文件,这是因为最上层中的文件
7 是文件 5 的一个更新版本。

这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新
镜像层添加到镜像当中。
Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统
一的文件系统。
Linux 上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储
引擎都基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。
Docker 在 Windows 上仅支持 windowsfifilter 一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分
层和 CoW。
下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。

特点
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!
6.4、镜像commit
docker commit 从容器创建一个新的镜像。
docker commit 提交容器副本使之成为一个新的镜像!
# 语法
docker commit -m="提交的描述信息" -a="作者" 容器id 要创建的目标镜像名:[标签名]
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -it -p 3355:8080 tomcat #1.启动tomcat
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
33ed62665435 tomcat "catalina.sh run" 32 seconds ago Up 31 seconds 0.0.0.0:3355->8080/tcp, :::3355->8080/tcp wonderful_sinoussi
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker exec -it 33ed62665435 /bin/bash #2.进入容器
root@33ed62665435:/usr/local/tomcat# cp -r webapps.dist/* webapps #3.把webapps.dist下的所有文件拷贝到webapps.dist下
root@33ed62665435:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
root@33ed62665435:/usr/local/tomcat/webapps# exit #4.退出但是不关闭容器
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
33ed62665435 tomcat "catalina.sh run" 3 minutes ago Up 3 minutes 0.0.0.0:3355->8080/tcp, :::3355->8080/tcp wonderful_sinoussi
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker commit -a="zyy" -m "add webapps app" 33ed62665435 mytomcat:1.0 #5.commit 注意:commit的时候,容器的名字不能有大写,否则报错:invalid reference format
sha256:0863ecb3b8ee295f8a3e8a3dc678dcdaa5cd8fd9bb329b0f302cb4b3c056178f
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker images #6.查看镜像,发现我们提交的镜像已经ok
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 1.0 0863ecb3b8ee 8 seconds ago 684MB
nginx latest 605c77e624dd 15 months ago 141MB
tomcat latest fb5657adc892 15 months ago 680MB
redis latest 7614ae9453d1 15 months ago 113MB
centos latest 5d0da3dc9764 18 months ago 231MB
portainer/portainer latest 580c0e4e98b0 2 years ago 79.1MB
elasticsearch 7.6.2 f29a1ee41030 3 years ago 791MB
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker stop 33ed62665435 #7.停止之前的tomcat容器
33ed62665435
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -it -p 3355:8080 mytomcat:1.0 #8.用我们自己制作的镜像启动容器
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eca87c7626a1 mytomcat:1.0 "catalina.sh run" 49 seconds ago Up 48 seconds 0.0.0.0:3355->8080/tcp, :::3355->8080/tcp laughing_liskov
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker exec -it eca87c7626a1 /bin/bash #9.进入容器
root@eca87c7626a1:/usr/local/tomcat# cd webapps
root@eca87c7626a1:/usr/local/tomcat/webapps# ls #10.直接进去webapps路径,发现已经有数据了
ROOT docs examples host-manager manager
如果你想要保存你当前的状态,可以通过commit,来提交镜像,方便使用,类似于 VM 中的快照!

7、容器数据卷
7.2、什么是容器数据卷
docker的理念回顾:
将应用和运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对于数据的要求,是希望能够
持久化的!
就好比,你安装一个MySQL,结果你把容器删了,就相当于删库跑路了,这TM也太扯了吧!
所以我们希望容器之间有可能可以共享数据,Docker容器产生的数据,如果不通过docker commit 生成
新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了!这样是行
不通的!
为了能保存数据在Docker中我们就可以使用卷!让数据挂载到我们本地!这样数据就不会因为容器删除
而丢失了!
作用:
卷就是目录或者文件,存在一个或者多个容器中,由docker挂载到容器,但不属于联合文件系统,因此
能够绕过 Union File System , 提供一些用于持续存储或共享数据的特性
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂
载的数据卷
特点:
- 数据卷可在容器之间共享或重用数据
- 卷中的更改可以直接生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
所以:总结一句话: 就是容器的持久化,以及容器间的继承和数据共享!
7.2、使用数据卷
方式一:容器中直接使用命令来添加
挂载
命令
# docker run -it -v 宿主机绝对路径目录:容器内目录 镜像名
测试
# docker run -it -v /home/test:/home centos /bin/bash
查看数据卷是否挂载成功docker inspect 容器id

测试容器和宿主机之间数据共享:可以发现,在容器中,创建的会在宿主机中看到!

测试容器停止退出后,主机修改数据是否会同步!
- 停止容器
- 在宿主机上修改文件
- 启动刚才停止的容器
- 然后查看对应的文件,发现数据依旧同步
[root@iZwz9bo1dt9faz5t06j6ijZ home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ecbd16b1e5dd centos "/bin/bash" 4 minutes ago Up 12 seconds infallible_elion
[root@iZwz9bo1dt9faz5t06j6ijZ home]# docker stop ecbd16b1e5dd #停止容器
ecbd16b1e5dd
[root@iZwz9bo1dt9faz5t06j6ijZ home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZwz9bo1dt9faz5t06j6ijZ test]# vim test.java #修改宿主机文件
[root@iZwz9bo1dt9faz5t06j6ijZ test]# cat test.java
hello linux update2
[root@iZwz9bo1dt9faz5t06j6ijZ test]#
[root@iZwz9bo1dt9faz5t06j6ijZ home]# docker start ecbd16b1e5dd #启动容器
ecbd16b1e5dd
[root@iZwz9bo1dt9faz5t06j6ijZ home]# docker attach ecbd16b1e5dd #进入容器
[root@ecbd16b1e5dd /]# cd /home/
[root@ecbd16b1e5dd home]# ls
test.java
[root@ecbd16b1e5dd home]# cat test.java #发现数据也同步过来了
hello linux update2
实战:使用docker安装mysql
思考:mysql 数据持久化的问题!
-
下载镜像
[root@iZwz9bo1dt9faz5t06j6ijZ home]# docker pull mysql:5.7 5.7: Pulling from library/mysql 72a69066d2fe: Pull complete 93619dbc5b36: Pull complete 99da31dd6142: Pull complete 626033c43d70: Pull complete 37d5d7efb64e: Pull complete ac563158d721: Pull complete d2ba16033dad: Pull complete 0ceb82207cd7: Pull complete 37f2405cae96: Pull complete e2482e017e53: Pull complete 70deed891d42: Pull complete Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94 Status: Downloaded newer image for mysql:5.7 docker.io/library/mysql:5.7 -
启动容器
[root@iZwz9bo1dt9faz5t06j6ijZ home]# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7 888477fe44cd759f7b9d06a37f2b8235de89a9eb4cff21f004dd56ca9ac60e6d -
阿里云服务器开通3310端口

-
sqlyog连接数据库

-
用sqlyog新建数据库

-
查看宿主机目录

已同步成功
就算删除了容器,宿主机的数据也依然存在
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7命名解释
这个命令使用 Docker 运行 MySQL 5.7 容器,并做出以下配置:
-d表示容器在后台运行(即“守护进程”模式)。-p 3310:3306将容器内的 MySQL 端口 3306 映射到主机的端口 3310 上,这样你就可以通过主机上的端口 3310 访问 MySQL 服务。-v /home/mysql/conf:/etc/mysql/conf.d将主机上的目录/home/mysql/conf挂载到容器的/etc/mysql/conf.d目录中,这样你可以在主机上编辑 MySQL 配置文件,并且它们会在容器内生效。-v /home/mysql/data:/var/lib/mysql将主机上的目录/home/mysql/data挂载到容器的/var/lib/mysql目录中,这样你可以在主机上保存 MySQL 数据文件,并且它们会在容器内生效。-e MYSQL_ROOT_PASSWORD=123456设置 MySQL root 用户的密码为123456。--name mysql01指定容器的名称为mysql01,以便于管理和查找。mysql:5.7指定使用官方提供的 MySQL 5.7 镜像。
这个命令的作用是在 Docker 中创建并运行一个 MySQL 容器,同时将主机上的目录挂载到容器中,以便于配置和保存数据。
7.3、匿名和具名挂载
# 匿名挂载
# -v的时候只写了容器内的路径看,而没有写容器外的路径
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -d -P --name nginx01 -v /etc/nginx nginx
4395837576fc8fa113c4cdbe3dfbda68636c257124a068c88fc5c33c88581978
# 匿名挂载的缺点,就是不好维护,通常使用命令 docker volume维护
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker volume ls
DRIVER VOLUME NAME
local 3badcf7f3b6ee71096cbaa41109f036a34d79b010cd75f6a356dc1b66d9a3e1f
local 430769043b687eaa8601a3b80a07193ac7198e50ca254d540c01e5147c5e4ce3
local b4ae158430f3bc4b4ae1fbaf686fbe2285707c411befff02c068f7501b8e72ae
# 具名挂载
# -v 卷名:容器内路径
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx nginx
915190c2b532a10ce05ed34cc76bd2cf79d56216ad65d4c9d2952306ecfb954e
# 查看挂载的路径
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker volume inspect nginxconfig
[
{
"CreatedAt": "2023-03-29T23:32:53+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/nginxconfig/_data",
"Name": "nginxconfig",
"Options": null,
"Scope": "local"
}
]
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker volume ls
DRIVER VOLUME NAME
local 3badcf7f3b6ee71096cbaa41109f036a34d79b010cd75f6a356dc1b66d9a3e1f
local 430769043b687eaa8601a3b80a07193ac7198e50ca254d540c01e5147c5e4ce3
local b4ae158430f3bc4b4ae1fbaf686fbe2285707c411befff02c068f7501b8e72ae
local nginxconfig
# 怎么判断挂载的是卷名而不是本机目录名?
# --不是/开始就是卷名,是/开始就是目录名
# 改变文件的读写权限
# ro: readonly
# rw: readwrite
# 指定容器对我们挂载出来的内容的读写权限
# docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:ro nginx
# docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:rw nginx
- -v 容器内路径 #匿名挂载
- -v 卷名:容器内路径 #具名挂载
- -v /宿主机路径:容器内路径 #指定路径挂载
7.4、初始dockerfile
DockerFile 是用来构建Docker镜像的构建文件,是由一些列命令和参数构成的脚本。
我们在这里,先体验下,后面我们会详细讲解 DockerFile !
#1.进入宿主机/home目录,在/home目录下再创建一个目录docker-test-volume,在这个新建目录下新建一个文件dockerfile1
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# cd /home/
[root@iZwz9bo1dt9faz5t06j6ijZ home]# mkdir docker-test-volume
[root@iZwz9bo1dt9faz5t06j6ijZ home]# cd docker-test-volume/
[root@iZwz9bo1dt9faz5t06j6ijZ docker-test-volume]# touch dockerfile1
#2.编辑dockerfile1这个文件
#说明:在编写DockerFile文件中使用 VOLUME 指令来给镜像添加一个或多个数据卷
#出于可移植和分享的考虑,我们之前使用的 -v 主机目录:容器目录 这种方式不能够直接在 DockerFile中实现
#由于宿主机目录是依赖于特定宿主机的,并不能够保证在所有宿主机上都存在这样的特定目录
[root@iZwz9bo1dt9faz5t06j6ijZ docker-test-volume]# vim dockerfile1
[root@iZwz9bo1dt9faz5t06j6ijZ docker-test-volume]# cat dockerfile1
FROM centos
VOLUME ["datavolume1","datavolume2"]
CMD echo "-----end-----"
CMD /bin/bash
#3.build后生成镜像,获得一个新镜像 zyy-centos
[root@iZwz9bo1dt9faz5t06j6ijZ docker-test-volume]# docker build -f /home/docker-test-volume/dockerfile1 -t zyy-centos . #注意最后有一个.
[+] Building 0.1s (5/5) FINISHED
=> [internal] load build definition from dockerfile1 0.1s
=> => transferring dockerfile: 126B 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/centos:latest 0.0s
=> [1/1] FROM docker.io/library/centos 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:e9fd2eb8a2cf3173deb865b3b85bb2cc9314b61ea8c233eb1a789479115239d6 0.0s
=> => naming to docker.io/library/zyy-centos 0.0s
[root@iZwz9bo1dt9faz5t06j6ijZ docker-test-volume]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 1.0 0863ecb3b8ee 2 days ago 684MB
nginx latest 605c77e624dd 15 months ago 141MB
tomcat latest fb5657adc892 15 months ago 680MB
redis latest 7614ae9453d1 15 months ago 113MB
mysql 5.7 c20987f18b13 15 months ago 448MB
zyy-centos latest e9fd2eb8a2cf 18 months ago 231MB
centos latest 5d0da3dc9764 18 months ago 231MB
portainer/portainer latest 580c0e4e98b0 2 years ago 79.1MB
elasticsearch 7.6.2 f29a1ee41030 3 years ago 791MB
#4.启动容器 发现数据卷目录datavolume1和datavolume2
[root@iZwz9bo1dt9faz5t06j6ijZ docker-test-volume]# docker run -it e9fd2eb8a2cf /bin/bash
[root@b71e1178705e /]# ls
bin datavolume1 datavolume2 dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
#5.进入容器,进入datavolume1目录,创建一个container.txt文件,然后退出容器
[root@b71e1178705e /]# cd datavolume1
[root@b71e1178705e datavolume1]# ls
[root@b71e1178705e datavolume1]# touch container.txt
[root@b71e1178705e datavolume1]# ls
container.txt
[root@b71e1178705e datavolume1]# exit
#问题:通过上述步骤,容器内的卷目录地址就已经知道了,但是对应的主机目录地址在哪里呢?
#6.查看容器信息
[root@iZwz9bo1dt9faz5t06j6ijZ docker-test-volume]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b71e1178705e e9fd2eb8a2cf "/bin/bash" About a minute ago Exited (0) 23 seconds ago pensive_greider
[root@iZwz9bo1dt9faz5t06j6ijZ docker-test-volume]# docker inspect b71e1178705

#8、发现宿主机文件
[root@iZwz9bo1dt9faz5t06j6ijZ docker-test-volume]# cd /var/lib/docker/volumes/b12b129396e69019665a1263d0f126fb4ee1d76db953f8c18365396d466b2ba4/_data
[root@iZwz9bo1dt9faz5t06j6ijZ _data]# ls
container.txt
注意:如果访问出现了 cannot open directory: Permission denied
解决办法:在挂载目录后多加一个 --privileged=true参数即可
7.5、数据卷容器
命名的容器挂载数据卷,其他容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为
数据卷容器。
我们使用上一步的镜像:zyy-centos 为模板,运行容器 docker01,docker02,docker03,他
们都会具有容器卷datavolume1和datavolume2
我们来测试下,容器间传递共享
-
用zyy-centos镜像,启动容器docker01,在datavolume2目录下新建一个文件from_docker01.txt
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -it --name docker01 zyy-centos [root@9d46172d421f /]# ls bin datavolume1 datavolume2 dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var [root@9d46172d421f /]# cd datavolume2 [root@9d46172d421f datavolume2]# ls [root@9d46172d421f datavolume2]# touch from_docker01.txt [root@9d46172d421f datavolume2]# ls from_docker01.txt退出不停止容器:ctrl+p+q
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9d46172d421f zyy-centos "/bin/sh -c /bin/bash" About a minute ago Up About a minute docker01 -
用zyy-centos镜像,启动容器docker02,让docker02继承docker01
--volumes-from在datavolume2目录下新建一个文件from_docker02.txt
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -it --name docker02 --volumes-from docker01 zyy-centos [root@943bcccfd0b7 /]# cd datavolume2 [root@943bcccfd0b7 datavolume2]# ls from_docker01.txt [root@943bcccfd0b7 datavolume2]# touch from_docker02.txt [root@943bcccfd0b7 datavolume2]# ls from_docker01.txt from_docker02.txt退出不停止容器:ctrl+p+q
-
用zyy-centos镜像,启动容器docker02,让docker02继承docker01
--volumes-from在datavolume2目录下新建一个文件from_docker03.txt
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -it --name docker03 --volumes-from docker01 zyy-centos [root@82261b446201 /]# cd datavolume2 [root@82261b446201 datavolume2]# ls from_docker01.txt from_docker02.txt [root@82261b446201 datavolume2]# touch from_docker03.txt [root@82261b446201 datavolume2]# ls from_docker01.txt from_docker02.txt from_docker03.txt退出不停止容器:ctrl+p+q
-
进入容器docker01,发现三个文件均可以看到
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker attach docker01 [root@9d46172d421f datavolume2]# ls from_docker01.txt from_docker02.txt from_docker03.txt退出不停止容器:ctrl+p+q
-
停止容器docker01,并删除docker01
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 82261b446201 zyy-centos "/bin/sh -c /bin/bash" 2 minutes ago Up 2 minutes docker03 943bcccfd0b7 zyy-centos "/bin/sh -c /bin/bash" 3 minutes ago Up 3 minutes docker02 9d46172d421f zyy-centos "/bin/sh -c /bin/bash" 6 minutes ago Up 6 minutes docker01 [root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker stop 9d46172d421f 9d46172d421f [root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 82261b446201 zyy-centos "/bin/sh -c /bin/bash" 2 minutes ago Up 2 minutes docker03 943bcccfd0b7 zyy-centos "/bin/sh -c /bin/bash" 4 minutes ago Up 4 minutes docker02 [root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker rm -f docker01 docker01 -
进入容器docker02,发现三个文件仍存在
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker attach docker02 [root@943bcccfd0b7 datavolume2]# ls from_docker01.txt from_docker02.txt from_docker03.txt
得出结论:
容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止。
存储在本机的文件则会一直保留!
8、dockerfile
大家想想,Nginx,tomcat,mysql 这些镜像都是哪里来的?官方能写,我们不能写吗?
我们要研究自己如何做一个镜像,而且我们写的微服务项目以及springboot打包上云部署,Docker就是
最方便的。
微服务打包成镜像,任何装了Docker的地方,都可以下载使用,极其的方便。
流程:开发应用=>DockerFile=>打包为镜像=>上传到仓库(私有仓库,公有仓库)=> 下载镜像 => 启动
运行。
还可以方便移植!
8.1、什么是dockerfile
dockerfifile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。
构建步骤:
- 编写DockerFile文件
- docker build 构建镜像
- docker run
dockerfifile文件我们刚才已经编写过了一次,这里我们继续使用 centos 来看!
https://hub.docker.com/_/centos


8.2、dockerfile构建过程
基础知识
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
- # 表示注释
- 每条指令都会创建一个新的镜像层,并对镜像进行提交
流程:
- docker从基础镜像运行一个容器
- 执行一条指令并对容器做出修改
- 执行类似 docker commit 的操作提交一个新的镜像层
- Docker再基于刚提交的镜像运行一个新容器
- 执行dockerfifile中的下一条指令直到所有指令都执行完成!
说明:
从应用软件的角度来看,DockerFile,docker镜像与docker容器分别代表软件的三个不同阶段。
- DockerFile 是软件的原材料 (代码)
- Docker 镜像则是软件的交付品 (.apk)
- Docker 容器则是软件的运行状态 (客户下载安装执行)
DockerFile 面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可!

DockerFile:需要定义一个DockerFile,DockerFile定义了进程需要的一切东西。DockerFile涉及的内容
包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进
程和内核进程(当引用进行需要和系统服务和内核进程打交道,这时需要考虑如何设计 namespace的权
限控制)等等。
Docker镜像:在DockerFile 定义了一个文件之后,Docker build 时会产生一个Docker镜像,当运行
Docker 镜像时,会真正开始提供服务;
Docker容器:容器是直接提供服务的。
8.3、dockerfile指令
关键字:
FROM # 基础镜像,当前新镜像是基于哪个镜像的
MAINTAINER # maintainer 镜像维护者的姓名和邮箱地址
RUN # 容器构建时需要运行的命令
EXPOSE # 当前容器对外暴露出的端口
WORKDIR # 指定在创建容器后,终端默认登录进来的工作目录,一个落脚点
ENV # 用来在构建镜像过程中设置环境变量
ADD # 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
COPY # 类似ADD,拷贝文件和目录到镜像中!但是是不会自动解压文件,也不能访问网络资源
VLIUME # 容器数据卷,用于数据保存和持久化工作
CMD # 指定一个容器启动时要运行的命令,dockerFile中可以有多个CMD指令,但只有最 后一个生效!
ENTRYPOINT # entrypoint 指定一个容器启动时要运行的命令!和CMD一样 可以追加命令
ONBUILD # 当构建一个被继承的DockerFile时运行命令,父镜像在被子镜像继承后,父镜像的 ONBUILD被触发


8.4、实战测试
Docker Hub 中99% 的镜像都是通过在base镜像(Scratch)中安装和配置需要的软件构建出来的

自定一个centos镜像
-
编写dockerfile
直接运行centos的官方镜像
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker run -it centos /bin/bash [root@bc7460c8a5fe /]# pwd / [root@bc7460c8a5fe /]# vim a bash: vim: command not found [root@bc7460c8a5fe /]# ifconfig bash: ifconfig: command not found [root@bc7460c8a5fe /]#发现,不支持vim和ifconfig命令,登陆后的默认路径是/
目的:使我们自己的镜像具备如下:登陆后的默认路径、vim编辑器、查看网络配置ifconfifig支持
准备编写DockerFlie文件
[root@iZwz9bo1dt9faz5t06j6ijZ home]# mkdir dockerfile-test [root@iZwz9bo1dt9faz5t06j6ijZ home]# ls dockerfile-test docker-test-volume mysql test www zyy zyy2 zyydir [root@iZwz9bo1dt9faz5t06j6ijZ home]# cd dockerfile-test/ [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# ls [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# touch mydockerfile-centos [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# vim mydockerfile-centos [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# cat mydockerfile-centos FROM centos MAINTAINER zyy<123456@qq.com> ENV MYPATH /usr/local WORKDIR $MYPATH RUN cd /etc/yum.repos.d/ RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* RUN yum -y install vim RUN yum -y install net-tools EXPOSE 80 CMD echo $MYPATH CMD echo "----end----" CMD /bin/bash [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]#说明:dockerfile中直接
RUN yum -y install vim可能会报下面错误#0 1.607 Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: No URLs in mirrorlist说明下面这些,其实就是为了让
RUN yum -y install vim可以执行成功RUN cd /etc/yum.repos.d/ RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* RUN yum -y install vim -
构建
[root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# docker build -f mydockerfile-centos -t mycentos:1.0 . [+] Building 17.1s (11/11) FINISHED => [internal] load build definition from mydockerfile-centos 0.0s => => transferring dockerfile: 449B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/centos:latest 0.0s => [1/7] FROM docker.io/library/centos 0.0s => CACHED [2/7] WORKDIR /usr/local 0.0s => [3/7] RUN cd /etc/yum.repos.d/ 0.3s => [4/7] RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* 0.3s => [5/7] RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* 0.3s => [6/7] RUN yum -y install vim 13.0s => [7/7] RUN yum -y install net-tools 2.6s => exporting to image 0.7s => => exporting layers 0.7s => => writing image sha256:f854c594a2cf96e93d0d89e678cbfa8fdfe774e7cc0d45d53a22d80daab8dceb 0.0s => => naming to docker.io/library/mycentos:1.0 0.0s [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mycentos 1.0 f854c594a2cf 32 seconds ago 312MB mytomcat 1.0 0863ecb3b8ee 4 days ago 684MB nginx latest 605c77e624dd 15 months ago 141MB tomcat latest fb5657adc892 15 months ago 680MB redis latest 7614ae9453d1 15 months ago 113MB mysql 5.7 c20987f18b13 15 months ago 448MB zyy-centos latest e9fd2eb8a2cf 18 months ago 231MB centos latest 5d0da3dc9764 18 months ago 231MB portainer/portainer latest 580c0e4e98b0 2 years ago 79.1MB elasticsearch 7.6.2 f29a1ee41030 3 years ago 791MB命令:
docker build -f mydockerfile-centos -t mycentos:1.0 .解释:这是一个Docker命令,将使用指定的Dockerfile构建一个新的Docker镜像。
具体来说,该命令的各个部分的含义如下:
docker build:使用Docker命令构建新的镜像-f mydockerfile-centos:指定Dockerfile的名称为mydockerfile-centos。默认情况下,Docker使用当前目录下的名为Dockerfile的文件作为Dockerfile,但是在这里我们指定了一个不同的名称。-t mycentos:1.0:指定构建的镜像名称为mycentos,标签为1.0。标签可用于标识同一镜像的不同版本或变体。.:指定上下文路径,即构建过程中所使用的文件路径。这里的.表示使用当前目录作为上下文路径。
因此,该命令的含义是使用
mydockerfile-centos文件作为Dockerfile,将当前目录下的文件作为上下文构建一个名为mycentos、标签为1.0的新Docker镜像。 -
运行
[root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# docker run -it mycentos:1.0 [root@2222adcdac78 local]# pwd /usr/local [root@2222adcdac78 local]# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet) RX packets 8 bytes 656 (656.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 [root@2222adcdac78 local]# vim a [1]+ Stopped vim a -
列出镜像的变更历史
docker history 镜像id
[root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# docker history f854c594a2cf IMAGE CREATED CREATED BY SIZE COMMENT f854c594a2cf 10 minutes ago CMD ["/bin/sh" "-c" "/bin/bash"] 0B buildkit.dockerfile.v0 <missing> 10 minutes ago CMD ["/bin/sh" "-c" "echo \"----end----\""] 0B buildkit.dockerfile.v0 <missing> 10 minutes ago CMD ["/bin/sh" "-c" "echo $MYPATH"] 0B buildkit.dockerfile.v0 <missing> 10 minutes ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0 <missing> 10 minutes ago RUN /bin/sh -c yum -y install net-tools # bu… 14.7MB buildkit.dockerfile.v0 <missing> 10 minutes ago RUN /bin/sh -c yum -y install vim # buildkit 66.3MB buildkit.dockerfile.v0 <missing> 10 minutes ago RUN /bin/sh -c sed -i 's|#baseurl=http://mir… 8.8kB buildkit.dockerfile.v0 <missing> 10 minutes ago RUN /bin/sh -c sed -i 's/mirrorlist/#mirrorl… 8.82kB buildkit.dockerfile.v0 <missing> 10 minutes ago RUN /bin/sh -c cd /etc/yum.repos.d/ # buildk… 0B buildkit.dockerfile.v0 <missing> 30 minutes ago WORKDIR /usr/local 0B buildkit.dockerfile.v0 <missing> 30 minutes ago ENV MYPATH=/usr/local 0B buildkit.dockerfile.v0 <missing> 30 minutes ago MAINTAINER zyy<123456@qq.com> 0B buildkit.dockerfile.v0 <missing> 18 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 18 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B <missing> 18 months ago /bin/sh -c #(nop) ADD file:805cb5e15fb6e0bb0… 231MB [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]#
CMD和ENTRYPOINT的去呗
我们之前说过,两个命令都是指定一个容器启动时要运行的命令
CMD**:**Dockerfifile 中可以有多个CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数
替换!
ENTRYPOINT**:** docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合!
测试:
-
新建两个dockerfile文件:mydockerfile-centos-cmd、mydockerfile-centos-entrypoint,编辑内容如下
[root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# vim mydockerfile-centos-cmd [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# vim mydockerfile-centos-entrypoint [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# cat mydockerfile-centos-cmd FROM centos CMD ["ls","-a"] [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# cat mydockerfile-centos-entrypoint FROM centos CMD ["ls","-a"] -
构建两个新的镜像:mydockerfile-centos-cmd、mydockerfile-centos-entrypoint
[root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# docker build -f mydockerfile-centos-cmd -t mycentos-cmd:1.0 . [+] Building 0.1s (5/5) FINISHED => [internal] load build definition from mydockerfile-centos-cmd 0.0s => => transferring dockerfile: 79B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/centos:latest 0.0s => CACHED [1/1] FROM docker.io/library/centos 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:21164980c13c6ef0c96c355528cf73f4b9a77b257abba4336afb88538296865f 0.0s => => naming to docker.io/library/mycentos-cmd:1.0 0.0s [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# docker build -f mydockerfile-centos-entrypoint -t mycentos-entrypoint:1.0 . [+] Building 0.0s (5/5) FINISHED => [internal] load build definition from mydockerfile-centos-entrypoint 0.0s => => transferring dockerfile: 93B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/centos:latest 0.0s => CACHED [1/1] FROM docker.io/library/centos 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:9f35f7608f6b68060dace86e7bbfd93750ff80067e358c829c227c97789b8579 0.0s => => naming to docker.io/library/mycentos-entrypoint:1.0 0.0s [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mycentos-entrypoint 1.0 9f35f7608f6b 18 months ago 231MB mycentos-cmd 1.0 21164980c13c 18 months ago 231MB -
运行mycentos-cmd
[root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# docker run 21164980c13c . .. .dockerenv bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# docker run 21164980c13c -l docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown.我们希望-l 列表展示信息,发现报错
之前我们说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。
因此这里的 -l 替换了原来的 CMD,而不是添加在原来的 ls -a 后面。而 -l 根本不是命令,所
以自然找不到。
那么如果我们希望加入 -l 这参数,我们就必须重新完整的输入这个命令:
[root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# docker run 21164980c13c ls -al total 56 drwxr-xr-x 1 root root 4096 Apr 1 08:33 . drwxr-xr-x 1 root root 4096 Apr 1 08:33 .. -rwxr-xr-x 1 root root 0 Apr 1 08:33 .dockerenv lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin drwxr-xr-x 5 root root 340 Apr 1 08:33 dev drwxr-xr-x 1 root root 4096 Apr 1 08:33 etc drwxr-xr-x 2 root root 4096 Nov 3 2020 home lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64 drwx------ 2 root root 4096 Sep 15 2021 lost+found drwxr-xr-x 2 root root 4096 Nov 3 2020 media drwxr-xr-x 2 root root 4096 Nov 3 2020 mnt drwxr-xr-x 2 root root 4096 Nov 3 2020 opt dr-xr-xr-x 108 root root 0 Apr 1 08:33 proc dr-xr-x--- 2 root root 4096 Sep 15 2021 root drwxr-xr-x 11 root root 4096 Sep 15 2021 run lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin drwxr-xr-x 2 root root 4096 Nov 3 2020 srv dr-xr-xr-x 13 root root 0 Apr 1 08:25 sys drwxrwxrwt 7 root root 4096 Sep 15 2021 tmp drwxr-xr-x 12 root root 4096 Sep 15 2021 usr drwxr-xr-x 20 root root 4096 Sep 15 2021 var [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# -
运行mycentos-entrypoint
[root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# docker run 9f35f7608f6b . .. .dockerenv bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var [root@iZwz9bo1dt9faz5t06j6ijZ dockerfile-test]# docker run 9f35f7608f6b -l total 56 drwxr-xr-x 1 root root 4096 Apr 1 08:25 . drwxr-xr-x 1 root root 4096 Apr 1 08:25 .. -rwxr-xr-x 1 root root 0 Apr 1 08:25 .dockerenv lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin drwxr-xr-x 5 root root 340 Apr 1 08:25 dev drwxr-xr-x 1 root root 4096 Apr 1 08:25 etc drwxr-xr-x 2 root root 4096 Nov 3 2020 home lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64 drwx------ 2 root root 4096 Sep 15 2021 lost+found drwxr-xr-x 2 root root 4096 Nov 3 2020 media drwxr-xr-x 2 root root 4096 Nov 3 2020 mnt drwxr-xr-x 2 root root 4096 Nov 3 2020 opt dr-xr-xr-x 108 root root 0 Apr 1 08:25 proc dr-xr-x--- 2 root root 4096 Sep 15 2021 root drwxr-xr-x 11 root root 4096 Sep 15 2021 run lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin drwxr-xr-x 2 root root 4096 Nov 3 2020 srv dr-xr-xr-x 13 root root 0 Apr 1 08:25 sys drwxrwxrwt 7 root root 4096 Sep 15 2021 tmp drwxr-xr-x 12 root root 4096 Sep 15 2021 usr drwxr-xr-x 20 root root 4096 Sep 15 2021 var测试-l参数,发现可以直接使用,这里就是一种追加,我们可以明显的知道 CMD 和
ENTRYPOINT 的区别了
自定义镜像tomcat
-
新建一个路径,并准备好tomcat和jdk的压缩包(官网下载后本地上传到服务器),并新建一个read.txt
[root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# pwd /home/zyydir/build/tomcat [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# touch read.txt [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# ll -rw-r--r-- 1 root root 11625808 Apr 2 10:38 apache-tomcat-9.0.73.tar.gz -rw-r--r-- 1 root root 194042837 Apr 2 10:51 jdk-8u202-linux-x64.tar.gz -rw-r--r-- 1 root root 0 Apr 2 10:52 read.txt -
新建一个Dockfile文件,并编辑
[root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# vim Dockerfile [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# cat Dockerfile FROM centos MAINTAINER zyy<123456@qq.com> COPY read.txt /usr/local/read.txt ADD apache-tomcat-9.0.73.tar.gz /usr/local/ ADD jdk-8u202-linux-x64.tar.gz /usr/local/ RUN cd /etc/yum.repos.d/ RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* RUN yum -y install vim ENV MYPATH /usr/local WORKDIR $MYPATH ENV JAVA_HOME /usr/local/jdk1.8.0_202 ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.73 ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.73 ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin EXPOSE 8080 CMD /usr/local/apache-tomcat-9.0.73/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.73/bin/logs/catalina.out [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# ll total 200856 -rw-r--r-- 1 root root 11625808 Apr 2 10:38 apache-tomcat-9.0.73.tar.gz -rw-r--r-- 1 root root 828 Apr 2 10:54 Dockerfile -rw-r--r-- 1 root root 194042837 Apr 2 10:51 jdk-8u202-linux-x64.tar.gz -rw-r--r-- 1 root root 0 Apr 2 10:52 read.txt -
构建镜像
[root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# docker build -t diytomcat . [+] Building 29.0s (14/14) FINISHED => [internal] load build definition from Dockerfile 0.1s => => transferring dockerfile: 867B 0.0s => [internal] load .dockerignore 0.1s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/centos:latest 0.0s => [1/9] FROM docker.io/library/centos 0.0s => [internal] load build context 2.8s => => transferring context: 205.72MB 2.8s => CACHED [2/9] COPY read.txt /usr/local/read.txt 0.0s => CACHED [3/9] ADD apache-tomcat-9.0.73.tar.gz /usr/local/ 0.0s => [4/9] ADD jdk-8u202-linux-x64.tar.gz /usr/local/ 6.8s => [5/9] RUN cd /etc/yum.repos.d/ 0.5s => [6/9] RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* 0.3s => [7/9] RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* 0.3s => [8/9] RUN yum -y install vim 13.8s => [9/9] WORKDIR /usr/local 0.1s => exporting to image 4.3s => => exporting layers 4.3s => => writing image sha256:283a8bc25a764cd5d2614b4a10a0660f330de15c1a0d4f89eeb0efc44bca3ce1 0.0s => => naming to docker.io/library/diytomcat 0.0s [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# docker images diytomcat REPOSITORY TAG IMAGE ID CREATED SIZE diytomcat latest 283a8bc25a76 42 seconds ago 716MB -
启动容器
[root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# docker run -d -p 9090:8080 --name mydiytomcat -v /home/zyydir/build/tomcat/test:/usr/local/apache-tomcat-9.0.73/webapps/test -v /home/zyydir/build/tomcat/logs:/usr/local/apache-tomcat-9.0.73/logs diytomcat 7794a2558b7d746b2579b48e4f6037fcca3ab7d43ae7ecab9bee3afa0984e4f2 [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7794a2558b7d diytomcat "/bin/sh -c '/usr/lo…" 10 seconds ago Up 9 seconds 0.0.0.0:9090->8080/tcp, :::9090->8080/tcp mydiytomcat [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# ls apache-tomcat-9.0.73.tar.gz Dockerfile jdk-8u202-linux-x64.tar.gz logs read.txt test [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# cd logs/ [root@iZwz9bo1dt9faz5t06j6ijZ logs]# ls catalina.2023-04-02.log catalina.out host-manager.2023-04-02.log localhost.2023-04-02.log localhost_access_log.2023-04-02.txt manager.2023-04-02.log [root@iZwz9bo1dt9faz5t06j6ijZ logs]# cd .. [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# ls apache-tomcat-9.0.73.tar.gz Dockerfile jdk-8u202-linux-x64.tar.gz logs read.txt test [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# cd test/ [root@iZwz9bo1dt9faz5t06j6ijZ test]# ls -
开启阿里云9090端口

-
访问
[root@iZwz9bo1dt9faz5t06j6ijZ test]# curl localhost:9090

-
结合前面学习的容器卷将测试的web服务test发布
WEB-INF下新建一个web.xml
[root@iZwz9bo1dt9faz5t06j6ijZ test]# mkdir WEB-INF [root@iZwz9bo1dt9faz5t06j6ijZ test]# cd WEB-INF/ [root@iZwz9bo1dt9faz5t06j6ijZ WEB-INF]# ls [root@iZwz9bo1dt9faz5t06j6ijZ WEB-INF]# vim web.xmlweb.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>test</display-name> </web-app>在test下新建一个a.jsp
[root@iZwz9bo1dt9faz5t06j6ijZ WEB-INF]# cd .. [root@iZwz9bo1dt9faz5t06j6ijZ test]# vim a.jspa.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>hello,kuangshen</title> </head> <body> -----------welcome------------ <%=" my docker tomcat "%> <br> <br> <% System.out.println("-------my docker tomcat-------");%> </body> </html> -
直接访问这个a.jsp
[root@iZwz9bo1dt9faz5t06j6ijZ test]# curl localhost:9090/test/a.jsp

还可以查看catalina.out,可以看到服务启动和我们打印的日志

8.5、发布镜像
DockerHub
-
注册dockerhub https://hub.docker.com/,注册一个账号

-
登录
[root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# docker login -u zyy1234 Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded -
修改一下tag
[root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE diytomcat latest 283a8bc25a76 About an hour ago 716MB mytomcat 1.0 0863ecb3b8ee 5 days ago 684MB [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# docker tag 283a8bc25a76 diytomcat:1.0 [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE diytomcat 1.0 283a8bc25a76 About an hour ago 716MB diytomcat latest 283a8bc25a76 About an hour ago 716MB mytomcat 1.0 0863ecb3b8ee 5 days ago 684MB -
push,发现报错
问题:本地镜像名无帐号信息,解决加 tag即可
[root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# docker push diytomcat:1.0 The push refers to repository [docker.io/library/diytomcat] 5f70bf18a086: Preparing a75326eea74e: Preparing 15c92469e90d: Preparing 81cdfe5060d2: Preparing 7f49a14bf706: Preparing 9e121fd97bcc: Waiting 43ca038d9c37: Waiting 74ddd0ec08fa: Waiting denied: requested access to the resource is denied -
修复问题,修改tag
[root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# docker tag 283a8bc25a76 zyy1234/diytomcat:1.0 [root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE diytomcat 1.0 283a8bc25a76 About an hour ago 716MB diytomcat latest 283a8bc25a76 About an hour ago 716MB zyy1234/diytomcat 1.0 283a8bc25a76 About an hour ago 716MB mytomcat 1.0 0863ecb3b8ee 5 days ago 684MB -
push
[root@iZwz9bo1dt9faz5t06j6ijZ tomcat]# docker push zyy1234/diytomcat:1.0 The push refers to repository [docker.io/zyy1234/diytomcat] 5f70bf18a086: Pushed a75326eea74e: Pushing [================================> ] 42.51MB/66.29MB 15c92469e90d: Pushed 81cdfe5060d2: Pushed 7f49a14bf706: Pushing [=======> ] 58.15MB/402.5MB 9e121fd97bcc: Pushing [===============================> ] 10.27MB/16.17MB 43ca038d9c37: Pushed 74ddd0ec08fa: Pushing [================> ] 74.42MB/231.3MB
阿里云镜像服务
-
登录阿里云,找到容器镜像服务

-
创建个人实例(已存在可以忽略)

-
进入个人实例,创建命名空间

-
镜像仓库中,创建镜像仓库



-
打开上面新建的仓库,这里有具体push的步骤

-
操作一下
[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker login --username=大垚大摆 registry.cn-shenzhen.aliyuncs.com Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded[root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker tag 283a8bc25a76 registry.cn-shenzhen.aliyuncs.com/zyy1234/zyy-repository:1.0 [root@iZwz9bo1dt9faz5t06j6ijZ ~]# docker push registry.cn-shenzhen.aliyuncs.com/zyy1234/zyy-repository:1.0
8.6、总结

9、docker网络
9.1、理解docker0
准备工作:清空所有的容器,清空所有的镜像
docker rm -f $(docker ps -a -q) # 删除所有容器
docker rmi -f $(docker images -qa) # 删除全部镜像
先做个测试--现象
-
制作一个可以使用
ip addr和ping命令的镜像(已经支持的,可以忽略这个步骤)下载tomcat原生镜像并启动tomcat容器
tomcat01[root@iZwz9efdd2ukk4oauustczZ zyydir]# docker run -d -P --name tomcat01 tomcat查看容器
tomcat01内部的ip地址,发现报错如下:[root@iZwz9efdd2ukk4oauustczZ zyydir]# docker exec -it tomcat01 ip addr OCI runtime exec failed: exec failed: unable to start container process: exec: "ip": executable file not found in $PATH: unknown [root@iZwz9efdd2ukk4oauustczZ zyydir]# docker exec -it tomcat01 /bin/bash root@de8e3961c49d:/usr/local/tomcat# ip addr bash: ip: command not found进入容器执行命令,即可解决
apt update && apt install -y iproute2在容器
tomcat01ping一下,发现报错如下[root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat02 ping 172.17.0.2 OCI runtime exec failed: exec failed: unable to start container process: exec: "ping": executable file not found in $PATH: unknown [root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it 3ff487ee3a74 /bin/bash root@3ff487ee3a74:/usr/local/tomcat# ping 172.17.0.2 bash: ping: command not found进入容器执行命令,即可解决
apt-get update && apt-get install -y iputils-ping容器执行了上面两个命令后,就可以正常使用
ip addr和ping这两个命令了,然后我们把容器commit一下,就有个一个新的镜像了 -
查看一下主机本地的ip 地址
ip addr
-
lo 本机回环地址
-
eth0 阿里云的私有ip
-
docker0 docker网桥
-
-
启动容器
tomcat01,查看一下容器的ip,然后再查一下主机本地ip[root@iZwz9efdd2ukk4oauustczZ ~]# docker run -d -P --name tomcat01 mytomcat1.1 f11117b10415507d70842a0f867e76fc90fcd9eeec3c839026dfd6deb3f04bf9 [root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat01 ip addr
[root@iZwz9efdd2ukk4oauustczZ ~]# ip addrdocker会给每个容器都分配一个ip

-
再启动容器
tomcat02,查看一下容器的ip,然后再查一下主机本地ip[root@iZwz9efdd2ukk4oauustczZ ~]# docker run -d -P --name tomcat02 mytomcat1.1 242682cc4bd9c20fe6e177e7c6f4bb5d64af5432ba553500d83546149cef6903 [root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat02 ip addr
[root@iZwz9efdd2ukk4oauustczZ ~]# ip addr
-
tomcat01中是否可以ping通tomcat02的ip?先进入tomcat01容器
[root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it f11117b10415 /bin/bash root@f11117b10415:/usr/local/tomcat# ping 172.17.0.3
是可以通的
原理
-
每一个安装了Docker的linux主机都有一个docker0的虚拟网卡。这是个桥接网卡,使用了veth-pair
技术!
-
每启动一个容器,linux主机就会多了一个虚拟网卡。
veth-pair 就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着。
正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备!

结论:tomcat1和tomcat2共用一个路由器。是的,他们使用的一个,就是docker0。任何一个容器启动
默认都是docker0网络。
docker默认会给容器分配一个可用ip。
小结
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据
Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网
关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接
通信。

Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并
让他们彼此联通(这样一对接口叫veth pair);
Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中
进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容
器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。
9.2、--link
思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们
能不能使用服务名访问呢?
jdbc:mysql://mysql:3306,这样的话哪怕mysql重启,我们也不需要修改配置了!docker提供了 --link
的操作!
# 直接用tomcat01 ping tomcat02 发现不行
[root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat01 ping tomcat02
ping: tomcat02: Name or service not known
# 我们再启动一个tomcat03 并且启动的时候连接tomcat02
[root@iZwz9efdd2ukk4oauustczZ ~]# docker run -d -P --name tomcat03 --link tomcat02 mytomcat1.1
4725505179ab997453583620c1fc37e3d0ebf80ec3ffe5dd80fb16f656730c46
# 这个时候我们就可以用tomcat03 ping tomcat02了
[root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.133 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.091 ms
^Z64 bytes from tomcat02 (172.17.0.3): icmp_seq=3 ttl=64 time=0.084 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=4 ttl=64 time=0.074 ms
# 再次测试,用tomcat02 ping tomcat03 发现不行 反向ping不通
[root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
# 再次测试,用tomcat03 ping tomcat01 发现也不行 没有连接也不行
[root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat03 ping tomcat01
ping: tomcat01: Name or service not known
思考,这个原理是什么呢?我们进入tomcat03中查看下host配置文件
[root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 tomcat02 242682cc4bd9 # 发现tomcat2直接被写在这里
172.17.0.4 4725505179ab
# 所以这里其实就是配置了一个 hosts 地址而已!
# 原因:--link的时候,直接把需要link的主机的域名和ip直接配置到了hosts文件中了。
--link早都过时了,我们不推荐使用!我们可以使用自定义网络的方式
9.3、自定义网络
基本命令查看
命令如下:
[root@iZwz9efdd2ukk4oauustczZ ~]# docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.
查看所有网络
[root@iZwz9efdd2ukk4oauustczZ ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
ba1f42400a65 bridge bridge local
8b1a4e90220e host host local
769e58794dd8 none null local
[root@iZwz9efdd2ukk4oauustczZ ~]#
所有网络模式
| 网络模式 | 配置 | 说明 |
|---|---|---|
| bridge模式 | --net=bridge | 默认值,在Docker网桥docker0上为容器创建新的网络栈 |
| none模式 | --net=none | 不配置网络,用户可以稍后进入容器,自行配置 |
| container模式 | --net=container:name/id | 容器和另外一个容器共享Network namespace。kubernetes中的pod就是多个容器共享一个Network namespace |
| host模式 | --net=host | 容器和宿主机共享Network namespace |
| 用户自定义模式 | --net=自定义网络 | 用户自己使用network相关命令定义网络,创建容器的时候可以指定为自己定义的网络 |
查看一个具体的网络的详情
[root@iZwz9efdd2ukk4oauustczZ ~]# docker network inspect 4725505179ab
[]
Error response from daemon: network 4725505179ab not found
[root@iZwz9efdd2ukk4oauustczZ ~]# docker network inspect ba1f42400a65
[
{
"Name": "bridge",
"Id": "ba1f42400a655aeee8c305cbfd9e05c65bda93d70728a3d9334b6eab242fd9b4",
"Created": "2023-04-05T00:31:36.123901723+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
// 默认docker0是管理这个子网范围内的
// docker0网络默认可以支持创建6万多个容器ip不重复 下面有解释为啥是6w多个
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"242682cc4bd9c20fe6e177e7c6f4bb5d64af5432ba553500d83546149cef6903": {
"Name": "tomcat02",
"EndpointID": "02c77bc16ed07d9626d6c3d0d6fc80ebf20573d624fed5418642064635698f1f",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"4725505179ab997453583620c1fc37e3d0ebf80ec3ffe5dd80fb16f656730c46": {
"Name": "tomcat03",
"EndpointID": "702d95da29bd806dede27c5d05fdf580398dbd9855a056fcc0de19737c1ab35f",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16",
"IPv6Address": ""
},
"f11117b10415507d70842a0f867e76fc90fcd9eeec3c839026dfd6deb3f04bf9": {
"Name": "tomcat01",
"EndpointID": "075900c171e9f982d38f6ccb4f069565c2e33402f62b28aaca8ac184c6b1838b",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
拓展:
- 172.17.0.0/16 是一个 CIDR 地址,其中 /16 表示子网掩码的位数,即 255.255.0.0。这个地址范围内的 IP 地址数量是 2^16 - 2 = 65534。其中,2^16 表示该地址范围内的 IP 地址总数,而减去 2 是因为该地址范围内的第一个 IP 地址是网络地址,最后一个 IP 地址是广播地址,不能使用
- 172.17.0.0/24 是一个 CIDR 地址,其中 /24 表示子网掩码的位数,即 255.255.255.0。这个地址范围内的 IP 地址数量是 2^8 - 2 = 254。其中,2^8 表示该地址范围内的 IP 地址总数,而减去 2 是因为该地址范围内的第一个 IP 地址是网络地址,最后一个 IP 地址是广播地址,不能使用。
自定义网卡
-
删除原来的所有的容器(这样干净一点)
[root@iZwz9efdd2ukk4oauustczZ ~]# docker rm -f $(docker ps -aq) 4725505179ab 242682cc4bd9 f11117b10415 [root@iZwz9efdd2ukk4oauustczZ ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES这样网络就恢复最初的样子了
[root@iZwz9efdd2ukk4oauustczZ ~]# ip addr 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 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00:16:3e:06:ad:3e brd ff:ff:ff:ff:ff:ff inet 172.19.41.97/18 brd 172.19.63.255 scope global dynamic eth0 valid_lft 315057909sec preferred_lft 315057909sec 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:b9:cf:20:fb brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever -
自定义网络
查看命令使用
[root@iZwz9efdd2ukk4oauustczZ ~]# docker network Usage: docker network COMMAND Manage networks Commands: connect Connect a container to a network create Create a network disconnect Disconnect a container from a network inspect Display detailed information on one or more networks ls List networks prune Remove all unused networks rm Remove one or more networks Run 'docker network COMMAND --help' for more information on a command. [root@iZwz9efdd2ukk4oauustczZ ~]# docker network create --help Usage: docker network create [OPTIONS] NETWORK Create a network Options: --attachable Enable manual container attachment --aux-address map Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[]) --config-from string The network from which to copy the configuration --config-only Create a configuration only network -d, --driver string Driver to manage the Network (default "bridge") --gateway strings IPv4 or IPv6 Gateway for the master subnet --ingress Create swarm routing-mesh network --internal Restrict external access to the network --ip-range strings Allocate container ip from a sub-range --ipam-driver string IP Address Management Driver (default "default") --ipam-opt map Set IPAM driver specific options (default map[]) --ipv6 Enable IPv6 networking --label list Set metadata on a network -o, --opt map Set driver specific options (default map[]) --scope string Control the network's scope --subnet strings Subnet in CIDR format that represents a network segment# 自定义一个网络 [root@iZwz9efdd2ukk4oauustczZ ~]# docker network create --driver bridge --subnet 192.17.0.0/16 --gateway 192.17.0.1 mynet b39a1b5892e34105b5cfc108e25f3e811248362334896adf1430c0c2c9a06b56 # 确认已经创建好 [root@iZwz9efdd2ukk4oauustczZ ~]# docker network ls NETWORK ID NAME DRIVER SCOPE ba1f42400a65 bridge bridge local 8b1a4e90220e host host local b39a1b5892e3 mynet bridge local 769e58794dd8 none null local # 查看一下自定义网络信息 [root@iZwz9efdd2ukk4oauustczZ ~]# docker network inspect mynet [ { "Name": "mynet", "Id": "b39a1b5892e34105b5cfc108e25f3e811248362334896adf1430c0c2c9a06b56", "Created": "2023-04-08T12:19:13.011744556+08:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "192.17.0.0/16", "Gateway": "192.17.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": {}, "Labels": {} } ] -
基于自定义网络启动2个容器
[root@iZwz9efdd2ukk4oauustczZ ~]# docker run -d -P --name tomcat-net-1 --net mynet mytomcat1.1 d882ec326550e16e0196c9e3257b0a87ce185d55f35918b0211c0e43264a72e7 [root@iZwz9efdd2ukk4oauustczZ ~]# docker run -d -P --name tomcat-net-2 --net mynet mytomcat1.1 43349138cfa25ef4d2fda31454dae9d783b3b029ad8eb10ebc1ddda8e9776a22 [root@iZwz9efdd2ukk4oauustczZ ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 43349138cfa2 mytomcat1.1 "catalina.sh run" 14 seconds ago Up 12 seconds 0.0.0.0:32779->8080/tcp tomcat-net-2 d882ec326550 mytomcat1.1 "catalina.sh run" 19 seconds ago Up 18 seconds 0.0.0.0:32778->8080/tcp tomcat-net-1 -
再次查看一下网络
[root@iZwz9efdd2ukk4oauustczZ ~]# docker network inspect mynet [ { //.... //这里多了2个容器的网络信息 "Containers": { "43349138cfa25ef4d2fda31454dae9d783b3b029ad8eb10ebc1ddda8e9776a22": { "Name": "tomcat-net-2", "EndpointID": "f508128854ce1ebb272db8c6c7b32ad5235ca6e79f262a17895a4ec43747b792", "MacAddress": "02:42:c0:11:00:03", "IPv4Address": "192.17.0.3/16", "IPv6Address": "" }, "d882ec326550e16e0196c9e3257b0a87ce185d55f35918b0211c0e43264a72e7": { "Name": "tomcat-net-1", "EndpointID": "a754bf88af0ceedd92a906e0e705403d940d6b5a3689c0f98ef368699a41352d", "MacAddress": "02:42:c0:11:00:02", "IPv4Address": "192.17.0.2/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ] -
测试网络连通性
# 直接tomcat-net-1 ping tomcat-net-2的ip 可以 [root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat-net-1 ping 192.17.0.3 PING 192.17.0.3 (192.17.0.3) 56(84) bytes of data. 64 bytes from 192.17.0.3: icmp_seq=1 ttl=64 time=0.107 ms 64 bytes from 192.17.0.3: icmp_seq=2 ttl=64 time=0.087 ms 64 bytes from 192.17.0.3: icmp_seq=3 ttl=64 time=0.081 ms 64 bytes from 192.17.0.3: icmp_seq=4 ttl=64 time=0.074 ms 64 bytes from 192.17.0.3: icmp_seq=5 ttl=64 time=0.096 ms 64 bytes from 192.17.0.3: icmp_seq=6 ttl=64 time=0.076 ms# 直接tomcat-net-1 ping tomcat-net-2的容器名 也可以 [root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat-net-1 ping tomcat-net-2 PING tomcat-net-2 (192.17.0.3) 56(84) bytes of data. 64 bytes from tomcat-net-2.mynet (192.17.0.3): icmp_seq=1 ttl=64 time=0.079 ms 64 bytes from tomcat-net-2.mynet (192.17.0.3): icmp_seq=2 ttl=64 time=0.075 ms 64 bytes from tomcat-net-2.mynet (192.17.0.3): icmp_seq=3 ttl=64 time=0.075 ms 64 bytes from tomcat-net-2.mynet (192.17.0.3): icmp_seq=4 ttl=64 time=0.086 ms 64 bytes from tomcat-net-2.mynet (192.17.0.3): icmp_seq=5 ttl=64 time=0.081 ms 64 bytes from tomcat-net-2.mynet (192.17.0.3): icmp_seq=6 ttl=64 time=0.114 ms发现,我们自定义的网络docker都已经帮我们维护好了对应的关系
所以我们平时都可以这样使用网络,不使用--link效果一样,所有东西实时维护好,直接域名 ping
通。
9.4、网络连通
-
启动两个容器(默认,基于docker0的网络)
[root@iZwz9efdd2ukk4oauustczZ ~]# docker run -d -P --name tomcat-1 mytomcat1.1 a4e6ece319c91eb8d67d646411f9809ffa570b8f8ff5fb020a19d813fc72952d [root@iZwz9efdd2ukk4oauustczZ ~]# docker run -d -P --name tomcat-2 mytomcat1.1 dae040020ecc87370713a87e0f68c6d5e6e3d3df2d29e887f251f8da7766e836 [root@iZwz9efdd2ukk4oauustczZ ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dae040020ecc mytomcat1.1 "catalina.sh run" 4 seconds ago Up 4 seconds 0.0.0.0:32781->8080/tcp tomcat-2 a4e6ece319c9 mytomcat1.1 "catalina.sh run" 8 seconds ago Up 8 seconds 0.0.0.0:32780->8080/tcp tomcat-1 43349138cfa2 mytomcat1.1 "catalina.sh run" 3 hours ago Up 3 hours 0.0.0.0:32779->8080/tcp tomcat-net-2 d882ec326550 mytomcat1.1 "catalina.sh run" 3 hours ago Up 3 hours 0.0.0.0:32778->8080/tcp tomcat-net-1
docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离:
那关键的问题来了,如何让 tomcat-1 访问 tomcat-net-1?
[root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat-1 ping tomcat-net-1 ping: tomcat-net-1: Name or service not known -
使用network connect 命令连接
[root@iZwz9efdd2ukk4oauustczZ ~]# docker network connect mynet tomcat-1 -
再次验证,通了
[root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat-1 ping tomcat-net-1 PING tomcat-net-1 (192.17.0.2) 56(84) bytes of data. 64 bytes from tomcat-net-1.mynet (192.17.0.2): icmp_seq=1 ttl=64 time=0.098 ms 64 bytes from tomcat-net-1.mynet (192.17.0.2): icmp_seq=2 ttl=64 time=0.081 ms 64 bytes from tomcat-net-1.mynet (192.17.0.2): icmp_seq=3 ttl=64 time=0.073 ms 64 bytes from tomcat-net-1.mynet (192.17.0.2): icmp_seq=4 ttl=64 time=0.073 ms 64 bytes from tomcat-net-1.mynet (192.17.0.2): icmp_seq=5 ttl=64 time=0.078 ms 64 bytes from tomcat-net-1.mynet (192.17.0.2): icmp_seq=6 ttl=64 time=0.085 ms 64 bytes from tomcat-net-1.mynet (192.17.0.2): icmp_seq=7 ttl=64 time=0.075 ms 64 bytes from tomcat-net-1.mynet (192.17.0.2): icmp_seq=8 ttl=64 time=0.086 ms 64 bytes from tomcat-net-1.mynet (192.17.0.2): icmp_seq=9 ttl=64 time=0.081 ms# tomcat-net-1 ping tomcat-1也是通的 [root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat-net-1 ping tomcat-1 PING tomcat-1 (192.17.0.4) 56(84) bytes of data. 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=1 ttl=64 time=0.074 ms 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=2 ttl=64 time=0.073 ms 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=3 ttl=64 time=0.100 ms 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=4 ttl=64 time=0.077 ms ^X64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=5 ttl=64 time=0.074 ms 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=6 ttl=64 time=0.075 ms 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=7 ttl=64 time=0.074 ms# tomcat-net-2 ping tomcat-1 也是通的 [root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat-net-2 ping tomcat-1 PING tomcat-1 (192.17.0.4) 56(84) bytes of data. 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=1 ttl=64 time=0.092 ms 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=2 ttl=64 time=0.100 ms 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=3 ttl=64 time=0.075 ms 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=4 ttl=64 time=0.091 ms 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=5 ttl=64 time=0.085 ms 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=6 ttl=64 time=0.089 ms 64 bytes from tomcat-1.mynet (192.17.0.4): icmp_seq=7 ttl=64 time=0.083 ms# tomcat-net-2 ping tomcat-2 不通,反之也一样,就和上面的图一样 [root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat-net-2 ping tomcat-2 ping: tomcat-2: Name or service not known -
看一下tomcat-1的网络信息(tomcat01拥有了双ip)
[root@iZwz9efdd2ukk4oauustczZ ~]# docker exec -it tomcat-1 ip addr 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 49: eth0@if50: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever 53: eth1@if54: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:c0:11:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 192.17.0.4/16 brd 192.17.255.255 scope global eth1 valid_lft forever preferred_lft forever -
再看一下mynet的网络信息
[root@iZwz9efdd2ukk4oauustczZ ~]# docker network inspect mynet [ { //... //发现我们的tomcat-1就进来这里了 "Containers": { "43349138cfa25ef4d2fda31454dae9d783b3b029ad8eb10ebc1ddda8e9776a22": { "Name": "tomcat-net-2", "EndpointID": "f508128854ce1ebb272db8c6c7b32ad5235ca6e79f262a17895a4ec43747b792", "MacAddress": "02:42:c0:11:00:03", "IPv4Address": "192.17.0.3/16", "IPv6Address": "" }, "a4e6ece319c91eb8d67d646411f9809ffa570b8f8ff5fb020a19d813fc72952d": { "Name": "tomcat-1", "EndpointID": "6d6118f21f6d53fa15efe96b8913036d1c731c2b2389d84e8e7d9ff4fcc49f06", "MacAddress": "02:42:c0:11:00:04", "IPv4Address": "192.17.0.4/16", "IPv6Address": "" }, "d882ec326550e16e0196c9e3257b0a87ce185d55f35918b0211c0e43264a72e7": { "Name": "tomcat-net-1", "EndpointID": "a754bf88af0ceedd92a906e0e705403d940d6b5a3689c0f98ef368699a41352d", "MacAddress": "02:42:c0:11:00:02", "IPv4Address": "192.17.0.2/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ]
结论:如果要跨网络操作别人,就需要使用 docker network connect [OPTIONS] NETWORK CONTAINER 连接
9.5、实战:部署一个redis集群
-
创建redis自定义网络
[root@iZwz9efdd2ukk4oauustczZ ~]# docker network create redis --subnet 172.38.0.0/16
-
通过shell脚本创建6个redis配置
for port in $(seq 1 6); \ do \ mkdir -p /mydata/redis/node-${port}/conf touch /mydata/redis/node-${port}/conf/redis.conf cat << EOF >/mydata/redis/node-${port}/conf/redis.conf port 6379 bind 0.0.0.0 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 cluster-announce-ip 172.38.0.1${port} cluster-announce-port 6379 cluster-announce-bus-port 16379 appendonly yes EOF done
-
启动6个redis容器
for i in $(seq 1 6); \ do \ docker run -p 637${i}:6379 -p 1637${i}:16379 --name redis-${i} -v /mydata/redis/node-${i}/data:/data -v /mydata/redis/node-${i}/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.1${i} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf done
-
进入一个redis,注意这里是sh命令
[root@iZwz9efdd2ukk4oauustczZ conf]# docker exec -it redis-1 /bin/sh -
然后在容器中创建集群
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
-
连接集群,并查看信息
# 连接集群 redis-cli -c # 查看集群信息 cluster info # 查看节点 cluster nodes连接集群,并查看集群信息

查看节点
cluster nodes
-
测试验证高可用
# set a b 127.0.0.1:6379> set a b -> Redirected to slot [15495] located at 172.38.0.13:6379 OK 172.38.0.13:6379> get a "b" # 172.38.0.13是master(主从复制模式),直接删除对应的容器redis-3 [root@iZwz9efdd2ukk4oauustczZ ~]# docker rm -f redis-3 redis-3 [root@iZwz9efdd2ukk4oauustczZ ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3b4a1e1eee93 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6376->6379/tcp, 0.0.0.0:16376->16379/tcp redis-6 918432f23434 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6375->6379/tcp, 0.0.0.0:16375->16379/tcp redis-5 5d67854fec50 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6374->6379/tcp, 0.0.0.0:16374->16379/tcp redis-4 e74d76ad7a23 redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6372->6379/tcp, 0.0.0.0:16372->16379/tcp redis-2 e404fdbafcbc redis:5.0.9-alpine3.11 "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6371->6379/tcp, 0.0.0.0:16371->16379/tcp redis-1 [root@iZwz9efdd2ukk4oauustczZ ~]# # 再去get a /data # redis-cli -c 127.0.0.1:6379> get a -> Redirected to slot [15495] located at 172.38.0.14:6379 "b" # 发现依然可以查到,我们在查一下节点,发现172.38.0.14已经变成master了 # 这里就实现高可用
10、idea整合docker
-
idea新建一个springboot项目,并提供一个接口
/helloimport org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @RequestMapping("/hello") public String hello() { return "hello docker springboot web"; } }
确保本地运行可以正常访问

-
打包

-
新建一个Dockerfile,并编辑如下
FROM java:8 COPY *.jar /app.jar CMD ["--server.port=8080"] EXPOSE 8080 ENTRYPOINT ["java","-jar","/app.jar"]
-
打开阿里云服务器,/home目录下新建一个目录/idea,并将jar包和Dockerfile文件上传到/idea目录下

-
构建镜像
[root@iZwz9efdd2ukk4oauustczZ idea]# docker build -t idea-springboot-web .
-
运行容器
[root@iZwz9efdd2ukk4oauustczZ idea]# docker run -d -P --name idea-springboot-web idea-springboot-web da437e54099d269a1a89d9edf7af202d662f7e2af8790b9d481d9114838fd3fa [root@iZwz9efdd2ukk4oauustczZ idea]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES da437e54099d idea-springboot-web "java -jar /app.jar …" 7 seconds ago Up 6 seconds 0.0.0.0:32783->8080/tcp idea-springboot-web -
验证
[root@iZwz9efdd2ukk4oauustczZ idea]# curl localhost:32783/hello hello docker springboot web正常输出!
11、docker compose
Compose 是用于定义和运行多容器 Docker 应用程序的工具。
通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
Compose 使用的三个步骤:
- 使用 Dockerfile 定义应用程序的环境
- 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行
- 最后,执行 docker-compose up 命令来启动并运行整个应用程序
compose安装
后续补充。。。
compose使用
后续补充。。。
12、docker swarm
官方文档位置:https://docs.docker.com/engine/swarm/
Docker Swarm 是 Docker 的集群管理工具。
swarm 集群由管理节点(manager)和工作节点(work node)构成。
- swarm mananger:负责整个集群的管理工作包括集群配置、服务管理等所有跟集群有关的工作。
- work node:主要负责运行相应的服务来执行任务(task)。

这里只做了解,简单写了一下笔记!我这里没有买四台服务器
准备:先买四台阿里云服务器(可以按量付费)
[root@iZwz9efdd2ukk4oauustczZ ~]# docker swarm --help
Usage: docker swarm COMMAND
Manage Swarm
Commands:
init Initialize a swarm
join Join a swarm as a node and/or manager
Run 'docker swarm COMMAND --help' for more information on a command.
[root@iZwz9efdd2ukk4oauustczZ ~]#
初始化节点
[root@iZwz9efdd2ukk4oauustczZ ~]# docker swarm init --help
Usage: docker swarm init [OPTIONS]
Initialize a swarm
Options:
--advertise-addr string Advertised address (format: "<ip|interface>[:port]")
--autolock Enable manager autolocking (requiring an unlock key to start a stopped manager)
--availability string Availability of the node ("active", "pause", "drain") (default "active")
--cert-expiry duration Validity period for node certificates (ns|us|ms|s|m|h) (default 2160h0m0s)
--data-path-addr string Address or interface to use for data path traffic (format: "<ip|interface>")
--data-path-port uint32 Port number to use for data path traffic (1024 - 49151). If no value is set or is set to 0, the default port (4789) is used.
--default-addr-pool ipNetSlice default address pool in CIDR format (default [])
--default-addr-pool-mask-length uint32 default address pool subnet mask length (default 24)
--dispatcher-heartbeat duration Dispatcher heartbeat period (ns|us|ms|s|m|h) (default 5s)
--external-ca external-ca Specifications of one or more certificate signing endpoints
--force-new-cluster Force create a new cluster from current state
--listen-addr node-addr Listen address (format: "<ip|interface>[:port]") (default 0.0.0.0:2377)
--max-snapshots uint Number of additional Raft snapshots to retain
--snapshot-interval uint Number of log entries between Raft snapshots (default 10000)
--task-history-limit int Task history retention limit (default 5)
docker swarm init --advertise-addr 192.168.99.121
Swarm initialized: current node (bvz81updecsj6wjz393c09vti) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-3pu6hszjas19xyp7ghgosyx9k8atbfcr8p2is99znpy26u2lkl-1awxwuwd3z9j1z3puu7rcgdbx \
172.17.0.2:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
添加节点
# docker swarm join --token SWMTKN-1-3pu6hszjas19xyp7ghgosyx9k8atbfcr8p2is99znpy26u2lkl-1awxwuwd3z9j1z3puu7rcgdbx 192.168.99.121:2377
This node joined a swarm as a worker.
# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
7ln70fl22uw2dvjn2ft53m3q5 worker2 Ready Active
dkp8vy1dq1kxleu9g4u78tlag worker1 Ready Active Reachable
dvfxp4zseq4s0rih1selh0d20 * manager1 Ready Active Leader
# docker swarm join-token worker # 生成添加worker节点的完整的命令
To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-3pu6hszjas19xyp7ghgosyx9k8atbfcr8p2is99znpy26u2lkl-1awxwuwd3z9j1z3puu7rcgdbx \
172.17.0.2:2377
# docker swarm join-token manager # 生成添加manager节点的完整的命令
To add a manager to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-3pu6hszjas19xyp7ghgosyx9k8atbfcr8p2is99znpy26u2lkl-7p73s1dx5in4tatdymyhg9hu2 \
172.17.0.2:2377
13、docker stack
后续补充。。。
14、docker secret
后续补充。。。
15、docker config
后续补充。。。
