五天SpringCloud计划——DAY2之使用Docker完成项目的部署
一、引言
刚刚学完了Docker的使用,现在知识在脑子里面还是热乎的,是时候把它总结一下了。
现在的我认为Docker时一个部署项目的工具(不知道是不是真的),相比于我以前使用宝塔面板部署项目,使用Docker更能让我看到代码之美,怎么一步步从繁琐到简单,怎么一步步的创建自己的镜像,并部署出去,不敢相信都是一行一行代码敲出来的。
下面我省去一些繁琐的方法,直接给大家讲一下我所学到的所有方法中最简单的方法
二、Docker部署项目前置知识
1.拉取和部署镜像
首先我们要学会使用Docker部署常见的数据库等,比如mysql,使用Docker去部署mysql异常的简单,你只需要在你的命令行运行下面的指令即可
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
mysql
如果你无法下载mysql镜像请阅读红色字
这里解释一下,其实我们部署MySQL是使用的仓库提供好的mysql镜像,我们只需要部署了这个镜像就可以部署一个mysql数据库,而mysql所在的官方仓库已经关闭了,所以我们要使用阿里云的镜像库,我们只需要运行下面的命令即可
# 创建目录
mkdir -p /etc/docker
# 复制内容
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"http://hub-mirror.c.163.com",
"https://mirrors.tuna.tsinghua.edu.cn",
"http://mirrors.sohu.com",
"https://ustc-edu-cn.mirror.aliyuncs.com",
"https://ccr.ccs.tencentyun.com",
"https://docker.m.daocloud.io",
"https://docker.awsl9527.cn"
]
}
EOF
# 重新加载配置
systemctl daemon-reload
# 重启Docker
systemctl restart docker
注意其中的"https://ustc-edu-cn.mirror.aliyuncs.com",要改为你自己的阿里云加速地址,详细说明见
安装Docker - 飞书云文档 (feishu.cn)
这里给大家解释一下,为什么这个镜像的下载部署要使用这一段代码——
应为是打包这个镜像的人要求的
下面是一些解读
解读:
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
: 设置镜像名称,Docker会根据这个名字搜索并下载镜像
格式:
REPOSITORY:TAG
,例如mysql:8.0
,其中REPOSITORY
可以理解为镜像名,TAG
是版本号在未指定
TAG
的情况下,默认是最新版本,也就是mysql:latest
其实很好理解
这个就是下载并且部署镜像,你可以在部署完mysql之后在自己的电脑上连接一下,是可以连接成功的
其实我们部署项目也是部署的镜像,只不过这个镜像是我们自定义的镜像
所以部署项目的过程,就是我们自定义镜像的过程
2.数据卷
我们部署的每一个镜像都会在我们的虚拟机中生成一个新的容器,我们可以把这个容器想象成一个新的小的服务器,它有自己的ip,有自己的文件,我们可以使用以下指令进入这个容器
docker exec -it nginx bash
但是你进入这个容器之后并不能去修改其中的文件,因为这个容器并没有提供像“vi”这种指令,所以我们如何修改这个容器里面的内容就成了一个新的问题,比如我们要在mysql容器中加入我们自己写的.sql文件,我们该怎么办呢
数据卷就帮我们解决了这个问题
我们可以把数据卷想象成一种哲学意义上的联系,它可以将你容器里面的文件和你虚拟机里面对应的文件产生一种联系,当你修改虚拟机里对应的文件之后,容器里面的文件会相应改变,就像vue中的数据双向绑定,这样我们就可以通过修改虚拟机里相应文件而达到修改容器内文件的目的
那么具体怎么操作呢
命令 | 说明 | 文档地址 |
---|---|---|
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 run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx
其中的-v html:/usr/share/nginx/html,便是将nginx中存储html的文件联系在了虚拟机上的/var/lib/docker/volumes/html/_data目录下,其中/var/lib/docker/volumes/是固定的,这样我们只需要把想放在容器/usr/share/nginx/html目录下的文件放在/var/lib/docker/volumes/html/_data目录下了,这样就可以部署前端项目了!
这里有一个问题,我们部署的mysql镜像有相应的数据卷吗,我们可以用下面的指令查看一下
docker inspect mysql
之后何以看到下面的一部分
{
"Mounts": [
{
"Type": "volume",
"Name": "29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f",
"Source": "/var/lib/docker/volumes/29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
}
]
}
/var/lib/docker/volumes/29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f/_data这个目录便是mysql容器/var/lib/mysql目录对应的虚拟机上的对应的目录,可以发现我们在拉取mysql镜像时,是会生成随机名称的匿名数据卷的,这时我们就不得不考虑一个问题了:
如果以后我们要升级mysql版本,将这个低版本mysql镜像卸载了,又从新下载了一个mysql的镜像,他会随机又生成一个匿名数据卷,但是我们之前的数据还在原来的某个匿名数据卷里面,数据并不能继承下来,这样非常的不方便
所以,为了解决它,我们可以直接将容器目录与宿主机指定目录挂载
代码如下
# 1.删除原来的MySQL容器
docker rm -f mysql
# 2.进入root目录
cd ~
# 3.创建并运行新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 \
mysql
这样我们就可以将mysql容器的内部文件和我们创建的目录挂载了,这样的话以后我们就算重新下载了一个mysql镜像,我们的sql数据也不会消失
3.自定义镜像
接下来我们尝试把自己的一个后端项目构建成镜像部署出去
首先了解一下我们所要构建的后端项目镜像的结构包括什么
1.基础环境 linux
2.依赖 jdk
3.应用本身 jar
4.运行配置 运行脚本
没错,这些我们自定义的镜像都需要,甚至需要一个linux系统
我们要将这些东西放在记录镜像结构的文件中,这种文件就称为Dockerfile,大概是下面的内容
# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录、容器内时区
ENV JAVA_DIR=/usr/local
ENV TZ=Asia/Shanghai
# 拷贝jdk和java项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar
# 设定时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 安装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"]
这个是不是非常复杂,其实已经有人帮我们封装很多了
比如我们可以下载一个openjdk:11.0-jre-buster
之后我们的
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包
COPY docker-demo.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]
我们现在只需要将我们的后端项目jar包和Dockerfile文件放在一起就可以部署镜像了
cd到它们所在的目录
像这样
# 进入镜像目录
cd /root/demo
# 开始构建
docker build -t docker-demo:1.0 .
便可以部署我们的自定义镜像了
docker build
: 就是构建一个docker镜像
-t docker-demo:1.0
:-t
参数是指定镜像的名称(repository
和tag
)
.
: 最后的点是指构建时Dockerfile所在路径,由于我们进入了demo目录,所以指定的是.
代表当前目录
4.网络问题
这里再提一个网络的问题
容器间的互联需要在同一个网络之下,默认拉取的镜像也是在同一个网络下的,但是这里建议新建一个网络去部署我们的项目,以便于容器的ip不易改变
常见命令有:
命令 | 说明 | 文档地址 |
---|---|---|
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 |
# 1.首先通过命令创建一个网络
docker network create hmall
# 2.然后查看网络
docker network ls
# 结果:
NETWORK ID NAME DRIVER SCOPE
639bc44d0a87 bridge bridge local
403f16ec62a2 hmall bridge local
0dc0f72a0fbb host host local
cd8d3e8df47b none null local
# 其中,除了hmall以外,其它都是默认的网络
# 3.让dd和mysql都加入该网络,注意,在加入网络时可以通过--alias给容器起别名
# 这样该网络内的其它容器可以用别名互相访问!
# 3.1.mysql容器,指定别名为db,另外每一个容器都有一个别名是容器名
docker network connect hmall mysql --alias db
# 3.2.db容器,也就是我们的java项目
docker network connect hmall dd
# 4.进入dd容器,尝试利用别名访问db
# 4.1.进入容器
docker exec -it dd bash
# 4.2.用db别名访问
ping db
# 结果
PING db (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=2 ttl=64 time=0.056 ms
# 4.3.用容器名访问
ping mysql
# 结果:
PING mysql (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=2 ttl=64 time=0.054 ms
三、Docker部署前端项目
接下来我们部署一个前端项目
首先将你的前端项目文件拷贝到虚拟机上
然后要拉取nginx镜像,并配置相应的数据卷,以及其所在的网络
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
接着,我们将前端的项目文件导入相应的文件中
测试时,可访问:http://你的虚拟机ip:18080
四、Docker部署后端端项目
先将你的后端项目的数据库配置改为你所在虚拟机上部署的mysql数据库
之后将相应的jar包和Dockerfile放在对应的目录下,然后运行命令
docker build -t hmall .
五、DockerCompose的使用
通过前文的学习我们可以在虚拟机上部署一个前后端分离的项目,但是这个项目时分散的,我们需要分别部署数据库,nginx,前端工程,后端工程,会显得项目部署杂乱无章
为了解决这个问题,我们引入一个新的文件
DockerCompose.yml
在这个文件中我们可以意见部署我们项目所需要的全部容器
我们只需要将部署项目所需要的文件放在同一级目录之下,然后再在该目录加入DockerCompose.yml文件
version: "3.8"
services:
mysql:
image: mysql
container_name: mysql
ports:
- "3306:3306"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 123
volumes:
- "./mysql/conf:/etc/mysql/conf.d"
- "./mysql/data:/var/lib/mysql"
- "./mysql/init:/docker-entrypoint-initdb.d"
networks:
- hm-net
hmall:
build:
context: .
dockerfile: Dockerfile
container_name: hmall
ports:
- "8080:8080"
networks:
- hm-net
depends_on:
- mysql
nginx:
image: nginx
container_name: nginx
ports:
- "18080:18080"
- "18081:18081"
volumes:
- "./nginx/nginx.conf:/etc/nginx/nginx.conf"
- "./nginx/html:/usr/share/nginx/html"
depends_on:
- hmall
networks:
- hm-net
networks:
hm-net:
name: hmall
下面是对上面部分代码的解释
docker run 参数 | docker compose 指令 | 说明 |
---|---|---|
--name | container_name | 容器名称 |
-p | ports | 端口映射 |
-e | environment | 环境变量 |
-v | volumes | 数据卷配置 |
--network | networks | 网络 |
然后运行
docker compose up -d
即可一键部署,非常的方便
下面时另外一些常用的命令
docker compose [OPTIONS] [COMMAND]
类型 | 参数或指令 | 说明 |
---|---|---|
Options | -f | 指定compose文件的路径和名称 |
-p | 指定project名称。project就是当前compose文件中设置的多个service的集合,是逻辑概念 | |
Commands | up | 创建并启动所有service容器 |
down | 停止并移除所有容器、网络 | |
ps | 列出所有启动的容器 | |
logs | 查看指定容器的日志 | |
stop | 停止容器 | |
start | 启动容器 | |
restart | 重启容器 | |
top | 查看运行的进程 | |
exec | 在指定的运行中容器中执行命令 |
六、结语
今天觉得依旧完不成既定的任务,虽然学了一整天,晚上的话,我的继续学习微服务,看看今天可以继续学多少吧