关于springboot:通过skaffold快速部署微服务

3次阅读

共计 17205 个字符,预计需要花费 44 分钟才能阅读完成。

通过 skaffold 疾速部署微服务

随着技术的一直倒退,程序员们相熟的传统单体利用开发流程,慢慢地无奈适应当下微服务化的潮流趋势。同时随着云原生开发的理念一直推广,越来越多的服务运行在不可变的基础设施之上,随之而来的是传统单体利用开发流程与云化水平日益加深服务之间的隔膜越发微小,开发人员越来越难以容忍反复繁琐且容易出错的低效率开发流程。因而,一款面向开发人员而运维施行人员的继续构建与继续部署工具 skaffold 应运而生

skaffold 简介

[skaffold]() 是一款 Google 推出的继续构建与继续部署工具,它次要面向开发人员而非运维施行人员,指标是突破本地开发与云化部署之间的隔膜,加重开发人员的心智累赘,帮忙开发人员专一于杰出地实现日常开发工作,防止开发人员在缭乱繁冗的运维流程中过多耗费贵重的精力与工夫。

根本架构

skaffold 的工作流依照开发流程的不同阶段,分为 4 个局部组成:

  1. 本地开发(文件同步)
  2. 继续构建
  3. 继续测试
  4. 继续部署

以上四个局部均能够依据理论需要进行定制化批改。

本地开发

skaffold 对支流的编程语言以及配套应用的技术栈都有着十分不错的反对,例如 GoJavaJavaScript

本地开发的核心内容是 文件同步 ,文件同步的监听对象大略能够分为 源代码 编译产物

skaffold 官网的举荐做法是监听源代码变动,而后自动化把源代码复制到 Docker 容器中进行编译和构建。

这种做法的问题不少,首先是源代码变动十分频繁,而编译和构建过程往往十分耗时,因而主动触发构建不太正当。

其次,在 Docker 容器中编译和构建,须要把握编写 Multi Stage Dockerfile 技能,否则构建进去的镜像大小会占据十分大的空间,另外还要耗费本就不拮据的带宽进行镜像传输。

最初,在 Docker 容器中编译和构建,要解决环境变量,代理设置、缓存构建两头后果等一系列问题,对老手十分不敌对。

因而,集体举荐,在本地开发环节尽量采纳手动触发编译构建,通过监听编译产物的形式来触发热更新等流程。

继续构建

因为抉择手动触发编译,所以本环节的内容次要讲述如何打包镜像的内容

目前 skaffold 官网反对的构建形式有三种:DockerJib(maven/gradle)Bazel

  • Docker
  • Jib(maven/gradle)
  • Bazel

这里以最常见 Docker 为例:

build:
  local:
    push: false                        # 镜像打包胜利后是否推送到远端的镜像仓库
  artifacts:                           # 反对打包多个不同组件的镜像
    - image: datacenter-eureka         # 打包后的镜像名称
      context: "eureka"                # Dockerfile 相对路径,就放在 eureka 目录下
      docker:
        dockerfile: Dockerfile
    - image: datacenter-school         # 打包后的镜像名称
      context: "school"                # Dockerfile 相对路径
      docker:
        dockerfile: Dockerfile
    - image: datacenter-teacher        # 打包后的镜像名称
      context: "teacher"               # Dockerfile 相对路径
      docker:
        dockerfile: Dockerfile
    - image: datacenter-student        # 打包后的镜像名称
      context: "student"               # Dockerfile 相对路径
      docker:
        dockerfile: Dockerfile

当运行 skaffold dev 时,会依照 编译 —> 构建 -> 测试 -> 部署 的规范流程走一遍。
当监听到指定门路下的文件发生变化时,skaffold 工具会尝试通过相似于 kubectl cp 命令的形式,间接把产生变动后的文件拷贝到运行中的容器外部,防止从新走一遍编译构建 / 上传镜像的步骤,缩小同步代码更改而耗费的工夫。

