用 Helm3 構(gòu)建多層微服務(wù)

Intro

Helm是一款非常流行的k8s包管理工具。以前就一直想用它,但看到它產(chǎn)生的文件比k8s要復(fù)雜許多秸苗,就一直猶豫,不知道它的好處能不能抵消掉它的復(fù)雜度运褪。但如果不用惊楼,而是用Kubectl來進(jìn)行調(diào)式真的很麻煩。正好最近Helm3正式版出來了秸讹,比原來的Helm2 簡單了不少檀咙,就決定還是試用一下。結(jié)果證明確實(shí)很復(fù)雜璃诀,它的好處和壞處大致相當(dāng)弧可。有了它確實(shí)能大大簡化對k8s的調(diào)式,但也需要花費(fèi)比較多的時(shí)間來學(xué)習(xí)劣欢,而且產(chǎn)生的配置文件要復(fù)雜許多棕诵。但是事實(shí)是現(xiàn)在沒有什么很方便的幫助調(diào)式k8s的工具,在沒有更好的方案之前氧秘,我還是建議用它年鸳,只是前期需要花些功夫?qū)W習(xí)和掌握它。

Helm3和Helm2的語法差不太多丸相,只是使用起來更方便搔确,不用安裝Tiller。一個(gè)比較明顯的變化是不再需要“requirements.yaml”, 依賴關(guān)系是直接在“chart.yaml”中定義灭忠。有關(guān)Helm3和Helm2的區(qū)別膳算,詳情請參見CHANGES SINCE HELM 2

網(wǎng)上有不少講述Helm的文章弛作,但大部分都是主要講解安裝和舉一個(gè)簡單的例子涕蜂。但Helm使用起來還是比較復(fù)雜的,一定要有一個(gè)復(fù)雜的例子才能把它的功能講清楚映琳,里面有不少設(shè)計(jì)方面的問題需要思考机隙。我剛開始接觸的時(shí)候就覺得頭緒繁多蜘拉,不知從哪下手。本文就通過一個(gè)相對復(fù)雜的例子來講解用Helm3來設(shè)計(jì)配置文件的思路有鹿,使上手更容易旭旭。

這里不講Helm3的安裝,它比較很容易葱跋。也不講解Helm的基本語法持寄,你可以自己去看其他文檔。即使你不懂Helm娱俺,應(yīng)該也能猜出七八成稍味,剩下的就要讀文檔了(Charts)。Helm的語法還是比較復(fù)雜的荠卷,要想搞懂可能要花一兩天時(shí)間模庐。

本文假設(shè)你對helm有一個(gè)大概的了解,想要構(gòu)建一個(gè)復(fù)雜的微服務(wù)顶吮,但有不知如何下手悴了;或者你想了解一下構(gòu)建Helm的最佳實(shí)踐湃交,那就請你繼續(xù)讀下去。

Helm文件結(jié)構(gòu)

chart里一個(gè)很重要的概念就是模板(template),它就是Go語言模板才沧,它是里面加入了編程邏輯的k8s文件。這些模板文件在使用時(shí)都要先進(jìn)行模板解析孩革,把其中的程序邏輯轉(zhuǎn)化成對應(yīng)的編碼锅移,最終生成k8s配置文件非剃。

以上就是Helm自動(dòng)生成的chart目錄結(jié)構(gòu),在Helm里每個(gè)項(xiàng)目叫一個(gè)chart,它由下面幾個(gè)組成部分:

  • "Chart.yaml":存有這個(gè)chart的基本信息压怠,
  • "values.yaml":定義模板中要用到的常量菌瘫。
  • “template”目錄:里面存有全部的模板文件,其中最重要的是“deployment.yaml”和“service.yaml”栖忠,分別是部署和服務(wù)文件. "helpers.tpl"用來定義變量,"ingress.yaml"和"serviceaccount.yaml"分別是對外接口和服務(wù)賬戶捐川,這里暫時(shí)沒用古沥, “NOTES.txt”是注釋文件。
  • “charts”目錄: 存有這個(gè)chart依賴的所有子chart纯衍。

Helm的基本元素

Helm有四個(gè)基本元素瓦堵,值菇用,常量惋鸥,變量和共享常量(這個(gè)后面會(huì)講)

值(literal)

Helm在k8s的基礎(chǔ)之上增加了模板功能,使k8s的配置文件更加靈活滤港。里面的主要概念就是模板(Template),也就是在k8s的配置文件里增加了常量和變量以及編程邏輯添履。如果你不用這些新增功能,那么就是普通的YAML文件(k8s配置文件)叔壤,里面用到的基本元素就是值。

