> 大家好 , 今天我要和大家分享一个现代软件开发中不可或缺的工具 - Docker . 在这个快速发展的技术时代 , 我们经常面临着应用部署的复杂性、环境差异以及不同操作系统之间的兼容性问题 . 这些问题不仅消耗大量时间 , 还可能导致项目延期和成本增加 . Docker 的出现解决了我们在应用部署过程中遇到的障碍和挑战 . 通过将应用程序及其依赖环境封装在一个轻量级的、可移植的容器中 , Docker 不仅简化了开发和部署流程 , 还确保了不同环境间的无缝衔接和一致性 .
>
>
>
> 本文参考资源 : https://www.bilibili.com/video/BV1HP4118797/?spm_id_from=333.337.search-card.all.click
一 . 镜像操作
镜像的名称一般都由两部分组成 : [repository]:[tag]
比如 mysql:5.7 , mysql 就是 Repository , 5.7 就是 Tag (版本) , 因此 mysql:5.7 和 mysql:5.6 其实是两个版本的镜像 .
如果没有指定 tag , 默认就是 latest (最新版本的镜像)
1.1 镜像操作命令
我们常见的镜像操作命令如下 :
其中的命令如下
# 后续详细介绍 # 构建镜像 docker build # 从服务器中拉取镜像 docker pull # 推送本地镜像到服务 docker push # 查看本地镜像 docker images # 删除镜像 docker rmi # 将镜像保存为压缩包 (可以 U 盘传给同事) docker save # 解压缩压缩包 docker load
如果记不住这些命令 , 我们还可以查阅帮助手册
docker --help
我们还可以查看某个具体的命令的用法
docker images --help
1.2 案例 1 : 从 DockerHub 中拉取 nginx 镜像并查看
1.2.1 拉取镜像
首先 , 我们就需要先访问 DockerHub 的网站 : https://hub.docker.com/
然后搜索 nginx
然后就展示出了一系列结果
然后点击这个镜像
我们将官方提供的命令复制下来 , 然后进行粘贴
docker pull nginx
下载可能会比较缓慢 , 稍等片刻
1.2.2 查看镜像
我们使用这条命令查看本地存在的镜像
# 本地存在的镜像 docker images
我们可以观察一些字段
- TAG : 他是 latest , 代表最新版本 .
- IMAGE ID : 该镜像对应的 ID
- CREATED : 创建时间 (这个镜像是 12 天前官方创建 / 更新的)
- SIZE : 该镜像的大小
1.3 案例 2 : 利用 docker save 将 nginx 镜像导出磁盘 , 然后再通过 load 加载回来
1.3.1 导出镜像
我们可以通过 docker --help 命令来查看一下帮助文档
# 查看 save 命令的用法 docker save --help
那 Usage 就是 save 命令的用法了
# [OPTIONS]: 选项,-o 选项表示输出到哪里 # IMAGE: 要输出的镜像 docker save [OPTIONS] IMAGE [IMAGE...]
我们可以试验一下
docker save -o nginx.tar nginx:latest
1.3.2 导入镜像
我们先把本地的 nginx 镜像删除掉
# 删除 nginx 镜像 docker rmi nginx:latest
然后再将我们刚才导出的镜像重新导入进来
我们先来看一下 docker load 的用法
# 查看导入镜像的语法 docker load --help
-i 参数表示要读取哪个镜像 , 所以我们就选择 -i 参数
# 导入镜像 docker load -i nginx.tar
1.4 案例 3 : 从 DockerHub 上搜索并拉取一个 Redis 镜像
第一步 : 去 DockerHub 搜索 Redis 镜像
访问 DockerHub 的官方网站 : https://hub.docker.com/
然后搜索 Redis
然后我们选择官方推荐的 Redis 镜像
第二步 : 查看 Redis 镜像的名称和版本
第三步 : 利用 docker pull 命令拉取镜像
我们直接复制 DockerHub 提供给我们的命令即可
docker pull redis
我们可以查看本地都有哪些镜像
docker images
第四步 : 利用 docker save 命令将 redis:latest 打包成一个 redis.tar 包
docker save -o redis.tar redis:latest
第五步 : 利用 docker rmi 删除本地的 redis:latest
docker rmi redis:latest
第六步 : 利用 docker load 重新加载 redis.tar 文件
docker load -i redis.tar
二 . 容器操作
2.1 容器相关命令
那我们分别列举出上面的命令
# 创建并运行容器 docker run # 运行 -> 暂停 docker pause # 暂停 -> 运行 docker unpause # 运行 -> 停止 docker stop # 停止 -> 运行 docker start # 查看所有运行的容器以及状态 docker ps # 查看所有容器以及状态 docker ps -a # 查看容器的运行日志 docker logs # 进入容器中执行一些命令 docker exec # 删除容器 docker rm
2.2 创建并运行一个 Nginx 容器
我们首先来到 nginx 的详情页面
https://hub.docker.com/_/nginx
然后往下翻 , 找到 How to use this image , 在这个位置就会展示出具体的容器创建方法
那下面给出了许多命令 , 我们可以选择一条简单的 , 比如这个 :
那我们可以来分析一下这段命令的含义
$ docker run --name some-nginx -d -p 8080:80 some-content-nginx
- docker run : 创建并运行一个容器
- --name : 给容器起一个名 , 叫做 some-niginx
- -d : 让容器后台运行
- -p : 将宿主机端口与容器端口进行映射 , 冒号左侧是宿主机端口 , 右侧是容器端口
我们这里将宿主机的 8080 端口与容器的 80 端口进行绑定
- some-content-nginx : 要操作的镜像的名称
那我们也可以试验一下
# docker run : 创建并运行一个容器 # --name : 给容器起一个名, 叫做 mynginx # -p 80:80 : 将宿主机的 80 端口与容器的 80 端口进行绑定 # -d : 让容器后台运行 # nginx : 要操作的镜像名称 docker run --name mynginx -p 80:80 -d nginx
那执行完这条命令 , 就会返回给我们一个独一无二的容器 ID
我们可以查看该容器是否运行成功
# 查看所有运行的容器以及状态 docker ps
那接下来我们就可以访问 80 端口来验证一下 nginx 容器是否创建成功
那访问了 nginx , 肯定就会有日志产生 , 我们也可以看一下
# 查看容器生成的日志 docker logs mynginx
那我们每次想要查看新的日志 , 就需要重新输入一次命令 , 我们能不能动态的渲染日志呢 ?
我们可以通过 docker 手册来看一下
# 查看 logs 命令的用法 docker logs --help
我们观察一下 , 发现 -f 参数可以实现日志的持续输出
那我们就执行一下这条命令
# 持续动态输出日志 docker logs -f mynginx
2.3 案例 1 : 进入 Nginx 容器 , 修改 HTML 文件内容 , 添加 "Hello World"
2.3.1 进入容器
那我们之前也介绍过进入容器的命令
# 可以进入容器中执行一些命令 docker exec
这个命令可以进入到 Nginx 容器中 , 去执行一些命令
那我们详细分析解读一下这个命令
docker exec -it mynginx bash
- docker exec : 进入容器内部 , 执行一个命令
- -it : 给当前进入的容器创建一个标准的输入、输出终端 , 允许我们与容器之间交互
- mynginx : 要进入的容器的名称
- bash : 进入容器后执行的命令 (bash 是一个 Linux 终端的交互命令)
那我们就可以在当前状态下执行一些命令 , 比如 : pwd
2.3.2 进入 nginx 的 HTML 所在目录 /usr/share/nginx/html
那接下来我们想修改 Nginx 提供的 HTML 文件的位置 , 那这个文件在哪找呢 ?
我们还是需要回到 Docker Hub 的界面来找一下
那接下来我们跳转到这个目录即可
cd /usr/share/nginx/html
那我们通过 vim 直接修改这个代码即可
vim index.html
但是他提示找不到此命令
这是因为我们之前也介绍过 , Docker 镜像封装的时候 , 只会封装一些需要的函数库 , 那这就代表 vim 并未被 nginx 收录进来 .
那我们该怎样修改这个文件呢
2.3.3 修改 index.html
我们需要通过这个命令来进行修改
sed -i -e 's#Welcome to nginx#Hello World#g' -e 's#<head>#<head><meta charset="utf-8">#g' index.html
那怎样验证呢 , 我们可以重新刷新一下页面来查看效果
2.3.4 停掉容器
我们先退出进入容器的状态 , 使用 exit 退出即可
那停止容器的命令如下 :
# 停掉容器 docker stop mynginx
2.3.5 启动容器
# 启动容器 docker start mynginx
2.3.6 删除容器
# 删除容器 docker rm mynginx
但是我们发现 , 报错了
他的意思是说 mynginx 这个容器还在运行 , 不能够删除 .
那我们能否强制删除呢 ? 我们还可以通过帮助手册来看一下
# 查看 rm 用法 docker rm --help
那我们加一个 -f 参数即可
# 强制删除容器 docker rm -f mynginx
2.4 案例 2 : 创建并运行一个redis容器 , 并且支持数据持久化
2.4.1 到 DockerHub 中搜索 Redis 镜像
2.4.2 查看 Redis 镜像中的描述信息
2.4.3 利用 docker run 命令运行一个 Redis 容器
docker run --name some-redis -d redis redis-server --save 60 1 --loglevel warning
但是我们还需要将这个命令进行一些改造 , 因为他还没进行宿主机和容器端口的绑定
那我们改造之后的命令如下 :
# docker run : 创建并运行容器 # --name myredis : 给当前容器设置名称 # -p 6379:6379 : 将宿主机的 6379 端口与容器的 6379 端口进行绑定 # -d : 让容器后台运行 # redis : 表示要操作的镜像名 # redis-server : 表示 Redis 服务 # --appendonly yes : 开启 AOF 持久化 docker run --name myredis -p 6379:6379 -d redis redis-server --appendonly yes
2.4.4 进入 Redis 容器
# docker exec : 进入 Docker 容器 # -it : 提供标准输入输出终端 # myredis : 要进入的容器的名称 # bash : 进入到 Linux 的命令行 docker exec -it myredis bash
2.4.5 执行 Redis 客户端
那我们此时已经进入到了 Linux 的终端 , 我们此时就可以再进入到 Redis 客户端
redis-cli
那我们就可以写入数据了
set k1 v1
2.4.6 直接进入到 Redis 客户端
我们刚才进入容器 , 是访问的 bash 命令行 , 那我们能否直接访问 Redis 客户端呢 ?
docker exec -it myredis redis-cli
三 . 数据卷
我们之前已经学习了镜像和容器的操作 , 我们发现了一个问题 : 所有的数据都是和容器耦合在一起的 , 因此带来了许多问题
- 不便于修改 : 如果我们想要修改数据 , 就必须先进入到容器内部中 , 并且容器内部一般没有什么高级的工具可以进行修改 , 非常麻烦 .
- 数据不可复用 : 在容器内的修改 , 对外是不可见的 . 这就导致所有数据的修改 , 对新创建的容器是不可复用的 .
- 升级维护困难 : 数据全部存储在容器的内部 , 那如果我们想要更新容器的话 , 就需要删除掉旧的容器 , 这也会导致数据被删除掉 .
那为了解决这些问题 , Docker 推出了一个叫做 "数据卷" 的东西 .
3.1 什么是数据卷 ?
数据卷是一个虚拟的目录 , 它指向宿主机文件系统中某个具体的目录 .
那容器创建出来 , 就会去使用对应的数据卷 , 数据卷就相当于宿主机和容器之间的桥梁 .
数据卷的作用是将容器与数据分离 , 进行了解耦合 . 这样就方便操作容器内的数据 , 保证了数据的安全 .
那这样的话 , 就解决了我们上面提出的问题
- 不便于修改 : 容器中的文件与宿主机中的文件通过数据卷一一对应 , 修改了宿主机的文件就相当于修改了容器中的文件
- 数据不可复用 : 我们可以让新的容器也来挂载修改过的数据卷 , 这样也解决了数据共享的问题
- 升级维护困难 : 如果我们升级版本的话 , 容器中的数据会被删除掉 , 但是数据卷以及宿主机中的数据不会被删除掉 , 之后新版本的容器只需要挂载之前的数据卷即可
3.2 操作数据卷
语法 :
docker volume [command]
那 command 提供了许多选项
- create : 创建一个数据卷
- inspect : 显示一个或者多个数据卷的具体信息
- ls : 列出所有的数据卷
- prune : 删除未使用的数据卷
- rm : 删除一个或者多个数据卷
3.3 案例 1 : 创建一个数据卷 , 并且查看数据卷在宿主机的目录位置
首先 , 我们可以来查看帮助文档
docker volume --help
帮助手册提示给了我们许多的参数 , 那我们接下来就逐一演示上面的各种 COMMAND 参数
3.3.1 创建数据卷
我们通过 create 来创建一个数据卷
# 创建一个名为 test 的数据卷 docker volume create test
3.3.2 查看当前所有的数据卷
那我们可以通过 ls 来查看当前所有的数据卷
# 查看当前所有的数据卷 docker volume ls
第一行的数据卷是 Docker 默认创建的数据卷 , 我们无需关注
3.3.3 查看数据卷的具体信息
# 查看 test 数据卷的具体信息 docker volume inspect test
那 Mountpoint 就是该数据卷的挂载点 , 也就是绑定的宿主机对应的目录
3.3.4 删除数据卷
删除数据卷有两种方式 :
- 删除未使用的数据卷
- 删除指定的数据卷
那我们先演示第一种 : 删除未使用的数据卷
# 删除未使用的数据卷 docker volume prune
那我们输入 y 就会将未使用的数据卷进行删除
接下来演示一下删除指定的数据卷
# 删除指定的数据卷 docker volume rm test
3.4 挂载数据卷
我们在创建容器的时候 , 可以通过 -v 参数来挂载一个数据卷到某个容器目录 , 这样的话就会实现宿主机的文件与容器的文件的绑定 .
我们可以举个例子
docker run \ # 创建并运行容器 --name mynginx \ # 给容器命名为 mynginx -v test:/root/test \ # : 前半部分是数据卷, 后半部分是容器内的目录 -p 8080:80 # 将宿主机的 8080 端口与容器的 80 端口进行绑定 nginx \ # 要操作的镜像名称
其他的部分我们都见过了 , 我们格外关注一下这个部分 : -v test:/root/test
这段代码的意思就是将 test 数据卷挂载到容器内的 /root/test 目录下
那知道了语法 , 我们就可以实现一个案例
3.5 案例 2 : 创建一个 Nginx 容器 , 修改容器内的 HTML 目录中的 index.html 内容
我们在之前的案例中 , 已经知道了 nginx 的 HTML 目录所在位置 : /usr/share/nginx/html , 那我们就需要将这个目录挂载到 test 这个数据卷上
3.5.1 创建容器并挂载数据卷到容器的 HTML 目录
我们先来看一下本地都有哪些容器
# 查看本地所有容器 docker ps -a
接下来 , 我们就可以创建 nginx 容器
# docker run : 创建并运行容器 # --name mynginx : 为该容器起名 # -p 80:80 : 将宿主机的 80 端口和容器的 80 端口进行绑定 # -v : 前半部分是数据卷的名称, 后半部分是要挂载的目录 # -d : 让容器后台运行 # nginx : 要操作的容器 docker run --name mynginx -p 80:80 -v test:/usr/share/nginx/html -d nginx
接下来我们就可以查看一下 test 数据卷挂载到宿主机的位置
# 查看 test 数据卷的相关信息 docker inspect test
那实际上这两个位置就是对应的了 , 他们之间通过数据卷进行关联
容器内部 : /usr/share/nginx/html 容器外部 : /var/lib/docker/volumes/test/_data
3.5.2 进入 html 数据卷所在位置 , 并修改 html 文件内容
我们刚才已经找到了 test 数据卷所挂载到宿主机的位置 , 那我们就可以进入到这个目录来看一下
cd /var/lib/docker/volumes/test/_data
然后查看一下这个目录的文件
我们此时可以发现 , 我们目前还并未进入到容器中 , 目前处在容器外部 , 就能看到 nginx 对应的 index.html 文件
那这就说明 , 数据卷的挂载已经实现 , 此时我们可以直接修改 index.html , 对宿主机的修改 , 也会影响到容器内部的 index.html
那我们可以访问一下此页面了
那我们上述完成的工作 , 都是建立在数据卷都已经提前创建好的情况 .
如果数据卷不存在 , 能否成功呢 ?
我们先把 mynginx 容器和 test 数据卷删除掉
# 删除 mynginx 容器 docker rm -f mynginx # 清除 test 数据卷 docker volume rm test
此时 test 数据卷已经被删除了 , 那此时我们不提前创建好数据卷 , 选择直接来去挂载数据卷 .
docker run --name mynginx -p 80:80 -v test:/usr/share/nginx/html -d nginx
那我们可以回到页面看一下
这就说明如果我们在做数据卷挂载的时候 , 数据卷不存在的话 , 会自动帮助我们创建数据卷并且进行挂载 .
3.6 案例 3 : 创建并运行一个 MySQL 容器 , 将宿主机目录直接挂载到容器
我们刚才已经完成了将数据卷挂载到容器目录 , 事实上 , 宿主机目录也可以直接跟容器进行挂载 .
那目录挂载与数据卷挂载的语法是类似的
- -v [宿主机目录]:[容器内目录]
- -v [宿主机文件]:[容器内文件]
那目录挂载还允许将宿主机文件跟容器内文件进行挂载 , 这样的话宿主机文件的内容就会覆盖掉容器内文件的内容 .
3.6.1 将 mysql.tar 文件上传到服务器 , 通过 load 命令加载为镜像
我们将 mysql.tar 文件导入到 tmp 目录中
cd /tmp/
上传成功之后 , 我们就需要将这个镜像进行解压缩了
docker load -i mysql.tar
那我们就可以查看一下 Docker 中都有哪些镜像了
docker images
3.6.2 创建目录 /tmp/mysql/data
mkdir -p mysql/data
3.6.3 去 DockerHub 查阅资料 , 创建并运行 MySQL 容器
我们来到 DockerHub , 搜索 MySQL
因为我们需要进行挂载 , 所以我们寻找带有 -v 的命令即可
那我们再稍加改造一下
# --restart=always 表示 Docker 重启的时候, MySQL 也进行重启 # -p 3306:3306 表示将宿主机的 3306 端口与容器中的 3306 端口进行绑定 # --name mysql 表示将该镜像命名为 mysql # -v /tmp/mysql/data:/var/lib/mysql 表示将宿主机的 MySQL 数据目录与宿主机的目录(DockerHub 查询到的)进行绑定 # -e 表示环境变量的意思 # MYSQL_ROOT_PASSWORD=root 表示设置 MySQL 的密码 # -d 表示让容器后台运行 # mysql:5.7.25 表示要操作的镜像 docker run --restart=always -p 3306:3306 --name mysql -v /tmp/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7.25