day02-Docker

YangeIT大约 39 分钟基础服务框架MybatisPlusMybatisPlus

day02-Docker

课程内容

1.快速入门

1.0 Docker简介和安装

安装Docker

同学们,在前两天我们学习了 Linux 操作系统的常见命令以及如何在 Linux 上部署一个单体项目。大家想一想自己最大的感受是什么?

我相信,除了个别天赋异禀的同学以外,大多数同学都会有相同的感受,那就是麻烦。核心体现在三点:

  • 命令太多了,记不住
  • 软件安装包名字复杂,不知道去哪里找
  • 安装和部署步骤复杂,容易出错

其实上述问题不仅仅是新手,即便是运维在安装、部署的时候一样会觉得麻烦、容易出错。

特别是我们即将进入微服务阶段学习,微服务项目动辄就是几十台、上百台服务需要部署,有些大型项目甚至达到数万台服务。而由于每台服务器的运行环境不同,你写好的安装流程、部署脚本并不一定在每个服务器都能正常运行,经常会出错。这就给系统的部署运维带来了很多困难。

那么,有没有一种技术能够避免部署对服务器环境的依赖,减少复杂的部署流程呢?

答案是肯定的,这就是我们今天要学习的 Docker 技术。你会发现,有了 Docker 以后项目的部署如丝般顺滑,大大减少了运维工作量。

即便你对 Linux 不熟悉,你也能轻松部署各种常见软件、Java 项目

通过今天的学习,希望大家能达成下面的学习目标:

  • 能利用 Docker 部署常见软件
  • 能利用 Docker 打包并部署 Java 应用
  • 理解 Docker 数据卷的基本作用
  • 能看懂 DockerCompose 文件

总结

课堂作业

  1. docker是什么?有何优势!🎤
  2. 参考上述的资料,在centos中安装docker!!

1.1.部署 MySQL

部署MySQL

我们利用 Docker 来安装一个 MySQL 软件,大家可以对比一下之前传统的安装方式,看看哪个效率更高一些。🎯

如果是利用传统方式部署 MySQL,大概的步骤有: 方式1

  • 搜索并下载 MySQL 安装包
  • 上传至 Linux 环境
  • 编译和配置环境
  • 安装
image
image

安装完后,先停止mysql服务,以防端口冲突,停止指令:systemctl stop mysqld

Docker部署MysQL方式2

如果docker未启动,执行:systemctl start docker 启动docker服务

而使用 Docker 安装,仅仅需要一步即可,在命令行输入下面的命令(建议采用 CV 大法):

docker run -d \
  --name mysql \
  -p 3306:3306 \
  -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=1234 \
  mysql:5.7.25

安装mysql5.7 的版本

运行效果如图:

image
image

MySQL 安装完毕!通过任意客户端工具即可连接到 MySQL.查看链接图解open in new window 👈

总结

课堂作业

  1. docker部署软件相对于linux直接部署软件,有什么优势?🎤
  2. 复制上面的命令,在docker中部署mysql,然后使用客户端连接上mysql,体会安装软件的便捷性!🎤

记得要把linux安装的mysql关闭哦,防止3306端口被占用

1.2.Docker架构 🍐

Docker架构

大家可以发现,当我们执行命令后,Docker 做的第一件事情,是去自动搜索并下载了 MySQL,然后会自动运行 MySQL,我们完全不用插手,是不是非常方便。 而且,这种安装方式你完全不用考虑运行的操作系统环境,它不仅仅在 CentOS 系统是这样,在 Ubuntu 系统、macOS 系统、甚至是装了 WSL 的 Windows 下,都可以使用这条命令来安装 MySQL。 要知道,不同操作系统下其安装包、运行环境是都不相同的!如果是手动安装,必须手动解决安装包不同、环境不同的、配置不同的问题

而使用 Docker,这些完全不用考虑。就是因为 Docker 会自动搜索并下载 MySQL。注意:这里下载的不是安装包,而是镜像。镜像中不仅包含了 MySQL 本身,还包含了其运行所需要的环境、配置、系统级函数库。镜像中的应用程序运行后形成的进程就是容器,而提供下载镜像的地方叫做仓库(DockerHub)

