加速云原生的 Java 开发

今天来说说日常在Kubernetes开发Java项目遇到的问题.

当我们新建一个项目的时候, 总是面临需要新建manifest, 平时都是copy+paste+modify. 能否以变成的方式来生成?

开发时的步骤也比较繁琐: docker build, docker push, kubectl apple, kubectl delete pod. 对于一个Java应用来说还多了一步编译. 操作一次还ok, 但是一天十几次总会有想吐的感觉. 这些步骤能否简化成一个命令, 甚至修改了代码自动就完成上面一系列的操作?

实现这些我们需要几个工具: dekorate, Jib, Skaffold. 其中Jib也在上一篇文章使用Jib为Java应用构建镜像中介绍过.

dekorate

Dekorate is a collection of Java compile-time generators and decorators for Kubernetes/OpenShift manifests. Dekorate是Java编译时生成和装饰Kubernetes/OpenShift的manifests的工具

快速开始

1. 通过使用Spring Initializer生成一个项目(Spring Boot 2.2.2), 并加入依赖:

<dependency>
  <groupId>io.dekorate</groupId>
  <artifactId>kubernetes-spring-starter</artifactId>
  <version>0.10.0</version>
</dependency>

2. 加入一个简单的Controller:

/**
 * @author Addo.Zhang
 * @date 2019/12/22
 */
@RestController
public class DekorateExampleController {

    @GetMapping
    public String hi() {
        return "Hello World";
    }

}

3. 执行命令mvn clean install, 然后在target/classes/META-INF/dekorate目录下可以找到kubernetes.jsonkubernetes.yml两个文件.

kubernetes.yml的内容:

---
apiVersion: "v1"
kind: "Service"
metadata:
  labels:
    app: "dekorate-example"
    version: "0.0.1-SNAPSHOT"
    group: "addo"
  name: "dekorate-example"
spec:
  ports:
  - name: "http"
    port: 8081
    targetPort: 8081
  selector:
    app: "dekorate-example"
    version: "0.0.1-SNAPSHOT"
    group: "addo"
  type: "ClusterIP"
---
apiVersion: "apps/v1"
kind: "Deployment"
metadata:
  labels:
    app: "dekorate-example"
    version: "0.0.1-SNAPSHOT"
    group: "addo"
  name: "dekorate-example"
spec:
  replicas: 1
  selector:
    matchLabels:
      app: "dekorate-example"
      version: "0.0.1-SNAPSHOT"
      group: "addo"
  template:
    metadata:
      labels:
        app: "dekorate-example"
        version: "0.0.1-SNAPSHOT"
        group: "addo"
    spec:
      containers:
      - env:
        - name: "KUBERNETES_NAMESPACE"
          valueFrom:
            fieldRef:
              fieldPath: "metadata.namespace"
        image: "addo/dekorate-example:0.0.1-SNAPSHOT"
        imagePullPolicy: "IfNotPresent"
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: "/actuator/info"
            port: 8081
            scheme: "HTTP"
          initialDelaySeconds: 0
          periodSeconds: 30
          successThreshold: 1
          timeoutSeconds: 10
        name: "dekorate-example"
        ports:
        - containerPort: 8081
          name: "http"
          protocol: "TCP"
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: "/actuator/health"
            port: 8081
            scheme: "HTTP"
          initialDelaySeconds: 0
          periodSeconds: 30
          successThreshold: 1
          timeoutSeconds: 10

yml中包含了ServiceDeployment两部分, dekorate完美兼容的Spring:

  • app: dekorate-example: 项目名
  • version: 0.0.1-SNAPSHOT: 项目当前版本
  • group: addo: 是我系统当前用户名
  • /actuator/health: Spring Boot 2.2后actuator的health endpoint, 作为readinessProbe
  • /actuator/info: Spring Boot 2.2后actuator的endpoint, 作为livenessProbe

进阶

前面yml的内容都是自动生成的, 假如有些特殊的需求. 比如修改镜像的repository即这里的group, 如何操作?

dekorate.kubernetes.group = addozhang

结果:

Change Image Repository

或者修改Service的类型为NodePort

dekorate.kubernetes.service-type = NodePort

NodePort Service

配置

dekoration提供了丰富的配置来个性化manifest.

除了上面使用的配置文件(properties/yaml)的方式, 还提供了Annotation注解配置方式.

import io.dekorate.kubernetes.annotation.Env;
import io.dekorate.kubernetes.annotation.KubernetesApplication;

@KubernetesApplication(envVars = @Env(name = "key1", value = "var1"))
public class Main {

