kim.zhang

风在前,无惧!


  • 首页

  • 标签42

  • 分类12

  • 归档94

  • 搜索

发表于 2021-11-21 更新于 2021-12-31
本文字数: 67k 阅读时长 ≈ 1:01
  • 1. Docker简介
    • 1.1 基本概念
    • 1.2 安装Docker
    • 1.3 阿里云镜像加速器
    • 1.4 docerk run 流程
    • 1.5 底层原理
  • 2.镜像的基本命令
    • 2.1 查看版本
    • 2.2 查看镜像
    • 2.2 搜索镜像
    • 2.3 下载镜像
    • 2.4 删除镜像
    • 2.5 导出镜像
    • 2.6 导入镜像
  • 3.容器的基本命令
    • 3.1 创建容器并启动
    • 3.2 查看容器
    • 3.3 退出容器
    • 3.4 删除容器
    • 3.5 启动和停止容器
    • 3.6 查看容器日志
    • 3.7 导出容器
    • 3.8 导入容器
  • 4.常用其他命令
    • 4.1 后台启动容器
    • 4.2 查看日志
    • 4.3 查看容器中进程的信息
    • 4.4 查看镜像的元数据
    • 4.5 进入当前正在运行的容器
    • 4.6 从容器内拷贝文件到主机上
  • 5.命令小结
  • 6. 小实战
    • 6.1 部署nginx
    • 6.2 部署tomcat
  • 7.提交镜像
  • 8.容器数据卷
    • 8.1 部署mysql
    • 8.2 具名挂载和匿名挂载
    • 8.3 权限
    • 8.4 多个容器挂载同一个目录
    • 8.5 Macos数据卷挂载目录
  • 9.Dockfile
    • 9.1 制作Dockefile
    • 9.2 Dockfile指令
      • 9.2.1 FROM
      • 9.2.2 RUN
      • 9.2.3 EXPOSE
      • 9.2.4 WORKDIR
      • 9.2.5 COPY
      • 9.2.6 ADD
      • 9.2.7 VOLUME
      • 9.2.8 EMV
      • 9.2.9 CMD
      • 9.2.10 ENTRYPOINT
      • 9.2.11 CMD|ENTRYPOINT区别
      • 9.2.12 HEALTHCHECK
      • 9.2.13 USER
    • 9.3 查看构建过程
    • 9.4 制作tomcat的Dockfile
    • 9.5 不同操作系统的镜像
      • 9.5.1 查看manifest列表
  • 10.发布自己的镜像
  • 11. Docker网络
    • 11.1 问题1:宿主机和容器能不能ping通? ✔
    • 11.2 问题2:两个容器直接能否直接ping通? ✔
    • 11.3 能否通过容器的name来连接? ×(–link ✔)
    • 11.4 自定义网络
    • 11.5 网络互联
    • 11.6 查看容器IP
      • 11.6.1 在容器内查看
      • 11.6.2 在容器外查看
      • 11.6.3 获取所有容器名称和IP
    • 11.7 Macos的网络问题
    • 11.8 查看端口映射配置
  • 12.Docker工具安装
    • 12.1 vim
    • 12.2 ping
    • 12.3 ifconfig
    • 12.4 yum
  • 13.常用容器
    • 13.1 Mysql
    • 13.2 tomcat

1. Docker简介

Docker是一种虚拟化技术,类比于虚拟机。虚拟机的使用需要安装操作系统并在操作系统上安装软件才能使用。虚拟机上的软件需要消耗系统的资源的时候,由虚拟机的操作系统向宿主机的操作系统申请.而Docker是共用宿主机的内核,而且各个容器之间是操作系统级别隔离的,每个容器都只安装了最小的运行环境.Dockre是比虚拟机更加轻量的虚拟技术。

Docker优势:
1.将应用程序和运行环境一起打包,保持一致的运行环境,轻松迁移
2.对进程进行封装隔离,容器与容器之间互不影响

1.1 基本概念

镜像image

Docker镜像就好比是一个软件安装包,通过这个镜像可以创建容器,一个镜像可以创建多个容器.

比如,一个tomcat镜像 -> docker run -> tomcat容器(提供服务)。
一个镜像可以创建多个tomcat容器,相当于通过一个软件包安装了多个tomcat,每个容器之间互不影响.

容器Container

Docker利用容器技术,独立运行一个或一组应用。

容器是通过镜像来创建的。

仓库Repository

仓库就是存放镜像的地方。分为公有仓库和私有仓库。

DockerHub(国外),阿里云(国内,配置镜像加速)

1.2 安装Docker

  1. 查看环境

查看Linux版本,系统内核要求3.10以上:

1
uname -a
1
Linux ming 3.10.0-514.26.2.el7.x86_64 #1 SMP Tue Jul 4 15:04:05 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

查看系统信息:

1
cat /etc/os-release
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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. 安装Docker

如果已经安装过docker,卸载已经安装的版本

1
2
3
4
5
6
7
8
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

设置Docker的仓库

1
2
3
4
# 1. 下载yum-utils(其中包含了yum-config-manager)
sudo yum install -y yum-utils
# 2. 设置阿里的docker仓库地址
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

安装Docker

1
2
3
4
# 清除缓存
yum makecache fast
# 下载docker
sudo yum install docker-ce docker-ce-cli containerd.io

查看Docker版本信息

1
docker version

出现以下结果,说明Docker安装成功。

1
2
3
4
5
6
7
8
9
Client: Docker Engine - Community
Version: 20.10.1
API version: 1.41
Go version: go1.13.15
Git commit: 831ebea
Built: Tue Dec 15 04:37:17 2020
OS/Arch: linux/amd64
Context: default
Experimental: true

启动docker

1
sudo systemctl start docker

运行hello-world示例镜像

1
sudo docker run hello-world

image-docker hello-world

1.3 阿里云镜像加速器

登录阿里云,找到容器镜像服务,镜像加速器。

image-阿里云镜像加速器

1.4 docerk run 流程

image-docker run运行流程

1.5 底层原理

Docker是怎么工作的?

Docker是一个Client-Server结构的系统,Docker的守护进程运行在服务器上,客户端通过Socket访问,

Docker Server接收到Docker Client的指令,就会执行这个命令。

image-Docker工作原理

2.镜像的基本命令

官方参考文档

2.1 查看版本

1
2
3
4
5
6
7
8
# 显示docker版本
docker -v
# 显示docker客户端和服务器的详细版本
docker version
# 显示docker的系统信息,包括镜像和容器的数量
docker info
# 帮助命令
docker 命令 --help

2.2 查看镜像

1
2
3
4
# 1. 查看所有镜像
docker images -a
# 2. 查看镜像的id
docker images -q

2.2 搜索镜像

搜索镜像可以使用DockerHub搜索,也可以使用命令进行搜索。

1
2
3
4
# 1. 搜索mysql的镜像
docker search mysql
# 2. 搜索stars大于9000的本版
docker search mysql --filter=stars=9000

2.3 下载镜像

1
2
3
4
# 1. 不指定版本,默认下载最新版本latest
docker pull mysql
# 2. 下载指定版本,这里的版本号一定要是DockerHub上有的版本
docker pull mysql:5.7

既然知道了真实地址,docker pull mysql:5.7 相当于 docker pull docker.io/library/mysql:5.7

image-docker pull mysql:5.7

2.4 删除镜像

如果有容器使用了镜像,即使容器没有启动,删除镜像之前也需要将对应的容器删除.当然可以使用-f强制删除.

1
2
3
4
5
6
# 1.通过镜像名称删除,-f 强制删除
docker rmi -f mysql
# 2. 通过id删除
docker rmi -f f07dfa83b528
# 3. 删除所有的镜像
docker rmi -f $(docker images -aq)

image-删除镜像

2.5 导出镜像

-o 指定输出文件

1
2
[root@aliyun ~]# docker import tomcat.tar mytomcat:01
sha256:528cde1da5e8e928b7c5415541371a6b6cdbc0c0a1aa05bba642e43ec9da4862

2.6 导入镜像

1
2
[root@aliyun ~]# docker import tomcat.tar mytomcat:01
sha256:528cde1da5e8e928b7c5415541371a6b6cdbc0c0a1aa05bba642e43ec9da4862

3.容器的基本命令

3.1 创建容器并启动

有些容器在使用Dockerfile构建镜像的时候,Dockerfile中可能就已经存在了CMD指令.
比如以-it交互模式启动centos容器时,默认执行的CMD指令是 /bin/bash.
当然,可以在启动容器的时候覆盖默认的CMD指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 查看centos:7镜像创建的过程,能发现默认的CMD指令是/bin/bash
[root@aliyun ~]# docker history centos:7
IMAGE CREATED CREATED BY SIZE COMMENT
eeb6ee3f44bd 3 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 3 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 3 months ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB

# 在启动容器时覆盖默认的CMD指令,会执行cat /etc/os-release 查看版本信息
[root@aliyun ~]# docker run -it centos:7 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"

# 参数解释
--name="" # 指定容器名字
-d # 后台方式运行
-it # 使用交互方式运行,进入容器查看内容
-p # 指定容器的端口,有以下几种形式
- 主机端口:容器端口(常用)
- ip:主机端口:容器端口
- 容器端口
-P # 随机指定端口

进入容器后,主机名称变成了容器id.
如果在启动容器的时候没有通过–name指定容器的名称,Docker会自动生成一个随机的容器名称.

1
2
3
4
5
6
# 进入容器后,主机名称变成了容器id
[root@8434890d1132 /]#

[root@ming local]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
41a27a712b32 centos "/bin/bash" 14 seconds ago Up 13 seconds funny_wright

3.2 查看容器

1
2
3
4
5
6
7
8
# 1. 查看正在运行的容器
docker ps
# 2. 查看正在运行的容器和历史运行的容器
docker ps -a

# 参数解释
-n=1 # 显示最近创建的容器
-q # 只显示容器id

3.3 退出容器

1
2
3
4
# 1. 退出容器并关闭
[root@8434890d1132 /]# exit
# 2. 退出容器,不关闭
CTRL + P + Q

3.4 删除容器

删除容器使用rm,删除镜像使用rmi。(i = image)

1
2
3
4
5
6
# 1. 指定容器id删除
docker rm -f 41a27a712b32
# 2. 删除所有容器,指定参数-f强制删除,如果容器正在运行,也能删除
docker rm -f $(docker ps -aq)
# 3. 删除所有容器,如果容器正在运行,会报错
docker ps -aq|xargs docker rm

3.5 启动和停止容器

1
2
3
4
5
6
7
8
# 1. 启动容器
docker start 容器id
# 2. 重启容器
docker restart 容器id
# 3. 停止容器
docker stop 容器id
# 4. 容器在运行,可以使用kill强制停止容器
docker kill 容器id

3.6 查看容器日志

1
2
3
4
5
docker logs 容器id

# -f 查看实时日志
# -t 显示宿主机的时间
# -n(--tail) 显示末尾的n行日志

3.7 导出容器

1
2
3
4
5
6
7
8
9
root@aliyun ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
47a5903b4f65 tomcat "catalina.sh run" 27 seconds ago Up 26 seconds 8080/tcp tomcat
# 将tomcat容器导出tomcat.tar包
[root@aliyun ~]# docker export 47a > tomcat.tar
[root@aliyun ~]# ls -l
total 667328
drwxr-xr-x 3 root root 4096 Dec 25 15:17 dockfile
-rw-r--r-- 1 root root 683334144 Dec 25 19:02 tomcat.tar

3.8 导入容器

1
2
3
4
5
6
7
# 第一种写法
[root@aliyun ~]# cat tomcat.tar | docker import - mytomcat:01
sha256:05c233b97f2fee4fb74846f74dcb72a98e5cb2ec454db1e3dcbd3aacb318ebff