因此,Docker安装软件的过程,就是自动搜索下载镜像,然后创建并运行容器的过程。

小结

镜像

  • 将应用程序及其依赖、环境、配置打包在一起

容器

  • 镜像运行起来就是容器,一个镜像可以运行多个容器

Docker结构

  • 服务端:接收命令或远程请求,操作镜像或容器

  • 客户端:发送命令或者请求到Docker服务端

DockerHub:

  • 一个镜像托管的服务器,类似的还有阿里云镜像服务,统称为DockerRegistry

1.3.命令解读

命令解读

利用 Docker 快速的安装了 MySQL,非常的方便,不过我们执行的命令到底是什么意思呢?

docker run -d \
  --name mysql \
  -p 3306:3306 \
  -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=1234 \
  mysql:5.7.25

解读:

  • docker run -d :创建并运行一个容器,-d 则是让容器以后台进程运行
  • --name mysql : 给容器起个名字叫 mysql,你可以叫别的
  • -p 3306:3306 : 设置端口映射。
    • 容器是隔离环境,外界不可访问。但是可以将宿主机端口映射容器内到端口,当访问宿主机指定端口时,就是在访问容器内的端口了。
    • 容器内端口往往是由容器内的进程决定,例如 MySQL 进程默认端口是 3306,因此容器内端口一定是 3306;而宿主机端口则可以任意指定,一般与容器内保持一致。
    • 格式: -p 宿主机端口:容器内端口,示例中就是将宿主机的 3306 映射到容器内的 3306 端口
  • -e TZ=Asia/Shanghai : 配置容器内进程运行时的一些参数
    • 格式:-e KEY=VALUE,KEY 和 VALUE 都由容器内进程决定
    • 案例中,TZ=Asia/Shanghai 是设置时区;MYSQL_ROOT_PASSWORD=123 是设置 MySQL 默认密码
  • mysql:5.7.25 : 设置镜像名称,Docker 会根据这个名字搜索并下载镜像
    • 格式:REPOSITORY:TAG,例如 mysql:8.0,其中 REPOSITORY 可以理解为镜像名,TAG 是版本号
    • 在未指定 TAG 的情况下,默认是最新版本,也就是 mysql:latest

镜像的名称不是随意的,而是要到 DockerRegistry 中寻找,镜像运行时的配置也不是随意的,要参考镜像的帮助文档,这些在 DockerHub 网站或者软件的官方网站中都能找到。

如果我们要安装其它软件,也可以到 DockerRegistry 中寻找对应的镜像名称和版本,阅读相关配置即可。

总结

课堂作业

  1. https://hub-stage.docker.com/open in new window 找一下redis的镜像imageopen in new window,体会下仓库的魅力!
  2. 端口映射是什么意思?为什么要进行端口映射?🎤
  3. 容器和镜像有什么区别?启动一个容器的命令是什么?🎤
  4. 说说部署nginx到docker容器的流程步骤?🎤

2.Docker 基础

接下来,我们一起来学习 Docker 使用的一些基础知识,为将来部署项目打下基础。

指令集

首先我们来学习 Docker 中的常见命令,其中,比较常见的命令有:

命令说明文档地址
docker pull拉取镜像docker pullopen in new window
docker push推送镜像到 DockerRegistrydocker pushopen in new window
docker images查看本地镜像docker imagesopen in new window
docker rmi删除本地镜像docker rmiopen in new window
docker save保存镜像到本地压缩文件docker saveopen in new window
docker load加载本地压缩文件到镜像docker loadopen in new window
docker run创建并运行容器(不能重复创建)docker runopen in new window
docker stop停止指定容器docker stopopen in new window
docker start启动指定容器docker startopen in new window
docker restart重新启动容器docker restartopen in new window
docker rm删除指定容器docs.docker.comopen in new window
docker ps查看容器docker psopen in new window
docker inspect查看容器详细信息docker inspectopen in new window
docker logs查看容器运行日志docker logsopen in new window
docker exec进入容器docker execopen in new window

用一副图来表示这些命令的关系:

image
image

