使用 Docker 构建、运行、发布一个 Spring Boot 应用

2019 年 5 月 31 日 0 条评论 1.59k 次阅读 1 人点赞

本文演示了如何用 Docker 构建、运行、发布来一个 Spring Boot 应用。

Docker 简介

Docker 是一个 Linux 容器管理工具包,具备“社交”方面,允许用户发布容器的 image (镜像),并使用别人发布的 image。Docker image 是用于运行容器化进程的方案,在本文中,我们将构建一个简单的 Spring Boot 应用程序。

前置条件

  • JDK 1.8+
  • Maven 3.0+
  • Docker 最新版。有关 Docker 在的安装,可以搜索下,跟常规软件安装一样。 如果你的电脑不是 Linux 系统,最好装个虚拟机,在虚拟机里面装个 Linux ,因为 Docker 的依赖 Linux。

创建一个Springboo项目

创建maven springboot项目

可以通过spring io 官网来快速创建,也可以使用IDEA来快速创建。
假设你已经创建了一个标准的是springboot项目,大概目录如下:

我们需要在main目录下创建一个 docker 目录,然后在该目录下创建 Dockerfile 文件。

然后配置 pom.xml 文件,内容大致如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>docker</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>docker</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <!-- 在docker运行时要用的,只是一个前缀而已,就像包名一样,可自己任意定义此名称,重要:不能用驼峰命名法,最好全小写 -->
        <docker.image.prefix>dockertest</docker.image.prefix>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!-- docker 插件 begin -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.4.13</version>
                <configuration>
                    <!--镜像名称以及版本号-->
                    <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
                    <!--依赖的基础镜像-->
                    <baseImage>java</baseImage>
                    <!--Dockerfile的位置 -->
                    <dockerDirectory>src/main/docker</dockerDirectory>
                    <!-- 这里是复制 jar 包到 docker 容器指定目录配置 -->
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>
            <!-- docker 插件 end -->
        </plugins>
    </build>

</project>

修改 Spring Boot 应用入口文件

这里为了简便我们直接修改了Spring Boot 应用的启动文件,增加一个Controller。正常情况下你应该创建单独的Controller来处理访问连接 :

package com.example.docker;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class DockerApplication {

    @RequestMapping("/")
    public String home() {
        return "Hello Docker World.";
    }

    public static void main(String[] args) {
        SpringApplication.run(DockerApplication.class, args);
    }
}

解释下上面的代码:

  • 类用 @SpringBootApplication @RestController 标识,可用 Spring MVC 来处理 Web 请求。
  • @RequestMapping 将 / 映射到 home() ,并将"Hello Docker World" 文本作为响应。
  • main() 方法使用 Spring Boot 的 SpringApplication.run() 方法来启动应用。

 

运行程序

使用 Maven,你也可以使用IDEA自带的maven控制台来打包,或者启动应用

使用idea启动springboot

使用idea插件打包项目,打包完成后的jar在项目根目录的 target 目录下

或者你也可以通过mvn命令编译:

mvn package

运行:

java -jar target/docker-0.0.1-SNAPSHOT.jar

访问项目

如果程序正确运行,浏览器访问 http://localhost:8080/,可以看到页面 “Hello Docker World.” 字样。

 

将项目容器化

Docker 使用 Dockerfile 文件格式来指定 image 层,

所以我们上面创建了文件 src/main/docker/Dockerfile

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD docker-0.0.1-SNAPSHOT.jar app.jar
RUN sh -c 'touch /app.jar'
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]

解释下这个配置文件:

  • FROM 是指定了应用哪个基本容器镜像,因为我们需要jdk java环境,所以这里指定了 openjdk:8-jdk-alpine 镜像
  • VOLUME 指定了临时文件目录为/tmp。其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp。该步骤是可选的,如果涉及到文件系统的应用就很有必要了。/tmp目录用来持久化到 Docker 数据文件夹,因为 Spring Boot 使用的内嵌 Tomcat 容器默认使用/tmp作为工作目录
  • ADD 是将项目的docker-0.0.1-SNAPSHOT.jar 文件名重命名为 "app.jar" 并添加到容器
  • ENTRYPOINT 执行项目 app.jar。为了缩短 Tomcat 启动时间,添加一个系统属性指向 "/dev/urandom" 作为 Entropy Source