常量

節(jié)點(diǎn)定位(Node Anchor):

如果你想復(fù)用重復(fù)的值俺亮,能把它定義成常量嗎?YAML有一個(gè)功能叫節(jié)點(diǎn)定位(Node Anchor)本讥,類似于定義一個(gè)常量,然后引用秧了。但它有一些限制,定義的必須是一個(gè)節(jié)點(diǎn)米罚,因此不如真正的常量靈活。
例如如下文件中,用“&”定義了一個(gè)常量“&k8sdemoDatabaseService”讼渊,然后用“*k8sdemoDatabaseService”引用它。

global:
  k8sdemoDatabaseService: &k8sdemoDatabaseService k8sdemo-database-service
  mysqlHost: *k8sdemoDatabaseService

這時(shí),“k8sdemoDatabaseService:”是YAML文件節(jié)點(diǎn)的鍵名奶甘,“&k8sdemoDatabaseService”是節(jié)點(diǎn)定位的名字,相當(dāng)于常量名方淤,“k8sdemo-database-service”是YAML節(jié)點(diǎn)的鍵值钉赁。在上述代碼中,k8sdemoDatabaseService和mysqlHost的值都是“k8sdemo-database-service”携茂。

有關(guān)節(jié)點(diǎn)定位(Node Anchor)的詳細(xì)內(nèi)容你踩,請參見 YAML

常量:

由于節(jié)點(diǎn)定位的局限性,Helm引入了真正的常量姓蜂,也就是在"values.yaml"里定義的內(nèi)容按厘,它可以定義是任何東西懒棉,不只限于節(jié)點(diǎn)妻导。

在"values.yaml"里定義常量:

replicaCount: 1

在部署模板里引用:

replicas: {{ .Values.replicaCount }}

那么什么時(shí)候用常量醇疼,什么時(shí)候用值(Literal)呢贵试?如果一個(gè)值在模板中出現(xiàn)多次梧疲,就要定義常量,避免重復(fù)喂分。例如“accessModes”,既要在存儲(chǔ)卷里出現(xiàn),又要在存儲(chǔ)卷申請里出現(xiàn)基括。另外如果值有可能變化(不論是隨部署環(huán)境變化魔眨,還是隨時(shí)間變化)当叭,那么就定義成常量,這樣在修改時(shí)就只用改"values.yaml"损肛,而不必修改模板文件笆焰。例如“replicas”的值(也就是集群的個(gè)數(shù))是可能變化的,就要定義成常量不皆。在模板里可以引用常量的,但在"values.yaml"里不行则果,因?yàn)樗皇瞧胀╕AML文件饰及,沒有模板解析功能,因此不支持常量渠牲,這里就只能用節(jié)點(diǎn)定位(來代替常量)旋炒。

有關(guān)Helm常量的詳細(xì)內(nèi)容步悠,請參見 Use placeholders in yamlUse YAML with variables签杈。

變量

節(jié)點(diǎn)定位的功能是有限的,例如你想利用已有的節(jié)點(diǎn)定位鼎兽,對它進(jìn)行轉(zhuǎn)換答姥,定義一個(gè)新的節(jié)點(diǎn)定位,這在"values.yaml"里就不行了谚咬。
例如你已有節(jié)點(diǎn)定位“name”鹦付,你想在這個(gè)基礎(chǔ)上定義一個(gè)新的節(jié)點(diǎn)定位“serviceName”,這個(gè)"values.yaml"就不支持了择卦,你必須要用模板敲长。

如下所示郎嫁,這在"values.yaml"里是不支持的。

name: &name k8sdemo-backend
serviceName:*name-service

這就引出了變量的概念祈噪,但它只能在模板里才行泽铛。 換句話說,模板既支持常量辑鲤,也支持變量盔腔。但如果把變量的定義邏輯放在Helm每個(gè)模板里,就顯得很亂月褥。因此一般的做法是把這些邏輯放在一個(gè)單獨(dú)的模板文件里弛随,這個(gè)就是前面講到的"_helpers.tpl"文件。當(dāng)你需要對常量進(jìn)行轉(zhuǎn)換宁赤,生成新的常量舀透,你就在定義變量,這部分代碼就放在"_helpers.tpl"里礁击。

下面就是"_helpers.tpl"中定義"k8sdemo.name"的代碼盐杂。

