我們可以將Helm看作Kubernetes下的apt-get/yum。Helm是kubernetes的包管理器,helm倉庫里面只有配置清單文件,而沒有鏡像,鏡像還是由鏡像倉庫來提供,比如hub.docker.com、私有倉庫。
官方文檔:https://v3.helm.sh/zh/docs/
其實之前也寫過關于helm的一篇文章【Kubernetes(k8s)包管理器Helm(Helm3)介紹&Helm3安裝Harbor】,可能講的不夠細致,這里會更加細致的講解helm。
下載地址:https://github.com/helm/helm/releases
# 下載包
$ wget https://get.helm.sh/helm-v3.9.4-linux-amd64.tar.gz
# 解壓壓縮包
$ tar -xf helm-v3.9.4-linux-amd64.tar.gz
# 制作軟連接
$ ln -s /opt/helm/linux-amd64/helm /usr/local/bin/helm
# 驗證
$ helm version
$ helm help
# 通過helm create命令創建一個新的chart包
helm create nginx
tree nginx
nginx/
├── charts #依賴其他包的charts文件
├── Chart.yaml # 該chart的描述文件,包括ico地址,版本信息等
├── templates # #存放k8s模板文件目錄
│ ├── deployment.yaml # 創建k8s資源的yaml 模板
│ ├── _helpers.tpl # 下劃線開頭的文件,可以被其他模板引用
│ ├── hpa.yaml # 彈性擴縮容,配置服務資源CPU 內存
│ ├── ingress.yaml # ingress 配合service域名訪問的配置
│ ├── NOTES.txt # 說明文件,helm install之后展示給用戶看的內容
│ ├── serviceaccount.yaml # 服務賬號配置
│ ├── service.yaml # kubernetes Serivce yaml 模板
│ └── tests # 測試模塊
│ └── test-connection.yaml
└── values.yaml # 給模板文件使用的變量
可能有寫包還會有以下幾個目錄:
wordpress/
...
LICENSE # 可選: 包含chart許可證的純文本文件
README.md # 可選: 可讀的README文件
values.schema.json # 可選: 一個使用JSON結構的values.yaml文件
charts/ # 包含chart依賴的其他chart
crds/ # 自定義資源的定義
...
apiVersion: chart API 版本 (必需)
name: chart名稱 (必需)
version: chart 版本,語義化2 版本(必需)
kubeVersion: 兼容Kubernetes版本的語義化版本(可選)
description: 一句話對這個項目的描述(可選)
type: chart類型 (可選)
keywords:
- 關于項目的一組關鍵字(可選)
home: 項目home頁面的URL (可選)
sources:
- 項目源碼的URL列表(可選)
dependencies: # chart 必要條件列表 (可選)
- name: chart名稱 (nginx)
version: chart版本 ("1.2.3")
repository: (可選)倉庫URL ("https://example.com/charts") 或別名 ("@repo-name")
condition: (可選) 解析為布爾值的yaml路徑,用于啟用/禁用chart (e.g. subchart1.enabled )
tags: # (可選)
- 用于一次啟用/禁用 一組chart的tag
import-values: # (可選)
- ImportValue 保存源值到導入父鍵的映射。每項可以是字符串或者一對子/父列表項
alias: (可選) chart中使用的別名。當你要多次添加相同的chart時會很有用
maintainers: # (可選)
- name: 維護者名字 (每個維護者都需要)
email: 維護者郵箱 (每個維護者可選)
url: 維護者URL (每個維護者可選)
icon: 用做icon的SVG或PNG圖片URL (可選)
appVersion: 包含的應用版本(可選)。不需要是語義化,建議使用引號
deprecated: 不被推薦的chart (可選,布爾值)
annotations:
example: 按名稱輸入的批注列表 (可選).
比如 nginx chart的版本字段version: 1.2.3按照名稱被設置為:
nginx-1.2.3.tgz
【溫馨提示】appVersion字段與version字段并不相關。這是指定應用版本的一種方式。比如,這個drupal chart可能有一個 appVersion: "8.2.1",表示包含在chart(默認)的Drupal的版本是8.2.1。
當前chart依賴的其他chart會在dependencies字段定義為一個列表。
dependencies:
- name: apache
version: 1.2.3
repository: https://example.com/charts
- name: mysql
version: 3.2.1
repository: https://another.example.com/charts
示例演示:
helm repo add bitnami https://charts.bitnami.com/bitnami
helm pull bitnami/wordpress
tar -xf wordpress
cat wordpress/Chart.yaml
一旦你定義好了依賴,運行 helm dependency update 就會使用你的依賴文件下載所有你指定的chart到你的charts/目錄。
helm dependency update ./wordpress
當 helm dependency update 拉取chart時,會在charts/目錄中形成一個chart包。因此對于上面的示例,會在chart目錄中期望看到以下文件:
wordpress/charts/
├── common
├── common-2.0.1.tgz
├── mariadb
├── mariadb-11.2.2.tgz
├── memcached
└── memcached-6.2.3.tgz
依賴中的tag和條件字段
除了上面的其他字段外,每個需求項可以包含可選字段 tags 和 condition。所有的chart會默認加載。如果存在 tags 或者 condition 字段,它們將被評估并用于控制它們應用的chart的加載。
# parentchart/Chart.yaml
dependencies:
- name: subchart1
repository: http://localhost:10191
version: 0.1.0
condition: subchart1.enabled, global.subchart1.enabled
tags:
- front-end
- subchart1
- name: subchart2
repository: http://localhost:10191
version: 0.1.0
condition: subchart2.enabled,global.subchart2.enabled
tags:
- back-end
- subchart2
# parentchart/values.yaml
subchart1:
enabled: true
tags:
front-end: false
back-end: true
--set 參數可以用來設置標簽和條件值。
helm install --set tags.front-end=true --set subchart2.enabled=false
標簽和條件的解析:
使用導出格式:
如果子chart的values.yaml文件中在根節點包含了exports字段,它的內容可以通過指定的可以被直接導入到父chart的value中, 如下所示:
# parent's Chart.yaml file
dependencies:
- name: subchart
repository: http://localhost:10191
version: 0.1.0
import-values:
- data
# child's values.yaml file
exports:
data:
myint: 99
只要我們再導入列表中指定了鍵data,Helm就會在子chart的exports字段查找data鍵并導入它的內容。
最終的父級value會包含我們的導出字段:
# parent's values
myint: 99
【注意】父級鍵 data 沒有包含在父級最終的value中,如果想指定這個父級鍵,要使用'子-父' 格式。
下面示例中的import-values 指示Helm去拿到能再child:路徑中找到的任何值,并拷貝到parent:的指定路徑。
# parent's Chart.yaml file
dependencies:
- name: subchart1
repository: http://localhost:10191
version: 0.1.0
...
import-values:
- child: default.data
parent: myimports
上面的例子中,在subchart1里面找到的default.data的值會被導入到父chart的myimports鍵中,細節如下:
# parent's values.yaml file
myimports:
myint: 0
mybool: false
mystring: "helm rocks!"
# subchart1's values.yaml file
default:
data:
myint: 999
mybool: true
父chart的結果值將會是這樣:
# parent's final values
myimports:
myint: 999
mybool: true
mystring: "helm rocks!"
模板的Value通過兩種方式提供:
模板示例
apiVersion: v1
kind: ReplicationController
metadata:
name: deis-database
namespace: deis
labels:
app.kubernetes.io/managed-by: deis
spec:
replicas: 1
selector:
app.kubernetes.io/name: deis-database
template:
metadata:
labels:
app.kubernetes.io/name: deis-database
spec:
serviceAccount: deis-database
containers:
- name: deis-database
image: {{ .Values.imageRegistry }}/postgres:{{ .Values.dockerTag }}
imagePullPolicy: {{ .Values.pullPolicy }}
ports:
- containerPort: 5432
env:
- name: DATABASE_STORAGE
value: {{ default "minio" .Values.storage }}
上面的例子,松散地基于 https://github.com/deis/charts, 是一個Kubernetes副本控制器的模板。可以使用下面四種模板值(一般被定義在values.yaml文件):
Values通過模板中.Values對象可訪問的values.yaml文件(或者通過 --set 參數)提供, 但可以模板中訪問其他預定義的數據片段。
以下值是預定義的,對每個模板都有效,并且可以被覆蓋。和所有值一樣,名稱 區分大小寫。
考慮到前面部分的模板,values.yaml文件提供的必要值如下:
imageRegistry: "quay.io/deis"
dockerTag: "latest"
pullPolicy: "Always"
storage: "s3"
values文件被定義為YAML格式。chart會包含一個默認的values.yaml文件。 Helm安裝命令允許用戶使用附加的YAML values覆蓋這個values:
helm install --generate-name --values=myvals.yaml wordpress
Values文件可以聲明頂級chart的值,以及charts/目錄中包含的其他任意chart。 或者換個說法,values文件可以為chart及其任何依賴項提供值。比如,上面示范的WordPress chart同時有 mysql 和 apache 作為依賴。values文件可以為以下所有這些組件提供依賴:
title: "My WordPress Site" # Sent to the WordPress template
mysql:
max_connections: 100 # Sent to MySQL
password: "secret"
apache:
port: 8080 # Passed to Apache
更高階的chart可以訪問下面定義的所有變量。因此WordPress chart可以用.Values.mysql.password訪問MySQL密碼。 但是低階的chart不能訪問父級chart,所以MySQL無法訪問title屬性。同樣也無法訪問apache.port。
從2.0.0-Alpha.2開始,Helm 支持特殊的"global"值。設想一下前面的示例中的修改版本:
title: "My WordPress Site" # Sent to the WordPress template
global:
app: MyWordPress
mysql:
max_connections: 100 # Sent to MySQL
password: "secret"
apache:
port: 8080 # Passed to Apache
面添加了global部分和一個值app: MyWordPress。這個值以.Values.global.app在 所有 chart中有效。
比如,mysql模板可以以{{.Values.global.app}}訪問app,同樣apache chart也可以訪問。 實際上,上面的values文件會重新生成為這樣:
title: "My WordPress Site" # Sent to the WordPress template
global:
app: MyWordPress
mysql:
global:
app: MyWordPress
max_connections: 100 # Sent to MySQL
password: "secret"
apache:
global:
app: MyWordPress
port: 8080 # Passed to Apache
Helm 自帶一個強大的搜索命令,可以用來從兩種來源中進行搜索:
# 添加bitnami倉庫源
helm repo add bitnami https://charts.bitnami.com/bitnami
# 從bitnami源查找所有chart包,不指定具體源的話,會查找本地添加的所有源地址的所有chart包
helm search repo bitnami
安裝過程中有兩種方式傳遞配置數據:
如果同時使用兩種方式,則 --set 中的值會被合并到 --values 中,但是 --set中的值優先級更高。在--set 中覆蓋的內容會被被保存在 ConfigMap 中。可以通過 helm get values <release-name> 來查看指定 release 中 --set 設置的值。也可以通過運行 helm upgrade 并指定 --reset-values 字段來清除 --set 中設置的值。示例如下:
echo '{mariadb.auth.database: user0db, mariadb.auth.username: user0}' > values.yaml
helm install -f values.yaml bitnami/wordpress --generate-name
helm install mysql bitnami/mysql
helm list
# 先刪除
helm uninstall mysql
# 拉包到本地
helm pull bitnami/mysql
# 不解壓直接安裝
helm install mysql ./mysql-9.3.1.tgz
helm list
# 拉包到本地
helm pull bitnami/mysql
# 解壓安裝
tar -xf mysql-9.3.1.tgz
# 開始安裝
helm install mysql ./mysql \
--namespace=mysql \
--create-namespace \
--set image.registry=myharbor.com \
--set image.repository=bigdata/mysql \
--set image.tag=8.0.30 \
--set primary.service.type=NodePort \
--set service.nodePorts.mysql=30306
# 查看在運行的Release
helm list
# 卸載
helm uninstall mysql -n mysql
模板(templates/)中的變量都放在{{}}中,比如:{{ .Values.images }} 表示 Values 對象下的images 字段。Values來源于values.yaml文件或者-f指定的yaml文件,或者--set設置的變量。
【溫馨提示】使用-刪除空格和換行符,要想刪除那行其他的空格和換行符可以用{{-或者-}},一個是刪除左邊的空格和換行符,一個是刪除右邊的空格和換行符。
該函數將值轉換成字符串用雙引號(quote) 或者單引號(squote)括起來。示例如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | quote }}
food: {{ .Values.favorite.food | upper | quote }}
倒置命令是模板中的常見做法。可以經常看到 .val | quote 而不是 quote .val。實際上兩種操作都是可以的。
這個函數允許你在模板中指定一個默認值,以防這個值被忽略。
# 如果.Values.favorite.drink是非空值,則使用它,否則會返回tea。
drink: {{ .Values.favorite.drink | default "tea" | quote }}
# 還可以這樣寫,如果.Bar是非空值,則使用它,否則會返回foo。
default "foo" .Bar
"空"定義取決于以下類型:
整型: 0
字符串: ""
列表: []
字典: {}
布爾: false
以及所有的nil (或 null)
返回各部分組合的字符串,非字符串類型會被轉換成字符串。
print "Matt has " .Dogs " dogs"
【溫馨提示】當相鄰兩個參數不是字符串時會在它們之間添加一個空格。
和 print效果一樣,但會在末尾新添加一行。
返回參數按順序傳遞的格式化字符串。
printf "%s has %d dogs." .Name .NumberDogs
{{- printf "%d" (.Values.externalCache.port | int ) -}}
{{- printf "%s" .Values.existingSecret -}}
{{- printf "%v" .context.Values.redis.enabled -}}
# %s 字符串占位符,未解析的二進制字符串或切片
# %d 數字占位符,十進制
# %v 默認格式的值,當打印字典時,加號參數(%+v)可以添加字段名稱
更多占位符的使用,可以參考官方文檔:https://helm.sh/zh/docs/chart_template_guide/function_list/
trim行數移除字符串兩邊的空格:
trim " hello "
從字符串中移除給定的字符:
trimAll "$" ".00"
上述結果為:5.00 (作為一個字符串)。
將整個字符串轉換成小寫:
lower "HELLO"
上述結果為: hello
將整個字符串轉換成大寫:
upper "hello"
上述結果為: HELLO
首字母轉換成大寫:
title "hello world"
上述結果為: Hello World
獲取字符串的子串,有三個參數:
substr 0 5 "hello world"
上述結果為: hello
用省略號截斷字符串 (...)
abbrev 5 "hello world"
# 第一個參數:最大長度
# 第二個參數:字符串
上述結果為: he..., 因為將省略號算進了長度中。
測試字符串是否包含在另一個字符串中:
contains "cat" "catch"
cat 函數將多個字符串合并成一個,用空格分隔:
cat "hello" "beautiful" "world"
上述結果為: hello beautiful world
indent 以指定長度縮進給定字符串所在行,在對齊多行字符串時很有用:
indent 4 $lots_of_text
上述結果會將每行縮進4個空格。
nindent 函數和indent函數一樣,但可以在字符串開頭添加新行。
nindent 4 $lots_of_text
上述結果會在字符串所在行縮進4個字符,并且在開頭新添加一行。
執行簡單的字符串替換。
# 下面兩行等價
replace " " "-" "I Am Henry VIII"
"I Am Henry VIII" | replace " " "-"
# 參數1:待替換字符串
# 參數2:要替換字符串
# 參數3:源字符串
上述結果為: I-Am-Henry-VIII
date函數格式化日期,日期格式化為YEAR-MONTH-DAY:
now | date "2006-01-02"
想了解更多內置函數,可以參考官方文檔:https://helm.sh/zh/docs/chart_template_guide/function_list/
Helm提供了以下類型轉換函數:
Helm 包含以下正則表達式函數
Helm有以下編碼和解碼函數:
Helm 提供了一個key/value存儲類型稱為dict("dictionary"的簡稱,Python中也有)。dict是無序類型。字典的key 必須是字符串。但值可以是任意類型,甚至是另一個dict 或 list。
下面是創建三個鍵值對的字典:
$myDict :=dict "name1" "value1" "name2" "value2" "name3" "value 3"
給定一個映射和一個鍵,從映射中獲取值。
get $myDict "name1"
上述結果為: "value1"
注意如果沒有找到,會簡單返回""。不會生成error。
使用set給字典添加一個鍵值對。
$_ :=set $myDict "name4" "value4"
注意set 返回字典 (Go模板函數的一個要求),因此你可能需要像上面那樣使用使用$_賦值來獲取值。
給定一個映射和key,從映射中刪除這個key。
$_ :=unset $myDict "name4"
和set一樣,需要返回字典。
hasKey函數會在給定字典中包含了給定key時返回true。
hasKey $myDict "name1"
如果key沒找到,會返回false。
pluck 函數給定一個鍵和多個映射,并獲得所有匹配項的列表:
pluck "name1" $myDict $myOtherDict
上述會返回的list包含了每個找到的值([value1 otherValue1])。
將兩個或多個字典合并為一個, 目標字典優先:
$newdict :=merge $dest $source1 $source2
keys函數會返回一個或多個dict類型中所有的key的list。由于字典是 無序的,key不會有可預料的順序。 可以使用sortAlpha存儲。
keys $myDict | sortAlpha
當提供了多個詞典時,key會被串聯起來。使用uniq函數和sortAlpha獲取一個唯一有序的鍵列表。
keys $myDict $myOtherDict | uniq | sortAlpha
values函數類似于keys,返回一個新的list包含源字典中所有的value(只支持一個字典)。
$vals :=values $myDict
上述結果為: list["value1", "value2", "value 3"]。
注意 values不能保證結果的順序;如果你需要順序, 請使用sortAlpha。
Helm 提供了一個簡單的list類型,包含任意順序的列表。類似于數組或切片,但列表是被設計用于不可變數據類型。
$myList :=list 1 2 3 4 5
上述會生成一個列表 [1 2 3 4 5]。
獲取列表中的第一項,使用 first。
first $myList
# 返回 1
first 有問題時會出錯,mustFirst 有問題時會向模板引擎返回錯誤。
獲取列表的尾部內容(除了第一項外的所有內容),使用rest。
rest $myList
# 返回 [2 3 4 5]
rest有問題時會出錯,mustRest 有問題時會向模板引擎返回錯誤。
使用last獲取列表的最后一項:
last $myList
# 返回 5。這大致類似于反轉列表然后調用first。
通過返回所有元素 但 除了最后一個元素。
initial $myList
# 返回 [1 2 3 4]。
initial有問題時會出錯,但是 mustInitial 有問題時會向模板引擎返回錯誤。
在已有列表中追加一項,創建一個新的列表。
$new=append $myList 6
上述語句會設置 $new 為 [1 2 3 4 5 6]。 $myList會保持不變。
append 有問題時會出錯,但 mustAppend 有問題時會向模板引擎返回錯誤。
將元素添加到列表的前面,生成一個新的列表。
prepend $myList 0
上述語句會生成 [0 1 2 3 4 5]。 $myList會保持不變。
prepend 有問題時會出錯,但 mustPrepend 有問題時會向模板引擎返回錯誤。
將任意數量的列表串聯成一個。
concat $myList ( list 6 7 ) ( list 8 )
上述語句會生成 [1 2 3 4 5 6 7 8]。 $myList 會保持不變。
反轉給定的列表生成一個新列表。
reverse $myList
上述語句會生成一個列表: [5 4 3 2 1]。
reverse 有問題時會出錯,但 mustReverse 有問題時會向模板引擎返回錯誤。
生成一個移除重復項的列表。
list 1 1 1 2 | uniq
上述語句會生成 [1 2]
uniq 有問題時會出錯,但 mustUniq 有問題時會向模板引擎返回錯誤。
without 函數從列表中過濾內容。
without $myList 3
# 上述語句會生成 [1 2 4 5]
一個過濾器可以過濾多個元素:
without $myList 1 3 5
# 這樣會得到: [2 4]
without 有問題時會出錯,但 mustWithout 有問題時會向模板引擎返回錯誤。
驗證列表是否有特定元素。
has 4 $myList
上述語句會返回 true, 但 has "hello" $myList 就會返回false。
has 有問題時會出錯,但 mustHas 有問題時會向模板引擎返回錯誤。
接收一個列表并刪除空值項。
$list :=list 1 "a" "foo" ""
$copy :=compact $list
compact 會返回一個移除了空值(比如, "")的新列表。
compact 有問題時會出錯,但 mustCompact 有問題時會向模板引擎返回錯誤。
使用index list [n]獲取列表的第n個元素。使用index list [n] [m] ...獲取多位列表元素。
從列表中獲取部分元素,使用 slice list [n] [m]。等同于 list[n:m].
slice 有問題時會出錯,但 mustSlice 有問題時會向模板引擎返回錯誤。
until 函數構建一個整數范圍。
until 5
上述語句會生成一個列表: [0, 1, 2, 3, 4]。
對循環語句很有用: range $i, $e :=until 5。
seq 5=> 1 2 3 4 5
seq -3=> 1 0 -1 -2 -3
seq 0 2=> 0 1 2
seq 2 -2=> 2 1 0 -1 -2
seq 0 2 10=> 0 2 4 6 8 10
seq 0 -2 -5=> 0 -2 -4
使用add求和。接受兩個或多個輸入。
add 1 2 3
自增加1,使用 add1。
相減使用 sub。
整除使用 div。
取模使用mod。
相乘使用mul。接受兩個或多個輸入。
mul 1 2 3
返回一組整數中最大的整數。
max 1 2 3
# 返回 3
返回一組數中最小的數。
min 1 2 3
# 會返回 1。
以整數返回參數的長度。
len .Arg
Helm提供了幾個網絡函數:
運算符:
eq: 等于(equal to)
ne: 不等于(not equal to)
lt: 小于(less than)
le: 小于等于(less than or equal to)
gt: 大于(greater than)
ge: 大于等于(greater than or equal to)
if/else 用法:
{{if 命令}}
…
{{else if 命令}}
…
{{else}}
…
{{end}}
如果是以下值時,管道會被設置為 false:
布爾false
數字0
空字符串
nil (空或null)
空集合(map, slice, tuple, dict, array)
【示例】
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{ if eq .Values.favorite.drink "coffee" }}mug: "true"{{ end }}
下一個控制結構是with操作。這個用來控制變量范圍。回想一下,.是對 當前作用域 的引用。因此.Values就是告訴模板在當前作用域查找Values對象。
with的語法與if語句類似:
{{ with PIPELINE }}
# restricted scope
{{ end }}
作用域可以被改變。with允許你為特定對象設定當前作用域(.)。比如,我們已經在使用.Values.favorite。 修改配置映射中的.的作用域指向.Values.favorite:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
但是這里有個注意事項,在限定的作用域內,無法使用.訪問父作用域的對象。錯誤示例如下:
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ .Release.Name }}
{{- end }}
這樣會報錯因為Release.Name不在.限定的作用域內。但是如果對調最后兩行就是正常的, 因為在{{ end }}之后作用域被重置了。
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
release: {{ .Release.Name }}
或者,我們可以使用$從父作用域中訪問Release.Name對象。當模板開始執行后$會被映射到根作用域,且執行過程中不會更改。 下面這種方式也可以正常工作:
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ $.Release.Name }}
{{- end }}
也可以在外邊定義變量,遵循$name變量的格式且指定了一個特殊的賦值運算符::=。 我們可以使用針對Release.Name的變量重寫上述內容。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- $relname :=.Release.Name -}}
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ $relname }}
{{- end }}
注意在with塊開始之前,賦值$relname :=.Release.Name。 現在在with塊中,$relname變量仍會執行版本名稱。
很多編程語言支持使用for循環,foreach循環,或者類似的方法機制。 在Helm的模板語言中,在一個集合中迭代的方式是使用range操作符。
定義values
favorite:
drink: coffee
food: pizza
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
現在我們有了一個pizzaToppings列表(模板中稱為切片)。修改模板把這個列表打印到配置映射中:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
toppings: |-
{{- range .Values.pizzaToppings }}
- {{ . | title | quote }}
{{- end }}
有時能在模板中快速創建列表然后迭代很有用,Helm模板的tuple可以很容易實現該功能。在計算機科學中, 元組表示一個有固定大小的類似列表的集合,但可以是任意數據類型。這大致表達了tuple的用法。
sizes: |-
{{- range tuple "small" "medium" "large" }}
- {{ . }}
{{- end }}
上述模板會生成以下內容:
sizes: |-
- small
- medium
- large
此時需要越過模板,開始創建其他內容了。該部分我們會看到如何在一個文件中定義 命名模板,并在其他地方使用。命名模板 (有時稱作一個 部分 或一個 子模板)僅僅是在文件內部定義的模板,并使用了一個名字。有兩種創建方式和幾種不同的使用方法。
在編寫模板細節之前,文件的命名慣例需要注意:
這些文件用來存儲局部和輔助對象,實際上當我們第一次創建mychart時,會看到一個名為_helpers.tpl的文件,這個文件是模板局部的默認位置。
define操作允許我們在模板文件中創建一個命名模板,語法如下:
{{- define "MY.NAME" }}
# body of template here
{{- end }}
比如我們可以定義一個模板封裝Kubernetes的標簽:
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
現在我們將模板嵌入到了已有的配置映射中,然后使用template包含進來:
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
{{- template "mychart.labels" }}
data:
myvalue: "Hello World"
{{- range $key, $val :=.Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
當模板引擎讀取該文件時,它會存儲mychart.labels的引用直到template "mychart.labels"被調用。 然后會按行渲染模板,因此結果類似這樣:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: running-panda-configmap
labels:
generator: helm
date: 2022-09-04
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
注意:define不會有輸出,除非像本示例一樣用模板調用它。
按照慣例,Helm chart將這些模板放置在局部文件中,一般是_helpers.tpl。把這個方法移到那里:
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
在上面定義的模板中,我們沒有使用任何對象,僅僅使用了方法。修改定義好的模板讓其包含chart名稱和版本號:
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
chart: {{ .Chart.Name }}
version: {{ .Chart.Version }}
{{- end }}
假設定義了一個簡單模板如下:
{{- define "mychart.app" -}}
app_name: {{ .Chart.Name }}
app_version: "{{ .Chart.Version }}"
{{- end -}}
現在假設我想把這個插入到模板的labels:部分和data:部分:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
labels:
{{ template "mychart.app" . }}
data:
myvalue: "Hello World"
{{- range $key, $val :=.Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
{{ template "mychart.app" . }}
如果渲染這個,會得到以下錯誤:
$ helm install --dry-run measly-whippet ./mychart
Error: unable to build kubernetes objects from release manifest: error validating "": error validating data: [ValidationError(ConfigMap): unknown field "app_name" in io.k8s.api.core.v1.ConfigMap, ValidationError(ConfigMap): unknown field "app_version" in io.k8s.api.core.v1.ConfigMap]
要查看渲染了什么,可以用--disable-openapi-validation參數重新執行: helm install --dry-run --disable-openapi-validation measly-whippet ./mychart。 輸入不是我們想要的:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: measly-whippet-configmap
labels:
app_name: mychart
app_version: "0.1.0"
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
app_name: mychart
app_version: "0.1.0"
注意兩處的app_version縮進都不對,為啥?因為被替換的模板中文本是左對齊的。由于template是一個行為,不是方法,無法將 template調用的輸出傳給其他方法,數據只是簡單地按行插入。
為了處理這個問題,Helm提供了一個include,可以將模板內容導入當前管道,然后傳遞給管道中的其他方法。下面這個示例,使用indent正確地縮進了mychart.app模板:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
labels:
{{ include "mychart.app" . | indent 4 }}
data:
myvalue: "Hello World"
{{- range $key, $val :=.Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
{{ include "mychart.app" . | indent 2 }}
現在生成的YAML每一部分都可以正確縮進了:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: edgy-mole-configmap
labels:
app_name: mychart
app_version: "0.1.0"
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
app_name: mychart
app_version: "0.1.0"
include 相較于使用template,在helm中使用include被認為是更好的方式 只是為了更好地處理YAML文檔的輸出格式。
該部分會介紹為chart用戶提供說明的Helm工具。在helm install 或 helm upgrade命令的最后,Helm會打印出對用戶有用的信息。 使用模板可以高度自定義這部分信息。
要在chart添加安裝說明,只需創建templates/NOTES.txt文件即可。該文件是純文本,但會像模板一樣處理, 所有正常的模板函數和對象都是可用的。讓我們創建一個簡單的NOTES.txt文件:
Thank you for installing {{ .Chart.Name }}.
Your release is named {{ .Release.Name }}.
To learn more about the release, try:
$ helm status {{ .Release.Name }}
$ helm get all {{ .Release.Name }}
現在如果我們執行helm install rude-cardinal ./mychart 會在底部看到:
RESOURCES:==> v1/Secret
NAME TYPE DATA AGE
rude-cardinal-secret Opaque 1 0s==> v1/ConfigMap
NAME DATA AGE
rude-cardinal-configmap 3 0s
NOTES:
Thank you for installing mychart.
Your release is named rude-cardinal.
To learn more about the release, try:
$ helm status rude-cardinal
$ helm get all rude-cardinal
使用NOTES.txt這種方式是給用戶提供關于如何使用新安裝的chart細節信息的好方法。盡管并不是必需的,強烈建議創建一個NOTES.txt文件。
調試模板可能很棘手,因為渲染后的模板發送給了Kubernetes API server,可能會以格式化以外的原因拒絕YAML文件。以下命令有助于調試:
當你的YAML文件解析失敗,但你想知道生成了什么,檢索YAML一個簡單的方式是注釋掉模板中有問題的部分, 然后重新運行 helm install --dry-run --debug:
apiVersion: v2
# some: problem section
# {{ .Values.foo | quote }}
以上內容會被渲染同時返回完整的注釋:
apiVersion: v2
# some: problem section
# "bar"
其實這里主要是正對官方文檔進行整理,列出了常見的使用語法,想了解更多,可以參考官方文檔,官方文檔講解的很細致,有疑問的小伙伴歡迎給我留言哦,后續會持續分享【云原生和大數據】相關的文章,請小伙伴耐心等待哦~
Java中,工具類定義了一組公共方法,這篇文章將介紹Java中使用最頻繁及最通用的Java工具類。以下工具類、方法按使用流行度排名,參考數據來源于Github上隨機選取的5萬個開源項目源碼。
一. org.apache.commons.io.IOUtils
closeQuietly:關閉一個IO流、socket、或者selector且不拋出異常,通常放在finally塊 toString:轉換IO流、 Uri、 byte[]為String copy:IO流數據復制,從輸入流寫到輸出流中,最大支持2GB toByteArray:從輸入流、URI獲取byte[] write:把字節. 字符等寫入輸出流 toInputStream:把字符轉換為輸入流 readLines:從輸入流中讀取多行數據,返回List<String> copyLarge:同copy,支持2GB以上數據的復制 lineIterator:從輸入流返回一個迭代器,根據參數要求讀取的數據量,全部讀取,如果數據不夠,則失敗
二. org.apache.commons.io.FileUtils
deleteDirectory:刪除文件夾 readFileToString:以字符形式讀取文件內容 deleteQueitly:刪除文件或文件夾且不會拋出異常 copyFile:復制文件 writeStringToFile:把字符寫到目標文件,如果文件不存在,則創建 forceMkdir:強制創建文件夾,如果該文件夾父級目錄不存在,則創建父級 write:把字符寫到指定文件中 listFiles:列舉某個目錄下的文件(根據過濾器) copyDirectory:復制文件夾 forceDelete:強制刪除文件
三. org.apache.commons.lang.StringUtils
isBlank:字符串是否為空 (trim后判斷) isEmpty:字符串是否為空 (不trim并判斷) equals:字符串是否相等 join:合并數組為單一字符串,可傳分隔符 split:分割字符串 EMPTY:返回空字符串 trimToNull:trim后為空字符串則轉換為null replace:替換字符串
四. org.apache.http.util.EntityUtils
toString:把Entity轉換為字符串 consume:確保Entity中的內容全部被消費。可以看到源碼里又一次消費了Entity的內容,假如用戶沒有消費,那調用Entity時候將會把它消費掉 toByteArray:把Entity轉換為字節流 consumeQuietly:和consume一樣,但不拋異常 getContentCharset:獲取內容的編碼
五. org.apache.commons.lang3.StringUtils
isBlank:字符串是否為空 (trim后判斷) isEmpty:字符串是否為空 (不trim并判斷) equals:字符串是否相等 join:合并數組為單一字符串,可傳分隔符 split:分割字符串 EMPTY:返回空字符串 replace:替換字符串 capitalize:首字符大寫
六. org.apache.commons.io.FilenameUtils
getExtension:返回文件后綴名 getBaseName:返回文件名,不包含后綴名 getName:返回文件全名 concat:按命令行風格組合文件路徑(詳見方法注釋) removeExtension:刪除后綴名 normalize:使路徑正常化 wildcardMatch:匹配通配符 seperatorToUnix:路徑分隔符改成unix系統格式的,即/ getFullPath:獲取文件路徑,不包括文件名 isExtension:檢查文件后綴名是不是傳入參數(List<String>)中的一個
七. org.springframework.util.StringUtils
hasText:檢查字符串中是否包含文本 hasLength:檢測字符串是否長度大于0 isEmpty:檢測字符串是否為空(若傳入為對象,則判斷對象是否為null) commaDelimitedStringToArray:逗號分隔的String轉換為數組 collectionToDelimitedString:把集合轉為CSV格式字符串 replace 替換字符串 7. delimitedListToStringArray:相當于split uncapitalize:首字母小寫 collectionToDelimitedCommaString:把集合轉為CSV格式字符串 tokenizeToStringArray:和split基本一樣,但能自動去掉空白的單詞
八. org.apache.commons.lang.ArrayUtils
contains:是否包含某字符串 addAll:添加整個數組 clone:克隆一個數組 isEmpty:是否空數組 add:向數組添加元素 subarray:截取數組 indexOf:查找某個元素的下標 isEquals:比較數組是否相等 toObject:基礎類型數據數組轉換為對應的Object數組
九. org.apache.commons.lang.StringEscapeUtils
參考十五:org.apache.commons.lang3.StringEscapeUtils
十. org.apache.http.client.utils.URLEncodedUtils
format:格式化參數,返回一個HTTP POST或者HTTP PUT可用application/x-www-form-urlencoded字符串 parse:把String或者URI等轉換為List<NameValuePair>
十一. org.apache.commons.codec.digest.DigestUtils
md5Hex:MD5加密,返回32位字符串 sha1Hex:SHA-1加密 sha256Hex:SHA-256加密 sha512Hex:SHA-512加密 md5:MD5加密,返回16位字符串
十二. org.apache.commons.collections.CollectionUtils
isEmpty:是否為空 select:根據條件篩選集合元素 transform:根據指定方法處理集合元素,類似List的map() filter:過濾元素,雷瑟List的filter() find:基本和select一樣 collect:和transform 差不多一樣,但是返回新數組 forAllDo:調用每個元素的指定方法 isEqualCollection:判斷兩個集合是否一致
十三. org.apache.commons.lang3.ArrayUtils
contains:是否包含某個字符串 addAll:添加整個數組 clone:克隆一個數組 isEmpty:是否空數組 add:向數組添加元素 subarray:截取數組 indexOf:查找某個元素的下標 isEquals:比較數組是否相等 toObject:基礎類型數據數組轉換為對應的Object數組
十四. org.apache.commons.beanutils.PropertyUtils
getProperty:獲取對象屬性值 setProperty:設置對象屬性值 getPropertyDiscriptor:獲取屬性描述器 isReadable:檢查屬性是否可訪問 copyProperties:復制屬性值,從一個對象到另一個對象 getPropertyDiscriptors:獲取所有屬性描述器 isWriteable:檢查屬性是否可寫 getPropertyType:獲取對象屬性類型
十五. org.apache.commons.lang3.StringEscapeUtils
unescapeHtml4:轉義html escapeHtml4:反轉義html escapeXml:轉義xml unescapeXml:反轉義xml escapeJava:轉義unicode編碼 escapeEcmaScript:轉義EcmaScript字符 unescapeJava:反轉義unicode編碼 escapeJson:轉義json字符 escapeXml10:轉義Xml10
這個現在已經廢棄了,建議使用commons-text包里面的方法。
十六. org.apache.commons.beanutils.BeanUtils
copyPeoperties:復制屬性值,從一個對象到另一個對象 getProperty:獲取對象屬性值 setProperty:設置對象屬性值 populate:根據Map給屬性復制 copyPeoperty:復制單個值,從一個對象到另一個對象 cloneBean:克隆bean實例
現在你只要了解了以上16種最流行的工具類方法,你就不必要再自己寫工具類了,不必重復造輪子。大部分工具類方法通過其名字就能明白其用途,如果不清楚的,可以看下別人是怎么用的,或者去網上查詢其用法。
另外,工具類,根據阿里開發手冊,包名如果要使用util不能帶s,工具類命名為 XxxUtils
文本標記語言(英語:HyperText Markup Language,簡稱:HTML)是一種用于創建網頁的標準標記語言。HTML是一種基礎技術,常與CSS、JavaScript一起被眾多網站用于設計令人賞心悅目的網頁、網頁應用程序以及移動應用程序的用戶界面。網頁瀏覽器可以讀取HTML文件,并將其渲染成可視化網頁。HTML描述了一個網站的結構語義隨著線索的呈現,使之成為一種標記語言而非編程語言。
HTML元素是構建網站的基石。HTML允許嵌入圖像與對象,并且可以用于創建交互式表單,它被用來結構化信息——例如標題、段落和列表等等,也可用來在一定程度上描述文檔的外觀和語義。HTML的語言形式為尖括號包圍的HTML元素(如<html>),瀏覽器使用HTML標簽和腳本來詮釋網頁內容,但不會將它們顯示在頁面上。
HTML可以嵌入如JavaScript的腳本語言,它們會影響HTML網頁的行為。網頁瀏覽器也可以引用層疊樣式表(CSS)來定義文本和其它元素的外觀與布局。維護HTML和CSS標準的組織萬維網聯盟(W3C)鼓勵人們使用CSS替代一些用于表現的HTML元素。
歷史
W3C制作的早期HTML標志
發展
蒂姆·伯納斯-李
1980年,物理學家蒂姆·伯納斯-李在歐洲核子研究中心(CERN)在承包工程期間,為使CERN的研究人員使用并共享文檔,他提出并創建原型系統ENQUIRE。1989年,伯納斯-李在一份備忘錄中提出一個基于互聯網的超文本系統。他規定HTML并在1990年底寫出瀏覽器和服務器軟件。同年,伯納斯-李與CERN的數據系統工程師羅伯特·卡里奧聯合為項目申請資助,但未被CERN正式批準。在他的個人筆記中伯納斯-李列舉“一些使用超文本的領域”,并把百科全書列為首位。
HTML的首個公開描述出現于一個名為“HTML標簽”的文件中,由蒂姆·伯納斯-李于1991年底提及。它描述18個元素,包括HTML初始的、相對簡單的設計。除了超鏈接標簽外,其他設計都深受CERN內部一個以標準通用標記語言(SGML)為基礎的文件格式SGMLguid的影響。這些元素在HTML 4中仍有11個存在。
伯納斯-李認為HTML是SGML的一個應用程序。1993年中期互聯網工程任務組(IETF)發布首個HTML規范的提案:“超文本標記語言(HTML)”互聯網草案,由伯納斯-李與丹·康納利(英語:Dan Connolly (computer scientist))撰寫。其中包括一個SGML文檔類型定義來定義語法。草案于6個月后過期,不過值得注意的是其對NCSA Mosaic瀏覽器自定義標簽從而將在線圖像嵌入的行為的認可,這反映IETF把標準立足于成功原型的理念。同樣,戴夫·拉格特(英語:Dave Raggett)在1993年末提出的與之競爭的互聯網草案“HTML+(超文本標記格式)”建議規范已經實現的功能,如表格與填寫表單。
在HTML和HTML+的草案于1994年初到期后,IETF創建一個HTML工作組,并在1995年完成"HTML 2.0",這是第一個旨在成為對其后續實現標準的依據的HTML規范。
在IETF的主持下,HTML標準的進一步發展因競爭利益而遭受停滯。自1996年起,HTML規范一直由萬維網聯盟(W3C)維護,并由商業軟件廠商出資。不過在2000年,HTML也成為國際標準(ISO/ IEC15445:2000)。HTML 4.01于1999年末發布,進一步的勘誤版本于2001年發布。2004年,網頁超文本應用技術工作小組(WHATWG)開始開發HTML5,并在2008年與W3C共同交付,2014年10月28日完成標準化。
版本時間線
1995年11月24日
HTML 2.0作為IETF RFC 1866發布。追加RFC的附加功能:
1995年11月25日:RFC 1867(基于表單的文件上傳)
1996年5月:RFC 1942(表格)
1996年8月:RFC 1980(客戶端圖像映射)
1997年1月:RFC 2070(國際化)
1997年1月14日
HTML 3.2作為W3C推薦標準發布。這是首個完全由W3C開發并標準化的版本,因IETF于1996年9月12日關閉它的HTML工作組。
最初代號為“威爾伯”(Wilbur),HTML 3.2完全去除數學公式,協調各種專有擴展,并采用網景設計的大多數視覺標記標簽。由于兩家公司達成了協議,網景的閃爍元素(英語:blink element)和微軟的滾動元素(英語:marquee element)被移除。HTML對數學公式的支持最后成為另外一種被稱為MathML的標準。
1997年12月18日
HTML 4.0作為W3C推薦標準發布。它提供三種變化:
嚴格,過時的元素被禁止。
過渡,過時的元素被允許。
框架集,大多只與框架相關的元素被允許。
最初代號“美洲獅”(Cougar), HTML 4.0采用許多特定瀏覽器的元素類型和屬性,并試圖淘汰網景的視覺標記功能,將其標記為不贊成使用。HTML 4是遵循ISO 8879 - SGML的SGML應用程序。
1998年4月24日
HTML 4.0進行微調,不增加版本號。
1999年12月24日
HTML 4.01作為W3C推薦標準發布。它同樣提供三種變化,最終勘誤版于2001年5月12日發布。
2000年5月
ISO/IEC 15445:2000("ISO HTML",基于HTML 4.01嚴格版)作為ISO/IEC國際標準發布。在ISO中這一標準位于ISO/IEC JTC 1/SC 34(英語:ISO/IEC JTC 1/SC 34)域(ISO/IEC聯合技術委員會1、小組委員會34 – 文檔描述與處理語言)。
2014年10月28日
HTML 5作為W3C推薦標準發布。
草案時間線
HTML5的Logo
1991年10月
HTML標簽,一個非正式CERN文件首次公開18個HTML標簽。
1992年6月
HTML DTD的首個非正式草案, 后續有七個修訂版(7月15日,8月6日,8月18日,11月17日,11月19日,11月20日,11月22日)。
1992年11月
HTML DTD 1.1(首個版本號,基于RCS修訂版,版本號從1.1開始而非1.0),非正式草案。
1993年6月
超文本標記語言由IETF IIIR工作小組作為互聯網草案(一個粗略的建議標準)。在被第二版代一個月后,IETF又發布6個草案,最終在RFC1866中發布HTML 2.0。
1993年11月
HTML+由IETF作為互聯網草案發布,是超文本標記語言草案的一個競爭性提案。它于1994年5月到期。
1995年4月 (1995年3月編寫)
HTML 3.0[33]被提議作為IETF的標準,但直到提案在五個月過期后(1995年9月28日)仍沒有進一步的行動。它包含許多拉格特HTML+提案的功能,如對表格的支持、圍繞數據的文本流和復雜的數學公式的顯示。W3C開始開發自己的Arena瀏覽器作為HTML 3和層疊樣式表的試驗臺(英語:Test bed),但HTML 3.0并沒有獲得成功。瀏覽器廠商,包括微軟和網景,選擇實現HTML3草案功能的不同子集并引入它們自己的插件(見瀏覽器大戰)。
2008年1月
HTML5由W3C作為工作草案(鏈接)發布。雖然HTML5的語法非常類似于SGML,但它已經放棄任何成為SGML應用程序的嘗試,除了一種替代的基于XML的HTML5序列,它已明確定義自己的“HTML”序列。
2011年 HTML5 – 最終征求
2011年5月,工作小組將HTML5推進至“最終征求”(Last Call)階段,邀請W3C社區內外人士以確認本規范的技術可靠性。W3C開發一套綜合性測試套件來實現完整規范的廣泛交互操作性,完整規范的目標日期為2014年。2011年1月,WHATWG將其“HTML5”活動標準重命名為“HTML”。W3C仍然繼續其發布HTML5的項目。
2012年 HTML5 – 候選推薦
2012年7月,WHATWG和W3C的工作產生一定程度的分離。W3C繼續HTML5規范工作,重點放在單一明確的標準上,這被WHATWG稱為“快照”。WHATWG組織則將HTML5作為一個“活動標準”(Living Standard)。活動標準的概念是從未完成但永遠保持更新與改進,可以添加新特性,但功能點不會被刪除。
2012年12月,W3C指定HTML5作為候選推薦階段。 該階段的標準為“兩個100%完成,完全實現交互操作”。
2014年 HTML5 – 提案推薦與推薦
2014年9月,HTML5進入提案推薦階段。
2014年10月28日,HTML5作為穩定W3C推薦標準發布,這意味著HTML5的標準化已經完成。
XHTML版本
XHTML是使用XML 1.0改寫自HTML 4.01的獨立語言。它不再被作為單獨標準開發。
XHTML 1.0, 2000年1月26日作為W3C推薦標準發布。修訂版于2002年8月1日發布,它提供與HTML 4.0和4.01相同的三個變化,這些變化被重新在XML中制定。
XHTML 1.1,基于XHTML 1.0 嚴格版,2001年5月31日 作為W3C推薦標準發布。修訂版可使用模塊化XHTML的模塊,2001年4月10日作為W3C推薦標準發布。
XHTML 2.0為工作草案,但為支持HTML5與XHTML5的工作,此草案被放棄。 XHTML 2.0與XHTML 1.x不兼容,因此更確切的說這是一個XHTML風格的新語言而不是XHTML 1.x的更新。
在HTML5草案中規定一個XHTML語法,稱為“XHTML5.1”。
標記
HTML標記包含標簽(及其屬性)、基于字符的數據類型、字符引用和實體引用等幾個關鍵部分。HTML標簽是最常見的,通常成對出現,比如<h1>與</h1>。這些成對出現的標簽中,第一個標簽是開始標簽,第二個標簽是結束標簽。兩個標簽之間為元素的內容,有些標簽沒有內容,為空元素,如<img>。
HTML另一個重要組成部分為文檔類型聲明(英語:document type declaration),這會觸發標準模式渲染。
以下是一個經典的Hello World程序的例子:
<!DOCTYPE html>
<html>
<head>
<title>This is a title</title>
</head>
<body>
<p>Hello world!</p>
</body>
</html>
<html>和</html>之間的文本描述網頁,<body>和</body>之間的文本為可視頁面內容。標記文本<title>This is a title</title>定義了瀏覽器的頁面標題。
文檔標記類型<!DOCTYPE html>用于HTML5。 如果未進行聲明,瀏覽器會使用“怪異模式”進行渲染。
元素
HTML文檔由嵌套的HTML元素構成。它們用HTML標簽表示,包含于尖括號中,如<p>
在一般情況下,一個元素由一對標簽表示:“開始標簽”<p>與“結束標簽”</p>。元素如果含有文本內容,就被放置在這些標簽之間。
在開始與結束標簽之間也可以封裝另外的標簽,包括標簽與文本的混合。這些嵌套元素是父元素的子元素。
開始標簽也可包含標簽屬性。這些屬性有諸如標識文檔區段、將樣式信息綁定到文檔演示和為一些如<img>等的標簽嵌入圖像、引用圖像來源等作用。
一些元素如換行符<br>,不允許嵌入任何內容,無論是文字或其他標簽。這些元素只需一個單一的空標簽(類似于一個開始標簽),無需結束標簽。
許多標簽是可選的,尤其是那些很常用的段落元素<p>的閉合端標簽。HTML瀏覽器或其他媒介可以從上下文識別出元素的閉合端以及由HTML標準所定義的結構規則。這些規則非常復雜,不是大多數HTML編碼人員可以完全理解的。
因此,一個HTML元素的一般形式為:<tag attribute1="value1" attribute2="value2">''content''</tag>。一些HTML元素被定義為空元素,其形式為<tag attribute1="value1" attribute2="value2">。空元素不能封裝任何內容。例如<br>標簽或內聯標簽<img>。一個HTML元素的名稱即為標簽使用的名稱。注意,結束標簽的名稱前面有一個斜杠“/”,空元素不需要也不允許結束標簽。如果元素屬性未標明,則使用其默認值。
例子
HTML文檔的頁眉:<head>...</head>。標題被包含在頭部,例如:
<head>
<title>The Title</title>
</head>
標題:HTML標題由<h1>到<h6>六個標簽構成,字體由大到小遞減:
<h1>Heading level 1</h1>
<h2>Heading level 2</h2>
<h3>Heading level 3</h3>
<h4>Heading level 4</h4>
<h5>Heading level 5</h5>
<h6>Heading level 6</h6>
段落:
<p>第一段</p> <p>第二段</p>
換行:<br>。<br>與<p>之間的差異是br換行但不改變頁面的語義結構,而p部分的頁面成段。
<p>這是<br>一個<br>使用換行<br>段落</p>
鏈接:使用<a>標簽來創建鏈接。href屬性包含鏈接的URL地址。
<a >中文維基百科的連結!</a>
注釋:
<!-- This is a comment -->
注釋有助于理解標記,但它不會在網頁上顯示。
HTML中存在以下幾種類型的標記元素:
用于文本的結構式標記
例如,<h2>羽毛球</h2>將“羽毛球”定義為二級標題。結構式標記不指示任何特定的渲染,但大多數網頁瀏覽器都會采用元素格式的默認樣式。要在內容上實現進一步的風格可以使用層疊樣式表(CSS)。
用于文本外觀的表現式標記,不論其目的
例如,<b>粗體</b>表示視覺輸出設備應將文本“粗體”加粗,但如果設備無法做到這一點(如朗讀文本的聽覺設備),就不會發生什么現象。在這種情況下,<b>粗體</b>與''斜體''也可能有相同的視覺效果,但在本質上它們更加語義化。如同<strong>加強文字</strong>與<em>強調文字</em>的區別。為支持CSS的使用,大多數表現式標記在HTML 4.0規范中不再被推薦使用。
超文本標記使文檔的一部分鏈接到其他文檔
錨元素在文檔中創建超鏈接,其href屬性設置鏈接的目標URL。例如:HTML標記<a 渲染為超鏈接。要將圖片渲染為超鏈接,img元素要作為內容插入到a元素中:<a ><img src="image.gif" alt="說明文字" width="50" height="50" border="0"></a>。
屬性
大多數元素的屬性以“名稱-值”的形式成對出現,由“=”分離并寫在開始標簽元素名之后。值一般由單引號或雙引號包圍,有些值的內容包含特定字符,在HTML中可以去掉引號(XHTML不行)。不加引號的屬性值被認為是不安全的[58]。有些屬性無需成對出現,僅存在于開始標簽中即可影響元素[6],如img 元素的ismap 屬性。
許多元素存在一些共通的屬性:
id屬性為元素提供了在全文檔內的唯一標識。它用于識別元素,以便樣式表可以改變其表現屬性,腳本可以改變、顯示或刪除其內容或格式化。對于添加到頁面的URL,它為元素提供了一個全局唯一標識,通常為頁面的子章節。例如,ID "屬性"對于https://zh.wikipedia.org/wiki/HTML#屬性
class屬性提供一種將類似元素分類的方式。常被用于語義化或格式化。例如,一個HTML文檔可指定類<class="標記">來表明所有具有這一類值的元素都從屬于文檔的主文本。格式化后,這樣的元素可能會聚集在一起,并作為頁面腳注而不會出現在HTML代碼中。類屬性也被用于微格式的語義化。類值也可進行多聲明。如<class="標記 重要">將元素同時放入標記與重要兩類中。
style屬性可以將表現性質賦予一個特定元素。比起使用id或class 屬性從樣式表中選擇元素,“style”被認為是一個更好的做法,盡管有時這對一個簡單、專用或特別的樣式顯得太繁瑣。
title屬性用于給元素一個附加的說明。 大多數瀏覽器中這一屬性顯示為工具提示(英語:Tooltip)。
lang屬性用于識別元素內容的語言,它可能與文檔的主要語言不同。例如,在中文文檔中:
<p>法語<span lang="fr">c'est la vie</span>在法國的應用很普遍,意為“這就是生活” 。<p>
縮寫元素abbr可用于說明一些屬性:
<abbr id="ID" class="術語" style="color:purple;" title="超文本標記語言">HTML</abbr>
這個例子顯示為HTML; 在大多數瀏覽器中,光標指向縮寫時會顯示標題文字“超文本標記語言”。
大多數元素采用與語言相關的屬性dir 來指定文字方向,如 "rtl"采用從右到左的文本,比如阿拉伯語、波斯語以及希伯來語。
字符與實體引用
參見:XML與HTML字符實體引用列表和Unicode與HTML
在4.0版本中,HTML定義了一系列共252個字符實體引用和1,114,050個字元值參考。二者都支持單個字符通過簡單的標記寫入。文字字符與其對應的標記渲染的效果相同。
用這種方式“轉義”字符的能力允許字符<與&(當分別被寫作<和&時)被理解為字符數據而不是標記。例如<通常為標簽的開頭,&通常為字符實體引用與數字字符引用的開頭;&或&或&將&作為元素的內容或屬性的值。雙引號字符"在不被用于屬性值的標示時必須轉義為"或"或";相等地,當于單引號字符'不被用于屬性值的標示時,也必須轉義為'或'(或HTML5與XHTML文檔中的')。
如果文檔作者忽略了轉義這樣的字符,一些瀏覽器會嘗試通過上下文猜測他們的意圖。如果結果仍為無效標記,這會使其他瀏覽器或用戶代理難以訪問到該文檔,并使它們嘗試使用搜索和索引來解析該文檔。
那些難以輸入或不在該文檔字符編碼中的字符也可通過轉義來實現。例如通常只在西歐或南美的鍵盤出現的重音符e(é),可以在HTML文檔中用作實體引用é 或數字引用é或é。 諸如UTF-8的Unicode字符編碼與所有的現代瀏覽器兼容并允許直接訪問全球書寫系統幾乎所有的字符 。
數據類型
HTML為元素內容定義了多種數據類型,如腳本數據、樣式表數據以及許多屬性值的類型,包括ID、名稱、URI、數字長度單位、語言、媒體描述符顏色、字符編碼、日期和時間等等。所有這些數據類型都是字符數據的特殊化。
文檔類型聲明
HTML文檔需要以文檔類型聲明(英語:document type declaration)(英語非正式說法“doctype”)開頭。在瀏覽器中,文檔類型聲明有助于確定渲染模式——特別是是否使用怪異模式。
文檔類型聲明的初衷是通過基于文檔類型定義(DTD)的SGML工具來解析并驗證HTML文檔。
HTML5未定義DTD,所以在HTML5中文檔類型聲明更為簡短:
<!DOCTYPE html>
HTML 4文檔類型聲明舉例:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
該聲明引用HTML 4.01“嚴格”版的DTD。基于SGML的驗證器可讀取DTD,正確解析這些文檔并執行驗證。在現代瀏覽器中,一個有效的文檔類型激活標準模式有別于怪異模式。
另外,HTML 4.01提供過渡型與框架集型的DTD。過渡型涵蓋最廣,它可整合當前以及老舊或“過時”的標簽,而嚴格型DTD排除了過時的標簽。框架集擁有所有構建框架所需的標簽以及過渡型的標簽。
語義化HTML
語義化HTML是一種編寫HTML的方式,它強調編碼信息的含義在其格式(樣子)之上。HTML從創立之初就包括語義化標記,但也包括標識性標記如<font>、<i>和<center>標簽。也存在一些語義上中立的span與div標簽。自1990年代末層疊樣式表開始應用于大多數瀏覽器,網頁制作者就被鼓勵使用CSS以便呈現與內容分離。
在2001年一次對語義網的討論中,蒂姆·伯納斯-李等人給出了一種的方法,使智能軟件“代理人”可能有一天會自動抓取網頁進行查找、過濾并將之前不相關的聯系起來。這種代理甚至在現在也不普遍,但一些Web 2.0、混搭和價格比較網站的想法可能會結束。這些網頁應用程序的混合與伯納斯-李的語義代理人的之間主要區別基于以下事實:當前的聚合與信息混合通常由網頁開發者設計,他們早已知道網絡位置和他們希望混搭、比較與結合的特定數據的API語義。
網頁代理的一個重要類型是網絡爬蟲或搜索引擎蜘蛛。這些軟件代理依賴于它們發現的網頁的語義清晰度,因為它們一天要使用各種技術與算法來讀取和索引數百萬個網頁并給網頁用戶提供搜索工具,沒有這些萬維網的有效性就會大大降低。
為使搜索引擎蜘蛛評估它們在HTML文檔中發現的文本片段的重要性,也為那些創建標記等混合的人與更多的自動化代理工具,HTML中的語義結構需要廣泛一致地應用從而將文本的含義呈現給瀏覽者。
表示性標記在當前的HTML和XHTML推薦中不被鼓勵使用,HTML5中則被視為非法。
好的語義化HTML也改善了網頁文檔的可訪問性。例如,當屏幕閱讀器或音頻瀏覽器可以正確判定一個文檔的結構時,視覺障礙用戶不會再因閱讀重復或無關的信息而浪費時間。
分發
HTML文檔分發的方法和其他計算機文件相同。不過,它們最常通過網頁服務器的超文本傳輸協議或電子郵件傳輸。
HTTP
萬維網主要由從服務器通過HTTP協議向瀏覽器發送的HTML文檔組成。但是,HTTP也可以被用于傳輸HTML之外的數據,例如圖像、聲音和其他內容。為使瀏覽器了解如何處理接收到的文檔,在傳輸文檔時必須同時傳遞文件類型。這種元數據包含MIME類型(對于HTML 4.01或更早版本是text/html,而對于XHTML 1.0或之后的版本是application/xhtml+xml),以及字符編碼(參見HTML字符編碼方式)。
在現在的瀏覽器中,和HTML文檔一起發送的MIME類型影響文檔的解讀方式。和XHTML MIME類型一起發送的文檔被認為是良構的XML,而語法錯誤會導致瀏覽器無法呈現文檔。完全相同的文檔如果和HTML MIME類型一起發送,則可能被正常顯示,因為瀏覽器對HTML的語法檢查更加松懈些。
W3C的推薦指出,遵循規定的推薦指引的XHTML 1.0文檔可標記二者任一的MIME類型。XHTML 1.1還指出,XHTML 1.1文檔應標有兩種MIME類型。
HTML郵件
大多數圖形電子郵件客戶端允許使用HTML的子集(經常界限不清)提供格式化和無法使用純文本的語義標記。這可能包括印刷信息,如彩色標題、強調和引用文本、內嵌圖片和圖表等。許多這樣的客戶包含一個編寫HTML電子郵件消息的圖形用戶界面編輯器和一個用于顯示的渲染引擎。在郵件中使用HTML受到了一些兼容性的批評,由于一些盲人或具有視覺障礙的人的訪問問題,這種方式有利于偽裝的釣魚攻擊。因其消息大小超過明文,所以它可混淆垃圾郵件過濾器。
命名規則
最常用的計算機文件擴展名為.html,通用縮寫為.htm。它起源于某些早期操作系統與文件系統,如DOS以及FAT數據結構的局限性,它將文件擴展名限制為3個字母。
HTML應用程序
HTML應用程序(HTA;文件擴展名".hta")是一個Microsoft Windows應用程序,它在瀏覽器中使用HTML和動態HTML提供應用程序圖形界面。正規HTML文件被限制在瀏覽器的安全模型中,只能分別通過網頁服務器和網頁對象與站點Cookie進行通信和操作。HTA作為完全受信任的應用程序運行,因此擁有更多的權限,如創建/編輯/刪除文件與注冊表項。因為它們在瀏覽器安全模式之外操作,所以HTA不能通過HTTP執行,必須下載(就像EXE文件)并在本地文件系統執行。
所見即所得編輯器
所見即所得編輯器使用圖形用戶界面(GUI)顯示HTML文檔,常常類似于文字處理器,所以用戶可以設計一切。編者面對的是文檔,而不是代碼,所以作者并不需要太多的HTML知識。這種所見即所得的編輯模式一直受到詬病,主要因為它生成的代碼質量不高;也有人主張將其改變至WYSIWYM模型(所見即所指)。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。