一、docker介绍
1,什么是虚拟化
虚拟化技术,就是在一个计算机系统中,虚拟出多个不同的系统,并正常运行和使用;
- 也就是说,我们vmware虚拟机,就是采用了虚拟化技术;
- 他能实现在一台windows主机中,创建多台、不同系统类型的计算机,供我们使用;
- docker你就可以简单理解为:linux系统中的vmware。
2,docker与vmware对比
· 必会关键词
| VMware | docker | 作用说明 |
|---|---|---|
| iso映像文件(系统的安装文件) | 镜像(image) | 就是不同系统的安装文件; |
| 虚拟主机(安装后启动的系统计算机) | 容器(container) | 就是运行起来的系统文件; |
| 计算机系统iso文件下载网站 | 镜像仓库(registry) | 就是下载系统文件的网站地址; |
· 虚拟化实现方法对比
| VMware | docker |
|---|---|
| 硬件级别虚拟化 | 软件系统级别虚拟化 |
3,为什么使用docker
· 业务隔离与资源充分利用
想象一个场景:
- 公司开始只有一个网站业务;
- 所以买了一台服务器,性能优越
- 128gb内存,32核心cpu,12TB磁盘;
- 但是,公司网站的用户体量特别小,性能只占用1核心1gb内存就够用;
- 随着公司业务的变化,公司又开了其他网站业务线
- 比如:java、python、php、nodejs等等都有涉及;
- 这一台机器足以满足所有业务线的需求,但是所有业务都部署在一台服务器中特别杂乱;
- 导致运维成本特别高,中间件特别多;
- 每次迭代其中一个业务,要联合其他所有部门配合;成本过高;
- 如果测试业务也加入:
- 这一台机器缺失能够满足需求,但是会导致业务耦合干扰特别严重;
- 如果再次购买另一台服务器,那么这一台的性能就不能充分利用;
- 增加无形的成本;

docker就可以解决这样的问题:
- 在一台机器上启动不同的子系统(容器);
- 每个系统中部署一台业务环境,进而实现资源隔离,提高运维、部署效率;

· 基础设施即服务
1,互联网业务类型
| 互联网业务类型 | 含义 | 比喻【盖房子】 |
|---|---|---|
| iaas | 基础设施即服务 | 水泥、砖头、搅拌机、瓷砖....... |
| paas | 功能即服务 | 盖好的一个单独的小房间; |
| saas | 软件即服务 | 改好的整个房子; |
2,docker服务能力
我们在部署一个网站的时候:
- 需要配合许多中间件的下载安装与配置;
- 这个过程对人的经验要求比较大而且一旦配置错误,排错跟需要技术经验;
- docker可以将:
- 配置好的中间件、网站业务代码,打包成镜像(image);
- 我们想要使用时,无需配置、或者无需配置中间件,直接将其拉起成容器(container)即可使用;免去配置成本;
- 一次配置终身可用;出现问题可以重新再次拉起,可以实现秒级重启,实现用户无感知;

· 学习环境准备
| 主机名 | ip地址 | |
|---|---|---|
| docker01 | 10.0.0.121 | |
| docker02 | 10.0.0.122 | |
| docker03 | 10.0.0.123 |
二、安装部署docker
1,下载docker
https://docs.docker.com

#点击【Manuals】
- 跳转后,找到二进制下载链接,点击进入;

#选择符合我们系统服务架构的安装包类型:
- 【x86_64】

#复制想要下载的版本链接;
- 案例中:我们选择【20.10.24】版本

#1,wget下载docker二进制安装包
[root@docker01 ~ 18:26:36]# wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.24.tgz
#2,查看
[root@docker01 ~ 18:28:16]# ll
...
-rw-r--r-- 1 root root 66990280 7月 12 2023 docker-20.10.24.tgz
2,安装部署docker
· 解压安装包
#解压安装包;
[root@docker01 ~ 18:28:19]# tar xf docker-20.10.24.tgz
[root@docker01 ~ 18:29:32]# ll
...
drwxrwxr-x 2 1000 1000 169 4月 5 2023 docker
-rw-r--r-- 1 root root 66990280 7月 12 2023 docker-20.10.24.tgz
#查看压缩包之下有什么?
[root@docker01 ~ 18:29:34]# ll docker
总用量 196944
-rwxr-xr-x 1 1000 1000 39451064 4月 5 2023 containerd
-rwxr-xr-x 1 1000 1000 7548928 4月 5 2023 containerd-shim
-rwxr-xr-x 1 1000 1000 9760768 4月 5 2023 containerd-shim-runc-v2
-rwxr-xr-x 1 1000 1000 21090304 4月 5 2023 ctr
-rwxr-xr-x 1 1000 1000 47955672 4月 5 2023 docker
-rwxr-xr-x 1 1000 1000 58246432 4月 5 2023 dockerd
-rwxr-xr-x 1 1000 1000 765808 4月 5 2023 docker-init
-rwxr-xr-x 1 1000 1000 2628514 4月 5 2023 docker-proxy
-rwxr-xr-x 1 1000 1000 14214624 4月 5 2023 runc
· 给docker文件管理员权限
[root@docker01 ~ 18:30:26]# chown root.root docker/*
[root@docker01 ~ 18:33:16]# ll docker
总用量 196944
-rwxr-xr-x 1 root root 39451064 4月 5 2023 containerd
-rwxr-xr-x 1 root root 7548928 4月 5 2023 containerd-shim
-rwxr-xr-x 1 root root 9760768 4月 5 2023 containerd-shim-runc-v2
-rwxr-xr-x 1 root root 21090304 4月 5 2023 ctr
-rwxr-xr-x 1 root root 47955672 4月 5 2023 docker
-rwxr-xr-x 1 root root 58246432 4月 5 2023 dockerd
-rwxr-xr-x 1 root root 765808 4月 5 2023 docker-init
-rwxr-xr-x 1 root root 2628514 4月 5 2023 docker-proxy
-rwxr-xr-x 1 root root 14214624 4月 5 2023 runc
· 将docker文件移动到PATH路径下
[root@docker01 ~ 18:33:18]# cp docker/* /usr/bin/
· Kylin系统需要删除自带runc
注意:只有kylin系统需要这样做!~
[root@docker01 ~ 18:35:32]# rm -rf /usr/local/bin/runc
· 配置Linux内核转发(内核转发:自己的网卡转为自己的另一种网卡)
[root@docker01 ~ 18:38:24]# echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
[root@docker01 ~ 18:39:08]# sysctl -p
......
net.ipv4.ip_forward = 1
· 启动docker测试(可以直接跳到,编辑systemd启动文件)
#1,启动docker
[root@docker01 ~ 18:39:10]# dockerd &
#2,查看是否有docker0网卡产生?
[root@docker01 ~ 18:40:08]# ip a
......
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:7f:4b:21:b2 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,配置systemd管理docker
· 杀死docker进程
[root@docker01 ~ 18:44:01]# ps -ef | grep -v grep | grep dockerd|awk '{print $2}'| xargs kill
· 编辑systemd启动文件
1,创建编辑启动文件
- ubuntu
[root@ceph01:~]# vim /lib/systemd/system/docker.service
- Centos/Kylin
[root@docker01 ~]# vim /usr/lib/systemd/system/docker.service
[Unit]
Description=bakwite docker
Documentation=https://www.bakwite.com
#启动docker时,需要什么程序已经准备好???(没启动成功也没关系)
After=network-online.target containerd.service
#如果这个程序没准备好,依旧可以启动docker
Wants=network-online.target
[Service]
Type=notify #systemd配置,表示,docker进程启动好running/active之后再进行下一步操作;
#服务启动时执行的命令
ExecStart=/usr/bin/dockerd
# 重启进程,$MAINPID表示docker的pid变量(systemd生成的)
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0 #docker停止时等待时间,0表示伊吾县等待其优雅停止,避免强制杀死
LimitNOFILE=infinity #不限制文件打开数
LimitNPROC=infinity #不限制系统进程打开数
[Install]
WantedBy=multi-user.target
2,设置开机自启动
[root@docker01 ~ 19:37:51]# systemctl enable --now docker.service
三、docker的命令文件
我们可以先查看下载的二进制安装包中有哪些文件
[root@docker01 ~ 18:33:16]# ll docker
总用量 196944
-rwxr-xr-x 1 root root 39451064 4月 5 2023 containerd
-rwxr-xr-x 1 root root 7548928 4月 5 2023 containerd-shim
-rwxr-xr-x 1 root root 9760768 4月 5 2023 containerd-shim-runc-v2
-rwxr-xr-x 1 root root 21090304 4月 5 2023 ctr
-rwxr-xr-x 1 root root 47955672 4月 5 2023 docker
-rwxr-xr-x 1 root root 58246432 4月 5 2023 dockerd
-rwxr-xr-x 1 root root 765808 4月 5 2023 docker-init
-rwxr-xr-x 1 root root 2628514 4月 5 2023 docker-proxy
-rwxr-xr-x 1 root root 14214624 4月 5 2023 runc

四、docker的家目录
[root@docker01 ~ 12:14:15]# ll /var/lib/docker/
总用量 0
drwx--x--x 4 root root 120 7月 2 18:40 buildkit
drwx--x--x 3 root root 20 7月 2 18:40 containerd
drwx--x--- 2 root root 6 7月 2 18:40 containers
drwx------ 3 root root 22 7月 2 18:40 image
drwxr-x--- 3 root root 19 7月 2 18:40 network
drwx--x--- 3 root root 40 7月 3 12:14 overlay2
drwx------ 4 root root 32 7月 2 18:40 plugins
drwx------ 2 root root 6 7月 3 12:14 runtimes
drwx------ 2 root root 6 7月 2 18:40 swarm
drwx------ 2 root root 6 7月 3 12:14 tmp
drwx------ 2 root root 6 7月 2 18:40 trust
drwx-----x 2 root root 50 7月 3 12:14 volumes
五、image镜像管理
1,拉取镜像
拉取镜像:就如同我们去下载iso映像文件一个意思;
docker如果不配置镜像仓库:
- 默认会前往docker官网的镜像仓库去下载(拉取)镜像文件;
- 由于“墙”的原因,我们需要配置成国内的下载地址;
· 镜像仓库配置
docker的主配置文件位置:/etc/docker/daemon.json
- 默认不存在,需要手动创建和编辑
- daemon.json文件中是json格式的代码文本;
- docker采用:【字典】嵌套的方式书写;
| daemon.json | 字段说明 |
|---|---|
| { | |
| "registry-mirrors" : [ "https://仓库地址" , "https://仓库地址".... ] | 表示【安全的仓库地址】配置; |
| "insecure-registries" : ["http://仓库地址","https://仓库地址"....] | 表示【不安全的仓库地址】配置,私有仓库 自签名证书的地址,或者没有证书的地址 |
| "log-opts": { "max-size": "10m", "max-file": "3" } | 容器日志设置: /var/lib/docker/containers/<容器ID>/<容器ID>-json.log 【max-size】单个日志文件最大10MB 【max-file】保留3个历史日志文件(滚动删除) |
| "data-root": "/var/lib/docker" | 指定docker的家目录,不指定默认就是:/var/lib/docker |
| "bip": "172.10.0.1/16" | 指定容器默认的bridge类型的网关地址(自动识别网段); |
| } |
#1,设置国内的仓库地址
[root@harbor ~ ]# mkdir /etc/docker/
[root@harbor /tools/harbor ]# vim /etc/docker/daemon.json
{
"registry-mirrors" : [
"https://docker.m.daocloud.io",
"https://k8s.m.daocloud.io"
]
}
#2,设置后,重启docker生效
[root@docker01 ~ 13:28:31]# systemctl restart docker.service
· 开始拉取镜像
1,拉取一个alpine镜像
#1,拉取一个alpine镜像
[root@docker01 ~ 13:49:26]# docker pull alpine
#2,查看本地镜像列表
[root@docker01 ~ 13:53:46]# docker image ls
或者
[root@docker01 ~ 13:53:39]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest cea2ff433c61 4 weeks ago 8.31MB
2,拉取一个nginx镜像
#1,拉取一个nginx1.20.1版本的alpine系统的镜像
[root@docker01 ~ 13:53:49]# docker pull nginx:1.20.1-alpine
[root@docker01 ~ 13:56:51]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest cea2ff433c61 4 weeks ago 8.31MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
nginx stable f6422896ca84 2 months ago 192MB
3,拉取一个nginx稳定版镜像
[root@docker01 ~ 14:37:52]# docker pull nginx:stable
[root@docker01 ~ 13:56:51]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest cea2ff433c61 4 weeks ago 8.31MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
nginx stable f6422896ca84 2 months ago 192MB
4,拉取一个ubuntu22.04镜像
[root@docker01 ~ 13:56:54]# docker pull ubuntu:22.04
[root@docker01 ~ 13:59:40]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 1b668a2d748d 12 days ago 77.9MB
alpine latest cea2ff433c61 4 weeks ago 8.31MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
nginx stable f6422896ca84 2 months ago 192MB
5,拉取一个centos镜像
[root@docker01 ~ 13:59:44]# docker pull centos:7
[root@docker01 ~ 14:02:41]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 1b668a2d748d 12 days ago 77.9MB
alpine latest cea2ff433c61 4 weeks ago 8.31MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
6,拉取一个php镜像
[root@docker01 ~ 14:03:16]# docker pull php:7.4
[root@docker01 ~ 14:10:14]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 1b668a2d748d 12 days ago 77.9MB
alpine latest cea2ff433c61 4 weeks ago 8.31MB
php 7.4 7bbbb12d1498 2 years ago 474MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
nginx stable f6422896ca84 2 months ago 192MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
7,拉取一个tomcat镜像
[root@docker01 ~ 14:03:16]# docker pull tomcat:9
[root@docker01 ~ 14:10:14]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat 9 1775987f0c24 3 weeks ago 470MB
ubuntu 22.04 1b668a2d748d 12 days ago 77.9MB
alpine latest cea2ff433c61 4 weeks ago 8.31MB
php 7.4 7bbbb12d1498 2 years ago 474MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
nginx stable f6422896ca84 2 months ago 192MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
· docker镜像说明
1,镜像的组成
#基础系统:就是这个子系统是什么类型的;
#依赖服务:子系统中运行起来后自带什么软件服务?
#业务代码:书写的代码,打包到镜像中,就是:nginx的代码目录下的代码;
#环境变量:如果镜像运行起来(容器),要使用的变量参数;
#启动命令:镜像的核心启动命令;
- 想要镜像能够启动成容器,就必须要有在宿主机上一直运行的命令作为守护进程;
- 如果没有运行的命令,那么容器将立刻关闭;

2,镜像的标签说明
| REPOSITORY | TAG | IMAGE ID | CREATED | SIZE |
|---|---|---|---|---|
| 镜像名称 | 标签信息 | 镜像的ID | 镜像创建的时间 | 镜像的文件大小 |
[root@docker01 ~]# docker images
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
alpine:latest 28bd5fe8b56d 13MB 3.93MB
centos:7 be65f488b776 301MB 76.1MB
nginx:1.20.1-alpine b92d3b942c8b 36.8MB 9.88MB
nginx:stable 5cf90903deda 240MB 66MB
php:7.4 620a6b9f4d4f 668MB 166MB
tomcat:9 fb9ee094c9c3 602MB 160MB
ubuntu:22.04 0e0a0fc6d18f 119MB 31.7MB
| 标签 | 解释说明 |
|---|---|
| 22.04 | 表示拉取镜像【主体】的具体版本(名称是系统,就是系统的版本,名称是服务,就是服务的版本) |
| 1.20.1-alpine | 表示拉取镜像【主体】的具体版本,和系统类型(alpine是linux最小化版本类型); |
| stable | 表示【最新的稳定版】 |
| latest | 表示【最新的版本】 |
3,镜像的系统类型
| 系统类型 | 说明 |
|---|---|
| ubuntu | |
| centos | 占用磁盘空间最大 |
| alpine | 占用磁盘空间最小,使用率最高; |
| ...... |
2,查看本地镜像
· 查看本地镜像列表
#1,查看本地镜像列表
[root@docker01 ~ 14:42:44]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 1b668a2d748d 12 days ago 77.9MB
alpine latest cea2ff433c61 4 weeks ago 8.31MB
nginx stable f6422896ca84 2 months ago 192MB
php 7.4 7bbbb12d1498 2 years ago 474MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
#2,简写
[root@docker01 ~ 14:42:44]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 1b668a2d748d 12 days ago 77.9MB
alpine latest cea2ff433c61 4 weeks ago 8.31MB
nginx stable f6422896ca84 2 months ago 192MB
php 7.4 7bbbb12d1498 2 years ago 474MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
· 查看隐藏的镜像
[root@docker01 ~ 14:52:03]# docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 1b668a2d748d 12 days ago 77.9MB
alpine latest cea2ff433c61 4 weeks ago 8.31MB
nginx stable f6422896ca84 2 months ago 192MB
php 7.4 7bbbb12d1498 2 years ago 474MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
· 获取所有镜像的id
[root@docker01 ~ 16:52:30]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 1b668a2d748d 12 days ago 77.9MB
alpine latest cea2ff433c61 4 weeks ago 8.31MB
nginx stable f6422896ca84 2 months ago 192MB
php 7.4 7bbbb12d1498 2 years ago 474MB
php 7.4.0 7bbbb12d1498 2 years ago 474MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
#获取所有镜像的ID
[root@docker01 ~ 16:58:14]# docker images -q
1b668a2d748d
cea2ff433c61
f6422896ca84
7bbbb12d1498
7bbbb12d1498
7f18bdc92ca5
eeb6ee3f44bd
3,保存镜像为压缩包
[root@docker01 ~ 16:35:22]# docker save ubuntu:22.04 > ubuntu:22.04.tar
[root@docker01 ~ 16:38:45]# docker save alpine:latest > alpine:latest.tar
[root@docker01 ~ 16:39:47]# docker save php:7.4 -o php:7.4.tar
[root@docker01 ~ 16:40:16]# docker save nginx:stable -o nginx:stable.tar
[root@docker01 ~ 16:40:27]# ll
总用量 749848
-rw-r--r-- 1 root root 8602112 7月 3 16:38 alpine:latest.tar
-rw-r--r-- 1 root root 196640256 7月 3 16:39 nginx:stable.tar
-rw-r--r-- 1 root root 482165248 7月 3 16:40 php:7.4.tar
-rw-r--r-- 1 root root 80425984 7月 3 16:35 ubuntu:22.04.tar
4,删除镜像
| 命令 | 参数 | 含义 |
|---|---|---|
| docker image | rm | 删除镜像【可以简写为:docker rmi】 |
| rm -f | 强制删除镜像 | |
| prune -f | 【清理镜像】删除没用的镜像(-f 免交互); |
· 通过镜像名称删除
[root@docker01 ~ 16:52:30]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 1b668a2d748d 12 days ago 77.9MB
alpine latest cea2ff433c61 4 weeks ago 8.31MB
nginx stable f6422896ca84 2 months ago 192MB
php 7.4 7bbbb12d1498 2 years ago 474MB
php 7.4.0 7bbbb12d1498 2 years ago 474MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
[root@docker01 ~ 16:41:13]# docker image rm ubuntu:22.04
[root@docker01 ~ 16:41:59]# docker image rm alpine:latest
· 通过镜像id删除
[root@docker01 ~ 16:42:10]# docker image rm f6422896ca84
[root@docker01 ~ 16:42:22]# docker image rm 7bbbb12d1498
[root@docker01 ~ 16:42:34]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
5,导入镜像压缩包为镜像
[root@docker01 ~ 16:43:55]# docker load < alpine\:latest.tar
[root@docker01 ~ 16:44:05]# docker load < nginx\:stable.tar
[root@docker01 ~ 16:44:12]# docker load -i php\:7.4.tar
[root@docker01 ~ 16:44:23]# docker load -i ubuntu\:22.04.tar
[root@docker01 ~ 16:44:31]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 1b668a2d748d 12 days ago 77.9MB
alpine latest cea2ff433c61 4 weeks ago 8.31MB
nginx stable f6422896ca84 2 months ago 192MB
php 7.4 7bbbb12d1498 2 years ago 474MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
6,给镜像打标签
本质上就是在复制出一个镜像,并改名;
#复制镜像php:7.4,改个名字为:php:7.4.0
[root@docker01 ~ 16:44:56]# docker tag php:7.4 php:7.4.0
#查看镜像列表
[root@docker01 ~ 16:52:27]# docker images
...
php 7.4 7bbbb12d1498 2 years ago 474MB
php 7.4.0 7bbbb12d1498 2 years ago 474MB
...
7,案例练习
· 导出所有镜像
[root@docker01 ~ 17:02:33]# for i in `docker images | awk 'NR != 1{print $1}'`;do docker save $i > $i.tar ;done
[root@docker01 ~ 17:02:55]# ll
总用量 1451156
-rw-r--r-- 1 root root 8602112 7月 3 17:02 alpine:latest.tar
-rw-r--r-- 1 root root 211696640 7月 3 17:02 centos:7.tar
-rw-r--r-- 1 root root 24271872 7月 3 17:02 nginx:1.20.1-alpine.tar
-rw-r--r-- 1 root root 196640256 7月 3 17:02 nginx:stable.tar
-rw-r--r-- 1 root root 482165248 7月 3 17:02 php:7.4.0.tar
-rw-r--r-- 1 root root 482165248 7月 3 17:02 php:7.4.tar
-rw-r--r-- 1 root root 80425984 7月 3 17:02 ubuntu:22.04.tar
· 删除所有镜像
[root@docker01 ~ 17:06:44]# docker image rm -f `docker images -q`
[root@docker01 ~ 17:06:34]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
· 批量导入镜像
[root@docker01 ~ 17:09:29]# for i in `ls`; do docker load < $i;done
[root@docker01 ~ 17:11:30]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 22.04 1b668a2d748d 12 days ago 77.9MB
alpine latest cea2ff433c61 4 weeks ago 8.31MB
nginx stable f6422896ca84 2 months ago 192MB
php 7.4 7bbbb12d1498 2 years ago 474MB
php 7.4.0 7bbbb12d1498 2 years ago 474MB
nginx 1.20.1-alpine 7f18bdc92ca5 3 years ago 22.7MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
六、容器管理
1,创建容器create(不启动)
create创建的容器,是关闭状态的容器;
- 就类似于一个关机的电脑;
- 镜像是一个启动U盘;
- create创建容器,就是安装完系统并关机;
#1,使用nginx:stable镜像,创建一个容器(子系统),名称为:web01
[root@docker01 ~ 17:22:15]# docker create --name web01 nginx:stable
#2,查看容器列表(默认只显示启动状态的)
[root@docker01 ~ 17:22:19]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
#3,查看容器列表(-a,表示显示所有,包括启动和不启动的)
[root@docker01 ~ 17:22:28]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b44b18490de3 nginx:stable "/docker-entrypoint.…" 16 seconds ago Created web01
2,启动容器start(开机)
[root@docker01 ~ 17:22:31]# docker start web01
web01
[root@docker01 ~ 17:26:17]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b44b18490de3 nginx:stable "/docker-entrypoint.…" 4 minutes ago Up 6 seconds 80/tcp web01
3,重启容器restart(重启)
[root@docker01 ~ 12:49:32]# docker restart web01
web01
[root@docker01 ~ 12:56:12]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b44b18490de3 nginx:stable "/docker-entrypoint.…" 20 hours ago Up 3 seconds 80/tcp web01
4,停止容器stop(关机)
[root@docker01 ~ 12:46:10]# docker stop web01
web01

5,查看容器ps
· 查看容器参数
| 命令 | 参数 | 解释说明 |
|---|---|---|
| docker | ps | 查看正在运行的容器列表 |
| -a | 查看所有(all)容器的列表; | |
| -l | 查看最新最近创建的容器; | |
| -q | 只显示容器的ID; | |
| -s | 显示容器的大小size |
· 查看容器说明
| CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORT | NAMES |
|---|---|---|---|---|---|---|
| 容器的ID | 启动容器所用的镜像 | 容器进程守护命令 | 容器创建时间 | 容器状态 | 容器开启的端口 | 容器名称 |
#1,查看正在运行的容器
[root@docker01 ~ 17:38:14]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b44b18490de3 nginx:stable "/docker-entrypoint.…" 16 minutes ago Up 12 minutes 80/tcp web01
#2,查看最新创建的容器
[root@docker01 ~ 17:38:17]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b44b18490de3 nginx:stable "/docker-entrypoint.…" 16 minutes ago Up 12 minutes 80/tcp web01
#3,查看所有容器(-a:ALL,启动+未启动)
[root@docker01 ~ 17:38:19]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b44b18490de3 nginx:stable "/docker-entrypoint.…" 16 minutes ago Up 12 minutes 80/tcp web01
#4,查看容器,并显示容器的大小
[root@docker01 ~ 17:38:19]# docker ps -s
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE
b44b18490de3 nginx:stable "/docker-…" 16 minutes ago Up 12 minutes 80/tcp web01 200M
#5,查询容器只显示容器的id
[root@docker01 ~ 17:42:01]# docker ps -q
b44b18490de3
#6,查询最新创建容器的id
[root@docker01 ~ 17:43:09]# docker ps -lq
b44b18490de3
# 查看容器的长格式
[root@docker01 ubuntu]# docker ps --no-trunc

6,查看容器的详细信息inspect
· 查看容器的详细信息
[root@docker01 ~ 17:26:23]# docker inspect web01
[
{
"Id": "b44b18490de3a0284168f3abddf9feb39a8fe8adf9b29a7f4c9aec280cc08cbc",
"Created": "2025-07-03T09:22:15.611126472Z",
"Path": "/docker-entrypoint.sh",
"Args": [
"nginx",
"-g",
"daemon off;"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 61798,
"ExitCode": 0,
"Error": "",
"StartedAt": "2025-07-03T09:26:17.654045664Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:f6422896ca84c9af48d5417d6b7a573bf6b38f81edc15538907d987fc658d909",
"ResolvConfPath": "/var/lib/docker/containers/b44b18490de3a0284168f3abddf9feb39a8fe8adf9b29a7f4c9aec280cc08cbc/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/b44b18490de3a0284168f3abddf9feb39a8fe8adf9b29a7f4c9aec280cc08cbc/hostname",
"HostsPath": "/var/lib/docker/containers/b44b18490de3a0284168f3abddf9feb39a8fe8adf9b29a7f4c9aec280cc08cbc/hosts",
"LogPath": "/var/lib/docker/containers/b44b18490de3a0284168f3abddf9feb39a8fe8adf9b29a7f4c9aec280cc08cbc/b44b18490de3a0284168f3abddf9feb39a8fe8adf9b29a7f4c9aec280cc08cbc-json.log",
"Name": "/web01",
"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/26e0f6c80669acf4367f323a37b7feae848389529b59e261d631b87f23f11a6c-init/diff:/var/lib/docker/overlay2/2b643a67e9721a11eb412425de4a407ecda1f689102e0887024685d478fb1852/diff:/var/lib/docker/overlay2/3ccd12724592eae9208f230c868d7196335b6424f565ae3a802a27232e47d118/diff:/var/lib/docker/overlay2/e30bfbcd917ca40cce9e10942a151e89e761dfd1095c9521f48fad155ff1a834/diff:/var/lib/docker/overlay2/fe20ff9b7ccc302a3b0cf582c08d4f23b5d6c4337c0a968ce3fec52fb3b266f8/diff:/var/lib/docker/overlay2/351affd00839f86d0ec180b59254222200f53e9a98f23d8f6bf30eb8a75e45d0/diff:/var/lib/docker/overlay2/1a6a23135a739ad79313fdd1f17ed4a1943a9dc5352174a0ed965ea06149bfab/diff:/var/lib/docker/overlay2/567252a414be61e82c04b40589bf4e7a33496bade3a6c449a4ab2bbd9383dfa2/diff",
"MergedDir": "/var/lib/docker/overlay2/26e0f6c80669acf4367f323a37b7feae848389529b59e261d631b87f23f11a6c/merged",
"UpperDir": "/var/lib/docker/overlay2/26e0f6c80669acf4367f323a37b7feae848389529b59e261d631b87f23f11a6c/diff",
"WorkDir": "/var/lib/docker/overlay2/26e0f6c80669acf4367f323a37b7feae848389529b59e261d631b87f23f11a6c/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "b44b18490de3",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": true,
"AttachStderr": true,
"ExposedPorts": {
"80/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NGINX_VERSION=1.28.0",
"NJS_VERSION=0.8.10",
"NJS_RELEASE=1~bookworm",
"PKG_RELEASE=1~bookworm",
"DYNPKG_RELEASE=1~bookworm"
],
"Cmd": [
"nginx",
"-g",
"daemon off;"
],
"Image": "nginx:stable",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
},
"StopSignal": "SIGQUIT"
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "0b2584a9853c9fd3be3ac579a7ae8babd367fbac7514c5aced58fc4340a49d40",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"80/tcp": null
},
"SandboxKey": "/var/run/docker/netns/0b2584a9853c",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "6f376697e8b0c13efab0939bc58c7b75002549d264c9f2a7f40fae9f7f3abcc4",
"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": "8168954c20e840a6bdf5ec27f7045ac4a68c4ced82bbd24cf3aeccc1a49cad71",
"EndpointID": "6f376697e8b0c13efab0939bc58c7b75002549d264c9f2a7f40fae9f7f3abcc4",
"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
}
}
}
}
]
· 过滤容器的IP地址
1,-f参数获取
[root@docker01 ~ 12:26:07]# docker inspect -f {{.NetworkSettings.Networks.bridge.IPAddress}} web01
172.17.0.2
2,三剑客获取
#获取容器的ip地址
[root@docker01 ~ 12:32:41]# docker inspect web01 |grep "\"IPAddress"\" |awk -F"[ :\"]+" 'NR==1{print $3}'
172.17.0.2
#获取最新创建的容器的ip地址
[root@docker01 ~ 12:32:41]# docker inspect `docker ps -lq` |grep "\"IPAddress"\" |awk -F"[ :\"]+" 'NR==1{print $3}'
172.17.0.2
7,运行容器run(创建+启动)
| 命令 | 参数 | 解释说明 |
|---|---|---|
| docker | run | 运行一个容器(就是create+start的组合使用) |
| -d | 表示后台运行容器; | |
| --name | 自定义容器名称; | |
| -i | stdin标准输入,进入交互模式(操作容器) | |
| -t | tty,分配一个终端; | |
| -p | 宿主机与容器做NAT端口映射 | |
| -exec | 在容器中运行一个命令,传入进去执行; | |
| -m --memory-swap |
限制内存使用:-m 209715200 限制swap使用:--memory-swap 209715200 当系统有swap的时候,这两个参数要一起使用 注意:设置必须是字节为单位 |
|
· 运行一个容器
提示:
- 当本地有这个镜像的时候,会直接使用本地的镜像;
- 当本地没有这个镜像的时候,docker会去远程仓库先拉取镜像,拉取完再运行;
#1,运行容器
[root@docker01 ~ 12:32:49]# docker run --name web02 nginx:stable
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2025/07/04 04:43:54 [notice] 1#1: using the "epoll" event method
2025/07/04 04:43:54 [notice] 1#1: nginx/1.28.0
2025/07/04 04:43:54 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
2025/07/04 04:43:54 [notice] 1#1: OS: Linux 4.19.90-52.22.v2207.ky10.x86_64
2025/07/04 04:43:54 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 524288:524288
2025/07/04 04:43:54 [notice] 1#1: start worker processes
2025/07/04 04:43:54 [notice] 1#1: start worker process 29
2025/07/04 04:43:54 [notice] 1#1: start worker process 30
#2,运行后,发现终端被占用,Ctrl + c 退出;
#3,查看容器列表
[root@docker01 ~ 12:46:06]# docker ps -a

· 后台运行容器
[root@docker01 ~ 12:56:15]# docker run -d --name web03 nginx:stable
ee0bc2f7c9d9e3f8eeb39bb488cdfab4e29835c36ba98c2c053a2efc168f267f
[root@docker01 ~ 12:57:57]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ee0bc2f7c9d9 nginx:stable "/docker-entrypoint.…" 5 seconds ago Up 5 seconds 80/tcp web03
b44b18490de3 nginx:stable "/docker-entrypoint.…" 20 hours ago Up About a minute 80/tcp web01
· 运行容器进入交互模式
-i 表示stdin 标准输入;
[root@docker01 ~ 13:06:21]# docker run -i --name web09 alpine:latest
ls
bin
dev
etc
home
lib
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
pwd
/
· 运行容器分配终端交互
-t 表示tty
#1,运行容器,并-it,进入交互模式,分配一个终端用来用户操作;
[root@docker01 ~ 13:07:16]# docker run -it --name web10 alpine:latest
/ # ls
bin dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
/ # pwd
/
/ #
#2,运行容器,进入交互模式,指定一个终端类型【/bin/bash或者/bin/sh】
[root@docker01 ~ 13:07:16]# docker run -it --name web10 alpine:latest /bin/sh
/ # ls
bin dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
· 容器的守护进程
进程分类回顾:
| 进程分类 | 解释说明 |
|---|---|
| 普通进程 | 运行完就结束; |
| 守护进程 | 运行完不结束,等待下一个任务进来继续执行; |
1,运行两个容器
运行alpine与nginx两个进程,运行后发现,一个是up状态,另一个是退出状态:
- 原因:容器中只要没有进程继续运行,就会自动退出;
- 查看ps列表,看COMMAND字段下:
- nginx镜像中:设置了启动就运行一个守护进程命令,所以他会一直运行;
- 而alpine镜像中:设置了一个/bin/sh的进程命令,你不使用就会退出;
#1,运行两个容器,一个nginx、另一个alpine
[root@docker01 ~ 13:17:08]# docker run -d --name web01 nginx:stable
[root@docker01 ~ 13:17:08]# docker run -d --name web02 alpine:latest
#2,查看容器列表
[root@docker01 ~ 13:17:08]# docker ps -a

2,设置守护进程
#给alpine分配一个终端,然后后台运行,只要终端不退出,就是类似守护进程的功能了;
[root@docker01 ~ 13:18:53]# docker run -itd --name web03 alpine:latest
#进入守护进程的系统操作
[root@docker01 ~ 13:18:53]# docker exec -it web03 /bin/bash
#再次查看容器列表,他就一直运行了
[root@docker01 ~ 13:26:43]# docker ps

· 宿主机与容器NAT端口映射
1,访问web01
我们访问nginx的容器:
- 宿主机curl模拟访问:发现访问成功
- 宿主机浏览器访问:访问失败;
- 原因:
- 容器是你宿主机下的局域网,就如同NAT模式下的VMware中的虚拟机一样;
- 默认是无法访问外网的;
#1,找到容器IP
[root@docker01 ~ 13:30:33]# docker inspect web01 | grep "IPAddress"
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.2",
"IPAddress": "172.17.0.2",
#2,curl访问,你会发现访问成功到nginx页面
[root@docker01 ~ 13:30:35]# curl 172.17.0.2
<!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>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
2,-p容器NAT端口映射
我们将宿主机开一个端口,映射到容器的nginx端口行,这样一来,就能够实现外网访问容器了;

[root@docker01 ~ 13:38:26]# docker run -d -p 80:80 --name web04 nginx:stable
bcea99b83149defe8af1f61ffc73d58b411404edde07b329d521f2bc53178653

3,容器端口映射原理
docker的端口映射:采用了linux的iptables端口转发功能;
[root@docker01 ~ 11:44:58]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
MASQUERADE tcp -- 172.17.0.2 172.17.0.2 tcp dpt:80
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80

4,-P随机端口映射
[root@docker01 ubuntu]# docker run -d -P --name v1 nginx:stable
353376397de42356faed79407e4c33bec44ea5884b54022e43c77304a28f8500
[root@docker01 ubuntu]# docker ps
CONTAINER ID IMAGE COMMAND PORTS NAMES
353376397de4 nginx:stable "/docker-.…" 0.0.0.0:32768->80/tcp, :::32768->80/tcp v1
# 查看宿主机端口,发现随机开启了一个端口,映射了容器暴露的端口
[root@docker01 ubuntu]# netstat -tnulp
......
tcp 0 0 0.0.0.0:32768 0.0.0.0:* LISTEN 1124306/docker-prox
· 运行容器限制资源使用
| docker run | 解释说明 |
|---|---|
| --cpus=1.5 | 限制cpu最多使用1.5核心 |
| --memory=2G | 限制内存最大使用量 |
| --memory-reservation 1G | 内存软限制为1GB,当系统紧张时,容器会被压缩至1GB以下。 |
| --pids-limit 200 | 限制整个容器进程最大数量 |
| --ulimit nproc=1024:1024 | 限制单个用户创建的最大进程数【软限制:硬限制】 |
| --ulimit nofile=8192:16384 | 文件最大描述符【软限制:硬限制】 |
注意:限制内存的使用,只能使用字节为单位进行设置!
[root@docker01 ~ 17:14:46]# docker run -d \
--name c1 \
--pids-limit 200 \
--cpus 1.5 \
--memory 2G \
--memory-reservation 1G \
--ulimit nproc=1024:1024 \
--ulimit nofile=8192:16384 \
nginx:1.20.1-alpine
#2,查看容器资源使用状态
[root@docker01 ~ 17:14:46]# docker stats --no-stream
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
d5537aa21bf4 web06 0.00% 2.449MiB / 200MiB 1.22% 796B / 0B 4.1kB / 7.17kB 3
8,exec已运行容器中执行命令
· 容器外执行命令
[root@docker01 ~ 13:38:45]# docker exec web04 ls -l
total 4
lrwxrwxrwx 1 root root 7 Jun 30 00:00 bin -> usr/bin
drwxr-xr-x 2 root root 6 May 9 14:50 boot
drwxr-xr-x 5 root root 340 Jul 4 05:38 dev
drwxr-xr-x 1 root root 41 Jul 1 02:12 docker-entrypoint.d
-rwxr-xr-x 1 root root 1620 Jul 1 02:12 docker-entrypoint.sh
drwxr-xr-x 1 root root 19 Jul 4 05:38 etc
drwxr-xr-x 2 root root 6 May 9 14:50 home
lrwxrwxrwx 1 root root 7 Jun 30 00:00 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Jun 30 00:00 lib64 -> usr/lib64
drwxr-xr-x 2 root root 6 Jun 30 00:00 media
drwxr-xr-x 2 root root 6 Jun 30 00:00 mnt
drwxr-xr-x 2 root root 6 Jun 30 00:00 opt
dr-xr-xr-x 230 root root 0 Jul 4 05:38 proc
drwx------ 2 root root 37 Jun 30 00:00 root
drwxr-xr-x 1 root root 23 Jul 4 05:38 run
lrwxrwxrwx 1 root root 8 Jun 30 00:00 sbin -> usr/sbin
drwxr-xr-x 2 root root 6 Jun 30 00:00 srv
dr-xr-xr-x 14 root root 0 Jul 4 05:38 sys
drwxrwxrwt 2 root root 6 Jun 30 00:00 tmp
drwxr-xr-x 1 root root 66 Jun 30 00:00 usr
drwxr-xr-x 1 root root 19 Jun 30 00:00 var
# 查看容器的ip地址
[root@docker01 ~]# docker exec web04 hostname -I
172.17.0.2
· 进入容器
[root@docker01 ~ 13:53:48]# docker exec -it web04 /bin/sh
# echo "bakwite" > /usr/share/nginx/html/index.html
#