2.1.镜像操作

镜像操作

首先来看下镜像的名称组成:

  • 镜名称一般分两部分组成:[repository]:[tag]

在没有指定tag时,默认是latest,代表最新版本的镜像 如图:image-20210731155141362 这里的mysql就是repository,5.7就是tag,合一起就是镜像名称,代表5.7版本的MySQL镜像。

Docker镜像操作👇

常见的镜像操作
常见的镜像操作

案例1-拉取、查看镜像

需求:从DockerHub中拉取一个nginx镜像并查看🎯

1)首先去镜像仓库搜索nginx镜像,比如DockerHubopen in new window:

image-20210731155844368
image-20210731155844368

2)根据查看到的镜像名称,拉取自己需要的镜像,通过命令:docker pull nginx

image
image

3)通过命令:docker images 查看拉取到的镜像

image
image

总结

  1. 镜名称一般分两部分组成:[repository]:[tag]

在没有指定tag时,默认是latest,代表最新版本的镜像

  1. Docker将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起,称为镜像。

  2. 镜像来源有2个

    1. 仓库中下载
    2. 自己定义

课堂作业

需求: 去DockerHub搜索并拉取一个Redis镜像 🎯必做

目标:

  1. DockerHubopen in new window搜索Redis镜像
  2. 查看Redis镜像的名称和版本
  3. 利用docker pull命令拉取镜像
  4. 利用docker save命令将 redis:latest打包为一个redis.tar包
  5. 利用docker rmi 删除本地的redis:latest
  6. 利用docker load 重新加载 redis.tar文件

查看redis版本或者指令open in new window

2.2.容器操作 ✏️ ❤️

容器操作

容器相关命令

容器操作的命令如图:

image-20210731161950495
image-20210731161950495

容器保护三个状态:

  • 运行:进程正常运行
  • 暂停:进程暂停,CPU不再运行,并不释放内存
  • 停止:进程终止,回收进程占用的内存、CPU等资源

指令(参考上图):

  • docker run:创建并运行一个容器,处于运行状态
  • docker pause:让一个运行的容器暂停
  • docker unpause:让一个容器从暂停状态恢复运行
  • docker stop:停止一个运行的容器
  • docker start:让一个停止的容器再次运行
  • docker rm:删除一个容器(所属的文件系统也会删除) rmi 是删除镜像

代码操作

案例1-创建并运行一个容器🎯

运行前查看,80端口是否被占用:lsof -i:端口号

创建并运行nginx容器的命令:

docker run --name containerName -p 80:80 -d nginx

命令解读:

  • docker run :创建并运行一个容器
  • --name : 给容器起一个名字,比如叫做mn
  • -p :将宿主机端口与容器端口映射,冒号左侧是宿主机端口,右侧是容器端口
  • -d:后台运行容器
  • nginx:镜像名称,例如nginx
  • 默认情况下,容器是隔离环境,我们直接访问宿主机的80端口,肯定访问不到容器中的nginx。
  • 现在,将容器的80与宿主机的80关联起来,当我们访问宿主机的80端口时,就会被映射到容器的80,这样就能访问到nginx了: image-20210731163255863

操作截图:👇

访问截图:👇

日志截图:👇

查看容器日志命令: docker logs 容器名字

通过帮助文档可以查出,docker logs mn -f能持续查看日志

🎉恭喜你🎉,掌握了将镜像创建一个容器,你可以利用docker ps 查看容器的启动情况

小结

docker run命令的常见参数有哪些?

  • --name:指定容器名称
  • -p:指定端口映射
  • -d:让容器后台运行

查看容器日志的命令:

  • docker logs
  • 添加 -f 参数可以持续查看日志

查看容器状态:

  • docker ps
  • docker ps -a 查看所有容器,包括已经停止的

课堂作业

🚩 1. 将上述的2.2容器操作依次练习一遍必练

或者完成

点击查看代码图解open in new window👈

  • 进入容器后,直接执行redis-cli,就可以操作 redis-cli命令 :
  • 保存:SET key value
  • 获取:GET key

2.3.数据卷✏️🍐

数据卷(容器数据管理)

