Docker

Docker

什么是Docker?

Docker是基于操作系统层级、开源的虚拟化容器技术,用于快速构建、打包、分发、和运行应用程序,它可以将应用程序以及所需要的所有依赖打包进一个轻量级、可移植的容器中,并在任何支持Docker的环境中运行。

Docker能干什么?

1、快速部署应用程序

2、解决了环境问题,在自己机器上能跑,上线却报错

3、安全隔离,每隔容器独立运行,不会影响到其他容器运行

Docker核心组成部分

**镜像:**容器的模板,类似安装包,镜像作为模板可以创建多个容器,例如:我用tomcat镜像通过命令启动了一个tomcat1容器,我还可以再通过命令启动N个tomcat容器,一个模板创建多个容器,互不干扰。

**容器:**类似轻量虚拟机,共享主机内核,无需完成操作系统;独立运行,互不干扰;启动快、占用资源少,可以理解成一个简易的Linux系统。

**Docker引擎:**核心组件,用于创建和管理容器。


Docker安装

1、卸载删除docker,更新系统

1
2
3
4
5
6
7
8
9
10
dnf remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

dnf update -y

2、安装必备工具

1
dnf -y install dnf-plugins-core

3、配置软件源加速镜像地址

1
2
3
#清华大学镜像加速
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sed -i 's+https://download.docker.com+https://mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo

4、安装docker

1
dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

5、启动、开机自启

1
2
3
4
5
6
7
8
#启动
systemctl start docker

#开机自启
systemctl enable docker

#是否安装成功
docker version

6、配置镜像加速,官方仓库在国外拉取镜像会很慢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vim /etc/docker/daemon.json 

#清华大学地址
"https://docker.mirrors.ustc.edu.cn",

#填入以下镜像加速地址
{
"registry-mirrors": [
"https://mirrors.tencent.com",
"https://dockercf.jsdelivr.fyi",
"https://docker.jsdelivr.fyi",
"https://dockertest.jsdelivr.fyi",
"https://docker.m.daocloud.io",
"https://mirror.iscas.ac.cn"
]
}

7、 重启docker、测试

1
2
3
4
5
systemctl daemon-reload

systemctl restart docker

docker run hello-world

Docker命令

====== 镜像命令 ======

查看本机所有镜像

1
2
3
4
5
6
7
8
9
10
11
docker images [选项]
#常用选项
-a:显示所有镜像
-q:只显示镜像ID

#结果参数解释
REPOSITORY:镜像仓库源,名称
TAG:标签
IMAGE_ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小

搜索镜像

1
docker search 镜像名称

下载镜像

1
2
3
4
5
#下载最新版本
docker pull 镜像名称

#下载指定版本
docker pull 镜像名称:版本号

删除镜像

1
2
3
4
5
6
7
#镜像id可以写多个一起删除,空格隔开
docker rmi [-f] 镜像id

-f:强制删除,加了-f会忽略依赖检查,导致留下残留问题,慎用!

#删除所有镜像
docker rmi $(docker images -aq)

====== 容器命令 ======

创建容器并启动

1
2
3
4
5
6
7
docker run [选项] 镜像名称
#常用选项
--name:指定容器名字,区分容器
-d:后台运行
-it:交互模式运行,exit停止退出容器,Ctrl + p + q 不停止退出容器
-p:指定容器端口,最常用格式 真机端口:容器端口
-P:随机指定端口

查看容器

1
2
3
4
5
#查看正在运行的容器
docker ps

#查看所有容器
docker ps -a

删除容器

1
2
3
4
5
#删除单个容器,不能删除正在运行的容器,需要先停止
docker rm 容器id

#删除全部容器
docker rm $(docker ps -aq)

启动和停止容器

1
2
3
4
5
6
7
8
9
10
11
#启动
docker start 容器id

#重启
docker restart 容器id

#停止
docker stop 容器id

#强行停止
docker kill 容器id

====== 其它常用命令 ======

后台启动容器

1
2
3
docker run -d 镜像名
#问题:docker ps查看会发现该容器自动停止了
#原因:docker容器使用后台运行,就必须要有一个前台进程,如果没有docker会认为该容器没有提供服务自动停止了

查看日志

1
2
#根据容器id查看该日志,数字是几就查看几条日志
docker logs -th --tail 数字 容器id

查看容器中的进程信息

1
docker top 容器id

查看镜像元数据