{{- define "k8sdemo.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}

在以上這些元素中,常量(也就是在"values.yaml"中定義的)是最靈活的哆窿,能用它時(shí)盡量用它链烈。而且因?yàn)樗嵌x在普通YAML文件中("values.yaml"),應(yīng)用程序可以直接訪問它挚躯,這樣可以實(shí)現(xiàn)應(yīng)用程序和k8s之間的數(shù)據(jù)共享强衡。但如果你需要對常量進(jìn)行編程轉(zhuǎn)換,那就沒辦法了码荔,只能定義變量漩勤,把它放在"_helpers.tpl"中。

ConfigMap和Secret

在k8s中ConfigMap和Secret是用來存儲(chǔ)共享配置參數(shù)和保密參數(shù)的缩搅,但在Helm中越败,由于有了上面講的Helm基本元素,它們完全可以代替ConfigMap的功能硼瓣,因此ConfigMap就不需要了究飞,但Secret還是需要的,因?yàn)橐鎯?chǔ)加密信息堂鲤。下面會(huì)講解亿傅。

有關(guān)ConfigMap的設(shè)計(jì)局限性,請參見把應(yīng)用程序遷移到k8s需要修改什么瘟栖?

Chart設(shè)計(jì)

現(xiàn)在我們就用一個(gè)具體的例子來展示Helm的chart設(shè)計(jì)葵擎。這個(gè)例子是一個(gè)微服務(wù)應(yīng)用程序,它共有三層: 前端半哟,后端和數(shù)據(jù)庫酬滤,只有這樣才能讓Helm的一些設(shè)計(jì)問題付出水面签餐,如果只有一層的話,就太簡單了盯串,沒有參考價(jià)值贱田。

在k8s中,每一層就是一個(gè)單獨(dú)的服務(wù)嘴脾,它里面有各種配置文件男摧。Helm的優(yōu)勢是把這些不同的服務(wù)組成一個(gè)Chart來共同管理和調(diào)式,方便了許多译打。

file

上面就是最終的chart目錄結(jié)構(gòu)圖耗拓。“chart”是總目錄奏司,里面有三個(gè)子目錄“k8sdemo”乔询,“k8sdemo-backend”,“k8sdemo-database”, 每一個(gè)對應(yīng)一個(gè)服務(wù)韵洋,每個(gè)服務(wù)都是一個(gè)獨(dú)立的chart竿刁,能單獨(dú)調(diào)式部署,chart之間也可以有依賴關(guān)系搪缨。其中“k8sdemo”是父chart食拜,同時(shí)也是前端服務(wù),它的“charts”目錄里有它依賴的另外兩個(gè)服務(wù)副编「旱椋“k8sdemo-backend”是后端服務(wù),“k8sdemo-database”是數(shù)據(jù)庫服務(wù)痹届。

處理Chart的依賴關(guān)系有兩種方式:

  1. 嵌入式:就是直接把依賴的chart放在“charts”子目錄里呻待,這樣子chart是父chart的一部分。它是一種緊耦合的關(guān)系队腐,好處是比較簡單蚕捉,但不夠靈活。
  2. 依賴導(dǎo)入式:就是各個(gè)chart是并列關(guān)系柴淘,各自單獨(dú)調(diào)試部署迫淹,互相獨(dú)立,需要合并時(shí)再把子chart導(dǎo)入父chart里悠就,它是一種松耦合的關(guān)系千绪,好處是比較靈活充易,但設(shè)計(jì)更復(fù)雜梗脾。 在這種結(jié)構(gòu)下,各個(gè)chart可以單獨(dú)工作也可以聯(lián)合工作盹靴,不過你需要更好的設(shè)計(jì)炸茧。

這里采用的是依賴導(dǎo)入式方式瑞妇,主要原因是我原來認(rèn)為嵌入式需要一起調(diào)試,復(fù)雜度太高梭冠,如果你覺得這不是問題辕狰,這也是個(gè)不錯(cuò)的辦法。用依賴導(dǎo)入式方式控漠,可以單獨(dú)調(diào)試各個(gè)chart蔓倍,簡單了很多。后來發(fā)現(xiàn)其實(shí)采用嵌入式也可以單獨(dú)調(diào)試子chart盐捷,只是父chart不能單獨(dú)調(diào)試而已偶翅。

調(diào)試順序:

當(dāng)你采用依賴導(dǎo)入式方式時(shí),調(diào)試順序關(guān)系不大碉渡,因?yàn)楦鱾€(gè)chart是各自獨(dú)立的聚谁,可以單獨(dú)調(diào)試。舉個(gè)例子滞诺,雖然“k8sdemo-backend”需要“k8sdemo-database”才能正常運(yùn)行形导,但當(dāng)沒有數(shù)據(jù)庫服務(wù)時(shí),你的程序也可以運(yùn)行习霹,只不過輸出的是錯(cuò)誤信息朵耕,但這并不影響你調(diào)試chart。

我先調(diào)試“k8sdemo”淋叶,它雖然依賴另外兩個(gè)chart憔披,但沒有它們也能單獨(dú)工作。然后再調(diào)試“k8sdemo-backend”和“k8sdemo-database”爸吮,最后再把它們導(dǎo)入到“k8sdemo”中去再進(jìn)行聯(lián)調(diào)芬膝。

調(diào)式“k8sdemo”

它的調(diào)試是最容易的,由于它里面沒有真正的前端代碼形娇,只要把Nginx調(diào)試成功了就可以了锰霜。只要在生成的文件基礎(chǔ)上做些修改就行了。

鍵入如下命令創(chuàng)建chart桐早,其中“k8sdemo”是chart的名字癣缅,這個(gè)名字很重要,服務(wù)的名字和label都是由它產(chǎn)生的哄酝。

helm create k8sdemo

這之后友存,系統(tǒng)會(huì)自動(dòng)創(chuàng)建前面講到的chart目錄結(jié)構(gòu)。讓后就是對已經(jīng)生成的文件進(jìn)行修改陶衅。

修改"values.yaml":
以下是"values.yaml"主要修改的地方

image:
  repository: nginx:1.17.6
  pullPolicy: Never

imagePullSecrets: []
nameOverride: "k8sdemo"
fullnameOverride: "k8sdemo"

service:
  type: NodePort
  port: 80
  nodePort: 31080

另外屡立,由于"ingress.yaml"和"serviceaccount.yaml"暫時(shí)沒用,就把它們都設(shè)成了“false”

ingress:
  enabled: false

serviceAccount:
  # Specifies whether a service account should be created
  create: false

修改"service.yaml":

apiVersion: v1
kind: Service
metadata:
  name: {{ include "k8sdemo.fullname" . }}
  labels:
    {{- include "k8sdemo.labels" . | nindent 4 }}
spec:
  type: {{.Values.service.type}}
  ports:
    - port: {{.Values.service.port}}
      nodePort: {{.Values.service.nodePort}}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "k8sdemo.selectorLabels" . | nindent 4 }}

修改"deployment.yaml":

搀军。膨俐。勇皇。
containers:
  - name: {{ .Chart.Name }}
    securityContext:
      {{- toYaml .Values.securityContext | nindent 12 }}
    image: {{ .Values.image.repository }}
    imagePullPolicy: {{ .Values.image.pullPolicy }}
。焚刺。敛摘。

以上都是簡單的修改,不涉及到設(shè)計(jì)問題乳愉。由于篇幅的關(guān)系兄淫,這里沒有列出全部源碼,如果有興趣請?jiān)诒疚哪┪舱业皆创a地址蔓姚。

共享常量

在進(jìn)行下面的調(diào)試之前拖叙,先要講一個(gè)重要概念。 前面介紹Helm的基本元素時(shí)講的都是在一個(gè)chart里共享值赂乐,如果要在不同chart之間共享值(例如k8s服務(wù)名薯鳍,數(shù)據(jù)庫用戶名和端口),那么這些還不夠挨措,你需要共享常量. 通常情況下子chart和父chart之間的常量是不能共享的挖滤,如果需要共享,需要有一種特殊的方法來定義常量浅役,這就是共享常量斩松。它必須是定義在父chart中。

共享常量

例如觉既,你在“k8sdemo”的“values.yaml”加入下面代碼惧盹,注意節(jié)點(diǎn)的名字必須是子chart名(例如“k8sdemo-backend”)

k8sdemo-backend:
  replicaCount: 2
k8sdemo-database:
  replicaCount: 2

在“k8sdemo”的模板里就可以通過“{{ .Values.k8sdemo-backend.replicaCount }}” 來訪問。當(dāng)Helm發(fā)現(xiàn)節(jié)點(diǎn)名是子chart名時(shí)瞪讼,它會(huì)自動(dòng)拷貝這個(gè)常量到子chart的“values.yaml”中钧椰,因此,在“k8sdemo-backend”中符欠,你也可以通過“{{ .Values.replicaCount }}” 來訪問這個(gè)常量嫡霞。注意這里并沒有包含子chart名(“k8sdemo-backend”),而是只有常量名希柿,因?yàn)樽觕hart名只是一個(gè)標(biāo)識诊沪,而不是常量名的一部分。