在之前的nginx案例中,修改nginx的html页面时,需要进入nginx内部。并且因为没有编辑器,修改文件也很麻烦。

这就是因为容器与数据(容器内文件)耦合带来的后果。

容器与数据(容器内文件)耦合的后果
容器与数据(容器内文件)耦合的后果

要解决这个问题,必须将数据与容器解耦 ,这就要用到数据卷了。🎯

代码操作

案例-创建和查看数据卷

需求:创建一个数据卷,并查看数据卷在宿主机的目录位置 🎯

宿主机目录 --> 数据卷 ---> 容器内目录关联关系图
宿主机目录 --> 数据卷 ---> 容器内目录关联关系图
1️⃣ 创建数据卷
docker volume create html
2️⃣ 查看所有数据卷
docker volume ls

结果:

image-20210731173746910
image-20210731173746910
3️⃣ 查看数据卷详细信息卷
docker volume inspect html

结果:

image-20210731173809877
image-20210731173809877

可以看到,我们创建的html这个数据卷关联的宿主机目录为/var/lib/docker/volumes/html/_data目录。

4️⃣ 删除未使用的数据卷
docker volume prune 

小结

数据卷的作用:

  • 将容器与数据分离,解耦合,方便操作容器内数据,保证数据安全

数据卷操作:

  • docker volume create:创建数据卷
  • docker volume ls:查看所有数据卷
  • docker volume inspect:查看数据卷详细信息,包括关联的宿主机目录位置
  • docker volume rm:删除指定数据卷
  • docker volume prune:删除所有未使用的数据卷

docker run的命令中通过 -v 参数挂载文件或目录到容器中:

  • -v volume名称:容器内目录
  • -v 宿主机文件:容器内文
  • -v 宿主机目录:容器内目录

数据卷挂载与目录直接挂载的

  • 数据卷挂载耦合度低,由docker来管理目录,但是目录较深,不好找
  • 目录挂载耦合度高,需要我们自己管理目录,不过目录容易寻找查看

作业

🚩 1. 将上述的2.3.数据卷案例依次练习一遍必练

  1. 导入商城初始化数据

2.4.Dockerfile自定义镜像 🍐

前面我们一直在使用别人准备好的镜像,那如果我要部署一个 Java 项目,把它打包为一个镜像该怎么做呢?

Dockerfile自定义镜像

常见的镜像在DockerHub就能找到,但是我们自己写的项目就必须自己构建镜像了。

而要自定义镜像,就必须先了解镜像的结构才行。

3.1.镜像结构

镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。

我们以MySQL为例,来看看镜像的组成结构:

MySQL镜像的组成结构
MySQL镜像的组成结构

简单来说,镜像就是在系统函数库、运行环境基础上,添加应用程序文件、配置文件、依赖文件等组合,然后编写好启动脚本打包在一起形成的文件

我们要构建镜像,其实就是实现上述打包的过程

实操:构建Java项目操作

案例1-基于Ubuntu构建Java项目

需求:基于Ubuntu镜像构建一个新镜像,运行一个java项目 🎯

  • 步骤1:新建一个空文件夹docker-demo

    image-20210801101207444
    image-20210801101207444
  • 步骤2:拷贝课前资料中的docker-demo.jar文件到docker-demo这个目录

    image-20210801101314816
    image-20210801101314816
  • 步骤3:拷贝课前资料中的jdk8.tar.gz文件到docker-demo这个目录

    image-20210801101410200
    image-20210801101410200
  • 步骤4:拷贝课前资料提供的Dockerfiledocker-demo这个目录

    image-20210801101455590
    image-20210801101455590

    其中的内容如下:

    # 指定基础镜像
    FROM ubuntu:16.04
    # 配置环境变量,JDK的安装目录
    ENV JAVA_DIR=/usr/local
    
    # 拷贝jdk和java项目的包
    COPY ./jdk8.tar.gz $JAVA_DIR/
    COPY ./docker-demo.jar /tmp/app.jar
    
    # 安装JDK
    RUN cd $JAVA_DIR \
     && tar -xf ./jdk8.tar.gz \
     && mv ./jdk1.8.0_144 ./java8
    
    # 配置环境变量
    ENV JAVA_HOME=$JAVA_DIR/java8
    ENV PATH=$PATH:$JAVA_HOME/bin
    
    # 暴露端口
    EXPOSE 8090
    # 入口,java项目的启动命令
    ENTRYPOINT java -jar /tmp/app.jar
    
  • 步骤5:进入docker-demo

    将准备好的docker-demo上传到虚拟机任意目录,然后进入docker-demo目录下

  • 步骤6:运行命令:

    docker build -t javaweb:1.0 .
    
