導(dǎo)言:在 Kubernetes 中,ConfigMap 是允許管理員將配置組件與鏡像內(nèi)容解耦,使容器化應(yīng)用程序產(chǎn)生可移植性的一種資源。ConfigMap 可以與 Kubernetes Pod 一起使用,用于動態(tài)添加或更改容器中的使用文件。本文將闡述 Kubernetes ConfigMap 如何利用動態(tài)應(yīng)用程序的方法來解決輕量級文件服務(wù)器部署到 Kubernetes 集群中的問題。
ConfigMap 概覽
生產(chǎn)環(huán)境中很多應(yīng)用程序的配置可能需要通過配置文件、命令行參數(shù)和環(huán)境變量的組合來完成。這些配置應(yīng)該從鏡像中解耦,通過這種方式來保持容器化應(yīng)用程序的可移植性。在 Kubernetes 1.2 版本以后,研發(fā)人員引入 ConfigMap 來處理這種類型的配置數(shù)據(jù)。
簡單來說,ConfigMap 是容器的配置管理。在容器運行時,ConfigMap 把配置文件、命令行參數(shù)、環(huán)境變量、端口號和其他配置組件綁定到 Pod 的容器和系統(tǒng)組件上,同時將應(yīng)用的代碼和配置區(qū)分開。從數(shù)據(jù)角度來看,ConfigMap 的類型只是鍵值對。從應(yīng)用角度來看,管理員可以從不同角度來配置它。
在 Pod 中使用 ConfigMap 大致有以下三種方式:
- 將 ConfigMap 中的數(shù)據(jù)設(shè)置為環(huán)境變量;
- 將 ConfigMap 中的數(shù)據(jù)設(shè)置為命令行參數(shù);
- 將 ConfigMap 作為文件或目錄掛載。
另外,由于應(yīng)用會從環(huán)境變量和包含配置數(shù)據(jù)的文件中讀取配置信息,所以 ConfigMap 是可以支持這兩種讀取方式的。
創(chuàng)配置 ConfigMap 的注意事項
眾所周知,ConfigMap 與 Secret 很相似。但是,ConfigMap 主要用來存儲和共享非敏感、未加密的配置信息。Secret 是用來存儲敏感信息(例如:密碼)。除了這個大家都了解的注意事項外,在配置 ConfigMap 時還要注意以下 4 點:
- ConfigMap 必須在被 Pod 使用之前創(chuàng)建;
- Pod 只能使用在同一 Namespace 中的 ConfigMap;
- ConfigMap 大小的配額是一個已經(jīng)設(shè)置好的功能;
- Kubelet 只支持 API 服務(wù)器中的 Pod 使用 ConfigMap。
注:API 服務(wù)器中的 Pod 包括用 Kubectl 創(chuàng)建的 Pod、間接通過 replication controller 創(chuàng)建的 Pod,不包括通過 Kubelet 的 –manifest-url 標(biāo)志創(chuàng)建的 Pod,也不包括從它的 REST API 創(chuàng)建的 Pod。
ConfigMap 用于動態(tài)應(yīng)用程序的實踐
需要解決的問題
作為 Kubernetes 安裝程序的一部分,很多人希望可以將輕量級文件服務(wù)器部署到 Kubernetes 集群中以此處理默認(root - path)入口請求。并且,我認為如果我們可以編輯 index.html 和 CSS 文件而不必重新部署應(yīng)用程序。
為了解決這個用例,我們決定構(gòu)建一個 Golang 應(yīng)用程序,將其部分文件系統(tǒng)映射到 Kubernetes ConfigMap 資源中。
Golang Fileserver
文件服務(wù)器應(yīng)用程序的設(shè)計非常簡單,它僅用于提供靜態(tài)內(nèi)容。這種方式可以幫助 Kubernetes 用戶使用入口功能。
package main
import (
“l(fā)og”
“net/http”
)
func main() {
fs := http.FileServer(http.Dir(“html”))
http.Handle(“/”, fs)
log.Println(“Listening…”)
http.ListenAndServe(“:8080”, nil)
}
應(yīng)用程序使用以下 Dockerfile 內(nèi)容構(gòu)建容器鏡像。它是一個兩階段的 Dockerfile,首先在 Alpine 容器中執(zhí)行 Golang 構(gòu)建,然后將已編譯的二進制和空 helm 目錄復(fù)制到最終的 scratch-based 鏡像上。
# build stage
FROM golang:alpine AS builder
WORKDIR /usr/local/go/src
COPY main.go .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .
# final stage
FROM scratch
WORKDIR /
COPY --from=builder /usr/local/go/src/main main
COPY html html
EXPOSE 8080
ENTRYPOINT ["/main"]
在 Golang 應(yīng)用程序中使用 scratch 容器來部署 Golang 容器是一種更安全、更輕量級的方法。
部署和運行
我使用 make 來自動化 Docker 操作。以下是此應(yīng)用程序的 Makefile 。
VERSION?= 0.0.1
NAME?=“ingress-default”
AUTHOR?=“Jimmy Ray”
PORT_EXT?= 8080
PORT_INT?= 8080
NO_CACHE?= true
.PHONY:build run stop clean
build:
docker build -f scratch.dockerfile.-t $(NAME)\:$(VERSION) - no-cache = $(NO_CACHE)
run: docker
run --name $(NAME)-d -p $(PORT_EXT):$(PORT_INT)$(NAME) \:$(VERSION)&& docker ps -a --format“{{.ID}} \ t {{.Names}}”| grep $(NAME)
stop:
docker rm $$(docker stop $$(docker ps) -a -q --filter“ancestor = $(NAME):$(VERSION)” - format =“{{.ID}}”))
clean:
@rm -f main
DEFAULT:build
我們可以使用 make 消除重復(fù)任務(wù)之間的可變性。有了上述的 Makefile,在將測試的應(yīng)用程序部署到 Kubernetes 之前,我們可以在 Docker 中構(gòu)建和運行應(yīng)用程序。
配置 Kubernetes
對于此解決方案,我們需要配置 Kubernetes Namespace、ConfigMap、Deployment、Service 和 Ingress。我們通過使用 kubectl apply -f 的方法來完成此操作(這是對 Kubernetes 集群資源應(yīng)用更改的聲明式方法)。
下面是我們將 munge 的 Kubernetes 資源的 YAML 文件。
apiVersion: v1
kind: Namespace
metadata:
name: ingress-default
labels:
app: ingress-default
---
kind: ConfigMap
apiVersion: v1
metadata:
name: ingress-default-static-files
namespace: ingress-default
labels:
app: ingress-default
data:
index.html: |
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Cluster Ingress Index</title>
<link rel="stylesheet" href="main.css">
</head>
<body>
<table class="class1">
<tr>
<td class="class2">Kubernetes Platform</td>
</tr>
<tr>
<td class="class1">
<table class="class3">
<tr><td><h1>Cluster Ingress Index</h1></td></tr>
</table>
</td>
</tr>
<tr>
<td>
<table class="class3">
<tr>
<td>
<h2>The following are links to this cluster's ingress resources:</h2>
</td>
</tr>
<tr>
<td class="class4">
<a href="https://<ROOT_INGRESS_PATH>" target="_blank">Root Ingress</a><br/>
<a href="https://<OTHER_INGRESS_PATH>" target="_blank">Other Ingress</a><br/>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
main.css: |
body {
background-color: rgb(224,224,224);
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 100%;
}
.class1 {
...
}
.class2 {
...
}
.class3 {
...
}
.class4 {
...
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: ingress-default
name: ingress-default
namespace: ingress-default
spec:
selector:
matchLabels:
app: ingress-default
replicas: 1
template:
metadata:
labels:
app: ingress-default
name: ingress-default
spec:
containers:
- name: ingress-default
image: <IMAGE_REGISTRY_REPO_TAG>
imagePullPolicy: Always
resources:
limits:
cpu: 100m
memory: 10Mi
requests:
cpu: 100m
memory: 10Mi
volumeMounts:
- readOnly: true
mountPath: html
name: html-files
volumes:
- name: html-files
configMap:
name: ingress-default-static-files
---
kind: Service
apiVersion: v1
metadata:
name: ingress-default
namespace: ingress-default
labels:
app: ingress-default
spec:
selector:
app: ingress-default
ports:
- name: http
protocol: TCP
port: 80
targetPort: 8080
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: default-ingress
namespace: ingress-default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: "nginx"
labels:
app: ingress-default
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: ingress-default
servicePort: 80
正如在 YAML 中的:
ingress-default-static-files
我們可以知道,ConfigMap 包含index.html 和 main.css 文件的內(nèi)容。通過編輯或替換此 ConfigMap,我們可以更改在 Golang 文件服務(wù)器應(yīng)用程序中的文件。
使用 ConfigMap 作為卷
在 Docker 和 Kubernetes 的中,卷用于解決兩個問題:
- 需要持久化的文件系統(tǒng);
- 需要在容器之間共享的文件系統(tǒng)。
現(xiàn)在,我們將已部署在容器中的卷映射到 ConfigMap 資源中。在下面的代碼段中,被配置的 html-files 卷可能被 Pod 中的所有容器使用。
卷會將數(shù)據(jù)配置映射到 ConfigMap 中的 ingress-default-static-files 上。
...volumes:
- name: html-files
configMap:
name: ingress-default-static-files…
在 Pod 級別配置卷后,我們將配置的卷裝入容器中。將此卷的掛載映射到在 Pod 中配置的 html-files 卷上。通過此映射,應(yīng)用程序容器現(xiàn)在可以訪問 ConfigMap 中的兩個文件:html/index.html 和 html/mian.css。
...volumeMounts:
- readOnly: true
mountPath: html
name: html-files
當(dāng)在 Kubernetes 集群中啟動 Golang 應(yīng)用程序時,ingress-default 會在 NGINX 入口控制器中配置上游規(guī)則。生成的路徑將通過 NGINX 入口控制器將集群邊緣連接到ingress-default 服務(wù)上。此服務(wù)指向 Golang 文件服務(wù)的 app Pod 中。在運行時,它為 ingress 控制器的根路徑上的默認 Web 應(yīng)用程序提供服務(wù)。如果需要更改此網(wǎng)頁,我們只需要 edit/replace ConfigMap。
結(jié)語
容器編排的一個關(guān)鍵好處是,它承諾消除多個容器工作負載所需的“無差異的繁重工作”。通過使用 Kubernetes 聲明性配置功能(如 ConfigMap),可以提高應(yīng)用程序部署和更改集群狀態(tài)的效率與速度。我們通過將 ConfigMap 資源作為已安裝的卷,使用正在運行的容器,可以從容器中抽象配置和內(nèi)容,減少對鏡像重構(gòu)和重新部署容器的需求。