上一章節說明了 Helmc Chart 概念以及安裝 Helm。這章節將會建立一個 Helm chart,並實際操作。
開始建立,透過以下
helm create quarkus-dns
沒錯,預設上會建立以下 templates 下的資源。
$ tree quarkus-dns/
quarkus-dns/
├── Chart.yaml # Chart 資訊檔案
├── charts # 依賴 Chart 的目錄
├── templates # 產生有效的 Kubernetes YAML,預設會與 values.yaml 整合
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml # Chart 預設配置值,templates 下的資源將會引用此檔案產生 Kubernetes 可部署資源
但因為 Quarkus 應用程式需要 ConfigMap 資源,因此多定義以下。
.tpl
基本上是寫共用函式。{{- define "quarkus-dns.applicationTemplate" -}}
{{- with .Values.config.application }}
{{- toYaml . | nindent 2 }}
{{- end -}}
{{- end -}}
{{- if .Values.config.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "quarkus-dns.fullname" . }}-config
labels:
{{- include "quarkus-dns.labels" . | nindent 4 }}
{{- with .Values.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
data:
application.yaml: |-
{{- include "quarkus-dns.applicationTemplate" . | nindent 2 }}
{{- end }}
...
config:
enabled: false
application:
定義完後,該如何驗證 ? 對於 Helm 來說可以使用 template 指令,格式 helm template {RELEASE_NAME} {CHART_CONTEXT} -f {VALUES_YAML} --skip-tests
,如下。基本上有看到 YAML 就是語法沒問題,但不代表可以正常部署。因為渲染結果是吻合 YAML 規範,但不見得符合 Kubernetes 欄位規範。
$ helm template testing . -f env/values-test.yaml --skip-tests
---
# Source: quarkus-dns/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: quarkus-dns
labels:
helm.sh/chart: quarkus-dns-0.1.0
app.kubernetes.io/name: quarkus-dns
app.kubernetes.io/instance: testing
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
---
# Source: quarkus-dns/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: testing-quarkus-dns-config
labels:
helm.sh/chart: quarkus-dns-0.1.0
app.kubernetes.io/name: quarkus-dns
app.kubernetes.io/instance: testing
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
data:
application.yaml: |
a1:
b: "testing"
---
# Source: quarkus-dns/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: testing-quarkus-dns
labels:
helm.sh/chart: quarkus-dns-0.1.0
app.kubernetes.io/name: quarkus-dns
app.kubernetes.io/instance: testing
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
spec:
type: ClusterIP
ports:
- port: 8080
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: quarkus-dns
app.kubernetes.io/instance: testing
---
# Source: quarkus-dns/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: testing-quarkus-dns
labels:
helm.sh/chart: quarkus-dns-0.1.0
app.kubernetes.io/name: quarkus-dns
app.kubernetes.io/instance: testing
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
revisionHistoryLimit: 5
strategy:
type: RollingUpdate
selector:
matchLabels:
app.kubernetes.io/name: quarkus-dns
app.kubernetes.io/instance: testing
template:
metadata:
annotations:
checksum/configmap-env: 8fa22e3cf3f8f9d86ad5d814cf64e209fe001792bc3bf86ce91b0cba02c52441
labels:
app.kubernetes.io/name: quarkus-dns
app.kubernetes.io/instance: testing
spec:
serviceAccountName: quarkus-dns
securityContext:
fsGroup: 2000
runAsGroup: 1001
runAsNonRoot: true
runAsUser: 1001
containers:
- name: quarkus-dns
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
image: "registry.hub.docker.com/cch0124/helmchartlab:day16"
imagePullPolicy: IfNotPresent
env:
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: KUBE_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: QUARKUS_CONFIG_LOCATIONS
value: /opt/config/application.yaml
ports:
- name: http
containerPort: 8080
protocol: TCP
livenessProbe:
failureThreshold: 3
httpGet:
path: /q/health/live
port: 8080
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
readinessProbe:
failureThreshold: 3
httpGet:
path: /q/health/ready
port: 8080
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
startupProbe:
failureThreshold: 3
httpGet:
path: /q/health/started
port: 8080
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
resources:
limits:
cpu: 100m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
volumeMounts:
- name: vertx-cache
mountPath: /tmp/vertx-cache
- name: config-volume
mountPath: /opt/jboss/config
readOnly: true
volumes:
- name: vertx-cache
emptyDir: {}
- name: config-volume
configMap:
name: testing-quarkus-dns-config
如果想要確認某個資源呢 ? 可以帶入 -s
參數再搭配指定要渲染的模板檔案,個人認為在很多資源的 template 下滿好用,因為就不會有一長串的東西要看。
helm template testing -s templates/configmap.yaml . -f env/values-te
st.yaml --skip-tests
---
# Source: quarkus-dns/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: testing-quarkus-dns-config
labels:
helm.sh/chart: quarkus-dns-0.1.0
app.kubernetes.io/name: quarkus-dns
app.kubernetes.io/instance: testing
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
data:
application.yaml: |-
a1:
如果要部署時,可以指定 namespace 且搭配 --create-namespace
不存在時建立。特別的是部署後可以看到輸出訊息,而該訊息從 NOTES.txt
預設檔案來,實務也會建議定義此內容。像是提供第一次密碼要如何取得等。不過預設上狀態為 deployed
也不代表資源是確定並且可使用。
$ helm install dns-1 . -f values.yaml --namespace day16 --create-namespace
NAME: dns-1
LAST DEPLOYED: Sat Sep 7 22:39:53 2024
NAMESPACE: day16
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace day16 -l "app.kubernetes.io/name=quarkus-dns,app.kubernetes.io/instance=dns-1" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace day16 $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace day16 port-forward $POD_NAME 8080:$CONTAINER_PORT
透過 history
可以看到部署歷史紀錄
$ helm history dns-1 -n day16
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Sat Sep 7 22:39:53 2024 deployed quarkus-dns-0.1.0 1.16.0 Install complete
架設 values.yaml 有異動則透過 upgrade 方式更新當前的 Chart。可以看到 REVISION 從 1 變 2。
$ helm upgrade dns-1 . -f values.yaml --namespace day16 --create-namespace
Release "dns-1" has been upgraded. Happy Helming!
NAME: dns-1
LAST DEPLOYED: Sat Sep 7 22:48:48 2024
NAMESPACE: day16
STATUS: deployed
REVISION: 2
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace day16 -l "app.kubernetes.io/name=quarkus-dns,app.kubernetes.io/instance=dns-1" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace day16 $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace day16 port-forward $POD_NAME 8080:$CONTAINER_PORT
透過 history 也是可以看到新增一個版本。
$ helm history dns-1 -n day16
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Sat Sep 7 22:39:53 2024 superseded quarkus-dns-0.1.0 1.16.0 Install complete
2 Sat Sep 7 22:48:48 2024 deployed quarkus-dns-0.1.0 1.16.0 Upgrade complete
此時驗證部署上去的資源。
$ kubectl port-forward -n day16 services/dns-1-quarkus-dns 9090:8080
$ curl http://localhost:9090/hello/myip?uri=www.google.com
["172.217.160.68"]
但預設上不能解析 Kubernetes 的 DNS 來獲取 IP。因此要將 dns.server 位置指向 Kubernetes 的 DNS。
config:
enabled: true
application:
dns:
server: 10.42.1.178
透過 endpoints
方式來獲取 Kubernetes 中的 DNS 位置。
$ kubectl get endpoints kube-dns -n kube-system
NAME ENDPOINTS AGE
kube-dns 10.42.1.178:53,10.42.1.178:53,10.42.1.178:9153 14d
當上述 dns.server 配置好後,在更新一版。
$ helm upgrade dns-1 . -f env/values-dev.yaml --namespace day16 --create-namespace
Release "dns-1" has been upgraded. Happy Helming!
NAME: dns-1
LAST DEPLOYED: Sun Sep 8 01:33:46 2024
NAMESPACE: day16
STATUS: deployed
REVISION: 11
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace day16 -l "app.kubernetes.io/name=quarkus-dns,app.kubernetes.io/instance=dns-1" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace day16 $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace day16 port-forward $POD_NAME 8080:$CONTAINER_PORT
原則上就可以解析到了~
$ curl http://localhost:9090/hello/myip?uri=dns-1-quarkus-dns.day16.svc
["10.43.121.65"]
對於 Quarkus 應用程式來說,log 也表示當前 dns.server 指向 Kubernetes DNS 服務。
2024-09-07 17:50:51,161 INFO [ith.cch.ser.ProducerService] (executor-thread-1) dns server: 10.42.1.178
到這邊可以完整 release(部署)一個 Chart。並讓使用者使用。
假設,當前的內容是錯誤,不應該可以解析 Kubernetes DNS 的內容。則可以使用 rollback 方式。
$ helm -n day16 rollback dns-1 7 --wait
每當執行 rollback,也算在歷史紀錄中,而每個歷史紀錄預設會記 10 筆。如下可以看到。
$ helm history dns-1 -n day16
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
3 Sat Sep 7 23:02:13 2024 superseded quarkus-dns-0.1.0 1.16.0 Upgrade complete
4 Sun Sep 8 00:47:26 2024 superseded quarkus-dns-0.1.0 1.16.0 Upgrade complete
5 Sun Sep 8 00:50:02 2024 failed quarkus-dns-0.1.0 1.16.0 Upgrade "dns-1" failed: cannot patch "dns-1-quarkus-dns" with kind Deployment: Deployment.apps "dns-1-quarkus-dns" is invalid: spec.template.spec.containers[0].volumeMounts[0].name: Not found: "vertx-cache"
6 Sun Sep 8 00:50:25 2024 superseded quarkus-dns-0.1.0 1.16.0 Upgrade complete
7 Sun Sep 8 01:12:38 2024 superseded quarkus-dns-0.1.0 1.16.0 Upgrade complete
8 Sun Sep 8 01:14:55 2024 superseded quarkus-dns-0.1.0 1.16.0 Upgrade complete
9 Sun Sep 8 01:33:46 2024 superseded quarkus-dns-0.1.0 1.16.0 Upgrade complete
10 Sun Sep 8 01:38:18 2024 superseded quarkus-dns-0.1.0 1.16.0 Upgrade complete
11 Sun Sep 8 01:49:20 2024 superseded quarkus-dns-0.1.0 1.16.0 Upgrade complete
12 Sun Sep 8 01:56:09 2024 deployed quarkus-dns-0.1.0 1.16.0 Rollback to 7
另外,使用 get values
時可以獲取當前部署 Chart 所配置的內容
$ helm get values dns-1 -n day16
USER-SUPPLIED VALUES:
config:
application:
dns:
server: 10.42.1.178
enabled: false
securityContext: {}
下個章節會介紹一些工具來驗證 Kubernetes 資源。