须要特地留神,这种形式对于反对 代码热更新 的技术栈十分实用,例如 JavaJavascript,但对于 Go 这类不反对 热更新 的技术栈来说成果非常无限,因为即使文件同步实现,仍然重启主过程能力让批改后的性能失效。

接着说 Jib(maven/gradle)Jib 也是由谷歌开发的一款专门针对 Java 生态的 CI/CD 工具,跟 skaffold 通用 CI/CD 不同,同时还有 VSCodeIDEA 插件,但作者自己并没有用过,所以等当前有机会再开展讲。

至于 Bazel 是微软开发的全平台构建工具,次要反对 C# 语言,甚至连前端相干 Javascript 我的项目也能够应用,但毛病就是十分轻便,这里也不开展讲。

此外,skaffold 还反对 Customize 自定义构建,这个形式的构建更自在可控,比方有些 WSL 环境的用户不违心为了装置 Docker 环境而重复折腾,甚至有些企业外部不容许员工在开发电脑装置虚拟机等等,通过自定义构建流程都能够解决,放到文章最初再具体解说。

继续测试

skaffold 官网的测试计划是把代码拷贝到定制化的测试环境容器中执行测试用例,这种办法十分麻烦,测试相干的内容这里就不开展讲。
感兴趣的读者能够查看 skaffold 官网配置文档

继续部署

skaffold 官网反对的部署形式有很多种,这里以 helm 为例:

deploy:
  helm:
    releases:
    - name: datacenter
      chartPath: package
      artifactOverrides:
        image:
          eureka: datacenter-eureka      # 镜像名称要跟后面构建环节的镜像名称保持一致,但不能呈现镜像标签
          school: datacenter-school      # 镜像名称要跟后面构建环节的镜像名称保持一致,但不能呈现镜像标签
          teacher: datacenter-teacher    # 镜像名称要跟后面构建环节的镜像名称保持一致,但不能呈现镜像标签
          student: datacenter-student    # 镜像名称要跟后面构建环节的镜像名称保持一致,但不能呈现镜像标签
      imageStrategy:
        helm: {}

配置参考

残缺的配置文件能够参考:datacenter

上手实际

后期筹备

  • skaffold
  • helm

点击上述两个组件的链接,下载到本地,再讲二进制退出 PATH 环境变量,具体装置过程不再赘述。

根本开发环境配置

JDKmavenGradle 这类 Java 开发必备的工具请自行装置,这里就不开展讲了。

初始化 helm chart

在一个空白目录下运行 helm create datacenter 命令,即可疾速创立 chart 包,包的目录构造如下所示:

├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

