本文介绍在开发过程中,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包含了下面的依赖关系和插件
org.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-testtestorg.springframework.bootspring-boot-maven-plugin
其中的HelloController包含一个方法,返回欢迎信息和执行的主机地址。
@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仓库。
com.google.cloud.toolsjib-maven-plugin1.8.0openjdk@sha256:b3e19d27caa8249aad6f90c6e987943d03e915bbf3a66bc1b7f994a4fed668f6docker.io/${docker.image.prefix}/${project.artifactId}${project.version}com.mydeveloperplanet.myskaffoldplanet.MySkaffoldPlanetApplicationnobody
为了使用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 -oyamlapiVersion: 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
ENDKubernetes 线上直播班