欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 社会 > Docker基础

Docker基础

2025/1/10 2:36:12 来源:https://blog.csdn.net/m0_45253972/article/details/145016488  浏览:    关键词:Docker基础

Docker基础

在这里插入图片描述

命令介绍

其中,比较常见的命令有:

命令说明文档地址
docker pull拉取镜像docker pull
docker push推送镜像到DockerRegistrydocker push
docker images查看本地镜像docker images
docker rmi删除本地镜像docker rmi
docker run创建并运行容器(不能重复创建)docker run
docker stop停止指定容器docker stop
docker start启动指定容器docker start
docker restart重新启动容器docker restart
docker rm删除指定容器docs.docker.com
docker ps查看容器docker ps
docker logs查看容器运行日志docker logs
docker exec进入容器psdocker exec
docker save保存镜像到本地压缩文件docker save
docker load加载本地压缩文件到镜像docker load
docker inspect查看容器详细信息docker inspect

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

在这里插入图片描述

默认情况下,每次重启虚拟机我们都需要手动启动Docker和Docker中的容器。通过命令可以实现开机自启:

# Docker开机自启
systemctl enable docker# Docker容器开机自启
docker update --restart=always [容器名/容器id]

命令演示

以Nginx为例演示上述命令。

第1步,去DockerHub查看nginx镜像仓库及相关信息

第2步,拉取Nginx镜像

docker pull nginx

在这里插入图片描述

第3步,查看镜像

docker images

在这里插入图片描述

第4步,保存镜像到本地

docker save -o nginx.tar nginx:latest
ll

在这里插入图片描述

第5步,删除镜像

docker rmi nginx:latest

查看镜像

docker images

在这里插入图片描述

第6步,读取本地镜像

docker load -i nginx.tar

再次查看

docker images

在这里插入图片描述

第7步,创建并运行容器

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

在这里插入图片描述

第8步,查看容器状态

docker ps

在这里插入图片描述

对输出的内容格式化

docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

在这里插入图片描述

第9步,停止容器

docker stop nginx

再次查看容器

docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

在这里插入图片描述

