五天SpringCloud计划——DAY2之使用Docker完成项目的部署

66 阅读13分钟

一、引言

刚刚学完了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

注意其中的"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参数是指定镜像的名称(repositorytag
  • . : 最后的点是指构建时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 指令说明
--namecontainer_name容器名称
-pports端口映射
-eenvironment环境变量
-vvolumes数据卷配置
--networknetworks网络

 然后运行

docker compose up -d

即可一键部署,非常的方便

下面时另外一些常用的命令 

docker compose [OPTIONS] [COMMAND]

类型参数或指令说明
Options-f指定compose文件的路径和名称
-p指定project名称。project就是当前compose文件中设置的多个service的集合,是逻辑概念
Commandsup创建并启动所有service容器
down停止并移除所有容器、网络
ps列出所有启动的容器
logs查看指定容器的日志
stop停止容器
start启动容器
restart重启容器
top查看运行的进程
exec在指定的运行中容器中执行命令

六、结语

今天觉得依旧完不成既定的任务,虽然学了一整天,晚上的话,我的继续学习微服务,看看今天可以继续学多少吧