vlambda博客
学习文章列表

一款让K8S开发变得简单的工具!

本文介绍在开发过程中,Skaffold自动化build和deploy应用到K8S集群。

Skaffold是由Google发布的命令行工具,专注于促进K8S应用的持续deployment。自动化building和deploying到k8s集群的任务,可以让开发者专注于编写代码。Skaffold是不是很有趣呢,让我们来仔细观察一下吧。

简介

2019年11月份,Skaffold普遍可用的版本发布了,承诺自动化开发工作流程,以此来节省开发者的时间。那么,Skaffold提供哪些功能呢?

  • 当你开发的时候,检测代码的变动

  • 基于你的Dockerfile或者Jib自动化build和创建你的artifacts(也就是Docker image)

  • 给artifacts打tag

  • 把artifacts发布/部署到你的kubernetes集群

为了熟悉Skaffold,我们使用minikube来运行一个本地的K8S集群,部署K8S的命令行工具kubectl。

更深入了解Skaffold,建议读者去官方网站去查看文档和例子。本文使用的源代码都在github是可见的。

先决条件

开始之前,我们需要安装minikube,kubectl和Skaffold,OS版本是Ubuntu 18.04

安装Minikube

Minikube(1.6.2)的安装工作在Linux上非常简单。如果使用Windows操作系统,请查询我们的过往文章,操作步骤还是非常复杂,未来可能会有所改善。

首先,检查我们的OS是否开启了虚拟化支持

$ egrep -q 'vmx|svm' /proc/cpuinfo && echo yes || echo no yes

命令的输出是yes,我们不需要额外执行命令了。

下载并安装minikube

$ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_1.6.2.deb && sudo dpkg -i minikube_1.6.2.deb

启动minikube

$ minikube startminikube v1.6.2 on Ubuntu 18.04Automatically selected the 'virtualbox' driver (alternates: [none])Downloading VM boot image ...> minikube-v1.6.0.iso.sha256: 65 B / 65 B [--------------] 100.00% ? p/s 0s> minikube-v1.6.0.iso: 150.93 MiB / 150.93 MiB [-] 100.00% 8.44 MiB p/s 18sCreating virtualbox VM (CPUs=2, Memory=2000MB, Disk=20000MB) ...Preparing Kubernetes v1.17.0 on Docker '19.03.5' ...Downloading kubelet v1.17.0Downloading kubeadm v1.17.0Pulling images ...Launching Kubernetes ...Waiting for cluster to come online ...Done! kubectl is now configured to use "minikube"

安装Kubectl

Kubectl的安装手册可以在kubernetes官网查看。对于LinuxOS,我们需要执行下面的步骤,使用kubectl version命令可以确认是否安装成功。

$ curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl$ chmod +x ./kubectl$ sudo mv ./kubectl /usr/local/bin/kubectl$ kubectl versionClient 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.0", GitCommit:"70132b0f130acc0bed193d9ba59dd186f0e634cf", GitTreeState:"clean", BuildDate:"2019-12-07T21:12:17Z", GoVersion:"go1.13.4", Compiler:"gc", Platform:"linux/amd64"}

安装Skaffold

Skaffold的安装文档可以在官网查看。安装方法非常和kubectl非常类似。

$ curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64$ chmod +x skaffold$ sudo mv skaffold /usr/local/bin$ skaffold versionv1.1.0

创建Demo应用

我们将会创建一个简单的Spring Boot demo应用。我们使用Spring MVC,创建一个REST endpoint,将会返回一个欢迎信息。

我们的Pom包含了下面的依赖关系和插件

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
@RestControllerpublic class HelloController {@RequestMapping("/hello")public String hello() {StringBuilder message = new StringBuilder("Hello Skaffold!");try {InetAddress ip = InetAddress.getLocalHost();message.append(" From host: " + ip);} catch (UnknownHostException e) {e.printStackTrace();}return message.toString();}}

使用Skaffold

现在我们已经完成了所有的准备,是时候开始使用Skaffold了。现在,我们故意遗漏一些Skaffold需要的重要配置,这可以让我们来检查报错信息和解决方法。

生成skaffold.yaml

Skaffold需要一个skaffold.yaml文件,包含你需要使用的开发工作流程。可以在你的项目目录里使用init命令来自动生成。

$ skaffold initFATA[0000] one or more valid Kubernetes manifests is required to run skaffold

Skaffold init并不会为我们创建k8s的mainfest文件,我们需要手动创建。

我们将会使用kubectl工具来创建k8s的部署文件。我们把Kubectl命令的输出复制到deployment.yaml文件中。命令行参数 –dry-run 可以确保部署并没有被执行, -oyaml参数会输出配置文件,我们可以从中复制内容。

$ kubectl create deployment myskaffoldplanet --image=docker.io/mydeveloperplanet/myskaffoldplanet --dry-run -oyamlapiVersion: apps/v1kind: Deploymentmetadata:creationTimestamp: nulllabels:app: myskaffoldplanetname: myskaffoldplanetspec:replicas: 1selector:matchLabels:app: myskaffoldplanetstrategy: {}template:metadata:creationTimestamp: nulllabels:app: myskaffoldplanetspec:containers:- image: docker.io/mydeveloperplanet/myskaffoldplanetname: myskaffoldplanetresources: {}status: {}

再次执行skaffold init命令,返回新的错误