· 进入容器并指定进入目录
[root@docker01 ubuntu]# docker exec -it -w /usr/share/nginx/html/ v1 bash
root@afc5ab552406:/usr/share/nginx/html# pwd
/usr/share/nginx/html
9,cp宿主机与容器复制文件
· 宿主机复制到容器
#1,创建一个文件
[root@docker01 ~ 13:59:59]# echo "<h1>www.bakwite.com<h1>" > index.html
#2,将这个文件复制到容器的代码目录
[root@docker01 ~ 14:00:54]# docker cp index.html web04:/usr/share/nginx/html/
#3,浏览器访问

· 容器复制到宿主机
#将容器中的日志文件复制到宿主机
[root@docker01 ~ 14:03:50]# docker cp web04:/var/log/nginx/error.log ./
[root@docker01 ~ 14:03:50]# docker cp web04:/var/log/nginx/access.log ./
[root@docker01 ~ 14:03:55]# ll
总用量 1451160
lrwxrwxrwx 1 root root 11 7月 1 10:12 access.log -> /dev/stdout
lrwxrwxrwx 1 root root 11 7月 1 10:12 error.log -> /dev/stderr
-rw-r--r-- 1 root root 27 7月 4 14:00 index.html
10,log查看容器的日志
· 查看容器日志
[root@docker01 ~ 14:07:24]# docker logs web04
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2025/07/04 05:38:45 [notice] 1#1: using the "epoll" event method
2025/07/04 05:38:45 [notice] 1#1: nginx/1.28.0
2025/07/04 05:38:45 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
2025/07/04 05:38:45 [notice] 1#1: OS: Linux 4.19.90-52.22.v2207.ky10.x86_64
2025/07/04 05:38:45 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 524288:524288
2025/07/04 05:38:45 [notice] 1#1: start worker processes
2025/07/04 05:38:45 [notice] 1#1: start worker process 29
2025/07/04 05:38:45 [notice] 1#1: start worker process 30
10.0.0.1 - - [04/Jul/2025:05:39:03 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
2025/07/04 05:39:04 [error] 29#29: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 10.0.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "10.0.0.91", referrer: "http://10.0.0.91/"
10.0.0.1 - - [04/Jul/2025:05:39:04 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://10.0.0.91/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
10.0.0.1 - - [04/Jul/2025:05:53:12 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
10.0.0.1 - - [04/Jul/2025:05:53:13 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
10.0.0.1 - - [04/Jul/2025:05:53:13 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
· -f监控查看日志
跟随日志变化,与linux中的tail -f一个意思
[root@docker01 ~ 14:07:24]# docker logs -f web04
· -n查看日志的后几行
[root@docker01 ~ 14:10:15]# docker logs -n 5 web04
10.0.0.1 - - [04/Jul/2025:06:09:34 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
10.0.0.1 - - [04/Jul/2025:06:09:34 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
10.0.0.1 - - [04/Jul/2025:06:09:34 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
10.0.0.1 - - [04/Jul/2025:06:09:35 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
10.0.0.1 - - [04/Jul/2025:06:09:35 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
· 根据时间查看日志
1,--until查看之前的日志
#查看5分钟之前的日志【m:分,h小时】
[root@docker01 ~ 14:12:54]# docker logs --until 5m web04
2,--since查看最近的日志
#查看10分钟之内的日志
[root@docker01 ~ 14:15:29]# docker logs --since 10m web04
10.0.0.1 - - [04/Jul/2025:06:09:32 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" "-"
10.0.0.1 - - [04/Jul/2025:06:09:32 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64;
11,top查看容器中进程
[root@docker01 ~ 14:19:27]# docker top web04

12,kill杀死容器
强制停止容器运行:
- kill与stop停止的区别:
- kill是强制停止;
- stop是温柔的停止;
[root@docker01 ~ 14:19:30]# docker kill web04
web04

13,删除容器rm
· 删除未运行的容器
[root@docker01 ~ 14:27:37]# docker rm web04
web04
· 删除正在运行的容器
#1,普通删除,无法删除正在运行的容器
[root@docker01 ~ 14:28:53]# docker rm web03
Error response from daemon: You cannot remove a running container 8963a87abc70dbbe3f48b355e557fc48a56b7a9d339309b836e8b429041a7740. Stop the container before attempting removal or force remove
#2,-f强制删除,可以删除正在运行的容器
[root@docker01 ~ 14:28:57]# docker rm -f web03
web03
14,port查看容器端口信息
[root@docker01 ~ 14:39:42]# docker port web03
80/tcp -> 0.0.0.0:80
80/tcp -> :::80
15,容器重命名rename
[root@docker01 ~ 16:54:38]# docker rename web03 web05
16,stats查看容器使用状态
· 动态查看容器的状态
#1,不指定容器名,会查看所有容器
[root@docker01 ~ 16:58:40]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
7f5f09d272cf web05 0.00% 2.461MiB / 1.91GiB 0.13% 1.22kB / 0B 4.1kB / 6.66kB 3
4512077f5966 web01 0.00% 2.562MiB / 1.91GiB 0.13% 2.6kB / 1.27kB 762kB / 6.66kB 3
#2,指定容器名查看状态
[root@docker01 ~ 16:57:09]# docker stats web01
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
4512077f5966 web01 0.00% 2.562MiB / 1.91GiB 0.13% 2.6kB / 1.27kB 762kB / 6.66kB 3
· 静态查看所有容器状态
[root@docker01 ~ 16:59:49]# docker stats --no-stream
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
7f5f09d272cf web05 0.00% 2.461MiB / 1.91GiB 0.13% 1.29kB / 0B 4.1kB / 6.66kB 3
4512077f5966 web01 0.00% 2.562MiB / 1.91GiB 0.13% 2.6kB / 1.27kB 762kB / 6.66kB 3
17,挂起/暂停与恢复容器
· pause挂起容器
[root@docker01 ~ 17:02:37]# docker pause web01
web01
[root@docker01 ~ 17:02:32]# docker ps

· unpause恢复挂起容器
[root@docker01 ~ 17:02:37]# docker unpause web01
web01
[root@docker01 ~ 17:02:32]# docker ps

18,update更新容器的硬件资源
容器默认可以使用系统所有的资源;
- 处于安全考虑,我们可以限制其资源的使用上限;
· 查看目前资源情况
[root@docker01 ~ 17:07:30]# docker stats --no-stream
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
7f5f09d272cf web05 0.00% 2.461MiB / 1.91GiB 0.13% 1.29kB / 0B 4.1kB / 6.66kB 3
4512077f5966 web01 0.00% 2.566MiB / 1.91GiB 0.13% 2.6kB / 1.27kB 762kB / 6.66kB 3
· update修改容器资源上限
修改为:内存上线为200m;
注意:限制内存的使用,只能使用字节为单位进行设置!
[root@docker01 ~ 17:07:38]# docker update -m 209715200 --memory-swap 209715200 web01
web01
[root@docker01 ~ 17:08:57]# docker stats --no-stream
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
7f5f09d272cf web05 0.00% 2.461MiB / 1.91GiB 0.13% 1.29kB / 0B 4.1kB / 6.66kB 3
4512077f5966 web01 0.00% 2.566MiB / 200MiB 1.28% 2.6kB / 1.27kB 762kB / 6.66kB 3
19,commit将容器保存为镜像
[root@docker01 ~ 17:16:58]# docker commit web01 web01:v1.0
sha256:ec969d114ff2c3fd6811bf13283eca9ca1fd59b12b7e28bbea7598cb82c914aa
[root@docker01 ~ 17:36:30]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
web01 v1.0 ec969d114ff2 6 seconds ago 192MB
20,-e设置容器环境变量
#运行容器,并设置容器的环境变量
[root@docker01 ~ 18:11:51]# docker run -dp 82:80 -e NAME=zhangsan -e AGE=18 --name web_env nginx:stable
#进入容器查看环境变量是否设置成功
[root@docker01 ~ 18:12:34]# docker exec -it web_env /bin/sh
# env
....
NAME=zhangsan
....
AGE=18
七、容器重启策略
1,重启策略介绍
· 重启策略分类
| 重启策略/类型 | 解释说明 |
|---|---|
| no | 不自动重启; |
| on-failure on-failure:3 |
【含义】:容器以非零($?)退出状态终止时 (程序内部错误/崩溃),才会重启 【on-failure:0】和【on-failure】 :都表示不限重启次数; |
| unless-stopped | 【含义】:除非stop 容器,否则容器任何原因终止时 (包括正常退出/崩溃),都会重启 |
| always | 【除非】:手动停止:docker stop 容器名; 【否则】:不论什么原因,一直重启; |
· 重启策略场景
| 重启场景 | no | on-failure on-failure:3 |
unless-stopped | always |
|---|---|---|---|---|
| 重启docker服务 | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| 先停容器、再重启docker服务 | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| 容器任务执行完毕,自动正常退出 | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: |
2,异常退出策略验证
· 准备环境
#1,清空容器列表
[root@docker01 ~ 18:31:00]# docker rm -f `docker ps -qa`
#2,用所有重启策略方式依次启动容器
[root@docker01 ~ 18:09:27]# docker run -id --name v1 --restart no alpine
[root@docker01 ~ 18:32:06]# docker run -id --name v2 --restart on-failure alpine
[root@docker01 ~ 18:32:32]# docker run -id --name v3 --restart on-failure:3 alpine
[root@docker01 ~ 18:32:42]# docker run -id --name v4 --restart unless-stopped alpine
[root@docker01 ~ 18:32:59]# docker run -id --name v5 --restart always alpine
[root@docker01 ~ 18:33:18]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
651ab4d4925f alpine "/bin/sh" 28 seconds ago Up 28 seconds v5
254c1e28beb5 alpine "/bin/sh" 47 seconds ago Up 47 seconds v4
359ef7da8df6 alpine "/bin/sh" About a minute ago Up About a minute v3
77cd77056d88 alpine "/bin/sh" About a minute ago Up About a minute v2
2a87034a8082 alpine "/bin/sh" About a minute ago Up About a minute v1
· 重启docker服务验证
#1,重启docker服务后,查看容器列表
[root@docker01 ~ 18:33:46]# systemctl restart docker
#2,查看容器列表就剩下4个了,【no】v1的没有自动启动;
[root@docker01 ~ 18:34:49]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
651ab4d4925f alpine "/bin/sh" 2 minutes ago Up 34 seconds v5
254c1e28beb5 alpine "/bin/sh" 2 minutes ago Up 34 seconds v4
359ef7da8df6 alpine "/bin/sh" 2 minutes ago Up 34 seconds v3
77cd77056d88 alpine "/bin/sh" 2 minutes ago Up 34 seconds v2
· 手动停容器验证
#1,手动停掉所有容器。再重启docker查看结果
[root@docker01 ~ 18:39:23]# docker stop `docker ps -qa`
651ab4d4925f
254c1e28beb5
359ef7da8df6
77cd77056d88
2a87034a8082
[root@docker01 ~ 18:40:12]# systemctl restart docker.service
#2,再次重启docker之后,发现剩下3个了,【unless-stopped】v4没有重新启动;
[root@docker01 ~ 18:41:05]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
651ab4d4925f alpine "/bin/sh" 7 minutes ago Up 2 seconds v5
359ef7da8df6 alpine "/bin/sh" 8 minutes ago Up 2 seconds v3
77cd77056d88 alpine "/bin/sh" 8 minutes ago Up 2 seconds v2
· 模拟意外退出容器
#1,模拟意外退出,获取容器id,并kill -9 强制杀死进程(多杀死几次,超过3次)
[root@docker01 ~ 18:47:29]# kill -9 `docker inspect v2 | grep "\bPid\b" | awk -F"[ :,]+" '{print$3}'`
[root@docker01 ~ 18:47:29]# kill -9 `docker inspect v3 | grep "\bPid\b" | awk -F"[ :,]+" '{print$3}'`
[root@docker01 ~ 18:47:29]# kill -9 `docker inspect v5 | grep "\bPid\b" | awk -F"[ :,]+" '{print$3}'`
#2,再次查看容器列表,发现:【on-failure:3】v3没有再启动了
[root@docker01 ~ 18:53:58]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
651ab4d4925f alpine "/bin/sh" 20 minutes ago Up About a minute v5
77cd77056d88 alpine "/bin/sh" 21 minutes ago Up 29 seconds v2
3,正常退出验证重启策略
· 准备环境
#1,清空容器列表
[root@docker01 ~ 18:31:00]# docker rm -f `docker ps -qa`
#2,用所有重启策略方式依次启动容器,并执行睡眠3秒
[root@docker01 ~ 18:09:27]# docker run -id --name v1 --restart no alpine sleep 3
[root@docker01 ~ 18:32:06]# docker run -id --name v2 --restart on-failure alpine sleep 3
[root@docker01 ~ 18:32:32]# docker run -id --name v3 --restart on-failure:3 alpine sleep 3
[root@docker01 ~ 18:32:42]# docker run -id --name v4 --restart unless-stopped alpine sleep 3
[root@docker01 ~ 18:32:59]# docker run -id --name v5 --restart always alpine sleep 3
[root@docker01 ~ 18:33:18]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
651ab4d4925f alpine "/bin/sh" 28 seconds ago Up 28 seconds v5
254c1e28beb5 alpine "/bin/sh" 47 seconds ago Up 47 seconds v4
359ef7da8df6 alpine "/bin/sh" About a minute ago Up About a minute v3
77cd77056d88 alpine "/bin/sh" About a minute ago Up About a minute v2
2a87034a8082 alpine "/bin/sh" About a minute ago Up About a minute v1
· 查看容器
[root@docker01 ~ 18:33:18]# docker ps
可以看到:unless-stopped和always一直在自动重启。

八、存储卷管理(数据持久化)
1,存储卷概念
· 案例演示
1,启动一个nginx容器
# 启动一个nginx容器
[root@docker01 ~]# docker run -d -p80:80 --name web01 nginx:stable
ffe6fee4496f023b1fc6aa785601c8df9cedbd8d08676a9bfcbf8dab3543ba1b
[root@docker01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ffe6fee4496f nginx:stable "/docke..." 4 seconds ago Up 4 seconds 0.0.0.0:80->80/tcp web01
2,浏览器访问
10.0.0.91

3,修改nginx首页文件
# 进入容器中
[root@docker01 ~]# docker exec -it web01 bash
# 修改首页文件内容
root@ffe6fee4496f:/# echo "www.bakwite.com" > /usr/share/nginx/html/index.html
# 退出容器
root@ffe6fee4496f:/# exit
exit
4,再次浏览器访问
10.0.0.91

5,删除再启动容器
# 删除容器
[root@docker01 ~]# docker rm -f `docker ps -aq`
ffe6fee4496f
# 查看是否删除成功
[root@docker01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 再拉起容器
[root@docker01 ~]# docker run -d -p80:80 --name web01 nginx:stable
d6a85882b04afcc528fe6f696a807551a1f486f89e880205754c8a1dd6875d3e
# 再次浏览器访问
10.0.0.91

6,总结现象
# 之前修改的首页文件内容数据已经不在了、消失了;
· 案例原理
1,查看容器的详细信息(新版本没这功能了)
# 查看容器的详细信息
[root@docker01 ~]# docker inspect web01
......
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/e1053ffac852b3d76306f33c96aa48c21f289538d13aaef89e3c6870b3338c69-init/diff:/var/lib/docker/overlay2/4e2fca550bc903d54e294f81460df4f0608dbe77a3f278dd483b208e56397f46/diff:/var/lib/docker/overlay2/e4968acaeab890131d9cd486ade4eca19bf20693e5db933ea3e0fb10ee30b84c/diff:/var/lib/docker/overlay2/e8740499a26904ef296abdb0be065337e90ad109a34a18b91c1cda88ce5806da/diff:/var/lib/docker/overlay2/620b20b6b81a04378d15df4a3cad042fa8529d313106aabb45e52c3145ff89c1/diff:/var/lib/docker/overlay2/e64d1f27ac569db429513e9dd56bc368b5a07c2cda61fcadaa702a680fca8a41/diff:/var/lib/docker/overlay2/38b28fbf0047177de7aba743ffa4db446bc5141a5f017c6ca4cd5cfb18f5bc2c/diff:/var/lib/docker/overlay2/621274d07ae6a53174f984b17b8299a7605395ad79ab21bfd6300a27a3c72e03/diff",
"MergedDir": "/var/lib/docker/overlay2/e1053ffac852b3d76306f33c96aa48c21f289538d13aaef89e3c6870b3338c69/merged",
"UpperDir": "/var/lib/docker/overlay2/e1053ffac852b3d76306f33c96aa48c21f289538d13aaef89e3c6870b3338c69/diff",
"WorkDir": "/var/lib/docker/overlay2/e1053ffac852b3d76306f33c96aa48c21f289538d13aaef89e3c6870b3338c69/work"
......
2,进入容器在宿主机的目录
# 查看所在宿主机的目录
[root@docker01 ~]# ll /var/lib/docker/overlay2/e1053ffac852b3d76306f33c96aa48c21f289538d13aaef89e3c6870b3338c69/
总用量 8
drwxr-xr-x 5 root root 39 8月 28 12:18 diff
-rw-r--r-- 1 root root 26 8月 28 12:18 link
-rw-r--r-- 1 root root 231 8月 28 12:18 lower
drwxr-xr-x 1 root root 39 8月 28 12:18 merged
drwx------ 3 root root 18 8月 28 12:18 work
# 查看merged目录
[root@docker01 ~]# ll /var/lib/docker/overlay2/e1053ffac852b3d76306f33c96aa48c21f289538d13aaef89e3c6870b3338c69/merged/
总用量 4
lrwxrwxrwx 1 root root 7 8月 11 08:00 bin -> usr/bin
drwxr-xr-x 2 root root 6 5月 9 22:50 boot
drwxr-xr-x 1 root root 43 8月 28 12:18 dev
drwxr-xr-x 1 root root 41 8月 14 02:52 docker-entrypoint.d
-rwxr-xr-x 1 root root 1620 8月 14 02:51 docker-entrypoint.sh
drwxr-xr-x 1 root root 19 8月 28 12:18 etc
drwxr-xr-x 2 root root 6 5月 9 22:50 home
lrwxrwxrwx 1 root root 7 8月 11 08:00 lib -> usr/lib
lrwxrwxrwx 1 root root 9 8月 11 08:00 lib64 -> usr/lib64
drwxr-xr-x 2 root root 6 8月 11 08:00 media
drwxr-xr-x 2 root root 6 8月 11 08:00 mnt
drwxr-xr-x 2 root root 6 8月 11 08:00 opt
drwxr-xr-x 2 root root 6 8月 11 08:00 proc
drwx------ 2 root root 37 8月 11 08:00 root
drwxr-xr-x 1 root root 23 8月 28 12:18 run
lrwxrwxrwx 1 root root 8 8月 11 08:00 sbin -> usr/sbin
drwxr-xr-x 2 root root 6 8月 11 08:00 srv
drwxr-xr-x 2 root root 6 5月 9 22:50 sys
drwxrwxrwt 2 root root 6 8月 11 08:00 tmp
drwxr-xr-x 1 root root 66 8月 11 08:00 usr
drwxr-xr-x 1 root root 19 8月 11 08:00 var
3,进入容器查看目录
# 进入容器查看容器目录
[root@docker01 ~]# docker exec -it web01 bash
root@d6a85882b04a:/# ls -l
total 4
lrwxrwxrwx 1 root root 7 Aug 11 00:00 bin -> usr/bin
drwxr-xr-x 2 root root 6 May 9 14:50 boot
drwxr-xr-x 5 root root 340 Aug 28 04:18 dev
drwxr-xr-x 1 root root 41 Aug 13 18:52 docker-entrypoint.d
-rwxr-xr-x 1 root root 1620 Aug 13 18:51 docker-entrypoint.sh
drwxr-xr-x 1 root root 19 Aug 28 04:18 etc
drwxr-xr-x 2 root root 6 May 9 14:50 home
lrwxrwxrwx 1 root root 7 Aug 11 00:00 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Aug 11 00:00 lib64 -> usr/lib64
drwxr-xr-x 2 root root 6 Aug 11 00:00 media
drwxr-xr-x 2 root root 6 Aug 11 00:00 mnt
drwxr-xr-x 2 root root 6 Aug 11 00:00 opt
dr-xr-xr-x 207 root root 0 Aug 28 04:18 proc
drwx------ 2 root root 37 Aug 11 00:00 root
drwxr-xr-x 1 root root 23 Aug 28 04:18 run
lrwxrwxrwx 1 root root 8 Aug 11 00:00 sbin -> usr/sbin
drwxr-xr-x 2 root root 6 Aug 11 00:00 srv
dr-xr-xr-x 14 root root 0 Aug 28 04:18 sys
drwxrwxrwt 2 root root 6 Aug 11 00:00 tmp
drwxr-xr-x 1 root root 66 Aug 11 00:00 usr
drwxr-xr-x 1 root root 19 Aug 11 00:00 var
4,对比两种查看容器的方式
可以发现:
- 从宿主机目录进入容器创建目录后,在容器中也能看到;
- 所以说,二者本质上在一个目录下;只是进入的方式不同而已;
# 宿主机进入容器目录下创建bakwite目录
[root@docker01 ~]# mkdir /var/lib/docker/overlay2/e1053ffac852b3d76306f33c96aa48c21f289538d13aaef89e3c6870b3338c69/merged/bakwite
# 进入容器中查看,可以看到这个目录
[root@docker01 ~]# docker exec -it web01 bash
......
root@d6a85882b04a:/# ls -l
.......
drwxr-xr-x 2 root root 6 Aug 28 05:24 bakwite

5,删除容器再查看宿主机目录
现象:
提示找不到这个目录了;
整个容器目录已经被删除了;
[root@docker01 ~]# docker rm -f `docker ps -aq`
d6a85882b04a
[root@docker01 ~]# ll /var/lib/docker/overlay2/e1053ffac852b3d76306f33c96aa48c21f289538d13aaef89e3c6870b3338c69/merged/
ls: 无法访问 '/var/lib/docker/overlay2/e1053ffac852b3d76306f33c96aa48c21f289538d13aaef89e3c6870b3338c69/merged/': 没有那个文件或目录
· 案例总结
同一个镜像拉起多个容器的情况下:
- 修改一个容器中的文件内容,另一个容器不会被修改;
- 修改容器中的文件后,镜像不会被修改;
- 删除容器,再次拉起容器,之前修改的内容会随着容器一起被删除;

· 什么是存储卷
1,存储卷概念
由上面案例可以知道:
- 容器中的数据,是随着容器被删除一起被删除的;
- 那么在生产环境中,一些业务如果使用容器运行,所产生的数据信息,就存在安全风险;
- 一旦容器意外退出删除,那么里面的数据也就随着丢失了
- 为了解决这个问题,于是就有了【存储卷的概念】:
- 存储卷:就是将容器中的数据,存放到宿主机的某个目录下;
- 这个目录不在容器的overlay目录下;
- 所以,当容器被删除,宿主机中的目录不会受到影响;确保数据不随着容器一起被删除;
- 存储卷,又被叫做【数据持久化】;
2,存储卷初体验
在宿主机当中创建一个给容器预留的数据存储目录,我们创建一个/data
# 创建容器挂载点
[root@docker01 ~]# mkdir /data
# 在挂载点目录下,创建首页文件
[root@docker01 ~]# echo "www.bakwite.com" > /data/index.html
启动一个nginx的web服务容器,将这个目录挂载到代码目录上
[root@docker01 ~]# docker run -d -p80:80 -v /data/:/usr/share/nginx/html --name web01 nginx:stable
4d64c2c091d053e5ff7d452404a3d509718a7e580aade791dc4a0d7cf2493701
此时访问浏览器
[root@docker01 ~]# curl 10.0.0.91
www.bakwite.com

此时修改/data目录下的首页文件内容,再次浏览器访问
[root@docker01 ~]# echo "<h1>bakwite</h1>" > /data/index.html
# 浏览器再次访问
10.0.0.91

删除容器web01,查看/data目录下,数据文件依然存在;
[root@docker01 ~]# docker rm -f `docker ps -aq`
5f1ea8369163
[root@docker01 ~]# ll /data/
总用量 4
-rw-r--r-- 1 root root 20 8月 28 13:53 index.html
[root@docker01 ~]# cat /data/index.html
<h1>bakwite</h1>
在启动容器,查看容器详细信息:
- 查看Mounts字段下,就有我们的挂载信息;
[root@docker01 ~]# docker run -d -p80:80 -v /data/:/usr/share/nginx/html --name web01 nginx:stable
4d64c2c091d053e5ff7d452404a3d509718a7e580aade791dc4a0d7cf2493701
[root@docker01 ~]# docker inspect web02
......
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/d1cb7fad384fd29eabeee6e7b62b85bdbc94f45052786012aa8f5d75c4aefda3-init/diff:/var/lib/docker/overlay2/4e2fca550bc903d54e294f81460df4f0608dbe77a3f278dd483b208e56397f46/diff:/var/lib/docker/overlay2/e4968acaeab890131d9cd486ade4eca19bf20693e5db933ea3e0fb10ee30b84c/diff:/var/lib/docker/overlay2/e8740499a26904ef296abdb0be065337e90ad109a34a18b91c1cda88ce5806da/diff:/var/lib/docker/overlay2/620b20b6b81a04378d15df4a3cad042fa8529d313106aabb45e52c3145ff89c1/diff:/var/lib/docker/overlay2/e64d1f27ac569db429513e9dd56bc368b5a07c2cda61fcadaa702a680fca8a41/diff:/var/lib/docker/overlay2/38b28fbf0047177de7aba743ffa4db446bc5141a5f017c6ca4cd5cfb18f5bc2c/diff:/var/lib/docker/overlay2/621274d07ae6a53174f984b17b8299a7605395ad79ab21bfd6300a27a3c72e03/diff",
"MergedDir": "/var/lib/docker/overlay2/d1cb7fad384fd29eabeee6e7b62b85bdbc94f45052786012aa8f5d75c4aefda3/merged",
"UpperDir": "/var/lib/docker/overlay2/d1cb7fad384fd29eabeee6e7b62b85bdbc94f45052786012aa8f5d75c4aefda3/diff",
"WorkDir": "/var/lib/docker/overlay2/d1cb7fad384fd29eabeee6e7b62b85bdbc94f45052786012aa8f5d75c4aefda3/work"
},
"Name": "overlay2"
},
"Mounts": [
{
"Type": "bind",
"Source": "/data",
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
2,存储卷管理命令
· 创建存储卷
这些存储卷默认都放到了:/var/lib/docker/volumes/目录下
# 创建一个叫bakwite的存储卷
[root@docker01 ~]# docker volume create bakwite
bakwite
# 查看存储卷列表
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local bakwite
· 查看存储卷
1,查看存储卷列表
| 列字段 | 解释说明 |
|---|---|
| DRIVER | 表示存储驱动类型;local 表示本地存储,nfs、CephFS表示网络文件系统; |
| VOLUME NAME | 表示存储卷的名称 |
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
2,查看存储卷详细信息
[root@docker01 ~]# docker volume inspect bakwite
[
{
"CreatedAt": "2025-08-28T14:34:43+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/bakwite/_data",
"Name": "bakwite",
"Options": {},
"Scope": "local"
}
]
# 根据显示查看存储卷位置
[root@docker01 ~]# ll /var/lib/docker/volumes/bakwite/_data
总用量 0
· 容器使用存储卷
1,启动容器挂载存储卷
# 拉起容器指定存储卷名称挂在到容器代码;
[root@docker01 ~]# docker run -d -v bakwite:/usr/share/nginx/html -p81:80 --name web03 nginx:stable
b96e3c3a91f03d5f32810066fd8cecd3ef09647f40a1204fed0b3627144f913e
# 查看存储卷目录
[root@docker01 ~]# ll /var/lib/docker/volumes/bakwite/_data
总用量 8
-rw-r--r-- 1 root root 497 4月 23 19:48 50x.html
-rw-r--r-- 1 root root 615 4月 23 19:48 index.html
# 删除容器
[root@docker01 ~]# docker rm -f `docker ps -aq`
b96e3c3a91f0
# 再次查看存储卷目录下,数据还在,说明删除容器后,数据没有丢失;
[root@docker01 ~]# ll /var/lib/docker/volumes/bakwite/_data
总用量 8
-rw-r--r-- 1 root root 497 4月 23 19:48 50x.html
-rw-r--r-- 1 root root 615 4月 23 19:48 index.html
2,自动创建存储卷和容器目录
# 查看当前存储卷列表
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local bakwite
# 启动容器,挂载一个不存在的存储卷,挂在到容器不存在的目录下;
[root@docker01 ~]# docker run -d -v xjzw_volume:/xjzw_dir -p80:80 --name web04 nginx:stable
bc1fd6a9abeb38b06692c88c1e946a9b4afb63b6c1f6e937f7c5a9788141f5df
# 再次查看存储卷,发现自动帮助我们创建了存储卷;
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local bakwite
local xjzw_volume
# 查看容器目录,发现自动帮我们创建了目录;
[root@docker01 ~]# docker exec web04 ls -l /
......
drwxr-xr-x 2 root root 6 Aug 28 23:36 xjzw_dir
3,启动容器挂载匿名存储卷
# 启动容器,指定存储卷,但是不写存储卷名称;
[root@docker01 ~]# docker run -d -v /xjzw_dir -p88:80 --name web05 nginx:stable
3d8a4870d53fd4c36bc4797039e6a4aa0a81651626011c1693fc7942b2d0d7f8
# 查看存储卷列表,发现,自动生成了匿名存储卷
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local a3b8a3936a5d428dad952fec755b02a1dce40a0df4cab79b10b36c0598f4d5b1
local bakwite
local xjzw_volume
4,多容器挂载相同匿名存储卷
目标:实现数据共享
参数:【--volumes-from】
# 启动一个容器,挂载两个匿名存储卷
[root@docker01 ~]# docker run -d -v /xjzw_dir -v /bakwite_dir -p80:80 --name web06 nginx:stable
d8d32a69132703bdf6d30e2fccf6a3e1bc9183a0f89ae7954d7427dac236fecd
# 查看容器,发现,自动创建了两个匿名存储卷
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local 96a976cd137a7cae8aa645872f4a46e027c5ab25bf41be21a0cbdf1035474846
local ae7272429fef0b167f603ce4bed8a0bbc2fcb9bb918ac506292cd93f166dfc6d
local bakwite
local xjzw_volume
# 在启动另一个容器,使用--volumes-from参数,指定模仿第一个容器的挂载方式挂载存储卷
[root@docker01 ~]# docker run -d --volumes-from web06 -p81:80 --name web07 nginx:stable
7c0e5a7013006835449344290d3fc25121a7d3211b78fc108971b0b0448268f3
# 再次查看存储卷列表,发先并没有新创建的存储卷,因为,两个容器你用的是相同的存储卷;
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local 96a976cd137a7cae8aa645872f4a46e027c5ab25bf41be21a0cbdf1035474846
local ae7272429fef0b167f603ce4bed8a0bbc2fcb9bb918ac506292cd93f166dfc6d
local bakwite
local xjzw_volume
验证共享数据
# 进入一个容器中,在挂载目录下创建数据文件
[root@docker01 ~]# docker exec -it web06 bash
root@d8d32a691327:/# echo 123 > bakwite_dir/1.txt
root@d8d32a691327:/# echo 123 > xjzw_dir/2.txt
# 进入另一个容器中,查看,数据是否共享
[root@docker01 ~]# docker exec -it web07 bash
root@7c0e5a701300:/# cat bakwite_dir/1.txt
123
root@7c0e5a701300:/# cat xjzw_dir/2.txt
123
· 删除存储卷
1,创建测试存储卷
[root@docker01 ~]# docker volume create wa
wa
[root@docker01 ~]# docker volume create xin
xin
[root@docker01 ~]# docker volume create ji
ji
[root@docker01 ~]# docker volume create zhi
zhi
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local a3b8a3936a5d428dad952fec755b02a1dce40a0df4cab79b10b36c0598f4d5b1
local ji
local wa
local xin
local bakwite
local xjzw_volume
local zhi
2,启动容器挂载存储卷
[root@docker01 ~]# docker run -d -v bakwite:/usr/share/nginx/html -p81:80 --name web03 nginx:stable
1383cfa3863f7d13a38da5064bac8a3b759e16ab0538bd82dd94a466ec0cb8f2
3,删除存储卷
# 删除挂载的、正在使用的存储卷会报错
[root@docker01 ~]# docker volume rm bakwite
Error response from daemon: remove bakwite: volume is in use - [1383cfa3863f7d13a38da5064bac8a3b759e16ab0538bd82dd94a466ec0cb8f2]
# 删除未被使用的存储卷
[root@docker01 ~]# docker volume rm xin
xin
# 查看存储卷列表,发现已经删除
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local a3b8a3936a5d428dad952fec755b02a1dce40a0df4cab79b10b36c0598f4d5b1
local ji
local wa
local bakwite
local xjzw_volume
local zhi
4,移除所有未使用的存储卷
[root@docker01 ~]# docker volume prune -f
Deleted Volumes:
ji
zhi
wa
Total reclaimed space: 0B
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local a3b8a3936a5d428dad952fec755b02a1dce40a0df4cab79b10b36c0598f4d5b1
local bakwite
local xjzw_volume
5,删除容器及其存储卷
注意:只能自动删除匿名的存储卷;
删除容器时的【-v】参数:表示删除存储卷;
# 删除挂载指定名称存储卷的容器
[root@docker01 ~]# docker rm -f -v web04
web04
# 查看存储卷列表,发现xjzw_volume并没有被删除;
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local a3b8a3936a5d428dad952fec755b02a1dce40a0df4cab79b10b36c0598f4d5b1
local bakwite
local xjzw_volume
# 删除挂载匿名存储卷的容器
[root@docker01 ~]# docker rm -f -v web05
web05
# 发现,匿名存储卷被一起删除了;
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local bakwite
local xjzw_volume
九、容器网络管理
1,容器的ip不固定问题演示(类似DHCP,IP自动分配)
· 创建多个容器
# 创建处c1、c2、c3、c4四个容器
[root@docker01 ~]# docker run -d --name c1 nginx:stable
[root@docker01 ~]# docker run -d --name c2 nginx:stable
[root@docker01 ~]# docker run -d --name c3 nginx:stable
[root@docker01 ~]# docker run -d --name c4 nginx:stable
· 查看容器ip
[root@docker01 ~]# docker exec c1 hostname -I
172.17.0.2
[root@docker01 ~]# docker exec c2 hostname -I
172.17.0.3
[root@docker01 ~]# docker exec c3 hostname -I
172.17.0.4
[root@docker01 ~]# docker exec c4 hostname -I
172.17.0.5
· 关闭一个容器
[root@docker01 ~]# docker stop c2
c2
· 再创建两个容器
[root@docker01 ~]# docker run -d --name c5 nginx:stable
cd61cd6176aceddc6a6e8ac0c52e2f6fea66998391bffc601218f6b174121699
[root@docker01 ~]# docker run -d --name c6 nginx:stable
16c706b63c6c2564e9c8555af3b0cae83ff363b52a408edd557b580f1563f149
· 再次启动关闭的容器查看ip
[root@docker01 ~]# docker start c2
c2
# 发现ip地址产生了变化;
[root@docker01 ~]# docker exec c2 hostname -I
172.17.0.7
· 总结
如果我们想要两个容器之间通讯:
- 使用容器的IP地址,是不靠谱的行为;
- 一旦容器停止之后再启动,ip容易改变,导致业务网络故障;
2,link实现容器互联
· 准备环境
[root@docker01 ~]# docker rm -f `docker ps -aq`
16c706b63c6c
cd61cd6176ac
78abfbdfd2d7
ad1a8c71125f
5bcf1f42a2ea
c8f00eda3f50
· 创建【容器1】
[root@docker01 ~]# docker run -d --name web01 nginx:1.20.1-alpine
1b19dce3eceaf0cc240df32e8790e0da5c219ed6a3601f7ccf9a4b79a25fc3db
· 创建【容器2】link【容器1】
[root@docker01 ~]# docker run -d --link web01 --name web02 nginx:1.20.1-alpine
50c9cb40427b30849417d6267b7b21f59dc1aafa97439a6791640208a3c8546d
· 查看两个容器的hosts文件
[root@docker01 ~]# docker exec web01 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.2 865849bc574a
# 可以看到,容器2将容器1的地址写入了本地解析文件中;
[root@docker01 ~]# docker exec web02 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.2 web01 865849bc574a
172.17.0.3 50c9cb40427b
· 测试容器网络链接
ping测试联通web01
[root@docker01 ~]# docker exec web02 ping web01 -c3
PING web01 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.154 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.059 ms
64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.060 ms
--- web01 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.059/0.091/0.154 ms
重启web01切换ip后在测试
# 停止web01容器
[root@docker01 ~]# docker stop web01
web01
# 新创将2个容器;为了占用web01的源ip地址
[root@docker01 ~]# docker run -d --name web03 nginx:1.20.1-alpine
[root@docker01 ~]# docker run -d --name web04 nginx:1.20.1-alpine
# 启动web01容器
[root@docker01 ~]# docker start web01
web01
# 使用web02测试ping命令,依旧可以ping通
[root@docker01 ~]# docker exec web02 ping web01 -c3
PING web01 (172.17.0.5): 56 data bytes
64 bytes from 172.17.0.5: seq=0 ttl=64 time=0.126 ms
64 bytes from 172.17.0.5: seq=1 ttl=64 time=0.077 ms
64 bytes from 172.17.0.5: seq=2 ttl=64 time=0.059 ms
--- web01 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.059/0.087/0.126 ms
# 此时查看web02的hosts文件,发现已经自动修改了web01的ip
[root@docker01 ~]# docker exec web02 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.5 web01 1b19dce3ecea
172.17.0.3 bb79f9283f1f
3,容器的网络类型说明
| 网络类型 | 说明 |
|---|---|
| 【bridge】 | 【桥接网络】默认的网络类型,桥接到宿主机虚拟网卡docker0网卡上,与docker0相同网段; |
| 【host】 | 【共享宿主机网络】网络性能最高; |
| 【none】 | 【没有网络】不能上网; |
| 【container】 | 【共享容器网络】共享其他容器的网络; |
查看宿主机网卡
[root@docker01 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:7a:e4:e3 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.91/24 brd 10.0.0.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::f1cd:133b:5aa9:4e32/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:8c:3d:1b:20 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
inet6 fe80::42:8cff:fe3d:1b20/64 scope link
valid_lft forever preferred_lft forever
1,创建bridge网络的容器
linux桥接类型网络

默认不指定bridge也是这个类型的网络哦
[root@docker01 ~]# docker run -itd --network bridge --name wa_bridge alpine
09bd4a316dcc02b6294c78c40abcddbfbb528349d757a0b897006f6e7a08fc95
# 查看容器网卡
[root@docker01 ~]# docker exec wa_bridge ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:10 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:836 (836.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
2,创建host网络的容器
host网络:就是共享宿主机的网络
# 运行容器,指定容器为host网络类型
[root@docker01 ~]# docker run -itd --network host --name wa_host alpine
f07be1a41f9892bee79857d591e3a71cb01e24ea58c31951b9b26542cd82e78a
# 查看容器网卡信息,你会发现,容器的网卡与宿主机的网卡现实的结果一模一样。
[root@docker01 ~]# docker exec wa_host ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP qlen 1000
link/ether 00:0c:29:7a:e4:e3 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.91/24 brd 10.0.0.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::f1cd:133b:5aa9:4e32/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:8c:3d:1b:20 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
inet6 fe80::42:8cff:fe3d:1b20/64 scope link
valid_lft forever preferred_lft forever
63: veth597837e@if62: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 4a:29:b3:94:65:39 brd ff:ff:ff:ff:ff:ff
inet6 fe80::4829:b3ff:fe94:6539/64 scope link
valid_lft forever preferred_lft forever
3,创建none网络的容器
就是没有网络
[root@docker01 ~]# docker run -itd --network none --name wa_none alpine
af9d4d893323da5519d9668171a215e95d4da113a468376b4c480652f043d5b1
# 查看网卡,发现,只有一个本地回环网卡;
[root@docker01 ~]# docker exec wa_none ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
4,创建container网络的容器
container类型网络,就是复制其他容器的网络类型的意思;
# 创建container类型的三个容器,分别复制上面三个容器的网络
[root@docker01 ~]# docker run -itd --network container:wa_bridge --name wa_c01 alpine
d8391a30dc01358191858a6ba20d1683edd3a2231e8516e2e7ff5422940359c4
[root@docker01 ~]# docker run -itd --network container:wa_host --name wa_c02 alpine
9200d4c9137b65da223a0e8546ea3927b18efbba008c639feb8aa55d776359e3
[root@docker01 ~]# docker run -itd --network container:wa_none --name wa_c03 alpine
ea2619245afaa9ec98bcaff614cb53bd9ac4b6e97140f4d1356c8aee4c1ee856
# 查看wa_c01的网卡,可以看到,与bridge网络类型的容器网卡一致;
[root@docker01 ~]# docker exec wa_c01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
66: eth0@if67: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 查看wa_c02的网卡,可以看到,与host网络类型的容器网卡一致;
[root@docker01 ~]# docker exec wa_c02 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP qlen 1000
link/ether 00:0c:29:7a:e4:e3 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.91/24 brd 10.0.0.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::f1cd:133b:5aa9:4e32/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:8c:3d:1b:20 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
inet6 fe80::42:8cff:fe3d:1b20/64 scope link
valid_lft forever preferred_lft forever
67: veth5d07307@if66: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 state UP
link/ether e2:66:e3:4b:cb:69 brd ff:ff:ff:ff:ff:ff
inet6 fe80::e066:e3ff:fe4b:cb69/64 scope link
valid_lft forever preferred_lft forever
# 查看wa_c03的网卡,可以看到,与none网络类型的容器网卡一致;
[root@docker01 ~]# docker exec wa_c03 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
4,自定义网络
· 查看网络
1,查看网络列表
可以看到只有默认存在的三种网络
[root@docker01 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
1b58d0421a59 bridge bridge local
43380701993b host host local
4408a46d7750 none null local
2,查看网络的详细信息
[root@docker01 ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "1b58d0421a5902a132d45a012d73478218d9355809e5c0fd4a9ace70a2036046",
"Created": "2025-08-27T17:56:50.798750461+08:00",
"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": {
"6a31589a4d558909e370c807283852263444e0320f506fc4c0203c661744e4f2": {
"Name": "wa_bridge",
"EndpointID": "ee91eaf0929a92124f404fd317f7786977f963cd76f378baecad04c4a5a39226",
"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": {}
}
]
· 创建网络
1,创建网络
# 创建一个叫wa_net01的网络类型
[root@docker01 ~]# docker network create wa_net01
3c8750a7a5936844b5b14264b1b4a4e3ef7e9022e609309d259ba9509cd8dcb8
# 查看网络类型列表,可以看到,默认就是bridge类型
[root@docker01 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
1b58d0421a59 bridge bridge local
43380701993b host host local
4408a46d7750 none null local
3c8750a7a593 wa_net01 bridge local
# 创建后,查看宿主机网卡,看到多出来一个新的网段的网卡
[root@docker01 ~]# ip a
.......
68: br-3c8750a7a593: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:70:0c:d2:0d brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global br-3c8750a7a593
valid_lft forever preferred_lft forever
查看刚刚创建的网络的详细信息
[root@docker01 ~]# docker network inspect wa_net01
[
{
"Name": "wa_net01",
"Id": "3c8750a7a5936844b5b14264b1b4a4e3ef7e9022e609309d259ba9509cd8dcb8",
"Created": "2025-08-29T14:50:33.140449267+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
2,创建网络指定ip地址范围
| 字段 | 解释说明 |
|---|---|
| --subnet | 网段 |
| --gateway | 网关 |
| --ip-range | ip分配的范围【很少用】 |
[root@docker01 ~]# docker network create wa_net01 --subnet 172.19.0.0/16 --gateway 172.19.0.1 --ip-range 172.19.0.0/16
[root@docker01 ~]# docker network inspect wa_net01
[
{
"Name": "wa_net01",
"Id": "3eda915cf433275a754712d55034089070e56df3a848299c7bb6e23d14dfe225",
"Created": "2025-08-29T15:10:00.900184205+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.19.0.0/16",
"IPRange": "172.19.0.0/16",
"Gateway": "172.19.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
· 删除自定义网络
1,删除单个网络
[root@docker01 ~]# docker network rm wa_net01
wa_net01
[root@docker01 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
1b58d0421a59 bridge bridge local
43380701993b host host local
4408a46d7750 none null local
2,移除未使用的网络
# 创建几个网络
[root@docker01 ~]# docker network create wa01
[root@docker01 ~]# docker network create wa02
[root@docker01 ~]# docker network create wa03
[root@docker01 ~]# docker network create wa04
# 查看网络列表
[root@docker01 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
1b58d0421a59 bridge bridge local
43380701993b host host local
4408a46d7750 none null local
bcbf54b9de82 wa01 bridge local
96028a775ddb wa02 bridge local
752ae5cf2ae9 wa03 bridge local
606aa4a96136 wa04 bridge local
75d82a168218 wa_net01 bridge local
# 移除未使用的所有网络
[root@docker01 ~]# docker network prune -f
Deleted Networks:
wa01
wa02
wa03
wa04
[root@docker01 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
1b58d0421a59 bridge bridge local
43380701993b host host local
4408a46d7750 none null local
75d82a168218 wa_net01 bridge local
· 运行容器指定自定义网络
1,创建两个容器指定自定义网络
[root@docker01 ~]# docker run -d --name web02 --network wa_net01 nginx:1.20.1-alpine
[root@docker01 ~]# docker run -d --name web03 --network wa_net01 nginx:1.20.1-alpine
2,查看两个容器的ip
# 查看容器网段,确定为我们自定义网络的网段;
[root@docker01 ~]# docker exec web02 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
75: eth0@if76: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:13:01:01 brd ff:ff:ff:ff:ff:ff
inet 172.19.1.1/16 brd 172.19.255.255 scope global eth0
valid_lft forever preferred_lft forever
[root@docker01 ~]# docker exec web03 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
77: eth0@if78: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:13:01:02 brd ff:ff:ff:ff:ff:ff
inet 172.19.1.2/16 brd 172.19.255.255 scope global eth0
valid_lft forever preferred_lft forever
3,查看自定义网络详细信息
会看到,每个使用自定网络类型的容器,都会出现在详细信息中的containers字段下;
[root@docker01 ~]# docker network inspect wa_net01
......
{
"Subnet": "172.19.0.0/16",
"IPRange": "172.19.1.0/24",
"Gateway": "172.19.0.1"
}
......
"Containers": {
"4b9a014edf3e9b39b35c4a52313c49c521068b79eafdf86863c4b79fc56dd15d": {
"Name": "web02",
"EndpointID": "f9f1282a20856a5c90b5c14a2582a9c74a0eabb2f690e0e1c8c0e4e29c9f97ba",
"MacAddress": "02:42:ac:13:01:01",
"IPv4Address": "172.19.1.1/16",
"IPv6Address": ""
},
"52960f539941ce82368f791af5c250a8aa6e71278f17252e0c72cb8d88363f01": {
"Name": "web03",
"EndpointID": "674062e3dcc01e8cb43e2551554272563818a4476505ce14e1df31cf3c35a0c0",
"MacAddress": "02:42:ac:13:01:02",
"IPv4Address": "172.19.1.2/16",
"IPv6Address": ""
},
......
4,测试两容器网络互通
可以看到,两个容器在相同的自定义网络下,可以自由通过主机名互相通信;
# web02去ping容器web03
[root@docker01 ~]# docker exec web02 ping web03 -c3
PING web03 (172.19.1.2): 56 data bytes
64 bytes from 172.19.1.2: seq=0 ttl=64 time=0.121 ms
64 bytes from 172.19.1.2: seq=1 ttl=64 time=0.058 ms
64 bytes from 172.19.1.2: seq=2 ttl=64 time=0.070 ms
--- web03 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.058/0.083/0.121 ms
# web03去ping容器web02
[root@docker01 ~]# docker exec web03 ping web02 -c3
PING web02 (172.19.1.1): 56 data bytes
64 bytes from 172.19.1.1: seq=0 ttl=64 time=0.044 ms
64 bytes from 172.19.1.1: seq=1 ttl=64 time=0.065 ms
64 bytes from 172.19.1.1: seq=2 ttl=64 time=0.063 ms
--- web02 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.044/0.057/0.065 ms
· 运行容器指定ip地址
| 字段参数 | 解释说明 |
|---|---|
| --ip 172.19.0.6 | 运行容器指定ip地址 |
# 运行容器指定自定义网络,【--ip】指定固定的ip地址;
# 注意:只有创建自定义网络时,使用了--subnet指定了网段,再启动容器指定自定义网络时,才能自定义ip地址;
[root@docker01 ubuntu]# docker run -d --name web04 --network wa_net01 --ip 172.19.0.6 nginx:1.20.1-alpine
b4c11e45f6781692032cbce662707f23daee9ccb9c74f73d6ad6dd5cf249d62b
# 查看容器的ip地址,发现,就是我们固定指定的172.19.0.6这个ip;
[root@docker01 ubuntu]# docker exec web04 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
158: eth0@if159: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:13:00:06 brd ff:ff:ff:ff:ff:ff
inet 172.19.0.6/16 brd 172.19.255.255 scope global eth0
valid_lft forever preferred_lft forever
· 给容器添加/移除网络
1,准备环境
# 清空容器
[root@docker01 ~]# docker rm -f `docker ps -aq `
52960f539941
4b9a014edf3e
e4c44f999d42
5c4a83de6500
24403cd0b34d
981c8ced7b34
6d6416150b8a
4e04a7c8db99
6a31589a4d55
# 清空网络
[root@docker01 ~]# docker network prune -f
Deleted Networks:
wa_net01
2,运行一个容器web01不指定网络
默认bridge网络
[root@docker01 ~]# docker run -d --name web01 nginx:1.20.1-alpine
d0d3a38191f193898d821b17a1728083e8ae4c2bfc238651c3882f197cc2e868
# 查看容器网卡
[root@docker01 ~]# docker exec web01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
83: eth0@if84: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
3,创建自定义网络wa01指定ip
[root@docker01 ~]# docker network create wa01 --subnet 172.19.0.0/16 --gateway 172.19.0.1 --ip-range 172.19.0.0/16
6ca10b51fa5ad122ea9ea59296351d6c51eefc8cdf88a9769cf0f94686c7aaae
[root@docker01 ~]# docker network ls
...
6ca10b51fa5a wa01 bridge local
4,运行容器web02指定自定义网络
[root@docker01 ~]# docker run -d --network wa01 --name web02 nginx:1.20.1-alpine
3f1c2fa7f05d3286183f52efeed4d4fc8b1ac76ade8d99d7f41b18b7fbbd5e8c
# 查看容器的ip地址
[root@docker01 ~]# docker exec web02 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
86: eth0@if87: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:13:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.19.0.2/16 brd 172.19.255.255 scope global eth0
valid_lft forever preferred_lft forever
5,两容器测试通讯
结果:相互无法通讯
[root@docker01 ~]# docker exec web01 ping -c3 web02
ping: bad address 'web02'
[root@docker01 ~]# docker exec web02 ping -c3 web01
ping: bad address 'web01'
6,给web01添加自定义网络
[root@docker01 ~]# docker network connect wa01 web01
# 添加后,再次查看web01的网卡,发现,多了一个自定义网络的网段的网卡;
[root@docker01 ~]# docker exec web01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
83: eth0@if84: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
88: eth1@if89: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:13:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.19.0.3/16 brd 172.19.255.255 scope global eth1
valid_lft forever preferred_lft forever
7,再次测试两容器通讯
结果:通讯成功
[root@docker01 ~]# docker exec web02 ping -c3 web01
PING web01 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.109 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.061 ms
64 bytes from 172.19.0.3: seq=2 ttl=64 time=0.056 ms
--- web01 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.056/0.075/0.109 ms
[root@docker01 ~]# docker exec web01 ping -c3 web02
PING web02 (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.039 ms
64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.060 ms
64 bytes from 172.19.0.2: seq=2 ttl=64 time=0.059 ms
--- web02 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.039/0.052/0.060 ms
8,移除容器的自定义网络
[root@docker01 ~]# docker network disconnect wa01 web01
# 移除后,再次查看web01网卡,发现自定义网卡消失了;
[root@docker01 ~]# docker exec web01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
83: eth0@if84: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 再次测试领容器通讯,结果无法通讯了
[root@docker01 ~]# docker exec web01 ping -c3 web02
ping: bad address 'web02'
[root@docker01 ~]# docker exec web02 ping -c3 web01
ping: bad address 'web01'
5,案例(根据官网做,不看笔记)
根据官网:部署zabbix容器服务;
· zabbix官网
# 前往官网
- www.zabbix.com
- 点击文档【Documentation】

# 点击最新版本

# 选择【Installation】安装
- 点击【Installation from container】容器方式安装

# 点击Docker容器的安装方式
- Installation

# 页面向下滑动,找到Examples案例
- 按照案例操作即可

· 官网案例部署
创建一个网络叫:zabbix-net
[root@docker01 ~]# docker network create --subnet 172.20.0.0/16 --ip-range 172.20.240.0/20 zabbix-net
75aa45ad9c4a2577c13a98b8e09b4819d3a27f46ddc75c36039103b68a9267b5
# 查看网络列表
[root@docker01 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
1b58d0421a59 bridge bridge local
43380701993b host host local
4408a46d7750 none null local
6ca10b51fa5a wa01 bridge local
75aa45ad9c4a zabbix-net bridge local
拉取并启动mysql的镜像容器;
| mysql容器启动命令参数 | 解释说明【这是mysql容器启动时的“启动命令参数”】 |
|---|---|
| --character-set-server=utf8 | 指定整个mysql服务的字符集; |
| --collation-server=utf8_bin | 指定mysql数据库的数据排序方式; |
| --default-authentication-plugin=mysql_native_password | 指定密码插件; |
[root@docker01 ~]# docker run --name mysql-server -t \
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="zabbix" \
-e MYSQL_PASSWORD="zabbix_pwd" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
--network=zabbix-net \
--restart unless-stopped \
-d mysql:8.0-oracle \
--character-set-server=utf8 \
--collation-server=utf8_bin \
--default-authentication-plugin=mysql_native_password
拉取并启动zabbix-java-gateway的镜像容器
- 它是 Zabbix 监控系统的一个组件,专门用于监控 Java 应用程序。
[root@docker01 ~]# docker run --name zabbix-java-gateway -t \
--network=zabbix-net \
--restart unless-stopped \
-d zabbix/zabbix-java-gateway:alpine-7.4-latest
拉取并启动zabbix-server服务的镜像容器
[root@docker01 ~]# docker run --name zabbix-server-mysql -t \
-e DB_SERVER_HOST="mysql-server" \
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="zabbix" \
-e MYSQL_PASSWORD="zabbix_pwd" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
-e ZBX_JAVAGATEWAY="zabbix-java-gateway" \
--network=zabbix-net \
-p 10051:10051 \
--restart unless-stopped \
-d zabbix/zabbix-server-mysql:alpine-7.4-latest
拉取并启动zabbix客户端web页面
[root@docker01 ~]# docker run --name zabbix-web-nginx-mysql -t \
-e ZBX_SERVER_HOST="zabbix-server-mysql" \
-e DB_SERVER_HOST="mysql-server" \
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="zabbix" \
-e MYSQL_PASSWORD="zabbix_pwd" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
--network=zabbix-net \
-p 80:8080 \
--restart unless-stopped \
-d zabbix/zabbix-web-nginx-mysql:alpine-7.4-latest
查看拉取的容器列表
[root@docker01 ~]# docker ps

· 浏览器访问测试
http://10.0.0.91

# 默认用户名密码
管理员用户:Admin
管理员密码:zabbix

十、Dockerfile手动构建镜像:star:
1,dockerfile概述
在以上学习中,我们目前只有一种方式来构建我们想要的镜像:
- 就是使用【docker commit】命令,将运行的容器,保存为本地的镜像;
- 在生产环境中,如果我们想构建一个公司的web网站镜像,那么【docker commit】命令就显得比较繁琐;不方便。
- 于是docker提供了一种基于文件的方式,在不拉起容器的前提下,迅速构建出我们想要的镜像;
- 这个方式就是:【dockerfile】;
总结:dockerfile就是docker通过文件的方式,快速构建自定义镜像的方法;
2,环境准备
创还能一个目录,专门用来学习dockerfile
[root@docker01 ~]# mkdir -p /bakwite/dockerfile/{ubuntu,alpine}
[root@docker01 ~]# cd /bakwite/dockerfile/ubuntu/
[root@docker01 ubuntu]#
3,dockerfile初体验
· 编辑dockerfile
[root@docker01 ubuntu]# vim Dockerfile
# 【FROM】指定使用基础镜像
FROM ubuntu:22.04
# 【COPY】将当前目录行下的文件复制到镜像目录下;
COPY sources.list /etc/apt/sources.list
# 【RUN运行命令】在镜像中安装软件
RUN apt update && apt -y install nginx
# 镜像运行为容器后的守护进程命令[只要运行容器,就前台启动nginx服务];
CMD ["nginx","-g","daemon off;"]
· 准备ubuntu软件源文件
[root@docker01 ubuntu]# vim sources.list
deb http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse
· 开始构建镜像
| 命令 | 参数 | 解释说明 |
|---|---|---|
| docker build | -t | 指定构建的镜像名称 |
| . | 以哪个目录为基准进行构建?【.】表示当前目录; | |
| -f | 一般不使用; 如果,Dockerfile文件名称不叫【Dockerfile】这个名,那么需要-f指定文件名称; |
[root@docker01 ubuntu]# docker build -t ubuntu_nginx:v1.0 .
......
Successfully built 1077e924bea8
Successfully tagged ubuntu_nginx:v1.0
[root@docker01 ubuntu]# docker build -t ubuntu_nginx:v1.0 -f ./Dockerfile .
# 还可以使用宿主机网络
# 使用宿主机网络进行构建(如果镜像本省网络不管用,则使用)
[root@docker01 ubuntu]# docker build --network=host -t nginx_php:v1.0 .
· 查看构建的镜像
1,查看生成的镜像
[root@docker01 ubuntu]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu_nginx v1.0 1077e924bea8 47 seconds ago 244MB
2,查看隐藏镜像
[root@docker01 ubuntu]# docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu_nginx v1.0 1077e924bea8 47 hours ago 244MB
# 下面这些【没有名称的镜像】,就是构建镜像过程中,生成的【中间层镜像】。
<none> <none> 867fb925e1b8 47 hours ago 244MB
<none> <none> a182121294c9 47 hours ago 77.9MB
· 将镜像运行为容器测试
[root@docker01 ubuntu]# docker run -d -p81:80 --name df02 ubuntu_nginx:v1.0
adb1ee3c2902cffa761204735cd744c26b44a13f2fdd4d448baee83651f91820
# 浏览器访问测试
10.0.0.91:81

致此,我们就成功构建出属于自己的镜像了;
· 查看镜像构建历史/过程
就是每一个步骤的构建过程
- 注意,从下往上看;
[root@docker01 ubuntu]# docker history ubuntu_nginx:v1.0
IMAGE CREATED CREATED BY SIZE COMMENT
1077e924bea8 3 days ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B
867fb925e1b8 3 days ago /bin/sh -c apt update && apt -y install nginx 166MB
a182121294c9 3 days ago /bin/sh -c #(nop) COPY file:514e0fb8d6c6df39… 714B
8a4eacce82df 4 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 4 weeks ago /bin/sh -c #(nop) ADD file:598bb7ba54e5a5767… 77.9MB
<missing> 4 weeks ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
<missing> 4 weeks ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
<missing> 4 weeks ago /bin/sh -c #(nop) ARG LAUNCHPAD_BUILD_ARCH 0B
<missing> 4 weeks ago /bin/sh -c #(nop) ARG RELEASE 0B
4,案例
· 负载均衡
构建三个镜像,一个是lb负载均衡器,另外两个是nginx静态web01和web02网站;
- 要求实现启动三个容器后,访问lb容器,会负载均衡到web01和web02容器中;
1,准备干净的环境
[root@docker01 ubuntu]# docker rm -f `docker ps -aq`
adb1ee3c2902
cecaee0acdf9
5f32ff04e0dd
21ab3e4b908c
31646e5aaba6
223a0dd21026
a850aa05bd51
c6c98c433910
4b25d77eb84f
84ecf483bc09
2,构建lb负载均衡镜像
准备nginx配置文件
[root@docker01 ubuntu]# vim lb.conf
#创建负载均衡分组,名称叫:【lb_proxy】
upstream lb_proxy {
#分组中就是后端负载均衡服务器ip;
server web01:80;
server web02:80;
}
server {
listen 80;
server_name localhost;
location / {
#把请求转发到分组(后面的web服务器节点)中;
proxy_pass http://lb_proxy;
#【修改转发数据报的请求头】将用户请求头中的域名Host字段转发过去;
#如果不加,负载均衡器去请求后端web节点的数据包中的请求头host就变成了分组的名字(host:lb_proxy)
#就等于负载均衡器拿着ip访问后端了,如果后端有多个站点,就会出错哦(多个配置文件默认访问第一个)~;
proxy_set_header Host $http_host;
}
}
编辑dockerfile
[root@docker01 ubuntu]# vim lb.Dockerfile
# 【FROM】指定使用基础镜像
FROM ubuntu:22.04
# 【COPY】将当前目录行下的文件复制到镜像目录下;
COPY sources.list /etc/apt/sources.list
# 安装nginx
RUN apt update && apt -y install nginx && \
rm -rf /etc/nginx/conf.d/* && \
rm -rf /etc/nginx/sites-enabled/*
# 将准备好的nginx配置文件复制到镜像nginx配置位置;
COPY lb.conf /etc/nginx/conf.d/lb.conf
# 【CMD】镜像启动为容器后的守护进程命令;nginx的启动并监听命令;
CMD ["nginx","-g","daemon off;"]
开始构建lb镜像
[root@docker01 ubuntu]# docker build -t lb:v1.0 -f lb.Dockerfile .
2,构建web服务镜像
准备nginx配置文件
# 编辑web01配置文件
[root@docker01 ubuntu]# cat web01.conf
server {
listen 80;
server_name localhost;
root /code/;
location / {
index index.html;
}
}
# 编辑web02配置文件
[root@docker01 ubuntu]# cat web02.conf
server {
listen 80;
server_name localhost;
root /code/;
location / {
index index.html;
}
}
编辑web01的dockerfile
[root@docker01 ubuntu]# cat web01.Dockerfile
# 【FROM】指定使用基础镜像
FROM ubuntu:22.04
# 【COPY】将当前目录行下的文件复制到镜像目录下;
COPY sources.list /etc/apt/sources.list
# 安装nginx
RUN apt update && apt -y install nginx && \
rm -rf /etc/nginx/conf.d/* && \
rm -rf /etc/nginx/sites-enabled/* && \
mkdir /code/ && \
echo "www.bakwite.com:web01" > /code/index.html
# 将准备好的nginx配置文件复制到镜像nginx配置位置;
COPY web01.conf /etc/nginx/conf.d/web01.conf
# 【CMD】镜像启动为容器后的守护进程命令;nginx的启动并监听命令;
CMD ["nginx","-g","daemon off;"]
构建web01镜像
[root@docker01 ubuntu]# docker build -t web01:v1.0 -f web01.Dockerfile .
编辑web02的dockerfile
[root@docker01 ubuntu]# vim web02.Dockerfile
# 【FROM】指定使用基础镜像
FROM ubuntu:22.04
# 【COPY】将当前目录行下的文件复制到镜像目录下;
COPY sources.list /etc/apt/sources.list
# 安装nginx
RUN apt update && apt -y install nginx && \
rm -rf /etc/nginx/conf.d/* && \
rm -rf /etc/nginx/sites-enabled/* && \
mkdir /code/ && \
echo "www.bakwite.com:web02" > /code/index.html
# 将准备好的nginx配置文件复制到镜像nginx配置位置;
COPY web02.conf /etc/nginx/conf.d/web02.conf
# 【CMD】镜像启动为容器后的守护进程命令;nginx的启动并监听命令;
CMD ["nginx","-g","daemon off;"]
构建web02镜像
[root@docker01 ubuntu]# docker build -t web02:v1.0 -f web02.Dockerfile .
3,查看构建的三个镜像
[root@docker01 ubuntu]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
web02 v1.0 a24d28d09dd4 2 minutes ago 244MB
web01 v1.0 48d7d2131158 4 minutes ago 244MB
lb v1.0 909742b60800 13 minutes ago 244MB
4,启动三个容器测试
创建网络
[root@docker01 ubuntu]# docker network create lb_server --subnet 172.16.0.0/16 --gateway 172.16.0.1 --ip-range 172.16.0.0/16
c77f8b2c1bbf96096bdd358e230032dd66fe4e7dd7f0c4c7eeaf682dc4545126
[root@docker01 ubuntu]# docker network ls
NETWORK ID NAME DRIVER SCOPE
...
c77f8b2c1bbf lb_server bridge local
...
启动3个容器指定相同网络
# 【必须】先启动web01和web02;(否则,lb找不到两个容器名称的网络地址会报错,起不来)
[root@docker01 ubuntu]# docker run -d --network lb_server --name web01 web01:v1.0
[root@docker01 ubuntu]# docker run -d --network lb_server --name web02 web02:v1.0
# 在启动lb;
[root@docker01 ubuntu]# docker run -d --network lb_server --name lb lb:v1.0
访问lb容器测试
# 查看lb地址
[root@docker01 ubuntu]# docker exec lb hostname -I
172.16.0.4
# curl命令访问这个lb的地址查看是否负载成功
[root@docker01 ubuntu]# curl 172.16.0.4
www.bakwite.com:web01
[root@docker01 ubuntu]# curl 172.16.0.4
www.bakwite.com:web02
[root@docker01 ubuntu]# curl 172.16.0.4
www.bakwite.com:web01
[root@docker01 ubuntu]# curl 172.16.0.4
www.bakwite.com:web02
· 构建nginx加php镜像
制作一个ubuntu镜像,启动为容器后里面包含:nginx+php两个服务
1,准备nginx配置文件
准备nginx主配置文件
[root@docker01 ubuntu]# cat nginx.conf
user www;
worker_processes auto;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
}
准备nginx子配置文件
[root@docker01 ubuntu]# cat web.conf
server {
listen 80;
server_name localhost;
root /code/;
location / {
index index.html index.php;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
2,准备php配置文件
[root@docker01 ubuntu]# cat www.conf -n
......
24 user = www
...
26 group = www
......
38 listen = 9000
3,准备软件apt源文件
[root@harbor01:/dockerfile]# cat sources.list
deb http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse
# deb http://mirrors.aliyun.com/ubuntu/ jammy-proposed main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ jammy-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse
4,编辑dockerfile
| 运行命令 | 前台运行 | 后台运行 |
|---|---|---|
| php | /usr/sbin/php-fpm7.4 -g 'daemonize=no' | /usr/sbin/php-fpm7.4 -g 'daemonize=yes' |
| nginx | /usr/sbin/nginx -g 'daemon off;' | /usr/sbin/nginx |
[root@docker01 ubuntu]# cat Dockerfile
# 【FROM】指定使用基础镜像
FROM ubuntu:22.04
# 【COPY】将当前目录行下的文件复制到镜像目录下;
COPY sources.list /etc/apt/sources.list
# 安装软件
RUN apt update && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apt -y install software-properties-common && \
add-apt-repository ppa:ondrej/php && \
apt update && \
apt -y install php7.4 && \
apt -y install php7.4-common && \
apt -y install php7.4-cli && \
apt -y install php7.4-fpm && \
apt -y install php7.4-mysql && \
apt -y install php7.4-xml && \
apt -y install php7.4-gd && \
apt -y install php7.4-mbstring && \
apt -y install php7.4-zip && \
apt -y install php7.4-bcmath && \
apt -y install php7.4-soap && \
apt -y install php7.4-intl && \
apt -y install php7.4-readline && \
apt -y install php7.4-opcache && \
apt -y install php7.4-curl && \
apt -y install php7.4-ldap && \
apt -y install php7.4-imap && \
apt -y install php7.4-pgsql && \
apt -y install php7.4-sqlite3 && \
apt -y install nginx && \
useradd -s /sbin/nologin -M www && \
rm -rf /etc/php-fpm.d/www.conf && \
rm -rf /etc/nginx/nginx.conf && \
rm -rf /etc/nginx/conf.d/* && \
mkdir /code/ && \
echo "<?php echo 'hello php-fpm';?>" > /code/index.php && \
echo "/usr/sbin/php-fpm7.4 --daemonize &" > /root/start.sh && \
echo "/usr/sbin/nginx -g 'daemon off;'" >> /root/start.sh && \
mkdir /run/php/ && \
chown -R www.www /run/php/ && \
rm -rf /var/cache/apt/archives/
# 复制配置文件
COPY www.conf /etc/php/7.4/fpm/pool.d/www.conf
COPY nginx.conf /etc/nginx/nginx.conf
COPY web.conf /etc/nginx/conf.d/web.conf
# 【CMD】镜像启动为容器后的守护进程命令;nginx的启动并监听命令;
CMD ["sh","/root/start.sh"]
5,构建镜像
[root@docker01 ubuntu]# docker build -t nginx_php:v1.0 .
# 使用宿主机网络进行构建(如果镜像本省网络不管用,则使用)
[root@docker01 ubuntu]# docker build --network=host -t nginx_php:v1.0 .
6,启动测试
[root@docker01 ubuntu]# docker run -d --name php_nginx-v1 nginx_php:v1.0
# 查看容器端口;
[root@docker01 ubuntu]# docker exec php_nginx-v1 ss -tnulp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
tcp LISTEN 0 128 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=8,fd=6))
tcp LISTEN 0 128 *:9000 *:* users:(("php-fpm7.4",pid=7,fd=7))
# 查看ip
[root@docker01 ubuntu]# docker exec php_nginx-v1 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
218: eth0@if219: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:08 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.8/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 模拟访问web网站
[root@docker01 ubuntu]# curl 172.17.0.8
hello php-fpm
· wordpress案例
要求:
- 基于构建好的nginx+php的镜像启动,代码目录需要挂载存储卷保证容器挂掉代码不丢失;
- 拉取mysql8.0镜像,数据目录挂载到存储卷保证数据不丢失;
- 安装部署wordpress个人博客;
1,环境准备
查看基础镜像
[root@docker01 ubuntu]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx_php v1.0 491ce4fe93e8 4 hours ago 462MB
......
mysql 8.0-oracle 57c7595ac65f 5 weeks ago 781MB
准备代码
[root@docker01 ubuntu]# ll
-rw-r--r-- 1 root root 35933779 9月 1 12:29 wordpress-6.8.2-zh_CN.zip
创建网络
[root@docker01 ubuntu]# docker network create wp_net
[root@docker01 ubuntu]# docker network ls
NETWORK ID NAME DRIVER SCOPE
......
5aced36029e4 wp_net bridge local
创建【代码目录】与【mysql数据目录】的存储卷
[root@docker01 ubuntu]# docker volume create wp_volume
[root@docker01 ubuntu]# docker volume create mysql_volume
[root@docker01 ubuntu]# docker volume ls
DRIVER VOLUME NAME
......
local mysql_volume
local wp_volume
2,启动mysql容器
| MySQL环境变量与参数 | 解释说明 |
|---|---|
| MYSQL_ROOT_PASSWORD=xxx | 设置数据库管理员root的登录密码 |
| MYSQL_ALLOW_EMPTY_PASSWORD=yes/no | 允许密码为空,不设置root的密码 |
| MYSQL_DATABASE=xxx | 创建的数据库名称 |
| MYSQL_USER=xx | 链接数据库的用户名 |
| MYSQL_PASSWORD=xxx | 链接数据库的密码 |
| --default-authentication-plugin=mysql_native_password | 指定mysql所使用的密码认证插件; |
| --character-set-server=utf8 | 指定系统默认的字符集 |
| --collation-server=utf8_bin | 指定系统默认的排序规则,严格按照字符的二进制编码值进行比较和排序。 |
[root@docker01 ubuntu]# docker run -d \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wp \
-e MYSQL_PASSWORD=123456 \
-v mysql_volume:/var/lib/mysql/ \
--network wp_net \
--name wp_db \
mysql:8.0-oracle \
--character-set-server=utf8 \
--collation-server=utf8_bin \
--default-authentication-plugin=mysql_native_password
3,验证数据库容器环境
# 验证数据库
[root@docker01 ubuntu]# docker exec -it wp_db bash
bash-5.1# mysql -uroot -p123456
......
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| wordpress |
+--------------------+
# 验证用户
[root@docker01 _data]# docker exec -it wp_db mysql -uroot -p123456 -e "SELECT User, Host FROM mysql.user;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------------+-----------+
| User | Host |
+------------------+-----------+
| root | % |
| wp | % |
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+------------------+-----------+
# 验证数据库存储卷
[root@docker01 ubuntu]# docker volume inspect mysql_volume
[
{
"CreatedAt": "2025-09-02T12:49:05+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/mysql_volume/_data",
"Name": "mysql_volume",
"Options": {},
"Scope": "local"
}
]
# 查看存储卷
[root@docker01 ubuntu]# ll /var/lib/docker/volumes/mysql_volume/_data
总用量 100648
-rw-r----- 1 systemd-coredump input 56 9月 2 12:48 auto.cnf
-rw-r----- 1 systemd-coredump input 2984796 9月 2 12:49 binlog.000001
-rw-r----- 1 systemd-coredump input 157 9月 2 12:49 binlog.000002
-rw-r----- 1 systemd-coredump input 32 9月 2 12:49 binlog.index
-rw------- 1 systemd-coredump input 1705 9月 2 12:48 ca-key.pem
-rw-r--r-- 1 systemd-coredump input 1112 9月 2 12:48 ca.pem
-rw-r--r-- 1 systemd-coredump input 1112 9月 2 12:48 client-cert.pem
-rw------- 1 systemd-coredump input 1705 9月 2 12:48 client-key.pem
-rw-r----- 1 systemd-coredump input 196608 9月 2 12:51 '#ib_16384_0.dblwr'
-rw-r----- 1 systemd-coredump input 8585216 9月 2 12:48 '#ib_16384_1.dblwr'
-rw-r----- 1 systemd-coredump input 5604 9月 2 12:49 ib_buffer_pool
-rw-r----- 1 systemd-coredump input 12582912 9月 2 12:49 ibdata1
-rw-r----- 1 systemd-coredump input 12582912 9月 2 12:49 ibtmp1
drwxr-x--- 2 systemd-coredump input 4096 9月 2 12:49 '#innodb_redo'
drwxr-x--- 2 systemd-coredump input 187 9月 2 12:49 '#innodb_temp'
drwxr-x--- 2 systemd-coredump input 143 9月 2 12:48 mysql
-rw-r----- 1 systemd-coredump input 32505856 9月 2 12:49 mysql.ibd
lrwxrwxrwx 1 systemd-coredump input 27 9月 2 12:49 mysql.sock -> /var/run/mysqld/mysqld.sock
drwxr-x--- 2 systemd-coredump input 8192 9月 2 12:48 performance_schema
-rw------- 1 systemd-coredump input 1705 9月 2 12:48 private_key.pem
-rw-r--r-- 1 systemd-coredump input 452 9月 2 12:48 public_key.pem
-rw-r--r-- 1 systemd-coredump input 1112 9月 2 12:48 server-cert.pem
-rw------- 1 systemd-coredump input 1705 9月 2 12:48 server-key.pem
drwxr-x--- 2 systemd-coredump input 28 9月 2 12:48 sys
-rw-r----- 1 systemd-coredump input 16777216 9月 2 12:51 undo_001
-rw-r----- 1 systemd-coredump input 16777216 9月 2 12:51 undo_002
drwxr-x--- 2 systemd-coredump input 6 9月 2 12:49 wordpress
4,启动web容器
[root@docker01 ubuntu]# docker run -d \
-v wp_volume:/code/ \
--network wp_net \
-p 80:80 \
--name wp_web \
nginx_php:v1.0
5,验证web容器环境
# 查看存储卷
[root@docker01 ubuntu]# docker volume inspect wp_volume
[
{
"CreatedAt": "2025-09-02T12:38:45+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/wp_volume/_data",
"Name": "wp_volume",
"Options": {},
"Scope": "local"
}
]
# 验证存储卷
[root@docker01 ubuntu]# ll /var/lib/docker/volumes/wp_volume/_data
总用量 4
-rw-r--r-- 1 root root 30 9月 2 08:22 index.php
6,配置代码
将代码移动至web存储卷
# 解压代码
[root@docker01 ubuntu]# unzip wordpress-6.8.2-zh_CN.zip
# 将代码移动至web存储卷
[root@docker01 ubuntu]# mv wordpress/* /var/lib/docker/volumes/wp_volume/_data/
[root@docker01 ubuntu]# ll /var/lib/docker/volumes/wp_volume/_data
总用量 232
-rw-r--r-- 1 root root 405 2月 6 2020 index.php
-rw-r--r-- 1 root root 19903 3月 6 22:24 license.txt
-rw-r--r-- 1 root root 7425 3月 7 16:45 readme.html
-rw-r--r-- 1 root root 7387 2月 13 2024 wp-activate.php
drwxr-xr-x 9 root root 4096 7月 29 15:00 wp-admin
-rw-r--r-- 1 root root 351 2月 6 2020 wp-blog-header.php
-rw-r--r-- 1 root root 2323 6月 14 2023 wp-comments-post.php
-rw-r--r-- 1 root root 3336 9月 1 18:03 wp-config-sample.php
drwxr-xr-x 5 root root 69 7月 29 15:00 wp-content
-rw-r--r-- 1 root root 5617 8月 3 2024 wp-cron.php
drwxr-xr-x 30 root root 12288 7月 29 15:00 wp-includes
-rw-r--r-- 1 root root 2502 11月 27 2022 wp-links-opml.php
-rw-r--r-- 1 root root 3937 3月 11 2024 wp-load.php
-rw-r--r-- 1 root root 51414 2月 4 2025 wp-login.php
-rw-r--r-- 1 root root 8727 2月 9 2025 wp-mail.php
-rw-r--r-- 1 root root 30081 3月 4 21:06 wp-settings.php
-rw-r--r-- 1 root root 34516 3月 11 02:16 wp-signup.php
-rw-r--r-- 1 root root 5102 10月 18 2024 wp-trackback.php
-rw-r--r-- 1 root root 3205 11月 8 2024 xmlrpc.php
复制改名wordpress配置文件【可以不做】
[root@docker01 _data]# cp wp-config-sample.php wp-config.php
[root@docker01 _data]# vim wp-config.php
/** The name of the database for WordPress */
define( 'DB_NAME', 'wordpress' );
/** Database username */
define( 'DB_USER', 'wp' );
/** Database password */
define( 'DB_PASSWORD', '123456' );
/** Database hostname */
define( 'DB_HOST', 'wp_db' );
7,浏览器访问安装
10.0.0.121

· zrlog博客LNMT镜像构建
1,准备nginx配置文件
主配置文件
[root@docker01:/build]# vim nginx.conf
user www;
worker_processes auto;
pid /run/nginx.pid;
# 【错误日志】直接定向到容器【标准错误输出】设备上;
error_log /dev/stderr warn;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 访问日志直接定向到容器的【标准输出设备】上;
access_log /dev/stdout main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
}
子配置文件
[root@docker01 ubuntu]# vim web.conf
server {
listen 80;
server_name localhost;
# 【错误日志】直接定向到容器【标准错误输出】设备上;
error_log /dev/stderr warn;
# 访问日志直接定向到容器的【标准输出设备】上;
access_log /dev/stdout main;
location / {
#将用户请求转发给本地的8080(Tomcat);
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
2,准备apt安装源文件
[root@harbor01:/dockerfile]# cat sources.list
deb http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse
# deb http://mirrors.aliyun.com/ubuntu/ jammy-proposed main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ jammy-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse
3,软件包准备
[root@harbor01:/dockerfile]# ls -l
total 100628
drwxr-xr-x 9 root root 4096 Oct 28 16:53 apache-tomcat-9.0.111
-rw-r--r-- 1 root root 13037002 Oct 28 16:40 apache-tomcat-9.0.111.tar.gz
drwxr-xr-x 8 root root 4096 Oct 28 16:37 jdk1.8.0_461
-rw-r--r-- 1 root root 79436023 Oct 28 16:31 jdk-8u461-linux-x64.tar.gz
-rw-r--r-- 1 root root 798 Oct 28 17:28 nginx.conf
-rw-r--r-- 1 root root 447 Oct 28 17:28 web.conf
-rw-r--r-- 1 root root 10547379 Oct 28 16:13 zrlog.war
4,编辑Dockerfile
[root@harbor01:/dockerfile]# vim Dockerfile
# 【FROM】指定使用基础镜像
FROM ubuntu:22.04
COPY sources.list /etc/apt/sources.list
# 安装软件
RUN apt update && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apt -y install nginx curl wget && \
useradd -s /sbin/nologin -M www && \
rm -rf /etc/nginx/nginx.conf && \
rm -rf /etc/nginx/conf.d/* && \
mkdir /app_tools && \
apt clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/
# 复制配置文件与服务
COPY jdk1.8.0_491 /app_tools/jdk1.8.0_491
COPY apache-tomcat-9.0.120/ /app_tools/apache-tomcat-9.0.120
COPY nginx.conf /etc/nginx/nginx.conf
COPY web.conf /etc/nginx/conf.d/web.conf
# 配置tomcat
ENV JAVA_HOME="/app_tools/jdk1.8.0_491"
ENV PATH="${JAVA_HOME}/bin:${JAVA_HOME}/jre/bin:${PATH}"
ENV CLASSPATH="${JAVA_HOME}/lib:${JAVA_HOME}/jre/lib:${JAVA_HOME}/lib/tools.jar"
# 配置启动脚本
RUN echo '#!/bin/bash' > /root/start.sh && \
echo '/app_tools/apache-tomcat-9.0.120/bin/startup.sh' >> /root/start.sh && \
echo '/usr/sbin/nginx -g "daemon off;"' >> /root/start.sh && \
chmod +x /root/start.sh && \
mv /app_tools/apache-tomcat-9.0.120/webapps/ROOT /app_tools/apache-tomcat-9.0.120/webapps/ROOT.bak
# 上传代码war包
COPY zrlog.war /app_tools/apache-tomcat-9.0.120/webapps/ROOT.war
# 暴露服务端口
EXPOSE 80 8080
# 【CMD】镜像启动为容器后的守护进程命令;nginx的启动并监听命令;
CMD ["bash","/root/start.sh"]
6,构建
[root@harbor01:/dockerfile]# docker build --network=host -t zrlog:v1.0 .
7,运行容器
[root@harbor01:/dockerfile]# docker network create zrlog_net
[root@harbor01:/dockerfile]# docker run -d --name zrlog -e JAVA_OPTS="-Dfile.encoding=UTF-8" --network zrlog_net -p 8899:80 zrlog:v1.0
[root@harbor01:/dockerfile]# mkdir /zrlog_mysql_volume
[root@harbor01:/dockerfile]# docker run -d \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=zrlog \
-e MYSQL_USER=zrlog \
-e MYSQL_PASSWORD=123456 \
-v /zrlog_mysql_volume:/var/lib/mysql/ \
--network zrlog_net \
--name zrlog_db \
mysql:8.0-oracle \
--character-set-server=utf8 \
--collation-server=utf8_bin \
--default-authentication-plugin=mysql_native_password
8,浏览器访问
http://10.0.0.121:8899

5,Dockerfile命令
· 基础命令
| Dockerfile命令 | 解释说明 |
|---|---|
| FROM | 【指定基础镜像】构建镜像要基于哪个镜像进行构建? |
| RUN | 【运行命令】构建镜像需要的操作命令;(在基础镜像中运行什么命令?) |
| COPY | 【复制】将宿主机的文件,复制到镜像中; |
| CMD | 【守护进程的命令】运行这个镜像为容器时,用什么命令作为守护进程? |
| LABEL | 【镜像的标签】:主要用于镜像的基础信息、备注信息; |
· LABEL声明标签
| Dockerfile命令 | 解释说明 |
|---|---|
| LABEL | 【OCI规范标签写法】:这么写高级; :one:【org.opencontainers.image.authors】:镜像的作者 :two:【org.opencontainers.image.title】:镜像名称 :three:【org.opencontainers.image.version】:镜像的版本信息(一般写里面的软件版本,如:php7.4) :four:【org.opencontainers.image.description】:镜像的描述信息 :five:【org.opencontainers.image.vendor】:镜像的提供企业名称; :six:【org.opencontainers.image.created】:镜像的创建时间; |
1,编辑Dockerfile
[root@docker01 ubuntu]# vim Dockerfile
FROM ubuntu:22.04
COPY sources.list /etc/apt/sources.list
CMD ["tail","-f","/etc/hosts;"]
# 【标签】
LABEL org.opencontainers.image.authors=bakwite \
org.opencontainers.image.title=ubuntu22.04 \
org.opencontainers.image.version=22.04 \
org.opencontainers.image.description=这是一个好玩的镜像 \
org.opencontainers.image.vendor=bakwite \
org.opencontainers.image.created=20250831
2,构建镜像
[root@docker01 ubuntu]# docker build -t wa:v01 .
3,查看镜像标签
| 查看镜像标签 |
|---|
| docker image inspect 镜像名:标签 --format='{{json .Config.Labels}}' |
# 安装jq命令
[root@docker01 ubuntu]# yum -y install jq
# 查看镜像标签
[root@docker01 ubuntu]# docker image inspect wa:v01 --format='{{json .Config.Labels}}' | jq
{
"org.opencontainers.image.authors": "bakwite",
"org.opencontainers.image.created": "20250831",
"org.opencontainers.image.description": "这是一个好玩的镜像",
"org.opencontainers.image.ref.name": "ubuntu",
"org.opencontainers.image.title": "ubuntu22.04",
"org.opencontainers.image.vendor": "bakwite",
"org.opencontainers.image.version": "22.04"
}
· ADD自动解压删除
| Dockerfile命令 | 解释说明 |
|---|---|
| ADD | 【上传解压后删除原压缩包】,但是,只能自动解压tar包的压缩包哦,zip不可以; |
1,准备压缩包
# 准备压缩包测试
[root@docker01 ubuntu]# tar zcf etc.tar.gz /etc
tar: 从成员名中删除开头的“/”
[root@docker01 ubuntu]# ll
-rw-r--r-- 1 root root 5380032 9月 2 15:30 etc.tar.gz
2,编辑dockerfile
[root@docker01 ubuntu]# cat Dockerfile
FROM ubuntu:22.04
# 创建两个目录
RUN mkdir /111 && \
mkdir /222
# 配置软件安装源,安装解压软件
COPY sources.list /etc/apt/sources.list
RUN apt update && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apt -y install tar
# 【copy】标签,上传解压并删除源压缩包文件
COPY etc.tar.gz /111/
RUN tar xf /111/etc.tar.gz -C /111/ && \
rm -rf /111/etc.tar.gz
# 【ADD】标签,上传、解压后,删除源文件;
ADD etc.tar.gz /222/
# 【CMD】镜像启动为容器后的守护进程命令;nginx的启动并监听命令;
CMD ["tail","-f","/etc/hosts"]
3,启动容器测试
[root@docker01 ubuntu]# docker run -d --name v3 run:v3
d9e6ba6582d7d245bb23962bcd308dc9d6a133228e7c7472b91b5aed3b7aa675
[root@docker01 ubuntu]# docker exec -it v3 bash
root@d9e6ba6582d7:/# ls -l /111
total 12
drwxr-xr-x 124 root root 8192 Sep 1 04:39 etc
root@d9e6ba6582d7:/# ls -l /222
total 12
drwxr-xr-x 124 root root 8192 Sep 1 04:39 etc
· EXPOSE暴露端口
| Dockerfile命令 | 解释说明 |
|---|---|
| EXPOSE | 容器对外暴露的端口号; |
1,构建nginx镜像
# 编辑Dockerfile
[root@docker01 ubuntu]# cat Dockerfile
FROM ubuntu:22.04
COPY sources.list /etc/apt/sources.list
RUN apt update && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apt -y install nginx
CMD ["nginx","-g","daemon off;"]
# 开始构建
[root@docker01 ubuntu]# docker build -t nginx_wa:v1 .
2,启动容器-P随机端口映射
# 先启动官方的nginx镜像
[root@docker01 ubuntu]# docker run -dP --name nginx nginx:stable
# 在启动我们自己构建的nginx镜像
[root@docker01 ubuntu]# docker run -dP --name nginx_wa nginx_wa:v1
5a6454a39014d4a5b69ce4c4fe03a5f658a9903e957d4f07b4a3a55dbf4bd6ab
3,查看容器列表
你会发现:
- 我们自己构建的nginx镜像,启动容器后,无法使用【-P】进行随机端口映射;
- 而官方的镜像,启动容器后使用【-P】进行随机端口映射就成功了;
[root@docker01 ubuntu]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5a6454a39014 nginx_wa:v1 "nginx " 44 seco Up nginx_wa
d701c89aa705 nginx:stable "/docke" About a Up 0.0.0.0:32769->80/tcp, :::32769->80/tcp nginx

4,Dockerfile加入EXPOSE暴露端口
[root@docker01 ubuntu]# cat Dockerfile
FROM ubuntu:22.04
COPY sources.list /etc/apt/sources.list
RUN apt update && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apt -y install nginx
# 【EXPOSE】对外暴露容器端口
EXPOSE 80
CMD ["nginx","-g","daemon off;"]
5,再次使用-P随机映射
[root@docker01 ubuntu]# docker run -dP --name wa nginx_wa:v2
# 查看docker容器列表,发现随机映射成功
[root@docker01 ubuntu]# docker ps

· WORKDIR指定工作目录
| Dockerfile命令 | 解释说明 |
|---|---|
| WORKDIR | 设置当用户进入容器时,默认的所在路径; |
1,编辑Dockerfile
[root@docker01 ubuntu]# cat Dockerfile
FROM ubuntu:22.04
COPY sources.list /etc/apt/sources.list
RUN apt update && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apt -y install nginx
EXPOSE 80
# 【WORKDIR】工作路径设置
WORKDIR /usr/share/nginx/html/
CMD ["nginx","-g","daemon off;"]
2,构建镜像
[root@docker01 ubuntu]# docker build -t nginx_wa:v3 .
3,运行容器测试
# 运行容器
[root@docker01 ubuntu]# docker run -d --name wa03 nginx_wa:v3
71fb40f37730163e0719601baa521bb36729079587a346199ffd1b083f481a4d
# 进入容器中,查看当前路径
[root@docker01 ubuntu]# docker exec -it wa03 bash
root@71fb40f37730:/usr/share/nginx/html# pwd
/usr/share/nginx/html
· VOLUME指定匿名存储卷
| Dockerfile命令 | 解释说明 |
|---|---|
| VOLUME | 指定匿名存储卷; |
1,先清空存储卷
[root@docker01 ubuntu]# docker volume prune -f
[root@docker01 ubuntu]# docker volume ls
DRIVER VOLUME NAME
2,编辑Dockerfile
[root@docker01 ubuntu]# cat Dockerfile
FROM ubuntu:22.04
COPY sources.list /etc/apt/sources.list
RUN apt update && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apt -y install nginx
EXPOSE 80
WORKDIR /usr/share/nginx/html/
# 【VOLUME】指定匿名存储卷
VOLUME /usr/share/nginx/html/
CMD ["nginx","-g","daemon off;"]
3,构建镜像
[root@docker01 ubuntu]# docker build -t nginx_wa:v4 .
4,启动容器查看存储卷
[root@docker01 ubuntu]# docker run -d --name wa04 nginx_wa:v4
46f67a1030ecfb640f76b2bc27826ef9c904441393f7490380dfe22f7e6ddca0
# 发现自动创建了存储卷
[root@docker01 ubuntu]# docker volume ls
DRIVER VOLUME NAME
local 809733cdb4e9ba4271429b98ea2d62e670a269d6265b83cfd1fc582014aaf7b5
· ENTRYPOINT不可修改的执行命令
| Dockerfile命令 | 解释说明 |
|---|---|
| ENTRYPOINT | 【容器运行的守护进程命令】-不可被修改,运行容器时传入命令,会当做参数传递给守护进程命令; |
| CMD | 【容器运行的守护进程命令】-可以被修改、运行容器时传入命令,会替换守护进程命令; |
| ENTRYPOINT搭配CMD | 【CMD】将作为参数传递给【ENTRYPOINT】; |
1,启动CMD命令构建的镜像
# 启动之前构建的【CMD】守护进程命令的镜像为容器
[root@docker01 ubuntu]# docker run -d --name wa05 nginx_wa:v4
98a10f6aa95f63ebe11bc05467717193e698c7018e0c08b4837390571dc1b77c
# 插卡内容器列表,可以看到COMMAND列的运行命令
[root@docker01 ubuntu]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
98a10f6aa95f nginx_wa:v4 "nginx -g 'daemon of…" 17 seconds ago Up 17 seconds 80/tcp wa05
2,启动并修改容器的运行命令
# 启动容器,并修改守护进程命令为sleep 10
[root@docker01 ubuntu]# docker run -d --name wa06 nginx_wa:v4 sleep 10
87071ffee2ceb1e847b4688cd0c48bcef76e4d124e4fe847e605f2dd7033fb9a
# 查看容器列表,可以看到,守护进程COMMAND列的命令变成了:sleep 10
[root@docker01 ubuntu]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
87071ffee2ce nginx_wa:v4 "sleep 10" 2 seconds ago Up 1 second 80/tcp wa06
98a10f6aa95f nginx_wa:v4 "nginx -g 'daemon of…" 3 minutes ago Up 3 minutes 80/tcp wa05
# 10秒后再次查看容器列表,发现容器退出了
[root@docker01 ubuntu]# docker ps -a

3,构建一个不可修改命令的镜像
# 编辑Dockerfile
[root@docker01 ubuntu]# cat Dockerfile
FROM ubuntu:22.04
COPY sources.list /etc/apt/sources.list
RUN apt update && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apt -y install nginx
EXPOSE 80
WORKDIR /usr/share/nginx/html/
VOLUME /usr/share/nginx/html/
# 【ENTRYPOINT】不可修改的守护进程命令,去掉前台运行的参数【daemin off;】
ENTRYPOINT ["nginx","-g"]
# 运行镜像为容器,并传递参数【daemon off;】
[root@docker01 ubuntu]# docker run -d --name wa06 nginx_wa:v6 daemon off;
8fe7522b3b71f0535ace5e7710ec235c3c45e9c682e21f811b93097a24c5f563
# 查看容器列表
[root@docker01 ubuntu]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
45faf3ff90b8 nginx_wa:v5 "nginx -g 'daemon of…" 4 minutes ago Up 4 minutes 80/tcp wa09

4,ENTRYPOINT与CMD搭配使用
# 编辑Dockerfile
[root@docker01 ubuntu]# vim Dockerfile
FROM ubuntu:22.04
COPY sources.list /etc/apt/sources.list
RUN apt update && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apt -y install nginx
EXPOSE 80
WORKDIR /usr/share/nginx/html/
VOLUME /usr/share/nginx/html/
# 【ENTRYPOINT】与【CMD】搭配使用
ENTRYPOINT ["nginx"]
CMD ["-g","daemon off;"]
# 构建镜像
[root@docker01 ubuntu]# docker build -t nginx_wa:v7 .
# 运行容器
[root@docker01 ubuntu]# docker run -d --name wa10 nginx_wa:v7
ecb933b0ee2d182805eb2633b8ca4a9ead8331c85c1c04cd45c1667da9381be3
# 查看容器,可以看到COMMAND列的命令是二者的组合;
[root@docker01 ubuntu]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ecb933b0ee2d nginx_wa:v7 "nginx -g 'daemon of…" 2 seconds ago Up 2 seconds 80/tcp wa10
· HEALTHCHECK健康检查
| Dockerfile命令 | 解释说明 |
|---|---|
| HEALTHCHECK | 【容器的健康检查】:想要使用这个命令,前提是容器中有curl命令; 【参数】说明: :one:--interval=30s 【容器启动后】每30s检查一次(默认30s) :two:--start-interval=5s 【容器启动时】每5s检查一次(密集检查,注意,此/老版本不支持); :three:--start-period=30s 表示容器启动多久开始健康检查(默认是30s) :four:--timeout=10s 健康检查的超时时间(默认是30s) :five:--retries=3 表示连续3次(默认)健康检查失败后,容器状态变为不健康(unhealthy) ; :six:【CMD curl http://localhost/ || exit 1】:健康检查的命令(靠什么进行健康检查?); |
# 健康检查命令说明:
curl -f http://localhost || exit 1
#如果前面curl命令执行失败,则执行后面的exit命令、也就是退出当前容器的意思,所以,只要检查失败,那么容器就会退出;
1,编辑Dockerfile
[root@docker01 ubuntu]# vim Dockerfile
FROM ubuntu:22.04
COPY sources.list /etc/apt/sources.list
RUN apt update && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apt -y install nginx
EXPOSE 80
WORKDIR /usr/share/nginx/html/
VOLUME /usr/share/nginx/html/
# 【HEALTHCHECK】健康检查
RUN apt -y install curl
HEALTHCHECK --start-period=30s --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost || exit 1
ENTRYPOINT ["nginx"]
CMD ["-g","daemon off;"]
2,构建镜像
[root@docker01 ubuntu]# docker build -t nginx_wa:v10 .
3,启动容器查看检查过程
# 启动容器
[root@docker01 ubuntu]# docker run -d --name v110 nginx_wa:v10
8eaf7e52521f460cd735e6fbe28e9a950e6530f7fed95198b3ec589f17a7ee7a
# 查看容器列表(发现状态是启动中【health: starting】)
[root@docker01 ubuntu]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8eaf7e52521f nginx_wa:v10 "nginx -g " 3 seconds ago Up 2 seconds (health: starting) 80/tcp v110
# 启动30秒后再查看容器列表(从【health: starting】变成了【health】)
[root@docker01 ubuntu]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8eaf7e52521f nginx_wa:v10 "nginx -g…" 30 seconds ago Up 30 seconds (healthy) 80/tcp v110
· ENV与ARG设置容器环境变量
| Dockerfile命令 | 解释说明 |
|---|---|
| ENV | 【设置镜像的环境变量】这个变量一直存在:构建的过程、启动后的容器,都会有这个环境变量; |
| ARG | 【设置镜像的环境变量】这个环境变量只存在于:构建的过程中,构建结束后,环境变量也随之结束、消失; |
1,编辑Dockerfile
[root@docker01 ubuntu]# vim Dockerfile
FROM ubuntu:22.04
# 声明ENV环境变量【一直存在】
ENV name=bakwite \
password=888888
# 声明ARG环境变量【只存在于构建镜像阶段】
ARG username=zhangsan \
userpassword=123456
RUN echo $name >> /user.txt && \
echo $password >> /user.txt && \
echo $username >> /user.txt && \
echo $userpassword >> /user.txt
CMD ["tail","-f","/etc/hosts"]
2,构建镜像
[root@docker01 ubuntu]# docker build -t env:v1 .
3,启动容器测试环境变量
# 启动容器
[root@docker01 ubuntu]# docker run -d --name env01 env:v1
5d8e4d0043133d1fc3e8908e6d2fe295e2256c7d74858a48927cf6c827b779c8
# 进入容器
[root@docker01 ubuntu]# docker exec -it env01 bash
# 查看环境变量,发现ARG的环境变量没了,只剩下ENV设置的环境变量了;
root@5d8e4d004313:/# env
......
password=888888
......
name=bakwite
......
# 查看构建时RUN命令写入的文件,发现4个变量都写入了,说明,build构建镜像时,ARG是存在的,构建后消失了;
root@5d8e4d004313:/# cat user.txt
bakwite
888888
zhangsan
123456
4,构建时替换ARG变量
[root@docker01 ubuntu]# docker build -t env:v3 --build-arg username=lisi .
[root@docker01 ubuntu]# docker run -d --name env03 env:v3
e2a71db1823d8c7ea8a9c2f9c43b3e0c2ca22894ed1fdd453b3153915103304e
[root@docker01 ubuntu]# docker exec -it env03 bash
root@e2a71db1823d:/# cat user.txt
bakwite
888888
lisi
123456
· ONBUILD引用触发器
专门的后门,黑客专用
| Dockerfile命令 | 解释说明 |
|---|---|
| ONBUILD | 设置这个指令后,当有人用FROM指定这个镜像为基础镜像时,会触发ONBUILD中的命令; |
1,构建一个ONBUILD镜像
# 编辑Dockerfile
[root@docker01 ubuntu]# cat Dockerfile
FROM ubuntu:22.04
ONBUILD RUN mkdir /bakwite.txt && touch /100.txt
CMD ["tail","-f","/etc/hosts"]
# 构建镜像
[root@docker01 ubuntu]# docker build -t onbuild:v1 .
2,构建镜像引用ONBUILD镜像
# 编辑Dockerfile
[root@docker01 ubuntu]# cat Dockerfile
FROM onbuild:v1
CMD ["tail","-f","/etc/hosts"]
# 构建镜像
[root@docker01 ubuntu]# docker build -t img:v1 .
3,启动容器查看
[root@docker01 ubuntu]# docker run -d --name img img:v1
[root@docker01 ubuntu]# docker exec -it img bash
root@f71673dc1dda:/# ls -l
......
-rw-r--r-- 1 root root 0 Sep 3 03:12 bakwite.txt
drwxr-xr-x 2 root root 6 Sep 3 03:12 100.txt
· USER指定运行用户
| Dockerfile命令 | 解释说明 |
|---|---|
| USER | 指定这个镜像启动为容器时的运行用户; |
1,编辑Dockerfile
[root@docker01 ubuntu]# cat Dockerfile
FROM ubuntu:22.04
RUN useradd -M -s /sbin/nologin bakwite
USER bakwite
CMD ["tail","-f","/etc/hosts"]
2,运行容器查看用户
[root@docker01 ubuntu]# docker run -d --name user user:v1
aa64bee147153e0a66d136f1d98b5aeb16ef98cc44e6d75d33b397aaad9073e6
[root@docker01 ubuntu]# docker exec -it user bash
bakwite@aa64bee14715:/$ whoami
bakwite
· FROM scratch不指定基础镜像
| Dockerfile命令 | 解释说明 |
|---|---|
| FROM scratch | 表示不指定基础镜像; |
1,构建一个打包根目录的镜像
[root@docker01 ubuntu]# cat Dockerfile
FROM alpine:latest
# 打包压缩根目录
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories && \
apk update && \
apk add --no-cache tar && \
tar zcf wa_sys.tar.gz \
--exclude=/wa_sys.tar.gz \
--exclude=/sys \
--exclude=/proc \
--exclude=/dev \
--exclude=/run \
--exclude=/tmp \
--exclude=/var/cache \
/*
CMD ["tail","-f","/etc/hosts"]
2,启动容器并复制出压缩包
# 启动容器
[root@docker01 ubuntu]# docker run -d --name sys01 sys:v1
# 进入容器修改系统文件
[root@docker01 ubuntu]# docker exec -it sys01 sh
/ # vi /etc/os-release
NAME="bakwite Linux"
ID=bakwite
VERSION_ID=1.0.0
PRETTY_NAME="bakwite Linux v1.0.0"
HOME_URL="https://www.bakwite.com"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
# 退出容器,将压缩包导出;
[root@docker01 ubuntu]# docker cp sys01:/wa_sys.tar.gz ./
[root@docker01 ubuntu]# ll
......
-rw-r--r-- 1 root root 3892386 9月 3 12:05 wa_sys.tar.gz
3,编辑Dockerfile不指定基础镜像
[root@docker01 ubuntu]# cat Dockerfile
FROM scratch
ADD wa_sys.tar.gz /
CMD ["tail","-f","/etc/hosts"]
4,构建镜像并启动容器
# 构建镜像
[root@docker01 ubuntu]# docker build -t wasys:v1 .
# 启动容器
[root@docker01 ubuntu]# docker run -d --name wasys01 wasys:v1
6e8ef576078705928ea68dc85ccb05856af58f58553a83941be96f2c3bed67b1
[root@docker01 ubuntu]# docker exec -it wasys01 sh
/ # cat /etc/os-release
NAME="bakwite Linux"
ID=bakwite
VERSION_ID=1.0.0
PRETTY_NAME="bakwite Linux v1.0.0"
HOME_URL="https://www.bakwite.com"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
6,多阶段构建镜像
· 基于alpine构建小游戏镜像
要求:
- 使用使用alpine作为镜像
- 编译安装Tengine网站服务
- 构建一键启动小游戏的镜像;
1,准备环境
准备alpine基础镜像
[root@docker01 ubuntu]# docker images
......
alpine latest 9234e8fb04c4 7 weeks ago 8.31M
准备小游戏安装包
[root@docker01 ubuntu]# cd ../alpine
# 上传小游戏压缩包
[root@docker01 alpine]# rz -E
[root@docker01 alpine]# ll
总用量 216948
-rw-r--r-- 1 root root 222151423 12月 4 2023 game.tar.gz
2,准备nginx配置文件
子配置文件
[root@docker01 alpine]# cat game.conf
server {
listen 80;
server_name localhost;
root /code/bird;
location / {
index index.html;
}
}
server {
listen 81;
server_name localhost;
root /code/chengbao;
location / {
index index.html;
}
}
server {
listen 82;
server_name localhost;
root /code/dayu;
location / {
index index.html;
}
}
server {
listen 83;
server_name localhost;
root /code/feijidazhan;
location / {
index index.html;
}
}
server {
listen 84;
server_name localhost;
root /code/huangjinkuanggong;
location / {
index index.html;
}
}
server {
listen 85;
server_name localhost;
root /code/liferestart;
location / {
index index.html;
}
}
server {
listen 86;
server_name localhost;
root /code/maliao;
location / {
index index.html;
}
}
server {
listen 87;
server_name localhost;
root /code/menghuanmonizhan;
location / {
index index.html;
}
}
server {
listen 88;
server_name localhost;
root /code/motuo;
location / {
index index.html;
}
}
server {
listen 89;
server_name localhost;
root /code/pingtai;
location / {
index index.html;
}
}
server {
listen 90;
server_name localhost;
root /code/pinshu;
location / {
index index.html;
}
}
server {
listen 91;
server_name localhost;
root /code/qieshuiguo;
location / {
index index.html;
}
}
server {
listen 92;
server_name localhost;
root /code/tanke;
location / {
index index.html;
}
}
server {
listen 93;
server_name localhost;
root /code/wangzhezhicheng;
location / {
index index.html;
}
}
server {
listen 94;
server_name localhost;
root /code/xiaobawang;
location / {
index index.html;
}
}
server {
listen 95;
server_name localhost;
root /code/zhiwudazhanjiangshi;
location / {
index index.html;
}
}
server {
listen 96;
server_name localhost;
root /code/zhiwuVSjiangshi;
location / {
index index.html;
}
}
主配置文件
[root@docker01 alpine]# cat ../ubuntu/nginx.conf
user nginx;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
}
3,编辑Dockerfile
| 说明 | 位置 |
|---|---|
| alpine的软件源配置文件 | /etc/apk/repositories |
| alpine的更新配置源命令 | apk update |
| alpine的安装软件命令 | apk add nginx |
| alpine创建用户 | adduser -D -s /sbin/nologin nginx :one:【-D】:表示不设置密码和家目录 :two:【-s】:指定命令解释器 |

[root@docker01 alpine]# vim Dockerfile
# [FROM] 指定基础镜像
FROM alpine:latest
# [LABEL]声明标签信息
LABEL org.opencontainers.image.authors=bakwite \
org.opencontainers.image.title=game \
org.opencontainers.image.version=1.0.0 \
org.opencontainers.image.description=bakwite \
org.opencontainers.image.vendor=bakwite \
org.opencontainers.image.created=20250903
# [RUN]安装基础软件,与编译安装Tengine
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories && \
apk update && \
apk add nginx && \
rm -rf /var/cache && \
mkdir -p /etc/nginx/conf.d/ && \
mkdir /code
# 暴露端口
EXPOSE 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
# [COPY] 上传nignx配置文件
COPY nginx.conf /etc/nginx/nginx.conf
COPY game.conf /etc/nginx/conf.d/game.conf
# [ADD]
ADD game.tar.gz /code/
# [CMD] 前台启动nginx
CMD ["nginx","-g","daemon off;"]
4,构建镜像启动容器
# 构建镜像
[root@docker01 alpine]# docker build --network=host -t game:v1 .
# 启动容器
[root@docker01 alpine]# docker run -d -p80-96:80-96 --name game_web game:v1
5,浏览器访问测试
10.0.0.91:80
10.0.0.91:81
10.0.0.91:82
10.0.0.91:83
10.0.0.91:84
10.0.0.91:85
10.0.0.91:86
10.0.0.91:87
10.0.0.91:88
10.0.0.91:89
10.0.0.91:90
10.0.0.91:91
10.0.0.91:92
10.0.0.91:93
10.0.0.91:94
10.0.0.91:95
10.0.0.91:96

6,查看镜像列表对比大小
[root@docker01 alpine]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
game v5 ca24de4e9196 5 minutes ago 585MB # 构建完:585M
...
alpine latest 9234e8fb04c4 7 weeks ago 8.31MB # 基础镜像8M
7,查看构建过程
查看构建过程我们可以清晰的看到:
- 每一个步骤、中间层镜像的SIZE大小;
[root@docker01 alpine]# docker history game:v5
IMAGE CREATED CREATED BY SIZE COMMENT
ca24de4e9196 21 minutes ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B
f908e0ecc546 21 minutes ago /bin/sh -c #(nop) ADD file:8f9d68b03b6f51603… 277MB
716e60202567 21 minutes ago /bin/sh -c #(nop) COPY file:1597110106ce5d13… 1.84kB
757cb28079b2 21 minutes ago /bin/sh -c #(nop) COPY file:92764060e292ac10… 626B
0094bfdacbe2 34 minutes ago /bin/sh -c #(nop) EXPOSE 80 81 82 83 84 85 … 0B
188cbdc7d403 38 minutes ago /bin/sh -c sed -i "s@dl-cdn.alpinelinux.org@… 300MB
b25e993674bd 51 minutes ago /bin/sh -c #(nop) ENV CONF=./configure --pr… 0B
48239e983373 51 minutes ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
9234e8fb04c4 7 weeks ago CMD ["/bin/sh"] 0B buildkit.dockerfile.v0
<missing> 7 weeks ago ADD alpine-minirootfs-3.22.1-x86_64.tar.gz /… 8.31MB buildkit.dockerfile.v0
· 多阶段构建缩小镜像
思考:
- 编译tengine的过程,所需要安装的依赖软件包,在构建完成之后,我们是不再需要的;
- 所以,能不能先编译,然后在打包镜像的时候,只保留编译好的tengine的软件包呐?
- 就此,我们来进入多阶段构建;
1,编辑Dockerfile
[root@docker01 alpine]# vim Dockerfile
############################################################
# 【第一阶段构建】:指定基础镜像,并起个别名:by_tengine
FROM alpine:latest AS by_tengine
# [ENV]声明环境变量
ENV CONF="./configure --prefix=/web-server/tengine/ \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_mp4_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--add-module=modules/ngx_http_upstream_check_module/ \
--add-module=modules/ngx_http_upstream_session_sticky_module"
# [RUN]安装基础软件,与编译安装Tengine
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories && \
apk update && \
apk add wget gcc g++ make pcre pcre-dev openssl-dev zlib-dev && \
wget https://tengine.taobao.org/download/tengine-3.1.0.tar.gz && \
tar xf tengine-3.1.0.tar.gz && \
cd tengine-3.1.0 && \
${CONF} && \
make -j `nproc` && \
make install
########################################################################################
# 【第二阶段构建】
FROM alpine:latest
# [LABEL]声明标签信息
LABEL org.opencontainers.image.authors=bakwite \
org.opencontainers.image.title=game \
org.opencontainers.image.version=1.0.0 \
org.opencontainers.image.description=bakwite \
org.opencontainers.image.vendor=bakwite \
org.opencontainers.image.created=20250903
#【重点】:从第一阶段的镜像中,取出编译好的tengine软件包放到当前阶段镜像中;
COPY --from=by_tengine /web-server /web-server
RUN ln -s /web-server/tengine/sbin/nginx /usr/sbin && \
sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories && \
apk add pcre pcre-dev && \
mkdir -p /etc/nginx/conf.d/ && \
mkdir /code && \
rm -rf /var/cache && \
adduser -D -s /sbin/nologin nginx
# 暴露端口
EXPOSE 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
# [COPY] 上传nignx配置文件
COPY nginx.conf /web-server/tengine/conf/nginx.conf
COPY game.conf /etc/nginx/conf.d/
# [ADD]
ADD game.tar.gz /code/
# [CMD] 前台启动nginx
CMD ["nginx","-g","daemon off;"]
2,开始构建
[root@docker01 alpine]# docker build -t game:v8 .
3,对比镜像的大小
你会发现:
- 在【使用多阶段构建】之后,足足节省了一半的镜像存储空间;
[root@docker01 alpine]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
game v8 2a2fef618790 4 minutes ago 299MB
......
game v5 ca24de4e9196 55 minutes ago 585MB
7,服务日志与容器日志合并
我们知道:
- 容器有自己的操作日志
- 容器内的服务,也有服务的日志;
- 如何将两个日志统一成一个日志????
| 例如 | 位置 |
|---|---|
| nginx日志 | 容器内: /var/log/nginx/access,log /var/log/nginx/error.log |
| 容器日志 | 宿主机内:/var/lib/docker/容器ID/容器ID-json.log |
· 自定义容器标准输出日志
1,准备nginx子
[root@docker01:/build]# vim web.conf
server {
listen 80;
server_name localhost;
root /code;
location / {
index index.html;
}
}
2,准备nginx主配置文件
| 重定向 | 进程指向 | 解释说明 |
|---|---|---|
| /dev/stderr | /proc/进程号/fd/2 | 标准错误输出 |
| /dev/stdout | /proc/进程号/fd/1 | 标准输出 |
| /dev/stdin | /proc/进程号/fd/0 | 标准输入 |
[root@docker01:/build]# vim nginx.conf
user nginx;
worker_processes auto;
pid /run/nginx.pid;
# 【错误日志】直接定向到容器【标准错误输出】设备上;
error_log /dev/stderr warn;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 访问日志直接定向到容器的【标准输出设备】上;
access_log /dev/stdout main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
}
3,编辑dockerfile
[root@docker01 alpine]# vim Dockerfile
# [FROM] 指定基础镜像
FROM alpine:latest
# [ENV]声明环境变量
ENV CONF="./configure --prefix=/web-server/tengine/ \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_mp4_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--add-module=modules/ngx_http_upstream_check_module/ \
--add-module=modules/ngx_http_upstream_session_sticky_module"
# [RUN]安装基础软件,与编译安装Tengine
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories && \
apk update && \
apk add wget gcc g++ make pcre pcre-dev openssl-dev zlib-dev && \
wget https://tengine.taobao.org/download/tengine-3.1.0.tar.gz && \
tar xf tengine-3.1.0.tar.gz && \
cd tengine-3.1.0 && \
${CONF} && \
make -j `nproc` && \
make install && \
ln -s /web-server/tengine/sbin/nginx /usr/sbin && \
rm -rf /var/cache && \
mkdir -p /etc/nginx/conf.d/ && \
mkdir /code && \
adduser -D -s /sbin/nologin nginx
# [COPY] 上传nignx配置文件
COPY nginx.conf /web-server/tengine/conf/nginx.conf
COPY web.conf /etc/nginx/conf.d/
# [CMD] 前台启动nginx
CMD ["nginx","-g","daemon off;"]
4,开始构建
[root@docker01:/build]# docker build -t tengine:v1 .
5,启动容器
[root@docker01:/build]# docker run -d -p80:80 --name t1 tengine:v1
02e42bdf7676a5fcac55b925285c025b44a8b0ddca0669a830c6c644d27b10ef
6,浏览器访问
多刷新几次网页
10.0.0.91

7,查看容器日子(定向成功)
[root@docker01:/build]# docker logs t1
2025/09/11 06:26:44 [error] 7#0: *1 directory index of "/code/" is forbidden, client: 10.0.0.1, server: localhost, request: "GET / HTTP/1.1", host: "10.0.0.121"
10.0.0.1 - - [11/Sep/2025:06:26:44 +0000] "GET / HTTP/1.1" 403 558 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" "-"
......
· 软连接nginx日志到标准输出(推荐)
1,准备nginx子配置文件
[root@docker01:/build]# vim web.conf
server {
listen 80;
server_name localhost;
root /code;
location / {
index index.html;
}
}
2,准备nginx主配置文件
[root@docker01:/build]# vim nginx.conf
user nginx;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log warn;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
}
3,编辑dockerfile
[root@docker01 alpine]# vim Dockerfile
# [FROM] 指定基础镜像
FROM alpine:latest
# [ENV]声明环境变量
ENV CONF="./configure --prefix=/web-server/tengine/ \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_mp4_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--add-module=modules/ngx_http_upstream_check_module/ \
--add-module=modules/ngx_http_upstream_session_sticky_module"
# [RUN]安装基础软件,与编译安装Tengine
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories && \
apk update && \
apk add wget gcc g++ make pcre pcre-dev openssl-dev zlib-dev && \
wget https://tengine.taobao.org/download/tengine-3.1.0.tar.gz && \
tar xf tengine-3.1.0.tar.gz && \
cd tengine-3.1.0 && \
${CONF} && \
make -j `nproc` && \
make install && \
ln -s /web-server/tengine/sbin/nginx /usr/sbin && \
rm -rf /var/cache && \
mkdir -p /etc/nginx/conf.d/ && \
mkdir -p /var/log/nginx/ && \
# 主要是这里的软连接;
ln -sf /dev/stdout /var/log/nginx/access.log && \
ln -sf /dev/stderr /var/log/nginx/error.log && \
mkdir /code && \
adduser -D -s /sbin/nologin nginx
# [COPY] 上传nignx配置文件
COPY nginx.conf /web-server/tengine/conf/nginx.conf
COPY web.conf /etc/nginx/conf.d/
# [CMD] 前台启动nginx
CMD ["nginx","-g","daemon off;"]
4,开始构建
[root@docker01:/build]# docker build -t tengine:v1 .
5,启动容器
[root@docker01:/build]# docker run -d --name c1 -p80:80 tengine:v1
6,浏览器访问测试
10.0.0.91

7,查看容器日志
[root@docker01:/build]# docker logs c1
......
10.0.0.1 - - [11/Sep/2025:06:50:01 +0000] "GET / HTTP/1.1" 403 558 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" "-"
2025/09/11 06:51:03 [error] 6#0: *1 directory index of "/code/" is forbidden, client: 10.0.0.1, server: localhost, request: "GET / HTTP/1.1", host: "10.0.0.121"
10.0.0.1 - - [11/Sep/2025:06:51:03 +0000] "GET / HTTP/1.1" 403 558 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" "-"
2025/09/11 06:51:03 [error] 6#0: *1 directory index of "/code/" is forbidden, client: 10.0.0.1, server: localhost, request: "GET / HTTP/1.1", host: "10.0.0.121"
· 日志位置
[root@docker01:/build]# ll /var/lib/docker/containers/容器的id号码/容器的id号-json.log
8,Dockerfile调优方法
· 构建过程分析
1,环境准备
创建测试目录
[root@docker01 alpine]# cd ..
[root@docker01 dockerfile]# mkdir test
[root@docker01 dockerfile]# cd test/
2,构建一个alpine的nginx镜像
编辑Dockerfile
[root@docker01 test]# vim Dockerfile
FROM alpine:latest
# 配置软件源,安装软件
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories && \
apk update && \
apk add nginx && \
rm -rf /var/cache/
CMD ["nginx","-g","daemon off;"]
开始构建
[root@docker01 test]# docker build -t test:v1 .
3,查看镜像构建过程
[root@docker01 test]# docker image history test:v1

4,总结
在Dockerfile构建镜像的过程中:
- 每一个Dockerfile指令,都会生成一个【中间层-镜像】;
· 减少指令的书写
1,构建另一个镜像
每一个命令都书写一个RUN
# 编辑Dockerfile
[root@docker01 test]# vim Dockerfile
FROM alpine:latest
# 配置软件源,安装软件
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories
RUN apk update
RUN apk add nginx
RUN rm -rf /var/cache/
CMD ["nginx","-g","daemon off;"]
# 构建镜像
[root@docker01 test]# docker build -t test:v2 .
2,对比【v1】与【v2】构建过程
[root@docker01 test]# docker image history test:v1
[root@docker01 test]# docker image history test:v2

3,对比两个镜像大小
[root@docker01 test]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test v2 1d87b7987479 About a minute ago 12.8MB
test v1 273d66aab7cb 5 minutes ago 10.3MB
......
4,总结
# 在书写Dockerfile时
- 要尽量减少【指令】的书写;
- 因为每一个指令都会生成一个中间层的镜像;
- 最终镜像时所有中间层镜像的总和;
- 所以,只要中间层镜像层数变少,最后生成的最终镜像才能最小;

· 排除不必要的文件
1,清除历史/缓存镜像
[root@docker01 test]# docker image rm -f test:v1
[root@docker01 test]# docker image rm -f test:v2
[root@docker01 test]# docker image prune -f
2,重新构建镜像v1
[root@docker01 test]# docker build -t test:v1 .
Sending build context to Docker daemon 2.048kB
......
3,Dockerfile目录生成大文件
[root@docker01 test]# dd if=/dev/zero of=nouse.txt bs=1M count=1024
记录了1024+0 的读入
记录了1024+0 的写出
1073741824字节(1.1 GB,1.0 GiB)已复制,0.693371 s,1.5 GB/s
[root@docker01 test]# ll -h
总用量 1.1G
-rw-r--r-- 1 root root 226 9月 3 13:36 Dockerfile
-rw-r--r-- 1 root root 1.0G 9月 3 13:57 nouse.txt
4,再次构建镜像v2
[root@docker01 test]# docker build -t test:v2 .
Sending build context to Docker daemon 1.074GB
......
5,对比两次构建的不同

6,总结
在Dockerfile构建镜像的时候:
- docker会将当前目录下的所有文件都打包发送给docker daemon守护进程;
- 如此一来,就会很大程度上降低Dockerfile的构建效率、构建速度;
- 所以,在构建镜像的时候,当前目录不要有其他没必要的文件出现;
7,排除非必要的文件
如果有一些文件非常大,但是又不能删除,那么在构建的时候,我们可以:
- 编辑一个隐藏文件:【.dockerignore】
- 将不打包的文件名写入其中,再次构建的时候,就不会打包不必要的文件了;
# 编辑.dockerignore文件【文件内容支持*等正则符号】
[root@docker01 test]# vim .dockerignore
nouse.txt
# 再次构建v3镜像,可以看到,打包的内容不再那么大了;
[root@docker01 test]# docker build -t test:v3 .
Sending build context to Docker daemon 3.072kB
......
· 不经常变更的指令写在上面
1,准备环境
[root@docker01 test]# docker image rm test:v1
[root@docker01 test]# docker image rm test:v2
[root@docker01 test]# docker image rm test:v3
2,先构建一个镜像v1
# 编辑dockerfile
[root@docker01 test]# cat Dockerfile
FROM alpine:latest
# 配置软件源,安装软件
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories
RUN apk update
RUN apk add nginx
RUN rm -rf /var/cache/
CMD ["nginx","-g","daemon off;"]
# 构建v1镜像
[root@docker01 test]# docker build -t test:v1 .
3,修改Dockerfile构建v2镜像
编辑Dockerfile,在最上面随便插入一个Dockerfile指令
[root@docker01 test]# vim Dockerfile
FROM alpine:latest
RUN mkdir 111 222 333
# 配置软件源,安装软件
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories
RUN apk update
RUN apk add nginx
RUN rm -rf /var/cache/
CMD ["nginx","-g","daemon off;"]
构建v2镜像
[root@docker01 test]# docker build -t test:v2 .
4,修改Dockerfile构建v3镜像
编辑Dockerfile,在最下面随便插入一个Dockerfile指令
[root@docker01 test]# cat Dockerfile
FROM alpine:latest
# 配置软件源,安装软件
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories
RUN apk update
RUN apk add nginx
RUN rm -rf /var/cache/
RUN mkdir 111 222 333
CMD ["nginx","-g","daemon off;"]
构建v3镜像
[root@docker01 test]# docker build -t test:v3 .
5,对比v2和v3的构建过程
在构建的过程中:
- 你可以清晰的感受到,v3镜像的构建速度,比v2快很多;
- 如下图所示,v3是将源v1的构建过程的最下方插入的指令,所以上面的都是利用v1构建过程的缓存;
- 而比较v2,是在最扇面插入的指令,所以没有缓存的中间层镜像可以利用,所以v2没有利用到v1的缓存;
- 总结:如果想要每次修改Dockerfile构建镜像,还想要追求速度效率,那么:
- 不改动的指令都放在上面;
- 要改动的指令都放在下面;
- 如此就能充分利用缓存,每次构建的速度都会更快。

9,案例
使用docker build手动构建镜像:
要求:
- 使用alpine作为基础镜像;
- 实现负载均衡;
- 要求访问结果如下:
- 当前时间,
- 客户端ip、
- xff真实ip、
- 访问的主机名称、
- 负载均衡的请求时间、
- 负载均衡的ip地址、
- 客户端ua信息、
- 响应状态码;
· 构建前准备工作
1,创建工作目录
[root@docker01:~]# mkdir -p /dockerfile/lb
[root@docker01:~]# cd /dockerfile/lb
[root@docker01:~]#
2,准备负载均衡器nginx子配置文件
[root@docker01:/dockerfile/lb]# vim lb.conf
upstream web-server {
server web01;
server web02;
}
server {
listen 80;
location / {
proxy_pass http://web-server;
proxy_set_header Host $http_host;
}
}
3,准备web服务的子配置文件
[root@docker01:/dockerfile/lb]# vim web.conf
server {
listen 80;
server_name localhost;
location / {
return 200 "{
'client_IP': $remote_addr,
'user_URI': $request_uri,
'request_web_IP': $server_addr,
'request_web_HOSTNAME': $hostname,
'request_HOST': $host,
'user_UA': $http_user_agent,
'response_byte_SIZE': $body_bytes_sent,
'response_status_NUM': $status,
'@timestamp': $time_iso8601
}\n";
}
}
4,编辑lb的dockerfile
[root@docker01:/dockerfile/lb]# vim lb-Dockerfile
FROM alpine:latest
# 【标签】
LABEL org.opencontainers.image.authors=bakwite \
org.opencontainers.image.title=alpine-lb \
org.opencontainers.image.version=v1.0.0 \
org.opencontainers.image.description=web01 \
org.opencontainers.image.vendor=bakwite \
org.opencontainers.image.created=20260724
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories && \
apk update && \
apk add nginx && \
rm -rf /var/cache/ && \
rm -rf /etc/nginx/http.d/default.conf
COPY lb.conf /etc/nginx/http.d/lb.conf
CMD ["nginx","-g","daemon off;"]
5,编辑web的dockerfile
[root@docker01:/dockerfile/lb]# vim web-Dockerfile
FROM alpine:latest
# 【标签】
LABEL org.opencontainers.image.authors=bakwite \
org.opencontainers.image.title=alpine-lb \
org.opencontainers.image.version=v1.0.0 \
org.opencontainers.image.description=web01 \
org.opencontainers.image.vendor=bakwite \
org.opencontainers.image.created=20260724
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories && \
apk update && \
apk add nginx && \
rm -rf /var/cache/ && \
rm -rf /etc/nginx/http.d/default.conf
COPY web.conf /etc/nginx/http.d/web.conf
CMD ["nginx","-g","daemon off;"]
6,创建网络
[root@docker01:/dockerfile/lb]# docker network create lb-server
f9c39ba6322df19b8a1f6e2fe8ef18e8aa8ab1e40e02fca8f42031e5827b65b7
· 构建镜像
1,构建web镜像
[root@docker01:/dockerfile/lb]# docker build -t alpine:web . -f web-Dockerfile
2,构建lb镜像
[root@docker01:/dockerfile/lb]# docker build -t alpine:lb . -f lb-Dockerfile
· 运行容器
1,运行web01和web02
[root@docker01:/dockerfile/lb]# docker run -d --network lb-server --name web01 alpine:web
[root@docker01:/dockerfile/lb]# docker run -d --network lb-server --name web02 alpine:web
2,运行lb
[root@docker01:/dockerfile/lb]# docker run -d --network lb-server -p 80:80 --name lb alpine:lb
· 访问lb容器测试
[root@docker01:/dockerfile/lb]# curl 172.20.0.4
{
'client_IP': 172.20.0.4,
'user_URI': /,
'request_web_IP': 172.20.0.2,
'request_web_HOSTNAME': ad058b2333ba,
'request_HOST': 172.20.0.4,
'user_UA': curl/7.81.0,
'response_byte_SIZE': 0,
'response_status_NUM': 200,
'@timestamp': 2025-09-08T07:23:40+00:00
}
[root@docker01:/dockerfile/lb]# curl 172.20.0.4
{
'client_IP': 172.20.0.4,
'user_URI': /,
'request_web_IP': 172.20.0.3,
'request_web_HOSTNAME': 7cb664e3e879,
'request_HOST': 172.20.0.4,
'user_UA': curl/7.81.0,
'response_byte_SIZE': 0,
'response_status_NUM': 200,
'@timestamp': 2025-09-08T07:23:41+00:00
}
十一、容器跨宿主机通信:x:(一般用k8s)
1,基于Linux内核macvlan互联:x:
macvlan概念:
- macvlan就是可以在物理网卡上虚拟出多个lan口的一种二层技术;
- 模拟不同docker服务器下的容器,在同一虚拟局域网下进行通信;

· docker主机内核加载macvlan
[root@docker01 test]# modprobe macvlan
[root@docker01 test]# lsmod | grep macvlan
macvlan 28672 0

· docker主机创建相同网段的网络
| 参数 | 解释说明 |
|---|---|
| -d macvlan | 必须指定网络类型为【macvlan】 |
| -o parent=ens33 | 必须指定真实的物理网卡名称【ens33】,因为实景物理网卡进行虚拟lan口; |
[root@docker01 test]# docker network create -d macvlan --subnet 172.30.0.0/16 --gateway 172.30.0.1 -o parent=ens33 macvlan_net

· 不同主机创建容器测试通信
1,docker01创建容器指定ip
[root@docker01 test]# docker run -d --name v1 --network macvlan_net --ip 172.30.0.2 nginx:1.20.1-alpine
2,docker02创建容器指定ip
[root@docker02 test]# docker run -d --name v2 --network macvlan_net --ip 172.30.0.3 nginx:1.20.1-alpine
3,harbor02创建容器指定ip
[root@harbor02 test]# docker run -d --name v3 --network macvlan_net --ip 172.30.0.4 nginx:1.20.1-alpine
4,测试容器之间互通
容器v1ping容器v2和v3
[root@docker01 test]# docker exec v1 ping 172.30.0.3 -c3
PING 172.30.0.3 (172.30.0.3): 56 data bytes
64 bytes from 172.30.0.3: seq=0 ttl=64 time=1.531 ms
64 bytes from 172.30.0.3: seq=1 ttl=64 time=0.407 ms
64 bytes from 172.30.0.3: seq=2 ttl=64 time=0.477 ms
--- 172.30.0.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.407/0.805/1.531 ms
[root@docker01 test]# docker exec v1 ping 172.30.0.4 -c3
PING 172.30.0.4 (172.30.0.4): 56 data bytes
64 bytes from 172.30.0.4: seq=0 ttl=64 time=1.825 ms
64 bytes from 172.30.0.4: seq=1 ttl=64 time=0.495 ms
64 bytes from 172.30.0.4: seq=2 ttl=64 time=0.360 ms
--- 172.30.0.4 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.360/0.893/1.825 ms
容器v2ping容器v1和v3
[root@docker02 ~]# docker exec v2 ping -c3 172.30.0.2
PING 172.30.0.2 (172.30.0.2): 56 data bytes
64 bytes from 172.30.0.2: seq=0 ttl=64 time=1.638 ms
64 bytes from 172.30.0.2: seq=1 ttl=64 time=0.396 ms
64 bytes from 172.30.0.2: seq=2 ttl=64 time=0.823 ms
--- 172.30.0.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.396/0.952/1.638 ms
[root@docker02 ~]# docker exec v2 ping -c3 172.30.0.4
PING 172.30.0.4 (172.30.0.4): 56 data bytes
64 bytes from 172.30.0.4: seq=0 ttl=64 time=1.686 ms
64 bytes from 172.30.0.4: seq=1 ttl=64 time=0.396 ms
64 bytes from 172.30.0.4: seq=2 ttl=64 time=0.512 ms
--- 172.30.0.4 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.396/0.864/1.686 ms
容器v3ping容器v1和v2
[root@harbor02 ~]# docker exec v3 ping -c3 172.30.0.2
PING 172.30.0.2 (172.30.0.2): 56 data bytes
64 bytes from 172.30.0.2: seq=0 ttl=64 time=1.511 ms
64 bytes from 172.30.0.2: seq=1 ttl=64 time=0.566 ms
64 bytes from 172.30.0.2: seq=2 ttl=64 time=0.476 ms
--- 172.30.0.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.476/0.851/1.511 ms
[root@harbor02 ~]# docker exec v3 ping -c3 172.30.0.3
PING 172.30.0.3 (172.30.0.3): 56 data bytes
64 bytes from 172.30.0.3: seq=0 ttl=64 time=1.493 ms
64 bytes from 172.30.0.3: seq=1 ttl=64 time=0.405 ms
64 bytes from 172.30.0.3: seq=2 ttl=64 time=0.689 ms
--- 172.30.0.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.405/0.862/1.493 ms
· macvlan的优劣势
优势:
- 不需要额外安装其他服务,linux原生内核就支持;
- 配置简单;
劣势:
- macvlan网络的容器支架你可以相互通信,但是无法与宿主机进行通信,更无法连接外网;
- 想要容器链接外网,还需要给容器添加可连接外网的网络:【docker network connect 网络名 容器名】
- ip地址必须手动分配,不同docker主机之间【自动分配会ip冲突】,冲突后必须手动干预,太过繁琐;
# 总结:macvlan只适合小规模集群的容器使用;
2,docker的swarm集群与overlay网络:star:
· 初始化集群主节点
[root@docker01 test]# docker swarm init --advertise-addr 10.0.0.91
Swarm initialized: current node (xjdcu14xewoa4l4p4e8uw6bet) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-1c64cdrffxtg79562v7m53jye33pe1nhw3wz5qe0duzgh0bdsc-4sbbjcqg25hrceee8b44lrt2j 10.0.0.91:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
· 其他节点加入集群
1,docker02加入集群
[root@docker02 ~]# docker swarm join --token SWMTKN-1-1c64cdrffxtg79562v7m53jye33pe1nhw3wz5qe0duzgh0bdsc-4sbbjcqg25hrceee8b44lrt2j 10.0.0.91:2377
This node joined a swarm as a worker.
2,harbor02加入集群
[root@docker02 ~]# docker swarm join --token SWMTKN-1-1c64cdrffxtg79562v7m53jye33pe1nhw3wz5qe0duzgh0bdsc-4sbbjcqg25hrceee8b44lrt2j 10.0.0.91:2377
This node joined a swarm as a worker.
3,主节点查看集群列表
[root@docker01 test]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
xjdcu14xewoa4l4p4e8uw6bet * docker01 Ready Active Leader 20.10.24
ahwy7ronkc4moq2xq0bt1xtax docker02 Ready Active 20.10.24
v9pa8fbj1oemy287x4l19hyfu harbor02 Ready Active 20.10.24
· 主节点创建overlay网络
[root@docker01 test]# docker network create -d overlay overlay_net
oenvhql6em5f0mdqnu3ttlxek
[root@docker01 test]# docker network ls
......
bb6mksyeyheh ingress overlay swarm
......
oenvhql6em5f overlay_net overlay swarm
· 各节点创建容器测试互通
1,主节点创建3个容器
注意:
- 此时创建容器,不能使用【docker run】了,会报错;
- 因为swarm服务,必须使用【docker services 】创建;
[root@docker01 test]# docker service create --name c1 --network overlay_net -d nginx:1.20.1-alpine
[root@docker01 test]# docker service create --name c2 --network overlay_net -d nginx:1.20.1-alpine
[root@docker01 test]# docker service create --name c3 --network overlay_net -d nginx:1.20.1-alpine
查看容器被创建在了哪个节点上:
- 可以看到,每个容器都分别部署在了3台机器上;
[root@docker01 test]# docker service ps c1 c2 c3
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
unhdx167vgry c1.1 nginx:1.20.1-alpine docker01 Running Running 6 minutes ago
yfz769vjj3nj c2.1 nginx:1.20.1-alpine docker02 Running Running 29 seconds ago
w2k6v2io7zqp c3.1 nginx:1.20.1-alpine harbor02 Running Running 13 seconds ago
2,使用一个容器测试通信
[root@docker01 test]# docker exec c1.1.unhdx167vgryztxt1crehcrb1 ping c2 -c3
PING c2 (10.0.2.5): 56 data bytes
64 bytes from 10.0.2.5: seq=0 ttl=64 time=0.045 ms
64 bytes from 10.0.2.5: seq=1 ttl=64 time=0.138 ms
64 bytes from 10.0.2.5: seq=2 ttl=64 time=0.070 ms
--- c2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.045/0.084/0.138 ms
[root@docker01 test]# docker exec c1.1.unhdx167vgryztxt1crehcrb1 ping c3 -c3
PING c3 (10.0.2.8): 56 data bytes
64 bytes from 10.0.2.8: seq=0 ttl=64 time=0.072 ms
64 bytes from 10.0.2.8: seq=1 ttl=64 time=0.077 ms
64 bytes from 10.0.2.8: seq=2 ttl=64 time=0.087 ms
--- c3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.072/0.078/0.087 ms
· swarm集群管理命令
1,集群管理
# 初始化集群主节点
[root@docker01 test]# docker swarm init --advertise-addr 10.0.0.91
# 其他docker主机加入集群
[root@docker02 test]# docker swarm join --token 主节点初始化生成的token串 10.0.0.91:2377
[root@harbor02 test]# docker swarm join --token 主节点初始化生成的token串 10.0.0.91:2377
# 查看集群节点列表
[root@docker01 test]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
xjdcu14xewoa4l4p4e8uw6bet * docker01 Ready Active Leader 20.10.24
ahwy7ronkc4moq2xq0bt1xtax docker02 Ready Active 20.10.24
v9pa8fbj1oemy287x4l19hyfu harbor02 Ready Active 20.10.24
# 设置集群节点的数量
[root@docker01 test]# docker service scale web_server=5
# 查看加入集群的token
[root@docker01 test]# docker swarm join-token worker
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-1c64cdrffxtg79562v7m53jye33pe1nhw3wz5qe0duzgh0bdsc-4sbbjcqg25hrceee8b44lrt2j 10.0.0.91:2377
# 查看管理节点的令牌token(用于添加新的管理节点实现高可用)
[root@docker01 test]# docker swarm join-token manager
To add a manager to this swarm, run the following command:
docker swarm join --token SWMTKN-1-1c64cdrffxtg79562v7m53jye33pe1nhw3wz5qe0duzgh0bdsc-d14iesiztnesnaaoperhxufmx 10.0.0.91:2377
驱逐节点
# 在要去住的节点上执行离开集群命令(如果是管理节点,需要--force)
[root@harbor02 ~]# docker swarm leave
Node left the swarm.
[root@docker01 test]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
xjdcu14xewoa4l4p4e8uw6bet * docker01 Ready Active Leader 20.10.24
ahwy7ronkc4moq2xq0bt1xtax docker02 Ready Active 20.10.24
v9pa8fbj1oemy287x4l19hyfu harbor02 Down Active 20.10.24
# 将节点设置为 Drain 模式
[root@docker01 test]# docker node update --availability drain harbor02
harbor02
[root@docker01 test]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
xjdcu14xewoa4l4p4e8uw6bet * docker01 Ready Active Leader 20.10.24
ahwy7ronkc4moq2xq0bt1xtax docker02 Ready Active 20.10.24
v9pa8fbj1oemy287x4l19hyfu harbor02 Down Drain 20.10.24
# 删除节点
[root@docker01 test]# docker node rm harbor02
harbor02
[root@docker01 test]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
xjdcu14xewoa4l4p4e8uw6bet * docker01 Ready Active Leader 20.10.24
ahwy7ronkc4moq2xq0bt1xtax docker02 Ready Active 20.10.24
以主节点身份加入集群
# 查看主节点的加入令牌token
[root@docker01 test]# docker swarm join-token manager
To add a manager to this swarm, run the following command:
docker swarm join --token SWMTKN-1-1c64cdrffxtg79562v7m53jye33pe1nhw3wz5qe0duzgh0bdsc-d14iesiztnesnaaoperhxufmx 10.0.0.91:2377
# 新节点,加入集群,并以管理节点的身份
[root@harbor02 ~]# docker swarm join --token SWMTKN-1-1c64cdrffxtg79562v7m53jye33pe1nhw3wz5qe0duzgh0bdsc-d14iesiztnesnaaoperhxufmx 10.0.0.91:2377
This node joined a swarm as a manager.
# 再次查看集群节点列表
[root@harbor02 ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
xjdcu14xewoa4l4p4e8uw6bet docker01 Ready Active Leader 20.10.24
ahwy7ronkc4moq2xq0bt1xtax docker02 Ready Active 20.10.24
opo8tppl9rlkyjnhlg8m27htv * harbor02 Ready Active Reachable 20.10.24
2,集群容器管理
# 在管理节点上执行
[root@docker01 test]# docker service create \
--name web_server \
--replicas 3 \ # [负载均衡]期望运行 3 个副本
--publish published=8080,target=80 \ # [端口映射]发布端口:外部 8080 -> 容器内 80 (Swarm Routing Mesh)
--network overlay_net \
nginx:1.20.1-alpine
# 查看集群容器列表
[root@docker01 test]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
py69mt21u848 c1 replicated 1/1 nginx:1.20.1-alpine
nr6wwwhl5gt5 c2 replicated 1/1 nginx:1.20.1-alpine
xxgdutgbu64e c3 replicated 1/1 nginx:1.20.1-alpine
# 删除容器
[root@docker01 test]# docker service rm c3
# 驱逐节点上的容器到其他节点(该节点维护时使用)
[root@docker01 test]# docker node update --availability drain worker01
3,解散集群
工作节点docker02退出集群
[root@docker02 ~]# docker swarm leave
Node left the swarm.
主节docker01和harbor02点退出集群
[root@harbor02 ~]# docker swarm leave --force
Node left the swarm.
3,etcd与flannel实现跨主机互联:x:
· 部署ETCD集群
主要以配置文件方式部署:
- 后续老师会使用systemd部署,减少配置文件的编写;
- 先难、后易;
1,Etcd数据库介绍

2,安装部署Etcd集群
下载软件包
- 注意:需要科学上网哦
https://etcd.io

#选择linux的amd64版本;

三个节点上传解压
[root@docker01 ~]# rz -E
[root@docker01 ~]# mkdir /etcd
[root@docker01 ~]# tar xf etcd-v3.6.4-linux-amd64.tar.gz -C /etcd/
给文件权限
[root@docker01 ~]# chown -R root.root /etcd/
[root@docker01 ~]# ll /etcd/etcd-v3.6.4-linux-amd64/
总用量 56928
drwxr-xr-x 6 root root 120 7月 10 16:01 Documentation
-rwxr-xr-x 1 root root 25268376 7月 10 16:01 etcd
-rwxr-xr-x 1 root root 16466072 7月 10 16:01 etcdctl
-rwxr-xr-x 1 root root 16470168 7月 10 16:01 etcdutl
-rw-r--r-- 1 root root 44075 7月 10 16:01 README-etcdctl.md
-rw-r--r-- 1 root root 8275 7月 10 16:01 README-etcdutl.md
-rw-r--r-- 1 root root 9839 7月 10 16:01 README.md
-rw-r--r-- 1 root root 7896 7月 10 16:01 READMEv2-etcdctl.md
查看版本信息
[root@docker01 ~]# cd /etcd/etcd-v3.6.4-linux-amd64/
[root@docker01 etcd-v3.6.2-linux-amd64]# ./etcdctl version
etcdctl version: 3.6.4
API version: 3.6
3,生成ssl证书
创建证书目录
[root@docker01 ~]# mkdir -p /certs/etcd_certs/
[root@docker01 ~]# cd /certs/etcd_certs/
[root@docker01 etcd_certs]#
生成ca证书
# 1,生成ca私钥
[root@docker01 etcd_certs]# openssl genrsa -out ca.key 2048
# 2,生成ca公钥证书【注意:证书的主要验证方式都在-subj字段下的CN=etcd;】
[root@docker01 etcd_certs]# openssl req -x509 -new -nodes -key ca.key -days 3650 -out ca.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=bakwite/OU=bakwite/CN=etcd CA"
生成etcd【服务端、客户端】合一的证书
# 1,生成etcd私钥
[root@docker01 etcd_certs]# openssl genrsa -out etcd.key 2048
# 2,生成etcd证书请求csr文件
[root@docker01 etcd_certs]# openssl req -new -key etcd.key -out etcd.csr \
-subj "/C=CN/ST=Beijing/L=Beijing/O=bakwite/OU=bakwite/CN=etcd"
# 3,生成etcd公钥[注意:ip地址要是集群的ip]
[root@docker01 etcd_certs]# openssl x509 -req -in etcd.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out etcd.crt -days 3650 -sha256 \
-extfile <(printf "keyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth,clientAuth\nsubjectAltName=IP:10.0.0.91,IP:10.0.0.92,IP:10.0.0.93")
证书发给其他节点
[root@docker01 ~]# scp -r /certs 10.0.0.92:/
[root@docker01 ~]# scp -r /certs 10.0.0.93:/
4,编辑配置文件
节点01
[root@docker01 ~]# vim /etcd/etcd-v3.6.4-linux-amd64/etcd.conf.yml
# 【基础配置】
name: 'docker01' #节点名称(保证集群中唯一)
data-dir: /etcd/etcd-v3.6.4-linux-amd64/data #数据目录
# wal目录的作用:记录所有数据变更的历史,包括Raft日志条目、集群配置变更等
# 在数据变更被应用到持久存储前,先将变更记录到日志文件中,确保数据一致性和可恢复性
wal-dir: /etcd/etcd-v3.6.4-linux-amd64/data/wal #日志快照存储目录
heartbeat-interval: 100 #心跳间隔时间(毫秒),影响leader发送心跳的频率
election-timeout: 1000 #选举超时时间
quota-backend-bytes: 0 #限制存储数据量大小,超过则变成只读模式;0表示不限制;
max-wals: 5 #保留最大WAL日志文件数量;
# 【集群通讯配置】
listen-peer-urls: 'https://10.0.0.91:2380' #集群内peer通讯的对外监听地址;
listen-client-urls: 'https://10.0.0.91:2379,http://127.0.0.1:2379' #客户端链接的监听地址;
# 向集群其他成员广播的peer通信URL,用于节点间数据同步和选举通信
initial-advertise-peer-urls: 'https://10.0.0.91:2380'
# 向客户端广播的访问URL
advertise-client-urls: 'https://10.0.0.91:2379'
# 【初始化配置】
# 初始集群成员列表
initial-cluster: 'docker01=https://10.0.0.91:2380,docker02=https://10.0.0.92:2380,harbor02=https://10.0.0.93:2380'
initial-cluster-token: 'etcd-cluster' #集群token;集群的唯一标识
# 参数用于指定etcd集群的初始状态,当设置为'new'时表示当前节点正在初始化一个全新的集群
# 【new】表示:表示当前节点正在创建一个全新的etcd集群
# 会生成新的集群ID(Cluster ID)和新的数据目录
# 【existing】表示当前节点正在加入一个已经存在的集群,节点会尝试连接现有集群而非创建新集群
initial-cluster-state: 'new'
strict-reconfig-check: false #允许在非理想条件下进行成员变更操作
# 【服务发现配置】
discovery:
#当发现服务不可用时,etcd将回退到代理模式。在这种模式下,节点作为只读代理运行,直到发现服务恢复
discovery-fallback: 'proxy'
#指定通过HTTP代理进行服务发现的URL。留空表示不使用代理发现
discovery-proxy:
#使用DNS SRV记录进行服务发现。留空表示不使用DNS发现机制。启用时需要指定DNS域名
discovery-srv:
# 【代理模式配置】
proxy: 'off' #代理模式关闭
proxy-failure-wait: 5000 #当代理节点检测到后端etcd集群不可用时,等待5000毫秒(5秒)后才会尝试重新连接
proxy-refresh-interval: 30000 #代理节点每30000毫秒(30秒)刷新一次后端etcd集群的端点列表
proxy-dial-timeout: 1000 #代理节点与后端etcd集群建立连接的超时时间为1000毫秒(1秒)
proxy-write-timeout: 5000 #代理节点处理写操作(如PUT/DELETE)的超时时间为5000毫秒(5秒)
proxy-read-timeout: 0 #代理节点处理读操作(如GET)的超时时间设置为0表示无超时限制
enable-pprof: true #开启性能分析接口
# 【证书配置】
client-transport-security: #客户端访问etcd时的验证证书
cert-file: '/certs/etcd_certs/etcd.crt'
key-file: '/certs/etcd_certs/etcd.key'
client-cert-auth: true #开启客户端双向加密认证
trusted-ca-file: '/certs/etcd_certs/ca.crt'
auto-tls: true #设置为true表示自动为对等连接生成自签名证书
peer-transport-security: #集群之间通信验证的证书
cert-file: '/certs/etcd_certs/etcd.crt'
key-file: '/certs/etcd_certs/etcd.key'
peer-client-cert-auth: true #开启双向加密认证
trusted-ca-file: '/certs/etcd_certs/ca.crt'
auto-tls: true #设置为true表示自动为对等连接生成自签名证书
# 【日志配置】
debug: false
log-package-levels:
log-outputs: [default]
force-new-cluster: false
节点02
[root@docker02 ~]# vim /etcd/etcd-v3.6.4-linux-amd64/etcd.conf.yml
# 【基础配置】
name: 'docker02' #节点名称(保证集群中唯一)
data-dir: /etcd/etcd-v3.6.4-linux-amd64/data #数据目录
wal-dir: /etcd/etcd-v3.6.4-linux-amd64/data/wal #日志快照存储目录
heartbeat-interval: 100 #心跳间隔时间(毫秒),影响leader发送心跳的频率
election-timeout: 1000 #选举超时时间
quota-backend-bytes: 0 #限制存储数据量大小,超过则变成只读模式;0表示不限制;
max-wals: 5 #保留最大WAL日志文件数量;
# 【集群通讯配置】
listen-peer-urls: 'https://10.0.0.92:2380' #集群内peer通讯的对外监听地址;
listen-client-urls: 'https://10.0.0.92:2379,http://127.0.0.1:2379' #客户端链接的监听地址;
# 向集群其他成员广播的peer通信URL,用于节点间数据同步和选举通信
initial-advertise-peer-urls: 'https://10.0.0.92:2380'
# 向客户端广播的访问URL
advertise-client-urls: 'https://10.0.0.92:2379'
# 【初始化配置】
# 初始集群成员列表
initial-cluster: 'docker01=https://10.0.0.91:2380,docker02=https://10.0.0.92:2380,harbor02=https://10.0.0.93:2380'
initial-cluster-token: 'etcd-cluster' #集群token;集群的唯一标识
# 参数用于指定etcd集群的初始状态,当设置为'new'时表示当前节点正在初始化一个全新的集群
# 【new】表示:表示当前节点正在创建一个全新的etcd集群
# 会生成新的集群ID(Cluster ID)和新的数据目录
# 【existing】表示当前节点正在加入一个已经存在的集群,节点会尝试连接现有集群而非创建新集群
initial-cluster-state: 'new'
strict-reconfig-check: false #允许在非理想条件下进行成员变更操作
# 【服务发现配置】
discovery:
#当发现服务不可用时,etcd将回退到代理模式。在这种模式下,节点作为只读代理运行,直到发现服务恢复
discovery-fallback: 'proxy'
#指定通过HTTP代理进行服务发现的URL。留空表示不使用代理发现
discovery-proxy:
#使用DNS SRV记录进行服务发现。留空表示不使用DNS发现机制。启用时需要指定DNS域名
discovery-srv:
# 【代理模式配置】
proxy: 'off' #代理模式关闭
proxy-failure-wait: 5000 #当代理节点检测到后端etcd集群不可用时,等待5000毫秒(5秒)后才会尝试重新连接
proxy-refresh-interval: 30000 #代理节点每30000毫秒(30秒)刷新一次后端etcd集群的端点列表
proxy-dial-timeout: 1000 #代理节点与后端etcd集群建立连接的超时时间为1000毫秒(1秒)
proxy-write-timeout: 5000 #代理节点处理写操作(如PUT/DELETE)的超时时间为5000毫秒(5秒)
proxy-read-timeout: 0 #代理节点处理读操作(如GET)的超时时间设置为0表示无超时限制
enable-pprof: true #开启性能分析接口
# 【证书配置】
client-transport-security: #客户端访问的证书
cert-file: '/certs/etcd_certs/etcd.crt'
key-file: '/certs/etcd_certs/etcd.key'
client-cert-auth: true
trusted-ca-file: '/certs/etcd_certs/ca.crt'
auto-tls: true
peer-transport-security: #集群验证的证书
cert-file: '/certs/etcd_certs/etcd.crt'
key-file: '/certs/etcd_certs/etcd.key'
peer-client-cert-auth: true
trusted-ca-file: '/certs/etcd_certs/ca.crt'
auto-tls: true
# 【日志配置】
debug: false
log-package-levels:
log-outputs: [default]
force-new-cluster: false
节点03
[root@harbor02 ~]# vim /etcd/etcd-v3.6.4-linux-amd64/etcd.conf.yml
# 【基础配置】
name: 'harbor02' #节点名称(保证集群中唯一)
data-dir: /etcd/etcd-v3.6.4-linux-amd64/data #数据目录
wal-dir: /etcd/etcd-v3.6.4-linux-amd64/data/wal #日志快照存储目录
heartbeat-interval: 100 #心跳间隔时间(毫秒),影响leader发送心跳的频率
election-timeout: 1000 #选举超时时间
quota-backend-bytes: 0 #限制存储数据量大小,超过则变成只读模式;0表示不限制;
max-wals: 5 #保留最大WAL日志文件数量;
# 【集群通讯配置】
listen-peer-urls: 'https://10.0.0.93:2380' #集群内peer通讯的对外监听地址;
listen-client-urls: 'https://10.0.0.93:2379,http://127.0.0.1:2379' #客户端链接的监听地址;
# 向集群其他成员广播的peer通信URL,用于节点间数据同步和选举通信
initial-advertise-peer-urls: 'https://10.0.0.93:2380'
# 向客户端广播的访问URL
advertise-client-urls: 'https://10.0.0.93:2379'
# 【初始化配置】
# 初始集群成员列表
initial-cluster: 'dooker01=https://10.0.0.91:2380,docker02=https://10.0.0.92:2380,harbor02=https://10.0.0.93:2380'
initial-cluster-token: 'etcd-cluster' #集群token;集群的唯一标识
# 参数用于指定etcd集群的初始状态,当设置为'new'时表示当前节点正在初始化一个全新的集群
# 【new】表示:表示当前节点正在创建一个全新的etcd集群
# 会生成新的集群ID(Cluster ID)和新的数据目录
# 【existing】表示当前节点正在加入一个已经存在的集群,节点会尝试连接现有集群而非创建新集群
initial-cluster-state: 'new'
strict-reconfig-check: false #允许在非理想条件下进行成员变更操作
# 【服务发现配置】
discovery:
#当发现服务不可用时,etcd将回退到代理模式。在这种模式下,节点作为只读代理运行,直到发现服务恢复
discovery-fallback: 'proxy'
#指定通过HTTP代理进行服务发现的URL。留空表示不使用代理发现
discovery-proxy:
#使用DNS SRV记录进行服务发现。留空表示不使用DNS发现机制。启用时需要指定DNS域名
discovery-srv:
# 【代理模式配置】
proxy: 'off' #代理模式关闭
proxy-failure-wait: 5000 #当代理节点检测到后端etcd集群不可用时,等待5000毫秒(5秒)后才会尝试重新连接
proxy-refresh-interval: 30000 #代理节点每30000毫秒(30秒)刷新一次后端etcd集群的端点列表
proxy-dial-timeout: 1000 #代理节点与后端etcd集群建立连接的超时时间为1000毫秒(1秒)
proxy-write-timeout: 5000 #代理节点处理写操作(如PUT/DELETE)的超时时间为5000毫秒(5秒)
proxy-read-timeout: 0 #代理节点处理读操作(如GET)的超时时间设置为0表示无超时限制
enable-pprof: true #开启性能分析接口
# 【证书配置】
client-transport-security: #客户端访问的证书
cert-file: '/certs/etcd_certs/etcd.crt'
key-file: '/certs/etcd_certs/etcd.key'
client-cert-auth: true
trusted-ca-file: '/certs/etcd_certs/ca.crt'
auto-tls: true
peer-transport-security: #集群验证的证书
cert-file: '/certs/etcd_certs/etcd.crt'
key-file: '/certs/etcd_certs/etcd.key'
peer-client-cert-auth: true
trusted-ca-file: '/certs/etcd_certs/ca.crt'
auto-tls: true
# 【日志配置】
debug: false
log-package-levels:
log-outputs: [default]
force-new-cluster: false
5,编辑system启动
[root@docker01 ~]# vim /usr/lib/systemd/system/etcd.service
[Unit]
Description=etcd key-value store
Documentation=https://etcd.io/docs
After=network.target
[Service]
Type=notify
ExecStart=/etcd/etcd-v3.6.4-linux-amd64/etcd \
--config-file=/etcd/etcd-v3.6.4-linux-amd64/etcd.conf.yml
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
6,启动etcd
[root@docker01 ~]# systemctl daemon-reload
[root@docker01 ~]# systemctl enable --now etcd.service
[root@docker01 etcd-v3.6.2-linux-amd64]# netstat -tnulp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 10.0.0.91:2379 0.0.0.0:* LISTEN 11574/etcd
tcp 0 0 127.0.0.1:2379 0.0.0.0:* LISTEN 11574/etcd
tcp 0 0 10.0.0.91:2380 0.0.0.0:* LISTEN 11574/etcd
...
7,将命令文件复制到PATH
[root@docker01 ~]# cd /etcd/etcd-v3.6.4-linux-amd64/
[root@docker01 etcd-v3.6.4-linux-amd64]# cp etcd /usr/bin/
[root@docker01 etcd-v3.6.4-linux-amd64]# cp etcdctl /usr/bin/
[root@docker01 etcd-v3.6.4-linux-amd64]# cp etcdutl /usr/bin/
8,查看集群状态
查看集群运行状态
[root@docker01 ~]# etcdctl \
--endpoints="https://10.0.0.91:2379,https://10.0.0.92:2379,https://10.0.0.93:2379" \
--cacert=/certs/etcd_certs/ca.crt \
--cert=/certs/etcd_certs/etcd.crt \
--key=/certs/etcd_certs/etcd.key \
endpoint status --write-out=table

查看集群健康状态
[root@harbor02 etcd-v3.6.4-linux-amd64]# etcdctl \
--endpoints="https://10.0.0.91:2379,https://10.0.0.92:2379,https://10.0.0.93:2379" \
--cacert=/certs/etcd_certs/ca.crt \
--cert=/certs/etcd_certs/etcd.crt \
--key=/certs/etcd_certs/etcd.key \
endpoint health
https://10.0.0.91:2379 is healthy: successfully committed proposal: took = 9.427785ms
https://10.0.0.92:2379 is healthy: successfully committed proposal: took = 9.378317ms
https://10.0.0.93:2379 is healthy: successfully committed proposal: took = 12.352809ms
9,验证高可用
关闭leader
[root@etcd01 ~]# systemctl stop etcd.service
其他节点查看集群状态
[root@docker01 ~]# etcdctl \
--endpoints="https://https://10.0.0.91:2379,10.0.0.92:2379,https://10.0.0.93:2379" \
--cacert=/certs/etcd_certs/ca.crt \
--cert=/certs/etcd_certs/etcd.crt \
--key=/certs/etcd_certs/etcd.key \
endpoint status --write-out=table

重新启动之前的leader
[root@docker01 ~]# systemctl start etcd.service

· Etcd的基础操作
etcd数据库是“非关系型数据库”:
- 存储数据的方式是:对象存储;
- 也就是key value的方式;
1,写入数据
| 命令 | 参数 | 举例 | 解释说明 |
|---|---|---|---|
| etcdctl | put | etcdctl put bakwite 999 | 写入数据【bakwite=999】 |
#1,写入键值对
[root@docker01 ~]# etcdctl put bakwite 999
OK
[root@docker01 ~]# etcdctl put school beijingdaxue
OK
[root@docker01 ~]# etcdctl put class jisuanji
OK
[root@docker01 ~]# etcdctl put /etc/ 系统配置文件目录
OK
2,查看数据
| 命令 | 参数 | 举例 | 解释说明 |
|---|---|---|---|
| etcdctl | get | etcdctl get bakwite | 查看数据bakwite |
| --prefix | etcdctl get / --prefix | 获取以[/]开头的key的数据 | |
| --keys-only | 只获取key不要value | ||
| --print-value-only | 只获取value不要key | ||
| etcdctl get "" --prefix --print-value-only | 获取所有key的value值 |
#1,通过key查询key和value的值;
[root@docker01 ~]# etcdctl get bakwite
bakwite
999
[root@docker01 ~]# etcdctl get school
school
beijingdaxue
[root@docker01 ~]# etcdctl get class
class
jisuanji
[root@docker01 ~]# etcdctl get /etc/
/etc/
系统配置文件目录
#2,通过key值,获取key,不要value;
[root@docker01 ~]# etcdctl get school --keys-only
school
#3,通过key值,获取value,不要key;
[root@docker01 ~]# etcdctl get school --print-value-only
beijingdaxue
#4,模糊查询,只查看以“/”开头为前缀的key
[root@docker01 ~]# etcdctl get / --prefix --print-value-only
系统配置文件目录
#5,获取所有数据的value值;
[root@docker01 ~]# etcdctl get "" --prefix --print-value-only
系统配置文件目录
jisuanji
beijingdaxue
999
3,修改数据
修改也是添加写入;
#1,通过key值,获取value,不要key;
[root@docker01 ~]# etcdctl get school --print-value-only
beijingdaxue
#2,修改school的值为:qinghua
[root@docker01 ~]# etcdctl put school qinghua
OK
#3,再次查看;
[root@docker01 ~]# etcdctl get school
school
qinghua
4,删除数据
| 命令 | 参数 | 案例 | 解释说明 |
|---|---|---|---|
| etcdctl | del | etcdctl del school | 删除school这个key的值 |
#1,删除key是school的数据
[root@docker01 ~]# etcdctl del school
1
[root@docker01 ~]# etcdctl get "" --prefix --print-value-only
系统配置文件目录
jisuanji
999
#2,删除所有数据
[root@docker01 ~]# etcdctl del "" --prefix
3
[root@docker01 ~]# etcdctl get "" --prefix --print-value-only
· Etcd的备份与恢复
1,准备测试数据
[root@docker01 ~]# etcdctl put school 清华大学
OK
[root@docker01 ~]# etcdctl put class 机电维修02
OK
[root@docker01 ~]# etcdctl put /etc/nginx/nginx.d/ 配置文件路径
OK
[root@docker01 ~]# etcdctl put /etc/nginx/nginx.conf 主配置文件
OK
[root@docker01 ~]# etcdctl get "" --prefix
/etc/nginx/nginx.conf
主配置文件
/etc/nginx/nginx.d/
配置文件路径
class
机电维修02
school
清华大学
2,创建快照备份
备份快照
#1,创建快照
[root@docker01 ~]# etcdctl snapshot save /tmp/snapshot001.db
#2,查看快照文件
[root@docker01 ~]# ll /tmp/
-rw------- 1 root root 24608 7月 18 08:40 snapshot.db
#3,【etcdutl】查看快照的状态
[root@etcd01 etcd-v3.6.2-linux-amd64]# etcdutl snapshot status /tmp/snapshot001.db -w table
+----------+----------+------------+------------+---------+
| HASH | REVISION | TOTAL KEYS | TOTAL SIZE | VERSION |
+----------+----------+------------+------------+---------+
| 11e1cfc4 | 15 | 2 | 25 kB | 3.6.0 |
+----------+----------+------------+------------+---------+
3,将备份快照发送其他节点
[root@docker01 ~]# scp /tmp/snapshot001.db 10.0.0.92:/tmp/
[root@docker01 ~]# scp /tmp/snapshot001.db 10.0.0.93:/tmp/
4,模拟数据丢失
#删除所有数据
[root@docker01 ~]# etcdctl del "" --prefix
4
[root@docker01 ~]# etcdctl get "" --prefix
5,恢复备份数据
停止集群
[root@docker01 ~]# systemctl stop etcd.service
[root@docker01 ~]# systemctl stop etcd.service
[root@docker01 ~]# systemctl stop etcd.service
恢复备份快照
[root@docker01 ~]# etcdutl snapshot restore /tmp/snapshot001.db --data-dir=/etcd/etcd-v3.6.4-linux-amd64/data001/
[root@docker01 ~]# etcdutl snapshot restore /tmp/snapshot001.db --data-dir=/etcd/etcd-v3.6.4-linux-amd64/data001/
[root@docker01 ~]# etcdutl snapshot restore /tmp/snapshot001.db --data-dir=/etcd/etcd-v3.6.4-linux-amd64/data001/
修改节点配置文件的数据库目录
注意:所有节点都需要修改;
[root@docker01 etcd-v3.6.4-linux-amd64]# vim etcd.conf.yml
# 【基础配置】
name: 'docker01' #节点名称(保证集群中唯一)
data-dir: /etcd/etcd-v3.6.4-linux-amd64/data001 #数据目录
wal-dir: /etcd/etcd-v3.6.4-linux-amd64/data001/wal #日志快照存储目录
启动集群
systemctl start etcd
6,验证备份恢复数据
[root@docker01 etcd-v3.6.4-linux-amd64]# etcdctl get "" --prefix
/etc/nginx/nginx.conf
主配置文件
/etc/nginx/nginx.d/
配置文件路径
school
清华大学
· Etcd的监控指标
#1,查看etcd暴露的监控指标数量
[root@docker01 ~]# curl -s -k --cacert /certs/etcd_certs/ca.crt --cert /certs/etcd_certs/etcd.crt --key /certs/etcd_certs/etcd.key https://10.0.0.91:2379/metrics | wc -l
1697
#2,查看指标
[root@docker01 ~]# curl -s -k --cacert /certs/etcd_certs/ca.crt --cert /certs/etcd_certs/etcd.crt --key /certs/etcd_certs/etcd.key https://10.0.0.91:2379/metrics | head -10
# HELP etcd_cluster_version Which version is running. 1 for 'cluster_version' label with current cluster version
# TYPE etcd_cluster_version gauge
etcd_cluster_version{cluster_version="3.0"} 0
etcd_cluster_version{cluster_version="3.6"} 1
# HELP etcd_debugging_auth_revision The current revision of auth store.
# TYPE etcd_debugging_auth_revision gauge
etcd_debugging_auth_revision 1
# HELP etcd_debugging_disk_backend_commit_rebalance_duration_seconds The latency distributions of commit.rebalance called by bboltdb backend.
# TYPE etcd_debugging_disk_backend_commit_rebalance_duration_seconds histogram
etcd_debugging_disk_backend_commit_rebalance_duration_seconds_bucket{le="0.001"} 9
· Etcd与flannel跨主机原理
通信过程:
- 前提:
- flannel配合etcd数据库,会维护一个主网段【172.100.0.0/16】和对应每个节点的容器的子网段【172.100.x.0/24】;
- flannel利用Vxlan网络技术,给自己的宿主机创建一张Flannel.1的虚拟网卡【vxlan的接口】;
- flannel.1网卡,只负责:
- 从etcd获取主机对应容器网段的信息:【vxlan接口的FDB表(就是主机ip对应容器网段)】
- 给宿主机设置路由规则(路由表):去往哪个容器网段,走哪张网卡,flannel.1还是docker0;
- 宿主机A中的容器01,要与宿主机B中的容器02通信;
- 先查本机路由表,看是容器集群的网段就走flannel.1;
- flannel.1获取FDB表中容器网段对应的素质及ip地址;
- 内核vxlan打包双层ip,并通过UDP:4789发送给目标物理主机;
- 宿主机B街道数据包:
- 宿主机ens33网卡接到UDP:4789数据包直接转发给flannel.1网卡;
- flannel.1拆包,拿到内层容器的源、目标ip;
- flannel.1将数据包交给docker0网卡,最后转交给容器;
[root@docker01 ~]# ip route
default via 10.0.0.2 dev ens33 proto static metric 100
10.0.0.0/24 dev ens33 proto kernel scope link src 10.0.0.91 metric 100
10.244.5.0/24 via 10.244.5.0 dev flannel.1 onlink
10.244.45.0/24 via 10.244.45.0 dev flannel.1 onlink
10.244.79.0/24 dev docker0 proto kernel scope link src 10.244.79.1

· Etcd与flannel跨主机互联
1,安装部署flannel
我们选择flannel的【稳定版-0.23.0】
#下载地址:https://github.com/flannel-io/flannel/releases/tag/v0.23.0

【所有节点】下载安装包
[root@docker01 ~]# wget https://github.com/flannel-io/flannel/releases/download/v0.23.0/flannel-v0.23.0-linux-amd64.tar.gz
[root@docker01 ~]# ll
......
-rw-r--r-- 1 root root 12563035 10月 31 2023 flannel-v0.23.0-linux-amd64.tar.gz
【所有节点】解压flannel软件包
[root@docker01 ~]# mkdir /flannel
[root@docker01 ~]# tar xf flannel-v0.23.0-linux-amd64.tar.gz -C /flannel
[root@docker01 ~]# ll /flannel/
总用量 39632
-rwxr-xr-x 1 1001 127 40568560 10月 31 2023 flanneld
-rwxr-xr-x 1 1001 127 2633 10月 31 2023 mk-docker-opts.sh
-rw-r--r-- 1 1001 127 5665 10月 31 2023 README.md
【所有节点】给flannel文件root权限
[root@docker01 ~]# chown -R root:root /flannel/
[root@docker01 ~]# ll /flannel/
总用量 39632
-rwxr-xr-x 1 root root 40568560 10月 31 2023 flanneld
-rwxr-xr-x 1 root root 2633 10月 31 2023 mk-docker-opts.sh
-rw-r--r-- 1 root root 5665 10月 31 2023 README.md
【所有节点】将命令文件移动至PATH路径下
[root@docker01 ~]# cp /flannel/flanneld /usr/local/bin/
[root@docker01 ~]# cp /flannel/mk-docker-opts.sh /usr/local/bin/
【所有节点】测试flanneld命令,查看flannel版本
[root@docker01 ~]# flanneld --version
v0.23.0
【所有节点】配置system管理flannel服务
| system参数 | 解释说明 |
|---|---|
| --etcd-endpoints | 指定flannel链接etcd的集群地址 |
| --etcd-cafile=/ --etcd-certfile= --etcd-keyfile= |
指定flannel链接集群的用的客户端证书; |
| --ip-masq | 设置 IP 伪装,允许容器访问外部网络(如互联网) |
| --iface=ens33 | 重要:改为你节点上用于通信的网卡名,如 eth0, ens33 等 |
[root@docker01 ~]# vim /usr/lib/systemd/system/flanneld.service
[Unit]
Description=Flannel Network Fabric
After=network.target etcd.service
Requires=etcd.service
[Service]
Type=notify
# 修改这里的 etcd 端点地址
ExecStart=/usr/local/bin/flanneld \
--etcd-endpoints=https://10.0.0.91:2379,https://10.0.0.92:2379,https://10.0.0.93:2379 \
--etcd-cafile=/certs/etcd_certs/ca.crt \
--etcd-certfile=/certs/etcd_certs/etcd.crt \
--etcd-keyfile=/certs/etcd_certs/etcd.key \
--ip-masq \
--iface=ens33
# mk-docker-opts.sh:这个脚本会根据从 etcd 获取的子网信息,生成 Docker 所需的网络配置环境变量。
ExecStartPost=/usr/local/bin/mk-docker-opts.sh -c /run/flannel/subnet.env -d /run/docker_opts.env
Restart=on-failure
[Install]
WantedBy=multi-user.target
2,向Etcd集群写入集群网段
[root@docker01 ~]# etcdctl \
--endpoints="https://10.0.0.91:2379,https://10.0.0.92:2379,https://10.0.0.93:2379" \
--cacert=/certs/etcd_certs/ca.crt \
--cert=/certs/etcd_certs/etcd.crt \
--key=/certs/etcd_certs/etcd.key \
put /coreos.com/network/config '{"Network": "10.244.0.0/16", "Backend": {"Type": "vxlan"}}'
3,启动flanneld服务
[root@docker01 ~]# systemctl daemon-reload
[root@docker01 ~]# systemctl enable --now flanneld.service
4,查看flannel生成的网络文件
[root@docker01 ~]# cat /run/flannel/subnet.env
FLANNEL_NETWORK=10.244.0.0/16 # 整个集群的通信网段
FLANNEL_SUBNET=10.244.79.1/24 # 本机的网关网段
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
5,修改3个docker主机默认网段
将:【FLANNEL_SUBNET=10.244.79.1/24】本机的网关网段写入docker配置文件的bip字段下
[root@docker01 ~]# cat /etc/docker/daemon.json
{
"registry-mirrors" : ["https://do.nark.eu.org",
"https://dc.j8.work",
"https://docker.m.daocloud.io",
"https://dockerproxy.com",
"https://docker.mirrors.ustc.edu.cn",
"https://docker.nju.edu.cn",
"https://docker.mirrors.ustc.edu.cn",
"https://docker.registry.cyou",
"https://docker-cf.registry.cyou",
"https://dockercf.jsdelivr.fyi",
"https://docker.jsdelivr.fyi",
"https://dockertest.jsdelivr.fyi",
"https://mirror.aliyuncs.com",
"https://dockerproxy.com",
"https://mirror.baidubce.com",
"https://docker.m.daocloud.io",
"https://docker.nju.edu.cn",
"https://docker.mirrors.sjtug.sjtu.edu.cn",
"https://docker.mirrors.ustc.edu.cn",
"https://mirror.iscas.ac.cn",
"https://docker.rainbond.cc",
"https://do.nark.eu.org",
"https://docker.shootchat.top",
"https://registry.docker-cn.com"],
"bip" : "10.244.79.1/24"
}
6,重启docker服务查看容器网络
[root@docker01 ~]# systemctl restart docker.service
# 查看本机bridge网络地址
[root@docker01 ~]# docker network inspect bridge
......
"Subnet": "10.244.79.0/24",
"Gateway": "10.244.79.1"
......
7,查看宿主机网络
[root@docker01 ~]# ip a
......
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:8c:3d:1b:20 brd ff:ff:ff:ff:ff:ff
inet 10.244.79.1/24 brd 10.244.79.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:8cff:fe3d:1b20/64 scope link
valid_lft forever preferred_lft forever
625: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
link/ether c2:7f:c8:cd:5f:74 brd ff:ff:ff:ff:ff:ff
inet 10.244.79.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
inet6 fe80::c07f:c8ff:fecd:5f74/64 scope link
valid_lft forever preferred_lft forever
8,测试跨主机通讯
# docker01创建容器c1
[root@docker01 ~]# docker run -d --name c1 nginx:1.20.1-alpine
# harbor02创建容器c2
[root@harbor02 ~]# docker run -d --name c2 nginx:1.20.1-alpine
# 查看容器c2的ip地址
[root@harbor02 ~]# docker exec c1 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
34: eth0@if35: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:0a:f4:2d:02 brd ff:ff:ff:ff:ff:ff
inet 10.244.45.2/24 brd 10.244.45.255 scope global eth0
valid_lft forever preferred_lft forever
# 使用容器c1去ping容器c2的的ip;通信成功;
[root@docker01 ~]# docker exec c1 ping -c3 10.244.45.2
PING 10.244.45.2 (10.244.45.2): 56 data bytes
64 bytes from 10.244.45.2: seq=0 ttl=62 time=1.794 ms
64 bytes from 10.244.45.2: seq=1 ttl=62 time=0.429 ms
64 bytes from 10.244.45.2: seq=2 ttl=62 time=0.420 ms
--- 10.244.45.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.420/0.881/1.794 ms
· 卸载flannel网络
1,删除所有容器
[root@docker01 ~]# docker rm -f `docker ps -aq`
[root@docker02 ~]# docker rm -f `docker ps -aq`
[root@harbor02 ~]# docker rm -f `docker ps -aq`
2,关闭flannel服务
[root@docker01 ~]# systemctl disable --now flanneld.service
[root@docker02 ~]# systemctl disable --now flanneld.service
[root@harbor02 ~]# systemctl disable --now flanneld.service
3,删除docker默认bip
[root@harbor02 ~]# vim /etc/docker/daemon.json
4,重启docker服务
[root@docker01 ~]# systemctl restart docker.service
[root@docker02 ~]# systemctl restart docker.service
[root@harbor02 ~]# systemctl restart docker.service
5,删除flannel.1网络设备
[root@docker01 ~]# ip link delete flannel.1
[root@docker02 ~]# ip link delete flannel.1
[root@harbor02 ~]# ip link delete flannel.1
6,再次重启docker
[root@docker01 ~]# systemctl restart docker.service
[root@docker02 ~]# systemctl restart docker.service
[root@harbor02 ~]# systemctl restart docker.service
7,清空无用的网络
[root@docker01 ~]# docker network prune -f
[root@docker02 ~]# docker network prune -f
[root@harbor02 ~]# docker network prune -f
8,删除etcd的flannel主网络
[root@docker01 ~]# etcdctl \
--endpoints="https://10.0.0.91:2379,https://10.0.0.92:2379,https://10.0.0.93:2379" \
--cacert=/certs/etcd_certs/ca.crt \
--cert=/certs/etcd_certs/etcd.crt \
--key=/certs/etcd_certs/etcd.key \
del /coreos.com/network/config
9,查看路由验证
[root@docker01 ~]# ip route
default via 10.0.0.2 dev ens33 proto static metric 100
10.0.0.0/24 dev ens33 proto kernel scope link src 10.0.0.91 metric 100
10.244.79.0/24 dev docker0 proto kernel scope link src 10.244.79.1 linkdown
十二、docker-compose
1,docker-compose概述
· docker面对的问题
Docker的核心问题:
- 当我们使用【docker run】命令运行一个容器时,根据业务需求,可能使用:
- -v 指定存储卷
- --network 指定网络
- -e 指定环境变量
- --name 执行容器名称
- ......等等
- 而在生产环境中,我们一套业务系统可能包含多个容器同时启动:
- web服务容器
- 中间件容器
- 数据库容器
- 缓存服务容器
- 日志收集服务容器
- ......其它容器......;
- 而当业务服务需要改动容器参数时,巨大的参数量与容器量,让人很难记忆,出现问题很难回溯;

· 解决方案
docker问题的解决方案:
- 我们将这些docker启动命令写入到一个文件中;
- 每次使用这个文件来启动同一个业务的多个容器;
- 如果对业务进行:【修改参数】或者【修改镜像版本】,也直接修改文件;
- 当遇到问题或者维护业务容器时,就不再需要人为记录这些信息,减轻了运维成本;

· docker-compose可以实现
# 一个以yml结尾的文件可以实现功能:
- 多个docker build 构建镜像;
- 多个docker run 运行多个容器;
- 实现:从构建到运行镜像容器【一步完成】;
2,二进制安装部署
· 下载docker-compose
官网下载地址
https://github.com/docker/compose/

点击版本入口,进入版本下载页面

# 向下滑动页面
- 点击【show all...】展示所有系统类型

# 选择符合我们系统架构的类型
- docker-compose-linux-x86_64

· 安装docker-compose
1,上传docker-compose文件
# 将文件上传到docker主机
[root@docker01:~]# wget https://github.com/docker/compose/releases/download/v2.39.3/docker-compose-linux-x86_64
[root@docker01:~]# ll
......
-rw-r--r-- 1 root root 75602664 Sep 7 19:30 docker-compose-linux-x86_64
2,授予执行权限并改名
[root@docker01:~]# mv docker-compose-linux-x86_64 docker-compose
[root@docker01:~]# chmod +x docker-compose
3,移动到PATH目录下
[root@docker01:~]# cp docker-compose /usr/local/bin/
4,查看docker-compose版本
[root@docker01:~]# docker-compose version
Docker Compose version v2.39.2
3,docker-compose初体验
· 创建业务目录
[root@docker01:~]# mkdir -p /docker-compose/test
[root@docker01:~]# cd /docker-compose/test
[root@docker01:/docker-compose/test]#
· 编辑yml文件
[root@docker01:/docker-compose/test]# vim docker-compose.yml
services:
# 声明服务的名称:
web-server-container01:
# 同等于【--name: web01】
container_name: web01
# 指定镜像
image: nginx:1.20.1-alpine
mysql-server-container02:
container_name: db01
image: mysql:8.0-oracle
# 同等于【-e key=value】
environment:
- MYSQL_DATABASE="bakwite"
- MYSQL_USER="bakwite"
- MYSQL_PASSWORD="123456"
- MYSQL_ROOT_PASSWORD="123456"
# [等同于dockerfile中的CMD指令]启动容器时,传入的命令/参数;
command:
- --character-set-server=utf8
- --collation-server=utf8_bin
- --default-authentication-plugin=mysql_native_password
· docker-compose运行容器
注意:
- 虽然我们运行docker-compose时没有设置网络;
- 但是,docker-compose默认给同一个yml文件下的容器自动创建并指定了相同的网络中;
[root@docker01:/docker-compose/test]# docker-compose up -d
# 运行后,查看网络,多了一个【test_default】的网络;
[root@docker01:/docker-compose/test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
7813d53a3faa bridge bridge local
8fedbda1bac8 host host local
e0d8d832d8ea none null local
899d2d1178a3 test_default bridge local
· docker-compose容器管理
| 命令 | 解释说明 |
|---|---|
| docker-compose up | 运行容器[前台] |
| docker-compose up -d | 运行容器[后台] |
| docker-compose ps | 查看容器列表 |
| docker-compose ps -a | 查看容器列表[显示隐藏] |
| docker-compose stop | 停止容器 |
| docker-compose start | 启动容器 |
| docker-compose restart | 重启容器 |
| docker-compose down | 停止并删除容器,默认等待10s在删除 |
| docker-compose down -t 0 | 立即停止并删除容器; |
1,前台运行容器
[root@docker01:/docker-compose/test]# docker-compose up

# 此时单独开启一个终端,查看两个终端:
- 【第一个终端】:被docker-compose占用了;
- 【第二个终端】:容器列表,发现两个容器已经启动成功;

2,检查yml文件格式
[root@docker01:/docker-compose/test]# docker-compose config
3,后台运行容器
# 后台运行容器
[root@docker01:/docker-compose/test]# docker-compose up -d
[+] Running 2/2
✔ Container db01 Started 0.5s
✔ Container web01 Started 0.5s
# 查看容器列表
[root@docker01:/docker-compose/test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
22092918c775 nginx... "/docker-entr..." 5 seconds Up 4 seconds 80/tcp web01
b26e20268705 mysql... "docker-entry..." 5 seconds Up 4 seconds 3306/tcp, 33060/tcp db01
4,查看容器服务
# 查看运行的容器
[root@docker01:/docker-compose/test]# docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
db01 mysql:... "docker..." bakwite-container02 4 minutes Up 4 minutes 3306/tcp, 33060/tcp
web01 nginx:... "docker..." bakwite-container01 4 minutes Up 4 minutes 80/tcp
# 查看隐藏的容器
[root@docker01:/docker-compose/test]# docker-compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
db01 mysql:... "docker..." bakwite-container02 4 minutes Up 4 minutes 3306/tcp, 33060/tcp
web01 nginx:... "docker..." bakwite-container01 4 minutes Up 4 minutes 80/tcp
5,停止容器
[root@docker01:/docker-compose/test]# docker-compose stop
[+] Stopping 2/2
✔ Container web01 Stopped 0.1s
✔ Container db01 Stopped 1.2s
# 停止后之后查看隐藏的容器
[root@docker01:/docker-compose/test]# docker-compose ps -a
NAME IMAGE COMMAND ERVICE CREATED STATUS PORTS
db01 mysql:8.0... "docker..." bakwite-container02 8 minutes ago Exited (0) 57 seconds ago
web01 nginx:1.2... "docker..." bakwite-container01 8 minutes ago Exited (0) 58 seconds ago
6,启动和重启容器
# 启动容器
[root@docker01:/docker-compose/test]# docker-compose start
[+] Running 2/2
✔ Container db01 Started 0.6s
✔ Container web01 Started 0.6s
# 重启容器
[root@docker01:/docker-compose/test]# docker-compose restart
[+] Restarting 2/2
✔ Container web01 Started 0.4s
✔ Container db01 Started 0.5s
7,停止并删除容器
[root@docker01:/docker-compose/test]# docker-compose down
[+] Running 3/3
✔ Container web01 Removed 0.2s
✔ Container db01 Removed 1.1s
✔ Network test_default Removed 0.2s
# 查看隐藏容器验证,已经被删除;
[root@docker01:/docker-compose/test]# docker-compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
4,yml文件的编写
· 指定网络类型与守护进程命令
| docker-compose | docker run | dockerfile | 说明 |
|---|---|---|---|
| network_mode | --network :one:bridge :two:host :three:none :four:container:容器名 |
指定默认网络类型 共享容器网络时2种写法: :one:【services: 服务模块名称】 :two:【container: 容器名称】 |
|
| services.服务模块名称.command | CMD | 可以改变的守护进程命令 | |
| services.服务模块名称.entrypoint | ENTRYPOINT | 不可以改变的守护进程命令 |
1,编辑yml文件
[root@docker01:/docker-compose/test]# vim docker-compose.yml
services:
bakwite-c1:
container_name: c1
image: alpine:latest
# [network_mode]指定默认的网络类型;
network_mode: host
# [command]指定容器运行的守护进程命令;
#command: ["tail","-f","/etc/hosts"] 这种写法也可以
entrypoint:
- tail
- -f
command:
- /etc/hosts
bakwite-c2:
container_name: c2
image: alpine:latest
network_mode: none
entrypoint:
- tail
- -f
command:
- /etc/hosts
bakwite-c3:
container_name: c3
image: alpine:latest
network_mode: bridge
entrypoint:
- tail
- -f
command:
- /etc/hosts
bakwite-c4:
container_name: c4
image: alpine:latest
network_mode: container:c3
#network_mode: services:bakwite-c3
entrypoint:
- tail
- -f
command:
- /etc/hosts
2,运行
[root@docker01:/docker-compose/test]# docker-compose up -d
[root@docker01:/docker-compose/test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8bd43939556c alpine:latest "tail -f /etc/hosts" 4 seconds ago Up 3 seconds c4
9dcc54178b6d alpine:latest "tail -f /etc/hosts" 4 seconds ago Up 3 seconds c2
2fdae0c166eb alpine:latest "tail -f /etc/hosts" 4 seconds ago Up 3 seconds c1
feb59ba525c5 alpine:latest "tail -f /etc/hosts" 4 seconds ago Up 3 seconds c3
3,查看网络测试
查看c1是否是【host】与宿主机相同网络
[root@docker01:/docker-compose/test]# docker exec c1 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP qlen 1000
link/ether 00:0c:29:f4:6e:a4 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.121/24 brd 10.0.0.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fef4:6ea4/64 scope link
valid_lft forever preferred_lft forever
4: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
40: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:d7:86:81:79 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
inet6 fe80::42:d7ff:fe86:8179/64 scope link
valid_lft forever preferred_lft forever
202: veth0576ddc@if201: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 state UP
link/ether da:42:f1:d9:4e:b7 brd ff:ff:ff:ff:ff:ff
inet6 fe80::d842:f1ff:fed9:4eb7/64 scope link
valid_lft forever preferred_lft forever
查看c2是否是【none】没有网络
[root@docker01:/docker-compose/test]# docker exec c2 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
查看c3是否为【bridge】默认容器网络
[root@docker01:/docker-compose/test]# docker exec c3 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
201: eth0@if202: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
查看c4是否是【container:c3】与c3容器共享网络
[root@docker01:/docker-compose/test]# docker exec c4 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
201: eth0@if202: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
· 自定义网络与构建镜像
回想alpine实现负载均衡的案例:我们使用docker-compose来完成一次;
1,环境准备
查看负载均衡的构建目录
[root@docker01:/docker-compose/test]# ll /dockerfile/lb/
......
-rw-r--r-- 1 root root 177 Sep 8 15:22 lb.conf
-rw-r--r-- 1 root root 608 Sep 8 15:03 lb-Dockerfile
-rw-r--r-- 1 root root 610 Sep 8 14:52 web-Dockerfile
-rw-r--r-- 1 root root 620 Sep 8 14:52 web.conf
删除所有本地镜像(为了测试)
[root@docker01:/docker-compose/test]# docker image rm -f `docker images -aq`
2,编辑yml文件
| yml文件区域 | docker-compose | 字段说明 |
|---|---|---|
| services区 | container_name: | 指定容器名称 如同docker run --name 注意:如果不写这个字段,默认使用模块名称做容器名; |
| services区 | image: | 指定使用的镜像名称 |
| services区 | networks: 网络名称: ipv4_address: ip地址 |
指定网络 如同: --network:网络名称 --ip: ip地址 |
| services区 | build: context: 构建目录 dockerfile: Dockerfile名称 |
构建镜像 如同:docker build |
| services区 | depends_on: 服务名称 |
表示,这个容器依赖于哪些容器? 就是在谁之后启动? |
| networks区 | name | 网络名称 注意:它与services下的network_mode冲突哦~ |
| networks区 | driver | 网络类型【briage、overlay、macvlan】 |
| networks区 | external: true | 表示这个网络已经存在,使用已经存在的网络,不创建 |
| networks区 | ipam.config - subnet: 172.88.0.0/16 gateway: 172.88.0.1 |
ip配置 |
[root@docker01:/docker-compose/test]# vim docker-compose.yml
# 声明【创建容器服务】
services:
# 自定义的【服务模块名称】服务容器的在yml文件中的模块名称,用于其他位置引用;
bakwite-web01:
# 【container_name】指定容器的名称,如果不写,会默认使用【服务模块名称-1】
container_name: web01
# 【image】指定镜像的名称,如果没有回去仓库拉取,如果是构建,则是构建出来的镜像名称
image: alpine:web
# 【networks】指定要使用的网络名称;
networks:
# 指定网络模块的名称;
bakwite-net:
# 【ipv4_address】容器ipv4的ip地址设置
ipv4_address: 172.88.0.3
# 【build】构建镜像
build:
# 【context】指定构建的目录
context: /dockerfile/lb
# 【dockerfile】指定dockerfile文件名
dockerfile: web-Dockerfile
bakwite-web02:
container_name: web02
image: alpine:web
networks:
bakwite-net:
ipv4_address: 172.88.0.4
# 【depends_on】表示基于哪个容器之后启动,依赖于那个容器;
depends_on:
# 容器名列表;
- bakwite-web01
bakwite-lb:
container_name: lb
image: alpine:lb
networks:
bakwite-net:
ipv4_address: 172.88.0.2
build:
context: /dockerfile/lb
dockerfile: lb-Dockerfile
depends_on:
- bakwite-web01
- bakwite-web02
# 声明【创建网络】
networks:
# 在yml文件中,网络模块的名称,用于创建多个网络时,区分网络;
bakwite-net:
# 【name】创建网络的名称
name: lb_network
# 【driver】指定创建的网络类型(bridge、overlay、macvlan等网络类型);
driver: bridge
# 【external】表示这个网络名称是存在的,直接使用,不创建新网络;
#external: true
# 【ipam】指定网络IP地址的规划设置;
ipam:
# 【config】网络配置
config:
# 【- subnet】指定容器的网段
- subnet: 172.88.0.0/16
# 【gateway】指定容器的网关出口
gateway: 172.88.0.1
3,运行docker-compose
[root@docker01:/docker-compose/test]# docker-compose up -d
[root@docker01:/docker-compose/test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c6c0a8cda053 alpine:lb "nginx -g 'daemon of…" 7 seconds ago Up 5 seconds lb
8c7b37eb7820 alpine:web "nginx -g 'daemon of…" 7 seconds ago Up 5 seconds web02
9b6975b89ed9 alpine:web "nginx -g 'daemon of…" 7 seconds ago Up 5 seconds web01
4,测试负载均衡效果
# 查看负载均衡容器的ip地址;
[root@docker01:/docker-compose/test]# docker exec lb ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
147: eth0@if148: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:58:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.88.0.2/16 brd 172.88.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 测试访问负载均衡器容器
[root@docker01:/docker-compose/test]# curl 172.88.0.2
{
'client_IP': 172.88.0.2,
'user_URI': /,
'request_web_IP': 172.88.0.3,
'request_web_HOSTNAME': c29b3bd8557c,
'request_HOST': 172.88.0.2,
'user_UA': curl/7.81.0,
'response_byte_SIZE': 0,
'response_status_NUM': 200,
'@timestamp': 2025-09-08T08:53:16+00:00
}
[root@docker01:/docker-compose/test]# curl 172.88.0.2
{
'client_IP': 172.88.0.2,
'user_URI': /,
'request_web_IP': 172.88.0.4,
'request_web_HOSTNAME': c7a0bf6ea102,
'request_HOST': 172.88.0.2,
'user_UA': curl/7.81.0,
'response_byte_SIZE': 0,
'response_status_NUM': 200,
'@timestamp': 2025-09-08T08:53:17+00:00
}
· 设置环境变量
| docker-compose | docker run | 解释说明 |
|---|---|---|
| services.服务名称.environment | -e | 传递环境变量到容器 |
| services.服务名称.env_file | 多个-e | 【多变量传递时使用】将文件中的环境变量传递到容器 |
1,编辑dockerCompose
启动一个容器,并传递环境变量
[root@docker01:/docker-compose/test]# cat docker-compose.yml
services:
bakwite-c1:
container_name: c1
image: nginx:1.20.1-alpine
networks:
bakwite-net:
ipv4_address: 172.77.0.2
# 【environment】传递环境变量
environment:
# 注意:key=value,不能使用引号,否则引号也会被当做变量;
- username=zhangsan
- password=123456
env_file:
- env.txt
networks:
bakwite-net:
name: net-wa
driver: bridge
ipam:
config:
- subnet: 172.77.0.0/16
gateway: 172.77.0.1
2,编辑变量文件
[root@docker01:/docker-compose/test]# vim env.txt
age=28
sex=女
3,运行测试
[root@docker01:/docker-compose/test]# docker-compose up -d
# 进入容器,查看环境变量
[root@docker01:/docker-compose/test]# docker exec -it c1 sh
- 使用docker-compose进入容器,注意,这里不能指定容器名称,需要指定yml的服务名称
[root@docker01:/docker-compose/test]# docker-compose exec bakwite-c1 sh
/ # env
......
username=zhangsan
......
age=28
......
password=123456
sex=女
......
· 暴露端口与端口映射
| docker-compose | docker run | dockerfile | 解释说明 |
|---|---|---|---|
| services.服务模块名称.expose | EXPOSE | 对外暴露端口 | |
| services.服务模块名称.ports | -p | 宿主机与容器端口映射 |
案例:
- 编辑dockerfile基于alpine镜像;构建openssh服务容器;
- 不使用EXPOSE暴露端口;
- 使用docker-compose进行端口暴露与端口映射;
- 最终实现:外部网络可以ssh连接容器;
1,编辑dockerfile
# 创建build目录
[root@docker01:/docker-compose/test]# mkdir build
[root@docker01:/docker-compose/test]# cd build/
# 编辑dockerfile
[root@docker01:/docker-compose/test/build]# cat Dockerfile
FROM alpine:latest
RUN sed -i 's@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g' /etc/apk/repositories && \
apk update && \
apk add openssh-server && \
sed -i 's@#PermitRootLogin prohibit-password@PermitRootLogin yes@g' /etc/ssh/sshd_config && \
echo "ssh-keygen -A" >> /root/ssh.sh && \
echo "echo 'root:123456' | chpasswd " >> /root/ssh.sh && \
echo "/usr/sbin/sshd -d" >> /root/ssh.sh && \
rm -rf /var/cache/
CMD ["/bin/sh","/root/ssh.sh"]
2,编辑yml文件
[root@docker01:/docker-compose/test]# vim docker-compose.yml
services:
bakwite-c1:
container_name: ssh
image: ssh-alpine:v1.0.0
networks:
bakwite-net:
ipv4_address: 172.77.0.2
build:
context: build/
dockerfile: Dockerfile
expose:
- 22
ports:
- 2222:22
networks:
bakwite-net:
name: net-wa
driver: bridge
ipam:
config:
- subnet: 172.77.0.0/16
gateway: 172.77.0.1
3,启动
[root@docker01:/docker-compose/test]# docker-compose up -d
[root@docker01:/docker-compose/test]# netstat -tnulp
......
tcp6 0 0 :::2222 :::* LISTEN 1324390/docker-prox
......
4,外网链接容器测试
[C:\~]$ ssh root@10.0.0.121 2222
Connecting to 10.0.0.121:2222...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.
WARNING! The remote SSH server rejected X11 forwarding request.
Welcome to Alpine!
The Alpine Wiki contains a large amount of how-to guides and general
information about administrating Alpine systems.
See <https://wiki.alpinelinux.org/>.
You can setup the system with the command: setup-alpine
You may change this message by editing /etc/motd.
debug1: permanently_set_uid: 0/0
Environment:
USER=root
LOGNAME=root
HOME=/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAIL=/var/mail/root
SHELL=/bin/sh
TERM=xterm
SSH_CLIENT=10.0.0.1 2786 22
SSH_CONNECTION=10.0.0.1 2786 172.77.0.2 22
SSH_TTY=/dev/pts/0
36bcfe7d9e24:~#
· 容器的重启策略
1,重启策略回顾
| docker-compose | docker run | 解释说明 |
|---|---|---|
| restart: no | --restart no | 不自动重启; |
| restart: on-failure | --restart on-failure --restart on-failure:3 |
【含义】:容器以非零($?)退出状态终止时 (程序内部错误/崩溃),才会重启 【on-failure:0】和【on-failure】 :都表示不限重启次数; |
| restart: unless-stopped | --restart unless-stopped | 【含义】:除非stop 容器 否则容器任何原因终止时 (包括正常退出/崩溃),都会重启 |
| restart: always | --restart always | 【除非】:手动停止:docker stop 容器名; 【否则】:不论什么原因,一直重启; |
重启策略场景
| 重启场景 | no | on-failure on-failure:3 |
unless-stopped | always |
|---|---|---|---|---|
| 重启docker服务 | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| 先停容器、再重启docker服务 | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| 容器任务执行完毕,自动正常退出 | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: |
2,编辑yml文件
[root@docker01:/docker-compose/test]# cat docker-compose.yml
services:
bakwite-c1:
container_name: c1
image: nginx:1.20.1-alpine
restart: no
bakwite-c2:
container_name: c2
image: nginx:1.20.1-alpine
restart: always
bakwite-c3:
container_name: c3
image: nginx:1.20.1-alpine
restart: on-failure
bakwite-c4:
container_name: c4
image: nginx:1.20.1-alpine
restart: unless-stopped
3,运行
[root@docker01:/docker-compose/test]# docker-compose up -d
[root@docker01:/docker-compose/test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
db7e91a22836 nginx:1.20.1-alpine "/docker-entrypoint.…" 4 seconds ago Up 2 seconds 80/tcp c3
65e9969ac88c nginx:1.20.1-alpine "/docker-entrypoint.…" 4 seconds ago Up 2 seconds 80/tcp c4
e416fb9a97da nginx:1.20.1-alpine "/docker-entrypoint.…" 4 seconds ago Up 2 seconds 80/tcp c1
46f2209ed60a nginx:1.20.1-alpine "/docker-entrypoint.…" 4 seconds ago Up 2 seconds 80/tcp c2
4,测试
重启docker测试
- 结论:只有c1【no的重启策略】没有启动,其他容器都启动了;
[root@docker01:/docker-compose/test]# systemctl restart docker.service
[root@docker01:/docker-compose/test]# docker ps -a

手动stop停止容器,再重启docker服务测试
- 结论:只有c2容器【always的重启策略】启动了,其他的没有重启;
# 手动关闭所有容器
[root@docker01:/docker-compose/test]# docker stop `docker ps -q`
db7e91a22836
65e9969ac88c
e416fb9a97da
46f2209ed60a
# 在重启docker服务
[root@docker01:/docker-compose/test]# systemctl restart docker.service

模拟异常退出容器
- 结论:只有c1没有重启,其他的都重启了;
# 先启动所有容器
[root@docker01:/docker-compose/test]# docker stop `docker ps -aq`
# 杀死进程,模拟意外退出
[root@docker01:/docker-compose/test]# kill -9 `docker inspect c1 | grep "\bPid\b" | awk -F"[ :,]+" '{print$3}'`
[root@docker01:/docker-compose/test]# kill -9 `docker inspect c2 | grep "\bPid\b" | awk -F"[ :,]+" '{print$3}'`
[root@docker01:/docker-compose/test]# kill -9 `docker inspect c3 | grep "\bPid\b" | awk -F"[ :,]+" '{print$3}'`
[root@docker01:/docker-compose/test]# kill -9 `docker inspect c4 | grep "\bPid\b" | awk -F"[ :,]+" '{print$3}'`

· 文件挂载
解释说明:就是将宿主机的【文件】,挂载到容器中;
| 区域 | docker-compose | 解释说明 |
|---|---|---|
| services区 | secrets | - source:宿主机本地原文件 target: 挂载到容器的路径(默认挂载到/run/secrets/目录下) uid: gid: mode: 0644 |
| secrets区 | 模块名称.file: |
1,编辑yml文件
[root@docker01:/docker-compose/test]# vim docker-compose.yml
services:
bakwite-c1:
container_name: c1
image: nginx:1.20.1-alpine
secrets:
- source: bakwite_file
target: /root/1.txt
secrets:
bakwite_file:
file: ./1.txt
2,编辑测试挂载
[root@docker01:/docker-compose/test]# cat 1.txt
123456
3,运行
[root@docker01:/docker-compose/test]# docker-compose up -d
4,查看容器挂载文件
# 查看容器中是否挂载到1.txt
[root@docker01:/docker-compose/test]# docker exec c1 ls /root
1.txt
# 查看容器中挂载的1.txt内容是否一致;
[root@docker01:/docker-compose/test]# docker exec c1 cat /root/1.txt
123456
# 修改宿主机的文件内容,
[root@docker01:/docker-compose/test]# echo abcdefg >> 1.txt
# 再次查看容器中挂载的文件;
[root@docker01:/docker-compose/test]# docker exec c1 cat /root/1.txt
123456
abcdefg
· 存储卷挂载
| 区域 | docker-compose | 解释说明 |
|---|---|---|
| services区 | volumes: - type: volume source: 存储卷模块名称 target: 挂载到容器的位置 |
引用存储卷; 【挂载类型】说明: :one:volume 正常存储卷挂载 :two:bind 路径:路径挂载 :three:tmpfs 宿主机内存挂载到目标容器 |
| volumes区 | volumes: bakwite_vol: name: xxxxxx |
声明存储卷 |
1,编辑yml文件
[root@docker01:/docker-compose/test]# cat docker-compose.yml
services:
bakwite-c1:
container_name: c1
image: nginx:1.20.1-alpine
volumes:
# 指定【存储卷模块名称】挂载的存储卷:类似于:docker run -v 存储卷名称:容器路径
- type: volume
source: bakwite_volumes
target: /bakwite/volume
# 指定绑定路径挂载:类似于:docker run -v 路径:容器路径
- type: bind
source: /root/
target: /bakwite/data
# 指定将一部分宿主机的内存挂载到"/tmp"目录上
- type: tmpfs
target: /tmp/
tmpfs:
size: 64M
mode: 0700
# 指定存储卷
volumes:
bakwite_volumes:
name: xjzw_v
# 【external】表示这个存储卷是已经存在的,直接使用,不创建新存储卷;
#external: true
#####################################
###############【NFS】###############
#####################################
#volumes:
# NFS_volume:
# name: xjzw_vol
# #external: true
# # [指定驱动]:默认:local,
# driver: local
# driver_opts:
# type: nfs
# device: 10.0.0.10:/data
# opt: |
# addr=10.0.0.10,
# rw,
# soft
#####################################
#############【cephFS】##############
#####################################
#volumes:
# cephFS_volume:
# name: xjzw_vol
# #external: true
# # [指定驱动]:默认:local,
# driver: local
# driver_opts:
# type: cephFS
# device: bakwite_fs
# opt: |
# name=myuser,
# secret=AQATGHdWgBhVJhAAoOO1V4hLriLqIx2Jp7gRBA==,
# mon_addr=10.0.0.1:6789,10.0.0.2:6789,10.0.0.3:6789,
# mount_timeout=30
##############################################################
2,运行
[root@docker01:/docker-compose/test]# docker-compose up -d
3,查看存储卷
[root@docker01:/docker-compose/test]# docker volume ls
DRIVER VOLUME NAME
local xjzw_v
[root@docker01:/docker-compose/test]# docker volume inspect xjzw_v
[
{
"CreatedAt": "2025-09-10T10:31:17+08:00",
"Driver": "local",
"Labels": {
"com.docker.compose.config-hash": "fae5ab615bc287b06e871f48661f66a7d1473ca0f657d890505371b6fa63ea2d",
"com.docker.compose.project": "test",
"com.docker.compose.version": "2.39.2",
"com.docker.compose.volume": "bakwite_volume"
},
"Mountpoint": "/var/lib/docker/volumes/xjzw_v/_data",
"Name": "xjzw_v",
"Options": null,
"Scope": "local"
}
]
4,存储卷写入数据测试
[root@docker01:/docker-compose/test]# echo 1234 > /var/lib/docker/volumes/xjzw_vol/_data/123.txt
[root@docker01:/docker-compose/test]# docker exec c1 cat /bakwite/data/123.txt
1234
5,删除容器测试持久化
# 删除容器
[root@docker01:/docker-compose/test]# docker-compose down -t 0
[+] Running 2/2
✔ Container c1 Removed 0.1s
✔ Network test_default Removed 0.1s
# 查看存储卷,发现依然存在
[root@docker01:/docker-compose/test]# docker volume ls
DRIVER VOLUME NAME
local xjzw_vol
6,删除容器并删除存储卷
# 清空存储卷
[root@docker01:/docker-compose/test]# docker volume prune -f
Deleted Volumes:
xjzw_v
Total reclaimed space: 5B
# 重新启动容器
[root@docker01:/docker-compose/test]# docker-compose up -d
[+] Running 3/3
✔ Network test_default Created 0.1s
✔ Volume "xjzw_v" Created 0.1s
✔ Container c1 Started 0.1s
# 再次删除容器,-v,表示同时删除存储卷;
[root@docker01:/docker-compose/test]# docker-compose down -t 0 -v
[+] Running 3/3
✔ Container c1 Removed 0.1s
✔ Volume xjzw_ Removed 0.1s
✔ Network test_default Removed 0.1s
· 容器的能力设置Capabilities(了解)
| linux的Capabilities能力 | 解释说明 |
|---|---|
| CAP_CHOWN | 允许改变文件所有者 和所有组 |
| CAP_NET_RAW | 允许使用 RAW 和 PACKET 套接字,ping, tcpdump, 网络探测 |
| CAP_NET_BIND_SERVICE | 允许绑定到 1024 以下的特权端口 |
| CAP_NET_ADMIN | 网络接口、路由、防火墙配置,VPN, 网络网关, 路由配置 |
| CAP_DAC_OVERRIDE | 忽略文件的 DAC 访问限制,绕过文件读写权限检查 极高 覆盖文件权限 |
| CAP_SYS_CHROOT | 允许使用 chroot()子系统功能,使用chroot()系统调用,创建隔离环境(旧式容器) |
| CAP_SYS_ADMIN | 允许执行系统管理任务(许多特权操作需要此能力) |
| CAP_SYS_PTRACE | 允许跟踪任意进程 |
| CAP_AUDIT_WRITE | 向内核审计日志写入记录,记录审计日志 |
| CAP_KILL | 向任意进程发送信号, 进程管理 |
| CAP_SETGID | 自由操纵进程组身份,切换组身份 |
| CAP_SETUID | 自由操纵进程用户身份,切换用户身份(如提权)(su - root) |
| CAP_SETPCAP | 管理其他进程的能力,能力管理 |
| CAP_SETFCAP | 为文件设置能力,给二进制文件赋予特权 |
| CAP_MKNOD | 创建设备特殊文件,创建/dev/下的设备节点 |
| CAP_FSETID | 写文件后保留setuid/setgid位,维护setuid程序 |
| CAP_FOWNER | 执行需文件属主权限的操作;文件管理、删除文件 |
1,编辑yml文件
[root@docker01:/docker-compose/test]# cat docker-compose.yml
services:
bakwite-c1:
container_name: c1
image: ubuntu:22.04
command:
- tail
- -f
- /etc/hosts
# 表示添加能力
cap_add:
- ALL
# 删除能力
cap_drop:
- NET_ADMIN # 不允许使用网络命令
- CHOWN # 不允许改变文件的属主与属组
bakwite-c2:
container_name: c2
image: ubuntu:22.04
command:
- tail
- -f
- /etc/hosts
2,运行
[root@docker01:/docker-compose/test]# docker-compose up -d
[+] Running 3/3
✔ bakwite-c1 Pulled 21.1s
✔ bakwite-c2 Pulled 21.1s
✔ 60d98d907669 Pull complete 4.3s
[+] Running 2/2
✔ Container c1 Started 0.8s
✔ Container c2 Started 0.8s
# 查看容器
[root@docker01:/docker-compose/test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8306515a2e16 ubuntu:22.04 "tail -f /etc/hosts" 33 seconds ago Up 32 seconds c1
0333b330ec4e ubuntu:22.04 "tail -f /etc/hosts" 33 seconds ago Up 32 seconds c2
3,测试修改文件所有者
# 在两个容器中创建1个文件
[root@docker01:/docker-compose/test]# docker exec c1 mkdir 1.txt
[root@docker01:/docker-compose/test]# docker exec c2 mkdir 1.txt
# 在两个容器中创建1个用户
[root@docker01:/docker-compose/test]# docker exec c1 useradd -M -s /sbin/nologin wa
[root@docker01:/docker-compose/test]# docker exec c2 useradd -M -s /sbin/nologin wa
[root@docker01:/docker-compose/test]# docker exec c1 id wa
uid=1000(wa) gid=1000 groups=1000
[root@docker01:/docker-compose/test]# docker exec c2 id wa
uid=1000(wa) gid=1000(wa) groups=1000(wa)
# 文件修改属主和数组
- c2 可以修改
[root@docker01:/docker-compose/test]# docker exec c2 chown wa.wa 1.txt
- c1 不可以修改
[root@docker01:/docker-compose/test]# docker exec c1 chown wa.wa 1.txt
chown: invalid user: 'wa.wa'
· 容器的健康检查
| docker-compose | dockerfile | 解释说明 |
|---|---|---|
| interval: 1m30s | --interval=1m30s | 每1分30秒检查一次 |
| start_period: 40s | --start-period=40s | 容器启动后40秒内失败不计入重试 |
| retries: 3 | --retries=3 | 连续失败3次才标记为不健康 |
| timeout: 10s | --timeout=10s | 每次检查最多等待10秒,超过10s算失败; |
| test:["CMD","curl","-f","http://localhost"] | CMD curl -f http://localhost || exit 1 | 健康检查的命令是什么 |
1,编辑yml文件
[root@docker01:/docker-compose/test]# cat docker-compose.yml
services:
bakwite-c1:
container_name: c1
image: nginx:1.20.1-alpine
command:
- nginx
- -g
- daemon off;
healthcheck:
test: ["CMD","curl","-f","http://localhost"]
interval: 1m30s
timeout: 10s
retries: 3
start_period: 40s
2,运行
[root@docker01:/docker-compose/test]# docker-compose up -d
[+] Running 2/2
✔ Network test_default Created 0.1s
✔ Container c1 Started 0.3s
3,查看容器列表
[root@docker01:/docker-compose/test]# docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
c1 nginx... "/docker..." bakwite-c1 8 s Up 7 s(health: starting) 80/tcp
# 到40s之后,staring才消失,才变成健康状态,证明健康检查成功;
[root@docker01:/docker-compose/test]# docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
c1 nginx... "/docker..." bakwite-c1 8 s Up 47 s(health) 80/tcp
· 容器的资源限制
| docker-compose | docker run | 解释说明 |
|---|---|---|
| services.服务模块名称.cpus | --cpus=1.5 | 限制cpu使用量1.5个核心 |
| services.服务模块名称.mem_limit: 2G | --memory=2G | 限制内存使用量 |
| services.服务模块名称.pids_limit: 200 | --pids-limit 200 | 限制整个容器进程最大数量 |
| services.服务模块名称.ulimits.nproc: 1024 | --ulimit nproc=1024:1024 | 限制单个用户创建的最大进程数 |
| services.服务模块名称.ulimits.nofile.soft: 8192 services.服务模块名称.ulimits.nofile.hard: 16384 |
--ulimit nofile=8192:16384 | 文件最大描述符 |
1,编辑yml文件
[root@docker01:/docker-compose/test]# cat docker-compose.yml
services:
xinjizhia-c1:
container_name: c1
image: nginx:1.20.1-alpine
cpus: '1.5'
mem_limit: 2G
pids_limit: 1024
ulimits:
nproc: 1024
nofile:
soft: 8192
hard: 16384
2,运行
[root@docker01:/docker-compose/test]# docker-compose up -d
[+] Running 2/2
✔ Network test_default Created 0.1s
✔ Container c1 Started 0.3s
3,查看限制结果
[root@docker02:~]# docker stats --no-stream
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
b5b3adb81a3f c1 0.00% 2.957MiB / 2GiB 0.14% 1.65kB / 0B 0B / 24.6kB 3
5,实战案例
要求:
- 实现wordpress个人博客的两个web容器负载均衡;
- 必须使用docker-compose来实现;
· 创建工作目录
# 创建工作目录
[root@docker02:~]# mkdir -p /bakwite/wordpress
[root@docker02:~]# cd /bakwite/wordpress
· 上传解压wordpress代码包
[root@docker02:/bakwite/wordpress]# rz -E
[root@docker02:/bakwite/wordpress]# rm -rf wordpress-6.8.2-zh_CN.zip
[root@docker02:/bakwite/wordpress]# ls -l
total 4
drwxr-xr-x 5 root root 4096 Jul 29 15:00 wordpress
· 准备nginx的lb配置文件
[root@docker02:/bakwite/wordpress]# vim lb.conf
upstream web-server {
server web01;
server web02;
}
server {
listen 80;
location / {
proxy_pass http://web-server;
proxy_set_header Host $http_host;
}
}
· 准备nginx的web配置文件
主配置文件
[root@docker02:/bakwite/wordpress]# vim nginx.conf
user www;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
}
子配置文件
[root@docker02:/bakwite/wordpress]# vim web.conf
server {
listen 80;
server_name localhost;
root /wordpress;
location / {
index index.html index.php;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
· 创建build构建php目录文件
[root@docker02:/bakwite/wordpress]# mkdir build
[root@docker02:/bakwite/wordpress]# vim build/Dockerfile
# 【FROM】指定使用基础镜像
FROM ubuntu:22.04
# 安装软件
RUN sed -i "s#http:\/\/archive.ubuntu.com/#http:\/\/mirrors.aliyun.com/#g" /etc/apt/sources.list && \
apt update && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apt -y install software-properties-common && \
add-apt-repository ppa:ondrej/php && \
apt update && \
apt -y install php7.4 && \
apt -y install php7.4-common && \
apt -y install php7.4-cli && \
apt -y install php7.4-fpm && \
apt -y install php7.4-mysql && \
apt -y install php7.4-xml && \
apt -y install php7.4-gd && \
apt -y install php7.4-mbstring && \
apt -y install php7.4-zip && \
apt -y install php7.4-bcmath && \
apt -y install php7.4-soap && \
apt -y install php7.4-intl && \
apt -y install php7.4-readline && \
apt -y install php7.4-opcache && \
apt -y install php7.4-curl && \
apt -y install php7.4-ldap && \
apt -y install php7.4-imap && \
apt -y install php7.4-pgsql && \
apt -y install php7.4-sqlite3 && \
apt -y install nginx && \
useradd -s /sbin/nologin -M www && \
rm -rf /etc/nginx/conf.d/* && \
sed -i "s#user = www-data#user = www#g" /etc/php/7.4/fpm/pool.d/www.conf && \
sed -i "s#group = www-data#group = www#g" /etc/php/7.4/fpm/pool.d/www.conf && \
sed -i "s#listen = /run/php/php7.4-fpm.sock#listen = 9000#g" /etc/php/7.4/fpm/pool.d/www.conf && \
echo "/usr/sbin/php-fpm7.4 -F &" > /root/start.sh && \
echo "/usr/sbin/nginx -g 'daemon off;'" >> /root/start.sh && \
mkdir /run/php/ && \
mkdir /wordpress && \
chown -R www.www /run/php/ && \
chown -R www.www /wordpress && \
rm -rf /var/cache/apt/archives/
# 【CMD】镜像启动为容器后的守护进程命令;nginx的启动并监听命令;
CMD ["sh","/root/start.sh"]
· 编辑yml文件
[root@docker01:/bakwite/wordpress]# cat docker-compose.yml
services:
wa_lb:
container_name: lb
image: nginx:1.20.1-alpine
secrets:
- source: lb_conf
target: /etc/nginx/conf.d/default.conf
ports:
- 80:80
depends_on:
- wa_web01
- wa_web02
wa_web01:
container_name: web01
image: n_p:v1.0
build:
context: ./build/
dockerfile: Dockerfile
secrets:
- source: web_conf
target: /etc/nginx/conf.d/default.conf
- source: nginx_conf
target: /etc/nginx/nginx.conf
volumes:
- type: bind
source: ./wordpress
target: /wordpress
wa_web02:
container_name: web02
image: n_p:v1.0
secrets:
- source: web_conf
target: /etc/nginx/conf.d/default.conf
- source: nginx_conf
target: /etc/nginx/nginx.conf
volumes:
- type: bind
source: ./wordpress
target: /wordpress
depends_on:
- wa_web01
wa_db:
container_name: db
image: mysql:8.0-oracle
environment:
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wp
- MYSQL_PASSWORD=123456
- MYSQL_ROOT_PASSWORD=123456
command:
- --character-set-server=utf8
- --collation-server=utf8_bin
- --default-authentication-plugin=mysql_native_password
secrets:
lb_conf:
file: ./lb.conf
web_conf:
file: ./web.conf
nginx_conf:
file: ./nginx.conf
· 启动
[root@docker01:/bakwite/wordpress]# docker-compose up -d
· 浏览器访问测试
10.0.0.121

十三、harbor私有镜像仓库
1,harbor概述
harbor是采用go语言开发的私有镜像仓库服务;

2,安装部署
· 准备harbor主机
| 主机名 | ip地址 |
|---|---|
| harbor01 | 10.0.0.131 |
| harbor02 | 10.0.0.132 |
· 准备环境
注意:要想安装harbor服务必须主机满足两个条件:
- 必须安装了docker环境;
- 必须安装了docker-compose环境
1,安装部署docker
#1,下载docker安装包
[root@docker01 ~ 18:26:36]# wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.24.tgz
#2,查看
[root@docker01 ~ 18:28:16]# ll
...
-rw-r--r-- 1 root root 66990280 7月 12 2023 docker-20.10.24.tgz
#3,解压软件包
[root@harbor01:~]# tar xf docker-20.10.24.tgz
#4,授权docker执行文件
[root@harbor01:~]# chown root.root docker/*
#5,将命令文件移动到PATH路径
[root@harbor01:~]# cp docker/* /usr/bin/
#6,配置linux的内核转发
[root@harbor01:~]# echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
[root@harbor01:~]# sysctl -p
net.ipv4.ip_forward = 1
#7,编辑systemctl启动文件
[root@harbor01:~]# vim /lib/systemd/system/docker.service
[Unit]
Description=bakwite docker
Documentation=https://www.bakwite.com
#启动docker时,需要什么程序已经准备好???(没启动成功页没关系)
After=network-online.target containerd.service
#如果这个程序没准备好,依旧可以启动docker
Wants=network-online.target
[Service]
Type=notify #systemd配置,表示,docker进程启动好running/active之后再进行下一步操作;
#服务启动时执行的命令
ExecStart=/usr/bin/dockerd
# 重启进程,$MAINPID表示docker的pid变量(systemd生成的)
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0 #docker停止时等待时间,0表示伊吾县等待其优雅停止,避免强制杀死
LimitNOFILE=infinity #不限制文件打开数
LimitNPROC=infinity #不限制系统进程打开数
[Install]
WantedBy=multi-user.target
# 启动docker
[root@harbor01:~]# systemctl enable --now docker.service
2,安装部署docker-compose
#1,下载docker-compose文件
[root@harbor01:~]# wget https://github.com/docker/compose/releases/download/v2.39.3/docker-compose-linux-x86_64
#2,将文件改名
[root@harbor01:~]# mv docker-compose-linux-x86_64 docker-compose
#3,给docker-compose文件执行权限
[root@harbor01:~]# chmod +x docker-compose
#4,将docker-compose文件移动到PATH目录
[root@harbor01:~]# cp docker-compose /usr/local/bin/
#5,查看版本
[root@harbor01:~]#
Docker Compose version v2.39.3
· 官网下载harbor安装包
注意:需要科学上网哦
https://github.com/goharbor/harbor/releases
注意:选择最新的稳定版即可

# 选择离线安装版本
- 选择【harbor-offine-installer-v2.13.2.tgz】

# 右键复制链接地址

# wget下载harbor软件包
[root@harbor01:~]# wget https://github.com/goharbor/harbor/releases/download/v2.13.2/harbor-offline-installer-v2.13.2.tgz
# 查看软件包
[root@harbor01:~]# ls -l
total 654988
-rw-r--r-- 1 root root 670694110 Jul 31 17:54 harbor-offline-installer-v2.13.2.tgz
· 解压harbor安装包
1,创建安装目录
[root@harbor01:~]# mkdir /harbor
2,解压harbor到安装目录
[root@harbor01:~]# tar xf harbor-offline-installer-v2.13.2.tgz -C /
[root@harbor01:~]# ls -l /harbor
total 659256
-rw-r--r-- 1 root root 3646 Jul 31 10:48 common.sh
-rw-r--r-- 1 root root 675032342 Jul 31 10:48 harbor.v2.13.2.tar.gz
-rw-r--r-- 1 root root 14688 Jul 31 10:48 harbor.yml.tmpl
-rwxr-xr-x 1 root root 1975 Jul 31 10:48 install.sh
-rw-r--r-- 1 root root 11347 Jul 31 10:48 LICENSE
-rwxr-xr-x 1 root root 2211 Jul 31 10:48 prepare
· 修改配置文件
复制一份临时harbor配置文件,将后缀tmpl去掉
[root@harbor01:~]# cp /harbor.yml.tmpl /harbor.yml
开始编辑harbor的配置文件
[root@harbor01:~]# vim /harbor/harbor.yml
# 定义 Harbor 服务的外部访问地址。客户端(如 Docker、Helm)将使用这个地址来访问 Harbor。
# 必须设置为 IP 或域名,并且不能是 `localhost` 或 `127.0.0.1`。
hostname: reg01.bakwite.com
# HTTP 协议配置
http:
# Harbor 服务监听 HTTP 请求的端口。默认为 80。
port: 80
# HTTPS 协议配置。如果配置了 HTTPS,HTTP 端口将自动重定向到 HTTPS 端口。
https:
# Harbor 服务监听 HTTPS 请求的端口。默认为 443。
port: 443
# SSL 证书公钥(最好是:ca公钥和harbor公钥合并)。
certificate: /harbor/certs/harbor.crt
# SSL 证书私钥。
private_key: /harbor/certs/harbor.key
# Harbor 系统管理员admin的初始密码。
harbor_admin_password: 123456
# 数据库配置。Harbor 使用 PostgreSQL 数据库来存储元数据(项目、用户、镜像列表等,不是镜像文件本身)。
database:
# 用于连接 PostgreSQL 数据库的密码。
password: root123
# 连接池中保持的最大空闲连接数。有助于提升性能,避免频繁建立新连接。
max_idle_conns: 100
# 数据库打开的最大连接数。根据服务器硬件和负载调整。
max_open_conns: 900
# 一个连接可被重用的最长时间。超过此时间后,连接将在被放回池中时关闭。
conn_max_lifetime: 5m
# 一个连接在空闲状态下的最长存活时间。0 表示没有限制。
conn_max_idle_time: 0
# Harbor 用于存储数据的目录。
# 包括镜像文件、图表(Chart)文件以及数据库数据(如果使用内部数据库)。
data_volume: /harbor/data
# Trivy 配置。Trivy 是 Harbor 集成的漏洞扫描器。
trivy:
# 是否忽略未提供修复方案的漏洞。`false` 表示不忽略,会报告所有漏洞。
ignore_unfixed: false
# 在启动时是否跳过更新 Trivy 的漏洞数据库。`false` 表示自动更新,建议生产环境保持更新。
skip_update: false
# (特定于Java) 是否跳过更新 Java 索引数据库。`false` 表示更新。
skip_java_db_update: false
# 是否启用离线扫描模式。如果为 `true`,则仅使用本地数据库,不尝试从网络获取更新。
offline_scan: false
# 扫描的安全检查类型。`vuln` 表示漏洞扫描。
security_check: vuln
# 是否允许 Trivy 使用不安全的连接(如自签名证书)下载漏洞数据库。
insecure: false
# 扫描超时时间。如果一次扫描超过此时间,将被终止。
timeout: 5m0s
# Jobservice 配置。Jobservice 是 Harbor 中处理异步任务(如镜像复制、扫描等)的组件。
jobservice:
# 最大并发工作线程数。决定了可以同时执行的任务数量。
max_job_workers: 10
# 一个任务的最长运行时间(小时)。超过此时间的任务将被标记为失败。
max_job_duration_hours: 24
# 任务日志的输出方式。
# STD_OUTPUT: 输出到标准输出(通常会被 Docker 日志捕获)
# FILE: 输出到文件(在 `data_volume` 指定的目录下)
job_loggers:
- STD_OUTPUT
- FILE
# 日志清理器运行的频率(天)。每隔 `1` 天,它会清理过期的任务日志文件。
logger_sweeper_duration: 1 #days
# Webhook 通知配置。当发生推送镜像、删除镜像等事件时,Harbor 可以向外部系统发送通知。
notification:
# 发送 webhook 通知失败后的最大重试次数。
webhook_job_max_retry: 3
# 发送 webhook 通知请求时的 HTTP 客户端超时时间(秒)。
webhook_job_http_client_timeout: 3 #seconds
# 日志配置。
log:
# 全局日志级别。可选值:debug, info, warning, error, fatal。
level: info
# 本地文件日志配置。
local:
# 保留的日志文件轮转数量。例如 50,表示最多保留 50 个旧的日志文件。
rotate_count: 50
# 每个日志文件的最大大小。超过此大小会触发轮转。200M 表示 200MB。
rotate_size: 200M
# Harbor 组件日志文件的存储位置。
location: /var/log/harbor
# Harbor 的配置版本。此字段由 Harbor 自身维护,通常不需要手动修改。
_version: 2.15.2
# 代理服务器配置。如果 Harbor 所在服务器需要通过代理才能访问外部网络(如下载 Trivy 数据库),则需要在此配置。
proxy:
# HTTP 代理服务器的地址。
http_proxy:
# HTTPS 代理服务器的地址。
https_proxy:
# 不需要通过代理访问的地址列表,用逗号分隔。
no_proxy:
# 哪些 Harbor 组件需要使用代理。这里配置了 core, jobservice, trivy。
components:
- core
- jobservice
- trivy
# 上传缓存清理策略。
# 当客户端上传文件(如镜像层)失败或中断时,会留下临时文件。此功能用于自动清理这些文件。
upload_purging:
# 是否启用自动清理。`true` 为启用。
enabled: true
# 清理多久之前的临时文件。`168h` 表示 168 小时(7 天)前的文件将被清理。
age: 168h
# 清理作业的运行间隔。`24h` 表示每 24 小时运行一次清理任务。
interval: 24h
# 是否仅模拟运行(dry run)。`true` 时只会打印要清理的文件列表而不会实际删除,用于测试。`false` 会实际执行删除。
dryrun: false
# 缓存配置(通常指项目的元数据缓存,用于加速 UI 显示)。
cache:
# 是否启用缓存。`false` 表示不启用。
enabled: false
# 缓存数据的过期时间(小时)。`24` 表示 24 小时后缓存失效。
expire_hours: 24
· 生成SSL证书
1,创建证书目录
[root@harbor01:~]# mkdir /harbor/certs
[root@harbor01:~]# cd /harbor/certs
[root@harbor01:/certs]#
2,生成CA根证书
# 生成CA私钥
[root@harbor01:/certs]# openssl genrsa -out ca.key 2048
# 生成CA公钥
[root@harbor01:/certs]# openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=IT/CN=MyRootCA"
3,生成harbor证书
# 生成harbor服务私钥
[root@harbor01:/certs]# openssl genrsa -out harbor.key 2048
# 生成证书请求文件CSR
[root@harbor01:/certs]# openssl req -new -key harbor.key -out harbor.csr \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=IT/CN=reg01.bakwite.com"
# 生成harbor服务公钥
[root@harbor01:/certs]# openssl x509 -req -in harbor.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out harbor.crt -days 3650 -sha256 \
-extensions san -extfile <(printf "[san]\nsubjectAltName=DNS:reg01.bakwite.com,DNS:harbor01,DNS:harbor02,DNS:localhost,IP:127.0.0.1,IP:10.0.0.131,IP:10.0.0.132")
4,ca公钥与harbor服务公钥合并(可以选做)
# 将服务器证书和CA证书合并为一个链文件
[root@harbor01:/certs]# cat harbor.crt ca.crt > harbor_ca.crt
5,查看生成的证书
[root@harbor01:/certs]# ls -l
total 24
-rw-r--r-- 1 root root 1334 Sep 11 16:34 ca.crt
-rw------- 1 root root 1704 Sep 11 16:33 ca.key
-rw-r--r-- 1 root root 2733 Sep 11 16:47 harbor_ca.crt
-rw-r--r-- 1 root root 1399 Sep 11 16:46 harbor.crt
-rw-r--r-- 1 root root 1013 Sep 11 16:37 harbor.csr
-rw------- 1 root root 1704 Sep 11 16:35 harbor.key
· 开始安装
# 回到安装目录
[root@harbor01:/certs]# cd /harbor
# 查看目录下文件
[root@harbor01:/harbor]# ls -l
total 659264
-rw-r--r-- 1 root root 3646 Jul 31 10:48 common.sh
-rw-r--r-- 1 root root 675032342 Jul 31 10:48 harbor.v2.13.2.tar.gz
-rw-r--r-- 1 root root 5486 Sep 11 16:24 harbor.yml
-rw-r--r-- 1 root root 14688 Jul 31 10:48 harbor.yml.tmpl
-rwxr-xr-x 1 root root 1975 Jul 31 10:48 install.sh
-rw-r--r-- 1 root root 11347 Jul 31 10:48 LICENSE
-rwxr-xr-x 1 root root 2211 Jul 31 10:48 prepare
# 执行安装脚本
[root@harbor01:/harbor]# ./install.sh
· 浏览器访问
10.0.0.131

用户:admin
密码:123456

3,docker主机链接harbor仓库
· harbor创建项目
# 点击导航栏【项目】
- 点击【新建项目】
- 编辑【项目名称】
- 勾选访问级别【公开】
- 确定

# 创建完成后,查看项目;

· docker主机添加harbor私有仓库
1,docker主机做harbor的hosts解析
[root@docker01 ~]# vim /etc/hosts
......
10.0.0.131 reg01.bakwite.com
# 测试解析
[root@docker01 ~]# ping -c3 reg01.bakwite.com
PING res.bakwite.com (10.0.0.131) 56(84) bytes of data.
64 bytes from res.bakwite.com (10.0.0.131): icmp_seq=1 ttl=64 time=0.027 ms
64 bytes from res.bakwite.com (10.0.0.131): icmp_seq=2 ttl=64 time=0.037 ms
64 bytes from res.bakwite.com (10.0.0.131): icmp_seq=3 ttl=64 time=0.034 ms
--- res.bakwite.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2032ms
rtt min/avg/max/mdev = 0.027/0.032/0.037/0.004 ms
2,docker添加harbor仓库
| daemin.json | 解释说明 |
|---|---|
| "registry-mirrors" : ["https://res.bakwite.com"] | 【安全的仓库】表示有TLS加密的访问仓库 |
| "insecure-registries" : ["http://10.0.0.131"] | 【不安全的仓库】表示没有TLS加密的访问仓库 |
[root@harbor01 ~]# vim /etc/docker/daemon.json
{
"registry-mirrors" : [
"https://docker.m.daocloud.io",
"https://k8s.m.daocloud.io",
"https://reg01.bakwite.com"
]
}
· docker主机创建ca证书目录
[root@docker01:~]# mkdir -p /etc/docker/certs.d/reg01.bakwite.com/
· harbor将ca公钥传给docker主机证书验证目录
[root@harbor01:/harbor]# scp /harbor/certs/ca.crt 10.0.0.121:/etc/docker/certs.d/reg01.bakwite.com/
· 重启docker
[root@harbor01 ~]# cd /harbor/
[root@docker01:~]# systemctl restart docker.service
[root@docker01:~]# docker-compose up -d
· docker主机登录harbor
root@docker01:~]# docker login -uadmin -p123456 https://reg01.bakwite.com
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
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
#上面有问题,解决方法
#如果还是证书错误
#方法1:将 CA 证书添加到系统信任库
# 复制证书到系统 CA 目录
cp /harbor/certs/ca.crt /usr/local/share/ca-certificates/harbor-ca.crt
# 更新 CA 证书
update-ca-certificates
# 重启 Docker
systemctl restart docker
# 启动 Harbor
cd /harbor
docker-compose up -d
# 测试登录
docker login -uadmin -p123456 https://reg01.bakwite.com
4,推送本地镜像到仓库
· 给本地镜像打标签
1,查看本地镜像
[root@docker01:~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest 9234e8fb04c4 8 weeks ago 8.31MB
2,修改本地镜像的标签名
修改规则:[harbor仓库访问域名]/[项目名称]/[镜像名称]:[镜像tag]
# 修改本地镜像标签;
[root@docker01:~]# docker tag alpine:latest reg01.bakwite.com/library/alpine:latest
# 再次查看本地镜像列表
[root@docker01:~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tengine v1 7da7ba474d1c 4 hours ago 303MB
reg01.bakwite.com/bakwite_project/tengine v1 7da7ba474d1c 4 hours ago 303MB
alpine latest 9234e8fb04c4 8 weeks ago 8.31MB
reg01.bakwite.com/bakwite_project/alpine latest 9234e8fb04c4 8 weeks ago 8.31MB
· 推送本地镜像
[root@docker01:~]# docker push reg01.bakwite.com/library/alpine:latest
· harbor页面查看
1,查看项目列表变化
# 查看项目中的镜像数量

2,查看项目中的镜像
# 点击进入【项目】中

5,拉取镜像从镜像仓库
· 删除所有镜像
[root@docker01:~]# docker image rm -f `docker images -aq`
[root@docker01:~]# docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
· 拉取镜像
[root@docker01:~]# docker pull reg01.bakwite.com/library/tengine:v1
v1: Pulling from bakwite_project/tengine
9824c27679d3: Already exists
ae578eecd27f: Pull complete
fc4abc47e882: Pull complete
b46e953b875b: Pull complete
Digest: sha256:f83709b20cc9a909cdaa6c0b1d3ca90c5569ab9140ce7d30d18e534b9a1a899f
Status: Downloaded newer image for reg01.bakwite.com/bakwite_project/tengine:v1
reg01.bakwite.com/bakwite_project/tengine:v1
# 拉取后再次查看镜像列表
[root@docker01:~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
reg01.bakwite.com/bakwite_project/tengine v1 7da7ba474d1c 5 hours ago 303MB
6,harbor的高可用配置
· 准备2个harbor主机环境
| 主机名 | ip地址 | 描述 |
|---|---|---|
| harbor01 | 10.0.0.131 | 已有环境,里面有项目,有镜像; |
| harbor02 | 10.0.0.132 | 新环境,什么都没有; |
· 两个harbor主机解析域名
[root@harbor01:/harbor]# vim /etc/hosts
[root@harbor02:/harbor]# vim /etc/hosts
......
10.0.0.131 reg01.bakwite.com
10.0.0.132 reg02.bakwite.com
[root@harbor01 ~]# vim /etc/docker/daemon.json
{
"registry-mirrors" : [
"https://docker.m.daocloud.io",
"https://k8s.m.daocloud.io",
"https://reg01.bakwite.com"
]
}
[root@harbor01 ~]# systemctl daemon-reload
[root@harbor02 ~]# vim /etc/docker/daemon.json
{
"registry-mirrors" : [
"https://docker.m.daocloud.io",
"https://k8s.m.daocloud.io",
"https://reg02.bakwite.com"
]
}
· 两个harbor主机证书互信
harbor01和harbor02分别创建信任证书目录
- harbor01创建:/etc/docker/certs.d/reg02.bakwite.com/目录
- harbor02创建:/etc/docker/certs.d/reg02.bakwite.com/目录
[root@harbor01:/harbor]# mkdir -p /etc/docker/certs.d/reg01.bakwite.com
[root@harbor02:/harbor]# mkdir -p /etc/docker/certs.d/reg02.bakwite.com
分发证书:
- harbor01将自己的ca证书发给harbor02
- harbor02将自己的ca证书发给harbor01
[root@harbor01:/harbor]# scp /harbor/certs/ca.crt 10.0.0.132:/etc/docker/certs.d/reg02.bakwite.com/
[root@harbor02:/harbor]# scp /harbor/certs/ca.crt 10.0.0.131:/etc/docker/certs.d/reg01.bakwite.com/
· harbor设置推送规则
1,添加仓库
# 仓库管理
- 新建仓库
目标URL:131网站就填132的地址(https://reg02.bakwite.com)

2,推送镜像到harbor02
# 复制管理
- 选择推送push
- 仓库备份名
- 设置定时任务:分时日月周

3,5分钟后查看新仓库项目
# 可以看到,推送成功;

7,harbor的容器组件
| 容器组件 | 功能作用 |
|---|---|
| harbor-core | 【核心API、UI、"认证"组件】:主要用于API调用、用户管理、系统配置、复制任务、链接其他仓库 等 |
| harbor-jobservice | 【执行后台任务】:复制镜像,漏洞扫描、垃圾回收等任务的详细执行日志; |
| harbor-portal | 【nginx服务】:用户访问UI的HTTP访问日志,通常错误会反向代理到 harbor-core |
| registry | 【pull、push分发镜像】:最底层的 docker push/pull 操作 |
| harbor-db | PostgreSQL 数据库 |
| redis | 缓存服务 |
| harbor-log | 【日志收集器】:收集其他容器的日志(如果配置了) |
# 如果是连接类错误,查看harbor-core的容器日志:
[root@harbor02:~]# docker logs -f harbor-core
# 如果是页面访问问题,查看nginx的容器日志
[root@harbor02:~]# docker logs -f nginx
十四、Linux虚拟化技术
1,OverlayFS堆叠文件系统
· OverlayFS文件系统介绍
OverlayFS文件系统:
- 是基于【xfs】或者【ext4】文件系统之上的二层文件系统;
- 文件系统分4个层级:
- lower层:负责【存储原始数据】的目录;
- work层:负载增删改查时,将【原始数据临时复制存放】的目录;
- upper层:用户对原始数据【增删改查后的结果数据】存储目录;
- Merged层:用户【最后看到的结果数据】目录;

# docker使用OverlayFS的原理:
1,将镜像放在Lower层,充当原始数据;
2,当用户启动容器后,对容器的文件操作,就是work层和upper层的作用;
3,最后,用户看到的修改后的容器,实际就是:Merged层的合并目录数据;
4,当用户再次启动一个容器,还是基于原来的镜像,重新创建OverlayFS文件系统挂载;
· OverlayFS文件系统验证
1,查看磁盘挂载
# 先查看磁盘挂载信息
[root@docker01:~]# df -h
Filesystem Size Used Avail Use% Mounted on
tmpfs 388M 1.7M 386M 1% /run
/dev/mapper/ubuntu--vg-lv--1 92G 7.4G 80G 9% /
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
/dev/sda2 2.0G 252M 1.6G 14% /boot
tmpfs 388M 4.0K 388M 1% /run/user/0
2,启动一个容器
[root@docker01:~]# docker run -d --name c1 nginx:1.20.1-alpine
3,再次查看磁盘挂载
发现:
- 多了一个OverlayFS的挂载;
- 文件系统名称叫:OverlayFS
- 挂载的目录是:merged
[root@docker01:~]# df -h
Filesystem Size Used Avail Use% Mounted on
......
overlay 92G 7.4G 80G 9% /var/lib/docker/overlay2/846c77.../merged
· OverlayFS案例复现
1,创建OverlayFS的4层目录
[root@docker01:~]# mkdir -p /bakwite/lower{1..3}
[root@docker01:~]# mkdir -p /bakwite/work
[root@docker01:~]# mkdir -p /bakwite/upper
[root@docker01:~]# mkdir -p /bakwite/megred
[root@docker01:~]# ls -l /bakwite/
total 28
drwxr-xr-x 2 root root 4096 Sep 12 11:41 lower1
drwxr-xr-x 2 root root 4096 Sep 12 11:41 lower2
drwxr-xr-x 2 root root 4096 Sep 12 11:41 lower3
drwxr-xr-x 2 root root 4096 Sep 12 11:42 megred
drwxr-xr-x 2 root root 4096 Sep 12 11:42 upper
drwxr-xr-x 4 root root 4096 Sep 11 13:07 wordpress
drwxr-xr-x 2 root root 4096 Sep 12 11:42 work
2,挂载OverlayFS文件系统
[root@docker01:~]# mount -t overlay overlay -o lowerdir=/bakwite/lower1:/bakwite/lower2:/bakwite/lower3,workdir=/bakwite/work/,upperdir=/bakwite/upper/ /bakwite/merged/
# 挂载OverlayFS后,查看磁盘挂载
[root@docker01:~]# df -h
Filesystem Size Used Avail Use% Mounted on
......
overlay 92G 7.3G 81G 9% /bakwite/megred
3,再次查看目录结构
[root@docker01:~]# tree /bakwite/
/bakwite/
├── lower1
├── lower2
├── lower3
├── merged
├── upper
└── work
└── work
4,查看挂载信息
[root@docker01:~]# mount | grep merged
overlay on /bakwite/merged type overlay (rw,relatime,lowerdir=/bakwite/lower1:/bakwite/lower2:/bakwite/lower3,upperdir=/bakwite/upper/,workdir=/bakwite/work/)
5,往lower层写入数据
[root@docker01:~]# echo "123456" > /bakwite/lower1/1.txt
[root@docker01:~]# echo "67890" > /bakwite/lower2/2.txt
[root@docker01:~]# echo "abcde" > /bakwite/lower3/3.txt
6,此时查看各个目录
# 查看merged合并层:突然出现了lower基础数据层的3个文件;
[root@docker01:~]# ls -l /bakwite/megred/
total 12
-rw-r--r-- 1 root root 7 Sep 12 11:52 1.txt
-rw-r--r-- 1 root root 6 Sep 12 11:53 2.txt
-rw-r--r-- 1 root root 6 Sep 12 11:53 3.txt
# 查看work工作层:什么都没有
[root@docker01:~]# ls -l /bakwite/work/work/
total 0
# 查看upper读写层:什么都没有
[root@docker01:~]# ls -l /bakwite/upper/
total 0
7,创建文件案例
# 创建文件到读写层
[root@docker01:~]# echo "fghigk" > /bakwite/upper/4.txt
# 查看merged合并层:出现了upper读写层的数据
[root@docker01:~]# ls -l /bakwite/megred/
total 16
-rw-r--r-- 1 root root 7 Sep 12 11:52 1.txt
-rw-r--r-- 1 root root 6 Sep 12 11:53 2.txt
-rw-r--r-- 1 root root 6 Sep 12 11:53 3.txt
-rw-r--r-- 1 root root 7 Sep 12 11:58 4.txt
# work层什么都没有
[root@docker01:~]# ls -l /bakwite/work/work/
total 0
# lower基础数据层没有任何变化
[root@docker01:~]# ls -l /bakwite/lower1
total 4
-rw-r--r-- 1 root root 7 Sep 12 11:52 1.txt
[root@docker01:~]# ls -l /bakwite/lower2
total 4
-rw-r--r-- 1 root root 6 Sep 12 11:53 2.txt
[root@docker01:~]# ls -l /bakwite/lower3
total 4
-rw-r--r-- 1 root root 6 Sep 12 11:53 3.txt
8,修改数据案例
# merged编辑1.txt
[root@docker01:~]# echo "123456" >> /bakwite/merged/1.txt
# 查看upper层:出现了一个1.txt
[root@docker01:~]# ls -l /bakwite/upper/
total 8
-rw-r--r-- 1 root root 14 Sep 12 12:03 1.txt
-rw-r--r-- 1 root root 7 Sep 12 11:58 4.txt
# 查看lower基础数据层的1.txt:发现没有变化
[root@docker01:~]# cat /bakwite/lower1/1.txt
123456
# 查看upper层的1.txt:发现是编辑后的1.txt
[root@docker01:~]# cat /bakwite/upper/1.txt
123456
123456
2,namespace名称空间
· 网络名称空间
实现目标:
- 实现创建网络名称空间,隔离宿主机与名称空间的网络
- 实现网络名称空间借助网桥上网;

什么是虚拟以太对:你可以将其理解为:【一根网线】;
1,创建虚拟(交换机)网桥设备
# 添加虚拟网桥设备
[root@wa ~]# ip l add name bakwite_net type bridge
# 启动虚拟网桥
[root@wa ~]# ip l set bakwite_net up
# 给虚拟网桥添加一个ip地址
[root@wa ~]# ip a add 172.100.0.1/24 dev bakwite_net
# 查看网卡设备
[root@wa ~]# ip a
......
6: bakwite_net: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether e2:55:db:38:b9:b3 brd ff:ff:ff:ff:ff:ff
inet 172.100.0.1/24 scope global bakwite_net
valid_lft forever preferred_lft forever
inet6 fe80::e055:dbff:fe38:b9b3/64 scope link
valid_lft forever preferred_lft forever
2,创建删除以太对
| 命令 | 参数 | 解释说明 |
|---|---|---|
| ip l add | 添加网络设备 | |
| veth_wa01 | 以太对儿(网线)的一头,自定义名称;名字随便写 | |
| type veth peer | 声明设备的类型是以太对儿 | |
| name veth_wa02 | 以太对儿(网线)的另一头,自定义名称;名字随便写 |
[root@wa ~]# ip l add veth_wa01 type veth peer name veth_wa02
[root@wa ~]# ip a
......
4: veth_wa02@veth_wa01: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether e6:79:24:17:bc:dd brd ff:ff:ff:ff:ff:ff
5: veth_wa01@veth_wa02: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether d6:91:73:0c:81:db brd ff:ff:ff:ff:ff:ff
6: bakwite_net: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether e2:55:db:38:b9:b3 brd ff:ff:ff:ff:ff:ff
inet 172.100.0.1/24 scope global bakwite_net
valid_lft forever preferred_lft forever
inet6 fe80::e055:dbff:fe38:b9b3/64 scope link
valid_lft forever preferred_lft forever
删除以太对:删除一端的名称即可实现删除
[root@wa ~]# ip l delete veth_wa01
3,将以太对一头接入网桥
[root@wa ~]# ip l set veth_wa01 master bakwite_net
4,启动以太对的网桥端
[root@wa ~]# ip l set veth_wa01 up
[root@wa ~]# ip a
......
4: veth_wa02@veth_wa01: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether e6:79:24:17:bc:dd brd ff:ff:ff:ff:ff:ff
5: veth_wa01@veth_wa02: <NO-CARRIER,BROADCAST,MULTICAST,UP,M-DOWN> mtu 1500 qdisc noqueue master bakwite_net state LOWERLAYERDOWN group default qlen 1000
link/ether d6:91:73:0c:81:db brd ff:ff:ff:ff:ff:ff
6: bakwite_net: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether d6:91:73:0c:81:db brd ff:ff:ff:ff:ff:ff
inet 172.100.0.1/24 scope global bakwite_net
valid_lft forever preferred_lft forever
inet6 fe80::e055:dbff:fe38:b9b3/64 scope link
valid_lft forever preferred_lft forever
5,查看网络名称空间列表
# 默认情况下,什么都没有
[root@wa ~]# ip netns
6,创建删除网络名称空间
[root@wa ~]# ip netns add wa_namespace
# 添加后再次查看名称空间列表
[root@wa ~]# ip netns
wa_namespace
删除名称空间:
- 实际上是删除:/var/run/netns/wa_namespace这个目录
[root@wa ~]# ip netns delete wa_namespace
7,将以太对另一头移动到名称空间
[root@wa ~]# ip l set veth_wa02 netns wa_namespace
8,名称空间内设置以太对另一头
# 进入网络名称空间中(不用做,如果进去了,exit退出)
[root@wa ~]# ip netns exec wa_namespace bash
# 在网络名称空间中查看网卡列表
[root@wa ~]# ip netns exec wa_namespace ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: veth_wa02@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether e6:79:24:17:bc:dd brd ff:ff:ff:ff:ff:ff link-netnsid 0
# 在网络名称空间内将以太对另一头改名
[root@wa ~]# ip netns exec wa_namespace ip link set veth_wa02 name ens33
[root@wa ~]# ip netns exec wa_namespace ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: ens33@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether e6:79:24:17:bc:dd brd ff:ff:ff:ff:ff:ff link-netnsid 0
# 给网络名称空间中的以太对另一头添加ip地址
[root@wa ~]# ip netns exec wa_namespace ip a add 172.100.0.2/24 dev ens33
[root@wa ~]# ip netns exec wa_namespace ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: ens33@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether e6:79:24:17:bc:dd brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.100.0.2/24 scope global ens33
valid_lft forever preferred_lft forever
# 网络名称空间中,启动以太对的另一头
[root@wa ~]# ip netns exec wa_namespace ip l set ens33 up
[root@wa ~]# ip netns exec wa_namespace ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: ens33@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether e6:79:24:17:bc:dd brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.100.0.2/24 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::e479:24ff:fe17:bcdd/64 scope link
valid_lft forever preferred_lft forever
# 网络名称空间中设置路由表,将网关设置为宿主机的虚拟网桥
[root@wa ~]# ip netns exec wa_namespace ip r add default via 172.100.0.1
[root@wa ~]# ip netns exec wa_namespace ip r
default via 172.100.0.1 dev ens33
172.100.0.0/24 dev ens33 proto kernel scope link src 172.100.0.2
9,测试名称空间中与宿主机网络
# 网络名称空间ping宿主机
[root@wa ~]# ip netns exec wa_namespace ping 172.100.0.1 -c3
PING 172.100.0.1 (172.100.0.1) 56(84) bytes of data.
64 bytes from 172.100.0.1: icmp_seq=1 ttl=64 time=0.125 ms
64 bytes from 172.100.0.1: icmp_seq=2 ttl=64 time=0.056 ms
64 bytes from 172.100.0.1: icmp_seq=3 ttl=64 time=0.050 ms
--- 172.100.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2044ms
rtt min/avg/max/mdev = 0.050/0.077/0.125/0.034 ms
# 宿主机ping网络名称空间
[root@wa ~]# ping -c3 172.100.0.2
PING 172.100.0.2 (172.100.0.2) 56(84) bytes of data.
64 bytes from 172.100.0.2: icmp_seq=1 ttl=64 time=0.038 ms
64 bytes from 172.100.0.2: icmp_seq=2 ttl=64 time=0.063 ms
64 bytes from 172.100.0.2: icmp_seq=3 ttl=64 time=0.048 ms
--- 172.100.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2057ms
rtt min/avg/max/mdev = 0.038/0.049/0.063/0.010 ms
10,设置网络名称空间上外网
# 配置内核转发
[root@wa ~]# echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
[root@wa ~]# sysctl -p
.....
net.ipv4.ip_forward = 1
# 配置iptables的NAT规则
[root@wa ~]# iptables -t nat -A POSTROUTING -s 172.100.0.0/24 -o ens33 -j MASQUERADE
# 测试网络名称空间上外网
[root@wa ~]# ip netns exec wa_namespace ping -c3 223.5.5.5
PING 223.5.5.5 (223.5.5.5) 56(84) bytes of data.
64 bytes from 223.5.5.5: icmp_seq=1 ttl=127 time=6.91 ms
64 bytes from 223.5.5.5: icmp_seq=2 ttl=127 time=7.57 ms
64 bytes from 223.5.5.5: icmp_seq=3 ttl=127 time=7.68 ms
--- 223.5.5.5 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 6.913/7.385/7.677/0.337 ms
3,cgroup资源限制
· 查看cgroup限制类型
| cgroup都限制什么 | 解释说明 |
|---|---|
| /sys/fs/cgroup/systemd | 【限制】 |
| /sys/fs/cgroup/pids | 【限制进程数量】 |
| /sys/fs/cgroup/net_cls,net_prio | 【net_cls】: :one:给进程产生的网络包打上一个 classid 标签 :two:然后可以由 tc (Traffic Control) 等工具根据标签进行带宽限制】 【net_prio】: :one:设置不同网络流量的优先级 |
| /sys/fs/cgroup/devices | 【设备访问控制】 |
| /sys/fs/cgroup/perf_event | 【性能监控】 |
| /sys/fs/cgroup/cpuset | 【cpu和内存绑定】 |
| /sys/fs/cgroup/rdma | 限制进程组使用的 RDMA(远程直接数据存取) 资源,这是一种高性能网络技术,常见于超级计算机和数据中心。普通场景很少用到。 |
| /sys/fs/cgroup/freezer | 【暂停/恢复进程】 |
| /sys/fs/cgroup/memory | 【内存使用限制】 |
| /sys/fs/cgroup/cpu,cpuacct | 【限制cpu使用/cpu统计】 |
| /sys/fs/cgroup/hugetlb | 【限制大页内存】 |
| /sys/fs/cgroup/blkio | 【限制块设备IO存储】 |
# 查看cgroup的挂载点
[root@wa ~]# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
· CPU限制案例
1,在cpu限制目录下创建目录
- 红帽
[root@wa ~]# mkdir /sys/fs/cgroup/cpu/bakwite_cpu_limit
- ubuntu
[root@wa ~]# mkdir /sys/fs/cgroup/bakwite_cpu_limit
2,查看刚刚创建的目录
你会发现:
- 刚刚创建的目录下自动创建了很多个文件;
| 文件名 | 解释说明 |
|---|---|
| cpu.cfs_period_us | 这个文件中规定,多长时间算作一个统计周期,默认是100000(100毫秒); |
| cpu.cfs_quota_us | 这个文件中规定,在【cpu.cfs_period_us】规定的周期内,做多只能使用多长时间,默认50000(50毫秒); |
| cpu.shares | cpu的权重设置:表示这个进程使用cpu的优先级; |
[root@wa ~]# ls -l /sys/fs/cgroup/cpu/bakwite_cpu_limit
总用量 0
-rw-r--r-- 1 root root 0 9月 5 20:02 cgroup.clone_children
-rw-r--r-- 1 root root 0 9月 5 20:02 cgroup.procs
-r--r--r-- 1 root root 0 9月 5 20:02 cpuacct.stat
-rw-r--r-- 1 root root 0 9月 5 20:02 cpuacct.usage
-r--r--r-- 1 root root 0 9月 5 20:02 cpuacct.usage_all
-r--r--r-- 1 root root 0 9月 5 20:02 cpuacct.usage_percpu
-r--r--r-- 1 root root 0 9月 5 20:02 cpuacct.usage_percpu_sys
-r--r--r-- 1 root root 0 9月 5 20:02 cpuacct.usage_percpu_user
-r--r--r-- 1 root root 0 9月 5 20:02 cpuacct.usage_sys
-r--r--r-- 1 root root 0 9月 5 20:02 cpuacct.usage_user
-rw-r--r-- 1 root root 0 9月 5 20:02 cpu.cfs_burst_us
-rw-r--r-- 1 root root 0 9月 5 20:02 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 9月 5 20:02 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 9月 5 20:02 cpu.qos_level
-rw-r--r-- 1 root root 0 9月 5 20:02 cpu.rt_period_us
-rw-r--r-- 1 root root 0 9月 5 20:02 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 9月 5 20:02 cpu.shares
-r--r--r-- 1 root root 0 9月 5 20:02 cpu.stat
-rw-r--r-- 1 root root 0 9月 5 20:02 notify_on_release
-rw-r--r-- 1 root root 0 9月 5 20:02 tasks
3,安装压测工具
[root@wa ~]# yum -y install stress
4,启动压测工具stress
| 命令 | 参数 | 解释说明 |
|---|---|---|
| stress | -c 4 | 启动4个worker子进程进行cpu压力测试 |
| -v | 显示过程 | |
| -t 20m | 压力测试20分钟 |
[root@wa ~]# stress -c 4 -v -t 20m
stress: info: [72291] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
stress: dbug: [72291] using backoff sleep of 12000us
stress: dbug: [72291] setting timeout to 1200s
stress: dbug: [72291] --> hogcpu worker 4 [72292] forked
stress: dbug: [72291] using backoff sleep of 9000us
stress: dbug: [72291] setting timeout to 1200s
stress: dbug: [72291] --> hogcpu worker 3 [72293] forked
stress: dbug: [72291] using backoff sleep of 6000us
stress: dbug: [72291] setting timeout to 1200s
stress: dbug: [72291] --> hogcpu worker 2 [72294] forked
stress: dbug: [72291] using backoff sleep of 3000us
stress: dbug: [72291] setting timeout to 1200s
stress: dbug: [72291] --> hogcpu worker 1 [72295] forked
5,此时查看cpu负载
可以看到:1分总内压测数据已经到了400%多;
[root@wa ~]# w
20:15:23 up 4 days, 3:48, 3 users, load average: 4.52, 1.71, 0.63
USER TTY LOGIN@ IDLE JCPU PCPU WHAT
root tty1 17:30 2:44m 0.09s 0.09s -bash
root pts/0 17:30 2:11 1:55 0.00s stress -c 4 -v -t 20m
root pts/1 20:13 3.00s 0.02s 0.00s w
6,此时我们修改CPU使用限制文件
- 红帽系统
[root@wa ~]# echo "10000" > /sys/fs/cgroup/cpu/bakwite_cpu_limit/cpu.cfs_quota_us
- ubuntu系统
[root@wa ~]# echo "10000" > /sys/fs/cgroup/cpu/bakwite_cpu_limit/cpu.max
7,查看stress进程号
[root@wa ~]# ps -ef | grep stress
root 72291 71289 0 20:13 pts/0 00:00:00 stress -c 4 -v -t 20m
root 72292 72291 22 20:13 pts/0 00:01:07 stress -c 4 -v -t 20m
root 72293 72291 22 20:13 pts/0 00:01:07 stress -c 4 -v -t 20m
root 72294 72291 22 20:13 pts/0 00:01:07 stress -c 4 -v -t 20m
root 72295 72291 22 20:13 pts/0 00:01:07 stress -c 4 -v -t 20m
8,将进程号写入资源限制tasks中
[root@wa ~]# echo "72292" >> /sys/fs/cgroup/cpu/bakwite_cpu_limit/tasks
[root@wa ~]# echo "72293" >> /sys/fs/cgroup/cpu/bakwite_cpu_limit/tasks
[root@wa ~]# echo "72291" >> /sys/fs/cgroup/cpu/bakwite_cpu_limit/tasks
[root@wa ~]# echo "72294" >> /sys/fs/cgroup/cpu/bakwite_cpu_limit/tasks
[root@wa ~]# echo "72295" >> /sys/fs/cgroup/cpu/bakwite_cpu_limit/tasks
# ubuntu系统写入
/sys/fs/cgroup/oldboy_cpu_limit/cgroup.procs
9,此时再次查看stress的cpu负载
等5分钟在查看,会发现,cpu使用率被降低到了10%;
[root@wa ~]# w
20:25:19 up 4 days, 3:58, 3 users, load average: 0.10, 1.73, 1.49
USER TTY LOGIN@ IDLE JCPU PCPU WHAT
root tty1 17:30 2:54m 0.09s 0.09s -bash
root pts/0 17:30 12:07 7:52 0.00s stress -c 4 -v -t 20m
root pts/1 20:13 7.00s 0.12s 0.00s w
4,chroot文件系统隔离
· 模仿系统创建子系统目录
[root@wa ~]# mkdir -p /bakwite/{/usr/bin,/usr/lib64,etc}
· 复制宿主机命令到子系统的bin下
[root@wa ~]# cp /usr/bin/ls /bakwite/usr/bin/
[root@wa ~]# cp /bin/bash /bakwite/usr/bin/
· 找到命令的依赖
[root@wa ~]# ldd /usr/bin/ls
linux-vdso.so.1 (0x00007ffffa389000)
libselinux.so.1 => /usr/lib64/libselinux.so.1 (0x00007f71f212f000)
libcap.so.2 => /usr/lib64/libcap.so.2 (0x00007f71f2127000)
libc.so.6 => /usr/lib64/libc.so.6 (0x00007f71f1f6f000)
libsecurity.so.0 => /usr/lib64/libsecurity.so.0 (0x00007f71f1f6a000)
libpcre2-8.so.0 => /usr/lib64/libpcre2-8.so.0 (0x00007f71f1ed5000)
libdl.so.2 => /usr/lib64/libdl.so.2 (0x00007f71f1ed0000)
/lib64/ld-linux-x86-64.so.2 (0x00007f71f2193000)
libpthread.so.0 => /usr/lib64/libpthread.so.0 (0x00007f71f1ead000)
[root@wa ~]# ldd /bin/bash
linux-vdso.so.1 (0x00007ffc4d7a4000)
libtinfo.so.6 => /usr/lib64/libtinfo.so.6 (0x00007f5a37059000)
libdl.so.2 => /usr/lib64/libdl.so.2 (0x00007f5a37054000)
libc.so.6 => /usr/lib64/libc.so.6 (0x00007f5a36e9c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5a371c3000)
· 将依赖复制到对应的同名目录下
# 复制ls命令的依赖
[root@wa ~]# cp /usr/lib64/libselinux.so.1 /bakwite/usr/lib64/
[root@wa ~]# cp /usr/lib64/libcap.so.2 /bakwite/usr/lib64/
[root@wa ~]# cp /usr/lib64/libc.so.6 /bakwite/usr/lib64/
[root@wa ~]# cp /usr/lib64/libsecurity.so.0 /bakwite/usr/lib64/
[root@wa ~]# cp /usr/lib64/libpcre2-8.so.0 /bakwite/usr/lib64/
[root@wa ~]# cp /usr/lib64/libdl.so.2 /bakwite/usr/lib64/
[root@wa ~]# cp /usr/lib64/ld-linux-x86-64.so.2 /bakwite/usr/lib64/
[root@wa ~]# cp /usr/lib64/libpthread.so.0 /bakwite/usr/lib64/
# 复制bash的依赖
[root@wa ~]# cp /usr/lib64/libtinfo.so.6 /bakwite/usr/lib64/
[root@wa ~]# cp /usr/lib64/libdl.so.2 /bakwite/usr/lib64/
cp:是否覆盖'/bakwite/lib64/libdl.so.2'? ^[[A
[root@wa ~]# cp /usr/lib64/libc.so.6 /bakwite/usr/lib64/
cp:是否覆盖'/bakwite/lib64/libc.so.6'?
[root@wa ~]# cp /usr/lib64/ld-linux-x86-64.so.2 /bakwite/usr/lib64/
cp:是否覆盖'/bakwite/lib64/ld-linux-x86-64.so.2'?
· chroot创建子系统
[root@wa ~]# chroot /bakwite/ /bin/bash
bash-5.0# ls
bin etc lib lib64 usr
bash-5.0# cat
bash: c: command not found
bash-5.0# ls -l /usr/lib64
total 3032
-rwxr-xr-x 1 0 0 162592 Sep 5 12:51 ld-linux-x86-64.so.2
-rwxr-xr-x 1 0 0 1791192 Sep 5 12:51 libc.so.6
-rwxr-xr-x 1 0 0 27328 Sep 5 12:51 libcap.so.2
-rwxr-xr-x 1 0 0 14424 Sep 5 12:52 libdl.so.2
-rwxr-xr-x 1 0 0 604504 Sep 5 12:51 libpcre2-8.so.0
-rwxr-xr-x 1 0 0 116328 Sep 5 12:51 libpthread.so.0
-rwxr-xr-x 1 0 0 14232 Sep 5 12:51 libsecurity.so.0
-rwxr-xr-x 1 0 0 166176 Sep 5 12:50 libselinux.so.1
-rwxr-xr-x 1 0 0 191688 Sep 5 12:52 libtinfo.so.6
· 总结说明
本质上:
- docker的容器就是采用了这些技术
- 通过chroot进入overlayFS文件系统的merged目录下;
十五、阿里云个人镜像仓库的使用
1,创建阿里云个人镜像仓库
· 前往官网
https://www.aliyun.com/

· 登录控制台
# 点击右上角【登录】

# 输入登录信息

# 登录后跳转到工作台

· 点击logo回到首页
# 点击左上角【阿里云logo】

# 点击后,回到了首页

· 搜索【容器镜像服务】
# 搜索框搜索【容器镜像服务】

# 回车键入搜索结果列表
- 点击title名称【容器镜像服务】

· 进入管理控制台
# 直接点击【管理控制台】

# 进入后页面显示两个板块:
- 企业版
- 个人版实例

· 开始创建个人镜像仓库
1,点击个人版实例

# 弹窗后,选择【创建个人版】

2,创建
# 选择【地区】
- 勾选两个协议
- 点击【立即创建】

3,设置仓库密码
# 点击【设置Registry登录密码】

# 设置密码

· 创建仓库
# 点击【创建镜像仓库】

# 点击弹窗中的【请先创建命名空间】

#设置命名空间名称

# 点击确定后,设置仓库信息
- 选择【命名空间】
- 设置【仓库名称】
- 选择【仓库类型】
- 编辑【仓库摘要】
- 点击【下一步】

# 选择【本地仓库】
- 点击【创建镜像仓库】

# 致此,阿里云容器镜像仓库创建成功

2,登录阿里云个人镜像仓库
[root@harbor01:~]# docker login --username=bakwite crpi-f5j1dkm1d8o5jd7w.cn-beijing.personal.cr.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
3,推送本地镜像到阿里云仓库
· 将本地镜像打标签
[root@harbor01:~]# docker tag ubuntu:22.04 crpi-f5j1dkm1d8o5jd7w.cn-beijing.personal.cr.aliyuncs.com/bakwite/ubuntu:22.04
· 推送本地镜像到阿里云ACR
[root@harbor01:~]# docker push crpi-f5j1dkm1d8o5jd7w.cn-beijing.personal.cr.aliyuncs.com/bakwite/ubuntu:22.04

Discussion
评论