<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    Helm Charts 開發(fā)完整示例

    共 27247字,需瀏覽 55分鐘

     ·

    2022-03-19 00:58

    Helm 的使用是比較簡(jiǎn)單的,但是要讓我們自己開發(fā)一個(gè) Chart 包還是有不小難度的,主要還是 go template 的語(yǔ)法規(guī)則不夠人性化,這里我們用一個(gè)完整的實(shí)例來(lái)演示下如何開發(fā)一個(gè) Helm Chart 包。

    應(yīng)用

    我們這里以 Ghost 博客應(yīng)用為例來(lái)演示如何開發(fā)一個(gè)完整的 Helm Chart 包,Ghost 是基于 Node.js 的開源博客平臺(tái)。在開發(fā) Helm Chart 包之前我們最需要做的的就是要知道我們自己的應(yīng)用應(yīng)該如何使用、如何部署,不然是不可能編寫出對(duì)應(yīng)的 Chart 包的。

    啟動(dòng) Ghost 最簡(jiǎn)單的方式是直接使用鏡像啟動(dòng):

    ??docker?run?-d?--name?my-ghost?-p?2368:2368?ghost

    然后我們就可以通過(guò) http://localhost:2368 訪問(wèn) Ghost 博客了。如果我們想要在 Kubernetes 集群中部署兩個(gè)副本的 Ghost,可以直接應(yīng)用下面的資源清單文件即可:

    #?ghost/deployment.yaml
    apiVersion:?apps/v1
    kind:?Deployment
    metadata:
    ??name:?ghost
    spec:
    ??selector:
    ????matchLabels:
    ??????app:?ghost-app
    ??replicas:?2
    ??template:
    ????metadata:
    ??????labels:
    ????????app:?ghost-app
    ????spec:
    ??????containers:
    ????????-?name:?ghost-app
    ??????????image:?ghost
    ??????????ports:
    ????????????-?containerPort:?2368
    ---
    #?ghost/service.yaml
    apiVersion:?v1
    kind:?Service
    metadata:
    ??name:?ghost
    spec:
    ??type:?NodePort
    ??selector:
    ????app:?ghost-app
    ??ports:
    ????-?protocol:?TCP
    ??????port:?80
    ??????targetPort:?2368

    直接通過(guò) kubectl 應(yīng)用上面的資源對(duì)象即可:

    ??kubectl?apply?-f?ghost/deployment.yaml?ghost/service.yaml
    deployment.apps/ghost?created
    service/ghost?created
    ??kubectl?get?pod?-l?app=ghost-app
    NAME????????????????????READY???STATUS????RESTARTS???AGE
    ghost-dfd958cc9-4s9b9???1/1?????Running???0??????????2m54s
    ghost-dfd958cc9-84kmv???1/1?????Running???0??????????2m54s
    ??kubectl?get?svc?ghost
    NAME????TYPE???????CLUSTER-IP??????EXTERNAL-IP???PORT(S)????????AGE
    ghost???NodePort???10.97.227.160???????????80:31950/TCP???3m33s

    這樣我們就可以通過(guò) http://:31950 訪問(wèn)到 Ghost 了:

    ghost

    看上去要部署 Ghost 是非常簡(jiǎn)單的,但是如果我們需要針對(duì)不同的環(huán)境進(jìn)行不同的設(shè)置呢?比如我們想將它部署到不同環(huán)境(staging、prod)中去,是不是我們需要一遍又一遍地復(fù)制我們的 Kubernetes 資源清單文件,這還只是一個(gè)場(chǎng)景,還有很多場(chǎng)景可能需要我們?nèi)ゲ渴饝?yīng)用,這種方式維護(hù)起來(lái)是非常困難的,這個(gè)時(shí)候就可以理由 Helm 來(lái)解放我們了。

    基礎(chǔ)模板

    現(xiàn)在我們開始創(chuàng)建一個(gè)新的 Helm Chart 包。直接使用 helm create 命令即可:

    ??helm?create?my-ghost

    Creating?my-ghost
    ??tree?my-ghost
    my-ghost
    ├──?Chart.yaml
    ├──?charts
    ├──?templates
    │???├──?NOTES.txt
    │???├──?_helpers.tpl
    │???├──?deployment.yaml
    │???├──?hpa.yaml
    │???├──?ingress.yaml
    │???├──?service.yaml
    │???├──?serviceaccount.yaml
    │???└──?tests
    │???????└──?test-connection.yaml
    └──?values.yaml

    3?directories,?10?files

    該命令會(huì)創(chuàng)建一個(gè)默認(rèn) Helm Chart 包的腳手架,可以刪掉下面的這些使用不到的文件:

    templates/tests/test-connection.yaml
    templates/serviceaccount.yaml
    templates/ingress.yaml
    templates/hpa.yaml
    templates/NOTES.txt

    然后修改 templates/deployment.yaml 模板文件:

    #?templates/deployment.yaml
    apiVersion:?apps/v1
    kind:?Deployment
    metadata:
    ??name:?ghost
    spec:
    ??selector:
    ????matchLabels:
    ??????app:?ghost-app
    ??replicas:?{{?.Values.replicaCount?}}
    ??template:
    ????metadata:
    ??????labels:
    ????????app:?ghost-app
    ????spec:
    ??????containers:
    ????????-?name:?ghost-app
    ??????????image:?{{?.Values.image?}}
    ??????????ports:
    ????????????-?containerPort:?2368
    ??????????env:
    ????????????-?name:?NODE_ENV
    ??????????????value:?{{?.Values.node_env?|?default?"production"?}}
    ????????????{{-?if?.Values.url?}}
    ????????????-?name:?url
    ??????????????value:?http://{{?.Values.url?}}
    ????????????{{-?end?}}

    這和我們前面的資源清單文件非常類似,只是將 replicas 的值使用 {{ .Values.replicaCount }} 模板來(lái)進(jìn)行替換了,表示會(huì)用 replicaCount 這個(gè) Values 值進(jìn)行渲染,然后還可以通過(guò)設(shè)置環(huán)境變量來(lái)配置 Ghost,同樣修改 templates/service.yaml 模板文件的內(nèi)容:

    #?templates/service.yaml
    apiVersion:?v1
    kind:?Service
    metadata:
    ??name:?ghost
    spec:
    ??selector:
    ????app:?ghost-app
    ??type:?{{?.Values.service.type?}}
    ??ports:
    ????-?protocol:?TCP
    ??????targetPort:?2368
    ??????port:?{{?.Values.service.port?}}
    ??????{{-?if?(and?(or?(eq?.Values.service.type?"NodePort")?(eq?.Values.service.type?"LoadBalancer"))?(not?(empty?.Values.service.nodePort)))?}}
    ??????nodePort:?{{?.Values.service.nodePort?}}
    ??????{{-?else?if?eq?.Values.service.type?"ClusterIP"?}}
    ??????nodePort:?null
    ??????{{-?end?}}

    同樣為了能夠兼容多個(gè)場(chǎng)景,這里我們?cè)试S用戶來(lái)定制 Service 的 type,如果是 NodePort 類型則還可以配置 nodePort 的值,不過(guò)需要注意這里的判斷,因?yàn)橛锌赡芗词古渲脼?NodePort 類型,用戶也可能不會(huì)主動(dòng)提供 nodePort,所以這里我們?cè)谀0逯凶隽艘粋€(gè)條件判斷:

    {{-?if?(and?(or?(eq?.Values.service.type?"NodePort")?(eq?.Values.service.type?"LoadBalancer"))?(not?(empty?.Values.service.nodePort)))?}}

    需要 service.type 為 NodePort 或者 LoadBalancer 并且 service.nodePort 不為空的情況下才會(huì)渲染 nodePort。

    然后最重要的就是要在 values.yaml 文件中提供默認(rèn)的 Values 值,如下所示是我們提供的默認(rèn)的 Values 值:

    #?values.yaml
    replicaCount:?1
    image:?ghost
    node_env:?production
    url:?ghost.k8s.local

    service:
    ??type:?NodePort
    ??port:?80

    然后我們可以使用 helm template 命令來(lái)渲染我們的模板輸出結(jié)果:

    ??helm?template?--debug?my-ghost
    install.go:178:?[debug]?Original?chart?version:?""
    install.go:195:?[debug]?CHART?PATH:?/Users/ych/devs/workspace/yidianzhishi/course/k8strain3/content/helm/manifests/my-ghost

    ---
    #?Source:?my-ghost/templates/service.yaml
    apiVersion:?v1
    kind:?Service
    metadata:
    ??name:?ghost
    spec:
    ??selector:
    ????app:?ghost-app
    ??type:?NodePort
    ??ports:
    ????-?protocol:?TCP
    ??????targetPort:?2368
    ??????port:?80
    ---
    #?Source:?my-ghost/templates/deployment.yaml
    apiVersion:?apps/v1
    kind:?Deployment
    metadata:
    ??name:?ghost
    spec:
    ??selector:
    ????matchLabels:
    ??????app:?ghost-app
    ??replicas:?1
    ??template:
    ????metadata:
    ??????labels:
    ????????app:?ghost-app
    ????spec:
    ??????containers:
    ????????-?name:?ghost-app
    ??????????image:?ghost
    ??????????ports:
    ????????????-?containerPort:?2368
    ??????????env:
    ????????????-?name:?NODE_ENV
    ??????????????value:?production
    ????????????-?name:?url
    ??????????????value:?http://ghost.k8s.local

    上面的渲染結(jié)果和我們上面的資源清單文件基本上一致了,只是我們現(xiàn)在的靈活性更大了,比如可以控制環(huán)境變量、服務(wù)的暴露方式等等。

    命名模板

    雖然現(xiàn)在我們可以使用 Helm Charts 模板來(lái)渲染安裝 Ghost 了,但是上面我們的模板還有很多改進(jìn)的地方,比如資源對(duì)象的名稱我們是固定的,這樣我們就沒辦法在同一個(gè)命名空間下面安裝多個(gè)應(yīng)用了,所以一般我們也會(huì)根據(jù) Chart 名稱或者 Release 名稱來(lái)替換資源對(duì)象的名稱。

    前面默認(rèn)創(chuàng)建的模板中包含一個(gè) _helpers.tpl 的文件,該文件中包含一些和名稱、標(biāo)簽相關(guān)的命名模板,我們可以直接使用即可,下面是默認(rèn)生成的已有的命名模板:

    {{/*
    Expand?the?name?of?the?chart.
    */}}
    {{-?define?"my-ghost.name"?-}}
    {{-?default?.Chart.Name?.Values.nameOverride?|?trunc?63?|?trimSuffix?"-"?}}
    {{-?end?}}

    {{/*
    Create?a?default?fully?qualified?app?name.
    We?truncate?at?63?chars?because?some?Kubernetes?name?fields?are?limited?to?this?(by?the?DNS?naming?spec).
    If?release?name?contains?chart?name?it?will?be?used?as?a?full?name.
    */}}
    {{-?define?"my-ghost.fullname"?-}}
    {{-?if?.Values.fullnameOverride?}}
    {{-?.Values.fullnameOverride?|?trunc?63?|?trimSuffix?"-"?}}
    {{-?else?}}
    {{-?$name?:=?default?.Chart.Name?.Values.nameOverride?}}
    {{-?if?contains?$name?.Release.Name?}}
    {{-?.Release.Name?|?trunc?63?|?trimSuffix?"-"?}}
    {{-?else?}}
    {{-?printf?"%s-%s"?.Release.Name?$name?|?trunc?63?|?trimSuffix?"-"?}}
    {{-?end?}}
    {{-?end?}}
    {{-?end?}}

    {{/*
    Create?chart?name?and?version?as?used?by?the?chart?label.
    */}}
    {{-?define?"my-ghost.chart"?-}}
    {{-?printf?"%s-%s"?.Chart.Name?.Chart.Version?|?replace?"+"?"_"?|?trunc?63?|?trimSuffix?"-"?}}
    {{-?end?}}

    {{/*
    Common?labels
    */}}
    {{-?define?"my-ghost.labels"?-}}
    helm.sh/chart:?{{?include?"my-ghost.chart"?.?}}
    {{?include?"my-ghost.selectorLabels"?.?}}
    {{-?if?.Chart.AppVersion?}}
    app.kubernetes.io/version:?{{?.Chart.AppVersion?|?quote?}}
    {{-?end?}}
    app.kubernetes.io/managed-by:?{{?.Release.Service?}}
    {{-?end?}}

    {{/*
    Selector?labels
    */}}
    {{-?define?"my-ghost.selectorLabels"?-}}
    app.kubernetes.io/name:?{{?include?"my-ghost.name"?.?}}
    app.kubernetes.io/instance:?{{?.Release.Name?}}
    {{-?end?}}

    然后我們可以將 Deployment 的名稱和標(biāo)簽替換掉:

    #?templates/deployment.yaml
    apiVersion:?apps/v1
    kind:?Deployment
    metadata:
    ??name:?{{?template?"my-ghost.fullname"?.?}}
    ??labels:
    {{?include?"my-ghost.labels"?.?|?indent?4?}}
    spec:
    ??selector:
    ????matchLabels:
    {{?include?"my-ghost.selectorLabels"?.?|?indent?6?}}
    ??replicas:?{{?.Values.replicaCount?}}
    ??template:
    ????metadata:
    ??????labels:
    {{?include?"my-ghost.selectorLabels"?.?|?indent?8?}}
    ????spec:
    ????#?other?spec...

    為 Deployment 增加 label 標(biāo)簽,同樣 labelSelector 中也使用 my-ghost.selectorLabels 這個(gè)命名模板進(jìn)行替換,同樣對(duì) Service 也做相應(yīng)的改造:

    apiVersion:?v1
    kind:?Service
    metadata:
    ??name:?{{?template?"my-ghost.fullname"?.?}}
    ??labels:
    {{?include?"my-ghost.labels"?.?|?indent?4?}}
    spec:
    ??selector:
    {{?include?"my-ghost.selectorLabels"?.?|?indent?4?}}
    ??type:?{{?.Values.service.type?}}
    ??#?other?spec...

    現(xiàn)在我們可以再使用 helm template 渲染驗(yàn)證結(jié)果是否正確:

    ??helm?template?--debug?my-ghost
    install.go:178:?[debug]?Original?chart?version:?""
    install.go:195:?[debug]?CHART?PATH:?/Users/ych/devs/workspace/yidianzhishi/course/k8strain3/content/helm/manifests/my-ghost

    ---
    #?Source:?my-ghost/templates/service.yaml
    apiVersion:?v1
    kind:?Service
    metadata:
    ??name:?release-name-my-ghost
    ??labels:
    ????helm.sh/chart:?my-ghost-0.1.0
    ????app.kubernetes.io/name:?my-ghost
    ????app.kubernetes.io/instance:?release-name
    ????app.kubernetes.io/version:?"1.16.0"
    ????app.kubernetes.io/managed-by:?Helm
    spec:
    ??selector:
    ????app.kubernetes.io/name:?my-ghost
    ????app.kubernetes.io/instance:?release-name
    ??type:?NodePort
    ??ports:
    ????-?protocol:?TCP
    ??????targetPort:?2368
    ??????port:?80
    ---
    #?Source:?my-ghost/templates/deployment.yaml
    apiVersion:?apps/v1
    kind:?Deployment
    metadata:
    ??name:?release-name-my-ghost
    ??labels:
    ????helm.sh/chart:?my-ghost-0.1.0
    ????app.kubernetes.io/name:?my-ghost
    ????app.kubernetes.io/instance:?release-name
    ????app.kubernetes.io/version:?"1.16.0"
    ????app.kubernetes.io/managed-by:?Helm
    spec:
    ??selector:
    ????matchLabels:
    ??????app.kubernetes.io/name:?my-ghost
    ??????app.kubernetes.io/instance:?release-name
    ??replicas:?1
    ??template:
    ????metadata:
    ??????labels:
    ????????app.kubernetes.io/name:?my-ghost
    ????????app.kubernetes.io/instance:?release-name
    ????spec:
    ??????containers:
    ????????-?name:?ghost-app
    ??????????image:?ghost
    ??????????ports:
    ????????????-?containerPort:?2368
    ??????????env:
    ????????????-?name:?NODE_ENV
    ??????????????value:?production
    ????????????-?name:?url
    ??????????????value:?http://ghost.k8s.local

    版本兼容

    由于 Kubernetes 的版本迭代非???,所以我們?cè)陂_發(fā) Chart 包的時(shí)候有必要考慮到對(duì)不同版本的 Kubernetes 進(jìn)行兼容,最明顯的就是 Ingress 的資源版本。Kubernetes 在 1.19 版本為 Ingress 資源引入了一個(gè)新的 API:networking.k8s.io/v1,這與之前的 networking.k8s.io/v1beta1 beta 版本使用方式基本一致,但是和前面的 extensions/v1beta1 這個(gè)版本在使用上有很大的不同,資源對(duì)象的屬性上有一定的區(qū)別,所以要兼容不同的版本,我們就需要對(duì)模板中的 Ingress 對(duì)象做兼容處理。

    新版本的資源對(duì)象格式如下所示:

    apiVersion:?networking.k8s.io/v1
    kind:?Ingress
    metadata:
    ??name:?minimal-ingress
    ??annotations:
    ????nginx.ingress.kubernetes.io/rewrite-target:?/
    spec:
    ??ingressClassName:?nginx
    ??rules:
    ??-?http:
    ??????paths:
    ??????-?path:?/testpath
    ????????pathType:?Prefix
    ????????backend:
    ??????????service:
    ????????????name:?test
    ????????????port:
    ??????????????number:?80

    而舊版本的資源對(duì)象格式如下:

    apiVersion:?extensions/v1beta1
    kind:?Ingress
    metadata:
    ??name:?minimal-ingress
    ??annotations:
    ????kubernetes.io/ingress.class:?nginx
    ????nginx.ingress.kubernetes.io/rewrite-target:?/
    spec:
    ??rules:
    ??-?http:
    ??????paths:
    ??????-?path:?/testpath
    ????????backend:
    ??????????serviceName:?test
    ??????????servicePort:?80

    現(xiàn)在我們?cè)贋?Ghost 添加一個(gè) Ingress 的模板,新建 templates/ingress.yaml 模板文件,先添加一個(gè) v1 版本的 Ingress 模板:

    apiVersion:?networking.k8s.io/v1
    kind:?Ingress
    metadata:
    ??name:?ghost
    spec:
    ??ingressClassName:?nginx
    ??rules:
    ??-?host:?ghost.k8s.local
    ????http:
    ??????paths:
    ??????-?path:?/
    ????????pathType:?Prefix
    ????????backend:
    ??????????service:
    ????????????name:?ghost
    ????????????port:
    ??????????????number:?80

    然后同樣將名稱和服務(wù)名稱這些使用模板參數(shù)進(jìn)行替換:

    apiVersion:?networking.k8s.io/v1
    kind:?Ingress
    metadata:
    ??name:?{{?template?"my-ghost.fullname"?.?}}
    ??labels:
    {{?include?"my-ghost.labels"?.?|?indent?4?}}
    spec:
    ??ingressClassName:?nginx
    ??rules:
    ??-?host:?{{?.Values.url?}}
    ????http:
    ??????paths:
    ??????-?path:?/
    ????????pathType:?Prefix
    ????????backend:
    ??????????service:
    ????????????name:?{{?template?"my-ghost.fullname"?.?}}
    ????????????port:
    ??????????????number:?{{?.Values.service.port?}}

    然后接下來(lái)我們來(lái)兼容下其他的版本格式,這里需要用到 Capabilities 對(duì)象,在 Chart 包的 _helpers.tpl 文件中添加幾個(gè)用于判斷集群版本或 API 的命名模板:

    {{/*?Allow?KubeVersion?to?be?overridden.?*/}}
    {{-?define?"my-ghost.kubeVersion"?-}}
    ??{{-?default?.Capabilities.KubeVersion.Version?.Values.kubeVersionOverride?-}}
    {{-?end?-

    {{/*?Get?Ingress?API?Version?*/}}
    {{-?define?"my-ghost.ingress.apiVersion"?-}}
    ??{{-?if?and?(.Capabilities.APIVersions.Has?"networking.k8s.io/v1")?(semverCompare?">=?1.19-0"?(include?"my-ghost.kubeVersion"?.))?-}}
    ??????{{-?print?"networking.k8s.io/v1"?-}}
    ??{{-?else?if?.Capabilities.APIVersions.Has?"networking.k8s.io/v1beta1"?-}}
    ????{{-?print?"networking.k8s.io/v1beta1"?-}}
    ??{{-?else?-}}
    ????{{-?print?"extensions/v1beta1"?-}}
    ??{{-?end?-}}
    {{-?end?-}}

    {{/*?Check?Ingress?stability?*/}}
    {{-?define?"my-ghost.ingress.isStable"?-}}
    ??{{-?eq?(include?"my-ghost.ingress.apiVersion"?.)?"networking.k8s.io/v1"?-}}
    {{-?end?-}}

    {{/*?Check?Ingress?supports?pathType?*/}}
    {{/*?pathType?was?added?to?networking.k8s.io/v1beta1?in?Kubernetes?1.18?*/}}
    {{-?define?"my-ghost.ingress.supportsPathType"?-}}
    ??{{-?or?(eq?(include?"my-ghost.ingress.isStable"?.)?"true")?(and?(eq?(include?"my-ghost.ingress.apiVersion"?.)?"networking.k8s.io/v1beta1")?(semverCompare?">=?1.18-0"?(include?"my-ghost.kubeVersion"?.)))?-}}
    {{-?end?-}}

    上面我們通過(guò) .Capabilities.APIVersions.Has 來(lái)判斷我們應(yīng)該使用的 APIVersion,如果版本為 networking.k8s.io/v1,則定義為 isStable,此外還根據(jù)版本來(lái)判斷是否需要支持 pathType 屬性,然后在 Ingress 對(duì)象模板中就可以使用上面定義的命名模板來(lái)決定應(yīng)該使用哪些屬性,如下所示:

    {{-?if?.Values.ingress.enabled?}}
    {{-?$apiIsStable?:=?eq?(include?"my-ghost.ingress.isStable"?.)?"true"?-}}
    {{-?$ingressSupportsPathType?:=?eq?(include?"my-ghost.ingress.supportsPathType"?.)?"true"?-}}
    apiVersion:?{{?include?"my-ghost.ingress.apiVersion"?.?}}
    kind:?Ingress
    metadata:
    ??name:?{{?template?"my-ghost.fullname"?.?}}
    ??annotations:
    ????nginx.ingress.kubernetes.io/ssl-redirect:?"false"
    ????{{-?if?and?.Values.ingress.ingressClass?(not?$apiIsStable)?}}
    ????kubernetes.io/ingress.class:?{{?.Values.ingress.ingressClass?}}
    ????{{-?end?}}
    ??labels:
    ????{{-?include?"my-ghost.labels"?.?|?nindent?4?}}
    spec:
    ??{{-?if?and?.Values.ingress.ingressClass?$apiIsStable?}}
    ??ingressClassName:?{{?.Values.ingress.ingressClass?}}
    ??{{-?end?}}
    ??rules:
    ??{{-?if?not?(empty?.Values.url)?}}
    ??-?host:?{{?.Values.url?}}
    ????http:
    ??{{-?else?}}
    ??-?http:
    ??{{-?end?}}
    ??????paths:
    ??????-?path:?/
    ????????{{-?if?$ingressSupportsPathType?}}
    ????????pathType:?Prefix
    ????????{{-?end?}}
    ????????backend:
    ??????????{{-?if?$apiIsStable?}}
    ??????????service:
    ????????????name:?{{?template?"my-ghost.fullname"?.?}}
    ????????????port:
    ??????????????number:?{{?.Values.service.port?}}
    ??????????{{-?else?}}
    ??????????serviceName:?{{?template?"my-ghost.fullname"?.?}}
    ??????????servicePort:?{{?.Values.service.port?}}
    ??????????{{-?end?}}
    {{-?end?}}

    由于有的場(chǎng)景下面并不需要使用 Ingress 來(lái)暴露服務(wù),所以首先我們通過(guò)一個(gè) ingress.enabled 屬性來(lái)控制是否需要渲染,然后定義了一個(gè) $apiIsStable 變量,來(lái)表示當(dāng)前集群是否是穩(wěn)定版本的 API,然后需要根據(jù)該變量去渲染不同的屬性,比如對(duì)于 ingressClass,如果是穩(wěn)定版本的 API 則是通過(guò) spec.ingressClassName 來(lái)指定,否則是通過(guò) kubernetes.io/ingress.class 這個(gè) annotations 來(lái)指定。然后這里我們?cè)?values.yaml 文件中添加如下所示默認(rèn)的 Ingress 的配置數(shù)據(jù):

    ingress:
    ??enabled:?true
    ??ingressClass:?nginx

    現(xiàn)在我們?cè)俅武秩?Helm Chart 模板來(lái)驗(yàn)證資源清單數(shù)據(jù):

    ??helm?template?--debug?my-ghost
    install.go:178:?[debug]?Original?chart?version:?""
    install.go:195:?[debug]?CHART?PATH:?/Users/ych/devs/workspace/yidianzhishi/course/k8strain3/content/helm/manifests/my-ghost

    ---
    #?Source:?my-ghost/templates/service.yaml
    apiVersion:?v1
    kind:?Service
    metadata:
    ??name:?release-name-my-ghost
    ??labels:
    ????helm.sh/chart:?my-ghost-0.1.0
    ????app.kubernetes.io/name:?my-ghost
    ????app.kubernetes.io/instance:?release-name
    ????app.kubernetes.io/version:?"1.16.0"
    ????app.kubernetes.io/managed-by:?Helm
    spec:
    ??selector:
    ????app.kubernetes.io/name:?my-ghost
    ????app.kubernetes.io/instance:?release-name
    ??type:?NodePort
    ??ports:
    ????-?protocol:?TCP
    ??????targetPort:?2368
    ??????port:?80
    ---
    #?Source:?my-ghost/templates/deployment.yaml
    apiVersion:?apps/v1
    kind:?Deployment
    metadata:
    ??name:?release-name-my-ghost
    ??labels:
    ????helm.sh/chart:?my-ghost-0.1.0
    ????app.kubernetes.io/name:?my-ghost
    ????app.kubernetes.io/instance:?release-name
    ????app.kubernetes.io/version:?"1.16.0"
    ????app.kubernetes.io/managed-by:?Helm
    spec:
    ??selector:
    ????matchLabels:
    ??????app.kubernetes.io/name:?my-ghost
    ??????app.kubernetes.io/instance:?release-name
    ??replicas:?1
    ??template:
    ????metadata:
    ??????labels:
    ????????app.kubernetes.io/name:?my-ghost
    ????????app.kubernetes.io/instance:?release-name
    ????spec:
    ??????containers:
    ????????-?name:?ghost-app
    ??????????image:?ghost
    ??????????ports:
    ????????????-?containerPort:?2368
    ??????????env:
    ????????????-?name:?NODE_ENV
    ??????????????value:?production
    ????????????-?name:?url
    ??????????????value:?http://ghost.k8s.local
    ---
    #?Source:?my-ghost/templates/ingress.yaml
    apiVersion:?networking.k8s.io/v1
    kind:?Ingress
    metadata:
    ??name:?release-name-my-ghost
    ??annotations:
    ????nginx.ingress.kubernetes.io/ssl-redirect:?"false"
    ??labels:
    ????helm.sh/chart:?my-ghost-0.1.0
    ????app.kubernetes.io/name:?my-ghost
    ????app.kubernetes.io/instance:?release-name
    ????app.kubernetes.io/version:?"1.16.0"
    ????app.kubernetes.io/managed-by:?Helm
    spec:
    ??ingressClassName:?nginx
    ??rules:
    ??-?host:?ghost.k8s.local
    ????http:
    ??????paths:
    ??????-?path:?/
    ????????pathType:?Prefix
    ????????backend:
    ??????????service:
    ????????????name:?release-name-my-ghost
    ????????????port:
    ??????????????number:?80

    從上面的資源清單可以看出是符合我們的預(yù)期要求的,我們可以來(lái)安裝測(cè)試下結(jié)果:

    ??helm?upgrade?--install?my-ghost?./my-ghost?-n?default
    Release?"my-ghost"?does?not?exist.?Installing?it?now.
    NAME:?my-ghost
    LAST?DEPLOYED:?Thu?Mar?17?13:11:15?2022
    NAMESPACE:?default
    STATUS:?deployed
    REVISION:?1
    TEST?SUITE:?None

    ??helm?ls?-n?default
    NAME????????????NAMESPACE???????REVISION????????UPDATED?????????????????????????????????STATUS??????????CHART????????????????APP?VERSION
    my-ghost????????default?????????1???????????????2022-03-17?13:11:15.79828?+0800?CST?????deployed????????my-ghost-0.1.0???????1.16.0
    ??kubectl?get?pods?-n?default
    NAME????????????????????????READY???STATUS??????RESTARTS???AGE
    my-ghost-7cf7fb6484-75hkk???1/1?????Running?????0??????????3m9s
    ??kubectl?get?svc?-n?default
    NAME?????????TYPE????????CLUSTER-IP???????EXTERNAL-IP???PORT(S)????????AGE
    kubernetes???ClusterIP???10.96.0.1????????????????443/TCP????????142d
    my-ghost?????NodePort????10.108.125.187???????????80:32433/TCP???3m20s
    ??kubectl?get?ingress?-n?default
    NAME???????CLASS???HOSTS?????????????ADDRESS?????????PORTS???AGE
    my-ghost???nginx???ghost.k8s.local???192.168.31.31???80??????3m32s

    正常就可以部署成功 Ghost 了,并且可以通過(guò)域名 http://ghost.k8s.local 進(jìn)行訪問(wèn)了:

    Ghost

    持久化

    上面我們使用的 Ghost 鏡像默認(rèn)使用 SQLite 數(shù)據(jù)庫(kù),所以非常有必要將數(shù)據(jù)進(jìn)行持久化,當(dāng)然我們要將這個(gè)開關(guān)給到用戶去選擇,修改 templates/deployment.yaml 模板文件,增加 volumes 相關(guān)配置:

    #?other?spec...
    spec:
    ??volumes:
    ????-?name:?ghost-data
    ????{{-?if?.Values.persistence.enabled?}}
    ??????persistentVolumeClaim:
    ????????claimName:?{{?.Values.persistence.existingClaim?|?default?(include?"my-ghost.fullname"?.)?}}
    ????{{-?else?}}
    ??????emptyDir:?{}
    ????{{?end?}}
    ??containers:
    ????-?name:?ghost-app
    ??????image:?{{?.Values.image?}}
    ??????volumeMounts:
    ????????-?name:?ghost-data
    ??????????mountPath:?/var/lib/ghost/content
    ??????#?other?spec...

    這里我們通過(guò) persistence.enabled 來(lái)判斷是否需要開啟持久化數(shù)據(jù),如果開啟則需要看用戶是否直接提供了一個(gè)存在的 PVC 對(duì)象,如果沒有提供,則我們需要自己創(chuàng)建一個(gè)合適的 PVC 對(duì)象,如果不需要持久化,則直接使用 emptyDir:{} 即可,添加 templates/pvc.yaml 模板,內(nèi)容如下所示:

    {{-?if?and?.Values.persistence.enabled?(not?.Values.persistence.existingClaim)?}}
    kind:?PersistentVolumeClaim
    apiVersion:?v1
    metadata:
    ??name:?{{?template?"my-ghost.fullname"?.?}}
    ??labels:
    ????{{-?include?"my-ghost.labels"?.?|?nindent?4?}}
    spec:
    ??{{-?if?.Values.persistence.storageClass?}}
    ??storageClassName:?{{?.Values.persistence.storageClass?|?quote?}}
    ??{{-?end?}}
    ??accessModes:
    ??-?{{?.Values.persistence.accessMode?|?quote?}}
    ??resources:
    ????requests:
    ??????storage:?{{?.Values.persistence.size?|?quote?}}
    {{-?end?-}}

    其中訪問(wèn)模式、存儲(chǔ)容量、StorageClass、存在的 PVC 都通過(guò) Values 來(lái)指定,增加了靈活性。對(duì)應(yīng)的 values.yaml 配置部分我們可以給一個(gè)默認(rèn)的配置:

    ##?是否使用?PVC?開啟數(shù)據(jù)持久化
    persistence:
    ??enabled:?true
    ??##?是否使用?storageClass,如果不適用則補(bǔ)配置
    ??#?storageClass:?"xxx"
    ??##
    ??##?如果想使用一個(gè)存在的?PVC?對(duì)象,則直接傳遞給下面的?existingClaim?變量
    ??#?existingClaim:?your-claim
    ??accessMode:?ReadWriteOnce??#?訪問(wèn)模式
    ??size:?1Gi??#?存儲(chǔ)容量

    定制

    除了上面的這些主要的需求之外,還有一些額外的定制需求,比如用戶想要配置更新策略,因?yàn)楦虏呗圆⒉皇且粚硬蛔兊?,這里和之前不太一樣,我們需要用到一個(gè)新的函數(shù) toYaml

    {{-?if?.Values.updateStrategy?}}
    strategy:?{{?toYaml?.Values.updateStrategy?|?nindent?4?}}
    {{-?end?}}

    意思就是我們將 updateStrategy 這個(gè) Values 值轉(zhuǎn)換成 YAML 格式,并保留4個(gè)空格。然后添加其他的配置,比如是否需要添加 nodeSelector、容忍、親和性這些,這里我們都是使用 toYaml 函數(shù)來(lái)控制空格,如下所示:

    {{-?if?.Values.nodeSelector?}}
    nodeSelector:?{{-?toYaml?.Values.nodeSelector?|?nindent?8?}}
    {{-?end?-}}
    {{-?with?.Values.affinity?}}
    affinity:?{{-?toYaml?.?|?nindent?8?}}
    {{-?end?}}
    {{-?with?.Values.tolerations?}}
    tolerations:?{{-?toYaml?.?|?nindent?8?}}
    {{-?end?}}

    接下來(lái)當(dāng)然就是鏡像的配置了,如果是私有倉(cāng)庫(kù)還需要指定 imagePullSecrets

    {{-?if?.Values.image.pullSecrets?}}
    imagePullSecrets:
    {{-?range?.Values.image.pullSecrets?}}
    -?name:?{{?.?}}
    {{-?end?}}
    {{-?end?}}
    containers:
    -?name:?ghost
    ??image:?{{?printf?"%s:%s"?.Values.image.name?.Values.image.tag?}}
    ??imagePullPolicy:?{{?.Values.image.pullPolicy?|?quote?}}
    ??ports:
    ??-?containerPort:?2368

    對(duì)應(yīng)的 Values 值如下所示:

    image:
    ??name:?ghost
    ??tag:?latest
    ??pullPolicy:?IfNotPresent
    ??##?如果是私有倉(cāng)庫(kù),需要指定?imagePullSecrets
    ??#?pullSecrets:
    ??#???-?myRegistryKeySecretName

    然后就是 resource 資源聲明,這里我們定義一個(gè)默認(rèn)的 resources 值,同樣用 toYaml 函數(shù)來(lái)控制空格:

    resources:
    {{?toYaml?.Values.resources?|?indent?10?}}

    最后是健康檢查部分,雖然我們之前沒有做 livenessProbe,但是我們開發(fā) Chart 模板的時(shí)候就要盡可能考慮周全一點(diǎn),這里我們加上存活性和可讀性、啟動(dòng)三個(gè)探針,并且根據(jù) livenessProbe.enabled 、readinessProbe.enabled 以及 startupProbe.enabled 三個(gè) Values 值來(lái)判斷是否需要添加探針,探針對(duì)應(yīng)的參數(shù)也都通過(guò) Values 值來(lái)配置:

    {{-?if?.Values.startupProbe.enabled?}}
    startupProbe:
    ??httpGet:
    ????path:?/
    ????port:?2368
    ??initialDelaySeconds:?{{?.Values.startupProbe.initialDelaySeconds?}}
    ??periodSeconds:?{{?.Values.startupProbe.periodSeconds?}}
    ??timeoutSeconds:?{{?.Values.startupProbe.timeoutSeconds?}}
    ??failureThreshold:?{{?.Values.startupProbe.failureThreshold?}}
    ??successThreshold:?{{?.Values.startupProbe.successThreshold?}}
    {{-?end?}}
    {{-?if?.Values.livenessProbe.enabled?}}
    livenessProbe:
    ??httpGet:
    ????path:?/
    ????port:?2368
    ??initialDelaySeconds:?{{?.Values.livenessProbe.initialDelaySeconds?}}
    ??periodSeconds:?{{?.Values.livenessProbe.periodSeconds?}}
    ??timeoutSeconds:?{{?.Values.livenessProbe.timeoutSeconds?}}
    ??failureThreshold:?{{?.Values.livenessProbe.failureThreshold?}}
    ??successThreshold:?{{?.Values.livenessProbe.successThreshold?}}
    {{-?end?}}
    {{-?if?.Values.readinessProbe.enabled?}}
    readinessProbe:
    ??httpGet:
    ????path:?/
    ????port:?2368
    ??initialDelaySeconds:?{{?.Values.readinessProbe.initialDelaySeconds?}}
    ??periodSeconds:?{{?.Values.readinessProbe.periodSeconds?}}
    ??timeoutSeconds:?{{?.Values.readinessProbe.timeoutSeconds?}}
    ??failureThreshold:?{{?.Values.readinessProbe.failureThreshold?}}
    ??successThreshold:?{{?.Values.readinessProbe.successThreshold?}}
    {{-?end?}}

    默認(rèn)的 values.yaml 文件如下所示:

    replicaCount:?1
    image:
    ??name:?ghost
    ??tag:?latest
    ??pullPolicy:?IfNotPresent

    node_env:?production
    url:?ghost.k8s.local

    service:
    ??type:?ClusterIP
    ??port:?80

    ingress:
    ??enabled:?true
    ??ingressClass:?nginx

    ##?是否使用?PVC?開啟數(shù)據(jù)持久化
    persistence:
    ??enabled:?true
    ??##?是否使用?storageClass,如果不適用則補(bǔ)配置
    ??#?storageClass:?"xxx"
    ??##
    ??##?如果想使用一個(gè)存在的?PVC?對(duì)象,則直接傳遞給下面的?existingClaim?變量
    ??#?existingClaim:?your-claim
    ??accessMode:?ReadWriteOnce??#?訪問(wèn)模式
    ??size:?1Gi??#?存儲(chǔ)容量

    nodeSelector:?{}

    affinity:?{}

    tolerations:?{}

    resources:?{}

    startupProbe:
    ??enabled:?false

    livenessProbe:
    ??enabled:?false

    readinessProbe:
    ??enabled:?false

    現(xiàn)在我們?cè)偃ジ?Release:

    ??helm?upgrade?--install?my-ghost?./my-ghost?-n?default
    Release?"my-ghost"?has?been?upgraded.?Happy?Helming!
    NAME:?my-ghost
    LAST?DEPLOYED:?Thu?Mar?17?16:03:02?2022
    NAMESPACE:?default
    STATUS:?deployed
    REVISION:?2
    TEST?SUITE:?None
    ??helm?ls?-n?default
    NAME????????????NAMESPACE???????REVISION????????UPDATED?????????????????????????????????STATUS??????????CHART????????????APP?VERSION
    my-ghost????????default?????????2???????????????2022-03-17?16:05:07.123349?+0800?CST????deployed????????my-ghost-0.1.0???1.16.0
    ??kubectl?get?pods?-n?default
    NAME????????????????????????READY???STATUS??????RESTARTS???AGE
    my-ghost-6dbc455fc7-cmm4p???1/1?????Running?????0??????????2m42s
    ??kubectl?get?pvc?-n?default
    NAME???????STATUS???VOLUME?????????????????????????????????????CAPACITY???ACCESS?MODES???STORAGECLASS???AGE
    my-ghost???Bound????pvc-2f0b7d5a-04d4-4331-848b-af21edce673e???1Gi????????RWO????????????nfs-client?????4m59s
    ??kubectl?get?ingress?-n?default
    NAME???????CLASS???HOSTS?????????????ADDRESS?????????PORTS???AGE
    my-ghost???nginx???ghost.k8s.local???192.168.31.31???80??????3h24m

    到這里我們就基本完成了這個(gè)簡(jiǎn)單的 Helm Charts 包的開發(fā),當(dāng)然以后可能還會(huì)有新的需求,我們需要不斷去迭代優(yōu)化。

    共享 Charts

    Helm Charts 包開發(fā)完成了,如果別人想要使用我們的包,則需要我們共享出去,我們可以通過(guò) Chart 倉(cāng)庫(kù)來(lái)進(jìn)行共享,Helm Charts 可以在遠(yuǎn)程存儲(chǔ)庫(kù)或本地環(huán)境/存儲(chǔ)庫(kù)中使用,遠(yuǎn)程存儲(chǔ)庫(kù)可以是公共的,如 Bitnami Charts 也可以是托管存儲(chǔ)庫(kù),如 Google Cloud Storage 或 GitHub。為了演示方便,這里我們使用 GitHub 來(lái)托管我們的 Charts 包。

    我們可以使用 GitHub Pages 來(lái)創(chuàng)建 Charts 倉(cāng)庫(kù),GitHub 允許我們以兩種不同的方式提供靜態(tài)網(wǎng)頁(yè):

    • 通過(guò)配置項(xiàng)目提供其 docs/ 目錄的內(nèi)容
    • 通過(guò)配置項(xiàng)目來(lái)服務(wù)特定的分支

    這里我們將采用第二種方法,首先在 GitHub 上創(chuàng)建一個(gè)代碼倉(cāng)庫(kù):https://github.com/cnych/helm101,將上面我們創(chuàng)建的 my-ghost 包提交到倉(cāng)庫(kù) charts 目錄下,然后打包 chart 包:

    ??helm?package?charts/my-ghost
    Successfully?packaged?chart?and?saved?it?to:?/Users/ych/devs/workspace/yidianzhishi/course/k8strain3/content/helm/manifests/helm101/my-ghost-0.1.0.tgz

    我們可以將打包的壓縮包放到另外的目錄 repo/stable 中去,現(xiàn)在倉(cāng)庫(kù)的結(jié)構(gòu)如下所示:

    ??tree?.
    .
    ├──?LICENSE
    ├──?README.md
    ├──?charts
    │???└──?my-ghost
    │???????├──?Chart.lock
    │???????├──?Chart.yaml
    │???????├──?charts
    │???????├──?templates
    │???????│???├──?_helpers.tpl
    │???????│???├──?deployment.yaml
    │???????│???├──?ingress.yaml
    │???????│???├──?pvc.yaml
    │???????│???├──?service.yaml
    │???????│???└──?tests
    │???????└──?values.yaml
    └──?repo
    ????└──?stable
    ????????└──?my-ghost-0.1.0.tgz

    執(zhí)行如下所示命令生成 index 索引文件:

    ??helm?repo?index?repo/stable?--url?https://raw.githubusercontent.com/cnych/helm101/main/repo/stable

    上述命令會(huì)在 repo/stable 目錄下面生成一個(gè)如下所示的 index.yaml 文件:

    apiVersion:?v1
    entries:
    ??my-ghost:
    ??-?apiVersion:?v2
    ????appVersion:?1.16.0
    ????created:?"2022-03-17T17:40:21.093654+08:00"
    ????description:?A?Helm?chart?for?Kubernetes
    ????digest:?f6d6308d6a6cd6357ab2b952650250c2df7b2727ce84c19150531fd72732626b
    ????name:?my-ghost
    ????type:?application
    ????urls:
    ????-?https://raw.githubusercontent.com/cnych/helm101/main/repo/stable/my-ghost-0.1.0.tgz
    ????version:?0.1.0
    generated:?"2022-03-17T17:40:21.090371+08:00"

    index.yaml 文件是我們通過(guò)倉(cāng)庫(kù)獲取 Chart 包的關(guān)鍵。然后將代碼推送到 GitHub:

    ??git?status
    On?branch?main
    Your?branch?is?up?to?date?with?'origin/main'.

    Untracked?files:
    ??(use?"git?add?..."?to?include?in?what?will?be?committed)

    ????????charts/
    ????????repo/

    nothing?added?to?commit?but?untracked?files?present?(use?"git?add"?to?track)
    ??git?commit?-m?"add?charts?and?index.yaml"
    [main?aae1059]?add?charts?and?index.yaml
    ?11?files?changed,?431?insertions(+)
    ?create?mode?100644?charts/my-ghost/.helmignore
    ?create?mode?100644?charts/my-ghost/Chart.lock
    ?create?mode?100644?charts/my-ghost/Chart.yaml
    ?create?mode?100644?charts/my-ghost/templates/_helpers.tpl
    ?create?mode?100644?charts/my-ghost/templates/deployment.yaml
    ?create?mode?100644?charts/my-ghost/templates/ingress.yaml
    ?create?mode?100644?charts/my-ghost/templates/pvc.yaml
    ?create?mode?100644?charts/my-ghost/templates/service.yaml
    ?create?mode?100644?charts/my-ghost/values.yaml
    ?create?mode?100644?repo/stable/index.yaml
    ?create?mode?100644?repo/stable/my-ghost-0.1.0.tgz
    ??git?push?origin?main
    Enumerating?objects:?18,?done.
    Counting?objects:?100%?(18/18),?done.
    Writing?objects:?100%?(18/18),?8.71?KiB?|?2.18?MiB/s,?done.
    Total?18?(delta?0),?reused?0?(delta?0)
    To?github.com:cnych/helm101.git
    ???9c389a6..aae1059??main?->?main

    接下來(lái)為該倉(cāng)庫(kù)設(shè)置 GitHub Pages,首先在本地新建一個(gè) gh-pages 分支:

    ??git?checkout?-b?gh-pages

    只將 repo/stable/index.yaml 文件保留到根目錄下面,其他文件忽略,然后推送到遠(yuǎn)程倉(cāng)庫(kù):

    ??git?push?origin?gh-pages
    Enumerating?objects:?2,?done.
    Counting?objects:?100%?(2/2),?done.
    Writing?objects:?100%?(2/2),?301?bytes?|?301.00?KiB/s,?done.
    Total?2?(delta?0),?reused?0?(delta?0)
    remote:
    remote:?Create?a?pull?request?for?'gh-pages'?on?GitHub?by?visiting:
    remote:??????https://github.com/cnych/helm101/pull/new/gh-pages
    remote:
    To?github.com:cnych/helm101.git
    ?*?[new?branch]??????gh-pages?->?gh-pages

    在 GitHub Pages 頁(yè)面選擇使用 gh-pages 分支即可:

    pages

    現(xiàn)在我們就可以通過(guò) https://cnych.github.io/helm101/ 來(lái)獲取我們的 Chart 包了。

    使用如下所示命令添加 repo 倉(cāng)庫(kù):

    ??helm?repo?add?helm101?https://cnych.github.io/helm101/

    "helm101"?has?been?added?to?your?repositories

    我們也可以使用 helm search 來(lái)搜索倉(cāng)庫(kù)中的 Chart 包,正常就包含上面我們的 my-ghost 了:

    ??helm?search?repo?helm101
    NAME????????????????????CHART?VERSION???APP?VERSION?????DESCRIPTION
    helm101/my-ghost????????0.1.0???????????1.16.0??????????A?Helm?chart?for?Kubernetes

    接下來(lái)就可以正常使用 chart 包進(jìn)行操作了,比如進(jìn)行安裝:

    ??helm?install?my-ghost?helm101/
    瀏覽 50
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評(píng)論
    圖片
    表情
    推薦
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    黄色免费啪啪 | 无码毛片一区二区三区人口 | 久久综合88 | 久爱免费视频 | 国产菊门残忍扩张视频 |