本文介绍了如何将Spring Boot应用使用Docker进行容器化部署的入门知识,详细讲解了从环境准备到构建Docker镜像,再到运行Docker容器的全过程。通过示例,读者可以轻松掌握Spring Boot应用的Docker容器化部署入门技巧。从安装Docker、创建Spring Boot项目到编写Dockerfile、构建和运行Docker容器的各个步骤,本文都将一一展开介绍。
Spring Boot 简介
Spring Boot 是由 Pivotal 团队提供的一个开源框架,旨在简化新 Spring 应用的初始搭建以及开发过程。通过 Spring Boot,可以非常方便地创建独立的、生产级别的基于 Spring 框架的应用程序。
Spring Boot 是什么
Spring Boot 是 Spring 的一个模块,它提供了一种新的方式来简化 Spring 应用程序的配置。它通过约定优于配置的方式,帮助开发者快速搭建项目。Spring Boot 的核心功能是允许开发者通过一个独立的可执行的 JAR 文件,并提供一系列默认配置来运行应用程序。
Spring Boot 的优势
- 简化配置:Spring Boot 提供了大量的默认配置,从而减少了 Spring 应用程序中常见的 XML 配置。
- 自动配置:Spring Boot 可以根据在类路径中的库自动配置 Spring 应用程序。
- 嵌入式服务器:Spring Boot 支持内置的 Tomcat、Jetty 或者 Undertow 服务器,允许开发者直接用 Spring Boot 创建一个可独立运行的 Web 应用程序。
- 依赖管理:Spring Boot 提供了对不同版本依赖的管理,使得开发者不需要关注版本的兼容性问题。
- 命令行接口:Spring Boot 提供了一个命令行接口 (CLI),可以用来创建和运行 Spring Boot 应用程序,也可以用于测试目的。
Docker 简介
Docker 是一个开源的应用容器引擎,基于容器技术(如 LXC 和 AUFS),可以将应用及其依赖打包在统一的容器中进行分发和运行。
Docker 的基本概念
- 镜像 (Image):镜像可以理解为一个轻量级的、独立的、可执行的容器软件包,它包含了运行一个特定软件所需的所有信息。
- 容器 (Container):容器是镜像的运行实例,是一个独立和轻量级的执行环境,可以将应用与开发环境完全隔离,并且可以通过 docker 命令进行启动、停止、删除等操作。
- 仓库 (Repository):仓库是管理镜像的中心,它提供了一个集中式的存储库来存放和下载镜像。
- 标签 (Tag):标签用于指定镜像的版本,每个镜像可以有多个标签,每个标签代表不同的版本。
- Dockerfile:Dockerfile 是一个文本文件,包含了容器的创建命令。它提供了详细的构建步骤,用于从零开始构建一个 Docker 镜像。
Docker 的优势
- 轻量级:容器化技术可以大大减小应用的启动时间,因为不需要初始化整个操作系统环境。
- 可移植性:使用 Docker,可以确保在不同的操作系统上和不同的机器上运行,不会因为环境差异导致程序无法运行。
- 隔离性:容器内的应用程序独立于宿主机的环境,不会相互干扰。
- 一致性:无论是在开发环境、测试环境还是生产环境中,使用 Docker,可以保证应用程序在任何地方都能得到一致的结果。
- 资源利用最大化:容器共享宿主机操作系统,这样可以大幅度减少系统资源的消耗,提高资源利用率。
准备工作
在开始将 Spring Boot 应用容器化之前,需要确保系统上已经安装了 Docker,并且成功创建了一个 Spring Boot 项目。
安装 Docker
安装 Docker 的步骤根据操作系统不同而略有不同,这里以 Ubuntu 系统为例,Docker 安装步骤如下:
-
更新软件包索引:
sudo apt-get update
-
安装 Docker 的包和依赖:
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
-
添加 Docker 的官方 GPG 密钥:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
-
添加 Docker 的 APT 仓库:
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
- 更新软件包索引并安装 Docker CE:
sudo apt-get update sudo apt-get install docker-ce
安装完成后,可以通过运行命令 docker --version
来验证 Docker 是否安装成功。
创建 Spring Boot 项目
这里以创建一个简单的 Spring Boot 应用程序为例。可以通过 Spring Initializr(如 https://start.spring.io/)来快速创建一个新的 Spring Boot 项目。选择所需依赖,例如 Web 依赖,并下载生成的项目,或者使用命令行工具 spring init
来创建项目:
mvn archetype:generate -DarchetypeGroupId=org.springframework.boot -DarchetypeArtifactId=spring-boot-archetype-web -DarchetypeVersion=2.2.2.RELEASE -DgroupId=com.example -DartifactId=hello-world -Dversion=1.0.0-SNAPSHOT -Dpackage=com.example.hello-world
在项目根目录下,可以通过执行以下命令来运行项目:
mvn spring-boot:run
完整的 HelloWorldApplication.java 代码
以下是一个简单的 Spring Boot 应用程序的完整代码:
package com.example.hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class HelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(HelloWorldApplication.class, args);
}
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, Docker!";
}
}
}
编写 Dockerfile
Dockerfile 是 Docker 镜像的构建文件,它定义了如何构建 Docker 镜像的步骤。Dockerfile 中的每一行指令都会执行一次构建步骤,并生成一个新的镜像层。
Dockerfile 的作用
Dockerfile 的主要作用是定义一个镜像的构建过程,包括基础镜像的选择、环境变量的设置、文件的复制、依赖的安装等。通过 Dockerfile,可以自动化构建出一个包含所有应用依赖的独立镜像。
如何编写 Dockerfile
以下是一个简单的 Dockerfile 示例,用于构建一个 Spring Boot 应用程序的 Docker 镜像:
# 使用官方的 Java 运行时作为基础镜像
FROM openjdk:8-jdk-alpine
# 设置镜像的工作目录
WORKDIR /app
# 复制编译好的 jar 文件到镜像中
COPY target/*.jar app.jar
# 设置环境变量
ENV JAVA_OPTS=""
# 暴露应用程序使用的端口
EXPOSE 8080
# 运行应用程序的命令
ENTRYPOINT ["java", "$JAVA_OPTS", "-jar", "/app/app.jar"]
Dockerfile 示例解析
FROM openjdk:8-jdk-alpine
:这一行指定了 Dockerfile 使用的基镜像,这里使用了openjdk:8-jdk-alpine
,它是一个基于 Alpine Linux 的 Java 运行时环境。WORKDIR /app
:定义了在 Docker 容器内部的工作目录。COPY target/*.jar app.jar
:将当前目录中target
文件夹下的所有.jar
文件复制到容器的/app
目录下,并命名为app.jar
。EXPOSE 8080
:指定容器运行时暴露 8080 端口,这是 Spring Boot 应用默认使用的端口。ENTRYPOINT ["java", "$JAVA_OPTS", "-jar", "/app/app.jar"]
:指定了容器启动时运行的命令,这里使用 Java 命令运行app.jar
文件。
构建 Docker 镜像
在编写了 Dockerfile 后,接下来需要通过 Docker 命令来构建 Docker 镜像,并验证构建是否成功。
构建镜像命令详解
构建 Docker 镜像的命令如下:
docker build -t spring-boot-app:1.0 .
这个命令将当前目录(.
)作为 Dockerfile 的位置,并使用 -t
参数为镜像指定一个名称和标签(这里是 spring-boot-app:1.0
)。
验证镜像是否构建成功
构建完成后,可以通过命令查看构建的镜像列表:
docker images
这会列出所有可用的 Docker 镜像,其中应该包括我们刚刚构建的 spring-boot-app:1.0
镜像。
构建命令及输出
# 构建命令及输出
$ docker build -t spring-boot-app:1.0 .
Sending build context to Docker daemon 88.18MB
Step 1/4 : FROM openjdk:8-jdk-alpine
---> 810b8e3e8e4f
Step 2/4 : WORKDIR /app
---> Using cache
---> 810b8e3e8e4f
Step 3/4 : COPY target/*.jar app.jar
---> Using cache
---> 810b8e3e8e4f
Step 4/4 : EXPOSE 8080
---> Using cache
---> 810b8e3e8e4f
Successfully built 810b8e3e8e4f
Successfully tagged spring-boot-app:1.0
运行 Docker 容器
在成功构建 Docker 镜像后,接下来就可以使用 Docker 命令来启动容器了。
启动容器基本命令
启动容器的命令如下:
docker run -d -p 8080:8080 --name spring-boot-container spring-boot-app:1.0
这个命令启动了一个 Docker 容器,并将其暴露在主机的 8080 端口上。-d
参数表示以分离模式运行容器,--name
参数用于为容器指定名称。
如何将容器暴露端口
在构建镜像时,我们已经使用 EXPOSE
指令指定了容器将要暴露的端口。然后在运行容器时,通过 -p
参数将容器内的端口映射到主机的端口。例如,-p 8080:8080
表示将容器内的 8080 端口映射到主机的 8080 端口。
运行命令及输出
# 运行命令及输出
$ docker run -d -p 8080:8080 --name spring-boot-container spring-boot-app:1.0
Unable to find image 'spring-boot-app:1.0' locally
1.0: Pulling from library/spring-boot-app
Digest: sha256:6a005d6b3d7b9f1d434f480c26c2b5b9d9c1e2c9e27b9e5d6a005d6b3d7b9f1d
Status: Downloaded newer image for spring-boot-app:1.0
00b0f65b6e8b66a10499966e8b66a1049996
# 验证容器是否运行
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
00b0f65b6e8b spring-boot-app "java -jar app.jar" 5 minutes ago Up 5 minutes 0.0.0.0:8080->8080/tcp spring-boot-container
实践示例
为了更好地理解如何将 Spring Boot 应用容器化,以下是一个完整的示例,包括从创建 Spring Boot 应用到容器化部署的所有步骤。
创建 Spring Boot 应用
首先,创建一个简单的 Spring Boot 应用,添加一个简单的 REST 控制器:
package com.example.hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class HelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(HelloWorldApplication.class, args);
}
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, Docker!";
}
}
}
构建 Spring Boot 应用
在项目目录中,执行以下命令构建项目:
mvn clean install
这会生成 target
目录下的 jar 文件。
构建命令及输出
# 构建命令及输出
$ mvn clean install
[INFO] Scanning for projects...
[INFO]
[INFO] --------------< com.example:hello-world >---------------
[INFO] Building hello-world 1.0.0-SNAPSHOT
[INFO] --------------------------------[ jar ]----------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello-world ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /path/to/project/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello-world ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /path/to/project/target/classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello-world ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /path/to/project/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hello-world ---
[INFO] Nothing to compile - skip compiling
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello-world ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello-world ---
[INFO] Building jar: /path/to/project/target/hello-world-1.0.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.190 s
[INFO] Finished at: 2023-10-08T12:34:56+08:00
[INFO] Final Memory: 15M/311M
[INFO] ------------------------------------------------------------------------
编写 Dockerfile
在项目根目录下创建一个 Dockerfile
文件,并添加以下内容:
FROM openjdk:8-jdk-alpine
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
构建 Docker 镜像
在项目根目录下,执行以下命令构建 Docker 镜像:
docker build -t spring-boot-app:1.0 .
构建命令及输出
# 构建命令及输出
$ docker build -t spring-boot-app:1.0 .
Sending build context to Docker daemon 88.18MB
Step 1/4 : FROM openjdk:8-jdk-alpine
---> 810b8e3e8e4f
Step 2/4 : WORKDIR /app
---> Using cache
---> 810b8e3e8e4f
Step 3/4 : COPY target/*.jar app.jar
---> Using cache
---> 810b8e3e8e4f
Step 4/4 : EXPOSE 8080
---> Using cache
---> 810b8e3e8e4f
Successfully built 810b8e3e8e4f
Successfully tagged spring-boot-app:1.0
运行 Docker 容器
构建完成后,执行以下命令启动容器:
docker run -d -p 8080:8080 --name spring-boot-container spring-boot-app:1.0
运行命令及输出
# 运行命令及输出
$ docker run -d -p 8080:8080 --name spring-boot-container spring-boot-app:1.0
Unable to find image 'spring-boot-app:1.0' locally
1.0: Pulling from library/spring-boot-app
Digest: sha256:6a005d6b3d7b9f1d434f480c26c2b5b9d9c1e2c9e27b9e5d6a005d6b3d7b9f1d
Status: Downloaded newer image for spring-boot-app:1.0
00b0f65b6e8b66a10499966e8b66a1049996
# 验证容器是否运行
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
00b0f65b6e8b spring-boot-app "java -jar app.jar" 5 minutes ago Up 5 minutes 0.0.0.0:8080->8080/tcp spring-boot-container
在浏览器中访问 http://localhost:8080/hello
,可以看到返回的响应 Hello, Docker!
,表示容器已经成功运行。
通过以上步骤,已经成功将一个简单的 Spring Boot 应用程序容器化,并运行在 Docker 容器中。