能够依据本身的理论需要,增删批改包的文件内容,例如这里用不到 hpa.yamlserviceaccount.yamltests/*,所以都删除了。

而后把 datacenter 重命名为 package,而后挪动到本来的代码目录下,这是约定成俗的习惯。

部署 MySQL 服务

经典的 Web 利用往往离不开数据库,而在 k8s 上运行数据库,则须要提供长久化存储,否则数据库的容器重启后数据就失落了。

首先,在 package/templates 目录下创立 pv.yaml 文件,而后写入以下内容:

kind: PersistentVolume
apiVersion: v1
metadata:
  name: mysql-pv-volume
  namespace: spring-cloud
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/opt/data/mysql"

解释:创立长久化卷 PersistentVolume,简称 PV,存储门路就用宿主机目录 /opt/data/mysql

而后,在同一个目录下创立 pvc.yaml 文件,而后写入以下内容:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  namespace: spring-cloud
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi

解释:创立长久卷应用申明 PersistentVolumeClaim,简称 PVC,绑定后面创立的 PV
PVC 的容量是 2G,必须小或等于 PV 的容量,否则无奈绑定,能够依据理论状况调整容量大小。

为了避免卸载过程中意外删除 PV 卷导致数据失落的状况,helm 不会执行删除 PV 的操作,必须要用户手动执行。
因而如果部署过程呈现 PVC 与 PV 无奈绑定而导致无奈持续的状况,请手动删除再从新 PV 以及 PVC 的形式排除故障

最初,在同一个目录下创立 statefulset.yaml 文件,而后写入以下内容:

apiVersion: v1
kind: Service
metadata:
  name: mysql                  # 同一个命名空间的其余服务能够通过域名“mysql”来拜访 MySQL 服务
  namespace: spring-cloud      # 通过命名空间来隔离不同的我的项目
spec:
  type: ClusterIP
  ports:
  - name: mysql
    protocol: TCP
    port: 3306
    targetPort: 3306
  selector:
    app: mysql                 # 通过定义标签选择器,只转发申请给带有 app: mysql 的 Pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: spring-cloud
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: bocloud@2019    # 明码属于高度敏感秘密,倡议在生成环境中通过 ServiceAccount 和 ConfigMap 等形式注入
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim   # 将后面定义的 pvc 挂载成卷,给容器应用

解释:创立 mysql 的 ServiceStatefulSet。因为 mysql 是个数据库,属于 有状态利用 ,所以倡议应用 StatefulSet 来治理。
另外因为 k8s 的机制问题,Pod 重启后 IP 地址会扭转,所以 Pod 之间的通信不适宜间接通过拜访 Pod IP 的形式进行,最佳实际是通过创立特定 Service , 申请方的 Pod 向特定 Service 发送申请,再由特定 Service 转发申请给被申请方的 Pod。

部署微服务

package/templates 目录下清空 deployment.yaml 文件,而后写入以下内容:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: datacenter-dep
  namespace: spring-cloud      # 同一个我的项目的命名空间肯定要雷同
  labels:
    app: datacenter            # 自定义标签
spec:
  replicas: 1                       # 正本数量
  selector:
    matchLabels:
      app: datacenter               # 通过统计有多少个带有 app: datacenter 的 Pod 来确定正本的数量
  template:
    metadata:
      labels:
        app: datacenter             # 给 Pod 打上 app: datacenter 标签,不便统计
    spec:
      containers:
      - name: school
        image: {{.Values.image.school.repository}}:{{.Values.image.school.tag}} # 注入真正的镜像
        imagePullPolicy: IfNotPresent
        env:
        - name: MYSQL_ADDRESS
          value: mysql:3306
        - name: MYSQL_PASSWORD
          value: bocloud@2019           # 明码属于高度敏感秘密,不倡议在实在环境应用明文明码,这里仅为展现
        ports:
        - containerPort: 8084
      - name: teacher
        image: {{.Values.image.teacher.repository}}:{{.Values.image.teacher.tag}} # 注入真正的镜像
        imagePullPolicy: IfNotPresent
        env:
        - name: MYSQL_ADDRESS
          value: mysql:3306
        - name: MYSQL_PASSWORD
          value: bocloud@2019           # 明码属于高度敏感秘密,不倡议在实在环境应用明文明码,这里仅为展现
        ports:
        - containerPort: 8082
      - name: student
        image: {{.Values.image.student.repository}}:{{.Values.image.student.tag}} # 注入真正的镜像
        imagePullPolicy: IfNotPresent
        env:
        - name: MYSQL_ADDRESS
          value: mysql:3306
        - name: MYSQL_PASSWORD
          value: bocloud@2019           # 明码属于高度敏感秘密,不倡议在实在环境应用明文明码,这里仅为展现
        ports:
        - containerPort: 8083

解释:依据 k8s 的标准要求,应该通过 Deployment 来部署 无状态利用

而后,在同一个目录下清空 service.yaml 文件,而后写入以下内容:

apiVersion: v1
kind: Service
metadata:
  name: datacenter
  namespace: spring-cloud
spec:
  type: ClusterIP
  selector:
    app: datacenter
  ports:
    - name: school
      protocol: TCP
      port: 8084
      targetPort: 8084
    - name: teacher
      protocol: TCP
      port: 8082
      targetPort: 8082
    - name: student
      protocol: TCP
      port: 8083
      targetPort: 8083

解释:创立 Service 裸露到集群外部,供集群外部的其余服务调用

最初,批改 package/values.yaml 文件,而后写入以下内容:

image:
  school:
    repository: datacenter-school
    tag: latest
  teacher:
    repository: datacenter-teacher
    tag: latest
  student:
    repository: datacenter-student
    tag: latest

解释:helm 举荐通过 values.yaml 文件对立治理 chart 模板的变量。
skaffold 也是通过批改 values.yaml 注入不同的镜像名称,动静更新运行中容器镜像

装置配置 kubectl 和 docker

装置 kubectl 与 k8s 通信

版本:v1.23.0

  • windows amd64
  • darwin amd64
  • linux amd64

点击上述链接,下载到本地,再讲二进制退出 PATH 环境变量,具体装置过程不再赘述。

K8S 配置 个别保留在主节点的 ~/.kube 目录下,将残缺目录复制到本地目录下,关上目录下的 .kube/config,能够相似的内容如下:

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: "****"  # 证书颁发机构的证书
    server: https://172.24.86.22:6443   # k8s 的 apiserver 地址
  name: kubernetes                      # k8s 集群的名称
contexts:
- context:
    cluster: kubernetes                        # 上下文的 k8s 集群的名称
    user: kubernetes-admin                     # 上下文的 k8s 凭证的用户名称
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes   # 设置以后上下文的所应用的 k8s 集群
kind: Config
preferences: {}
users:
- name: kubernetes-admin             # k8s 凭证的用户名称
  user:
    client-certificate-data: "****"  # 用户证书
    client-key-data: "****"          # 用户密钥

而后设置环境变量 KUBECONFIG 指向本地的 ./kube/config 门路,kubectl 便能够通过凭证与 k8sAPIServer 通信。
批改环境变量后,记得运行命令更新环境变量,Windows 平台执行 refreshenv 命令。

装置 docker 用于打包镜像

如果你的本地电脑环境存在 docker 环境,能够跳过 docker 装置配置环节

装置 Docker 客户端

点击这里,
下载到本地,再讲二进制退出 PATH 环境变量,具体装置过程不再赘述。

配置 Docker

假如你的 WSL 环境中存在 Docker 环境,又或者近程 Linux 服务器上存在 Docker 环境,
能够通过批改 Docker 守护过程的配置,将 Docker 过程裸露到内网供其余设施进行应用。

首先,编辑 /etc/systemd/system/multi-user.target.wants/docker.service 文件,将 ExecStart 行改成以下内容:

ExecStart=/usr/bin/dockerd --containerd=/run/containerd/containerd.sock

重点是去掉 fd://,接着编辑 /etc/docker/daemon.json 文件,重点是 hosts 加上 fd://tcp://0.0.0.0:10086

注意事项:降级 docker 后会笼罩以后设置,导致 docker 无奈失常运行,须要参考上述步骤从新设置 docker.service 文件能力失常运行

端口号能够依据理论状况调整

{
  "hosts": [
    "fd://",
    "tcp://0.0.0.0:10086"
  ],
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn/",
    "https://dockerhub.azk8s.cn/",
    "https://hub-mirror.c.163.com/"
  ],
  "exec-opts": ["native.cgroupdriver=systemd"],
    "log-driver": "json-file",
    "log-opts": {"max-size": "100m"},
  "storage-driver": "overlay2"
}

接口执行以下命令,重启 docker

systemctl daemon-reload
systemctl restart docker

最初,在本地设置环境变量 DOCKER_HOST=<eth0IP>:10086,把 <eth0IP> 换成近程 Linux 服务器的实在 IP。

因为 WSL 每次重启 eth0 的 IP 会变动,须要从新设置 DOCKER_HOST 变量

在本地命令行界面,执行 docker info 命令查看是否设置胜利。

C:\WINDOWS\system32>docker info
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc., v0.7.1)
  compose: Docker Compose (Docker Inc., v2.2.1)
  scan: Docker Scan (Docker Inc., 0.9.0)

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 30
 Server Version: 20.10.12
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 7b11cfaabd73bb80907dd23182b9347b4245eb5d
 runc version: v1.0.2-0-g52b36a2
 init version: de40ad0
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 5.10.74.3-microsoft-standard-WSL2+
 Operating System: Ubuntu 20.04.3 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 8
 Total Memory: 7.239GiB
 Name: LAPTOP-MAGICBOOKPRO
 ID: EXNQ:FGLE:MROB:C7FG:WJXC:R7YV:HUFB:6A46:4KAW:LG2A:TM3J:SAAB
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Registry Mirrors:
  https://docker.mirrors.ustc.edu.cn/
  https://dockerhub.azk8s.cn/
  https://hub-mirror.c.163.com/
 Live Restore Enabled: false

填写 skaffold 配置并运行

在我的项目根目录下,创立 skaffold.yaml 文件,填写以下内容

apiVersion: skaffold/v2beta26                     # version of the configuration.
kind: Config                                     # always Config.
metadata:
  name: datacenter
build:
  local:
    push: false
  artifacts:
    - image: datacenter-school         # must match in artifactOverrides
      context: "school"
      docker:
        dockerfile: Dockerfile
    - image: datacenter-teacher        # must match in artifactOverrides
      context: "teacher"
      docker:
        dockerfile: Dockerfile
    - image: datacenter-student        # must match in artifactOverrides
      context: "student"
      docker:
        dockerfile: Dockerfile
deploy:
  helm:
    releases:
    - name: datacenter
      chartPath: package
      artifactOverrides:
        image:
          school: datacenter-school               # no tag present!
          teacher: datacenter-teacher               # no tag present!
          student: datacenter-student               # no tag present!
      imageStrategy:
        helm: {}

先执行以下命令创立 spring-cloud 命名空间,k8s 通过命名空间来隔离不同微服务的资源

kubectl create namespace spring-cloud

再执行 skaffold dev 命令,如果后面的步骤和配置都正确,应该能够看到以下输入

C:\Users\huang\Documents\datacenter>skaffold dev
time="2022-02-14T00:13:29+08:00" level=warning msg="failed to detect active kubernetes cluter node platform. Specify the correct build platform in the `skaffold.yaml` file or using the `--platform` flag" subtask=-1 task=DevLoop
Listing files to watch...
 - datacenter-eureka
 - datacenter-school
 - datacenter-teacher
 - datacenter-student
Generating tags...
 - datacenter-eureka -> datacenter-eureka:13577a5
 - datacenter-school -> datacenter-school:13577a5
 - datacenter-teacher -> datacenter-teacher:13577a5
 - datacenter-student -> datacenter-student:13577a5
Checking cache...
 - datacenter-eureka: Found. Tagging
 - datacenter-school: Found. Tagging
 - datacenter-teacher: Found. Tagging
 - datacenter-student: Found. Tagging
Tags used in deployment:
 - datacenter-eureka -> datacenter-eureka:769afdbaaf2a35acada2a56cf1d1cccbc8a8ab8196396a8ff9e2803cf6a49490
 - datacenter-school -> datacenter-school:b89167e724932d41e40945a39ff04d84e419345957c4c0a022e7c4694153b609
 - datacenter-teacher -> datacenter-teacher:9d013f9295b7bd3e75b68b2d8a9df434a77cbc9514df1ae36a967b6841c4328f
 - datacenter-student -> datacenter-student:3f5267479ce35cec929485edce5f1dfc2cb1017136bbc90f2a0de5cd4f48f808
Starting deploy...

Ctrl+C 即可进行服务,如果 kubernetes 集群中仍旧存在 datacenter 相干的资源,能够通过 helm uninstall datacenter 手动革除。

[可选]应用 Buildah 代替 Docker

对于 WSL1 或者 厌弃在 WSL2 装置 docker 环境太麻烦的 windows 用户,以及不想在本地装置 dockerMac 用户,
能够尝试装置 redhat 开源的 buildah

依照官网教程自行装置即可。
装置完结后运行 buildah image,若遇到以下谬误:

kernel does not support overlay fs: 'overlay' is not supported over <unknown> at "/home/zaoying/.local/share/containers/storage/overlay": backing file system is unsupported for this graph driver
WARN[0000] failed to shutdown storage: "kernel does not support overlay fs:'overlay'is not supported over <unknown> at \"/home/zaoying/.local/share/containers/storage/overlay\": backing file system is unsupported for this graph driver"
ERRO[0000] exit status 125

只须要装置 fuse-overlayfs 即可:

# for debian/ubuntu
apt install fuse-overlayfs

buildah 基于 fork 模型,不须要 daemon 守护过程,因而不依赖于 systemd,不须要 root 权限即可运行。
装置完后即可应用,不须要额定的配置。但 skaffold 尚未提供 buildah 官网反对,因而须要自定义构建脚本。

apiVersion: skaffold/v2beta26                     # version of the configuration.
kind: Config                                     # always Config.
metadata:
 name: datacenter
build:
 local:
   push: false
 artifacts:
   - image: datacenter-school         # must match in artifactOverrides
     context: "school"
     custom:
       buildCommand: |
         buildah bud -t $IMAGE -f .
   - image: datacenter-teacher        # must match in artifactOverrides
     context: "teacher"
     custom:
       buildCommand: |
         buildah bud -t $IMAGE -f .
   - image: datacenter-student        # must match in artifactOverrides
     context: "student"
     custom:
       buildCommand: |
         buildah bud -t $IMAGE -f .
deploy:
 helm:
   releases:
   - name: datacenter
     chartPath: package
     artifactOverrides:
       image:
         school: datacenter-school               # no tag present!
         teacher: datacenter-teacher               # no tag present!
         student: datacenter-student               # no tag present!
     imageStrategy:
       helm: {}

更多具体的自定义构建器帮忙,请查看官网文档

[可选]代码热更新

代码热更新在日常的开发过程十分实用,能够放慢个性开发与性能验证的效率。

skaffold 能够解析 Dockerfile,依据 COPYADD 等指令,主动抉择监听和同步哪些文件。

当批改完代码后,手动执行 mvn clean & mvn package 命令,skaffold 监听 jar 包变动,主动从新打包镜像并替换。

整个过程算不上真正意思上的热更新,次要的起因是 spring boot 通过 jar 包部署,每次只做了很小的改变都须要从新打包镜像,消耗十分多的工夫。

如果改为 exploded war 的形式部署,就能够实现 class 粒度的 热更新

间接跳过 mvn package 打包环节,间接将编译的两头产物 .class 字节码文件同步到运行中的容器中,从而在不重启容器的前提下实现代码热更新。

实践上来说,skaffold 的代码热更新性能同时实用于 JavaJavascript 等技术栈。但限于篇幅,本文仅限于 Java。

首先要革新 pom.xml 配置,把 <package>jar</package> 改成 <package>war</package>

    <packaging>war</packaging>

而后加上 spring-boot-starter-tomcatscope 改为 provided,以及减少 start-class 属性,填写全门路的启动类

  ...
    <properties>
    ...
        <start-class>com.springcloud.eureka.SchoolApplication</start-class>
    ...
    </properties>
  ...
  <dependencys>
    ...
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <scope>provided</scope>
    </dependency>
    ...
  </dependencys>

关上启动类 SpringApplication.java,减少 extends SpringBootServletInitializer 并重载 configure 办法

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class SchoolApplication extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(SchoolApplication.class);
    }

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

接着,批改 Dockerfile, 如果你不违心在生产环境采纳 war,这里能够另存为 Dockerfile.dev

FROM tomcat:9.0.62-jre11-temurin-focal
RUN rm -rf /usr/local/tomcat/webapps.dist
# 通过批改 server.xml 的形式批改端口
RUN sed -i 's/redirectPort="8443"//' /usr/local/tomcat/conf/server.xml && sed -i 's/8005/8004/' /usr/local/tomcat/conf/server.xml && sed -i 's/8080/8084/' /usr/local/tomcat/conf/server.xml
COPY target/exploded /usr/local/tomcat/webapps/ROOT
COPY target/classes /usr/local/tomcat/webapps/ROOT/WEB-INF/classes
CMD ["catalina.sh", "run"]

以上操作都是针对单个服务,因而每个服务都要反复一遍上述操作,但以下操作则是针对整体服务。

最初批改 skaffold.yaml,减少自定义构建脚本

apiVersion: skaffold/v2beta26                     # version of the configuration.
kind: Config                                     # always Config.
metadata:
  name: datacenter
build:
  local:
    push: false
  artifacts:
    - image: datacenter-eureka         # must match in artifactOverrides
      context: "eureka"
      custom:
        buildCommand: |
          mvn clean package && 7z x target/eureka-0.0.1-SNAPSHOT.war -otarget/exploded && docker build -t %IMAGE% -f Dockerfile.dev %BUILD_CONTEXT%
        dependencies:
          paths:
          - target/classes
          - Dockerfile.dev
          ignore:
          - target/exploded
    - image: datacenter-school         # must match in artifactOverrides
      context: "school"
      custom:
        buildCommand: |
          mvn clean package && 7z x target/school-0.0.1-SNAPSHOT.war -otarget/exploded && docker build -t %IMAGE% -f Dockerfile.dev %BUILD_CONTEXT%
        dependencies:
          paths:
          - target/classes
          - Dockerfile.dev
          ignore:
          - target/exploded
    - image: datacenter-teacher        # must match in artifactOverrides
      context: "teacher"
      custom:
        buildCommand: |
          mvn clean package && 7z x target/teacher-0.0.1-SNAPSHOT.war -otarget/exploded && docker build -t %IMAGE% -f Dockerfile.dev %BUILD_CONTEXT%
        dependencies:
          paths:
          - target/classes
          - Dockerfile.dev
          ignore:
          - target/exploded
    - image: datacenter-student        # must match in artifactOverrides
      context: "student"
      custom:
        buildCommand: |
          mvn clean package && 7z x target/student-0.0.1-SNAPSHOT.war -otarget/exploded && docker build -t %IMAGE% -f Dockerfile.dev %BUILD_CONTEXT%
        dependencies:
          paths:
          - target/classes
          - Dockerfile.dev
          ignore:
          - target/exploded
deploy:
  helm:
    releases:
    - name: datacenter
      chartPath: package
      artifactOverrides:
        image:
          eureka: datacenter-eureka               # no tag present!
          school: datacenter-school               # no tag present!
          teacher: datacenter-teacher               # no tag present!
          student: datacenter-student               # no tag present!
      imageStrategy:
        helm: {}

图中所展现的 buildCommand 是在 Windows 平台执行的,如果是 LinuxMacOS,请参考以下命令

# 打包 eureka
mvn clean package && unzip target/eureka-0.0.1-SNAPSHOT.war -o target/exploded && docker build -t $IMAGE -f Dockerfile.dev $BUILD_CONTEXT

# 打包 school
mvn clean package && unzip target/school-0.0.1-SNAPSHOT.war -o target/exploded && docker build -t $IMAGE -f Dockerfile.dev $BUILD_CONTEXT

# 打包 teacher
mvn clean package && unzip target/teacher-0.0.1-SNAPSHOT.war -o target/exploded && docker build -t $IMAGE -f Dockerfile.dev $BUILD_CONTEXT

# 打包 student
mvn clean package && unzip target/student-0.0.1-SNAPSHOT.war -o target/exploded && docker build -t $IMAGE -f Dockerfile.dev $BUILD_CONTEXT

仅第一次运行须要打包 war 再解压的操作,后续可通过 mvn compile 即能够 class 为粒度实现 热更新

总结

本次演示所应用的微服务项目是很多年前笔者为了学习 Spring Cloud 而编写的 Demo
时隔多年 Spring Cloud 曾经不再举荐 Eureka 作为服务发现与注册核心。
同时 k8s 自身也反对将 CoreDNS 作为服务发现 / 注册的组件应用。
所以读者不用纠结 Demo 代码中的谬误,因为本文的重点是 skaffold 的配置与应用。

正文完
 0