前言

简单的学习下怎么在 Spring Boot 中使用 Docker 进行构建,发布一个镜像,现在我们通过远程的 docker api 构建镜像,运行容器,发布镜像等操作。

这里只介绍两种方式:

  1. 远程命令 api (需要知道 Docker 命令)
  2. maven 插件 (不需要了解 Docker 命令)

开启 Docker api 远程访问

开启 docker api 远程操作的功能,

例如,centos 7 中在 /usr/lib/systemd/system/docker.service,文件中,修改 ExecStart 的参数:

ExecStart=/usr/bin/dockerd  -H tcp://0.0.0.0:2375  -H unix:///var/run/docker.sock

端口自定义设置即可。

重载所有修改过的配置文件,并且重启 docker,

systemctl daemon-reload
systemctl restart docker.service

需要注意的是,由于没有密码登陆任何权限验证,外网或者生产环境需要上证书使用。

命令方式构建镜像

这种方式其实非常简单,就是需要懂得 docker 命令,才能操作。

经过上面开启 Docker Api 后,我们可以使用网络环境操作 Docker 引擎了。

  1. 新建 Dockerfile 构建镜像文件,新创建一个文件夹,专门放构建镜像需要的文件,我创建的是 /src/docker/

    FROM java:8
    EXPOSE 8080 VOLUME /tmp
    ADD springboot-docker.jar app.jar
    ENTRYPOINT ["java","-jar","/app.jar"]
  2. 执行 maven 命令 ,将项目打包 mvn clean package --DskipTests,然后将打好的 jar 包,也放入到 Dockerfile项目目录中。

  3. 然后进入 src/docker 目录下执行 :

    docker -H tcp://xxx.xxx.xxx.xxx:2375 build -t test .

    开始构建镜像:

    Sending build context to Docker daemon  31.74MB
    Step 1/5 : FROM java:8
    ---> d23bdf5b1b1b
    Step 2/5 : EXPOSE 8080
    ---> Using cache
    ---> 060a43a42146
    Step 3/5 : VOLUME /tmp
    ---> Using cache
    ---> b4f88fde6181
    Step 4/5 : ADD springboot-docker.jar app.jar
    ---> 3a40188825b0
    Step 5/5 : ENTRYPOINT ["java","-jar","/app.jar"]
    ---> Running in ab093916fc4c
    Removing intermediate container ab093916fc4c
    ---> 45a3966feb60
    Successfully built 45a3966feb60
    Successfully tagged test:latest

使用 docker-maven-plugin构建镜像

在 maven 项目下加入 docker-maven-plugin

            <!--打包docker插件相关参数的配置-->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.14</version>
<configuration>
<!--打包的镜像名-->
<imageName>${project.groupId}/${project.artifactId}</imageName>
<!--Dockerfile文件位置,以项目的 root 目录为根节点,建议到单独建立一个目录-->
<dockerDirectory>./src/docker/</dockerDirectory>
<!--Docker 远程的 API 地址及端口-->
<dockerHost>http://xxx.xxx.xxx.199:2375</dockerHost>
<imageTags>
<imageTag>latest</imageTag>
</imageTags>
<!--执行构建docker镜像的时候需要哪些文件,springboot项目指定 打包好的jar 镜像就好-->
<resources>
<resource>
<!--这里指定的文件是target中的jar文件-->
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>

创建 Dockerfile

需要跟pom.xml 上面配置的路径保持一致,所以我的路径是 ${baseProjectFolder}/src/docker的文件夹下新建一个文件 Dockerfile,添加构建 docker 相关命令参数:

FROM java:8
EXPOSE 8080 VOLUME /tmp
ADD springboot-docker.jar app.jar # 根据打包的jar 包文件名进行修改
ENTRYPOINT ["java","-jar","/app.jar"]

打包

在应用的根目录下执行命令(打包加 dokcer build):

$ mvn clean package docker:build -DskipTests

比如使用我的工程,进行打包后完成了 docker 的构建的信息:

[INFO] Building image com.wuwii/springboot-docker
Step 1/5 : FROM java:8 ---> d23bdf5b1b1b
Step 2/5 : EXPOSE 8080 ---> Running in b7936baae57f
Removing intermediate container b7936baae57f
---> 060a43a42146
Step 3/5 : VOLUME /tmp ---> Running in 65e2b8ac44d3
Removing intermediate container 65e2b8ac44d3
---> b4f88fde6181
Step 4/5 : ADD springboot-docker.jar app.jar ---> aa3762cda143
Step 5/5 : ENTRYPOINT ["java","-jar","/app.jar"] ---> Running in d9f5f63b9736
Removing intermediate container d9f5f63b9736
---> 622a7d1e315c
ProgressMessage{id=null, status=null, stream=null, error=null, progress=null, progressDetail=null}
Successfully built 622a7d1e315c
Successfully tagged com.wuwii/springboot-docker:latest