  public static void main(String[] args) {
    //Your code goes here
  }
}

@KubernetesApplication Annotation

Jib

Jib的说明请看上一篇文章:使用Jib为Java应用构建镜像

插件配置

下面是针对该项目添加的配置:

<plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>jib-maven-plugin</artifactId>
    <version>1.8.0</version>
    <configuration>
        <container>
            <jvmFlags>
                <jvmFlag>-Xmx128m</jvmFlag>
                <jvmFlag>-Xms64m</jvmFlag>
            </jvmFlags>
            <labels>
                <Author>Addo.Zhang</Author>
            </labels>
            <creationTime>USE_CURRENT_TIMESTAMP</creationTime>
        </container>
        <from>
            <image>openjdk:8-jdk-alpine</image>
        </from>
        <to>
            <image>addo/dekorate-example</image>
            <tags>
                <tag>latest</tag>
            </tags>
        </to>
        <allowInsecureRegistries>true</allowInsecureRegistries>
    </configuration>
</plugin>

执行命令mvn compile jib:dockerBuild便可以编译代码, 构建镜像并推送到镜像仓库.

Skaffold

Skaffold也是GoogleContainerTools中的一个工具.

Skaffold is a command line tool that facilitates continuous development for Kubernetes applications. You can iterate on your application source code locally then deploy to local or remote Kubernetes clusters. Skaffold handles the workflow for building, pushing and deploying your application. It also provides building blocks and describe customizations for a CI/CD pipeline. Skaffold是一个命令行工具, 可促进Kubernetes应用程序的持续开发. 可以在本地迭代应用程序源代码, 然后部署到本地或远程Kubernetes集群. Skaffold处理构建, 推送和部署应用程序的工作流程. 它还提供了构建块并描述了CI/CD管道的自定义.

在我们这个例子中, 通过与Jib的联动, 完成编译代码, 构建镜像, 推送镜像, 部署一系列操作.

![Run](https://raw.githubusercontent.com/addozhang/oss/master/blog/upload/2019-12-23 15.12.24.gif)

截屏中的操作, 因为没有代码改动而不续构建镜像, Skaffold直接从cache中获取镜像并部署到Kubernetes中.

Skaffold操作

1. 执行命令skaffold init --XXenableJibInit并在提示出输入y

2. 该命令会生成一个名为skaffold.yaml的文件

由于dekorate同时生成了jsonyaml格式的manifest, 被skaffold检测到. 实际操作中只需要其中一个即可.

apiVersion: skaffold/v1
kind: Config
metadata:
  name: dekorate-example
build:
  artifacts:
  - image: addo/dekorate-example
    jib: {}
deploy:
  kubectl:
    manifests:
    - target/classes/META-INF/dekorate/kubernetes.json
    - target/classes/META-INF/dekorate/kubernetes.yml

3. 执行skaffold run

4. pod启动完成后, 通过kubectl port-forward PODNAME-HERE 8081

5. 请求http http://localhost:8081

进阶

Skaffold的功能强大, 目前个人使用的有限, 有时间新开一篇来学习一下.

CLI

➜  ~ skaffold help
A tool that facilitates continuous development for Kubernetes applications.

  Find more information at: https://skaffold.dev/docs/getting-started/

End-to-end pipelines:
  run               Run a pipeline
  dev               Run a pipeline in development mode
  debug             [beta] Run a pipeline in debug mode

Pipeline building blocks for CI/CD:
  build             Build the artifacts
  deploy            Deploy pre-built artifacts
  delete            Delete the deployed application
  render            [alpha] Perform all image builds, and output rendered Kubernetes manifests

Getting started with a new project:
  init              [alpha] Generate configuration for deploying an application
  fix               Update old configuration to newest schema version

Other Commands:
  completion        Output shell completion for the given shell (bash or zsh)
  config            Interact with the Skaffold configuration
  credits           Export third party notices to given path (./skaffold-credits by default)
  diagnose          Run a diagnostic on Skaffold
  version           Print the version information

Usage:
  skaffold [flags] [options]

Use "skaffold <command> --help" for more information about a given command.
Use "skaffold options" for a list of global command-line options (applies to all commands).

Yaml配置

参考skaffold.yaml

总结

文章的开头我们提到如何做到修改代码后自动完成一些列的操作, 通过skaffold dev就可以实现.

文章中使用的dekoration-example可在GitHub上找到.


文章同步发送到公众号:云编码 (微信号:sevenfeet)。

qrcode

comments powered by Disqus