1
docker inspect 镜像id

进入正在运行的容器

1
2
3
4
5
#进入容器会打开一个新窗口
docker exec -it 容器id /bin/bash

#进入容器不会打开新窗口
docker attach 容器id

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

1
docker cp 容器id:容器文件所在路径 主机存放路径

Docker练习

====== 部署Nginx ======

1、安装

1
docker pull nginx

2、查看

1
docker imgages

3、运行

1
docker run -d --name nginx01 -p 801:80 nginx

4、查看

1
docker ps

5、进入容器查看

1
2
3
docker exec -it 容器id /bin/bash

whereis nginx

6、查看、放行宿主机801端口

1
2
3
4
5
6
7
8
#查看
firewall-cmd --list-port

#放行
firewall-cmd --permanent --add-port=801/tcp

#重新加载
firewall-cmd --reload

7、测试

1
2
3
4
5
#Linux下测试
curl http://192.168.10.20:801

#windows下测试
http://192.168.10.20:801

====== 部署Tomcat ======

1、拉取镜像

1
docker pull tomcat

2、查看

1
docker images

3、运行容器

1
docker run -d -p 8081:8080 --name tomcat01 tomcat

4、查看

1
docker ps

5、进入容器,查看

1
2
3
docker exec -it tomcat01 /bin/bash

whereis tomcat

6、宿主机放行8081端口

1
2
3
4
5
6
7
8
#查看
firewall-cmd --list-port

#放行
firewall-cmd --permanent --add-port=8081/tcp

#重新加载
firewall-cmd --reload

7、测试