使用镜像

  1. 进入安装 docker 的主机中,使用命令查看镜像(IMAGE ID 和上面是一致的):

    $ docker image ls com.wuwii/springboot-docker
    REPOSITORY TAG IMAGE ID CREATED SIZE
    com.wuwii/springboot-docker latest 622a7d1e315c 22 minutes ago 659MB
  2. 运行容器:

    $ docker run -d -p 8080:8080 --name learn  com.wuwii/springboot-docker
    
    180fe4a7ddfc10c0cf2c37649ae1628e804564bfe1594ef05840e707801e6da3

    监听 8080 端口,测试是否成功。

服务编排 compose

一般的我们的 WEB 项目会使用到很多外部工具,例如 Redis ,MYSQL, ES等,如果一个一个启动搭建部署,太麻烦了,还要测试如果把这个一套环境拿到别的地方还能用吗?

使用服务编排可以避免这些坑。

加入我们的项目中增加了 Mysql 的数据库,在根目录新建一个 docker-compose.yml

version: '3'
services:
web:
depends_on:
- db
ports:
- "8080:8080" # 建议加上引号,如果单独两位数的数字,可能出现解析问题
restart: always
# build:
# context: ./src/docker # Dockerfile 文件的目录,可以远程地址,绝对 or 相对
# dockerfile: Dockerfile # 如果你的 Dockerfile 重命名了,需要指定
image: test:latest
environment:
DB_HOST: db:3306
DATABASE: learn
DB_USERNAME: root # 测试用下 root
DB_PASSWORD: 123456 # # 建议使用 secret db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: learn
MYSQL_USER: kronchan
MYSQL_PASSWORD: 123456 volumes:
db_data: # 使用的数据卷必须声明

上面我使用的是前面已经构建好的镜像,然后执行的编排,更好的是直接使用 build 让它自己编排服务。

系统配置文件application.yml使用缺省值的方式,不影响开发的使用:

spring:
datasource:
url: jdbc:mysql://${DB_HOST:localhost:3306}/${DATABASE:learn}?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8
username: ${DB_USERNAME:root}
password: ${DB_PASSWORD:123456}
driver-class-name: com.mysql.jdbc.Driver
jpa:
show-sql: true
database: mysql
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL57Dialect # 方言根据 数据库版本选择吧

也可以使用不同的 spring.profiles指定不同的环境,在 docker-compose.yml 中覆盖执行命令指定环境也是常见做法的:command: mvn clean spring-boot:run -Dspring-boot.run.profiles=xxx

最后启动,在 docker-compose.yml目录下执行 : docker-compose up

关闭服务 docker-compose down

注意

docker-compose 顺序的问题,这个是开始学习编排的时候需要注意的问题,如果上面的服务编排中 mysql 启动的慢, web 项目就会启动失败,它启动的时候不知道被依赖的服务是否启动完成,就会出现这样的问题。

解决的办法有以下几种:

  • 足够的容错和重试机制,比如连接数据库,在初次连接不上的时候,服务消费者可以不断重试,直到连接上位置
  • docker-compose拆分,分成两部分部署,将要先启动的服务放在一个docker-compose中,后启动的服务放在两一个docker-compose中,启动两次,两者使用同一个网络。
  • 同步等待,使用wait-for-it.sh或者其他shell脚本将当前服务启动阻塞,直到被依赖的服务加载完毕

    wait-for-it的github地址为:wait-for-it

总结

  1. 主要是写 Dockerfile 的时候最好单独的拿出一个文件夹来放它,我开始的时候就是直接放在项目的根路径,结果构建镜像的时候总是出现了将其他的文件也一起复制到了 Docker 目录中,WINDOW下使用 maven 插件操作这个需要注意这个上下文环境,不然很容易将一个磁盘的文件都拷贝进来了,初学者血的教训。解决办法就是单独创建一个文件夹,将需要的东西单独放置,就不用考虑这么多问题。

代码