# 第二种写法
[root@aliyun ~]# docker import tomcat.tar mytomcat:01
sha256:528cde1da5e8e928b7c5415541371a6b6cdbc0c0a1aa05bba642e43ec9da4862

用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库.
这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大.
此外,从容器快照文件导入时可以重新指定标签等元数据信息

4.常用其他命令

4.1 后台启动容器

1
docker run -d 镜像名称
1
2
# 问题:后台方式启动容器后,docker ps查看容器,发现刚启动的容器停止了?
docker容器使用后台运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止.

4.2 查看日志

1
2
3
4
5
6
7
# 查看容器7194f420dccf最近10行的日志信息
docker logs -tf --tail 10 7194f420dccf

# 参数解释
-f # 显示最新的日志
-t # 显示时间戳
-tail n # 显示最后n行

为了方便查看日志,启动容器的时候让它运行脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 后台方式启动,每隔1s输出hello,world,方便查看日志信息
docker run -d centos /bin/sh -c "while true;do echo hello,world;sleep 1;done"

[root@ming local]# docker logs -tf --tail 10 7194f420dccf
2021-01-02T04:59:49.064172640Z hello,world
2021-01-02T04:59:50.065917036Z hello,world
2021-01-02T04:59:51.067497230Z hello,world
2021-01-02T04:59:52.069279085Z hello,world
2021-01-02T04:59:53.070906928Z hello,world
2021-01-02T04:59:54.072698176Z hello,world
2021-01-02T04:59:55.074312881Z hello,world
2021-01-02T04:59:56.075940314Z hello,world
2021-01-02T04:59:57.077579824Z hello,world
2021-01-02T04:59:58.083724580Z hello,world
2021-01-02T04:59:59.085284061Z hello,world
2021-01-02T05:00:00.086883423Z hello,world
2021-01-02T05:00:01.088530900Z hello,world

4.3 查看容器中进程的信息

1
2
# 1. 查看容器中进程信息
docker top 7194f420dccf

4.4 查看镜像的元数据

1
docker inspect 容器id
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
[
{
# 容器的完整id,默认只是截取前面几位
"Id": "7194f420dccf83fc219103ba4b8fe704583cbe52a8e0ad53bc5ee7c788ece631",
"Created": "2021-01-02T04:54:22.996950933Z", # 容器创建时间
"Path": "/bin/sh",
"Args": [ # 启动容器时使用的参数
"-c",
"while true;do echo hello,world;sleep 1;done"
],
"State": { # 容器状态
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 19341,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-01-02T04:54:23.420056968Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:300e315adb2f96afe5f0b2780b87f28ae95231fe3bdd1e16b9ba606307728f55", # 镜像信息
"ResolvConfPath": "/var/lib/docker/containers/7194f420dccf83fc219103ba4b8fe704583cbe52a8e0ad53bc5ee7c788ece631/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/7194f420dccf83fc219103ba4b8fe704583cbe52a8e0ad53bc5ee7c788ece631/hostname",
"HostsPath": "/var/lib/docker/containers/7194f420dccf83fc219103ba4b8fe704583cbe52a8e0ad53bc5ee7c788ece631/hosts",
"LogPath": "/var/lib/docker/containers/7194f420dccf83fc219103ba4b8fe704583cbe52a8e0ad53bc5ee7c788ece631/7194f420dccf83fc219103ba4b8fe704583cbe52a8e0ad53bc5ee7c788ece631-json.log",
"Name": "/quizzical_brown",
"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,
"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",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"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/d76624dcc42355cece3b8a39ba99dcf0b1714c80f5c28fc7ff80cf778a635932-init/diff:/var/lib/docker/overlay2/d5c1df794c28e4c26a5118b7df6f110d8cd67fd4b2184e3f0509513bde2686ac/diff",
"MergedDir": "/var/lib/docker/overlay2/d76624dcc42355cece3b8a39ba99dcf0b1714c80f5c28fc7ff80cf778a635932/merged",
"UpperDir": "/var/lib/docker/overlay2/d76624dcc42355cece3b8a39ba99dcf0b1714c80f5c28fc7ff80cf778a635932/diff",
"WorkDir": "/var/lib/docker/overlay2/d76624dcc42355cece3b8a39ba99dcf0b1714c80f5c28fc7ff80cf778a635932/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "7194f420dccf",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"while true;do echo hello,world;sleep 1;done"
],
"Image": "centos",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20201204",
"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": "ea030739e7cabd90101a0040969de447c6ba176267e502f5a5558b19f2a4d813",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/ea030739e7ca",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "2cef83333f52c17f883782c62909d4878761bb98238aa45939039609e2d1ccfc",
"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": "1cd4dcbb6871cbcce8292729579d2a62dee582c9b7cd3810298c1d69bc1de4cb",
"EndpointID": "2cef83333f52c17f883782c62909d4878761bb98238aa45939039609e2d1ccfc",
"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
}
}
}
}
]

4.5 进入当前正在运行的容器

1
2
3
4
# 1. 进入当前正在运行的容器进行操作,不会启动新的进程
docker attach 4db8b5f683c1
# 2. 进入当前正在运行的容器进行操作,会重新启动一个进程
docker exec -it 4db8b5f683c1 /bin/bash

虽然是不同的进程进行操作,但容器内的资源还是共享的。

首先使用docker exec -it 4db8b5f683c1 /bin/bash进入容器:

image-docker attach

然后使用docker attach 4db8b5f683c1进入容器:并没有启动一个新的/bin/bash进程。

image-docker exec

4.6 从容器内拷贝文件到主机上

1
2
# 即使容器当前不在运行,也可以拷贝出文件
docker cp 容器id:容器内路径 当前主机路径
1
2
3
[root@ming local]# docker cp 4db8b5f683c1:/aaa.txt /home/  # 将容器内/aaa.txt 拷贝到当前主机 /home/ 目录下
[root@ming local]# ls /home
aaa.txt

5.命令小结

docker命令图谱

6. 小实战

6.1 部署nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 1. 下载nginx
docker pull nginx

