通过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: PersistentVolumeapiVersion: v1metadata:  name: mysql-pv-volume  namespace: spring-cloud  labels:    type: localspec:  storageClassName: manual  capacity:    storage: 2Gi  accessModes:    - ReadWriteOnce  hostPath:    path: "/opt/data/mysql"

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

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

apiVersion: v1kind: PersistentVolumeClaimmetadata:  name: mysql-pv-claim  namespace: spring-cloudspec:  storageClassName: manual  accessModes:    - ReadWriteOnce  resources:    requests:      storage: 2Gi

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

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

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

apiVersion: v1kind: Servicemetadata:  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/v1kind: StatefulSetmetadata:  name: mysql  namespace: spring-cloudspec:  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/v1kind: Deploymentmetadata:  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: v1kind: Servicemetadata:  name: datacenter  namespace: spring-cloudspec:  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: v1clusters:- 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@kubernetescurrent-context: kubernetes-admin@kubernetes   # 设置以后上下文的所应用的k8s集群kind: Configpreferences: {}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-reloadsystemctl restart docker

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

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

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

C:\WINDOWS\system32>docker infoClient: 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: datacenterbuild:  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: Dockerfiledeploy:  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 devtime="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=DevLoopListing files to watch... - datacenter-eureka - datacenter-school - datacenter-teacher - datacenter-studentGenerating tags... - datacenter-eureka -> datacenter-eureka:13577a5 - datacenter-school -> datacenter-school:13577a5 - datacenter-teacher -> datacenter-teacher:13577a5 - datacenter-student -> datacenter-student:13577a5Checking cache... - datacenter-eureka: Found. Tagging - datacenter-school: Found. Tagging - datacenter-teacher: Found. Tagging - datacenter-student: Found. TaggingTags used in deployment: - datacenter-eureka -> datacenter-eureka:769afdbaaf2a35acada2a56cf1d1cccbc8a8ab8196396a8ff9e2803cf6a49490 - datacenter-school -> datacenter-school:b89167e724932d41e40945a39ff04d84e419345957c4c0a022e7c4694153b609 - datacenter-teacher -> datacenter-teacher:9d013f9295b7bd3e75b68b2d8a9df434a77cbc9514df1ae36a967b6841c4328f - datacenter-student -> datacenter-student:3f5267479ce35cec929485edce5f1dfc2cb1017136bbc90f2a0de5cd4f48f808Starting 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 driverWARN[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/ubuntuapt install fuse-overlayfs

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

apiVersion: skaffold/v2beta26                     # version of the configuration.kind: Config                                     # always Config.metadata: name: datacenterbuild: 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@EnableFeignClientspublic 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-focalRUN 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.xmlCOPY target/exploded /usr/local/tomcat/webapps/ROOTCOPY target/classes /usr/local/tomcat/webapps/ROOT/WEB-INF/classesCMD ["catalina.sh", "run"]

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

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

apiVersion: skaffold/v2beta26                     # version of the configuration.kind: Config                                     # always Config.metadata:  name: datacenterbuild:  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/explodeddeploy:  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,请参考以下命令

# 打包eurekamvn clean package && unzip target/eureka-0.0.1-SNAPSHOT.war -o target/exploded && docker build -t $IMAGE -f Dockerfile.dev $BUILD_CONTEXT# 打包schoolmvn clean package && unzip target/school-0.0.1-SNAPSHOT.war -o target/exploded && docker build -t $IMAGE -f Dockerfile.dev $BUILD_CONTEXT# 打包teachermvn clean package && unzip target/teacher-0.0.1-SNAPSHOT.war -o target/exploded && docker build -t $IMAGE -f Dockerfile.dev $BUILD_CONTEXT# 打包studentmvn 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 的配置与应用。