学习Spring Boot:(二十三)Spring Boot 中使用 Docker的更多相关文章

  1. Spring Boot(二):Spring Boot中的配置参数

    Spring Boot 配置参数 Spring Boot 帮助我们完成了许许多多的自动化配置 如果我们需要根据自己的需求修改配置 也是可以的 可以使用.properties 和 .yml 格式配置 这 ...

  2. spring学习笔记(二)spring中的事件及多线程

    我们知道,在实际开发中为了解耦,或者提高用户体验,都会采用到异步的方式.这里举个简单的例子,在用户注册的sh时候,一般我们都会要求手机验证码验证,邮箱验证,而这都依赖于第三方.这种情况下,我们一般会通 ...

  3. Spring学习进阶(二)Spring IoC

    在使用Spring所提供的各种丰富而神奇的功能之前,必须在Spring IoC容器中装配好Bean,并建立Bean与Bean之间的关联关系.控制反转(Inverser of Control ioc)是 ...

  4. Spring(二)--Spring入门案例

    Spring入门案例 1.需要的实体类 2.需要的接口和实现类 3.需要的service和实现类 /** * service层的作用 * 在不改变dao层代码的前提下,增加业务逻辑操作 */ publ ...

  5. Docker学习笔记之在 Windows 和 Mac 中使用 Docker

    0x00 概述 对于开发来说,Windows 和 macOS 是更为常见和常用的系统,所以也很有必要了解在 Windows 和 macOS 中使用 Docker 的方法.很幸运的是,Docker 的官 ...

  6. Spring学习笔记(二)Spring基础AOP、IOC

    Spring AOP 1. 代理模式 1.1. 静态代理 程序中经常需要为某些动作或事件作下记录,以便在事后检测或作为排错的依据,先看一个简单的例子: import java.util.logging ...

  7. Spring学习笔记(二)——Spring相关配置&属性注入&Junit整合

    一.Spring的相关配置 1.1 Bean元素 class属性:被管理对象的完整类名 name属性:给Bean起个名字,能重复,能使用特殊字符.后来属性 id属性:给Bean起个名字,不能重复,不能 ...

  8. Spring(二十三):Spring自动注入的实现方式

    注解注入顾名思义就是通过注解来实现注入,Spring和注入相关的常见注解包含:Autowrired/Resource/Qualifier/Service/Controller/Repository/C ...

  9. Hadoop学习之路(二十三)MapReduce中的shuffle详解

    概述 1.MapReduce 中,mapper 阶段处理的数据如何传递给 reducer 阶段,是 MapReduce 框架中 最关键的一个流程,这个流程就叫 Shuffle 2.Shuffle: 数 ...

  10. Spring Cloud(二):Spring Cloud Eureka Server高可用注册服务中心的配置

    前言 Eureka 作为一个云端负载均衡,本身是一个基于REST的服务,在 Spring Cloud 中用于发现和注册服务. 那么当成千上万个微服务注册到Eureka Server中的时候,Eurek ...

随机推荐

  1. 解决PowerDesigner 16 Generate Datebase For Sql2005/2008 对象名sysproperties无效的问题

    在PowerDesigner 16 中生成的sql语句,在执行的时候报错:对象名sysproperties 无效的错误;造成此问题的原因是由于Sql 2005.2008 删除了系统表 sysprope ...

  2. Luogu P4211 [LNOI2014]LCA

    我去这道题的Luogu评级是假的吧,这都算黑题. 我们首先考虑把操作离线不强制在线的题目离线一下一般都要方便些 考虑差分,我们用\(f(x)\)表示\([1,x]\)之间的点与\(z\)的答案,那么显 ...

  3. [python][spark]wholeTextFiles 读入多个文件的例子

    $pwd /home/training/mydir $cat file1.json {"firstName":"Fred", "lastName&qu ...

  4. [Codeforces1137D]Cooperative Game

    [Codeforces1137D]Cooperative Game Tags:题解 题意 这是一道交互题. 给你一张下面这样的地图,由一条长为\(t\)的有向链和一个长为\(c\)的环构成. 现在你有 ...

  5. Ionic 2 中生命周期的命名改变及说明

    原文发表于我的技术博客 本文简要整理了在 Ionic 2 的版本中生命周期命名的改变,以及各个事件的解释. 原文发表于我的技术博客 在之前的课程中讲解了 Ionic 生命周期的命名以及使用,不过在 I ...

  6. 解密自动CPS变换

    7.2 1 前言 我最一开始听到 CPS 变换这个词是在王垠的博客里 (请求不要喷我),就是那篇他第一次宣传他的40行代码的文章. 我当时什么都看不懂,所以没太注意,不过我也正在学程序语言方面的东西, ...

  7. Linux下批量ping某个网段ip的脚本

    比如现在需要对172.16.50.0/24网段的ip进行检查,检查哪些ip现在被占用,哪些ip没有被占用,可以通过ping命令来检查,脚本如下: [root@uatdns01 opt]# vim /o ...

  8. Python-集合-17

    ''' 集合:可变的数据类型,他里面的元素必须是不可变的数据类型,无序,不重复. {} ''' set1 = set({1,2,3}) # set2 = {1,2,3,[2,3],{'name':'a ...

  9. Linux大棚命令记录

    查看系统支持的shell: cat  /etc/shells 查看当前系统用的shell: echo $SHELL 从bash切换到zsh: 先yum安装,然后 chsh -s /bin/zsh ,退 ...

  10. 个人博客作业Week2(9月30日)

    一.是否需要有代码规范 1.这些规范都是官僚制度下产生的浪费大家的编程时间.影响人们开发效率, 浪费时间的东西. 这些规范并不是一开始就有的,也不是由某个人规定的,代码规范是程序员们在不断地编程实践过 ...