# 2. 查看镜像
[root@ming ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest ae2feff98a0c 2 weeks ago 133MB
centos latest 300e315adb2f 3 weeks ago 209MB

# 3. 启动容器,将主机的3344端口映射到容器内的80端口
[root@ming ~]# docker run -p 3344:80 -it nginx /bin/bash
root@6b29c7751037:/#

# 4.查看nginx安装目录,版本信息
root@6b29c7751037:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@6b29c7751037:/# cd /usr/sbin
root@6b29c7751037:/usr/sbin# ./nginx -version
nginx version: nginx/1.19.6

# 5.启动nginx
root@6b29c7751037:/usr/sbin# ./nginx

外网访问http://47.96.224.198:3344/,容器内启动nginx成功。

image-docker部署nginx

6.2 部署tomcat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. 查看镜像
[root@ming ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat latest feba8d001e3f 2 weeks ago 649MB
nginx latest ae2feff98a0c 2 weeks ago 133MB
centos latest 300e315adb2f 3 weeks ago 209MB

# 2. 启动容器,将主机的3355端口映射到容器内的80端口
[root@ming ~]# docker run -p 3355:8080 -it tomcat /bin/bash

# 3. 启动tomcat
root@5e2e3cb50a29:/usr/local/tomcat/bin# ./startup.sh

# 4. 查看进程,tomcat已经启动
root@5e2e3cb50a29:/usr/local/tomcat/bin# ps -ef|grep tomcat
root 15 1 1 07:45 pts/0 00:00:02 /usr/local/openjdk-11/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start
root 45 1 0 07:47 pts/0 00:00:00 grep tomcat

外网访问http://47.96.224.198:3355/,出现以下界面:

image-访问tomcat

这是因为阿里云镜像默认是下载最小的镜像,只下载了必要的组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
root@5e2e3cb50a29:/usr/local/tomcat# ls  
BUILDING.txt LICENSE README.md RUNNING.txt conf logs temp webapps.dist
CONTRIBUTING.md NOTICE RELEASE-NOTES bin lib native-jni-lib webapps work
root@5e2e3cb50a29:/usr/local/tomcat# ls webapps # webapps目录是空的
root@5e2e3cb50a29:/usr/local/tomcat# ls webapps.dist/ # webapps.dist目录才是原本的webapps目录
ROOT docs examples host-manager manager
root@5e2e3cb50a29:/usr/local/tomcat# mv webapps webapps.backup
root@5e2e3cb50a29:/usr/local/tomcat# mv webapps.dist webapps # 将webapps.dist目录改成webapps目录
root@5e2e3cb50a29:/usr/local/tomcat# ls
BUILDING.txt LICENSE README.md RUNNING.txt conf logs temp webapps.backup
CONTRIBUTING.md NOTICE RELEASE-NOTES bin lib native-jni-lib webapps work
root@5e2e3cb50a29:/usr/local/tomcat# ls webapps
ROOT docs examples host-manager manager

再次访问[http://47.96.224.198:3355/,这次就可以正常访问了。

image-访问docker中的tomcat

7.提交镜像

从仓库下载下来的镜像都是只读的,每当我们操作镜像,就会在原来镜像的上面加一层我们自己的操作,我们可以将它保存起来,下次直接使用我们操作过的镜像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. 查看镜像
[root@ming /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
89b24a4b7084 tomcat "/bin/bash" 4 hours ago Up 4 hours 0.0.0.0:3366->8080/tcp infallible_lewin

# 2. 将我们操作过的镜像commit成mytomcat
[root@ming /]# docker commit -m 'tomcat add webapps' -a 'xiaoming' 89b24a4b7084 mytomcat
sha256:42d7b6dea11ce283033c6015765bff176ffbdad71105c02048e4e7352a5239f4

# 3. 查看镜像
[root@ming /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat latest 42d7b6dea11c 10 seconds ago 654MB # 我们自己生成的镜像
tomcat latest feba8d001e3f 2 weeks ago 649MB
nginx latest ae2feff98a0c 2 weeks ago 133MB
centos latest 300e315adb2f 3 weeks ago 209MB
1
2
3
4
5
6
# 将镜像89b24a4b7084提交,生成我们自己的镜像mytomcat
docker commit -m 'tomcat add webapps' -a 'xiaoming' 89b24a4b7084 mytomcat

# 参数解释
-m # 提交的信息,类似于git commit
-a # 作者

8.容器数据卷

我们在容器内操作,数据保存在容器内,这是一件很危险的事情,假如不小心删除了容器,容器内的数据就全部丢失了。

有没有一种技术可以将容器内的数据同步到宿主机器上,将容器内的目录和宿主机的目录进行绑定,无论修改容器内的目录,还是修改宿主机的目录,都能自动同步数据,完成数据的持久化呢? 这就是数据卷的技术。

使用以下命令完成数据卷的挂载:

1
docker run -v 宿主机的目录:容器内的目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 1. 进入容器,进行目录挂载
docker run -p 3355:8080 -v /home/test/:/home -it mytomcat /bin/bash

# 2. 查看镜像状态,查看挂载信息
docker inspect 7feb5a932a8b
"Mounts": [
{
"Type": "bind",
"Source": "/home/test",
"Destination": "/home",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],

# 3. 进入到容器内,/home目录下创建文件test.java
root@7feb5a932a8b:/home# ls
test.java

# 4. 查看宿主机器/home/test目录下是否同步了test.java文件
[root@ming test]# pwd
/home/test
[root@ming test]# ls
test.java

# 5.在宿主机上修改test.java文件,修改其内容
[root@ming test]# vim test.java
[root@ming test]# cat test.java
hello,world

# 6.查看容器中/home目录下的test.java文件
root@7feb5a932a8b:/home# cat test.java
hello,world

# 结论:使用数据卷技术,可以将容器内的目录和宿主机器上的目录进行同步,从而达到数据持久化的目的。

8.1 部署mysql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 1. 直接使用docker run 下载mysql,如果本地不存在mysql的镜像,会从远程仓库中拉取
docker run -p 3307:3306 -v /home/mysql/data:/var/lib/mysql -v /home/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql5.7 mysql:5.7

# 参数解释
-e # 设置环境
MYSQL_ROOT_PASSWORD # mysql root用户的密码
--name # 容器的名称

# 2.使用navicat连接数据库,并创建数据库test
host:47.96.224.198:3307
username:root
password:123456

# 3. 查看宿主机上/home/mysql/data目录下有没有test数据库
[root@ming data]# pwd
/home/mysql/data
[root@ming data]# ll |grep test
drwxr-x--- 2 systemd-bus-proxy input 4096 Jan 2 20:14 test # test数据库,说明容器内的目录和宿主机的目录已经同步

# 4. 删除容器
docker rm -f a312a3e56f40

# 5.数据持久化了,即使删除容器,数据也不会丢失
[root@ming data]# ll | grep test
drwxr-x--- 2 systemd-bus-proxy input 4096 Jan 2 20:14 test

8.2 具名挂载和匿名挂载

之前使用的docker run -v 宿主机的目录:容器内的目录是指定目录的挂载方式。

除此之外,还有具名挂载和匿名挂载。

具名挂载

具名挂载通过docker run -v 卷名:容器内的目录进行挂载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 1. 具名挂载的方式启动nginx
docker run -d -p 3344:80 -v juming_nginx:/etc/nginx nginx

# 2. 查看数据卷
[root@ming /]# docker volume ls
DRIVER VOLUME NAME
local juming_nginx

# 3. 查看juming_nginx的详细信息
[root@ming /]# docker volume inspect juming_nginx
[
{
"CreatedAt": "2021-01-02T20:37:12+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming_nginx/_data", # 挂载的路径
"Name": "juming_nginx",
"Options": null,
"Scope": "local"
}
]

# 4. 到挂载的路径下查看,nginx的配置文件目录已经挂载到了/var/lib/docker/volumes/juming_nginx/_data目录下
[root@ming _data]# pwd
/var/lib/docker/volumes/juming_nginx/_data
[root@ming _data]# ls
conf.d koi-utf mime.types nginx.conf uwsgi_params
fastcgi_params koi-win modules scgi_params win-utf

匿名挂载

匿名挂载通过docker run -v 容器内路径进行挂载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 1. 匿名挂载的方式启动nginx
docker run -d -p 3344:80 -v /etc/nginx.conf nginx

# 2. 查看数据卷,是一串字符串
[root@ming _data]# docker volume ls
DRIVER VOLUME NAME
local ffb564010a743ee8d607d1fd35bdf54fbef705881cf9c2625c431e83f626c532

# 3. 查看挂载的详细信息
[root@ming _data]# docker volume inspect ffb564010a743ee8d607d1fd35bdf54fbef705881cf9c2625c431e83f626c532
[
{
"CreatedAt": "2021-01-02T20:42:50+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/ffb564010a743ee8d607d1fd35bdf54fbef705881cf9c2625c431e83f626c532/_data", # 挂载的目录
"Name": "ffb564010a743ee8d607d1fd35bdf54fbef705881cf9c2625c431e83f626c532",
"Options": null,
"Scope": "local"
}
]

# 4.到挂载的目录查看,发现目录是空的
[root@ming _data]# pwd
/var/lib/docker/volumes/2909b1711dfe40c72036dc8d950d2da653a6b88563acbb0b1e49932469e1247d/_data
[root@ming _data]# ls

我们发现,如果不是以指定目录的方式进行挂载,挂载的目录默认是在/var/lib/docker/volumes/卷名/_data/目录下。

8.3 权限

相对于容器内而言,默认情况下,文件是可读可写的。

1
2
3
4
5
# 1. 启动nginx容器并进入容器
docker run -p 3344:80 -v juming_nginx:/etc/nginx.conf -it nginx /bin/bash

# 2. 到/etc/目录下,查看nginx.conf的权限
drwxr-xr-x 3 root root 4096 Jan 2 12:37 nginx.conf # 可读可写的权限

我们可以在启动容器的时候,指定容器内的文件权限:

1
2
3
4
5
# 1. ro = read only ,在容器内只读,不能修改
docker run -p 3344:80 -v juming_nginx:/etc/nginx.conf:ro -it nginx /bin/bash

# 2. rw = read write,在容器内可读,可写
docker run -p 3344:80 -v juming_nginx:/etc/nginx.conf:ro -it nginx /bin/bash

8.4 多个容器挂载同一个目录

使用–volume-for指定一个容器,同步这个容器的数据。就相当于,继承一个容器,自动同步它的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 1. 启动容器centos1,挂载容器内的目录/home/centos1
docker run -it --name centos1 -v centos1:/home/centos1/ centos /bin/bash

# 2. 在centos1容器的/home/centos1目录下创建centos1.txt文件
[root@69a8809a9e6f centos1]# pwd
/home/centos1
[root@69a8809a9e6f centos1]# ls
centos1.txt

# 3. 查看宿主机上centos1的挂载目录
[root@ming _data]# pwd
/var/lib/docker/volumes/centos1/_data
[root@ming _data]# ls
centos1.txt

# 4. 启动容器centos2,centos2继承自centos1
docker run -it --name centos2 --volumes-from centos1 centos /bin/bash

# 5. 进入到centos2的/home/centos1目录下
[root@a5afec9346bd centos1]# pwd
/home/centos1
[root@a5afec9346bd centos1]# ls
centos1.txt

# 在centos2的目录下,可以看到centos1的目录

# 6. centos2容器中,在centos1目录中创建centos2.txt
[root@a5afec9346bd centos2]# pwd
/home/centos1
[root@a5afec9346bd centos2]# ls
centos1.txt centos2.txt


# 7. 进入到centos1容器中,查看/home/centos1目录下是否多了centos2.txt
[root@06e27ea51ee0 centos1]# ls # centos1的目录下,存在centos2.txt,说明centos2创建的文件自动同步到centos1
centos1.txt centos2.txt

# 8. 查看centos2的挂载目录
docker inspect centos2
"Mounts": [
{
"Type": "volume",
"Name": "centos1",
"Source": "/var/lib/docker/volumes/centos1/_data",
"Destination": "/home/centos1",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],

# 9. 查看centos1的挂载目录
docker inspect centos1
"Mounts": [
{
"Type": "volume",
"Name": "centos1",
"Source": "/var/lib/docker/volumes/centos1/_data",
"Destination": "/home/centos1",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],

# 结论:centos1和centos2挂载的是同一个目录,连name都是相同的centos1。
# 这意味着,我们查看centos2的详细数据卷信息,也是使用docker volume inspect centos1

接下来,我们创建一个新的容器centos3,让它–volumes-from centos2,它能不能自动同步centos2创建的目录centos2呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 1. 启动centos3容器
docker run -it --name centos3 --volumes-from centos2 centos /bin/bash

# 2. 查看/home目录下是否存在centos2目录
[root@96b772d61de0 home]# ls # 说明centos3不能同步centos2创建的目录
centos1

# 3. 查看centos3挂载的目录信息
docker inspect centos3
"Mounts": [
{
"Type": "volume",
"Name": "centos1",
"Source": "/var/lib/docker/volumes/centos1/_data",
"Destination": "/home/centos1",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],

# centos3虽然继承自centos2,但是centos2是继承自centos1,挂载的只是centos1的目录,所以centos3不能同步centos2创建的目录。

8.5 Macos数据卷挂载目录

Macos系统中,Docker与宿主机之间多了一层Linux,无法直接查看数据卷挂载的目录.
可以重新创建一个Debian的Linux虚拟机,在/var/lib/docker/volumes/目录下可以查看docker挂载的数据卷.

1
2
3
4
5
6
7
8
# 拉取了一个debian的镜像
docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh

# 进入/var/lib/docker/volumes既可以看到docker挂载的数据卷
/var/lib/docker/volumes # ls
backingFsBlockDev
metadata.db
mysqldata

9.Dockfile

我们可以使用Docker官方(或其他人)编写的镜像.也可以使用Dockerfile创建自己的镜像.我们以后要发布项目,就需要编写dockfile文件.

9.1 制作Dockefile

dockerfile就是一个脚本文件,里面的脚本用来创建镜像.
dockerfile文件的命名官方推荐为Dockerfile.
Dockerfile文件所在的目录称为上下文目录,当执行docker commit提交的时候,会将上下文路径的所有路径上传到Docker Server端.
所以,要么Dockerfile文件所在上下文目录存放的全部都是构建镜像所需要的文件,
要么添加Dockerignore文件描述构建镜像时需要忽略的文件.

需要注意的几点:

  • 每个保留关键字(指令)都必须是大写字母
  • 执行从上到下顺序执行
  • 每一个指令都会创建提交一个新的镜像层,并提交
  • 必须使用双引号,单引号不行
  • Dockerfile的第一条指令必须是FROM

写好脚本文件后,使用docker build命令生成镜像.
需要注意的几点:

  • -t 生成的镜像名称不能带/
  • 最后一个参数指定上下文路径,’.’代表当前所在目录
  • 如果文件命名为Dockerfile,在docker build的时候可以不指定-f参数.否则可以通过-f指定Dockerfile文件所在的目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# 1. 利用当前目录下的dockerfile文件在当前目录下生成xiaoming/centos的镜像
[root@ming docker_volume_test]# docker build -f dockerfile1 -t xiaoming/centos .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 300e315adb2f
Step 2/4 : VOLUME ["volume1","volume2"]
---> Running in 7d9097ed198e
Removing intermediate container 7d9097ed198e
---> 8f3d72c8bccc
Step 3/4 : CMD echo '------end------'
---> Running in 27f56b2fe602
Removing intermediate container 27f56b2fe602
---> bdcf8bb3ee27
Step 4/4 : CMD /bin/bash
---> Running in e9c64f298af8
Removing intermediate container e9c64f298af8
---> 7fc575cbe035
Successfully built 7fc575cbe035
Successfully tagged xiaoming/centos:latest


# 参数解释
-f # 指定的dockfile文件
-t # target,生成的目录镜像

# 2. 查看镜像
[root@ming docker_volume_test]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
xiaoming/centos latest 7fc575cbe035 21 seconds ago 209MB # 利用dockerfile生成的镜像文件

# 3. 启动容器
[root@ming docker_volume_test]# docker run -it xiaoming/centos /bin/bash
[root@40476da59260 /]# ls -l
drwxr-xr-x 2 root root 4096 Jan 3 07:14 volume1 # 生成镜像的时候自动挂载的volume1目录
drwxr-xr-x 2 root root 4096 Jan 3 07:14 volume2 # 生成镜像的时候自动挂载的volume2目录

# 4. 在容器内的volume1目录中创建文件volume1.txt
[root@40476da59260 volume1]# pwd
/volume1
[root@40476da59260 volume1]# ls
volume1.txt

# 5. 查看挂载信息
docker inspect 40476da59260 # 容器id
"Mounts": [
{
"Type": "volume",
"Name": "188f9cd826889b4497db0df774a3c493666b808bce0cffbadc90ae20901fda49",
"Source": "/var/lib/docker/volumes/188f9cd826889b4497db0df774a3c493666b808bce0cffbadc90ae20901fda49/_data",
"Destination": "volume1",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "9ecc05996ab6035f6fee907b130473f8ad9eba1244635a98bbf3e5dbde8747a8",
"Source": "/var/lib/docker/volumes/9ecc05996ab6035f6fee907b130473f8ad9eba1244635a98bbf3e5dbde8747a8/_data",
"Destination": "volume2",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],

# 6. 到挂载目录下查看是否同步了容器的文件
[root@ming _data]# pwd
/var/lib/docker/volumes/188f9cd826889b4497db0df774a3c493666b808bce0cffbadc90ae20901fda49/_data
[root@ming _data]# ls
volume1.txt # 容器内创建的文件已经同步,说明挂载成功。

9.2 Dockfile指令

命令 描述
FROM 指定基础镜像,一切从这里开始构建
MAINTAINER 指定维护者信息(姓名+邮箱)
RUN 镜像构建的时候需要运行的命令
ADD 添加内容,会自动解压
WORKDIR 镜像的工作目录
VOLUME 设置卷,挂载主机目录
EXPOSE 暴露端口配置
CMD 指定容器启动的时候运行的命令,只有最后一个会生效
ENTRYPOINT 指定这个容器启动的时候运行的命令,可以追加命令
ONBUILD 当构建一个被继承Dockfile就会触发指令
COPY 类似ADD,将文件拷贝到镜像中
ENV 构建的时候设置环境变量
9.2.1 FROM

FROM 指令表明构建的镜像是基于FROM指定的这个镜像构建的.
Dockerfile的第一条指令就必须是FROM指令.
以后我们将自己的项目构建成一个容器的时候,比如需要JDK的开发环境,就应该基于一个包含JDK环境的镜像去构建.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 当前目录下存在Dockerfile文件和hello.txt文件
[root@aliyun dockfile]# ls
Dockerfile hello.txt

# 构建镜像,-t指定构建后镜像的名称, . 代表基于当前的路径构建镜像,即指定上下文目录
[root@aliyun dockfile]# docker build -t mycentos:01 .
Sending build context to Docker daemon 3.072kB
Step 1/1 : FROM centos:7 # 每一条指令都会生成一个镜像层,镜像层可以复用
---> eeb6ee3f44bd
Successfully built eeb6ee3f44bd
Successfully tagged mycentos:01

# 查看刚刚构建的镜像
[root@aliyun dockfile]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat latest 24207ccc9cce 9 days ago 680MB
centos 7 eeb6ee3f44bd 3 months ago 204MB
mycentos 01 eeb6ee3f44bd 3 months ago 204MB

# 启动镜像,发现自动退出了,是因为镜像中没有服务在运行,容器就自动退出了
# 可以使用-it以交互的形式启动
[root@aliyun dockfile]# docker run --name mycentos mycentos:01
[root@aliyun dockfile]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
114aad00ed59 mycentos:01 "/bin/bash" 3 seconds ago Exited (0) 2 seconds ago mycentos

# 以交互形式启动容器并进入容器
[root@aliyun dockfile]# docker run -it --name mycentos mycentos:01 bash
9.2.2 RUN

RUN可以在创建镜像时执行命令.

1
2
3
4
FROM centos:7

# 在容器中安装vim
RUN yum install -y vim

每一个RUN都是启动一个容器、执行命令、然后提交存储层文件变更.
第一层RUN cd /app的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更.
而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化.

1
2
RUN cd /app
RUN echo "hello" > world.txt
9.2.3 EXPOSE

EXPOSE声明容器对外暴露的端口,并不会在自动在宿主机上进行端口映射.
即使不声明也是可以在运行容器的时候进行端口映射的,但是遵守规范,还是在Dockerfile文件中声明一下.
如果在启动容器时使用随机端口映射(-P),会自动映射EXPOSE端口.
EXPOSE 指令可以声明多次.

1
2
EXPOSE 8080
EXPOST 8081
9.2.4 WORKDIR

WORKDIR 指定进入容器时的默认工作路径.
如果WORKDIR指定的目录不存在,会自动创建.

1
2
3
4
5
6
WORKDIR /usr/local

# 进入容器后,默认的工作路径就是/usr/local
[root@aliyun dockfile]# docker run -it mytomcat:02 bash
root@33353414815f:/usr/local# pwd
/usr/local

WORKDIR 可以声明多次.
如果每个WORKDIR指令声明的都是绝对路径,以最后一个绝对路径为准.
如果最后一个WORKDIR指令声明的是相对路径,会将多个WORKDIR的路径连接在一起.

1
2
3
4
5
6
7
8
9
# Dockerfile文件中声明多条WORKDIR指令,后面两条WORKDIR指令是相对路径
WORKDIR /usr/local
WORKDIR tomcat
WORKDIR webapps

# 最终容器内的工作目录是/usr/local/tomcat/webapps
[root@aliyun dockfile]# docker run -it mytomcat:02 bash
root@0a4ce65817ab:/usr/local/tomcat/webapps# pwd
/usr/local/tomcat/webapps
9.2.5 COPY

COPY 拷贝文件到容器内.
源路径(宿主机上的路径)只能写相对路径(一般都是在上下文目录中),不能写绝对路径.

1
2
# 绝对路径
COPY hello.index /usr/local/tomcat/webapps

源路径可以指定多个.
如果源路径为文件夹,复制的时候不是直接复制该文件夹,而是将文件夹中的内容复制到目标路径.
如果源路径为文件夹,目标路径以/结尾.
目标路径可以是相对路径,相对于WORKDIR的相对路径.
复制源路径的时候,源文件的用户|权限等信息都会保留,可以在CPOY指定–chown修改文件的所属用户和所属组.

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM tomcat

WORKDIR /usr/local
WORKDIR tomcat
# 复制宿主机的hello.txt和app目录到容器内的/usr/local/tomcat/webapps目录中
# 这里使用的是相对于WORKDIR的相对路径
COPY hello.txt app webapps/

# 源文件的用户和用户组都被复制过来了
root@8d48ef0e9be1:/usr/local/tomcat/webapps# ls -l
total 8
-rw-r--r-- 1 root root 15 Dec 23 16:01 hello.index
-rw-r--r-- 1 root root 42 Dec 18 16:35 hello.txt
9.2.6 ADD

ADD与COPY命令相似,它可以指定一个url,从url中下载文件到指定目录中.
下载的文件权限默认是600.可以使用RUN命令进行权限的调整.所以,还不如使用RUN + WGET(CURL)下载文件并处理好权限后再上传到容器中.
从远程的url中下载文件到容器中,并不会自动解压.
从上下文目录中上传文件到容器中,会自动进行解压.

1
2
3
4
5
6
7
8
# 下载yum的安装包到容器内的/usr/local/tomcat中
ADD http://yum.baseurl.org/download/3.2/yum-3.2.28.tar.gz /usr/local/tomcat


# 查看容器内,安装包成功下载,但是并没有解压
root@2046c78ec7e5:/usr/local/tomcat# ls
BUILDING.txt LICENSE README.md RUNNING.txt conf logs temp webapps.dist yum-3.2.28.tar.gz
CONTRIBUTING.md NOTICE RELEASE-NOTES bin lib native-jni-lib webapps work
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 从上下文路径中上传tar包到容器内指定的目录
FROM tomcat
WORKDIR /usr/local
WORKDIR tomcat
ADD yum-3.2.28.tar.gz /usr/local/tomcat
RUN cd /usr/local/tomcat/
RUN mv yum-3.2.28 yum
WORKDIR yum

# 进入容器内查看,tar已经自动解压
root@0f124e894e13:/usr/local/tomcat/yum# ls
AUTHORS FAQ PLUGINS bin docs po test yum-updatesd.py yummain.py
COPYING INSTALL README callback.py etc rpmUtils utils.py yum.spec
ChangeLog Makefile TODO cli.py output.py shell.py yum yumcommands.py

因此在COPY和ADD指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用COPY指令,仅在需要自动解压缩的场合使用ADD.

9.2.7 VOLUME

VOLUME使用匿名挂载容器内的数据卷.
为了避免在启动容器的时候忘记挂载数据卷,可以在Dockerfile文件中指定VOLUME匿名挂载.当容器启动时,如果使用-d指定了数据卷挂载,Dockerfile中的VOLUME会被覆盖.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# dockerfile中挂载这两个目录
VOLUME ["/usr/local/tomcat/webapps","/usr/local/tomcat/conf"]

# 构建成镜像mytomcat:08并启动
[root@aliyun dockfile]# docker run -d --name mytomcat mytomcat:08
5d2efc3a8ccca3c57b7c482ada72e1f646b4fd20c6f60709985c7551f58e357c
[root@aliyun dockfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5d2efc3a8ccc mytomcat:08 "catalina.sh run" 3 seconds ago Up 2 seconds 8080-8081/tcp nostalgic_moor

# 查看mytomcat:08的挂载信息
[root@aliyun dockfile]# docker inspect mytomcat
"Mounts": [
{
"Type": "volume",
"Name": "c5f6f552ffd603fd0695488a1580051c619bdae946087b1078aed86c1efa3569",
"Source": "/var/lib/docker/volumes/c5f6f552ffd603fd0695488a1580051c619bdae946087b1078aed86c1efa3569/_data",
"Destination": "/usr/local/tomcat/conf",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "d55e90013313c951f40ac0830e1079380352df53afd82be69d7b03c3a2b6517f",
"Source": "/var/lib/docker/volumes/d55e90013313c951f40ac0830e1079380352df53afd82be69d7b03c3a2b6517f/_data",
"Destination": "/usr/local/tomcat/webapps",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],

# 查看匿名挂载的数据卷
[root@aliyun volumes]# ls
apps
backingFsBlockDev
c5f6f552ffd603fd0695488a1580051c619bdae946087b1078aed86c1efa3569 # /usr/local/tomcat/conf
confs
d55e90013313c951f40ac0830e1079380352df53afd82be69d7b03c3a2b6517f # /usr/local/tomcat/webapps
metadata.db


# 在Dockfile文件中指定了VOLUME,但是在启动容器的时候也挂载了自定义的数据卷,Dockfile文件中匿名挂载的数据卷会被覆盖
[root@aliyun dockfile]# docker run -d -v apps:/usr/local/tomcat/webapps mytomcat:08
[root@aliyun dockfile]# docker inspect mytomcat
"Mounts": [
{
"Type": "volume",
"Name": "apps",
"Source": "/var/lib/docker/volumes/apps/_data", # 容器中的/usr/local/tomcat/webapps被挂载到了apps
"Destination": "/usr/local/tomcat/webapps",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "e92f66076c6b742ea9b1f3286c51b671e2ed3ce93d3b1d2b4485e1a31c1e91e8",
"Source": "/var/lib/docker/volumes/ e92f66076c6b742ea9b1f3286c51b671e2ed3ce93d3b1d2b4485e1a31c1e91e8/_data", # 容器中的/usr/local/tomcat/conf还是Dockerfile文件中指定的匿名挂载
"Destination": "/usr/local/tomcat/conf",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
9.2.8 EMV

EMV 设置环境变量,在EMV指令之后的指令都可以通过$()来使用环境变量

1
2
ENV MAINDIR /usr/local/tomcat
WORKDIR $MAINDIR
9.2.9 CMD

CMD指令指定在容器启动时(docker run)执行的命令.
CMD指令有两种方式:

  • shell模式: CMD ls /usr/local/tomcat 实际上会被包装成 CMD [“sh”,”-c”,”ls”,”/usr/local/tomcat”],由于sh的存在,可以使用环境变量.
  • exec模式: CMD [“ls”,”/usr/local/tomcat”]
    1
    CMD ["ls","/usr/local/tomcat"]

当在Dockerfile指定了CMD指令的时候,可以在启动容器时覆盖CMD命令.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CMD ["ls","-l"]

# 覆盖了dockerfile中的ls -l指令,而/usr不是一个有效的命令,所以报错
[root@aliyun dockfile]# docker run -it mytomcat:09 /usr
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "/usr": permission denied: unknown.

# 使用有效的命令可以覆盖Dockerfile中的CMD指令
[root@aliyun dockfile]# docker run -it mytomcat:09 ls -l /usr
total 36
drwxr-xr-x 1 root root 4096 Dec 8 20:53 bin
drwxr-xr-x 2 root root 4096 Oct 3 09:15 games
drwxr-xr-x 1 root root 4096 Dec 8 20:53 include
drwxr-xr-x 1 root root 4096 Dec 8 20:53 lib
drwxr-xr-x 1 root root 4096 Dec 2 11:34 libexec
drwxr-xr-x 1 root root 4096 Dec 3 14:11 local
drwxr-xr-x 1 root root 4096 Dec 2 03:39 sbin
drwxr-xr-x 1 root root 4096 Dec 8 20:53 share
drwxr-xr-x 2 root root 4096 Oct 3 09:15 src
9.2.10 ENTRYPOINT

ENTRYPOINT和CMD指令有着类似的功能.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# Dockerfile中指令
ENTRYPOINT ["ls","-l","/"]

# 启动时执行Dockerfile中的ENTYRYPOINT指令 ls -l /
[root@aliyun dockfile]# docker run mytomcat:09
total 64
drwxr-xr-x 1 root root 4096 Dec 2 11:34 bin
drwxr-xr-x 2 root root 4096 Oct 3 09:15 boot
drwxr-xr-x 5 root root 340 Dec 23 14:57 dev
drwxr-xr-x 1 root root 4096 Dec 23 14:57 etc
drwxr-xr-x 2 root root 4096 Oct 3 09:15 home
drwxr-xr-x 1 root root 4096 Dec 8 20:53 lib
drwxr-xr-x 2 root root 4096 Dec 1 00:00 lib64
drwxr-xr-x 2 root root 4096 Dec 1 00:00 media
drwxr-xr-x 2 root root 4096 Dec 1 00:00 mnt
drwxr-xr-x 2 root root 4096 Dec 1 00:00 opt
dr-xr-xr-x 89 root root 0 Dec 23 14:57 proc
drwx------ 1 root root 4096 Dec 2 11:34 root
drwxr-xr-x 3 root root 4096 Dec 1 00:00 run
drwxr-xr-x 1 root root 4096 Dec 2 03:40 sbin
drwxr-xr-x 2 root root 4096 Dec 1 00:00 srv
dr-xr-xr-x 13 root root 0 Dec 23 14:57 sys
drwxrwxrwt 1 root root 4096 Dec 8 20:53 tmp
drwxr-xr-x 1 root root 4096 Dec 1 00:00 usr
drwxr-xr-x 1 root root 4096 Dec 1 00:00 var

# 启动容器时使用--entrypoint覆盖Dockerfile中的ENTRYPOINT指令
# 注意--entrypoint要写在'镜像名称'前后,如果写在镜像名称后面,会被当成CMD指令
[root@aliyun dockfile]# docker run --entrypoint ls -l /usr/local/tomcat mytomcat:09
BUILDING.txt
CONTRIBUTING.md
LICENSE
NOTICE
README.md
RELEASE-NOTES
RUNNING.txt
bin
conf
lib
logs
native-jni-lib
temp
webapps
webapps.dist
work
9.2.11 CMD|ENTRYPOINT区别

如果在Dockerfile文件中同时指定了CMD和ENTRYPOINT指令,CMD的含义就发生了改变,不再是直接的运行其命令,而是将CMD的内容作为参数传给 ENTRYPOINT 指令,换句话说实际执行时,将变为ENTRYPOINT CMD.

应用场景1: 在Dockerfile文件中指定ENTRYPOINT默认运行的命令,在启动容器的时候指定CMD指令,CMD指令会被当成ENTRYPOINT的参数,从而达到动态添加执行参数的效果.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# Dockerfile中指令
ENTRYPOINT ["ls","-l","/"]

# 相当于执行了ls -l / /usr/local/tomcat
# 会将/和/usr/local/tomcat目录下的文件都列出来
# Dockerfile中默认运行的指令是ls -l /,/usr/local/tomcat是在容器启动时'动态添加的'
[root@aliyun dockfile]# docker run mycentos:09 /usr/local/tomcat
/:
total 64
drwxr-xr-x 1 root root 4096 Dec 2 11:34 bin
drwxr-xr-x 2 root root 4096 Oct 3 09:15 boot
drwxr-xr-x 5 root root 340 Dec 19 15:42 dev
drwxr-xr-x 1 root root 4096 Dec 19 15:42 etc
drwxr-xr-x 2 root root 4096 Oct 3 09:15 home
drwxr-xr-x 1 root root 4096 Dec 8 20:53 lib
drwxr-xr-x 2 root root 4096 Dec 1 00:00 lib64
drwxr-xr-x 2 root root 4096 Dec 1 00:00 media
drwxr-xr-x 2 root root 4096 Dec 1 00:00 mnt
drwxr-xr-x 2 root root 4096 Dec 1 00:00 opt
dr-xr-xr-x 87 root root 0 Dec 19 15:42 proc
drwx------ 1 root root 4096 Dec 2 11:34 root
drwxr-xr-x 3 root root 4096 Dec 1 00:00 run
drwxr-xr-x 1 root root 4096 Dec 2 03:40 sbin
drwxr-xr-x 2 root root 4096 Dec 1 00:00 srv
dr-xr-xr-x 13 root root 0 Dec 19 15:42 sys
drwxrwxrwt 1 root root 4096 Dec 8 20:53 tmp
drwxr-xr-x 1 root root 4096 Dec 1 00:00 usr
drwxr-xr-x 1 root root 4096 Dec 1 00:00 var

/usr/local/tomcat:
total 160
-rw-r--r-- 1 root root 18994 Dec 2 22:01 BUILDING.txt
-rw-r--r-- 1 root root 6210 Dec 2 22:01 CONTRIBUTING.md
-rw-r--r-- 1 root root 60269 Dec 2 22:01 LICENSE
-rw-r--r-- 1 root root 2333 Dec 2 22:01 NOTICE
-rw-r--r-- 1 root root 3378 Dec 2 22:01 README.md
-rw-r--r-- 1 root root 6905 Dec 2 22:01 RELEASE-NOTES
-rw-r--r-- 1 root root 16517 Dec 2 22:01 RUNNING.txt
drwxr-xr-x 2 root root 4096 Dec 8 20:53 bin
drwxr-xr-x 2 root root 4096 Dec 2 22:01 conf
drwxr-xr-x 2 root root 4096 Dec 8 20:53 lib
drwxrwxrwx 2 root root 4096 Dec 2 22:01 logs
drwxr-xr-x 2 root root 4096 Dec 8 20:53 native-jni-lib
drwxrwxrwx 2 root root 4096 Dec 8 20:53 temp
drwxr-xr-x 2 root root 4096 Dec 8 20:53 webapps
drwxr-xr-x 7 root root 4096 Dec 2 22:01 webapps.dist
drwxrwxrwx 2 root root 4096 Dec 2 22:01 work

应用场景2: 在Dockerfile文件中通过ENTRYPOINT指定通用的命令,在容器启动时指定CMD指令,CMD指令会被当成ENTRYPOINT的参数,从而达到动态传参的效果.
比如在发布springboot项目的时候,运行java -jar 项目名,只是项目名称不同,执行的命令都是一致的,就可以使用这种方法来动态传参.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
CMD ["/usr/local/tomcat"]
ENTRYPOINT ["ls","-l"]

# CMD和ENTRYPOINT一起执行了,相当于执行了 ls -l /usr/local/tomcat
[root@aliyun dockfile]# docker run mytomcat:09
total 160
-rw-r--r-- 1 root root 18994 Dec 2 22:01 BUILDING.txt
-rw-r--r-- 1 root root 6210 Dec 2 22:01 CONTRIBUTING.md
-rw-r--r-- 1 root root 60269 Dec 2 22:01 LICENSE
-rw-r--r-- 1 root root 2333 Dec 2 22:01 NOTICE
-rw-r--r-- 1 root root 3378 Dec 2 22:01 README.md
-rw-r--r-- 1 root root 6905 Dec 2 22:01 RELEASE-NOTES
-rw-r--r-- 1 root root 16517 Dec 2 22:01 RUNNING.txt
drwxr-xr-x 2 root root 4096 Dec 8 20:53 bin
drwxr-xr-x 2 root root 4096 Dec 2 22:01 conf
drwxr-xr-x 2 root root 4096 Dec 8 20:53 lib
drwxrwxrwx 2 root root 4096 Dec 2 22:01 logs
drwxr-xr-x 2 root root 4096 Dec 8 20:53 native-jni-lib
drwxrwxrwx 2 root root 4096 Dec 8 20:53 temp
drwxr-xr-x 2 root root 4096 Dec 8 20:53 webapps
drwxr-xr-x 7 root root 4096 Dec 2 22:01 webapps.dist
drwxrwxrwx 2 root root 4096 Dec 2 22:01 work

# 可以在启动容器的时候覆盖CMD命令,相当于执行了 ls -l /
[root@aliyun dockfile]# docker run mytomcat:09 /
total 64
drwxr-xr-x 1 root root 4096 Dec 2 11:34 bin
drwxr-xr-x 2 root root 4096 Oct 3 09:15 boot
drwxr-xr-x 5 root root 340 Dec 19 15:04 dev
drwxr-xr-x 1 root root 4096 Dec 19 15:04 etc
drwxr-xr-x 2 root root 4096 Oct 3 09:15 home
drwxr-xr-x 1 root root 4096 Dec 8 20:53 lib
drwxr-xr-x 2 root root 4096 Dec 1 00:00 lib64
drwxr-xr-x 2 root root 4096 Dec 1 00:00 media
drwxr-xr-x 2 root root 4096 Dec 1 00:00 mnt
drwxr-xr-x 2 root root 4096 Dec 1 00:00 opt
dr-xr-xr-x 85 root root 0 Dec 19 15:04 proc
drwx------ 1 root root 4096 Dec 2 11:34 root
drwxr-xr-x 3 root root 4096 Dec 1 00:00 run
drwxr-xr-x 1 root root 4096 Dec 2 03:40 sbin
drwxr-xr-x 2 root root 4096 Dec 1 00:00 srv
dr-xr-xr-x 13 root root 0 Dec 19 15:04 sys
drwxrwxrwt 1 root root 4096 Dec 8 20:53 tmp
drwxr-xr-x 1 root root 4096 Dec 1 00:00 usr
drwxr-xr-x 1 root root 4096 Dec 1 00:00 var
9.2.12 HEALTHCHECK

HEALTHCHECK指令指定一行命令,用这行命令来判断容器主进程的服务状态是否还正常,从而比较真实的反应容器实际状态.

当在一个镜像指定了HEALTHCHECK指令后,用其启动容器,初始状态会为starting,在HEALTHCHECK指令检查成功后变为healthy,如果连续一定次数失败,则会变为unhealthy.

HEALTHCHECK 支持下列选项:
–interval=<间隔>:两次健康检查的间隔,默认为30秒
–timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认30秒
–retries=<次数>:当连续失败指定次数后,则将容器状态视为unhealthy,默认3次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 这里举个例子,也就是说每隔5s向hello.txt文件中打印一句'healthcheck'
HEALTHCHECK --interval=5s --timeout=3s --retries=3 CMD echo "healthcheck" >> hello.txt

# 容器钢启动,初始状态为starting
[root@aliyun dockfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c0ff58d3a715 mytomcat:09 "catalina.sh run" 3 seconds ago Up 2 seconds (health: starting) 8080-8081/tcp elated_germain

# HEALTHCHECK检查成功后,容器状态变成healthy
[root@aliyun dockfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c0ff58d3a715 mytomcat:09 "catalina.sh run" 4 minutes ago Up 4 minutes (healthy) 8080-8081/tcp elated_germain

# 通过docker inspect查看healthcheck的状态,每一次启动都会执行一次HEALTHCHECK
"Health": {
"Status": "healthy",
"FailingStreak": 0,
"Log": [
{
"Start": "2021-12-24T18:13:59.064542488+08:00",
"End": "2021-12-24T18:13:59.119104436+08:00",
"ExitCode": 0,
"Output": ""
}
]
},
"Healthcheck": {
"Test": [
"CMD-SHELL",
"echo \"healthcheck\" >> hello.txt"
],
"Interval": 5000000000,
"Timeout": 3000000000,
"Retries": 3
}
9.2.13 USER

USER指令切换用户,对后面的RUN等其他指令生效.
USER指定的用户必须存在.否则报错unable to find user test: no matching entries in passwd file.

1
2
RUN groupadd -r tomcat && useradd -r tomcat -g tomcat
USER tomcat

9.3 查看构建过程

从镜像构造的过程来看,当执行docker build的时候,一条Dockerfile指令就对应着一层镜像层.
查看CREATED镜像层的创建时间可知,如果有共享的镜像层可以使用,则不会生成新的镜像层.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 使用docker history 镜像id  可以查看一个镜像构建的过程
[root@aliyun dockfile]# docker history mytomcat:09
IMAGE CREATED CREATED BY SIZE COMMENT
a67571bcc990 25 minutes ago /bin/sh -c #(nop) ENTRYPOINT ["ls" "-l"] 0B
c51982690654 8 hours ago /bin/sh -c #(nop) WORKDIR /usr/local/tomcat 0B
e1d45fab1f8a 8 hours ago /bin/sh -c #(nop) WORKDIR /usr/local 0B
fba543986ae7 8 hours ago /bin/sh -c #(nop) EXPOSE 8081 0B
7ccc021ae63d 8 hours ago /bin/sh -c #(nop) EXPOSE 8080 0B
24207ccc9cce 10 days ago /bin/sh -c #(nop) CMD ["catalina.sh" "run"] 0B
<missing> 10 days ago /bin/sh -c #(nop) EXPOSE 8080 0B
<missing> 10 days ago /bin/sh -c set -eux; nativeLines="$(catalin… 0B
<missing> 10 days ago /bin/sh -c set -eux; savedAptMark="$(apt-m… 20.2MB
<missing> 10 days ago /bin/sh -c #(nop) ENV TOMCAT_SHA512=c2d2ad5… 0B
<missing> 10 days ago /bin/sh -c #(nop) ENV TOMCAT_VERSION=10.0.14 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ENV TOMCAT_MAJOR=10 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ENV GPG_KEYS=A9C5DF4D22E9… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ENV LD_LIBRARY_PATH=/usr/… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ENV TOMCAT_NATIVE_LIBDIR=… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) WORKDIR /usr/local/tomcat 0B
<missing> 2 weeks ago /bin/sh -c mkdir -p "$CATALINA_HOME" 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ENV PATH=/usr/local/tomca… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ENV CATALINA_HOME=/usr/lo… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) CMD ["jshell"] 0B
<missing> 2 weeks ago /bin/sh -c set -eux; arch="$(dpkg --print-… 343MB
<missing> 2 weeks ago /bin/sh -c #(nop) ENV JAVA_VERSION=11.0.13 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ENV LANG=C.UTF-8 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ENV PATH=/usr/local/openj… 0B
<missing> 2 weeks ago /bin/sh -c { echo '#/bin/sh'; echo 'echo "$J… 27B
<missing> 2 weeks ago /bin/sh -c #(nop) ENV JAVA_HOME=/usr/local/… 0B
<missing> 2 weeks ago /bin/sh -c set -eux; apt-get update; apt-g… 11.3MB
<missing> 2 weeks ago /bin/sh -c apt-get update && apt-get install… 152MB
<missing> 2 weeks ago /bin/sh -c set -ex; if ! command -v gpg > /… 18.9MB
<missing> 2 weeks ago /bin/sh -c set -eux; apt-get update; apt-g… 10.7MB
<missing> 2 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:e777355768c63f735… 124MB

9.4 制作tomcat的Dockfile

准备tomcat,JDK的压缩包,编写Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 基于centos
FROM centos
# 作者信息
MAINTAINER xiaoming<1149895826@qq.com>
# 下载vim
RUN yum -y install vim
RUN yum -y install rpm
# 将当前目录下的压缩包发送到服务器,ADD指令会自动解压
ADD apache-tomcat-8.5.61.tar.gz /usr/local/tomcat/
# 将当前目录下的JDK rpm包发送到服务器
ADD jdk-8u271-linux-x64.rpm /usr/local/java/
# 下载rpm包,安装JDK
RUN cd /usr/local/java && yum -y install /usr/local/java/jdk-8u271-linux-x64.rpm && yum install which -y
# 设置环境变量,这里非常重要,稍微有一点错误,容器就启动不起来
ENV JAVA_HOME /usr/java/jdk1.8.0_271-amd64
ENV CLASSPATH .:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/tomcat/apache-tomcat-8.5.61
ENV CATALINA_BASH /usr/local/tomcat/apache-tomcat-8.5.61
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
# 设置容器启动时的工作目录
ENV MAINPATH /usr/local/tomcat
WORKDIR $MAINPATH
# 暴露容器的端口
EXPOSE 8080
# 容器启动时执行的命令:启动tomcat,并打印启动日志
CMD sh /usr/local/tomcat/apache-tomcat-8.5.61/bin/startup.sh && tail -f /usr/local/tomcat/apache-tomcat-8.5.61/logs/catalina.out

docker build 生成镜像文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. 由于文件命名是Dockerfile,无需指定-f参数
docker build -t diy_tomcat .

# 2. 后台启动容器,将tomcat的webapps和日志目录挂载到宿主机,启动后自动打印启动日志
[root@ming diy_tomcat]# docker run -p 3344:8080 -v /home/diy_tomcat/webapps/:/usr/local/tomcat/apache-tomcat-8.5.61/webapps/ -v /home/diy_tomcat/logs/:/usr/local/tomcat/apache-tomcat-8.5.61/logs/ diy_tomcat

# 3. 查看容器,容器正在运行
[root@ming diy_tomcat]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3134796152c3 diy_tomcat "/bin/sh -c 'sh /usr…" About a minute ago Up About a minute 0.0.0.0:3344->8080/tcp heuristic_kare

# 4.外网访问http://47.96.224.198:3344/,访问正常

# 5. 查看宿主机挂载的目录是否挂载成功
[root@ming webapps]# pwd
/home/diy_tomcat/webapps
[root@ming webapps]# ls
balance dev docs examples host-manager manager ROOT

# 以后,我们只需要将项目部署在宿主机的webapps目录下就可以啦
1
echo "1">/proc/sys/vm/drop_caches

9.5 不同操作系统的镜像

使用镜像创建容器,该镜像必须与Docker宿主机系统架构一致.为了在不同的操作系统上使用相同的镜像,就必须为每个操作系统单独构建一个镜像.
但是Docker官方提供了一个Manifest列表.
当用户获取一个镜像时,Docker引擎会首先查找该镜像是否有manifest列表,如果有的话Docker引擎会按照Docker运行环境(系统及架构)查找出对应镜像.如果没有的话会直接获取镜像.

9.5.1 查看manifest列表

使用docker manifest inspect 查看manifest列表.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[root@aliyun ~]# docker manifest inspect golang:alpine
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 1365,
"digest": "sha256:8474650232fca6807a8567151ee0a6bd2a54ea28cfc93f7824b42267ef4af693",
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 1365,
"digest": "sha256:53b31b66a1c02978ab537c4eacb242aebd48cc5bf59f1310d6e373a852140e2d",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v6"
}
}
}

10.发布自己的镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 1. 首先需要创建DockerHub的账号

# 2. 在命令行中先登录账户
[root@ming ~]# docker login -u jinming8
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

# 3. 将要发布的镜像tag成 用户名/镜像名,这一步至关重要
[root@ming ~]# docker tag nginx jinming8/nginx:0.1

# 4. 执行push命令,发布到Dockhub
[root@ming ~]# docker push jinming8/nginx:0.1
The push refers to repository [docker.io/jinming8/nginx]
4eaf0ea085df: Mounted from library/nginx
2c7498eef94a: Mounted from library/nginx
7d2b207c2679: Mounted from library/nginx
5c4e5adc71a8: Mounted from library/nginx
87c8a1d8f54f: Mounted from library/mysql
0.1: digest: sha256:13e4551010728646aa7e1b1ac5313e04cf75d051fa441396832fcd6d600b5e71 size: 1362 # 发布成功

# 5. 退出登录
[root@ming ~]# docker logout
Removing login credentials for https://index.docker.io/v1/

11. Docker网络

安装了docker之后,Docker默认使用桥接模式,会自动分配一个网卡docker0,我们可以通过以下命令查看:

1
2
3
4
5
6
7
8
9
10
➜  ~ docker network ls
NETWORK ID NAME DRIVER SCOPE
65835d31d2aa bridge bridge local
7855b7c8c192 host host local
62e33b041284 none null local

# docker有3种网络模式:
# 1.bridge:桥接模式,docker默认的网络模式
# 2.host:与宿主机器共享网络
# 3.none:不使用网络

如果想查看网络的详细信息,可以使用docker network inspect ID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
➜  ~ docker inspect bridge
[
{
"Name": "bridge",
"Id": "65835d31d2aae177b93753c41e7bcddc7a16bca5ba7203f37f15db0c30ed1d55",
"Created": "2021-12-13T11:35:03.449943083Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
# 所有连接到该网桥的容器的信息
"Containers": {
"0fde18a60470ab399cafdf9fc6d407fa125ac0fc7a1af9610649968e19c70fa7": {
"Name": "mysql-test",
"EndpointID": "d6bf32b11b1f9b4a48a3794bfe2583bb522ac12159439359a6dcfc4ca433e2f0",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16", # mysql容器的IP
"IPv6Address": ""
},
"f1953dca10dbbb7ebb2b77693ed7fbcceba997ed533dff76ba63e9e08c53a863": {
"Name": "tomcat",
"EndpointID": "b8cf305cf3bc697b10535263c13b9c30daca3b812a33ac29e021cab7b137059a",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16", # tomcat容器的IP
"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": {}
}
]

桥接模式使用veth-pair的技术(一对虚拟设备接口,一端连着容器,一端连着docker0,只要一端收到数据,另外一端也会接受到相同的数据).
当宿主机与容器通信时,宿主机往docker0的设备接口发送数据,连接着docker0的容器端的设备接口也会收到相同的数据.
当容器与宿主机通信时,容器往容器的设备接口发送数据,连接着容器的docker0端设备接口也会收到相同的数据.
而容器的IP与docker0的IP会在同一个网段,可以相互通信.这就实现了容器间的通信.

11.1 问题1:宿主机和容器能不能ping通? ✔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# 1. 查看宿主机器的ip addr
[root@ming ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
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 qlen 1000
link/ether 00:16:3f:00:fd:98 brd ff:ff:ff:ff:ff:ff
inet 172.16.47.149/20 brd 172.16.47.255 scope global dynamic eth0
valid_lft 314901004sec preferred_lft 314901004sec
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:e7:4f:27:e0 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

# 宿主机器上有3个网卡:
# 1. lo:本地回环地址
# 2. eth0:阿里云内网,ip=172.16.47.149
# 3. docker0:docker的网卡,只要我们安装了docker就会有这个网卡

# 2. 启动一个tomcat容器
[root@ming ~]# docker run -it --name tomcat1 tomcat /bin/bash

# 3. 进入容器内查看ip
root@1826a8cb702d:/usr/local/tomcat# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
332: eth0@if333: <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

# 容器内有2个网卡:
# 1. lo:本地回环地址
# 2. 332: eth0@if333:docker为容器分配的网卡,ip=172.17.0.2

# 4. 在容器内ping宿主机器的ip 172.16.47.149
root@1826a8cb702d:/usr/local/tomcat# ping 172.16.47.149
PING 172.16.47.149 (172.16.47.149) 56(84) bytes of data.
64 bytes from 172.16.47.149: icmp_seq=1 ttl=64 time=0.079 ms
64 bytes from 172.16.47.149: icmp_seq=2 ttl=64 time=0.075 ms
64 bytes from 172.16.47.149: icmp_seq=3 ttl=64 time=0.077 ms
64 bytes from 172.16.47.149: icmp_seq=4 ttl=64 time=0.077 ms


# 结论1:在容器内是可以ping通宿主机器地址的

# 5. CTRL+P+Q退出容器,在宿主机查看ip addr
[root@ming ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
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 qlen 1000
link/ether 00:16:3f:00:fd:98 brd ff:ff:ff:ff:ff:ff
inet 172.16.47.149/20 brd 172.16.47.255 scope global dynamic eth0
valid_lft 314900722sec preferred_lft 314900722sec
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:e7:4f:27:e0 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
333: veth740bb55@if332: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 06:b3:9f:71:29:93 brd ff:ff:ff:ff:ff:ff link-netnsid 0

# 相比与启动容器tomcat之前,宿主机多了一个网卡333: veth740bb55@if332,而且我们发现,它与容器的内的网卡332: eth0@if333形成了一对。

# 6. 在宿主机内ping容器地址172.17.0.2
[root@ming ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.059 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.066 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.064 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.084 ms

# 结论2:宿主机是可以ping通容器内的ip的

11.2 问题2:两个容器直接能否直接ping通? ✔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 1.再次启动一个容器tomcat2,查看ip地址
[root@ming ~]# docker run -it --name=tomcat2 tomcat /bin/bash
root@9d1e83b5c4d6:/usr/local/tomcat# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
334: eth0@if335: <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

# 容器内也是有2个网卡,一个本机回环地址,一个docker分配的网卡,tomcat2的ip=172.17.0.3

# 2. tomcat2 能否ping通 tomcat1 ?
root@9d1e83b5c4d6:/usr/local/tomcat# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.099 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.087 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.085 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.089 ms

# 结果肯定是可以的,因为从ip地址可以看出,它们属于同一个网段。

# 3. 进入到tomcat1容器,ping tomcat2的ip
[root@ming ~]# docker attach 1826a8cb702d
root@1826a8cb702d:/usr/local/tomcat# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.075 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.090 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.085 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.089 ms

# 再次验证。

# 结论:两个容器之间也是可以相互ping通的。虽然两个容器直接能ping通,但两个容器间却不是直接相连接的。它们通过veth-pair与docker0相连,docker0这个桥接起了作用

11.3 能否通过容器的name来连接? ×(–link ✔)

默认容器之间的通信使用的是IP的形式,如果想使用容器的名字来进行通信,需要在创建容器的时候指定–link参数.
需要注意的是–link参数是单向的.
–link参数实际上是在容器的/etc/hosts文件中增加了一个host的映射,当通过名称访问时,会被映射成对应的IP地址.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 1. 进入到tomcat1容器,直接ping tomcat2容器的名字
root@1826a8cb702d:/usr/local/tomcat# ping tomcat2
ping: tomcat2: Name or service not known

# 不能直接通过容器名称来连接

# 2. 重新启动容器tomcat3,指定--link 连接tomcat2
[root@ming ~]# docker run -it --name tomcat3 --link tomcat2 tomcat /bin/bash
root@0ded9ce6d825:/usr/local/tomcat# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
338: eth0@if339: <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

# 注意,这里tomcat3的ip=172.17.0.2,好像和tomcat1的ip相同,但是我这里是把tomcat1容器退出了的

# 3. 在tomcat3容器内直接ping tomcat2
root@0ded9ce6d825:/usr/local/tomcat# ping tomcat2
PING tomcat2 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat2 (172.17.0.3): icmp_seq=1 ttl=64 time=0.094 ms
64 bytes from tomcat2 (172.17.0.3): icmp_seq=2 ttl=64 time=0.084 ms
64 bytes from tomcat2 (172.17.0.3): icmp_seq=3 ttl=64 time=0.085 ms
64 bytes from tomcat2 (172.17.0.3): icmp_seq=4 ttl=64 time=0.084 ms

# 结论1:在启动容器的时候,使用--link 参数指定容器,可以与指定的容器通过名称连接

# 4. 进入容器tomcat2,ping tomcat3
[root@ming ~]# docker attach 9d1e83b5c4d6
root@9d1e83b5c4d6:/usr/local/tomcat# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
334: eth0@if335: <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@9d1e83b5c4d6:/usr/local/tomcat# ping tomcat3
ping: tomcat3: Name or service not known

# 结论2:tomcat2是不能ping通tomcat3的,说明tomcat3容器启动的时候指定的--link参数是单向的。

# 5. 进入tomcat3容器,查看/etc/hosts文件
[root@ming ~]# docker attach 0ded9ce6d825
root@0ded9ce6d825:/usr/local/tomcat# 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 tomcat2 9d1e83b5c4d6
172.17.0.2 0ded9ce6d825

# 结论3:我们惊奇的发现,所谓的tomcat3启动时指定的--link参数,只是修改了tomcat的hosts文件,当tomcat3访问tomcat2的时候,跳转到172.17.0.3(也就是tomcat的ip地址)

虽然–link能使用容器名称来连接,但这种做法是过时的,更好的方法是使用自定义网络。

11.4 自定义网络

自定义一个网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 1. 创建网络,指定网关和子网掩码
[root@ming ~]# docker network create --gateway 192.168.0.1 --subnet 192.168.0.0/16 mynet

# 2. 查看创建的网络
[root@ming ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
1cd4dcbb6871 bridge bridge local
937119faf618 host host local
805e98b29181 mynet bridge local
5f780b566b6c none null local

# 3. 启动容器的时候指定网络
[root@ming ~]# docker run -it --name tomcat1 --network mynet tomcat /bin/bash
root@a8d9dd3ce963:/usr/local/tomcat# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
341: eth0@if342: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c0:a8:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.0.2/16 brd 192.168.255.255 scope global eth0
valid_lft forever preferred_lft forever

# 容器启动后的ip=192.168.0.2,是我们自定义的网络mynet

# 4. 查看mynet的详细信息

[root@ming ~]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "805e98b29181a303950c9f3267587e6ea27c2df3728a0723e4f16acb43add392",
"Created": "2021-01-05T19:12:36.296644818+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16", # 我们设置的子网
"Gateway": "192.168.0.1" # 我们设置的网关
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": { # 此网络内的容器信息
"a8d9dd3ce9633968957a5d1487bbf85716985f97ed6cf4f2b9a78c47d2c3f67d": {
"Name": "tomcat1",
"EndpointID": "f1bbab5f9d330f62f17ef2076dd09d00a124d14d5ce8c3658d8e6459215c4e19",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16", # tomcat1容器的ip
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]

# 5. 启动容器tomcat2,查看ip,并通过容器名称连接tomcat1
[root@ming ~]# docker run -it --name tomcat2 --net mynet tomcat /bin/bash
root@bf9e41e968ae:/usr/local/tomcat# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
343: eth0@if344: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c0:a8:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.0.3/16 brd 192.168.255.255 scope global eth0
valid_lft forever preferred_lft forever
root@bf9e41e968ae:/usr/local/tomcat# ping tomcat1
PING tomcat1 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat1.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.101 ms
64 bytes from tomcat1.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.083 ms
64 bytes from tomcat1.mynet (192.168.0.2): icmp_seq=3 ttl=64 time=0.098 ms
64 bytes from tomcat1.mynet (192.168.0.2): icmp_seq=4 ttl=64 time=0.088 ms

# 结论1:通过自定义网络是能通过容器名称进行连接的。

11.5 网络互联

上面tomcat1和tomcat2已经连接在mynet网络下了,那么连接在docker0的容器,能否访问mynet网络下的容器呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# 1. 使用默认的docker0启动一个容器tomcat3
[root@ming ~]# docker run -it --name tomcat3 tomcat /bin/bash
root@bac489a3beb3:/usr/local/tomcat# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
345: eth0@if346: <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

# 2. 使用tomcat3连接mynet网络下的tomcat2
root@bac489a3beb3:/usr/local/tomcat# ping tomcat2
ping: tomcat2: Name or service not known
root@bac489a3beb3:/usr/local/tomcat# ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.

# 无论是通过ip,还是通过容器名称,都无法连接。
# mynet和docker0的网段不同

# 3. 使用docker network connect让docker0下的tomcat3容器连接到mynet网络
[root@ming ~]# docker network connect mynet tomcat3

# 4. 查看mynet网络的详细信息
[root@ming ~]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "805e98b29181a303950c9f3267587e6ea27c2df3728a0723e4f16acb43add392",
"Created": "2021-01-05T19:12:36.296644818+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"a8d9dd3ce9633968957a5d1487bbf85716985f97ed6cf4f2b9a78c47d2c3f67d": {
"Name": "tomcat1",
"EndpointID": "f1bbab5f9d330f62f17ef2076dd09d00a124d14d5ce8c3658d8e6459215c4e19",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
},
"bf9e41e968aeccc9ccd0ecc3efc60c1d38b550ea783dbc530b68eba9b7952d5c": {
"Name": "tomcat2",
"EndpointID": "f016fc90361535f9e08c0ad4dfd92bc630c83a88704680231e33a4bbd201f15a",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
},
"f1933b52fa5559c60890e2a223cb118ff2290a5f0ff4966d1cffac28c280c439": {
"Name": "tomcat3", # mynet网络下已经有了tomcat3的容器
"EndpointID": "48ce720242696f70d6ae7051a8754d56b30ae2d3bc08b82761822eeca25ddebf",
"MacAddress": "02:42:c0:a8:00:04",
"IPv4Address": "192.168.0.4/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]

# 5. 查看tomcat3容器的ip
root@f1933b52fa55:/usr/local/tomcat# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
347: eth0@if348: <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
349: eth1@if350: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c0:a8:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.0.4/16 brd 192.168.255.255 scope global eth1
valid_lft forever preferred_lft forever

# 可以看到,tomcat有2个ip地址
# 172.17.0.2 docker0网卡的
# 192.168.0.4 mynet网卡的

11.6 查看容器IP

11.6.1 在容器内查看

如果在容器内查看容器IP,可以查看/etc/hosts文件

1
2
3
4
5
6
7
8
root@f1953dca10db:/etc# cat 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 f1953dca10db
11.6.2 在容器外查看

如果在容器外查看容器IP,可以使用docker inspect 容器id|name 查看容器的信息,其中有一个字段IPAddress就是容器IP
或者可以添加–format 只获取容器信息的IPAddress字段

1
2
# -f 表示format
docker inspect tomcat -f '{{.NetworkSettings.IPAddress}}'
11.6.3 获取所有容器名称和IP

-f 参数必须使用单引号

1
docker inspect -f '{{.Name}} - {{.NetworkSettings.IPAddress}}' $(docker ps -aq)

或者可以通过网桥查看所有连接到该网桥的容器的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#  查看所有的网桥信息
➜ ~ docker network ls
NETWORK ID NAME DRIVER SCOPE
65835d31d2aa bridge bridge local
7855b7c8c192 host host local
62e33b041284 none null local

# 查看bridge网桥的信息
➜ ~ docker inspect bridge
[
{
"Name": "bridge",
"Id": "65835d31d2aae177b93753c41e7bcddc7a16bca5ba7203f37f15db0c30ed1d55",
"Created": "2021-12-13T11:35:03.449943083Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
# 所有连接到该网桥的容器的信息
"Containers": {
"0fde18a60470ab399cafdf9fc6d407fa125ac0fc7a1af9610649968e19c70fa7": {
"Name": "mysql-test",
"EndpointID": "d6bf32b11b1f9b4a48a3794bfe2583bb522ac12159439359a6dcfc4ca433e2f0",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16", # mysql容器的IP
"IPv6Address": ""
},
"f1953dca10dbbb7ebb2b77693ed7fbcceba997ed533dff76ba63e9e08c53a863": {
"Name": "tomcat",
"EndpointID": "b8cf305cf3bc697b10535263c13b9c30daca3b812a33ac29e021cab7b137059a",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16", # tomcat容器的IP
"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": {}
}
]

11.7 Macos的网络问题

Docker For Mac的网络问题及解决办法
Docker官方对于MacOs网络的描述

Docker是利用Linux的Namespace和Cgroups来实现资源的隔离和限制,容器共享宿主机内核.所以Mac本身没法运行Docker容器.
Mac是在Macos上跑了一个Linux虚拟机,然后在虚拟机上跑的Docker.
这就导致Mac上没有Docker0的网桥,Mac上也不能直接ping通容器的IP.

解决方法(docker-connector):
1.(Macos端):在Mac上安装docker-connector,并修改docker-connector.conf添加bridge的IP
Mac上使用homebrew安装,安装后的默认路径是在/opt/homebrew

1
brew install wenjunxiao/brew/docker-connector

修改/opt/homebrew/etc/docker-connector.conf配置文件,添加需要访问容器的bridge:

1
2
# 添加docker默认的bridge
route 172.17.0.0/16

启动docker-connector服务:

1
brew services start docker-connector

2.(Docker端):拉取docker-connector镜像,并创建容器:

1
docker run -it -d --restart always --net host --cap-add NET_ADMIN --name connector wenjunxiao/mac-docker-connector

根据以上的配置,Mac宿主机就能ping通容器内IP了.

11.8 查看端口映射配置

1
2
3
4
5
6
7
# 查看tomcat容器所有的端口映射
➜ ~ docker port tomcat
8080/tcp -> 0.0.0.0:8080

# 查看tomcat容器8080端口的映射
➜ ~ docker port tomcat 8080
0.0.0.0:8080

12.Docker工具安装

12.1 vim
1
2
apt-get update
apt-get install vim

或者使用yum安装:

1
yum install -y vim
12.2 ping
1
2
apt-get update
apt-get install iputils-ping
12.3 ifconfig
1
2
apt-get update
apt-get install net-tools
12.4 yum
1
2
3
wget http://yum.baseurl.org/download/3.2/yum-3.2.28.tar.gz
tar xvf yum-3.2.28.tar.gz
cd yum-3.2.28

13.常用容器

13.1 Mysql

使用别人镜像的时候,很重要的一点是到Docker Hub上查找镜像并查看镜像的使用方法.
主要是关于数据持久化或配置备份相关的目录,只有根据镜像的说明文档才知道它存放的路径在哪里.

后台启动mysql容器,挂载到docker的数据款mysqldata上,映射宿主机的3306端口,在macos上需要指定platform
-e参数是环境变量,指定mysql启动时root的密码

1
docker run -d --name mysql -v mysqldata:/var/lib/mysql -p 3306:3306 --platform linux/amd64 -e MYSQL_ROOT_PASSWORD=root mysql

容器启动之后查看mysql容器的信息,这里只列出基本信息和数据卷信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
➜  bin docker inspect mysql
[
{
"Id": "a5a6aa84ab7091059fae4f0504faa3cd59c25b607dab6ffe0c5f3f9b0678d4c7",
"Created": "2021-12-15T13:55:43.516570797Z",
"Path": "docker-entrypoint.sh",
"Args": [
"mysqld"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 3185,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-12-15T13:55:43.73619438Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Mounts": [
{
"Type": "volume",
"Name": "mysqldata", # docker run时指定的数据卷的名称
"Source": "/var/lib/docker/volumes/mysqldata/_data", # 挂载在宿主机上的这个目录
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "z",
"RW": true, # 具有可读可写的权限
"Propagation": ""
}
]
}
]

13.2 tomcat

直接使用docker run启动一个容器,当本地没有tomcat的镜像时,会直接到远程仓库中拉取.
将容器内的webapps目录挂载到宿主机的/usr/local/apps目录中,以后项目只需要部署在宿主机的/usr/local/apps目录下.
将容器内的conf目录挂载到宿主机的/usr/local/confs目录中,以后tomcat的配置文件只需要修改/usr/local/confs目录下的配置文件.

1
docker run -d --name tomcat -p 8080:8080 -v /usr/local/apps:/usr/local/tomcat/webapps -v /usr/local/confs :/usr/local/tomcat/conf tomcat:latest

此时,通过宿主机IP:端口是访问不到tomcat的.
查看容器内的webapps目录,发现其目录下是空的.同时发现有一个webapps.dist的目录,我们需要将webapps.dist目录下的所有文件移动或复制到webapps目录下,才可以通过外网访问.

1
2
3
4
5
# 移动webapps.dist下的所有文件到webapps
mv webapps.dist/* webapps/

# 复制webapps.dist下的所有文件到webapps
cp -r webapps.dist/* webapps/

完成复制的操作后,需要查看tomcat的启动日志,是否有重新加载了webapps的目录下的文件,如果还是加载webapps.dist目录的话,需要重启tomcat服务器.

关于修改tomcat的配置文件,如果修改的是tomcat不能重加载的配置,我们需要重新运行一个容器来修改tomcat的配置.
假设我们将tomcat的配置文件已经挂载到了宿主机上的/usr/local/confs/server.xml下,修改server.xml的tomcat的端口8080->8081
此时查看tomcat的日志,发现tomcat的端口还是8080,而不是8081,这是因为tomcat不能加载到tomcat端口改变的这个配置.
重启一下tomcat容器,查看日志如下:

1
2
3
4
5
18-Dec-2021 13:39:56.343 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8081"]
18-Dec-2021 13:39:56.427 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [1668] milliseconds
18-Dec-2021 13:39:56.589 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
18-Dec-2021 13:39:56.589 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.0.14]
18-Dec-2021 13:39:56.609 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/docs]

日志显示,当前容器内的tomcat已经监听8081端口,宿主机上的8080映射容器内的8081端口.
但是当我们使用外网访问8080端口的时候,却访问不到.
此时,我们退出tomcat容器,在宿主机上查看当前运行的tomcat容器信息:

1
2
3
[root@aliyun ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7b25deacf086 tomcat "catalina.sh run" 44 minutes ago Up 7 minutes 0.0.0.0:8080->8080/tcp tomcat

我们可以发现,即使容器内的tomcat已经运行在8081端口,但是这个容器启动的时候,也就是执行docker run命令的时候,就已经指定了
-p 8080:8080,即使容器内的tomcat修改了端口,这个映射没有修改,也无法通过8081端口访问到tomcat.
此时,我们可以重新启动一个容器,使用原来的webapps和confs,修改端口映射为宿主机8080->容器8081

1
docker run -d --name tomcat1 -p 8080:8081 -v /usr/local/apps:/usr/local/tomcat/webapps -v /usr/local/confs:/usr/local/tomcat/conf tomcat

此时,查看启动的容器:
端口映射已经修改为8080->8081,而webapps和confs因为之前已经被挂载到了宿主机持久化了,再次启动一个新的容器的时候挂载的数据和原来的一致,只是端口的映射修改了.
此时,通过外网访问8080端口,能正常访问到容器内的8081端口.

1
2
3
[root@aliyun _data]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6b2fc0243d5b tomcat "catalina.sh run" 3 minutes ago Up 3 minutes 8080/tcp, 0.0.0.0:8080->8081/tcp tomcat1
一毛也是爱~
Kim.Zhang 微信支付

微信支付

  • 文章目录
  • 站点概览
Kim.Zhang

Kim.Zhang

且行且珍惜
94 日志
12 分类
42 标签
E-Mail Weibo
  1. 1. 1. Docker简介
    1. 1.1. 1.1 基本概念
    2. 1.2. 1.2 安装Docker
    3. 1.3. 1.3 阿里云镜像加速器
    4. 1.4. 1.4 docerk run 流程
    5. 1.5. 1.5 底层原理
  2. 2. 2.镜像的基本命令
    1. 2.1. 2.1 查看版本
    2. 2.2. 2.2 查看镜像
    3. 2.3. 2.2 搜索镜像
    4. 2.4. 2.3 下载镜像
    5. 2.5. 2.4 删除镜像
    6. 2.6. 2.5 导出镜像
    7. 2.7. 2.6 导入镜像
  3. 3. 3.容器的基本命令
    1. 3.1. 3.1 创建容器并启动
    2. 3.2. 3.2 查看容器
    3. 3.3. 3.3 退出容器
    4. 3.4. 3.4 删除容器
    5. 3.5. 3.5 启动和停止容器
    6. 3.6. 3.6 查看容器日志
    7. 3.7. 3.7 导出容器
    8. 3.8. 3.8 导入容器
  4. 4. 4.常用其他命令
    1. 4.1. 4.1 后台启动容器
    2. 4.2. 4.2 查看日志
    3. 4.3. 4.3 查看容器中进程的信息
    4. 4.4. 4.4 查看镜像的元数据
    5. 4.5. 4.5 进入当前正在运行的容器
    6. 4.6. 4.6 从容器内拷贝文件到主机上
  5. 5. 5.命令小结
  6. 6. 6. 小实战
    1. 6.1. 6.1 部署nginx
    2. 6.2. 6.2 部署tomcat
  7. 7. 7.提交镜像
  8. 8. 8.容器数据卷
    1. 8.1. 8.1 部署mysql
    2. 8.2. 8.2 具名挂载和匿名挂载
    3. 8.3. 8.3 权限
    4. 8.4. 8.4 多个容器挂载同一个目录
    5. 8.5. 8.5 Macos数据卷挂载目录
  9. 9. 9.Dockfile
    1. 9.1. 9.1 制作Dockefile
    2. 9.2. 9.2 Dockfile指令
      1. 9.2.1. 9.2.1 FROM
      2. 9.2.2. 9.2.2 RUN
      3. 9.2.3. 9.2.3 EXPOSE
      4. 9.2.4. 9.2.4 WORKDIR
      5. 9.2.5. 9.2.5 COPY
      6. 9.2.6. 9.2.6 ADD
      7. 9.2.7. 9.2.7 VOLUME
      8. 9.2.8. 9.2.8 EMV
      9. 9.2.9. 9.2.9 CMD
      10. 9.2.10. 9.2.10 ENTRYPOINT
      11. 9.2.11. 9.2.11 CMD|ENTRYPOINT区别
      12. 9.2.12. 9.2.12 HEALTHCHECK
      13. 9.2.13. 9.2.13 USER
    3. 9.3. 9.3 查看构建过程
    4. 9.4. 9.4 制作tomcat的Dockfile
    5. 9.5. 9.5 不同操作系统的镜像
      1. 9.5.1. 9.5.1 查看manifest列表
  10. 10. 10.发布自己的镜像
  11. 11. 11. Docker网络
    1. 11.1. 11.1 问题1:宿主机和容器能不能ping通? ✔
    2. 11.2. 11.2 问题2:两个容器直接能否直接ping通? ✔
    3. 11.3. 11.3 能否通过容器的name来连接? ×(–link ✔)
    4. 11.4. 11.4 自定义网络
    5. 11.5. 11.5 网络互联
    6. 11.6. 11.6 查看容器IP
      1. 11.6.1. 11.6.1 在容器内查看
      2. 11.6.2. 11.6.2 在容器外查看
      3. 11.6.3. 11.6.3 获取所有容器名称和IP
    7. 11.7. 11.7 Macos的网络问题
    8. 11.8. 11.8 查看端口映射配置
  12. 12. 12.Docker工具安装
    1. 12.0.1. 12.1 vim
    2. 12.0.2. 12.2 ping
    3. 12.0.3. 12.3 ifconfig
    4. 12.0.4. 12.4 yum
  • 13. 13.常用容器
    1. 13.1. 13.1 Mysql
    2. 13.2. 13.2 tomcat
  • 粵ICP备19091267号 © 2019 – 2022 Kim.Zhang | 629k | 9:32
    本站总访问量 4 次 | 有 309 人看我的博客啦 |
    博客全站共176.7k字
    载入天数...载入时分秒...
    0%