1
2
3
4
5
6
7
8
9
#下载下来的镜像是被阉割过的最小环境,它的webapps目录下是空的,因为访问会404
#解决办法就是把webapps.dist目录下的内容复制到webapps下
cp -r webapps.dist/* webapps

#Linux下测试
curl http://192.168.10.20:8081

#windons下测试
http://192.168.10.20:8081

====== 部署MySQL ======

1、拉取镜像

1
docker pull mysql:8.0

2、查看

1
docker images

3、运行

1
2
3
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=Yang@963214 --name mysql01 mysql:8.0 

#-e 表示设置环境,给root用户设置密码

4、查看

1
docker ps

5、进入测试

1
2
docker exec -it mysql01 mysql -uroot -p
#输入上面设置的密码

6、放行宿主机3306端口

1
2
3
4
5
6
7
8
#查看
firewall-cmd --list-port

#放行
firewall-cmd --permanent --add-port=3306/tcp

#重新加载
firewall-cmd --reload

7、使用Navicat测试

1
2
3
地址:192.168.10.20
用户名:root
密码:Yang@963214

Docker联合文件系统

UnionFS联合文件系统,它是Docker构建和管理容器镜像的核心技术之一,它允许将多个文件系统以层层叠加的形式组成一个单一同一的文件系统,所谓的分层简单理解就比如搭建一个环境,第一步安装了JDK环境比作第一层,第二步安装了mysql作为第二层,第三步安装Tomcat作为第三层,最后有联合文件系统一层层读取最后构建成一个完整的环境。

联合文件系统的优势

1、共享相同的基础镜像层,例如先下载了一个Tomcat 8,再去下载一个Tomcat 9时,当Tomcat 8里有Tomcat 9 所需要的层Docker就不会去再下载,而是拿Tomcat 8的过来直接用,只会下载缺失的层。

2、每一个层都有唯一的哈希标识,可以轻松退回到之前的层


Docker镜像都是只读的,当容器启动时,一个新的可写层会被加载到镜像的顶部,而这就是我们操作的地方,当我们将修改过的镜像打包时镜像已经被加了一层,比如一开始是6层,修改完打包完后就变成7层,新的那层就是我们所修改的东西。

提交自己镜像的命令

1
docekr commit -m="提交的描述信息" -a="作者" 容器id 为镜像取名:自定义版本

容器数据卷

什么是容器数据卷?

它是一个数据共享技术,通过目录挂载的方式可以完成Docker本地产生的数据同步到本地,完成数据持久化,这就是卷技术。

在启动容器的时候使用 -v 宿主机路径:容器内路径就可以实现挂载

实例1

要求:启动 rockylinux 将容器内的volume01挂载到宿主机的 /yzg/volumes/下,在容器中编写 hello.txt ,返回宿主查看

1、启动 rockylinux 容器并挂载

1
docker run --name yzg-linux01 -it -P -v /yzg/volumes:/volume01 rockylinux /bin/bash

2、进入volume目录创建 hello.txt

1
2
cd volume01
touch hello.txt

3、返回宿主机查看

1
ll /yzg/volumes

实例2

要求:启动数据库容器,将 容器内的mysql 配置文件挂载到宿主机 /yzg/mysql/cnof 目录下,将 mysql 工作目录挂载到 /yzg/mysql/data 目录

1
2
3
4
5
#msyql配置文件默认地址
/etc/mysql/conf.d

#mysql数据默认存放地址
/var/lib/mysql

1、启动并挂载mysql容器

1
docker run -d --name mysql01 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=Yang@963214 -v /yzg/mysql/conf:/etc/mysql/conf.d -v /yzg/mysql/data:/var/lib/mysql mysql:8.0

2、查看

1
2
3
ll /yzg/mysql/data

#看见mysql工作目录的文件和信息就成功了

匿名和具名挂载

具名挂载:不写宿主机挂载目录路径,而是为数据卷取一个名字(常用这种)

1
-v volume01:容器内地址

!!!====== 只要没指定宿主机挂载目录,全部默认在/var/lib/docker/volumes/下 ====== !!!

匿名挂载:顾名思义,挂载的时候不写宿主机地址或不取名,docker会自定为数据卷取名,但是很长

查看所有数据卷

1
docker volume ls

查看指定数据卷信息

1
docker inspect volume 数据卷名称

容器与容器之间实现数据共享

需要由第一个容器挂载到宿主机上,第二个容器再去挂载第一个容器;

第一个称为父容器,第二个称为子容器。

1
子容器 --volumes-form 父容器

1、父容器挂载宿主机

1
docker run -it --name linux01 -v /yzg/volumes/volume01:/home rockylinux /bin/bash

2、子容器挂载父容器

1
docker run -it --name linux02 --volumes-from linux01 rockylinux

DockerFile

什么是DocekrFile?

dockerfile是用来构建docker镜像的文件,一个命令参数脚本,通过docekrfile来生成一个镜像并发布发去。

DockerFile指令

注意事项

1、指令全部都是大写的

2、指令都是从上往下执行

3、#代表注释

4、每一个指令都会创建并提交一个新的镜像层

常用指令

1
2
3
4
5
6
7
8
9
10
11
12
FROM				#指定基础镜像
MAINTAINER #镜像作责信息,姓名+邮箱
RUN #镜像构建的时候需要运行的命令,想干点啥
ADD #将文件添加进镜像中,例如:tomcat压缩包
WORKDIR #镜像工作目录
VOLUM #挂载目录
EXPOSE #端口配置
CMD #指定容器启动时要运行的命令,只有最后一个会生效
ENTRYPOINT #类似CMD,区别是会追加命令而不是替换命令
ONBUILD #当构建一个被继承的DockerFile是就会运行ONBUILDD的指令,一个触发指令。
COPY #类似ADD,将文件拷贝进镜像中
ENV #构建的时候设置环境变量

编写DockerFiel构建自己的镜像

1、创建并编辑

1
2
3
4
5
6
7
8
9
vim rocyklinux-1.0

FROM rockylinux
MAINTAINER yzg-viper<3013237187@qq.com>
RUN dnf -y install vim
WORKDIR /home
EXPOSE 7777
CMD "======= yzg-viper ======"
CMD "====== Welcome to yzg-viper ======"

2、构建

1
docker build -f rocyklinux-1.0 -t yzg-rocky:1.0 .

3、查看是否构建完成

1
docker images

4、运行

1
docker run -it --name yzg-rocky01 yzg-rocky:1.0 /bin/bash

5、查看构建过程

1
docker history yzg-rocky:1.0

Docker网络

当安装完Docker的时候,Docker会提供一个叫Docker0的网卡,而docker0就相当于一个路由器一样管理docker中的网络,只要没有指定网络配置,在docker下都归docker0管,它使用的是 evth-pair 桥接技术,一段连着协议,一段相互连着,就是容器和docker0相连。

示意图

image-20250517151812698

容器与容器之间也可以互通,在容器启动的时候加上 容器A --link 容器B,这样A容器就能ping通容器B,但是反过来就不行,因为容器B里没有配置容器A的网络信息,现在已经不建议使用 –link 的形式来实现容器之间的相互通信,而是使用自定义网络

image-20250517143357647


Docker自定义网络

Docker自定义网络也叫容器互联。

doker创建网络命令语法格式

1
2
#--driver bridge表示桥接模式,可以省略不写,网段例如:192.168.0.0/16 
docker network create --driver bridge --subnet 网段 --gateway 网关 网络名字

启动容器时加入上面创建的网络

1
docker run --name 容器名 -it -p 宿主机端口:容器端口 --net 网络名字 镜像名:版本 

查看新建网络元数据

1
docker network inspect 网络名称

测试同网络下的容器互通

1
2
3
4
5
#tomcat默认使用精简版的Ubuntu作为基础镜像,没有ip addr 和ping等命令,需要进入容器内安装
apt-get update && apt-get install -y iputils-ping net-tools iproute2

#测试
docker exec -it tomcat01 ping tomcat02

Docker0和自定义网络的区别

Docker0默认只能通过ip访问;

而自定义网络即可以通过ip访问,又可以通过容器名访问。


网络联通

问题:在docker网络中,不同的网络怎么连通?比如,docker0网络的网段是172.168.0.0/16,而新建的网络网段是192.168.0.0/16,在docker0中的容器怎么访问到新建网络中的容器?

解决:在docker中使用 connect参数来解决这个问题,原理是将A网络中的容器加入到B网络中,在B网络中给加进来的容器赋一个本网段的ip地址,这样A网络中的容器就可以访问到B网络中的容器了!

简单理解就是一个容器两个IP,就好比阿里云的公网ip和本主机ip。

语法格式

1
docker network connect 网络名称 容器名称

Docekr网络常命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#查看所有网络
docker network ls

#创建自定义网络
docker network create --driver bridge 网络名称

#查看网络详情
docker network inspect 网络名称

#运行容器并加入网络
docker run --name 容器名称 -d -P --net 网络名称 镜像名:版本

#将容器加入到别的网络
docker network connect 网络名称 容器名称

#断开容器与网络的连接
docker network disconnect 网络名称 容器名称

#删除网络
docker network rm 网络名称

Docker Compose

什么是DockerCompose?

DockerCompose它是一款用于定义和运行多容器Docker应用程序的工具,使用YAML文件来配置应用服务,一个yaml配置文件管里N个容器。

服务:一个容器实例

项目:一组关联服务的集合,默认为目录名

顶级元素

1
2
3
4
5
name:指定项目名称
services:定义应用程序需的服务集合
networks:定义应用程序的网络,不存在则会创建
volumes:定义数据卷
environment:全局环境变量

常用配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
image:指定镜像
ports:指定宿主机和容器端口
volumes:指定容器数据卷挂载
networks:指定容器所使用的网络,网络必须已存在
environment:指定容器使用的环境变量
env_file:指定容器所使用的环境变量文件,与yaml主配置文同级目录
expose:指定对外暴露端口,提供给别的容量来访问

build:指定使用的自定义镜像,不能和image一起使用,二选一
context:build的子项,指定DockerFile文件的路径
dockerfile:build的子项,指定文件名,如果使用Docker默认的Dockerfile作为文件名的话,这一项可以不用配置

depends_on:指定服务所依赖的其它服务,确保依赖服务先启动
command:指定容器启动后将执行的命令

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
#启动所有服务,-d后台启动
docker compose up
#停止并删除容器、网络
docekr compose down
#查看运行中的镜像
docker compose ps
#查看日志,-f实时跟踪
docekr compose logs
#重新构建镜像
docker compose build
#进入容器
docker compose exec 容器名称

部署MySQL实战

1、目录结构

1
2
3
yzg_mysql/
├── docker-compose.yaml
└── .mysql_env

2、编辑.mysql_env文件,数据库密码

1
MYSQL_ROOT_PASSWORD: 000000

3、编辑docker-compose.yaml,默认文件名就使用这个,不用这个会找不到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#指定项目名称
name: yzg_mysql
#定义网络
networks:
net1:
#定义数据卷
volumes:
db_data:
#定义容器
services:
mysql01:
image: mysql
ports: ["3306:3306"]
volumes:
- db_data:/var/lib/mysql
env_file:
- .mysql_env
networks:
- net1

4、运行

1
docker compose docke-compose.yaml

5、navicat测试

1
2
#用户名root
#密码000000