Kubernetes官方java客戶(hù)端之七:patch操作

      網(wǎng)友投稿 700 2022-05-30

      歡迎訪問(wèn)我的GitHub

      https://github.com/zq2599/blog_demos

      內(nèi)容:所有原創(chuàng)文章分類(lèi)匯總及配套源碼,涉及Java、Docker、Kubernetes、DevOPS等;

      概覽

      本文是《Kubernetes官方j(luò)ava客戶(hù)端》系列的第七篇,以下提到的

      java客戶(hù)端

      都是指

      client-jar.jar

      本文主要內(nèi)容是通過(guò)java客戶(hù)端發(fā)起patch請(qǐng)求,用來(lái)修改已有資源;

      接下來(lái)會(huì)對(duì)kubernetes的patch做一些介紹,由于咱們這里的

      重點(diǎn)還是java客戶(hù)端的patch操作

      ,因此不會(huì)對(duì)patch的原理和概念展開(kāi)太多,僅做最基本的說(shuō)明能即可;

      本文內(nèi)容

      這是篇萬(wàn)字長(zhǎng)文,所以一開(kāi)始就要明確本文的核心內(nèi)容:開(kāi)發(fā)一個(gè)SpringBoot應(yīng)用并部署在kubernetes環(huán)境,這個(gè)應(yīng)用通過(guò)kubernetes的java客戶(hù)端向API Server發(fā)請(qǐng)求,請(qǐng)求內(nèi)容包括:創(chuàng)建名為

      test123

      的deployment、對(duì)這個(gè)deployment進(jìn)行patch操作,如下圖:

      接下來(lái)先了解一些kubernetes的patch相關(guān)的基本知識(shí);

      關(guān)于patch

      是對(duì)各種資源的增刪改查是kubernetes的基本操作;

      對(duì)于修改操作,分為

      Replace

      Patch

      兩種;

      Replace好理解,就是用指定資源替換現(xiàn)有資源,replace有個(gè)特點(diǎn),就是optimistic lock約束(類(lèi)似與轉(zhuǎn)賬操作,先讀再計(jì)算再寫(xiě)入);

      Patch用來(lái)對(duì)資源做局部更新,沒(méi)有optimistic lock約束,總是最后的請(qǐng)求會(huì)生效,因此如果您只打算修改局部信息,例如某個(gè)屬性,只要指定屬性去做patch即可(如果用Replace,就只能先取得整個(gè)資源,在本地修改指定屬性,再用Replace整體替換);

      更詳細(xì)的信息請(qǐng)參考下圖,來(lái)自官方文檔,地址:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/

      patch的四種類(lèi)型

      kubernetes的patch一共有四種:

      json patch:在請(qǐng)求中指定操作類(lèi)型,例如:add、replace,再指定json內(nèi)容進(jìn)行操作z,請(qǐng)參考:https://tools.ietf.org/html/rfc6902

      merge patch:合并操作,可以提交整個(gè)資源的信息,與現(xiàn)有信息進(jìn)行合并后生效,也可以提交部分信息用于替換,請(qǐng)參考:https://tools.ietf.org/html/rfc7386

      strategic merge patch:json patch和merge patch都遵守rfc標(biāo)準(zhǔn),但是strategic merge patch卻是kubernetes獨(dú)有的,官方中文文檔中稱(chēng)為

      策略性合并

      ,也是merge的一種,但是真正執(zhí)行時(shí)kubernetes會(huì)做合并還是替換是和具體的資源定義相關(guān)的(具體策略由 Kubernetes 源代碼中字段標(biāo)記中的 patchStrategy 鍵的值指定),以Pod的Container為例,下面是其源碼,紅框中顯示其Container節(jié)點(diǎn)的patchStrategy屬性是merge,也就是說(shuō)如果您提交了一份strategic merge patch,里面的內(nèi)容是關(guān)于Pod的Container的,那么原有的Container不會(huì)被替換,而是合并(例如以前只有nginx,提交的strategic merge patch是redis,那么最終pod下會(huì)有兩個(gè)container:nginx和redis):

      通過(guò)源碼查看資源的

      patchStrategy

      屬性是很麻煩的事情,因此也可以通過(guò)Kubernetes API 文檔來(lái)查看,如下圖,地址是:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#podspec-v1-core

      第四種是apply patch:主要是指kubernetes 1.14版本開(kāi)始的server-side apply,由APIServer 做 diff 和 merge 操作,很多原本易碎的現(xiàn)象都得到了解決(例如controller和kubectl都在更新),另外要格外注意的是:1.14版本默認(rèn)是不開(kāi)啟server-side apply特性的,具體的開(kāi)啟操作在下面會(huì)詳細(xì)講解;

      以上是對(duì)kubernetes四種patch的簡(jiǎn)介,講得很淺,如果您想深入了解每種patch,建議參閱官方資料,接下來(lái)咱們聚焦java客戶(hù)端對(duì)這些patch能力的實(shí)現(xiàn);

      源碼下載

      如果您不想編碼,可以在GitHub下載所有源碼,地址和鏈接信息如下表所示(https://github.com/zq2599/blog_demos):

      這個(gè)git項(xiàng)目中有多個(gè)文件夾,本章的應(yīng)用在

      kubernetesclient

      文件夾下,如下圖紅框所示:

      實(shí)戰(zhàn)步驟概述

      接下來(lái)會(huì)創(chuàng)建一個(gè)springboot工程(該工程是

      kubernetesclient

      的子工程),針對(duì)四種patch咱們都有對(duì)應(yīng)的操作;

      每種patch都會(huì)準(zhǔn)備對(duì)應(yīng)的json文件,提前將這些文件的內(nèi)容保存在字符串變量中,在程序里用kubernetes客戶(hù)端的patch專(zhuān)用API,將此json字符串發(fā)送出去,流程簡(jiǎn)圖如下:

      編碼完成后,就來(lái)動(dòng)手驗(yàn)證功能,具體操作如下:

      部署名為

      patch

      的deployment,這里面是咱們編碼的SpringBoot工程,提供多個(gè)web接口;

      瀏覽器訪問(wèn)

      /patch/deploy

      接口,就會(huì)創(chuàng)建名為

      test123

      的deployment,這個(gè)deployment里面是個(gè)nginx,接下來(lái)的patch操作都是針對(duì)這個(gè)名為test123的deployment;

      瀏覽器訪問(wèn)

      test123

      的nginx服務(wù),確保部署成功了;

      瀏覽器訪問(wèn)

      /patch/json

      接口,該接口會(huì)修改test123的一個(gè)屬性:

      terminationGracePeriodSeconds

      瀏覽器訪問(wèn)

      /patch/fullmerge

      接口,該接口會(huì)提交全量merge請(qǐng)求,修改內(nèi)容很少,僅增加了一個(gè)label屬性;

      接下來(lái)是對(duì)比merge patch和strategic merge patch區(qū)別,分別訪問(wèn)

      /patch/partmerge

      /patch/strategic

      這兩個(gè)接口,其實(shí)它們操作的是同一段patch內(nèi)容(一個(gè)新的container),結(jié)果merge patch會(huì)替換原有的continer,而strategic merge patch不會(huì)動(dòng)原有的container,而是新增container,導(dǎo)致test123這個(gè)deployment下面的pod從一個(gè)變?yōu)閮蓚€(gè);

      最后是apply yaml patch,訪問(wèn)接口

      /patch/apply

      ,會(huì)將nginx容器的標(biāo)簽從

      1.18.0

      改為

      1.19.1

      ,咱們只要在瀏覽器訪問(wèn)test123里面的nginx服務(wù)就能確定是否修改生效了;

      準(zhǔn)備工作

      準(zhǔn)備工作包括創(chuàng)建工程、編寫(xiě)輔助功能代碼、初始化代碼等:

      打開(kāi)《Kubernetes官方j(luò)ava客戶(hù)端之一:準(zhǔn)備 》一文創(chuàng)建的項(xiàng)目

      kubernetesclient

      ,新增名為

      patch

      的子工程,pom.xml內(nèi)容如下:

      4.0.0 com.bolingcavalry kubernetesclient 1.0-SNAPSHOT ../pom.xml com.bolingcavalry patch 0.0.1-SNAPSHOT patch patch demo jar org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-json org.springframework.boot spring-boot-starter-actuator org.projectlombok lombok true io.kubernetes client-java org.springframework.boot spring-boot-maven-plugin 2.3.0.RELEASE true

      編寫(xiě)一個(gè)輔助類(lèi)

      ClassPathResourceReader.java

      ,作用是讀取json文件的內(nèi)容作為字符串返回:

      package com.bolingcavalry.patch; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.stream.Collectors; import org.springframework.core.io.ClassPathResource; public class ClassPathResourceReader { private final String path; private String content; public ClassPathResourceReader(String path) { this.path = path; } public String getContent() { if (content == null) { try { ClassPathResource resource = new ClassPathResource(path); BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream())); content = reader.lines().collect(Collectors.joining("\n")); reader.close(); } catch (IOException ex) { throw new RuntimeException(ex); } } return content; } }

      接下來(lái)新建本篇文章的核心類(lèi)

      PatchExample.java

      ,首先這個(gè)類(lèi)中有main方法,整個(gè)應(yīng)用從這里啟動(dòng):

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

      接下來(lái)有兩個(gè)常量定義,分別是kubernetes環(huán)境里用來(lái)測(cè)試的deployment名稱(chēng),以及namespace名稱(chēng):

      static String DEPLOYMENT_NAME = "test123"; static String NAMESPACE = "default";

      然后定義幾個(gè)字符串變量,執(zhí)行patch操作時(shí)用到的json內(nèi)容都保存到這些字符串變量中:

      static String deployStr, jsonStr, mergeStr, strategicStr, applyYamlStr;

      resources

      文件夾中放入json文件,稍后的初始化代碼會(huì)將這些文件讀取到字符串變量中,如下圖,這些json文件的內(nèi)容稍后會(huì)詳細(xì)說(shuō)明:

      編寫(xiě)初始化代碼(通過(guò)

      PostConstruct

      注解實(shí)現(xiàn)),主要是客戶(hù)端配置,還有將json文件的內(nèi)容讀出來(lái),保存到剛剛準(zhǔn)備的字符串變量中:

      @PostConstruct private void init() throws IOException { // 設(shè)置api配置 ApiClient client = Config.defaultClient(); Configuration.setDefaultApiClient(client); // 設(shè)置超時(shí)時(shí)間 Configuration.getDefaultApiClient().setConnectTimeout(30000); // 部署用的JSON字符串 deployStr = new ClassPathResourceReader("deploy.json").getContent(); // json patch用的JSON字符串 jsonStr = new ClassPathResourceReader("json.json").getContent(); // merge patch用的JSON字符串,和部署的JSON相比:replicas從1變成2,增加一個(gè)名為from的label,值為merge mergeStr = new ClassPathResourceReader("merge.json").getContent(); // strategic merge patch用的JSON字符串 strategicStr = new ClassPathResourceReader("strategic.json").getContent(); // server side apply用的JSON字符串 applyYamlStr = new ClassPathResourceReader("applyYaml.json").getContent(); }

      以上就是準(zhǔn)備工作;

      創(chuàng)建服務(wù)

      首先要開(kāi)發(fā)一個(gè)部署的接口,通過(guò)調(diào)用此接口可以在kubernetes環(huán)境部署一個(gè)deployment:

      部署服務(wù)的path是

      /patch/deploy

      ,代碼如下,可見(jiàn)部署deployment的代碼分為三步:創(chuàng)建api實(shí)例、用字符串創(chuàng)建body實(shí)例、把body傳給api即可:

      /** * 通用patch方法 * @param patchFormat patch類(lèi)型,一共有四種 * @param deploymentName deployment的名稱(chēng) * @param namespace namespace名稱(chēng) * @param jsonStr patch的json內(nèi)容 * @param fieldManager server side apply用到 * @param force server side apply要設(shè)置為true * @return patch結(jié)果對(duì)象轉(zhuǎn)成的字符串 * @throws Exception */ private String patch(String patchFormat, String deploymentName, String namespace, String jsonStr, String fieldManager, Boolean force) throws Exception { // 創(chuàng)建api對(duì)象,指定格式是patchFormat ApiClient patchClient = ClientBuilder .standard() .setOverridePatchFormat(patchFormat) .build(); log.info("start deploy : " + patchFormat); // 開(kāi)啟debug便于調(diào)試,生產(chǎn)環(huán)境慎用!!! patchClient.setDebugging(true); // 創(chuàng)建deployment ExtensionsV1beta1Deployment deployment = new ExtensionsV1beta1Api(patchClient) .patchNamespacedDeployment( deploymentName, namespace, new V1Patch(jsonStr), null, null, fieldManager, force ); log.info("end deploy : " + patchFormat); return new GsonBuilder().setPrettyPrinting().create().toJson(deployment); }

      body實(shí)例用到的json字符串來(lái)自deploy.json文件,內(nèi)容如下,很簡(jiǎn)單,只有nginx的1.18.0版本的pod:

      { "kind":"Deployment", "apiVersion":"extensions/v1beta1", "metadata":{ "name":"test123", "labels":{ "run":"test123" } }, "spec":{ "replicas":1, "selector":{ "matchLabels":{ "run":"test123" } }, "template":{ "metadata":{ "creationTimestamp":null, "labels":{ "run":"test123" } }, "spec":{ "terminationGracePeriodSeconds":30, "containers":[ { "name":"test123", "image":"nginx:1.18.0", "ports":[ { "containerPort":80 } ], "resources":{ } } ] } }, "strategy":{ } }, "status":{ } }

      如此一來(lái),web瀏覽器只要訪問(wèn)

      /patch/deploy

      就能創(chuàng)建deployment了;

      發(fā)起patch請(qǐng)求的通用方法

      通過(guò)kubernetes的客戶(hù)端發(fā)起不同的patch請(qǐng)求,其大致步驟都是相同的,只是參數(shù)有所不同,我這里做了個(gè)私有方法,發(fā)起幾種patch請(qǐng)求的操作都調(diào)用此方法實(shí)現(xiàn)(只是入?yún)⒉煌?,可見(jiàn)都是先建好ApiClient實(shí)例,將patch類(lèi)型傳入,再創(chuàng)建V1Patch實(shí)例,將patch字符串傳入,最后執(zhí)行ExtensionsV1beta1Api實(shí)例的patchNamespacedDeployment方法即可發(fā)送patch請(qǐng)求:

      /** * 通用patch方法 * @param patchFormat patch類(lèi)型,一共有四種 * @param deploymentName deployment的名稱(chēng) * @param namespace namespace名稱(chēng) * @param jsonStr patch的json內(nèi)容 * @param fieldManager server side apply用到 * @param force server side apply要設(shè)置為true * @return patch結(jié)果對(duì)象轉(zhuǎn)成的字符串 * @throws Exception */ private String patch(String patchFormat, String deploymentName, String namespace, String jsonStr, String fieldManager, Boolean force) throws Exception { // 創(chuàng)建api對(duì)象,指定格式是patchFormat ApiClient patchClient = ClientBuilder .standard() .setOverridePatchFormat(patchFormat) .build(); log.info("start deploy : " + patchFormat); // 開(kāi)啟debug便于調(diào)試,生產(chǎn)環(huán)境慎用!!! patchClient.setDebugging(true); // 創(chuàng)建deployment ExtensionsV1beta1Deployment deployment = new ExtensionsV1beta1Api(patchClient) .patchNamespacedDeployment( deploymentName, namespace, new V1Patch(jsonStr), null, null, fieldManager, force ); log.info("end deploy : " + patchFormat); return new GsonBuilder().setPrettyPrinting().create().toJson(deployment); }

      上述代碼中,有一行代碼要格外重視,就是

      patchClient.setDebugging(true)

      這段,執(zhí)行了這一行,在log日志中就會(huì)將http的請(qǐng)求和響應(yīng)全部打印出來(lái),是我們調(diào)試的利器,但是日志內(nèi)容過(guò)多,生產(chǎn)環(huán)境請(qǐng)慎用;

      上述patch方法有六個(gè)入?yún)ⅲ鋵?shí)除了patch類(lèi)型和patch內(nèi)容,其他參數(shù)都可以固定下來(lái),于是再做個(gè)簡(jiǎn)化版的

      patch

      方法:

      /** * 通用patch方法,fieldManager和force都默認(rèn)為空 * @param patchFormat patch類(lèi)型,一共有四種 * @param jsonStr patch的json內(nèi)容 * @return patch結(jié)果對(duì)象轉(zhuǎn)成的字符串 * @throws Exception */ private String patch(String patchFormat, String jsonStr) throws Exception { return patch(patchFormat, DEPLOYMENT_NAME, NAMESPACE, jsonStr, null, null); }

      入?yún)atchFormat的值是四種patch類(lèi)型的定義,在V1Patch.java中,其值如下所示:

      接下來(lái)可以輕松的開(kāi)發(fā)各種類(lèi)型patch的代碼了;

      執(zhí)行json patch

      首先來(lái)看json patch要提交的內(nèi)容,即

      json.json

      文件的內(nèi)容,這些內(nèi)容在應(yīng)用啟動(dòng)時(shí)被保存到變量

      jsonStr

      ,如下所示,非常簡(jiǎn)單,修改了

      terminationGracePeriodSeconds

      屬性的值,原來(lái)是30,這個(gè)屬性在停止pod的時(shí)候用到,是等待pod的主進(jìn)程的最長(zhǎng)時(shí)間:

      [ { "op":"replace", "path":"/spec/template/spec/terminationGracePeriodSeconds", "value":27 } ]

      接下來(lái)就是web接口的代碼,可見(jiàn)非常簡(jiǎn)單,僅需調(diào)用前面準(zhǔn)備好的

      patch

      方法:

      /** * JSON patch格式的關(guān)系 * * @return * @throws Exception */ @RequestMapping(value = "/patch/json", method = RequestMethod.GET) public String json() throws Exception { return patch(V1Patch.PATCH_FORMAT_JSON_PATCH, jsonStr); }

      merge patch(全量)

      先嘗試全量的merge patch,也就是準(zhǔn)備好完整的deployment內(nèi)容,修改其中一部分后進(jìn)行提交,下圖是json文件merge.json的內(nèi)容,其內(nèi)容前面的deploy.json相比,僅增加了紅框處的內(nèi)容,即增加了一個(gè)label:

      代碼依然很簡(jiǎn)單:

      @RequestMapping(value = "/patch/fullmerge", method = RequestMethod.GET) public String fullmerge() throws Exception { return patch(V1Patch.PATCH_FORMAT_JSON_MERGE_PATCH, mergeStr); }

      merge patch(增量)

      前面曾提到merge patch和strategic merge patch的區(qū)別:merge patch提交一個(gè)container時(shí)做的是替換,而strategic merge patch提交一個(gè)container時(shí)做的是合并,為了展示這兩種patch的不同,這里我們就用同一個(gè)json內(nèi)容,分別執(zhí)行merge patch和strategic merge patch,看看結(jié)果有什么區(qū)別,這是最直觀的學(xué)習(xí)方法;

      這個(gè)json對(duì)應(yīng)的文件是

      strategic.json

      ,內(nèi)容如下:

      { "spec":{ "template":{ "spec":{ "containers":[ { "name":"test456", "image":"tomcat:7.0.105-jdk8" } ] } } } }

      增量merge的代碼如下:

      @RequestMapping(value = "/patch/partmerge", method = RequestMethod.GET) public String partmerge() throws Exception { return patch(V1Patch.PATCH_FORMAT_JSON_MERGE_PATCH, strategicStr); }

      strategic merge patch

      strategic merge patch用的json內(nèi)容和前面的增量merge patch是同一個(gè),代碼如下:

      @RequestMapping(value = "/patch/strategic", method = RequestMethod.GET) public String strategic() throws Exception { return patch(V1Patch.PATCH_FORMAT_STRATEGIC_MERGE_PATCH, strategicStr); }

      apply yaml patch

      apply yaml patch與其他patch略有不同,調(diào)用

      ExtensionsV1beta1Api

      的patchNamespacedDeployment方法發(fā)請(qǐng)求時(shí),fieldManager和force字段不能像之前那樣為空了:

      @RequestMapping(value = "/patch/apply", method = RequestMethod.GET) public String apply() throws Exception { return patch(V1Patch.PATCH_FORMAT_APPLY_YAML, DEPLOYMENT_NAME, NAMESPACE, applyYamlStr, "example-field-manager", true); }

      上面的代碼中,如果force字段不等于true,可能會(huì)導(dǎo)致patch失敗,在官方文檔也有說(shuō)明,如下圖紅框:

      apply yaml patch的json字符串來(lái)自文件

      applyYaml.json

      ,其內(nèi)容是從deploy.json直接復(fù)制的,然后改了下圖兩個(gè)紅框中的內(nèi)容,紅框1修改了nginx的版本號(hào),用來(lái)驗(yàn)證patch是否生效(原有版本是1.18),紅框2是kubernetes1.16之前的一個(gè)問(wèn)題,protocol字段必填,否則會(huì)報(bào)錯(cuò),問(wèn)題詳情請(qǐng)參考:https://github.com/kubernetes-sigs/structured-merge-diff/issues/130

      以上就是所有代碼和patch的內(nèi)容了,接下來(lái)部署到kubernetes環(huán)境實(shí)戰(zhàn)吧

      制作鏡像并且部署

      在patch工程目錄下執(zhí)行以下命令編譯構(gòu)建:

      mvn clean package -U -DskipTests

      在patch工程目錄下創(chuàng)建Dockerfile文件,內(nèi)容如下:

      # 指定基礎(chǔ)鏡像,這是分階段構(gòu)建的前期階段 FROM openjdk:8u212-jdk-stretch as builder # 執(zhí)行工作目錄 WORKDIR application # 配置參數(shù) ARG JAR_FILE=target/*.jar # 將編譯構(gòu)建得到的jar文件復(fù)制到鏡像空間中 COPY ${JAR_FILE} application.jar # 通過(guò)工具spring-boot-jarmode-layertools從application.jar中提取拆分后的構(gòu)建結(jié)果 RUN java -Djarmode=layertools -jar application.jar extract # 正式構(gòu)建鏡像 FROM openjdk:8u212-jdk-stretch WORKDIR application # 前一階段從jar中提取除了多個(gè)文件,這里分別執(zhí)行COPY命令復(fù)制到鏡像空間中,每次COPY都是一個(gè)layer COPY --from=builder application/dependencies/ ./ COPY --from=builder application/spring-boot-loader/ ./ COPY --from=builder application/snapshot-dependencies/ ./ COPY --from=builder application/application/ ./ ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

      在patch工程目錄下執(zhí)行以下命令創(chuàng)建docker鏡像:

      docker build -t 192.168.50.43:5888/common/patch:1.0-SNAPSHOT .

      如果您已經(jīng)配置了docker鏡像倉(cāng)庫(kù)私服,建議將此鏡像推送到私服上去,以便kubernetes上可以使用該鏡像,我這邊的推送命令如下,僅供參考(涉及到身份驗(yàn)證的話還請(qǐng)執(zhí)行docker login登錄):

      docker push 192.168.50.43:5888/common/patch:1.0-SNAPSHOT

      SSH登錄kubernetes環(huán)境,新建patch.yaml文件,內(nèi)容如下,image那里請(qǐng)按您的鏡像情況自行調(diào)整:

      apiVersion: v1 kind: Service metadata: name: patch namespace : kubernetesclient spec: type: NodePort ports: - port: 8080 nodePort: 30102 selector: name: patch --- apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace : kubernetesclient name: patch spec: replicas: 1 template: metadata: labels: name: patch spec: serviceAccountName: kubernates-client-service-account containers: - name: patch image: 192.168.50.43:5888/common/patch:1.0-SNAPSHOT tty: true livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 5 failureThreshold: 10 timeoutSeconds: 10 periodSeconds: 5 readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 5 timeoutSeconds: 10 periodSeconds: 5 ports: - containerPort: 8080 resources: requests: memory: "512Mi" cpu: "100m" limits: memory: "1Gi" cpu: "1000m"

      執(zhí)行以下命令即可完成部署:

      kubectl apply -f patch.yaml

      用于驗(yàn)證patch的deployment名為test123(瀏覽器訪問(wèn)/patch/deploy就會(huì)創(chuàng)建),這個(gè)deployment里面是個(gè)nginx容器,咱們要給它準(zhǔn)備一個(gè)NodePort類(lèi)型的service,以便驗(yàn)證的是否可以通過(guò)瀏覽器訪問(wèn),該service對(duì)應(yīng)的yaml文件是nginx-service.yaml,內(nèi)容如下:

      apiVersion: v1 kind: Service metadata: name: test123 namespace : default spec: type: NodePort ports: - port: 80 nodePort: 30101 selector: run: test123

      執(zhí)行以下命令即可完成部署:

      kubectl apply -f nginx-service.yaml

      終于,部署工作全部完成,可以驗(yàn)證patch了!

      驗(yàn)證的步驟

      先說(shuō)一下驗(yàn)證的步驟:

      調(diào)用創(chuàng)建deployment的接口,創(chuàng)建名為test123的deployment,里面是個(gè)nginx-1.18版本的pod,可以通過(guò)瀏覽器訪問(wèn)到(前面的nginx-service.yaml已經(jīng)部署了service);

      通過(guò)web請(qǐng)求執(zhí)行各種patch操作;

      創(chuàng)建deployment

      假設(shè)kubernetes宿主機(jī)IP地址是192.168.50.135,所以通過(guò)瀏覽器訪問(wèn):http://192.168.50.135:30102/patch/deploy,即可創(chuàng)建名為test123的deployment,如下圖,創(chuàng)建成功后deployment的詳細(xì)信息會(huì)展示在瀏覽器上:

      用kubectl命令驗(yàn)證deployment和pod都正常:

      瀏覽器訪問(wèn)

      test123

      這個(gè)deployment里面的nginx容器,地址是

      http://192.168.50.135:30101/

      ,如下圖紅框所示,返回的header中顯示,nginx的版本是1.18.0:

      接下來(lái)開(kāi)始提交patch;

      驗(yàn)證json patch

      json patch修改的是原deployment的

      terminationGracePeriodSeconds

      屬性,所以咱們先來(lái)看看修改前是啥樣的,執(zhí)行命令

      kubectl get deployment test123 -o yaml

      ,如下圖紅框,terminationGracePeriodSeconds等于

      30

      瀏覽器訪問(wèn)

      http://192.168.50.135:30102/patch/json

      ,即可發(fā)起json patch請(qǐng)求,并將deployment的結(jié)果返回,如下圖所示,terminationGracePeriodSeconds屬性值已經(jīng)改變:

      再次用命令

      kubectl get deployment test123 -o yaml

      Kubernetes官方j(luò)ava客戶(hù)端之七:patch操作

      查看,如下圖紅框,json patch已經(jīng)生效:

      執(zhí)行

      kubectl logs -f patch-56cd7f7f87-bpl5r -n kubernetesclient

      可以看到咱們應(yīng)用通過(guò)java客戶(hù)端與kubernetes 的API Server之前的詳細(xì)日志(patch-56cd7f7f87-bpl5r是patch工程對(duì)應(yīng)的pod),如下圖:

      json patch驗(yàn)證已經(jīng)完成,接著驗(yàn)證下一個(gè);

      驗(yàn)證merge patch(全量)

      merge patch(全量)給原有的deployment增加了一個(gè)label,先看看執(zhí)行patch之前是啥樣,如下圖紅框:

      瀏覽器訪問(wèn)http://192.168.50.135:30102/patch/fullmerge ,就發(fā)起了merge請(qǐng)求,操作成功后再次查看,如下圖紅框,新增了一個(gè)label:

      驗(yàn)證merge patch(增量)

      瀏覽器訪問(wèn)

      http://192.168.50.135:30102/patch/partmerge

      在kubernetes環(huán)境查看

      test123

      這個(gè)deployment的pod,發(fā)現(xiàn)原有pod被刪除,新增了一個(gè):

      執(zhí)行命令

      kubectl describe pod test123-5ff477967-tv729

      查看新pod的詳情,發(fā)現(xiàn)已經(jīng)部署nginx了,而是patch中提交的tomcat,如下圖所示,

      看來(lái)增量merge patch實(shí)際上做是替換操作

      驗(yàn)證strategic merge patch

      此時(shí)的

      test123

      這個(gè)deployment,其pod已經(jīng)被剛才的merge patch操作改成了tomcat,不適合接下來(lái)的驗(yàn)證,因此要執(zhí)行以下操作進(jìn)行清理和重新部署:

      刪除test123這個(gè)deployment:

      kubectl delete deployment test123

      瀏覽器訪問(wèn):

      http://192.168.50.135:30102/patch/deploy

      ,就會(huì)重新部署test123

      上述操作完成后,test123就恢復(fù)到最初狀態(tài)了,在瀏覽器執(zhí)行

      http://192.168.50.135:30102/patch/strategic

      ,即可提交strategic merge patch

      再去執(zhí)行

      kubectl get pod

      命令查看,會(huì)發(fā)現(xiàn)pod會(huì)被刪除,然后創(chuàng)建新pod,這個(gè)新pod的容器數(shù)量是2,如下圖紅框:

      執(zhí)行命令

      kubectl describe pod test123-59db4854f5-bstz5

      查看新pod的詳情,下圖兩個(gè)紅框,可見(jiàn)原有的strategic merge patch并沒(méi)有替換container,而是新增了一個(gè):

      此時(shí)您應(yīng)該對(duì)merge patch和strategic merge patch的區(qū)別應(yīng)該有了清晰的認(rèn)識(shí);

      開(kāi)啟kubernetes的Server-side Apply(低于1.16版本才需要執(zhí)行)

      最后一個(gè)實(shí)戰(zhàn)是apply yaml patch,此類(lèi)型patch主要是用于Server-side Apply特性的,

      該特性自kubernetes的1.14版本就有了,但是默認(rèn)并未開(kāi)啟,直到1.16版本才默認(rèn)開(kāi)啟,因此,如果您的kubernetes低于1.16版本,需要開(kāi)啟這個(gè)特性;

      java客戶(hù)端的官方demo代碼中,有一些簡(jiǎn)單描述,如下圖紅框:

      kubernetes的官方文檔中,提到此特性在低版本可以通過(guò)開(kāi)關(guān)來(lái)開(kāi)啟,文檔地址:https://kubernetes.cn/docs/reference/command-line-tools-reference/feature-gates/

      我這里kubernetes版本是

      1.14

      ,因此需要手動(dòng)開(kāi)啟Server-side Apply,首先SSH登錄kubernetes環(huán)境;

      打開(kāi)文件

      /etc/kubernetes/manifests/kube-apiserver.yaml

      ,給spec.containers.command增加一個(gè)參數(shù)

      –feature-gates=ServerSideApply=true

      ,如下圖紅框所示:

      修改完畢后請(qǐng)保存,由于kubernetes一直在監(jiān)聽(tīng)此文件,因此會(huì)立即自動(dòng)生效;

      驗(yàn)證apply yaml patch

      此時(shí)的test123,由于剛剛驗(yàn)證過(guò)strategic merge patch,現(xiàn)在的pod里面有nginx和tomcat兩個(gè)container;

      瀏覽器訪問(wèn)

      http://192.168.50.135:30102/patch/apply

      此時(shí)pod會(huì)重建,如下圖,可見(jiàn)最終container還是兩個(gè),也就是說(shuō),盡管applyYaml.json中的container只有一個(gè)nginx,但由于是在服務(wù)端merge的,服務(wù)端只會(huì)升級(jí)nginx的版本,對(duì)于已有的tomcat這個(gè)container依舊會(huì)保留:

      用瀏覽器訪問(wèn)test123提供的nginx服務(wù),如下圖紅框所示,nginx版本已經(jīng)升級(jí),證明本次patch已經(jīng)生效:

      至此,通過(guò)kubernetes的java客戶(hù)端執(zhí)行patch操作的實(shí)戰(zhàn)就全部完成了,從理論到環(huán)境準(zhǔn)備,再到實(shí)際操作,涉及到太多內(nèi)容,感謝您的耐心,希望本文能助您用好java客戶(hù)端這個(gè)利器,更高效的操作kubernetes環(huán)境;

      Java K8s Kubernetes

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶(hù)投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:Java并發(fā)基礎(chǔ) - synchronized篇
      下一篇:萬(wàn)字長(zhǎng)文帶你詳解九大數(shù)據(jù)存儲(chǔ)引擎結(jié)構(gòu)(上)
      相關(guān)文章
      亚洲熟妇中文字幕五十中出| 亚洲av永久无码精品三区在线4 | 亚洲精品二区国产综合野狼| 国产尤物在线视精品在亚洲| 亚洲字幕AV一区二区三区四区| 亚洲成在人线中文字幕| 老司机亚洲精品影院| 亚洲国产综合专区电影在线 | 久久综合久久综合亚洲| 亚洲依依成人精品| 亚洲中文无码线在线观看| 亚洲欧洲精品久久| 亚洲一区电影在线观看| 亚洲一卡2卡4卡5卡6卡残暴在线| 亚洲videosbestsex日本| 亚洲精品二三区伊人久久| 亚洲已满18点击进入在线观看| 亚洲成年网站在线观看| 亚洲色无码国产精品网站可下载| 在线精品亚洲一区二区| 亚洲av永久无码精品秋霞电影秋| 亚洲国产无线乱码在线观看| 亚洲AV成人一区二区三区观看 | 亚洲成av人片在www鸭子| 久久久久亚洲国产AV麻豆| 成人精品国产亚洲欧洲| 免费亚洲视频在线观看| 亚洲精品国产电影| 中文字幕亚洲天堂| 亚洲AV中文无码字幕色三| 亚洲视频在线一区| 亚洲国产成人精品无码一区二区 | 丝袜熟女国偷自产中文字幕亚洲| 国产成人A亚洲精V品无码| 亚洲AV综合色区无码另类小说| 亚洲一区综合在线播放| 亚洲免费视频播放| 亚洲精品GV天堂无码男同| 亚洲av再在线观看| 亚洲人成色7777在线观看| 日木av无码专区亚洲av毛片|