build和run区别
build和run区别

通过docker build命令来构建一个docker的镜像文件

-t : 指定构建后的image的名字和标签,我们一般把标签用来表示版本;

docker build默认会查找构建路径下的Dockerfile同名文件;

将镜像执行docker run 的命令:docker run --name web -p 8090:8090 -d javaweb:1.0

最后访问 http://192.168.150.101:8090/hello/count,其中的ip改成你的虚拟机ip

小结

  1. Dockerfile的本质是一个文件,通过指令描述镜像的构建过程

  2. Dockerfile的第一行必须是FROM,从一个基础镜像来构建

  3. 基础镜像可以是基本操作系统,如Ubuntu。也可以是其他人制作好的镜像,例如:java:8-alpine

2.4.网络

网络

上节课我们创建了一个 Java 项目的容器,而 Java 项目往往需要访问其它各种中间件,例如 MySQL、Redis 等。现在,我们的容器之间能否互相访问呢?我们来测试一下

首先,我们查看下 MySQL 容器的详细信息,重点关注其中的网络 IP 地址:

# 1.用基本命令,寻找Networks.bridge.IPAddress属性
docker inspect mysql
# 也可以使用format过滤结果
docker inspect --format='{{range .NetworkSettings.Networks}}{{println .IPAddress}}{{end}}' mysql

得到IP地址如下: 172.17.0.2

image
image

然后,通过命令进入dd容器,通过ping命令测试网络

如果出现:bash: ping: command not found 容器类没有ping命令, 安装教程open in new window

# 2.然后通过命令进入dd容器
docker exec -it mn bash
# 3.在容器内,通过ping命令测试网络
ping 172.17.0.2
image
image

发现可以互联,没有问题。

image
image

默认情况下,所有容器都是以bridge方式连接到Docker的一个虚拟网桥上

但是,容器的网络 IP 其实是一个虚拟的 IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个 IP,而在部署时很可能 MySQL 容器的 IP 会发生变化,连接会失败。

所以,我们必须借助于 docker 的网络功能来解决这个问题,官方文档:

https://docs.docker.com/engine/reference/commandline/network/open in new window

常见命令有:

命令说明文档地址
docker network create创建一个网络docker network createopen in new window
docker network ls查看所有网络docs.docker.comopen in new window
docker network rm删除指定网络docs.docker.comopen in new window
docker network prune清除未使用的网络docs.docker.comopen in new window
docker network connect使指定容器连接加入某网络docs.docker.comopen in new window
docker network disconnect使指定容器连接离开某网络docker network disconnectopen in new window
docker network inspect查看网络详细信息docker network inspectopen in new window

教学演示:自定义网络

核心步骤

  1. 通过命令创建一个网络,并查看查看网络
  2. 让其他容器加入上述网络
  3. 通过别名访问其他容器
# 1.首先通过命令创建一个网络
docker network create hmall

# 2.然后查看网络
docker network ls

image
image

🎉恭喜你🎉,掌握了无需记住 IP 地址也可以实现容器互联,docekr技术跟进一步!。

总结

  • 在自定义网络中,可以给容器起多个别名,默认的别名是容器名本身
  • 在同一个自定义网络中的容器,可以通过别名互相访问

课堂作业

  1. 自定义网络解决了什么问题?🎤

3.项目部署

3.1.部署 Java 项目

部署Java项目

好了,我们已经熟悉了 Docker 的基本用法,接下来可以尝试部署项目了。

在课前资料中已经提供了一个黑马商城项目给大家,如图:

项目说明:

  • hmall:商城的后端代码
  • hmall-portal:商城用户端的前端代码
  • hmall-admin:商城管理端的前端代码

部署的容器及端口说明:

项目容器名端口备注
hmallhmall8080黑马商城后端 API 入口
hmall-portalnginx18080黑马商城用户端入口
hmall-admin18081黑马商城管理端入口
mysqlmysql3306数据库

在正式部署前,我们先删除之前的 nginx、dd 两个容器:

docker rm -f nginx dd

mysql 容器中已经准备好了商城的数据,所以就不再删除了。

代码操作

部署项目:

# 1.构建项目镜像,不指定tag,则默认为latest  注意小数点不能省
docker build -t hmall .
image
image

查看镜像

# 2.查看镜像
docker images
image
image

创建并运行容器

# 3.创建并运行容器,并通过--network将其加入hmall网络,这样才能通过容器名访问mysql
docker run -d --name hmall --network hmall -p 8080:8080 hmall
image
image

注意检查代码是否有错,建议在本地先运行一下

测试,通过浏览器访问:http://你的虚拟机地址:8080/search/listopen in new windowimage

总结

课堂作业

  1. 为什么下图中mysql的地址可以写成mysql🎤 image

3.2.部署前端

部署前端

hmall-portalhmall-admin 是前端代码,需要基于 nginx 部署。在课前资料中已经给大家提供了 nginx 的部署目录:

其中:

  • html 是静态资源目录,我们需要把 hmall-portal 以及 hmall-admin 都复制进去
  • nginx.conf 是 nginx 的配置文件,主要是完成对 html 下的两个静态资源目录做代理

我们现在要做的就是把整个 nginx 目录上传到虚拟机的 /root 目录下:

然后创建 nginx 容器并完成两个挂载:

  • /root/nginx/nginx.conf 挂载到 /etc/nginx/nginx.conf
  • /root/nginx/html 挂载到 /usr/share/nginx/html

由于需要让 nginx 同时代理 hmall-portal 和 hmall-admin 两套前端资源,因此我们需要暴露两个端口:

  • 18080:对应 hmall-portal
  • 18081:对应 hmall-admin

命令如下:

docker run -d \
  --name nginx \
  -p 18080:18080 \
  -p 18081:18081 \
  -v /root/nginx/html:/usr/share/nginx/html \
  -v /root/nginx/nginx.conf:/etc/nginx/nginx.conf \
  --network hmall \
  nginx
  • -v [宿主机目录]:[容器内目录]
  • -v [宿主机文件]:[容器内文件]

测试,通过浏览器访问:http://你的虚拟机ip:18080open in new window

3.3.DockerCompose

DockerCompose

大家可以看到,我们部署一个简单的 java 项目,其中包含 3 个容器:

  • MySQL
  • Nginx
  • Java 项目

而稍微复杂的项目,其中还会有各种各样的其它中间件,需要部署的东西远不止 3 个。如果还像之前那样手动的逐一部署,就太麻烦了。

而 Docker Compose 就可以帮助我们实现多个相互关联的 Docker 容器的快速部署。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器。

总结

课堂作业

  1. DockerCompose作用是什么,应用场景是什么?🎤
  2. 编写好 docker-compose.yml 文件,就可以部署项目,命令是什么?🎤

课后作业

🚩 1. 重点完成上述的课堂作业

  1. 晚自习第一节课的前30分钟,总结完毕之后,每个同学先必须梳理今日知识点 (记得写不知道的,以及感恩三件事);整理好的笔记可以发给组长,组长交给班长,意在培养大家总结的能力)

  2. 晚自习第一节课的后30分钟开始练习(记住:程序员是代码堆起来的):

    • 先要把今天的所有案例或者课堂练习,如果没练完的,练完他
    • 部署项目 👈
  3. 剩余的时间:预习第二天的知识,预习的时候一定要注意:

  • 预习不是学习,不要死看第二天的视频(很容易出现看了白看,为了看视频而看视频)
  • 预习看第二天的笔记,把笔记中标注重要的知识,可以找到预习视频,先看一遍,如果不懂的 ,记住做好标注。