全局常量

共享常量只能把常量共享給一個(gè)字chart曾撤,如果你需要多個(gè)子chart之間共享端姚,就需要?jiǎng)?chuàng)建全局常量,它用“global”來標(biāo)識挤悉,下面是示例渐裸。

在“k8sdemo-backend”的"values.yaml"中定義:

global:
  k8sdemoDatabaseService: &k8sdemoDatabaseService k8sdemo-database-service
  mysqlUserName: dbuser
  mysqlUserPassword: dbuser
  mysqlPort: 3306
  mysqlHost: *k8sdemoDatabaseService
  mysqlDatabase: service_config

在“k8sdemo-backend”的“deployment.yaml”中引用。

env:
  - name: MYSQL_USER_NAME
    value: {{ .Values.global.mysqlUserName }}
  - name: MYSQL_USER_PASSWORD
    value: {{ .Values.global.mysqlUserPassword }}
  - name: MYSQL_HOST
    value: {{ .Values.global.mysqlHost }}
  - name: MYSQL_PORT
    value: "{{ .Values.global.mysqlPort }}"
  - name: MYSQL_DATABASE
    value: {{ .Values.global.mysqlDatabase }}

在“k8sdemo-database”的"values.yaml"中定義:

global:
  k8sdemoDatabaseService: k8sdemo-database-service
  mysqlUserName: dbuser
  mysqlUserPassword: dbuser
  mysqlRootPassword: root
  mysqlDatabase: service_config

在“k8sdemo-database”的“deployment.yaml”中引用。

env:
  - name: MYSQL_ROOT_PASSWORD
    value: {{ .Values.global.mysqlRootPassword }}
  - name: MYSQL_USER_NAME
    value: {{ .Values.global.mysqlUserName }}
  - name: MYSQL_USER_PASSWORD
    value: {{ .Values.global.mysqlUserPassword }}
  - name: MYSQL_DATABASE
    value: {{ .Values.global.mysqlDatabase }}

當(dāng)把“k8sdemo-backend”和“k8sdemo-database”導(dǎo)入"k8sdemo"后進(jìn)行聯(lián)調(diào)時(shí), 就要把上面提到的全局常量寫入"k8sdemo"的"values.yaml"文件中橄仆,這樣就能讓各個(gè)子chart共享這些常量。如下所示:

global:
  k8sdemoBackendService: k8sdemo-backend-service
  k8sdemoDatabaseService: &k8sdemoDatabaseService k8sdemo-database-service
  mysqlUserName: dbuser
  mysqlUserPassword: dbuser
  mysqlRootPassword: root
  mysqlPort: 3306
  mysqlHost: *k8sdemoDatabaseService
  mysqlDatabase: service_config

如果父chart和子chart有重復(fù)的全局常量衅斩,這時(shí)父chart("k8sdemo")的全局常量值就會(huì)覆蓋子chart的全局常量盆顾。

它的使用原則就是如果只是子chart獨(dú)有的常量就在子chart的"values.yaml"中定義,如果是共享的常量就在父chart中定義畏梆。但如果采用的是依賴導(dǎo)入方式您宪,由于子chart也要單獨(dú)調(diào)試,這時(shí)你在子chart里也要定義這些全局常量奠涌。這樣在進(jìn)行chart總調(diào)試時(shí)宪巨,就會(huì)使用父chart的中的值。

詳情請參見 Subcharts and Global Values溜畅。

調(diào)試“k8sdemo-backend”

“k8sdemo-backend”的chart需要饶笞俊(與“k8ssdemo”)不同的名字,
創(chuàng)建:

helm create k8sdemo-backend
file

上面就是“k8sdemo-backend”的目錄圖慈格。由于它需要建持久卷怠晴,因此這里增加了兩個(gè)文件“persistentvolume.yaml”和“persistentvolumeclaim.yaml” ( 不是自動(dòng)生成的)。

值得一提的是k8s對象的命名浴捆。一般情況下蒜田,如果不需要對其進(jìn)行引用,用chart的全名就行了选泻。例如部署的名稱冲粤,如下所示。

name: {{ include "k8sdemo.fullname" . }}

如果是服務(wù)名(Service Name)页眯,它需要在應(yīng)用程序和k8s之間共享梯捕,也需要在父chart和子chart之間共享,這時(shí)最好單獨(dú)定義一個(gè)全局共享常量窝撵。

在“values.yaml”中定義:

global:
  k8sdemoBackendService: k8sdemo-backend-service

在“service.yaml”中引用:

name: {{.Values.global.k8sdemoBackendService}}

調(diào)試“k8sdemo-database”

它的調(diào)試方式與“k8sdemo-backend”大同小異科阎,就不詳細(xì)講解了。

聯(lián)合調(diào)試:

上面各個(gè)chart都單獨(dú)調(diào)試成功之后忿族,就要把它們合在一起進(jìn)行聯(lián)合調(diào)試锣笨。
在“k8sdemo”(父chart)中加入依賴關(guān)系(Chart.yaml)。

dependencies:
  - name: k8sdemo-backend
    repository: file://../k8sdemo-backend
    version: 0.1.0
  - name: k8sdemo-database
    repository: file://../k8sdemo-database
    version: 0.1.0

這里為了簡單起見道批,沒有用到chart庫(Chart Repository)错英,使用了本地目錄。這里的“file://”是針對chart的根的相對路徑隆豹,“file://..”就是“k8sdemo”的上級目錄椭岩。

詳情請參見How to refer to a helm chart in the same repository

修改全局常量("values.yaml"):

global:
  k8sdemoBackendService: k8sdemo-backend-service
  k8sdemoDatabaseService: &k8sdemoDatabaseService k8sdemo-database-service
  mysqlUserName: dbuser
  mysqlUserPassword: dbuser
  mysqlRootPassword: root
  mysqlPort: 3306
  mysqlHost: *k8sdemoDatabaseService
  mysqlDatabase: service_config

只有需要在chart之間共享的常量才需要在父chart里的"values.yaml"定義,其余的在各自子chart里的"values.yaml"定義就可以了判哥。

鍵入如下命令“helm dependency update k8sdemo”献雅,更新依賴關(guān)系

~ # vagrant@ubuntu-xenial:~/jfeng45/k8sdemo/script/kubernetes/chart$ helm dependency update k8sdemo
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "stable" chart repository
Update Complete. ?Happy Helming!?
Saving 2 charts
Deleting outdated charts

完成之后,生成的圖如下所示塌计,這時(shí)在“charts”目錄下就導(dǎo)入了新的依賴關(guān)系“k8sdemo-backend”和“k8sdemo-database”的chart挺身。

file

有一點(diǎn)需要注意的是,單獨(dú)調(diào)試和聯(lián)合調(diào)試時(shí)锌仅,生成的k8s配置文件大部分都是一樣的章钾,但有一個(gè)地方不同

下面是聯(lián)合調(diào)試時(shí)“k8sdemo-database”的部署文件,最后一行“app.kubernetes.io/instance: ”的值是“k8sdemo”热芹。

# Source: k8sdemo/charts/k8sdemo-database/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8sdemo-database
  labels:
    helm.sh/chart: k8sdemo-database-0.1.0
    app.kubernetes.io/name: k8sdemo-database
    app.kubernetes.io/instance: k8sdemo
贱傀。。伊脓。

下面是單獨(dú)調(diào)試時(shí)“k8sdemo-database”的部署文件府寒,最后一行“app.kubernetes.io/instance: ”的值是“”k8sdemo-database”。

# Source: k8sdemo/charts/k8sdemo-database/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8sdemo-database
  labels:
    helm.sh/chart: k8sdemo-database-0.1.0
    app.kubernetes.io/name: k8sdemo-database
    app.kubernetes.io/instance: k8sdemo-database
报腔。椰棘。。

因?yàn)椤癷nstance”的名字是“{{ .Release.Name }}”榄笙,而單獨(dú)調(diào)試和聯(lián)合調(diào)試時(shí)給的“release”名字不同邪狞。而其他的值都是由配置文件決定的,因此不會(huì)有意外茅撞。

安裝k8sdemo:

vagrant@ubuntu-xenial:~/jfeng45/k8sdemo/script/kubernetes/chart$ helm upgrade k8sdemo ./k8sdemo
Release "k8sdemo" has been upgraded. Happy Helming!
NAME: k8sdemo
LAST DEPLOYED: Fri Nov 29 01:28:55 2019
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
1\. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services k8sdemo)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT

獲取Pod名稱:

vagrant@ubuntu-xenial:~/jfeng45/k8sdemo/script/kubernetes/chart$ kubectl get pod
NAME                                          READY   STATUS    RESTARTS   AGE
k8sdemo-74cb7b997c-pgcj4                      1/1     Running   0          33s
k8sdemo-backend-5cd9d79856-dqlmz              1/1     Running   0          33s
k8sdemo-database-85855485c6-jtksb             1/1     Running   0          33s
k8sdemo-jenkins-deployment-675dd574cb-r57sb   1/1     Running   3          23d

