写点什么

在 Kubernetes 上运行 SpringBoot 应用

用户头像
铁花盆
关注
发布于: 2020 年 04 月 29 日
在Kubernetes上运行SpringBoot应用

花仲抒站在荒凉的山丘上,看着两位截移派大神WebLogic和WebSphere老态龙钟渐行渐远的背影,心中竟有些许伤感,不禁吟道:



滚滚长江东逝水,浪花淘尽英雄。

是非成败转头空。

青山依旧在,几度夕阳红。

白发渔樵江渚上,惯看秋月春风。

一壶浊酒喜相逢。

古今多少IT技,都付笑谈中。



吟罢双腿微曲,体内运行着库泊大法,将真虚二气容纳其中,纵身一跃,跳上旁边一颗古树,起落之间已经站在树梢,一套SpringBoot春初拳施展开来,真是行云流水,简约轻盈至极。



本文介绍如何将一个SpringBoot应用打docker镜像包,推送到docker镜像库,然后部署到kubernetes上运行。

一、环境准备

首先检查你的kubernetes集群环境已经就绪,如果你没有的话,最简单的方式是使用Minikube,如何安装详见kubernetes官网 https://kubernetes.io/docs/tasks/tools/install-minikube/

执行以下命令检查k8s环境

jared@ubuntu-box:~$ kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.0", GitCommit:"70132b0f130acc0bed193d9ba59dd186f0e634cf", GitTreeState:"clean", BuildDate:"2019-12-07T21:20:10Z", GoVersion:"go1.13.4", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.2", GitCommit:"59603c6e503c87169aea6106f57b9f242f64df89", GitTreeState:"clean", BuildDate:"2020-01-18T23:22:30Z", GoVersion:"go1.13.5", Compiler:"gc", Platform:"linux/amd64"}
jared@ubuntu-box:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ubuntu-box Ready master 40d v1.17.2

这是一个单节点的minikube环境,一切正常,Let us go!

二、编写一个简单的SpringBoot应用

本文采用在 https://start.spring.io/ 创建SpringBoot应用的方式,创建一个只需要Spring Web依赖的简单web应用,如下图所示

点击GENERATE按钮,将下载到本地的zip包解压,然后用IDE打开,添加一个Controller类

package com.tiehuapen.hellok8s;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Hellok8sController {
@GetMapping("/")
public String home() {
return "Hello K8S!";
}
}

执行 mvn clean package 并检查在本地能正常运行。

三、打包docker镜像

你可以采用Dockerfile方式创建Docker镜像,这种方式需要你本地安装了Docker。你也可以采用谷歌提供的容器化工具JIB来打包镜像,这种方式更方便,无需本地安装Docker,maven/gradle命令调用插件即可。

方式一:使用Dockerfile

在Spring boot项目根目录下创建一个名为Dockerfile的文件,文件内容如下:

FROM openjdk:8-jdk-alpine
ARG JARFILE=target/*.jar
COPY ${JARFILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

然后在项目根目录下执行构建镜像包的命令:

$ docker build -t tiehuapen/hellok8s:v1 .

构建完成后,执行镜像列表查询的命令:

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tiehuapen/hellok8s v1 9228d650f5e3 22 seconds ago 122MB

可以看到该镜像已经构建好了,接下来在本地docker环境测试一下该镜像是否可以正常运行,执行运行容器的命令:

$ docker run -p 8080:8080 --rm tiehuapen/hellok8s:v1

打开浏览器访问 http://localhost:8080/ ,运行正常。

上面那个Dockerfile非常简洁,但是它默认采用root用户执行程序,另外,为了将Spring Boot fat jar中依赖项和应用程序资源之间干净分离,我们将Dockerfile做一些改进,改进后如下所示:

FROM openjdk:8-jdk-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
ARG DEPENDENCY=target/dependency
COPY ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY ${DEPENDENCY}/META-INF /app/META-INF
COPY ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","com.tiehuapen.hellok8s.Hellok8sApplication"]

然后在项目根目录下执行构建镜像包的命令,并将tag设置为v2,注意:在构建之前要先将Spring Boot far jar解压到Dockerfile中指定的路径中。

$ mkdir -p target/dependency
$ cd .\target\dependency\
$ jar -xf ../*.jar
$ docker build -t tiehuapen/hellok8s:v2 .

构建完成后,执行镜像列表查询的命令:

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tiehuapen/hellok8s v2 81e53377d1ea 9 minutes ago 122MB
tiehuapen/hellok8s v1 f79127e183a1 About an hour ago 122MB

可以看到镜像v2也已经构建好了,类似v1版本,在本地docker环境测试一下是否可以正常运行。

方式二:使用Google GIB插件

采用Google GIB插件无需调用docker命令,可直接使用maven/gradle命令构建docker镜像。

首先,在pom.xml中添加GIB插件:

<project>
...
<build>
<plugins>
...
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>2.1.0</version>
<configuration>
<from>
<image>openjdk:alpine</image>
</from>
<to>
<image>tiehuapen/hellok8s:v3</image>
</to>
</configuration>
</plugin>
...
</plugins>
</build>
...
</project>

需要配置的主要信息就是from.image和to.image,from.image设置基础镜像,to.image设置将要构建的镜像名和标签。上面的from.image没有设置仓库地址,这表示将从默认的仓库地址docker.io下载基础镜像,速度一般会比较慢。

如果你本地docker环境已经有该基础镜像了,那你也可以直接从本地docker环境获取基础镜像,如下所示:

<from>
<image>docker://openjdk:alpine</image>
</from>

构建镜像命令如下所示,你可以选择将镜像生成在本地docker环境,也可以选择生成并上传到远程的镜像仓库。

# 将镜像生成在本地docker环境
$ mvn compile jib:dockerBuild
# 生成并上传到远程的镜像仓库
$ mvn compile jib:build

上面的例子中,将镜像生成在本地docker环境会执行成功,构建完成后,执行镜像列表查询的命令,可以看到本地docker已经有hellok8s:v3了。

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tiehuapen/hellok8s v2 81e53377d1ea 19 hours ago 122MB
tiehuapen/hellok8s v1 f79127e183a1 20 hours ago 122MB
openjdk alpine 5801f7d008e5 21 months ago 103MB
tiehuapen/hellok8s v3 a26b5c4f4e7b 50 years ago 120MB

但是生成并上传到远程的镜像仓库的命令会执行失败,报 401 Unauthorized 错误,这是因为to.image没有设置仓库地址(默认为docker hub),也没有设置用户鉴权信息。

现在我们来设置将生成镜像上传到阿里云容器镜像仓库,同时还可以指定多个标签,如下所示:

<to>
<image>registry.cn-beijing.aliyuncs.com/tiehuapen/hellok8s:v3</image>
<auth>
<username>xxx</username>
<password>yyy</password>
</auth>
<tags>
<tag>jib</tag>
<tag>latest</tag>
</tags>
</to>

其中的username和password是阿里云容器镜像服务的账号密码,而tiehuapen则是阿里云容器镜像服务的命名空间。

再次执行mvn compile jib:build,结果显示 BUILD SUCCESS。在阿里云控制台访问容器镜像服务,可以发现该镜像已经上传成功。

关于GIB最后要说的是,可以将jib的构建目标绑定到maven的生命周期,比如package,如下所示:

<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
...
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>dockerBuild</goal>
</goals>
</execution>
</executions>
</plugin>

现在执行mvn package,将会自动调用JIB插件命令,构建镜像。

四、部署到kubernetes

有了docker镜像之后,我们来将该镜像部署到kubernetes。首先创建一个namespace给我们这个演示使用,你当然也可以用已经存在的namespace,不过单独的命名空间更利于资源管理和清理。

$ kubectl create ns demo
namespace/demo created

接下来,我们以两种不同的方式来将hellok8s应用部署到Kubernetes,一种是命令行方式,一种是yaml文件方式。

方式一:命令行方式部署

首先执行kubectl create deployment来部署hellok8s应用,如下所示,在命令中指定image和命名空间。

$ kubectl create deployment hellok8s --image=registry.cn-beijing.aliyuncs.com/tiehuapen/hellok8s:v3 -n demo
deployment.apps/hellok8s created

查询命名空间demo中的资源,发现deployment资源已经成功创建,并且随之创建了replicaset和pod。

$ kubectl get all -n demo
NAME READY STATUS RESTARTS AGE
pod/hellok8s-dd4ddd4dc-gt6v2 1/1 Running 0 8s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/hellok8s 1/1 1 1 8s
NAME DESIRED CURRENT READY AGE
replicaset.apps/hellok8s-dd4ddd4dc 1 1 1 8s

现在,hellok8s应用可以通过K8S内部pod进行访问了,但是我们想通过浏览器来外部访问,为此,我们可以通过kubectl expose deployment命令,创建service资源来暴露hellok8s给外部访问。

$ kubectl expose deployment hellok8s --type=LoadBalancer --name hellok8s-svc \
> --port 80 --target-port 8080 -n demo
service/hellok8s-svc exposed

执行成功后,执行kubectl get svc命令来查询结果。

$ kubectl get svc -n demo
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hellok8s-svc LoadBalancer 10.108.10.165 <pending> 80:32483/TCP 5m49s
$ kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ubuntu-box Ready master 44d v1.17.2 192.168.1.109 <none> Ubuntu 16.04.3 LTS 4.4.0-87-generic docker://19.3.6

其中,CLUSTER-IP为k8s集群内部IP,只可内部访问;可以发现该service在k8s节点的端口32483上对外暴露访问,执行kubectl get node 查询node的IP地址后,打开浏览器即可成功访问了。

方式二:yaml文件方式部署

更好的方式是编写yaml文件,在yaml文件中规定要创建的deployment和service,然后只需要apply这个文件就可以了,hellok8s.yaml文件如下所示。

apiVersion: apps/v1
kind: Deployment
metadata:
name: hellok8s
namespace: demo
spec:
replicas: 2
selector:
matchLabels:
app: hellok8s
template:
metadata:
name: hellok8s
labels:
app: hellok8s
spec:
containers:
- image: registry.cn-beijing.aliyuncs.com/tiehuapen/hellok8s:v3
name: hellok8s-web
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
name: hellok8s-svc
namespace: demo
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30123
selector:
app: hellok8s


通过kubectl apply 命令部署该文件所描述的资源。

$ kubectl apply -f hellok8s.yaml
deployment.apps/hellok8s created
service/hellok8s-svc created

查询执行结果,结果显示2个Pod实例已经成功运行,服务已经在指定的端口30123对外暴露。

$ kubectl get all -n demo
NAME READY STATUS RESTARTS AGE
pod/hellok8s-68dffd9c4-dp8vj 1/1 Running 0 10s
pod/hellok8s-68dffd9c4-jmqlv 1/1 Running 0 10s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/hellok8s-svc NodePort 10.108.245.158 <none> 80:30123/TCP 10s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/hellok8s 2/2 2 2 10s
NAME DESIRED CURRENT READY AGE
replicaset.apps/hellok8s-68dffd9c4 2 2 2 10s

打开浏览器输入 192.168.1.109:30123 即可成功访问。

五、从Kubernetes清除应用

文章的最后,我们来清理干净上面演示中所创建的资源,因为上面都是在命名空间demo中操作的,所以就非常容易清理了。

$ kubectl delete all --all -n demo
pod "hellok8s-68dffd9c4-dp8vj" deleted
pod "hellok8s-68dffd9c4-jmqlv" deleted
service "hellok8s-svc" deleted
deployment.apps "hellok8s" deleted
replicaset.apps "hellok8s-68dffd9c4" deleted

当然,你也可以直接删除命名空间demo,那么它里面的资源也会自动删除。

$ kubectl delete ns demo
namespace "demo" deleted

看完这篇文章之后,你是不是跃跃欲试,想把自己的SpringBoot应用跑到Kubernetes上面去呢。

更多精彩文章,请扫码关注我的微信公众号。



发布于: 2020 年 04 月 29 日阅读数: 1358
用户头像

铁花盆

关注

微信公众号:tiehuapen 2020.03.25 加入

一个被春天、容器和云耽误了的历史玄幻世界的拾荒者

评论

发布
暂无评论
在Kubernetes上运行SpringBoot应用