$ skaffold initFATA[0000] one or more valid builder configuration (Dockerfile or Jib configuration) must be present to build images with skaffold; please provide at least one build config and try again or run `skaffold init --skip-build`

上面的报错是可以预见的,因为我们并没有提供Dockerfile或者Jib配置。使用我们在之前的文章中提到的方法,我们使用Jib。添加Jib Maven插件到我们的pom中。这一次我们不提供认证,因为我们并不会把docker镜像提交给docker仓库。

<plugin><groupId>com.google.cloud.tools</groupId><artifactId>jib-maven-plugin</artifactId><version>1.8.0</version><configuration><!-- openjdk:11.0.5-jre --><from><image>openjdk@sha256:b3e19d27caa8249aad6f90c6e987943d03e915bbf3a66bc1b7f994a4fed668f6</image></from><to><image>docker.io/${docker.image.prefix}/${project.artifactId}</image><tags><tag>${project.version}</tag></tags></to><container><mainClass>com.mydeveloperplanet.myskaffoldplanet.MySkaffoldPlanetApplication</mainClass><user>nobody</user></container></configuration></plugin>

为了使用Jib,我们需要在skaffold命令中加入参数:–XxenableJibInit

$ skaffold init --XXenableJibInitapiVersion: skaffold/v2alpha1kind: Configmetadata:name: myskaffoldplanetbuild:artifacts:- image: docker.io/mydeveloperplanet/myskaffoldplanetjib: {}deploy:kubectl:manifests:- k8s/deployment.yamlDo you want to write this configuration to skaffold.yaml? [y/n]: yConfiguration skaffold.yaml was writtenYou can now run [skaffold build] to build the artifactsor [skaffold run] to build and deployor [skaffold dev] to enter development mode, with auto-redeploy

Skaffold持续发布

为了配合skaffold dev命令做实验,我们已经做好了所有配置。这将会扫描我们的项目,一旦有变更,便会自动build和部署到我们的K8S集群中。执行下面的命令

$ skaffold dev

我们的应用正在被build部署到K8S集群中。操作可以在minikube的dashboard里观察。

minikube dashboard

因为并没有创建service的缘故,现在还不能调用我们的URL。我们通过NodePort方式映射端口8080。使用kubectl命令生成service yaml文件,复制内容(忽略label)到文件service.yaml到k8s的目录:

$ kubectl expose deployment myskaffoldplanet --type=NodePort --port=8080 --dry-run -oyaml
apiVersion: v1kind: Servicemetadata:creationTimestamp: nulllabels:app: myskaffoldplanetapp.kubernetes.io/managed-by: skaffold-v1.1.0skaffold.dev/builder: localskaffold.dev/cleanup: "true"skaffold.dev/deployer: kubectlskaffold.dev/docker-api-version: "1.40"skaffold.dev/run-id: c8fc23d2-85f5-453a-bc22-19f4a9ec88a6skaffold.dev/tag-policy: git-commitskaffold.dev/tail: "true"name: myskaffoldplanetspec:ports:- port: 8080protocol: TCPtargetPort: 8080selector:app: myskaffoldplanettype: NodePortstatus:loadBalancer: {}

还有,把service.yaml文件作为mainfest文件添加到skaffold.yaml文件:

deploy:kubectl:manifests:- k8s/deployment.yaml- k8s/service.yaml

Skaffold会迅速观察到这些变化,自动创建服务。可以在Skaffold console输出中得到确认:

Starting deploy...- deployment.apps/myskaffoldplanet configured- service/myskaffoldplanet createdWatching for changes...

使用Kubectl来确认服务已经被创建:

$ kubectl get servicesNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.96.0.1 443/TCP 24hmyskaffoldplanet NodePort 10.96.65.87 8080:30272/TCP 42s

NodePort已经被分配给30272端口。我们现在可以引用我们的Rest endpoint:

$ curl $(minikube ip):30272/helloHello Skaffold! From host: myskaffoldplanet-76f44959c9-tcvw5/172.17.0.6

在HelloController中修改欢迎致辞:

StringBuilder message = new StringBuilder(“Hello there, Skaffold!”);

再一次地,改动自动被Skaffold识别,后台进程中,我们的应用正在被build和部署。我们再一次调用URL:

$ curl $(minikube ip):30272/helloHello there, Skaffold! From host: myskaffoldplanet-54b59fb785-hczn8/172.17.0.7

我们也可以使用skaffold up命令来基于需求部署应用:

$ skaffold run...Starting deploy...- deployment.apps/myskaffoldplanet created- service/myskaffoldplanet createdYou can also run [skaffold run --tail] to get the logs

Troubleshooting

之前执行skaffold dev和skaffold run命令遇到的报错如下:

rpc error: code = Unknown desc = Error response from daemon: pull access denied for mydeveloperplanet/myskaffoldplanet, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

解决方案:把下面的内容加入到skaffold.yaml文件。

build:local:push: falseartifacts:- image: docker.io/mydeveloperplanet/myskaffoldplanetjib: {}

结论

本文中,我们观察了开发环境中Skaffold自动build和部署应用给K8S集群的过程。本文的内容仅仅是稍微观察Skaffold提供的功能,但是skaffold确实让人印象深刻。Skaffold绝对是值得使用和后续观察的。

译者:李原

原文链接:https://dzone.com/articles/skaffold-k8s-development-made-easy


END