運(yùn)行程序進(jìn)行測設(shè):

vagrant@ubuntu-xenial:~/jfeng45/k8sdemo/script/kubernetes/chart$ kubectl exec -ti k8sdemo-backend-5cd9d79856-dqlmz -- /bin/sh
~ # ./main.exe
time="2019-11-27T07:03:03Z" level=debug msg="connect to database "
time="2019-11-27T07:03:03Z" level=debug msg="dataSourceName:dbuser:dbuser@tcp(k8sdemo-database-service:3306)/service_config?charset=utf8"
time="2019-11-27T07:03:03Z" level=debug msg="FindAll()"
time="2019-11-27T07:03:03Z" level=debug msg="created=2019-10-21"
time="2019-11-27T07:03:03Z" level=debug msg="find user:{1 Tony IT 2019-10-21}"
time="2019-11-27T07:03:03Z" level=debug msg="find user list:[{1 Tony IT 2019-10-21}]"
time="2019-11-27T07:03:03Z" level=debug msg="user lst:[{1 Tony IT 2019-10-21}]"
~ #

其他問題:

由于篇幅有限帆卓,本文不可能把所有的問題都講清楚,還有兩個(gè)比較重要的問題米丘,這里簡單的提一下剑令。

1.Secret:
本文用的都是明碼,如果需要加密的話有兩種方式拄查,一種是 helm-secrets吁津,另一種是Vault,請閱讀相關(guān)文檔堕扶。

2.為不同環(huán)境設(shè)置不同的常量:
本文只創(chuàng)建了針對一種環(huán)境的文件 碍脏,如果你需要針對不同環(huán)境(例如DEV,QA稍算,PROD)配置不同的參數(shù)的話典尾,你可以在“k8sdemo”的chart里給不同的環(huán)境創(chuàng)建不同的"values.yaml",例如“values-dev.yaml”給DEV環(huán)境糊探。但在子chart里钾埂,就不能這樣做河闰,因?yàn)橄到y(tǒng)要求"values.yaml"。這時(shí)褥紫,你可以在父chart的“values-dev.yaml”里為不同的子chart創(chuàng)建常量姜性,這樣這些常量就能覆蓋子chart里定義的常量。

在“values-dev.yaml”加入下面代碼髓考。

k8sdemo-backend:
    replicaCount: 2
k8sdemo-database:
    replicaCount: 2

鍵入如下命令試運(yùn)行:

vagrant@ubuntu-xenial:~$ cd /home/vagrant/jfeng45/k8sdemo/script/kubernetes/chart
vagrant@ubuntu-xenial:~/jfeng45/k8sdemo/script/kubernetes/chart$ helm install --dry-run --values ./k8sdemo/values-dev.yaml --debug k8sdemo ./k8sdemo

查看結(jié)果部念,子chart中的相應(yīng)參數(shù)已被覆蓋。

詳情請參閱How to set environment related values.yaml in Helm subcharts?

常見錯(cuò)誤:

在調(diào)試過程中還是遇到了不少問題绳军,但大多數(shù)都是與語法有關(guān)的問題印机,因?yàn)镠elm和k8s都用的是YAML文件矢腻,而它對文件格式有著嚴(yán)格的要求门驾,如果不滿足要求就會(huì)報(bào)錯(cuò)。幸好它報(bào)錯(cuò)時(shí)包含了錯(cuò)誤代碼行號多柑,這樣查找起來比較容易奶是。

  1. Pod的狀態(tài)是CrashLoopBackOff

它的癥狀是在用“helm install --dry-run --debug”調(diào)試時(shí)沒有問題,但正式運(yùn)行時(shí)出了問題竣灌,用下面命令檢查聂沙,Pod的狀態(tài)是“CrashLoopBackOff”。

vagrant@ubuntu-xenial:~$ kubectl get pod
NAME                                           READY   STATUS             RESTARTS   AGE
k8sdemo-74cb7b997c-gn5v2                       1/1     Running            1          47h
k8sdemo-backend-6cdbb96964-tb2xd               0/1     CrashLoopBackOff   129        9h
k8sdemo-database-deployment-578fc88c88-mm6x8   1/1     Running            12         37d
k8sdemo-jenkins-deployment-675dd574cb-r57sb    1/1     Running            3          19d