构建 Docker Image

执行构建成为 docker image:

mvn package docker:build

当然你也可以通过IDEA的maven插件来,点击按钮执行构建镜像

分别点击,1、clean   2、package   3、docker/docker:build

构建完成后,我们可以使用 docker images 来查看我们刚刚构建的镜像

通过docker images 命令我们看到刚才构建的镜像已经成功

运行

运行我们刚才构建的docker 镜像

docker run -p 8080:8080 -t dockertest/docker

前面的8080是指本机的端口,后面的是容器的端口。即把本机的8080端口映射到容器的8080端口上。


myiMac:docker auan$ docker run -p 18080:8080 -t dockertest/docker

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.5.RELEASE)

2019-05-31 08:21:27.442  INFO 1 --- [           main] com.example.docker.DockerApplication     : Starting DockerApplication v0.0.1-SNAPSHOT on 31eb12a6a818 with PID 1 (/app.jar started by root in /)
2019-05-31 08:21:27.447  INFO 1 --- [           main] com.example.docker.DockerApplication     : No active profile set, falling back to default profiles: default
2019-05-31 08:21:28.636  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2019-05-31 08:21:28.675  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-05-31 08:21:28.675  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.19]
2019-05-31 08:21:28.778  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-05-31 08:21:28.778  INFO 1 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1276 ms
2019-05-31 08:21:29.001  INFO 1 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-05-31 08:21:29.123  WARN 1 --- [           main] ion$DefaultTemplateResolverConfiguration : Cannot find template location: classpath:/templates/ (please add some templates or check your Thymeleaf configuration)
2019-05-31 08:21:29.261  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-05-31 08:21:29.265  INFO 1 --- [           main] com.example.docker.DockerApplication     : Started DockerApplication in 2.354 seconds (JVM running for 2.763)

访问项目

如果程序正确运行,浏览器访问 http://localhost:8080/,可以看到页面 “Hello Docker World.” 字样。

推送 image 到 Docker Hub

首先,你在 Docker Hub 要有注册账号,且创建了相应的库;

其次,docker 推送前,先要登录,否则报unauthorized: access to the requested resource is not authorized的错误

执行:

docker login

输出为:

Username: auan
Password: 
Email: *****@gmail.com
WARNING: login credentials saved in /root/.docker/config.json
Login Succeeded

执行推送

docker push dockertest/docker
The push refers to a repository [docker.io/dockertest/docker]
11fe0c5fec8c: Pushed 
9f41d126a004: Pushed 
ceaf9e1ebef5: Pushed 
9b9b7f3d56a0: Pushed 
f1b5933fe4b5: Pushed 
latest: digest: sha256:583a1b2519535df7d49d18281c0ba29df610f71a6b52cfd0c7b357c96e7637fc size: 1371

镜像加速器

Docker Hub 在国外,有时候拉取 Image 极其缓慢,可以使用国内的镜像来实现加速

阿里云

echo "DOCKER_OPTS=\"--registry-mirror=https://yourlocation.mirror.aliyuncs.com\"" | sudo tee -a /etc/default/docker
sudo service docker restart

其中 https://yourlocation.mirror.aliyuncs.com 是您在阿里云注册后的专属加速器地址

DaoCloud

sudo echo “DOCKER_OPTS=\”\$DOCKER_OPTS –registry-mirror=http://your-id.m.daocloud.io -d\”” >> /etc/default/docker
sudo service docker restart

其中 http://your-id.m.daocloud.io 是您在 DaoCloud 注册后的专属加速器地址

 

遇到的问题:
1、maven构建时报错:
maven docker 插件 org.apache.http.client.ClientProtocolException: Cannot retry request with a non-repeatable request entity: Broken pipe -> [Help 1]

原因:由于docker maven 插件的限制,docker项目的artifactId不能包含有大写字母
解决办法:将maven项目的artifactId改成纯小写(可包含字母和下划线的形式)。

雷雷

这个人太懒什么东西都没留下

文章评论(0)

(Spamcheck Enabled)