小编目前大一,刚开始着手学习微服务的相关知识,小编会把它们整理成知识点发布出来。我认为同为初学者,我把我对知识点的理解以这种代码加观点的方式分享出来不仅加深了我的理解,或许在某个时候对你也有所帮助,同时也欢迎大家在评论区分享你们的观点。
带着决心起床,带着满意入睡。
目录
概述
Docker是一款能够帮助我们快速构建,运行管理应用的工具,如果按照传统的方式在Linux系统上安装一个MySQL,那些命令行可是多的让人头皮发麻,同时也会被繁琐的步骤劝退,现在我们有了Docker这款工具,我们安装MySQL只需要一条命令,就可以直接躺平等着了。接下来让我们来进行一个快速入门案例来感受一下Docker的便捷。如果还没有安装Docker的可以看我上一篇文章,下面是传送门:
快速入门
部署MySql
利用docker部署MySql,只需要下面这一条命令就好了,现在我们不需要明白这一条命令是上什么含义,因为当前我们只是尝试感受一下docker的便捷。
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
mysql
其实可以写作一行,我这里只是为了美观以及后面解释方便。 运行完这一行我们就可以躺平等着docker就会自动帮我们部署好MySql。接着我们只要随便打开一个数据库管理工具,然后连接当前虚拟机部署的数据库就好了。
走到这一步,那么恭喜你已经安装成功了。
接着我们来看看命令行执行的过程。首先第一行的意思是说它在本地找不到最新的mysql镜像,于是它就进行了一顿下载操作,下载好了后也就结束了。首先这里肯定下载的不只是mysql的安装包,如果下载的只是mysql的驱动那么这里是绝对不可能下载好我们就能连接上的,毕竟我们都还没有设置环境和配置。这里其实它下载的是镜像,镜像不仅包含应用本身,还包含应用运行所需要的环境,配置,系统函数库。Docker会在运行镜像时创建一个隔离环境,称为容器。
既然Docker在运行镜像时会创建一个隔离环境,那么这时我们就可以去部署n多应用,哪怕是部署一个MySQL集群也是可以的。 但是注意名字和端口需要改变,见下面,具体含义后面命令解读再来解释。
docker run -d \
--name mysql2 \
-p 3307:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
mysql
按照这个套路下去,mysql3--3308,mysql4-3309等等,我们可以实现部署MySQL集群,这里提示一下,镜像只需要下载一次就好了,后面我们部署都是不用下载的,一秒就好了。
这时我们调用下面这个命令就可以看到mysql和mysql2都启动起来了
docker ps
其实镜像是从镜像仓库 下载下来的,Docker官方就维护了一个公共仓库叫 Docker Hub感兴趣可以搜一下,镜像仓库就好比存储和管理镜像的平台。
下面这张图差不多就是Docker部署的大致流程。
命令解读
接下来我们来解读一下快速入门的命令。
docker run -d : 创建并运行一个容器,-d 是让容器在后台运行(不要让命令行卡住)。
--name mysql : 给容器起个名字,必须唯一。
-p 3306:3306 : 设置端口映射,容器内部其实是一台模拟的机器,也有自己的ip地址和端口,所以我们需要把宿主机(当前机器)的3306端口去映射容器内的3306端口。所以前面的3306是宿主机端口,后面的3306是容器内端口,所以我们在部署mysql2的时候前一个变成了3307,也就是宿主机3307端口映射到容器内3306端口。
**-e KEY=VALUE:**是设置环境变量,采用键值对的形式配置,具体有哪些环境变量可以设置,我们要去Docke Hub中查看,其实对于mysql我们必填的只有一个MYSQL_ROOT_PASSWORD也就是root账号的密码,额外我还配了一个时区。
mysql: 指定运行的镜像的名字,完整写法是**[repository] : [tag]** ,前面repository 就是镜像名,后面tag 就是指定镜像版本。如果像上面一样没有指定tag时,默认是latest,代表最新版本。
bash
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
mysql
Docker基础
常见命令
Docker最常见的命令就是操作镜像,容器的命令。
**docker pull :**将远端镜像仓库中的镜像下载到本地。
**docker images :**查看本地镜像。
docker rmi : 删除镜像。
docker build : 自己自定义构建镜像。
**docker save :**保存镜像为压缩文件
**docker load :**将压缩的镜像文件解压到本地。
**docker push :**将本地镜像推到镜像仓库。
docker run : 创建并运行容器。
**docker stop :**停止容器中运行镜像的进程,容器仍然存在。
docker start : 启动容器中停掉的进程。
docker ps : 查看当前运行中的容器,加上选项**-a**展示所有容器。
docker rm : 删除容器。
**docker logs :**查看容器运行时的日志。
docker exec : 进入容器内部。
有些命令如果以后忘记了,直接去docker官网查找就好了。
接着可以尝试一下拉取Nginx镜像,创建并运行Nginx容器,这个任务就交给你了。遇到不清楚后续选项的的可以查官网,也可以--help哦。
数据卷挂载
前面我们提到容器其实是一个运行的机器,但是这台机器所拥有的系统库只是满足了内部镜像进程运行的最基本需求,有些命令如vi,rm,cp这些命令都是没有的,所有这时我们想修改容器内的文件或者拷贝是非常困难的,这时就需要我们继续向下引出数据卷的知识。
数据卷是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁。如下图,我们想在下面nginx容器中的html文件部署静态资源,conf文件中做配置去实现反向代理,是非常困难的。
这时我们就可以通过docker命令去创建两个数据卷,一个是html,一个是conf。
数据卷创建完后,docker接着就会在我们宿主机文件系统,var/lib/docker/volumes 这个固定目录(仅Linux操作系统)中自动创建html和conf目录,下面都有一个_data目录。
接着 hmtl卷就映射到html目录下的_data,conf卷就映射到conf目录下的_data。
这样每一个卷都与宿主机上的文件目录所对应。所以说卷是虚拟的,但是对应到宿主机上的文件目录是真实的。 接着我们只要让容器内的conf目录和html目录分别与卷挂载,这样就实现容器目录与宿主机目录相关联了,docker此时就会自动实现 二者之间的双向绑定,这时我们只需要在宿主机上编辑文件,容器内文件也会被修改。
接着我们就来学习一下docker是如很操作数据卷的。
创建数据卷我们学会了,接着我们来看看如何完场挂载,其实就是在执行docker run命令时,使用 -v 数据卷:容器内目录可以完成数据卷挂载。所以我们只有在容器创建时去挂载,如果容器创建了之后,我们是没有办法去实现挂载的。
接着我们就来实现一下挂载html目录,首先删掉原来的nginx容器
bash
docker rm -f nginx
接着创建新的nginx并挂载数据卷,至于容器内的目录可以去Docker Hub官网查,这个也是查来的。
bash
docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx
接着为了检验是否创建成功,我们就可以用命令查看一下是否存在html卷。
上面那个名叫一堆看不懂字符串的卷我们先不管。
接着我们通过命令来查看一下html的详细信息,我们可以看到有一个目录是不是和上面讲述的宿主机目录一样,这就是说明与宿主机目录已经完成了双向绑定。同时我们可以cd过去看看是不是这么个事。
两个html就是文件就是nginx中的初始文件。这时我们只要vim修改宿主机文件,那么容器内也会修改。
同样我们也可以往里面添加静态资源。
同时也可以进入nginx容器对应目录下查看文件内容是否被修改,这个就交给你们了。
以上就是数据卷的基本知识。
本地目录挂载
刚刚我们学习了数据卷挂载,其实容器的挂载方式不止这一种,接着来看看别的挂载方式。
之前我们在入门案例是创建了一个mysql容器我们可以通过命令查看mysql容器是否有挂载数据卷。
Mounts这一块就是表示挂载信息,我们发现mysql容器也是挂载了一个名字是很长一串字符串的卷,如果大家还有印象的话,在前面我们查看nginx挂载卷的时候就见过它。这个卷就是前面一长串字符串的卷。这种卷就叫做匿名卷。另外这个目录挂载的是mysql数据存储目录,其实这很好理解,mysql本来就是村粗大量数据,同样重要的需要修改的也是数据。
如果我们要进行mysql升级,但是卷保存的数据就会因为容器的删除而消失,所以这时我们就需要进行本地目录挂载,这非常简单,我们需要提前创建好待挂载的本地目录,接着再进行挂载。本地目录挂载和数据卷挂载的方式大同小异,以前写数据卷名的地方现在改成本地目录就行了。
挂载mysql容器的数据,配置和初始化脚本,这三个目录的代码就如图所示。
至此mysql的本地目录挂载我们就实现好了。
Dockerfile语法
接着我们来学习如何自定义镜像,在之前我们知道镜像就是包含了应用程序,程序运行的系统函数库,运行配置等文件的文件包。构建镜像的过程其实就是把上述文件打包的过程。接着我们来回顾一下部署一个java应用的步骤。
其实构建一个java镜像的步骤和它差不多。
其实当我们把上面的东西都打成文件,最后形成镜像时,它是有层级结构的。这些层级合并在一起才是完整的镜像。
因为镜像是分层结构,所以在某些层上其实是共享层,也就是这一层是很多镜像的共享层,就好比最底层的系统函数库层。这种共享层有个名字叫做基础镜像,指的是应用依赖的系统函数库,环境,配置,文件等。好比这时我们拉拉取一个redis镜像,就会发现第一层是一个Already exists,说明这一层就是基础镜像,之前我们下载nginx或mysql的时候已经下载过这一层了。
同样最顶层启动脚本也有个名字叫做入口,指的是镜像运行入口,一般是程序启动的脚本和参数。
其实并不需要我们自己亲手去找文件,打包,分层这些操作去做镜像,只需要告诉docker我们镜像结构,它就可以自动去完成构建了。至于怎么告诉docker我们镜像的结构,这时就需要用到Dockerfile了。
Dockerfile就是一个文本文件,其中包含一个个的指令,用指令来说明要执行什么操作来构建镜像。将来Docker可以根据Dockerfile帮我们构建镜像。常见指令如下。
以上只是基础常用指令,更多指令还是可以去官网看一下。
一下就是基于Ubuntu基础镜像,利用Dockerfile描述镜像结构
其实通过观察上面,我们可以发现每次变幻的其实就是jar包名字,所以以上指令基本上完全可以复用,使用时改掉jar包名字就好了。
既然可以基于Ubuntu基础镜像,其实还可以基于jdk为基础镜像,这可是有说法的。
所以其实dockerfile中的指令其实没那么重要,我们制作java镜像,只要把上面三行指令敲上去差不多就完事了。
自定义镜像
前面我们知道了如何构造java镜像,这时我们就可以尝试构造一下java镜像。
当我们编写好Dockerfile后,我们可以用下面命令来构建镜像:
bash
docker build -t 镜像名字:版本号 .
-t : 是给镜像起名,格式依然时repository:tag的格式,不指定tag时,默认为latest。
. : 最后还有一个点啊,不要看走眼了,这个点是指定Dockerfile所在目录,如果就在当前目录,则指定为**"."**。与版本号之间是有一个空格哦。
接着我这里有个jar包我们可以来演示一下啊。
首先我们需要一个Dockerfile,里面写好下面这几个指令,设定时区主要就是为了日志和数据库的数据时间不要产生差异。
bash
# 基础镜像
FROM openjdk:11.0-jre-buster
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包
COPY docker-demo.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]
接着我们要把整个文件夹(jar包和Dockerfile)上传到虚拟机。
然后我们就可以运行下面指令构建镜像了。
bash
docker build -t docker-demo .
镜像构建的也是非常的快哦,0.1s就构建完成了,真的是舒舒又服服,仔细查看可以发现有三步,第一步构建基础镜像,第二步设置时区,第三步就是拷贝jar包。同时docker ps也是可以查到该镜像的。
接着我们也可以docker run运行镜像,还可以docker logs查看日志。
非常熟悉的一个spring标志,也是说明运行成功了。同时还可以去浏览器访问一下试试。
以上就是比较重要的知识点。
容器网络互连
之前我们查看过容器的信息,同时也知道容器内部其实就是模拟的一个系统,所以容器其实是有网络信息的。
默认情况下,所有容器都是以bridge方式连接到Docker的一个虚拟网桥上,容器创建就会被分配到同一个网段,与网桥建立联系。注意网桥后的/16指的是在这一网段中,前16位是不能改变的。
这种随机分配方式其实是不好的,因为每一次容器停止和启动的ip地址都会不一样,这不利于连接。接下来我们就需要自定义网络了。我们创建自定义网络后会形成新的网桥,加入自定义网络的容器不仅可以通过ip地址相连,还可以通过容器名互相访问。既然容器名不变,我们也就不用的担心连接不稳定了。
这里我是创建了一个网络,然后将nginx和前面自定义镜像都加入了进来。我再用dd容器去连接nginx是没有问题的。
项目部署
接下来我们就尝试一下去用docker部署项目。后端的部署前面我们已经实现过了,所以我们这里就试着部署一下前端。我们先来看一下前端项目所需挂载的目录
接着就是一串docker run的命令,这些命令其实都是前面所讲解的。
接着我们就可以实现浏览器访问前端网页了。
以上这种部署只是为了演示,回顾总结前面的知识,其实真正并不是这样去一个个部署的,在实际中,我们是借助DockerCompose工具。
DockerCompose通过一个独立的docker-compose.yml 模板文件(YAML格式)来定义一组相关联的应用容器,帮助我们实现多个相互关联的Docker容器的快速部署。模板文件大致格式就像下面这样,一般一个项目对应一个模板文件。
其实如果我们仔细比照一下下面这张图,就会发现docker-compose描述的信息和docker run描述的信息几乎是一模一样,只不过是语法不同罢了。
接着我们准备好了docker-compose文件后,我们来看一下如何部署,我们只需要使用下面相对应的命令就可以实现部署了。
至此作为一个java后端开发人员需要掌握的docker的一些基本知识就结束了。
有梦别怕苦,想赢别喊累。