发现没有查看到nginx容器,是因为ps查看的是运行状态的容器。如果需要查看所有的容器,需要在最后面加上参数`

在这里插入图片描述

第10步,启动容器

docker start nginx

再次使用ps查看状态

在这里插入图片描述

第11步,查看日志

后面加上容器名,加上-f持续输出,Ctrl+C停止日志。

docker logs -f nginx

在这里插入图片描述

第12步,进入容器内部

exec执行,-it是可交互终端,容器是一个隔离环境模拟了一个计算机。进去之后采用命令行交互,命令行交互需要有个终端,-it是添加一个可输入的终端。使用bash命令进行交互。

docker exec -it nginx bash

在这里插入图片描述

exit退出容器

第13步,通过容器内部命令,直接访问mysql。

先进入mysql容器

docker exec -it mysql bash

在这里插入图片描述

使用mysql客户端命令,访问mysql

mysql -u root -p

在这里插入图片描述

show databases;

exit退出

在这里插入图片描述

第14步,删除容器

docker rm mysql

在这里插入图片描述

命令别名

给常用Docker命令起别名,方便我们访问:

找到root目录下的bashrc文件

vi ~/.bashrc

添加dps和dis,右边是其对应的原始命令。

# User specific aliases and functionsalias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias dps='docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"'
alias dis='docker images'# Source global definitions
if [ -f /etc/bashrc ]; then. /etc/bashrc
fi

然后,执行命令使别名生效

source ~/.bashrc

在这里插入图片描述

数据卷

连接nginx容器,通过bash命令进入控制台:

docker exec -it nginx bash

在这里插入图片描述

进入到静态资源目录:

cd /usr/share/nginx/html

在这里插入图片描述

对查看到的html文件进行修改:

docker容器确实提供了运行需要的环境,但是里面只包含运行必备的函数,nginx运行不限于要ll或者vi命令。因此在容器内修改和复制文件比较麻烦。这就需要使用数据卷解决。

容器是隔离环境,容器内程序的文件、配置、运行时产生的容器都在容器内部,我们要读写容器内的文件非常不方便。可以思考几个问题:

  • 如果要升级MySQL版本,需要销毁旧容器,那么数据岂不是跟着被销毁了?
  • MySQL、Nginx容器运行后,如果我要修改其中的某些配置该怎么办?
  • 我想要让Nginx代理我的静态资源怎么办?

因此,容器提供程序的运行环境,但是程序运行产生的数据、程序运行依赖的配置都应该与容器解耦。

什么是数据卷

数据卷(volume)是一个虚拟目录,逻辑上存在,是容器内目录宿主机目录之间映射的桥梁。

以Nginx为例,我们知道Nginx中有两个关键的目录:

  • html:放置一些静态资源
  • conf:放置配置文件

如果想对nginx的配置和静态资源都做处理,就需要创建两个数据卷confhtml。这两个数据卷是用docker命令创建的,docker会帮助对这两个数据卷创建对应的真实的目录,在宿主机中创建,也就是容器所在的机器。在虚拟机的文件系统里的准备对应的目录,只要是Linux系统就会固定在/var/lib/docker/volumes/目录下创建数据卷对应的目录。将来html卷就映射到html下的/_dataconf卷就映射到conf下的/_data。也就是每一个数据卷都与宿主机上的一个目录一一对应,所以数据卷是逻辑的,但是对应宿主机上的文件是真实的。既然它是容器目录与宿主机目录之间映射的桥梁,所以需要让容器的目录与数据卷做挂载。

现在容器的/conf目录指向了conf卷conf卷又指向了宿主机/conf下的/data

在这里插入图片描述

数据卷是两者之间关联的桥梁,一旦关联之后docker就会实现宿主机目录与容器内目录之间的双向绑定。一旦这个绑定产生了,只需要在宿主机目录的/_data下新增一个文件,就会自动跑到容器内的对应的目录下,同样在容器内目录下做修改,在对应的宿主机的目录里这个文件也会进行修改。现在要去修改nginx的配置文件或者部署静态资源就不需要进入到容器内,只需要绑定,然后更改宿主机即可。

数据卷命令

docker提供一些命令来操作数据卷:

命令说明文档地址
docker volume create创建数据卷docker volume create
docker volume ls查看所有数据卷docs.docker.com
docker volume rm删除指定数据卷docs.docker.com
docker volume inspect查看某个数据卷的详情docs.docker.com
docker volume prune删除未使用的卷docker volume prune

这些命令不需要记,只需要使用docker volume --help即可查看所有命令的帮助信息。

在这里插入图片描述

案例一:数据卷挂载

在这里插入图片描述

为了方便修改,需要对nginx下的html目录做挂载。

注意:容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且创建容器的过程中,数据卷会自动创建

演示一下nginx的html目录挂载:

第0步,删除原有的nginx容器

docker rm -f nginx

在这里插入图片描述

第1步,首先创建容器并指定数据卷,通过 -v 数据卷:容器内目录完成数据卷挂载

数据卷的名字可以随便起,但是不要冲突。在创建容器时,如果挂载了数据卷且数据卷不存在,会自动创建数据卷,不需要自己执行docker volume create

docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx

在这里插入图片描述

通过docker ps查看容器创建成功。

第2步,查看数据卷

docker volume ls

在这里插入图片描述

第3步,查看数据卷详情

html卷已经有了,可以通过inspect命令查看挂载到宿主机的具体位置。

docker volume inspect html

在这里插入图片描述

第4步,查看/var/lib/docker/volumes/html/_data目录

ll /var/lib/docker/volumes/html/_data

可以看到nginx的html内容

在这里插入图片描述

index.html对应的就是nginx的欢迎文档

在这里插入图片描述

第5步,进入该目录,并随意修改index.html内容

cd /var/lib/docker/volumes/html/_data
vi index.html

第6步,打开页面,查看效果

在这里插入图片描述

第7步,将本地图片上传到宿主机的静态资源目录下

在这里插入图片描述

在这里插入图片描述

第7步,进入容器内部,查看/usr/share/nginx/html目录内的文件是否变化

docker exec -it nginx bash
cd /usr/share/nginx/html

在这里插入图片描述

这说明在宿主机内做的操作,容器内也就出现了。

案例二:本地挂载

之前学习了数据卷的知识,并且实现了容器目录与数据卷的挂载。在实际的应用中容器的挂载方式不止一种,通过案例学习其他的与容器挂载的方式。

在这里插入图片描述

在之前创建MySQL容器的时候,没有进行数据卷的挂载,因为当时没学-v参数。

之前已经在nginx中挂载了数据卷,可以通过命令查看。

docker inspect nginx

在这里插入图片描述

演示一下MySQL的匿名数据卷:

首先查看容器是否有挂载数据卷,可以通过inspect命令查看容器详情。

# 1.查看MySQL容器详细信息
docker inspect mysql
# 关注其中.Config.Volumes部分和.Mounts部分,Mounts就是挂载。

在这里插入图片描述

我们在创建Mysql容器的时候并没有指定数据卷,但是它本身就有一个数据卷,像这种不是我们创建的卷,是由容器运行自动创建的卷就是匿名卷。匿名卷的名字是自动生成的,/var/lib/mysql是数据存储的目录,因为mysql是一个数据库将来增删改查产生的数据就保存在这个目录下。

直接进入这个数据卷,这个数据卷中有非常多的文件,binlog文件是mysql做主从同步的。其中mysql文件中存放的是数据库中的表,sys中存放的是系统中的表。这里就是mysql的data目录,也就是数据存储的目录。

在这里插入图片描述

为什么mysql要将数据存储目录挂载到宿主机?因为mysql在运行的过程中不断产生数据,如果不做挂载的话这些数据都会保存在容器内的文件系统里。将来这个容器的体积将会越来越大,对容器做迁移也就很不方便,出于数据解耦的考虑就将这个存储目录挂载到宿主机中。只不过这种做法用的是匿名卷,匿名卷的名字是随机生成的,超级长。如果相对mysql的版本做升级,需要对旧的mysql容器删掉,创建新的容器。

删除旧的mysql容器:

docker rm -f mysql

在这里插入图片描述

删除之后数据卷还是存在,数据也就还存在,但是重新创建mysql新版本的容器的时候,生成卷的名字也就改变了。原来的数据在旧的数据卷里面,也就相当于丢失了。

所以不太建议使用匿名卷,最好自己实现挂载,也不需要挂载到volume中,因为会自动存放在/var/lib/docker/volumes目录中。可以挂载到任意目录下,建议在root目录下,将来操作的时候目录在哪会一目了然。

实现宿主机目录与mysql目录的挂载:

在这里插入图片描述

之前学的是数据卷的挂载,这种目录直接挂载也是通过-v参数来实现,不过之前是-v 数据卷名:容器内的目录,现在只需要使用-v 本地目录:容器内目录即可。注意直接以目录名开头会认为这是一个数据卷,会在/var/lib/docker/volumes中查找。但是以./或者/开头,都以为是一个目录,就可以去本地磁盘找。

这个需求不仅要求挂载mysql的数据目录,还需要挂载mysql的配置文件和初始化脚本。数据目录在/var/lib/mysql中,但是配置文件和初始化脚本就需要查找官方镜像文档,找到其位置。mysql的配置文件是放在/etc/mysql/conf.d中,只需要将自己的目录与这个目录挂载即可,将来把mysql的配置文件放到自己的目录下,就会自动出现在容器内。初始化脚本在第一次启动时生效,它会去执行一些sql的脚本,在容器内的/docker-entrypoint-initdb.d目录下。

在root目录下创建本地目录:

mkdir mysql
cd mysql/
mkdir data
mkdir conf
mkdir init

在这里插入图片描述

在这里插入图片描述

将配置文件和脚本放到创建好的本地目录里面。

通过网盘分享的文件:docker
链接: https://pan.baidu.com/s/15MYeRXnsGyH6zVjj68wzcg?pwd=be7i 提取码: be7i
–来自百度网盘超级会员v5的分享

在这里插入图片描述

在这里插入图片描述

检查mysql容器是否删除掉:

dps -a

在这里插入图片描述

将宿主机的本地目录挂载到容器内:

docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
-v /root/mysql/data:/var/lib/mysql \
-v /root/mysql/init:/docker-entrypoint-initdb.d \
-v /root/mysql/conf:/etc/mysql/conf.d \
mysql

在这里插入图片描述

查看data目录下内容:

在这里插入图片描述

说明数据目录成功挂载到宿主机中,同时还存在一个新的数据库hmall。里面很多表,这证明初始化脚本也成功执行了。说明挂载完全成功。

在这里插入图片描述

总结:

主要是容器的挂载还有第二种方式,就是基于本地目录直接挂载到容器内的目录。语法跟数据卷挂载类似,区别在于前面的不是数据卷而是目录。同时目录的名字要以./或者/开头,否则就会识别成数据卷。同时也不建议使用mysql的匿名卷,这种匿名卷挂载的位置太深了,而且不方便迁移,推荐挂载自己设定的目录,这样哪怕删掉mysql容器,将来再次运行mysql容器的时候所有的mysql数据还在,这就实现了数据的持久保存。

自定义镜像

前面使用的nginx和mysql的镜像,这两个镜像都是由官方制作上传的,我们下载下来就可以使用。将来自己开发完成Java应用去部署,也需要使用docker部署,也需要制作成镜像才可以,这就需要自定义镜像。

镜像结构

镜像就是一个文件包,里面包含了这个镜像应用程序本身还有这个应用程序运行所需要的环境系统函数配置等。构建镜像就是把这些文件找到,然后打包即可。

部署Java应用:

在企业中服务器一般都是Linux操作系统,首先得有一个Linux操作环境,接下来就需要在这个环境中安装好JREJVM运行环境)。紧接着就是将自己的jar包传上去,然后启动就部署成功了。

在这里插入图片描述

如果想要别人拿到自己的Java镜像直接可以运行,不需要上面的部署过程,只准备JREJar包是不行的。Java应用之所以可以跨系统运行确实因为JRE或者JVMJVM最终是会跟操作系统交互的,不同的操作系统使用的JVM也不一样。自己做镜像的时候也不知道将来部署的服务器用的是什么样的系统。所以不仅仅要准备JRE,还需要将JRE所依赖的系统也就是系统中的函数库也加进去,这样镜像就不依赖所部署的操作系统了。

比如准备的JRE是基于Ubuntu系统的,这就需要将JRE所依赖的Ubuntu系统的函数库拿过来。如果不知道Ubuntu版的JRE需要什么样的函数库,可以在制作Java镜像的时候,将整个Ubuntu的运行环境全拿过来。再将对应的JRE整合进去,配置好环境变量。再将Jar包整进去,编写一个运行的脚本。最后打成一个包,拿过去后直接执行脚本即可。

在这里插入图片描述

每一步制作镜像的过程都会产生一些文件,docker再去制作镜像的时候,不是将每一步产生的文件合并在一起打成一个包作为镜像。而是会把每一步操作产生的文件分别打成压缩包作为镜像的一部分,最终合在一起才是一个完整的镜像。

上述步骤中的每一次操作其实都是在生产一些文件(系统运行环境、函数库、配置最终都是磁盘文件),所以镜像就是一堆文件的集合。但需要注意的是,镜像文件不是随意堆放的,而是按照操作的步骤分层叠加而成,每一层形成的文件都会单独打包并标记一个唯一id,称为Layer)。之前在下载mysql和nginx的时候,下载产生的日志不是下载一个文件,它有好几行日志,其实也就是在分成下载。下载完成之后,需要将每层文件都解压,最后合并在一起才是真正完整的镜像。

制作镜像的时候都有一个类似的结构,首先有一个基础镜像,还有一个统一的入口,紧接着就是制作镜像过程中,操作产生的文件形成的层。只需要将每一层分别压缩打包,镜像就制作完成了。

在这里插入图片描述

docker为什么将这些镜像分层打包?首先在制作镜像的时候,我们可以将UbuntuJRE依赖的函数库单独拿出来,打成一个包,作为镜像直接上传到公共镜像仓库。接下来再去制作镜像的时候这样,就不需要再从0开始了,直接从原来制作好的基础Ubuntu镜像开始,这样就不需要重复挑函数库的操作了。这就是分层的好处,可以共享某些基础的层。第二个就是有这些基础镜像,以后很多镜像都可以共享前面的几层,这样下载的时候也就方便了。如果a镜像和b镜像的前两层是一样的,当去下载b镜像的时候,docker会先检查下前两层在本地有没有,如果一就可以不用下载,直接下载后面的即可。这样下载速度也会提升,本地存储文件的体积也会减少。

目前已经有nginx和mysql镜像,现在拉一个redis镜像:

docker pull redis

在下载redis的时候会有Already exists,这说明redis镜像分n层,其中的第一层跟前面下载的某一层一样,所以就省略了一次下载。

在这里插入图片描述

上面的操作有些复杂,首先需要找镜象,还需要将每一层压缩打包,这些操作如果个人去做比较困难。

Dockerfile

由于制作镜像的过程中,需要逐层处理和打包,比较复杂,所以Docker就提供了自动打包镜像的功能。我们根本不需要亲自动手做镜像,只需要描述清楚镜像的结构,入口是什么?基础是什么?中间有哪些层?docker就会自动帮助完成整个镜像的构建,如何告诉docker镜像结构?就需要通过Dockerfile。Dockerfile就是一个普通的文本文件,这个文件里面可以用一个个指令描述整个镜像的结构。docker就可以按照这些指令构建镜像。我们只需要将打包的过程,每一层要做的事情用固定的语法写下来,交给Docker去执行即可。

https://docs.docker.com/engine/reference/builder/

其中的语法比较多,比较常用的有:

指令说明示例
FROM指定基础镜像FROM centos:6
ENV设置环境变量,可在后面指令使用ENV key value
COPY拷贝本地文件到镜像的指定目录COPY ./xx.jar /tmp/app.jar
RUN执行Linux的shell命令,一般是安装过程的命令RUN yum install gcc
EXPOSE指定容器运行时监听的端口,是给镜像使用者看的。EXPOSE 8080
ENTRYPOINT镜像中应用的启动命令,容器运行时调用ENTRYPOINT java -jar xx.jar

EXPOSE 8080并不是将来使用镜像的人可以直接访问8080,还是需要通过-p做端口映射。这里只是描述,并不影响使用者需要做端口映射。

例如,要基于Ubuntu镜像来构建一个Java应用,其Dockerfile内容如下:

# 指定基础镜像
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 8080
# 入口,java项目的启动命令
ENTRYPOINT ["java", "-jar", "/app.jar"]

同学们思考一下:以后我们会有很多很多java项目需要打包为镜像,他们都需要Linux系统环境、JDK环境这两层,只有上面的3层不同(因为jar包不同)。如果每次制作java镜像都重复制作前两层镜像,是不是很麻烦。

所以,就有人提供了基础的系统加JDK环境,我们在此基础上制作java镜像,就可以省去JDK的配置了

在这里插入图片描述

# 基础镜像
FROM openjdk:11.0-jre-buster
# 拷贝jar包
COPY docker-demo.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]

只需要将jar包备份一下,每次构建新镜像的时候就只需要拷贝过去,jar包名字更改下即可,是不是简单多了。

构建镜像

利用Dockerfile构建java镜像非常简单,只需简单的几行命令就能搞定,只不过Dockerfile写完之后,怎么让docker帮我们去构建?这里就需要用一些命令,当Dockerfile写好了之后,可以用下面的命令来构建镜像。

docker build -t myImage:1.0 .

-t:是给镜像起名,格式依然是repository:tag的格式,不指定tag时,默认为latest

.: 是指定Dockerfile所在的目录,如果就是在当前目录,则指定为".",也就是docker build在指定运行的时候,是跟Dockerfile在同一个目录运行的。Dockerfile所在的位置要跟将来的文件是有关联的,因为前面有拷贝的动作,拷贝写的就是相对路径,就意味着jar包得跟Dockerfile在一块。

在下面的资料中有Dockerfile还有一个docker-demo.jar包。

通过网盘分享的文件:demo
链接: https://pan.baidu.com/s/11Ega-hiyJoB0cf3bevZeGQ?pwd=v4ws 提取码: v4ws
–来自百度网盘超级会员v5的分享

在这里插入图片描述

打开Dockerfile文件:

# 基础镜像
FROM openjdk:11.0-jre-buster
# 设定时区,如果不做就默认是中时区,而不是东八区,这样跟国内的时间有差距。
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包,将同目录下的docker-demo.jar拷贝到根目录的app.jar
COPY docker-demo.jar /app.jar
# 入口就是app.jar,就找到它去执行了。
ENTRYPOINT ["java", "-jar", "/app.jar"]

首先,我们将课前资料提供的docker-demo.jar包以及Dockerfile拷贝到虚拟机的/root/demo目录:

在这里插入图片描述

在下面资料中有jdk.tar的镜像,直接将其传到根目录下,省的下载花费很多时间。

通过网盘分享的文件:images
链接: https://pan.baidu.com/s/1vqr2R8AcsgzXfugINWKJEw?pwd=5nii 提取码: 5nii
–来自百度网盘超级会员v5的分享

在这里插入图片描述

对于准备好的tar包,如何将其变成自己的镜像,可以通过下面的命令来加载镜像。

docker load -i jdk.tar

在这里插入图片描述

查看镜像,发下openjdk已经加载成功了。

在这里插入图片描述

接下来需要进入到demo目录里面运行指令。

# 必须进入到Dockerfile所在的目录,这样写路径的时候省事。.就是指定Dockerfile所在的目录,如果后面没有指定文件名,那么Dockerfile名就得是Dockerfile才可以。
cd ./demo
docker build -t docker-demo .

在这里插入图片描述

第一步FROM基础镜像,第二步RUN配置时区,第三步COPY将jar包拷进去。入口就是一个脚本,将来直接运行就可以按照脚本运行。

通过dis查看,docker-demo已经变成一个镜像了,最新版本。

在这里插入图片描述

运行容器

java应用的端口号为8080:

docker run -d --name dd -p 8080:8080 docker-demo

通过docker ps查看运行状态:

在这里插入图片描述

发现docker-demo属于运行状态

通过docker logs查看日志后面跟上容器名dd。

docker logs -f dd

在这里插入图片描述

访问8080端口查看详情,提前定义好的一个路径/hello/count

在这里插入图片描述

这就说明自己可以给java应用构建镜像,并且部署了。

总结

镜像的结构是怎样的?

镜像的结构就是就是文件包,镜像中包含了应用程序所需的运行环境、函数库、配置以及应用本身等文件。但是这些文件不是在一个包里,是在构建镜像中逐层打包的,一般情况下会有一个入口和基础镜像。

Dockerfile是做什么的?

Dockerfile是用来帮助构建镜像的,镜像结构要分成打包比较麻烦,所以不用自己去构建。而是去利用Dockerfile中的指令去描述镜像的结构和构建过程,这样docker才能基于描述完成镜像的构建。

镜像构建的命令是什么?

镜像构建最后是基于Dockerfile,但是需要docker bulid -t 镜像名 Dockerfile目录。镜像名一般是名字:版本号,不指定版本号就是默认最新。一般情况下执行命令的目录就是Dockerfile当前所在目录,所以写个.即可。

网络

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

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

# 1.用基本命令,寻找Networks.bridge.IPAddress属性
docker inspect mysql

在这里插入图片描述

查看服务器dd容器的详细信息,查看其网络IP地址:

docker inspect dd

在这里插入图片描述

发现这两个容器的IP地址是相似的,都是172.17.0开始的,只有最后一位不同。说明这两个容器是在一个网段当中的,在一个网段当中意味着它们之间是可以相互访问的。容器都是相互隔离的空间,为什么还有相同的网段可以相互访问,这是因为它们都有相同的网关。

在安装Docker的时候,docker就会在虚拟机里面创建一张虚拟的网卡。这个网卡的名字默认是docker0,并且还会给这个网卡创建一个虚拟的网桥。所有与这个网桥连上的容器都会分配一个ip,ip的范围就是网桥的范围。

在这里插入图片描述

相当于各个容器虽然是独立空间,但是它们通过这个网桥建立了连接,因此它们之间可以相互访问。

连接服务器这个dd容器,进入bash控制台,通过ping命令访问mysql容器。

docker exec -it dd bashping 172.17.0.3

在这里插入图片描述

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

但是,这个ip地址是docker网桥分配的,假如这个服务重新启动,或者在重启的过程中其他容器也启动了,那么ip地址就可能会被其他人占用。容器的网络IP其实是一个虚拟的IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个IP,而在部署时很可能MySQL容器的IP会发生变化,连接会失败。

所以,我们必须借助于docker的自定义网络功能来解决这个问题,

查看当前虚拟机的网卡:

ip addr

在这里插入图片描述

默认情况下有两张网卡,lo和ens33网卡,虚拟机的真实ip地址是192.168.202.128/24。docker0网桥是docker一安装就有的,如果创建自定义网络就会形成一个新的网桥,而新的网桥是自定义的,其网段与docker0的是不一样的。如果自己的容器加入到自定义的网桥,那么加入到这个网桥的容器就能互联了。

加入自定义网络的容器可以通过新的网桥互联,也可以通过容器名互相访问,这样就无需知道对方的ip地址,只需要知道容器名即可。

官方文档:

https://docs.docker.com/engine/reference/commandline/network/

常见命令有:

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

第一步,首先查看所有的网络

docker network ls

在这里插入图片描述

第二步,创建自己的网桥,网桥名叫Charlie

docker network create Charlie

在这里插入图片描述

第三步,查看网桥信息

ip addr

在这里插入图片描述

发现除了docker0以外,出现了新的网卡172.18.0.1/16

第四步,让mysql容器加入到创建的网桥

docker network connect Charlie mysql

第五步,查看mysql容器

docker inspect mysql

在这里插入图片描述

发现mysql容器的network有两个,一个是默认网桥17网段,一个是新的网桥18网段。因为1是网关,所以ip地址从2开始递增。

第六步,创建容器并连接

上面是容器已经存在然后去连接创建的网桥,还可以让容器在创建的时候就连接。

# 删除容器
docker rm -f dd
# 创建启动容器,并连接网桥
docker run -d --name dd -p 8080:8080 --network Charlie docker-demo

在这里插入图片描述

会在创建容器的那一刻,直接加入网络,不需要后面添加。

第七步,查看dd容器

docker inspect dd

在这里插入图片描述

发现网络里只有Charlie,没有默认网桥docker0,就是因为在创建时指定就不会再加入默认,这样dd容器就跟默认网桥里的容器连不上了。

第八步,进入dd容器,连接nginx容器。

docker exec -it dd bash
ping mysql
ping nginx

在这里插入图片描述

通过自定义网络,将来就能非常方便的做容器间的相互访问,可以使用容器名。

项目部署

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

在网盘资料中已经提供了一个黑马商城项目:

通过网盘分享的文件:黑马商城
链接: https://pan.baidu.com/s/1GbTe43W79KboRn_l8syOeA?pwd=3yhq 提取码: 3yhq
–来自百度网盘超级会员v5的分享

项目说明:

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

部署的容器及端口说明:

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

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

docker rm -f nginx dd

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

部署Java项目

hmall项目是一个maven聚合项目,使用IDEA打开hmall项目,查看项目结构如图:

在这里插入图片描述

这个项目需要访问之前部署好的mysql数据库,数据库里面有很多的表,实现了商城的一些基础功能,商品表中有数万条的数据。因此,项目代码需要访问数据库,但是这个数据库是部署在虚拟机里docker内部。在真实项目部署的时候,数据库这样的容器不会对外做端口映射的,无法在外面访问。将来只能通过容器名去访问,将来JDBC的连接必须得按照容器名去配置。

在项目配置里,查看JDBC的连接参数:

在这里插入图片描述

可以发现连接的地址没有写死,$用于读取配置中的其他配置变量,这个地方的ip地址不是写死的,而是一个变量。因为要将其部署到虚拟机内,相当于一个公司内的整体开发环境,但是平常开发是在本地开发。本地开发和部署到开发环境之后的地址是不一样的,所以不能写死是动态的。变量地址取决于两个配置文件devlocal,dev放到开发环境之后的地址,local是本地开发时的配置。

查看application-dev.yaml

hm:db:host: mysqlpw: 123

配置的不是ip地址,而是容器名字。将来放在虚拟机里,用docker部署以后,用容器名与mysql容器互连,就没有任何问题。

查看application-local.yaml

hm:db:host: 192.168.150.101 # 修改为你自己的虚拟机IP地址pw: 123 # 修改为docker中的MySQL密码

这是本地开发时,需要写成一个真实的ip地址。

在项目中Dockerfile也已准备,直接将jar包准备好就能构建镜像。

# 基础镜像
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 hm-service.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]

我们将项目打包:

在这里插入图片描述

结果:

在这里插入图片描述

hm-service目录下的Dockerfilehm-service/target目录下的hm-service.jar一起上传到虚拟机的root目录:

在这里插入图片描述

部署项目:

构建项目:

# 1.构建项目镜像,不指定tag,则默认为latest
docker build -t hmall .

在这里插入图片描述

查看镜像:

# 2.查看镜像
docker images

在这里插入图片描述

查看正在运行的容器详情:

docker ps

在这里插入图片描述

发现已经有一个dd容器为8080端口,而hamll配置也是8080,这就会造成冲突。

删除dd容器:

docker rm -f dd

在这里插入图片描述

运行创建的hmall镜像:

要与mysql连接在一个网络里面,所以要在network中添加网络名Charlie。

docker run -d --name hm -p 8080:8080 --network Charlie hmall

在这里插入图片描述

查看刚创建的容器

docker ps

在这里插入图片描述

查看容器的日志:

docker logs -f hm

在这里插入图片描述

访问ip加controller中的接口:

http://你的虚拟机地址:8080/接口名

在这里插入图片描述

http://192.168.202.128:8080/hi

在这里插入图片描述

http://192.168.202.128:8080/search/list?pageNo=1&pageSize=5

在这里插入图片描述

这样证明服务已经部署成功,回到控制台也能看到输出的SQL语句。

总结:

部署Java项目需要做几件事?

  • 将项目打包,打包完成之后得到jar包

  • 将jar包与Dockerfile一起放到虚拟机里,利用命令docker build构建镜像。

  • 镜像构建完成之后,使用docekr run命令部署应用,可以添加network参数,与数据库放到同一网络段里面。

部署前端

hmall-portalhmall-admin是前端代码,需要基于nginx部署。在百度网盘资料中已经给了nginx

通过网盘分享的文件:nginx
链接: https://pan.baidu.com/s/1oUZl00IL4QLOBKe5e5J2vQ?pwd=7ehw 提取码: 7ehw
–来自百度网盘超级会员v5的分享

在这里插入图片描述

其中:

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

需要创建一个新的nginx容器,将nginx.confhtml目录与容器挂载。之前的nginx容器只挂载了html目录,没有挂载conf文件,所以没有办法对nginx的conf配置,因此需要创建一个新的容器,完成对于配置文件的挂载。

在html里包含了商城的前端页面hmall-portal以及后台管理页面hmall-admin,因此nginx需要对这两个目录做代理。

在这里插入图片描述

在nginx.conf中配置了对这两个目录的代理

server {# 服务监听了18080端口listen       18080;# 指定前端项目所在的位置location / {root /usr/share/nginx/html/hmall-portal;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}location /api {rewrite /api/(.*)  /$1 break;proxy_pass http://hm:8080;}}server {listen       18081;# 指定前端项目所在的位置location / {root /usr/share/nginx/html/hmall-admin;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}# 后端接口配置,前端向后端发送请求都发送给到了/api路径,这个路径最终要代理到后端的8080。location /api {rewrite /api/(.*)  /$1 break;proxy_pass http://hm:8080;}}

将来访问用户端就访问18080,管理端就访问18081。指向的前端地址/usr/share/nginx/html/是容器内的html,本地也有html文件,应该将本地的html文件与容器内html做挂载。一旦做了挂载,html下的两个文件就放到容器内了,将来反向代理就能找到这两个静态资源目录。

删除原有的nginx容器:

在这里插入图片描述

挂载nginx目录和conf文件:

之前学习了挂载html目录,现在需要挂载conf文件。

首先上传整个nginx目录到root目录下

在这里插入图片描述

查看官网可知-v 宿主机文件地址:/etc/nginx/nginx.conf,挂载命令如下:

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 Charlie \
nginx

在这里插入图片描述

访问18081端口号:

http://192.168.202.128:18081

在这里插入图片描述

输出日志:

docker logs -f hm

在这里插入图片描述

前端点击搜索,后端输出日志信息。

在这里插入图片描述

证明前后端和数据库这三个容器之间互联没有任何问题。

DockerCompose

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

  • MySQL
  • Nginx
  • Java项目

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

而Docker Compose就可以帮助我们实现多个相互关联的Docker容器的快速部署。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器。这样就可以统一管理相关的容器,可以直接将整个项目启用或停用。

一个docker-compose.yaml文件对应一个完整的项目,一个项目内部有很多部分组成,每一部分旧称之为服务。所以,docker-compose.yaml文件就是描述一个项目内多个服务的信息。

在这里插入图片描述

基本语法

docker-compose.yml文件的基本语法可以参考官方文档:

https://docs.docker.com/compose/compose-file/compose-file-v3/

docker-compose文件中可以定义多个相互关联的应用容器,每一个应用容器被称为一个服务(service)。由于service就是在定义某个应用的运行时参数,因此与docker run参数非常相似。

举例来说,用docker run部署MySQL的命令如下:

docker run -d \--name mysql \-p 3306:3306 \-e TZ=Asia/Shanghai \-e MYSQL_ROOT_PASSWORD=123 \-v ./mysql/data:/var/lib/mysql \-v ./mysql/conf:/etc/mysql/conf.d \-v ./mysql/init:/docker-entrypoint-initdb.d \--network hmallmysql

如果用docker-compose.yml文件来定义,就是这样:

version: "3.8"services:mysql:image: mysqlcontainer_name: mysqlports:- "3306:3306"environment:TZ: Asia/ShanghaiMYSQL_ROOT_PASSWORD: 123volumes:- "./mysql/conf:/etc/mysql/conf.d"- "./mysql/data:/var/lib/mysql"networks:- new
networks:new:name: hmall

对比如下:

docker run 参数docker compose 指令说明
–namecontainer_name容器名称
-pports端口映射
-eenvironment环境变量
-vvolumes数据卷配置
–networknetworks网络

明白了其中的对应关系,相信编写docker-compose文件应该难不倒大家。

黑马商城部署文件:

version: "3.8"services:mysql:image: mysqlcontainer_name: mysqlports:- "3306:3306"environment:TZ: Asia/ShanghaiMYSQL_ROOT_PASSWORD: 123volumes:- "./mysql/conf:/etc/mysql/conf.d"- "./mysql/data:/var/lib/mysql"- "./mysql/init:/docker-entrypoint-initdb.d"# 声明网络标识networks:- hm-net# 手动部署Java应用的时候,先要将jar包通过docker build构建成镜像,再去docker run。# docker-compose文件里,直接build,会在当前目录自动去找Dockerfile文件,接下来就可以基于Dockerfile描述的信息完成镜像构建# 这里将手动转jar包的动作替换了,镜像就已经存在了,不需要再添加image了。hmall:build: # 当前目录context: .dockerfile: Dockerfilecontainer_name: hmallports:- "8080:8080"networks:- hm-net# 这个项目依赖mysql,会先创建mysql再创建这个项目的容器。depends_on:- mysqlnginx:image: nginxcontainer_name: nginxports:- "18080:18080"- "18081:18081"volumes:- "./nginx/nginx.conf:/etc/nginx/nginx.conf"- "./nginx/html:/usr/share/nginx/html"depends_on:- hmallnetworks:- hm-net
# 之前都是手动创建网络,再将容器添加到对应的网络。在这里只需要告诉这些网络在一个标识hm-net里,然后声明这个网络。
# docker-compose会自动先去帮助创建网络,再去完成网络的连接。
networks:# 标识名hm-net:# 网络名name: Charlie

整个命令都是以相对路径写的,所以docker-compose文件应该与mysql目录、nginx目录、jar包和Dockerfile文件在一起。

在这里插入图片描述

注意在反向代理nginx中,后端的地址容器名为hm,在上面文件中项目容器的名字叫hmall,所以需要将hm改为hmall

在这里插入图片描述

基础命令

编写好docker-compose.yml文件,就可以部署项目了。常见的命令:

https://docs.docker.com/compose/reference/

基本语法如下:

docker compose [OPTIONS] [COMMAND]

其中,OPTIONS和COMMAND都是可选参数,比较常见的有:

类型参数或指令说明
Options-f指定compose文件的路径和名称,如果在当前目录下就可以不需要指定。
-p指定project名称,不需要一般默认就是root
Commandsup创建并启动所有service容器,就是一键启动
down停止并移除所有容器、网络
ps列出所有启动的容器,只查看与这个projrct有关的。
logs查看指定容器的日志
stop停止某一个容器
start启动某一个容器
restart重启某一个容器
top查看运行的进程
exec在指定的运行中容器中执行命令,进入某个容器。

删除之前部署的容器:

docker ps

在这里插入图片描述

docker rm -f nginx hm mysql
docker ps -a

在这里插入图片描述

删除之前部署的网络:

docker network rm -f Charlie

在这里插入图片描述

移除相关镜像:

dis
docker rmi hamll docker-demo
dis -a

在这里插入图片描述

一键部署:

加上-d,后台运行,否则一直在前台打印各种信息。

docker compose up -d

查看项目下的所有运行的容器:

docker compose ps

在这里插入图片描述

打开浏览器,访问:http://192.168.202.128:18080/

在这里插入图片描述

登录:账号名:jack 密码:123

在这里插入图片描述

一键删除:

docker compose down

在这里插入图片描述

查看容器和网络:

docker ps -a
docker network ls

在这里插入图片描述

DockerCompose不止可以做项目部署,还可以做集群部署。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com