1.前言

在上一篇笔记 Docker基本概念与安装 中,我们已经获取到了一个Docker服务,并了解了Docker的基本组成及其各个组件的作用。
我们了解到,使用Docker的其中一个目的,是为了更加简单,方便的部署我们编写的服务,接下来,就以发布一个SpringBoot的服务为例,来学习部署服务需要是用到的API指令。

2.准备工作

首先,需要准备一个Springboot的项目,这里准备一个简单的 Hello World 工程:

@RestController@RequestMapping("hello")public class HelloController {    @GetMapping("sayHello")    public String sayHello(String name) {        return "hello " + name;    }}

提供一个GET请求的接口,在请求参数中输入什么就返回什么,这里不过多的赘述。
接下来,需要使用MavenGradle打包工具,将这个服务打成jar包,我这里使用的是Gradle,打包完成之后在build目录中就可以找到一个可运行的jar包。

由于我的Docker是安装在虚拟机中的,所以我还需要将这个jar拷贝到我的虚拟机中完成Docker镜像的构建,如果Docker是直接安装在当前系统中的话,后续的操作在当前系统中就可以完成了。

此处使用Xftp将生成的jar包拷贝到了虚拟机的/user/hello-boot下,接下来的操作都在这里面完成。

3.Docker镜像构建

下一步就是将刚刚生成的jar包构建成可供Docker运行的image文件,这一步需要使用到两个知识点:

  • docker build指令
  • Dockerfile文件

3.1.docker build

docker build指令的作用,是解析Dockerfile文件中的的脚本,把可执行文件(如上面的jar包)打包到Docker镜像文件中,这个镜像文件可以在后续使用docker run时,按照Dockerfile文件中的脚本,执行相应的操作。简单的说,就是构建出docker的可执行文件。

先看构建语法:

docker build [OPTIONS] PATH | URL | -
  • [OPTIONS] 是执行build时的可选项,常用是有-t-f

    • -t:给构建的镜像打一个tag标签
    • -f:指定本次构建使用到的Dockerfile文件路径,默认值为Dockerfile

    其他先选项可以参考: docker build options

  • PATH 与 URL 是当前构建操作的context,它可以是一个文件路径(PATH),也可以是远程地址(URL),构建时需要引用的文件就应该放在context中,例如刚刚生成的jar包。


综上,可以进入jar包所在的文件目录,输入构建指令:

cd /usr/hello-boot/docker build -t hello-boot:1.0.0 -f ./Dockerfile .

我们知道默认使用的就是当前路径下的Dockerfile,所以构建指令可以简化为:

docker build -t hello-boot:1.0.0 .

指令中最后那个.就是上述语法中的 PATH ,在这里的含义就是执行当前目录为构建的context

现在我们得到了一个完整的构建指令,但是仔细观察一下这个指令,会发现其中还缺少处理jar包的指令,思考一下,这个指令会在什么位置呢?

3.2.DockerFile

Dockerfile 是一个脚本文件,里面定义了context的各种操作指令,以生成SpringBoot镜像为例:

FROM openjdk:8-alpine3.9MAINTAINER huizhiyimoRUN mkdir -p /user/my-demoCOPY ./*.jar /user/my-demoWORKDIR /user/my-demoEXPOSE 8080ENTRYPOINT java -Xms256m -Xmx256m -jar -Dspring.profiles.active=${SPRING_PROFILES_ACTIVE} *.jar
  • FROM:指定基础镜像,也就是当前需要构建的镜像是哪一个镜像的基础上做构建的,当前指定在openjdk:8-alpine3.9上构建。
  • MAINTAINER:作者信息,类似于@author
  • RUN:在容器中运行指令,此处是创建文件夹 /user/my-demo
  • COPY:将宿主机context中的jar,复制到容器中的/user/my-demo
  • WORKDIR:指定容器中的工作目录,类似于cd /user/my-demo
  • EXPOSE:应用程序暴露的默认端口
  • ENTRYPOINT:应用程序切入点,在启动容器时运行,在这里定义启动SpringBoot服务

Docker的镜像是像集装箱那样一层一层往上搭建的,通过 FROM 指令可以实现下图的分层效果:

FROM后面的镜像会先从本地的镜像仓库中寻找,如果本地没有就会从 DockerHub 中寻找,此处的openjdk:8-alpine3.9是一个带有Java运行环境的轻量级服务器,在DockerHub中找到这个镜像,打开IMAGE LAYERS就能大概知道这个镜像会怎么运行,如下图红框中的内容。

显然,通过这个镜像我们就可以得到一个Java的运行环境,以此为基础来运行SpringBoot的服务就是顺理成章的事情了。

3.3.镜像构建

将编写好的DockerFile与jar包放在同一目录下,执行构建指令:

docker build -t hello-boot:1.0.0 .

提示构建成功,此时再运行查看镜像的指令,就可以看到刚才通过FROM下载的openjdk镜像与hello-boot镜像:

docker images

如果构建的镜像有问题,可以通过删除镜像指令删掉再重新构建:

docker rmi [name:tag]docker rmi hello-boot:1.0.0

4.运行镜像

通过docker run指令可以将镜像运行起来:

docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=test --restart=always --name=hello-1 hello-boot:1.0.0
  • -d: 后台运行程序
  • -p:指定端口映射,左边的是宿主机端口,右边的是容器中的应用端口,与-d可以合并为-dp
  • -e: 指定环境变量,此处是指定profiles为test(在Dockerfile的ENTRYPOINT中定义的变量)
  • --restart=always:启动docker容器时,自动运行
  • --name:指定运行容器的名称
  • hello-boot:1.0.0:指定镜像名称与tag标签

运行起来之后,可以通过docker ps查看:

此时容器已经正常启动了,通过curl指令来测试一下是否启动成功:

curl "http://127.0.0.1:8080/hello/sayHello" />

至此,SpringBoot服务就通过Docker发布成功了,如果想停止这个服务,可以使用下面的指令:

# 停止容器,hello-1为容器名docker stop hello-1# 删除容器docker rm hello -1

注:如果项目迭代到了下一个版本,要发布新的服务,就需要执行上面的两个指令删除旧的容器,再通过新构建的镜像来运行新的容器。

5.指令参考

Docker的运行指令可以参考 官方指令教程

6.结语

本篇通过打包、构建镜像、运行容器、停止容器、删除容器的过程,学习了Docker的基本指令:

  • docker build:构建镜像
  • docker images:查看本地镜像
  • docker rmi:删除镜像
  • docker run:运行容器
  • docker ps:查看容器
  • docker stop:停止容器
  • docker rm:删除容器

一些思考
本篇描述的Docker使用方式,相对于传统的服务发布方式并没有太大的优势,不管是发布新服务,还是对服务进行扩展都需要按照流程重新构建镜像。
这是由于没有做到镜像的共享与复用导致的,在后续的笔记中,会接受如何通过远程镜像仓库来复用镜像来提升部署的效率。