這個(gè)問題我以前調(diào)試k8s時(shí)也碰到過初嘹,主要是與Docker鏡像有關(guān)及汉,但這次明明鏡像是 好的。試了很多組合屯烦,最后終于發(fā)現(xiàn)是自動(dòng)生成的代碼出了問題坷随。
在“deployment.yaml”里有下面代碼,這是Helm自動(dòng)生成用來測試部署的驻龟。

livenessProbe:
  httpGet:
    path: /
    port: http
readinessProbe:
  httpGet:
    path: /
    port: http

把它去掉之后就沒有問題了温眉。而且它只在特定的chart(“k8sedemo-backend”)里會(huì)出錯(cuò),在“k8sdemo”里就沒有問題翁狐。我現(xiàn)在也不是特別清楚問題在哪类溢,只是把它暫時(shí)刪除掉了。

  1. 持久卷未能綁定到持久卷申請

它的癥狀是宿主機(jī)的持久卷未能綁定到持久卷申請露懒,導(dǎo)致持久卷申請又另外創(chuàng)建了一個(gè)持久卷闯冷。你用“kubectl get pv”就能看到新創(chuàng)建的持久卷,但實(shí)際上它是不必要的懈词,只要把持久卷申請綁定到已有的PV上就行了窃躲。這個(gè)錯(cuò)誤并不是每次都發(fā)生,而是隨機(jī)的钦睡。大部分時(shí)間綁定正確蒂窒,少數(shù)時(shí)候綁定錯(cuò)誤躁倒。我開始想是不是因?yàn)閳?zhí)行k8s文件的順序問題,但k8s文件是按照文件類別(kind)來執(zhí)行的洒琢,按理來說順序應(yīng)該是正確的秧秉。再有一個(gè)可能就是時(shí)間延遲,因?yàn)閯?chuàng)建持久卷需要時(shí)間衰抑,而如果持久卷申請沒有檢測到這個(gè)持久卷象迎,那么它就會(huì)另外創(chuàng)建一個(gè)。如果真是這樣的話呛踊,就要在創(chuàng)建時(shí)設(shè)定一個(gè)延遲砾淌。但它暫時(shí)來講對我影響不大,因此就偷了一下懶谭网,以后有時(shí)間再來調(diào)試汪厨。

源碼庫

完整源碼的github鏈接:
k8sdemo

索引:

  1. CHANGES SINCE HELM 2
  2. Charts
  3. YAML
  4. Use placeholders in yaml
  5. Use YAML with variables
  6. 把應(yīng)用程序遷移到k8s需要修改什么?
  7. Subcharts and Global Values
  8. How to refer to a helm chart in the same repository
  9. helm-secrets
  10. Vault
  11. How to set environment related values.yaml in Helm subcharts?

不堆砌術(shù)語愉择,不羅列架構(gòu)劫乱,不迷信權(quán)威,不盲從流行锥涕,堅(jiān)持獨(dú)立思考

Memo

本文轉(zhuǎn)載至:https://www.cnblogs.com/code-craftsman/p/11958281.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衷戈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子层坠,更是在濱河造成了極大的恐慌殖妇,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件破花,死亡現(xiàn)場離奇詭異谦趣,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)旧乞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進(jìn)店門蔚润,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人尺栖,你說我怎么就攤上這事嫡纠。” “怎么了延赌?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵除盏,是天一觀的道長。 經(jīng)常有香客問我挫以,道長者蠕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任掐松,我火速辦了婚禮踱侣,結(jié)果婚禮上粪小,老公的妹妹穿的比我還像新娘。我一直安慰自己抡句,他們只是感情好探膊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著待榔,像睡著了一般逞壁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锐锣,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天腌闯,我揣著相機(jī)與錄音,去河邊找鬼雕憔。 笑死姿骏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的橘茉。 我是一名探鬼主播工腋,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼姨丈,長吁一口氣:“原來是場噩夢啊……” “哼畅卓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蟋恬,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤翁潘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后歼争,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拜马,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年沐绒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了俩莽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡乔遮,死狀恐怖扮超,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蹋肮,我是刑警寧澤出刷,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站坯辩,受9級特大地震影響馁龟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜漆魔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一坷檩、第九天 我趴在偏房一處隱蔽的房頂上張望却音。 院中可真熱鬧,春花似錦矢炼、人聲如沸僧家。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽八拱。三九已至,卻和暖如春涯塔,著一層夾襖步出監(jiān)牢的瞬間肌稻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工匕荸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留爹谭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓榛搔,卻偏偏與公主長得像诺凡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子践惑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容